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$";
45 static void do_1pos(rvec xnew
,rvec xold
,rvec f
,real k_1
,real step
)
63 static void shell_pos_sd(FILE *log
,real step
,rvec xold
[],rvec xnew
[],rvec f
[],
69 for(i
=0; (i
<ns
); i
++) {
72 do_1pos(xnew
[shell
],xold
[shell
],f
[shell
],k_1
,step
);
74 pr_rvec(debug
,0,"fshell",f
[shell
],DIM
);
75 pr_rvec(debug
,0,"xold",xold
[shell
],DIM
);
76 pr_rvec(debug
,0,"xnew",xnew
[shell
],DIM
);
81 static void predict_shells(FILE *log
,rvec x
[],rvec v
[],real dt
,
83 real mass
[],bool bInit
)
86 real dt_1
,dt_2
,dt_3
,fudge
,tm
,m1
,m2
,m3
;
89 /* We introduce a fudge factor for performance reasons: with this choice
90 * the initial force on the shells is about a factor of two lower than without
95 fprintf(log
,"RELAX: Using prediction for initial shell placement\n");
104 for(i
=0; (i
<ns
); i
++) {
108 switch (s
[i
].nnucl
) {
111 for(m
=0; (m
<DIM
); m
++)
112 x
[s1
][m
]+=ptr
[n1
][m
]*dt_1
;
120 for(m
=0; (m
<DIM
); m
++)
121 x
[s1
][m
]+=(m1
*ptr
[n1
][m
]+m2
*ptr
[n2
][m
])*tm
;
130 tm
= dt_1
/(m1
+m2
+m3
);
131 for(m
=0; (m
<DIM
); m
++)
132 x
[s1
][m
]+=(m1
*ptr
[n1
][m
]+m2
*ptr
[n2
][m
]+m3
*ptr
[n3
][m
])*tm
;
135 fatal_error(0,"Shell %d has %d nuclei!",i
,s
[i
].nnucl
);
140 static void print_epot(FILE *fp
,
141 int mdstep
,int count
,real step
,real epot
,real df
,
142 bool bOptim
,bool bLast
)
146 fprintf(fp
,"MDStep=%5d EPot: %12.8e\n",mdstep
,epot
);
148 fprintf(fp
,"MDStep=%5d/%2d lamb: %6g, RMSF: %12.8e\n",
149 mdstep
,count
,step
,df
);
152 fprintf(fp
,"MDStep=%5d/%2d lamb: %6g, EPot: %12.8e",
153 mdstep
,count
,step
,epot
);
156 fprintf(fp
,", rmsF: %12.8e\n",df
);
163 static real
rms_force(t_commrec
*cr
,rvec f
[],int ns
,t_shell s
[])
171 for(i
=0; (i
<ns
); i
++) {
173 df2
+= iprod(f
[shell
],f
[shell
]);
182 static void check_pbc(FILE *fp
,rvec x
[],int shell
)
187 for(m
=0; (m
<DIM
); m
++)
188 if (fabs(x
[shell
][m
]-x
[now
][m
]) > 0.3) {
189 pr_rvecs(fp
,0,"SHELL-X",x
+now
,5);
194 static void dump_shells(FILE *fp
,rvec x
[],rvec f
[],real ftol
,int ns
,t_shell s
[])
201 for(i
=0; (i
<ns
); i
++) {
203 ff2
= iprod(f
[shell
],f
[shell
]);
205 fprintf(fp
,"SHELL %5d, force %10.5f %10.5f %10.5f, |f| %10.5f\n",
206 shell
,f
[shell
][XX
],f
[shell
][YY
],f
[shell
][ZZ
],sqrt(ff2
));
207 check_pbc(fp
,x
,shell
);
211 void set_nbfmask(t_forcerec
*fr
,t_mdatoms
*md
,int ngrp
,bool bMask
)
213 static bool *bShell
=NULL
;
216 /* THIS CODE IS OUT OF ORDER */
221 /* Loop over atoms */
222 for(i
=0; (i
<md
->nr
); i
++)
223 /* If it is a shell, then set the value to TRUE */
224 if (md
->ptype
[i
] == eptShell
) {
232 /* Loop over all the energy groups */
233 for(i
=0; (i
<ngrp
); i
++)
234 for(j
=i
; (j
<ngrp
); j
++) {
236 /* If either of the groups denote a group with shells, then */
238 if (bShell[i] || bShell[j])
239 fr->bMask[gid] = bMask;
241 fr->bMask[gid] = !bMask;
246 int relax_shells(FILE *log
,t_commrec
*cr
,bool bVerbose
,
247 int mdstep
,t_parm
*parm
,bool bDoNS
,bool bStopCM
,
248 t_topology
*top
,real ener
[],
249 rvec x
[],rvec vold
[],rvec v
[],rvec vt
[],rvec f
[],
250 rvec buf
[],t_mdatoms
*md
,t_nsborder
*nsb
,t_nrnb
*nrnb
,
251 t_graph
*graph
,t_groups
*grps
,tensor vir_part
,
252 int nshell
,t_shell shells
[],t_forcerec
*fr
,
253 char *traj
,real t
,real lambda
,
254 int natoms
,matrix box
,bool *bConverged
)
256 static bool bFirst
=TRUE
,bOptim
=FALSE
;
257 static rvec
*pos
[2],*force
[2];
258 real Epot
[2],df
[2],Estore
[F_NRE
];
259 tensor my_vir
[2],vir_last
;
260 #define NEPOT asize(Epot)
261 real ftol
,step
,step0
,xiH
,xiS
;
266 int i
,start
=START(nsb
),homenr
=HOMENR(nsb
),end
=START(nsb
)+HOMENR(nsb
);
268 #define Try (1-Min) /* At start Try = 1 */
271 /* Allocate local arrays */
272 for(i
=0; (i
<2); i
++) {
273 snew(pos
[i
],nsb
->natoms
);
274 snew(force
[i
],nsb
->natoms
);
276 bOptim
= (getenv("SHELL_OPTIM") != NULL
);
277 fprintf(log
,"bOptim = %s\n",bool_names
[bOptim
]);
281 ftol
= parm
->ir
.em_tol
;
282 number_steps
= parm
->ir
.niter
;
285 /* Do a prediction of the shell positions */
286 predict_shells(log
,x
,v
,parm
->ir
.delta_t
,nshell
,shells
,
287 md
->massT
,(mdstep
== 0));
289 /* Calculate the forces first time around */
291 set_nbfmask(fr
,md
,parm
->ir
.opts
.ngener
,TRUE
);
292 clear_mat(my_vir
[Min
]);
293 do_force(log
,cr
,parm
,nsb
,my_vir
[Min
],mdstep
,nrnb
,
294 top
,grps
,x
,v
,force
[Min
],buf
,md
,ener
,bVerbose
&& !PAR(cr
),
295 lambda
,graph
,bDoNS
,FALSE
,fr
);
296 df
[Min
]=rms_force(cr
,force
[Min
],nshell
,shells
);
298 fprintf(debug
,"df = %g %g\n",df
[Min
],df
[Try
]);
302 pr_rvecs(debug
,0,"force0",force
[Min
],md
->nr
);
303 calc_f_dev(md
->nr
,md
->chargeA
,x
,force
[Min
],&top
->idef
,&xiH
,&xiS
);
304 fprintf(log
,"xiH = %e, xiS = %e\n",xiH
,xiS
);
307 /* Copy x to pos[Min] & pos[Try]: during minimization only the
308 * shell positions are updated, therefore the other particles must
311 memcpy(pos
[Min
],x
,nsb
->natoms
*sizeof(x
[0]));
312 memcpy(pos
[Try
],x
,nsb
->natoms
*sizeof(x
[0]));
314 /* Sum the potential energy terms from group contributions */
315 sum_epot(&(parm
->ir
.opts
),grps
,ener
);
316 Epot
[Min
]=ener
[F_EPOT
];
319 gmx_sum(NEPOT
,Epot
,cr
);
323 if (bVerbose
&& MASTER(cr
) && (nshell
> 0))
324 print_epot(stdout
,mdstep
,0,step
,Epot
[Min
],df
[Min
],bOptim
,FALSE
);
327 fprintf(debug
,"%17s: %14.10e\n",
328 interaction_function
[F_EKIN
].longname
, ener
[F_EKIN
]);
329 fprintf(debug
,"%17s: %14.10e\n",
330 interaction_function
[F_EPOT
].longname
, ener
[F_EPOT
]);
331 fprintf(debug
,"%17s: %14.10e\n",
332 interaction_function
[F_ETOT
].longname
, ener
[F_ETOT
]);
333 fprintf(debug
,"SHELLSTEP %d\n",mdstep
);
336 /* First check whether we should do shells, or whether the force is
337 * low enough even without minimization.
339 *bConverged
= bDone
= (df
[Min
] < ftol
) || (nshell
== 0);
341 for(count
=1; (!bDone
&& (count
< number_steps
)); count
++) {
343 /* New positions, Steepest descent */
344 shell_pos_sd(log
,step
,pos
[Min
],pos
[Try
],force
[Min
],nshell
,shells
);
347 pr_rvecs(debug
,0,"pos[Try] b4 do_force",pos
[Try
] + start
,homenr
);
348 pr_rvecs(debug
,0,"pos[Min] b4 do_force",pos
[Min
] + start
,homenr
);
350 /* Try the new positions */
351 clear_mat(my_vir
[Try
]);
352 do_force(log
,cr
,parm
,nsb
,my_vir
[Try
],1,nrnb
,
353 top
,grps
,pos
[Try
],v
,force
[Try
],buf
,md
,ener
,bVerbose
&& !PAR(cr
),
354 lambda
,graph
,FALSE
,FALSE
,fr
);
355 df
[Try
]=rms_force(cr
,force
[Try
],nshell
,shells
);
357 fprintf(debug
,"df = %g %g\n",df
[Min
],df
[Try
]);
360 pr_rvecs(debug
,0,"F na do_force",force
[Try
] + start
,homenr
);
361 fprintf(debug
,"SHELL ITER %d\n",count
);
362 dump_shells(debug
,pos
[Try
],force
[Try
],ftol
,nshell
,shells
);
364 /* Sum the potential energy terms from group contributions */
365 sum_epot(&(parm
->ir
.opts
),grps
,ener
);
366 Epot
[Try
]=ener
[F_EPOT
];
369 gmx_sum(1,&Epot
[Try
],cr
);
371 if (bVerbose
&& MASTER(cr
))
372 print_epot(stdout
,mdstep
,count
,step
,Epot
[Try
],df
[Try
],bOptim
,FALSE
);
374 *bConverged
= (df
[Try
] < ftol
);
375 bDone
= *bConverged
|| (step
< 0.5);
377 if ((Epot
[Try
] < Epot
[Min
])) {
379 fprintf(debug
,"Swapping Min and Try\n");
386 if (MASTER(cr
) && !bDone
)
387 fprintf(stderr
,"EM did not converge in %d steps\n",number_steps
);
389 /* Now compute the forces on the other particles (atom-atom) */
391 /* Store the old energies */
392 for(i
=0; (i
<F_NRE
); i
++)
394 /* Set the mask to only do atom-atom interactions */
395 set_nbfmask(fr
,md
,parm
->ir
.opts
.ngener
,FALSE
);
396 /* Compute remaining forces and energies now */
397 do_force(log
,cr
,parm
,nsb
,vir_last
,1,nrnb
,
398 top
,grps
,pos
[Try
],v
,force
[Try
],buf
,md
,ener
,bVerbose
&& !PAR(cr
),
399 lambda
,graph
,FALSE
,TRUE
,fr
);
400 /* Sum the potential energy terms from group contributions */
401 sum_epot(&(parm
->ir
.opts
),grps
,ener
);
403 /* Sum over processors */
405 gmx_sum(NEPOT
,Epot
,cr
);
407 /* Add the stored energy contributions */
408 for(i
=0; (i
<F_NRE
); i
++)
409 ener
[i
] += Estore
[i
];
411 /* Sum virial tensors */
412 m_add(vir_last
,my_vir
[Min
],vir_part
);
414 /* Last output line */
415 if (bVerbose
&& MASTER(cr
)) {
416 Epot
[Try
]=ener
[F_EPOT
];
417 print_epot(stdout
,mdstep
,count
,step
,Epot
[Try
],0.0,bOptim
,TRUE
);
419 /* Sum the forces from the previous calc. (shells only)
420 * and the current calc (atoms only)
422 for(i
=0; (i
<nsb
->natoms
); i
++)
423 rvec_add(force
[Try
][i
],force
[Min
][i
],f
[i
]);
426 /* Parallelise this one! */
427 memcpy(f
,force
[Min
],nsb
->natoms
*sizeof(f
[0]));
429 copy_mat(my_vir
[Min
],vir_part
);
431 memcpy(x
,pos
[Min
],nsb
->natoms
*sizeof(x
[0]));