LCOV - code coverage report
Current view: top level - src/80_tdep - m_tdep_model.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 99.4 % 156 155
Test Date: 2026-09-20 15:27:41 Functions: 55.6 % 9 5

            Line data    Source code
       1              : !!****m* ABINIT/m_tdep_model
       2              : !! NAME
       3              : !!  m_tdep_model
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module contains the TDEP Model data type
       7              : !!  which holds the IFC at all orders and derived quantities.
       8              : !!
       9              : !! COPYRIGHT
      10              : !! Copyright (C) 2011-2026 ABINIT group (GA,FB,JB)
      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_tdep_model
      24              : 
      25              :  use defs_basis
      26              :  use m_errors
      27              :  use m_abicore
      28              :  use m_xmpi
      29              :  use m_io_tools
      30              :  use m_tdep_dataset,     only : atdep_dataset_type, MPI_enreg_type
      31              :  use m_tdep_sampling,    only : tdep_Sampling_type
      32              :  use m_tdep_shell,       only : Shell_type
      33              : 
      34              :  implicit none
      35              : 
      36              : !----------------------------------------------------------------------
      37              : 
      38              : !!***
      39              : !!****t* m_tdep_model/Phi2_type
      40              : !! NAME
      41              : !! Phi2_type
      42              : !!
      43              : !! FUNCTION
      44              : !!  Second-order IFC
      45              : !!
      46              : !! SOURCE
      47              : 
      48              :  type Phi2_type
      49              : 
      50              :    double precision, allocatable :: SR(:,:)
      51              :    ! SR(3*natom, 3*natom)
      52              :    ! Short-range part of the second-order IFC
      53              : 
      54              :    double precision, allocatable :: LR(:,:)
      55              :    ! LR(3*natom, 3*natom)
      56              :    ! Long-range part of the second-order IFC
      57              : 
      58              :    double precision, allocatable :: Tot(:,:)
      59              :    ! Tot(3*natom, 3*natom)
      60              :    ! Second-order IFC (SR + LR)
      61              : 
      62              : 
      63              :  end type Phi2_type
      64              : 
      65              : 
      66              : !----------------------------------------------------------------------
      67              : 
      68              : !!***
      69              : !!****t* m_tdep_model/tdep_Model_type
      70              : !! NAME
      71              : !! tdep_Model_type
      72              : !!
      73              : !! FUNCTION
      74              : !!  Holds the result of the TDEP fit, that is, the IFCs and resulting forces
      75              : !!  and energy contributions.
      76              : !!
      77              : !! SOURCE
      78              : 
      79              :  type,public :: tdep_Model_type
      80              : 
      81              :    integer :: order
      82              :    ! Maximum IFC order (2, 3, or 4)
      83              : 
      84              :    integer :: natom
      85              :    ! Number of atoms
      86              : 
      87              :    integer :: natom_unitcell
      88              :    ! Number of atoms in the unitcell
      89              : 
      90              :    integer :: my_nstep
      91              :    ! Number of MD steps held locally
      92              : 
      93              :    integer :: nshell3rd
      94              :    ! Number of shells for 3rd order IFC
      95              : 
      96              :    integer :: nshell4th
      97              :    ! Number of shells for 4th order IFC
      98              : 
      99              :    double precision :: U0
     100              :    ! Constant term contribution to energy
     101              : 
     102              :    double precision, allocatable :: Forces(:)
     103              :    ! Forces(3*natom*my_nstep)
     104              :    ! Forces computed from the fitted IFC and the displacements
     105              : 
     106              :    double precision, allocatable :: Phi1(:)
     107              :    ! Phi1(3*natom)
     108              :    ! First-order IFC
     109              : 
     110              :    type(Phi2_type) :: Phi2
     111              :    ! Second-order IFC
     112              : 
     113              :    double precision, allocatable :: Phi3(:,:,:,:)
     114              :    ! Phi3(3,3,3,Shell3at%nshell)
     115              :    ! Third-order IFC
     116              : 
     117              :    double precision, allocatable :: Phi4(:,:,:,:,:)
     118              :    ! Phi3(3,3,3,3,Shell4at%nshell)
     119              :    ! Fourth-order IFC
     120              : 
     121              :    double precision, allocatable :: Phi1Ui(:)
     122              :    ! Phi1Ui(my_nstep)
     123              :    ! First-order IFC contribution to energy
     124              : 
     125              :    double precision, allocatable :: Phi2UiUj(:)
     126              :    ! Phi2UiUj(my_nstep)
     127              :    ! Second-order IFC contribution to energy
     128              : 
     129              :    double precision, allocatable :: Phi3UiUjUk(:)
     130              :    ! Phi3UiUjUk(my_nstep)
     131              :    ! Third-order IFC contribution to energy
     132              : 
     133              :    double precision, allocatable :: Phi4UiUjUkUl(:)
     134              :    ! Phi4UiUjUkUl(my_nstep)
     135              :    ! Fourth-order IFC contribution to energy
     136              : 
     137              :  end type tdep_Model_type
     138              : 
     139              :  public :: tdep_init_phi2
     140              :  public :: tdep_destroy_phi2
     141              :  public :: tdep_model_init
     142              :  public :: tdep_model_free
     143              :  public :: tdep_calc_model
     144              : 
     145              : contains
     146              : 
     147              : !=====================================================================================================
     148              : 
     149           46 : subroutine tdep_init_phi2(Phi2,dipdip,natom)
     150              : 
     151              :   type(Phi2_type),intent(out) :: Phi2
     152              :   logical, intent(in) :: dipdip
     153              :   integer, intent(in) :: natom
     154              : 
     155     13524742 :   ABI_CALLOC(Phi2%SR ,(3*natom,3*natom))
     156           46 :   if (dipdip) then
     157       923727 :     ABI_CALLOC(Phi2%Tot,(3*natom,3*natom))
     158       923727 :     ABI_CALLOC(Phi2%LR ,(3*natom,3*natom))
     159              :   end if
     160              : 
     161           46 : end subroutine tdep_init_phi2
     162              : 
     163              : !=====================================================================================================
     164              : 
     165           46 : subroutine tdep_destroy_phi2(Phi2)
     166              : 
     167              :   type(Phi2_type),intent(inout) :: Phi2
     168              : 
     169           46 :   ABI_FREE(Phi2%SR)
     170           46 :   ABI_SFREE(Phi2%Tot)
     171           46 :   ABI_SFREE(Phi2%LR)
     172              : 
     173           46 : end subroutine tdep_destroy_phi2
     174              : 
     175              : !=====================================================================================================
     176              : 
     177           44 : subroutine tdep_model_init(Model, Invar, Shell3at, Shell4at)
     178              : 
     179              :  type(tdep_Model_type),intent(out) :: Model
     180              :  type(atdep_dataset_type),intent(in) :: Invar
     181              :  type(Shell_type),intent(in) :: Shell3at, Shell4at
     182              : 
     183           44 :  Model%order = Invar%order
     184           44 :  Model%natom = Invar%natom
     185           44 :  Model%natom_unitcell = Invar%natom_unitcell
     186           44 :  Model%my_nstep = Invar%my_nstep
     187           44 :  Model%nshell3rd = 1
     188           44 :  Model%nshell4th = 1
     189              : 
     190           44 :  Model%U0 = zero
     191              : 
     192       417588 :  ABI_CALLOC(Model%Forces, (3*Model%natom*Model%my_nstep))
     193         1084 :  ABI_CALLOC(Model%Phi1Ui      ,(Model%my_nstep))
     194         1040 :  ABI_CALLOC(Model%Phi2UiUj    ,(Model%my_nstep))
     195         1040 :  ABI_CALLOC(Model%Phi3UiUjUk  ,(Model%my_nstep))
     196         1040 :  ABI_CALLOC(Model%Phi4UiUjUkUl,(Model%my_nstep))
     197              : 
     198        20778 :  ABI_CALLOC(Model%Phi1,(3*Model%natom))
     199              : 
     200           44 :  call tdep_init_phi2(Model%Phi2,Invar%loto,Invar%natom)
     201              : 
     202           44 :  if (Model%order.ge.3) then
     203           14 :    Model%nshell3rd = Shell3at%nshell
     204         2002 :    ABI_CALLOC(Model%Phi3,(3,3,3,Model%nshell3rd))
     205              :  end if
     206              : 
     207           44 :  if (Model%order.eq.4) then
     208            8 :    Model%nshell4th = Shell4at%nshell
     209         5590 :    ABI_CALLOC(Model%Phi4,(3,3,3,3,Model%nshell4th))
     210              :  end if
     211              : 
     212           44 : end subroutine tdep_model_init
     213              : 
     214              : !=====================================================================================================
     215              : 
     216           44 : subroutine tdep_model_free(Model)
     217              : 
     218              :  type(tdep_Model_type),intent(inout) :: Model
     219              : 
     220           44 :  ABI_FREE(Model%Forces)
     221           44 :  ABI_FREE(Model%Phi1Ui)
     222           44 :  ABI_FREE(Model%Phi2UiUj)
     223           44 :  ABI_FREE(Model%Phi3UiUjUk)
     224           44 :  ABI_FREE(Model%Phi4UiUjUkUl)
     225              : 
     226           44 :  ABI_FREE(Model%Phi1)
     227              : 
     228           44 :  call tdep_destroy_phi2(Model%Phi2)
     229              : 
     230           44 :  if (Model%order.ge.3) then
     231           14 :    ABI_FREE(Model%Phi3)
     232              :  end if
     233              : 
     234           44 :  if (Model%order.eq.4) then
     235            8 :    ABI_FREE(Model%Phi4)
     236              :  end if
     237              : 
     238           44 : end subroutine tdep_model_free
     239              : 
     240              : !====================================================================================================
     241              : 
     242           44 :  subroutine tdep_calc_model(Model,MD,Invar,MPIdata)
     243              : 
     244              :   type(tdep_Model_type),intent(inout) :: Model
     245              :   type(tdep_Sampling_type),intent(in) :: MD
     246              :   type(atdep_dataset_type),intent(in) :: Invar
     247              :   type(MPI_enreg_type), intent(in) :: MPIdata
     248              : 
     249              :   integer :: ii,jj,istep,iatom
     250              :   double precision :: Delta_F2,Delta_U,Delta_U2
     251              :   double precision :: sigma,U_1,U_2,U_3,U_4,UMD
     252           44 :   double precision, allocatable :: tmp(:),Phi_tot(:)
     253           44 :   double precision, allocatable :: U_MD(:),U_TDEP(:),weights_tot(:)
     254              :   integer :: ierr
     255              : 
     256              :   ! Compute the different contributions to total energy from the model
     257              : 
     258           44 :   write(Invar%stdout,*)' '
     259           44 :   write(Invar%stdout,*) '#############################################################################'
     260           44 :   write(Invar%stdout,*) '######################### Energies, errors,...  #############################'
     261           44 :   write(Invar%stdout,*) '#############################################################################'
     262              : 
     263              : ! Compute U0, U_TDEP, Delta_U and write them in the output file
     264           44 :   write(Invar%stdout,'(a)') ' Thermodynamic quantities and convergence parameters of THE MODEL,'
     265           44 :   write(Invar%stdout,'(a)') '      as a function of the step number (energies in eV/atom and forces in Ha/bohr) :'
     266           44 :   if (Invar%order.eq.4) then
     267            8 :     write(Invar%stdout,'(a)') ' <U_TDEP> = U_0 + U_1 + U_2 + U_3 + U_4'
     268            8 :     write(Invar%stdout,'(2a)') '       with U_0 = < U_MD - sum_i Phi1 ui - 1/2 sum_ij Phi2 ui uj ',&
     269           16 : &                             '- 1/6 sum_ijk Phi3 ui uj uk - 1/24 sum_ijkl Phi4 ui uj uk ul >'
     270            8 :     write(Invar%stdout,'(a)') '        and U_1 = <      sum_i    Phi1 ui >'
     271            8 :     write(Invar%stdout,'(a)') '        and U_2 = < 1/2  sum_ij   Phi2 ui uj >'
     272            8 :     write(Invar%stdout,'(a)') '        and U_3 = < 1/6  sum_ijk  Phi3 ui uj uk >'
     273            8 :     write(Invar%stdout,'(a)') '        and U_4 = < 1/24 sum_ijkl Phi4 ui uj uk ul >'
     274           36 :   else if (Invar%order.eq.3) then
     275            6 :     write(Invar%stdout,'(a)') ' <U_TDEP> = U_0 + U_1 + U_2 + U_3'
     276            6 :     write(Invar%stdout,'(a)') '       with U_0 = < U_MD - sum_i Phi1 ui - 1/2 sum_ij Phi2 ui uj - 1/6 sum_ijk Phi3 ui uj uk >'
     277            6 :     write(Invar%stdout,'(a)') '        and U_1 = <      sum_i    Phi1 ui >'
     278            6 :     write(Invar%stdout,'(a)') '        and U_2 = < 1/2  sum_ij   Phi2 ui uj >'
     279            6 :     write(Invar%stdout,'(a)') '        and U_3 = < 1/6  sum_ijk  Phi3 ui uj uk >'
     280              :   else
     281           30 :     write(Invar%stdout,'(a)') ' <U_TDEP> = U_0 + U_1 + U_2'
     282           30 :     write(Invar%stdout,'(a)') '       with U_0 = < U_MD - sum_i Phi1 ui - 1/2 sum_ij Phi2 ui uj >'
     283           30 :     write(Invar%stdout,'(a)') '        and U_1 = <      sum_i    Phi1 ui >'
     284           30 :     write(Invar%stdout,'(a)') '        and U_2 = < 1/2  sum_ij   Phi2 ui uj >'
     285              :   end if
     286           44 :   write(Invar%stdout,'(a)') '  Delta_U =   < U_MD - U_TDEP > '
     287           44 :   write(Invar%stdout,'(a)') '  Delta_U2= (< (U_MD - U_TDEP)^2 >)**0.5 '
     288           44 :   write(Invar%stdout,'(a)') '  Delta_F2= (< (F_MD - F_TDEP)^2 >)**0.5 '
     289           44 :   write(Invar%stdout,'(a)') '  Sigma   = (< (F_MD - F_TDEP)^2 >/<F_MD**2>)**0.5 '
     290           44 :   if (Invar%order.eq.4) then
     291            8 :     write(Invar%stdout,'(2a)') '     <U_MD>            U_0              U_1              U_2  ',&
     292           16 : &     '            U_3              U_4            Delta_U          Delta_U2          Delta_F2          Sigma'
     293           36 :   else if (Invar%order.eq.3) then
     294            6 :     write(Invar%stdout,'(2a)') '     <U_MD>            U_0              U_1              U_2  ',&
     295           12 : &     '            U_3            Delta_U          Delta_U2          Delta_F2          Sigma'
     296              :   else
     297           30 :     write(Invar%stdout,'(2a)') '     <U_MD>            U_0              U_1              U_2  ',&
     298           60 : &     '          Delta_U          Delta_U2          Delta_F2          Sigma'
     299              :   end if
     300              : 
     301              : ! Compute eucledian distance for forces
     302          528 :   ABI_MALLOC(tmp,(11))                  ; tmp(:)   =0.d0
     303          996 :   do istep=1,MD%my_nstep
     304       140148 :     do iatom=1,MD%natom
     305       557560 :       do ii=1,3
     306       417456 :         jj = ii + 3*(iatom-1) + 3*MD%natom*(istep-1)
     307       417456 :         tmp(4)=tmp(4)+(MD%Forces(jj)-Model%Forces(jj))**2*MD%weights(istep)
     308       556608 :         tmp(5)=tmp(5)+MD%Forces(jj)**2*MD%weights(istep)
     309              :       end do
     310              :     end do
     311              :   end do
     312              : ! Compute energies
     313         1084 :   ABI_MALLOC(U_TDEP,     (MD%nstep_tot)) ; U_TDEP(:)=0.d0
     314         1040 :   ABI_MALLOC(U_MD,       (MD%nstep_tot)) ; U_MD(:)  =0.d0
     315         1040 :   ABI_MALLOC(weights_tot,(MD%nstep_tot)) ; weights_tot(:)=0.d0
     316         1084 :   ABI_MALLOC(Phi_tot,    (MPIdata%my_nstep)); Phi_tot(:)=0.d0
     317          996 :   do istep=1,MD%my_nstep
     318          952 :     tmp(7) =tmp(7) +MD%etot(istep)*MD%weights(istep)
     319          952 :     tmp(10)=tmp(10)+Model%Phi1Ui(istep)*MD%weights(istep)
     320          952 :     tmp(6) =tmp(6) +Model%Phi2UiUj(istep)*MD%weights(istep)
     321          952 :     tmp(8) =tmp(8) +Model%Phi3UiUjUk(istep)*MD%weights(istep)
     322          996 :     tmp(11)=tmp(11)+Model%Phi4UiUjUkUl(istep)*MD%weights(istep)
     323              :   end do
     324           44 :   call xmpi_sum(tmp,MPIdata%comm_step,ierr)
     325           44 :   tmp(1) = tmp(7)-tmp(10)-tmp(6)-tmp(8)-tmp(11)
     326          996 :   Phi_tot(:)=tmp(1)+Model%Phi1Ui(:)+Model%Phi2UiUj(:)+Model%Phi3UiUjUk(:)+Model%Phi4UiUjUkUl(:)
     327              :   call xmpi_gatherv(Phi_tot,MD%my_nstep,U_TDEP,MPIdata%nstep_all,MPIdata%shft_step,&
     328           44 : &                   MPIdata%master,MPIdata%comm_step,ierr)
     329              :   call xmpi_gatherv(MD%etot,MD%my_nstep,U_MD,MPIdata%nstep_all,MPIdata%shft_step,&
     330           44 : &                   MPIdata%master,MPIdata%comm_step,ierr)
     331              :   call xmpi_gatherv(MD%weights,MD%my_nstep,weights_tot,MPIdata%nstep_all,MPIdata%shft_step,&
     332           44 : &                   MPIdata%master,MPIdata%comm_step,ierr)
     333          996 :   do istep=1,MD%nstep_tot
     334          952 :     tmp(2) =tmp(2) + (U_MD(istep)-U_TDEP(istep)) * weights_tot(istep)
     335          996 :     tmp(9) =tmp(9) + (U_MD(istep)-U_TDEP(istep))**2 * weights_tot(istep)
     336              :   end do
     337           44 :   Model%U0       =tmp(1) /real(MD%natom)
     338           44 :   UMD      =tmp(7) /real(MD%natom)
     339           44 :   U_1      =tmp(10)/real(MD%natom)
     340           44 :   U_2      =tmp(6) /real(MD%natom)
     341           44 :   U_3      =tmp(8) /real(MD%natom)
     342           44 :   U_4      =tmp(11)/real(MD%natom)
     343           44 :   Delta_U  =tmp(2) /real(MD%natom)
     344           44 :   Delta_U2 =tmp(9) /real(MD%natom)
     345           44 :   Delta_F2 =tmp(4) /real(MD%natom*3)
     346           44 :   if (tmp(5).eq.0.d0) then
     347            1 :     sigma = 0.d0
     348              :   else
     349           43 :     sigma = dsqrt(tmp(4)/tmp(5))
     350              :   end if
     351           44 :   if (Invar%order.eq.4) then
     352            8 :     write(Invar%stdout,'(10(f12.5,5x))') UMD*Ha_eV,Model%U0*Ha_eV,U_1*Ha_eV,U_2*Ha_eV,U_3*Ha_eV,U_4*Ha_eV,&
     353           16 : &     Delta_U*Ha_eV,Delta_U2**0.5*Ha_eV,Delta_F2**0.5,sigma
     354           36 :   else if (Invar%order.eq.3) then
     355            6 :     write(Invar%stdout,'(9(f12.5,5x))') UMD*Ha_eV,Model%U0*Ha_eV,U_1*Ha_eV,U_2*Ha_eV,U_3*Ha_eV,&
     356           12 : &     Delta_U*Ha_eV,Delta_U2**0.5*Ha_eV,Delta_F2**0.5,sigma
     357              :   else
     358           30 :     write(Invar%stdout,'(8(f12.5,5x))') UMD*Ha_eV,Model%U0*Ha_eV,U_1*Ha_eV,U_2*Ha_eV,&
     359           60 : &     Delta_U*Ha_eV,Delta_U2**0.5*Ha_eV,Delta_F2**0.5,sigma
     360              :   endif
     361           44 :   ABI_FREE(tmp)
     362           44 :   write(Invar%stdout,'(a,1x,f12.5)') ' NOTE : in the harmonic and classical limit (T>>T_Debye), U_2=3/2*kB*T=',&
     363           88 : &   3.d0/2.d0*kb_HaK*Ha_eV*Invar%temperature
     364              : 
     365              : ! Write : i) (U_TDEP vs U_MD) in etotMDvsTDEP.dat
     366              : !        ii) (Model%Forces vs MD%Forces) in fcartMDvsTDEP.dat
     367           44 :   write(Invar%stdout,'(a)') ' '
     368           44 :   write(Invar%stdout,'(a)') ' See the etotMDvsTDEP.dat & fcartMDvsTDEP.dat files'
     369           44 :   if (MPIdata%iam_master) then
     370           44 :     open(unit=32,file=trim(Invar%output_prefix)//'_etotMDvsTDEP.dat')
     371           44 :     open(unit=33,file=trim(Invar%output_prefix)//'_fcartMDvsTDEP.dat')
     372           44 :     write(32,'(a)') '#   Istep      U_MD(Ha)         U_TDEP(Ha)'
     373           44 :     write(33,'(a)') '# Forces_MD(Ha/bohr) Forces_TDEP(Ha/bohr)'
     374          996 :     do istep=1,MD%nstep_tot
     375          996 :       write(32,'(i6,1x,2(f17.6,1x))') istep,U_MD(istep),U_TDEP(istep)
     376              :     end do
     377          996 :     do istep=1,MD%my_nstep
     378       140148 :       do iatom=1,MD%natom
     379       557560 :         do ii=1,3
     380       417456 :           write(33,'(2(f17.10,1x))') MD%Forces  (ii+3*(iatom-1)+3*MD%natom*(istep-1)),&
     381       974064 : &                                    Model%Forces(ii+3*(iatom-1)+3*MD%natom*(istep-1))
     382              :         end do
     383              :       end do
     384              :     end do
     385           44 :     close(32)
     386           44 :     close(33)
     387              :   end if
     388           44 :   ABI_FREE(U_MD)
     389           44 :   ABI_FREE(U_TDEP)
     390           44 :   ABI_FREE(Phi_tot)
     391           44 :   ABI_FREE(weights_tot)
     392              : 
     393           88 :  end subroutine tdep_calc_model
     394              : 
     395              : !====================================================================================================
     396              : 
     397            0 : end module m_tdep_model
     398              : !!***
        

Generated by: LCOV version 2.3-1