LCOV - code coverage report
Current view: top level - src/45_geomoptim - m_ipi.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 103 0
Test Date: 2026-11-08 00:10:28 Functions: 0.0 % 5 0
Branches: 0.0 % 152 0

             Branch data     Line data    Source code
       1                 :             : !!****m* ABINIT/m_ipi
       2                 :             : !! NAME
       3                 :             : !!  m_ipi
       4                 :             : !!
       5                 :             : !! FUNCTION
       6                 :             : !!  This module implements the client-side parf of the i-pi protocol.
       7                 :             : !!  The communication between the driver and the client (Abinit) is implemented as follows:
       8                 :             : !!     1)
       9                 :             : !!     2)
      10                 :             : !!
      11                 :             : !!  Only structural relaxations with ionmov 28 are implemented.
      12                 :             : !!  Support MD runs requires the proper handling of velocities.
      13                 :             : !!  No parallelism over images.
      14                 :             : !!
      15                 :             : !! COPYRIGHT
      16                 :             : !!  Copyright (C) 2020-2026 ABINIT group (MG)
      17                 :             : !!  This file is distributed under the terms of the
      18                 :             : !!  GNU General Public License, see ~abinit/COPYING
      19                 :             : !!  or http://www.gnu.org/copyleft/gpl.txt .
      20                 :             : !!
      21                 :             : !! NOTES
      22                 :             : !!
      23                 :             : !!  From the i-pi user guide available at: https://github.com/i-pi/i-pi/blob/master/doc/manual.tex
      24                 :             : !!
      25                 :             : !!  The server assumes that 4-byte integers, 8-byte floats and 1-byte characters are used.
      26                 :             : !!  The typical communication flow is as follows:
      27                 :             : !!
      28                 :             : !!  1. a header string "STATUS" is sent by the server to the client that has connected to it;
      29                 :             : !!
      30                 :             : !!  2. a header string is then returned, giving the status of the client code.
      31                 :             : !!     Recognized messages are:
      32                 :             : !!
      33                 :             : !!  "NEEDINIT": if the client code needs any initialising data, it can be sent here.
      34                 :             : !!  The server code will then send a header string "INIT", followed by an integer
      35                 :             : !!  corresponding to the bead index, another integer giving the number of bits
      36                 :             : !!  in the initialization string, and finally the initialization string itself.
      37                 :             : !!
      38                 :             : !!  "READY": sent if the client code is ready to calculate the forces. The server
      39                 :             : !!  socket will then send a string "POSDATA", then nine floats for the cell vector
      40                 :             : !!  matrix, then another nine floats for the inverse matrix. The server socket
      41                 :             : !!  will then send one integer giving the number of atoms, then the position data
      42                 :             : !!  as 3 floats for each atom giving the 3 cartesian components of its position.
      43                 :             : !!
      44                 :             : !!  "HAVEDATA": is sent if the client has finished computing the potential and
      45                 :             : !!  forces. The server socket then sends a string "GETFORCE", and the client
      46                 :             : !!  socket returns "FORCEREADY". The potential is then returned as a float,
      47                 :             : !!  the number of atoms as an integer, then the force data as 3 floats per atom
      48                 :             : !!  in the same way as the positions, and the virial as 9 floats in the same
      49                 :             : !!  way as the cell vector matrix. Finally, the client may return an arbitrary
      50                 :             : !!  string containing additional data that have been obtained by the electronic
      51                 :             : !!  structure calculation (atomic charges, dipole moment). The client first
      52                 :             : !!  returns an integer specifying the number of characters, and then the string,
      53                 :             : !!  which will be output verbatim if this "extra" information is requested in the
      54                 :             : !!  output section (see 3.2.2).
      55                 :             : !!
      56                 :             : !!  3. The server socket waits until the force data for each replica of the system has
      57                 :             : !!  been calculated and returned, then the MD can be propagated for one more time
      58                 :             : !!  step, and new force requests will be dispatched.
      59                 :             : !!
      60                 :             : !! SOURCE
      61                 :             : 
      62                 :             : #if defined HAVE_CONFIG_H
      63                 :             : #include "config.h"
      64                 :             : #endif
      65                 :             : 
      66                 :             : #include "abi_common.h"
      67                 :             : 
      68                 :             : module m_ipi
      69                 :             : 
      70                 :             :  use defs_basis
      71                 :             :  use m_abicore
      72                 :             :  use m_abimover
      73                 :             :  use m_abihist
      74                 :             :  use m_xmpi
      75                 :             :  use m_errors
      76                 :             :  use m_fsockets
      77                 :             : 
      78                 :             :  use m_fstrings,  only : sjoin, itoa
      79                 :             :  use m_geometry,  only : xcart2xred, det3r, stress_voigt_to_mat
      80                 :             : 
      81                 :             :  implicit none
      82                 :             : 
      83                 :             :  private
      84                 :             : 
      85                 :             :  public :: ipi_setup
      86                 :             :  public :: ipi_shutdown
      87                 :             :  public :: ipi_pred
      88                 :             :  public :: ipi_check_initial_consistency
      89                 :             : !!***
      90                 :             : 
      91                 :             : ! =============
      92                 :             : ! private stuff
      93                 :             : ! =============
      94                 :             : 
      95                 :             :  INTEGER, PARAMETER :: HDRLEN = 12
      96                 :             :  integer, save :: socket
      97                 :             :  integer, save :: origin_natom = 0
      98                 :             :  real(dp), save :: origin_rprimd(3, 3) = zero
      99                 :             :  real(dp), save, allocatable :: origin_xred(:,:)
     100                 :             : 
     101                 :             : contains
     102                 :             : !!***
     103                 :             : 
     104                 :             : !!****f* m_ipi/ipi_setup
     105                 :             : !! NAME
     106                 :             : !! ipi_setup
     107                 :             : !!
     108                 :             : !! FUNCTION
     109                 :             : !!  Initialize the socket from a string that is usually passed via the command line interface.
     110                 :             : !!  Get the initial configuration from the server and save it in module global variables
     111                 :             : !!  for subsequent consistency check.
     112                 :             : !!  These values, indeed, must agree with those read from the input file.
     113                 :             : !!  See also ipi_check_initial_consistency.
     114                 :             : !!
     115                 :             : !! INPUTS
     116                 :             : !!
     117                 :             : !! OUTPUT
     118                 :             : !!
     119                 :             : !! OUTPUT
     120                 :             : !!
     121                 :             : !! SOURCE
     122                 :             : 
     123                 :           0 : subroutine ipi_setup(string, comm)
     124                 :             : 
     125                 :             : !Arguments ------------------------------------
     126                 :             : !scalars
     127                 :             :  character(len=*),intent(in) :: string
     128                 :             :  integer,intent(in) :: comm
     129                 :             : 
     130                 :             : !local variables
     131                 :             :  integer,parameter :: master = 0
     132                 :             :  integer :: my_rank, ierr
     133                 :             :  character(len=HDRLEN) :: header
     134                 :             : 
     135                 :             : ! *************************************************************************
     136                 :             : 
     137                 :           0 :  my_rank = xmpi_comm_rank(comm)
     138                 :             : 
     139                 :           0 :  call wrtout(std_out, "Initializing i-pi protocol...")
     140         [ #  # ]:           0 :  if (my_rank == master) then
     141                 :           0 :    call socket_from_string(string, socket)
     142                 :           0 :    call readbuffer(socket, header, HDRLEN)
     143   [ #  #  #  # ]:           0 :    ABI_CHECK(trim(header) == "STATUS", sjoin("Expecting STATUS header, got:", trim(header)))
     144                 :           0 :    call writebuffer(socket, "READY       ", HDRLEN)
     145                 :           0 :    call readbuffer(socket, header, HDRLEN)
     146   [ #  #  #  # ]:           0 :    ABI_CHECK(trim(header) == "POSDATA", sjoin("Expecting POSDATA header, got:", trim(header)))
     147         [ #  # ]:           0 :    call handle_posdata(origin_natom, origin_rprimd, origin_xred)
     148                 :             :  end if
     149                 :             : 
     150                 :             :  ! broadcast data to other procs.
     151                 :           0 :  call xmpi_bcast(origin_natom, master, comm, ierr)
     152                 :           0 :  call xmpi_bcast(origin_rprimd, master, comm, ierr)
     153         [ #  # ]:           0 :  if (my_rank /= master) then
     154   [ #  #  #  #  :           0 :    ABI_MALLOC(origin_xred, (3, origin_natom))
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     155                 :             :  end if
     156                 :           0 :  call xmpi_bcast(origin_xred, master, comm, ierr)
     157                 :           0 :  call wrtout(std_out, "ipi_setup completed")
     158                 :             : 
     159                 :           0 : end subroutine ipi_setup
     160                 :             : !!***
     161                 :             : 
     162                 :             : !!****f* m_ipi/ipi_check_initial_consistency
     163                 :             : !! NAME
     164                 :             : !! ipi_check_initial_consistency
     165                 :             : !!
     166                 :             : !! FUNCTION
     167                 :             : !! Compare initial configuration read from input file with the one trasmitted by the server.
     168                 :             : !!
     169                 :             : !! INPUTS
     170                 :             : !!
     171                 :             : !! OUTPUT
     172                 :             : !!
     173                 :             : !! OUTPUT
     174                 :             : !!
     175                 :             : !! SOURCE
     176                 :             : 
     177                 :           0 : subroutine ipi_check_initial_consistency(in_natom, in_rprimd, in_xred, ierr)
     178                 :             : 
     179                 :             :  integer,intent(in) :: in_natom
     180                 :             :  real(dp),intent(in) :: in_rprimd(3,3)
     181                 :             :  real(dp),intent(in) :: in_xred(3,in_natom)
     182                 :             :  integer,intent(out) :: ierr
     183                 :             : 
     184                 :             :  integer :: ii
     185                 :             : 
     186                 :           0 :  call wrtout(std_out, "ipi mode: Checking whether initial geometry from server agrees with input file")
     187                 :             : 
     188                 :           0 :  ierr = 0
     189         [ #  # ]:           0 :  if (in_natom /= origin_natom) then
     190                 :           0 :    ABI_WARNING(sjoin("in_natom:", sjoin(itoa(in_natom), " != origin_natom", itoa(origin_natom))))
     191                 :           0 :    ierr = ierr + 1
     192                 :             :  end if
     193                 :             : 
     194   [ #  #  #  #  :           0 :  if (any(abs(in_rprimd - origin_rprimd) > tol6)) then
             #  #  #  # ]
     195                 :           0 :    ABI_WARNING("Mismatch between input file and data from socket: in_rprimd and origin_rprimd do not agree within 1e-6")
     196                 :           0 :    write(std_out, "(a)")" in_rprind(:,ii), origin_rprimd(:,ii)"
     197         [ #  # ]:           0 :    do ii=1,3
     198                 :           0 :      write(std_out, *)in_rprimd(:,ii), origin_rprimd(:,ii)
     199                 :             :    end do
     200                 :           0 :    ierr = ierr + 1
     201                 :             :  end if
     202                 :             : 
     203         [ #  # ]:           0 :  if (.not. allocated(origin_xred)) then
     204                 :           0 :    ierr = ierr + 1
     205                 :           0 :    ABI_WARNING("origin_xred is not allocated!")
     206                 :             :  end if
     207                 :             : 
     208   [ #  #  #  # ]:           0 :  if (in_natom == origin_natom .and. allocated(origin_xred)) then
     209   [ #  #  #  #  :           0 :    if (any(abs(in_xred - origin_xred) > tol6)) then
             #  #  #  # ]
     210                 :           0 :      ABI_WARNING("Mismatch between input file and data from socket: in_xred and origin_xred do not agree withing 1e-6")
     211                 :           0 :      ierr = ierr + 1
     212                 :           0 :      write(std_out, "(a)")" in_xred(:,ii), origin_xred(:,ii)"
     213         [ #  # ]:           0 :      do ii=1,3
     214                 :           0 :        write(std_out, *)in_xred(:,ii), origin_xred(:,ii)
     215                 :             :      end do
     216                 :             :    end if
     217                 :             :  end if
     218                 :             : 
     219                 :             :  !ABI_CHECK(ierr == 0, "Initial structure sent by i-pi server does not match the one read from file! See messages above")
     220                 :             : 
     221                 :           0 : end subroutine ipi_check_initial_consistency
     222                 :             : !!***
     223                 :             : 
     224                 :             : !!****f* m_ipi/handle_posdata
     225                 :             : !! NAME
     226                 :             : !! handle_posdata
     227                 :             : !!
     228                 :             : !! FUNCTION
     229                 :             : !! Receive new geometry from the server after POSDATA header.
     230                 :             : !!
     231                 :             : !! INPUTS
     232                 :             : !!
     233                 :             : !! OUTPUT
     234                 :             : !!
     235                 :             : !! OUTPUT
     236                 :             : !!
     237                 :             : !! SOURCE
     238                 :             : 
     239                 :           0 : subroutine handle_posdata(out_natom, out_rprimd, out_xred)
     240                 :             : 
     241                 :             :  integer,intent(out) :: out_natom
     242                 :             :  real(dp),intent(out) :: out_rprimd(3,3)
     243                 :             :  real(dp),allocatable,intent(out) :: out_xred(:,:)
     244                 :             : 
     245                 :             :  real(dp) :: gprimd(3,3), mtxbuffer(9)
     246                 :           0 :  real(dp), allocatable :: combuf(:), xcart(:,:)
     247                 :             : 
     248                 :           0 :  call readbuffer(socket, mtxbuffer, 9)
     249   [ #  #  #  # ]:           0 :  out_rprimd = transpose(reshape(mtxbuffer, [3, 3]))
     250                 :           0 :  call readbuffer(socket, mtxbuffer, 9)
     251                 :           0 :  gprimd = transpose(reshape(mtxbuffer, [3, 3]))
     252                 :           0 :  call readbuffer(socket, out_natom)
     253   [ #  #  #  #  :           0 :  ABI_MALLOC(combuf, (3 * out_natom))
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     254                 :           0 :  call readbuffer(socket, combuf, 3 * out_natom)
     255   [ #  #  #  #  :           0 :  ABI_MALLOC(xcart, (3, out_natom))
          #  #  #  #  #  
                #  #  # ]
     256         [ #  # ]:           0 :  xcart = reshape(combuf, [3, out_natom])
     257   [ #  #  #  #  :           0 :  ABI_MALLOC(out_xred, (3, out_natom))
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     258                 :           0 :  call xcart2xred(out_natom, out_rprimd, xcart, out_xred)
     259         [ #  # ]:           0 :  ABI_FREE(combuf)
     260         [ #  # ]:           0 :  ABI_FREE(xcart)
     261                 :             : 
     262                 :           0 : end subroutine handle_posdata
     263                 :             : !!***
     264                 :             : 
     265                 :             : !!****f* m_ipi/ipi_shutdown
     266                 :             : !! NAME
     267                 :             : !! ipi_shutdown
     268                 :             : !!
     269                 :             : !! FUNCTION
     270                 :             : !!
     271                 :             : !! INPUTS
     272                 :             : !!
     273                 :             : !! OUTPUT
     274                 :             : !!
     275                 :             : !! OUTPUT
     276                 :             : !!
     277                 :             : !! SOURCE
     278                 :             : 
     279                 :           0 : subroutine ipi_shutdown()
     280                 :             : 
     281                 :             : ! *************************************************************************
     282                 :             : 
     283                 :           0 :  origin_natom = 0
     284                 :           0 :  origin_rprimd = zero
     285         [ #  # ]:           0 :  ABI_SFREE(origin_xred)
     286                 :             :  !call close_socket()
     287                 :             : 
     288                 :           0 : end subroutine ipi_shutdown
     289                 :             : !!***
     290                 :             : 
     291                 :             : !!****f* m_ipi/ipi_pred
     292                 :             : !! NAME
     293                 :             : !! ipi_pred
     294                 :             : !!
     295                 :             : !! FUNCTION
     296                 :             : !!  "predict" new structure using the data sent by the server.
     297                 :             : !!
     298                 :             : !! INPUTS
     299                 :             : !! ab_mover <type(abimover)> : Datatype with all the information needed by the predictor
     300                 :             : !! itime  : Index of the present iteration
     301                 :             : !! ntime  : Maximal number of iterations
     302                 :             : !! zDEBUG : if true print some debugging information
     303                 :             : !!
     304                 :             : !! OUTPUT
     305                 :             : !!
     306                 :             : !! SIDE EFFECTS
     307                 :             : !! hist <type(abihist)>: History of positions,forces,acell, rprimd, stresses
     308                 :             : !!
     309                 :             : !! OUTPUT
     310                 :             : !!
     311                 :             : !! SOURCE
     312                 :             : 
     313                 :           0 : subroutine ipi_pred(ab_mover, hist, itime, ntime, zDEBUG, iexit, comm_cell)
     314                 :             : 
     315                 :             : !Arguments ------------------------------------
     316                 :             : !scalars
     317                 :             :  integer,intent(in) :: itime, ntime, iexit, comm_cell
     318                 :             :  logical,intent(in) :: zDEBUG
     319                 :             :  type(abimover),intent(in) :: ab_mover
     320                 :             :  type(abihist),intent(inout) :: hist
     321                 :             : 
     322                 :             : !local variables
     323                 :             :  integer,parameter :: master = 0
     324                 :             :  integer :: my_rank, natom, new_natom, ierr !, ihist_prev
     325                 :             :  real(dp) :: etotal, ucvol
     326                 :             :  character(len=HDRLEN) :: header
     327                 :             :  character(len=500) :: msg
     328                 :             : !arrays
     329                 :           0 :  real(dp) :: acell(3), rprimd(3,3), xred(3,ab_mover%natom), strten(6), sigma(3,3)
     330                 :             :  real(dp) :: new_rprimd(3, 3)
     331                 :           0 :  real(dp),allocatable :: new_xred(:,:)
     332                 :             : 
     333                 :             : ! *************************************************************************
     334                 :             : 
     335                 :           0 :  write(msg, "(3(a,i0))")" ipi_pred: itime: ", itime, ", ntime: ", ntime, ", iexit:", iexit
     336                 :           0 :  call wrtout(std_out, msg)
     337                 :             : 
     338                 :           0 :  natom = ab_mover%natom
     339                 :             :  ! Obtain the present values from the history
     340                 :           0 :  call hist2var(acell, hist, natom, rprimd, xred, zDEBUG)
     341                 :           0 :  etotal = hist%etot(hist%ihist)
     342         [ #  # ]:           0 :  strten = hist%strten(:,hist%ihist)
     343                 :           0 :  ucvol = det3r(rprimd)
     344                 :             : 
     345         [ #  # ]:           0 :  if (my_rank == master) then
     346                 :           0 :    call readbuffer(socket, header, HDRLEN)
     347   [ #  #  #  # ]:           0 :    ABI_CHECK(trim(header) == "STATUS", sjoin("Expecting STATUS header, got:", trim(header)))
     348                 :           0 :    call writebuffer( socket, "HAVEDATA    ", HDRLEN )
     349                 :           0 :    call readbuffer(socket, header, HDRLEN)
     350   [ #  #  #  # ]:           0 :    ABI_CHECK(trim(header) == "GETFORCE", sjoin("Expecting GETFORCE header, got:", trim(header)))
     351                 :             : 
     352                 :             :    ! Communicate energy info back to i-pi
     353                 :           0 :    call wrtout(std_out, " i-pi mode: Returning etotal, forces, and stress tensor to server...")
     354                 :           0 :    call writebuffer(socket, "FORCEREADY  ", HDRLEN)
     355                 :           0 :    call writebuffer(socket, etotal)
     356                 :           0 :    call writebuffer(socket, natom)
     357                 :           0 :    call writebuffer_dv(socket, hist%fcart(:,:,hist%ihist), 3 * natom)
     358                 :           0 :    call stress_voigt_to_mat(strten, sigma)
     359                 :             :    ! Well it's a symmetric tensor.
     360                 :             :    ! TODO: Check volume
     361   [ #  #  #  #  :           0 :    sigma = -ucvol * transpose(sigma)
             #  #  #  # ]
     362                 :           0 :    call writebuffer_dv(socket, sigma, 9)
     363                 :             : 
     364                 :             :    ! Note: i-pi can also receive an arbitrary string, that will be printed
     365                 :             :    ! out to the "extra" trajectory file. This is useful if you want to
     366                 :             :    ! return additional information, e.g. atomic charges, wannier centres,
     367                 :             :    ! etc. one must return the number of characters, then the string. Here
     368                 :             :    ! we just send back zero characters.
     369                 :             :    !
     370                 :           0 :    call writebuffer(socket, 0)
     371                 :             : 
     372                 :             :    ! ===============================================================
     373                 :             :    ! Here master waits for new lattice and positions from the server
     374                 :             :    ! ===============================================================
     375                 :           0 :    call readbuffer(socket, header, HDRLEN)
     376   [ #  #  #  # ]:           0 :    ABI_CHECK(trim(header) == "STATUS", sjoin("Expecting STATUS header, got:", trim(header)))
     377                 :           0 :    call writebuffer(socket, "READY       ", HDRLEN)
     378                 :           0 :    call readbuffer(socket, header, HDRLEN)
     379   [ #  #  #  # ]:           0 :    ABI_CHECK(trim(header) == "POSDATA", sjoin("Expecting POSDATA header, got:", trim(header)))
     380                 :           0 :    call handle_posdata(new_natom, new_rprimd, new_xred)
     381                 :             : 
     382                 :             :    ! Some basic consistency checks. Obviously there are lot of things that can go wrong here
     383                 :             :    ! if the driver changes the space group or the input file is not consistent with
     384                 :             :    ! the logic implemented by the server.
     385         [ #  # ]:           0 :    ABI_CHECK(new_natom == ab_mover%natom, "ipi server shall not change the number of atoms!")
     386   [ #  #  #  #  :           0 :    if (ab_mover%optcell == 0 .and. any(abs(new_rprimd - origin_rprimd) > tol6)) then
          #  #  #  #  #  
                      # ]
     387                 :           0 :      ABI_ERROR("Mismatch between origin_rprimd and data from socket: origin_rprimd and new_rprimd do not agree within 1e-6")
     388                 :             :    end if
     389                 :             :  end if
     390                 :             : 
     391                 :             :  ! ====================
     392                 :             :  ! All procs block here
     393                 :             :  ! ====================
     394                 :           0 :  call xmpi_barrier(comm_cell)
     395                 :           0 :  call xmpi_bcast(new_rprimd, master, comm_cell, ierr)
     396                 :           0 :  call xmpi_bcast(new_xred, master, comm_cell, ierr)
     397                 :             : 
     398                 :             :  ! Update the history with the prediction
     399                 :             :  ! Increase indexes
     400                 :           0 :  hist%ihist = abihist_findIndex(hist, +1)
     401                 :             :  !call mkradim(acell,rprim,rprimd_symm)
     402                 :             : 
     403                 :             :  ! Fill the history with the variables xred, acell, rprimd, vel
     404         [ #  # ]:           0 :  acell = one
     405                 :           0 :  call var2hist(acell, hist, ab_mover%natom, new_rprimd, new_xred, zDEBUG)
     406                 :             :  !ihist_prev = abihist_findIndex(hist, -1)
     407                 :             :  ! FIXME: I don't know how to handle vel if MD run!
     408                 :             :  !hist%vel(:,:,hist%ihist) = hist%vel(:,:,ihist_prev)
     409                 :             : 
     410         [ #  # ]:           0 : end subroutine ipi_pred
     411                 :             : !!***
     412                 :             : 
     413                 :             : end module m_ipi
     414                 :             : !!***
        

Generated by: LCOV version 2.3-1