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