LCOV - code coverage report
Current view: top level - src - ipi_driver.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:2c0d679) Lines: 0.0 % 126 0
Test Date: 2026-09-25 00:58:37 Functions: 0.0 % 1 0

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Driver mode - To communicate with i-PI Python wrapper
      10              : !> \par History
      11              : !>      none
      12              : !> \author Michele Ceriotti 03.2012
      13              : ! **************************************************************************************************
      14              : MODULE ipi_driver
      15              :    USE, INTRINSIC :: IEEE_ARITHMETIC, ONLY: ieee_is_finite
      16              :    USE ISO_C_BINDING, ONLY: C_CHAR, &
      17              :                             C_DOUBLE, &
      18              :                             C_INT, &
      19              :                             C_LOC, &
      20              :                             C_NULL_CHAR, &
      21              :                             C_PTR
      22              :    USE bibliography, ONLY: Ceriotti2014, &
      23              :                            Kapil2016, &
      24              :                            cite_reference
      25              :    USE cell_methods, ONLY: cell_create, &
      26              :                            init_cell
      27              :    USE cell_types, ONLY: cell_release, &
      28              :                          cell_type
      29              :    USE cp_external_control, ONLY: external_control
      30              :    USE cp_log_handling, ONLY: cp_logger_get_default_io_unit
      31              :    USE cp_subsys_types, ONLY: cp_subsys_get, &
      32              :                               cp_subsys_set, &
      33              :                               cp_subsys_type
      34              :    USE force_env_methods, ONLY: force_env_calc_energy_force
      35              :    USE force_env_types, ONLY: force_env_get, &
      36              :                               force_env_type
      37              :    USE global_types, ONLY: global_environment_type
      38              :    USE input_section_types, ONLY: section_vals_get_subs_vals, &
      39              :                                   section_vals_type, &
      40              :                                   section_vals_val_get
      41              :    USE kinds, ONLY: default_path_length, &
      42              :                     default_string_length, &
      43              :                     dp, &
      44              :                     int_4
      45              :    USE message_passing, ONLY: mp_para_env_type, &
      46              :                               mp_request_type, &
      47              :                               mp_testany
      48              :    USE mathlib, ONLY: det_3x3
      49              : #ifndef __NO_SOCKETS
      50              :    USE sockets_interface, ONLY: writebuffer, &
      51              :                                 readbuffer, &
      52              :                                 open_connect_socket, &
      53              :                                 close_socket, &
      54              :                                 uwait
      55              : #endif
      56              :    USE virial_types, ONLY: virial_type
      57              : #include "./base/base_uses.f90"
      58              : 
      59              :    IMPLICIT NONE
      60              : 
      61              :    PRIVATE
      62              : 
      63              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'ipi_driver'
      64              : 
      65              :    PUBLIC :: run_driver
      66              : 
      67              : CONTAINS
      68              : 
      69              : ! **************************************************************************************************
      70              : !> \brief ...
      71              : !> \param force_env ...
      72              : !> \param globenv ...
      73              : !> \par History
      74              : !>       12.2013 included in repository
      75              : !> \author Ceriotti
      76              : ! **************************************************************************************************
      77              : 
      78            0 :    SUBROUTINE run_driver(force_env, globenv)
      79              :       TYPE(force_env_type), POINTER            :: force_env
      80              :       TYPE(global_environment_type), POINTER   :: globenv
      81              : 
      82              :       CHARACTER(len=*), PARAMETER :: routineN = 'run_driver'
      83              : 
      84              : #ifdef __NO_SOCKETS
      85              :       INTEGER                                  :: handle
      86              :       CALL timeset(routineN, handle)
      87              :       CPABORT("CP2K was compiled with the __NO_SOCKETS option!")
      88              :       MARK_USED(globenv)
      89              :       MARK_USED(force_env)
      90              : #else
      91              :       INTEGER, PARAMETER                       :: MSGLEN = 12
      92              : 
      93              :       CHARACTER(len=default_path_length)       :: c_hostname, drv_hostname, drv_prefix
      94              :       CHARACTER(LEN=default_string_length)     :: header
      95              :       INTEGER                                  :: drv_port, handle, i_drv_unix, &
      96              :                                                   idir, ii, inet, ip, iwait, &
      97              :                                                   nat, output_unit, socket
      98            0 :       TYPE(mp_request_type), DIMENSION(2) ::                                            wait_req
      99            0 :       INTEGER(KIND=int_4), POINTER             :: wait_msg(:)
     100              :       LOGICAL                                  :: drv_unix, fwait, hasdata, &
     101              :                                                   ionode, should_stop
     102              :       REAL(KIND=dp)                            :: cellh(3, 3), cellih(3, 3), &
     103              :                                                   mxmat(9), pot, vir(3, 3)
     104            0 :       REAL(KIND=dp), ALLOCATABLE               :: combuf(:)
     105              :       TYPE(cell_type), POINTER                 :: cpcell
     106              :       TYPE(mp_para_env_type), POINTER          :: para_env
     107              :       TYPE(cp_subsys_type), POINTER            :: subsys
     108              :       TYPE(section_vals_type), POINTER         :: drv_section, motion_section
     109              :       TYPE(virial_type), POINTER               :: virial
     110              :       REAL(KIND=dp)                            :: sleeptime
     111              :       INTEGER, DIMENSION(3)                    :: perd
     112              :       TYPE(cell_type), POINTER                 :: oldcell
     113              : 
     114            0 :       CALL timeset(routineN, handle)
     115              : 
     116            0 :       CALL cite_reference(Ceriotti2014)
     117            0 :       CALL cite_reference(Kapil2016)
     118              : 
     119              : ! server address parsing
     120              : ! buffers and temporaries for communication
     121              : ! access cp2k structures
     122              : 
     123            0 :       CPASSERT(ASSOCIATED(force_env))
     124            0 :       CALL force_env_get(force_env, para_env=para_env)
     125              : 
     126            0 :       hasdata = .FALSE.
     127            0 :       ionode = para_env%is_source()
     128              : 
     129            0 :       output_unit = cp_logger_get_default_io_unit()
     130              : 
     131              :       ! reads driver parameters from input
     132            0 :       motion_section => section_vals_get_subs_vals(force_env%root_section, "MOTION")
     133            0 :       drv_section => section_vals_get_subs_vals(motion_section, "DRIVER")
     134              : 
     135            0 :       CALL section_vals_val_get(drv_section, "HOST", c_val=drv_hostname)
     136            0 :       CALL section_vals_val_get(drv_section, "PORT", i_val=drv_port)
     137            0 :       CALL section_vals_val_get(drv_section, "UNIX", l_val=drv_unix)
     138            0 :       CALL section_vals_val_get(drv_section, "PREFIX", c_val=drv_prefix)
     139            0 :       CALL section_vals_val_get(drv_section, "SLEEP_TIME", r_val=sleeptime)
     140            0 :       CPASSERT(sleeptime >= 0)
     141              : 
     142              :       ! opens the socket
     143            0 :       socket = 0
     144            0 :       inet = 1
     145            0 :       i_drv_unix = 1 ! a bit convoluted. socket.c uses a different convention...
     146            0 :       IF (drv_unix) i_drv_unix = 0
     147            0 :       IF (output_unit > 0) THEN
     148            0 :          WRITE (output_unit, *) "@ i-PI DRIVER BEING LOADED"
     149            0 :          WRITE (output_unit, *) "@ INPUT DATA: ", TRIM(drv_hostname), drv_port, drv_unix
     150              :       END IF
     151              : 
     152            0 :       IF (drv_unix) THEN
     153              :          ! for UNIX sockets, HOST names the socket file which lives at
     154              :          ! /tmp/<PREFIX>_<HOST> (PREFIX must match the peer's convention,
     155              :          ! e.g. "ipi" for i-PI)
     156            0 :          c_hostname = "/tmp/"//TRIM(drv_prefix)//"_"//TRIM(drv_hostname)//C_NULL_CHAR
     157              :       ELSE
     158            0 :          c_hostname = TRIM(drv_hostname)//C_NULL_CHAR
     159              :       END IF
     160            0 :       IF (ionode) CALL open_connect_socket(socket, i_drv_unix, drv_port, c_hostname)
     161              : 
     162              :       NULLIFY (wait_msg)
     163            0 :       ALLOCATE (wait_msg(1))
     164              :       !now we have a socket, so we can initialize the CP2K environments.
     165            0 :       NULLIFY (cpcell)
     166            0 :       CALL cell_create(cpcell)
     167              :       driver_loop: DO
     168              :          ! do communication on master node only...
     169            0 :          header = ""
     170              : 
     171            0 :          CALL para_env%sync()
     172              : 
     173              :          ! non-blocking sync to avoid useless CPU consumption
     174            0 :          IF (ionode) THEN
     175            0 :             CALL readbuffer(socket, header, MSGLEN)
     176            0 :             wait_msg = 0
     177            0 :             DO iwait = 0, para_env%num_pe - 1
     178            0 :                IF (iwait /= para_env%source) THEN
     179            0 :                   CALL para_env%send(msg=wait_msg, dest=iwait, tag=666)
     180              :                END IF
     181              :             END DO
     182              :          ELSE
     183              :             CALL para_env%irecv(msgout=wait_msg, source=para_env%source, &
     184            0 :                                 tag=666, request=wait_req(2))
     185            0 :             CALL mp_testany(wait_req(2:), flag=fwait)
     186            0 :             DO WHILE (.NOT. fwait)
     187            0 :                CALL mp_testany(wait_req(2:), flag=fwait)
     188            0 :                CALL uwait(sleeptime)
     189              :             END DO
     190              :          END IF
     191              : 
     192            0 :          CALL para_env%sync()
     193              : 
     194            0 :          CALL para_env%bcast(header)
     195              : 
     196            0 :          IF (output_unit > 0) WRITE (output_unit, *) " @ DRIVER MODE: Message from server: ", TRIM(header)
     197            0 :          IF (TRIM(header) == "STATUS") THEN
     198              : 
     199            0 :             CALL para_env%sync()
     200            0 :             IF (ionode) THEN ! does not  need init (well, maybe it should, just to check atom numbers and the like... )
     201            0 :                IF (hasdata) THEN
     202            0 :                   CALL writebuffer(socket, "HAVEDATA    ", MSGLEN)
     203              :                ELSE
     204            0 :                   CALL writebuffer(socket, "READY       ", MSGLEN)
     205              :                END IF
     206              :             END IF
     207            0 :             CALL para_env%sync()
     208            0 :          ELSE IF (TRIM(header) == "POSDATA") THEN
     209            0 :             IF (hasdata) CPABORT("@DRIVER MODE: POSDATA received before GETFORCE")
     210            0 :             IF (ionode) THEN
     211            0 :                CALL readbuffer(socket, mxmat, 9)
     212            0 :                cellh = RESHAPE(mxmat, [3, 3])
     213            0 :                CALL readbuffer(socket, mxmat, 9)
     214            0 :                cellih = RESHAPE(mxmat, [3, 3])
     215            0 :                CALL readbuffer(socket, nat)
     216            0 :                cellh = TRANSPOSE(cellh)
     217            0 :                cellih = TRANSPOSE(cellih)
     218              :             END IF
     219            0 :             CALL para_env%bcast(cellh)
     220            0 :             CALL para_env%bcast(cellih)
     221            0 :             CALL para_env%bcast(nat)
     222            0 :             CALL force_env_get(force_env, subsys=subsys)
     223              :             ! Check before allocating/reading: nat is supplied by the socket peer.
     224            0 :             IF (nat <= 0 .OR. nat /= subsys%particles%n_els .OR. nat > HUGE(nat)/3) THEN
     225            0 :                CPABORT("@DRIVER MODE: Particle number mismatch between i-PI and CP2K input")
     226              :             END IF
     227            0 :             IF (.NOT. ALL(ieee_is_finite(cellh)) .OR. .NOT. ALL(ieee_is_finite(cellih))) THEN
     228            0 :                CPABORT("@DRIVER MODE: Non-finite cell received from i-PI")
     229              :             END IF
     230            0 :             IF (.NOT. ieee_is_finite(det_3x3(cellh)) .OR. det_3x3(cellh) <= 0.0_dp) THEN
     231            0 :                CPABORT("@DRIVER MODE: i-PI cell must be nonsingular and right-handed")
     232              :             END IF
     233            0 :             IF (.NOT. ALLOCATED(combuf)) ALLOCATE (combuf(3*nat))
     234            0 :             IF (ionode) CALL readbuffer(socket, combuf, nat*3)
     235            0 :             CALL para_env%bcast(combuf)
     236              : 
     237            0 :             IF (.NOT. ALL(ieee_is_finite(combuf))) THEN
     238            0 :                CPABORT("@DRIVER MODE: Non-finite positions received from i-PI")
     239              :             END IF
     240            0 :             ii = 0
     241            0 :             DO ip = 1, subsys%particles%n_els
     242            0 :                DO idir = 1, 3
     243            0 :                   ii = ii + 1
     244            0 :                   subsys%particles%els(ip)%r(idir) = combuf(ii)
     245              :                END DO
     246              :             END DO
     247            0 :             NULLIFY (oldcell)
     248            0 :             CALL cp_subsys_get(subsys, cell=oldcell)
     249            0 :             perd = oldcell%perd
     250              : 
     251            0 :             CALL init_cell(cpcell, hmat=cellh, periodic=perd)
     252            0 :             CALL cp_subsys_set(subsys, cell=cpcell)
     253              : 
     254            0 :             CALL force_env_calc_energy_force(force_env, calc_force=.TRUE.)
     255              : 
     256            0 :             IF (output_unit > 0) WRITE (output_unit, *) " @ DRIVER MODE: Received positions "
     257              : 
     258            0 :             combuf = 0
     259            0 :             ii = 0
     260            0 :             DO ip = 1, subsys%particles%n_els
     261            0 :                DO idir = 1, 3
     262            0 :                   ii = ii + 1
     263            0 :                   combuf(ii) = subsys%particles%els(ip)%f(idir)
     264              :                END DO
     265              :             END DO
     266            0 :             CALL force_env_get(force_env, potential_energy=pot)
     267            0 :             CALL force_env_get(force_env, cell=cpcell)
     268            0 :             CALL cp_subsys_get(subsys, virial=virial)
     269            0 :             vir = TRANSPOSE(virial%pv_virial)
     270              : 
     271            0 :             CALL external_control(should_stop, "IPI", globenv=globenv)
     272            0 :             IF (should_stop) EXIT driver_loop
     273              : 
     274            0 :             hasdata = .TRUE.
     275            0 :          ELSE IF (TRIM(header) == "GETFORCE") THEN
     276            0 :             IF (.NOT. hasdata) CPABORT("@DRIVER MODE: GETFORCE received without POSDATA")
     277            0 :             IF (output_unit > 0) WRITE (output_unit, *) " @ DRIVER MODE: Returning v,forces,stress "
     278            0 :             IF (ionode) THEN
     279            0 :                CALL writebuffer(socket, "FORCEREADY  ", MSGLEN)
     280            0 :                CALL writebuffer(socket, pot)
     281            0 :                CALL writebuffer(socket, nat)
     282            0 :                CALL writebuffer(socket, combuf, 3*nat)
     283            0 :                CALL writebuffer(socket, RESHAPE(vir, [9]), 9)
     284              : 
     285              :                ! i-pi can also receive an arbitrary string, that will be printed out to the "extra"
     286              :                ! trajectory file. this is useful if you want to return additional information, e.g.
     287              :                ! atomic charges, wannier centres, etc. one must return the number of characters, then
     288              :                ! the string. here we just send back zero characters.
     289            0 :                nat = 0
     290            0 :                CALL writebuffer(socket, nat) ! writes out zero for the length of the "extra" field (not implemented yet!)
     291              :             END IF
     292              :             hasdata = .FALSE.
     293            0 :          ELSE IF (TRIM(header) == "EXIT") THEN
     294            0 :             IF (output_unit > 0) WRITE (output_unit, *) " @DRIVER MODE:  Socket disconnected, time to exit."
     295              :             EXIT driver_loop
     296              :          ELSE
     297            0 :             CPABORT("@DRIVER MODE: Unknown i-PI message: "//TRIM(header))
     298              :          END IF
     299              :       END DO driver_loop
     300              : 
     301              :       ! clean up
     302            0 :       IF (ionode) CALL close_socket(socket)
     303            0 :       CALL cell_release(cpcell)
     304            0 :       DEALLOCATE (wait_msg)
     305              : #endif
     306              : 
     307            0 :       CALL timestop(handle)
     308              : 
     309            0 :    END SUBROUTINE run_driver
     310              : END MODULE ipi_driver
        

Generated by: LCOV version 2.0-1