3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
55 const real tol = 1e-8;
65 real uhat(int porder,real k1,real k2,real k3,real h1,real h2,real h3)
71 fac1 = sinx_x(k1*h1*0.5);
72 fac2 = sinx_x(k2*h2*0.5);
73 fac3 = sinx_x(k3*h3*0.5);
76 f123 = fac1*fac2*fac3;
77 for(i=1; (i<=porder+1); i++)
86 real uhat1D(int porder,real k1,real h1)
92 fac1 = sinx_x(k1*h1*0.5);
95 for(i=1; (i<=porder+1); i++)
104 real shat(real acut,real kmag,real r1)
106 return gk(kmag,acut,r1);
109 real dhat(real alpha,real k,real h)
113 dh = alpha*(sin(k*h)/h) + (1.0-alpha)*(sin(2.0*k*h)/(2.0*h) );
121 real cufrth(int porder,real k1,real k2,real k3,
122 real h1,real h2,real h3,int nalias)
124 real kn1,kn2,kn3,tmp;
131 tmp = uhat(porder,k1,k2,k3,h1,h2,h3);
132 ufrth = tmp*tmp*tmp*tmp;
136 for( n1 = -nalias; (n1<= nalias); n1++) {
137 for( n2 = -nalias; (n2<= nalias); n2++) {
138 for( n3 = -nalias; (n3<= nalias); n3++) {
139 kn1 = k1 + n1*twopi/h1;
140 kn2 = k2 + n2*twopi/h2;
141 kn3 = k3 + n3*twopi/h3;
142 tmp = uhat(porder,kn1,kn2,kn3,h1,h2,h3);
143 ufrth += tmp*tmp*tmp*tmp;
148 if (fabs(ufrth) < tol)
154 real crsqal(real acut,real r1,real k1,real k2,real k3,
155 real h1,real h2,real h3,int nalias)
159 real ksq,kmag,tmp,Rsqal;
168 ksq = k1*k1 + k2*k2 + k3*k3;
170 tmp = shat(acut,kmag,r1);
171 Rsqal = tmp*tmp/(ksq);
175 for(n1 = -nalias; (n1<= nalias); n1++) {
176 for( n2 = -nalias; (n2<= nalias); n2++) {
177 for( n3 = -nalias; (n3<= nalias); n3++) {
181 ksq = kn1*kn1 + kn2*kn2 + kn3*kn3;
183 tmp = shat(acut,kmag,r1);
184 Rsqal = Rsqal + tmp*tmp/ksq;
193 real usqsq(int porder,real k1,real k2,real k3,real h1,real h2,real h3)
195 const real tt=2.0/3.0;
196 const real tx=2.0/15.0;
197 real t1,t2,t3,t12,t22,t32,tmp;
207 tmp = (1.0-tt*t12)*(1-tt*t22)*(1-tt*t32);
208 else if (porder == 2)
209 tmp = ( (1.0 - t12 + tx*t12*t12)*
210 (1.0 - t22 + tx*t22*t22)*
211 (1.0 - t32 + tx*t32*t32) );
213 gmx_fatal(FARGS,"porder = %d in usqsq",porder);
218 real usqsq1D(int porder,real k1,real h1)
220 const real tt=2.0/3.0;
221 const real tx=2.0/15.0;
229 else if (porder == 2)
230 tmp = ( (1.0 - t12 + tx*t12*t12));
232 gmx_fatal(FARGS,"porder = %d in usqsq",porder);
237 real ursum(int term,int porder,real acut,real r1,
238 real k1,real k2,real k3,real h1,real h2,real h3,int nalias)
242 real kn1,kn2,kn3,urs,tmp;
252 c for large enough values of k, the terms become negligable
253 c if shat(k) = exp(-k^2/4*acut) < eps
254 c kcutsq = 4*alpha* (-ln(eps))
255 c eps = 10^-6, -ln(eps) = 14
256 c eps = 10^-10, -ln(eps) = 23
257 c eps = 10^-20, -ln(eps) = 46
259 c kcutsq = 4.0*acut*115;
263 if (term==XX) kt = k1;
264 if (term==YY) kt = k2;
265 if (term==ZZ) kt = k3;
266 ksq = k1*k1 + k2*k2 + k3*k3;
268 tmp = uhat(porder,k1,k2,k3,h1,h2,h3);
269 urs = tmp*tmp*kt*shat(acut,kmag,r1)/(ksq);
273 for(n1 = -nalias; (n1<= nalias); n1++) {
274 for( n2 = -nalias; (n2<= nalias); n2++) {
275 for( n3 = -nalias; (n3<= nalias); n3++) {
279 ksq = kn1*kn1 + kn2*kn2 + kn3*kn3;
281 if (term==XX) kt = kn1;
282 if (term==YY) kt = kn2;
283 if (term==ZZ) kt = kn3;
286 tmp = uhat(porder,kn1,kn2,kn3,h1,h2,h3);
288 urs = urs + tmp*tmp*kt*shat(acut,kmag,r1)/ksq;
297 real ursum1D(int term,int porder,real acut,real r1,real k1,real h1,int nalias)
309 c for large enough values of k, the terms become negligable
310 c if shat(k) = exp(-k^2/4*acut) < eps
311 c kcutsq = 4*alpha* (-ln(eps))
312 c eps = 10^-6, -ln(eps) = 14
313 c eps = 10^-10, -ln(eps) = 23
314 c eps = 10^-20, -ln(eps) = 46
317 /* kcutsq = 4.0*acut*115; */
320 if (term==1) kt = k1;
323 tmp = uhat1D(porder,k1,h1);
324 urs = tmp*tmp*kt*shat(acut,kmag,r1)/(EPSILON0*ksq);
328 for(n1 = -nalias; (n1<= nalias); n1++) {
331 /*c if (ksq.lt.kcutsq) then*/
332 if (term==XX) kt = kn1;
335 tmp = uhat1D(porder,kn1,h1);
337 urs = urs + tmp*tmp*kt*shat(acut,kmag,r1)/(EPSILON0*ksq);
345 real sym(int indx,int maxind)
347 if ( (indx == 0 ) || (indx == maxind/2) )
353 void calc(gmx_bool bSym,gmx_bool bVerbose,
354 const int n1max,const int n2max,const int n3max,
355 const real h1,const real h2,const real h3,
356 int nalias,int porder,real acut,real r1,const real alpha,
357 const gmx_bool bSearch,
358 real ***ghat,real *ppval,real *zzval,real *eeref,real *qqopt)
361 real k1,k2,k3,ksq,kmag;
362 real gnumer,dsq,gdenom,gsq;
363 real ufrth,rsqal,rsq;
367 real d1,d2,d3,u1,u2,u3,ss,gg;
368 real pval,zval,eref,qopt;
369 int N1MAX,N2MAX,N3MAX;
391 for(l1=0; (l1<N1MAX); l1++) {
393 fprintf(stderr,"\rl1=%5d qopt=%12.6e",l1,qopt);
396 d1 = dhat(alpha,k1,h1);
398 for(l2=0; (l2<N2MAX); l2++) {
400 d2 = dhat(alpha,k2,h2);
402 for(l3=0; (l3<N3MAX); l3++) {
403 if (((l1+l2+l3) == 0) /*|| (l1 == n1max/2) || (l2 == n2max/2) ||
408 ksq = k1*k1 + k2*k2 + k3*k3;
411 d3 = dhat(alpha,k3,h3);
412 u1 = ursum(XX,porder,acut,r1,k1,k2,k3,h1,h2,h3,nalias);
413 u2 = ursum(YY,porder,acut,r1,k1,k2,k3,h1,h2,h3,nalias);
414 u3 = ursum(ZZ,porder,acut,r1,k1,k2,k3,h1,h2,h3,nalias);
416 gnumer = d1*u1+d2*u2+d3*u3;
417 dsq = d1*d1+d2*d2+d3*d3;
418 gdenom = dsq*usqsq(porder,k1,k2,k3,h1,h2,h3);
420 symfac = sym(l1,n1max)*sym(l2,n2max)*sym(l3,n3max);
424 rsqal = crsqal(acut,r1,k1,k2,k3,h1,h2,h3,nalias);
427 qopt += (symfac*(rsqal - sqr(gnumer)/gdenom));
429 fprintf(debug,"rsqal: %10.3e, gnumer: %10.3e, gdenom: %10.3e, ratio: %10.3e\n",
430 rsqal,gnumer,gdenom,gnumer/gdenom);
433 if ((l1 == n1max/2) || (l2 == n2max/2) || (l3 == n3max/2))
434 printf("L(%2d,%2d,%2d) D(%10.3e,%10.3e,%10.3e) U(%10.3e,%10.3e,%10.3e) gnumer=%10.3em dsq=%10.3e, gdenom=%10.3e, ghat=%10.3e\n",
435 l1,l2,l3,d1,d2,d3,u1,u2,u3,gnumer,dsq,gdenom,
436 (gdenom == 0.0) ? 0 : gnumer/gdenom);
443 ghat[l1][l2][l3] = gg/EPSILON0;
446 ufrth = cufrth(porder,k1,k2,k3,h1,h2,h3,nalias);
447 pval = pval + symfac*
448 (dsq*gsq*(usqsq(porder,k1,k2,k3,h1,h2,h3)-ufrth));
450 zval = zval + symfac*
451 (dsq*gsq*ufrth - 2.0*gnumer*gnumer/gdenom + rsqal);
452 ss = shat(acut,kmag,r1);
454 eref = eref + symfac* (rsqal - rsq);
461 fprintf(stderr,"\n");
462 *ppval = pval/(box1*box2*box3);
463 *zzval = zval/(box1*box2*box3);
464 *eeref = eref/(box1*box2*box3);
465 *qqopt = qopt/(EPSILON0*box1*box2*box3);
468 void calc1D(gmx_bool bSym,gmx_bool bVerbose,
469 const int n1max,const int n2max,const int n3max,
470 const real h1,const real h2,const real h3,
471 int nalias,int porder,real acut,real r1,const real alpha,
472 const gmx_bool bSearch,
473 real ***ghat,real *ppval,real *zzval,real *eeref,real *qqopt)
477 real gnumer,dsq,gdenom;
483 real pval,zval,eref,qopt;
485 /* int N2MAX,N3MAX; */
489 /* N2MAX = n2max/2+1; */
490 /* N3MAX = n3max/2+1; */
509 for(l1=0; (l1<N1MAX); l1++) {
511 fprintf(stderr,"\rl1=%5d qopt=%12.6e",l1,qopt);
514 d1 = dhat(alpha,k1,h1);
519 u1 = ursum1D(XX,porder,acut,r1,k1,h1,nalias);
523 gdenom = dsq*usqsq(porder,k1,k2,k3,h1,h2,h3);
525 symfac = sym(l1,n1max);
529 rsqal = crsqal(acut,r1,k1,k2,k3,h1,h2,h3,nalias);
532 qopt += symfac*(rsqal - (gnumer*gnumer)/gdenom);
536 fprintf(stderr,"\n");
537 *ppval = pval/(box1*box2*box3);
538 *zzval = zval/(box1*box2*box3);
539 *eeref = eref/(box1*box2*box3);
540 *qqopt = qopt/(box1*box2*box3);
543 void read_params(char *fn,t_inputrec *ir,rvec boxs)
549 /* Read topology and coordinates */
550 read_tpx(fn,&step,&t,&lambda,ir,box,&natoms,NULL,NULL,NULL,NULL);
551 for(m=0; (m<DIM); m++)
555 int main(int argc,char *argv[])
558 const real gold=0.38197;
560 int n1max,n2max,n3max;
566 gmx_bool bSearch,bConv;
567 /* gmx_bool bNL=FALSE; */
569 real pval,zval,eref,qopt,norm;
570 real alpha0,alpha1,alpha2,alpha3,alptol;
573 /* int ii,jj,kk,nn; */
576 { efTPX, NULL, NULL, ffREAD },
577 { efHAT, "-o", "ghat", ffWRITE }
579 #define NFILE asize(fnm)
580 static gmx_bool bVerbose=FALSE,bCubic=TRUE,bSym=TRUE;
581 static t_pargs pa[] = {
582 { "-v", FALSE, etBOOL, &bVerbose, "Verbose on"},
583 { "-cubic", FALSE, etBOOL, &bCubic, "Force beta to be the same in all directions" },
584 { "-sym", FALSE, etBOOL, &bSym, "HIDDENUse symmetry for the generation of ghat function (turn off for debugging only!)" }
587 CopyRight(stdout,argv[0]);
588 parse_common_args(&argc,argv,0,TRUE,NFILE,fnm,asize(pa),pa,0,NULL,0,NULL);
590 read_params(ftp2fn(efTPX,NFILE,fnm),&ir,box);
592 r1 = ir.rcoulomb_switch;
600 /* These are not parameters. They are fixed.
601 * Luty et al. determined their optimal values to be 2.
607 set_LRconsts(stdout,r1,acut,box,NULL);
609 printf("Grid cell size is %8.4f x %8.4f x %8.4f nm\n",h1,h2,h3);
611 ghat=mk_rgrid(n1max,n2max,n3max);
619 calc(bSym,bVerbose,n1max,n2max,n3max,h1,h2,h3,
620 nalias,porder,acut,r1,alpha,bSearch,
621 ghat,&pval,&zval,&eref,&qopt);
627 calc(bSym,bVerbose,n1max,n2max,n3max,h1,h2,h3,
628 nalias,porder,acut,r1,alpha0,bSearch,
629 ghat,&pval,&zval,&eref,&q0);
630 calc(bSym,bVerbose,n1max,n2max,n3max,h1,h2,h3,
631 nalias,porder,acut,r1,alpha1,bSearch,
632 ghat,&pval,&zval,&eref,&q1);
633 calc(bSym,bVerbose,n1max,n2max,n3max,h1,h2,h3,
634 nalias,porder,acut,r1,alpha3,bSearch,
635 ghat,&pval,&zval,&eref,&q3);
637 /* if ( (q1 > q0) || (q1 > q3) )
638 gmx_fatal(FARGS,"oops q1=%f,q0=%f,q3=%f",q1,q0,q3); */
639 alpha2 = alpha1 + gold*(alpha3-alpha1);
640 calc(bSym,bVerbose,n1max,n2max,n3max,h1,h2,h3,
641 nalias,porder,acut,r1,alpha2,bSearch,
642 ghat,&pval,&zval,&eref,&q2);
646 fprintf(stderr,"q0 = %10g, q1= %10g, q2 = %10g, q3 = %10g\n",
649 while ((!bConv) && (niter < mxiter)) {
650 fprintf(stderr,"%2d %10.4f %10.4f %10.4f %10.4f\n",
651 niter,alpha0,alpha1,alpha2,alpha3);
658 alpha2 = alpha1 + gold*(alpha3-alpha1);
659 calc(bSym,bVerbose,n1max,n2max,n3max,h1,h2,h3,
660 nalias,porder,acut,r1,alpha2,bSearch,
661 ghat,&pval,&zval,&eref,&q2);
668 alpha1 = alpha2 - gold*(alpha2-alpha0);
669 calc(bSym,bVerbose,n1max,n2max,n3max,h1,h2,h3,
670 nalias,porder,acut,r1,alpha1,bSearch,
671 ghat,&pval,&zval,&eref,&q1);
673 if ((alpha3-alpha0) < alptol)
679 calc(bSym,bVerbose,n1max,n2max,n3max,h1,h2,h3,
680 nalias,porder,acut,r1,alpha,bSearch,
681 ghat,&pval,&zval,&eref,&qopt);
685 calc(bSym,bVerbose,n1max,n2max,n3max,h1,h2,h3,
686 nalias,porder,acut,r1,alpha,bSearch,
687 ghat,&pval,&zval,&eref,&qopt);
690 fprintf(stderr,"%10g %10g %10g %10g %10g %10g\n",
691 acut,r1,pval,zval,eref,qopt);
692 norm = sqr(1.0/(4.0*M_PI*h1*h1))*(4.0/3.0*M_PI*h1*h1*h1);
694 pval = sqrt(fabs(pval)/norm)*100.0;
695 zval = sqrt(fabs(zval)/norm)*100.0;
696 eref = sqrt(fabs(eref)/norm)*100.0;
697 qopt = sqrt(fabs(qopt)/norm)*100.0;
699 beta[XX] = beta[YY] = beta[ZZ] = alpha;
700 wr_ghat(ftp2fn(efHAT,NFILE,fnm),n1max,n2max,n3max,h1,h2,h3,
701 ghat,nalias,porder,niter,bSym,beta,
702 r1,acut,pval,zval,eref,qopt);
704 /* fp=ftp2FILE(efHAT,NFILE,fnm,"w");
705 fprintf(fp,"%8d %8d %8d %15.10e %15.10e %15.10e\n",
706 n1max,n2max,n3max,h1,h2,h3);
707 fprintf(fp,"%8d %8d %8d %8d %15.10e %15.10e %15.10e\n",
708 nalias,porder,niter,bSym,alpha,alpha,alpha);
709 fprintf(fp,"%10g %10g %10g %10g %10g %10g\n",
710 acut,r1,pval,zval,eref,qopt);
712 int N1MAX,N2MAX,N3MAX;
724 for(ii=0; (ii<N1MAX); ii++) {
725 for(jj=0; (jj<N2MAX); jj++) {
726 for(kk=0,nn=1; (kk<N3MAX); kk++,nn++) {
728 fprintf(fp," %12.5e",ghat[ii][jj][kk]);
741 pr_scalar_gk("ghat.xvg",n1max,n2max,n3max,box,ghat);