Branch data Line data Source code
1 : : !!****m* ABINIT/m_tdep_sampling
2 : : !! NAME
3 : : !! m_tdep_sampling
4 : : !!
5 : : !! FUNCTION
6 : : !! This module contains the TDEP Sampling data type
7 : : !! which holds the set of configurations from which the IFC will be fit.
8 : : !!
9 : : !! COPYRIGHT
10 : : !! Copyright (C) 2011-2026 ABINIT group (GA,FB,JB)
11 : : !! This file is distributed under the terms of the
12 : : !! GNU General Public License, see ~abinit/COPYING
13 : : !! or http://www.gnu.org/copyleft/gpl.txt .
14 : : !!
15 : : !! SOURCE
16 : :
17 : : #if defined HAVE_CONFIG_H
18 : : #include "config.h"
19 : : #endif
20 : :
21 : : #include "abi_common.h"
22 : :
23 : : module m_tdep_sampling
24 : :
25 : : use defs_basis
26 : : use m_errors
27 : : use m_abicore
28 : : use m_xmpi
29 : : use m_io_tools
30 : : use m_abihist, only : abihist
31 : : use m_matrix, only : matr3inv
32 : : use m_tdep_dataset, only : atdep_dataset_type, MPI_enreg_type
33 : : use m_tdep_latt, only : Lattice_type, tdep_make_inbox
34 : : use m_tdep_supercell, only : tdep_Supercell_type
35 : :
36 : : implicit none
37 : : !!***
38 : :
39 : : !----------------------------------------------------------------------
40 : :
41 : : !!****t* m_tdep_sampling/tdep_Sampling_type
42 : : !! NAME
43 : : !! tdep_Sampling_type
44 : : !!
45 : : !! FUNCTION
46 : : !! Holds the set of configurations (positions, forces, energies and weights)
47 : : !! sampled along the MD trajectory, from which the IFC are fitted,
48 : : !! together with the derived displacements.
49 : : !!
50 : : !! SOURCE
51 : :
52 : : type tdep_Sampling_type
53 : :
54 : : integer :: natom
55 : : ! Number of atoms in the supercell
56 : :
57 : : integer :: natom_unitcell
58 : : ! Number of atoms in the unitcell
59 : :
60 : : integer :: my_nstep
61 : : ! Number of MD steps held locally
62 : :
63 : : integer :: nstep_tot
64 : : ! Total of MD steps
65 : :
66 : : integer, allocatable :: typat_unitcell(:)
67 : : ! typat_unitcell(natom_unitcell)
68 : : ! Atom type in the unitcell.
69 : :
70 : : integer, allocatable :: typat(:)
71 : : ! typat(natom)
72 : : ! Atom type in the supercell.
73 : :
74 : : !integer, allocatable :: iat_unitcell(:)
75 : : ! iat_unitcell(natom)
76 : : ! Atom index in the unitcell
77 : :
78 : : !integer, allocatable :: icell_supercell(:)
79 : : ! icell_supercell(natom)
80 : : ! Index of the supercell lattice vector.
81 : :
82 : : !integer, allocatable :: iat_supercell(:) ! GA: Not necessary
83 : : ! iat_supercell(natom)
84 : : ! Ordering of the atoms in the supercell (different from input ordering)
85 : :
86 : : double precision :: rprimd(3,3)
87 : : ! Primitve vectors of the supercell, in which xred is expressed.
88 : :
89 : : double precision, allocatable :: xred(:,:,:)
90 : : ! xred(3, natom, my_nstep)
91 : : ! Reduced position of the atom at each step,
92 : :
93 : : double precision, allocatable :: xred_average(:,:)
94 : : ! xred_average(3, natom)
95 : : ! Average position of the atoms
96 : :
97 : : double precision, allocatable :: fcart(:,:,:)
98 : : ! fcart(3, natom, my_nstep)
99 : : ! Cartesian forces at each step.
100 : :
101 : : double precision, allocatable :: etot(:)
102 : : ! etot(my_nstep)
103 : : ! Total energy at each step.
104 : :
105 : : double precision, allocatable :: weights(:)
106 : : ! weights(my_nstep)
107 : : ! The weight of each configuration for the fitting.
108 : : ! By default, these will be 1 / nstep_tot.
109 : :
110 : : double precision, allocatable :: Rlatt_cart(:,:,:)
111 : : ! Rlatt_cart(3, natom_unitcell, natom)
112 : : ! Cartesian lattice vector between a unitcell reference atom
113 : : ! and the ideal site of each atom.
114 : :
115 : : double precision, allocatable :: Rlatt_scaled(:,:,:)
116 : : ! Rlatt_scaled(3, natom_unitcell, natom)
117 : : ! Rlatt_cart divided by acell_unitcell.
118 : : ! May be non-integer for non-orthogonal lattice vectors.
119 : :
120 : : double precision, allocatable :: ucart(:,:,:)
121 : : ! ucart(3, natom, my_nstep)
122 : : ! Cartesian displacements of the atoms with respect to their equilibrium
123 : : ! positions (or mean displacement) at each time step.
124 : :
125 : : double precision, allocatable :: ucart0(:,:)
126 : : ! ucart0(3, natom)
127 : : ! Mean Cartesian displacements of the atoms with respect to their equilibrium position.
128 : :
129 : : double precision, allocatable :: Forces(:)
130 : : ! Forces(3*natom*my_nstep)
131 : : ! The cartesian forces for all configurations, as a flat array.
132 : :
133 : : contains
134 : :
135 : : procedure :: init => tdep_sampling_init_read
136 : : procedure :: free => tdep_sampling_free
137 : : procedure :: get_flat_index => tdep_sampling_get_flat_index
138 : : procedure :: shift_xred => tdep_sampling_shift_xred
139 : : procedure :: reorder => tdep_sampling_reorder
140 : : procedure :: rotate => tdep_sampling_rotate
141 : : procedure :: gather_inbox => tdep_sampling_gather_inbox
142 : :
143 : : end type tdep_Sampling_type
144 : : !!***
145 : :
146 : : public :: tdep_match_supercell
147 : : public :: tdep_match_unitcell
148 : : public :: tdep_write_xred_average_ideal
149 : : public :: tdep_write_ucart_fcart
150 : : public :: tdep_write_distance_rlatt
151 : :
152 : : contains
153 : :
154 : : !=====================================================================================================
155 : :
156 : : !!****f* ABINIT/m_tdep_sampling/tdep_sampling_init_read
157 : : !! NAME
158 : : !! tdep_sampling_init_read
159 : : !!
160 : : !! FUNCTION
161 : : !! Initialize the TDEP Sampling object: allocate its arrays, then read the
162 : : !! reduced positions, cartesian forces and total energies of the MD
163 : : !! trajectory, either from the HIST.nc netcdf file or from the _xred.dat,
164 : : !! _fcart.dat and _etot.dat ASCII files. Only the steps between
165 : : !! Invar%nstep_min and Invar%nstep_max (every Invar%slice steps) that
166 : : !! belong to the present MPI process are stored.
167 : : !! The weights of the configurations are either read from the _weights.dat
168 : : !! file (Invar%use_weights=1) or set to 1/nstep_tot.
169 : : !! Finally, a global shift is applied to the reduced positions so that the
170 : : !! first atom of the unitcell (Invar%xred_unitcell) is anchored at the origin.
171 : : !!
172 : : !! INPUTS
173 : : !! Invar = Input object containing the input variables.
174 : : !! MPIdata = Info on MPI parallelism.
175 : : !! Hist = abihist object containing the MD trajectory
176 : : !! (only used if Invar%netcdf is true).
177 : : !!
178 : : !! OUTPUT
179 : : !!
180 : : !! SIDE EFFECTS
181 : : !! MD = TDEP Sampling object. On exit, its arrays are allocated and
182 : : !! MD%typat, MD%typat_unitcell, MD%xred, MD%fcart, MD%etot and
183 : : !! MD%weights are filled.
184 : : !!
185 : : !! SOURCE
186 : :
187 : 46 : subroutine tdep_sampling_init_read(MD,Invar,MPIdata,Hist)
188 : :
189 : : class(tdep_Sampling_type), intent(inout) :: MD
190 : : type(atdep_dataset_type), intent(in) :: Invar
191 : : type(MPI_enreg_type), intent(in) :: MPIdata
192 : : type(abihist), intent(in) :: Hist
193 : :
194 : : integer :: this_istep,istep,iatom,jstep
195 : : double precision :: tmp1,tmp2,tmp3
196 : : real(dp) :: multiplicity(3,3), multiplicity_invT(3,3)
197 : : real(dp) :: shift_unit(3), shift_scaled(3)
198 : :
199 : : ! FIXME Check that the number of step requested is not larger than available steps.
200 : :
201 : 46 : MD%natom = Invar%natom
202 : 46 : MD%natom_unitcell = Invar%natom_unitcell
203 : 46 : MD%my_nstep = Invar%my_nstep
204 : 46 : MD%nstep_tot = Invar%nstep_tot
205 : :
206 [ - + + - : 248 : ABI_CALLOC(MD%typat_unitcell, (MD%natom_unitcell))
+ - + - -
+ - + - +
+ + ]
207 [ - + + - : 7416 : ABI_CALLOC(MD%typat, (MD%natom))
+ - + - -
+ - + - +
+ + ]
208 [ - + + - : 589464 : ABI_CALLOC(MD%xred, (3,MD%natom,MD%my_nstep))
- + + - +
- + - - +
- + - + +
+ + + +
+ ]
209 [ - + + - : 138 : ABI_MALLOC(MD%xred_average, (3,MD%natom))
+ - + - -
+ - + -
+ ]
210 [ - + + - : 589418 : ABI_CALLOC(MD%fcart, (3,MD%natom,MD%my_nstep))
- + + - -
+ - + - +
+ + + + +
+ ]
211 [ - + + - : 1130 : ABI_CALLOC(MD%etot, (MD%my_nstep))
+ - + - -
+ - + - +
+ + ]
212 [ - + + - : 1084 : ABI_CALLOC(MD%weights, (MD%my_nstep))
- + - + -
+ + + ]
213 [ - + + - : 70174 : ABI_CALLOC(MD%Rlatt_scaled, (3,MD%natom_unitcell,MD%natom))
- + + - +
- + - - +
- + - + +
+ + + +
+ ]
214 [ - + + - : 70128 : ABI_CALLOC(MD%Rlatt_cart, (3,MD%natom_unitcell,MD%natom))
- + + - -
+ - + - +
+ + + + +
+ ]
215 [ - + + - : 589418 : ABI_CALLOC(MD%ucart, (3,MD%natom,MD%my_nstep))
- + + - -
+ - + - +
+ + + + +
+ ]
216 [ - + + - : 29204 : ABI_CALLOC(MD%ucart0, (3,MD%natom))
- + - + -
+ + + +
+ ]
217 [ + - - + : 441354 : ABI_CALLOC(MD%Forces, (3*MD%natom*MD%my_nstep))
+ - + - +
- - + - +
- + + + ]
218 : :
219 : : !ABI_CALLOC(MD%iat_unitcell, (MD%natom))
220 : : !ABI_CALLOC(MD%icell_supercell, (MD%natom))
221 : :
222 [ + + ]: 156 : MD%typat_unitcell(:) = Invar%typat_unitcell(:)
223 [ + + ]: 7324 : MD%typat(:) = Invar%typat(:)
224 : :
225 : : ! Read xred.dat, fcart.dat and etot.dat ASCII files or extract them from the HIST.nc netcdf file.
226 : 46 : write(ab_out,'(a)') ' '
227 : 46 : this_istep=0
228 : 46 : jstep=0
229 [ + + ]: 46 : if (Invar%use_weights.eq.1) then
230 : 1 : open(unit=30,file=trim(Invar%input_prefix)//'_weights.dat')
231 [ + - ]: 45 : else if (Invar%use_weights.eq.0) then
232 [ + + ]: 1017 : MD%weights=1.0d0/real(MD%nstep_tot)
233 : : endif
234 [ + + ]: 46 : if (Invar%netcdf) then
235 [ + + ]: 238 : do istep=Invar%nstep_min,Invar%nstep_max
236 [ + + ]: 238 : if (mod(istep-Invar%nstep_min,Invar%slice).ne.0) then
237 : : cycle
238 : : else
239 : 221 : jstep=jstep+1
240 [ - + ]: 221 : if (.not.MPIdata%my_step(jstep)) cycle
241 : 221 : this_istep=this_istep+1
242 [ + + + + ]: 79741 : MD%xred(:,:,this_istep) =Hist%xred (:,:,istep)
243 [ + + + + ]: 79741 : MD%fcart(:,:,this_istep)=Hist%fcart(:,:,istep)
244 : 231 : MD%etot(this_istep) =Hist%etot (istep)
245 : : end if
246 : : end do !istep
247 : 7 : write(ab_out,'(a)') ' The positions, forces and energies are extracted from the NetCDF file: HIST.nc'
248 : : else
249 : 39 : open(unit=60,file=trim(Invar%input_prefix)//'_fcart.dat')
250 : 39 : open(unit=50,file=trim(Invar%input_prefix)//'_xred.dat')
251 : 39 : open(unit=40,file=trim(Invar%input_prefix)//'_etot.dat')
252 [ - + ]: 39 : do istep=1,Invar%nstep_min-1
253 [ # # ]: 0 : if (Invar%use_weights.eq.1) then
254 : 0 : read(30,*) tmp1
255 : : endif
256 : 0 : read(40,*) tmp1
257 [ - - ]: 39 : do iatom=1,MD%natom
258 : 0 : read(50,*) tmp1,tmp2,tmp3
259 : 0 : read(60,*) tmp1,tmp2,tmp3
260 : : end do
261 : : end do
262 [ + + ]: 820 : do istep=Invar%nstep_min,Invar%nstep_max
263 [ + + ]: 820 : if (mod(istep-Invar%nstep_min,Invar%slice).ne.0) then
264 [ - + ]: 10 : if (Invar%use_weights.eq.1) then
265 : 0 : read(30,*) tmp1
266 : : endif
267 : 10 : read(40,*) tmp1
268 [ + + ]: 1290 : do iatom=1,Invar%natom
269 : 1280 : read(50,*) tmp1,tmp2,tmp3
270 : 1290 : read(60,*) tmp1,tmp2,tmp3
271 : : end do
272 : : else
273 : 771 : jstep=jstep+1
274 [ - + ]: 771 : if (.not.MPIdata%my_step(jstep)) then
275 [ # # ]: 0 : if (Invar%use_weights.eq.1) then
276 : 0 : read(30,*) tmp1
277 : : endif
278 : 0 : read(40,*) tmp1
279 [ # # ]: 0 : do iatom=1,Invar%natom
280 : 0 : read(50,*) tmp1,tmp2,tmp3
281 : 0 : read(60,*) tmp1,tmp2,tmp3
282 : : end do
283 : : else
284 : 771 : this_istep=this_istep+1
285 [ + + ]: 771 : if (Invar%use_weights.eq.1) then
286 : 20 : read(30,*) MD%weights(this_istep)
287 : : endif
288 : 771 : read(40,*) MD%etot(this_istep)
289 [ + + ]: 127963 : do iatom=1,MD%natom
290 : 127192 : read(50,*) MD%xred (1,iatom,this_istep),MD%xred (2,iatom,this_istep),MD%xred (3,iatom,this_istep)
291 : 127963 : read(60,*) MD%fcart(1,iatom,this_istep),MD%fcart(2,iatom,this_istep),MD%fcart(3,iatom,this_istep)
292 : : end do
293 : : end if !my_step
294 : : end if !slice
295 : : end do !istep
296 : 39 : close(40)
297 : 39 : close(50)
298 : 39 : close(60)
299 : 39 : write(ab_out,'(2a)') ' The positions, forces and energies are extracted from the ASCII files:',&
300 : 78 : & ' xred.dat, fcart.dat & etot.dat'
301 : : end if !netcdf
302 [ + + ]: 46 : if (Invar%use_weights.eq.1) then
303 : 1 : close(30)
304 : : end if
305 : :
306 : : ! Apply xred_unitcell shift to anchor atom 1 at the origin.
307 [ + + + + ]: 598 : multiplicity(:,:) = real(NINT(Invar%multiplicity(:,:)), kind=dp)
308 : 46 : call matr3inv(multiplicity, multiplicity_invT)
309 [ + + ]: 184 : shift_unit(:) = Invar%xred_unitcell(:,1) - Invar%xred_unitcell_original(:,1)
310 [ + + + + ]: 598 : shift_scaled = matmul(multiplicity_invT, shift_unit)
311 [ + + ]: 1038 : do istep=1,MD%my_nstep
312 [ + + ]: 148110 : do iatom=1,MD%natom
313 [ + + ]: 589280 : MD%xred(:,iatom,istep) = MD%xred(:,iatom,istep) + shift_scaled(:)
314 : : end do
315 : : end do
316 : :
317 : 46 : end subroutine tdep_sampling_init_read
318 : : !!***
319 : :
320 : : !=====================================================================================================
321 : :
322 : : !!****f* ABINIT/m_tdep_sampling/tdep_sampling_free
323 : : !! NAME
324 : : !! tdep_sampling_free
325 : : !!
326 : : !! FUNCTION
327 : : !! Free the memory allocated in the TDEP Sampling object.
328 : : !!
329 : : !! SIDE EFFECTS
330 : : !! MD = TDEP Sampling object. All its allocated arrays are deallocated.
331 : : !!
332 : : !! SOURCE
333 : :
334 : 46 : subroutine tdep_sampling_free(MD)
335 : :
336 : : class(tdep_Sampling_type), intent(inout) :: MD
337 : :
338 [ - + ]: 46 : ABI_FREE(MD%typat)
339 [ - + ]: 46 : ABI_FREE(MD%typat_unitcell)
340 [ - + ]: 46 : ABI_FREE(MD%fcart)
341 [ - + ]: 46 : ABI_FREE(MD%etot)
342 [ - + ]: 46 : ABI_FREE(MD%weights)
343 [ - + ]: 46 : ABI_FREE(MD%Rlatt_scaled)
344 [ - + ]: 46 : ABI_FREE(MD%Rlatt_cart)
345 [ - + ]: 46 : ABI_FREE(MD%ucart)
346 [ - + ]: 46 : ABI_FREE(MD%ucart0)
347 [ - + ]: 46 : ABI_FREE(MD%Forces)
348 : :
349 [ - + ]: 46 : ABI_SFREE(MD%xred)
350 [ + - ]: 46 : ABI_SFREE(MD%xred_average)
351 : :
352 : 46 : end subroutine tdep_sampling_free
353 : : !!***
354 : :
355 : : !=====================================================================================================
356 : :
357 : : !!****f* ABINIT/m_tdep_sampling/tdep_sampling_get_flat_index
358 : : !! NAME
359 : : !! tdep_sampling_get_flat_index
360 : : !!
361 : : !! FUNCTION
362 : : !! Return the index, in the flat arrays of dimension 3*natom*my_nstep
363 : : !! (such as MD%Forces), corresponding to a given cartesian direction,
364 : : !! atom and (local) MD step.
365 : : !!
366 : : !! INPUTS
367 : : !! MD = TDEP Sampling object.
368 : : !! icart = Cartesian direction (1 to 3).
369 : : !! iatom = Atom index (1 to natom).
370 : : !! istep = Local MD step index (1 to my_nstep).
371 : : !!
372 : : !! OUTPUT
373 : : !! ii = Flat index: icart + 3*(iatom-1) + 3*natom*(istep-1).
374 : : !!
375 : : !! SOURCE
376 : :
377 : 916992 : function tdep_sampling_get_flat_index(MD,icart,iatom,istep) result(ii)
378 : : class(tdep_Sampling_type), intent(in) :: MD
379 : : integer, intent(in) :: icart, iatom, istep
380 : : integer :: ii
381 : 916992 : ii = icart + 3*(iatom-1) + 3*MD%natom*(istep-1)
382 : 475776 : end function tdep_sampling_get_flat_index
383 : : !!***
384 : :
385 : : !=====================================================================================================
386 : :
387 : : !!****f* ABINIT/m_tdep_sampling/tdep_sampling_shift_xred
388 : : !! NAME
389 : : !! tdep_sampling_shift_xred
390 : : !!
391 : : !! FUNCTION
392 : : !! Apply a constant shift to all reduced positions (MD%xred, and
393 : : !! MD%xred_average if allocated), at every MD step.
394 : : !!
395 : : !! INPUTS
396 : : !! shift(3) = Shift to apply, in reduced coordinates of the supercell.
397 : : !!
398 : : !! OUTPUT
399 : : !!
400 : : !! SIDE EFFECTS
401 : : !! MD = TDEP Sampling object. MD%xred and MD%xred_average are shifted.
402 : : !!
403 : : !! SOURCE
404 : :
405 : 46 : subroutine tdep_sampling_shift_xred(MD,shift)
406 : :
407 : : class(tdep_Sampling_type), intent(inout) :: MD
408 : : real(dp), intent(in) :: shift(3)
409 : : integer :: iatom,istep
410 : :
411 [ + + ]: 1038 : do istep=1, MD%my_nstep
412 [ + + ]: 148110 : do iatom=1,MD%natom
413 [ + + ]: 589280 : MD%xred(:,iatom,istep) = MD%xred(:,iatom,istep) + shift(:)
414 : : end do
415 : : end do
416 : :
417 [ + - ]: 46 : if (allocated(MD%xred_average)) then
418 [ + + ]: 7324 : do iatom=1,MD%natom
419 [ + + ]: 29158 : MD%xred_average(:,iatom) = MD%xred_average(:,iatom) + shift(:)
420 : : end do
421 : : end if
422 : :
423 : : ! Ideal positions are a property of SC (computed on the fly from it), not of MD, so nothing else to update here.
424 : :
425 : 46 : end subroutine tdep_sampling_shift_xred
426 : : !!***
427 : :
428 : : !=====================================================================================================
429 : :
430 : : !!****f* ABINIT/m_tdep_sampling/tdep_match_unitcell
431 : : !! NAME
432 : : !! tdep_match_unitcell
433 : : !!
434 : : !! FUNCTION
435 : : !! Find and apply a global shift to all xred so that the unitcell is
436 : : !! found within the set of xred_average.
437 : : !!
438 : : !! Every raw atom is tested against every unitcell site that shares its type.
439 : : !! Testing every atom against every type-matching site guarantees the correct
440 : : !! cluster wins outright: every atom contributes exactly one vote for the true
441 : : !! global shift (via its own true site), so that cluster totals natom
442 : : !! votes, strictly more than any single wrong (site,tested-site) mismatch
443 : : !! can gather (each such mismatch only ever collects votes from the one
444 : : !! subset of atoms that are truly the mismatched site).
445 : : !!
446 : : !! The clustering itself is done in UNITCELL-fractional coordinates, not
447 : : !! MD%xred_average's own (supercell-fractional) ones: a unitcell site
448 : : !! repeats once per PRIMITIVE cell, i.e. many times per supercell, and two
449 : : !! raw atoms that are both (a periodic copy of) the same unitcell site
450 : : !! generally differ by a fraction of a supercell period, not by a whole
451 : : !! one -- only in unitcell-fractional coordinates does "belongs to the
452 : : !! same unitcell site" reduce to a plain equality modulo 1.
453 : : !!
454 : : !! INPUTS
455 : : !! SC = Supercell object describing the ideal structure
456 : : !! (SC%xred_unitcell is used).
457 : : !!
458 : : !! OUTPUT
459 : : !!
460 : : !! SIDE EFFECTS
461 : : !! MD = TDEP Sampling object. On entry, MD%xred_average must already be
462 : : !! computed. On exit, MD%xred and MD%xred_average are shifted
463 : : !! (see tdep_sampling_shift_xred).
464 : : !!
465 : : !! SOURCE
466 : :
467 : 46 : subroutine tdep_match_unitcell(MD, SC)
468 : :
469 : : type(tdep_Sampling_type), intent(inout) :: MD
470 : : type(tdep_Supercell_type), intent(in) :: SC
471 : :
472 : : integer :: iatcell, jatcell, islot, iatom, icluster, ibest, ncluster, iatom_ref, islot_ref, navg
473 : : integer :: nclustermax
474 : : real(dp) :: tol, mindist, dnorm
475 : : real(dp) :: shift(3), tmp(3), diff(3), xred_unit(3), shift_ref(3), shift_sum(3)
476 : 46 : real(dp), allocatable :: cluster_shift(:,:)
477 : 46 : integer, allocatable :: cluster_count(:)
478 : 46 : integer, allocatable :: cluster_atom(:), cluster_slot(:)
479 : :
480 : : ! Clustering tolerance: half the smallest distance (unitcell-fractional,
481 : : ! minimum-image) separating any two distinct unitcell sites that share the
482 : : ! SAME type. This guarantees two genuinely distinct (and confusable, i.e.
483 : : ! same-type) unitcell sites are never merged into the same shift cluster,
484 : : ! while remaining generous relative to thermal noise on xred_average.
485 : : ! Sites of different types are never compared against each other in the
486 : : ! clustering loop below (the type check there rules that out), so they
487 : : ! must not constrain the tolerance either -- e.g. two unitcell sites of
488 : : ! different species placed at the very same reduced position (a legitimate
489 : : ! input) would otherwise force mindist, and hence tol, to zero.
490 : 46 : mindist = greatest_real
491 [ + + ]: 156 : do iatcell=1,MD%natom_unitcell
492 [ + + ]: 362 : do jatcell=iatcell+1,MD%natom_unitcell
493 [ + + ]: 206 : if (MD%typat_unitcell(jatcell) /= MD%typat_unitcell(iatcell)) cycle
494 [ + + ]: 744 : tmp = SC%xred_unitcell(:,jatcell) - SC%xred_unitcell(:,iatcell)
495 : 186 : call tdep_make_inbox(tmp,1,tol8)
496 [ + + ]: 874 : mindist = min(mindist, sqrt(sum(tmp**2)))
497 : : end do
498 : : end do
499 : : ! No two unitcell sites share a type (most common case, e.g. natom_unitcell==1):
500 : : ! there is nothing a candidate shift could be confused with, so a generous
501 : : ! tolerance is safe -- it only needs to comfortably exceed thermal noise.
502 [ + + ]: 46 : if (mindist == greatest_real) mindist = 0.8
503 : 46 : tol = half * mindist
504 : :
505 : : ! Cluster the candidate global shifts (in unitcell-fractional coordinates)
506 : : ! implied by every (raw atom, type-matching unitcell site) pairing:
507 : : ! shift_candidate(iatom,islot) = xred_unitcell(islot) - scaled_to_unit(xred_average(iatom)),
508 : : ! wrapped to the minimum image.
509 : 46 : nclustermax = MD%natom_unitcell*MD%natom_unitcell
510 [ - + + - : 138 : ABI_MALLOC(cluster_shift,(3,nclustermax))
+ - + - -
+ - + ]
511 [ - + + - : 138 : ABI_MALLOC(cluster_count,(nclustermax))
+ - + - -
+ - + ]
512 [ - + + - : 92 : ABI_MALLOC(cluster_atom,(nclustermax))
- + - + ]
513 [ - + + - : 92 : ABI_MALLOC(cluster_slot,(nclustermax))
- + - + ]
514 : 46 : ncluster = 0
515 : :
516 [ + + ]: 7324 : do iatom=1,MD%natom
517 : 7278 : xred_unit = SC%scaled_to_unit(MD%xred_average(:,iatom))
518 : :
519 [ + + ]: 23002 : do islot=1,MD%natom_unitcell
520 [ + + ]: 15678 : if (MD%typat(iatom) /= MD%typat_unitcell(islot)) cycle
521 : :
522 [ + + ]: 54072 : tmp = SC%xred_unitcell(:,islot) - xred_unit
523 : 13518 : call tdep_make_inbox(tmp,1,tol8)
524 : :
525 : 13518 : ibest = 0
526 [ + + ]: 49563 : do icluster=1,ncluster
527 : : ! Two independently-wrapped values sitting on
528 : : ! opposite sides of the [-0.5,0.5) boundary (e.g. +0.499 and -0.499)
529 : : ! represent the same cluster, so the DIFFERENCE must be re-wrapped
530 : : ! before measuring its norm.
531 [ + + ]: 197584 : diff = tmp-cluster_shift(:,icluster)
532 : 49396 : call tdep_make_inbox(diff,1,tol8)
533 [ + + ]: 197584 : dnorm = sqrt(sum(diff**2))
534 [ + + ]: 49563 : if (dnorm < tol) then
535 : : ibest = icluster
536 : : exit
537 : : end if
538 : : end do
539 : :
540 [ + + ]: 20796 : if (ibest > 0) then
541 : 13351 : cluster_count(ibest) = cluster_count(ibest) + 1
542 : : else
543 : 167 : ncluster = ncluster + 1
544 [ - + ]: 167 : if (ncluster > nclustermax) then
545 : 0 : ABI_ERROR('Found more distinct (unitcell site, global shift) combinations than expected.')
546 : : end if
547 [ + + ]: 668 : cluster_shift(:,ncluster) = tmp
548 : 167 : cluster_atom(ncluster) = iatom
549 : 167 : cluster_slot(ncluster) = islot
550 : 167 : cluster_count(ncluster) = 1
551 : : end if
552 : : end do
553 : : end do
554 : :
555 [ - + ]: 46 : if (ncluster == 0) then
556 : 0 : ABI_ERROR('Could not find any atom matching any of the unitcell atom types.')
557 : : end if
558 : :
559 [ - + + + : 259 : ibest = maxloc(cluster_count(1:ncluster), dim=1)
+ + ]
560 : 46 : iatom_ref = cluster_atom(ibest)
561 : 46 : islot_ref = cluster_slot(ibest)
562 : :
563 : : ! Compute a first estimate of the shift directly in supercell-fractional
564 : : ! coordinates (MD%xred's own units), from iatom_ref's own raw xred_average
565 : : ! -- NOT by converting cluster_shift(:,ibest) back through unit_to_scaled.
566 : : ! cluster_shift was wrapped to the minimum image in UNITCELL-fractional
567 : : ! coordinates, and a unitcell-fractional wrap boundary (e.g. a basis atom
568 : : ! sitting at exactly 0.5) does not correspond to a negligible ambiguity
569 : : ! once converted to supercell-fractional coordinates: it can differ by as
570 : : ! much as 1/N of a supercell period, N being the relevant HNF diagonal
571 : : ! entry. Recomputing directly in supercell-fractional coordinates and
572 : : ! wrapping only once, there, avoids that.
573 [ + + ]: 184 : shift_ref = SC%unit_to_scaled(SC%xred_unitcell(:,islot_ref)) - MD%xred_average(:,iatom_ref)
574 : 46 : call tdep_make_inbox(shift_ref,1,tol8)
575 : :
576 : : ! Refine shift_ref into the actual average over every (atom,slot) pairing
577 : : ! belonging to the winning cluster, not just iatom_ref alone: a single
578 : : ! atom's own thermal displacement at that instant is otherwise baked
579 : : ! wholesale into the global shift, which is precise enough to place every
580 : : ! atom on the right periodic image (find_nearest_atom's job) but noisier
581 : : ! than necessary as an origin convention -- averaging over the whole
582 : : ! cluster (typically a sizeable fraction of natom) suppresses that noise
583 : : ! by a further sqrt(cluster size).
584 : : !
585 : : ! The average is accumulated ENTIRELY in unitcell-fractional coordinates,
586 : : ! as deviations from cluster_shift(:,ibest) (already guaranteed small by
587 : : ! the cluster membership test itself). Averaging directly in
588 : : ! supercell-fractional coordinates does NOT work: different members of
589 : : ! the same cluster generally sit in different primitive cells, so their
590 : : ! raw supercell-fractional positions differ from each other by
591 : : ! cell-dependent fractions of a supercell period, not by small thermal
592 : : ! noise alone. The (small) averaged unitcell-fractional correction is
593 : : ! converted to supercell-fractional coordinates and added to shift_ref
594 : : ! only at the very end, which is safe precisely because it is small: it
595 : : ! does not, unlike a full shift value, sit near a wrap boundary.
596 : 46 : shift_sum = zero
597 : 46 : navg = 0
598 [ + + ]: 7324 : do iatom=1,MD%natom
599 [ + + ]: 23002 : do islot=1,MD%natom_unitcell
600 [ + + ]: 15678 : if (MD%typat(iatom) /= MD%typat_unitcell(islot)) cycle
601 : :
602 [ + + ]: 54072 : tmp = SC%xred_unitcell(:,islot) - SC%scaled_to_unit(MD%xred_average(:,iatom))
603 : 13518 : call tdep_make_inbox(tmp,1,tol8)
604 [ + + ]: 54072 : diff = tmp-cluster_shift(:,ibest)
605 : 13518 : call tdep_make_inbox(diff,1,tol8)
606 [ + + + + ]: 54072 : if (sqrt(sum(diff**2)) >= tol) cycle ! not a member of the winning cluster
607 : :
608 [ + + ]: 29112 : shift_sum = shift_sum + diff
609 : 22956 : navg = navg + 1
610 : : end do
611 : : end do
612 : :
613 [ + + + + ]: 368 : shift = shift_ref + SC%unit_to_scaled(shift_sum/real(navg,kind=dp))
614 : 46 : call tdep_make_inbox(shift,1,tol8)
615 : :
616 : 46 : call MD%shift_xred(shift)
617 : :
618 [ - + ]: 46 : ABI_FREE(cluster_shift)
619 [ - + ]: 46 : ABI_FREE(cluster_count)
620 : 46 : ABI_FREE(cluster_atom)
621 : 46 : ABI_FREE(cluster_slot)
622 : :
623 : 46 : end subroutine tdep_match_unitcell
624 : : !!***
625 : :
626 : : !=====================================================================================================
627 : :
628 : : !!****f* ABINIT/m_tdep_sampling/tdep_sampling_reorder
629 : : !! NAME
630 : : !! tdep_sampling_reorder
631 : : !!
632 : : !! FUNCTION
633 : : !! Reorder all populated per-atom arrays held by MD, according to a gather-style index map:
634 : : !! new_array(:,iatom) = old_array(:,order(iatom)).
635 : : !!
636 : : !! Only the atom-indexed quantities that are populated by the time atoms get
637 : : !! reordered in tdep_match_supercell are handled here:
638 : : !! typat, xred_average, xred and fcart.
639 : : !! Quantities computed later (ucart, Forces, ucart0, Rlatt_cart, Rlatt_scaled)
640 : : !! are untouched. (xred_ideal and dij live in SC, which is never reordered.)
641 : : !!
642 : : !! INPUTS
643 : : !! order(natom) = Gather-style index map (see above).
644 : : !!
645 : : !! OUTPUT
646 : : !!
647 : : !! SIDE EFFECTS
648 : : !! MD = TDEP Sampling object. MD%typat, MD%xred_average, MD%xred and
649 : : !! MD%fcart are reordered.
650 : : !!
651 : : !! SOURCE
652 : :
653 : 46 : subroutine tdep_sampling_reorder(MD, order)
654 : :
655 : : class(tdep_Sampling_type),intent(inout) :: MD
656 : : integer,intent(in) :: order(MD%natom)
657 : :
658 : : integer :: istep,iatom
659 : 46 : integer, allocatable :: typat_tmp(:)
660 : 46 : real(dp), allocatable :: vec_tmp(:,:)
661 : :
662 [ - + + - : 138 : ABI_MALLOC(typat_tmp,(MD%natom))
+ - + - -
+ + - ]
663 [ + + ]: 7324 : do iatom=1,MD%natom
664 : 7324 : typat_tmp(iatom) = MD%typat(order(iatom))
665 : : end do
666 [ + + ]: 7324 : MD%typat(:) = typat_tmp(:)
667 [ - + ]: 46 : ABI_FREE(typat_tmp)
668 : :
669 [ - + + - : 138 : ABI_MALLOC(vec_tmp,(3,MD%natom))
+ - + - -
+ - + ]
670 : :
671 [ + + ]: 7324 : do iatom=1,MD%natom
672 [ + + ]: 29158 : vec_tmp(:,iatom) = MD%xred_average(:,order(iatom))
673 : : end do
674 [ + + + + ]: 29158 : MD%xred_average(:,:) = vec_tmp(:,:)
675 : :
676 [ + + ]: 1038 : do istep=1,MD%my_nstep
677 : :
678 [ + + ]: 148064 : do iatom=1,MD%natom
679 [ + + ]: 589280 : vec_tmp(:,iatom) = MD%xred(:,order(iatom),istep)
680 : : end do
681 [ + + + + ]: 589280 : MD%xred(:,:,istep) = vec_tmp(:,:)
682 : :
683 [ + + ]: 148064 : do iatom=1,MD%natom
684 [ + + ]: 589280 : vec_tmp(:,iatom) = MD%fcart(:,order(iatom),istep)
685 : : end do
686 [ + + + + ]: 589326 : MD%fcart(:,:,istep) = vec_tmp(:,:)
687 : :
688 : : end do
689 : :
690 [ - + ]: 46 : ABI_FREE(vec_tmp)
691 : :
692 : 46 : end subroutine tdep_sampling_reorder
693 : : !!***
694 : :
695 : : !=====================================================================================================
696 : :
697 : : !!****f* ABINIT/m_tdep_sampling/tdep_sampling_gather_inbox
698 : : !! NAME
699 : : !! tdep_sampling_gather_inbox
700 : : !!
701 : : !! FUNCTION
702 : : !! Shift xred to keep atoms in the same unit cell at each step.
703 : : !! For each atom and each step, every reduced coordinate is shifted by
704 : : !! an integer (-1, 0 or 1) so as to be as close as possible to the
705 : : !! corresponding coordinate at the first MD step (which is communicated
706 : : !! to all MPI processes).
707 : : !!
708 : : !! INPUTS
709 : : !! MPIdata = Info on MPI parallelism.
710 : : !!
711 : : !! OUTPUT
712 : : !!
713 : : !! SIDE EFFECTS
714 : : !! MD = TDEP Sampling object. MD%xred is shifted.
715 : : !!
716 : : !! SOURCE
717 : :
718 : 46 : subroutine tdep_sampling_gather_inbox(MD,MPIdata)
719 : :
720 : : class(tdep_Sampling_type), intent(inout) :: MD
721 : : type(MPI_enreg_type), intent(in) :: MPIdata
722 : : integer :: natom,ii,iatom,istep,ierr
723 : : integer :: shift,shift_max,shift_best
724 : : double precision :: xi, dist, best_dist
725 : 46 : double precision, allocatable :: x0(:,:)
726 : :
727 : 46 : natom = MD%natom
728 [ - + + - : 138 : ABI_MALLOC(x0,(3,natom))
+ - + - -
+ - + ]
729 : :
730 : : ! Communicate xred at the first step
731 [ + + + + ]: 29158 : x0(:,:) = zero
732 [ + - ]: 46 : if (MPIdata%my_step(1)) then
733 [ + + + + ]: 29158 : x0(:,:) = MD%xred(:,:,1)
734 : : end if
735 : 46 : call xmpi_sum(x0,MPIdata%comm_step,ierr)
736 : :
737 : : ! Shift xred from all steps in the same unitcell as the first step
738 : 46 : shift_max = 1
739 [ + + ]: 1038 : do istep=1, MD%my_nstep
740 [ + + ]: 148110 : do iatom=1,natom
741 [ + + ]: 589280 : do ii=1,3
742 : 441216 : best_dist = abs(MD%xred(ii,iatom,istep) - x0(ii,iatom))
743 : 441216 : shift_best = 0
744 [ + + ]: 1764864 : do shift=-shift_max,shift_max
745 : 1323648 : xi = MD%xred(ii,iatom,istep) + shift
746 : 1323648 : dist = abs(xi - x0(ii,iatom))
747 [ + + ]: 1764864 : if (dist < best_dist) then
748 : 366 : best_dist = dist
749 : 366 : shift_best = shift
750 : : end if
751 : : end do
752 : 588288 : MD%xred(ii,iatom,istep) = MD%xred(ii,iatom,istep) + shift_best
753 : : end do
754 : : end do
755 : : end do
756 : :
757 [ - + ]: 46 : ABI_FREE(x0)
758 : :
759 : 46 : end subroutine tdep_sampling_gather_inbox
760 : : !!***
761 : :
762 : : !=====================================================================================================
763 : :
764 : : !!****f* ABINIT/m_tdep_sampling/tdep_sampling_rotate
765 : : !! NAME
766 : : !! tdep_sampling_rotate
767 : : !!
768 : : !! FUNCTION
769 : : !! Apply a rotation to the sampling.
770 : : !! Rotation_cart is a rotation matrix that has been applied to each primitive
771 : : !! vectors. Hence, the xred are unchanged, but the forces stored in Cartesian
772 : : !! coordinates must be rotated.
773 : : !!
774 : : !! INPUTS
775 : : !! rotation_cart(3,3) = Rotation matrix, in cartesian coordinates.
776 : : !!
777 : : !! OUTPUT
778 : : !!
779 : : !! SIDE EFFECTS
780 : : !! MD = TDEP Sampling object. MD%fcart is rotated.
781 : : !!
782 : : !! SOURCE
783 : :
784 : 46 : subroutine tdep_sampling_rotate(MD,rotation_cart)
785 : :
786 : : class(tdep_Sampling_type), intent(inout) :: MD
787 : : real(dp), intent(in) :: rotation_cart(3,3)
788 : : integer :: iatom,istep
789 : :
790 : : ! Apply rotation to fcart
791 [ + + ]: 1038 : do istep=1,MD%my_nstep
792 [ + + ]: 148110 : do iatom=1,MD%natom
793 [ + + + + : 2942432 : MD%fcart(:,iatom,istep) = MATMUL(rotation_cart, MD%fcart(:,iatom,istep))
+ + + + +
- + - ]
794 : : end do
795 : : end do
796 : :
797 : 46 : end subroutine tdep_sampling_rotate
798 : : !!***
799 : :
800 : : !====================================================================================================
801 : :
802 : : !!****f* ABINIT/m_tdep_sampling/tdep_match_supercell
803 : : !! NAME
804 : : !! tdep_match_supercell
805 : : !!
806 : : !! FUNCTION
807 : : !! Find the mapping between the atoms of the ideal (equilibrium) supercell SC
808 : : !! and the atoms of the input molecular dynamics (MD) trajectory, using their
809 : : !! average positions. Then compute the atom displacements (ucart) with
810 : : !! respect to the equilibrium positions at each time step of the MD, and a
811 : : !! few geometric quantities of SC (dij, Rlatt_cart/Rlatt_scaled) that are
812 : : !! needed downstream to build the shells and the IFC.
813 : : !!
814 : : !! Concretely, this routine, in order:
815 : : !! 1) Computes the average MD position of each atom (MD%xred_average).
816 : : !! 2) Applies a global shift to all MD positions so that they share the
817 : : !! same unitcell definition as SC (tdep_match_unitcell).
818 : : !! 3) Matches every raw MD atom to its nearest SC site (SC%find_nearest_atom)
819 : : !! and shifts its MD trajectory (xred and xred_average) by a supercell
820 : : !! lattice vector so that it sits on SC's fixed, centered ideal site.
821 : : !! 4) Reorders every per-atom quantity held by MD (typat, xred,
822 : : !! xred_average, fcart) to match the natural atom ordering of SC.
823 : : !! 5) Writes the (raw, unwrapped) ideal and average positions to
824 : : !! xred_average.xyz, and the supercell definition to a CIF file, for
825 : : !! diagnostic purposes.
826 : : !! 6) Computes the cartesian displacements MD%ucart at each MD step, the
827 : : !! flat cartesian force array MD%Forces, and the mean displacement
828 : : !! MD%ucart0. MD%xred is freed at the end of this step, since it is no
829 : : !! longer needed.
830 : : !! 7) Computes SC%dij, the distance (and cartesian vector) between every
831 : : !! pair of atoms in the supercell.
832 : : !! 8) Computes MD%Rlatt_cart and MD%Rlatt_scaled, the cartesian (resp.
833 : : !! scaled) lattice vector between each atom and its parent reference
834 : : !! unitcell atom. Their construction must match the convention expected
835 : : !! by module m_ifc (see the comment further below).
836 : : !!
837 : : !! INPUTS
838 : : !! Invar = Input object containing the input variables.
839 : : !! MPIdata = Info on MPI parallelism.
840 : : !!
841 : : !! OUTPUT
842 : : !!
843 : : !! SIDE EFFECTS
844 : : !! MD = TDEP Sampling object containing the input positions and forces.
845 : : !! Its per-atom quantities are reordered to match the natural
846 : : !! ordering of SC (see step 4 above), and xred_average, ucart,
847 : : !! ucart0, Forces, Rlatt_cart and Rlatt_scaled are computed
848 : : !! (see FUNCTION above for details). xred is freed.
849 : : !! SC = Supercell object describing the ideal structure. SC%dij is
850 : : !! computed (see FUNCTION above). SC itself is never reordered.
851 : : !!
852 : : !! NOTES
853 : : !!
854 : : !! SOURCE
855 : :
856 : 46 : subroutine tdep_match_supercell(Invar,MPIdata,MD,SC)
857 : :
858 : : type(atdep_dataset_type),intent(in) :: Invar
859 : : type(MPI_enreg_type),intent(in) :: MPIdata
860 : : type(tdep_Sampling_type),intent(inout) :: MD
861 : : type(tdep_Supercell_type),intent(inout) :: SC
862 : :
863 : : ! Scalars
864 : : logical :: debug
865 : : integer :: natom, natom_unitcell, nstep
866 : : integer :: ii,jj,iatcell,iatom,jatom,istep
867 : : integer :: ierr
868 : : integer :: icell,iat_unit,iat_super
869 : :
870 : : ! Arrays
871 : : integer :: R_at(3)
872 : : integer :: R_at_centered(3)
873 : : integer :: R_shift(3)
874 : : real(dp) :: R_shift_scaled(3)
875 : : real(dp) :: xred(3),xcart(3)
876 : : real(dp) :: xred_unit(3),xred_scaled(3)
877 : : real(dp) :: ucart(3)
878 : : real(dp) :: rprimd(3,3)
879 : : real(dp) :: xcart_average(3)
880 : : real(dp) :: Rlatt(3)
881 : : real(dp) :: R_cell(3)
882 : : real(dp) :: R_cell_ref(3)
883 : : real(dp) :: xred_ideal_iatom(3)
884 : : real(dp) :: origin(3)
885 : : logical :: freeze_dir(3)
886 : :
887 : 46 : integer, allocatable :: raw_of_natural(:)
888 : 46 : real(dp), allocatable :: xcart_ideal(:,:)
889 : 46 : real(dp), allocatable :: xred_ideal_raw(:,:)
890 : : character(len=500) :: msg
891 : :
892 : 46 : debug = (Invar%prtvol > 1)
893 : :
894 : 46 : write(ab_out,*)' '
895 : 46 : write(ab_out,*) '#############################################################################'
896 : 46 : write(ab_out,*) '###### Find the matching between ideal and average positions ###############'
897 : 46 : write(ab_out,*) '#############################################################################'
898 : :
899 : 46 : nstep = MD%my_nstep
900 : 46 : natom = MD%natom
901 : 46 : natom_unitcell = MD%natom_unitcell
902 : :
903 : : ! ===============================================================================
904 : : ! 1) Compute average positions from MD
905 : : !
906 : 46 : write(ab_out,*)' Computing average positions.'
907 [ + + + + ]: 29158 : MD%xred_average = zero
908 [ + + ]: 1038 : do istep=1,nstep
909 [ + + ]: 148110 : do iatom=1,natom
910 [ + + ]: 589280 : MD%xred_average(:,iatom) = MD%xred_average(:,iatom) + MD%xred(:,iatom,istep)
911 : : end do
912 : : end do
913 : 46 : call xmpi_sum(MD%xred_average,MPIdata%comm_step,ierr)
914 [ + + + + ]: 29158 : MD%xred_average(:,:) = MD%xred_average(:,:) / real(MD%nstep_tot)
915 : :
916 : :
917 : : ! ===============================================================================
918 : : ! 2) Find and apply a global shift to all xred to match the unitcell definition.
919 : : !
920 : : ! GA: This would not be necessary if the unitcell definition in the input file
921 : : ! matched the supercell constructed for the MD trajectory.
922 : : ! We could add this requirement explicitly and avoid this step.
923 : : !
924 : : ! TODO add an input variable to activate this call when needed.
925 : 46 : write(ab_out,*)' Computing global shift to match unitcell definition.'
926 : 46 : call tdep_match_unitcell(MD, SC)
927 : :
928 : :
929 : : ! ===============================================================================
930 : : ! 3) Match raw MD atoms to SC's natural sites and shift MD onto SC's fixed,
931 : : ! centered ideal positions (still in raw order, before any reordering).
932 : :
933 : : ! -----------------------------------------------------------------------------
934 : : ! Prepare second reordering to match legacy tdep_MatchIdeal2Average.
935 : : ! Find, in the raw MD order, the anchor atom that tdep_MatchIdeal2Average
936 : : ! uses to define its own reference order: the first atom whose type
937 : : ! matches the first unitcell atom. This only depends on the (untouched)
938 : : ! input ordering, so it can be found before any matching below.
939 : : !
940 : : !iatom_raw_ref = 0
941 : : !do iatom=1,natom
942 : : ! if (Invar%typat(iatom) == SC%typat_unitcell(1)) then
943 : : ! iatom_raw_ref = iatom
944 : : ! exit
945 : : ! end if
946 : : !end do
947 : : !if (iatom_raw_ref == 0) then
948 : : ! ABI_ERROR('Could not find an atom matching the unitcell basis type.')
949 : : !end if
950 : : ! ---------------------------------------------------------------------
951 : :
952 : 46 : write(ab_out,*)' Matching average atom positions to supercell sites.'
953 : :
954 [ - + + - : 7416 : ABI_CALLOC(raw_of_natural, (natom))
+ - + - -
+ - + +
+ ]
955 : :
956 [ + + ]: 7324 : do iatom=1,natom
957 : :
958 : 7278 : xcart = SC%red_scaled_to_cart(MD%xred_average(:,iatom))
959 : :
960 : 7278 : call SC%find_nearest_atom(xcart, MD%typat(iatom), iat_super, R_at, ucart)
961 : :
962 : : ! Shift the atom by a supercell lattice vector to match the SC definition.
963 : 7278 : R_at_centered = SC%get_R_at(iat_super)
964 [ + + ]: 29112 : R_shift = R_at_centered - R_at
965 [ + + - + ]: 29112 : R_shift_scaled = SC%unit_to_scaled(real(R_shift, kind=dp))
966 : :
967 [ + + ]: 29112 : MD%xred_average(:,iatom) = MD%xred_average(:,iatom) + R_shift_scaled
968 [ + + ]: 154350 : do istep=1,nstep
969 [ + + ]: 595566 : MD%xred(:,iatom,istep) = MD%xred(:,iatom,istep) + R_shift_scaled
970 : : end do
971 : :
972 : : ! --------------------------------------------------------------------
973 : : ! Check that no two atoms of the MD sampling have been assigned
974 : : ! to the same atom in the supercell.
975 [ - + ]: 7278 : if (raw_of_natural(iat_super) .ne. 0) then
976 : 0 : jatom = raw_of_natural(iat_super)
977 : 0 : call SC%get_iat_unitcell(jatom, icell, iat_unit)
978 : 0 : write(msg,*) 'More than one atom assigned to supercell site:',ch10, &
979 : 0 : & 'iatom = ', iatom, ch10,&
980 : 0 : & 'icell, iat_unit = ', icell, iat_unit, ch10,&
981 : 0 : & 'jatom = ', jatom, ch10,&
982 : 0 : & 'xcart (1) = ', xcart,ch10,&
983 [ # # ]: 0 : & 'xcart (2) = ', SC%get_xcart(iat_super)
984 : 0 : ABI_WARNING(msg)
985 : : end if
986 : 7324 : raw_of_natural(iat_super) = iatom
987 : : ! ----------------------------------------------------------------------
988 : :
989 : : end do
990 : :
991 : :
992 : : ! ===============================================================================
993 : : ! 4) Reorder atom positions, types, and forces to match the natural ordering of SC.
994 : : !
995 : 46 : write(ab_out,*)' Reordering atoms in MD trajectory.'
996 : 46 : call MD%reorder(raw_of_natural)
997 : :
998 : : ! ---------------------------------------------------------------------
999 : : !! Second reordering: natural -> reference
1000 : : !! Bring MD into the same atom enumeration as the legacy
1001 : : !! tdep_MatchIdeal2Average routine, anchored on the same physical atom
1002 : : !! (iat_super_ref) that routine would pick as its own reference.
1003 : :
1004 : : !ABI_CALLOC(natural_of_reference, (natom))
1005 : : !natural_of_reference = get_ifc_order(SC, iat_super_ref)
1006 : :
1007 : : !! Apply the reordering to the per-atom quantities currently held by MD
1008 : : !! (so far expressed in the natural SC order), bringing them into the
1009 : : !! reference order: vec_new(:,iatom) = vec_old(:,natural_of_reference(iatom)).
1010 : : !call MD%reorder(natural_of_reference)
1011 : :
1012 : : !! The "original MD order" bookkeeping array is not part of MD, so it is
1013 : : !! reordered separately, using the same gather convention.
1014 : : !ABI_MALLOC(raw_of_natural_tmp, (natom))
1015 : : !do iatom=1,natom
1016 : : ! raw_of_natural_tmp(iatom) = raw_of_natural(natural_of_reference(iatom))
1017 : : !end do
1018 : : !raw_of_natural(:) = raw_of_natural_tmp(:)
1019 : : !ABI_FREE(raw_of_natural_tmp)
1020 : :
1021 : : !! From this point on, all per-atom quantities in MD are in reference
1022 : : !! order. SC itself is never reordered, so any subsequent call into SC
1023 : : !! must translate via natural_of_reference(iatom).
1024 : :
1025 : : ! =============================================================================
1026 : : ! 5) Save ideal positions and write them to file.
1027 : :
1028 : : ! Save ideal positions
1029 [ - + + - : 138 : ABI_MALLOC(xred_ideal_raw,(3,natom))
+ - + - -
+ - + ]
1030 [ + + ]: 7324 : do iatom=1,natom
1031 : 7324 : xred_ideal_raw(:,iatom) = SC%get_xred_scaled(iatom)
1032 : : end do
1033 : :
1034 : : ! Note that xred_ideal_raw, used here, is not wrapped, unlike the ideal
1035 : : ! positions computed on the fly in step 8 (via
1036 : : ! SC%get_xred_scaled(iatom,wrap=.true.)). In previous implementation,
1037 : : ! this wrap happened before writing this file, which created an
1038 : : ! apparent mismatch.
1039 : 46 : write(ab_out,*)' Writing ideal and average positions in file xred_average.xyz'
1040 [ + - ]: 46 : if (MPIdata%iam_master) then
1041 : 46 : call tdep_write_xred_average_ideal(Invar,MD%xred_average,xred_ideal_raw,raw_of_natural)
1042 : : end if
1043 : :
1044 [ - + ]: 46 : ABI_FREE(xred_ideal_raw)
1045 [ - + ]: 46 : ABI_FREE(raw_of_natural)
1046 : :
1047 : : ! Write the supercell in file.
1048 [ + - ]: 46 : if (MPIdata%iam_master) then
1049 : 46 : call SC%write_cif(Invar%output_prefix)
1050 : : end if
1051 : :
1052 : : ! =============================================================================
1053 : : ! 6) Compute cartesian displacements at each MD step.
1054 : :
1055 : 46 : write(ab_out,*)' Computing cartesian displacements.'
1056 : :
1057 [ - + + - : 29204 : ABI_CALLOC(xcart_ideal,(3,natom))
- + - + +
+ + + ]
1058 [ + + ]: 46 : if (Invar%use_ideal_positions.eq.0) then
1059 [ + + ]: 1252 : do iatom=1,natom
1060 : : ! This is in scaled reduced coordinates
1061 [ + + ]: 4968 : xred = MD%xred_average(:,iatom)
1062 : 1242 : xcart = SC%red_scaled_to_cart(xred)
1063 [ + + ]: 4978 : xcart_ideal(:,iatom) = xcart
1064 : : end do
1065 : : else
1066 [ + + ]: 6072 : do iatom=1,natom
1067 : 6072 : xcart_ideal(:,iatom) = SC%get_xcart(iatom)
1068 : : end do
1069 : : end if
1070 : :
1071 : : ! Compute ucart for all MD steps
1072 [ + + ]: 1038 : do istep=1,nstep
1073 [ + + ]: 148110 : do iatom=1,natom
1074 [ + + ]: 588288 : xred = MD%xred(:,iatom,istep)
1075 : 147072 : xcart = SC%red_scaled_to_cart(xred)
1076 [ + + ]: 589280 : MD%ucart(:,iatom,istep) = xcart - xcart_ideal(:,iatom)
1077 : : end do
1078 : : end do
1079 : :
1080 : : ! Rearrange fcart into the Forces vector
1081 [ + + ]: 1038 : do istep=1,nstep
1082 [ + + ]: 148110 : do jatom=1,natom
1083 [ + + ]: 589280 : do ii=1,3
1084 : 441216 : jj = MD%get_flat_index(ii,jatom,istep)
1085 : 588288 : MD%Forces(jj) = MD%fcart(ii,jatom,istep)
1086 : : enddo
1087 : : enddo
1088 : : enddo
1089 : :
1090 : : ! Write ucart/fcart (for debugging)
1091 [ - + - - ]: 46 : if (debug.and.MPIdata%iam_master) then
1092 : 0 : write(ab_out,*)' Writing displacements and forces in file ucart_fcart.dat'
1093 : 0 : call tdep_write_ucart_fcart(Invar,MPIdata,natom,nstep,MD%typat,MD%ucart,MD%fcart)
1094 : : end if
1095 : :
1096 : : ! Save the average displacement, in case we want to reconstruct xcart from ucart
1097 [ + + ]: 46 : if (Invar%use_ideal_positions.eq.0) then
1098 [ + + + + ]: 4978 : MD%ucart0 = zero
1099 : : else
1100 [ + + ]: 6072 : do iatom=1,natom
1101 : 6036 : xcart_average = SC%red_scaled_to_cart(MD%xred_average(:,iatom))
1102 [ + + ]: 24180 : MD%ucart0(:,iatom) = xcart_average(:) - xcart_ideal(:,iatom)
1103 : : end do
1104 : : end if
1105 : :
1106 [ - + ]: 46 : ABI_FREE(xcart_ideal)
1107 : :
1108 : : ! We no longer need xred after this routine
1109 [ - + ]: 46 : ABI_FREE(MD%xred)
1110 : :
1111 : : ! ==========================================================================
1112 : : ! Here we should perform a check on ucart to make sure that it is not larger
1113 : : ! than rprimd, and warn the user when this is the case.
1114 : : ! In that case, unitcell attribution has failed, and the IFC will be wrong.
1115 : : ! One possible cause of this situation is that two atoms have swapped place
1116 : : ! during the MD simulation.
1117 : : ! In that case, we should be able to REPAIR this situation by swapping atom indices
1118 : : ! for certain steps.
1119 : : ! Otherwise, the user should curate their data.
1120 : :
1121 : :
1122 : : ! ==========================================================================
1123 : : ! 7) Compute all interatomic distances in the supercell.
1124 : : ! They are used to initialize the shell objects.
1125 : : !
1126 : : ! GA: Those quantities could be computed on-the-fly.
1127 : :
1128 : 46 : write(ab_out,*)' Computing all interatomic distances.'
1129 : 46 : call SC%calc_dij()
1130 : :
1131 : :
1132 : : ! ==========================================================================
1133 : : ! 8) Compute Rlatt_cart and Rlatt_scaled.
1134 : : ! These are the Cartesian lattice vector between a unitcell reference atom
1135 : : ! and the ideal site of each atom, and will be used in tdep_ifc2phi2
1136 : : ! and tdep_calc_gruneisen.
1137 : : !
1138 : : ! The construction of these arrays is quite convoluted, because they must
1139 : : ! match exactly the convention expected by module m_ifc, which compares
1140 : : ! lattice vectors against its own real-space box
1141 : : ! (Ifc%rcan/Ifc%rpt, built independently by canat9/make_bigbox in m_dynmat).
1142 : : !
1143 : : ! GA: TODO:
1144 : : ! Eventually, m_ifc should be refactored to consume the Supercell object
1145 : : ! convention directly. Then, this step could be removed.
1146 : :
1147 : : ! Compute supercell rprimd scaled by acell
1148 [ + + + + ]: 598 : rprimd = SC%rprimd_scaled
1149 [ + + ]: 184 : do ii=1,3
1150 [ + + ]: 598 : rprimd(:,ii) = rprimd(:,ii) / SC%acell(ii)
1151 : : end do
1152 : :
1153 : : ! Ideal positions are computed on the fly (SC%get_xred_scaled(iatom,...)).
1154 : : ! They are anchored on atom 1's ideal position and wrapped to [-0.5,0.5).
1155 : : ! This anchoring matters: wrapping is not linear, so wrap(x-origin) differs
1156 : : ! from wrap(x)-origin whenever origin is not itself a lattice vector (i.e.
1157 : : ! whenever the first unitcell site is not at the reduced-coordinate origin).
1158 : 46 : origin = SC%get_xred_scaled(1)
1159 : :
1160 : : ! Scaled position of atom 1 unitcell site, placed in the origin cell
1161 : 46 : call SC%get_iat_unitcell(1,icell,iat_unit)
1162 : 46 : xred_unit = SC%get_xred(SC%get_iat_supercell(1,iat_unit))
1163 : 46 : R_cell_ref(:) = SC%unit_to_scaled(xred_unit)
1164 : :
1165 : : ! When the supercell does not repeat the unitcell along one reduced direction
1166 : : ! (multiplicity=1 along the diagonal, 0 elsewhere in that row),
1167 : : ! force the per-cell reduced-coordinate component of Rlatt_red(:,1,:)
1168 : : ! to zero along that direction for every atom.
1169 [ + + ]: 184 : do ii=1,3
1170 : : freeze_dir(ii) = (abs(Invar%multiplicity(ii,ii)-one)<tol8) .and. &
1171 : : & (abs(Invar%multiplicity(ii,mod(ii,3)+1))<tol8) .and. &
1172 [ + + + + : 321 : & (abs(Invar%multiplicity(ii,mod(ii+1,3)+1))<tol8)
- + ]
1173 : : end do
1174 : :
1175 : : ! Compute Rlatt
1176 [ + + ]: 7324 : do iatom=1,natom
1177 : :
1178 : : ! Ideal position of this atom, anchored on atom 1 and wrapped;
1179 : : ! reused below for every iatcell.
1180 [ + + ]: 29112 : xred_ideal_iatom = SC%wrap_inbox(SC%get_xred_scaled(iatom) - origin)
1181 : :
1182 : 7278 : call SC%get_iat_unitcell(iatom,icell,iat_unit)
1183 : 7278 : xred_unit = SC%get_xred(SC%get_iat_supercell(1,iat_unit))
1184 [ + + ]: 36390 : R_cell(:) = xred_ideal_iatom(:) + R_cell_ref(:) - SC%unit_to_scaled(xred_unit)
1185 [ + + + + ]: 29112 : where (freeze_dir) R_cell = zero
1186 : :
1187 [ + + ]: 23002 : do iatcell=1,natom_unitcell
1188 : :
1189 : 15678 : xred_unit = SC%get_xred(SC%get_iat_supercell(1,iatcell))
1190 [ + + ]: 78390 : xred_scaled = SC%unit_to_scaled(xred_unit) - origin
1191 : 15678 : call tdep_make_inbox(xred_scaled,1,tol8)
1192 : :
1193 [ + + ]: 62712 : xred_scaled = xred_ideal_iatom(:) - xred_scaled
1194 : 15678 : Rlatt = R_cell
1195 : 15678 : call tdep_make_inbox(xred_scaled,1,tol8,Rlatt)
1196 : :
1197 [ + + ]: 62712 : MD%Rlatt_cart(:,iatcell,iatom) = SC%red_scaled_to_cart(Rlatt)
1198 [ + + + + : 258126 : MD%Rlatt_scaled(:,iatcell,iatom) = matmul(rprimd, Rlatt)
+ + + - ]
1199 : :
1200 : : end do
1201 : :
1202 : : end do
1203 : :
1204 : : ! Write distance/Rlatt for debugging.
1205 : 46 : call tdep_write_distance_rlatt(Invar,MPIdata,SC,natom,natom_unitcell,MD%Rlatt_cart,MD%Rlatt_scaled)
1206 : :
1207 : 46 : end subroutine tdep_match_supercell
1208 : : !!***
1209 : :
1210 : : !====================================================================================================
1211 : :
1212 : : !!****f* ABINIT/m_tdep_sampling/get_ifc_order
1213 : : !! NAME
1214 : : !! get_ifc_order
1215 : : !!
1216 : : !! FUNCTION
1217 : : !! Enumerate the atoms of the supercell in the reference order expected by
1218 : : !! the legacy IFC routines (i.e. the order in which tdep_MatchIdeal2Average,
1219 : : !! itself inherited from m_dynmat/make_bigbox, enumerates atoms when building
1220 : : !! its "bigbox").
1221 : : !!
1222 : : !! This can be combined with SC%reorder to bring any per-atom (3,natom) array,
1223 : : !! currently ordered according to the natural SC order, into the legacy
1224 : : !! (IFC-reference) order.
1225 : : !!
1226 : : !! INPUTS
1227 : : !! SC = Supercell object describing the ideal structure.
1228 : : !! iat_ref (optional) = natural SC atom (see get_iat_supercell/get_iat_unitcell)
1229 : : !! that should be placed at reference position 1. The legacy routine
1230 : : !! (tdep_MatchIdeal2Average) does not enumerate atoms in SC's own natural
1231 : : !! frame: it anchors its bigbox scan on whichever atom of the unitcell#1
1232 : : !! pattern it finds first in the MD trajectory (its "iatom_ref"), shifting
1233 : : !! the whole enumeration so that atom sits at reference position 1. Passing
1234 : : !! the natural SC atom corresponding to that same physical atom here
1235 : : !! reproduces the legacy ordering exactly. If absent, the enumeration is
1236 : : !! anchored on whatever site the bigbox scan naturally finds first (SC's own
1237 : : !! frame), which will generally NOT match the legacy order.
1238 : : !!
1239 : : !! OUTPUT
1240 : : !! order(natom) = order(iatom_ref) = iat_super, where iat_super is the natural
1241 : : !! (icell,iat_unit) index of the atom (see get_iat_supercell/get_iat_unitcell)
1242 : : !! that occupies reference position iatom_ref in the legacy enumeration.
1243 : : !!
1244 : : !! SOURCE
1245 : :
1246 [ # # ]: 0 : function get_ifc_order(SC, iat_ref) result(order)
1247 : :
1248 : : type(tdep_Supercell_type),intent(in) :: SC
1249 : : integer, intent(in), optional :: iat_ref
1250 : : integer :: order(SC%natom)
1251 : :
1252 : : integer, parameter :: max_ijk=20
1253 : : integer :: ii,jj,kk,iatcell,iatom
1254 : : integer :: jcell,jat_supercell
1255 : : integer :: R_at(3)
1256 : : integer :: R_shift(3)
1257 : : logical :: discard_R
1258 : : logical :: first
1259 : : real(dp) :: Rlatt(3),xred_try(3),xred_box(3)
1260 : :
1261 [ # # ]: 0 : order(:) = 0
1262 : 0 : R_shift = 0
1263 : 0 : first = .true.
1264 : :
1265 : 0 : iatom = 1
1266 [ # # ]: 0 : do ii=-max_ijk,max_ijk
1267 [ # # ]: 0 : do jj=-max_ijk,max_ijk
1268 [ # # ]: 0 : do kk=-max_ijk,max_ijk
1269 : :
1270 : 0 : Rlatt(1) = real(ii-1,kind=dp)
1271 : 0 : Rlatt(2) = real(jj-1,kind=dp)
1272 : 0 : Rlatt(3) = real(kk-1,kind=dp)
1273 : :
1274 : 0 : discard_R = .false.
1275 [ # # ]: 0 : do iatcell=1,SC%natom_unitcell
1276 : :
1277 [ # # ]: 0 : if (discard_R) cycle
1278 : :
1279 : : ! Compute the reduced position in the supercell.
1280 [ # # ]: 0 : xred_try(:) = Rlatt(:) + SC%xred_unitcell(:,iatcell)
1281 : 0 : xred_box = SC%unit_to_scaled(xred_try)
1282 : :
1283 : : ! If the first atom of the pattern is in the [0;1[ range then keep
1284 : : ! all the atoms of the pattern (even if the others are outside the
1285 : : ! box). Else, none are taken.
1286 [ # # ]: 0 : if (iatcell==1) then
1287 [ # # # # : 0 : if (minval(xred_box(:)).lt.0.d0.or.maxval(xred_box(:)).ge.(1.d0-tol12)) then
# # # # #
# # # # #
# # ]
1288 : : discard_R = .true.
1289 : : cycle
1290 : : end if
1291 : : end if
1292 : :
1293 [ # # ]: 0 : if (iatom.gt.(SC%natom+1)) then
1294 : 0 : ABI_ERROR('The number of atoms found in the bigbox exceeds natom')
1295 : : end if
1296 : :
1297 : : ! The very first atom kept by the scan defines reference position 1.
1298 : : ! Compute the shift that brings it into coincidence with iat_ref
1299 : : ! (if provided), and apply it to every subsequent site so the whole
1300 : : ! enumeration is anchored on iat_ref, exactly as the legacy routine
1301 : : ! anchors its own bigbox scan on iatom_ref.
1302 [ # # ]: 0 : if (first) then
1303 [ # # ]: 0 : if (present(iat_ref)) then
1304 [ # # ]: 0 : R_shift = NINT(Rlatt) - SC%get_R_at(iat_ref)
1305 : : end if
1306 : : first = .false.
1307 : : end if
1308 : :
1309 [ # # ]: 0 : R_at = NINT(Rlatt) - R_shift
1310 : 0 : jcell = SC%get_icell(R_at)
1311 : 0 : jat_supercell = SC%get_iat_supercell(jcell, iatcell)
1312 : :
1313 : 0 : order(iatom) = jat_supercell
1314 : 0 : iatom = iatom + 1
1315 : :
1316 : : end do
1317 : : end do
1318 : : end do
1319 : : end do
1320 : :
1321 [ # # ]: 0 : if (iatom.lt.SC%natom+1) then
1322 : 0 : ABI_ERROR('The number of atoms found in the big box is smaller than natom')
1323 : : end if
1324 : :
1325 : 0 : end function get_ifc_order
1326 : : !!***
1327 : :
1328 : : !====================================================================================================
1329 : :
1330 : : !!****f* ABINIT/m_tdep_sampling/tdep_write_xred_average_ideal
1331 : : !! NAME
1332 : : !! tdep_write_xred_average_ideal
1333 : : !!
1334 : : !! FUNCTION
1335 : : !! Write, for each atom, the ideal (equilibrium) position and the average
1336 : : !! MD position, both in reduced and cartesian coordinates, in the
1337 : : !! _xred_average.xyz file, for diagnostic purposes.
1338 : : !!
1339 : : !! INPUTS
1340 : : !! Invar = Input object containing the input variables.
1341 : : !! xred_average(3,natom) = Average reduced positions of the atoms.
1342 : : !! xred_ideal(3,natom) = Ideal reduced positions of the atoms.
1343 : : !! original_order(natom) = Index of each atom in the original ordering
1344 : : !! of the MD trajectory (written next to the
1345 : : !! average position).
1346 : : !!
1347 : : !! OUTPUT
1348 : : !! Only writing.
1349 : : !!
1350 : : !! SOURCE
1351 : :
1352 : 46 : subroutine tdep_write_xred_average_ideal(Invar,xred_average,xred_ideal,original_order)
1353 : :
1354 : : type(atdep_dataset_type), intent(in) :: Invar
1355 : : real(dp),intent(in) :: xred_average(3,Invar%natom)
1356 : : real(dp),intent(in) :: xred_ideal(3,Invar%natom)
1357 : : integer,intent(in) :: original_order(Invar%natom)
1358 : :
1359 : : integer :: unt
1360 : : integer :: iatom,jatom,ii,jj
1361 : : real(dp) :: rprimdt(3,3)
1362 : : real(dp) :: xred_A(3),xred_I(3),xcart_A(3),xcart_I(3)
1363 : :
1364 [ + + + + ]: 598 : rprimdt(:,:) = transpose(Invar%rprimd_md(:,:))
1365 : :
1366 : 46 : unt = get_unit()
1367 : 46 : open(unit=unt,file=trim(Invar%output_prefix)//'_xred_average.xyz')
1368 : 46 : write(unt,'(a,i4)') '# natom = ',Invar%natom
1369 : 46 : write(unt,'(a,i4)') '# natom_unitcell = ',Invar%natom_unitcell
1370 [ + - + + : 598 : write(unt,'(a,9(f4.1,1x))') '# multiplicity = ',((Invar%multiplicity(ii,jj),jj=1,3),ii=1,3 )
+ - + + ]
1371 : 46 : write(unt,'(a)') '#'
1372 : :
1373 : 46 : write(unt,'(a1,1x,a8,4x,a6,4x,3(a5,30x))') '#', 'position', 'iatom', 'xred ', 'xcart'
1374 : 46 : write(unt,'(a)')''
1375 : :
1376 : 46 : xred_I = zero
1377 : 46 : xred_A = zero
1378 [ + + ]: 7324 : do iatom=1,Invar%natom
1379 [ + + ]: 29112 : xred_A(:) = xred_average(:,iatom)
1380 [ + + ]: 29112 : xred_I(:) = xred_ideal(:,iatom)
1381 : :
1382 [ + + + + ]: 94614 : xcart_A = matmul(rprimdt, xred_A)
1383 [ + + + + ]: 94614 : xcart_I = matmul(rprimdt, xred_I)
1384 : :
1385 : 7278 : jatom = original_order(iatom)
1386 : :
1387 : : ! write(unt,'(2x,a8,4x,i6,2x,3(f10.6,1x),2x,3(f10.6,1x))')'Average',jatom,xred_A,xcart_A
1388 : : ! write(unt,'(2x,a8,4x,i6,2x,3(f10.6,1x),2x,3(f10.6,1x),2x,3(f10.6,1x))')'Ideal ',iatom,xred_I,xcart_I,R_red
1389 : 7278 : write(unt,'(2x,a8,4x,i6,2x,3(f10.6,1x),2x,3(f10.6,1x),2x,3(f10.6,1x))')'Ideal ',iatom,xred_I,xcart_I
1390 : 7278 : write(unt,'(2x,a8,4x,i6,2x,3(f10.6,1x),2x,3(f10.6,1x))')'Average',jatom,xred_A,xcart_A
1391 : 7324 : write(unt,'(a)')''
1392 : :
1393 : : end do
1394 : :
1395 : 46 : close(unt)
1396 : :
1397 : 46 : end subroutine tdep_write_xred_average_ideal
1398 : : !!***
1399 : :
1400 : : !====================================================================================================
1401 : :
1402 : : !!****f* ABINIT/m_tdep_sampling/tdep_write_ucart_fcart
1403 : : !! NAME
1404 : : !! tdep_write_ucart_fcart
1405 : : !!
1406 : : !! FUNCTION
1407 : : !! Write, for each MD step and each atom, the Cartesian displacement
1408 : : !! (ucart) and the Cartesian force (fcart), together with the relevant
1409 : : !! indices. This is meant for debugging/comparison purposes, e.g. to
1410 : : !! directly diff the output of tdep_match_supercell against that of
1411 : : !! tdep_MatchIdeal2Average for the same input trajectory.
1412 : : !!
1413 : : !! INPUTS
1414 : : !! Invar = Input object containing the input variables.
1415 : : !! MPIdata = Info on MPI parallelism.
1416 : : !! natom = Number of atoms in the supercell.
1417 : : !! nstep = Number of MD steps (locally held).
1418 : : !! typat(natom) = Atom type, in the same order as ucart/fcart.
1419 : : !! ucart(3,natom,nstep) = Cartesian displacements.
1420 : : !! fcart(3,natom,nstep) = Cartesian forces.
1421 : : !!
1422 : : !! NOTES
1423 : : !! ucart and fcart must already be expressed in the same atom ordering
1424 : : !! (this is not necessarily true of MD%fcart itself in every routine;
1425 : : !! callers should pass whichever arrays are mutually consistent).
1426 : : !!
1427 : : !! SOURCE
1428 : :
1429 : 0 : subroutine tdep_write_ucart_fcart(Invar,MPIdata,natom,nstep,typat,ucart,fcart)
1430 : :
1431 : : type(atdep_dataset_type),intent(in) :: Invar
1432 : : type(MPI_enreg_type),intent(in) :: MPIdata
1433 : : integer,intent(in) :: natom,nstep
1434 : : integer,intent(in) :: typat(natom)
1435 : : real(dp),intent(in) :: ucart(3,natom,nstep)
1436 : : real(dp),intent(in) :: fcart(3,natom,nstep)
1437 : :
1438 : : integer :: unt,istep,iatom
1439 : :
1440 [ # # ]: 0 : if (.not.MPIdata%iam_master) return
1441 : :
1442 : 0 : unt = get_unit()
1443 : 0 : open(unit=unt,file=trim(Invar%output_prefix)//'_ucart_fcart.dat')
1444 : :
1445 : 0 : write(unt,'(a)') '# istep iatom typat ucart(1:3) fcart(1:3)'
1446 : :
1447 [ # # ]: 0 : do istep=1,nstep
1448 [ # # ]: 0 : do iatom=1,natom
1449 : : write(unt,'(2(i6,1x),i4,4x,3(f16.10,1x),4x,3(f16.10,1x))') &
1450 : 0 : & istep,iatom,typat(iatom),ucart(:,iatom,istep),fcart(:,iatom,istep)
1451 : : end do
1452 : : end do
1453 : :
1454 : 0 : close(unt)
1455 : :
1456 : : end subroutine tdep_write_ucart_fcart
1457 : : !!***
1458 : :
1459 : : !====================================================================================================
1460 : :
1461 : : !!****f* ABINIT/m_tdep_sampling/tdep_write_distance_rlatt
1462 : : !! NAME
1463 : : !! tdep_write_distance_rlatt
1464 : : !!
1465 : : !! FUNCTION
1466 : : !! Write distance (interatomic distances between ideal positions) and
1467 : : !! MD%Rlatt_cart/MD%Rlatt_scaled (lattice vectors between the ideal site of
1468 : : !! each atom and each unitcell reference atom), for debugging/comparison
1469 : : !! purposes, e.g. to directly diff the output of tdep_match_supercell
1470 : : !! against that of tdep_MatchIdeal2Average for the same input trajectory.
1471 : : !! Both quantities are purely geometric (computed from ideal positions
1472 : : !! only), so unlike ucart/fcart they do not depend on which raw MD atom
1473 : : !! was matched to which site, and should already share a common atom
1474 : : !! ordering (the IFC-reference/box-scan order) in both routines.
1475 : : !!
1476 : : !! INPUTS
1477 : : !! Invar = Input object containing the input variables.
1478 : : !! MPIdata = Info on MPI parallelism.
1479 : : !! SC = Supercell object describing the ideal structure. SC%dij (distance
1480 : : !! and cartesian components between the ideal positions of pairs of
1481 : : !! atoms) is used.
1482 : : !! natom = Number of atoms in the supercell.
1483 : : !! natom_unitcell = Number of atoms in the unitcell.
1484 : : !! Rlatt_cart(3,natom_unitcell,natom) = Cartesian lattice vector between
1485 : : !! a unitcell reference atom and the ideal
1486 : : !! site of each atom.
1487 : : !! Rlatt_scaled(3,natom_unitcell,natom) = Rlatt_cart divided by acell_unitcell.
1488 : : !!
1489 : : !! SOURCE
1490 : :
1491 : 46 : subroutine tdep_write_distance_rlatt(Invar,MPIdata,SC,natom,natom_unitcell,Rlatt_cart,Rlatt_scaled)
1492 : :
1493 : : type(atdep_dataset_type),intent(in) :: Invar
1494 : : type(MPI_enreg_type),intent(in) :: MPIdata
1495 : : type(tdep_Supercell_type),intent(in) :: SC
1496 : : integer,intent(in) :: natom,natom_unitcell
1497 : : real(dp),intent(in) :: Rlatt_cart(3,natom_unitcell,natom)
1498 : : real(dp),intent(in) :: Rlatt_scaled(3,natom_unitcell,natom)
1499 : :
1500 : : integer :: unt,iatom,jatom,iatcell
1501 : :
1502 [ - + ]: 46 : if (.not.MPIdata%iam_master) return
1503 : :
1504 : 46 : unt = get_unit()
1505 : 46 : open(unit=unt,file=trim(Invar%output_prefix)//'_distance.dat')
1506 : 46 : write(unt,'(a)') '# iatom jatom dist rij(1:3)'
1507 [ + + ]: 7324 : do iatom=1,natom
1508 [ + + ]: 1558688 : do jatom=1,natom
1509 : 1558642 : write(unt,'(2(i6,1x),4(f16.10,1x))') iatom,jatom,SC%dij(iatom,jatom,1),SC%dij(iatom,jatom,2:4)
1510 : : end do
1511 : : end do
1512 : 46 : close(unt)
1513 : :
1514 : 46 : unt = get_unit()
1515 : 46 : open(unit=unt,file=trim(Invar%output_prefix)//'_rlatt.dat')
1516 : 46 : write(unt,'(a)') '# iatcell iatom Rlatt_cart(1:3) Rlatt_scaled(1:3)'
1517 [ + + ]: 7324 : do iatom=1,natom
1518 [ + + ]: 23002 : do iatcell=1,natom_unitcell
1519 : : write(unt,'(2(i6,1x),3(f16.10,1x),4x,3(f16.10,1x))') &
1520 : 22956 : & iatcell,iatom,Rlatt_cart(:,iatcell,iatom),Rlatt_scaled(:,iatcell,iatom)
1521 : : end do
1522 : : end do
1523 : 46 : close(unt)
1524 : :
1525 : : end subroutine tdep_write_distance_rlatt
1526 : : !!***
1527 : :
1528 : : !====================================================================================================
1529 : :
1530 [ # # # # : 147072 : end module m_tdep_sampling
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1531 : : !!***
|