4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
12 * Copyright (c) 1991-1999
13 * BIOSON Research Institute, Dept. of Biophysical Chemistry
14 * University of Groningen, The Netherlands
17 * GROMACS: A message-passing parallel molecular dynamics implementation
18 * H.J.C. Berendsen, D. van der Spoel and R. van Drunen
19 * Comp. Phys. Comm. 91, 43-56 (1995)
21 * Also check out our WWW page:
22 * http://md.chem.rug.nl/~gmx
27 * GRowing Old MAkes el Chrono Sweat
29 static char *SRCID_sim_util_c
= "$Id$";
51 #define difftime(end,start) ((double)(end)-(double)(start))
53 void print_time(FILE *out
,time_t start
,int step
,t_inputrec
*ir
)
55 static real time_per_step
;
61 fprintf(out
,"\rstep %d",step
);
62 if ((step
>= ir
->nstlist
)) {
63 if ((ir
->nstlist
== 0) || ((step
% ir
->nstlist
) == 0)) {
64 /* We have done a full cycle let's update time_per_step */
66 dt
=difftime(end
,start
);
67 time_per_step
=dt
/(step
+1);
69 dt
=(ir
->nsteps
-step
)*time_per_step
;
72 finish
= end
+(time_t)dt
;
73 sprintf(buf
,"%s",ctime(&finish
));
74 buf
[strlen(buf
)-1]='\0';
75 fprintf(out
,", will finish at %s",buf
);
78 fprintf(out
,", remaining runtime: %5d s ",(int)dt
);
87 time_t print_date_and_time(FILE *log
,int pid
,char *title
)
90 char *ts
,time_string
[STRLEN
];
95 for (i
=0; ts
[i
]>=' '; i
++) time_string
[i
]=ts
[i
];
97 fprintf(log
,"%s on processor %d %s\n",title
,pid
,time_string
);
101 static void pr_commrec(FILE *log
,t_commrec
*cr
)
103 fprintf(log
,"commrec: pid=%d, nprocs=%d, left=%d, right=%d\n",
104 cr
->pid
,cr
->nprocs
,cr
->left
,cr
->right
);
107 static void sum_forces(int start
,int end
,rvec f
[],rvec flr
[])
111 for(i
=start
; (i
<end
); i
++)
112 rvec_inc(f
[i
],flr
[i
]);
115 static void reset_energies(t_grpopts
*opts
,t_groups
*grp
,
116 t_forcerec
*fr
,bool bNS
,real epot
[])
120 /* First reset all energy components but the Long Range, except in
121 * some special cases.
123 for(i
=0; (i
<egNR
); i
++)
124 if (((i
!= egLR
) && (i
!= egLJLR
)) ||
125 (fr
->bTwinRange
&& bNS
) || (!fr
->bTwinRange
))
126 for(j
=0; (j
<grp
->estat
.nn
); j
++)
127 grp
->estat
.ee
[i
][j
]=0.0;
129 /* Normal potential energy components */
130 for(i
=0; (i
<=F_EPOT
); i
++)
133 epot
[F_DVDLKIN
] = 0.0;
137 * calc_f_el calculates forces due to an electric field.
139 * force is kJ mol^-1 nm^-1 = e * kJ mol^-1 nm^-1 / e
141 * Et[] contains the parameters for the time dependent
142 * part of the field (not yet used).
143 * Ex[] contains the parameters for
144 * the spatial dependent part of the field. You can have cool periodic
145 * fields in principle, but only a constant field is supported
147 * The function should return the energy due to the electric field
148 * (if any) but for now returns 0.
151 static real
calc_f_el(int start
,int homenr
,real charge
[],rvec f
[],t_cosines Ex
[])
153 real Emu
,fmu
,strength
;
157 for(m
=0; (m
<DIM
); m
++)
159 /* Convert the field strength from V/nm to MD-units */
160 strength
= Ex
[m
].a
[0]*FIELDFAC
;
161 for(i
=start
; (i
<start
+homenr
); i
++) {
162 fmu
= charge
[i
]*strength
;
170 void do_force(FILE *log
,t_commrec
*cr
,
171 t_parm
*parm
,t_nsborder
*nsb
,tensor vir_part
,
172 int step
,t_nrnb
*nrnb
,t_topology
*top
,t_groups
*grps
,
173 rvec x
[],rvec v
[],rvec f
[],rvec buf
[],
174 t_mdatoms
*mdatoms
,real ener
[],bool bVerbose
,
175 real lambda
,t_graph
*graph
,
176 bool bNS
,bool bNBFonly
,t_forcerec
*fr
)
178 static rvec box_size
;
179 static real dvdl_lr
= 0;
182 matrix lr_vir
; /* used for PME long range virial */
186 homenr
= HOMENR(nsb
);
190 update_forcerec(log
,fr
,parm
->box
);
192 if (fr
->eBox
!= ebtNONE
) {
193 /* Compute shift vectors every step, because of pressure coupling! */
194 if (parm
->ir
.epc
!= epcNO
)
195 calc_shifts(parm
->box
,box_size
,fr
->shift_vec
,FALSE
);
198 put_charge_groups_in_box(log
,cg0
,cg1
,FALSE
,
199 parm
->box
,box_size
,&(top
->blocks
[ebCGS
]),x
,
200 fr
->shift_vec
,fr
->cg_cm
);
201 inc_nrnb(nrnb
,eNR_RESETX
,homenr
);
205 calc_cgcm(log
,cg0
,cg1
,&(top
->blocks
[ebCGS
]),x
,fr
->cg_cm
);
208 inc_nrnb(nrnb
,eNR_CGCM
,cg1
-cg0
);
210 move_cgcm(log
,cr
,fr
->cg_cm
,nsb
->workload
);
212 pr_rvecs(debug
,0,"cgcm",fr
->cg_cm
,nsb
->cgtotal
);
215 /* Communicate coordinates if necessary */
217 move_x(log
,cr
->left
,cr
->right
,x
,nsb
,nrnb
);
220 reset_energies(&(parm
->ir
.opts
),grps
,fr
,bNS
,ener
);
223 if (fr
->eBox
!= ebtNONE
)
224 /* Calculate intramolecular shift vectors to make molecules whole */
225 mk_mshift(log
,graph
,parm
->box
,x
);
227 /* Reset long range forces if necessary */
228 if (fr
->bTwinRange
) {
229 clear_rvecs(nsb
->natoms
,fr
->flr
);
230 clear_rvecs(SHIFTS
,fr
->fshift_lr
);
232 /* Do the actual neighbour searching and if twin range electrostatics
233 * also do the calculation of long range forces and energies.
236 ns(log
,fr
,x
,f
,parm
->box
,grps
,&(parm
->ir
.opts
),top
,mdatoms
,
237 cr
,nrnb
,nsb
,step
,lambda
,&dvdl_lr
);
240 /* Reset forces or copy them from long range forces */
241 if (fr
->bTwinRange
) {
242 for(i
=0; i
<nsb
->natoms
; i
++)
243 copy_rvec(fr
->flr
[i
],f
[i
]);
244 for(i
=0; i
<SHIFTS
; i
++)
245 copy_rvec(fr
->fshift_lr
[i
],fr
->fshift
[i
]);
247 if (fr
->eeltype
== eelPPPM
||
248 fr
->eeltype
== eelPME
||
249 fr
->eeltype
== eelEWALD
)
250 clear_rvecs(homenr
,fr
->flr
+start
);
251 clear_rvecs(nsb
->natoms
,f
);
252 clear_rvecs(SHIFTS
,fr
->fshift
);
255 /* Compute the forces */
256 force(log
,step
,fr
,&(parm
->ir
),&(top
->idef
),nsb
,cr
,nrnb
,grps
,mdatoms
,
257 top
->atoms
.grps
[egcENER
].nr
,&(parm
->ir
.opts
),
258 x
,f
,ener
,bVerbose
,parm
->box
,lambda
,graph
,&(top
->atoms
.excl
),
261 /* Take long range contribution to free energy into account */
262 ener
[F_DVDL
] += dvdl_lr
;
264 /* Compute forces due to electric field */
265 calc_f_el(start
,homenr
,mdatoms
->chargeT
,f
,parm
->ir
.ex
);
269 print_nrnb(log
,nrnb
);
272 /* The short-range virial from surrounding boxes */
274 calc_vir(log
,SHIFTS
,fr
->shift_vec
,fr
->fshift
,vir_part
,cr
);
275 inc_nrnb(nrnb
,eNR_VIRIAL
,SHIFTS
);
279 pr_rvecs(debug
,0,"fr->fshift",fr
->fshift
,SHIFTS
);
280 pr_rvecs(debug
,0,"in force.c vir",vir_part
,DIM
);
284 /* When using PME/Ewald we compute the long range virial (lr_vir) there.
285 * otherwise we do it based on long range forces from twin range
286 * cut-off based calculation (or not at all).
289 /* Communicate the forces */
291 move_f(log
,cr
->left
,cr
->right
,f
,buf
,nsb
,nrnb
);
293 /* Now it is time for the short range virial. At this timepoint vir_part
294 * already contains the virial from surrounding boxes.
295 * Calculate partial virial, for local atoms only, based on short range.
296 * Total virial is computed in global_stat, called from do_md
298 f_calc_vir(log
,start
,start
+homenr
,x
,f
,vir_part
,cr
,graph
,fr
->shift_vec
);
299 inc_nrnb(nrnb
,eNR_VIRIAL
,homenr
);
301 if ((fr
->eeltype
== eelPPPM
) ||
302 (fr
->eeltype
== eelPME
) ||
303 (fr
->eeltype
== eelEWALD
)) {
304 /* Now add the forces from the PME calculation. Since this only produces
305 * forces on the local atoms, this can be safely done after the
306 * communication step. The same goes for the virial.
308 sum_forces(start
,start
+homenr
,f
,fr
->flr
);
309 if (fr
->eeltype
!= eelPPPM
) /* PPPM virial sucks */
310 for(i
=0; (i
<DIM
); i
++)
311 for(j
=0; (j
<DIM
); j
++)
312 vir_part
[i
][j
]+=lr_vir
[i
][j
];
316 pr_rvecs(debug
,0,"vir_part",vir_part
,DIM
);
322 static double runtime
=0;
323 static clock_t cprev
;
325 void start_time(void)
331 void update_time(void)
336 runtime
+= (c
-cprev
)/(double)CLOCKS_PER_SEC
;
340 double cpu_time(void)
345 void do_shakefirst(FILE *log
,bool bTYZ
,real lambda
,real ener
[],
346 t_parm
*parm
,t_nsborder
*nsb
,t_mdatoms
*md
,
347 rvec x
[],rvec vold
[],rvec buf
[],rvec f
[],
348 rvec v
[],t_graph
*graph
,t_commrec
*cr
,t_nrnb
*nrnb
,
349 t_groups
*grps
,t_forcerec
*fr
,t_topology
*top
,
350 t_edsamyn
*edyn
,t_pull
*pulldata
)
354 real dt
=parm
->ir
.delta_t
;
357 if ((top
->idef
.il
[F_SHAKE
].nr
> 0) ||
358 (top
->idef
.il
[F_SETTLE
].nr
> 0)) {
359 /* Do a first SHAKE to reset particles... */
360 clear_mat(shake_vir
);
361 update(nsb
->natoms
,START(nsb
),HOMENR(nsb
),
362 -1,lambda
,&ener
[F_DVDL
],
363 &(parm
->ir
),md
,x
,graph
,
364 fr
->shift_vec
,NULL
,NULL
,vold
,x
,NULL
,parm
->pres
,parm
->box
,
365 top
,grps
,shake_vir
,cr
,nrnb
,bTYZ
,FALSE
,edyn
,pulldata
);
366 /* Compute coordinates at t=-dt, store them in buf */
367 for(i
=0; (i
<nsb
->natoms
); i
++) {
368 for(m
=0; (m
<DIM
); m
++) {
370 buf
[i
][m
]=x
[i
][m
]-dt
*v
[i
][m
];
374 /* Shake the positions at t=-dt with the positions at t=0
375 * as reference coordinates.
377 clear_mat(shake_vir
);
378 update(nsb
->natoms
,START(nsb
),HOMENR(nsb
),
379 0,lambda
,&ener
[F_DVDL
],&(parm
->ir
),md
,f
,graph
,
380 fr
->shift_vec
,NULL
,NULL
,vold
,buf
,NULL
,parm
->pres
,parm
->box
,
381 top
,grps
,shake_vir
,cr
,nrnb
,bTYZ
,FALSE
,edyn
,pulldata
);
383 /* Compute the velocities at t=-dt/2 using the coordinates at
387 for(i
=0; (i
<nsb
->natoms
); i
++) {
388 for(m
=0; (m
<DIM
); m
++)
389 v
[i
][m
]=(x
[i
][m
]-f
[i
][m
])*dt_1
;
392 /* Shake the positions at t=-dt with the positions at t=0
393 * as reference coordinates.
395 clear_mat(shake_vir
);
396 update(nsb
->natoms
,START(nsb
),HOMENR(nsb
),
397 0,lambda
,&ener
[F_DVDL
],&(parm
->ir
),md
,f
,graph
,
398 fr
->shift_vec
,NULL
,NULL
,vold
,buf
,NULL
,parm
->pres
,parm
->box
,
399 top
,grps
,shake_vir
,cr
,nrnb
,bTYZ
,FALSE
,edyn
,pulldata
);
401 /* Compute the velocities at t=-dt/2 using the coordinates at
405 for(i
=0; (i
<nsb
->natoms
); i
++) {
406 for(m
=0; (m
<DIM
); m
++)
407 v
[i
][m
]=(x
[i
][m
]-f
[i
][m
])*dt_1
;
412 void calc_dispcorr(FILE *log
,bool bDispCorr
,t_forcerec
*fr
,int natoms
,
413 matrix box
,tensor pres
,tensor virial
,real ener
[])
415 static bool bFirst
=TRUE
;
416 real vol
,rc3
,spres
,svir
;
421 /* Forget the (small) effect of the shift on the LJ energy *
422 * when fr->bLJShift = TRUE */
423 rc3
= fr
->rvdw
*fr
->rvdw
*fr
->rvdw
;
424 ener
[F_DISPCORR
] = -2.0*natoms
*natoms
*M_PI
*fr
->avcsix
/(3.0*vol
*rc3
);
425 spres
= 2.0*ener
[F_DISPCORR
]*PRESFAC
/vol
;
426 svir
= -6.0*ener
[F_DISPCORR
];
427 ener
[F_PRES
] = trace(pres
)/3.0+spres
;
428 for(m
=0; (m
<DIM
); m
++) {
430 virial
[m
][m
] += svir
;
434 "Long Range LJ corrections: Epot=%10g, Pres=%10g, Vir=%10g\n",
435 ener
[F_DISPCORR
],spres
,svir
);
440 ener
[F_DISPCORR
] = 0.0;
441 ener
[F_PRES
] = trace(pres
)/3.0;
443 ener
[F_EPOT
] += ener
[F_DISPCORR
];
444 ener
[F_ETOT
] += ener
[F_DISPCORR
];