Added conditional inclusion of config.h to source files
[gromacs.git] / src / mdlib / coupling.c
blob8becdda11c62256da47ed9997e0031f03181334d
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 3.2.0
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
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 * For more info, check our website at http://www.gromacs.org
33 * And Hey:
34 * GROwing Monsters And Cloning Shrimps
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
40 #include "typedefs.h"
41 #include "smalloc.h"
42 #include "update.h"
43 #include "vec.h"
44 #include "macros.h"
45 #include "physics.h"
46 #include "names.h"
47 #include "fatal.h"
48 #include "txtdump.h"
49 #include "nrnb.h"
51 /*
52 * This file implements temperature and pressure coupling algorithms:
53 * For now only the Weak coupling and the modified weak coupling.
55 * Furthermore computation of pressure and temperature is done here
59 void calc_pres(int ePBC,matrix box,tensor ekin,tensor vir,tensor pres,real Elr)
61 int n,m;
62 real fac,Plr;
64 if (ePBC == epbcNONE)
65 clear_mat(pres);
66 else {
67 /* Uitzoeken welke ekin hier van toepassing is, zie Evans & Morris - E.
68 * Wrs. moet de druktensor gecorrigeerd worden voor de netto stroom in
69 * het systeem...
72 /* Long range correction for periodic systems, see
73 * Neumann et al. JCP
74 * divide by 6 because it is multiplied by fac later on.
75 * If Elr = 0, no correction is made.
78 /* This formula should not be used with Ewald or PME,
79 * where the full long-range virial is calculated. EL 990823
81 Plr = Elr/6.0;
83 fac=PRESFAC*2.0/det(box);
84 for(n=0; (n<DIM); n++)
85 for(m=0; (m<DIM); m++)
86 pres[n][m]=(ekin[n][m]-vir[n][m]+Plr)*fac;
88 if (debug) {
89 pr_rvecs(debug,0,"PC: pres",pres,DIM);
90 pr_rvecs(debug,0,"PC: ekin",ekin,DIM);
91 pr_rvecs(debug,0,"PC: vir ",vir, DIM);
92 pr_rvecs(debug,0,"PC: box ",box, DIM);
97 real calc_temp(real ekin,real nrdf)
99 if (nrdf > 0)
100 return (2.0*ekin)/(nrdf*BOLTZ);
101 else
102 return 0;
105 void parrinellorahman_pcoupl(t_inputrec *ir,int step,tensor pres,
106 tensor box,tensor boxv,tensor M,
107 bool bFirstStep)
109 /* This doesn't do any coordinate updating. It just
110 * integrates the box vector equations from the calculated
111 * acceleration due to pressure difference. We also compute
112 * the tensor M which is used in update to couple the particle
113 * coordinates to the box vectors.
115 * In Nose and Klein (Mol.Phys 50 (1983) no 5., p 1055) this is
116 * given as
117 * -1 . . -1
118 * M_nk = (h') * (h' * h + h' h) * h
120 * with the dots denoting time derivatives and h is the transformation from
121 * the scaled frame to the real frame, i.e. the TRANSPOSE of the box.
122 * This also goes for the pressure and M tensors - they are transposed relative
123 * to ours. Our equation thus becomes:
125 * -1 . . -1
126 * M_gmx = M_nk' = b * (b * b' + b * b') * b'
128 * where b is the gromacs box matrix.
129 * Our box accelerations are given by
130 * .. ..
131 * b = vol/W inv(box') * (P-ref_P) (=h')
134 int d,n;
135 tensor winv;
136 real vol=box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
137 real fac=vol/PRESFAC;
138 real atot,arel,change,maxchange,xy_pressure;
139 tensor invbox,pdiff,t1,t2;
141 real maxl;
143 m_inv(box,invbox);
145 if (!bFirstStep) {
146 maxl=max(box[XX][XX],box[YY][YY]);
147 maxl=max(maxl,box[ZZ][ZZ]);
148 for(d=0;d<DIM;d++)
149 for(n=0;n<DIM;n++)
150 winv[d][n]=
151 (4*M_PI*M_PI*ir->compress[d][n])/(3*ir->tau_p*ir->tau_p*maxl);
153 m_sub(pres,ir->ref_p,pdiff);
155 if(ir->epct==epctSURFACETENSION) {
156 /* Unlike Berendsen coupling it might not be trivial to include a z
157 * pressure correction here? On the other hand we don't scale the
158 * box momentarily, but change accelerations, so it might not be crucial.
160 xy_pressure=0.5*(pres[XX][XX]+pres[YY][YY]);
161 for(d=0;d<ZZ;d++)
162 pdiff[d][d]=(xy_pressure-(pres[ZZ][ZZ]-ir->ref_p[d][d]/box[d][d]));
165 tmmul(invbox,pdiff,t1);
167 switch (ir->epct) {
168 case epctANISOTROPIC:
169 for(d=0;d<DIM;d++)
170 for(n=0;n<=d;n++)
171 t1[d][n]*=winv[d][n]*fac;
172 break;
173 case epctISOTROPIC:
174 /* calculate total volume acceleration */
175 atot=box[XX][XX]*box[YY][YY]*t1[ZZ][ZZ]+
176 box[XX][XX]*t1[YY][YY]*box[ZZ][ZZ]+
177 t1[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
178 arel=atot/(3*vol);
179 /* set all RELATIVE box accelerations equal, and maintain total V
180 * change speed */
181 for(d=0;d<DIM;d++)
182 for(n=0;n<=d;n++)
183 t1[d][n]=winv[0][0]*fac*arel*box[d][n];
184 break;
185 case epctSEMIISOTROPIC:
186 case epctSURFACETENSION:
187 /* Note the correction to pdiff above for surftens. coupling */
189 /* calculate total XY volume acceleration */
190 atot=box[XX][XX]*t1[YY][YY]+t1[XX][XX]*box[YY][YY];
191 arel=atot/(2*box[XX][XX]*box[YY][YY]);
192 /* set RELATIVE XY box accelerations equal, and maintain total V
193 * change speed. Dont change the third box vector accelerations */
194 for(d=0;d<ZZ;d++)
195 for(n=0;n<=d;n++)
196 t1[d][n]=winv[d][n]*fac*arel*box[d][n];
197 for(n=0;n<DIM;n++)
198 t1[ZZ][n]*=winv[d][n]*fac;
199 break;
200 default:
201 fatal_error(0,"Parrinello-Rahman pressure coupling type %s "
202 "not supported yet\n",EPCOUPLTYPETYPE(ir->epct));
203 break;
206 maxchange=0;
207 for(d=0;d<DIM;d++)
208 for(n=0;n<=d;n++) {
209 boxv[d][n] += ir->delta_t*t1[d][n];
210 /* We do NOT update the box vectors themselves here, since
211 * we need them for shifting later. It is instead done last
212 * in the update() routine.
215 /* Calculate the change relative to diagonal elements -
216 * since it's perfectly ok for the off-diagonal ones to
217 * be zero it doesn't make sense to check the change relative
218 * to its current size.
220 change=fabs(ir->delta_t*boxv[d][n]/box[d][d]);
221 if(change>maxchange)
222 maxchange=change;
225 if(maxchange>0.01)
226 fprintf(stdlog,"\nStep %d Warning: Pressure scaling more than 1%%.\n",
227 step);
230 mtmul(boxv,box,t1); /* t1=boxv * b' */
231 for(d=0;d<DIM;d++)
232 for(n=0;n<DIM;n++)
233 t1[d][n] += t1[n][d]; /* t1=t1+t1' */
234 mmul(invbox,t1,t2);
235 mtmul(t2,invbox,M);
238 void berendsen_pcoupl(t_inputrec *ir,int step,tensor pres,matrix box,
239 matrix mu)
241 int d,n;
242 real scalar_pressure, xy_pressure, p_corr_z;
243 char *ptr,buf[STRLEN];
246 * Calculate the scaling matrix mu
248 scalar_pressure=0;
249 xy_pressure=0;
250 for(d=0; d<DIM; d++) {
251 scalar_pressure += pres[d][d]/DIM;
252 if (d != ZZ)
253 xy_pressure += pres[d][d]/(DIM-1);
255 /* Pressure is now in bar, everywhere. */
256 #define factor(d,m) (ir->compress[d][m]*ir->delta_t/ir->tau_p)
258 /* mu has been changed from pow(1+...,1/3) to 1+.../3, since this is
259 * necessary for triclinic scaling
261 clear_mat(mu);
262 switch (ir->epct) {
263 case epctISOTROPIC:
264 for(d=0; d<DIM; d++)
265 mu[d][d] = 1.0 - factor(d,d)*(ir->ref_p[d][d] - scalar_pressure)/DIM;
266 break;
267 case epctSEMIISOTROPIC:
268 for(d=0; d<ZZ; d++)
269 mu[d][d] = 1.0 - factor(d,d)*(ir->ref_p[d][d]-xy_pressure)/DIM;
270 mu[ZZ][ZZ] =
271 1.0 - factor(ZZ,ZZ)*(ir->ref_p[ZZ][ZZ] - pres[ZZ][ZZ])/DIM;
272 break;
273 case epctANISOTROPIC:
274 for(d=0; d<DIM; d++)
275 for(n=0; n<DIM; n++)
276 mu[d][n] = (d==n ? 1.0 : 0.0)
277 -factor(d,n)*(ir->ref_p[d][n] - pres[d][n])/DIM;
278 break;
279 case epctSURFACETENSION:
280 /* ir->ref_p[0/1] is the reference surface-tension times *
281 * the number of surfaces */
282 if (ir->compress[ZZ][ZZ])
283 p_corr_z = ir->delta_t/ir->tau_p*(ir->ref_p[ZZ][ZZ] - pres[ZZ][ZZ]);
284 else
285 /* when the compressibity is zero, set the pressure correction *
286 * in the z-direction to zero to get the correct surface tension */
287 p_corr_z = 0;
288 mu[ZZ][ZZ] = 1.0 - ir->compress[ZZ][ZZ]*p_corr_z;
289 for(d=0; d<DIM-1; d++)
290 mu[d][d] = 1.0 + factor(d,d)*(ir->ref_p[d][d]/(mu[ZZ][ZZ]*box[ZZ][ZZ])
291 - (pres[ZZ][ZZ]+p_corr_z - xy_pressure))/(DIM-1);
292 break;
293 default:
294 fatal_error(0,"Berendsen pressure coupling type %s not supported yet\n",
295 EPCOUPLTYPETYPE(ir->epct));
296 break;
298 /* To fullfill the orientation restrictions on triclinic boxes
299 * we will set mu_yx, mu_zx and mu_zy to 0 and correct
300 * the other elements of mu to first order.
302 mu[YY][XX] += mu[XX][YY];
303 mu[ZZ][XX] += mu[XX][ZZ];
304 mu[ZZ][YY] += mu[YY][ZZ];
305 mu[XX][YY] = 0;
306 mu[XX][ZZ] = 0;
307 mu[YY][ZZ] = 0;
309 if (debug) {
310 pr_rvecs(debug,0,"PC: pres ",pres,3);
311 pr_rvecs(debug,0,"PC: mu ",mu,3);
314 if (mu[XX][XX]<0.99 || mu[XX][XX]>1.01 ||
315 mu[YY][YY]<0.99 || mu[YY][YY]>1.01 ||
316 mu[ZZ][ZZ]<0.99 || mu[ZZ][ZZ]>1.01) {
317 sprintf(buf,"\nStep %d Warning: pressure scaling more than 1%%, "
318 "mu: %g %g %g\n",step,mu[XX][XX],mu[YY][YY],mu[ZZ][ZZ]);
319 fprintf(stdlog,"%s",buf);
320 fprintf(stderr,"%s",buf);
324 void berendsen_pscale(matrix mu,
325 matrix box,int start,int nr_atoms,
326 rvec x[],unsigned short cFREEZE[],
327 t_nrnb *nrnb,ivec nFreeze[])
329 int n,d,g;
331 /* Scale the positions */
332 for (n=start; n<start+nr_atoms; n++) {
333 g=cFREEZE[n];
335 if (!nFreeze[g][XX])
336 x[n][XX] = mu[XX][XX]*x[n][XX]+mu[YY][XX]*x[n][YY]+mu[ZZ][XX]*x[n][ZZ];
337 if (!nFreeze[g][YY])
338 x[n][YY] = mu[YY][YY]*x[n][YY]+mu[ZZ][YY]*x[n][ZZ];
339 if (!nFreeze[g][ZZ])
340 x[n][ZZ] = mu[ZZ][ZZ]*x[n][ZZ];
342 /* compute final boxlengths */
343 for (d=0; d<DIM; d++) {
344 box[d][XX] = mu[XX][XX]*box[d][XX]+mu[YY][XX]*box[d][YY]+mu[ZZ][XX]*box[d][ZZ];
345 box[d][YY] = mu[YY][YY]*box[d][YY]+mu[ZZ][YY]*box[d][ZZ];
346 box[d][ZZ] = mu[ZZ][ZZ]*box[d][ZZ];
349 /* (un)shifting should NOT be done after this,
350 * since the box vectors might have changed
352 inc_nrnb(nrnb,eNR_PCOUPL,nr_atoms);
355 void berendsen_tcoupl(t_grpopts *opts,t_groups *grps,real dt,real lambda[])
357 int i;
359 real T,reft=0,lll;
361 for(i=0; (i<opts->ngtc); i++) {
362 T = grps->tcstat[i].T;
364 if ((opts->tau_t[i] > 0) && (T > 0.0)) {
366 reft = max(0.0,opts->ref_t[i]);
367 lll = sqrt(1.0 + (dt/opts->tau_t[i])*(reft/T-1.0));
368 lambda[i] = max(min(lll,1.25),0.8);
370 else
371 lambda[i] = 1.0;
373 if (debug)
374 fprintf(debug,"TC: group %d: T: %g, Lambda: %g\n",
375 i,T,lambda[i]);
379 void nosehoover_tcoupl(t_grpopts *opts,t_groups *grps,real dt,real xi[])
381 real Qinv;
382 int i;
383 real reft=0,xit,oldxi;
385 for(i=0; (i<opts->ngtc); i++) {
386 if ((opts->tau_t[i] > 0) && (opts->ref_t[i] > 0))
387 Qinv=1.0/(opts->tau_t[i]*opts->tau_t[i]*opts->ref_t[i]/(4*M_PI*M_PI));
388 else
389 Qinv=0.0;
390 reft = max(0.0,opts->ref_t[i]);
391 xi[i] += dt*Qinv*(grps->tcstat[i].T-reft);
395 /* set target temperatures if we are annealing */
396 void update_annealing_target_temp(t_grpopts *opts,real t)
398 int i,j,n,npoints;
399 real pert,thist=0,x;
401 for(i=0;i<opts->ngtc;i++) {
402 npoints = opts->anneal_npoints[i];
403 switch (opts->annealing[i]) {
404 case eannNO:
405 continue;
406 case eannPERIODIC:
407 /* calculate time modulo the period */
408 pert = opts->anneal_time[i][npoints-1];
409 n = t / pert;
410 thist = t - n*pert; /* modulo time */
411 /* Make sure rounding didn't get us outside the interval */
412 if (fabs(thist-pert) < GMX_REAL_EPS*100)
413 thist=0;
414 break;
415 case eannSINGLE:
416 thist = t;
417 break;
418 default:
419 fatal_error(0,"Death horror in update_annealing_target_temp (i=%d/%d npoints=%d)",i,opts->ngtc,npoints);
421 /* We are doing annealing for this group if we got here,
422 * and we have the (relative) time as thist.
423 * calculate target temp */
424 j=0;
425 while ((j < npoints-1) && (thist>(opts->anneal_time[i][j+1])))
426 j++;
427 if (j < npoints-1) {
428 /* Found our position between points j and j+1.
429 * Interpolate: x is the amount from j+1, (1-x) from point j
430 * First treat possible jumps in temperature as a special case.
432 if ((opts->anneal_time[i][j+1]-opts->anneal_time[i][j]) < GMX_REAL_EPS*100)
433 opts->ref_t[i]=opts->anneal_temp[i][j+1];
434 else {
435 x = ((thist-opts->anneal_time[i][j])/
436 (opts->anneal_time[i][j+1]-opts->anneal_time[i][j]));
437 opts->ref_t[i] = x*opts->anneal_temp[i][j+1]+(1-x)*opts->anneal_temp[i][j];
440 else {
441 opts->ref_t[i] = opts->anneal_temp[i][npoints-1];