2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team,
6 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012,2013, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
49 #include "gmx_fatal.h"
54 #include "sighandler.h"
63 #include "mpelogging.h"
65 #define PP_PME_CHARGE (1<<0)
66 #define PP_PME_CHARGEB (1<<1)
67 #define PP_PME_COORD (1<<2)
68 #define PP_PME_FEP (1<<3)
69 #define PP_PME_ENER_VIR (1<<4)
70 #define PP_PME_FINISH (1<<5)
71 #define PP_PME_SWITCH (1<<6)
73 #define PME_PP_SIGSTOP (1<<0)
74 #define PME_PP_SIGSTOPNSS (1<<1)
76 typedef struct gmx_pme_pp {
78 MPI_Comm mpi_comm_mysim;
80 int nnode; /* The number of PP node to communicate with */
81 int *node; /* The PP node ranks */
82 int node_peer; /* The peer PP node rank */
83 int *nat; /* The number of atom for each PP node */
84 int flags_charge; /* The flags sent along with the last charges */
96 typedef struct gmx_pme_comm_n_box {
103 gmx_large_int_t step;
104 ivec grid_size; /* For PME grid tuning */
105 real ewaldcoeff; /* For PME grid tuning */
106 } gmx_pme_comm_n_box_t;
113 gmx_stop_cond_t stop_cond;
114 } gmx_pme_comm_vir_ene_t;
119 gmx_pme_pp_t gmx_pme_pp_init(t_commrec *cr)
121 struct gmx_pme_pp *pme_pp;
127 pme_pp->mpi_comm_mysim = cr->mpi_comm_mysim;
128 MPI_Comm_rank(cr->mpi_comm_mygroup,&rank);
129 get_pme_ddnodes(cr,rank,&pme_pp->nnode,&pme_pp->node,&pme_pp->node_peer);
130 snew(pme_pp->nat,pme_pp->nnode);
131 snew(pme_pp->req,2*pme_pp->nnode);
132 snew(pme_pp->stat,2*pme_pp->nnode);
134 pme_pp->flags_charge = 0;
140 /* This should be faster with a real non-blocking MPI implementation */
141 /* #define GMX_PME_DELAYED_WAIT */
143 static void gmx_pme_send_q_x_wait(gmx_domdec_t *dd)
147 MPI_Waitall(dd->nreq_pme,dd->req_pme,MPI_STATUSES_IGNORE);
153 static void gmx_pme_send_q_x(t_commrec *cr, int flags,
154 real *chargeA, real *chargeB,
157 int maxshift_x, int maxshift_y,
158 gmx_large_int_t step)
161 gmx_pme_comm_n_box_t *cnb;
168 fprintf(debug,"PP node %d sending to PME node %d: %d%s%s\n",
169 cr->sim_nodeid,dd->pme_nodeid,n,
170 flags & PP_PME_CHARGE ? " charges" : "",
171 flags & PP_PME_COORD ? " coordinates" : "");
173 #ifdef GMX_PME_DELAYED_WAIT
174 /* When can not use cnb until pending communication has finished */
175 gmx_pme_send_x_q_wait(dd);
178 if (dd->pme_receive_vir_ener) {
179 /* Peer PP node: communicate all data */
186 cnb->maxshift_x = maxshift_x;
187 cnb->maxshift_y = maxshift_y;
188 cnb->lambda = lambda;
190 if (flags & PP_PME_COORD)
191 copy_mat(box,cnb->box);
193 MPI_Isend(cnb,sizeof(*cnb),MPI_BYTE,
194 dd->pme_nodeid,0,cr->mpi_comm_mysim,
195 &dd->req_pme[dd->nreq_pme++]);
197 } else if (flags & PP_PME_CHARGE) {
199 /* Communicate only the number of atoms */
200 MPI_Isend(&n,sizeof(n),MPI_BYTE,
201 dd->pme_nodeid,0,cr->mpi_comm_mysim,
202 &dd->req_pme[dd->nreq_pme++]);
208 if (flags & PP_PME_CHARGE) {
209 MPI_Isend(chargeA,n*sizeof(real),MPI_BYTE,
210 dd->pme_nodeid,1,cr->mpi_comm_mysim,
211 &dd->req_pme[dd->nreq_pme++]);
213 if (flags & PP_PME_CHARGEB) {
214 MPI_Isend(chargeB,n*sizeof(real),MPI_BYTE,
215 dd->pme_nodeid,2,cr->mpi_comm_mysim,
216 &dd->req_pme[dd->nreq_pme++]);
218 if (flags & PP_PME_COORD) {
219 MPI_Isend(x[0],n*sizeof(rvec),MPI_BYTE,
220 dd->pme_nodeid,3,cr->mpi_comm_mysim,
221 &dd->req_pme[dd->nreq_pme++]);
225 #ifndef GMX_PME_DELAYED_WAIT
226 /* Wait for the data to arrive */
227 /* We can skip this wait as we are sure x and q will not be modified
228 * before the next call to gmx_pme_send_x_q or gmx_pme_receive_f.
230 gmx_pme_send_q_x_wait(dd);
235 void gmx_pme_send_q(t_commrec *cr,
236 gmx_bool bFreeEnergy, real *chargeA, real *chargeB,
237 int maxshift_x, int maxshift_y)
241 flags = PP_PME_CHARGE;
243 flags |= PP_PME_CHARGEB;
245 gmx_pme_send_q_x(cr,flags,
246 chargeA,chargeB,NULL,NULL,0,maxshift_x,maxshift_y,-1);
249 void gmx_pme_send_x(t_commrec *cr, matrix box, rvec *x,
250 gmx_bool bFreeEnergy, real lambda,
252 gmx_large_int_t step)
256 flags = PP_PME_COORD;
260 flags |= PP_PME_ENER_VIR;
262 gmx_pme_send_q_x(cr,flags,NULL,NULL,box,x,lambda,0,0,step);
265 void gmx_pme_send_finish(t_commrec *cr)
269 flags = PP_PME_FINISH;
271 gmx_pme_send_q_x(cr,flags,NULL,NULL,NULL,NULL,0,0,0,-1);
274 void gmx_pme_send_switch(t_commrec *cr, ivec grid_size, real ewaldcoeff)
277 gmx_pme_comm_n_box_t cnb;
279 if (cr->dd->pme_receive_vir_ener)
281 cnb.flags = PP_PME_SWITCH;
282 copy_ivec(grid_size,cnb.grid_size);
283 cnb.ewaldcoeff = ewaldcoeff;
285 /* We send this, uncommon, message blocking to simplify the code */
286 MPI_Send(&cnb,sizeof(cnb),MPI_BYTE,
287 cr->dd->pme_nodeid,0,cr->mpi_comm_mysim);
292 int gmx_pme_recv_q_x(struct gmx_pme_pp *pme_pp,
293 real **chargeA, real **chargeB,
294 matrix box, rvec **x,rvec **f,
295 int *maxshift_x, int *maxshift_y,
296 gmx_bool *bFreeEnergy,real *lambda,
298 gmx_large_int_t *step,
299 ivec grid_size, real *ewaldcoeff)
301 gmx_pme_comm_n_box_t cnb;
302 int nat=0,q,messages,sender;
307 /* avoid compiler warning about unused variable without MPI support */
311 /* Receive the send count, box and time step from the peer PP node */
312 MPI_Recv(&cnb,sizeof(cnb),MPI_BYTE,
314 pme_pp->mpi_comm_mysim,MPI_STATUS_IGNORE);
318 fprintf(debug,"PME only node receiving:%s%s%s%s\n",
319 (cnb.flags & PP_PME_CHARGE) ? " charges" : "",
320 (cnb.flags & PP_PME_COORD ) ? " coordinates" : "",
321 (cnb.flags & PP_PME_FINISH) ? " finish" : "",
322 (cnb.flags & PP_PME_SWITCH) ? " switch" : "");
325 if (cnb.flags & PP_PME_SWITCH)
327 /* Special case, receive the new parameters and return */
328 copy_ivec(cnb.grid_size,grid_size);
329 *ewaldcoeff = cnb.ewaldcoeff;
334 if (cnb.flags & PP_PME_CHARGE) {
335 /* Receive the send counts from the other PP nodes */
336 for(sender=0; sender<pme_pp->nnode; sender++) {
337 if (pme_pp->node[sender] == pme_pp->node_peer) {
338 pme_pp->nat[sender] = cnb.natoms;
340 MPI_Irecv(&(pme_pp->nat[sender]),sizeof(pme_pp->nat[0]),
342 pme_pp->node[sender],0,
343 pme_pp->mpi_comm_mysim,&pme_pp->req[messages++]);
346 MPI_Waitall(messages, pme_pp->req, pme_pp->stat);
350 for(sender=0; sender<pme_pp->nnode; sender++)
351 nat += pme_pp->nat[sender];
353 if (nat > pme_pp->nalloc) {
354 pme_pp->nalloc = over_alloc_dd(nat);
355 srenew(pme_pp->chargeA,pme_pp->nalloc);
356 if (cnb.flags & PP_PME_CHARGEB)
357 srenew(pme_pp->chargeB,pme_pp->nalloc);
358 srenew(pme_pp->x,pme_pp->nalloc);
359 srenew(pme_pp->f,pme_pp->nalloc);
362 /* maxshift is sent when the charges are sent */
363 *maxshift_x = cnb.maxshift_x;
364 *maxshift_y = cnb.maxshift_y;
366 /* Receive the charges in place */
367 for(q=0; q<((cnb.flags & PP_PME_CHARGEB) ? 2 : 1); q++) {
369 charge_pp = pme_pp->chargeA;
371 charge_pp = pme_pp->chargeB;
373 for(sender=0; sender<pme_pp->nnode; sender++) {
374 if (pme_pp->nat[sender] > 0) {
375 MPI_Irecv(charge_pp+nat,
376 pme_pp->nat[sender]*sizeof(real),
378 pme_pp->node[sender],1+q,
379 pme_pp->mpi_comm_mysim,
380 &pme_pp->req[messages++]);
381 nat += pme_pp->nat[sender];
383 fprintf(debug,"Received from PP node %d: %d "
385 pme_pp->node[sender],pme_pp->nat[sender]);
390 pme_pp->flags_charge = cnb.flags;
393 if (cnb.flags & PP_PME_COORD) {
394 if (!(pme_pp->flags_charge & PP_PME_CHARGE))
395 gmx_incons("PME-only node received coordinates before charges"
398 /* The box, FE flag and lambda are sent along with the coordinates
400 copy_mat(cnb.box,box);
401 *bFreeEnergy = (cnb.flags & PP_PME_FEP);
402 *lambda = cnb.lambda;
403 *bEnerVir = (cnb.flags & PP_PME_ENER_VIR);
405 if (*bFreeEnergy && !(pme_pp->flags_charge & PP_PME_CHARGEB))
406 gmx_incons("PME-only node received free energy request, but "
407 "did not receive B-state charges");
409 /* Receive the coordinates in place */
411 for(sender=0; sender<pme_pp->nnode; sender++) {
412 if (pme_pp->nat[sender] > 0) {
413 MPI_Irecv(pme_pp->x[nat],pme_pp->nat[sender]*sizeof(rvec),
415 pme_pp->node[sender],3,
416 pme_pp->mpi_comm_mysim,&pme_pp->req[messages++]);
417 nat += pme_pp->nat[sender];
419 fprintf(debug,"Received from PP node %d: %d "
421 pme_pp->node[sender],pme_pp->nat[sender]);
426 /* Wait for the coordinates and/or charges to arrive */
427 MPI_Waitall(messages, pme_pp->req, pme_pp->stat);
429 } while (!(cnb.flags & (PP_PME_COORD | PP_PME_FINISH)));
434 *chargeA = pme_pp->chargeA;
435 *chargeB = pme_pp->chargeB;
440 return ((cnb.flags & PP_PME_FINISH) ? -1 : nat);
443 static void receive_virial_energy(t_commrec *cr,
444 matrix vir,real *energy,real *dvdlambda,
447 gmx_pme_comm_vir_ene_t cve;
449 if (cr->dd->pme_receive_vir_ener) {
452 "PP node %d receiving from PME node %d: virial and energy\n",
453 cr->sim_nodeid,cr->dd->pme_nodeid);
455 MPI_Recv(&cve,sizeof(cve),MPI_BYTE,cr->dd->pme_nodeid,1,cr->mpi_comm_mysim,
458 memset(&cve,0,sizeof(cve));
461 m_add(vir,cve.vir,vir);
462 *energy = cve.energy;
463 *dvdlambda += cve.dvdlambda;
464 *pme_cycles = cve.cycles;
466 if ( cve.stop_cond != gmx_stop_cond_none )
468 gmx_set_stop_condition(cve.stop_cond);
476 void gmx_pme_receive_f(t_commrec *cr,
477 rvec f[], matrix vir,
478 real *energy, real *dvdlambda,
483 #ifdef GMX_PME_DELAYED_WAIT
484 /* Wait for the x request to finish */
485 gmx_pme_send_q_x_wait(cr->dd);
488 natoms = cr->dd->nat_home;
490 if (natoms > cr->dd->pme_recv_f_alloc)
492 cr->dd->pme_recv_f_alloc = over_alloc_dd(natoms);
493 srenew(cr->dd->pme_recv_f_buf, cr->dd->pme_recv_f_alloc);
497 MPI_Recv(cr->dd->pme_recv_f_buf[0],
498 natoms*sizeof(rvec),MPI_BYTE,
499 cr->dd->pme_nodeid,0,cr->mpi_comm_mysim,
503 for(i=0; i<natoms; i++)
504 rvec_inc(f[i],cr->dd->pme_recv_f_buf[i]);
507 receive_virial_energy(cr,vir,energy,dvdlambda,pme_cycles);
510 void gmx_pme_send_force_vir_ener(struct gmx_pme_pp *pme_pp,
512 real energy, real dvdlambda,
515 gmx_pme_comm_vir_ene_t cve;
516 int messages,ind_start,ind_end,receiver;
520 /* Now the evaluated forces have to be transferred to the PP nodes */
523 for (receiver=0; receiver<pme_pp->nnode; receiver++) {
525 ind_end = ind_start + pme_pp->nat[receiver];
527 if (MPI_Isend(f[ind_start],(ind_end-ind_start)*sizeof(rvec),MPI_BYTE,
528 pme_pp->node[receiver],0,
529 pme_pp->mpi_comm_mysim,&pme_pp->req[messages++]) != 0)
530 gmx_comm("MPI_Isend failed in do_pmeonly");
534 /* send virial and energy to our last PP node */
535 copy_mat(vir,cve.vir);
537 cve.dvdlambda = dvdlambda;
538 /* check for the signals to send back to a PP node */
539 cve.stop_cond = gmx_get_stop_condition();
544 fprintf(debug,"PME node sending to PP node %d: virial and energy\n",
547 MPI_Isend(&cve,sizeof(cve),MPI_BYTE,
549 pme_pp->mpi_comm_mysim,&pme_pp->req[messages++]);
551 /* Wait for the forces to arrive */
552 MPI_Waitall(messages, pme_pp->req, pme_pp->stat);