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 * Great Red Oystrich Makes All Chemists Sane
29 static char *SRCID_relax_sh_c = "$Id$";
46 static void do_1pos(rvec xnew,rvec xold,rvec f,real k_1,real step)
64 static void directional_sd(FILE *log,real step,rvec xold[],rvec xnew[],
65 rvec min_f[],int start,int homenr,real k)
69 for(i=start; i<homenr; i++)
70 do_1pos(xnew[i],xold[i],min_f[i],-k,step);
73 static void shell_pos_sd(FILE *log,real step,rvec xold[],rvec xnew[],rvec f[],
79 for(i=0; (i<ns); i++) {
82 do_1pos(xnew[shell],xold[shell],f[shell],k_1,step);
84 pr_rvec(debug,0,"fshell",f[shell],DIM);
85 pr_rvec(debug,0,"xold",xold[shell],DIM);
86 pr_rvec(debug,0,"xnew",xnew[shell],DIM);
91 static void zero_shell_forces(FILE *log,rvec f[],int ns,t_shell s[])
96 /* Subtract remaining forces on shells from the attaching atoms.
97 * This way energy conservation may get better, and it is not unreasonable:
98 * It corresponds to an ad-hoc change in the force constants, which is exactly
99 * large enough to compensate for the remaining force on the shell. The
100 * shell forces then becomes zero.
102 for(i=0; (i<ns); i++) {
104 switch (s[i].nnucl) {
107 rvec_dec(f[n1],f[s1]);
124 tm = dt_1/(m1+m2+m3);*/
127 fatal_error(0,"Shell %d has %d nuclei!",i,s[i].nnucl);
132 static void predict_shells(FILE *log,rvec x[],rvec v[],real dt,
134 real mass[],bool bInit)
137 real dt_1,dt_2,dt_3,fudge,tm,m1,m2,m3;
140 /* We introduce a fudge factor for performance reasons: with this choice
141 * the initial force on the shells is about a factor of two lower than
147 fprintf(log,"RELAX: Using prediction for initial shell placement\n");
156 for(i=0; (i<ns); i++) {
160 switch (s[i].nnucl) {
163 for(m=0; (m<DIM); m++)
164 x[s1][m]+=ptr[n1][m]*dt_1;
172 for(m=0; (m<DIM); m++)
173 x[s1][m]+=(m1*ptr[n1][m]+m2*ptr[n2][m])*tm;
182 tm = dt_1/(m1+m2+m3);
183 for(m=0; (m<DIM); m++)
184 x[s1][m]+=(m1*ptr[n1][m]+m2*ptr[n2][m]+m3*ptr[n3][m])*tm;
187 fatal_error(0,"Shell %d has %d nuclei!",i,s[i].nnucl);
192 static void print_epot(FILE *fp,int mdstep,int count,real step,real epot,
195 fprintf(fp,"MDStep=%5d/%2d lamb: %6g, EPot: %12.8e",
196 mdstep,count,step,epot);
199 fprintf(fp,", rmsF: %12.8e\n",df);
205 static real rms_force(t_commrec *cr,rvec f[],int ns,t_shell s[])
213 for(i=0; (i<ns); i++) {
215 df2 += iprod(f[shell],f[shell]);
224 static void check_pbc(FILE *fp,rvec x[],int shell)
229 for(m=0; (m<DIM); m++)
230 if (fabs(x[shell][m]-x[now][m]) > 0.3) {
231 pr_rvecs(fp,0,"SHELL-X",x+now,5);
236 static void dump_shells(FILE *fp,rvec x[],rvec f[],real ftol,int ns,t_shell s[])
243 for(i=0; (i<ns); i++) {
245 ff2 = iprod(f[shell],f[shell]);
247 fprintf(fp,"SHELL %5d, force %10.5f %10.5f %10.5f, |f| %10.5f\n",
248 shell,f[shell][XX],f[shell][YY],f[shell][ZZ],sqrt(ff2));
249 check_pbc(fp,x,shell);
253 int relax_shells(FILE *log,t_commrec *cr,bool bVerbose,
254 int mdstep,t_parm *parm,bool bDoNS,bool bStopCM,
255 t_topology *top,real ener[],
256 rvec x[],rvec vold[],rvec v[],rvec vt[],rvec f[],
257 rvec buf[],t_mdatoms *md,t_nsborder *nsb,t_nrnb *nrnb,
258 t_graph *graph,t_groups *grps,tensor vir_part,
260 int nshell,t_shell shells[],t_forcerec *fr,
261 char *traj,real t,real lambda,rvec mu_tot,
262 int natoms,matrix box,bool *bConverged)
264 static bool bFirst=TRUE,bInit;
265 static rvec *pos[2],*force[2];
266 real Epot[2],df[2],Estore[F_NRE];
267 tensor my_vir[2],vir_last,pme_vir[2];
268 rvec *min_f_dir=NULL;
269 #define NEPOT asize(Epot)
270 real ftol,step,step0,xiH,xiS,dum=0;
276 int i,start=START(nsb),homenr=HOMENR(nsb),end=START(nsb)+HOMENR(nsb);
278 #define Try (1-Min) /* At start Try = 1 */
281 /* Allocate local arrays */
282 for(i=0; (i<2); i++) {
284 snew(pos[i],nsb->natoms);
285 snew(force[i],nsb->natoms);
287 bInit = (getenv("FORCEINIT") != NULL);
291 ftol = parm->ir.em_tol;
292 number_steps = parm->ir.niter;
295 /* Do a prediction of the shell positions */
296 predict_shells(log,x,v,parm->ir.delta_t,nshell,shells,
297 md->massT,bInit || (mdstep == 0));
299 /* Calculate the forces first time around */
300 clear_mat(my_vir[Min]);
301 clear_mat(pme_vir[Min]);
302 do_force(log,cr,parm,nsb,my_vir[Min],pme_vir[Min],mdstep,nrnb,
303 top,grps,x,v,force[Min],buf,md,ener,bVerbose && !PAR(cr),
304 lambda,graph,bDoNS,FALSE,fr,mu_tot,FALSE);
305 sum_lrforces(force[Min],fr,start,homenr);
307 df[Min]=rms_force(cr,force[Min],nshell,shells);
310 fprintf(debug,"df = %g %g\n",df[Min],df[Try]);
311 sprintf(cbuf,"myvir step %d",0);
312 pr_rvecs(debug,0,cbuf,my_vir[Min],DIM);
317 pr_rvecs(debug,0,"force0",force[Min],md->nr);
321 /* Copy x to pos[Min] & pos[Try]: during minimization only the
322 * shell positions are updated, therefore the other particles must
325 memcpy(pos[Min],x,nsb->natoms*sizeof(x[0]));
326 memcpy(pos[Try],x,nsb->natoms*sizeof(x[0]));
328 /* Sum the potential energy terms from group contributions */
329 sum_epot(&(parm->ir.opts),grps,ener);
330 Epot[Min]=ener[F_EPOT];
333 gmx_sum(NEPOT,Epot,cr);
337 if (bVerbose && MASTER(cr) && (nshell > 0))
338 print_epot(stdout,mdstep,0,step,Epot[Min],df[Min],FALSE);
341 fprintf(debug,"%17s: %14.10e\n",
342 interaction_function[F_EKIN].longname, ener[F_EKIN]);
343 fprintf(debug,"%17s: %14.10e\n",
344 interaction_function[F_EPOT].longname, ener[F_EPOT]);
345 fprintf(debug,"%17s: %14.10e\n",
346 interaction_function[F_ETOT].longname, ener[F_ETOT]);
347 fprintf(debug,"SHELLSTEP %d\n",mdstep);
350 /* First check whether we should do shells, or whether the force is
351 * low enough even without minimization.
353 *bConverged = bDone = (df[Min] < ftol) || (nshell == 0);
355 for(count=1; (!bDone && (count < number_steps)); count++) {
357 /* New positions, Steepest descent */
358 shell_pos_sd(log,step,pos[Min],pos[Try],force[Min],nshell,shells);
361 if (min_f_dir == NULL)
362 snew(min_f_dir,homenr);
363 constrain(log,top,&(parm->ir),mdstep,md,start,end,
364 pos[Min],force[Min],min_f_dir,parm->box,
365 lambda,&dum,nrnb,FALSE);
366 directional_sd(log,step,pos[Min],pos[Try],min_f_dir,start,homenr,
371 pr_rvecs(debug,0,"pos[Try] b4 do_force",pos[Try] + start,homenr);
372 pr_rvecs(debug,0,"pos[Min] b4 do_force",pos[Min] + start,homenr);
374 /* Try the new positions */
375 clear_mat(my_vir[Try]);
376 clear_mat(pme_vir[Try]);
377 do_force(log,cr,parm,nsb,my_vir[Try],pme_vir[Try],1,nrnb,
378 top,grps,pos[Try],v,force[Try],buf,md,ener,bVerbose && !PAR(cr),
379 lambda,graph,FALSE,FALSE,fr,mu_tot,FALSE);
380 sum_lrforces(force[Try],fr,start,homenr);
381 df[Try]=rms_force(cr,force[Try],nshell,shells);
383 fprintf(debug,"df = %g %g\n",df[Min],df[Try]);
386 /*pr_rvecs(debug,0,"F na do_force",force[Try] + start,homenr);*/
387 sprintf(cbuf,"myvir step %d",count);
388 pr_rvecs(debug,0,cbuf,my_vir[Try],DIM);
389 /*fprintf(debug,"SHELL ITER %d\n",count);
390 dump_shells(debug,pos[Try],force[Try],ftol,nshell,shells);*/
392 /* Sum the potential energy terms from group contributions */
393 sum_epot(&(parm->ir.opts),grps,ener);
394 Epot[Try]=ener[F_EPOT];
397 gmx_sum(1,&Epot[Try],cr);
399 if (bVerbose && MASTER(cr))
400 print_epot(stdout,mdstep,count,step,Epot[Try],df[Try],FALSE);
402 *bConverged = (df[Try] < ftol);
403 bDone = *bConverged || (step < 0.01);
405 /* if ((Epot[Try] < Epot[Min])) { */
406 if ((df[Try] < df[Min])) {
408 fprintf(debug,"Swapping Min and Try\n");
415 if (MASTER(cr) && !bDone)
416 fprintf(stderr,"EM did not converge in %d steps\n",number_steps);
419 zero_shell_forces(log,force[Min],nshell,shells);
421 /* Parallelise this one! */
422 if (EEL_LR(fr->eeltype)) {
423 for(i=start; (i<end); i++)
424 rvec_dec(force[Min][i],fr->f_pme[i]);
426 memcpy(f,force[Min],nsb->natoms*sizeof(f[0]));
429 copy_mat(my_vir[Min],vir_part);
430 copy_mat(pme_vir[Min],pme_vir_part);
433 sprintf(cbuf,"myvir step %d",count);
434 pr_rvecs(debug,0,cbuf,vir_part,DIM);
437 memcpy(x,pos[Min],nsb->natoms*sizeof(x[0]));