Branch data Line data Source code
1 : : !!****m* ABINIT/m_supercell
2 : : !! NAME
3 : : !! m_supercell
4 : : !!
5 : : !! FUNCTION
6 : : !! Module for using a supercell, in particular for phonon displacement freezing.
7 : : !! Container type is defined, and destruction, print subroutines as well as the central supercell_init
8 : : !!
9 : : !! COPYRIGHT
10 : : !! Copyright (C) 2010-2026 ABINIT group (MJV, DJA)
11 : : !! This file is distributed under the terms of the
12 : : !! GNU General Public Licence, see ~abinit/COPYING
13 : : !! or http://www.gnu.org/copyleft/gpl.txt .
14 : : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
15 : : !!
16 : : !! SOURCE
17 : :
18 : : #if defined HAVE_CONFIG_H
19 : : #include "config.h"
20 : : #endif
21 : :
22 : : #include "abi_common.h"
23 : :
24 : : module m_supercell
25 : :
26 : : use defs_basis
27 : : use m_errors
28 : : use m_abicore
29 : :
30 : : use m_matrix, only : matr3inv
31 : : use m_copy, only : alloc_copy
32 : : use m_io_tools, only : open_file
33 : : use m_fstrings, only : int2char4, write_num, itoa, sjoin
34 : : use m_numeric_tools, only : isdiagmat
35 : :
36 : : implicit none
37 : :
38 : : private
39 : :
40 : : !!***
41 : :
42 : : !!****t* m_supercell/supercell_type
43 : : !! NAME
44 : : !! supercell_type
45 : : !!
46 : : !! FUNCTION
47 : : !! structure for a supercell constructed from a basic rprimd and xcart, with indexing to original atoms
48 : : !! The supercell may not be oriented the same way as the original cell, if you can reduce it by symmetry
49 : : !!
50 : : !! SOURCE
51 : :
52 : : type, public :: supercell_type
53 : : integer :: natom_primcell
54 : : ! number of atoms in primitive cell
55 : : integer :: natom
56 : : ! number of atoms in supercell
57 : : integer :: ntypat
58 : : ! number of atom types
59 : : integer :: ncells
60 : : ! number of unit cells in supercell
61 : : integer :: rlatt(3,3)
62 : : ! matrix for multiplicity of supercell (for the time being must be diagonal)
63 : : real(dp) :: rprimd(3,3)
64 : : ! new lattice vectors for supercell
65 : : real(dp) :: qphon(3)
66 : : ! phonon q vector used to generate scell, if any
67 : : character(len=3) :: xyz_order
68 : : ! Order used to build the supercell.
69 : : real(dp), allocatable :: xcart(:,:)
70 : : ! (3, natom) Cartesian positions of atoms
71 : : real(dp), allocatable :: xcart_ref(:,:)
72 : : ! (3, natom) equilibrium Cartesian positions of atoms
73 : : integer, allocatable :: atom_indexing(:)
74 : : ! (natom) indexes original atom: 1..natom_primcell
75 : : integer, allocatable :: uc_indexing(:,:)
76 : : ! (3, natom) indexes unit cell atom is.
77 : : integer, allocatable :: typat(:)
78 : : ! (natom) type of each atom in the supercell.
79 : : real(dp), allocatable :: znucl(:)
80 : : ! (ntypat) nuclear charges of species
81 : : integer, allocatable :: rvecs(:,:)
82 : : ! supercell vectors
83 : :
84 : : contains
85 : : procedure :: init_for_qpt => supercell_init_for_qpt
86 : : procedure :: init => supercell_init
87 : : procedure :: freeze_displ => supercell_freeze_displ
88 : : procedure :: copy => supercell_copy
89 : : procedure :: free => supercell_free
90 : : procedure :: print_for_qpt => supercell_print_for_qpt
91 : : procedure :: print_abinit => supercell_print_abinit
92 : : procedure :: write_xsf => supercell_write_xsf
93 : : end type supercell_type
94 : :
95 : : public :: distance_supercell
96 : : public :: findBound_supercell
97 : : public :: getPBCIndexes_supercell
98 : : public :: mksupercell ! computes atomic positons, magnetic ordering of supercell
99 : : !!***
100 : :
101 : : CONTAINS !===========================================================================================
102 : :
103 : : !!****f* m_supercell/supercell_init_for_qpt
104 : : !!
105 : : !! NAME
106 : : !! supercell_init_for_qpt
107 : : !!
108 : : !! FUNCTION
109 : : !! Initialize scell structure, from unit cell vectors, and atoms, based on qpoint chosen
110 : : !!
111 : : !! INPUTS
112 : : !! natom_primcell = number of atoms in primitive cell
113 : : !! qphon(3) = phonon wavevector
114 : : !! find smallest supercell which will accomodate phonon qphon = (1/2,1/2,1/2)
115 : : !! rprimd_primcell(3,3) = real space lattice vectors (bohr)
116 : : !! typat_primcell = types of atoms
117 : : !! xcart_primcell(3,natom) = cartesian positions of atoms in primitive cell
118 : : !! znucl = nuclear charges for all species
119 : : !! ordering = if true, typat will be 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 ....
120 : : !! if false, typat will be 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 ....
121 : : !!
122 : : !! OUTPUT
123 : : !! scell = supercell structure to be initialized
124 : : !!
125 : : !! SOURCE
126 : :
127 : 6 : subroutine supercell_init_for_qpt(scell, natom_primcell, qphon, rprimd_primcell, &
128 [ - + + - ]: 6 : typat_primcell, xcart_primcell, znucl, ordering)
129 : :
130 : : !Arguments ------------------------------------
131 : : !scalars
132 : : class(supercell_type), intent(out) :: scell
133 : : integer, intent(in) :: natom_primcell
134 : : logical,optional,intent(in) :: ordering
135 : : !arrays
136 : : integer , intent(in) :: typat_primcell(natom_primcell)
137 : : real(dp), intent(in) :: qphon(3)
138 : : real(dp), intent(in) :: znucl(:)
139 : : real(dp), intent(in) :: rprimd_primcell(3,3)
140 : : real(dp), intent(in) :: xcart_primcell(3,natom_primcell)
141 : :
142 : : !Local variables-------------------------------
143 : : !scalar
144 : : integer :: ii, maxsc, iscmult
145 : : real(dp) :: qbymult
146 : : !arrays
147 : : integer :: rlatt(3,3) ! number of primitive cells in each direction for the supercell
148 : : character(len=500) :: msg
149 : : ! *************************************************************************
150 : :
151 : : ! maximum number of unit cells in a given direction
152 : 6 : maxsc = 10
153 : :
154 : : ! find smallest supercell which will accomodate phonon.
155 : : ! FIXME: for the moment, just get smallest multiple along each direction, with an upper bound
156 : 6 : rlatt = 0
157 : 6 : rlatt(1,1) = -1
158 : 6 : rlatt(2,2) = -1
159 : 6 : rlatt(3,3) = -1
160 [ + + ]: 24 : do ii=1,3
161 [ + - ]: 21 : do iscmult=1,maxsc
162 : 21 : qbymult = qphon(ii)*iscmult
163 [ + + ]: 21 : if (abs(qbymult - int(qbymult)) < tol10) then
164 : 18 : rlatt(ii,ii) = iscmult
165 : 18 : exit
166 : : end if
167 : : end do
168 [ - + ]: 24 : if (rlatt(ii,ii) == -1) then
169 : 0 : write(msg,'(a,I0,a,I0,2a,3E20.10)')' No supercell found with less than ', &
170 : 0 : maxsc,' unit cells in direction ', ii, ch10, ' qphon = ', qphon
171 : 0 : ABI_ERROR(msg)
172 : : end if
173 : : end do
174 : :
175 [ - + ]: 6 : if (present(ordering)) then
176 : 0 : call scell%init(natom_primcell, rlatt, rprimd_primcell, typat_primcell, xcart_primcell, znucl, ordering)
177 : : else
178 : 6 : call scell%init(natom_primcell, rlatt, rprimd_primcell, typat_primcell, xcart_primcell, znucl)
179 : : end if
180 : :
181 [ + + ]: 24 : scell%qphon = qphon
182 : :
183 : 6 : end subroutine supercell_init_for_qpt
184 : : !!***
185 : :
186 : : !!****f* m_supercell/supercell_init
187 : : !! NAME
188 : : !! supercell_init
189 : : !!
190 : : !! FUNCTION
191 : : !! Initialize scell structure, from unit cell vectors, and atoms, based on rlatt multiplicity matrix
192 : : !!
193 : : !! INPUTS
194 : : !! natom_primcell = number of atoms in primitive cell
195 : : !! rlatt(3,3) = multiplicity of primtive unit cells in supercell
196 : : !! rprimd_primcell(3,3) = real space lattice vectors (bohr)
197 : : !! typat_primcell(natom) = types of all atoms in primitive cell
198 : : !! xcart_primcell(3,natom) = cartesian positions of atoms in primitive cell
199 : : !! znucl = nuclear charges for all species
200 : : !! [ordering] = if true, typat will be 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 ....
201 : : !! if false, typat will be 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 ....
202 : : !! [xyz_order]= Order used to build the supercell.
203 : : !! "zyx" if one should move along z first.
204 : : !! "xyz" if one should move along x first. This value should be used for plotting purposes
205 : : !!
206 : : !! OUTPUT
207 : : !! scell = supercell structure to be initialized
208 : : !!
209 : : !! SOURCE
210 : :
211 [ - + + - ]: 212 : subroutine supercell_init(scell, natom_primcell, rlatt, rprimd_primcell, typat_primcell, xcart_primcell, znucl, &
212 : : ordering, xyz_order) ! optional
213 : :
214 : : !Arguments ------------------------------------
215 : : !scalars
216 : : class(supercell_type), intent(out) :: scell
217 : : integer, intent(in) :: natom_primcell
218 : : logical,optional,intent(in) :: ordering
219 : : character(len=*),optional,intent(in) :: xyz_order
220 : : !arrays
221 : : integer , intent(in) :: rlatt(3,3)
222 : : integer , intent(in) :: typat_primcell(natom_primcell)
223 : : real(dp), intent(in) :: znucl(:)
224 : : real(dp), intent(in) :: rprimd_primcell(3,3)
225 : : real(dp), intent(in) :: xcart_primcell(3,natom_primcell)
226 : :
227 : : !Local variables-------------------------------
228 : : !scalars
229 : : integer :: iatom_supercell, i1,i2,i3, iatom, icell
230 : : ! *************************************************************************
231 : :
232 [ - + ]: 212 : if (.not. isdiagmat(rlatt)) then
233 : 0 : ABI_ERROR('rlatt is not diagonal.')
234 : : end if
235 : :
236 [ + + ]: 212 : scell%xyz_order = "zyx"; if (present(xyz_order)) scell%xyz_order = xyz_order(1:3)
237 : :
238 : 212 : scell%natom_primcell = natom_primcell
239 [ + + + + ]: 2756 : scell%rlatt = rlatt
240 : 212 : scell%ncells = rlatt(1,1)*rlatt(2,2)*rlatt(3,3)
241 [ + + ]: 848 : scell%rprimd(:,1) = rprimd_primcell(:,1) * rlatt(1,1)
242 [ + + ]: 848 : scell%rprimd(:,2) = rprimd_primcell(:,2) * rlatt(2,2)
243 [ + + ]: 848 : scell%rprimd(:,3) = rprimd_primcell(:,3) * rlatt(3,3)
244 : :
245 : : !call metric(scell%gmet, scell%gprimd, -1, scell%rmet, scell%rprimd, scell%ucvol)
246 : :
247 : 212 : scell%ntypat = size(znucl)
248 [ - + + - : 636 : ABI_MALLOC(scell%znucl,(scell%ntypat))
+ - + - -
+ - + -
+ ]
249 [ + + ]: 751 : scell%znucl(:) = znucl(:)
250 : :
251 : : ! number of atoms in full supercell
252 : 212 : scell%natom= natom_primcell*scell%ncells
253 [ - + + - : 636 : ABI_MALLOC(scell%xcart,(3,scell%natom))
+ - + - -
+ - + -
+ ]
254 [ - + + - : 636 : ABI_MALLOC(scell%xcart_ref,(3,scell%natom))
+ - + - -
+ - + -
+ ]
255 [ - + + - : 636 : ABI_MALLOC(scell%typat,(scell%natom))
+ - + - -
+ - + -
+ ]
256 [ - + + - : 636 : ABI_MALLOC(scell%atom_indexing,(scell%natom))
+ - + - -
+ - + -
+ ]
257 [ - + + - : 636 : ABI_MALLOC(scell%uc_indexing,(3,scell%natom))
+ - + - -
+ - + -
+ ]
258 [ - + + - : 636 : ABI_MALLOC(scell%rvecs, (3, scell%ncells))
+ - + - -
+ - + -
+ ]
259 : :
260 : 212 : iatom_supercell = 0; icell =0
261 : :
262 : 199 : select case (scell%xyz_order)
263 : : case ("zyx")
264 : : ! legacy mode.
265 [ + + ]: 604 : do i1 = 1, rlatt(1,1)
266 [ + + ]: 1607 : do i2 = 1, rlatt(2,2)
267 [ + + ]: 3523 : do i3 = 1, rlatt(3,3)
268 : 3118 : call build_()
269 : : end do
270 : : end do
271 : : end do
272 : :
273 : : case ("xyz")
274 [ + + ]: 90 : do i3 = 1, rlatt(3,3)
275 [ + + ]: 749 : do i2 = 1, rlatt(2,2)
276 [ + + ]: 7965 : do i1 = 1, rlatt(1,1)
277 : 7888 : call build_()
278 : : end do
279 : : end do
280 : : end do
281 : :
282 : : case default
283 [ + + - ]: 212 : ABI_ERROR(sjoin("Invalid xyz_order", scell%xyz_order))
284 : : end select
285 : :
286 [ - + ]: 212 : ABI_CHECK_IEQ(iatom_supercell, scell%natom, "iatom_supercell /= scell%natom")
287 : :
288 [ + - + - : 107088 : scell%xcart = scell%xcart_ref
- + - - -
- - - + +
+ + ]
289 [ + + ]: 848 : scell%qphon = zero
290 : :
291 [ - + ]: 212 : if (present(ordering)) then
292 [ # # ]: 0 : if (ordering) call order_supercell_typat(scell)
293 : : end if
294 : :
295 : : contains
296 : 9344 : subroutine build_()
297 [ + + ]: 37376 : icell = icell+1; scell%rvecs(:,icell) = [i1-1, i2-1, i3-1]
298 [ + + ]: 36010 : do iatom = 1, natom_primcell
299 : 26666 : iatom_supercell = iatom_supercell + 1
300 [ + + ]: 106664 : scell%uc_indexing(:,iatom_supercell) = [i1-1, i2-1, i3-1]
301 : : scell%xcart_ref(:,iatom_supercell) = xcart_primcell(:,iatom) &
302 [ + + + + : 586652 : + matmul(rprimd_primcell,scell%uc_indexing(:,iatom_supercell))
+ + + + +
- + - +
+ ]
303 : 26666 : scell%atom_indexing(iatom_supercell) = iatom
304 : 36010 : scell%typat(iatom_supercell) = typat_primcell(iatom)
305 : : end do
306 : 9344 : end subroutine build_
307 : :
308 : : end subroutine supercell_init
309 : : !!***
310 : :
311 : : !!****f* m_supercell/order_supercell_typat
312 : : !!
313 : : !! NAME
314 : : !! order_supercell_typat
315 : : !!
316 : : !! FUNCTION
317 : : !! Re-order atoms in place for types
318 : : !!
319 : : !! INPUTS
320 : : !! scell = supercell structure with reference atomic positions etc...
321 : : !!
322 : : !! OUTPUT
323 : : !! scell = supercell structure: typat, xcart and so on will be updated
324 : : !!
325 : : !! SOURCE
326 : :
327 : 0 : subroutine order_supercell_typat(scell)
328 : :
329 : : !Arguments ------------------------------------
330 : : !scalars
331 : : class(supercell_type), intent(inout) :: scell
332 : :
333 : : !Local variables-------------------------------
334 : : integer :: itypat, iatom_supercell, iatom
335 : 0 : type(supercell_type) :: scell_tmp
336 : : ! *************************************************************************
337 : :
338 : 0 : call scell%copy(scell_tmp)
339 : :
340 : 0 : iatom_supercell = 0
341 [ # # ]: 0 : do itypat = 1, scell%ntypat
342 [ # # ]: 0 : do iatom = 1, scell%natom
343 [ # # ]: 0 : if (scell_tmp%typat(iatom) /= itypat) cycle
344 : 0 : iatom_supercell = iatom_supercell + 1
345 [ # # ]: 0 : scell%xcart(:,iatom_supercell) = scell_tmp%xcart(:,iatom)
346 [ # # ]: 0 : scell%xcart_ref(:,iatom_supercell) = scell_tmp%xcart_ref(:,iatom)
347 : 0 : scell%atom_indexing(iatom_supercell) = scell_tmp%atom_indexing(iatom)
348 [ # # ]: 0 : scell%uc_indexing(:,iatom_supercell) = scell_tmp%uc_indexing(:,iatom)
349 : 0 : scell%typat(iatom_supercell) = scell_tmp%typat(iatom)
350 : : end do
351 : : end do
352 : :
353 : 0 : call scell_tmp%free()
354 : :
355 [ # # # # : 0 : end subroutine order_supercell_typat
# # # # #
# # # #
# ]
356 : : !!***
357 : :
358 : :
359 : : !!****f* m_supercell/freeze_displ_supercell
360 : : !!
361 : : !! NAME
362 : : !! freeze_displ_supercell
363 : : !!
364 : : !! FUNCTION
365 : : !! Freeze a specific displacement phonon field into the supercell scell
366 : : !!
367 : : !! INPUTS
368 : : !! displ = phonon displacement vectors for this mode
369 : : !! freeze_displ = desired amplitude for phonon displacement along displ.
370 : : !! for thermal displacement use sqrt[ (1/2 + bose_einstein(freq,T)) / freq ]
371 : : !! scell = supercell structure with reference atomic positions etc...
372 : : !!
373 : : !! OUTPUT
374 : : !! scell = supercell structure: xcart will be updated with phonon displacement
375 : : !!
376 : : !! SOURCE
377 : :
378 : 1446 : subroutine supercell_freeze_displ(scell, displ, freeze_displ)
379 : :
380 : : !Arguments ------------------------------------
381 : : !scalars
382 : : class(supercell_type), intent(inout) :: scell
383 : : real(dp), intent(in) :: freeze_displ
384 : : !arrays
385 : : real(dp), intent(in) :: displ(2,3*scell%natom_primcell)
386 : :
387 : : !Local variables-------------------------------
388 : : integer :: iatom, ipratom
389 : : complex(dp) :: expqdotr, j=cmplx(zero,one)
390 : : complex(dp) :: phase
391 : 2892 : complex(dp) :: zdispl(3,scell%natom_primcell)
392 : : ! *************************************************************************
393 : :
394 : : zdispl = (cmplx(reshape(displ(1,:), (/3,scell%natom_primcell/)),&
395 [ + + + + : 41358 : reshape(displ(2,:), (/3,scell%natom_primcell/))))
+ - + + +
+ ]
396 : :
397 : : ! fix gauge by imposing real displacement for first atom in first direction
398 : : ! multiply by normalized complex conjugate of first element
399 : : ! NB 6 March 2018: this may be imposing a positive (not just real) displacement for 1st atom along x!!!
400 : : ! That might be problematic below, though for the thermal displacement method freeze_displ swaps sign for each new mode
401 : 1446 : phase = cmplx(one,zero)
402 [ + + ]: 1446 : if (abs(zdispl(1,1)) > tol10) then
403 : 697 : phase = conjg(zdispl(1,1)) / abs(zdispl(1,1))
404 : : end if
405 : :
406 [ + + ]: 69234 : do iatom = 1, scell%natom
407 : : expqdotr = exp(j*two_pi*(scell%qphon(1)*scell%uc_indexing(1,iatom) &
408 : : +scell%qphon(2)*scell%uc_indexing(2,iatom) &
409 : 67788 : +scell%qphon(3)*scell%uc_indexing(3,iatom)))
410 : :
411 : : ! this is offset in zdispl vector due to primitive cell atom position
412 : 67788 : ipratom = scell%atom_indexing(iatom)
413 : :
414 : : !add real part of displacement times Bloch phase
415 : : scell%xcart(:,iatom) = scell%xcart(:,iatom) &
416 [ + + ]: 272598 : & + freeze_displ * real(expqdotr * zdispl(:,ipratom) * phase)
417 : :
418 : : ! scell%xcart(:,iatom) = scell%xcart(:,iatom) &
419 : : !& + freeze_displ * cos(qdotr) * displ(1,ipratom+1:ipratom+3) &
420 : : !& - freeze_displ * sin(qdotr) * displ(2,ipratom+1:ipratom+3)
421 : : end do
422 : :
423 : 1446 : end subroutine supercell_freeze_displ
424 : : !!***
425 : :
426 : : !****f* m_supercell/supercell_print_for_qpt
427 : : !!
428 : : !! NAME
429 : : !! supercell_print_for_qpt
430 : : !!
431 : : !! FUNCTION
432 : : !! output atomic positions, supercell vectors, etc... to a file. single qpoint and mode.
433 : : !!
434 : : !! INPUTS
435 : : !! freq = phonon frequency for mode jmode
436 : : !! jmode = mode which has been frozen into xcart contained in scell
437 : : !! outfile_radix = radix of file name to be written to
438 : : !!
439 : : !! OUTPUT
440 : : !! printing to file
441 : : !!
442 : : !! SOURCE
443 : :
444 : 36 : subroutine supercell_print_for_qpt(scell, freq, jmode, outfile_radix)
445 : :
446 : : !Arguments ------------------------------------
447 : : !scalars
448 : : class(supercell_type), intent(in) :: scell
449 : : real(dp), intent(in) :: freq
450 : : integer, intent(in) :: jmode
451 : : character(len=*), intent(in) :: outfile_radix
452 : :
453 : : !Local variables-------------------------------
454 : : !scalar
455 : : character(len=fnlen) :: filename
456 : : character(len=10) :: jmodestring
457 : : character(len=80) :: title1, title2
458 : : character(len=5) :: qphonstring1, qphonstring2, qphonstring3
459 : : ! *************************************************************************
460 : :
461 : : ! add suffix with mode and qpoint
462 : 36 : call int2char4(jmode, jmodestring)
463 [ - + ]: 36 : ABI_CHECK((jmodestring(1:1)/='#'),'Bug: string length too short!')
464 : :
465 : : ! qphonstring should be like 0.000_0.000_0.000
466 : 36 : call write_num(scell%qphon(1),qphonstring1,'(F5.3)')
467 : 36 : call write_num(scell%qphon(2),qphonstring2,'(F5.3)')
468 : 36 : call write_num(scell%qphon(3),qphonstring3,'(F5.3)')
469 : : filename = trim(outfile_radix) // "_qpt_" // qphonstring1 // "_" // qphonstring2 // &
470 [ + - ]: 36 : "_" // qphonstring3 // "_mode_" // trim(jmodestring)
471 : :
472 : 36 : write (title1, '(a,3E20.10)') '# phonon q point : ', scell%qphon
473 : 36 : write (title2, '(a,I7,a,E20.10)') '# phonon mode number : ', jmode, ' frequency ', freq
474 : :
475 : 36 : call scell%print_abinit(filename, title1, title2)
476 : :
477 : 36 : end subroutine supercell_print_for_qpt
478 : : !!***
479 : :
480 : : !****f* m_supercell/supercell_print_abinit
481 : : !! NAME
482 : : !! supercell_print_abinit
483 : : !!
484 : : !! FUNCTION
485 : : !! output atomic positions, supercell vectors, etc... to a file
486 : : !! in Abinit input format.
487 : : !!
488 : : !! INPUTS
489 : : !! filename = filename
490 : : !! title1 = first line of description of contents
491 : : !! title2 = second line of description of contents
492 : : !! scell = supercell structure with data to be output
493 : : !!
494 : : !! OUTPUT
495 : : !! printing to file
496 : : !!
497 : : !! SOURCE
498 : :
499 : 46 : subroutine supercell_print_abinit(scell, filename, title1, title2)
500 : :
501 : : !Arguments ------------------------------------
502 : : !scalars
503 : : class(supercell_type), intent(in) :: scell
504 : : character(len=fnlen), intent(in) :: filename
505 : : character(len=80), intent(in) :: title1
506 : : character(len=80), intent(in) :: title2
507 : :
508 : : !Local variables-------------------------------
509 : : !scalar
510 : : integer :: scunit, iatom
511 : : character(len=500) :: msg
512 : : real(dp) :: xred(3), gprimd(3,3)
513 : : ! *************************************************************************
514 : :
515 [ - + ]: 46 : if (open_file(filename, msg, newunit=scunit, status="unknown", action="write") /= 0) then
516 : 0 : ABI_ERROR(msg)
517 : : end if
518 : :
519 : : ! print header
520 : 46 : write (scunit, '(a)') '#'
521 : 46 : write (scunit, '(a)') '# anaddb file with frozen phonon mode in supercell'
522 : 46 : write (scunit, '(a)') '# !!! Do not forget to adjust nband !!! '
523 : 46 : write (scunit, '(a)') '#'
524 : 46 : write (scunit, '(a)') title1
525 : 46 : write (scunit, '(a)') title2
526 : 46 : write (scunit, '(a,3(3I7,2x))') '# supercell rlatt is ', scell%rlatt
527 : 46 : write (scunit, '(a,I7,a)') '# and has ', scell%ncells, ' primitive unit cells '
528 : 46 : write (scunit, '(a)') '#'
529 : 46 : write (scunit, '(a)') '# lattice vectors for supercell :'
530 : 46 : write (scunit, '(a,I7)') 'natom ', scell%natom
531 : 46 : write (scunit, *)
532 : 46 : write (scunit, '(a)') 'znucl '
533 [ + + ]: 114 : do iatom = 1, size(scell%znucl)
534 : 68 : write (scunit, '(I5)', ADVANCE="NO") int(scell%znucl(iatom))
535 [ - + ]: 114 : if (mod(iatom,6) == 0) write (scunit, *)
536 : : end do
537 : 46 : write (scunit, *)
538 : 46 : write (scunit, *)
539 : 46 : write (scunit, '(a,I7)') 'ntypat', scell%ntypat
540 : 46 : write (scunit, '(a)') 'typat '
541 [ + + ]: 634 : do iatom = 1, scell%natom
542 : 588 : write (scunit, '(I5)', ADVANCE="NO") scell%typat(iatom)
543 [ + + ]: 634 : if (mod(iatom,6) == 0) write (scunit, *)
544 : : end do
545 : 46 : write (scunit, *)
546 : 46 : write (scunit, '(a)') 'acell 1.0 1.0 1.0'
547 : 46 : write (scunit, '(a)') 'rprim'
548 : 46 : write (scunit, '(3E20.10)') scell%rprimd(:,1)
549 : 46 : write (scunit, '(3E20.10)') scell%rprimd(:,2)
550 : 46 : write (scunit, '(3E20.10)') scell%rprimd(:,3)
551 : 46 : write (scunit, *)
552 : 46 : write (scunit, '(a)') 'xcart'
553 [ + + ]: 634 : do iatom = 1, scell%natom
554 : 634 : write (scunit, '(3E20.10)') scell%xcart(:,iatom)
555 : : end do
556 : : ! for information, also print xred for atoms inside full supercell
557 : 46 : call matr3inv(scell%rprimd, gprimd)
558 : : ! TODO: check this transpose is correct in some asymetric case
559 [ + + + + : 1196 : gprimd = transpose(gprimd)
+ + + + ]
560 : 46 : write (scunit, '(a)') '# for information, add xred as well'
561 : 46 : write (scunit, '(a)') '# xred'
562 [ + + ]: 634 : do iatom = 1, scell%natom
563 [ + + + + : 7644 : xred = matmul (gprimd, scell%xcart(:,iatom))
+ - ]
564 : 634 : write (scunit, '(a, 3E20.10)') '# ', xred
565 : : end do
566 : :
567 : : ! close file
568 : 46 : close(scunit)
569 : :
570 : 46 : end subroutine supercell_print_abinit
571 : : !!***
572 : :
573 : : !****f* m_supercell/supercell_copy
574 : : !!
575 : : !! NAME
576 : : !! supercell_copy
577 : : !!
578 : : !! FUNCTION
579 : : !! copy supercell structure
580 : : !!
581 : : !! INPUTS
582 : : !! scell_in = supercell structure with data to copy
583 : : !!
584 : : !! OUTPUT
585 : : !! scell = supercell structure with data to be output
586 : : !!
587 : : !! SOURCE
588 : :
589 : 105 : subroutine supercell_copy(scell_in, scell_copy)
590 : :
591 : : !Arguments ------------------------------------
592 : : class(supercell_type), intent(in) :: scell_in
593 : : class(supercell_type), intent(inout) :: scell_copy
594 : : ! *************************************************************************
595 : :
596 : 105 : call scell_copy%free()
597 : :
598 : 105 : scell_copy%natom_primcell = scell_in%natom_primcell
599 : 105 : scell_copy%natom = scell_in%natom
600 : 105 : scell_copy%ntypat = scell_in%ntypat
601 : 105 : scell_copy%ncells = scell_in%ncells
602 [ + + + + ]: 1365 : scell_copy%rlatt = scell_in%rlatt
603 [ + + + + ]: 1365 : scell_copy%rprimd = scell_in%rprimd
604 [ + + ]: 420 : scell_copy%qphon = scell_in%qphon
605 [ - + ]: 105 : call alloc_copy(scell_in%xcart , scell_copy%xcart)
606 [ - + ]: 105 : call alloc_copy(scell_in%xcart_ref , scell_copy%xcart_ref)
607 [ - + ]: 105 : call alloc_copy(scell_in%atom_indexing, scell_copy%atom_indexing)
608 [ - + ]: 105 : call alloc_copy(scell_in%uc_indexing , scell_copy%uc_indexing)
609 [ - + ]: 105 : call alloc_copy(scell_in%typat , scell_copy%typat)
610 [ - + ]: 105 : call alloc_copy(scell_in%znucl , scell_copy%znucl)
611 : :
612 : 105 : end subroutine supercell_copy
613 : : !!***
614 : :
615 : : !!****f* m_effective_potential/getPBCIndexes_supercell
616 : : !! NAME
617 : : !!
618 : : !! FUNCTION
619 : : !! Get the index of the cell by using PBC
620 : : !!
621 : : !! INPUTS
622 : : !! index = index of the cell into the supercell
623 : : !! ncell = number of total cell
624 : : !!
625 : : !! OUTPUT
626 : : !! index = index of the cell into the supercell with PBC
627 : : !!
628 : : !! SOURCE
629 : :
630 : 4411437984 : subroutine getPBCIndexes_supercell(index,ncell)
631 : :
632 : : !Arguments ---------------------------------------------
633 : : integer, intent(inout) :: index(3)
634 : : integer, intent(in) :: ncell(3)
635 : :
636 : : !Local variables ---------------------------------------
637 : : integer :: ii
638 : : ! *********************************************************************
639 : :
640 [ + + ]: 17645751936 : do ii=1,3
641 [ + + ]: 13848999534 : do while (index(ii) > ncell(ii))
642 : 13848999534 : index(ii) = index(ii) - ncell(ii)
643 : : end do
644 [ + + ]: 18203804122 : do while (index(ii) <= 0)
645 : 558052186 : index(ii) = index(ii) + ncell(ii)
646 : : end do
647 : : end do
648 : :
649 : 4411437984 : end subroutine getPBCIndexes_supercell
650 : : !!***
651 : :
652 : : !****f* m_supercell/findBound_supercell
653 : : !! NAME
654 : : !! findBound_supercell
655 : : !!
656 : : !! FUNCTION
657 : : !! compute the bound of the supercell by considering the 0 0 0 (reference)
658 : : !! in the center of the supercell.
659 : : !! for example: (4 4 4) => min = -1 and max = 2
660 : : !!
661 : : !! INPUTS
662 : : !! ncell(3) = size of the supercell (for example 3 3 3)
663 : : !!
664 : : !! OUTPUT
665 : : !! min = minimun of the range
666 : : !! max = maximum of the range
667 : : !!
668 : : !! SOURCE
669 : :
670 : 204 : subroutine findBound_supercell(min, max, ncell)
671 : :
672 : : !Arguments ---------------------------------------------
673 : : integer, intent(inout) :: min,max
674 : : integer, intent(in) :: ncell
675 : :
676 : : ! *********************************************************************
677 [ - + ]: 204 : if(abs(max)>abs(min)) then
678 [ # # ]: 0 : max=(ncell)/2; min=-max; if(mod(ncell,2)==0) max = max -1
679 : : else
680 [ + + ]: 204 : min=-(ncell)/2; max=-min; if(mod(ncell,2)==0) min= min +1
681 : : end if
682 : :
683 : 204 : end subroutine findBound_supercell
684 : : !!***
685 : :
686 : : !!****f* m_supercell/distance_supercell
687 : : !! NAME
688 : : !!
689 : : !! FUNCTION
690 : : !! compute the distance_supercell betwen 2 atoms in different cell
691 : : !!
692 : : !! INPUTS
693 : : !! xcart1(3) = cartesian coordinates of the first atom
694 : : !! xcart1(3) = cartesian coordinates of the second atom
695 : : !! rprimd(3,3) = primitive lattice vectors
696 : : !! cell1(3) = index of the cell of the first atom (for example -1 0 2)
697 : : !! cell2(3) = index of the cell of the second atom (for example 0 0 2)
698 : : !!
699 : : !! OUTPUT
700 : : !! distance_supercell = distance_supercell between the 2 atoms
701 : : !!
702 : : !! SOURCE
703 : : !!
704 : :
705 : 0 : pure real(dp) function distance_supercell(xcart1,xcart2,rprimd,cell1,cell2) result(dist)
706 : :
707 : : !Arguments ------------------------------------
708 : : real(dp),intent(in):: rprimd(3,3)
709 : : real(dp),intent(in):: xcart1(3),xcart2(3)
710 : : integer,intent(in) :: cell1(3),cell2(3)
711 : :
712 : : !Local variables -------------------------------
713 : : real(dp) :: rpt1(3),rpt2(3)
714 : : integer :: mu
715 : : ! *************************************************************************
716 : :
717 [ # # ]: 0 : do mu=1,3
718 : 0 : rpt1(mu) = cell1(1)*rprimd(mu,1)+cell1(2)*rprimd(mu,2)+cell1(3)*rprimd(mu,3)
719 : 0 : rpt2(mu) = cell2(1)*rprimd(mu,1)+cell2(2)*rprimd(mu,2)+cell2(3)*rprimd(mu,3)
720 : : end do
721 : :
722 : : dist = ((xcart2(1)+rpt2(1)-xcart1(1)-rpt1(1))**2+&
723 : : (xcart2(2)+rpt2(2)-xcart1(2)-rpt1(2))**2+&
724 : 0 : (xcart2(3)+rpt2(3)-xcart1(3)-rpt1(3))**2)**0.5
725 : :
726 : 0 : end function distance_supercell
727 : : !!***
728 : :
729 : : !****f* m_supercell/supercell_free
730 : : !!
731 : : !! NAME
732 : : !! supercell_free
733 : : !!
734 : : !! FUNCTION
735 : : !! deallocate all dynamic memory for this supercell structure
736 : : !!
737 : : !! SOURCE
738 : :
739 : 889 : subroutine supercell_free(scell)
740 : :
741 : : !Arguments ------------------------------------
742 : : class(supercell_type), intent(inout) :: scell
743 : : ! *************************************************************************
744 : :
745 [ + + ]: 889 : ABI_SFREE(scell%xcart)
746 [ + + ]: 889 : ABI_SFREE(scell%xcart_ref)
747 [ + + ]: 889 : ABI_SFREE(scell%typat)
748 [ + + ]: 889 : ABI_SFREE(scell%atom_indexing)
749 [ + + ]: 889 : ABI_SFREE(scell%uc_indexing)
750 [ + + ]: 889 : ABI_SFREE(scell%znucl)
751 [ + + ]: 889 : ABI_SFREE(scell%rvecs)
752 : :
753 : 889 : end subroutine supercell_free
754 : : !!***
755 : :
756 : : !!****f* m_supercell/mksupercell
757 : : !! NAME
758 : : !! mksupercell
759 : : !!
760 : : !! FUNCTION
761 : : !! computes atomic positons, magnetic ordering of supercell
762 : : !!
763 : : !! INPUTS
764 : : !! magv_org (optional) magnetic ordering of atoms in primitive cell,
765 : : !! ordering of atoms given als 1 and -1, if not given fm is assumed
766 : : !! xred_org relative position of atoms in primitive cell
767 : : !! rprimd_org unit cell dimensions of primitive cell
768 : : !! natom=number of atoms in unit cell
769 : : !! option= 1 output ion-ion distances / 2 output ordering of ion-ion distances / 3 output variables in varlist
770 : : !! according to ion-ion distances * magnetic ordering
771 : : !!
772 : : !! OUTPUT
773 : : !! magv_sc magnetic ordering of atoms in supercell
774 : : !! xred_sc relative position of atoms in supercell
775 : : !! rprimd_sc unit cell dimensions of supercell
776 : : !!
777 : : !! SOURCE
778 : :
779 : 45 : subroutine mksupercell(xred_org,magv_org,rprimd_org,nat_org,nat_sc,xred_sc,magv_sc,rprimd_sc,ext,prtvol)
780 : :
781 : : !Arguments ------------------------------------
782 : : !scalars
783 : : integer,intent(in) :: nat_org,nat_sc
784 : : integer,intent(in),optional :: prtvol
785 : : !arrays
786 : : real(dp),intent(in) :: rprimd_org(3,3)
787 : : integer,intent(in) :: ext(3)
788 : : real(dp),intent(in) :: xred_org(3,nat_org)
789 : : real(dp),intent(out) :: xred_sc(3,nat_sc)
790 : : real(dp),intent(out) :: magv_sc(nat_sc)
791 : : real(dp),intent(out) :: rprimd_sc(3,3)
792 : : integer,intent(in),optional :: magv_org(nat_org)
793 : :
794 : : !Local variables-------------------------------
795 : : !scalars
796 : : integer :: prtvoll,ix,iy,iz,nprcl,iprcl,jdim,iatom
797 : : !arrays
798 : 90 : real(dp) :: magvv_org(nat_org)
799 : 45 : real(dp),allocatable :: transv(:,:,:)
800 : : ! *************************************************************************
801 : :
802 [ + - ]: 45 : if (present(magv_org)) then
803 [ + + ]: 110 : magvv_org=magv_org
804 : : else
805 [ # # # # : 0 : magvv_org=(/ (1, iatom=1,nat_org) /)
# # ]
806 : : end if
807 : :
808 : : if (present(prtvol)) then
809 : : prtvoll=prtvol
810 : : else
811 : : prtvoll=1
812 : : end if
813 : :
814 [ + + + + : 990 : rprimd_sc=reshape((/ (rprimd_org(ix,:)*ext(ix) ,ix=1,3) /),(/3,3 /))
+ + ]
815 [ + + ]: 180 : nprcl=product(ext)
816 [ - + + - : 180 : ABI_MALLOC(transv,(3,nat_org,nprcl))
- + + - +
- + - - +
- + ]
817 : :
818 [ + + + + : 64355 : transv=reshape((/ (((((/ ix,iy,iz /),iatom=1,nat_org),ix=0,ext(1)-1),iy=0,ext(2)-1),iz=0,ext(3)-1) /), (/ 3, nat_org,nprcl/) )
+ + + - +
+ + - + +
+ + + - +
+ + + + +
+ - + - +
- - + - -
+ + + + +
+ ]
819 : :
820 : : !write(std_out,*)'mksupercell: xred_org ' ,xred_org
821 [ + + ]: 3365 : do iprcl=1,nprcl
822 [ + + + + ]: 21080 : xred_sc(:,1+(iprcl-1)*nat_org:iprcl*nat_org)=xred_org+transv(:,:,iprcl)
823 [ + + ]: 7805 : magv_sc(1+(iprcl-1)*nat_org:iprcl*nat_org)=magv_org
824 : : end do
825 : :
826 [ + + ]: 180 : do jdim=1,3
827 [ + + ]: 13500 : xred_sc(jdim,:)=xred_sc(jdim,:)/ext(jdim)
828 : : end do
829 : :
830 : : !write(std_out,*)'mksupercell: xred_sc ', xred_sc
831 : : !write(std_out,*)'mksupercell: magv_sc ', magv_sc
832 : :
833 [ - + ]: 45 : ABI_FREE(transv)
834 : :
835 [ + - ]: 45 : end subroutine mksupercell
836 : : !!***
837 : :
838 : : !****f* m_supercell/supercell_write_xsf
839 : : !! NAME
840 : : !! supercell_write_xsf
841 : : !!
842 : : !! FUNCTION
843 : : !! output atomic positions, supercell vectors, etc... to xsf_filenamt
844 : : !!
845 : : !! INPUTS
846 : : !! xsf_filename = filename
847 : : !!
848 : : !! OUTPUT
849 : : !! printing to file
850 : : !!
851 : : !! SOURCE
852 : :
853 : 4 : subroutine supercell_write_xsf(scell, xsf_filename)
854 : :
855 : : !Arguments ------------------------------------
856 : : !scalars
857 : : class(supercell_type), intent(in) :: scell
858 : : character(len=*), intent(in) :: xsf_filename
859 : :
860 : : !Local variables-------------------------------
861 : : integer :: ount, ix, iy, iatom
862 : : character(len=500) :: msg
863 : : ! *************************************************************************
864 : :
865 [ - + ]: 4 : if (open_file(xsf_filename, msg, newunit=ount, status="unknown", action="write") /= 0) then
866 : 0 : ABI_ERROR(msg)
867 : : end if
868 : :
869 : : ! Note: Don't put comments because Vesta on my Mac does not like them!
870 : : !write (ount, '(a)')"#", trim(title)
871 : : !write (ount, '(a,3(3I7,2x))') '# supercell rlatt is ', scell%rlatt
872 : : !write (ount, '(a,I0,a)') '# and has ', scell%ncells, ' primitive unit cells '
873 : : !write (ount, '(a)') '#'
874 : :
875 : 4 : write(ount,'(1X,A)') 'DIM-GROUP'
876 : 4 : write(ount,*) '3 1'
877 : 4 : write(ount,'(1X,A)') 'PRIMVEC'
878 : : !write(ount, "(a)")"# these are primitive lattice vectors (in Angstroms)"
879 [ + + ]: 16 : do iy = 1,3
880 [ + - + + ]: 52 : write(ount, '(3(ES17.10,2X))') (Bohr_Ang * scell%rprimd(ix,iy), ix=1,3)
881 : : end do
882 : 4 : write(ount, "(1X, a)")"PRIMCOORD"
883 : 4 : write(ount, "(i0,1x,i0)") scell%natom, 1 ! # The second number is always 1 for PRIMCOORD coordinates.
884 : :
885 [ + + ]: 4560 : do iatom=1,scell%natom
886 : : write(ount, '(i9, 6(3X,ES17.10))') &
887 : 4556 : NINT(scell%znucl(scell%typat(iatom))), & ! WARNING alchemy not supported by XCrysden
888 [ + + + + ]: 36452 : scell%xcart_ref(:,iatom) * Bohr_Ang, (scell%xcart(:,iatom) - scell%xcart_ref(:,iatom)) * Bohr_Ang
889 : : end do
890 : :
891 : 4 : close(ount)
892 : :
893 : 4 : end subroutine supercell_write_xsf
894 : : !!***
895 : :
896 [ - + - - : 27320 : end module m_supercell
+ + - + +
- - + - +
+ - - + -
+ - + - +
- + ]
897 : : !!***
|