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_mkice_c = "$Id$";
51 #define DCONS 0.117265878
57 static char *watname[] = { "OW ", "HW1", "HW2", "DW", "SW" };
58 static char *diamname[] = { "C1", "H2", "H3", "H4", "H5", "H2", "H3", "H4", "H5" };
59 static real qspc[] = { -0.82, 0.41, 0.41 };
60 static real qyaw[] = { 1.24588, 0.62134, 0.62134, 0.0, -2.48856 };
61 static real spc_lj[3][6] = {
62 { 2.6171e-3, 2.6331e-6, 0, 0, 0, 0 },
69 static real yaw_lj[5][10] = {
70 { 0, 0, 0, 0, 0, 0, 0, 0, 0, COS },
71 { 0, 0, 0, CHH, 0, CHH, 0, 0, 0, CHS },
72 { 0, 0, 0, CHH, 0, CHH, 0, 0, 0, CHS },
73 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
74 { 0, COS, 0, CHS, 0, CHS, 0, 0, 2.6e-3, 0 }
77 void unitcell(rvec x[],rvec box,bool bYaw,real odist,real hdist)
81 #define cy2 0.94280904
86 { 0, 0, 1 }, /* H relative to Oxygen */
88 { cx, cy, -cz }, /* O2 */
89 { 0, 0, -1 }, /* H relative to Oxygen */
91 { cx, cy+cy2, 0 }, /* O3 */
92 { -cx, cy, -cz }, /* H relative to Oxygen */
94 { 0, 2*cy+cy2, -cz }, /* O4 */
95 {-cx,-cy, +cz }, /* H relative to Oxygen */
98 {-cx, cy, +cz }, /* H relative to Oxygen */
100 { cx, cy, 1+cz }, /* O6 */
101 { -cx, -cy, -cz }, /* H relative to Oxygen */
103 { cx, cy+cy2, 1 }, /* O7 */
104 { 0, 0, -1 }, /* H relative to Oxygen */
106 { 0, 2*cy+cy2,1+cz }, /* O8 */
107 { 0, 0, 1 }, /* H relative to Oxygen */
114 for(i=0; (i<8); i++) {
120 svmul(odist,xx[iin],x[iout]);
121 svmul(-0.82,x[iout],t2);
123 for(j=1; (j<=2); j++) {
124 svmul(hdist,xx[iin+j],tmp);
125 rvec_add(x[iout],tmp,x[iout+j]);
126 svmul(0.41,x[iout+j],t2);
130 for(m=0; (m<DIM); m++)
131 x[iout+3][m] = x[iout+4][m] =
132 (1-2*DCONS)*x[iout][m]+DCONS*(x[iout+1][m]+x[iout+2][m]);
136 box[YY] = 2*(cy2+cy);
138 for(i=0; (i<DIM); i++)
141 printf("Unitcell: %10.5f %10.5f %10.5f\n",box[XX],box[YY],box[ZZ]);
142 printf("Dipole: %10.5f %10.5f %10.5f (e nm)\n",dip[XX],dip[YY],dip[ZZ]);
145 void unitcell_d(rvec x[],rvec box,real odist)
148 { 0, 0, 0 }, /* C1 */
149 { cx, cy, -cz }, /* C2 */
150 { cx, cy+cy2, 0 }, /* C3 */
151 { 0, 2*cy+cy2, -cz }, /* C4 */
152 { 0, 0, 1 }, /* C5 */
153 { cx, cy, 1+cz }, /* C6 */
154 { cx, cy+cy2, 1 }, /* C7 */
155 { 0, 2*cy+cy2,1+cz }, /* C8 */
158 { 0, 0, 1 }, /* H relative to C */
167 for(i=0; (i<8); i++) {
170 svmul(odist,cc[iin],x[iout]);
173 box[YY] = 2*(cy2+cy);
175 for(i=0; (i<DIM); i++)
178 printf("Unitcell: %10.5f %10.5f %10.5f\n",box[XX],box[YY],box[ZZ]);
181 static t_bbb *mk_bonds(int natoms,rvec x[],real odist)
183 real od2 = odist*odist+1e-5;
189 for(i=0; (i<natoms); i++) {
190 for(j=i+1; (j<natoms); j++) {
191 rvec_sub(x[i],x[j],dx);
192 if (iprod(dx,dx) <= od2) {
193 bbb[i].aa[bbb[i].n++] = j;
194 bbb[j].aa[bbb[j].n++] = i;
199 #define PRB(nn) (bbb[(i)].n >= (nn)) ? bbb[i].aa[nn-1] : -1
200 for(i=0; (i<natoms); i++)
201 fprintf(debug,"bonds from %3d: %d %d %d %d\n",
202 i,PRB(1),PRB(2),PRB(3),PRB(4));
207 static void mk_diamond(t_atoms *a,rvec x[],real odist,t_symtab *symtab)
210 int i,ib,j,k,l,m,nrm=0;
217 bbb = mk_bonds(a->nr,x,odist);
219 for(i=0; (i<a->nr); i++) {
221 for(k=0; (k<bbb[i].n); k++) {
223 for(j=0; (j<bbb[ib].n); j++)
224 if (bbb[ib].aa[j] == i)
227 fatal_error(0,"Bond inconsistency (%d not in list of %d)!\n",i,ib);
228 for( ; (j<bbb[ib].n-1); j++)
229 bbb[ib].aa[j] = bbb[ib].aa[j+1];
237 for(i=j=0; (i<a->nr); i++) {
239 copy_rvec(x[i],x[j]);
243 fprintf(stderr,"Kicking out %d carbon atoms (out of %d)\n",
249 bbb = mk_bonds(a->nr,x,odist);
250 for(i=0; (i<a->nr); i++) {
253 a->atomname[i] = put_symtab(symtab,"C");
256 a->atomname[i] = put_symtab(symtab,"CH1");
259 a->atomname[i] = put_symtab(symtab,"CH2");
262 fatal_error(0,"This atom (%d) has %d bonds only",i,bbb[i].n);
268 static real calc_ener(real c6,real c12,rvec dx,tensor vir)
274 e = c12*pow(r,-12.0) - c6*pow(r,-6.0);
275 f = 12*c12*pow(r,-14.0) - 6*c6*pow(r,-8.0);
276 for(m=0; (m<DIM); m++)
277 for(n=0; (n<DIM); n++)
278 vir[m][n] -= 0.5*f*dx[m]*dx[n];
283 void virial(FILE *fp,bool bFull,int nmol,rvec x[],matrix box,real rcut,
284 bool bYaw,real q[],bool bLJ)
286 int i,j,im,jm,natmol,ik,jk,m,ninter;
287 rvec dx,f,ftot,dvir,vir,pres,xcmi,xcmj,*force;
288 real dx6,dx2,dx1,fscal,c6,c12,vcoul,v12,v6,vctot,v12tot,v6tot;
291 /* Initiate the periodic boundary conditions. Set bTruncOct to
292 * TRUE when using a truncated octahedron box.
294 fprintf(fp,"%3s - %3s: %6s %6s %6s %6s %8s %8s %8s\n",
295 "ai","aj","dx","dy","dz","|d|","virx","viry","virz");
302 natmol = bYaw ? 5 : 3;
303 snew(force,nmol*natmol);
305 for(i=0; (i<nmol); i++) {
307 /* Center of geometry */
309 for(ik=0; (ik<natmol); ik++)
310 rvec_inc(xcmi,x[im+ik]);
311 for(m=0; (m<DIM); m++)
314 for(j=i+1; (j<nmol); j++) {
316 /* Center of geometry */
318 for(jk=0; (jk<natmol); jk++)
319 rvec_inc(xcmj,x[jm+jk]);
320 for(m=0; (m<DIM); m++)
323 /* First check COM-COM distance */
324 pbc_dx(xcmi,xcmj,dx);
325 if (norm(dx) < rcut) {
327 /* Neirest neighbour molecules! */
329 for(ik=0; (ik<natmol); ik++) {
330 for(jk=0; (jk<natmol); jk++) {
331 pbc_dx(x[im+ik],x[jm+jk],dx);
334 vcoul = q[ik]*q[jk]*ONE_4PI_EPS0/dx1;
339 c6 = yaw_lj[ik][2*jk];
340 c12 = yaw_lj[ik][2*jk+1];
343 c6 = spc_lj[ik][2*jk];
344 c12 = spc_lj[ik][2*jk+1];
351 fscal = (vcoul+12*v12-6*v6)/dx2;
355 for(m=0; (m<DIM); m++) {
357 dvir[m] -= 0.5*dx[m]*f[m];
359 rvec_inc(force[ik+im],f);
360 rvec_dec(force[jk+jm],f);
362 fprintf(fp,"%3s%4d-%3s%4d: %6.3f %6.3f %6.3f %6.3f"
363 " %8.3f %8.3f %8.3f\n",
364 watname[ik],im+ik,watname[jk],jm+jk,
365 dx[XX],dx[YY],dx[ZZ],norm(dx),
366 dvir[XX],dvir[YY],dvir[ZZ]);*/
370 fprintf(fp,"%3s%4d-%3s%4d: "
371 " %8.3f %8.3f %8.3f\n",
372 "SOL",i,"SOL",j,dvir[XX],dvir[YY],dvir[ZZ]);
377 fprintf(fp,"There were %d interactions between the %d molecules (%.2f %%)\n",
378 ninter,nmol,(real)ninter/(0.5*nmol*(nmol-1)));
379 fprintf(fp,"Vcoul: %10.4e V12: %10.4e V6: %10.4e Vtot: %10.4e (kJ/mol)\n",
380 vctot/nmol,v12tot/nmol,v6tot/nmol,(vctot+v12tot+v6tot)/nmol);
381 pr_rvec(fp,0,"vir ",vir,DIM);
383 for(m=0; (m<DIM); m++)
384 pres[m] = -2*PRESFAC/(det(box))*vir[m];
385 pr_rvec(fp,0,"pres",pres,DIM);
386 pr_rvecs(fp,0,"force",force,natmol*nmol);
390 static real calc_mass(t_atoms *atoms,bool bGetMass)
396 for(i=0; (i<atoms->nr); i++) {
398 atoms->atom[i].m = get_mass(*atoms->resname[atoms->atom[i].resnr],
399 *atoms->atomname[i]);
400 tmass += atoms->atom[i].m;
406 static real density(t_atoms *atoms,matrix box)
412 tm = calc_mass(atoms,TRUE);
414 return (tm*AMU)/(vol*NANO*NANO*NANO);
417 int main(int argc,char *argv[])
419 static char *desc[] = {
420 "mkice generates an ice crystal in the Ih crystal form which is the",
421 "most stable form. The rectangular unitcell contains eight molecules",
422 "and all oxygens are tetrahedrally coordinated."
424 static int nx=1,ny=1,nz=1;
425 static bool bYaw=FALSE,bLJ=TRUE,bFull=TRUE,bSeries=FALSE;
426 static bool bOrdered=TRUE,bDiamond=FALSE;
427 static real rcut=0.3,odist=0.274,hdist=0.09572;
429 { "-nx", FALSE, etINT, {&nx}, "nx" },
430 { "-ny", FALSE, etINT, {&ny}, "ny" },
431 { "-nz", FALSE, etINT, {&nz}, "nz" },
432 { "-yaw", FALSE, etBOOL, {&bYaw},
433 "Generate dummies and shell positions" },
434 { "-lj", FALSE, etBOOL, {&bLJ},
435 "Use LJ as well as coulomb for virial calculation" },
436 { "-rcut", FALSE,etREAL, {&rcut},"Cut-off for virial calculations" },
437 { "-full", FALSE,etBOOL, {&bFull},"Full virial output" },
438 { "-odist", FALSE, etREAL, {&odist}, "Distance (nm) between oxygens" },
439 { "-hdist", FALSE, etREAL, {&hdist}, "Bondlength (nm) for OH bond" },
440 { "-diamond",FALSE,etBOOL, {&bDiamond}, "Make a diamond instead" },
441 { "-order", FALSE,etBOOL, {&bOrdered}, "Make a proton-ordered ice lattice" },
442 { "-series",FALSE, etBOOL, {&bSeries},
443 "Do a series of virial calculations with different cut-off (from 0.3 up till the specified one)" }
446 { efPDB, "-p", "ice", ffWRITE },
447 { efSTO, "-c", NULL, ffOPTRD },
448 { efTRN, "-o", "ice", ffOPTWR }
450 #define NFILE asize(fnm)
453 int i,j,k,n,nmax,m,natom,natmol;
460 CopyRight(stdout,argv[0]);
461 parse_common_args(&argc,argv,0,FALSE,NFILE,fnm,asize(pa),pa,asize(desc),
464 fprintf(debug,"nx = %3d, ny = %3d, nz = %3d\n",nx,ny,nz);
465 fprintf(debug,"YAW = %3s, LJ = %3s, rcut = %g\n",yesno_names[bYaw],
466 yesno_names[bLJ],rcut);
476 nmax = natom*nx*ny*nz;
479 init_t_atoms(pdba,nmax,TRUE);
481 open_symtab(&symtab);
482 for(n=0; (n<nmax); n++) {
483 pdba->pdbinfo[n].type = epdbATOM;
484 pdba->pdbinfo[n].atomnr = n;
485 pdba->atom[n].resnr = n/natmol;
486 pdba->atomname[n] = put_symtab(&symtab,
487 bDiamond ? diamname[(n % natmol)] : watname[(n % natmol)]);
489 pdba->resname[n] = put_symtab(&symtab,"DIA");
491 pdba->resname[n] = put_symtab(&symtab,"SOL");
492 sprintf(pdba->pdbinfo[n].pdbresnr,"%d",n);
493 pdba->atom[n].chain = ' ';
496 /* Generate the unit cell */
498 unitcell_d(xx,box,odist);
500 unitcell(xx,box,bYaw,odist,hdist);
503 boxje[XX][XX] = box[XX];
504 boxje[YY][YY] = box[YY];
505 boxje[ZZ][ZZ] = box[ZZ];
508 for(i=0; (i<nx); i++) {
510 for(j=0; (j<ny); j++) {
512 for(k=0; (k<nz); k++) {
514 for(m=0; (m<natom); m++,n++) {
515 if ((!bOrdered && ((m % natmol) == 0)) || bOrdered)
516 rvec_add(xx[n % natom],tmp,xx[n]);
525 boxje[XX][XX] = box[XX]*nx;
526 boxje[YY][YY] = box[YY]*ny;
527 boxje[ZZ][ZZ] = box[ZZ]*nz;
529 printf("Crystal: %10.5f %10.5f %10.5f\n",
530 nx*box[XX],ny*box[YY],nz*box[ZZ]);
532 if (debug && !bDiamond) {
534 for(i=3; (i<=10*rcut); i++) {
535 fprintf(debug,"This is with rcut = %g\n",i*0.1);
536 virial(debug,bFull,nmax/natmol,xx,boxje,
537 0.1*i,bYaw,bYaw ? qyaw : qspc,bLJ);
540 virial(debug,bFull,nmax/natmol,xx,boxje,
541 rcut,bYaw,bYaw ? qyaw : qspc,bLJ);
545 mk_diamond(pdba,xx,odist,&symtab);
547 fp = ftp2FILE(efPDB,NFILE,fnm,"w");
549 fprintf(fp,"HEADER This is a *diamond*\n");
551 fprintf(fp,"HEADER A beautiful Ice Ih crystal\n");
552 fprintf(fp,"REMARK Generated by mkice with the following options:\n"
553 "REMARK nx = %d, ny = %d, nz = %d, odist = %g, hdist = %g\n",
554 nx,ny,nz,odist,hdist);
555 fprintf(fp,"REMARK Density of this crystal is %g (g/l)\n",
556 density(pdba,boxje));
557 write_pdbfile(fp,bromacs(),pdba,xx,boxje,' ',-1);
560 if (ftp2bSet(efTRN,NFILE,fnm))
561 write_trn(ftp2fn(efTRN,NFILE,fnm),0,0,0,boxje,nmax,xx,NULL,NULL);