-
Notifications
You must be signed in to change notification settings - Fork 1
/
mscfg_methods.F
503 lines (446 loc) · 24.2 KB
/
mscfg_methods.F
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
!--------------------------------------------------------------------------------------------------!
! CP2K: A general program to perform molecular dynamics simulations !
! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
! !
! SPDX-License-Identifier: GPL-2.0-or-later !
!--------------------------------------------------------------------------------------------------!
! **************************************************************************************************
!> \brief Subroutines to perform calculations on molecules from a bigger
!> system. Useful to generate a high-quality MO guess for systems
!> of many molecules with complex electronic structure, to bootstrap
!> ALMO simulations, etc.
!> \par History
!> 10.2014 Rustam Z Khaliullin
!> 09.2018 ALMO smearing support and ALMO diag+molecular_guess patch [Ruben Staub]
!> \author Rustam Z Khaliullin
! **************************************************************************************************
MODULE mscfg_methods
USE almo_scf_types, ONLY: almo_scf_env_type
USE atomic_kind_types, ONLY: get_atomic_kind
USE cell_types, ONLY: cell_type
USE cp_dbcsr_api, ONLY: dbcsr_copy,&
dbcsr_create,&
dbcsr_type_no_symmetry
USE cp_dbcsr_operations, ONLY: copy_fm_to_dbcsr
USE cp_log_handling, ONLY: cp_get_default_logger,&
cp_logger_get_default_unit_nr,&
cp_logger_type
USE cp_subsys_methods, ONLY: create_small_subsys
USE cp_subsys_types, ONLY: cp_subsys_get,&
cp_subsys_release,&
cp_subsys_type
USE force_env_types, ONLY: force_env_get,&
force_env_type
USE global_types, ONLY: global_environment_type
USE input_constants, ONLY: almo_frz_crystal,&
almo_frz_none,&
do_qs,&
molecular_guess
USE input_section_types, ONLY: section_vals_get_subs_vals,&
section_vals_type,&
section_vals_val_get,&
section_vals_val_set
USE kinds, ONLY: default_string_length
USE message_passing, ONLY: mp_para_env_type
USE molecule_types, ONLY: get_molecule_set_info,&
molecule_type
USE mscfg_types, ONLY: molecular_scf_guess_env_init,&
molecular_scf_guess_env_type,&
mscfg_max_moset_size
USE particle_list_types, ONLY: particle_list_type
USE qs_energy, ONLY: qs_energies
USE qs_energy_types, ONLY: qs_energy_type
USE qs_environment, ONLY: qs_init
USE qs_environment_types, ONLY: get_qs_env,&
qs_env_create,&
qs_env_release,&
qs_environment_type
USE qs_mo_types, ONLY: get_mo_set,&
mo_set_type
#include "./base/base_uses.f90"
IMPLICIT NONE
PRIVATE
CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mscfg_methods'
PUBLIC :: loop_over_molecules, do_mol_loop
CONTAINS
! **************************************************************************************************
!> \brief Prepare data for calculations on isolated molecules.
!> \param globenv ...
!> \param force_env ...
!> \par History
!> 10.2014 created [Rustam Z Khaliullin]
!> \author Rustam Z Khaliullin
! **************************************************************************************************
SUBROUTINE loop_over_molecules(globenv, force_env)
TYPE(global_environment_type), POINTER :: globenv
TYPE(force_env_type), POINTER :: force_env
INTEGER :: nmols
INTEGER, ALLOCATABLE, DIMENSION(:) :: charge_of_frag, first_atom_of_frag, &
last_atom_of_frag, multip_of_frag
TYPE(molecule_type), DIMENSION(:), POINTER :: molecule_set
TYPE(qs_environment_type), POINTER :: qs_env
CALL force_env_get(force_env, qs_env=qs_env)
CPASSERT(ASSOCIATED(qs_env))
CALL get_qs_env(qs_env, &
molecule_set=molecule_set)
nmols = SIZE(molecule_set)
ALLOCATE (first_atom_of_frag(nmols))
ALLOCATE (last_atom_of_frag(nmols))
ALLOCATE (charge_of_frag(nmols))
ALLOCATE (multip_of_frag(nmols))
CALL get_molecule_set_info(molecule_set, &
mol_to_first_atom=first_atom_of_frag, &
mol_to_last_atom=last_atom_of_frag, &
mol_to_charge=charge_of_frag, &
mol_to_multiplicity=multip_of_frag)
CALL calcs_on_isolated_molecules(force_env, globenv, nmols, &
first_atom_of_frag, last_atom_of_frag, charge_of_frag, multip_of_frag)
DEALLOCATE (first_atom_of_frag)
DEALLOCATE (last_atom_of_frag)
DEALLOCATE (charge_of_frag)
DEALLOCATE (multip_of_frag)
END SUBROUTINE loop_over_molecules
! **************************************************************************************************
!> \brief Run calculations on isolated molecules. The ideas for setting up
!> the calculations are borrowed from BSSE files
!> \param force_env ...
!> \param globenv ...
!> \param nfrags ...
!> \param first_atom_of_frag ...
!> \param last_atom_of_frag ...
!> \param charge_of_frag ...
!> \param multip_of_frag ...
!> \par History
!> 10.2014 created
!> 09.2018 ALMO smearing support, and ALMO diag+molecular_guess patch [Ruben Staub]
!> \author Rustam Z Khaliullin
! **************************************************************************************************
SUBROUTINE calcs_on_isolated_molecules(force_env, globenv, nfrags, &
first_atom_of_frag, last_atom_of_frag, charge_of_frag, multip_of_frag)
TYPE(force_env_type), POINTER :: force_env
TYPE(global_environment_type), POINTER :: globenv
INTEGER, INTENT(IN) :: nfrags
INTEGER, DIMENSION(:), INTENT(IN) :: first_atom_of_frag, last_atom_of_frag, &
charge_of_frag, multip_of_frag
CHARACTER(LEN=*), PARAMETER :: routineN = 'calcs_on_isolated_molecules'
CHARACTER(LEN=default_string_length) :: name
CHARACTER(LEN=default_string_length), &
DIMENSION(:), POINTER :: atom_type
INTEGER :: first_atom, force_method, global_charge, global_multpl, handle, i, ifrag, imo, &
isize, j, k, last_atom, my_targ, nb_eigenval_stored, nmo, nmo_of_frag, nmosets_of_frag, &
tot_added_mos, tot_isize
INTEGER, DIMENSION(:), POINTER :: atom_index, atom_list
LOGICAL :: global_almo_scf_keyword, smear_almo_scf
TYPE(almo_scf_env_type), POINTER :: almo_scf_env
TYPE(cell_type), POINTER :: cell
TYPE(cp_subsys_type), POINTER :: subsys, subsys_loc
TYPE(mo_set_type), DIMENSION(:), POINTER :: mos, mos_of_frag
TYPE(molecular_scf_guess_env_type), POINTER :: mscfg_env
TYPE(mp_para_env_type), POINTER :: para_env
TYPE(particle_list_type), POINTER :: particles
TYPE(qs_energy_type), POINTER :: qs_energy
TYPE(qs_environment_type), POINTER :: qs_env, qs_env_loc
TYPE(section_vals_type), POINTER :: dft_section, force_env_section, &
qs_section, root_section, scf_section, &
subsys_section
CALL timeset(routineN, handle)
NULLIFY (subsys_loc, subsys, particles, para_env, cell, atom_index, atom_type, &
force_env_section, qs_env_loc, mscfg_env, qs_env, qs_energy)
CALL force_env_get(force_env, force_env_section=force_env_section, &
qs_env=qs_env)
CALL section_vals_val_get(force_env_section, "METHOD", i_val=force_method)
CPASSERT(force_method .EQ. do_qs)
root_section => force_env%root_section
subsys_section => section_vals_get_subs_vals(force_env_section, "SUBSYS")
dft_section => section_vals_get_subs_vals(force_env_section, "DFT")
!
! Save several global settings to restore them after the loop:
! charge, multiplicity, ALMO flag
!
CALL section_vals_val_get(dft_section, "CHARGE", i_val=global_charge)
CALL section_vals_val_get(dft_section, "MULTIPLICITY", i_val=global_multpl)
qs_section => section_vals_get_subs_vals(dft_section, "QS")
CALL section_vals_val_get(qs_section, "ALMO_SCF", l_val=global_almo_scf_keyword)
!
! Get access to critical data before the loop
!
CALL force_env_get(force_env=force_env, subsys=subsys, para_env=para_env, &
cell=cell)
CALL cp_subsys_get(subsys, particles=particles)
CALL get_qs_env(qs_env, mscfg_env=mscfg_env, almo_scf_env=almo_scf_env)
CPASSERT(ASSOCIATED(mscfg_env))
IF (global_almo_scf_keyword) THEN !! Check if smearing is on, and retrieve smearing parameters accordingly
smear_almo_scf = qs_env%scf_control%smear%do_smear
IF (smear_almo_scf) THEN
scf_section => section_vals_get_subs_vals(dft_section, "SCF")
CALL section_vals_val_get(scf_section, "added_mos", i_val=tot_added_mos) !! Get total number of added MOs
tot_isize = last_atom_of_frag(nfrags) - first_atom_of_frag(1) + 1 !! Get total number of atoms (assume consecutive atoms)
!! Check that number of added MOs matches the number of atoms
!! (to ensure compatibility, since each fragment will be computed with such parameters)
IF (tot_isize .NE. tot_added_mos) THEN
CPABORT("ALMO smearing currently requires ADDED_MOS == total number of atoms")
END IF
!! Get total number of MOs
CALL get_qs_env(qs_env, mos=mos)
IF (SIZE(mos) .GT. 1) CPABORT("Unrestricted ALMO methods are NYI") !! Unrestricted ALMO is not implemented yet
CALL get_mo_set(mo_set=mos(1), nmo=nmo)
!! Initialize storage of MO energies for ALMO smearing
CPASSERT(ASSOCIATED(almo_scf_env))
ALLOCATE (almo_scf_env%mo_energies(nmo, SIZE(mos)))
ALLOCATE (almo_scf_env%kTS(SIZE(mos)))
nb_eigenval_stored = 0 !! Keep track of how many eigenvalues were stored in mo_energies
END IF
ELSE
smear_almo_scf = .FALSE.
END IF
!
! These flags determine the options of molecular runs (e.g. cell size)
!
!!!LATER is_fast_dirty = mscfg_env%is_fast_dirty - shrink the cell
!!!LATER is_crystal = mscfg_env%is_crystal - remove periodicity
!
! Prepare storage for the results
! Until molecular_scf_guess_env is destroyed it will keep
! the results of fragment calculations
!
CALL molecular_scf_guess_env_init(mscfg_env, nfrags)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! Start the loop over molecules
!
! Here is the list of modifications necessary to run isolated molecules:
! * Atom list of a subsystem and their names
! * Charge and multiplicity of a subsystem
! * ALMO SCF flag off (unless several levels of recursion is desired)
! * Smaller cell can be provided if a fast-and-dirty approach is ok
! * Set ADDED_MOS to number of atoms in the fragment, if smearing requested (VASP default)
! * ... add your own and explain it here ...
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
DO ifrag = 1, nfrags
!
! Turn ALMO SCF flag off
!
CALL section_vals_val_set(qs_section, "ALMO_SCF", l_val=.FALSE.)
!
! Setup the charge and multiplicity of the molecule
!
CALL section_vals_val_set(dft_section, "CHARGE", i_val=charge_of_frag(ifrag))
CALL section_vals_val_set(dft_section, "MULTIPLICITY", i_val=multip_of_frag(ifrag))
!
! Create a list of atoms in the current molecule
!
! Assume that atoms arranged consecutively (in ALMO SCF it is always the case)
! It is important to have a linear scaling procedure here
first_atom = first_atom_of_frag(ifrag)
last_atom = last_atom_of_frag(ifrag)
isize = last_atom - first_atom + 1
ALLOCATE (atom_index(isize))
atom_index(1:isize) = (/(i, i=first_atom, last_atom)/)
!
! Get atom type names
!
ALLOCATE (atom_type(isize))
DO j = 1, isize
my_targ = atom_index(j)
DO k = 1, SIZE(particles%els)
CALL get_atomic_kind(particles%els(k)%atomic_kind, atom_list=atom_list, name=name)
IF (ANY(atom_list == my_targ)) EXIT
END DO
atom_type(j) = name
END DO
!
! If smearing requested, setup ADDED_MOS correctly for each fragment (i.e. number of atoms in fragment)
!
IF (smear_almo_scf) THEN
CALL section_vals_val_set(scf_section, "added_mos", i_val=isize)
END IF
!
! Create the environment of a subsystem
!
CALL create_small_subsys(subsys_loc, big_subsys=subsys, &
small_para_env=para_env, small_cell=cell, sub_atom_index=atom_index, &
sub_atom_kind_name=atom_type, para_env=para_env, &
force_env_section=force_env_section, subsys_section=subsys_section)
ALLOCATE (qs_env_loc)
CALL qs_env_create(qs_env_loc, globenv)
CALL qs_init(qs_env_loc, para_env, root_section, globenv=globenv, cp_subsys=subsys_loc, &
force_env_section=force_env_section, subsys_section=subsys_section, &
use_motion_section=.FALSE.)
CALL cp_subsys_release(subsys_loc)
!
! Print-out fragment info
!
CALL print_frag_info(atom_index, atom_type, ifrag, nfrags, &
charge_of_frag(ifrag), multip_of_frag(ifrag))
!
! Run calculations on a subsystem
!
CALL qs_energies(qs_env_loc)
!
! Get the desired results (energy and MOs) out
!
CALL get_qs_env(qs_env_loc, mos=mos_of_frag, energy=qs_energy)
!
! Store all desired results of fragment calculations in the fragment_env
! of the qs_env to use them later as needed
!
mscfg_env%energy_of_frag(ifrag) = qs_energy%total
nmosets_of_frag = SIZE(mos_of_frag)
CPASSERT(nmosets_of_frag .LE. mscfg_max_moset_size)
mscfg_env%nmosets_of_frag(ifrag) = nmosets_of_frag
DO imo = 1, nmosets_of_frag
!! Forcing compatibility for ALMO smearing
IF (global_almo_scf_keyword) THEN
!! Manually add compatibility between ALMO SCF and diag SCF (used for smearing compatibility)
!! MOs are required to compute ALMO orbitals, but not stored with diag SCF algorithm...
!! RS-WARNING: Should be properly fixed, this is just a raw fix.
CALL copy_fm_to_dbcsr(mos_of_frag(imo)%mo_coeff, &
mos_of_frag(imo)%mo_coeff_b)
IF (smear_almo_scf) THEN
!! Store MOs energies for ALMO smearing purpose
nmo_of_frag = SIZE(mos_of_frag(imo)%eigenvalues)
almo_scf_env%mo_energies(nb_eigenval_stored + 1:nb_eigenval_stored + nmo_of_frag, imo) &
= mos_of_frag(imo)%eigenvalues(:)
!! update stored energies offset. Assumes nmosets_of_frag == 1 (general smearing ALMO assumption)
nb_eigenval_stored = nb_eigenval_stored + nmo_of_frag
END IF
END IF !! ALMO
! the matrices have been allocated already - copy the results there
CALL dbcsr_create(mscfg_env%mos_of_frag(ifrag, imo), &
template=mos_of_frag(imo)%mo_coeff_b, &
matrix_type=dbcsr_type_no_symmetry)
CALL dbcsr_copy(mscfg_env%mos_of_frag(ifrag, imo), &
mos_of_frag(imo)%mo_coeff_b)
END DO
!
! Clean up
!
NULLIFY (qs_energy)
CALL qs_env_release(qs_env_loc)
DEALLOCATE (qs_env_loc)
DEALLOCATE (atom_index)
DEALLOCATE (atom_type)
END DO
CALL section_vals_val_set(dft_section, "CHARGE", i_val=global_charge)
CALL section_vals_val_set(dft_section, "MULTIPLICITY", i_val=global_multpl)
CALL section_vals_val_set(qs_section, "ALMO_SCF", l_val=global_almo_scf_keyword)
CALL timestop(handle)
END SUBROUTINE calcs_on_isolated_molecules
! **************************************************************************************************
!> \brief Print info about fragment
!> \param atom_index ...
!> \param atom_type ...
!> \param frag ...
!> \param nfrags ...
!> \param charge ...
!> \param multpl ...
!> \par History
!> 07.2005 created as a part of BSSE calculations [tlaino]
!> 10.2014 adapted to ALMO guess calculations [Rustam Z Khaliullin]
!> \author Rustam Z Khaliullin
! **************************************************************************************************
SUBROUTINE print_frag_info(atom_index, atom_type, frag, nfrags, charge, &
multpl)
INTEGER, DIMENSION(:), POINTER :: atom_index
CHARACTER(len=default_string_length), &
DIMENSION(:), POINTER :: atom_type
INTEGER, INTENT(IN) :: frag, nfrags, charge, multpl
CHARACTER(len=11) :: charI
INTEGER :: i, iw
TYPE(cp_logger_type), POINTER :: logger
NULLIFY (logger)
logger => cp_get_default_logger()
IF (logger%para_env%is_source()) THEN
iw = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
ELSE
iw = -1
END IF
IF (iw > 0) THEN
WRITE (UNIT=iw, FMT="(/,T2,A)") REPEAT("-", 79)
WRITE (UNIT=iw, FMT="(T2,A,T80,A)") "-", "-"
WRITE (UNIT=iw, FMT="(T2,A,T5,A,T25,A,T40,I11,T53,A,T67,I11,T80,A)") &
"-", "MOLECULAR GUESS:", "FRAGMENT", frag, "OUT OF", nfrags, "-"
WRITE (UNIT=iw, FMT="(T2,A,T25,A,T40,I11,T53,A,T67,I11,T80,A)") "-", "CHARGE", charge, "MULTIPLICITY", &
multpl, "-"
WRITE (UNIT=iw, FMT="(T2,A,T80,A)") "-", "-"
WRITE (UNIT=iw, FMT="(T2,A,T25,A,T53,A,T80,A)") "-", "ATOM INDEX", "ATOM NAME", "-"
WRITE (UNIT=iw, FMT="(T2,A,T25,A,T53,A,T80,A)") "-", "----------", "---------", "-"
DO i = 1, SIZE(atom_index)
WRITE (charI, '(I11)') atom_index(i)
WRITE (UNIT=iw, FMT="(T2,A,T25,A,T53,A,T80,A)") "-", ADJUSTL(charI), TRIM(atom_type(i)), "-"
END DO
WRITE (UNIT=iw, FMT="(T2,A)") REPEAT("-", 79)
END IF
END SUBROUTINE print_frag_info
! **************************************************************************************************
!> \brief Is the loop over molecules requested?
!> \param force_env ...
!> \return ...
!> \par History
!> 10.2014 created [Rustam Z. Khaliullin]
!> \author Rustam Z. Khaliullin
! **************************************************************************************************
FUNCTION do_mol_loop(force_env)
TYPE(force_env_type), POINTER :: force_env
LOGICAL :: do_mol_loop
INTEGER :: almo_guess_type, frz_term_type, &
method_name_id, scf_guess_type
LOGICAL :: almo_scf_is_on, is_crystal, is_fast_dirty
TYPE(molecular_scf_guess_env_type), POINTER :: mscfg_env
TYPE(qs_environment_type), POINTER :: qs_env
TYPE(section_vals_type), POINTER :: force_env_section, subsection
do_mol_loop = .FALSE.
! What kind of options are we using in the loop ?
is_fast_dirty = .TRUE.
is_crystal = .FALSE.
almo_scf_is_on = .FALSE.
NULLIFY (qs_env, mscfg_env, force_env_section, subsection)
CALL force_env_get(force_env, force_env_section=force_env_section)
CALL section_vals_val_get(force_env_section, "METHOD", i_val=method_name_id)
IF (method_name_id .EQ. do_qs) THEN
CALL force_env_get(force_env, qs_env=qs_env)
CPASSERT(ASSOCIATED(qs_env))
CALL get_qs_env(qs_env, mscfg_env=mscfg_env)
CPASSERT(ASSOCIATED(mscfg_env))
!!!! RZK-warning: All decisions are based on the values of input keywords
!!!! The real danger is that many of these keywords might not be even
!!!! in control of the job. They might be simply present in the input
!!!! This section must be re-written more accurately
! check ALMO SCF guess option
NULLIFY (subsection)
subsection => section_vals_get_subs_vals(force_env_section, "DFT%ALMO_SCF")
CALL section_vals_val_get(subsection, "ALMO_SCF_GUESS", i_val=almo_guess_type)
! check whether ALMO SCF is on
NULLIFY (subsection)
subsection => section_vals_get_subs_vals(force_env_section, "DFT%QS")
CALL section_vals_val_get(subsection, "ALMO_SCF", l_val=almo_scf_is_on)
! check SCF guess option
NULLIFY (subsection)
subsection => section_vals_get_subs_vals(force_env_section, "DFT%SCF")
CALL section_vals_val_get(subsection, "SCF_GUESS", i_val=scf_guess_type)
! check ALMO EDA options
NULLIFY (subsection)
!!!LATER subsection => section_vals_get_subs_vals(force_env_section,"DFT%ALMO_SCF%ALMO_DA")
!!!LATER CALL section_vals_val_get(subsection,"FRZ_TERM",i_val=frz_term_type)
frz_term_type = almo_frz_none
! Are we doing the loop ?
IF (scf_guess_type .EQ. molecular_guess .OR. & ! SCF guess is molecular
(almo_guess_type .EQ. molecular_guess .AND. almo_scf_is_on) .OR. & ! ALMO SCF guess is molecular
frz_term_type .NE. almo_frz_none) THEN ! ALMO FRZ term is requested
do_mol_loop = .TRUE.
! If we are calculating molecular guess it is OK to do fast and dirty loop
! It is NOT ok to be sloppy with ALMO EDA calculations of the FRZ term
IF (frz_term_type .NE. almo_frz_none) THEN
is_fast_dirty = .FALSE.
IF (frz_term_type .EQ. almo_frz_crystal) THEN
is_crystal = .TRUE.
END IF
END IF
END IF
mscfg_env%is_fast_dirty = is_fast_dirty
mscfg_env%is_crystal = is_crystal
END IF
RETURN
END FUNCTION do_mol_loop
END MODULE mscfg_methods