Line data Source code
1 : !!****m* ABINIT/m_spin_primitive_potential
2 : !! NAME
3 : !! m_spin_primitive_potential
4 : !!
5 : !! FUNCTION
6 : !! This module contains the atomic structures and the spin hamiltonian inside the primitive cell
7 : !! which can be directly mapped to the xml file. It is not for the calculation, but for constructing
8 : !! the hamiltonian in supercell. It is also used as input for the magnon band structure calculation.
9 : !!
10 : !! Datatypes:
11 : !! spin_primitive_potential_t
12 : !!
13 : !! Subroutines:
14 : !!
15 : !! COPYRIGHT
16 : !! Copyright (C) 2001-2026 ABINIT group (hexu)
17 : !! This file is distributed under the terms of the
18 : !! GNU General Public License, see ~abinit/COPYING
19 : !! or http://www.gnu.org/copyleft/gpl.txt .
20 : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
21 : !!
22 : !! SOURCE
23 :
24 :
25 : #if defined HAVE_CONFIG_H
26 : #include "config.h"
27 : #endif
28 : #include "abi_common.h"
29 :
30 : module m_spin_primitive_potential
31 : use, intrinsic :: iso_c_binding
32 : use m_dynamic_array, only: int_array_type, real_array_type, int2d_array_type
33 : use m_mathfuncs
34 : use defs_basis
35 : use m_abicore
36 : use m_errors
37 : use m_xmpi
38 : use m_nctk
39 : #if defined HAVE_NETCDF
40 : use netcdf
41 : #endif
42 :
43 : use m_mpi_scheduler, only: init_mpi_info
44 : use m_multibinit_dataset, only: multibinit_dtset_type
45 : use m_multibinit_io_xml, only: xml_read_spin, xml_free_spin
46 : use m_multibinit_cell, only: mbcell_t, mbsupercell_t
47 : use m_primitive_potential, only: primitive_potential_t
48 : use m_abstract_potential, only: abstract_potential_t
49 : use m_dynamic_array, only: int2d_array_type
50 : use m_supercell_maker, only: supercell_maker_t
51 : use m_spmat_ndcoo, only: ndcoo_mat_t
52 : use m_spin_potential, only: spin_potential_t
53 :
54 : implicit none
55 : private
56 : !!***
57 :
58 :
59 : type, public, extends(primitive_potential_t) :: spin_primitive_potential_t
60 : integer :: natoms
61 : integer :: nspin ! on every mpi node
62 : type(ndcoo_mat_t) :: coeff ! only on master node
63 : type(int2d_array_type) :: Rlist !only on master node
64 :
65 : ! Here the coeff is a NOCOO matrix, which has the indices and values.
66 : ! The indices is a 2d integer matrix.
67 : ! | indices | value|
68 : ! | i1 | j1| indR1| val1 |
69 : ! | i2 | j2| indR2| val2 |
70 : !
71 : ! and the Rlist is a list of R values.
72 : ! for the k'th element ik, jk, indRk, valk, the R value is Rlist(indRk).
73 : contains
74 : procedure:: initialize
75 : procedure:: finalize
76 : procedure :: set_spin_primcell ! set primitve cell infor (rprimd, xcart, ...)
77 : procedure :: set_bilinear_1term ! set one (i,j,R) val(3,3)
78 : procedure:: set_bilinear ! set list of bilinear terms (ilist, jlist, Rlist, valllist)
79 : procedure:: set_exchange ! set list of exchange terms
80 : procedure:: set_dmi ! set list of dmi terms
81 : procedure:: set_sia ! set list of sia terms
82 : procedure :: add_input_sia ! add a SIA term from input file
83 : procedure :: load_from_files ! read potential from files
84 : procedure:: read_xml ! read potential from one xml file
85 : procedure :: read_netcdf ! read potential from one netcdf file
86 : procedure:: fill_supercell ! fill supercell.
87 : end type spin_primitive_potential_t
88 :
89 : contains
90 :
91 2 : subroutine initialize(self, primcell)
92 : class(spin_primitive_potential_t), intent(inout) :: self
93 : type(mbcell_t), target, intent(inout) :: primcell
94 : !integer, intent(in) :: nspin
95 2 : self%primcell=>primcell
96 2 : self%label="Spin_primitive_potential"
97 2 : self%has_spin=.True.
98 2 : self%has_displacement=.False.
99 2 : self%has_strain=.False.
100 2 : self%has_lwf=.False.
101 2 : end subroutine initialize
102 :
103 :
104 2 : subroutine finalize(self)
105 : class(spin_primitive_potential_t), intent(inout) :: self
106 2 : call self%coeff%finalize()
107 2 : call self%Rlist%finalize()
108 2 : nullify(self%primcell)
109 2 : self%nspin=0
110 2 : self%natoms=0
111 2 : self%label="Destroyed Spin_primitive_potential"
112 2 : call self%primitive_potential_t%finalize()
113 2 : end subroutine finalize
114 :
115 :
116 4 : subroutine set_spin_primcell(self, natoms, unitcell, positions, &
117 2 : & nspin, index_spin, spinat, gyroratios, damping_factors, &
118 : & Sref, ref_spin_qpoint, ref_spin_rotate_axis)
119 :
120 : class(spin_primitive_potential_t), intent(inout) :: self
121 : integer, intent(inout) :: natoms, nspin, index_spin(:)
122 : real(dp), intent(inout) :: unitcell(3, 3), positions(3,natoms)
123 : real(dp), intent(inout) :: spinat(3, natoms), gyroratios(nspin), damping_factors(nspin)
124 : real(dp), optional, intent(inout) :: Sref(3, nspin), ref_spin_qpoint(3), ref_spin_rotate_axis(3)
125 :
126 : integer :: iatom, ispin
127 4 : real(dp) :: ms(nspin), spin_positions(3, nspin)
128 : integer :: master, my_rank, comm, nproc, ierr
129 : logical :: iam_master
130 2 : call init_mpi_info(master, iam_master, my_rank, comm, nproc)
131 :
132 2 : ABI_UNUSED_A(unitcell)
133 :
134 2 : self%nspin=nspin
135 2 : call xmpi_bcast(self%nspin, master, comm, ierr)
136 2 : if (iam_master) then
137 8 : call self%coeff%initialize(mshape=[-1, self%nspin*3, self%nspin*3])
138 12 : do iatom=1, natoms
139 10 : ispin=index_spin(iatom)
140 12 : if(ispin>0) then
141 8 : spin_positions(:,ispin)= positions(:, iatom)
142 8 : ms(ispin) = sqrt(sum(spinat(:,iatom)**2, dim=1))* mu_B
143 : end if
144 : end do
145 : endif
146 : call self%primcell%set_spin(nspin, ms, unitcell, spin_positions, gyroratios, damping_factors, &
147 2 : & Sref=Sref, ref_qpoint=ref_spin_qpoint, ref_rotate_axis=ref_spin_rotate_axis)
148 :
149 : !call self%primcell%set_lattice(natom=natoms, cell=unitcell, xcart=spin_positions, masses, zion)
150 2 : end subroutine set_spin_primcell
151 :
152 :
153 2 : subroutine load_from_files(self, params, fnames)
154 : class(spin_primitive_potential_t), intent(inout) :: self
155 : type(multibinit_dtset_type), intent(in) :: params
156 : character(len=fnlen), intent(in) :: fnames(:)
157 : character(len=fnlen) :: fname
158 : character(len=500) :: message
159 : integer :: ii
160 : logical:: use_sia, use_exchange, use_dmi, use_bi
161 2 : fname=params%spin_pot_fname
162 : ABI_UNUSED(fnames)
163 2 : if (xmpi_comm_rank(xmpi_world)==0) then
164 164 : write(message,'(a,(80a),3a)') ch10,('=',ii=1,80),ch10,ch10,&
165 166 : & 'reading spin terms.'
166 2 : call wrtout(ab_out,message,'COLL')
167 2 : call wrtout(std_out,message,'COLL')
168 : endif
169 2 : use_exchange=.True.
170 2 : use_sia=.True.
171 2 : use_dmi=.True.
172 2 : use_bi=.True.
173 : ! Do not use sia term in xml if spin_sia_add is set to 1.
174 2 : if(params%spin_sia_add == 1) use_sia=.False.
175 :
176 2 : if(endswith(trim(fname), ".xml")) then
177 : call self%read_xml( trim(fname)//char(0), &
178 0 : & use_exchange=use_exchange, use_sia=use_sia, use_dmi=use_dmi, use_bi=use_bi)
179 2 : else if(endswith(trim(fname), ".nc")) then
180 2 : call self%read_netcdf(fname)
181 : endif
182 2 : if (params%spin_sia_add /= 0 ) then
183 : call self%add_input_sia(params%spin_sia_k1amp, &
184 0 : & params%spin_sia_k1dir)
185 : end if
186 2 : end subroutine load_from_files
187 :
188 :
189 : !-------------------------------------------------------------------!
190 : ! load_from_netcdf
191 : ! Load spin primitive potential from a netcdf file.
192 : !-------------------------------------------------------------------!
193 2 : subroutine read_netcdf(self, fname)
194 : class(spin_primitive_potential_t), intent(inout) :: self
195 : character(len=fnlen), intent(in) :: fname
196 : integer :: ierr, ncid, varid
197 :
198 : integer :: nspin, natom
199 : real(dp) :: cell(3,3)
200 : real(dp) :: ref_spin_qpoint(3), ref_spin_rotate_axis(3)
201 2 : real(dp), allocatable :: ref_spin_orientation(:, :)
202 2 : integer, allocatable :: index_spin(:)
203 2 : real(dp), allocatable :: spinat(:,:)
204 2 : real(dp), allocatable :: xcart(:,:)
205 2 : real(dp), allocatable :: gyroratio(:)
206 2 : real(dp), allocatable :: gilbert_damping(:)
207 :
208 : integer :: spin_exchange_nterm
209 2 : integer , allocatable:: spin_exchange_ilist(:)
210 2 : integer , allocatable:: spin_exchange_jlist(:)
211 2 : integer , allocatable:: spin_exchange_Rlist(:,:)
212 2 : real(dp), allocatable:: spin_exchange_vallist(:,:)
213 :
214 : integer :: spin_dmi_nterm
215 2 : integer , allocatable:: spin_dmi_ilist(:)
216 2 : integer , allocatable:: spin_dmi_jlist(:)
217 2 : integer , allocatable:: spin_dmi_Rlist(:,:)
218 2 : real(dp), allocatable:: spin_dmi_vallist(:,:)
219 :
220 :
221 : integer :: spin_SIA_nterm
222 2 : integer , allocatable:: spin_SIA_ilist(:)
223 2 : real(dp), allocatable:: spin_SIA_k1list(:)
224 2 : real(dp), allocatable:: spin_SIA_k1dirlist(:,:)
225 :
226 :
227 : integer :: spin_bilinear_nterm
228 2 : integer , allocatable:: spin_bilinear_ilist(:)
229 2 : integer , allocatable:: spin_bilinear_jlist(:)
230 2 : integer , allocatable:: spin_bilinear_Rlist(:,:)
231 2 : real(dp), allocatable:: spin_bilinear_vallist(:,:,:)
232 :
233 : #if defined HAVE_NETCDF
234 :
235 : ! open netcdf file
236 2 : ierr=nf90_open(trim(fname)//char(0), NF90_NOWRITE, ncid)
237 2 : NCF_CHECK_MSG(ierr, "open netcdf file")
238 :
239 : ! read primcell info
240 2 : ierr=nctk_get_dim(ncid, "natom", natom)
241 2 : NCF_CHECK_MSG(ierr, "getting natom in spin potential file")
242 2 : ierr=nctk_get_dim(ncid, "nspin", nspin)
243 2 : NCF_CHECK_MSG(ierr, "getting nspin in spin potential file")
244 :
245 : ! allocate for primcell
246 6 : ABI_MALLOC(xcart, (3, natom))
247 4 : ABI_MALLOC(spinat, (3, natom))
248 6 : ABI_MALLOC(index_spin, (natom))
249 6 : ABI_MALLOC(gyroratio, (nspin))
250 4 : ABI_MALLOC(gilbert_damping, (nspin))
251 6 : ABI_MALLOC(ref_spin_orientation, (3, nspin))
252 :
253 2 : ierr =nf90_inq_varid(ncid, "ref_cell", varid)
254 2 : NCF_CHECK_MSG(ierr, "ref_cell")
255 2 : ierr = nf90_get_var(ncid, varid, cell)
256 2 : NCF_CHECK_MSG(ierr, "ref_cell")
257 26 : cell(:,:)=cell(:,:)/ Bohr_Ang
258 :
259 2 : ierr =nf90_inq_varid(ncid, "ref_xcart", varid)
260 2 : NCF_CHECK_MSG(ierr, "ref_xcart")
261 2 : ierr = nf90_get_var(ncid, varid, xcart)
262 2 : NCF_CHECK_MSG(ierr, "ref_xcart")
263 :
264 42 : xcart(:,:)=xcart(:,:)/ Bohr_Ang
265 :
266 2 : ierr =nf90_inq_varid(ncid, "spin_ref_orientation", varid)
267 2 : if(ierr==NF90_NOERR) then
268 0 : ierr = nf90_get_var(ncid, varid, ref_spin_orientation)
269 0 : NCF_CHECK_MSG(ierr, "spin_ref_orientation")
270 : else
271 2 : ABI_WARNING("Could not read spin_ref_orientation from nc file, will use z-direction.")
272 4 : ref_spin_orientation(1,:)=0.0d0
273 4 : ref_spin_orientation(2,:)=0.0d0
274 4 : ref_spin_orientation(3,:)=1.0d0
275 : endif
276 :
277 : !NCF_CHECK_MSG(ierr, "spin_ref_orientation")
278 : !ierr = nf90_get_var(ncid, varid, ref_spin_orientation)
279 : !NCF_CHECK_MSG(ierr, "spin_ref_orientation")
280 :
281 2 : ierr =nf90_inq_varid(ncid, "spin_ref_qpoint", varid)
282 2 : if(ierr==NF90_NOERR) then
283 2 : ierr = nf90_get_var(ncid, varid, ref_spin_qpoint)
284 2 : NCF_CHECK_MSG(ierr, "spin_ref_qpoint")
285 : else
286 0 : ABI_WARNING("Could not read spin_ref_qpoint from nc file, will use Gamma point.")
287 0 : ref_spin_qpoint(:)=0.0d0
288 : endif
289 : !NCF_CHECK_MSG(ierr, "spin_ref_qpoint")
290 : !ierr = nf90_get_var(ncid, varid, ref_spin_qpoint)
291 : !NCF_CHECK_MSG(ierr, "spin_ref_qpoint")
292 :
293 2 : ierr =nf90_inq_varid(ncid, "spin_ref_rotate_axis", varid)
294 2 : if(ierr==NF90_NOERR) then
295 2 : ierr = nf90_get_var(ncid, varid, ref_spin_rotate_axis)
296 2 : NCF_CHECK_MSG(ierr, "spin_ref_rotate_axis")
297 : else
298 0 : ABI_WARNING("Could not read spin_ref_rotate_axis from nc file, will use x-axis.")
299 0 : ref_spin_rotate_axis(1)=1.0d0
300 0 : ref_spin_rotate_axis(2)=0.0d0
301 0 : ref_spin_rotate_axis(3)=0.0d0
302 : endif
303 :
304 : !NCF_CHECK_MSG(ierr, "spin_ref_rotate_axis")
305 : !ierr = nf90_get_var(ncid, varid, ref_spin_rotate_axis)
306 : !NCF_CHECK_MSG(ierr, "spin_ref_rotate_axis")
307 :
308 2 : ierr =nf90_inq_varid(ncid, "spinat", varid)
309 2 : NCF_CHECK_MSG(ierr, "spinat")
310 2 : ierr = nf90_get_var(ncid, varid, spinat)
311 2 : NCF_CHECK_MSG(ierr, "spinat")
312 :
313 2 : ierr =nf90_inq_varid(ncid, "index_spin", varid)
314 2 : NCF_CHECK_MSG(ierr, "index_spin")
315 2 : ierr = nf90_get_var(ncid, varid, index_spin)
316 2 : NCF_CHECK_MSG(ierr, "index_spin")
317 :
318 2 : ierr =nf90_inq_varid(ncid, "gyroratio", varid)
319 2 : NCF_CHECK_MSG(ierr, "gyroratio")
320 2 : ierr = nf90_get_var(ncid, varid, gyroratio)
321 2 : NCF_CHECK_MSG(ierr, "gyroratio")
322 :
323 2 : ierr =nf90_inq_varid(ncid, "gilbert_damping", varid)
324 2 : NCF_CHECK_MSG(ierr, "gilbert_damping")
325 2 : ierr = nf90_get_var(ncid, varid, gilbert_damping)
326 2 : NCF_CHECK_MSG(ierr, "gilbert_damping")
327 :
328 : call self%set_spin_primcell( natoms=natom, unitcell=cell, positions=xcart, &
329 : & nspin=nspin, index_spin=index_spin, spinat=spinat, &
330 : & gyroratios=gyroratio, damping_factors=gilbert_damping, &
331 2 : & Sref=ref_spin_orientation, ref_spin_qpoint=ref_spin_qpoint, ref_spin_rotate_axis=ref_spin_rotate_axis)
332 :
333 2 : ABI_SFREE(xcart)
334 2 : ABI_SFREE(spinat)
335 2 : ABI_SFREE(index_spin)
336 2 : ABI_SFREE(gyroratio)
337 2 : ABI_SFREE(gilbert_damping)
338 2 : ABI_SFREE(ref_spin_orientation)
339 :
340 : !== read exchange terms
341 2 : ierr=nf90_inq_dimid(ncid, "spin_exchange_nterm", spin_exchange_nterm)
342 2 : if (ierr==0) then ! if has exchange
343 2 : ierr=nctk_get_dim(ncid, "spin_exchange_nterm", spin_exchange_nterm)
344 6 : ABI_MALLOC(spin_exchange_ilist, (spin_exchange_nterm))
345 4 : ABI_MALLOC(spin_exchange_jlist, (spin_exchange_nterm))
346 6 : ABI_MALLOC(spin_exchange_Rlist, (3,spin_exchange_nterm))
347 6 : ABI_MALLOC(spin_exchange_vallist, (3,spin_exchange_nterm))
348 :
349 2 : ierr =nf90_inq_varid(ncid, "spin_exchange_ilist", varid)
350 2 : NCF_CHECK_MSG(ierr, "spin_exchange_ilist")
351 2 : ierr = nf90_get_var(ncid, varid, spin_exchange_ilist)
352 2 : NCF_CHECK_MSG(ierr, "spin_exchange_ilist")
353 :
354 2 : ierr =nf90_inq_varid(ncid, "spin_exchange_jlist", varid)
355 2 : NCF_CHECK_MSG(ierr, "spin_exchange_jlist")
356 2 : ierr = nf90_get_var(ncid, varid, spin_exchange_jlist)
357 2 : NCF_CHECK_MSG(ierr, "spin_exchange_jlist")
358 :
359 2 : ierr =nf90_inq_varid(ncid, "spin_exchange_Rlist", varid)
360 2 : NCF_CHECK_MSG(ierr, "spin_exchange_Rlist")
361 2 : ierr = nf90_get_var(ncid, varid, spin_exchange_Rlist)
362 2 : NCF_CHECK_MSG(ierr, "spin_exchange_Rlist")
363 :
364 :
365 2 : ierr =nf90_inq_varid(ncid, "spin_exchange_vallist", varid)
366 2 : NCF_CHECK_MSG(ierr, "spin_exchange_vallist")
367 2 : ierr = nf90_get_var(ncid, varid, spin_exchange_vallist)
368 2 : NCF_CHECK_MSG(ierr, "spin_exchange_vallist")
369 :
370 210 : spin_exchange_vallist(:,:) = spin_exchange_vallist(:,:) * eV_Ha
371 :
372 : call self%set_exchange(n=spin_exchange_nterm, ilist=spin_exchange_ilist, &
373 : & jlist=spin_exchange_jlist, Rlist=spin_exchange_Rlist, &
374 2 : & vallist=spin_exchange_vallist)
375 :
376 2 : ABI_SFREE(spin_exchange_ilist)
377 2 : ABI_SFREE(spin_exchange_jlist)
378 2 : ABI_SFREE(spin_exchange_Rlist)
379 2 : ABI_SFREE(spin_exchange_vallist)
380 : endif
381 :
382 :
383 :
384 : !== read dmi terms
385 2 : ierr=nf90_inq_dimid(ncid, "spin_dmi_nterm", spin_dmi_nterm)
386 2 : if (ierr==0) then ! if has dmi
387 0 : ierr=nctk_get_dim(ncid, "spin_dmi_nterm", spin_dmi_nterm)
388 0 : NCF_CHECK_MSG(ierr, "spin_dmi_nterm found but is not readable")
389 0 : ABI_MALLOC(spin_dmi_ilist, (spin_dmi_nterm))
390 0 : ABI_MALLOC(spin_dmi_jlist, (spin_dmi_nterm))
391 0 : ABI_MALLOC(spin_dmi_Rlist, (3,spin_dmi_nterm))
392 0 : ABI_MALLOC(spin_dmi_vallist, (3,spin_dmi_nterm))
393 :
394 0 : ierr =nf90_inq_varid(ncid, "spin_dmi_ilist", varid)
395 0 : NCF_CHECK_MSG(ierr, "spin_dmi_ilist")
396 0 : ierr = nf90_get_var(ncid, varid, spin_dmi_ilist)
397 0 : NCF_CHECK_MSG(ierr, "spin_dmi_ilist")
398 :
399 0 : ierr =nf90_inq_varid(ncid, "spin_dmi_jlist", varid)
400 0 : NCF_CHECK_MSG(ierr, "spin_dmi_jlist")
401 0 : ierr = nf90_get_var(ncid, varid, spin_dmi_jlist)
402 0 : NCF_CHECK_MSG(ierr, "spin_dmi_jlist")
403 :
404 0 : ierr =nf90_inq_varid(ncid, "spin_dmi_Rlist", varid)
405 0 : NCF_CHECK_MSG(ierr, "spin_dmi_Rlist")
406 0 : ierr = nf90_get_var(ncid, varid, spin_dmi_Rlist)
407 0 : NCF_CHECK_MSG(ierr, "spin_dmi_Rlist")
408 :
409 :
410 0 : ierr =nf90_inq_varid(ncid, "spin_dmi_vallist", varid)
411 0 : NCF_CHECK_MSG(ierr, "spin_dmi_vallist")
412 0 : ierr = nf90_get_var(ncid, varid, spin_dmi_vallist)
413 0 : NCF_CHECK_MSG(ierr, "spin_dmi_vallist")
414 :
415 0 : spin_dmi_vallist(:,:) = spin_dmi_vallist(:,:) * eV_Ha
416 :
417 : call self%set_dmi(n=spin_dmi_nterm, ilist=spin_dmi_ilist, &
418 : & jlist=spin_dmi_jlist, Rlist=spin_dmi_Rlist, &
419 0 : & vallist=spin_dmi_vallist)
420 :
421 0 : ABI_SFREE(spin_dmi_ilist)
422 0 : ABI_SFREE(spin_dmi_jlist)
423 0 : ABI_SFREE(spin_dmi_Rlist)
424 0 : ABI_SFREE(spin_dmi_vallist)
425 : endif
426 :
427 : !== read SIA terms
428 2 : ierr=nf90_inq_dimid(ncid, "spin_SIA_nterm", spin_SIA_nterm)
429 2 : if (ierr==0) then ! if has SIA
430 0 : ierr=nctk_get_dim(ncid, "spin_SIA_nterm", spin_SIA_nterm)
431 0 : ABI_MALLOC(spin_SIA_ilist, (spin_SIA_nterm))
432 0 : ABI_MALLOC(spin_SIA_k1list, (spin_SIA_nterm))
433 0 : ABI_MALLOC(spin_SIA_k1dirlist, (3,spin_SIA_nterm))
434 :
435 0 : ierr =nf90_inq_varid(ncid, "spin_SIA_ilist", varid)
436 0 : NCF_CHECK_MSG(ierr, "spin_SIA_ilist")
437 0 : ierr = nf90_get_var(ncid, varid, spin_SIA_ilist)
438 0 : NCF_CHECK_MSG(ierr, "spin_SIA_ilist")
439 :
440 0 : ierr =nf90_inq_varid(ncid, "spin_SIA_k1list", varid)
441 0 : NCF_CHECK_MSG(ierr, "spin_SIA_k1list")
442 0 : ierr = nf90_get_var(ncid, varid, spin_SIA_k1list)
443 0 : NCF_CHECK_MSG(ierr, "spin_SIA_k1list")
444 :
445 :
446 0 : ierr =nf90_inq_varid(ncid, "spin_SIA_k1dirlist", varid)
447 0 : NCF_CHECK_MSG(ierr, "spin_SIA_k1dirlist")
448 0 : ierr = nf90_get_var(ncid, varid, spin_SIA_k1dirlist)
449 0 : NCF_CHECK_MSG(ierr, "spin_SIA_k1dirlist")
450 :
451 0 : spin_SIA_k1list(:) = spin_SIA_k1list(:) * eV_Ha
452 :
453 : call self%set_SIA(n=spin_SIA_nterm, ilist=spin_SIA_ilist, &
454 0 : & k1list=spin_SIA_k1list, k1dirlist=spin_SIA_k1dirlist)
455 :
456 0 : ABI_SFREE(spin_SIA_ilist)
457 0 : ABI_SFREE(spin_SIA_k1list)
458 0 : ABI_SFREE(spin_SIA_k1dirlist)
459 : endif
460 :
461 :
462 :
463 : ! read bilinear terms
464 2 : ierr=nf90_inq_dimid(ncid, "spin_bilinear_nterm", varid)
465 2 : if (ierr==0) then ! if has bilinear
466 0 : ABI_MALLOC(spin_bilinear_ilist, (spin_bilinear_nterm))
467 0 : ABI_MALLOC(spin_bilinear_jlist, (spin_bilinear_nterm))
468 0 : ABI_MALLOC(spin_bilinear_Rlist, (3,spin_bilinear_nterm))
469 0 : ABI_MALLOC(spin_bilinear_vallist, (3,3,spin_bilinear_nterm))
470 :
471 0 : ierr =nf90_inq_varid(ncid, "spin_bilinear_ilist", varid)
472 0 : NCF_CHECK_MSG(ierr, "spin_bilinear_ilist")
473 0 : ierr = nf90_get_var(ncid, varid, spin_bilinear_ilist)
474 0 : NCF_CHECK_MSG(ierr, "spin_bilinear_ilist")
475 :
476 0 : ierr =nf90_inq_varid(ncid, "spin_bilinear_jlist", varid)
477 0 : NCF_CHECK_MSG(ierr, "spin_bilinear_jlist")
478 0 : ierr = nf90_get_var(ncid, varid, spin_bilinear_jlist)
479 0 : NCF_CHECK_MSG(ierr, "spin_bilinear_jlist")
480 :
481 0 : ierr =nf90_inq_varid(ncid, "spin_bilinear_Rlist", varid)
482 0 : NCF_CHECK_MSG(ierr, "spin_bilinear_Rlist")
483 0 : ierr = nf90_get_var(ncid, varid, spin_bilinear_Rlist)
484 0 : NCF_CHECK_MSG(ierr, "spin_bilinear_Rlist")
485 :
486 0 : ierr =nf90_inq_varid(ncid, "spin_bilinear_vallist", varid)
487 0 : NCF_CHECK_MSG(ierr, "spin_bilinear_vallist")
488 0 : ierr = nf90_get_var(ncid, varid, spin_bilinear_vallist)
489 0 : NCF_CHECK_MSG(ierr, "spin_bilinear_vallist")
490 :
491 0 : spin_bilinear_vallist(:,:,:) = spin_bilinear_vallist(:,:,:) * eV_Ha
492 :
493 : call self%set_bilinear( n=spin_bilinear_nterm, ilist=spin_bilinear_ilist, &
494 : & jlist=spin_bilinear_jlist, Rlist=spin_bilinear_Rlist, &
495 0 : & vallist=spin_bilinear_vallist)
496 :
497 0 : ABI_SFREE(spin_bilinear_ilist)
498 0 : ABI_SFREE(spin_bilinear_jlist)
499 0 : ABI_SFREE(spin_bilinear_Rlist)
500 0 : ABI_SFREE(spin_bilinear_vallist)
501 : end if
502 :
503 2 : ierr=nf90_close(ncid)
504 2 : NCF_CHECK_MSG(ierr, "Close netcdf file")
505 : #else
506 : NETCDF_NOTENABLED_ERROR()
507 : #endif
508 2 : end subroutine read_netcdf
509 :
510 :
511 : !-------------------------------------------------------------------!
512 : ! set_bilinear_1term:
513 : ! Add a bilinear term
514 : ! Inputs:
515 : ! i: index of spin i
516 : ! j: index of spin j
517 : ! R: cell vector R (vector3)
518 : ! val : a 3*3 matrix.
519 : !-------------------------------------------------------------------!
520 52 : subroutine set_bilinear_1term(self, i, j, R, val)
521 : class(spin_primitive_potential_t), intent(inout) :: self
522 : integer, intent(in) :: i, j, R(3)
523 : real(dp), intent(in) :: val(3,3)
524 : real(dp) :: v
525 : integer :: indR, iv, jv
526 :
527 52 : if (xmpi_comm_rank(xmpi_world)==0) then
528 52 : call self%Rlist%push_unique(R, position=indR)
529 208 : do jv=1,3
530 676 : do iv=1,3
531 468 : v=val(iv,jv)
532 2028 : call self%coeff%add_entry(ind=[indR, (i-1)*3+iv, (j-1)*3+jv ], val=v)
533 : end do
534 : end do
535 : endif
536 52 : end subroutine set_bilinear_1term
537 :
538 : !-------------------------------------------------------------------!
539 : ! set_bilinear:
540 : !Inputs:
541 : ! n: number of terms
542 : ! ilist: list of i (length n)
543 : ! jlist: list of j (length n)
544 : ! Rlist: list of R mat(3, n)
545 : ! vallist: list of val . mat(3,3,n)
546 : !-------------------------------------------------------------------!
547 2 : subroutine set_bilinear(self, n, ilist, jlist, Rlist, vallist)
548 : class(spin_primitive_potential_t), intent(inout) :: self
549 : integer, intent(in) :: n, ilist(n), jlist(n), Rlist(3,n)
550 : real(dp), intent(in) :: vallist(3, 3,n)
551 : integer :: idx
552 2 : if (xmpi_comm_rank(xmpi_world)==0) then
553 54 : do idx = 1, n
554 54 : call self%set_bilinear_1term(ilist(idx), jlist(idx), Rlist(:,idx), vallist(:,:, idx))
555 : end do
556 : endif
557 2 : end subroutine set_bilinear
558 :
559 : !-------------------------------------------------------------------!
560 : ! set_exchange terms.
561 : ! same as set_bilinear, except the vallist only have the diagonal.
562 : !-------------------------------------------------------------------!
563 2 : subroutine set_exchange(self, n, ilist, jlist, Rlist, vallist)
564 : class(spin_primitive_potential_t), intent(inout) :: self
565 : integer, intent(in) :: n, ilist(:), jlist(:), Rlist(:,:)
566 : real(dp), intent(in) :: vallist(:,:)
567 : integer :: idx
568 4 : real(dp) :: bivallist(3,3, n)
569 :
570 2 : if (xmpi_comm_rank(xmpi_world)==0) then
571 678 : bivallist(:,:,:)=0.0d0
572 54 : do idx = 1, n, 1
573 52 : bivallist(1,1,idx)=vallist(1, idx)
574 52 : bivallist(2,2,idx)=vallist(2, idx)
575 54 : bivallist(3,3,idx)=vallist(3, idx)
576 : end do
577 2 : call self%set_bilinear(n,ilist,jlist,Rlist,bivallist)
578 : endif
579 2 : end subroutine set_exchange
580 :
581 :
582 : !-------------------------------------------------------------------!
583 : ! set the DMI term.
584 : ! here vallist is a list(n) of 3-vectors.
585 : !-------------------------------------------------------------------!
586 0 : subroutine set_dmi(self, n, ilist, jlist, Rlist, vallist)
587 : class(spin_primitive_potential_t), intent(inout) :: self
588 : integer, intent(in) :: n, ilist(:), jlist(:), Rlist(:,:)
589 : real(dp), intent(in) :: vallist(:,:)
590 : integer :: idx
591 0 : real(dp) :: bivallist(3,3, n), D(3)
592 :
593 0 : if (xmpi_comm_rank(xmpi_world)==0) then
594 0 : bivallist(:,:,:)=0.0d0
595 0 : do idx=1,n, 1
596 0 : D(:)=vallist(:, idx)
597 : ! 0 Dz -Dy
598 : ! -Dz 0 Dx
599 : ! Dy -Dx 0
600 : bivallist(:,:, idx)=reshape ( (/0.0d0, -D(3), D(2), &
601 : D(3), 0.0d0, -D(1), &
602 0 : -D(2), D(1), 0.0d0 /),(/3,3/) )
603 : end do
604 0 : call self%set_bilinear(n,ilist,jlist,Rlist,bivallist)
605 : endif
606 0 : end subroutine set_dmi
607 :
608 : !-------------------------------------------------------------------!
609 : ! set_sia:
610 : ! set a list of single ion anisotropy
611 : ! k1list: amplitudes mat(n)
612 : ! k1dirlist: directions mat(3, n)
613 : !-------------------------------------------------------------------!
614 0 : subroutine set_sia(self, n, ilist, k1list, k1dirlist)
615 :
616 : class(spin_primitive_potential_t), intent(inout) :: self
617 : integer, intent(in) :: n, ilist(:)
618 : real(dp), intent(in) :: k1list(:), k1dirlist(:, :)
619 0 : integer :: idx, Rlist(3, n)
620 0 : real(dp) :: bivallist(3,3, n)
621 0 : if (xmpi_comm_rank(xmpi_world)==0) then
622 0 : bivallist(:,:,:)=0.0d0
623 0 : Rlist(:, :)=0
624 0 : do idx=1,n, 1
625 : bivallist(:,:, idx)= (- k1list(idx))* &
626 0 : outer_product(k1dirlist(:,idx), k1dirlist(:, idx))
627 :
628 : end do
629 0 : call self%set_bilinear(n,ilist,ilist,Rlist,bivallist)
630 : endif
631 0 : end subroutine set_sia
632 :
633 : !-------------------------------------------------------------------!
634 : ! add a SIA for every spin, usually from a user input.
635 : ! input_sia_k1amp: amplitude of SIA, a scalar
636 : ! input_sia_k1dir: direction of SIA, a vector
637 : !-------------------------------------------------------------------!
638 :
639 0 : subroutine add_input_sia(self, input_sia_k1amp, input_sia_k1dir)
640 : class(spin_primitive_potential_t), intent(inout) :: self
641 : real(dp), intent(in):: input_sia_k1amp, input_sia_k1dir(3)
642 0 : integer :: in_sia_ind(self%nspin)
643 0 : real(dp):: in_sia_k1amp(self%nspin), in_sia_k1dir(3, self%nspin)
644 :
645 : integer :: i
646 :
647 0 : if (xmpi_comm_rank(xmpi_world)==0) then
648 0 : write(std_out,'(A28)') "Adding SIA terms from input"
649 0 : do i =1, self%nspin
650 0 : in_sia_ind(i)=i
651 0 : in_sia_k1amp(i)=input_sia_k1amp
652 0 : in_sia_k1dir(:,i)=input_sia_k1dir
653 : end do
654 0 : call self%set_sia(self%nspin, in_sia_ind, in_sia_k1amp, in_sia_k1dir )
655 : endif
656 0 : end subroutine add_input_sia
657 :
658 :
659 : !-------------------------------------------------------------------!
660 : ! Read potential from xml file
661 : ! Inputs:
662 : ! xml_fname: filename
663 : ! use_exchange: whether to read exchange term
664 : ! use_dmi: whether to read DMI term
665 : ! use_sia: whether to read SIA term
666 : ! use_bi: whether to read bilinear term (added on top of other terms.)
667 : !-------------------------------------------------------------------!
668 0 : subroutine read_xml(self, xml_fname, use_exchange, use_dmi, use_sia, use_bi)
669 : class(spin_primitive_potential_t), intent(inout) :: self
670 : character(kind=C_CHAR) :: xml_fname(*)
671 : integer :: natoms, nspin, exc_nnz, dmi_nnz, uni_nnz, bi_nnz
672 : logical, optional, intent(in) :: use_exchange, use_dmi, use_sia, use_bi
673 : logical :: uexc, udmi, usia, ubi
674 : real(dp) :: ref_energy
675 :
676 : type(c_ptr) :: p_unitcell, &
677 : p_masses, p_index_spin, p_gyroratios, p_damping_factors, p_positions, p_spinat, &
678 : p_exc_ilist, p_exc_jlist, p_exc_Rlist, p_exc_vallist, &
679 : p_dmi_ilist, p_dmi_jlist, p_dmi_Rlist, p_dmi_vallist, &
680 : p_uni_ilist, p_uni_amplitude_list, p_uni_direction_list, &
681 : p_bi_ilist, p_bi_jlist, p_bi_Rlist, p_bi_vallist
682 :
683 : real(dp), target :: dummy_real(1)
684 : integer(c_int),target :: dummy_int(1)
685 :
686 : integer(c_int),pointer :: index_spin(:)=>null() ,&
687 : exc_ilist(:)=>null(), exc_jlist(:)=>null(), exc_Rlist(:)=>null(), &
688 : dmi_ilist(:)=>null(), dmi_jlist(:)=>null(), dmi_Rlist(:)=>null(), &
689 : bi_ilist(:)=>null(), bi_jlist(:)=>null(), bi_Rlist(:)=>null(), &
690 : uni_ilist(:)=>null()
691 :
692 : real(c_double), pointer:: unitcell(:)=>null(), masses(:)=>null(), &
693 : gyroratios(:)=>null(), damping_factors(:)=>null(), &
694 : positions(:)=>null(), spinat(:)=>null(), &
695 : exc_vallist(:)=>null(), dmi_vallist(:)=>null(), &
696 : uni_amplitude_list(:)=>null(), uni_direction_list(:)=>null(), &
697 : bi_vallist(:)=>null()
698 :
699 :
700 : real(dp) :: uc(3,3)
701 :
702 : integer :: master, my_rank, comm, nproc
703 : logical :: iam_master
704 0 : call init_mpi_info(master, iam_master, my_rank, comm, nproc)
705 :
706 : ! associate the fortran pointers with the dummy variables
707 0 : if(.not. iam_master) then
708 0 : index_spin=>dummy_int
709 0 : exc_ilist=>dummy_int
710 0 : exc_jlist=>dummy_int
711 0 : exc_Rlist=>dummy_int
712 0 : exc_vallist=>dummy_real
713 0 : dmi_ilist=>dummy_int
714 0 : dmi_jlist=>dummy_int
715 0 : dmi_Rlist=>dummy_int
716 0 : dmi_vallist=>dummy_real
717 0 : uni_ilist=>dummy_int
718 0 : uni_amplitude_list=>dummy_real
719 0 : uni_direction_list=>dummy_real
720 0 : bi_ilist=>dummy_int
721 0 : bi_jlist=>dummy_int
722 0 : bi_Rlist=>dummy_int
723 0 : bi_vallist=>dummy_real
724 0 : unitcell=>dummy_real
725 0 : masses=>dummy_real
726 0 : gyroratios=>dummy_real
727 0 : damping_factors=>dummy_real
728 0 : positions=>dummy_real
729 0 : spinat=>dummy_real
730 : endif
731 :
732 0 : if (iam_master) then
733 0 : write(std_out,'(A58)') "Reading parameters from xml file and setting up spin model"
734 0 : write(std_out,'(A80)') " "
735 : call xml_read_spin(xml_fname, ref_energy, p_unitcell, &
736 : natoms, p_masses, nspin, p_index_spin, p_gyroratios, p_damping_factors, p_positions, p_spinat, &
737 : exc_nnz, p_exc_ilist, p_exc_jlist, p_exc_Rlist, p_exc_vallist, &
738 : dmi_nnz, p_dmi_ilist, p_dmi_jlist, p_dmi_Rlist, p_dmi_vallist, &
739 : uni_nnz, p_uni_ilist, p_uni_amplitude_list, p_uni_direction_list, &
740 0 : bi_nnz, p_bi_ilist, p_bi_jlist, p_bi_Rlist, p_bi_vallist)
741 0 : call c_f_pointer(p_unitcell, unitcell, [9])
742 0 : call c_f_pointer(p_masses, masses, [natoms])
743 0 : call c_f_pointer(p_index_spin, index_spin, [natoms])
744 0 : call c_f_pointer(p_gyroratios, gyroratios, [nspin])
745 0 : call c_f_pointer(p_damping_factors, damping_factors, [nspin])
746 0 : call c_f_pointer(p_positions, positions, [natoms*3])
747 0 : call c_f_pointer(p_spinat, spinat, [natoms*3])
748 0 : call c_f_pointer(p_exc_ilist, exc_ilist, [exc_nnz])
749 0 : call c_f_pointer(p_exc_jlist, exc_jlist, [exc_nnz])
750 0 : call c_f_pointer(p_exc_Rlist, exc_Rlist, [exc_nnz*3])
751 0 : call c_f_pointer(p_exc_vallist, exc_vallist, [exc_nnz*3])
752 0 : call c_f_pointer(p_dmi_ilist, dmi_ilist, [dmi_nnz])
753 0 : call c_f_pointer(p_dmi_jlist, dmi_jlist, [dmi_nnz])
754 0 : call c_f_pointer(p_dmi_Rlist, dmi_Rlist, [dmi_nnz*3])
755 0 : call c_f_pointer(p_dmi_vallist, dmi_vallist, [dmi_nnz*3])
756 0 : call c_f_pointer(p_uni_ilist, uni_ilist, [uni_nnz])
757 0 : call c_f_pointer(p_uni_amplitude_list, uni_amplitude_list, [uni_nnz])
758 0 : call c_f_pointer(p_uni_direction_list, uni_direction_list, [uni_nnz*3])
759 0 : call c_f_pointer(p_bi_ilist, bi_ilist, [bi_nnz])
760 0 : call c_f_pointer(p_bi_jlist, bi_jlist, [bi_nnz])
761 0 : call c_f_pointer(p_bi_Rlist, bi_Rlist, [bi_nnz*3])
762 0 : call c_f_pointer(p_bi_vallist, bi_vallist, [bi_nnz*9])
763 :
764 : ! change of units to a.u.
765 :
766 : ! unitcell already Bohr
767 :
768 : !gyroratios already in a.u. (unit=1)
769 :
770 : ! masses already in a.u.
771 :
772 : ! J, DMI, k1, bi are in eV
773 0 : exc_vallist(:) =exc_vallist(:) * eV_Ha
774 0 : dmi_vallist(:) = dmi_vallist(:) * eV_Ha
775 0 : uni_amplitude_list(:) = uni_amplitude_list(:) * eV_Ha
776 0 : bi_vallist(:) = bi_vallist(:) * eV_Ha
777 :
778 0 : write(std_out,'(A80)') " "
779 0 : write(std_out,'(A21)') "Setting up spin model"
780 0 : write(std_out,'(A15)') "Setting system"
781 0 : uc(:,:)=transpose(reshape(unitcell, [3,3]))
782 : !call set_atoms(self,)
783 : endif
784 :
785 : ! (MPI) Only this runs on non-master node
786 : call self%set_spin_primcell(natoms, uc, positions, &
787 0 : nspin, index_spin, spinat, gyroratios, damping_factors )
788 :
789 0 : if (iam_master) then
790 0 : if(.not. present(use_exchange)) then
791 : uexc=.True.
792 : else
793 0 : uexc=use_exchange
794 : end if
795 :
796 0 : if(uexc .and. exc_nnz>0) then
797 0 : write(std_out,'(A23)') "Setting exchange terms"
798 : call self%set_exchange(exc_nnz,exc_ilist,exc_jlist,&
799 : reshape(exc_Rlist, (/3, exc_nnz /)), &
800 0 : reshape(exc_vallist, (/3, exc_nnz/)))
801 : else
802 0 : if (.not. uexc) write(std_out, '(A38)') " Exchange term from xml file not used."
803 : endif
804 :
805 0 : if(.not. present(use_dmi)) then
806 : udmi=.True.
807 : else
808 0 : udmi=use_dmi
809 : end if
810 0 : if (udmi .and. dmi_nnz>0) then
811 0 : write(std_out,'(A19)') "Setting DMI terms."
812 : call self%set_dmi( n=dmi_nnz, ilist=dmi_ilist, jlist=dmi_jlist, &
813 : Rlist=reshape(dmi_Rlist, (/3, dmi_nnz /)), &
814 0 : vallist = reshape(dmi_vallist, (/3, dmi_nnz/)))
815 : else
816 0 : if (.not. udmi) write(std_out, '(A35)') " DMI term from xml file not used."
817 : end if
818 :
819 0 : if(.not. present(use_sia)) then
820 : usia=.True.
821 : else
822 0 : usia=use_sia
823 : end if
824 0 : if (usia .and. uni_nnz>0) then
825 0 : write(std_out,'(A18)') "Setting SIA terms"
826 : call self%set_sia(uni_nnz, uni_ilist, uni_amplitude_list, &
827 0 : reshape(uni_direction_list, [3, uni_nnz]) )
828 : else
829 0 : if(.not. usia) write(std_out,'(A34)') " SIA term in xml file not used."
830 : end if
831 :
832 0 : if(.not. present(use_bi)) then
833 : ubi=.True.
834 : else
835 0 : ubi=use_bi
836 : endif
837 0 : if (ubi .and. bi_nnz>0) then
838 0 : write(std_out,'(A23)') "Setting bilinear terms."
839 : call self%set_bilinear(bi_nnz, bi_ilist, bi_jlist, &
840 : Rlist=reshape(bi_Rlist, (/3, bi_nnz /)), &
841 0 : vallist = reshape(bi_vallist, (/3,3, bi_nnz/)))
842 : else
843 0 : if(.not. ubi) write(std_out, '(A38)') " Bilinear term in xml file not used."
844 : endif
845 : endif
846 :
847 0 : if (iam_master) then
848 : call xml_free_spin(xml_fname, ref_energy, p_unitcell, &
849 : natoms, p_masses, nspin, p_index_spin, p_gyroratios, p_damping_factors, p_positions, p_spinat, &
850 : exc_nnz, p_exc_ilist, p_exc_jlist, p_exc_Rlist, p_exc_vallist, &
851 : dmi_nnz, p_dmi_ilist, p_dmi_jlist, p_dmi_Rlist, p_dmi_vallist, &
852 : uni_nnz, p_uni_ilist, p_uni_amplitude_list, p_uni_direction_list, &
853 0 : bi_nnz, p_bi_ilist, p_bi_jlist, p_bi_Rlist, p_bi_vallist)
854 : endif
855 :
856 0 : end subroutine read_xml
857 :
858 : !-------------------------------------------------------------------!
859 : ! fill_supercell:
860 : ! generate a supercell potential from primitive potential
861 : ! Input:
862 : ! scmaker: supercell maker helper class
863 : ! scpot: supercell potential (a pointer to a abstract potential)
864 : !-------------------------------------------------------------------!
865 2 : subroutine fill_supercell(self, scmaker, params, scpot, supercell)
866 : class(spin_primitive_potential_t) , intent(inout) :: self
867 : type(supercell_maker_t), intent(inout) :: scmaker
868 : type(multibinit_dtset_type), intent(inout) :: params
869 : class(abstract_potential_t), pointer, intent(inout) :: scpot
870 : type(mbsupercell_t), target :: supercell
871 :
872 : integer :: nspin, sc_nspin, i, R(3), ind_Rij(3), iR, ii, ij, inz
873 : integer :: master, my_rank, comm, nproc, ierr
874 2 : integer, allocatable :: i_sc(:), j_sc(:), Rj_sc(:, :)
875 : logical :: iam_master
876 4 : real(dp) :: val_sc(scmaker%ncells)
877 :
878 2 : ABI_UNUSED_A(params)
879 :
880 2 : call init_mpi_info(master, iam_master, my_rank, comm, nproc)
881 :
882 2 : nspin=self%nspin
883 2 : sc_nspin= nspin * scmaker%ncells
884 2 : call xmpi_bcast(sc_nspin, master, comm, ierr)
885 : !ABI_MALLOC_SCALAR(spin_potential_t::scpot)
886 2 : ABI_MALLOC_TYPE_SCALAR(spin_potential_t, scpot)
887 : select type(scpot) ! use select type because properties only defined for spin_potential is used.
888 : type is (spin_potential_t)
889 2 : call scpot%initialize(sc_nspin)
890 2 : call scpot%set_supercell(supercell)
891 4 : if (iam_master) then
892 2 : call self%coeff%sum_duplicates()
893 158 : do inz=1, self%coeff%nnz
894 156 : ind_Rij=self%coeff%get_ind_inz(inz)
895 156 : iR=ind_Rij(1)
896 156 : ii=ind_Rij(2)
897 156 : ij=ind_Rij(3)
898 624 : R=self%Rlist%data(:,iR)
899 156 : call scmaker%trans_i(nbasis=nspin*3, i=ii, i_sc=i_sc)
900 156 : call scmaker%trans_j_and_Rj(nbasis=nspin*3, j=ij, Rj=R, j_sc=j_sc, Rj_sc=Rj_sc)
901 33852 : val_sc(:)= self%coeff%val%data(inz)
902 33852 : do i=1, scmaker%ncells
903 33852 : call scpot%add_bilinear_term(i_sc(i), j_sc(i), val_sc(i))
904 : end do
905 156 : ABI_SFREE(i_sc)
906 156 : ABI_SFREE(j_sc)
907 158 : ABI_SFREE(Rj_sc)
908 : end do
909 : endif
910 : end select
911 2 : ABI_UNUSED_A(params)
912 4 : end subroutine fill_supercell
913 :
914 : !-------------------------------------------------------------------!
915 : ! check if a string1 ends with string2.
916 : ! used to check if file is .nc or .xml
917 : !-------------------------------------------------------------------!
918 4 : function endswith(string1, string2) result(answer)
919 : character(len=*), intent(in) :: string1
920 : character(len=*), intent(in) :: string2
921 : logical :: answer
922 4 : answer = .False.
923 4 : if(len(string2)>len(string1)) return
924 4 : if(string1(len(string1)-len(string2)+1:)==string2) answer = .True.
925 : end function endswith
926 :
927 :
928 8 : end module m_spin_primitive_potential
|