4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Copyright (c) 1991-2001, University of Groningen, The Netherlands
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * If you want to redistribute modifications, please consider that
18 * scientific software is very special. Version control is crucial -
19 * bugs must be traceable. We will be happy to consider code for
20 * inclusion in the official distribution, but derived work must not
21 * be called official GROMACS. Details are found in the README & COPYING
22 * files - if they are missing, get the official version at www.gromacs.org.
24 * To help us fund GROMACS development, we humbly ask that you cite
25 * the papers on the package - you can find them in the top README file.
27 * For more info, check our website at http://www.gromacs.org
30 * Great Red Owns Many ACres of Sand
53 #define DCONS 0.117265878
59 static char *watname
[] = { "OW ", "HW1", "HW2", "DW", "SW" };
60 static char *diamname
[] = { "C1", "H2", "H3", "H4", "H5", "H2", "H3", "H4", "H5" };
61 static real qspc
[] = { -0.82, 0.41, 0.41 };
62 static real qyaw
[] = { 1.24588, 0.62134, 0.62134, 0.0, -2.48856 };
63 static real spc_lj
[3][6] = {
64 { 2.6171e-3, 2.6331e-6, 0, 0, 0, 0 },
71 static real yaw_lj
[5][10] = {
72 { 0, 0, 0, 0, 0, 0, 0, 0, 0, COS
},
73 { 0, 0, 0, CHH
, 0, CHH
, 0, 0, 0, CHS
},
74 { 0, 0, 0, CHH
, 0, CHH
, 0, 0, 0, CHS
},
75 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
76 { 0, COS
, 0, CHS
, 0, CHS
, 0, 0, 2.6e-3, 0 }
79 void unitcell(rvec x
[],rvec box
,bool bYaw
,real odist
,real hdist
)
83 #define cy2 0.94280904
88 { 0, 0, 1 }, /* H relative to Oxygen */
90 { cx
, cy
, -cz
}, /* O2 */
91 { 0, 0, -1 }, /* H relative to Oxygen */
93 { cx
, cy
+cy2
, 0 }, /* O3 */
94 { -cx
, cy
, -cz
}, /* H relative to Oxygen */
96 { 0, 2*cy
+cy2
, -cz
}, /* O4 */
97 {-cx
,-cy
, +cz
}, /* H relative to Oxygen */
100 {-cx
, cy
, +cz
}, /* H relative to Oxygen */
102 { cx
, cy
, 1+cz
}, /* O6 */
103 { -cx
, -cy
, -cz
}, /* H relative to Oxygen */
105 { cx
, cy
+cy2
, 1 }, /* O7 */
106 { 0, 0, -1 }, /* H relative to Oxygen */
108 { 0, 2*cy
+cy2
,1+cz
}, /* O8 */
109 { 0, 0, 1 }, /* H relative to Oxygen */
116 for(i
=0; (i
<8); i
++) {
122 svmul(odist
,xx
[iin
],x
[iout
]);
123 svmul(-0.82,x
[iout
],t2
);
125 for(j
=1; (j
<=2); j
++) {
126 svmul(hdist
,xx
[iin
+j
],tmp
);
127 rvec_add(x
[iout
],tmp
,x
[iout
+j
]);
128 svmul(0.41,x
[iout
+j
],t2
);
132 for(m
=0; (m
<DIM
); m
++)
133 x
[iout
+3][m
] = x
[iout
+4][m
] =
134 (1-2*DCONS
)*x
[iout
][m
]+DCONS
*(x
[iout
+1][m
]+x
[iout
+2][m
]);
138 box
[YY
] = 2*(cy2
+cy
);
140 for(i
=0; (i
<DIM
); i
++)
143 printf("Unitcell: %10.5f %10.5f %10.5f\n",box
[XX
],box
[YY
],box
[ZZ
]);
144 printf("Dipole: %10.5f %10.5f %10.5f (e nm)\n",dip
[XX
],dip
[YY
],dip
[ZZ
]);
147 void unitcell_d(rvec x
[],rvec box
,real odist
)
150 { 0, 0, 0 }, /* C1 */
151 { cx
, cy
, -cz
}, /* C2 */
152 { cx
, cy
+cy2
, 0 }, /* C3 */
153 { 0, 2*cy
+cy2
, -cz
}, /* C4 */
154 { 0, 0, 1 }, /* C5 */
155 { cx
, cy
, 1+cz
}, /* C6 */
156 { cx
, cy
+cy2
, 1 }, /* C7 */
157 { 0, 2*cy
+cy2
,1+cz
}, /* C8 */
160 { 0, 0, 1 }, /* H relative to C */
169 for(i
=0; (i
<8); i
++) {
172 svmul(odist
,cc
[iin
],x
[iout
]);
175 box
[YY
] = 2*(cy2
+cy
);
177 for(i
=0; (i
<DIM
); i
++)
180 printf("Unitcell: %10.5f %10.5f %10.5f\n",box
[XX
],box
[YY
],box
[ZZ
]);
183 static t_bbb
*mk_bonds(int natoms
,rvec x
[],real odist
,
184 bool bPBC
,matrix box
)
186 real od2
= odist
*odist
+1e-5;
194 for(i
=0; (i
<natoms
); i
++) {
195 for(j
=i
+1; (j
<natoms
); j
++) {
197 pbc_dx(x
[i
],x
[j
],dx
);
199 rvec_sub(x
[i
],x
[j
],dx
);
200 if (iprod(dx
,dx
) <= od2
) {
201 bbb
[i
].aa
[bbb
[i
].n
++] = j
;
202 bbb
[j
].aa
[bbb
[j
].n
++] = i
;
207 #define PRB(nn) (bbb[(i)].n >= (nn)) ? bbb[i].aa[nn-1] : -1
208 for(i
=0; (i
<natoms
); i
++)
209 fprintf(debug
,"bonds from %3d: %d %d %d %d\n",
210 i
,PRB(1),PRB(2),PRB(3),PRB(4));
215 static void mk_diamond(t_atoms
*a
,rvec x
[],real odist
,t_symtab
*symtab
,
216 bool bPBC
,matrix box
)
219 int i
,ib
,j
,k
,l
,m
,nrm
=0;
226 bbb
= mk_bonds(a
->nr
,x
,odist
,bPBC
,box
);
228 for(i
=0; (i
<a
->nr
); i
++) {
230 for(k
=0; (k
<bbb
[i
].n
); k
++) {
232 for(j
=0; (j
<bbb
[ib
].n
); j
++)
233 if (bbb
[ib
].aa
[j
] == i
)
236 fatal_error(0,"Bond inconsistency (%d not in list of %d)!\n",i
,ib
);
237 for( ; (j
<bbb
[ib
].n
-1); j
++)
238 bbb
[ib
].aa
[j
] = bbb
[ib
].aa
[j
+1];
246 for(i
=j
=0; (i
<a
->nr
); i
++) {
248 copy_rvec(x
[i
],x
[j
]);
252 fprintf(stderr
,"Kicking out %d carbon atoms (out of %d)\n",
258 bbb
= mk_bonds(a
->nr
,x
,odist
,bPBC
,box
);
259 for(i
=0; (i
<a
->nr
); i
++) {
262 a
->atomname
[i
] = put_symtab(symtab
,"C");
265 a
->atomname
[i
] = put_symtab(symtab
,"CH1");
268 a
->atomname
[i
] = put_symtab(symtab
,"CH2");
271 fatal_error(0,"This atom (%d) has %d bonds only",i
,bbb
[i
].n
);
277 static real
calc_ener(real c6
,real c12
,rvec dx
,tensor vir
)
283 e
= c12
*pow(r
,-12.0) - c6
*pow(r
,-6.0);
284 f
= 12*c12
*pow(r
,-14.0) - 6*c6
*pow(r
,-8.0);
285 for(m
=0; (m
<DIM
); m
++)
286 for(n
=0; (n
<DIM
); n
++)
287 vir
[m
][n
] -= 0.5*f
*dx
[m
]*dx
[n
];
292 void virial(FILE *fp
,bool bFull
,int nmol
,rvec x
[],matrix box
,real rcut
,
293 bool bYaw
,real q
[],bool bLJ
)
295 int i
,j
,im
,jm
,natmol
,ik
,jk
,m
,ninter
;
296 rvec dx
,f
,ftot
,dvir
,vir
,pres
,xcmi
,xcmj
,*force
;
297 real dx6
,dx2
,dx1
,fscal
,c6
,c12
,vcoul
,v12
,v6
,vctot
,v12tot
,v6tot
;
300 fprintf(fp
,"%3s - %3s: %6s %6s %6s %6s %8s %8s %8s\n",
301 "ai","aj","dx","dy","dz","|d|","virx","viry","virz");
308 natmol
= bYaw
? 5 : 3;
309 snew(force
,nmol
*natmol
);
311 for(i
=0; (i
<nmol
); i
++) {
313 /* Center of geometry */
315 for(ik
=0; (ik
<natmol
); ik
++)
316 rvec_inc(xcmi
,x
[im
+ik
]);
317 for(m
=0; (m
<DIM
); m
++)
320 for(j
=i
+1; (j
<nmol
); j
++) {
322 /* Center of geometry */
324 for(jk
=0; (jk
<natmol
); jk
++)
325 rvec_inc(xcmj
,x
[jm
+jk
]);
326 for(m
=0; (m
<DIM
); m
++)
329 /* First check COM-COM distance */
330 pbc_dx(xcmi
,xcmj
,dx
);
331 if (norm(dx
) < rcut
) {
333 /* Neirest neighbour molecules! */
335 for(ik
=0; (ik
<natmol
); ik
++) {
336 for(jk
=0; (jk
<natmol
); jk
++) {
337 pbc_dx(x
[im
+ik
],x
[jm
+jk
],dx
);
340 vcoul
= q
[ik
]*q
[jk
]*ONE_4PI_EPS0
/dx1
;
345 c6
= yaw_lj
[ik
][2*jk
];
346 c12
= yaw_lj
[ik
][2*jk
+1];
349 c6
= spc_lj
[ik
][2*jk
];
350 c12
= spc_lj
[ik
][2*jk
+1];
357 fscal
= (vcoul
+12*v12
-6*v6
)/dx2
;
361 for(m
=0; (m
<DIM
); m
++) {
363 dvir
[m
] -= 0.5*dx
[m
]*f
[m
];
365 rvec_inc(force
[ik
+im
],f
);
366 rvec_dec(force
[jk
+jm
],f
);
368 fprintf(fp,"%3s%4d-%3s%4d: %6.3f %6.3f %6.3f %6.3f"
369 " %8.3f %8.3f %8.3f\n",
370 watname[ik],im+ik,watname[jk],jm+jk,
371 dx[XX],dx[YY],dx[ZZ],norm(dx),
372 dvir[XX],dvir[YY],dvir[ZZ]);*/
376 fprintf(fp
,"%3s%4d-%3s%4d: "
377 " %8.3f %8.3f %8.3f\n",
378 "SOL",i
,"SOL",j
,dvir
[XX
],dvir
[YY
],dvir
[ZZ
]);
383 fprintf(fp
,"There were %d interactions between the %d molecules (%.2f %%)\n",
384 ninter
,nmol
,(real
)ninter
/(0.5*nmol
*(nmol
-1)));
385 fprintf(fp
,"Vcoul: %10.4e V12: %10.4e V6: %10.4e Vtot: %10.4e (kJ/mol)\n",
386 vctot
/nmol
,v12tot
/nmol
,v6tot
/nmol
,(vctot
+v12tot
+v6tot
)/nmol
);
387 pr_rvec(fp
,0,"vir ",vir
,DIM
);
389 for(m
=0; (m
<DIM
); m
++)
390 pres
[m
] = -2*PRESFAC
/(det(box
))*vir
[m
];
391 pr_rvec(fp
,0,"pres",pres
,DIM
);
392 pr_rvecs(fp
,0,"force",force
,natmol
*nmol
);
396 static real
calc_mass(t_atoms
*atoms
,bool bGetMass
)
402 for(i
=0; (i
<atoms
->nr
); i
++) {
404 atoms
->atom
[i
].m
= get_mass(*atoms
->resname
[atoms
->atom
[i
].resnr
],
405 *atoms
->atomname
[i
]);
406 tmass
+= atoms
->atom
[i
].m
;
412 static real
density(t_atoms
*atoms
,matrix box
)
418 tm
= calc_mass(atoms
,TRUE
);
420 return (tm
*AMU
)/(vol
*NANO
*NANO
*NANO
);
423 int main(int argc
,char *argv
[])
425 static char *desc
[] = {
426 "mkice generates an ice crystal in the Ih crystal form which is the",
427 "most stable form. The rectangular unitcell contains eight molecules",
428 "and all oxygens are tetrahedrally coordinated."
430 static int nx
=1,ny
=1,nz
=1;
431 static bool bYaw
=FALSE
,bLJ
=TRUE
,bFull
=TRUE
,bSeries
=FALSE
;
432 static bool bOrdered
=TRUE
,bDiamond
=FALSE
,bPBC
=TRUE
;
433 static real rcut
=0.3,odist
=0.274,hdist
=0.09572;
435 { "-nx", FALSE
, etINT
, {&nx
}, "nx" },
436 { "-ny", FALSE
, etINT
, {&ny
}, "ny" },
437 { "-nz", FALSE
, etINT
, {&nz
}, "nz" },
438 { "-yaw", FALSE
, etBOOL
, {&bYaw
},
439 "Generate dummies and shell positions" },
440 { "-lj", FALSE
, etBOOL
, {&bLJ
},
441 "Use LJ as well as coulomb for virial calculation" },
442 { "-rcut", FALSE
,etREAL
, {&rcut
},"Cut-off for virial calculations" },
443 { "-full", FALSE
,etBOOL
, {&bFull
},"Full virial output" },
444 { "-odist", FALSE
, etREAL
, {&odist
}, "Distance (nm) between oxygens" },
445 { "-hdist", FALSE
, etREAL
, {&hdist
}, "Bondlength (nm) for OH bond" },
446 { "-diamond",FALSE
,etBOOL
, {&bDiamond
}, "Make a diamond instead" },
447 { "-pbc", FALSE
, etBOOL
, {&bPBC
}, "Make a pariodic diamond" },
448 { "-order", FALSE
,etBOOL
, {&bOrdered
}, "Make a proton-ordered ice lattice" },
449 { "-series",FALSE
, etBOOL
, {&bSeries
},
450 "Do a series of virial calculations with different cut-off (from 0.3 up till the specified one)" }
453 { efSTO
, "-p", "ice", ffWRITE
},
454 { efSTO
, "-c", NULL
, ffOPTRD
},
455 { efTRN
, "-o", "ice", ffOPTWR
}
457 #define NFILE asize(fnm)
461 int i
,j
,k
,n
,nmax
,m
,natom
,natmol
;
468 CopyRight(stdout
,argv
[0]);
469 parse_common_args(&argc
,argv
,0,NFILE
,fnm
,asize(pa
),pa
,asize(desc
),
472 fprintf(debug
,"nx = %3d, ny = %3d, nz = %3d\n",nx
,ny
,nz
);
473 fprintf(debug
,"YAW = %3s, LJ = %3s, rcut = %g\n",yesno_names
[bYaw
],
474 yesno_names
[bLJ
],rcut
);
484 nmax
= natom
*nx
*ny
*nz
;
487 init_t_atoms(pdba
,nmax
,TRUE
);
489 open_symtab(&symtab
);
490 for(n
=0; (n
<nmax
); n
++) {
491 pdba
->pdbinfo
[n
].type
= epdbATOM
;
492 pdba
->pdbinfo
[n
].atomnr
= n
;
493 pdba
->atom
[n
].resnr
= n
/natmol
;
494 pdba
->atomname
[n
] = put_symtab(&symtab
,
495 bDiamond
? diamname
[(n
% natmol
)] : watname
[(n
% natmol
)]);
497 pdba
->resname
[n
] = put_symtab(&symtab
,"DIA");
499 pdba
->resname
[n
] = put_symtab(&symtab
,"SOL");
500 sprintf(pdba
->pdbinfo
[n
].pdbresnr
,"%d",n
);
501 pdba
->atom
[n
].chain
= ' ';
504 /* Generate the unit cell */
506 unitcell_d(xx
,box
,odist
);
508 unitcell(xx
,box
,bYaw
,odist
,hdist
);
511 boxje
[XX
][XX
] = box
[XX
];
512 boxje
[YY
][YY
] = box
[YY
];
513 boxje
[ZZ
][ZZ
] = box
[ZZ
];
516 for(i
=0; (i
<nx
); i
++) {
518 for(j
=0; (j
<ny
); j
++) {
520 for(k
=0; (k
<nz
); k
++) {
522 for(m
=0; (m
<natom
); m
++,n
++) {
523 if ((!bOrdered
&& ((m
% natmol
) == 0)) || bOrdered
)
524 rvec_add(xx
[n
% natom
],tmp
,xx
[n
]);
533 boxje
[XX
][XX
] = box
[XX
]*nx
;
534 boxje
[YY
][YY
] = box
[YY
]*ny
;
535 boxje
[ZZ
][ZZ
] = box
[ZZ
]*nz
;
537 printf("Crystal: %10.5f %10.5f %10.5f\n",
538 nx
*box
[XX
],ny
*box
[YY
],nz
*box
[ZZ
]);
540 if (debug
&& !bDiamond
) {
542 for(i
=3; (i
<=10*rcut
); i
++) {
543 fprintf(debug
,"This is with rcut = %g\n",i
*0.1);
544 virial(debug
,bFull
,nmax
/natmol
,xx
,boxje
,
545 0.1*i
,bYaw
,bYaw
? qyaw
: qspc
,bLJ
);
548 virial(debug
,bFull
,nmax
/natmol
,xx
,boxje
,
549 rcut
,bYaw
,bYaw
? qyaw
: qspc
,bLJ
);
553 mk_diamond(pdba
,xx
,odist
,&symtab
,bPBC
,boxje
);
555 fn
= ftp2fn(efSTO
,NFILE
,fnm
);
556 if (fn2ftp(fn
) == efPDB
) {
559 fprintf(fp
,"HEADER This is a *diamond*\n");
561 fprintf(fp
,"HEADER A beautiful Ice Ih crystal\n");
562 fprintf(fp
,"REMARK Generated by mkice with the following options:\n"
563 "REMARK nx = %d, ny = %d, nz = %d, odist = %g, hdist = %g\n",
564 nx
,ny
,nz
,odist
,hdist
);
565 fprintf(fp
,"REMARK Density of this crystal is %g (g/l)\n",
566 density(pdba
,boxje
));
567 write_pdbfile(fp
,bromacs(quote
,255),pdba
,xx
,boxje
,' ',-1);
571 write_sto_conf(fn
,bromacs(quote
,255),pdba
,xx
,NULL
,boxje
);
574 if (ftp2bSet(efTRN
,NFILE
,fnm
))
575 write_trn(ftp2fn(efTRN
,NFILE
,fnm
),0,0,0,boxje
,nmax
,xx
,NULL
,NULL
);