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
42 #include "gromacs/commandline/pargs.h"
44 #include "gromacs/utility/fatalerror.h"
45 #include "gromacs/fileio/pdbio.h"
47 #include "gromacs/utility/smalloc.h"
48 #include "gromacs/math/vec.h"
49 #include "gromacs/pbcutil/pbc.h"
50 #include "gromacs/math/units.h"
53 #include "gromacs/fileio/trnio.h"
54 #include "gromacs/topology/symtab.h"
55 #include "gromacs/fileio/strdb.h"
56 #include "gromacs/fileio/confio.h"
59 #define DCONS 0.117265878
65 static char *watname
[] = { "OW ", "HW1", "HW2", "DW", "SW" };
66 static char *diamname
[] = { "C1", "H2", "H3", "H4", "H5", "H2", "H3", "H4", "H5" };
67 static real qspc
[] = { -0.82, 0.41, 0.41 };
68 static real qyaw
[] = { 1.24588, 0.62134, 0.62134, 0.0, -2.48856 };
69 static real spc_lj
[3][6] = {
70 { 2.6171e-3, 2.6331e-6, 0, 0, 0, 0 },
77 static real yaw_lj
[5][10] = {
78 { 0, 0, 0, 0, 0, 0, 0, 0, 0, COS
},
79 { 0, 0, 0, CHH
, 0, CHH
, 0, 0, 0, CHS
},
80 { 0, 0, 0, CHH
, 0, CHH
, 0, 0, 0, CHS
},
81 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
82 { 0, COS
, 0, CHS
, 0, CHS
, 0, 0, 2.6e-3, 0 }
85 void unitcell(rvec x
[],rvec box
,gmx_bool bYaw
,real odist
,real hdist
)
89 #define cy2 0.94280904
94 { 0, 0, 1 }, /* H relative to Oxygen */
96 { cx
, cy
, -cz
}, /* O2 */
97 { 0, 0, -1 }, /* H relative to Oxygen */
99 { cx
, cy
+cy2
, 0 }, /* O3 */
100 { -cx
, cy
, -cz
}, /* H relative to Oxygen */
102 { 0, 2*cy
+cy2
, -cz
}, /* O4 */
103 {-cx
,-cy
, +cz
}, /* H relative to Oxygen */
105 { 0, 0, 1 }, /* O5 */
106 {-cx
, cy
, +cz
}, /* H relative to Oxygen */
108 { cx
, cy
, 1+cz
}, /* O6 */
109 { -cx
, -cy
, -cz
}, /* H relative to Oxygen */
111 { cx
, cy
+cy2
, 1 }, /* O7 */
112 { 0, 0, -1 }, /* H relative to Oxygen */
114 { 0, 2*cy
+cy2
,1+cz
}, /* O8 */
115 { 0, 0, 1 }, /* H relative to Oxygen */
122 for(i
=0; (i
<8); i
++) {
128 svmul(odist
,xx
[iin
],x
[iout
]);
129 svmul(-0.82,x
[iout
],t2
);
131 for(j
=1; (j
<=2); j
++) {
132 svmul(hdist
,xx
[iin
+j
],tmp
);
133 rvec_add(x
[iout
],tmp
,x
[iout
+j
]);
134 svmul(0.41,x
[iout
+j
],t2
);
138 for(m
=0; (m
<DIM
); m
++)
139 x
[iout
+3][m
] = x
[iout
+4][m
] =
140 (1-2*DCONS
)*x
[iout
][m
]+DCONS
*(x
[iout
+1][m
]+x
[iout
+2][m
]);
144 box
[YY
] = 2*(cy2
+cy
);
146 for(i
=0; (i
<DIM
); i
++)
149 printf("Unitcell: %10.5f %10.5f %10.5f\n",box
[XX
],box
[YY
],box
[ZZ
]);
150 printf("Dipole: %10.5f %10.5f %10.5f (e nm)\n",dip
[XX
],dip
[YY
],dip
[ZZ
]);
153 void random_h_coords(int natmol
,int nmol
,rvec x
[],rvec box
,
154 gmx_bool bYaw
,real odist
,real hdist
)
156 #define cx 0.81649658
157 #define cy 0.47140452
158 #define cy2 0.94280904
159 #define cz 0.33333333
162 { 0, 0, 0 }, /* O1 */
163 { 0, 0, 1 }, /* H relative to Oxygen */
165 { cx
, cy
, -cz
}, /* O2 */
166 { 0, 0, -1 }, /* H relative to Oxygen */
168 { cx
, cy
+cy2
, 0 }, /* O3 */
169 { -cx
, cy
, -cz
}, /* H relative to Oxygen */
171 { 0, 2*cy
+cy2
, -cz
}, /* O4 */
172 {-cx
,-cy
, +cz
}, /* H relative to Oxygen */
174 { 0, 0, 1 }, /* O5 */
175 {-cx
, cy
, +cz
}, /* H relative to Oxygen */
177 { cx
, cy
, 1+cz
}, /* O6 */
178 { -cx
, -cy
, -cz
}, /* H relative to Oxygen */
180 { cx
, cy
+cy2
, 1 }, /* O7 */
181 { 0, 0, -1 }, /* H relative to Oxygen */
183 { 0, 2*cy
+cy2
,1+cz
}, /* O8 */
184 { 0, 0, 1 }, /* H relative to Oxygen */
191 for(i
=0; (i
<nmol
); i
++) {
194 svmul(odist
,x
[iin
],x
[iout
]);
195 svmul(-0.82,x
[iout
],t2
);
197 for(j
=1; (j
<=2); j
++) {
198 svmul(hdist
,xx
[3*(i
% 8)+j
],tmp
);
199 rvec_add(x
[iout
],tmp
,x
[iout
+j
]);
200 svmul(0.41,x
[iout
+j
],t2
);
206 box
[YY
] = 2*(cy2
+cy
);
208 for(i
=0; (i
<DIM
); i
++)
211 printf("Unitcell: %10.5f %10.5f %10.5f\n",box
[XX
],box
[YY
],box
[ZZ
]);
212 printf("Dipole: %10.5f %10.5f %10.5f (e nm)\n",dip
[XX
],dip
[YY
],dip
[ZZ
]);
215 void unitcell_d(rvec x
[],rvec box
,real odist
)
218 { 0, 0, 0 }, /* C1 */
219 { cx
, cy
, -cz
}, /* C2 */
220 { cx
, cy
+cy2
, 0 }, /* C3 */
221 { 0, 2*cy
+cy2
, -cz
}, /* C4 */
222 { 0, 0, 1 }, /* C5 */
223 { cx
, cy
, 1+cz
}, /* C6 */
224 { cx
, cy
+cy2
, 1 }, /* C7 */
225 { 0, 2*cy
+cy2
,1+cz
}, /* C8 */
228 { 0, 0, 1 }, /* H relative to C */
237 for(i
=0; (i
<8); i
++) {
240 svmul(odist
,cc
[iin
],x
[iout
]);
243 box
[YY
] = 2*(cy2
+cy
);
245 for(i
=0; (i
<DIM
); i
++)
248 printf("Unitcell: %10.5f %10.5f %10.5f\n",box
[XX
],box
[YY
],box
[ZZ
]);
251 static t_bbb
*mk_bonds(int natoms
,rvec x
[],real odist
,
252 gmx_bool bPBC
,matrix box
)
254 real od2
= odist
*odist
+1e-5;
263 for(i
=0; (i
<natoms
); i
++) {
264 for(j
=i
+1; (j
<natoms
); j
++) {
266 pbc_dx(&pbc
,x
[i
],x
[j
],dx
);
268 rvec_sub(x
[i
],x
[j
],dx
);
269 if (iprod(dx
,dx
) <= od2
) {
270 bbb
[i
].aa
[bbb
[i
].n
++] = j
;
271 bbb
[j
].aa
[bbb
[j
].n
++] = i
;
276 #define PRB(nn) (bbb[(i)].n >= (nn)) ? bbb[i].aa[nn-1] : -1
277 for(i
=0; (i
<natoms
); i
++)
278 fprintf(debug
,"bonds from %3d: %d %d %d %d\n",
279 i
,PRB(1),PRB(2),PRB(3),PRB(4));
284 static void mk_diamond(t_atoms
*a
,rvec x
[],real odist
,t_symtab
*symtab
,
285 gmx_bool bPBC
,matrix box
)
288 int i
,ib
,j
,k
,l
,m
,nrm
=0;
295 bbb
= mk_bonds(a
->nr
,x
,odist
,bPBC
,box
);
297 for(i
=0; (i
<a
->nr
); i
++) {
299 for(k
=0; (k
<bbb
[i
].n
); k
++) {
301 for(j
=0; (j
<bbb
[ib
].n
); j
++)
302 if (bbb
[ib
].aa
[j
] == i
)
305 gmx_fatal(FARGS
,"Bond inconsistency (%d not in list of %d)!\n",i
,ib
);
306 for( ; (j
<bbb
[ib
].n
-1); j
++)
307 bbb
[ib
].aa
[j
] = bbb
[ib
].aa
[j
+1];
315 for(i
=j
=0; (i
<a
->nr
); i
++) {
317 copy_rvec(x
[i
],x
[j
]);
321 fprintf(stderr
,"Kicking out %d carbon atoms (out of %d)\n",
327 bbb
= mk_bonds(a
->nr
,x
,odist
,bPBC
,box
);
328 for(i
=0; (i
<a
->nr
); i
++) {
331 a
->atomname
[i
] = put_symtab(symtab
,"C");
334 a
->atomname
[i
] = put_symtab(symtab
,"CH1");
337 a
->atomname
[i
] = put_symtab(symtab
,"CH2");
340 gmx_fatal(FARGS
,"This atom (%d) has %d bonds only",i
,bbb
[i
].n
);
346 static real
calc_ener(real c6
,real c12
,rvec dx
,tensor vir
)
352 e
= c12
*pow(r
,-12.0) - c6
*pow(r
,-6.0);
353 f
= 12*c12
*pow(r
,-14.0) - 6*c6
*pow(r
,-8.0);
354 for(m
=0; (m
<DIM
); m
++)
355 for(n
=0; (n
<DIM
); n
++)
356 vir
[m
][n
] -= 0.5*f
*dx
[m
]*dx
[n
];
361 static int read_rel_coords(char *fn
,rvec
**xx
,int natmol
)
367 nline
= get_file(fn
,&strings
);
368 printf("Read %d lines from %s\n",nline
,fn
);
369 snew(*xx
,nline
*natmol
);
370 for(i
=0; (i
<nline
); i
++) {
371 if (sscanf(strings
[i
],"%lf%lf%lf",&x
,&y
,&z
) != 3)
372 gmx_fatal(FARGS
,"Not enough arguments on line %d of file %s (should be 3)",i
,fn
);
373 (*xx
)[natmol
*i
][XX
] = x
;
374 (*xx
)[natmol
*i
][YY
] = y
;
375 (*xx
)[natmol
*i
][ZZ
] = z
;
380 void virial(FILE *fp
,gmx_bool bFull
,int nmol
,rvec x
[],matrix box
,real rcut
,
381 gmx_bool bYaw
,real q
[],gmx_bool bLJ
)
383 int i
,j
,im
,jm
,natmol
,ik
,jk
,m
,ninter
;
384 rvec dx
,f
,ftot
,dvir
,vir
,pres
,xcmi
,xcmj
,*force
;
385 real dx6
,dx2
,dx1
,fscal
,c6
,c12
,vcoul
,v12
,v6
,vctot
,v12tot
,v6tot
;
389 fprintf(fp
,"%3s - %3s: %6s %6s %6s %6s %8s %8s %8s\n",
390 "ai","aj","dx","dy","dz","|d|","virx","viry","virz");
397 natmol
= bYaw
? 5 : 3;
398 snew(force
,nmol
*natmol
);
400 for(i
=0; (i
<nmol
); i
++) {
402 /* Center of geometry */
404 for(ik
=0; (ik
<natmol
); ik
++)
405 rvec_inc(xcmi
,x
[im
+ik
]);
406 for(m
=0; (m
<DIM
); m
++)
409 for(j
=i
+1; (j
<nmol
); j
++) {
411 /* Center of geometry */
413 for(jk
=0; (jk
<natmol
); jk
++)
414 rvec_inc(xcmj
,x
[jm
+jk
]);
415 for(m
=0; (m
<DIM
); m
++)
418 /* First check COM-COM distance */
419 pbc_dx(&pbc
,xcmi
,xcmj
,dx
);
420 if (norm(dx
) < rcut
) {
422 /* Neirest neighbour molecules! */
424 for(ik
=0; (ik
<natmol
); ik
++) {
425 for(jk
=0; (jk
<natmol
); jk
++) {
426 pbc_dx(&pbc
,x
[im
+ik
],x
[jm
+jk
],dx
);
429 vcoul
= q
[ik
]*q
[jk
]*ONE_4PI_EPS0
/dx1
;
434 c6
= yaw_lj
[ik
][2*jk
];
435 c12
= yaw_lj
[ik
][2*jk
+1];
438 c6
= spc_lj
[ik
][2*jk
];
439 c12
= spc_lj
[ik
][2*jk
+1];
446 fscal
= (vcoul
+12*v12
-6*v6
)/dx2
;
450 for(m
=0; (m
<DIM
); m
++) {
452 dvir
[m
] -= 0.5*dx
[m
]*f
[m
];
454 rvec_inc(force
[ik
+im
],f
);
455 rvec_dec(force
[jk
+jm
],f
);
457 fprintf(fp,"%3s%4d-%3s%4d: %6.3f %6.3f %6.3f %6.3f"
458 " %8.3f %8.3f %8.3f\n",
459 watname[ik],im+ik,watname[jk],jm+jk,
460 dx[XX],dx[YY],dx[ZZ],norm(dx),
461 dvir[XX],dvir[YY],dvir[ZZ]);*/
465 fprintf(fp
,"%3s%4d-%3s%4d: "
466 " %8.3f %8.3f %8.3f\n",
467 "SOL",i
,"SOL",j
,dvir
[XX
],dvir
[YY
],dvir
[ZZ
]);
472 fprintf(fp
,"There were %d interactions between the %d molecules (%.2f %%)\n",
473 ninter
,nmol
,(real
)ninter
/(0.5*nmol
*(nmol
-1)));
474 fprintf(fp
,"Vcoul: %10.4e V12: %10.4e V6: %10.4e Vtot: %10.4e (kJ/mol)\n",
475 vctot
/nmol
,v12tot
/nmol
,v6tot
/nmol
,(vctot
+v12tot
+v6tot
)/nmol
);
476 pr_rvec(fp
,0,"vir ",vir
,DIM
,TRUE
);
478 for(m
=0; (m
<DIM
); m
++)
479 pres
[m
] = -2*PRESFAC
/(det(box
))*vir
[m
];
480 pr_rvec(fp
,0,"pres",pres
,DIM
,TRUE
);
481 pr_rvecs(fp
,0,"force",force
,natmol
*nmol
);
487 int main(int argc
,char *argv
[])
489 static char *desc
[] = {
490 "[TT]mkice[tt] generates an ice crystal in the Ih crystal form which is the",
491 "most stable form. The rectangular unitcell contains eight molecules",
492 "and all oxygens are tetrahedrally coordinated.[PAR]",
493 "If an input file is given it is interpreted as a series of oxygen",
494 "coordinates the distance between which can be scaled by the odist flag.",
495 "The program then adds hydrogens to the oxygens in random orientation",
496 "but with proper OH distances and HOH angle. This feature allows to",
497 "build water clusters based on oxygen coordinates only."
499 static int nx
=1,ny
=1,nz
=1;
500 static gmx_bool bYaw
=FALSE
,bLJ
=TRUE
,bFull
=TRUE
,bSeries
=FALSE
;
501 static gmx_bool bOrdered
=TRUE
,bDiamond
=FALSE
,bPBC
=TRUE
;
502 static real rcut
=0.3,odist
=0.274,hdist
=0.09572;
504 { "-nx", FALSE
, etINT
, {&nx
}, "nx" },
505 { "-ny", FALSE
, etINT
, {&ny
}, "ny" },
506 { "-nz", FALSE
, etINT
, {&nz
}, "nz" },
507 { "-yaw", FALSE
, etBOOL
, {&bYaw
},
508 "Generate virtual sites and shell positions" },
509 { "-lj", FALSE
, etBOOL
, {&bLJ
},
510 "Use LJ as well as coulomb for virial calculation" },
511 { "-rcut", FALSE
,etREAL
, {&rcut
},"Cut-off for virial calculations" },
512 { "-full", FALSE
,etBOOL
, {&bFull
},"Full virial output" },
513 { "-odist", FALSE
, etREAL
, {&odist
}, "Distance (nm) between oxygens" },
514 { "-hdist", FALSE
, etREAL
, {&hdist
}, "Bondlength (nm) for OH bond" },
515 { "-diamond",FALSE
,etBOOL
, {&bDiamond
}, "Make a diamond instead" },
516 { "-pbc", FALSE
, etBOOL
, {&bPBC
}, "Make a periodic diamond" },
517 { "-order", FALSE
,etBOOL
, {&bOrdered
}, "Make a proton-ordered ice lattice" },
518 { "-series",FALSE
, etBOOL
, {&bSeries
},
519 "Do a series of virial calculations with different cut-off (from 0.3 up till the specified one)" }
522 { efSTO
, "-p", "ice", ffWRITE
},
523 { efSTO
, "-c", NULL
, ffOPTRD
},
524 { efDAT
, "-f", NULL
, ffOPTRD
},
525 { efTRN
, "-o", "ice", ffOPTWR
}
527 #define NFILE asize(fnm)
531 int i
,j
,k
,n
,nmax
,m
,natom
,natmol
;
538 CopyRight(stdout
,argv
[0]);
539 parse_common_args(&argc
,argv
,0,NFILE
,fnm
,asize(pa
),pa
,asize(desc
),
542 fprintf(debug
,"nx = %3d, ny = %3d, nz = %3d\n",nx
,ny
,nz
);
543 fprintf(debug
,"YAW = %3s, LJ = %3s, rcut = %g\n",yesno_names
[bYaw
],
544 yesno_names
[bLJ
],rcut
);
554 if (opt2bSet("-f",NFILE
,fnm
)) {
555 natom
= read_rel_coords(opt2fn("-f",NFILE
,fnm
),&xx
,natmol
);
560 nmax
= natom
*nx
*ny
*nz
;
564 init_t_atoms(pdba
,nmax
,TRUE
);
566 open_symtab(&symtab
);
567 for(n
=0; (n
<nmax
); n
++) {
568 pdba
->pdbinfo
[n
].type
= epdbATOM
;
569 pdba
->pdbinfo
[n
].atomnr
= 1+n
;
570 pdba
->atom
[n
].resnr
= 1+(n
/natmol
);
571 pdba
->atomname
[n
] = put_symtab(&symtab
,
572 bDiamond
? diamname
[(n
% natmol
)] : watname
[(n
% natmol
)]);
574 pdba
->resname
[n
] = put_symtab(&symtab
,"DIA");
576 pdba
->resname
[n
] = put_symtab(&symtab
,"SOL");
577 sprintf(pdba
->pdbinfo
[n
].pdbresnr
,"%d",n
);
578 pdba
->atom
[n
].chain
= ' ';
581 /* Generate the unit cell */
583 unitcell_d(xx
,box
,odist
);
584 else if (opt2bSet("-f",NFILE
,fnm
)) {
585 random_h_coords(natmol
,natom
/natmol
,xx
,box
,bYaw
,odist
,hdist
);
588 unitcell(xx
,box
,bYaw
,odist
,hdist
);
591 boxje
[XX
][XX
] = box
[XX
];
592 boxje
[YY
][YY
] = box
[YY
];
593 boxje
[ZZ
][ZZ
] = box
[ZZ
];
596 for(i
=0; (i
<nx
); i
++) {
598 for(j
=0; (j
<ny
); j
++) {
600 for(k
=0; (k
<nz
); k
++) {
602 for(m
=0; (m
<natom
); m
++,n
++) {
603 if ((!bOrdered
&& ((m
% natmol
) == 0)) || bOrdered
)
604 rvec_add(xx
[n
% natom
],tmp
,xx
[n
]);
613 boxje
[XX
][XX
] = box
[XX
]*nx
;
614 boxje
[YY
][YY
] = box
[YY
]*ny
;
615 boxje
[ZZ
][ZZ
] = box
[ZZ
]*nz
;
617 printf("Crystal: %10.5f %10.5f %10.5f\n",
618 nx
*box
[XX
],ny
*box
[YY
],nz
*box
[ZZ
]);
620 if (debug
&& !bDiamond
) {
622 for(i
=3; (i
<=10*rcut
); i
++) {
623 fprintf(debug
,"This is with rcut = %g\n",i
*0.1);
624 virial(debug
,bFull
,nmax
/natmol
,xx
,boxje
,
625 0.1*i
,bYaw
,bYaw
? qyaw
: qspc
,bLJ
);
628 virial(debug
,bFull
,nmax
/natmol
,xx
,boxje
,
629 rcut
,bYaw
,bYaw
? qyaw
: qspc
,bLJ
);
633 mk_diamond(pdba
,xx
,odist
,&symtab
,bPBC
,boxje
);
635 fn
= ftp2fn(efSTO
,NFILE
,fnm
);
636 if (fn2ftp(fn
) == efPDB
) {
637 fp
= gmx_ffopen(fn
,"w");
639 fprintf(fp
,"HEADER This is a *diamond*\n");
641 fprintf(fp
,"HEADER A beautiful Ice Ih crystal\n");
642 fprintf(fp
,"REMARK Generated by mkice with the following options:\n"
643 "REMARK nx = %d, ny = %d, nz = %d, odist = %g, hdist = %g\n",
644 nx
,ny
,nz
,odist
,hdist
);
646 write_pdbfile(fp
,quote
,pdba
,xx
,boxje
,' ',-1);
651 write_sto_conf(fn
,quote
,pdba
,xx
,NULL
,boxje
);
654 if (ftp2bSet(efTRN
,NFILE
,fnm
))
655 write_trn(ftp2fn(efTRN
,NFILE
,fnm
),0,0,0,boxje
,nmax
,xx
,NULL
,NULL
);