changed reading hint
[gromacs/adressmacs.git] / src / local / relax_sh.c
blob72257e3b9f9eb704f346b51e9abfbd6134e54f0b
1 /*
2 * $Id$
3 *
4 * This source code is part of
5 *
6 * G R O M A C S
7 *
8 * GROningen MAchine for Chemical Simulations
9 *
10 * VERSION 2.0
12 * Copyright (c) 1991-1999
13 * BIOSON Research Institute, Dept. of Biophysical Chemistry
14 * University of Groningen, The Netherlands
16 * Please refer to:
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
23 * or e-mail to:
24 * gromacs@chem.rug.nl
26 * And Hey:
27 * Great Red Oystrich Makes All Chemists Sane
29 static char *SRCID_relax_sh_c = "$Id$";
31 #include <string.h>
32 #include "assert.h"
33 #include "typedefs.h"
34 #include "smalloc.h"
35 #include "fatal.h"
36 #include "vec.h"
37 #include "txtdump.h"
38 #include "mdrun.h"
39 #include "init_sh.h"
40 #include "mdatoms.h"
41 #include "network.h"
42 #include "do_gct.h"
43 #include "names.h"
45 static void do_1pos(rvec xnew,rvec xold,rvec f,real k_1,real step)
47 real xo,yo,zo;
48 real dx,dy,dz,dx2;
50 xo=xold[XX];
51 yo=xold[YY];
52 zo=xold[ZZ];
54 dx=f[XX]*k_1;
55 dy=f[YY]*k_1;
56 dz=f[ZZ]*k_1;
58 xnew[XX]=xo+dx*step;
59 xnew[YY]=yo+dy*step;
60 xnew[ZZ]=zo+dz*step;
63 static void shell_pos_sd(FILE *log,real step,rvec xold[],rvec xnew[],rvec f[],
64 int ns,t_shell s[])
66 int i,shell;
67 real k_1;
69 for(i=0; (i<ns); i++) {
70 shell = s[i].shell;
71 k_1 = s[i].k_1;
72 do_1pos(xnew[shell],xold[shell],f[shell],k_1,step);
73 if (debug) {
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,
82 int ns,t_shell s[],
83 real mass[],bool bInit)
85 int i,m,s1,n1,n2,n3;
86 real dt_1,dt_2,dt_3,fudge,tm,m1,m2,m3;
87 rvec *ptr;
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
92 fudge = 1.0;
94 if (bInit) {
95 fprintf(log,"RELAX: Using prediction for initial shell placement\n");
96 ptr = x;
97 dt_1 = 1;
99 else {
100 ptr = v;
101 dt_1 = fudge*dt;
104 for(i=0; (i<ns); i++) {
105 s1 = s[i].shell;
106 if (bInit)
107 clear_rvec(x[s1]);
108 switch (s[i].nnucl) {
109 case 1:
110 n1 = s[i].nucl1;
111 for(m=0; (m<DIM); m++)
112 x[s1][m]+=ptr[n1][m]*dt_1;
113 break;
114 case 2:
115 n1 = s[i].nucl1;
116 n2 = s[i].nucl2;
117 m1 = mass[n1];
118 m2 = mass[n2];
119 tm = dt_1/(m1+m2);
120 for(m=0; (m<DIM); m++)
121 x[s1][m]+=(m1*ptr[n1][m]+m2*ptr[n2][m])*tm;
122 break;
123 case 3:
124 n1 = s[i].nucl1;
125 n2 = s[i].nucl2;
126 n3 = s[i].nucl3;
127 m1 = mass[n1];
128 m2 = mass[n2];
129 m3 = mass[n3];
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;
133 break;
134 default:
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)
144 if (bOptim) {
145 if (bLast)
146 fprintf(fp,"MDStep=%5d EPot: %12.8e\n",mdstep,epot);
147 else if (count > 0)
148 fprintf(fp,"MDStep=%5d/%2d lamb: %6g, RMSF: %12.8e\n",
149 mdstep,count,step,df);
151 else {
152 fprintf(fp,"MDStep=%5d/%2d lamb: %6g, EPot: %12.8e",
153 mdstep,count,step,epot);
155 if (count != 0)
156 fprintf(fp,", rmsF: %12.8e\n",df);
157 else
158 fprintf(fp,"\n");
163 static real rms_force(t_commrec *cr,rvec f[],int ns,t_shell s[])
165 int i,shell;
166 real df2;
168 if (!ns)
169 return 0;
170 df2=0.0;
171 for(i=0; (i<ns); i++) {
172 shell = s[i].shell;
173 df2 += iprod(f[shell],f[shell]);
175 if (PAR(cr)) {
176 gmx_sum(1,&df2,cr);
177 gmx_sumi(1,&ns,cr);
179 return sqrt(df2/ns);
182 static void check_pbc(FILE *fp,rvec x[],int shell)
184 int m,now;
186 now = shell-4;
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);
190 break;
194 static void dump_shells(FILE *fp,rvec x[],rvec f[],real ftol,int ns,t_shell s[])
196 int i,shell;
197 real ft2,ff2;
199 ft2 = sqr(ftol);
201 for(i=0; (i<ns); i++) {
202 shell = s[i].shell;
203 ff2 = iprod(f[shell],f[shell]);
204 if (ff2 > ft2)
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;
214 int i,j,gid;
216 /* THIS CODE IS OUT OF ORDER */
217 return;
219 if (!bShell) {
220 snew(bShell,ngrp);
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) {
225 gid = md->cENER[i];
226 assert(gid < ngrp);
227 assert(gid >= 0);
228 bShell[gid] = TRUE;
232 /* Loop over all the energy groups */
233 for(i=0; (i<ngrp); i++)
234 for(j=i; (j<ngrp); j++) {
235 gid = GID(i,j,ngrp);
236 /* If either of the groups denote a group with shells, then */
238 if (bShell[i] || bShell[j])
239 fr->bMask[gid] = bMask;
240 else
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;
262 bool bDone;
263 int g;
264 int number_steps;
265 int count=0;
266 int i,start=START(nsb),homenr=HOMENR(nsb),end=START(nsb)+HOMENR(nsb);
267 int Min=0;
268 #define Try (1-Min) /* At start Try = 1 */
270 if (bFirst) {
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]);
278 bFirst = FALSE;
281 ftol = parm->ir.em_tol;
282 number_steps = parm->ir.niter;
283 step0 = 1.0;
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 */
290 if (bOptim)
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);
297 if (debug)
298 fprintf(debug,"df = %g %g\n",df[Min],df[Try]);
300 #ifdef DEBUG
301 if (debug) {
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);
306 #endif
307 /* Copy x to pos[Min] & pos[Try]: during minimization only the
308 * shell positions are updated, therefore the other particles must
309 * be set here.
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];
318 if (PAR(cr))
319 gmx_sum(NEPOT,Epot,cr);
321 step=step0;
323 if (bVerbose && MASTER(cr) && (nshell > 0))
324 print_epot(stdout,mdstep,0,step,Epot[Min],df[Min],bOptim,FALSE);
326 if (debug) {
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);
346 if (debug) {
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);
356 if (debug)
357 fprintf(debug,"df = %g %g\n",df[Min],df[Try]);
359 if (debug) {
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];
368 if (PAR(cr))
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])) {
378 if (debug)
379 fprintf(debug,"Swapping Min and Try\n");
380 Min = Try;
381 step = step0;
383 else
384 step *= 0.8;
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) */
390 if (bOptim) {
391 /* Store the old energies */
392 for(i=0; (i<F_NRE); i++)
393 Estore[i] = ener[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 */
404 if (PAR(cr))
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]);
425 else {
426 /* Parallelise this one! */
427 memcpy(f,force[Min],nsb->natoms*sizeof(f[0]));
428 /* CHECK VIRIAL */
429 copy_mat(my_vir[Min],vir_part);
431 memcpy(x,pos[Min],nsb->natoms*sizeof(x[0]));
432 return count;