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