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