3# program that builds spheres of water
5# author = "Dan Gezelter
6# copyright = "Copyright (c) 2004-present The University of Notre Dame. All Rights Reserved."
10use List::Util qw[min max];
14$mass = 2.99151E-23; # mass of H2O in grams
15$cm3ToAng3 = 1E24; # convert cm^3 to angstroms^3
16$densityConvert = $mass*$cm3ToAng3;
28getopts('hmrvd:l:c:o:w:O:I:');
31$opt_h = "true" if $#ARGV >= 0;
35 print "waterSphere: builds spheres of water\n\n";
36 print "usage: waterSphere [-hmrv] [-d density] [-l lattice] [-n # waters]\n";
37 print "\t[-o file name] [-w water name] \n\n";
38 print " -h : show this message\n";
39 print " -m : print out a water.inc file (file with all water models)\n";
40 print " -r : randomize orientations\n";
41 print " -v : verbose output\n\n";
42 print " -d real : density in g/cm^3\n";
43 print " (default: 1)\n";
44 print " -l integer : 0 - face centered cubic, 1 - simple cubic\n";
45 print " (default: 0)\n";
48 print " -c real : default overlap cutoff in angstroms\n";
49 print " (default: 3.3)\n";
50 print " -o char : output file name\n";
51 print " (default: freshWater.omd)\n";
52 print " -w char : name of the water stunt double\n";
53 print " (default: SPCE)\n";
54 print " -R real : outer radius of the water sphere\n";
55 print " -I real : inner radius of the water sphere\n";
56 print "Note: you can only use values of -O that are smaller\n";
57 print " than the derived radius for a given density and\n";
58 print " number of molecules.\n\n";
60 die " waterSphere -d 0.997 -I 20 -O 40 -w SSD_RF -o ssdrfWater.omd\n";
63# set some variables to be used in the code
68 $fileName = 'freshWater.omd';
71 die "Error: $fileName cannot be \"water.inc\"\n Please choose a different name\n" if $fileName eq 'water.inc';
72 $waterFileHandle = 'WATERMD';
75 $waterFileHandle = 'OUTFILE';
78 $doRandomize = $opt_r;
84 if ($opt_d =~ /^[0-9]/) {
87 die "Error: the value for '-d' ($opt_d) is not a valid number\n Please choose a positive real # value\n";
92 if ($opt_c =~ /^[0-9]/) {
95 die "Error: the value for '-c' ($opt_c) is not a valid number\n Please choose a positive real # value\n";
101 $nothingSelected = 0;
106if ($invalidWater == 1){
107 print "Warning: \'$waterName\' is not a recognized water model name.\n";
108 print " Use the \'-m\' option to generate a \'water.inc\' with the\n";
109 print " recognized water model geometries.\n\n";
111if ($waterName eq 'DPD') {
112 # DPD waters are stand-ins for 4 water molecules
113 $density = $density * 0.25;
115if ($waterName eq 'CG2') {
116 # CG2 waters are stand-ins for 2 water molecules
117 $density = $density * 0.5;
121 $nothingSelected = 0;
122 if ($opt_l =~ /^[0-9]/) {
124 if ($lattice != 0 && $lattice != 1){
125 die "Error: the '-l' value ($opt_l) is not a valid number\n Please choose 0 or 1\n";
128 die "Error: the '-l' value ($opt_l) is not a valid number\n Please choose 0 or 1\n";
132 $nothingSelected = 0;
133 if ($opt_O =~ /^[0-9]/) {
139 die "Error: the value for '-O' ($opt_O) is not a valid number\n Please choose a positive real # value\n";
142 die "Error: the outer radius of the sphere '-O' must be set\n";
145 $nothingSelected = 0;
146 if ($opt_I =~ /^[0-9]/) {
149 die "Error: the value for '-I' ($opt_I) is not a valid number\n Please choose a positive real # value\n";
155if ($nothingSelected == 1) {
156 die "(For help, use the \'-h\' option.)\n";
159# open the file writer
160open(OUTFILE, ">./$fileName") || die "Error: can't open file $fileName\n";
162# check to set magic lattice numbers
164 $a = (4*18.01/(0.602*$density))**(1.0/3.0);
165 $acut = $rcut * sqrt(2.0);
168 $newDensity = 4.0*18.01/(0.602*$a**3);
169 print "using density of $newDensity to match cutoff value ($rcut)\n";
171} elsif ($lattice == 1){
172 $a = (18.01/(0.602*$density))**(1.0/3.0);
176 $newDensity = 18.01/(0.602*$a**3);
177 print "using density of $newDensity to match cutoff value ($rcut)\n";
181$nx = int($nxFloat + $nxFloat/abs($nxFloat*2));
183$ny = int($nyFloat + $nyFloat/abs($nyFloat*2));
185$nz = int($nzFloat + $nzFloat/abs($nzFloat*2));
187$anew = min($boxx/$nx, $boxy/$ny, $boxz/$nz);
193$nxFloat = $boxx/$anew;
194$nx = int($nxFloat + $nxFloat/abs($nxFloat*2));
195$nyFloat = $boxy/$anew;
196$ny = int($nyFloat + $nyFloat/abs($nyFloat*2));
197$nzFloat = $boxz/$anew;
198$nz = int($nzFloat + $nzFloat/abs($nzFloat*2));
201 $nMol = 4 * $nx * $ny * $nz;
203 $nMol = $nx * $ny * $nz;
206$newDensity = $nMol * $densityConvert / ($boxx*$boxy*$boxz);
208if (abs($newDensity-$density) > $tolerance) {
209 print "Resetting density to $newDensity to make chosen sphere radius work out\n";
211$cellLengthX = $boxx/$nx;
212$cellLengthY = $boxy/$ny;
213$cellLengthZ = $boxz/$nz;
215$cell2X = $cellLengthX*0.5;
216$cell2Y = $cellLengthY*0.5;
217$cell2Z = $cellLengthZ*0.5;
219$centerx = 0.5 * $boxx;
220$centery = 0.5 * $boxy;
221$centerz = 0.5 * $boxz;
241# assemble the lattice
243 for ($z = 0; $z < $nz ; $z++) {
244 for ($y = 0; $y < $ny; $y++) {
245 for ($x = 0; $x < $nx; $x++) {
246 for ($uc = 0; $uc < 4; $uc++) {
247 $xtest = $xref[$uc] + $cellLengthX*$x - $centerx;
248 $ytest = $yref[$uc] + $cellLengthY*$y - $centery;
249 $ztest = $zref[$uc] + $cellLengthZ*$z - $centerz;
250 $rtest = sqrt($xtest*$xtest + $ytest*$ytest + $ztest*$ztest);
251 if (($rtest > $inner) && ($rtest < $outer)) {
252 $xCorr[$counter] = $xref[$uc] + $cellLengthX*$x - $centerx;
253 $yCorr[$counter] = $yref[$uc] + $cellLengthY*$y - $centery;
254 $zCorr[$counter] = $zref[$uc] + $cellLengthZ*$z - $centerz;
262} elsif ($lattice == 1) {
263 # build the unit cell
270 for ($z = 0; $z < $nz ; $z++) {
271 for ($y = 0; $y < $ny; $y++) {
272 for ($x = 0; $x < $nx; $x++) {
273 $xtest = $xref[0] + $cellLengthX*$x - $centerx;
274 $ytest = $yref[0] + $cellLengthY*$y - $centery;
275 $ztest = $zref[0] + $cellLengthZ*$z - $centerz;
276 $rtest = sqrt($xtest*$xtest + $ytest*$ytest + $ztest*$ztest);
277 if (($rtest > $inner) && ($rtest < $outer)) {
278 $xCorr[$counter] = $xref[0] + $cellLengthX*$x - $centerx;
279 $yCorr[$counter] = $yref[0] + $cellLengthY*$y - $centery;
280 $zCorr[$counter] = $zref[0] + $cellLengthZ*$z - $centerz;
290print "The water box \"$fileName\" was generated.\n";
294 print "The file \"water.inc\" was generated for inclusion in \"$fileName\"\n";
299# this marks the end of the main program, below is subroutines
303 my $ret = atan2(sqrt(1 - $rad*$rad), $rad);
308 # write out the header
309 print OUTFILE "<OpenMD version=1>\n";
313 print OUTFILE " <StuntDoubles>\n";
315 # write out the coordinates
316 for ($i = 0; $i < $nMol; $i++) {
323 if ($doRandomize == 1){
324 $cosTheta = 2.0*rand() - 1.0;
325 $theta = acos($cosTheta);
326 $phi = 2.0*3.14159265359*rand();
327 $psi = 2.0*3.14159265359*rand();
329 $q0 = cos(0.5*$theta)*cos(0.5*($phi + $psi));
330 $q1 = sin(0.5*$theta)*cos(0.5*($phi - $psi));
331 $q2 = sin(0.5*$theta)*sin(0.5*($phi - $psi));
332 $q3 = cos(0.5*$theta)*sin(0.5*($phi + $psi));
335 print OUTFILE "$i\tpq\t$xCorr[$i] $yCorr[$i] $zCorr[$i] ";
336 print OUTFILE "$q0 $q1 $q2 $q3\n";
339 print OUTFILE " </StuntDoubles>\n </Snapshot>\n</OpenMD>\n";
343 print OUTFILE " <MetaData>\n";
345# print the water model or includes
347 print OUTFILE "#include \"water.inc\"";
351 printFakeWater() if $invalidWater == 1;
353# now back to the metaData output
354 print OUTFILE "\n\ncomponent{
355 type = \"$waterName\";
359ensemble = \"LangevinHull\";
360forceField = \"Water\";
361electrostaticSummationMethod = \"shifted_force\";
362electrostaticScreeningMethod = \"damped\";
363cutoffRadius = $cutoff;
364switchingRadius = $cutoff;
365dampingAlpha = $alpha;
366usePeriodicBoundaryConditions = \"false\";
394 $boxLength2 = 0.5*$bm;
395 if ($boxLength2 > $cutoff){
396 # the default is good
398 $cutoff = int($boxLength2);
407 Hmat: {{ $boxx, 0, 0 }, { 0, $boxy, 0 }, { 0, 0, $boxz }}
412 open(WATERMD, ">./water.inc") || die "Error: can't open file water.inc\n";
413 $waterFileHandle = 'WATERMD';
415 print WATERMD "#ifndef _WATER_INC_\n#define _WATER_INC_\n";
442 print WATERMD "\n\n#endif";
446 print $waterFileHandle "\n\nmolecule{
451 position(0.0, 0.0, 0.0);
457 print $waterFileHandle "\n\nmolecule{
462 position(0.0, 0.0, 0.0);
468 print $waterFileHandle "\n\nmolecule{
473 position( 0.0, 0.0, 0.0 );
474 orientation( 0.0, 0.0, 0.0 );
480 print $waterFileHandle "\n\nmolecule{
485 position( 0.0, 0.0, 0.0 );
486 orientation( 0.0, 0.0, 0.0 );
492 print $waterFileHandle "\n\nmolecule{
497 position( 0.0, 0.0, 0.0 );
498 orientation( 0.0, 0.0, 0.0 );
504 print $waterFileHandle "\n\nmolecule{
509 position( 0.0, 0.0, 0.0 );
510 orientation( 0.0, 0.0, 0.0 );
516 print $waterFileHandle "\n\nmolecule{
521 position( 0.0, 0.0, 0.0 );
522 orientation( 0.0, 0.0, 0.0 );
528 print $waterFileHandle "\n\nmolecule{
533 position( 0.0, 0.0, 0.0 );
534 orientation( 0.0, 0.0, 0.0 );
540 print $waterFileHandle "\n\nmolecule{
545 position( 0.0, 0.0, 0.0 );
546 orientation( 0.0, 0.0, 0.0 );
550 position( 0.0, 0.0, 0.5 );
561 print $waterFileHandle "\n\nmolecule{
566 position( 0.0, 0.0, -0.06556 );
570 position( 0.0, 0.75695, 0.52032 );
574 position( 0.0, -0.75695, 0.52032 );
585 print $waterFileHandle "\n\nmolecule{
590 position( 0.0, 0.0, -0.06556 );
594 position( 0.0, 0.75695, 0.52032 );
598 position( 0.0, -0.75695, 0.52032 );
602 position( 0.0, 0.0, 0.08444 );
613 print $waterFileHandle "\n\nmolecule{
614 name = \"TIP4P-Ice\";
617 type = \"O_TIP4P-Ice\";
618 position( 0.0, 0.0, -0.06556 );
621 type = \"H_TIP4P-Ice\";
622 position( 0.0, 0.75695, 0.52032 );
625 type = \"H_TIP4P-Ice\";
626 position( 0.0, -0.75695, 0.52032 );
629 type = \"EP_TIP4P-Ice\";
630 position( 0.0, 0.0, 0.09214 );
641 print $waterFileHandle "\n\nmolecule{
645 type = \"O_TIP4P-Ew\";
646 position( 0.0, 0.0, -0.06556 );
649 type = \"H_TIP4P-Ew\";
650 position( 0.0, 0.75695, 0.52032 );
653 type = \"H_TIP4P-Ew\";
654 position( 0.0, -0.75695, 0.52032 );
657 type = \"EP_TIP4P-Ew\";
658 position( 0.0, 0.0, 0.05944 );
669 print $waterFileHandle "\n\nmolecule{
670 name = \"TIP4P-2005\";
673 type = \"O_TIP4P-2005\";
674 position( 0.0, 0.0, -0.06556 );
677 type = \"H_TIP4P-2005\";
678 position( 0.0, 0.75695, 0.52032 );
681 type = \"H_TIP4P-2005\";
682 position( 0.0, -0.75695, 0.52032 );
685 type = \"EP_TIP4P-2005\";
686 position( 0.0, 0.0, 0.08904 );
697 print $waterFileHandle "\n\nmolecule{
702 position( 0.0, 0.0, -0.06556 );
706 position( 0.0, 0.75695, 0.52032 );
710 position( 0.0, -0.75695, 0.52032 );
714 position( 0.57154, 0.0, -0.46971 );
718 position( -0.57154, 0.0, -0.46971 );
722 members(0, 1, 2, 3, 4);
729 print $waterFileHandle "\n\nmolecule{
733 type = \"O_TIP5P-E\";
734 position( 0.0, 0.0, -0.06556 );
738 position( 0.0, 0.75695, 0.52032 );
742 position( 0.0, -0.75695, 0.52032 );
746 position( 0.57154, 0.0, -0.46971 );
750 position( -0.57154, 0.0, -0.46971 );
754 members(0, 1, 2, 3, 4);
761 print $waterFileHandle "\n\nmolecule{
766 position( 0.0, 0.0, 0.0 );
770 position( 0.0, 0.576029, 0.79283665 );
774 position( 0.0, -0.576029, 0.79283665 );
778 position( 0.0, 0.23, 0.0 );
782 position( 0.732813007, -0.50364843, 0.0 );
786 position( -0.732813007, -0.50364843, 0.0 );
790 members(0, 1, 2, 3, 4, 5);
796print $waterFileHandle "\n\nmolecule{
801 position( 0.0, 0.0, -0.06461 );
805 position( 0.0, 0.81649, 0.51275 );
809 position( 0.0, -0.81649, 0.51275 );
820print $waterFileHandle "\n\nmolecule{
825 position( 0.0, 0.0, -0.06461 );
829 position( 0.0, 0.81649, 0.51275 );
833 position( 0.0, -0.81649, 0.51275 );
844print $waterFileHandle "\n\nmolecule{
849 position( 0.0, 0.0, -0.0603651 );
853 position( 0.0, 0.685582, 0.479134 );
857 position( 0.0, -0.685582, 0.479134 );
861 position( 0.0, 0.0, 0.0990349 );
871print $waterFileHandle "\n\nmolecule{
876 position( 0.0, 0.0, -0.0632382 );
880 position( 0.0, 0.799262, 0.501939 );
884 position( 0.0, -0.799262, 0.501939 );
894print $waterFileHandle "\n\nmolecule{
898 type = \"O_TIP3P-FB\";
899 position( 0.0, 0.0, -0.066424 );
902 type = \"H_TIP3P-FB\";
903 position( 0.0, 0.819341, 0.527225 );
906 type = \"H_TIP3P-FB\";
907 position( 0.0, -0.819341, 0.527225 );
917print $waterFileHandle "\n\nmolecule{
921 type = \"O_TIP4P-FB\";
922 position( 0.0, 0.0, -0.0655549 );
925 type = \"H_TIP4P-FB\";
926 position( 0.0, 0.75695, 0.520327 );
929 type = \"H_TIP4P-FB\";
930 position( 0.0, -0.75695, 0.520327 );
933 type = \"EP_TIP4P-FB\";
934 position( 0.0, 0.0, 0.0397151 );
945print $waterFileHandle "\n\nmolecule{
950 position( 0.0, 0.0, -0.06461 );
954 position( 0.0, 0.81649, 0.51275 );
958 position( 0.0, -0.81649, 0.51275 );
969 print $waterFileHandle "\n\nmolecule{
974 position(0.0, 0.0, 0.0);
980 print $waterFileHandle "\n\nmolecule{
985 position(0.0, 0.0, 0.0);
991 print $waterFileHandle "\n\nmolecule{
992 name = \"$waterName\";
995 type = \"$waterName\";
996 position(0.0, 0.0, 0.0);
1003 if ($waterName eq 'Cl-') { $waterCase = 0; }
1004 elsif ($waterName eq 'Na+') { $waterCase = 1; }
1005 elsif ($waterName eq 'SSD_E') { $waterCase = 2; }
1006 elsif ($waterName eq 'SSD_RF') { $waterCase = 3; }
1007 elsif ($waterName eq 'SSD') { $waterCase = 4; }
1008 elsif ($waterName eq 'SSD1') { $waterCase = 5; }
1009 elsif ($waterName eq 'TIP3P') { $waterCase = 6; }
1010 elsif ($waterName eq 'TIP4P') { $waterCase = 7; }
1011 elsif ($waterName eq 'TIP4P-Ew') { $waterCase = 8; }
1012 elsif ($waterName eq 'TIP5P') { $waterCase = 9; }
1013 elsif ($waterName eq 'TIP5P-E') { $waterCase = 10; }
1014 elsif ($waterName eq 'SPCE') { $waterCase = 11; }
1015 elsif ($waterName eq 'SPC') { $waterCase = 12; }
1016 elsif ($waterName eq 'DPD') { $waterCase = 13; }
1017 elsif ($waterName eq 'CG2') { $waterCase = 14; }
1018 elsif ($waterName eq 'SSDQ') { $waterCase = 15; }
1019 elsif ($waterName eq 'SSDQO') { $waterCase = 16; }
1020 elsif ($waterName eq 'TIP4P-Ice'){ $waterCase = 17; }
1021 elsif ($waterName eq 'TIP4P-2005'){ $switchCase = 18; }
1022 elsif ($waterName eq 'SPC-HW') { $waterCase == 19; }
1023 elsif ($waterName eq 'NE6') { $waterCase == 20; }
1024 elsif ($waterName eq 'TIP3P-FB') { $waterCase == 21; }
1025 elsif ($waterName eq 'TIP4P-FB') { $waterCase == 22; }
1026 elsif ($waterName eq 'OPC') { $waterCase == 23; }
1027 elsif ($waterName eq 'OPC3') { $waterCase == 24; }
1028 else { $invalidWater = 1; }
1031sub printWaterModel {
1032 if ($waterCase == 0) { printCl(); }
1033 elsif ($waterCase == 1) { printNa(); }
1034 elsif ($waterCase == 2) { printSSD_E(); }
1035 elsif ($waterCase == 3) { printSSD_RF(); }
1036 elsif ($waterCase == 4) { printSSD(); }
1037 elsif ($waterCase == 5) { printSSD1(); }
1038 elsif ($waterCase == 6) { printTIP3P(); }
1039 elsif ($waterCase == 7) { printTIP4P(); }
1040 elsif ($waterCase == 8) { printTIP4PEw(); }
1041 elsif ($waterCase == 9) { printTIP5P(); }
1042 elsif ($waterCase == 10) { printTIP5PE(); }
1043 elsif ($waterCase == 11) { printSPCE(); }
1044 elsif ($waterCase == 12) { printSPC(); }
1045 elsif ($waterCase == 13) { printDPD(); }
1046 elsif ($waterCase == 14) { printCG2(); }
1047 elsif ($waterCase == 15) { printSSDQ(); }
1048 elsif ($waterCase == 16) { printSSDQO(); }
1049 elsif ($waterCase == 17) { printTIP4PIce();}
1050 elsif ($waterCase == 18) { printTIP4P2005();}
1051 elsif ($waterCase == 19) { printSPCHW(); }
1052 elsif ($waterCase == 20) { printNE6(); }
1053 elsif ($waterCase == 21) { printTIP3PFB(); }
1054 elsif ($waterCase == 22) { printTIP4PFB(); }
1055 elsif ($waterCase == 23) { printOPC(); }
1056 elsif ($waterCase == 24) { printOPC3(); }