3__author__ = "Chris Fennell and Dan Gezelter"
4__copyright__ = "Copyright (c) 2004-present The University of Notre Dame. All Rights Reserved."
12from argparse import RawDescriptionHelpFormatter
17# function to calculate the arccosine
19 return math.atan2(math.sqrt(1 - rad * rad), rad)
21# Function to check if a point is within the spherical boundaries
22def inSphere(x, y, z, radius):
23 return math.sqrt(x**2 + y**2 + z**2) <= radius
25# Function to open the output file
26def open_output_file(fileName):
27 f = open(fileName, 'w')
28 if os.path.exists(fileName):
31 sys.exit("Error: can't open file {}\n".format(fileName))
33# Function to find the cutoff
34def find_cutoff(cutoff, boxx, boxy, boxz):
35 bm = min(boxx, boxy, boxz)
37 if boxLength2 <= cutoff:
38 cutoff = int(boxLength2)
40# Functions to print the water model types
47 position(0.0, 0.0, 0.0);
57 position(0.0, 0.0, 0.0);
61def print_ssd_e(outfile):
67 position( 0.0, 0.0, 0.0 );
68 orientation( 0.0, 0.0, 0.0 );
72def print_ssd_rf(outfile):
78 position( 0.0, 0.0, 0.0 );
79 orientation( 0.0, 0.0, 0.0 );
83def print_ssd(outfile):
89 position( 0.0, 0.0, 0.0 );
90 orientation( 0.0, 0.0, 0.0 );
94def print_ssdq(outfile):
100 position( 0.0, 0.0, 0.0 );
101 orientation( 0.0, 0.0, 0.0 );
105def print_ssdqo(outfile):
111 position( 0.0, 0.0, 0.0 );
112 orientation( 0.0, 0.0, 0.0 );
116def print_ssd1(outfile):
122 position( 0.0, 0.0, 0.0 );
123 orientation( 0.0, 0.0, 0.0 );
127def print_tip3p(outfile):
133 position( 0.0, 0.0, -0.06556 );
137 position( 0.0, 0.75695, 0.52032 );
141 position( 0.0, -0.75695, 0.52032 );
148def print_tip4p(outfile):
154 position( 0.0, 0.0, -0.06556 );
158 position( 0.0, 0.75695, 0.52032 );
162 position( 0.0, -0.75695, 0.52032 );
166 position( 0.0, 0.0, 0.08444 );
173def print_tip4p_ice(outfile):
178 type = "O_TIP4P-Ice";
179 position( 0.0, 0.0, -0.06556 );
182 type = "H_TIP4P-Ice";
183 position( 0.0, 0.75695, 0.52032 );
186 type = "H_TIP4P-Ice";
187 position( 0.0, -0.75695, 0.52032 );
190 type = "EP_TIP4P-Ice";
191 position( 0.0, 0.0, 0.09214 );
198def print_tip4p_2005(outfile):
203 type = "O_TIP4P-2005";
204 position( 0.0, 0.0, -0.06556 );
207 type = "H_TIP4P-2005";
208 position( 0.0, 0.75695, 0.52032 );
211 type = "H_TIP4P-2005";
212 position( 0.0, -0.75695, 0.52032 );
215 type = "EP_TIP4P-2005";
216 position( 0.0, 0.0, 0.08904 );
223def print_tip4pew(outfile):
229 position( 0.0, 0.0, -0.06556 );
233 position( 0.0, 0.75695, 0.52032 );
237 position( 0.0, -0.75695, 0.52032 );
240 type = "EP_TIP4P-Ew";
241 position( 0.0, 0.0, 0.05944 );
248def print_tip5p(outfile):
254 position( 0.0, 0.0, -0.06556 );
258 position( 0.0, 0.75695, 0.52032 );
262 position( 0.0, -0.75695, 0.52032 );
266 position( 0.57154, 0.0, -0.46971 );
270 position( -0.57154, 0.0, -0.46971 );
273 members(0, 1, 2, 3, 4);
277def print_tip5pe(outfile):
283 position( 0.0, 0.0, -0.06556 );
287 position( 0.0, 0.75695, 0.52032 );
291 position( 0.0, -0.75695, 0.52032 );
295 position( 0.57154, 0.0, -0.46971 );
299 position( -0.57154, 0.0, -0.46971 );
302 members(0, 1, 2, 3, 4);
306def print_spce(outfile):
312 position( 0.0, 0.0, -0.06461 );
316 position( 0.0, 0.81649, 0.51275 );
320 position( 0.0, -0.81649, 0.51275 );
327def print_spc(outfile):
333 position( 0.0, 0.0, -0.06461 );
337 position( 0.0, 0.81649, 0.51275 );
341 position( 0.0, -0.81649, 0.51275 );
348def print_spc_hw(outfile):
354 position( 0.0, 0.0, -0.06461 );
358 position( 0.0, 0.81649, 0.51275 );
362 position( 0.0, -0.81649, 0.51275 );
369def print_ne6(outfile):
375 position( 0.0, 0.0, 0.0 );
379 position( 0.0, 0.576029, 0.79283665 );
383 position( 0.0, -0.576029, 0.79283665 );
387 position( 0.0, 0.23, 0.0 );
391 position( 0.732813007, -0.50364843, 0.0 );
395 position( -0.732813007, -0.50364843, 0.0 );
398 members(0, 1, 2, 3, 4, 5);
402def print_tip3p_fb(outfile):
408 position( 0.0, 0.0, -0.066424 );
412 position( 0.0, 0.819341, 0.527225 );
416 position( 0.0, -0.819341, 0.527225 );
423def print_tip4p_fb(outfile):
429 position( 0.0, 0.0, -0.0655549 );
433 position( 0.0, 0.75695, 0.520327 );
437 position( 0.0, -0.75695, 0.520327 );
440 type = "EP_TIP4P-FB";
441 position( 0.0, 0.0, 0.0397151 );
448def print_opc(outfile):
454 position( 0.0, 0.0, -0.0603651 );
458 position( 0.0, 0.685582, 0.479134 );
462 position( 0.0, -0.685582, 0.479134 );
466 position( 0.0, 0.0, 0.0990349 );
473def print_opc3(outfile):
479 position( 0.0, 0.0, -0.0632382 );
483 position( 0.0, 0.799262, 0.501939 );
487 position( 0.0, -0.799262, 0.501939 );
494def print_dpd(outfile):
500 position( 0.0, 0.0, 0.0 );
504def print_cg2(outfile):
510 position( 0.0, 0.0, 0.0 );
514# Function to print fake water model
515def print_fake_water(waterName, outfile):
516 outfile.write("\n\nmolecule{{\n name = \"{}\";\n atom[0]{{\n type = \"{}\";\n position(0.0, 0.0, 0.0);\n }}\n}}".format(waterName, waterName))
518# Function to print the water model
519def print_water_model(waterCase, outfile):
520 if waterCase == 0: print_cl(outfile)
521 elif waterCase == 1: print_na(outfile)
522 elif waterCase == 2: print_ssd_e(outfile)
523 elif waterCase == 3: print_ssd_rf(outfile)
524 elif waterCase == 4: print_ssd(outfile)
525 elif waterCase == 5: print_ssd1(outfile)
526 elif waterCase == 6: print_tip3p(outfile)
527 elif waterCase == 7: print_tip4p(outfile)
528 elif waterCase == 8: print_tip4pew(outfile)
529 elif waterCase == 9: print_tip5p(outfile)
530 elif waterCase == 10: print_tip5pe(outfile)
531 elif waterCase == 11: print_spce(outfile)
532 elif waterCase == 12: print_spc(outfile)
533 elif waterCase == 13: print_dpd(outfile)
534 elif waterCase == 14: print_cg2(outfile)
535 elif waterCase == 15: print_ssdq(outfile)
536 elif waterCase == 16: print_ssdqo(outfile)
537 elif waterCase == 17: print_tip4p_ice(outfile)
538 elif waterCase == 18: print_tip4p_2005(outfile)
539 elif waterCase == 19: print_spc_hw(outfile)
540 elif waterCase == 20: print_ne6(outfile)
541 elif waterCase == 21: print_tip3p_fb(outfile)
542 elif waterCase == 22: print_tip4p_fb(outfile)
543 elif waterCase == 23: print_opc(outfile)
544 elif waterCase == 24: print_opc3(outfile)
546# Function to validate the water model
547def validate_water(waterName):
549 'Cl-': 0, 'Na+': 1, 'SSD_E': 2, 'SSD_RF': 3, 'SSD': 4, 'SSD1': 5,
550 'TIP3P': 6, 'TIP4P': 7, 'TIP4P-Ew': 8, 'TIP5P': 9, 'TIP5P-E': 10,
551 'SPCE': 11, 'SPC': 12, 'DPD': 13, 'CG2': 14, 'SSDQ': 15, 'SSDQO': 16,
552 'TIP4P-Ice': 17, 'TIP4P-2005': 18, 'SPC-HW': 19, 'NE6': 20,
553 'TIP3P-FB': 21, 'TIP4P-FB': 22, 'OPC': 23, 'OPC3': 24
555 waterCase = water_models.get(waterName, -1)
559 return (waterCase, invalidWater)
561# Function to print the meta data
562def print_meta_data(outfile, doWaterInc, waterName, waterCase, invalidWater,
563 nMol, cutoff, alpha):
564 outfile.write(" <MetaData>\n")
567 outfile.write('#include "water.inc"')
569 print_water_model(waterCase, outfile)
572 print_fake_water(waterName, outfile)
574 outfile.write("\n\n")
575 outfile.write("component{\n")
576 outfile.write(" type = \"{}\";\n".format(waterName))
577 outfile.write(" nMol = {};\n".format(nMol))
579 outfile.write("ensemble = \"LangevinHull\";\n")
580 outfile.write("forceField = \"Water\";\n")
581 outfile.write("electrostaticSummationMethod = \"shifted_force\";\n")
582 outfile.write("electrostaticScreeningMethod = \"damped\";\n")
583 outfile.write("cutoffRadius = {};\n".format(cutoff))
584 outfile.write("dampingAlpha = {};\n".format(alpha))
585 outfile.write("usePeriodicBoundaryConditions = \"false\";\n")
587 outfile.write("targetTemp = 300;\n")
588 outfile.write("targetPressure = 1.0;\n")
590 outfile.write("tauThermostat = 1e3;\n")
591 outfile.write("tauBarostat = 1e4;\n")
593 outfile.write("dt = 2.0;\n")
594 outfile.write("runTime = 1e3;\n")
596 outfile.write("tempSet = \"true\";\n")
597 outfile.write("thermalTime = 10;\n")
598 outfile.write("sampleTime = 100;\n")
599 outfile.write("statusTime = 2;\n")
600 outfile.write(" </MetaData>\n")
602# Function to print the frame data
603def print_frame_data(outfile, boxx, boxy, boxz):
604 outfile.write(" <Snapshot>\n")
605 outfile.write(" <FrameData>\n")
606 outfile.write(" Time: 0\n")
607 outfile.write(" Hmat: {{{{ {}, 0, 0 }}, {{ 0, {}, 0 }}, {{ 0, 0, {} }}}}\n".format(boxx, boxy, boxz))
608 outfile.write(" </FrameData>\n")
610# Function to write the output file
611def write_output_file(outfile, nMol, xCorr, yCorr, zCorr, cutoff, alpha,
612 boxx, boxy, boxz, waterName, waterCase, invalidWater,
613 doRandomize, doWaterInc):
614 # Write out the header
615 outfile.write("<OpenMD version=2>\n")
616 find_cutoff(cutoff, boxx, boxy, boxz)
617 print_meta_data(outfile, doWaterInc, waterName, waterCase, invalidWater,
619 print_frame_data(outfile, boxx, boxy, boxz)
620 outfile.write(" <StuntDoubles>\n")
622 # Shift the box center to the origin and write out the coordinates
623 for i in range(nMol):
624 xCorr[i] -= 0.5 * boxx
625 yCorr[i] -= 0.5 * boxy
626 zCorr[i] -= 0.5 * boxz
632 cosTheta = 2.0 * random.random() - 1.0
633 theta = acos(cosTheta)
634 phi = 2.0 * math.pi * random.random()
635 psi = 2.0 * math.pi * random.random()
637 q0 = math.cos(0.5 * theta) * math.cos(0.5 * (phi + psi))
638 q1 = math.sin(0.5 * theta) * math.cos(0.5 * (phi - psi))
639 q2 = math.sin(0.5 * theta) * math.sin(0.5 * (phi - psi))
640 q3 = math.cos(0.5 * theta) * math.sin(0.5 * (phi + psi))
642 outfile.write("{}\tpq\t{} {} {} {} {} {} {}\n".format(i, xCorr[i], yCorr[i], zCorr[i], q0, q1, q2, q3))
644 outfile.write(" </StuntDoubles>\n")
645 outfile.write(" </Snapshot>\n")
646 outfile.write("</OpenMD>\n")
650 parser = argparse.ArgumentParser(
651 description='builds spheres of water',
652 formatter_class=argparse.RawDescriptionHelpFormatter,
655Note: you can only use values of -O that are smaller
656 than the derived radius for a given density and
660 waterSphere -d 0.997 -I 20 -O 40 -w SSD_RF -o ssdrfWater.omd
662 parser.add_argument("-d", "--density=", action="store", dest='density',
663 type=float, help="density in g/cm^3",
664 required=False, default=1.0)
665 parser.add_argument("-l", "--lattice=", choices=[0,1],
666 action="store", dest='lattice',
667 type=int, default=0, required=False,
668 help="0 - face centered cubic, 1 - simple cubic")
669 parser.add_argument("-c", "--rcut=", action="store", dest="rcut",
670 type=float, default=3.2, required=False,
671 help="default overlap cutoff in angstroms")
672 parser.add_argument("-o", "--output=", action="store", dest='fileName',
673 help="output file name", required=False,
674 default="freshWater.omd")
675 parser.add_argument("-w", "--water=", action="store", dest="waterName",
676 help="name of the water StuntDouble",
677 required=False, default="SPCE")
678 parser.add_argument("-r", "--randomize",
679 action=argparse.BooleanOptionalAction, default=False,
680 type=bool, dest='doRandomize',
681 help="randomize orientations")
682 parser.add_argument("-O", "--outer_radius", action="store", required=True,
683 dest='outer_radius', type=float,
684 help="outer radius of the water sphere")
685 parser.add_argument("-I", "--inner_radius", action="store", required=False,
686 dest='inner_radius', type=float, default=0.0,
687 help="inner radius of the water sphere")
688 parser.add_argument("-m", "--printInclude",
689 action=argparse.BooleanOptionalAction, default=False,
690 type=bool, dest='doWaterInc',
691 help="print out a water.inc file (file with all water models)")
693 if len(sys.argv) == 1:
696 args = parser.parse_args()
698 density = args.density
699 lattice = args.lattice
701 fileName = args.fileName
702 waterName = args.waterName
703 outer_radius = args.outer_radius
704 inner_radius = args.inner_radius
705 boxx = boxy = boxz = 2 * outer_radius
706 doRandomize = args.doRandomize
707 doWaterInc = args.doWaterInc
710 mass = 2.99151E-23 # mass of H2O in grams
711 cm3ToAng3 = 1E24 # convert cm^3 to angstroms^3
712 densityConvert = mass * cm3ToAng3
719 if fileName == 'water.inc':
720 sys.exit("Error: {} cannot be \"water.inc\"\n Please choose a different name\n".format(fileName))
723 sys.exit("Error: the value for '-d' ({}) is not a valid number\n Please choose a positive real # value\n".format(density))
726 sys.exit("Error: the value for '-c' ({}) is not a valid number\n Please choose a positive real # value\n".format(arg))
727 if lattice != 0 and lattice != 1:
729 sys.exit("Error: the '-l' value ({}) is not a valid number\n Please choose 0 or 1\n".format(arg))
730 if outer_radius <= 0:
732 sys.exit("Error: the value for '-O' ({}) is not a valid number\n Please choose a positive real # value\n".format(outer_radius))
735 sys.exit("Error: the value for '-I' ({}) is not a valid number\n Please choose a positive real # value\n".format(inner_radius))
737 outfile = open_output_file(fileName)
739 # Set magic lattice numbers
741 a = (4 * 18.01 / (0.602 * density)) ** (1.0 / 3.0)
742 acut = rcut * math.sqrt(2.0)
745 newDensity = 4.0 * 18.01 / (0.602 * a ** 3)
746 print("using density of {} to match cutoff value ({})\n".format(newDensity, rcut))
748 a = (18.01 / (0.602 * density)) ** (1.0 / 3.0)
752 newDensity = 18.01 / (0.602 * a ** 3)
753 print("using density of {} to match cutoff value ({})\n".format(newDensity, rcut))
756 nx = int(nxFloat + nxFloat / abs(nxFloat * 2))
758 ny = int(nyFloat + nyFloat / abs(nyFloat * 2))
760 nz = int(nzFloat + nzFloat / abs(nzFloat * 2))
762 anew = min(boxx / nx, boxy / ny, boxz / nz)
767 nxFloat = boxx / anew
768 nx = int(nxFloat + nxFloat / abs(nxFloat * 2))
769 nyFloat = boxy / anew
770 ny = int(nyFloat + nyFloat / abs(nyFloat * 2))
771 nzFloat = boxz / anew
772 nz = int(nzFloat + nzFloat / abs(nzFloat * 2))
775 nMol = 4 * nx * ny * nz
779 newDensity = nMol * densityConvert / (boxx * boxy * boxz)
781 if abs(newDensity - density) > tolerance:
782 print("Resetting density to {} to make chosen box sides work out\n".format(newDensity))
784 cellLengthX = boxx / nx
785 cellLengthY = boxy / ny
786 cellLengthZ = boxz / nz
788 cell2X = cellLengthX * 0.5
789 cell2Y = cellLengthY * 0.5
790 cell2Z = cellLengthZ * 0.5
802 xref = [0.0, 0.0, cell2X, cell2X]
803 yref = [0.0, cell2Y, cell2Y, 0.0]
804 zref = [0.0, cell2Z, 0.0, cell2Z]
811 xt = xref[uc] + cellLengthX * x - centerx
812 yt = yref[uc] + cellLengthY * y - centery
813 zt = zref[uc] + cellLengthZ * z - centerz
814 if inSphere(xt, yt, zt, outer_radius) and \
815 inSphere(xt, yt, zt, inner_radius) == False:
829 xt = xref[uc] + cellLengthX * x - centerx
830 yt = yref[uc] + cellLengthY * y - centery
831 zt = zref[uc] + cellLengthZ * z - centerz
832 if inSphere(xt, yt, zt, outer_radius) and \
833 inSphere(xt, yt, zt, inner_radius) == False:
841 (waterCase, invalidWater) = validate_water(waterName)
843 print("Warning: '{}' is not a recognized water model name.\n".format(waterName))
844 print(" Use the '-m' option to generate a 'water.inc' with the\n")
845 print(" recognized water model geometries.\n\n")
846 if waterName == 'DPD':
848 elif waterName == 'CG2':
851 write_output_file(outfile, nMol, xCorr, yCorr, zCorr, cutoff, alpha,
852 boxx, boxy, boxz, waterName, waterCase, invalidWater,
853 doRandomize, doWaterInc)
856 print("The water box \"{}\" was generated.\n".format(fileName))
860 outfile = open("./water.inc", "w")
862 sys.exit("Error: can't open file {}\n".format("water.inc"))
864 outfile.write("#ifndef _WATER_INC_\n#define _WATER_INC_\n")
868 print_ssd_rf(outfile)
873 print_tip4pew(outfile)
875 print_tip5pe(outfile)
882 print_tip4p_ice(outfile)
883 print_tip4p_2005(outfile)
884 print_spc_hw(outfile)
886 print_tip3p_fb(outfile)
887 print_tip4p_fb(outfile)
890 outfile.write("\n\n#endif")
892 print("The file \"water.inc\" was generated for inclusion in \"{}\"\n".format(fileName))
896if __name__ == "__main__":