4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
12 * Copyright (c) 1991-2001
13 * BIOSON Research Institute, Dept. of Biophysical Chemistry
14 * University of Groningen, The Netherlands
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * Do check out http://www.gromacs.org , or mail us at gromacs@gromacs.org .
34 * Gromacs Runs On Most of All Computer Systems
36 static char *SRCID_relax_sh_c = "$Id$";
52 static void do_1pos(rvec xnew,rvec xold,rvec f,real k_1,real step)
70 static void directional_sd(FILE *log,real step,rvec xold[],rvec xnew[],
71 rvec min_f[],int start,int homenr,real k)
75 for(i=start; i<homenr; i++)
76 do_1pos(xnew[i],xold[i],min_f[i],-k,step);
79 static void shell_pos_sd(FILE *log,real step,rvec xold[],rvec xnew[],rvec f[],
85 for(i=0; (i<ns); i++) {
88 do_1pos(xnew[shell],xold[shell],f[shell],k_1,step);
90 pr_rvec(debug,0,"fshell",f[shell],DIM);
91 pr_rvec(debug,0,"xold",xold[shell],DIM);
92 pr_rvec(debug,0,"xnew",xnew[shell],DIM);
97 static void zero_shell_forces(FILE *log,rvec f[],int ns,t_shell s[])
102 /* Subtract remaining forces on shells from the attaching atoms.
103 * This way energy conservation may get better, and it is not unreasonable:
104 * It corresponds to an ad-hoc change in the force constants, which is exactly
105 * large enough to compensate for the remaining force on the shell. The
106 * shell forces then becomes zero.
108 for(i=0; (i<ns); i++) {
110 switch (s[i].nnucl) {
113 rvec_dec(f[n1],f[s1]);
130 tm = dt_1/(m1+m2+m3);*/
133 fatal_error(0,"Shell %d has %d nuclei!",i,s[i].nnucl);
138 static void predict_shells(FILE *log,rvec x[],rvec v[],real dt,
140 real mass[],bool bInit)
143 real dt_1,dt_2,dt_3,fudge,tm,m1,m2,m3;
146 /* We introduce a fudge factor for performance reasons: with this choice
147 * the initial force on the shells is about a factor of two lower than
153 fprintf(log,"RELAX: Using prediction for initial shell placement\n");
162 for(i=0; (i<ns); i++) {
166 switch (s[i].nnucl) {
169 for(m=0; (m<DIM); m++)
170 x[s1][m]+=ptr[n1][m]*dt_1;
178 for(m=0; (m<DIM); m++)
179 x[s1][m]+=(m1*ptr[n1][m]+m2*ptr[n2][m])*tm;
188 tm = dt_1/(m1+m2+m3);
189 for(m=0; (m<DIM); m++)
190 x[s1][m]+=(m1*ptr[n1][m]+m2*ptr[n2][m]+m3*ptr[n3][m])*tm;
193 fatal_error(0,"Shell %d has %d nuclei!",i,s[i].nnucl);
198 static void print_epot(FILE *fp,int mdstep,int count,real step,real epot,
201 fprintf(fp,"MDStep=%5d/%2d lamb: %6g, EPot: %12.8e",
202 mdstep,count,step,epot);
205 fprintf(fp,", rmsF: %12.8e\n",df);
211 static real rms_force(t_commrec *cr,rvec f[],int ns,t_shell s[])
219 for(i=0; (i<ns); i++) {
221 df2 += iprod(f[shell],f[shell]);
230 static void check_pbc(FILE *fp,rvec x[],int shell)
235 for(m=0; (m<DIM); m++)
236 if (fabs(x[shell][m]-x[now][m]) > 0.3) {
237 pr_rvecs(fp,0,"SHELL-X",x+now,5);
242 static void dump_shells(FILE *fp,rvec x[],rvec f[],real ftol,int ns,t_shell s[])
249 for(i=0; (i<ns); i++) {
251 ff2 = iprod(f[shell],f[shell]);
253 fprintf(fp,"SHELL %5d, force %10.5f %10.5f %10.5f, |f| %10.5f\n",
254 shell,f[shell][XX],f[shell][YY],f[shell][ZZ],sqrt(ff2));
255 check_pbc(fp,x,shell);
259 int relax_shells(FILE *log,t_commrec *cr,bool bVerbose,
260 int mdstep,t_parm *parm,bool bDoNS,bool bStopCM,
261 t_topology *top,real ener[],
262 rvec x[],rvec vold[],rvec v[],rvec vt[],rvec f[],
263 rvec buf[],t_mdatoms *md,t_nsborder *nsb,t_nrnb *nrnb,
264 t_graph *graph,t_groups *grps,tensor vir_part,
266 int nshell,t_shell shells[],t_forcerec *fr,
267 char *traj,real t,real lambda,rvec mu_tot,
268 int natoms,matrix box,bool *bConverged)
270 static bool bFirst=TRUE,bInit;
271 static rvec *pos[2],*force[2];
272 real Epot[2],df[2],Estore[F_NRE];
273 tensor my_vir[2],vir_last,pme_vir[2];
274 rvec *min_f_dir=NULL;
275 #define NEPOT asize(Epot)
276 real ftol,step,step0,xiH,xiS,dum=0;
282 int i,start=START(nsb),homenr=HOMENR(nsb),end=START(nsb)+HOMENR(nsb);
284 #define Try (1-Min) /* At start Try = 1 */
287 /* Allocate local arrays */
288 for(i=0; (i<2); i++) {
290 snew(pos[i],nsb->natoms);
291 snew(force[i],nsb->natoms);
293 bInit = (getenv("FORCEINIT") != NULL);
297 ftol = parm->ir.em_tol;
298 number_steps = parm->ir.niter;
301 /* Do a prediction of the shell positions */
302 predict_shells(log,x,v,parm->ir.delta_t,nshell,shells,
303 md->massT,bInit || (mdstep == 0));
305 /* Calculate the forces first time around */
306 clear_mat(my_vir[Min]);
307 clear_mat(pme_vir[Min]);
308 do_force(log,cr,parm,nsb,my_vir[Min],pme_vir[Min],mdstep,nrnb,
309 top,grps,x,v,force[Min],buf,md,ener,bVerbose && !PAR(cr),
310 lambda,graph,bDoNS,FALSE,fr,mu_tot,FALSE);
311 sum_lrforces(force[Min],fr,start,homenr);
313 df[Min]=rms_force(cr,force[Min],nshell,shells);
316 fprintf(debug,"df = %g %g\n",df[Min],df[Try]);
317 sprintf(cbuf,"myvir step %d",0);
318 pr_rvecs(debug,0,cbuf,my_vir[Min],DIM);
323 pr_rvecs(debug,0,"force0",force[Min],md->nr);
327 /* Copy x to pos[Min] & pos[Try]: during minimization only the
328 * shell positions are updated, therefore the other particles must
331 memcpy(pos[Min],x,nsb->natoms*sizeof(x[0]));
332 memcpy(pos[Try],x,nsb->natoms*sizeof(x[0]));
334 /* Sum the potential energy terms from group contributions */
335 sum_epot(&(parm->ir.opts),grps,ener);
336 Epot[Min]=ener[F_EPOT];
339 gmx_sum(NEPOT,Epot,cr);
343 if (bVerbose && MASTER(cr) && (nshell > 0))
344 print_epot(stdout,mdstep,0,step,Epot[Min],df[Min],FALSE);
347 fprintf(debug,"%17s: %14.10e\n",
348 interaction_function[F_EKIN].longname, ener[F_EKIN]);
349 fprintf(debug,"%17s: %14.10e\n",
350 interaction_function[F_EPOT].longname, ener[F_EPOT]);
351 fprintf(debug,"%17s: %14.10e\n",
352 interaction_function[F_ETOT].longname, ener[F_ETOT]);
353 fprintf(debug,"SHELLSTEP %d\n",mdstep);
356 /* First check whether we should do shells, or whether the force is
357 * low enough even without minimization.
359 *bConverged = bDone = (df[Min] < ftol) || (nshell == 0);
361 for(count=1; (!bDone && (count < number_steps)); count++) {
363 /* New positions, Steepest descent */
364 shell_pos_sd(log,step,pos[Min],pos[Try],force[Min],nshell,shells);
367 if (min_f_dir == NULL)
368 snew(min_f_dir,homenr);
369 constrain(log,top,&(parm->ir),mdstep,md,start,end,
370 pos[Min],force[Min],min_f_dir,parm->box,
371 lambda,&dum,nrnb,FALSE);
372 directional_sd(log,step,pos[Min],pos[Try],min_f_dir,start,homenr,
377 pr_rvecs(debug,0,"pos[Try] b4 do_force",pos[Try] + start,homenr);
378 pr_rvecs(debug,0,"pos[Min] b4 do_force",pos[Min] + start,homenr);
380 /* Try the new positions */
381 clear_mat(my_vir[Try]);
382 clear_mat(pme_vir[Try]);
383 do_force(log,cr,parm,nsb,my_vir[Try],pme_vir[Try],1,nrnb,
384 top,grps,pos[Try],v,force[Try],buf,md,ener,bVerbose && !PAR(cr),
385 lambda,graph,FALSE,FALSE,fr,mu_tot,FALSE);
386 sum_lrforces(force[Try],fr,start,homenr);
387 df[Try]=rms_force(cr,force[Try],nshell,shells);
389 fprintf(debug,"df = %g %g\n",df[Min],df[Try]);
392 /*pr_rvecs(debug,0,"F na do_force",force[Try] + start,homenr);*/
393 sprintf(cbuf,"myvir step %d",count);
394 pr_rvecs(debug,0,cbuf,my_vir[Try],DIM);
395 /*fprintf(debug,"SHELL ITER %d\n",count);
396 dump_shells(debug,pos[Try],force[Try],ftol,nshell,shells);*/
398 /* Sum the potential energy terms from group contributions */
399 sum_epot(&(parm->ir.opts),grps,ener);
400 Epot[Try]=ener[F_EPOT];
403 gmx_sum(1,&Epot[Try],cr);
405 if (bVerbose && MASTER(cr))
406 print_epot(stdout,mdstep,count,step,Epot[Try],df[Try],FALSE);
408 *bConverged = (df[Try] < ftol);
409 bDone = *bConverged || (step < 0.01);
411 /* if ((Epot[Try] < Epot[Min])) { */
412 if ((df[Try] < df[Min])) {
414 fprintf(debug,"Swapping Min and Try\n");
421 if (MASTER(cr) && !bDone)
422 fprintf(stderr,"EM did not converge in %d steps\n",number_steps);
425 zero_shell_forces(log,force[Min],nshell,shells);
427 /* Parallelise this one! */
428 if (EEL_LR(fr->eeltype)) {
429 for(i=start; (i<end); i++)
430 rvec_dec(force[Min][i],fr->f_pme[i]);
432 memcpy(f,force[Min],nsb->natoms*sizeof(f[0]));
435 copy_mat(my_vir[Min],vir_part);
436 copy_mat(pme_vir[Min],pme_vir_part);
439 sprintf(cbuf,"myvir step %d",count);
440 pr_rvecs(debug,0,cbuf,vir_part,DIM);
443 memcpy(x,pos[Min],nsb->natoms*sizeof(x[0]));