LCOV - code coverage report
Current view: top level - src/45_geomoptim - m_mep.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 17.7 % 412 73
Test Date: 2026-09-21 19:39:32 Functions: 38.5 % 13 5

            Line data    Source code
       1              : !!****m* ABINIT/m_mep
       2              : !! NAME
       3              : !!  m_mep
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module provides several routines and datatypes for the
       7              : !!  Minimal Energy Path (MEP) search implementation.
       8              : !!
       9              : !! COPYRIGHT
      10              : !! Copyright (C) 2012-2026 ABINIT group (MT)
      11              : !! This file is distributed under the terms of the
      12              : !! GNU General Public License, see ~abinit/COPYING
      13              : !! or http://www.gnu.org/copyleft/gpl.txt .
      14              : !!
      15              : !! SOURCE
      16              : 
      17              : #if defined HAVE_CONFIG_H
      18              : #include "config.h"
      19              : #endif
      20              : 
      21              : #include "abi_common.h"
      22              : 
      23              : MODULE m_mep
      24              : 
      25              :  use defs_basis
      26              :  use m_abicore
      27              :  use m_errors
      28              :  use m_dtset
      29              :  use m_xmpi
      30              : 
      31              :  use defs_abitypes, only : MPI_type
      32              :  use m_geometry,    only : gred2fcart, fcart2gred, xcart2xred, xred2xcart, metric
      33              :  use m_bfgs,        only : hessupdt
      34              :  use m_results_img, only : results_img_type, gather_array_img
      35              : 
      36              :  implicit none
      37              : 
      38              :  private
      39              : 
      40              : !public procedures
      41              :  public :: mep_init
      42              :  public :: mep_destroy
      43              :  public :: mep_steepest
      44              :  public :: mep_qmin
      45              :  public :: mep_lbfgs
      46              :  public :: mep_gbfgs
      47              :  public :: mep_rk4
      48              :  public :: mep_img_dotp
      49              :  public :: mep_img_norm
      50              :  public :: mep_img_dotp_red
      51              :  public :: mep_img_norm_red
      52              : !!***
      53              : 
      54              : !!****t* m_mep/mep_type
      55              : !! NAME
      56              : !! mep_type
      57              : !!
      58              : !! FUNCTION
      59              : !! Datatype with the variables required to perform MEP search
      60              : !!
      61              : !! SOURCE
      62              : 
      63              :  type,public :: mep_type
      64              : ! Scalars
      65              :   integer  :: cineb_start   ! Starting iteration for the CI-NEB
      66              :   integer  :: mep_solver    ! Selection of a solver for the ODE
      67              :   integer  :: neb_algo      ! Selection of the variant of the NEB method
      68              :   integer  :: neb_cell_algo ! Selection of the cell modification algorithm
      69              :   integer  :: string_algo   ! Selection of the variant of the String Method
      70              :   real(dp) :: fxcartfactor  ! Time step for steepest descent or RK4
      71              :   real(dp) :: mep_mxstep    ! Selection of a max. step size for the ODE
      72              : ! Arrays
      73              :   integer,pointer      :: iatfix(:,:)=>null() ! Atoms to fix (this pointer is associated with dtset%iatfix)
      74              :   real(dp)             :: neb_spring(2)       ! Spring constants for the NEB method
      75              :   real(dp),allocatable :: bfgs_xprev(:,:,:)   ! BFGS storage (prev positions)
      76              :   real(dp),allocatable :: bfgs_fprev(:,:,:)   ! BFGS storage (prev forces)
      77              :   real(dp),allocatable :: gbfgs_hess(:,:)     ! global-BFGS storage (Hessian matrix)
      78              :   real(dp),allocatable :: lbfgs_hess(:,:,:)   ! local-BFGS storage (Hessian matrix)
      79              :   real(dp),allocatable :: qmin_vel(:,:,:)     ! Quick-min algo storage (velocities)
      80              :   real(dp),allocatable :: rk4_xcart1(:,:,:)   ! 4th-order Runge-Kutta storage
      81              :   real(dp),allocatable :: rk4_fcart1(:,:,:)   ! 4th-order Runge-Kutta storage
      82              :   real(dp),allocatable :: rk4_fcart2(:,:,:)   ! 4th-order Runge-Kutta storage
      83              :   real(dp),allocatable :: rk4_fcart3(:,:,:)   ! 4th-order Runge-Kutta storage
      84              :   real(dp),pointer     :: rprimd_start(:,:,:) ! real space primitive translations at start of the MEP search
      85              :  end type mep_type
      86              : 
      87              : !Public constants
      88              :  !NEB algorithms
      89              :  integer, public :: NEB_ALGO_STANDARD     = 0
      90              :  integer, public :: NEB_ALGO_IMPROVED_TAN = 1
      91              :  integer, public :: NEB_ALGO_CINEB        = 2
      92              :  !Variable-cell NEB algorithms
      93              :  integer, public :: NEB_CELL_ALGO_NONE    = 0
      94              :  integer, public :: NEB_CELL_ALGO_GSSNEB  = 1
      95              :  integer, public :: NEB_CELL_ALGO_VCNEB   = 2
      96              :  !String method algorithms
      97              :  integer, public :: STRING_ALGO_ORIGINAL          = 0
      98              :  integer, public :: STRING_ALGO_SIMPLIFIED_EQUAL  = 1
      99              :  integer, public :: STRING_ALGO_SIMPLIFIED_ENERGY = 2
     100              :  !MEP solvers
     101              :  integer, public :: MEP_SOLVER_STEEPEST = 0
     102              :  integer, public :: MEP_SOLVER_QUICKMIN = 1
     103              :  integer, public :: MEP_SOLVER_LBFGS    = 2
     104              :  integer, public :: MEP_SOLVER_GBFGS    = 3
     105              :  integer, public :: MEP_SOLVER_RK4      = 4
     106              : !!***
     107              : 
     108              : CONTAINS
     109              : 
     110              : !===========================================================
     111              : !!***
     112              : 
     113              : !!****f* m_mep/mep_init
     114              : !! NAME
     115              : !!  mep_init
     116              : !!
     117              : !! FUNCTION
     118              : !!  Initialize a datastructure of type mep_type.
     119              : !!
     120              : !! INPUTS
     121              : !!  dtset <type(dataset_type)>=all input variables in current dataset
     122              : !!
     123              : !! OUTPUT
     124              : !!
     125              : !! SIDE EFFECTS
     126              : !!  mep_param=datastructure of type mep_type.
     127              : !!            several parameters for Minimal Energy Path (MEP) search.
     128              : !!
     129              : !! SOURCE
     130              : 
     131         3975 : subroutine mep_init(dtset,mep_param)
     132              : 
     133              : !Arguments ------------------------------------
     134              : !scalars
     135              :  type(dataset_type),target,intent(in) :: dtset
     136              :  type(mep_type),intent(inout) :: mep_param
     137              : 
     138              : !************************************************************************
     139              : 
     140         3975 :  if((dtset%imgmov==1).or.(dtset%imgmov==2).or.(dtset%imgmov==5))then
     141           29 :    mep_param%cineb_start   = dtset%cineb_start
     142           29 :    mep_param%mep_solver    = dtset%mep_solver
     143           29 :    mep_param%neb_algo      = dtset%neb_algo
     144           29 :    mep_param%neb_cell_algo = dtset%neb_cell_algo
     145           29 :    mep_param%string_algo   = dtset%string_algo
     146           29 :    mep_param%fxcartfactor  = dtset%fxcartfactor
     147           29 :    mep_param%mep_mxstep    = dtset%mep_mxstep
     148           87 :    mep_param%neb_spring    = dtset%neb_spring
     149           29 :    mep_param%iatfix        =>dtset%iatfix
     150           29 :    mep_param%rprimd_start  =>dtset%rprimd_orig
     151              :    !TODO: Q. DELACROIX DID PUT THIS - TO BE CHECKED
     152              :    ! do ii=1,dtset%nimage
     153              :    !   mep_param%rprimd_start(:,:,iimage)=dtset%rprimd_orig(:,:,1)
     154              :    ! end do
     155              :  else
     156         3946 :    mep_param%cineb_start   = -1
     157         3946 :    mep_param%mep_solver    = -1
     158         3946 :    mep_param%neb_algo      = -1
     159         3946 :    mep_param%neb_cell_algo = -1
     160         3946 :    mep_param%string_algo   = -1
     161         3946 :    mep_param%fxcartfactor  = zero
     162         3946 :    mep_param%mep_mxstep    = 100._dp
     163        11838 :    mep_param%neb_spring    = zero
     164         3946 :    nullify(mep_param%iatfix)
     165         3946 :    nullify(mep_param%rprimd_start)
     166              :  end if
     167              : 
     168         3975 : end subroutine mep_init
     169              : !!***
     170              : 
     171              : !----------------------------------------------------------------------
     172              : 
     173              : !!****f* m_mep/mep_destroy
     174              : !! NAME
     175              : !!  mep_destroy
     176              : !!
     177              : !! FUNCTION
     178              : !!  Destroy the content of a datastructure of type mep_type.
     179              : !!
     180              : !! INPUTS
     181              : !!
     182              : !! OUTPUT
     183              : !!
     184              : !! SIDE EFFECTS
     185              : !!  mep_param=datastructure of type mep_type.
     186              : !!            several parameters for Minimal Energy Path (MEP) search.
     187              : !!
     188              : !! SOURCE
     189              : 
     190         3975 : subroutine mep_destroy(mep_param)
     191              : 
     192              : !Arguments ------------------------------------
     193              : !scalars
     194              :  type(mep_type),intent(inout) :: mep_param
     195              : 
     196              : !************************************************************************
     197              : 
     198         3975 :  ABI_SFREE(mep_param%bfgs_xprev)
     199         3975 :  ABI_SFREE(mep_param%gbfgs_hess)
     200         3975 :  ABI_SFREE(mep_param%bfgs_fprev)
     201         3975 :  ABI_SFREE(mep_param%lbfgs_hess)
     202         3975 :  ABI_SFREE(mep_param%qmin_vel)
     203         3975 :  ABI_SFREE(mep_param%rk4_xcart1)
     204         3975 :  ABI_SFREE(mep_param%rk4_fcart1)
     205         3975 :  ABI_SFREE(mep_param%rk4_fcart2)
     206         3975 :  ABI_SFREE(mep_param%rk4_fcart3)
     207              : 
     208         3975 :  nullify(mep_param%iatfix)
     209         3975 :  nullify(mep_param%rprimd_start)
     210              : 
     211         3975 : end subroutine mep_destroy
     212              : !!***
     213              : 
     214              : !----------------------------------------------------------------------
     215              : 
     216              : !!****f* m_mep/mep_steepest
     217              : !! NAME
     218              : !!  mep_steepest
     219              : !!
     220              : !! FUNCTION
     221              : !!  Make a path (string of images) evolve according to a steepest descent algorithm
     222              : !!
     223              : !! INPUTS
     224              : !!  fcart(3,natom_eff,nimage)=cartesian forces in each image along the path
     225              : !!  list_dynimage(nimage)=list of dynamical images.
     226              : !!  mep_param=datastructure of type mep_type.
     227              : !!            several parameters for Minimal Energy Path (MEP) search.
     228              : !!  natom=number of atoms
     229              : !!  natom_eff="effective" number of atoms, including possibly the unit cell vectors
     230              : !!  ndynimage=number of dynamical images along the path
     231              : !!  nimage=number of images (including static ones)
     232              : !!  results_img(nimage)=datastructure that hold data for each image
     233              : !!                      (positions, forces, energy, ...)
     234              : !!  rprimd(3,3,nimage)=dimensional primitive translations for each image along the path
     235              : !!  [use_reduced_coord]=force the use of reduced coordinates instead of cartesian ones
     236              : !!  [rprimd_start(3,3,nimage)]=real space primitive translations at start of the MEP search
     237              : !!                             Mandatory if natom_eff=natom+3
     238              : !!  [strainfact(nimage)]=only for variable cell algorithms. Factor applied to strains
     239              : !!                        to align their dimension to atomic positions.
     240              : !!                        Only valid when use_reduced_coordinates=.false.
     241              : !!                        (essentially used for the GSS-NEB method)
     242              : !!!
     243              : !! OUTPUT
     244              : !!
     245              : !! SIDE EFFECTS
     246              : !!  xcart(3,natom_eff,nimage)=cartesian coordinates of atoms in each image along the path
     247              : !!          before and after time evolution. If natom_eff=natom+3, then the 3 last "atoms"
     248              : !!          are the primitive vectors of the cell
     249              : !!  xred(3,natom_eff,nimage)=reduced coordinates of atoms in each image along the path
     250              : !!          before and after time evolution. If natom_eff=natom+3, then the 3 last "atoms"
     251              : !!          are the primitive vectors of the cell
     252              : !!
     253              : !! SOURCE
     254              : 
     255          138 : subroutine mep_steepest(fcart,list_dynimage,mep_param,natom,natom_eff,ndynimage,nimage,rprimd,xcart,xred, &
     256              : &                       use_reduced_coord,rprimd_start,strainfact) ! optional arguments
     257              : 
     258              : !Arguments ------------------------------------
     259              : !scalars
     260              :  integer,intent(in) :: natom,natom_eff,ndynimage,nimage
     261              :  logical,intent(in),optional :: use_reduced_coord
     262              :  type(mep_type),intent(in) :: mep_param
     263              : !arrays
     264              :  integer,intent(in) :: list_dynimage(ndynimage)
     265              :  real(dp),intent(in) :: fcart(3,natom_eff,nimage)
     266              :  real(dp),intent(inout) :: rprimd(3,3,nimage),xcart(3,natom_eff,nimage),xred(3,natom_eff,nimage)
     267              :  real(dp),intent(in),optional :: rprimd_start(3,3,nimage),strainfact(nimage)
     268              : !Local variables-------------------------------
     269              : !scalars
     270              :  integer :: iatom,idynimage,iimage
     271              :  logical :: use_reduced_coord_
     272              :  real(dp) :: stepsize
     273              :  character(len=500) :: msg
     274              : !arrays
     275              :  real(dp),parameter :: identity_real(3,3)=reshape([one,zero,zero,zero,one,zero,zero,zero,one],[3,3])
     276              :  real(dp) :: mat3(3,3)
     277          138 :  real(dp),allocatable :: xred_old(:,:),xstep(:,:)
     278              : 
     279              : !************************************************************************
     280              : 
     281          138 :  use_reduced_coord_=.false.
     282          138 :  if (present(use_reduced_coord)) use_reduced_coord_=use_reduced_coord
     283              : 
     284          138 :  if (natom_eff>=natom+3.and.(.not.present(rprimd_start))) then
     285            0 :    ABI_BUG("Mandatory arg missing (rprimd_start)!")
     286              :  end if
     287              : 
     288          414 :  ABI_MALLOC(xred_old,(3,natom_eff))
     289          276 :  ABI_MALLOC(xstep,(3,natom_eff))
     290              : 
     291          804 :  do idynimage=1,ndynimage
     292          666 :    iimage=list_dynimage(idynimage)
     293         6534 :    xred_old(:,:)=xred(:,:,iimage)
     294              : 
     295              : !  Compute image step
     296              : !  Note that one uses fcart, for which the sum of forces on all atoms vanish
     297         6534 :    xstep(:,:)=mep_param%fxcartfactor*fcart(:,:,iimage)
     298          666 :    stepsize=mep_img_norm(xstep)
     299          666 :    if (stepsize>=mep_param%mep_mxstep) then
     300            0 :      xstep=xstep*mep_param%mep_mxstep/stepsize
     301            0 :      write(msg,'(a,i3,a)') " Restricting step size of image ",iimage,"."
     302            0 :      call wrtout(std_out,msg,'COLL')
     303            0 :      call wrtout(ab_out ,msg,'COLL')
     304              :    end if
     305              : 
     306              : !  Update positions
     307          666 :    if (use_reduced_coord_) then
     308            0 :      xred(:,:,iimage)=xred(:,:,iimage)+xstep(:,:)
     309            0 :      call xred2xcart(natom,rprimd(:,:,iimage),xcart(:,1:natom,iimage),xred(:,1:natom,iimage))
     310              :    else
     311         6534 :      xcart(:,:,iimage)=xcart(:,:,iimage)+xstep(:,:)
     312          666 :      call xcart2xred(natom,rprimd(:,:,iimage),xcart(:,1:natom,iimage),xred(:,1:natom,iimage))
     313              :    end if
     314              : 
     315              : !  Update unit cell vectors if they are included in the list of "atoms"
     316          666 :    if (natom_eff>=natom+3) then
     317           45 :      if (use_reduced_coord_) then
     318            0 :        mat3(1:3,1:3)=identity_real(1:3,1:3)+xred(:,natom+1:natom+3,iimage)
     319            0 :        rprimd(:,:,iimage)=matmul(mat3(:,:),rprimd_start(:,:,iimage))
     320              :      else
     321          585 :        mat3(1:3,1:3)=xcart(1:3,natom+1:natom+3,iimage)
     322          585 :        if (present(strainfact)) mat3(1:3,1:3)=mat3(1:3,1:3)/strainfact(iimage)
     323              :        rprimd(:,:,iimage)=matmul(rprimd_start(:,:,iimage),mat3(:,:)) &
     324         2880 : &                        +rprimd_start(:,:,iimage)
     325              :      end if
     326              :    end if
     327              : 
     328              : !  In case atom is fixed, we restore its previous value ; forbidden if variable cell
     329          804 :    if (mep_param%neb_cell_algo==NEB_CELL_ALGO_NONE) then
     330         1863 :      do iatom=1,natom
     331         3834 :        if (any(mep_param%iatfix(:,iatom)==1)) then
     332         2340 :          where(mep_param%iatfix(:,iatom)==1)
     333              :            xred(:,iatom,iimage)=xred_old(:,iatom)
     334              :          end where
     335          585 :          call xred2xcart(1,rprimd(:,:,iimage),xcart(:,iatom,iimage),xred(:,iatom,iimage))
     336              :        end if
     337              :      end do
     338              :    end if
     339              : 
     340              :  end do
     341              : 
     342          138 :  ABI_FREE(xred_old)
     343          138 :  ABI_FREE(xstep)
     344              : 
     345          138 : end subroutine mep_steepest
     346              : !!***
     347              : 
     348              : !----------------------------------------------------------------------
     349              : 
     350              : !!****f* m_mep/mep_qmin
     351              : !! NAME
     352              : !!  mep_qmin
     353              : !!
     354              : !! FUNCTION
     355              : !!  Make a path (string of images) evolve according to a quick-minimizer algorithm
     356              : !!
     357              : !! INPUTS
     358              : !!  fcart(3,natom,nimage)=cartesian forces in each image along the path
     359              : !!  itime=time step
     360              : !!  list_dynimage(nimage)=list of dynamical images.
     361              : !!  mep_param=datastructure of type mep_type.
     362              : !!            several parameters for Minimal Energy Path (MEP) search.
     363              : !!  natom=number of atoms
     364              : !!  ndynimage=number of dynamical images along the path
     365              : !!  nimage=number of images (including static ones)
     366              : !!  results_img(nimage)=datastructure that hold data for each image
     367              : !!                      (positions, forces, energy, ...)
     368              : !!  rprimd(3,3,nimage)=dimensional primitive translations for each image along the path
     369              : !!
     370              : !! OUTPUT
     371              : !!
     372              : !! SIDE EFFECTS
     373              : !!  xcart(3,natom,nimage)=cartesian coordinates of atoms in each image along the path
     374              : !!                        before and after time evolution
     375              : !!  xred(3,natom,nimage)=reduced coordinates of atoms in each image along the path
     376              : !!                       before and after time evolution
     377              : !!
     378              : !! SOURCE
     379              : 
     380            0 : subroutine mep_qmin(fcart,itime,list_dynimage,mep_param,natom,ndynimage,nimage,rprimd,xcart,xred)
     381              : 
     382              : !Arguments ------------------------------------
     383              : !scalars
     384              :  integer,intent(in) :: itime,natom,ndynimage,nimage
     385              :  type(mep_type),intent(inout) :: mep_param
     386              : !arrays
     387              :  integer,intent(in) :: list_dynimage(ndynimage)
     388              :  real(dp),intent(in) :: fcart(3,natom,nimage),rprimd(3,3,nimage)
     389              :  real(dp),intent(inout) :: xcart(3,natom,nimage),xred(3,natom,nimage)
     390              : !Local variables-------------------------------
     391              : !scalars
     392              :  integer :: iatom,idynimage,iimage
     393              :  real(dp) :: stepsize,vdotf
     394              :  character(len=500) :: msg
     395              : !arrays
     396              :  real(dp) :: vel_red(3)
     397            0 :  real(dp),allocatable :: xred_old(:,:),xstep(:,:)
     398              : 
     399              : !***********************************************************************
     400              : 
     401              : !Allocate history array (at first time step)
     402            0 :  if (itime==1) then
     403            0 :    ABI_SFREE(mep_param%qmin_vel)
     404            0 :    ABI_MALLOC(mep_param%qmin_vel,(3,natom,ndynimage))
     405            0 :    mep_param%qmin_vel=zero
     406              :  end if
     407              : 
     408            0 :  ABI_MALLOC(xred_old,(3,natom))
     409            0 :  ABI_MALLOC(xstep,(3,natom))
     410              : 
     411            0 :  do idynimage=1,ndynimage
     412            0 :    iimage=list_dynimage(idynimage)
     413            0 :    xred_old(:,:)=xred(:,:,iimage)
     414              : 
     415              : !  Compute velocities
     416            0 :    vdotf=mep_img_dotp(mep_param%qmin_vel(:,:,idynimage),fcart(:,:,iimage))
     417            0 :    if (vdotf>=zero) then
     418              :      mep_param%qmin_vel(:,:,idynimage)=vdotf*fcart(:,:,iimage) &
     419            0 : &                              /mep_img_norm(fcart(:,:,iimage))
     420              :    else
     421            0 :      mep_param%qmin_vel(:,:,idynimage)=zero
     422            0 :      write(msg,'(a,i3,a)') " Setting velocities of image ",iimage," to zero."
     423            0 :      call wrtout(std_out,msg,'COLL')
     424            0 :      call wrtout(ab_out ,msg,'COLL')
     425              :    end if
     426              :    mep_param%qmin_vel(:,:,idynimage)=mep_param%qmin_vel(:,:,idynimage) &
     427            0 : &                   +mep_param%fxcartfactor*fcart(:,:,iimage)
     428              : 
     429              : !  Compute image step
     430            0 :    xstep(:,:)=mep_param%fxcartfactor*mep_param%qmin_vel(:,:,idynimage)
     431            0 :    stepsize=mep_img_norm(xstep)
     432            0 :    if (stepsize>=mep_param%mep_mxstep) then
     433            0 :      xstep=xstep*mep_param%mep_mxstep/stepsize
     434            0 :      write(msg,'(a,i3,a)') " Restricting step size of image ",iimage,"."
     435            0 :      call wrtout(std_out,msg,'COLL')
     436            0 :      call wrtout(ab_out ,msg,'COLL')
     437              :    end if
     438              : 
     439              : !  Update positions
     440            0 :    xcart(:,:,iimage)=xcart(:,:,iimage)+xstep(:,:)
     441            0 :    call xcart2xred(natom,rprimd(:,:,iimage),xcart(:,:,iimage),xred(:,:,iimage))
     442              : 
     443              : !  In case atom is fixed, we restore its previous value
     444            0 :    do iatom=1,natom
     445            0 :      if (any(mep_param%iatfix(:,iatom)==1)) then
     446            0 :        call xcart2xred(1,rprimd(:,:,iimage),mep_param%qmin_vel(:,iatom,idynimage),vel_red)
     447            0 :        where(mep_param%iatfix(:,iatom)==1)
     448              :          xred(:,iatom,iimage)=xred_old(:,iatom)
     449              :          vel_red(:)=zero
     450              :        end where
     451            0 :        call xred2xcart(1,rprimd(:,:,iimage),xcart(:,iatom,iimage),xred(:,iatom,iimage))
     452            0 :        call xred2xcart(1,rprimd(:,:,iimage),mep_param%qmin_vel(:,iatom,idynimage),vel_red)
     453              :      end if
     454              :    end do
     455              : 
     456              :  end do
     457              : 
     458            0 :  ABI_FREE(xred_old)
     459            0 :  ABI_FREE(xstep)
     460              : 
     461            0 : end subroutine mep_qmin
     462              : !!***
     463              : 
     464              : !----------------------------------------------------------------------
     465              : 
     466              : !!****f* m_mep/mep_lbfgs
     467              : !! NAME
     468              : !!  mep_lbfgs
     469              : !!
     470              : !! FUNCTION
     471              : !!  Make a path (string of images) evolve according to a
     472              : !!  local Broyden-Fletcher-Goldfarb-Shanno (BFGS) algorithm
     473              : !!
     474              : !! INPUTS
     475              : !!  itime=time step
     476              : !!  list_dynimage(nimage)=list of dynamical images.
     477              : !!  mep_param=datastructure of type mep_type.
     478              : !!            several parameters for Minimal Energy Path (MEP) search.
     479              : !!  natom=number of atoms
     480              : !!  ndynimage=number of dynamical images along the path
     481              : !!  nimage=number of images (including static ones)
     482              : !!  rprimd(3,3,nimage)=dimensional primitive translations for each image along the path
     483              : !!
     484              : !! OUTPUT
     485              : !!
     486              : !! SIDE EFFECTS
     487              : !!  mep_param=datastructure of type mep_type.
     488              : !!            History for Runge-Kutta algorithm is filled up
     489              : !!  xcart(3,natom,nimage)=cartesian coordinates of atoms in each image along the path
     490              : !!                        before and after time evolution
     491              : !!  xred(3,natom,nimage)=reduced coordinates of atoms in each image along the path
     492              : !!                       before and after time evolution
     493              : !!
     494              : !! NOTES
     495              : !!  Could see Numerical Recipes (Fortran), 1986, page 307.
     496              : !!
     497              : !! SOURCE
     498              : 
     499            0 : subroutine mep_lbfgs(fcart,itime,list_dynimage,mep_param,natom,ndynimage,&
     500            0 : &                    nimage,rprimd,xcart,xred)
     501              : 
     502              : !Arguments ------------------------------------
     503              : !scalars
     504              :  integer,intent(in) :: itime,natom,ndynimage,nimage
     505              :  type(mep_type),intent(inout) :: mep_param
     506              : !arrays
     507              :  integer,intent(in) :: list_dynimage(ndynimage)
     508              :  real(dp),intent(in) :: rprimd(3,3,nimage)
     509              :  real(dp),intent(in) :: fcart(3,natom,nimage)
     510              :  real(dp),intent(inout) :: xcart(3,natom,nimage),xred(3,natom,nimage)
     511              : !Local variables-------------------------------
     512              : !scalars
     513              :  integer :: iatom,idynimage,ii,iimage,indi,indj,jatom,jj
     514              :  logical :: reset
     515              :  real(dp),parameter :: initial_Hessian=1._dp ! in Bohr^2/Hartree
     516              :  real(dp) :: dot1,dot2,stepsize,ucvol
     517              :  character(len=500) :: msg
     518              : !arrays
     519              :  real(dp) :: gprimd(3,3),gmet(3,3),rmet(3,3)
     520            0 :  real(dp),allocatable :: gred(:,:),xstep(:,:)
     521              : 
     522              : !************************************************************************
     523              : 
     524              : !Allocate history array (at first time step)
     525            0 :  if (itime==1) then
     526            0 :    ABI_SFREE(mep_param%bfgs_xprev)
     527            0 :    ABI_SFREE(mep_param%bfgs_fprev)
     528            0 :    ABI_SFREE(mep_param%lbfgs_hess)
     529            0 :    ABI_MALLOC(mep_param%bfgs_xprev,(3,natom,ndynimage))
     530            0 :    ABI_MALLOC(mep_param%bfgs_fprev,(3,natom,ndynimage))
     531            0 :    ABI_MALLOC(mep_param%lbfgs_hess,(3*natom,3*natom,ndynimage))
     532            0 :    mep_param%bfgs_xprev=zero
     533            0 :    mep_param%bfgs_fprev=zero
     534              :  end if
     535              : 
     536              : !Temporary storage
     537            0 :  ABI_MALLOC(gred,(3,natom))
     538            0 :  ABI_MALLOC(xstep,(3,natom))
     539              : 
     540              : !Loop over images
     541            0 :  do idynimage=1,ndynimage
     542            0 :    iimage=list_dynimage(idynimage)
     543            0 :    call metric(gmet,gprimd,-1,rmet,rprimd(:,:,iimage),ucvol)
     544            0 :    call fcart2gred(fcart(:,:,iimage),gred,rprimd(:,:,iimage),natom)
     545              : 
     546              : !  Test if a reset is needed
     547            0 :    reset=.false.
     548            0 :    if (itime>1) then
     549            0 :      dot1=mep_img_dotp(mep_param%bfgs_fprev(:,:,idynimage),gred)
     550              :      dot2=mep_img_dotp(mep_param%bfgs_fprev(:,:,idynimage), &
     551            0 : &                      mep_param%bfgs_fprev(:,:,idynimage))
     552              : !     dot1=mep_img_dotp_red(rmet,mep_param%bfgs_fprev(:,:,idynimage),gred)
     553              : !     dot2=mep_img_dotp_red(rmet,mep_param%bfgs_fprev(:,:,idynimage), &
     554              : !&                               mep_param%bfgs_fprev(:,:,idynimage))
     555            0 :      reset=((dot2<two*abs(dot1)).or.abs(dot2)<tol8)
     556              :      if (reset) then
     557            0 :        write(msg,'(a,i3,a)') " Resetting Hessian matrix for image ",iimage,"."
     558            0 :        call wrtout(std_out,msg,'COLL')
     559            0 :        call wrtout(ab_out ,msg,'COLL')
     560              :      end if
     561              :    end if
     562              : 
     563              : !  ===> First step or reset: initialize the Hessian matrix (in reduced coordinates)
     564            0 :    if (itime==1.or.reset) then
     565            0 :      mep_param%lbfgs_hess(:,:,idynimage)=zero
     566            0 :      do iatom=1,natom
     567            0 :        indi=3*(iatom-1)
     568            0 :        do ii=1,3
     569            0 :          do jj=1,3
     570            0 :            if (mep_param%iatfix(ii,iatom)==0.and. &
     571            0 : &              mep_param%iatfix(jj,iatom)==0) then
     572            0 :              mep_param%lbfgs_hess(indi+ii,indi+jj,idynimage)=gmet(ii,jj)*initial_Hessian
     573              :            end if
     574              :          end do
     575              :        end do
     576              :      end do
     577              : 
     578              : !  ===> Other steps: update the Hessian matrix
     579              :    else
     580              :      call hessupdt(mep_param%lbfgs_hess(:,:,idynimage),&
     581              : &                  mep_param%iatfix,natom,3*natom, &
     582              :                    xred(:,:,iimage),mep_param%bfgs_xprev(:,:,idynimage),&
     583            0 :                    gred(:,:),mep_param%bfgs_fprev(:,:,idynimage))
     584              :    end if
     585              : 
     586              : !  Update history
     587            0 :    mep_param%bfgs_xprev(:,:,idynimage)=xred(:,:,iimage)
     588            0 :    mep_param%bfgs_fprev(:,:,idynimage)=gred(:,:)
     589              : 
     590              : !  Compute image step
     591            0 :    xstep=zero
     592            0 :    do iatom=1,natom
     593            0 :      indi=3*(iatom-1)
     594            0 :      do ii=1,3
     595            0 :        do jatom=1,natom
     596            0 :          indj=3*(jatom-1)
     597            0 :          do jj=1,3
     598              :            xstep(ii,iatom)=xstep(ii,iatom) &
     599            0 : &             -mep_param%lbfgs_hess(indi+ii,indj+jj,idynimage)*gred(jj,jatom)
     600              :          end do
     601              :        end do
     602              :      end do
     603              :    end do
     604              : 
     605              : !  Restrict image step size
     606            0 :    stepsize=mep_img_norm_red(rmet,xstep)
     607            0 :    if (stepsize>=mep_param%mep_mxstep) then
     608            0 :      xstep=xstep*mep_param%mep_mxstep/stepsize
     609            0 :      write(msg,'(a,i3,a)') " Restricting BFGS step size of image ",iimage,"."
     610            0 :      call wrtout(std_out,msg,'COLL')
     611            0 :      call wrtout(ab_out ,msg,'COLL')
     612              :    end if
     613              : 
     614              : !  Update positions
     615            0 :    xred(:,:,iimage)=xred(:,:,iimage)+xstep(:,:)
     616              : 
     617              : !  In case atom is fixed, we restore its previous value
     618            0 :    where(mep_param%iatfix(:,:)==1)
     619              :      xred(:,:,iimage)=mep_param%bfgs_xprev(:,:,idynimage)
     620              :    end where
     621              : 
     622            0 :    call xred2xcart(natom,rprimd(:,:,iimage),xcart(:,:,iimage),xred(:,:,iimage))
     623              : 
     624              : !End loop over images
     625              :  end do
     626              : 
     627            0 :  ABI_FREE(gred)
     628            0 :  ABI_FREE(xstep)
     629              : 
     630            0 : end subroutine mep_lbfgs
     631              : !!***
     632              : 
     633              : !----------------------------------------------------------------------
     634              : 
     635              : !!****f* m_mep/mep_gbfgs
     636              : !! NAME
     637              : !!  mep_gbfgs
     638              : !!
     639              : !! FUNCTION
     640              : !!  Make a path (string of images) evolve according to a
     641              : !!  global Broyden-Fletcher-Goldfarb-Shanno (BFGS) algorithm
     642              : !!
     643              : !! INPUTS
     644              : !!  itime=time step
     645              : !!  list_dynimage(nimage)=list of dynamical images.
     646              : !!  mep_param=datastructure of type mep_type.
     647              : !!  mpi_enreg=MPI-parallelisation information
     648              : !!  mep_param=several parameters for Minimal Energy Path (MEP) search.
     649              : !!  natom=number of atoms
     650              : !!  ndynimage=number of dynamical images along the path
     651              : !!  nimage=number of images (including static ones)
     652              : !!  nimage_tot=total number of images
     653              : !!  rprimd(3,3,nimage)=dimensional primitive translations for each image along the path
     654              : !!
     655              : !! OUTPUT
     656              : !!
     657              : !! SIDE EFFECTS
     658              : !!  mep_param=datastructure of type mep_type.
     659              : !!            History for Runge-Kutta algorithm is filled up
     660              : !!  xcart(3,natom,nimage)=cartesian coordinates of atoms in each image along the path
     661              : !!                        before and after time evolution
     662              : !!  xred(3,natom,nimage)=reduced coordinates of atoms in each image along the path
     663              : !!                       before and after time evolution
     664              : !!
     665              : !! NOTES
     666              : !!  Could see Numerical Recipes (Fortran), 1986, page 307.
     667              : !!  Has to work in cartesian coordinates
     668              : !!
     669              : !! SOURCE
     670              : 
     671            0 : subroutine mep_gbfgs(fcart,itime,list_dynimage,mep_param,mpi_enreg,natom,&
     672            0 : &                    ndynimage,nimage,nimage_tot,rprimd,xcart,xred)
     673              : 
     674              : !Arguments ------------------------------------
     675              : !scalars
     676              :  integer,intent(in) :: itime,natom,ndynimage,nimage,nimage_tot
     677              :  type(mep_type),intent(inout) :: mep_param
     678              :  type(MPI_type),intent(in) :: mpi_enreg
     679              : !arrays
     680              :  integer,intent(in) :: list_dynimage(ndynimage)
     681              :  real(dp),intent(in) :: fcart(3,natom,nimage),rprimd(3,3,nimage)
     682              :  real(dp),intent(inout) :: xcart(3,natom,nimage),xred(3,natom,nimage)
     683              : !Local variables-------------------------------
     684              : !scalars
     685              :  integer :: iatom,idynimage,ii,iimage,iimage_tot,indi,indj,ierr
     686              :  integer :: jdynimage,jatom,jj,mu,ndynimage_tot,nu
     687              :  logical :: reset
     688              :  real(dp),parameter :: initial_Hessian=1._dp ! in Bohr^2/Hartree
     689              :  real(dp) :: dot1,dot2,stepsize,ucvol
     690              :  character(len=500) :: msg
     691              : !arrays
     692            0 :  integer,allocatable :: dynimage_tot(:),iatfix_fake(:,:),ind_dynimage_tot(:)
     693            0 :  integer,allocatable :: list_dynimage_tot(:)
     694              :  real(dp) :: favg(3),gprimd(3,3),gmet(3,3),rmet(3,3)
     695            0 :  real(dp),allocatable :: buffer(:,:),buffer_all(:,:),gred(:,:)
     696            0 :  real(dp),allocatable :: fcart_all(:,:,:),fcartp_all(:,:,:)
     697            0 :  real(dp),allocatable :: gmet_all(:,:,:),gprimd_all(:,:,:),rprimd_all(:,:,:)
     698            0 :  real(dp),allocatable :: xcart_all(:,:,:),xcartp_all(:,:,:),xred_old(:,:),xstep_all(:,:,:)
     699              : 
     700              : !************************************************************************
     701              : 
     702              : !Retrieve indexes of all dynamical images
     703            0 :  ABI_MALLOC(ind_dynimage_tot,(nimage_tot))
     704            0 :  if (mpi_enreg%paral_img==1) then
     705            0 :    ABI_MALLOC(dynimage_tot,(nimage_tot))
     706            0 :    dynimage_tot=0
     707            0 :    do idynimage=1,ndynimage
     708            0 :      iimage=list_dynimage(idynimage)
     709            0 :      iimage_tot=mpi_enreg%my_imgtab(iimage)
     710            0 :      dynimage_tot(iimage_tot)=1
     711              :    end do
     712            0 :    call xmpi_sum(dynimage_tot,mpi_enreg%comm_img,ierr)
     713            0 :    ndynimage_tot=count(dynimage_tot(:)>0)
     714            0 :    ABI_MALLOC(list_dynimage_tot,(ndynimage_tot))
     715            0 :    idynimage=0;ind_dynimage_tot(:)=-1
     716            0 :    do iimage_tot=1,nimage_tot
     717            0 :      if (dynimage_tot(iimage_tot)>0) then
     718            0 :        idynimage=idynimage+1
     719            0 :        ind_dynimage_tot(iimage_tot)=idynimage
     720            0 :        list_dynimage_tot(idynimage)=iimage_tot
     721              :      end if
     722              :    end do
     723            0 :    ABI_FREE(dynimage_tot)
     724              :  else
     725            0 :    ndynimage_tot=ndynimage
     726            0 :    ABI_MALLOC(list_dynimage_tot,(ndynimage))
     727            0 :    ind_dynimage_tot(:)=-1
     728            0 :    do idynimage=1,ndynimage
     729            0 :      ind_dynimage_tot(list_dynimage(idynimage))=idynimage
     730            0 :      list_dynimage_tot(idynimage)=list_dynimage(idynimage)
     731              :    end do
     732              :  end if
     733              : 
     734              : !Allocate history array (at first time step)
     735            0 :  if (itime==1) then
     736            0 :    ABI_SFREE(mep_param%bfgs_xprev)
     737            0 :    ABI_SFREE(mep_param%bfgs_fprev)
     738            0 :    ABI_SFREE(mep_param%gbfgs_hess)
     739            0 :    ABI_MALLOC(mep_param%bfgs_xprev,(3,natom,ndynimage))
     740            0 :    ABI_MALLOC(mep_param%bfgs_fprev,(3,natom,ndynimage))
     741            0 :    ABI_MALLOC(mep_param%gbfgs_hess,(3*natom*ndynimage_tot,3*natom*ndynimage_tot))
     742            0 :    mep_param%bfgs_xprev=zero
     743            0 :    mep_param%bfgs_fprev=zero
     744              :  end if
     745              : 
     746              : !Retrieve positions and forces for all images
     747            0 :  ABI_MALLOC(xcart_all,(3,natom,ndynimage_tot))
     748            0 :  ABI_MALLOC(fcart_all,(3,natom,ndynimage_tot))
     749            0 :  ABI_MALLOC(xcartp_all,(3,natom,ndynimage_tot))
     750            0 :  ABI_MALLOC(fcartp_all,(3,natom,ndynimage_tot))
     751            0 :  ABI_MALLOC(rprimd_all,(3,3,ndynimage_tot))
     752            0 :  ABI_MALLOC(gprimd_all,(3,3,ndynimage_tot))
     753            0 :  ABI_MALLOC(gmet_all,(3,3,ndynimage_tot))
     754            0 :  if (mpi_enreg%paral_img==1) then
     755            0 :    ABI_MALLOC(buffer,(12*natom+27,nimage))
     756            0 :    ABI_MALLOC(buffer_all,(12*natom+27,nimage_tot))
     757            0 :    buffer=zero
     758            0 :    do idynimage=1,ndynimage
     759            0 :      iimage=list_dynimage(idynimage)
     760            0 :      call metric(gmet,gprimd,-1,rmet,rprimd(:,:,iimage),ucvol)
     761            0 :      buffer(         1:3 *natom  ,iimage)=reshape(xcart(:,:,iimage),(/3*natom/))
     762            0 :      buffer(3 *natom+1:6 *natom  ,iimage)=reshape(fcart(:,:,iimage),(/3*natom/))
     763            0 :      buffer(6 *natom+1:9 *natom  ,iimage)=reshape(mep_param%bfgs_xprev(:,:,idynimage),(/3*natom/))
     764            0 :      buffer(9 *natom+1:12*natom  ,iimage)=reshape(mep_param%bfgs_fprev(:,:,idynimage),(/3*natom/))
     765            0 :      buffer(12*natom+1:12*natom+9,iimage)=reshape(rprimd(:,:,iimage),(/9/))
     766            0 :      buffer(12*natom+10:12*natom+18,iimage)=reshape(gprimd(:,:),(/9/))
     767            0 :      buffer(12*natom+19:12*natom+27,iimage)=reshape(gmet(:,:),(/9/))
     768              :    end do
     769            0 :    call gather_array_img(buffer,buffer_all,mpi_enreg,allgather=.true.)
     770            0 :    do idynimage=1,ndynimage_tot
     771            0 :      iimage_tot=list_dynimage_tot(idynimage)
     772            0 :      do iatom=1,natom
     773            0 :        indi=12*(iatom-1)
     774            0 :        do ii=1,3
     775            0 :          xcart_all (ii,iatom,idynimage)= buffer_all(indi  +ii,iimage_tot)
     776            0 :          fcart_all (ii,iatom,idynimage)=-buffer_all(indi+3+ii,iimage_tot) ! use fcart=-cartesian_force
     777            0 :          xcartp_all(ii,iatom,idynimage)= buffer_all(indi+6+ii,iimage_tot)
     778            0 :          fcartp_all(ii,iatom,idynimage)= buffer_all(indi+9+ii,iimage_tot)
     779              :        end do
     780              :      end do
     781            0 :      indi=12*natom
     782            0 :      rprimd_all(1:3,1:3,idynimage)=reshape(buffer_all(indi+ 1:indi+ 9,iimage_tot),(/3,3/))
     783            0 :      gprimd_all(1:3,1:3,idynimage)=reshape(buffer_all(indi+10:indi+18,iimage_tot),(/3,3/))
     784            0 :      gmet_all  (1:3,1:3,idynimage)=reshape(buffer_all(indi+19:indi+27,iimage_tot),(/3,3/))
     785              :    end do
     786            0 :    ABI_FREE(buffer)
     787            0 :    ABI_FREE(buffer_all)
     788              :  else
     789            0 :    do idynimage=1,ndynimage
     790            0 :      iimage=list_dynimage(idynimage)
     791            0 :      xcart_all(:,:,idynimage)= xcart(:,:,iimage)
     792            0 :      fcart_all(:,:,idynimage)=-fcart(:,:,iimage) ! use fcart=-cartesian_force
     793            0 :      xcartp_all(:,:,idynimage)=mep_param%bfgs_xprev(:,:,idynimage)
     794            0 :      fcartp_all(:,:,idynimage)=mep_param%bfgs_fprev(:,:,idynimage)
     795            0 :      rprimd_all(:,:,idynimage)=rprimd(:,:,iimage)
     796            0 :      call metric(gmet_all(:,:,idynimage),gprimd_all(:,:,idynimage),-1,rmet,rprimd(:,:,iimage),ucvol)
     797              :    end do
     798              :  end if
     799              : 
     800              : !Test if a reset is needed
     801            0 :  reset=.false.
     802            0 :  if (itime>1) then
     803              :    dot1=zero;dot2=zero
     804            0 :    do idynimage=1,ndynimage_tot
     805            0 :      dot1=dot2+mep_img_dotp(fcartp_all(:,:,idynimage),fcart_all (:,:,idynimage))
     806            0 :      dot2=dot1+mep_img_dotp(fcartp_all(:,:,idynimage),fcartp_all(:,:,idynimage))
     807              :    end do
     808            0 :    reset=((dot2<two*abs(dot1)).or.abs(dot2)<tol8)
     809              :    if (reset) then
     810            0 :      msg=' Resetting Hessian matrix.'
     811            0 :      call wrtout(std_out,msg,'COLL')
     812            0 :      call wrtout(ab_out ,msg,'COLL')
     813              :    end if
     814              :  end if
     815              : 
     816              : !===> First step or reset: initialize the Hessian matrix
     817            0 :  if (itime==1.or.reset) then
     818            0 :    mep_param%gbfgs_hess(:,:)=zero
     819            0 :    do idynimage=1,ndynimage_tot
     820            0 :      indi=3*natom*(idynimage-1)
     821            0 :      do iatom=1,natom
     822            0 :        do mu=1,3
     823            0 :          do nu=1,3
     824            0 :            do ii=1,3
     825            0 :              do jj=1,3
     826            0 :                if (mep_param%iatfix(ii,iatom)==0.and. &
     827            0 : &                  mep_param%iatfix(jj,iatom)==0) then
     828              :                    mep_param%gbfgs_hess(indi+mu,indi+nu)=mep_param%gbfgs_hess(indi+mu,indi+nu) &
     829              : &                    +rprimd_all(mu,ii,idynimage)*rprimd_all(nu,jj,idynimage) &
     830            0 : &                    *gmet_all(ii,jj,idynimage)*initial_Hessian
     831              :                end if
     832              :              end do
     833              :            end do
     834              :          end do
     835              :        end do
     836            0 :        indi=indi+3
     837              :      end do
     838              :    end do
     839              : 
     840              : !===> Other steps: update the Hessian matrix
     841              :  else
     842              : 
     843              : !  Impose here f-fprev=0 (cannot be done inside hessupdt in cartesian coordinates)
     844            0 :    ABI_MALLOC(gred,(3,natom))
     845            0 :    do idynimage=1,ndynimage_tot
     846            0 :      fcartp_all(:,:,idynimage)=fcartp_all(:,:,idynimage)-fcart_all(:,:,idynimage)
     847            0 :      call fcart2gred(fcartp_all(:,:,idynimage),gred,rprimd_all(:,:,idynimage),natom)
     848            0 :      where (mep_param%iatfix(:,:)==1) ! iatfix is defined in reduced coordinates
     849              :        gred(:,:)=zero
     850              :      end where
     851            0 :      call gred2fcart(favg,.TRUE.,fcartp_all(:,:,idynimage),gred,gprimd_all(:,:,idynimage),natom)
     852            0 :      do iatom=1,natom
     853              :        fcartp_all(:,iatom,idynimage)=fcartp_all(:,iatom,idynimage) &
     854            0 : &                                   +fcart_all(:,iatom,idynimage)+favg(:)
     855              :      end do
     856              :    end do
     857            0 :    ABI_FREE(gred)
     858              : 
     859              : !  f-fprev=0 has already been imposed for fixed atoms:
     860              : !  we call hessupdt with no fixed atom
     861            0 :    ABI_MALLOC(iatfix_fake,(3,natom))
     862            0 :    iatfix_fake(:,:)=0
     863              :    call hessupdt(mep_param%gbfgs_hess,&
     864              : &                iatfix_fake,natom,3*natom*ndynimage_tot, &
     865              :                  xcart_all,xcartp_all,fcart_all,fcartp_all, &
     866            0 : &                nimage=ndynimage_tot)
     867            0 :    ABI_FREE(iatfix_fake)
     868              :  end if
     869              : 
     870              : !Free memory
     871            0 :  ABI_FREE(xcart_all)
     872            0 :  ABI_FREE(xcartp_all)
     873            0 :  ABI_FREE(fcartp_all)
     874            0 :  ABI_FREE(rprimd_all)
     875            0 :  ABI_FREE(gprimd_all)
     876            0 :  ABI_FREE(gmet_all)
     877              : 
     878              : !Update history
     879            0 :  do idynimage=1,ndynimage
     880            0 :    iimage=list_dynimage(idynimage)
     881            0 :    mep_param%bfgs_xprev(:,:,idynimage)=xcart(:,:,iimage)
     882            0 :    mep_param%bfgs_fprev(:,:,idynimage)=fcart(:,:,iimage)
     883              :  end do
     884              : 
     885              : !Compute image step
     886            0 :  ABI_MALLOC(xstep_all,(3,natom,ndynimage_tot))
     887            0 :  xstep_all=zero
     888            0 :  do idynimage=1,ndynimage_tot
     889            0 :    indi=3*natom*(idynimage-1)
     890            0 :    do iatom=1,natom
     891            0 :      do ii=1,3
     892            0 :        do jdynimage=1,ndynimage_tot
     893            0 :          indj=3*natom*(jdynimage-1)
     894            0 :          do jatom=1,natom
     895            0 :            do jj=1,3
     896              : !            Be careful: minus sign because fcart=-cartesian_force
     897              :              xstep_all(ii,iatom,idynimage)=xstep_all(ii,iatom,idynimage) &
     898              : &                           -fcart_all(jj,jatom,jdynimage) &
     899            0 : &                           *mep_param%gbfgs_hess(indi+ii,indj+jj)
     900              :            end do
     901            0 :            indj=indj+3
     902              :          end do
     903              :        end do
     904              :      end do
     905            0 :      indi=indi+3
     906              :    end do
     907              :  end do
     908              : 
     909              : !Restrict image step size
     910              :  stepsize=zero
     911            0 :  do idynimage=1,ndynimage_tot
     912            0 :    stepsize=stepsize+mep_img_dotp(xstep_all(:,:,idynimage),xstep_all(:,:,idynimage))
     913              :  end do
     914            0 :  stepsize=sqrt(stepsize)
     915            0 :  if (stepsize>=mep_param%mep_mxstep*dble(ndynimage_tot)) then
     916            0 :    xstep_all=xstep_all*mep_param%mep_mxstep*dble(ndynimage_tot)/stepsize
     917            0 :    write(msg,'(a,i3,a)') " Restricting BFGS step size."
     918            0 :    call wrtout(std_out,msg,'COLL')
     919            0 :    call wrtout(ab_out ,msg,'COLL')
     920              :  end if
     921              : 
     922              : !Update positions
     923            0 :  ABI_MALLOC(xred_old,(3,natom))
     924            0 :  do idynimage=1,ndynimage
     925            0 :    iimage=list_dynimage(idynimage)
     926            0 :    iimage_tot=mpi_enreg%my_imgtab(iimage)
     927            0 :    xred_old(:,:)=xred(:,:,iimage)
     928            0 :    xcart(:,:,iimage)=xcart(:,:,iimage)+xstep_all(:,:,ind_dynimage_tot(iimage_tot))
     929            0 :    call xcart2xred(natom,rprimd(:,:,iimage),xcart(:,:,iimage),xred(:,:,iimage))
     930              : !  In case atom is fixed, we restore its previous value
     931            0 :    do iatom=1,natom
     932            0 :      if (any(mep_param%iatfix(:,iatom)==1)) then
     933            0 :        where(mep_param%iatfix(:,iatom)==1)
     934              :          xred(:,iatom,iimage)=xred_old(:,iatom)
     935              :        end where
     936            0 :        call xred2xcart(1,rprimd(:,:,iimage),xcart(:,iatom,iimage),xred(:,iatom,iimage))
     937              :      end if
     938              :    end do
     939              :  end do
     940            0 :  ABI_FREE(xred_old)
     941              : 
     942              : !Free memory
     943            0 :  ABI_FREE(fcart_all)
     944            0 :  ABI_FREE(xstep_all)
     945            0 :  ABI_FREE(ind_dynimage_tot)
     946            0 :  ABI_FREE(list_dynimage_tot)
     947              : 
     948            0 : end subroutine mep_gbfgs
     949              : !!***
     950              : 
     951              : !----------------------------------------------------------------------
     952              : 
     953              : !!****f* m_mep/mep_rk4
     954              : !! NAME
     955              : !!  mep_rk4
     956              : !!
     957              : !! FUNCTION
     958              : !!  Make a path (string of images) evolve according to a fourfth-order Runge-Kutta algorithm
     959              : !!
     960              : !! INPUTS
     961              : !!  itime=time step
     962              : !!  list_dynimage(nimage)=list of dynamical images.
     963              : !!  mep_param=datastructure of type mep_type.
     964              : !!            several parameters for Minimal Energy Path (MEP) search.
     965              : !!  natom=number of atoms
     966              : !!  ndynimage=number of dynamical images along the path
     967              : !!  nimage=number of images (including static ones)
     968              : !!
     969              : !! OUTPUT
     970              : !!
     971              : !! SIDE EFFECTS
     972              : !!  mep_param=datastructure of type mep_type.
     973              : !!            History for Runge-Kutta algorithm is filled up
     974              : !!  xcart(3,natom,nimage)=cartesian coordinates of atoms in each image along the path
     975              : !!                        before and after time evolution
     976              : !!                        after time evolution
     977              : !!  xred(3,natom,nimage)=reduced coordinates of atoms in each image along the path
     978              : !!                       before and after time evolution
     979              : !!
     980              : !! SOURCE
     981              : 
     982            0 : subroutine mep_rk4(fcart,itime,list_dynimage,mep_param,natom,ndynimage,nimage,rprimd,xcart,xred)
     983              : 
     984              : !Arguments ------------------------------------
     985              : !scalars
     986              :  integer,intent(in) :: itime,natom,ndynimage,nimage
     987              :  type(mep_type),intent(inout) :: mep_param
     988              : !arrays
     989              :  integer,intent(in) :: list_dynimage(ndynimage)
     990              :  real(dp),intent(in) :: rprimd(3,3,nimage)
     991              :  real(dp),intent(in) :: fcart(3,natom,nimage)
     992              :  real(dp),intent(inout) :: xcart(3,natom,nimage),xred(3,natom,nimage)
     993              : !Local variables-------------------------------
     994              : !scalars
     995              :  integer,save :: istep_rk=0
     996              :  integer :: iatom,idynimage,iimage
     997              :  real(dp) :: stepsize
     998              :  character(len=500) :: msg
     999              : !arrays
    1000            0 :  real(dp),allocatable :: xred_old(:,:),xstep(:,:)
    1001              : 
    1002              : !************************************************************************
    1003              : 
    1004              : !Step for RK4 algorithm
    1005            0 :  istep_rk=mod(itime,4)
    1006              : 
    1007              : !Store data according to Runge-Kutta algo step
    1008            0 :  if (istep_rk==1) then
    1009            0 :    ABI_SFREE(mep_param%rk4_xcart1)
    1010            0 :    ABI_SFREE(mep_param%rk4_fcart1)
    1011            0 :    ABI_MALLOC(mep_param%rk4_xcart1,(3,natom,nimage))
    1012            0 :    ABI_MALLOC(mep_param%rk4_fcart1,(3,natom,nimage))
    1013            0 :    mep_param%rk4_xcart1 = xcart
    1014            0 :    mep_param%rk4_fcart1 = fcart
    1015            0 :  else if (istep_rk==2) then
    1016            0 :    ABI_SFREE(mep_param%rk4_fcart2)
    1017            0 :    ABI_MALLOC(mep_param%rk4_fcart2,(3,natom,nimage))
    1018            0 :    mep_param%rk4_fcart2 = fcart
    1019            0 :  else if (istep_rk==3) then
    1020            0 :    ABI_SFREE(mep_param%rk4_fcart3)
    1021            0 :    ABI_MALLOC(mep_param%rk4_fcart3,(3,natom,nimage))
    1022            0 :    mep_param%rk4_fcart3 = fcart
    1023              :  end if
    1024              : 
    1025            0 :  ABI_MALLOC(xred_old,(3,natom))
    1026            0 :  if (istep_rk==0) then
    1027            0 :    ABI_MALLOC(xstep,(3,natom))
    1028              :  end if
    1029              : 
    1030            0 :  do idynimage=1,ndynimage
    1031            0 :    iimage=list_dynimage(idynimage)
    1032            0 :    xred_old(:,:)=xred(:,:,iimage)
    1033              : 
    1034              : !  Note that one uses fcart, for which the sum of forces on all atoms vanish
    1035              : 
    1036              : !  Intermediate Runge-Kutta step 1
    1037            0 :    if      (istep_rk==1) then
    1038              :      xcart(:,:,iimage)=mep_param%rk4_xcart1(:,:,iimage) &
    1039            0 : &       -half*mep_param%fxcartfactor*fcart(:,:,iimage)
    1040              : 
    1041              : !  Intermediate Runge-Kutta step 2
    1042            0 :    else if (istep_rk==2) then
    1043              :      xcart(:,:,iimage)=mep_param%rk4_xcart1(:,:,iimage) &
    1044            0 : &       -half*mep_param%fxcartfactor*fcart(:,:,iimage)
    1045              : 
    1046              : !  Intermediate Runge-Kutta step 3
    1047            0 :    else if (istep_rk==3) then
    1048              :      xcart(:,:,iimage)=mep_param%rk4_xcart1(:,:,iimage) &
    1049            0 : &       -mep_param%fxcartfactor*fcart(:,:,iimage)
    1050              : 
    1051              : !  Final Runge-Kutta step
    1052            0 :    else if (istep_rk==0) then
    1053              : !    Compute image step
    1054              :      xstep(:,:)=third*mep_param%fxcartfactor &
    1055              : &      *(half*fcart(:,:,iimage) &
    1056              : &       +half*mep_param%rk4_fcart1(:,:,iimage) &
    1057              : &       +mep_param%rk4_fcart2(:,:,iimage) &
    1058            0 : &       +mep_param%rk4_fcart3(:,:,iimage))
    1059            0 :      stepsize=mep_img_norm(xstep)
    1060            0 :      if (stepsize>=mep_param%mep_mxstep) then
    1061            0 :        xstep=xstep*mep_param%mep_mxstep/stepsize
    1062            0 :        write(msg,'(a,i3,a)') " Restricting step size of image ",iimage,"."
    1063            0 :        call wrtout(std_out,msg,'COLL')
    1064            0 :        call wrtout(ab_out ,msg,'COLL')
    1065              :      end if
    1066              : !    Update positions
    1067            0 :      xcart(:,:,iimage)=mep_param%rk4_xcart1(:,:,iimage)+xstep(:,:)
    1068              :    end if
    1069              : 
    1070            0 :    call xcart2xred(natom,rprimd(:,:,iimage),xcart(:,:,iimage),xred(:,:,iimage))
    1071              : 
    1072              : !  In case atom is fixed, we restore its previous value
    1073            0 :    do iatom=1,natom
    1074            0 :      if (any(mep_param%iatfix(:,iatom)==1)) then
    1075            0 :        where(mep_param%iatfix(:,iatom)==1)
    1076              :          xred(:,iatom,iimage)=xred_old(:,iatom)
    1077              :        end where
    1078            0 :        call xred2xcart(1,rprimd(:,:,iimage),xcart(:,iatom,iimage),xred(:,iatom,iimage))
    1079              :      end if
    1080              :    end do
    1081              : 
    1082              :  end do
    1083              : 
    1084            0 :  ABI_FREE(xred_old)
    1085            0 :  if (istep_rk==0) then
    1086            0 :    ABI_FREE(xstep)
    1087              :  end if
    1088              : 
    1089              : !Cancel storage when final RK step has been done
    1090            0 :  if (istep_rk==0) then
    1091            0 :    ABI_SFREE(mep_param%rk4_xcart1)
    1092            0 :    ABI_SFREE(mep_param%rk4_fcart1)
    1093            0 :    ABI_SFREE(mep_param%rk4_fcart2)
    1094            0 :    ABI_SFREE(mep_param%rk4_fcart3)
    1095              :  end if
    1096              : 
    1097            0 : end subroutine mep_rk4
    1098              : !!***
    1099              : 
    1100              : !----------------------------------------------------------------------
    1101              : 
    1102              : !!****f* m_mep/mep_img_dotp
    1103              : !! NAME
    1104              : !!  mep_img_dotp
    1105              : !!
    1106              : !! FUNCTION
    1107              : !!  Compute the dot product of two vectors in the configuration space:
    1108              : !!    Vect1(3,natom).Vect2(3,natom)
    1109              : !!
    1110              : !! INPUTS
    1111              : !!  vect1(3,natom)=input vector 1
    1112              : !!  vect2(3,natom)=input vector 2
    1113              : !!
    1114              : !! OUTPUT
    1115              : !!  mep_img_dotp=dot product
    1116              : !!
    1117              : !! SOURCE
    1118              : 
    1119          226 : function mep_img_dotp(vect1,vect2)
    1120              : 
    1121              : !Arguments ------------------------------------
    1122              : !scalars
    1123              :  real(dp) :: mep_img_dotp
    1124              : !arrays
    1125              :  real(dp),intent(in) :: vect1(:,:),vect2(:,:)
    1126              : !Local variables-------------------------------
    1127              : !scalars
    1128              :  integer :: size1,size2
    1129              : !arrays
    1130              : 
    1131              : !************************************************************************
    1132              : 
    1133          226 :  size1=size(vect1,1);size2=size(vect1,2)
    1134          226 :  if (size1/=size(vect2,1).or.size2/=size(vect2,2)) then
    1135            0 :    ABI_BUG("Error on dimensions !")
    1136              :  end if
    1137              : 
    1138         2574 :  mep_img_dotp=sum(vect1*vect2)
    1139              : 
    1140          226 : end function mep_img_dotp
    1141              : !!***
    1142              : 
    1143              : !----------------------------------------------------------------------
    1144              : 
    1145              : !!****f* m_mep/mep_img_norm
    1146              : !! NAME
    1147              : !!  mep_img_norm
    1148              : !!
    1149              : !! FUNCTION
    1150              : !!  Compute the norm of a vector in the configuration space:
    1151              : !!    |Vect(3,natom)|
    1152              : !!
    1153              : !! INPUTS
    1154              : !!  vect(3,natom)=input vector
    1155              : !!
    1156              : !! OUTPUT
    1157              : !!  mep_img_norm=norm
    1158              : !!
    1159              : !! SOURCE
    1160              : 
    1161         1590 : function mep_img_norm(vect)
    1162              : 
    1163              : !Arguments ------------------------------------
    1164              : !scalars
    1165              :  real(dp) :: mep_img_norm
    1166              : !arrays
    1167              :  real(dp),intent(in) :: vect(:,:)
    1168              : 
    1169              : !************************************************************************
    1170              : 
    1171        16038 :  mep_img_norm=sqrt(sum(vect*vect))
    1172              : 
    1173         1590 : end function mep_img_norm
    1174              : !!***
    1175              : 
    1176              : !----------------------------------------------------------------------
    1177              : 
    1178              : !!****f* m_mep/mep_img_dotp_red
    1179              : !! NAME
    1180              : !!  mep_img_dotp_red
    1181              : !!
    1182              : !! FUNCTION
    1183              : !!  Compute the dot product of two vectors in the configuration space:
    1184              : !!    Vect1(3,natom).Vect2(3,natom)
    1185              : !!  using reduced coordinates
    1186              : !!
    1187              : !! INPUTS
    1188              : !!  rmet(3,3)=metric tensor
    1189              : !!  vect1(3,natom)=input vector 1
    1190              : !!  vect2(3,natom)=input vector 2
    1191              : !!
    1192              : !! OUTPUT
    1193              : !!  mep_img_dotp_red=dot product
    1194              : !!
    1195              : !! SOURCE
    1196              : 
    1197            0 : function mep_img_dotp_red(rmet,vect1,vect2)
    1198              : 
    1199              : !Arguments ------------------------------------
    1200              : !scalars
    1201              :  real(dp) :: mep_img_dotp_red
    1202              : !arrays
    1203              :  real(dp),intent(in) :: rmet(3,3)
    1204              :  real(dp),intent(in) :: vect1(:,:),vect2(:,:)
    1205              : !Local variables-------------------------------
    1206              : !scalars
    1207              :  integer :: iatom,size1,size2
    1208              : 
    1209              : !************************************************************************
    1210              : 
    1211            0 :  size1=size(vect1,1);size2=size(vect1,2)
    1212            0 :  if (size1/=size(vect2,1).or.size2/=size(vect2,2).or.size1/=3) then
    1213            0 :    ABI_BUG("Error on dimensions !")
    1214              :  end if
    1215              : 
    1216            0 :  mep_img_dotp_red=zero
    1217            0 : do iatom = 1, size2
    1218            0 :   mep_img_dotp_red = mep_img_dotp_red + dot_product(vect1(:, iatom), matmul(rmet, vect2(:, iatom)))
    1219              : end do
    1220              : 
    1221            0 : end function mep_img_dotp_red
    1222              : !!***
    1223              : 
    1224              : !----------------------------------------------------------------------
    1225              : 
    1226              : !!****f* m_mep/mep_img_norm_red
    1227              : !! NAME
    1228              : !!  mep_img_norm_red
    1229              : !!
    1230              : !! FUNCTION
    1231              : !!  Compute the norm of a vector in the configuration space:
    1232              : !!    |Vect(3,natom)|
    1233              : !!  using reduced coordinates
    1234              : !!
    1235              : !! INPUTS
    1236              : !!  rmet(3,3)=metric tensor
    1237              : !!  vect(3,natom)=input vector
    1238              : !!
    1239              : !! OUTPUT
    1240              : !!  mep_img_norm_red=norm
    1241              : !!
    1242              : !!
    1243              : !! SOURCE
    1244              : 
    1245            0 : function mep_img_norm_red(rmet,vect)
    1246              : 
    1247              : !Arguments ------------------------------------
    1248              : !scalars
    1249              :  real(dp) :: mep_img_norm_red
    1250              : !arrays
    1251              :  real(dp),intent(in) :: rmet(3,3)
    1252              :  real(dp),intent(in) :: vect(:,:)
    1253              : !************************************************************************
    1254              : 
    1255            0 :  mep_img_norm_red=sqrt(mep_img_dotp_red(rmet,vect,vect))
    1256              : 
    1257            0 : end function mep_img_norm_red
    1258              : !!***
    1259              : 
    1260            0 : END MODULE m_mep
    1261              : !!***
        

Generated by: LCOV version 2.3-1