3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
9 * VERSION 3.3.99_development_20071104
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2006, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * Groningen Machine for Chemical Simulation
46 #include "gromacs/fileio/tpxio.h"
47 #include "gromacs/commandline/pargs.h"
48 #include "gromacs/fileio/futil.h"
49 #include "gmx_fatal.h"
60 #include "gromacs/utility/gmxmpi.h"
66 static int comp_xptr(const void *a
,const void *b
)
74 if ((dx
= (xptr
[va
][XX
] - xptr
[vb
][XX
])) < 0)
82 static void do_my_pme(FILE *fp
,real tm
,gmx_bool bVerbose
,t_inputrec
*ir
,
83 rvec x
[],rvec xbuf
[],rvec f
[],
84 real charge
[],real qbuf
[],real qqbuf
[],
85 matrix box
,gmx_bool bSort
,
86 t_commrec
*cr
,t_nsborder
*nsb
,t_nrnb
*nrnb
,
87 t_block
*excl
,real qtot
,
88 t_forcerec
*fr
,int index
[],FILE *fp_xvg
,
89 int ngroups
,unsigned short cENER
[])
91 real ener
,vcorr
,q
,xx
,dvdl
=0,vdip
,vcharge
;
92 tensor vir
,vir_corr
,vir_tot
;
97 /* Initiate local variables */
103 fprintf(fp
,"There are %d energy groups\n",ngroups
);
105 for(i
=0; (i
<ngroups
); i
++)
106 snew(epme
[i
],ngroups
);
109 /* Put x is in the box, this part needs to be parallellized properly */
110 /*put_atoms_in_box(box,nsb->natoms,x);*/
111 /* Here sorting of X (and q) is done.
112 * Alternatively, one could just put the atoms in one of the
113 * cr->nnodes slabs. That is much cheaper than sorting.
115 for(i
=0; (i
<nsb
->natoms
); i
++)
119 qsort(index
,nsb
->natoms
,sizeof(index
[0]),comp_xptr
);
120 xptr
= NULL
; /* To trap unintentional use of the ptr */
122 /* After sorting we only need the part that is to be computed on
123 * this processor. We also compute the mu_tot here (system dipole)
125 clear_rvec(mu_tot
[0]);
126 for(i
=START(nsb
); (i
<START(nsb
)+HOMENR(nsb
)); i
++) {
130 for(m
=0; (m
<DIM
); m
++) {
133 mu_tot
[0][m
] += q
*xx
;
137 copy_rvec(mu_tot
[0],mu_tot
[1]);
139 pr_rvec(debug
,0,"qbuf",qbuf
,nsb
->natoms
,TRUE
);
140 pr_rvecs(debug
,0,"xbuf",xbuf
,nsb
->natoms
);
141 pr_rvecs(debug
,0,"box",box
,DIM
);
143 for(ig
=0; (ig
<ngroups
); ig
++) {
144 for(jg
=ig
; (jg
<ngroups
); jg
++) {
146 for(i
=START(nsb
); (i
<START(nsb
)+HOMENR(nsb
)); i
++) {
147 if ((cENER
[i
] == ig
) || (cENER
[i
] == jg
))
156 ener
= do_pme(fp
,bVerbose
,ir
,xbuf
,f
,qptr
,qptr
,box
,cr
,
157 nsb
,nrnb
,vir
,fr
->ewaldcoeff
,FALSE
,0,&dvdl
,FALSE
);
158 vcorr
= ewald_LRcorrection(fp
,nsb
,cr
,fr
,qptr
,qptr
,excl
,xbuf
,box
,mu_tot
,
159 ir
->ewald_geometry
,ir
->epsilon_surface
,
160 0,&dvdl
,&vdip
,&vcharge
);
162 gmx_sum(1,&vcorr
,cr
);
164 epme
[ig
][jg
] = ener
+vcorr
;
169 fprintf(fp_xvg
,"%10.3f",tm
);
170 for(ig
=0; (ig
<ngroups
); ig
++) {
171 for(jg
=ig
; (jg
<ngroups
); jg
++) {
173 epme
[ig
][jg
] -= epme
[ig
][ig
]+epme
[jg
][jg
];
175 fprintf(fp_xvg
," %12.5e",epme
[ig
][jg
]);
179 fprintf(fp_xvg
,"\n");
182 fprintf(fp
,"Time: %10.3f Energy: %12.5e Correction: %12.5e Total: %12.5e\n",
183 tm
,ener
,vcorr
,ener
+vcorr
);
185 fprintf(fp_xvg
,"%10.3f %12.5e %12.5e %12.5e\n",tm
,ener
+vcorr
,vdip
,vcharge
);
187 m_add(vir
,vir_corr
,vir_tot
);
188 gmx_sum(9,vir_tot
[0],cr
);
189 pr_rvecs(fp
,0,"virial",vir_tot
,DIM
);
195 int main(int argc
,char *argv
[])
197 static char *desc
[] = {
198 "The [TT]pmetest[tt] program tests the scaling of the PME code. When only given",
199 "a [TT].tpr[tt] file it will compute PME for one frame. When given a trajectory",
200 "it will do so for all the frames in the trajectory. Before the PME",
201 "routine is called the coordinates are sorted along the X-axis.[PAR]",
202 "As an extra service to the public the program can also compute",
203 "long-range Coulomb energies for components of the system. When the",
204 "[TT]-groups[tt] flag is given to the program the energy groups",
205 "from the [TT].tpr[tt] file will be read, and half an energy matrix computed."
208 static t_filenm fnm
[] = {
209 { efTPX
, NULL
, NULL
, ffREAD
},
210 { efTRN
, "-o", NULL
, ffWRITE
},
211 { efLOG
, "-g", "pme", ffWRITE
},
212 { efTRX
, "-f", NULL
, ffOPTRD
},
213 { efXVG
, "-x", "ener-pme", ffWRITE
}
215 #define NFILE asize(fnm)
217 /* Command line options ! */
218 static gmx_bool bVerbose
=FALSE
;
219 static gmx_bool bOptFFT
=FALSE
;
220 static gmx_bool bSort
=FALSE
;
221 static int ewald_geometry
=eewg3D
;
223 static int pme_order
=0;
224 static rvec grid
= { -1, -1, -1 };
225 static real rc
= 0.0;
226 static real dtol
= 0.0;
227 static gmx_bool bGroups
= FALSE
;
228 static t_pargs pa
[] = {
229 { "-np", FALSE
, etINT
, {&nnodes
},
230 "Number of nodes, must be the same as used for [TT]grompp[tt]" },
231 { "-v", FALSE
, etBOOL
,{&bVerbose
},
232 "Be loud and noisy" },
233 { "-sort", FALSE
, etBOOL
,{&bSort
},
234 "Sort coordinates. Crucial for domain decomposition." },
235 { "-grid", FALSE
, etRVEC
,{&grid
},
236 "Number of grid cells in X, Y, Z dimension (if -1 use from [TT].tpr[tt])" },
237 { "-order", FALSE
, etINT
, {&pme_order
},
238 "Order of the PME spreading algorithm" },
239 { "-groups", FALSE
, etBOOL
, {&bGroups
},
240 "Compute half an energy matrix based on the energy groups in your [TT].tpr[tt] file" },
241 { "-rc", FALSE
, etREAL
, {&rc
},
242 "Rcoulomb for Ewald summation" },
243 { "-tol", FALSE
, etREAL
, {&dtol
},
244 "Tolerance for Ewald summation" }
255 int natoms
,step
,status
,i
,ncg
,root
;
256 real t
,lambda
,ewaldcoeff
,qtot
;
260 real
*charge
,*qbuf
,*qqbuf
;
263 /* Start the actual parallel code if necessary */
264 cr
= init_par(&argc
,&argv
);
268 CopyRight(stderr
,argv
[0]);
270 /* Parse command line on all processors, arguments are passed on in
271 * init_par (see above)
273 parse_common_args(&argc
,argv
,
274 PCA_NOEXIT_ON_ARGS
| PCA_BE_NICE
|
275 PCA_CAN_SET_DEFFNM
| (MASTER(cr
) ? 0 : PCA_QUIET
),
276 NFILE
,fnm
,asize(pa
),pa
,asize(desc
),desc
,0,NULL
);
280 gmx_fatal(FARGS
,"GROMACS compiled without MPI support - can't do parallel runs");
283 /* Open log files on all processors */
284 open_log(ftp2fn(efLOG
,NFILE
,fnm
),cr
);
288 /* Read tpr file etc. */
289 read_tpxheader(ftp2fn(efTPX
,NFILE
,fnm
),&tpx
,FALSE
,NULL
,NULL
);
291 read_tpx(ftp2fn(efTPX
,NFILE
,fnm
),&step
,&t
,&lambda
,ir
,
292 box
,&natoms
,x
,NULL
,NULL
,&top
);
296 for(i
=0; (i
<natoms
); i
++) {
297 charge
[i
] = top
.atoms
.atom
[i
].q
;
302 if (opt2parg_bSet("-grid",asize(pa
),pa
)) {
307 /* Check command line parameters for consistency */
308 if ((ir
->nkx
<= 0) || (ir
->nky
<= 0) || (ir
->nkz
<= 0))
309 gmx_fatal(FARGS
,"PME grid = %d %d %d",ir
->nkx
,ir
->nky
,ir
->nkz
);
310 if (opt2parg_bSet("-rc",asize(pa
),pa
))
312 if (ir
->rcoulomb
<= 0)
313 gmx_fatal(FARGS
,"rcoulomb should be > 0 (not %f)",ir
->rcoulomb
);
314 if (opt2parg_bSet("-order",asize(pa
),pa
))
315 ir
->pme_order
= pme_order
;
316 if (ir
->pme_order
<= 0)
317 gmx_fatal(FARGS
,"pme_order should be > 0 (not %d)",ir
->pme_order
);
318 if (opt2parg_bSet("-tol",asize(pa
),pa
))
319 ir
->ewald_rtol
= dtol
;
320 if (ir
->ewald_rtol
<= 0)
321 gmx_fatal(FARGS
,"ewald_tol should be > 0 (not %f)",ir
->ewald_rtol
);
327 /* Add parallellization code here */
330 ncg
= top
.blocks
[ebCGS
].multinr
[0];
331 for(i
=0; (i
<cr
->nnodes
-1); i
++)
332 top
.blocks
[ebCGS
].multinr
[i
] = min(ncg
,(ncg
*(i
+1))/cr
->nnodes
);
333 for( ; (i
<MAXNODES
); i
++)
334 top
.blocks
[ebCGS
].multinr
[i
] = ncg
;
337 /* Set some variables to zero to avoid core dumps */
338 ir
->opts
.ngtc
= ir
->opts
.ngacc
= ir
->opts
.ngfrz
= ir
->opts
.ngener
= 0;
340 /* Distribute the data over processors */
341 MPI_Bcast(&natoms
,1,MPI_INT
,root
,MPI_COMM_WORLD
);
342 MPI_Bcast(ir
,sizeof(*ir
),MPI_BYTE
,root
,MPI_COMM_WORLD
);
343 MPI_Bcast(&qtot
,1,GMX_MPI_REAL
,root
,MPI_COMM_WORLD
);
346 /* Call some dedicated communication routines, master sends n-1 times */
348 for(i
=1; (i
<cr
->nnodes
); i
++) {
349 mv_block(i
,&(top
.blocks
[ebCGS
]));
350 mv_block(i
,&(top
.atoms
.excl
));
354 ld_block(root
,&(top
.blocks
[ebCGS
]));
355 ld_block(root
,&(top
.atoms
.excl
));
362 MPI_Bcast(charge
,natoms
,GMX_MPI_REAL
,root
,MPI_COMM_WORLD
);
365 ewaldcoeff
= calc_ewaldcoeff(ir
->rcoulomb
,ir
->ewald_rtol
);
369 pr_inputrec(stdlog
,0,"Inputrec",ir
);
371 /* Allocate memory for temp arrays etc. */
378 /* Initialize the PME code */
379 init_pme(stdlog
,cr
,ir
->nkx
,ir
->nky
,ir
->nkz
,ir
->pme_order
,
380 natoms
,FALSE
,bOptFFT
,ewald_geometry
);
382 /* MFlops accounting */
385 /* Initialize the work division */
386 calc_nsb(stdlog
,&(top
.blocks
[ebCGS
]),cr
->nnodes
,nsb
,0);
387 nsb
->nodeid
= cr
->nodeid
;
388 print_nsb(stdlog
,"pmetest",nsb
);
390 /* Initiate forcerec */
391 mdatoms
= atoms2md(stdlog
,&top
.atoms
,ir
->opts
.nFreeze
,ir
->eI
,
392 ir
->delta_t
,0,ir
->opts
.tau_t
,FALSE
,FALSE
);
394 init_forcerec(stdlog
,fr
,ir
,&top
,cr
,mdatoms
,nsb
,box
,FALSE
,NULL
,NULL
,FALSE
);
396 /* First do PME based on coordinates in tpr file, send them to
397 * other processors if needed.
400 fprintf(stdlog
,"-----\n"
401 "Results based on tpr file %s\n",ftp2fn(efTPX
,NFILE
,fnm
));
404 MPI_Bcast(x
[0],natoms
*DIM
,GMX_MPI_REAL
,root
,MPI_COMM_WORLD
);
405 MPI_Bcast(box
[0],DIM
*DIM
,GMX_MPI_REAL
,root
,MPI_COMM_WORLD
);
406 MPI_Bcast(&t
,1,GMX_MPI_REAL
,root
,MPI_COMM_WORLD
);
409 do_my_pme(stdlog
,0,bVerbose
,ir
,x
,xbuf
,f
,charge
,qbuf
,qqbuf
,box
,bSort
,
410 cr
,nsb
,&nrnb
,&(top
.atoms
.excl
),qtot
,fr
,index
,NULL
,
411 bGroups
? ir
->opts
.ngener
: 1,mdatoms
->cENER
);
413 /* If we have a trajectry file, we will read the frames in it and compute
416 if (ftp2bSet(efTRX
,NFILE
,fnm
)) {
417 fprintf(stdlog
,"-----\n"
418 "Results based on trx file %s\n",ftp2fn(efTRX
,NFILE
,fnm
));
421 natoms
= read_first_x(&status
,ftp2fn(efTRX
,NFILE
,fnm
),&t
,&x
,box
);
422 if (natoms
!= top
.atoms
.nr
)
423 gmx_fatal(FARGS
,"natoms in trx = %d, in tpr = %d",natoms
,top
.atoms
.nr
);
424 fp
= xvgropen(ftp2fn(efXVG
,NFILE
,fnm
),"PME Energy","Time (ps)","E (kJ/mol)");
429 /* Send coordinates, box and time to the other nodes */
432 MPI_Bcast(x
[0],natoms
*DIM
,GMX_MPI_REAL
,root
,MPI_COMM_WORLD
);
433 MPI_Bcast(box
[0],DIM
*DIM
,GMX_MPI_REAL
,root
,MPI_COMM_WORLD
);
434 MPI_Bcast(&t
,1,GMX_MPI_REAL
,root
,MPI_COMM_WORLD
);
437 rm_pbc(&top
.idef
,nsb
->natoms
,box
,x
,x
);
438 /* Call the PME wrapper function */
439 do_my_pme(stdlog
,t
,bVerbose
,ir
,x
,xbuf
,f
,charge
,qbuf
,qqbuf
,box
,bSort
,cr
,
440 nsb
,&nrnb
,&(top
.atoms
.excl
),qtot
,fr
,index
,fp
,
441 bGroups
? ir
->opts
.ngener
: 1,mdatoms
->cENER
);
442 /* Only the master processor reads more data */
444 bCont
= read_next_x(status
,&t
,natoms
,x
,box
);
445 /* Check whether we need to continue */
448 MPI_Bcast(&bCont
,1,MPI_INT
,root
,MPI_COMM_WORLD
);
453 /* Finish I/O, close files */
461 /* Do some final I/O about performance, might be useful in debugging */
462 fprintf(stdlog
,"-----\n");
463 print_nrnb(stdlog
,&nrnb
);
466 /* Finish the parallel stuff */
467 if (gmx_parallel_env_initialized())
470 /* Thank the audience, as usual */