3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
9 * VERSION 3.3.99_development_20071104
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-2006, 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 * Groningen Machine for Chemical Simulation
44 #include "gmx_fatal.h"
60 #define DCONS 0.117265878
66 static char *watname
[] = { "OW ", "HW1", "HW2", "DW", "SW" };
67 static char *diamname
[] = { "C1", "H2", "H3", "H4", "H5", "H2", "H3", "H4", "H5" };
68 static real qspc
[] = { -0.82, 0.41, 0.41 };
69 static real qyaw
[] = { 1.24588, 0.62134, 0.62134, 0.0, -2.48856 };
70 static real spc_lj
[3][6] = {
71 { 2.6171e-3, 2.6331e-6, 0, 0, 0, 0 },
78 static real yaw_lj
[5][10] = {
79 { 0, 0, 0, 0, 0, 0, 0, 0, 0, COS
},
80 { 0, 0, 0, CHH
, 0, CHH
, 0, 0, 0, CHS
},
81 { 0, 0, 0, CHH
, 0, CHH
, 0, 0, 0, CHS
},
82 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
83 { 0, COS
, 0, CHS
, 0, CHS
, 0, 0, 2.6e-3, 0 }
86 void unitcell(rvec x
[],rvec box
,bool bYaw
,real odist
,real hdist
)
90 #define cy2 0.94280904
95 { 0, 0, 1 }, /* H relative to Oxygen */
97 { cx
, cy
, -cz
}, /* O2 */
98 { 0, 0, -1 }, /* H relative to Oxygen */
100 { cx
, cy
+cy2
, 0 }, /* O3 */
101 { -cx
, cy
, -cz
}, /* H relative to Oxygen */
103 { 0, 2*cy
+cy2
, -cz
}, /* O4 */
104 {-cx
,-cy
, +cz
}, /* H relative to Oxygen */
106 { 0, 0, 1 }, /* O5 */
107 {-cx
, cy
, +cz
}, /* H relative to Oxygen */
109 { cx
, cy
, 1+cz
}, /* O6 */
110 { -cx
, -cy
, -cz
}, /* H relative to Oxygen */
112 { cx
, cy
+cy2
, 1 }, /* O7 */
113 { 0, 0, -1 }, /* H relative to Oxygen */
115 { 0, 2*cy
+cy2
,1+cz
}, /* O8 */
116 { 0, 0, 1 }, /* H relative to Oxygen */
123 for(i
=0; (i
<8); i
++) {
129 svmul(odist
,xx
[iin
],x
[iout
]);
130 svmul(-0.82,x
[iout
],t2
);
132 for(j
=1; (j
<=2); j
++) {
133 svmul(hdist
,xx
[iin
+j
],tmp
);
134 rvec_add(x
[iout
],tmp
,x
[iout
+j
]);
135 svmul(0.41,x
[iout
+j
],t2
);
139 for(m
=0; (m
<DIM
); m
++)
140 x
[iout
+3][m
] = x
[iout
+4][m
] =
141 (1-2*DCONS
)*x
[iout
][m
]+DCONS
*(x
[iout
+1][m
]+x
[iout
+2][m
]);
145 box
[YY
] = 2*(cy2
+cy
);
147 for(i
=0; (i
<DIM
); i
++)
150 printf("Unitcell: %10.5f %10.5f %10.5f\n",box
[XX
],box
[YY
],box
[ZZ
]);
151 printf("Dipole: %10.5f %10.5f %10.5f (e nm)\n",dip
[XX
],dip
[YY
],dip
[ZZ
]);
154 void random_h_coords(int natmol
,int nmol
,rvec x
[],rvec box
,
155 bool bYaw
,real odist
,real hdist
)
157 #define cx 0.81649658
158 #define cy 0.47140452
159 #define cy2 0.94280904
160 #define cz 0.33333333
163 { 0, 0, 0 }, /* O1 */
164 { 0, 0, 1 }, /* H relative to Oxygen */
166 { cx
, cy
, -cz
}, /* O2 */
167 { 0, 0, -1 }, /* H relative to Oxygen */
169 { cx
, cy
+cy2
, 0 }, /* O3 */
170 { -cx
, cy
, -cz
}, /* H relative to Oxygen */
172 { 0, 2*cy
+cy2
, -cz
}, /* O4 */
173 {-cx
,-cy
, +cz
}, /* H relative to Oxygen */
175 { 0, 0, 1 }, /* O5 */
176 {-cx
, cy
, +cz
}, /* H relative to Oxygen */
178 { cx
, cy
, 1+cz
}, /* O6 */
179 { -cx
, -cy
, -cz
}, /* H relative to Oxygen */
181 { cx
, cy
+cy2
, 1 }, /* O7 */
182 { 0, 0, -1 }, /* H relative to Oxygen */
184 { 0, 2*cy
+cy2
,1+cz
}, /* O8 */
185 { 0, 0, 1 }, /* H relative to Oxygen */
192 for(i
=0; (i
<nmol
); i
++) {
195 svmul(odist
,x
[iin
],x
[iout
]);
196 svmul(-0.82,x
[iout
],t2
);
198 for(j
=1; (j
<=2); j
++) {
199 svmul(hdist
,xx
[3*(i
% 8)+j
],tmp
);
200 rvec_add(x
[iout
],tmp
,x
[iout
+j
]);
201 svmul(0.41,x
[iout
+j
],t2
);
207 box
[YY
] = 2*(cy2
+cy
);
209 for(i
=0; (i
<DIM
); i
++)
212 printf("Unitcell: %10.5f %10.5f %10.5f\n",box
[XX
],box
[YY
],box
[ZZ
]);
213 printf("Dipole: %10.5f %10.5f %10.5f (e nm)\n",dip
[XX
],dip
[YY
],dip
[ZZ
]);
216 void unitcell_d(rvec x
[],rvec box
,real odist
)
219 { 0, 0, 0 }, /* C1 */
220 { cx
, cy
, -cz
}, /* C2 */
221 { cx
, cy
+cy2
, 0 }, /* C3 */
222 { 0, 2*cy
+cy2
, -cz
}, /* C4 */
223 { 0, 0, 1 }, /* C5 */
224 { cx
, cy
, 1+cz
}, /* C6 */
225 { cx
, cy
+cy2
, 1 }, /* C7 */
226 { 0, 2*cy
+cy2
,1+cz
}, /* C8 */
229 { 0, 0, 1 }, /* H relative to C */
238 for(i
=0; (i
<8); i
++) {
241 svmul(odist
,cc
[iin
],x
[iout
]);
244 box
[YY
] = 2*(cy2
+cy
);
246 for(i
=0; (i
<DIM
); i
++)
249 printf("Unitcell: %10.5f %10.5f %10.5f\n",box
[XX
],box
[YY
],box
[ZZ
]);
252 static t_bbb
*mk_bonds(int natoms
,rvec x
[],real odist
,
253 bool bPBC
,matrix box
)
255 real od2
= odist
*odist
+1e-5;
264 for(i
=0; (i
<natoms
); i
++) {
265 for(j
=i
+1; (j
<natoms
); j
++) {
267 pbc_dx(&pbc
,x
[i
],x
[j
],dx
);
269 rvec_sub(x
[i
],x
[j
],dx
);
270 if (iprod(dx
,dx
) <= od2
) {
271 bbb
[i
].aa
[bbb
[i
].n
++] = j
;
272 bbb
[j
].aa
[bbb
[j
].n
++] = i
;
277 #define PRB(nn) (bbb[(i)].n >= (nn)) ? bbb[i].aa[nn-1] : -1
278 for(i
=0; (i
<natoms
); i
++)
279 fprintf(debug
,"bonds from %3d: %d %d %d %d\n",
280 i
,PRB(1),PRB(2),PRB(3),PRB(4));
285 static void mk_diamond(t_atoms
*a
,rvec x
[],real odist
,t_symtab
*symtab
,
286 bool bPBC
,matrix box
)
289 int i
,ib
,j
,k
,l
,m
,nrm
=0;
296 bbb
= mk_bonds(a
->nr
,x
,odist
,bPBC
,box
);
298 for(i
=0; (i
<a
->nr
); i
++) {
300 for(k
=0; (k
<bbb
[i
].n
); k
++) {
302 for(j
=0; (j
<bbb
[ib
].n
); j
++)
303 if (bbb
[ib
].aa
[j
] == i
)
306 gmx_fatal(FARGS
,"Bond inconsistency (%d not in list of %d)!\n",i
,ib
);
307 for( ; (j
<bbb
[ib
].n
-1); j
++)
308 bbb
[ib
].aa
[j
] = bbb
[ib
].aa
[j
+1];
316 for(i
=j
=0; (i
<a
->nr
); i
++) {
318 copy_rvec(x
[i
],x
[j
]);
322 fprintf(stderr
,"Kicking out %d carbon atoms (out of %d)\n",
328 bbb
= mk_bonds(a
->nr
,x
,odist
,bPBC
,box
);
329 for(i
=0; (i
<a
->nr
); i
++) {
332 a
->atomname
[i
] = put_symtab(symtab
,"C");
335 a
->atomname
[i
] = put_symtab(symtab
,"CH1");
338 a
->atomname
[i
] = put_symtab(symtab
,"CH2");
341 gmx_fatal(FARGS
,"This atom (%d) has %d bonds only",i
,bbb
[i
].n
);
347 static real
calc_ener(real c6
,real c12
,rvec dx
,tensor vir
)
353 e
= c12
*pow(r
,-12.0) - c6
*pow(r
,-6.0);
354 f
= 12*c12
*pow(r
,-14.0) - 6*c6
*pow(r
,-8.0);
355 for(m
=0; (m
<DIM
); m
++)
356 for(n
=0; (n
<DIM
); n
++)
357 vir
[m
][n
] -= 0.5*f
*dx
[m
]*dx
[n
];
362 static int read_rel_coords(char *fn
,rvec
**xx
,int natmol
)
368 nline
= get_file(fn
,&strings
);
369 printf("Read %d lines from %s\n",nline
,fn
);
370 snew(*xx
,nline
*natmol
);
371 for(i
=0; (i
<nline
); i
++) {
372 if (sscanf(strings
[i
],"%lf%lf%lf",&x
,&y
,&z
) != 3)
373 gmx_fatal(FARGS
,"Not enough arguments on line %d of file %s (should be 3)",i
,fn
);
374 (*xx
)[natmol
*i
][XX
] = x
;
375 (*xx
)[natmol
*i
][YY
] = y
;
376 (*xx
)[natmol
*i
][ZZ
] = z
;
381 void virial(FILE *fp
,bool bFull
,int nmol
,rvec x
[],matrix box
,real rcut
,
382 bool bYaw
,real q
[],bool bLJ
)
384 int i
,j
,im
,jm
,natmol
,ik
,jk
,m
,ninter
;
385 rvec dx
,f
,ftot
,dvir
,vir
,pres
,xcmi
,xcmj
,*force
;
386 real dx6
,dx2
,dx1
,fscal
,c6
,c12
,vcoul
,v12
,v6
,vctot
,v12tot
,v6tot
;
390 fprintf(fp
,"%3s - %3s: %6s %6s %6s %6s %8s %8s %8s\n",
391 "ai","aj","dx","dy","dz","|d|","virx","viry","virz");
398 natmol
= bYaw
? 5 : 3;
399 snew(force
,nmol
*natmol
);
401 for(i
=0; (i
<nmol
); i
++) {
403 /* Center of geometry */
405 for(ik
=0; (ik
<natmol
); ik
++)
406 rvec_inc(xcmi
,x
[im
+ik
]);
407 for(m
=0; (m
<DIM
); m
++)
410 for(j
=i
+1; (j
<nmol
); j
++) {
412 /* Center of geometry */
414 for(jk
=0; (jk
<natmol
); jk
++)
415 rvec_inc(xcmj
,x
[jm
+jk
]);
416 for(m
=0; (m
<DIM
); m
++)
419 /* First check COM-COM distance */
420 pbc_dx(&pbc
,xcmi
,xcmj
,dx
);
421 if (norm(dx
) < rcut
) {
423 /* Neirest neighbour molecules! */
425 for(ik
=0; (ik
<natmol
); ik
++) {
426 for(jk
=0; (jk
<natmol
); jk
++) {
427 pbc_dx(&pbc
,x
[im
+ik
],x
[jm
+jk
],dx
);
430 vcoul
= q
[ik
]*q
[jk
]*ONE_4PI_EPS0
/dx1
;
435 c6
= yaw_lj
[ik
][2*jk
];
436 c12
= yaw_lj
[ik
][2*jk
+1];
439 c6
= spc_lj
[ik
][2*jk
];
440 c12
= spc_lj
[ik
][2*jk
+1];
447 fscal
= (vcoul
+12*v12
-6*v6
)/dx2
;
451 for(m
=0; (m
<DIM
); m
++) {
453 dvir
[m
] -= 0.5*dx
[m
]*f
[m
];
455 rvec_inc(force
[ik
+im
],f
);
456 rvec_dec(force
[jk
+jm
],f
);
458 fprintf(fp,"%3s%4d-%3s%4d: %6.3f %6.3f %6.3f %6.3f"
459 " %8.3f %8.3f %8.3f\n",
460 watname[ik],im+ik,watname[jk],jm+jk,
461 dx[XX],dx[YY],dx[ZZ],norm(dx),
462 dvir[XX],dvir[YY],dvir[ZZ]);*/
466 fprintf(fp
,"%3s%4d-%3s%4d: "
467 " %8.3f %8.3f %8.3f\n",
468 "SOL",i
,"SOL",j
,dvir
[XX
],dvir
[YY
],dvir
[ZZ
]);
473 fprintf(fp
,"There were %d interactions between the %d molecules (%.2f %%)\n",
474 ninter
,nmol
,(real
)ninter
/(0.5*nmol
*(nmol
-1)));
475 fprintf(fp
,"Vcoul: %10.4e V12: %10.4e V6: %10.4e Vtot: %10.4e (kJ/mol)\n",
476 vctot
/nmol
,v12tot
/nmol
,v6tot
/nmol
,(vctot
+v12tot
+v6tot
)/nmol
);
477 pr_rvec(fp
,0,"vir ",vir
,DIM
,TRUE
);
479 for(m
=0; (m
<DIM
); m
++)
480 pres
[m
] = -2*PRESFAC
/(det(box
))*vir
[m
];
481 pr_rvec(fp
,0,"pres",pres
,DIM
,TRUE
);
482 pr_rvecs(fp
,0,"force",force
,natmol
*nmol
);
488 int main(int argc
,char *argv
[])
490 static char *desc
[] = {
491 "mkice generates an ice crystal in the Ih crystal form which is the",
492 "most stable form. The rectangular unitcell contains eight molecules",
493 "and all oxygens are tetrahedrally coordinated.[PAR]",
494 "If an input file is given it is interpreted as a series of oxygen",
495 "coordinates the distance between which can be scaled by the odist flag.",
496 "The program then adds hydrogens to the oxygens in random orientation",
497 "but with proper OH distances and HOH angle. This feature allows to",
498 "build water clusters based on oxygen coordinates only."
500 static int nx
=1,ny
=1,nz
=1;
501 static bool bYaw
=FALSE
,bLJ
=TRUE
,bFull
=TRUE
,bSeries
=FALSE
;
502 static bool bOrdered
=TRUE
,bDiamond
=FALSE
,bPBC
=TRUE
;
503 static real rcut
=0.3,odist
=0.274,hdist
=0.09572;
505 { "-nx", FALSE
, etINT
, {&nx
}, "nx" },
506 { "-ny", FALSE
, etINT
, {&ny
}, "ny" },
507 { "-nz", FALSE
, etINT
, {&nz
}, "nz" },
508 { "-yaw", FALSE
, etBOOL
, {&bYaw
},
509 "Generate virtual sites and shell positions" },
510 { "-lj", FALSE
, etBOOL
, {&bLJ
},
511 "Use LJ as well as coulomb for virial calculation" },
512 { "-rcut", FALSE
,etREAL
, {&rcut
},"Cut-off for virial calculations" },
513 { "-full", FALSE
,etBOOL
, {&bFull
},"Full virial output" },
514 { "-odist", FALSE
, etREAL
, {&odist
}, "Distance (nm) between oxygens" },
515 { "-hdist", FALSE
, etREAL
, {&hdist
}, "Bondlength (nm) for OH bond" },
516 { "-diamond",FALSE
,etBOOL
, {&bDiamond
}, "Make a diamond instead" },
517 { "-pbc", FALSE
, etBOOL
, {&bPBC
}, "Make a periodic diamond" },
518 { "-order", FALSE
,etBOOL
, {&bOrdered
}, "Make a proton-ordered ice lattice" },
519 { "-series",FALSE
, etBOOL
, {&bSeries
},
520 "Do a series of virial calculations with different cut-off (from 0.3 up till the specified one)" }
523 { efSTO
, "-p", "ice", ffWRITE
},
524 { efSTO
, "-c", NULL
, ffOPTRD
},
525 { efDAT
, "-f", NULL
, ffOPTRD
},
526 { efTRN
, "-o", "ice", ffOPTWR
}
528 #define NFILE asize(fnm)
532 int i
,j
,k
,n
,nmax
,m
,natom
,natmol
;
539 CopyRight(stdout
,argv
[0]);
540 parse_common_args(&argc
,argv
,0,NFILE
,fnm
,asize(pa
),pa
,asize(desc
),
543 fprintf(debug
,"nx = %3d, ny = %3d, nz = %3d\n",nx
,ny
,nz
);
544 fprintf(debug
,"YAW = %3s, LJ = %3s, rcut = %g\n",yesno_names
[bYaw
],
545 yesno_names
[bLJ
],rcut
);
555 if (opt2bSet("-f",NFILE
,fnm
)) {
556 natom
= read_rel_coords(opt2fn("-f",NFILE
,fnm
),&xx
,natmol
);
561 nmax
= natom
*nx
*ny
*nz
;
565 init_t_atoms(pdba
,nmax
,TRUE
);
567 open_symtab(&symtab
);
568 for(n
=0; (n
<nmax
); n
++) {
569 pdba
->pdbinfo
[n
].type
= epdbATOM
;
570 pdba
->pdbinfo
[n
].atomnr
= 1+n
;
571 pdba
->atom
[n
].resnr
= 1+(n
/natmol
);
572 pdba
->atomname
[n
] = put_symtab(&symtab
,
573 bDiamond
? diamname
[(n
% natmol
)] : watname
[(n
% natmol
)]);
575 pdba
->resname
[n
] = put_symtab(&symtab
,"DIA");
577 pdba
->resname
[n
] = put_symtab(&symtab
,"SOL");
578 sprintf(pdba
->pdbinfo
[n
].pdbresnr
,"%d",n
);
579 pdba
->atom
[n
].chain
= ' ';
582 /* Generate the unit cell */
584 unitcell_d(xx
,box
,odist
);
585 else if (opt2bSet("-f",NFILE
,fnm
)) {
586 random_h_coords(natmol
,natom
/natmol
,xx
,box
,bYaw
,odist
,hdist
);
589 unitcell(xx
,box
,bYaw
,odist
,hdist
);
592 boxje
[XX
][XX
] = box
[XX
];
593 boxje
[YY
][YY
] = box
[YY
];
594 boxje
[ZZ
][ZZ
] = box
[ZZ
];
597 for(i
=0; (i
<nx
); i
++) {
599 for(j
=0; (j
<ny
); j
++) {
601 for(k
=0; (k
<nz
); k
++) {
603 for(m
=0; (m
<natom
); m
++,n
++) {
604 if ((!bOrdered
&& ((m
% natmol
) == 0)) || bOrdered
)
605 rvec_add(xx
[n
% natom
],tmp
,xx
[n
]);
614 boxje
[XX
][XX
] = box
[XX
]*nx
;
615 boxje
[YY
][YY
] = box
[YY
]*ny
;
616 boxje
[ZZ
][ZZ
] = box
[ZZ
]*nz
;
618 printf("Crystal: %10.5f %10.5f %10.5f\n",
619 nx
*box
[XX
],ny
*box
[YY
],nz
*box
[ZZ
]);
621 if (debug
&& !bDiamond
) {
623 for(i
=3; (i
<=10*rcut
); i
++) {
624 fprintf(debug
,"This is with rcut = %g\n",i
*0.1);
625 virial(debug
,bFull
,nmax
/natmol
,xx
,boxje
,
626 0.1*i
,bYaw
,bYaw
? qyaw
: qspc
,bLJ
);
629 virial(debug
,bFull
,nmax
/natmol
,xx
,boxje
,
630 rcut
,bYaw
,bYaw
? qyaw
: qspc
,bLJ
);
634 mk_diamond(pdba
,xx
,odist
,&symtab
,bPBC
,boxje
);
636 fn
= ftp2fn(efSTO
,NFILE
,fnm
);
637 if (fn2ftp(fn
) == efPDB
) {
640 fprintf(fp
,"HEADER This is a *diamond*\n");
642 fprintf(fp
,"HEADER A beautiful Ice Ih crystal\n");
643 fprintf(fp
,"REMARK Generated by mkice with the following options:\n"
644 "REMARK nx = %d, ny = %d, nz = %d, odist = %g, hdist = %g\n",
645 nx
,ny
,nz
,odist
,hdist
);
647 write_pdbfile(fp
,quote
,pdba
,xx
,boxje
,' ',-1);
652 write_sto_conf(fn
,quote
,pdba
,xx
,NULL
,boxje
);
655 if (ftp2bSet(efTRN
,NFILE
,fnm
))
656 write_trn(ftp2fn(efTRN
,NFILE
,fnm
),0,0,0,boxje
,nmax
,xx
,NULL
,NULL
);