LCOV - code coverage report
Current view: top level - src/motion - gopt_f_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 99.6 % 488 486
Test Date: 2026-10-15 00:55:44 Functions: 100.0 % 21 21

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief contains a functional that calculates the energy and its derivatives
      10              : !>      for the geometry optimizer
      11              : !> \par History
      12              : !>      none
      13              : ! **************************************************************************************************
      14              : MODULE gopt_f_methods
      15              : 
      16              :    USE atomic_kind_list_types,          ONLY: atomic_kind_list_type
      17              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      18              :                                               get_atomic_kind_set
      19              :    USE bibliography,                    ONLY: Henkelman1999,&
      20              :                                               cite_reference
      21              :    USE cell_methods,                    ONLY: cell_create,&
      22              :                                               init_cell,&
      23              :                                               write_cell
      24              :    USE cell_opt_utils,                  ONLY: cell_opt_constraint_label,&
      25              :                                               get_dg_dh,&
      26              :                                               rescale_new_cell_volume
      27              :    USE cell_types,                      ONLY: cell_copy,&
      28              :                                               cell_release,&
      29              :                                               cell_type,&
      30              :                                               real_to_scaled,&
      31              :                                               scaled_to_real
      32              :    USE cp_log_handling,                 ONLY: cp_to_string
      33              :    USE cp_subsys_types,                 ONLY: cp_subsys_get,&
      34              :                                               cp_subsys_set,&
      35              :                                               cp_subsys_type,&
      36              :                                               pack_subsys_particles,&
      37              :                                               unpack_subsys_particles
      38              :    USE cp_units,                        ONLY: cp_unit_from_cp2k
      39              :    USE dimer_methods,                   ONLY: cp_eval_at_ts
      40              :    USE dimer_types,                     ONLY: dimer_env_type
      41              :    USE dimer_utils,                     ONLY: update_dimer_vec
      42              :    USE distribution_1d_types,           ONLY: distribution_1d_type
      43              :    USE force_env_methods,               ONLY: force_env_calc_energy_force
      44              :    USE force_env_types,                 ONLY: force_env_get,&
      45              :                                               force_env_get_natom,&
      46              :                                               force_env_get_nparticle,&
      47              :                                               force_env_type,&
      48              :                                               use_qmmm,&
      49              :                                               use_qmmmx
      50              :    USE gopt_f_types,                    ONLY: gopt_f_type
      51              :    USE gopt_param_types,                ONLY: gopt_param_type
      52              :    USE input_constants,                 ONLY: default_cell_method_id,&
      53              :                                               default_minimization_method_id,&
      54              :                                               default_shellcore_method_id,&
      55              :                                               default_ts_method_id,&
      56              :                                               fix_none
      57              :    USE input_cp2k_restarts,             ONLY: write_restart
      58              :    USE input_section_types,             ONLY: section_vals_type,&
      59              :                                               section_vals_val_get
      60              :    USE kinds,                           ONLY: default_string_length,&
      61              :                                               dp,&
      62              :                                               int_8
      63              :    USE machine,                         ONLY: m_flush
      64              :    USE md_energies,                     ONLY: sample_memory
      65              :    USE message_passing,                 ONLY: mp_para_env_type
      66              :    USE motion_utils,                    ONLY: write_simulation_cell,&
      67              :                                               write_stress_tensor_to_file,&
      68              :                                               write_trajectory
      69              :    USE particle_list_types,             ONLY: particle_list_type
      70              :    USE particle_methods,                ONLY: write_final_structure,&
      71              :                                               write_structure_data
      72              :    USE particle_types,                  ONLY: particle_type
      73              :    USE qmmm_util,                       ONLY: apply_qmmm_translate
      74              :    USE qmmmx_util,                      ONLY: apply_qmmmx_translate
      75              :    USE space_groups,                    ONLY: spgr_apply_rotations_force,&
      76              :                                               spgr_apply_rotations_stress,&
      77              :                                               spgr_project_cell_metric,&
      78              :                                               spgr_write_stress_tensor
      79              :    USE space_groups_types,              ONLY: spgr_type
      80              :    USE virial_methods,                  ONLY: virial_evaluate,&
      81              :                                               virial_update
      82              :    USE virial_types,                    ONLY: virial_type
      83              : #include "../base/base_uses.f90"
      84              : 
      85              :    IMPLICIT NONE
      86              :    PRIVATE
      87              : 
      88              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'gopt_f_methods'
      89              :    INTEGER(KIND=int_8), PARAMETER, PRIVATE :: bytes_per_mib = 1024*1024
      90              : 
      91              :    PUBLIC :: cp_eval_at, &
      92              :              gopt_f_create_x0, &
      93              :              print_geo_opt_header, print_geo_opt_nc, &
      94              :              gopt_f_io_init, gopt_f_io, gopt_f_io_finalize, gopt_f_ii, &
      95              :              apply_cell_change
      96              : 
      97              : CONTAINS
      98              : 
      99              : ! **************************************************************************************************
     100              : !> \brief returns the value of the parameters for the actual configuration
     101              : !> \param gopt_env the geometry optimization environment you want the info about
     102              : !>      x0: the parameter vector (is allocated by this routine)
     103              : !> \param x0 ...
     104              : !> \par History
     105              : !>      - Cell optimization revised (06.11.2012,MK)
     106              : ! **************************************************************************************************
     107         1119 :    SUBROUTINE gopt_f_create_x0(gopt_env, x0)
     108              : 
     109              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
     110              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: x0
     111              : 
     112              :       INTEGER                                            :: i, idg, j, nparticle
     113              :       TYPE(cell_type), POINTER                           :: cell
     114              :       TYPE(cp_subsys_type), POINTER                      :: subsys
     115              : 
     116         1119 :       NULLIFY (cell)
     117         1119 :       NULLIFY (subsys)
     118              : 
     119         2004 :       SELECT CASE (gopt_env%type_id)
     120              :       CASE (default_minimization_method_id, default_ts_method_id)
     121          885 :          CALL force_env_get(gopt_env%force_env, subsys=subsys)
     122              :          ! before starting we handle the case of translating coordinates (QM/MM)
     123          885 :          CALL apply_qmmm_translation(gopt_env)
     124          885 :          nparticle = force_env_get_nparticle(gopt_env%force_env)
     125         2655 :          ALLOCATE (x0(3*nparticle))
     126          885 :          CALL pack_subsys_particles(subsys=subsys, r=x0)
     127              :       CASE (default_cell_method_id)
     128          234 :          CALL force_env_get(gopt_env%force_env, subsys=subsys, cell=cell)
     129              :          ! Store reference cell
     130         6084 :          gopt_env%h_ref = cell%hmat
     131              :          ! before starting we handle the case of translating coordinates (QM/MM)
     132          234 :          CALL apply_qmmm_translation(gopt_env)
     133          234 :          nparticle = force_env_get_nparticle(gopt_env%force_env)
     134          702 :          ALLOCATE (x0(3*nparticle + 6))
     135          234 :          CALL pack_subsys_particles(subsys=subsys, r=x0)
     136          234 :          idg = 3*nparticle
     137          936 :          DO i = 1, 3
     138         2340 :             DO j = 1, i
     139         1404 :                idg = idg + 1
     140         2106 :                x0(idg) = gopt_env%cell_env%opt_cell%hmat(j, i)
     141              :             END DO
     142              :          END DO
     143              :       CASE DEFAULT
     144         1119 :          CPABORT("Invalid or not yet implemented type of optimization")
     145              :       END SELECT
     146              : 
     147         1119 :    END SUBROUTINE gopt_f_create_x0
     148              : 
     149              : ! **************************************************************************************************
     150              : !> \brief Apply the QM/MM and QM/MM/X coordinate translations before packing x0
     151              : !> \param gopt_env ...
     152              : ! **************************************************************************************************
     153         1119 :    SUBROUTINE apply_qmmm_translation(gopt_env)
     154              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
     155              : 
     156         1119 :       IF (gopt_env%force_env%in_use == use_qmmm) THEN
     157           36 :          CALL apply_qmmm_translate(gopt_env%force_env%qmmm_env)
     158              :       END IF
     159         1119 :       IF (gopt_env%force_env%in_use == use_qmmmx) THEN
     160            0 :          CALL apply_qmmmx_translate(gopt_env%force_env%qmmmx_env)
     161              :       END IF
     162         1119 :    END SUBROUTINE apply_qmmm_translation
     163              : 
     164              : ! **************************************************************************************************
     165              : !> \brief evaluete the potential energy and its gradients using an array
     166              : !>      with same dimension as the particle_set
     167              : !> \param gopt_env the geometry optimization environment
     168              : !> \param x the position where the function should be evaluated
     169              : !> \param f the function value
     170              : !> \param gradient the value of its gradient
     171              : !> \param master ...
     172              : !> \param para_env ...
     173              : !> \par History
     174              : !>       CELL OPTIMIZATION:  Teodoro Laino [tlaino] - University of Zurich - 03.2008
     175              : !>       07.2020 Pierre Cazade [pcazade] Space Group Symmetry
     176              : !> \author Teodoro Laino [tlaino] - University of Zurich - 01.2008
     177              : ! **************************************************************************************************
     178        17041 :    SUBROUTINE cp_eval_at(gopt_env, x, f, gradient, master, &
     179              :                          para_env)
     180              : 
     181              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
     182              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: x
     183              :       REAL(KIND=dp), INTENT(OUT), OPTIONAL               :: f
     184              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER     :: gradient
     185              :       INTEGER, INTENT(IN)                                :: master
     186              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     187              : 
     188              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cp_eval_at'
     189              : 
     190              :       INTEGER                                            :: handle, idg, idir, ip, nparticle, nsize, &
     191              :                                                             shell_index
     192              :       REAL(KIND=dp)                                      :: f_ts
     193              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: av_ptens, av_ptens_opt
     194        17041 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: cell_gradient, gradient_ts
     195              :       TYPE(cell_type), POINTER                           :: cell
     196              :       TYPE(cp_subsys_type), POINTER                      :: subsys
     197              :       TYPE(particle_list_type), POINTER                  :: core_particles, particles, &
     198              :                                                             shell_particles
     199              :       TYPE(spgr_type), POINTER                           :: spgr
     200              :       TYPE(virial_type), POINTER                         :: virial
     201              : 
     202        17041 :       NULLIFY (cell)
     203        17041 :       NULLIFY (core_particles)
     204        17041 :       NULLIFY (gradient_ts)
     205        17041 :       NULLIFY (particles)
     206        17041 :       NULLIFY (shell_particles)
     207        17041 :       NULLIFY (subsys)
     208        17041 :       NULLIFY (virial)
     209        17041 :       NULLIFY (spgr)
     210              : 
     211        17041 :       CALL timeset(routineN, handle)
     212              : 
     213        17041 :       CALL force_env_get(gopt_env%force_env, subsys=subsys, cell=cell)
     214              :       CALL cp_subsys_get(subsys, &
     215              :                          core_particles=core_particles, &
     216              :                          particles=particles, &
     217              :                          shell_particles=shell_particles, &
     218        17041 :                          virial=virial)
     219              : 
     220        17041 :       spgr => gopt_env%spgr
     221              : 
     222        25442 :       SELECT CASE (gopt_env%type_id)
     223              :       CASE (default_minimization_method_id, default_ts_method_id)
     224         8401 :          CALL unpack_subsys_particles(subsys=subsys, r=x)
     225         8401 :          CALL write_structure_data(particles%els, cell, gopt_env%motion_section)
     226        15014 :          SELECT CASE (gopt_env%type_id)
     227              :          CASE (default_minimization_method_id)
     228              :             ! Geometry Minimization
     229              :             CALL force_env_calc_energy_force(gopt_env%force_env, &
     230              :                                              calc_force=PRESENT(gradient), &
     231         6613 :                                              require_consistent_energy_force=gopt_env%require_consistent_energy_force)
     232              :             ! Possibly take the potential energy
     233         6613 :             IF (PRESENT(f)) THEN
     234         6613 :                CALL force_env_get(gopt_env%force_env, potential_energy=f)
     235              :             END IF
     236              :             ! Possibly take the gradients
     237         6613 :             IF (PRESENT(gradient)) THEN
     238         6075 :                IF (master == para_env%mepos) THEN ! we are on the master
     239         5924 :                   CALL pack_subsys_particles(subsys=subsys, f=gradient, fscale=-1.0_dp)
     240         5924 :                   IF (spgr%keep_space_group) THEN
     241            8 :                      CALL spgr_apply_rotations_force(spgr, gradient)
     242            8 :                      CALL unpack_subsys_particles(subsys=subsys, f=gradient, fscale=-1.0_dp)
     243              :                   END IF
     244              :                END IF
     245              :             END IF
     246              :          CASE (default_ts_method_id)
     247              :             ! Transition State Optimization
     248         5364 :             ALLOCATE (gradient_ts(particles%n_els*3))
     249              :             ! Real calculation of energy and forces for transition state optimization:
     250              :             ! When doing dimer methods forces have to be always computed since the function
     251              :             ! to minimize is not the energy but the effective force
     252         1788 :             CALL cp_eval_at_ts(gopt_env, x, f_ts, gradient_ts, calc_force=.TRUE.)
     253         1788 :             CALL cite_reference(Henkelman1999)
     254              :             ! Possibly take the potential energy
     255         1788 :             IF (PRESENT(f)) f = f_ts
     256              :             ! Possibly take the gradients
     257         1788 :             IF (PRESENT(gradient)) THEN
     258          844 :                IF (master == para_env%mepos) THEN ! we are on the master
     259          844 :                   CPASSERT(ASSOCIATED(gradient))
     260        29420 :                   gradient = gradient_ts
     261              :                END IF
     262              :             END IF
     263        10189 :             DEALLOCATE (gradient_ts)
     264              :          END SELECT
     265              :          ! This call is necessary for QM/MM if a Translation is applied
     266              :          ! this makes the geometry optimizer consistent
     267         8401 :          CALL unpack_subsys_particles(subsys=subsys, r=x)
     268              :       CASE (default_cell_method_id)
     269              :          ! Check for VIRIAL
     270         8320 :          IF (.NOT. virial%pv_availability) THEN
     271              :             CALL cp_abort(__LOCATION__, &
     272              :                           "For the CELL_OPT task, the FORCE_EVAL/STRESS_TENSOR "// &
     273              :                           "keyword MUST be defined in the input file for the "// &
     274            0 :                           "evaluation of the stress tensor, but none is found!")
     275              :          END IF
     276         8320 :          IF (gopt_env%cell_env%keep_volume) THEN
     277         2284 :             nparticle = force_env_get_nparticle(gopt_env%force_env)
     278         2284 :             idg = 3*nparticle
     279         2284 :             CALL rescale_new_cell_volume(cell%deth, x, idg)
     280              :          END IF
     281              : 
     282         8320 :          CALL apply_cell_change(gopt_env, cell, x, update_forces=.FALSE.)
     283              :          ! Possibly output the new cell used for the next calculation
     284         8320 :          CALL write_cell(cell, gopt_env%geo_section)
     285              :          ! Compute the pressure tensor
     286         8320 :          BLOCK
     287              :             TYPE(virial_type) :: virial_avg
     288              :             CALL force_env_calc_energy_force(gopt_env%force_env, &
     289              :                                              calc_force=PRESENT(gradient), &
     290         8320 :                                              require_consistent_energy_force=gopt_env%require_consistent_energy_force)
     291              :             ! Possibly take the potential energy
     292         8320 :             virial_avg = virial
     293         8320 :             CALL virial_update(virial_avg, subsys, para_env)
     294         8320 :             IF (PRESENT(f)) THEN
     295         8320 :                CALL force_env_get(gopt_env%force_env, potential_energy=f)
     296              :             END IF
     297              :             ! Possibly take the gradients
     298      2063360 :             IF (PRESENT(gradient)) THEN
     299         6992 :                CPASSERT(ANY(virial_avg%pv_total /= 0))
     300              :                ! Convert the average ptens
     301        90896 :                av_ptens(:, :) = virial_avg%pv_total(:, :)/cell%deth
     302         6992 :                IF (master == para_env%mepos) THEN ! we are on the master
     303         5333 :                   CPASSERT(ASSOCIATED(gradient))
     304         5333 :                   nparticle = force_env_get_nparticle(gopt_env%force_env)
     305         5333 :                   nsize = 3*nparticle
     306         5333 :                   CPASSERT((SIZE(gradient) == nsize + 6))
     307         5333 :                   CALL pack_subsys_particles(subsys=subsys, f=gradient(1:nsize), fscale=-1.0_dp)
     308         5333 :                   CALL apply_cell_change(gopt_env, cell, gradient, update_forces=.TRUE.)
     309         5333 :                   IF (spgr%keep_space_group) THEN
     310          556 :                      CALL spgr_apply_rotations_force(spgr, gradient)
     311          556 :                      CALL spgr_apply_rotations_stress(spgr, cell, av_ptens)
     312          556 :                      CALL spgr_write_stress_tensor(av_ptens, spgr)
     313              :                   END IF
     314         5333 :                   cell_gradient => gradient(nsize + 1:nsize + 6)
     315        37331 :                   cell_gradient = 0.0_dp
     316              :                   av_ptens_opt = MATMUL(gopt_env%cell_env%input_to_opt, &
     317       421307 :                                         MATMUL(av_ptens, gopt_env%cell_env%opt_to_input))
     318              :                   CALL get_dg_dh(cell_gradient, av_ptens_opt, gopt_env%cell_env%pres_ext, &
     319              :                                  gopt_env%cell_env%opt_cell, gopt_env%cell_env%mtrx, &
     320              :                                  keep_angles=gopt_env%cell_env%keep_angles, &
     321              :                                  keep_symmetry=gopt_env%cell_env%keep_symmetry, &
     322              :                                  pres_int=gopt_env%cell_env%pres_int, &
     323              :                                  pres_constr=gopt_env%cell_env%pres_constr, &
     324         5333 :                                  constraint_id=gopt_env%cell_env%constraint_id)
     325              :                END IF
     326              :                ! some callers expect pres_int to be available on all ranks. Also, here master is not necessarily a single rank.
     327              :                ! Assume at least master==0
     328         6992 :                CALL para_env%bcast(gopt_env%cell_env%pres_int, 0)
     329         6992 :                IF (gopt_env%cell_env%constraint_id /= fix_none) THEN
     330          296 :                   CALL para_env%bcast(gopt_env%cell_env%pres_constr, 0)
     331              :                END IF
     332              :             END IF
     333              :          END BLOCK
     334              :       CASE (default_shellcore_method_id)
     335              :          idg = 0
     336        31040 :          DO ip = 1, particles%n_els
     337        30720 :             shell_index = particles%els(ip)%shell_index
     338        31040 :             IF (shell_index /= 0) THEN
     339       122880 :                DO idir = 1, 3
     340        92160 :                   idg = 3*(shell_index - 1) + idir
     341       122880 :                   shell_particles%els(shell_index)%r(idir) = core_particles%els(ip)%r(idir) - x(idg)
     342              :                END DO
     343              :             END IF
     344              :          END DO
     345          320 :          CALL write_structure_data(particles%els, cell, gopt_env%motion_section)
     346              : 
     347              :          ! Shell-core optimization
     348              :          CALL force_env_calc_energy_force(gopt_env%force_env, &
     349              :                                           calc_force=PRESENT(gradient), &
     350          320 :                                           require_consistent_energy_force=gopt_env%require_consistent_energy_force)
     351              : 
     352              :          ! Possibly take the potential energy
     353          320 :          IF (PRESENT(f)) THEN
     354          320 :             CALL force_env_get(gopt_env%force_env, potential_energy=f)
     355              :          END IF
     356              : 
     357              :          ! Possibly take the gradients
     358          320 :          IF (PRESENT(gradient)) THEN
     359          320 :             IF (master == para_env%mepos) THEN ! we are on the master
     360          320 :                CPASSERT(ASSOCIATED(gradient))
     361          320 :                idg = 0
     362        31040 :                DO ip = 1, shell_particles%n_els
     363       123200 :                   DO idir = 1, 3
     364        92160 :                      idg = idg + 1
     365       122880 :                      gradient(idg) = -(core_particles%els(ip)%f(idir) - shell_particles%els(ip)%f(idir))
     366              :                   END DO
     367              :                END DO
     368              :             END IF
     369              :          END IF
     370              :       CASE DEFAULT
     371        17041 :          CPABORT("Invalid or not yet implemented type of optimization")
     372              :       END SELECT
     373              : 
     374        17041 :       CALL timestop(handle)
     375              : 
     376        17041 :    END SUBROUTINE cp_eval_at
     377              : 
     378              : ! **************************************************************************************************
     379              : !> \brief Prints iteration step of the optimization procedure on screen
     380              : !> \param its ...
     381              : !> \param output_unit ...
     382              : !> \author Teodoro Laino [tlaino] - University of Zurich - 03.2008
     383              : ! **************************************************************************************************
     384         9272 :    SUBROUTINE gopt_f_ii(its, output_unit)
     385              : 
     386              :       INTEGER, INTENT(IN)                                :: its, output_unit
     387              : 
     388         9272 :       IF (output_unit > 0) THEN
     389         4796 :          WRITE (UNIT=output_unit, FMT="(/,T2,26('-'))")
     390         4796 :          WRITE (UNIT=output_unit, FMT="(T2,A,I6)") "OPTIMIZATION STEP: ", its
     391         4796 :          WRITE (UNIT=output_unit, FMT="(T2,26('-'))")
     392         4796 :          CALL m_flush(output_unit)
     393              :       END IF
     394              : 
     395         9272 :    END SUBROUTINE gopt_f_ii
     396              : 
     397              : ! **************************************************************************************************
     398              : !> \brief Retrieves the reporting metadata used during an optimization step.
     399              : !> \param gopt_env Optimization environment supplying print configuration and units
     400              : !> \param force_env Force environment used for memory sampling
     401              : !> \param max_memory Sampled memory, or zero if memory reporting is disabled
     402              : !> \param energy_unit Energy reporting unit
     403              : !> \param stress_unit Stress reporting unit
     404              : ! **************************************************************************************************
     405        10433 :    SUBROUTINE get_reporting_metadata(gopt_env, force_env, max_memory, energy_unit, stress_unit)
     406              : 
     407              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
     408              :       TYPE(force_env_type), POINTER                      :: force_env
     409              :       INTEGER(KIND=int_8), INTENT(OUT)                   :: max_memory
     410              :       CHARACTER(LEN=default_string_length), INTENT(OUT)  :: energy_unit, stress_unit
     411              : 
     412              :       LOGICAL                                            :: print_memory
     413              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     414              : 
     415        10433 :       NULLIFY (para_env)
     416        10433 :       CALL section_vals_val_get(gopt_env%motion_section, "PRINT%MEMORY_INFO", l_val=print_memory)
     417        10433 :       max_memory = 0
     418        10433 :       IF (print_memory) THEN
     419        10433 :          CALL force_env_get(force_env, para_env=para_env)
     420        10433 :          max_memory = sample_memory(para_env)
     421              :       END IF
     422              : 
     423              :       CALL section_vals_val_get(gopt_env%force_env%force_env_section, &
     424              :                                 "PRINT%PROGRAM_RUN_INFO%ENERGY_UNIT", &
     425        10433 :                                 c_val=energy_unit)
     426              :       CALL section_vals_val_get(gopt_env%force_env%force_env_section, &
     427              :                                 "PRINT%STRESS_TENSOR%STRESS_UNIT", &
     428        10433 :                                 c_val=stress_unit)
     429              : 
     430        10433 :    END SUBROUTINE get_reporting_metadata
     431              : 
     432              : ! **************************************************************************************************
     433              : !> \brief Handles the Output during an optimization run
     434              : !> \param gopt_env ...
     435              : !> \param output_unit ...
     436              : !> \param opt_energy ...
     437              : !> \param wildcard ...
     438              : !> \param its ...
     439              : !> \param used_time ...
     440              : !> \author Teodoro Laino [tlaino] - University of Zurich - 03.2008
     441              : ! **************************************************************************************************
     442         1163 :    SUBROUTINE gopt_f_io_init(gopt_env, output_unit, opt_energy, wildcard, its, used_time)
     443              : 
     444              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
     445              :       INTEGER, INTENT(IN)                                :: output_unit
     446              :       REAL(KIND=dp)                                      :: opt_energy
     447              :       CHARACTER(LEN=5)                                   :: wildcard
     448              :       INTEGER, INTENT(IN)                                :: its
     449              :       REAL(KIND=dp)                                      :: used_time
     450              : 
     451              :       CHARACTER(LEN=default_string_length)               :: energy_unit, stress_unit
     452              :       INTEGER(KIND=int_8)                                :: max_memory
     453              :       REAL(KIND=dp)                                      :: pres_int
     454              : 
     455         1163 :       CALL get_reporting_metadata(gopt_env, gopt_env%force_env, max_memory, energy_unit, stress_unit)
     456              : 
     457         2130 :       SELECT CASE (gopt_env%type_id)
     458              :       CASE (default_ts_method_id, default_minimization_method_id)
     459              :          ! Geometry Optimization (Minimization and Transition State Search)
     460          967 :          IF (.NOT. gopt_env%dimer_rotation) THEN
     461              :             CALL write_cycle_infos(output_unit, &
     462              :                                    it=its, &
     463              :                                    etot=opt_energy, &
     464              :                                    wildcard=wildcard, &
     465              :                                    used_time=used_time, &
     466              :                                    max_memory=max_memory, &
     467              :                                    energy_unit=energy_unit, &
     468          839 :                                    stress_unit=stress_unit)
     469              :          ELSE
     470              :             CALL write_rot_cycle_infos(output_unit, &
     471              :                                        it=its, &
     472              :                                        etot=opt_energy, &
     473              :                                        dimer_env=gopt_env%dimer_env, &
     474              :                                        wildcard=wildcard, &
     475              :                                        used_time=used_time, &
     476          128 :                                        max_memory=max_memory)
     477              :          END IF
     478              :       CASE (default_cell_method_id)
     479              :          ! Cell Optimization
     480          176 :          pres_int = gopt_env%cell_env%pres_int
     481              :          CALL write_cycle_infos(output_unit, &
     482              :                                 it=its, &
     483              :                                 etot=opt_energy, &
     484              :                                 pres_int=pres_int, &
     485              :                                 wildcard=wildcard, &
     486              :                                 used_time=used_time, &
     487              :                                 max_memory=max_memory, &
     488              :                                 energy_unit=energy_unit, &
     489          176 :                                 stress_unit=stress_unit)
     490              :       CASE (default_shellcore_method_id)
     491              :          CALL write_cycle_infos(output_unit, &
     492              :                                 it=its, &
     493              :                                 etot=opt_energy, &
     494              :                                 wildcard=wildcard, &
     495              :                                 used_time=used_time, &
     496              :                                 max_memory=max_memory, &
     497              :                                 energy_unit=energy_unit, &
     498         1163 :                                 stress_unit=stress_unit)
     499              :       END SELECT
     500              : 
     501         1163 :    END SUBROUTINE gopt_f_io_init
     502              : 
     503              : ! **************************************************************************************************
     504              : !> \brief Handles the Output during an optimization run
     505              : !> \param gopt_env ...
     506              : !> \param force_env ...
     507              : !> \param root_section ...
     508              : !> \param its ...
     509              : !> \param opt_energy ...
     510              : !> \param output_unit ...
     511              : !> \param eold ...
     512              : !> \param emin ...
     513              : !> \param wildcard ...
     514              : !> \param gopt_param ...
     515              : !> \param ndf ...
     516              : !> \param dx ...
     517              : !> \param xi ...
     518              : !> \param conv ...
     519              : !> \param pred ...
     520              : !> \param rat ...
     521              : !> \param step ...
     522              : !> \param rad ...
     523              : !> \param used_time ...
     524              : !> \author Teodoro Laino [tlaino] - University of Zurich - 03.2008
     525              : ! **************************************************************************************************
     526        18540 :    SUBROUTINE gopt_f_io(gopt_env, force_env, root_section, its, opt_energy, &
     527         9270 :                         output_unit, eold, emin, wildcard, gopt_param, ndf, dx, xi, conv, pred, rat, &
     528              :                         step, rad, used_time)
     529              : 
     530              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
     531              :       TYPE(force_env_type), POINTER                      :: force_env
     532              :       TYPE(section_vals_type), POINTER                   :: root_section
     533              :       INTEGER, INTENT(IN)                                :: its
     534              :       REAL(KIND=dp), INTENT(IN)                          :: opt_energy
     535              :       INTEGER, INTENT(IN)                                :: output_unit
     536              :       REAL(KIND=dp)                                      :: eold, emin
     537              :       CHARACTER(LEN=5)                                   :: wildcard
     538              :       TYPE(gopt_param_type), POINTER                     :: gopt_param
     539              :       INTEGER, INTENT(IN), OPTIONAL                      :: ndf
     540              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: dx
     541              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER     :: xi
     542              :       LOGICAL, OPTIONAL                                  :: conv
     543              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: pred, rat, step, rad
     544              :       REAL(KIND=dp)                                      :: used_time
     545              : 
     546              :       CHARACTER(LEN=default_string_length)               :: energy_unit, stress_unit
     547              :       INTEGER(KIND=int_8)                                :: max_memory
     548              :       REAL(KIND=dp)                                      :: pres_diff, pres_diff_constr, pres_int, &
     549              :                                                             pres_tol
     550              : 
     551         9270 :       CALL get_reporting_metadata(gopt_env, force_env, max_memory, energy_unit, stress_unit)
     552              : 
     553        14346 :       SELECT CASE (gopt_env%type_id)
     554              :       CASE (default_ts_method_id, default_minimization_method_id)
     555              :          ! Geometry Optimization (Minimization and Transition State Search)
     556         5076 :          IF (.NOT. gopt_env%dimer_rotation) THEN
     557              :             CALL geo_opt_io(force_env=force_env, root_section=root_section, &
     558         4354 :                             motion_section=gopt_env%motion_section, its=its, opt_energy=opt_energy)
     559              :             CALL write_cycle_infos(output_unit, &
     560              :                                    it=its, &
     561              :                                    etot=opt_energy, &
     562              :                                    ediff=(opt_energy - eold), &
     563              :                                    pred=pred, &
     564              :                                    rat=rat, &
     565              :                                    step=step, &
     566              :                                    rad=rad, &
     567              :                                    emin=emin, &
     568              :                                    wildcard=wildcard, &
     569              :                                    used_time=used_time, &
     570              :                                    max_memory=max_memory, &
     571              :                                    energy_unit=energy_unit, &
     572         4354 :                                    stress_unit=stress_unit)
     573              :             ! Possibly check convergence
     574         4354 :             IF (PRESENT(conv)) THEN
     575         4354 :                CPASSERT(PRESENT(ndf))
     576         4354 :                CPASSERT(PRESENT(dx))
     577         4354 :                CPASSERT(PRESENT(xi))
     578              :                CALL check_and_report_convergence(output_unit, gopt_param, ndf, dx, xi, conv, &
     579         4354 :                                                  max_memory, stress_unit)
     580              :             END IF
     581              :          ELSE
     582          722 :             CALL update_dimer_vec(gopt_env%dimer_env, gopt_env%motion_section)
     583          722 :             CALL write_restart(force_env=force_env, root_section=root_section)
     584              :             CALL write_rot_cycle_infos(output_unit, its, opt_energy, opt_energy - eold, emin, gopt_env%dimer_env, &
     585          722 :                                        wildcard=wildcard, used_time=used_time, max_memory=max_memory)
     586              :             ! Possibly check convergence
     587          722 :             IF (PRESENT(conv)) THEN
     588          722 :                CPASSERT(ASSOCIATED(gopt_env%dimer_env))
     589          722 :                CALL check_rot_conv(gopt_env%dimer_env, output_unit, conv)
     590              :             END IF
     591              :          END IF
     592              :       CASE (default_cell_method_id)
     593              :          ! Cell Optimization
     594         4044 :          pres_diff = gopt_env%cell_env%pres_int - gopt_env%cell_env%pres_ext
     595         4044 :          pres_int = gopt_env%cell_env%pres_int
     596         4044 :          pres_tol = gopt_env%cell_env%pres_tol
     597              :          CALL geo_opt_io(force_env=force_env, root_section=root_section, &
     598         4044 :                          motion_section=gopt_env%motion_section, its=its, opt_energy=opt_energy)
     599              :          CALL write_cycle_infos(output_unit, &
     600              :                                 it=its, &
     601              :                                 etot=opt_energy, &
     602              :                                 ediff=(opt_energy - eold), &
     603              :                                 pred=pred, &
     604              :                                 rat=rat, &
     605              :                                 step=step, &
     606              :                                 rad=rad, &
     607              :                                 emin=emin, &
     608              :                                 pres_int=pres_int, &
     609              :                                 wildcard=wildcard, &
     610              :                                 used_time=used_time, &
     611              :                                 max_memory=max_memory, &
     612              :                                 energy_unit=energy_unit, &
     613         4044 :                                 stress_unit=stress_unit)
     614              :          ! Possibly check convergence
     615         4044 :          IF (PRESENT(conv)) THEN
     616         4044 :             CPASSERT(PRESENT(ndf))
     617         4044 :             CPASSERT(PRESENT(dx))
     618         4044 :             CPASSERT(PRESENT(xi))
     619         4044 :             IF (gopt_env%cell_env%constraint_id == fix_none) THEN
     620              :                CALL check_and_report_convergence(output_unit, gopt_param, ndf, dx, xi, conv, &
     621         3920 :                                                  max_memory, stress_unit, pres_diff, pres_tol)
     622              :             ELSE
     623          124 :                pres_diff_constr = gopt_env%cell_env%pres_constr - gopt_env%cell_env%pres_ext
     624              :                CALL check_and_report_convergence(output_unit, gopt_param, ndf, dx, xi, conv, &
     625              :                                                  max_memory, stress_unit, pres_diff, pres_tol, &
     626          124 :                                                  pres_diff_constr)
     627              :             END IF
     628              :          END IF
     629              :       CASE (default_shellcore_method_id)
     630              :          CALL write_cycle_infos(output_unit, &
     631              :                                 it=its, &
     632              :                                 etot=opt_energy, &
     633              :                                 ediff=(opt_energy - eold), &
     634              :                                 pred=pred, &
     635              :                                 rat=rat, &
     636              :                                 step=step, &
     637              :                                 rad=rad, &
     638              :                                 emin=emin, &
     639              :                                 wildcard=wildcard, &
     640              :                                 used_time=used_time, &
     641              :                                 max_memory=max_memory, &
     642              :                                 energy_unit=energy_unit, &
     643          150 :                                 stress_unit=stress_unit)
     644              :          ! Possibly check convergence
     645         9420 :          IF (PRESENT(conv)) THEN
     646          150 :             CPASSERT(PRESENT(ndf))
     647          150 :             CPASSERT(PRESENT(dx))
     648          150 :             CPASSERT(PRESENT(xi))
     649              :             CALL check_and_report_convergence(output_unit, gopt_param, ndf, dx, xi, conv, &
     650          150 :                                               max_memory, stress_unit)
     651              :          END IF
     652              :       END SELECT
     653              : 
     654         9270 :    END SUBROUTINE gopt_f_io
     655              : 
     656              : ! **************************************************************************************************
     657              : !> \brief Handles the Output at the end of an optimization run
     658              : !> \param gopt_env ...
     659              : !> \param force_env ...
     660              : !> \param x0 ...
     661              : !> \param conv ...
     662              : !> \param its ...
     663              : !> \param root_section ...
     664              : !> \param para_env ...
     665              : !> \param master ...
     666              : !> \param output_unit ...
     667              : !> \author Teodoro Laino [tlaino] - University of Zurich - 03.2008
     668              : ! **************************************************************************************************
     669         1267 :    RECURSIVE SUBROUTINE gopt_f_io_finalize(gopt_env, force_env, x0, conv, its, root_section, &
     670              :                                            para_env, master, output_unit)
     671              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
     672              :       TYPE(force_env_type), POINTER                      :: force_env
     673              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: x0
     674              :       LOGICAL                                            :: conv
     675              :       INTEGER                                            :: its
     676              :       TYPE(section_vals_type), POINTER                   :: root_section
     677              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     678              :       INTEGER, INTENT(IN)                                :: master, output_unit
     679              : 
     680         1267 :       IF (gopt_env%eval_opt_geo) THEN
     681         1247 :          IF (.NOT. gopt_env%dimer_rotation) THEN
     682              :             CALL write_final_info(output_unit, conv, its, gopt_env, x0, master, &
     683         1119 :                                   para_env, force_env, gopt_env%motion_section, root_section)
     684              :          ELSE
     685          128 :             CALL update_dimer_vec(gopt_env%dimer_env, gopt_env%motion_section)
     686          128 :             CALL write_restart(force_env=force_env, root_section=root_section)
     687              :          END IF
     688              :       END IF
     689              : 
     690         1267 :    END SUBROUTINE gopt_f_io_finalize
     691              : 
     692              : ! **************************************************************************************************
     693              : !> \brief ...
     694              : !> \param output_unit ...
     695              : !> \param it ...
     696              : !> \param etot ...
     697              : !> \param ediff ...
     698              : !> \param pred ...
     699              : !> \param rat ...
     700              : !> \param step ...
     701              : !> \param rad ...
     702              : !> \param emin ...
     703              : !> \param pres_int ...
     704              : !> \param wildcard ...
     705              : !> \param used_time ...
     706              : !> \param max_memory ...
     707              : !> \param energy_unit ...
     708              : !> \param stress_unit ...
     709              : ! **************************************************************************************************
     710         9583 :    SUBROUTINE write_cycle_infos(output_unit, it, etot, ediff, pred, rat, step, rad, emin, &
     711              :                                 pres_int, wildcard, used_time, max_memory, energy_unit, stress_unit)
     712              : 
     713              :       INTEGER, INTENT(IN)                                :: output_unit, it
     714              :       REAL(KIND=dp), INTENT(IN)                          :: etot
     715              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: ediff, pred, rat, step, rad, emin, &
     716              :                                                             pres_int
     717              :       CHARACTER(LEN=5), INTENT(IN)                       :: wildcard
     718              :       REAL(KIND=dp), INTENT(IN)                          :: used_time
     719              :       INTEGER(KIND=int_8), INTENT(IN)                    :: max_memory
     720              :       CHARACTER(LEN=default_string_length), INTENT(IN)   :: energy_unit, stress_unit
     721              : 
     722              :       CHARACTER(LEN=5)                                   :: tag
     723              : 
     724         9583 :       IF (output_unit > 0) THEN
     725         4975 :          tag = "OPT| "
     726         4975 :          WRITE (UNIT=output_unit, FMT="(/,T2,A)") tag//REPEAT("*", 74)
     727              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,I25)") &
     728         4975 :             tag//"Step number", it
     729              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,A25)") &
     730         4975 :             tag//"Optimization method", wildcard
     731              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     732         4975 :             tag//"Total energy ["//TRIM(ADJUSTL(energy_unit))//"]", &
     733         9950 :             cp_unit_from_cp2k(etot, TRIM(energy_unit))
     734         4975 :          IF (PRESENT(pres_int)) THEN
     735              :             WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     736         2110 :                tag//"Internal pressure ["//TRIM(ADJUSTL(stress_unit))//"]", &
     737         4220 :                cp_unit_from_cp2k(pres_int, TRIM(stress_unit))
     738              :          END IF
     739         4975 :          IF (PRESENT(ediff)) THEN
     740              :             WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     741         4434 :                tag//"Effective energy change ["//TRIM(ADJUSTL(energy_unit))//"]", &
     742         8868 :                cp_unit_from_cp2k(ediff, TRIM(energy_unit))
     743              :          END IF
     744         4975 :          IF (PRESENT(pred)) THEN
     745              :             WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     746         2094 :                tag//"Predicted energy change ["//TRIM(ADJUSTL(energy_unit))//"]", &
     747         4188 :                cp_unit_from_cp2k(pred, TRIM(energy_unit))
     748              :          END IF
     749         4975 :          IF (PRESENT(rat)) THEN
     750              :             WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     751         2350 :                tag//"Scaling factor", rat
     752              :          END IF
     753         4975 :          IF (PRESENT(step)) THEN
     754              :             WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     755         2350 :                tag//"Step size", step
     756              :          END IF
     757         4975 :          IF (PRESENT(rad)) THEN
     758              :             WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     759         2350 :                tag//"Trust radius", rad
     760              :          END IF
     761         4975 :          IF (PRESENT(emin)) THEN
     762         4434 :             IF (etot < emin) THEN
     763              :                WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") &
     764         4026 :                   tag//"Decrease in energy", " YES"
     765              :             ELSE
     766              :                WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") &
     767          408 :                   tag//"Decrease in energy", "  NO"
     768              :             END IF
     769              :          END IF
     770              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.3)") &
     771         4975 :             tag//"Used time [s]", used_time
     772         4975 :          IF (it == 0) THEN
     773          535 :             WRITE (UNIT=output_unit, FMT="(T2,A)") tag//REPEAT("*", 74)
     774          535 :             IF (max_memory /= 0) THEN
     775              :                WRITE (UNIT=output_unit, FMT="(T2,A,T60,1X,I20)") &
     776          535 :                   tag//"Estimated peak process memory [MiB]", &
     777         1070 :                   (max_memory + bytes_per_mib - 1)/bytes_per_mib
     778              :             END IF
     779              :          END IF
     780              :       END IF
     781              : 
     782         9583 :    END SUBROUTINE write_cycle_infos
     783              : 
     784              : ! **************************************************************************************************
     785              : !> \brief ...
     786              : !> \param output_unit ...
     787              : !> \param it ...
     788              : !> \param etot ...
     789              : !> \param ediff ...
     790              : !> \param emin ...
     791              : !> \param dimer_env ...
     792              : !> \param used_time ...
     793              : !> \param wildcard ...
     794              : !> \param max_memory ...
     795              : !> \date  01.2008
     796              : !> \author Luca Bellucci and Teodoro Laino - created [tlaino]
     797              : ! **************************************************************************************************
     798          850 :    SUBROUTINE write_rot_cycle_infos(output_unit, it, etot, ediff, emin, dimer_env, used_time, &
     799              :                                     wildcard, max_memory)
     800              : 
     801              :       INTEGER, INTENT(IN)                                :: output_unit, it
     802              :       REAL(KIND=dp), INTENT(IN)                          :: etot
     803              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: ediff, emin
     804              :       TYPE(dimer_env_type), POINTER                      :: dimer_env
     805              :       REAL(KIND=dp), INTENT(IN)                          :: used_time
     806              :       CHARACTER(LEN=5), INTENT(IN)                       :: wildcard
     807              :       INTEGER(KIND=int_8), INTENT(IN)                    :: max_memory
     808              : 
     809              :       CHARACTER(LEN=5)                                   :: tag
     810              : 
     811          850 :       IF (output_unit > 0) THEN
     812          425 :          tag = "OPT| "
     813          425 :          WRITE (UNIT=output_unit, FMT="(/,T2,A)") tag//REPEAT("*", 74)
     814              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,I25)") &
     815          425 :             tag//"Rotational step number", it
     816              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,A25)") &
     817          425 :             tag//"Optimization method", wildcard
     818              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     819          425 :             tag//"Local curvature", dimer_env%rot%curvature, &
     820          850 :             tag//"Total rotational force", etot
     821          425 :          IF (PRESENT(ediff)) THEN
     822              :             WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     823          361 :                tag//"Rotational force change", ediff
     824              :          END IF
     825          425 :          IF (PRESENT(emin)) THEN
     826          361 :             IF (etot < emin) THEN
     827              :                WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") &
     828          155 :                   tag//"Decrease in rotational force", " YES"
     829              :             ELSE
     830              :                WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") &
     831          206 :                   tag//"Decrease in rotational force", "  NO"
     832              :             END IF
     833              :          END IF
     834              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.3)") &
     835          425 :             tag//"Used time [s]", used_time
     836          425 :          IF (it == 0) THEN
     837           64 :             WRITE (UNIT=output_unit, FMT="(T2,A)") tag//REPEAT("*", 74)
     838           64 :             IF (max_memory /= 0) THEN
     839              :                WRITE (UNIT=output_unit, FMT="(T2,A,T60,1X,I20)") &
     840           64 :                   tag//"Estimated peak process memory [MiB]", &
     841          128 :                   (max_memory + bytes_per_mib - 1)/bytes_per_mib
     842              :             END IF
     843              :          END IF
     844              :       END IF
     845              : 
     846          850 :    END SUBROUTINE write_rot_cycle_infos
     847              : 
     848              : ! **************************************************************************************************
     849              : !> \brief Evaluate the geometry/cell optimization convergence criteria (pure decision, no I/O)
     850              : !> \param ndf ...
     851              : !> \param dr ...
     852              : !> \param g ...
     853              : !> \param gopt_param ...
     854              : !> \param conv ...
     855              : !> \param conv_dx ...
     856              : !> \param conv_rdx ...
     857              : !> \param conv_g ...
     858              : !> \param conv_rg ...
     859              : !> \param conv_p ...
     860              : !> \param max_dr ...
     861              : !> \param rms_dr ...
     862              : !> \param max_grad ...
     863              : !> \param rms_grad ...
     864              : !> \param pres_diff ...
     865              : !> \param pres_tol ...
     866              : !> \param pres_diff_constr ...
     867              : ! **************************************************************************************************
     868         8548 :    SUBROUTINE check_converg(ndf, dr, g, gopt_param, conv, conv_dx, conv_rdx, conv_g, conv_rg, conv_p, &
     869              :                             max_dr, rms_dr, max_grad, rms_grad, pres_diff, pres_tol, pres_diff_constr)
     870              : 
     871              :       INTEGER, INTENT(IN)                                :: ndf
     872              :       REAL(KIND=dp), INTENT(IN)                          :: dr(ndf), g(ndf)
     873              :       TYPE(gopt_param_type), POINTER                     :: gopt_param
     874              :       LOGICAL, INTENT(OUT)                               :: conv, conv_dx, conv_rdx, conv_g, &
     875              :                                                             conv_rg, conv_p
     876              :       REAL(KIND=dp), INTENT(OUT)                         :: max_dr, rms_dr, max_grad, rms_grad
     877              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: pres_diff, pres_tol, pres_diff_constr
     878              : 
     879              :       INTEGER                                            :: indf
     880              :       REAL(KIND=dp)                                      :: dumm, dxcon, gcon, rmsgcon, rmsxcon
     881              : 
     882         8548 :       dxcon = gopt_param%max_dr
     883         8548 :       gcon = gopt_param%max_force
     884         8548 :       rmsgcon = gopt_param%rms_force
     885         8548 :       rmsxcon = gopt_param%rms_dr
     886              : 
     887         8548 :       conv = .FALSE.
     888         8548 :       conv_dx = .TRUE.
     889         8548 :       conv_rdx = .TRUE.
     890         8548 :       conv_g = .TRUE.
     891         8548 :       conv_rg = .TRUE.
     892         8548 :       conv_p = .TRUE.
     893              : 
     894         8548 :       dumm = 0.0_dp
     895      2545084 :       DO indf = 1, ndf
     896      2536536 :          IF (indf == 1) max_dr = ABS(dr(indf))
     897      2536536 :          dumm = dumm + dr(indf)**2
     898      2536536 :          IF (ABS(dr(indf)) > dxcon) conv_dx = .FALSE.
     899      2545084 :          IF (ABS(dr(indf)) > max_dr) max_dr = ABS(dr(indf))
     900              :       END DO
     901              :       ! SQRT(dumm/ndf) > rmsxcon
     902         8548 :       IF (dumm > (rmsxcon*rmsxcon*ndf)) conv_rdx = .FALSE.
     903         8548 :       rms_dr = SQRT(dumm/ndf)
     904              : 
     905         8548 :       dumm = 0.0_dp
     906      2545084 :       DO indf = 1, ndf
     907      2536536 :          IF (indf == 1) max_grad = ABS(g(indf))
     908      2536536 :          dumm = dumm + g(indf)**2
     909      2536536 :          IF (ABS(g(indf)) > gcon) conv_g = .FALSE.
     910      2545084 :          IF (ABS(g(indf)) > max_grad) max_grad = ABS(g(indf))
     911              :       END DO
     912              :       ! SQRT(dumm/ndf) > rmsgcon
     913         8548 :       IF (dumm > (rmsgcon*rmsgcon*ndf)) conv_rg = .FALSE.
     914         8548 :       rms_grad = SQRT(dumm/ndf)
     915              : 
     916         8548 :       IF (PRESENT(pres_diff_constr) .AND. PRESENT(pres_tol)) THEN
     917          124 :          conv_p = ABS(pres_diff_constr) < ABS(pres_tol)
     918         8424 :       ELSE IF (PRESENT(pres_diff) .AND. PRESENT(pres_tol)) THEN
     919         3920 :          conv_p = ABS(pres_diff) < ABS(pres_tol)
     920              :       END IF
     921              : 
     922         8548 :       IF (conv_dx .AND. conv_rdx .AND. conv_g .AND. conv_rg .AND. conv_p) conv = .TRUE.
     923              : 
     924         8548 :    END SUBROUTINE check_converg
     925              : 
     926              : ! **************************************************************************************************
     927              : !> \brief Print one YES/NO convergence flag line
     928              : !> \param output_unit ...
     929              : !> \param tag ...
     930              : !> \param label ...
     931              : !> \param flag ...
     932              : ! **************************************************************************************************
     933        20119 :    SUBROUTINE write_conv_flag(output_unit, tag, label, flag)
     934              :       INTEGER, INTENT(IN)                                :: output_unit
     935              :       CHARACTER(LEN=*), INTENT(IN)                       :: tag, label
     936              :       LOGICAL, INTENT(IN)                                :: flag
     937              : 
     938        20119 :       IF (flag) THEN
     939         3463 :          WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") tag//label, " YES"
     940              :       ELSE
     941        16656 :          WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") tag//label, "  NO"
     942              :       END IF
     943        20119 :    END SUBROUTINE write_conv_flag
     944              : 
     945              : ! **************************************************************************************************
     946              : !> \brief Print the per-cycle convergence report (body moved verbatim from check_converg)
     947              : !> \param output_unit ...
     948              : !> \param gopt_param ...
     949              : !> \param conv ...
     950              : !> \param conv_dx ...
     951              : !> \param conv_rdx ...
     952              : !> \param conv_g ...
     953              : !> \param conv_rg ...
     954              : !> \param conv_p ...
     955              : !> \param max_dr ...
     956              : !> \param rms_dr ...
     957              : !> \param max_grad ...
     958              : !> \param rms_grad ...
     959              : !> \param max_memory ...
     960              : !> \param stress_unit ...
     961              : !> \param pres_diff ...
     962              : !> \param pres_tol ...
     963              : !> \param pres_diff_constr ...
     964              : ! **************************************************************************************************
     965         8548 :    SUBROUTINE write_convergence_infos(output_unit, gopt_param, conv, conv_dx, conv_rdx, conv_g, &
     966              :                                       conv_rg, conv_p, max_dr, rms_dr, max_grad, rms_grad, &
     967              :                                       max_memory, stress_unit, pres_diff, pres_tol, pres_diff_constr)
     968              : 
     969              :       INTEGER, INTENT(IN)                                :: output_unit
     970              :       TYPE(gopt_param_type), POINTER                     :: gopt_param
     971              :       LOGICAL, INTENT(IN)                                :: conv, conv_dx, conv_rdx, conv_g, &
     972              :                                                             conv_rg, conv_p
     973              :       REAL(KIND=dp), INTENT(IN)                          :: max_dr, rms_dr, max_grad, rms_grad
     974              :       INTEGER(KIND=int_8), INTENT(IN)                    :: max_memory
     975              :       CHARACTER(LEN=default_string_length), INTENT(IN)   :: stress_unit
     976              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: pres_diff, pres_tol, pres_diff_constr
     977              : 
     978              :       CHARACTER(LEN=5)                                   :: tag
     979              :       REAL(KIND=dp)                                      :: dxcon, gcon, rmsgcon, rmsxcon
     980              : 
     981         8548 :       dxcon = gopt_param%max_dr
     982         8548 :       gcon = gopt_param%max_force
     983         8548 :       rmsgcon = gopt_param%rms_force
     984         8548 :       rmsxcon = gopt_param%rms_dr
     985              : 
     986         8548 :       IF (output_unit > 0) THEN
     987              : 
     988         4434 :          tag = "OPT| "
     989              : 
     990         4434 :          WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
     991              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     992         4434 :             tag//"Maximum step size", max_dr, &
     993         8868 :             tag//"Convergence limit for maximum step size", dxcon
     994              :          CALL write_conv_flag(output_unit, tag, "Maximum step size is converged", &
     995         4434 :                               conv_dx)
     996              : 
     997         4434 :          WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
     998              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
     999         4434 :             tag//"RMS step size", rms_dr, &
    1000         8868 :             tag//"Convergence limit for RMS step size", rmsxcon
    1001              :          CALL write_conv_flag(output_unit, tag, "RMS step size is converged", &
    1002         4434 :                               conv_rdx)
    1003              : 
    1004         4434 :          WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
    1005              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
    1006         4434 :             tag//"Maximum gradient", max_grad, &
    1007         8868 :             tag//"Convergence limit for maximum gradient", gcon
    1008              :          CALL write_conv_flag(output_unit, tag, "Maximum gradient is converged", &
    1009         4434 :                               conv_g)
    1010              : 
    1011         4434 :          WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
    1012              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
    1013         4434 :             tag//"RMS gradient", rms_grad, &
    1014         8868 :             tag//"Convergence limit for RMS gradient", rmsgcon
    1015              :          CALL write_conv_flag(output_unit, tag, "RMS gradient is converged", &
    1016         4434 :                               conv_rg)
    1017              : 
    1018         4434 :          IF (PRESENT(pres_diff) .AND. PRESENT(pres_tol)) THEN
    1019         2022 :             WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
    1020         2022 :             IF (PRESENT(pres_diff_constr)) THEN
    1021              :                WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
    1022              :                   tag//"Pressure deviation without constraint ["// &
    1023           62 :                   TRIM(ADJUSTL(stress_unit))//"]", &
    1024          124 :                   cp_unit_from_cp2k(pres_diff, TRIM(stress_unit))
    1025              :                WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
    1026              :                   tag//"Pressure deviation with constraint ["// &
    1027           62 :                   TRIM(ADJUSTL(stress_unit))//"]", &
    1028          124 :                   cp_unit_from_cp2k(pres_diff_constr, TRIM(stress_unit))
    1029              :             ELSE
    1030              :                WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
    1031         1960 :                   tag//"Pressure deviation ["//TRIM(ADJUSTL(stress_unit))//"]", &
    1032         3920 :                   cp_unit_from_cp2k(pres_diff, TRIM(stress_unit))
    1033              :             END IF
    1034              :             WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
    1035         2022 :                tag//"Pressure tolerance ["//TRIM(ADJUSTL(stress_unit))//"]", &
    1036         4044 :                cp_unit_from_cp2k(pres_tol, TRIM(stress_unit))
    1037         2022 :             CALL write_conv_flag(output_unit, tag, "Pressure is converged", conv_p)
    1038              :          END IF
    1039              : 
    1040         4434 :          WRITE (UNIT=output_unit, FMT="(T2,A)") tag//REPEAT("*", 74)
    1041              : 
    1042         4434 :          IF (max_memory /= 0) THEN
    1043              :             WRITE (UNIT=output_unit, FMT="(T2,A,T60,1X,I20)") &
    1044         4434 :                tag//"Estimated peak process memory after this step [MiB]", &
    1045         8868 :                (max_memory + bytes_per_mib - 1)/bytes_per_mib
    1046              :          END IF
    1047              : 
    1048              :       END IF
    1049              : 
    1050         8548 :       IF ((conv) .AND. (output_unit > 0)) THEN
    1051          223 :          WRITE (UNIT=output_unit, FMT="(/,T2,A)") REPEAT("*", 79)
    1052              :          WRITE (UNIT=output_unit, FMT="(T2,A,T25,A,T78,A)") &
    1053          223 :             "***", "GEOMETRY OPTIMIZATION COMPLETED", "***"
    1054          223 :          WRITE (UNIT=output_unit, FMT="(T2,A)") REPEAT("*", 79)
    1055              :       END IF
    1056              : 
    1057         8548 :    END SUBROUTINE write_convergence_infos
    1058              : 
    1059              : ! **************************************************************************************************
    1060              : !> \brief Check convergence and print the per-cycle report (gopt_f_io call sites)
    1061              : !> \param output_unit ...
    1062              : !> \param gopt_param ...
    1063              : !> \param ndf ...
    1064              : !> \param dr ...
    1065              : !> \param g ...
    1066              : !> \param conv ...
    1067              : !> \param max_memory ...
    1068              : !> \param stress_unit ...
    1069              : !> \param pres_diff ...
    1070              : !> \param pres_tol ...
    1071              : !> \param pres_diff_constr ...
    1072              : ! **************************************************************************************************
    1073         8548 :    SUBROUTINE check_and_report_convergence(output_unit, gopt_param, ndf, dr, g, conv, &
    1074              :                                            max_memory, stress_unit, pres_diff, pres_tol, pres_diff_constr)
    1075              : 
    1076              :       INTEGER, INTENT(IN)                                :: output_unit
    1077              :       TYPE(gopt_param_type), POINTER                     :: gopt_param
    1078              :       INTEGER, INTENT(IN)                                :: ndf
    1079              :       REAL(KIND=dp), INTENT(IN)                          :: dr(ndf), g(ndf)
    1080              :       LOGICAL, INTENT(INOUT)                             :: conv
    1081              :       INTEGER(KIND=int_8), INTENT(IN)                    :: max_memory
    1082              :       CHARACTER(LEN=default_string_length), INTENT(IN)   :: stress_unit
    1083              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: pres_diff, pres_tol, pres_diff_constr
    1084              : 
    1085              :       LOGICAL                                            :: conv_dx, conv_g, conv_p, conv_rdx, &
    1086              :                                                             conv_rg
    1087              :       REAL(KIND=dp)                                      :: max_dr, max_grad, rms_dr, rms_grad
    1088              : 
    1089              :       CALL check_converg(ndf, dr, g, gopt_param, conv, conv_dx, conv_rdx, conv_g, conv_rg, &
    1090              :                          conv_p, max_dr, rms_dr, max_grad, rms_grad, pres_diff, pres_tol, &
    1091         8548 :                          pres_diff_constr)
    1092              :       CALL write_convergence_infos(output_unit, gopt_param, conv, conv_dx, conv_rdx, conv_g, &
    1093              :                                    conv_rg, conv_p, max_dr, rms_dr, max_grad, rms_grad, &
    1094         8548 :                                    max_memory, stress_unit, pres_diff, pres_tol, pres_diff_constr)
    1095         8548 :    END SUBROUTINE check_and_report_convergence
    1096              : 
    1097              : ! **************************************************************************************************
    1098              : !> \brief ...
    1099              : !> \param dimer_env ...
    1100              : !> \param output_unit ...
    1101              : !> \param conv ...
    1102              : !> \date  01.2008
    1103              : !> \author Luca Bellucci and Teodoro Laino - created [tlaino]
    1104              : ! **************************************************************************************************
    1105          722 :    SUBROUTINE check_rot_conv(dimer_env, output_unit, conv)
    1106              : 
    1107              :       TYPE(dimer_env_type), POINTER                      :: dimer_env
    1108              :       INTEGER, INTENT(IN)                                :: output_unit
    1109              :       LOGICAL, INTENT(OUT)                               :: conv
    1110              : 
    1111              :       CHARACTER(LEN=5)                                   :: tag
    1112              : 
    1113          722 :       conv = (ABS(dimer_env%rot%angle2) < dimer_env%rot%angle_tol)
    1114              : 
    1115          722 :       IF (output_unit > 0) THEN
    1116          361 :          tag = "OPT| "
    1117          361 :          WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
    1118              :          WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
    1119          361 :             tag//"Predicted angle step size", dimer_env%rot%angle1, &
    1120          361 :             tag//"Effective angle step size", dimer_env%rot%angle2, &
    1121          722 :             tag//"Convergence limit for angle step size", dimer_env%rot%angle_tol
    1122          361 :          CALL write_conv_flag(output_unit, tag, "Angle step size is converged", conv)
    1123          361 :          WRITE (UNIT=output_unit, FMT="(T2,A)") tag//REPEAT("*", 74)
    1124              :       END IF
    1125              : 
    1126          722 :       IF ((conv) .AND. (output_unit > 0)) THEN
    1127           59 :          WRITE (UNIT=output_unit, FMT="(/,T2,A)") REPEAT("*", 79)
    1128              :          WRITE (UNIT=output_unit, FMT="(T2,A,T25,A,T78,A)") &
    1129           59 :             "***", "ROTATION OPTIMIZATION COMPLETED", "***"
    1130           59 :          WRITE (UNIT=output_unit, FMT="(T2,A)") REPEAT("*", 79)
    1131              :       END IF
    1132              : 
    1133          722 :    END SUBROUTINE check_rot_conv
    1134              : 
    1135              : ! **************************************************************************************************
    1136              : !> \brief ...
    1137              : !> \param output_unit ...
    1138              : !> \param conv ...
    1139              : !> \param it ...
    1140              : !> \param gopt_env ...
    1141              : !> \param x0 ...
    1142              : !> \param master ...
    1143              : !> \param para_env ...
    1144              : !> \param force_env ...
    1145              : !> \param motion_section ...
    1146              : !> \param root_section ...
    1147              : !> \date  11.2007
    1148              : !> \author Teodoro Laino [tlaino] - University of Zurich
    1149              : ! **************************************************************************************************
    1150         1119 :    RECURSIVE SUBROUTINE write_final_info(output_unit, conv, it, gopt_env, x0, master, para_env, force_env, &
    1151              :                                          motion_section, root_section)
    1152              :       INTEGER, INTENT(IN)                                :: output_unit
    1153              :       LOGICAL, INTENT(IN)                                :: conv
    1154              :       INTEGER, INTENT(INOUT)                             :: it
    1155              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
    1156              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: x0
    1157              :       INTEGER, INTENT(IN)                                :: master
    1158              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1159              :       TYPE(force_env_type), POINTER                      :: force_env
    1160              :       TYPE(section_vals_type), POINTER                   :: motion_section, root_section
    1161              : 
    1162              :       CHARACTER(LEN=default_string_length)               :: constraint_label
    1163              :       LOGICAL                                            :: keep_angles, keep_symmetry, keep_volume
    1164              :       REAL(KIND=dp)                                      :: etot
    1165              :       TYPE(cell_type), POINTER                           :: cell
    1166              :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1167              :       TYPE(particle_list_type), POINTER                  :: particles
    1168         1119 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1169              : 
    1170         1119 :       CALL force_env_get(force_env, cell=cell, subsys=subsys)
    1171         1119 :       CALL cp_subsys_get(subsys=subsys, particles=particles)
    1172         1119 :       particle_set => particles%els
    1173              : 
    1174              :       ! Passing gopt_f_type pointer gopt_env to particle_methods where
    1175              :       ! write_final_structure is defined causes a circular dependency, so it
    1176              :       ! is necessary to get some flags by preprocessing...
    1177         1119 :       keep_angles = .TRUE.
    1178         1119 :       keep_symmetry = .TRUE.
    1179         1119 :       keep_volume = .TRUE.
    1180         1119 :       constraint_label = "NONE"
    1181         1119 :       IF (gopt_env%type_id == default_cell_method_id) THEN
    1182          234 :          keep_angles = gopt_env%cell_env%keep_angles
    1183          234 :          keep_symmetry = gopt_env%cell_env%keep_symmetry
    1184          234 :          keep_volume = gopt_env%cell_env%keep_volume
    1185          234 :          constraint_label = cell_opt_constraint_label(gopt_env%cell_env%constraint_id)
    1186              :       END IF
    1187              :       CALL write_final_structure(particle_set, cell, motion_section, conv, &
    1188              :                                  keep_angles, keep_symmetry, keep_volume, &
    1189         1119 :                                  gopt_env%label, constraint_label)
    1190              : 
    1191         1119 :       IF (conv) THEN
    1192          382 :          it = it + 1
    1193          382 :          CALL write_structure_data(particle_set, cell, motion_section)
    1194          382 :          CALL write_restart(force_env=force_env, root_section=root_section)
    1195              : 
    1196          382 :          IF (output_unit > 0) THEN
    1197          214 :             WRITE (UNIT=output_unit, FMT="(/,T20,' Reevaluating energy at the minimum')")
    1198              :          END IF
    1199              : 
    1200              :          CALL cp_eval_at(gopt_env, x0, f=etot, master=master, &
    1201          382 :                          para_env=para_env)
    1202          382 :          CALL write_geo_traj(force_env, root_section, it, etot)
    1203          382 :          CALL write_simulation_cell(cell, motion_section, it, 0.0_dp)
    1204              :       END IF
    1205              : 
    1206         1119 :    END SUBROUTINE write_final_info
    1207              : 
    1208              : ! **************************************************************************************************
    1209              : !> \brief  Specific driver for dumping trajectory during a GEO_OPT
    1210              : !> \param force_env ...
    1211              : !> \param root_section ...
    1212              : !> \param it ...
    1213              : !> \param etot ...
    1214              : !> \date   11.2007
    1215              : !> \par    History
    1216              : !>         09.2010: Output of core and shell positions and forces (MK)
    1217              : !> \author Teodoro Laino [tlaino] - University of Zurich
    1218              : ! **************************************************************************************************
    1219        17560 :    SUBROUTINE write_geo_traj(force_env, root_section, it, etot)
    1220              : 
    1221              :       TYPE(force_env_type), POINTER                      :: force_env
    1222              :       TYPE(section_vals_type), POINTER                   :: root_section
    1223              :       INTEGER, INTENT(IN)                                :: it
    1224              :       REAL(KIND=dp), INTENT(IN)                          :: etot
    1225              : 
    1226              :       LOGICAL                                            :: shell_adiabatic, shell_present
    1227              :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
    1228         8780 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    1229              :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1230              :       TYPE(particle_list_type), POINTER                  :: core_particles, shell_particles
    1231              : 
    1232         8780 :       NULLIFY (atomic_kinds)
    1233         8780 :       NULLIFY (atomic_kind_set)
    1234         8780 :       NULLIFY (core_particles)
    1235         8780 :       NULLIFY (shell_particles)
    1236         8780 :       NULLIFY (subsys)
    1237              : 
    1238         8780 :       CALL write_trajectory(force_env, root_section, it, 0.0_dp, 0.0_dp, etot)
    1239              :       ! Print Force
    1240         8780 :       CALL write_trajectory(force_env, root_section, it, 0.0_dp, 0.0_dp, etot, "FORCES", middle_name="frc")
    1241         8780 :       CALL force_env_get(force_env, subsys=subsys)
    1242         8780 :       CALL cp_subsys_get(subsys, atomic_kinds=atomic_kinds)
    1243         8780 :       atomic_kind_set => atomic_kinds%els
    1244              :       CALL get_atomic_kind_set(atomic_kind_set, &
    1245              :                                shell_present=shell_present, &
    1246         8780 :                                shell_adiabatic=shell_adiabatic)
    1247         8780 :       IF (shell_present) THEN
    1248              :          CALL cp_subsys_get(subsys, &
    1249              :                             core_particles=core_particles, &
    1250         3414 :                             shell_particles=shell_particles)
    1251              :          CALL write_trajectory(force_env, root_section, it=it, time=0.0_dp, dtime=0.0_dp, &
    1252              :                                etot=etot, pk_name="SHELL_TRAJECTORY", middle_name="shpos", &
    1253         3414 :                                particles=shell_particles)
    1254         3414 :          IF (shell_adiabatic) THEN
    1255              :             CALL write_trajectory(force_env, root_section, it=it, time=0.0_dp, dtime=0.0_dp, &
    1256              :                                   etot=etot, pk_name="SHELL_FORCES", middle_name="shfrc", &
    1257         3414 :                                   particles=shell_particles)
    1258              :             CALL write_trajectory(force_env, root_section, it=it, time=0.0_dp, dtime=0.0_dp, &
    1259              :                                   etot=etot, pk_name="CORE_TRAJECTORY", middle_name="copos", &
    1260         3414 :                                   particles=core_particles)
    1261              :             CALL write_trajectory(force_env, root_section, it=it, time=0.0_dp, dtime=0.0_dp, &
    1262              :                                   etot=etot, pk_name="CORE_FORCES", middle_name="cofrc", &
    1263         3414 :                                   particles=core_particles)
    1264              :          END IF
    1265              :       END IF
    1266              : 
    1267         8780 :    END SUBROUTINE write_geo_traj
    1268              : 
    1269              : ! **************************************************************************************************
    1270              : !> \brief ...
    1271              : !> \param gopt_env ...
    1272              : !> \param output_unit ...
    1273              : !> \param label ...
    1274              : !> \date  01.2008
    1275              : !> \author Teodoro Laino [tlaino] - University of Zurich
    1276              : ! **************************************************************************************************
    1277         1267 :    SUBROUTINE print_geo_opt_header(gopt_env, output_unit, label)
    1278              : 
    1279              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
    1280              :       INTEGER, INTENT(IN)                                :: output_unit
    1281              :       CHARACTER(LEN=*), INTENT(IN)                       :: label
    1282              : 
    1283              :       CHARACTER(LEN=default_string_length)               :: my_format, my_label
    1284              :       INTEGER                                            :: ix
    1285              : 
    1286         1267 :       IF (output_unit > 0) THEN
    1287          657 :          WRITE (UNIT=output_unit, FMT="(/,T2,A)") REPEAT("*", 79)
    1288          657 :          IF (gopt_env%dimer_rotation) THEN
    1289           64 :             my_label = "OPTIMIZING DIMER ROTATION"
    1290              :          ELSE
    1291          593 :             my_label = "STARTING "//gopt_env%tag(1:8)//" OPTIMIZATION"
    1292              :          END IF
    1293              : 
    1294          657 :          ix = (80 - 7 - LEN_TRIM(my_label))/2
    1295          657 :          ix = ix + 5
    1296          657 :          my_format = "(T2,A,T"//cp_to_string(ix)//",A,T78,A)"
    1297          657 :          WRITE (UNIT=output_unit, FMT=TRIM(my_format)) "***", TRIM(my_label), "***"
    1298              : 
    1299          657 :          ix = (80 - 7 - LEN_TRIM(label))/2
    1300          657 :          ix = ix + 5
    1301          657 :          my_format = "(T2,A,T"//cp_to_string(ix)//",A,T78,A)"
    1302          657 :          WRITE (UNIT=output_unit, FMT=TRIM(my_format)) "***", TRIM(label), "***"
    1303              : 
    1304          657 :          WRITE (UNIT=output_unit, FMT="(T2,A)") REPEAT("*", 79)
    1305          657 :          CALL m_flush(output_unit)
    1306              :       END IF
    1307         1267 :    END SUBROUTINE print_geo_opt_header
    1308              : 
    1309              : ! **************************************************************************************************
    1310              : !> \brief ...
    1311              : !> \param gopt_env ...
    1312              : !> \param output_unit ...
    1313              : !> \date  01.2008
    1314              : !> \author Teodoro Laino [tlaino] - University of Zurich
    1315              : ! **************************************************************************************************
    1316          735 :    SUBROUTINE print_geo_opt_nc(gopt_env, output_unit)
    1317              : 
    1318              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
    1319              :       INTEGER, INTENT(IN)                                :: output_unit
    1320              : 
    1321          735 :       IF (output_unit > 0) THEN
    1322              :          WRITE (UNIT=output_unit, FMT="(/,T2,A)") &
    1323          368 :             "*** MAXIMUM NUMBER OF OPTIMIZATION STEPS REACHED ***"
    1324          368 :          IF (.NOT. gopt_env%dimer_rotation) THEN
    1325              :             WRITE (UNIT=output_unit, FMT="(T2,A)") &
    1326          363 :                "***        EXITING GEOMETRY OPTIMIZATION         ***"
    1327              :          ELSE
    1328              :             WRITE (UNIT=output_unit, FMT="(T2,A)") &
    1329            5 :                "***        EXITING ROTATION OPTIMIZATION         ***"
    1330              :          END IF
    1331          368 :          CALL m_flush(output_unit)
    1332              :       END IF
    1333              : 
    1334          735 :    END SUBROUTINE print_geo_opt_nc
    1335              : 
    1336              : ! **************************************************************************************************
    1337              : !> \brief   Prints information during GEO_OPT common to all optimizers
    1338              : !> \param force_env ...
    1339              : !> \param root_section ...
    1340              : !> \param motion_section ...
    1341              : !> \param its ...
    1342              : !> \param opt_energy ...
    1343              : !> \date    02.2008
    1344              : !> \author  Teodoro Laino [tlaino] - University of Zurich
    1345              : !> \version 1.0
    1346              : ! **************************************************************************************************
    1347         8398 :    SUBROUTINE geo_opt_io(force_env, root_section, motion_section, its, opt_energy)
    1348              : 
    1349              :       TYPE(force_env_type), POINTER                      :: force_env
    1350              :       TYPE(section_vals_type), POINTER                   :: root_section, motion_section
    1351              :       INTEGER, INTENT(IN)                                :: its
    1352              :       REAL(KIND=dp), INTENT(IN)                          :: opt_energy
    1353              : 
    1354              :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
    1355         8398 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    1356              :       TYPE(cell_type), POINTER                           :: cell
    1357              :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1358              :       TYPE(distribution_1d_type), POINTER                :: local_particles
    1359              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1360              :       TYPE(particle_list_type), POINTER                  :: particles
    1361         8398 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1362              :       TYPE(virial_type), POINTER                         :: virial
    1363              : 
    1364         8398 :       NULLIFY (para_env, atomic_kind_set, subsys, particle_set, &
    1365         8398 :                local_particles, atomic_kinds, particles)
    1366              : 
    1367              :       ! Write Restart File
    1368         8398 :       CALL write_restart(force_env=force_env, root_section=root_section)
    1369              : 
    1370              :       ! Write Trajectory
    1371         8398 :       CALL write_geo_traj(force_env, root_section, its, opt_energy)
    1372              : 
    1373              :       ! Write the stress Tensor
    1374              :       CALL force_env_get(force_env, cell=cell, para_env=para_env, &
    1375         8398 :                          subsys=subsys)
    1376              :       CALL cp_subsys_get(subsys=subsys, atomic_kinds=atomic_kinds, local_particles=local_particles, &
    1377         8398 :                          particles=particles, virial=virial)
    1378         8398 :       atomic_kind_set => atomic_kinds%els
    1379         8398 :       particle_set => particles%els
    1380              :       CALL virial_evaluate(atomic_kind_set, particle_set, local_particles, &
    1381         8398 :                            virial, para_env)
    1382         8398 :       CALL write_stress_tensor_to_file(virial, cell, motion_section, its, 0.0_dp)
    1383              : 
    1384              :       ! Write the cell
    1385         8398 :       CALL write_simulation_cell(cell, motion_section, its, 0.0_dp)
    1386              : 
    1387         8398 :    END SUBROUTINE geo_opt_io
    1388              : 
    1389              : ! **************************************************************************************************
    1390              : !> \brief   Apply coordinate transformations after cell (shape) change
    1391              : !> \param gopt_env ...
    1392              : !> \param cell ...
    1393              : !> \param x ...
    1394              : !> \param update_forces ...
    1395              : !> \date    05.11.2012 (revised version of unbiase_coordinates moved here, MK)
    1396              : !> \author  Matthias Krack
    1397              : !> \version 1.0
    1398              : ! **************************************************************************************************
    1399        13653 :    SUBROUTINE apply_cell_change(gopt_env, cell, x, update_forces)
    1400              : 
    1401              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
    1402              :       TYPE(cell_type), POINTER                           :: cell
    1403              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: x
    1404              :       LOGICAL, INTENT(IN)                                :: update_forces
    1405              : 
    1406              :       INTEGER                                            :: i, iatom, idg, j, natom, nparticle, &
    1407              :                                                             shell_index
    1408              :       REAL(KIND=dp)                                      :: fc, fs, mass
    1409              :       REAL(KIND=dp), DIMENSION(3)                        :: s
    1410              :       TYPE(cell_type), POINTER                           :: cell_ref
    1411              :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1412              :       TYPE(particle_list_type), POINTER                  :: core_particles, particles, &
    1413              :                                                             shell_particles
    1414              : 
    1415        13653 :       NULLIFY (cell_ref)
    1416        13653 :       NULLIFY (core_particles)
    1417        13653 :       NULLIFY (particles)
    1418        13653 :       NULLIFY (shell_particles)
    1419        13653 :       NULLIFY (subsys)
    1420              : 
    1421        13653 :       natom = force_env_get_natom(gopt_env%force_env)
    1422        13653 :       nparticle = force_env_get_nparticle(gopt_env%force_env)
    1423              :       CALL force_env_get(gopt_env%force_env, &
    1424        13653 :                          subsys=subsys)
    1425              :       CALL cp_subsys_get(subsys=subsys, &
    1426              :                          core_particles=core_particles, &
    1427              :                          particles=particles, &
    1428        13653 :                          shell_particles=shell_particles)
    1429              : 
    1430              :       ! Retrieve the reference cell
    1431        13653 :       CALL cell_create(cell_ref)
    1432        13653 :       CALL cell_copy(cell, cell_ref, tag="CELL_OPT_REF")
    1433              : 
    1434              :       ! Load the updated cell information
    1435        13653 :       idg = 3*nparticle
    1436        13653 :       CALL init_cell(cell_ref, hmat=gopt_env%h_ref)
    1437        13653 :       CPASSERT((SIZE(x) == idg + 6))
    1438              : 
    1439        13653 :       IF (update_forces) THEN
    1440              : 
    1441              :          ! Transform particle forces back to reference cell
    1442              :          idg = 1
    1443       339687 :          DO iatom = 1, natom
    1444       334354 :             CALL real_to_scaled(s, x(idg:idg + 2), cell)
    1445       334354 :             CALL scaled_to_real(x(idg:idg + 2), s, cell_ref)
    1446       339687 :             idg = idg + 3
    1447              :          END DO
    1448              : 
    1449              :       ELSE
    1450              : 
    1451              :          ! Update the six independent components in the canonical optimization frame.
    1452       108160 :          gopt_env%cell_env%opt_cell%hmat = 0.0_dp
    1453        33280 :          DO i = 1, 3
    1454        83200 :             DO j = 1, i
    1455        49920 :                idg = idg + 1
    1456        74880 :                gopt_env%cell_env%opt_cell%hmat(j, i) = x(idg)
    1457              :             END DO
    1458              :          END DO
    1459         8320 :          CALL init_cell(gopt_env%cell_env%opt_cell)
    1460         8320 :          IF (gopt_env%spgr%keep_space_group) THEN
    1461          798 :             CALL spgr_project_cell_metric(gopt_env%spgr, gopt_env%cell_env%opt_cell)
    1462              :             ! Keep the optimizer variables synchronized with the projected cell.
    1463          798 :             idg = 3*nparticle
    1464         3192 :             DO i = 1, 3
    1465         7980 :                DO j = 1, i
    1466         4788 :                   idg = idg + 1
    1467         7182 :                   x(idg) = gopt_env%cell_env%opt_cell%hmat(j, i)
    1468              :                END DO
    1469              :             END DO
    1470              :          END IF
    1471              : 
    1472              :          ! Reconstruct the physical cell in the fixed orientation of the input cell.
    1473              :          cell%hmat = MATMUL(gopt_env%cell_env%opt_to_input, &
    1474       648960 :                             gopt_env%cell_env%opt_cell%hmat)
    1475         8320 :          CALL init_cell(cell)
    1476         8320 :          CALL cp_subsys_set(subsys, cell=cell)
    1477              : 
    1478              :          ! Retrieve particle coordinates for the current cell
    1479         8320 :          idg = 1
    1480       635672 :          DO iatom = 1, natom
    1481       627352 :             CALL real_to_scaled(s, x(idg:idg + 2), cell_ref)
    1482       627352 :             shell_index = particles%els(iatom)%shell_index
    1483       627352 :             IF (shell_index == 0) THEN
    1484       307612 :                CALL scaled_to_real(particles%els(iatom)%r, s, cell)
    1485              :             ELSE
    1486       319740 :                CALL scaled_to_real(core_particles%els(shell_index)%r, s, cell)
    1487       319740 :                i = 3*(natom + shell_index - 1) + 1
    1488       319740 :                CALL real_to_scaled(s, x(i:i + 2), cell_ref)
    1489       319740 :                CALL scaled_to_real(shell_particles%els(shell_index)%r, s, cell)
    1490              :                ! Update atomic position due to core and shell motion
    1491       319740 :                mass = particles%els(iatom)%atomic_kind%mass
    1492       319740 :                fc = core_particles%els(shell_index)%atomic_kind%shell%mass_core/mass
    1493       319740 :                fs = shell_particles%els(shell_index)%atomic_kind%shell%mass_shell/mass
    1494              :                particles%els(iatom)%r(1:3) = fc*core_particles%els(shell_index)%r(1:3) + &
    1495      2557920 :                                              fs*shell_particles%els(shell_index)%r(1:3)
    1496              :             END IF
    1497       635672 :             idg = idg + 3
    1498              :          END DO
    1499              :       END IF
    1500              : 
    1501        13653 :       CALL cell_release(cell_ref)
    1502              : 
    1503        13653 :    END SUBROUTINE apply_cell_change
    1504              : 
    1505              : END MODULE gopt_f_methods
        

Generated by: LCOV version 2.0-1