def _WriteMEADFiles(self, system, systemCharges, systemRadii): """For each instance of each site, write: - PQR file for the site - PQR file for the model compound - OGM file for the site - MGM file for the model compound""" grids = [] model = self.parent for stepIndex, (nodes, resolution) in enumerate(model.focusingSteps): if stepIndex < 1: grids.append("ON_GEOM_CENT %d %f\n" % (nodes, resolution)) else: x, y, z = self.center grids.append("(%f %f %f) %d %f\n" % (x, y, z, nodes, resolution)) selectSite = Selection(self.siteAtomIndices) selectModel = Selection(self.modelAtomIndices) # . In the PQR file of the model compound, charges of the site atoms must be set to zero (requirement of the my_2diel_solver program) chargesZeroSite = Clone(systemCharges) for atomIndex in self.siteAtomIndices: chargesZeroSite[atomIndex] = 0.0 for instance in self.instances: PQRFile_FromSystem( instance.modelPqr, system, selection=selectModel, charges=chargesZeroSite, radii=systemRadii, ) # . Update system charges with instance charges chargesInstance = Clone(systemCharges) for chargeIndex, atomIndex in enumerate(self.siteAtomIndices): chargesInstance[atomIndex] = instance.charges[chargeIndex] PQRFile_FromSystem( instance.sitePqr, system, selection=selectSite, charges=chargesInstance, radii=systemRadii, ) del chargesInstance # . Write OGM and MGM files (they have the same content) for fileGrid in (instance.modelGrid, instance.siteGrid): WriteInputFile(fileGrid, grids) del chargesZeroSite
def _PlaceIonsAtGridPoints ( ions, grid, unoccupied ): """Place ions at grid points.""" # # . Placement is currently done randomly. In principle it could also be done using energies using a procedure such as: # # - Calculate potentials (1/r,1/r^6,1/r^12) on unoccupied grid points due to protein. # - Loop over ions (+/- alternate pairs): # Determine energy of each grid points as q * pot(1/r) + e * s^3 * pot(1/r^6) + ... # Find point with lowest energy and put ion at this point. # Update potentials due to the ion at this point. # # . Requires a single NB model method that calculates/updates potentials. # # . However, a similar result can be achieved by using random placement, doing a Monte Carlo (no waters) with # . an NBModel with dielectric of 80 and then choosing low energy conformations. # # . Number of ions. nions = len ( ions.atoms ) # . Get a random number of points from the unoccupied sites. points = sample ( unoccupied, nions ) # . Calculate the coordinates - these are implicitly sorted due to the selection. coordinates3 = Coordinates3_FromGrid ( grid, selection = Selection.FromIterable ( points ) ) # . Shuffle again. points = sample ( range ( nions ), nions ) for ( n, p ) in enumerate ( points ): for i in range ( 3 ): ions.coordinates3[n,i] = coordinates3[p,i]
def CovarianceMatrix(*arguments, **keywordArguments): """Calculate the covariance matrix for selected particles.""" # . Initialization. covariance = None # . Get the trajectory and associated system data. (system, trajectories) = _GetSystemAndTrajectoriesFromArguments(*arguments) # . Get the selection and the size of the problem. selection = keywordArguments.pop("selection", None) if selection is None: selection = Selection.FromIterable(range(len(system.atoms))) n = 3 * len(selection) # . Get the average positions. averagePositions = keywordArguments.pop("averagePositions", None) if averagePositions is None: averagePositions = AveragePositions(trajectories, selection=selection) _CheckForUnknownOptions(keywordArguments) # . Continue processing. if (n > 0) and (averagePositions is not None): # . Allocate space. covariance = SymmetricMatrix.WithExtent(n) covariance.Set(0.0) displacement = Real1DArray.WithExtent(n) displacement.Set(0.0) # . Loop over trajectory frames. numberFrames = 0 for trajectory in trajectories: trajectory.ReadHeader() while trajectory.RestoreOwnerData(): frame = system.coordinates3 for (p, i) in enumerate(selection): displacement[3 * p] = frame[i, 0] - averagePositions[p, 0] displacement[3 * p + 1] = frame[i, 1] - averagePositions[p, 1] displacement[3 * p + 2] = frame[i, 2] - averagePositions[p, 2] for i in range(n): dI = displacement[i] for j in range(i + 1): covariance[i, j] += (dI * displacement[j]) trajectory.ReadFooter() trajectory.Close() numberFrames += len(trajectory) # . Scale. if numberFrames > 0: covariance.Scale(1.0 / float(numberFrames)) return covariance
def ToFixedAtoms(self, system): """Define fixed atoms for the system.""" natoms = self.counters.get("Atoms", 0) if natoms > 0: # . Get the fixed atom indices. indices = [] for (index, datum) in enumerate(self.atoms): flag = datum[8] if flag == 1: indices.append(index) # . Define the fixed atoms. if len(indices) > 0: system.DefineFixedAtoms(Selection.FromIterable(indices))
def BuildSolventBox ( crystalClass, symmetryParameters, molecule, density, log = logFile, randomNumberGenerator = None ): """Build a solvent box. No attempt is made to avoid overlapping molecules as it is assumed this will be corrected in a subsequent optimization process. """ # . Initialization. solvent = None # . Find the number of solvent molecules that fit in the box. nmolecules = SolventMoleculeNumber ( molecule, symmetryParameters, density ) # . Check the number of molecules. if nmolecules > 0: # . Create the solvent system. molecule.coordinates3.ToPrincipalAxes ( ) solvent = MergeRepeatByAtom ( molecule, nmolecules ) solvent.DefineSymmetry ( crystalClass = crystalClass, a = symmetryParameters.a, \ b = symmetryParameters.b, \ c = symmetryParameters.c, \ alpha = symmetryParameters.alpha, \ beta = symmetryParameters.beta, \ gamma = symmetryParameters.gamma ) # . Check the random number generator. if randomNumberGenerator is None: randomNumberGenerator = RandomNumberGenerator.WithRandomSeed ( ) # . Do random rotations and translations. natoms = len ( molecule.atoms ) rotation = Matrix33.Null ( ) selection = Selection.FromIterable ( range ( natoms ) ) translation = Vector3.Null ( ) for i in range ( nmolecules ): rotation.RandomRotation ( randomNumberGenerator ) solvent.coordinates3.Rotate ( rotation, selection = selection ) for j in range ( 3 ): translation[j] = randomNumberGenerator.NextReal ( ) symmetryParameters.M.ApplyTo ( translation ) solvent.coordinates3.Translate ( translation, selection = selection ) selection.Increment ( natoms ) # . Do some printing. if LogFileActive ( log ): summary = log.GetSummary ( ) summary.Start ( "Cubic Solvent Box Summary" ) summary.Entry ( "Number of Molecules", "{:d}" .format ( nmolecules ) ) summary.Entry ( "Density (kg m^-3)", "{:.3f}".format ( SystemDensity ( solvent ) ) ) summary.Entry ( "Box Volume", "{:.3f}".format ( solvent.symmetryParameters.volume ) ) summary.Stop ( ) # . Return the system. return solvent
def TypeAtoms(self, connectivity, sequence, log): """Assign atom types and charges to the atoms.""" # . Initialization. atomCharges = [0.0 for i in range(len(connectivity.atoms))] atomTypes = [None for i in range(len(connectivity.atoms))] untypedAtoms = Selection.FromIterable(range(len(atomTypes))) # . Type the atoms. self.TypeBySequence(sequence, atomTypes, atomCharges, untypedAtoms) self.TypeByPattern(connectivity, atomTypes, atomCharges, untypedAtoms) # . Check for untyped atoms. self.CheckUntypedAtoms(connectivity, untypedAtoms, log) # . Finish up. return (atomTypes, atomCharges)
def FilterAtoms ( self, filterlevel ): """Filter out Mopac-specific atoms.""" if self.QPARSED and ( filterlevel > -3 ): atomicNumbers = [] selected = [] for ( i, a ) in enumerate ( self.atomicNumbers ): if a >= filterlevel: atomicNumbers.append ( a ) selected.append ( i ) if len ( atomicNumbers ) < len ( self.atomicNumbers ): coordinates3 = Coordinates3.WithExtent ( len ( atomicNumbers ) ) coordinates3.Gather ( self.coordinates3, Selection.FromIterable ( selected ) ) self.atomicNumbers = atomicNumbers self.coordinates3 = coordinates3
def DefineQCModel(self, qcModel, log=logFile, qcSelection=None): """Define a quantum chemical model for the system.""" if isinstance(qcModel, QCModel): # . Get an energy model in the correct state. if self.energyModel is None: self.__dict__["_energyModel"] = EnergyModel() else: self.energyModel.ClearQCModel(self.configuration, fixedAtoms=None) em = self.energyModel # . Assign a default electronic state if necessary. if self.electronicState is None: self.electronicState = ElectronicState() # . Get the QC atom selection and the boundary atoms. if (qcSelection is None) or (qcSelection.size == len(self.atoms)): atomindices = Selection.FromIterable(range(len(self.atoms))) boundaryatoms = {} else: atomindices = qcSelection boundaryatoms = em.IdentifyBoundaryAtoms(atomindices) # . Set up the QC atom data. qcAtoms = QCAtomContainer_FromAtomContainer( self.atoms, atomindices, boundaryatoms, getattr(qcModel, "linkAtomRatio", True)) # . Get the qcParameters. anlist = qcAtoms.UniqueAtomicNumbers() qcParameters = qcModel.DefineParameters(anlist, log=log) # . Fill in the remaining qcatom data. qcAtoms.AssignParameterData(anlist, qcParameters) # . Save the data. em.qcAtoms = qcAtoms em.qcModel = qcModel em.__dict__["qcParameters"] = qcParameters em.MakeLabel() # . Modify the MM terms if appropriate. em.DeactivateQCAtomMMTerms() # . Deactivate MM terms if fixed atoms are defined. if (self.hardConstraints is not None): em.DeactivateFixedAtomMMTerms(self.hardConstraints.fixedAtoms) # . Check the total MM charge. em.CheckActiveMMAtomTotalCharge()
def AveragePositions(*arguments, **keywordArguments): """Calculate the average positions for selected particles.""" # . Initialization. positions = None # . Process arguments. (system, trajectories) = _GetSystemAndTrajectoriesFromArguments(*arguments) # . Get the selection (or all particles otherwise). selection = keywordArguments.pop("selection", None) if selection is None: selection = Selection.FromIterable(range(len(system.atoms))) _CheckForUnknownOptions(keywordArguments) # . Get the size of the problem. n = len(selection) if n > 0: # . Allocate space. positions = Coordinates3.WithExtent(n) positions.Set(0.0) # . Loop over trajectory frames. numberFrames = 0 for trajectory in trajectories: trajectory.ReadHeader() while trajectory.RestoreOwnerData(): frame = system.coordinates3 for (p, i) in enumerate(selection): positions[p, 0] += frame[i, 0] positions[p, 1] += frame[i, 1] positions[p, 2] += frame[i, 2] trajectory.ReadFooter() trajectory.Close() numberFrames += len(trajectory) # . Scale. if numberFrames > 0: positions.Scale(1.0 / float(numberFrames)) return positions
def SetUpSystem(path, forceNoQC=False, useSystemWithTimings=True): """Set up the system.""" # . Get system data. systemData = YAMLUnpickle(os.path.join(path, _TestDataFileName)) # . Get the parameters. parameters = CHARMMParameterFiles_ToParameters( glob.glob(os.path.join(path, "*.prm"))) # . Get the test name. name = os.path.split(path)[-1] # . Generate the system. system = CHARMMPSFFile_ToSystem(os.path.join(path, name + ".psfx"), isXPLOR=True, parameters=parameters) if useSystemWithTimings: system = SystemWithTimings.FromSystem(system) system.coordinates3 = XYZFile_ToCoordinates3( os.path.join(path, name + ".xyz")) system.label = systemData["Label"] # . Symmetry. if systemData.get("Crystal Class", None) is not None: symmetryOptions = systemData["Symmetry Parameters"] symmetryOptions["crystalClass"] = _CrystalClasses[ systemData["Crystal Class"]] system.DefineSymmetry(**symmetryOptions) # . QC data. if not forceNoQC: qcData = systemData.get(_QCRegionKey, None) if qcData is not None: # . Electronic state. system.electronicState = ElectronicState( charge=qcData.get("Charge", 0), multiplicity=qcData.get("Multiplicity", 1)) # . QC atoms. qcAtoms = set() for path in qcData["Atoms"]: index = system.sequence.AtomIndex(path) qcAtoms.add(index) system.DefineQCModel(_QCModel, qcSelection=Selection(qcAtoms)) # . Finish set up. system.DefineNBModel(_NBModel) return system
def ExtractDisorderData ( self, dataBlock, system, disorderGroup = _DefaultDisorderGroup ): """Extract atom data from a data block.""" result = system table = dataBlock.get ( "atom_site", None ) if table is not None: # . Disorder and multiplicity information. assemblies = table.ColumnValues ( "atom_site_disorder_assembly" ) groups = table.ColumnValues ( "atom_site_disorder_group" ) multiplicities = table.ColumnValues ( "atom_site_symmetry_multiplicity" ) # . Check for the disorder groups to include. if groups is not None: uniqueGroups = set ( groups ) uniqueGroups.discard ( disorderGroup ) uniqueGroups.discard ( "-" + disorderGroup ) uniqueGroups.discard ( _UndefinedCharacter ) if len ( uniqueGroups ) > 0: toInclude = set ( [ _UndefinedCharacter, disorderGroup, "-" + disorderGroup ] ) indices = [] for ( i, group ) in enumerate ( groups ): if group in toInclude: indices.append ( i ) if len ( indices ) < len ( groups ): result = system.Prune ( Selection ( indices ) ) result.label = system.label return result
def RadialDistributionFunction(*arguments, **keywordArguments): """Calculate a radial distribution function.""" # . Get the trajectory and associated system data. (system, trajectories) = _GetSystemAndTrajectoriesFromArguments(*arguments) # . Keyword arguments. bins = keywordArguments.pop("bins", 100) log = keywordArguments.pop("log", logFile) safety = keywordArguments.pop("safety", _DEFAULTSAFETY) selection1 = keywordArguments.pop("selection1", None) selection2 = keywordArguments.pop("selection2", None) upper = keywordArguments.pop("maximumR", None) if selection1 is None: selection1 = Selection.FromIterable(range(len(system.atoms))) if selection2 is None: selection2 = selection1 _CheckForUnknownOptions(keywordArguments) # . Get the numbers of particles. np1 = len(selection1) np2 = len(selection2) # . Check for a cubic system. try: cc = system.symmetry.crystalClass if not isinstance(cc, CrystalClassCubic): raise except: raise ValueError("System does not have cubic symmetry.") # . Estimate an upper bound. if upper is None: try: upper = (system.symmetryParameters.a - safety) / 2.0 except: raise ValueError( "Please supply an upper bound for the RDF calculation.") # . Initialization. lower = 0.0 distances = [] histogram = [0 for i in range(bins)] rdf = [] # . Calculate the width of each bin. width = (upper - lower) / float(bins) vacc = 0.0 # . Loop over trajectory frames. numberFrames = 0 for trajectory in trajectories: trajectory.ReadHeader() while trajectory.RestoreOwnerData(): # . Get the frame. frame = system.coordinates3 numberFrames += 1 # . Accumulate the volume. a = system.symmetryParameters.a vacc += a**3 # . Check a. if upper > 0.5 * a: raise ValueError( "Box does not satisfy minimum image convention.") # . Bin the distances. # . This loop involves duplicate work for self rdfs. for i in selection1: for j in selection2: if i != j: dr = frame.Displacement(i, j) for c in range(3): x = a * round(dr[c] / a) dr[c] -= x r = dr.Norm2() if (r >= lower) and (r < upper): b = int((r - lower) / width) histogram[b] += 1 # . Finish up. trajectory.ReadFooter() trajectory.Close() # . Calculate g(r). fact = 4.0 * math.pi * float(np1 * np2 * numberFrames**2) / (3.0 * vacc) for i in range(bins): rlower = lower + float(i) * width rupper = rlower + width distances.append(rlower + 0.5 * width) rdf.append(float(histogram[i]) / (fact * (rupper**3 - rlower**3))) # . Output the results. if LogFileActive(log): table = log.GetTable(columns=[20, 20]) table.Start() table.Title("Radial Distribution Function") table.Heading("Distance") table.Heading("g(r)") for (r, g) in zip(distances, rdf): table.Entry("{:20.4f}".format(r)) table.Entry("{:20.4f}".format(g)) table.Stop() # . Return results. return (distances, rdf)
def SelfDiffusionFunction(*arguments, **keywordArguments): """Calculate the self diffusion function.""" # . Get the trajectory and associated system data. (system, trajectories) = _GetSystemAndTrajectoriesFromArguments(*arguments) # . Keyword arguments. log = keywordArguments.pop("log", logFile) maximumTime = keywordArguments.pop("maximumTime", None) selection = keywordArguments.pop("selection", None) timeStep = keywordArguments.pop("timeStep", 1.0) if selection is None: selection = Selection.FromIterable(range(len(system.atoms))) _CheckForUnknownOptions(keywordArguments) # . Initialization. np = len(selection) # . The number of particles. dSelf = [] frames = [] times = [] # . Loop over trajectory frames. for trajectory in trajectories: trajectory.ReadHeader() while trajectory.RestoreOwnerData(): frames.append(system.coordinates3.Prune(selection)) trajectory.ReadFooter() trajectory.Close() # . Get the number of frames and tStop. numberFrames = len(frames) if maximumTime is None: tStop = numberFrames - 1 else: tStop = int(maximumTime / timeStep) tStop = min(numberFrames - 1, tStop) # . Calculate the function - slow version. # . Loop over time differences to calculate. for t in range(tStop + 1): # . Initialization. tmax = numberFrames - t total = 0.0 # . Loop over allowed increments. for t0 in range(tmax): # . Calculate differences. fa = frames[t0 + t] fb = frames[t0] for i in range(np): total += (fa[i, 0] - fb[i, 0])**2 + ( fa[i, 1] - fb[i, 1])**2 + (fa[i, 2] - fb[i, 2])**2 # . Calculate dSelf. dSelf.append(total / float(3 * np * tmax)) times.append(float(t) * timeStep) # . Output the results. if LogFileActive(log): table = log.GetTable(columns=[20, 20]) table.Start() table.Title("Self-Diffusion Function") table.Heading("Time") table.Heading("Dself") for (t, d) in zip(times, dSelf): table.Entry("{:20.4f}".format(t)) table.Entry("{:20.4f}".format(d)) table.Stop() # . Return results. return (times, dSelf)
"P61" : [ "(x,y,z)", "(-y,x-y,z+1/3)", "(-x+y,-x,z+2/3)", "(-x,-y,z+1/2)", "(y,-x+y,z+5/6)", "(x-y,x,z+1/6)" ], "P21c" : [ "(x,y,z)", "(-x,y+1/2,-z+1/2)", "(-x,-y,-z)", "(x,-y+1/2,z+1/2)" ], "P21a" : [ "(x,y,z)", "(-x+1/2,y+1/2,-z)", "(-x,-y,-z)", "(x+1/2,-y+1/2,z)" ], "R3" : [ "(x,y,z)", "(z,x,y)", "(y,z,x)" ] } # . Convert to transformation sets. _transformationSets = {} for ( key, olist ) in _operations.iteritems ( ): tset = [] for o in olist: tset.append ( Transformation3_FromSymmetryOperationString ( o ) ) _transformationSets[key] = Transformation3Container.WithTransformations ( tset ) # . Molecule definitions. _keywordLabels = ( "label", "canQCOptimize", "qcSelection", "qcCharge", "vacuumEnergy", "crystalEnergy", "crystalClass", "transformations", "crystalParameters" ) _moleculeData = ( ( "ALAALA", False, Selection.FromIterable ( range ( 6, 10 ) ), 0, -178.7095, -677.7298, CrystalClassTetragonal ( ), _transformationSets["I4"], { "a" : 17.9850, "c" : 5.1540 } ), ( "ALAMET01", False, Selection.FromIterable ( range ( 16, 27 ) ), 0, -135.0084, -652.9681, CrystalClassMonoclinic ( ), _transformationSets["P21c"], { "a" : 13.089, "b" : 5.329, "c" : 15.921, "beta" : 108.57 } ), ( "AQARUF", False, Selection.FromIterable ( range ( 6, 19 ) ), 0, -144.5558, -608.3551, CrystalClassHexagonal ( ), _transformationSets["P61"], { "a" : 14.3720, "c" : 9.8282 } ), ( "BEVXEF01", False, Selection.FromIterable ( range ( 23, 29 ) ), 0, -240.0604, -878.7555, CrystalClassOrthorhombic ( ), _transformationSets["P212121"], { "a" : 9.6590, "b" : 9.6720, "c" : 10.7390 } ), ( "GLYALB", False, Selection.FromIterable ( range ( 13, 17 ) ), 0, -44.8402, -562.9905, CrystalClassOrthorhombic ( ), _transformationSets["P212121"], { "a" : 9.6930, "b" : 9.5240, "c" : 7.5370 } ), ( "GLYGLY", False, Selection.FromIterable ( range ( 14, 17 ) ), -1, -184.8863, -687.4449, CrystalClassMonoclinic ( ), _transformationSets["P21a"], { "a" : 7.812, "b" : 9.566, "c" : 9.410, "beta" : 124.60 } ), ( "GUFQON", False, Selection.FromIterable ( range ( 13, 18 ) ), 0, -191.1490, -511.8117, CrystalClassOrthorhombic ( ), _transformationSets["P212121"], { "a" : 7.2750, "b" : 9.0970, "c" : 10.5070 } ), ( "HXACAN19", True, Selection.FromIterable ( range ( 16, 20 ) ), 0, 157.7170, 24.6588, CrystalClassMonoclinic ( ), _transformationSets["P21a"], { "a" : 12.8720, "b" : 9.3700, "c" : 7.0850, "beta" : 115.6200 } ), ( "IWANID", False, Selection.FromIterable ( range ( 37, 51 ) ), 0, 4380.9282, 4070.8472, CrystalClassMonoclinic ( ), _transformationSets["C2"], { "a" : 23.091, "b" : 5.494, "c" : 17.510, "beta" : 117.88 } ), ( "LCDMPP10", True, Selection.FromIterable ( range ( 4, 8 ) ), 0, 157.3277, 40.3629, CrystalClassTriclinic ( ), _transformationSets["P1"], { "a" : 8.067, "b" : 6.082, "c" : 5.155, "alpha" : 131.7, "beta" : 82.4, "gamma" : 106.6 } ), ( "WIRYEB", False, Selection.FromIterable ( range ( 6, 16 ) ), 0, -155.7355, -612.6186, CrystalClassHexagonal ( ), _transformationSets["P61"], { "a" : 14.4240, "c" : 9.9960 } ), ( "WABZOO", True, Selection.FromIterable ( range ( 0, 4 ) + range ( 10, 14 ) + range ( 18, 25 ) ), 0, 209.9697, 152.9967, CrystalClassRhombohedral ( ), _transformationSets["R3"], { "a" : 12.5940 , "alpha" : 118.0300 } ) ) # . Options for expanding to P1 symmetry. _defaultRange = range ( 1 ) #range ( -1, 2 ) _aRange = _defaultRange
def Within ( self, distance, excludeSelf = False ): """Selection of atoms within a given distance.""" # . Find all atoms within distance of the current selection. selfSelection = self.selection system = self.system pairlist = CrossPairList_FromSingleCoordinates3 ( system.coordinates3, selection1 = Selection.FromIterable ( selfSelection ), safety = distance ) selection = set ( selfSelection ) for ( i, j ) in pairlist: selection.add ( j ) # . Exclude self? if excludeSelf: selection -= self.selection # . Finish up. return self.__class__ ( selection = selection, system = self.system )
# takes no (interesting) arguments. # # . Note on scratch names: # # It has been noticed that ORCA itself can give an error when the name of the scratch directory is too long. # This occurs in the "%pcname" line of the ORCA input file. To cure this use a shorter name - either by resetting # the environment variable PDYNAMO_SCRATCH or by explicitly passing a name to the model with the "scratch" option. # # . Define the MM, NB and QC models. mmModel = MMModelOPLS("bookSmallExamples") nbModel = NBModelORCA() qcModel = QCModelORCA("MP2:6-31G*", "EXTREMESCF", "SCFCONV10") # . Define the molecule. molecule = MOLFile_ToSystem( os.path.join(os.getenv("PDYNAMO_PMOLECULE"), "data", "mol", "waterDimer_cs.mol")) # . Define the selection for the first molecule. firstWater = Selection.FromIterable([0, 1, 2]) # . Define the energy model. molecule.DefineMMModel(mmModel) molecule.DefineQCModel(qcModel, qcSelection=firstWater) molecule.DefineNBModel(nbModel) molecule.Summary() # . Calculate an energy. molecule.Energy(doGradients=True)
def runTest(self): """The test.""" # . Initialization. dataPath = os.path.join(os.getenv("PDYNAMO_PMOLECULE"), "data", "mol") log = self.GetLog() translation = Vector3.Uninitialized() # . Get the individual systems. energies = [] molecules = [] for (i, label) in enumerate(_Molecules): molecule = MOLFile_ToSystem(os.path.join(dataPath, label + ".mol")) molecule.label = label molecule.DefineMMModel(_mmModel) molecule.DefineNBModel(_nbModel) molecule.Summary(log=log) molecule.coordinates3.TranslateToCenter() molecule.configuration.Clear() energies.append(molecule.Energy(log=log, doGradients=True)) molecules.append(molecule) # . Data initialization. observed = {} referenceData = TestDataSet("Merge/Prune Energies") # . Loop over the tests. for (testIndex, (moleculeFrequencies, moleculePruneIndices)) in enumerate(_Tests): # . Heading. if log is not None: log.Heading("Merge/Prune Test {:d}".format(testIndex), QBLANKLINE=True) # . Initialization. mergedEnergy = 0.0 prunedEnergy = 0.0 translation.Set(0.0) # . Gather items. index = 0 numberAtoms = 0 pruneIndices = [] toMerge = [] for (i, frequency) in enumerate(moleculeFrequencies): molecule = molecules[i] mergedEnergy += energies[i] * frequency for f in range(frequency): cloned = Clone(molecule) translation[0] += _Displacement cloned.coordinates3.Translate(translation) toMerge.append(cloned) if index in moleculePruneIndices: pruneIndices.extend( range(numberAtoms, numberAtoms + len(cloned.atoms))) prunedEnergy += energies[i] index += 1 numberAtoms += len(cloned.atoms) # . Merging. merged = toMerge[0].Merge(toMerge[1:]) merged.Summary(log=log) eMerged = merged.Energy(log=log) # . Pruning. pruned = merged.Prune(Selection.FromIterable(pruneIndices)) pruned.Summary(log=log) ePruned = pruned.Energy(log=log) # . Get the observed and reference data. for (tag, eObserved, eReference) in (("Merged Energy {:d}".format(testIndex), eMerged, mergedEnergy), ("Pruned Energy {:d}".format(testIndex), ePruned, prunedEnergy)): observed[tag] = eObserved referenceData.AddDatum( TestReal( tag, eReference, referenceData, absoluteErrorTolerance=_EnergyAbsoluteErrorTolerance, toleranceFormat="{:.3f}", valueFormat="{:.3f}")) # . Finish up. if log is not None: log.Separator() # . Check for success/failure. if len(observed) > 0: results = referenceData.VerifyAgainst(observed) results.Summary(log=log, fullSummary=self.fullVerificationSummary) isOK = results.WasSuccessful() else: isOK = True # . Success/failure. self.assertTrue(isOK)
def runTest(self): """The test.""" # . Output setup. dataPath = os.path.join(os.getenv("PDYNAMO_PMOLECULE"), "data", "mol") log = self.GetLog() # . Define the MM, NB and QC models. mmModel = MMModelOPLS("bookSmallExamples") nbModel = NBModelFull() qcModel = QCModelMNDO() # . Define the dimer with an MM model. dimer = MOLFile_ToSystem(os.path.join(dataPath, "waterDimer_cs.mol")) dimer.DefineMMModel(mmModel) dimer.Summary(log=log) # . Define the monomer selections. selection1 = Selection.FromIterable(range(0, 3)) selection2 = Selection.FromIterable(range(3, 6)) # . Get the monomer energies. e1 = self.MonomerEnergies(dimer, selection1, nbModel, qcModel, log=log) e2 = self.MonomerEnergies(dimer, selection2, nbModel, qcModel, log=log) # . Get the binding energies. e12 = {} for model1 in _Models: for model2 in _Models: key = model1 + " " + model2 if log is not None: log.Heading(model1 + "/" + model2 + " Dimer Calculation", QBLANKLINE=True) # . Define the energy model. if key == "QC QC": dimer.DefineQCModel(qcModel) elif key == "QC MM": dimer.DefineQCModel(qcModel, qcSelection=selection1) elif key == "MM QC": dimer.DefineQCModel(qcModel, qcSelection=selection2) else: dimer.energyModel.ClearQCModel(dimer.configuration) if "MM" in key: dimer.DefineNBModel(nbModel) dimer.Summary(log=log) # . Store the results. e12[key] = dimer.Energy(log=log) - e1[model1] - e2[model2] # . Output the results. if log is not None: keys = e12.keys() keys.sort() table = log.GetTable(columns=[20, 20, 20]) table.Start() table.Title("Water Dimer Binding Energies") table.Heading("Monomer 1") table.Heading("Monomer 2") table.Heading("Binding Energy") for key in keys: (model1, model2) = key.split() table.Entry(model1) table.Entry(model2) table.Entry("{:.1f}".format(e12[key])) table.Stop() # . Success/failure. isOK = True for e in e12.values(): if (e < _LowerBound) or (e > _UpperBound): isOK = False break self.assertTrue(isOK)
def runTest ( self ): """The test.""" # . Initialization. failures = 0 otherFailures = 0 successes = 0 # . Paths. dataPath = os.path.join ( os.getenv ( "PDYNAMO_PMOLECULE" ), "data", "pdb" ) if self.resultPath is None: outPath = os.path.join ( os.getenv ( "PDYNAMO_SCRATCH" ), _Destination ) else: outPath = os.path.join ( self.resultPath, _Destination ) if not os.path.exists ( outPath ): os.mkdir ( outPath ) log = self.GetLog ( ) # . Models. mmModel = MMModelCHARMM ( "c36a2" ) nbModel = NBModelABFS ( ) qcModel = QCModelMNDO ( ) # . Get the file. pdbFile = os.path.join ( dataPath, "2E4E_folded_solvated.pdb" ) ( head, tail ) = os.path.split ( pdbFile ) tag = tail[0:-4] if log is not None: log.Text ( "\nProcessing " + pdbFile + ":\n" ) system = PDBFile_ToSystem ( pdbFile, log = log, useComponentLibrary = True ) try: # . Fixed atoms. fixedAtoms = Selection ( ~ AtomSelection.FromAtomPattern ( system, "A:*:*" ) ) # . QC selection. indices = set ( ) for atomTag in _Tags: indices.add ( system.sequence.AtomIndex ( "A:TYR.2:" + atomTag ) ) tyrosine = Selection ( indices ) # . Setup. system.electronicState = ElectronicState ( charge = 0, multiplicity = 1 ) system.DefineFixedAtoms ( fixedAtoms ) system.DefineSymmetry ( crystalClass = CrystalClassCubic ( ), a = _BoxSize ) system.DefineMMModel ( mmModel, log = log ) system.DefineQCModel ( qcModel, qcSelection = tyrosine ) system.DefineNBModel ( nbModel ) system.Summary ( log = log ) referenceEnergy = system.Energy ( log = log, doGradients = True ) # . Pickling. pklFile = os.path.join ( outPath, tag + ".pkl" ) yamlFile = os.path.join ( outPath, tag + ".yaml" ) Pickle ( pklFile , system ) YAMLPickle ( yamlFile, system ) # . Unpickling. pklSystem = Unpickle ( pklFile ) pklSystem.label += " (Pickled)" pklSystem.Summary ( log = log ) pklEnergy = pklSystem.Energy ( log = log, doGradients = True ) if math.fabs ( referenceEnergy - pklEnergy <= _Tolerance ): successes += 1 else: failures += 1 yamlSystem = YAMLUnpickle ( yamlFile ) yamlSystem.label += " (YAMLPickled)" yamlSystem.Summary ( log = log ) yamlEnergy = yamlSystem.Energy ( log = log, doGradients = True ) if math.fabs ( referenceEnergy - yamlEnergy <= _Tolerance ): successes += 1 else: failures += 1 except Exception as e: otherFailures += 1 if log is not None: log.Text ( "\nError occurred> " + e.args[0] + "\n" ) # . Summary of results. if log is not None: summary = log.GetSummary ( ) summary.Start ( "Pickle Tests" ) summary.Entry ( "Pickle Successes", "{:d}".format ( successes ) ) summary.Entry ( "Pickle Failures" , "{:d}".format ( failures ) ) summary.Entry ( "Total Tests" , "2" ) summary.Entry ( "Loop Failures" , "{:d}".format ( otherFailures ) ) summary.Stop ( ) # . Success/failure. self.assertTrue ( ( failures == 0 ) and ( otherFailures == 0 ) )
def SolvateSystemBySuperposition ( solute, solvent, log = logFile, excludeHydrogens = True, reorientSolute = True, printPairs = False, scaleradii = 0.75 ): """Solvate a system by superposition.""" # . Check that the solvent has a full connectivity. if not solvent.connectivity.HasFullConnectivity ( ): raise ValueError ( "The solvent must have a full connectivity." ) # . Create a sequence. if solute.sequence is not None: entityLabel = DetermineUniqueEntityLabel ( solute, label = "W" ) CreateHomogeneousIsolateSequence ( solvent, entityLabel = entityLabel ) # . Merge the two systems. solution = MergeByAtom ( solute, solvent ) # . Get the atom masses and selections corresponding to the solute and solvent atoms. masses = solution.atoms.GetItemAttributes ( "mass" ) nsolute = len ( solute.atoms ) nsolvent = len ( solvent.atoms ) soluteatoms = Selection.FromIterable ( range ( nsolute ) ) solventatoms = Selection.FromIterable ( range ( nsolute, nsolute + nsolvent ) ) # . Reorient the solute coordinates if required. if reorientSolute: solution.coordinates3.ToPrincipalAxes ( selection = soluteatoms, weights = masses ) # . Check the extents of the solute and solvent - to ensure the box is big enough! ( origin1, extents1 ) = solution.coordinates3.EnclosingOrthorhombicBox ( selection = soluteatoms ) ( origin2, extents2 ) = solution.coordinates3.EnclosingOrthorhombicBox ( selection = solventatoms ) extents2.AddScaledVector3 ( -1.0, extents1 ) if min ( extents2 ) < 0.0: raise ValueError ( "It is likely that the solvent box is too small for the solute." ) # . Move the center of the solute atoms to that of the solvent atoms. translation = Clone ( origin2 ) translation.AddScaledVector3 ( 0.5, extents2 ) # translation.AddScaledVector3 ( -0.5, extents1 ) # . Not needed as done above. translation.AddScaledVector3 ( -1.0, origin1 ) solution.coordinates3.Translate ( translation, selection = soluteatoms ) # . Reduce the selections if hydrogens are to be excluded. if excludeHydrogens: indices = [] for i in soluteatoms: if solution.atoms[i].atomicNumber != 1: indices.append ( i ) soluteatoms = Selection.FromIterable ( indices ) indices = [] for i in solventatoms: if solution.atoms[i].atomicNumber != 1: indices.append ( i ) solventatoms = Selection.FromIterable ( indices ) # . Get the radii. radii = solution.atoms.GetItemAttributes ( "vdwRadius" ) radii.Scale ( scaleradii ) # . Get the pairlist. pairlist = CrossPairList_FromSingleCoordinates3 ( solution.coordinates3, selection1 = solventatoms, selection2 = soluteatoms, radii = radii ) npairs = len ( pairlist ) # . Find the solvent atoms in the pairlist (which are the first indices in the list). indices = set ( ) for ( i, j ) in pairlist: indices.add ( i ) # . Now find the indices of all the atoms in the corresponding solvent isolates. if len ( indices ) > 0: toremove = solution.connectivity.isolates.GetAllIndices ( Selection.FromIterable ( indices ) ) ntoremove = len ( toremove ) # . Remove unwanted atoms. reduced = PruneByAtom ( solution, toremove.Complement ( upperBound = nsolute + nsolvent ) ) if solution.sequence is not None: RenumberEntityComponents ( reduced, entityLabels = [ entityLabel ] ) else: ntoremove = 0 reduced = solution # . Set the symmetry of solution by copying that of solvent. if ( solvent.symmetry is not None ) and ( solvent.symmetryParameters is not None ): keywordArguments = solvent.symmetryParameters.__getstate__ ( ) keywordArguments["crystalClass"] = solvent.symmetry.crystalClass keywordArguments["transformations"] = solvent.symmetry.transformations reduced.DefineSymmetry ( **keywordArguments ) # . Do some printing. if LogFileActive ( log ): # . Distances. if printPairs: table = log.GetTable ( columns = [ 10, 10, 20, 20 ] ) table.Start ( ) table.Title ( "Solute/Solvent Pairs" ) table.Heading ( "Solvent" ) table.Heading ( "Solute" ) table.Heading ( "Distance" ) table.Heading ( "Cutoff" ) for ( i, j ) in pairlist: table.Entry ( PeriodicTable.Symbol ( solution.atoms[i].atomicNumber, index = i ) ) table.Entry ( PeriodicTable.Symbol ( solution.atoms[j].atomicNumber, index = j ) ) table.Entry ( "{:.3f}".format ( solution.coordinates3.Distance ( i, j ) ) ) table.Entry ( "{:.3f}".format ( radii[i] + radii[j] ) ) table.Stop ( ) # . Summary. summary = log.GetSummary ( ) summary.Start ( "Solvation By Superposition Summary" ) summary.Entry ( "Solute Atoms" , "{:d}".format ( nsolute ) ) summary.Entry ( "Solvent Atoms" , "{:d}".format ( nsolvent - ntoremove ) ) summary.Entry ( "Atoms Removed" , "{:d}".format ( ntoremove ) ) summary.Entry ( "Solute/Solvent Pairs" , "{:d}".format ( npairs ) ) summary.Stop ( ) # . Finish up. return reduced
#=================================================================================================================================== # . Parameters for system definitions. #=================================================================================================================================== # . Model definitions. _converger = DIISSCFConverger(densityTolerance=1.0e-8, maximumSCFCycles=250) _qcModelDFT = QCModelDFT(converger=_converger, densityBasis="demon", orbitalBasis="321g") _qcModelMNDO = QCModelMNDO(converger=_converger) _qcModelORCA = QCModelORCA("HF:6-31G*", "SCFCONV10", "EXTREMESCF") _nbModel = NBModelABFS() # . Job data. # . Options: doQCMM for bottom layer, QC model for upper layer and QC selection for upper layer. _jobData = { "Water Dimer 1" : ( ( False, _qcModelDFT, Selection.FromIterable ( range ( 3 ) ) ), \ ( False, _qcModelORCA, Selection.FromIterable ( range ( 3, 6 ) ) ), \ ( True, _qcModelDFT, Selection.FromIterable ( range ( 3 ) ) ) ), \ "Water Dimer 2" : ( ( True, _qcModelORCA, Selection.FromIterable ( range ( 3, 6 ) ) ), ), \ "Cyclohexane 9" : ( ( False, _qcModelDFT, Selection.FromIterable ( range ( 6 ) ) ), \ ( True, _qcModelORCA, Selection.FromIterable ( range ( 3, 6 ) ) ) ), \ "Alanine Dipeptide" : ( ( False, _qcModelDFT, Selection.FromIterable ( range ( 10, 14 ) ) ), \ ( False, _qcModelORCA, Selection.FromIterable ( range ( 10, 14 ) ) ), \ ( True, _qcModelDFT, Selection.FromIterable ( range ( 10, 14 ) ) ), \ ( True, _qcModelORCA, Selection.FromIterable ( range ( 10, 14 ) ) ) ) } #=================================================================================================================================== # . Parameters for test. #=================================================================================================================================== # . Tolerances. _EnergyTolerance = 0.1
def WriteJobFiles(self, log=logFile): """Write files: PQR, FPT, OGM and MGM.""" if self.isInitialized: # . Get atomic charges and radii for the system system = self.owner systemCharges = system.AtomicCharges() systemRadii = [] systemTypes = system.energyModel.mmAtoms.AtomTypes() radii = YAMLUnpickle("%s/%s" % (YAMLPATHIN, "radii.yaml")) for atomType in systemTypes: if radii.has_key(atomType): radius = radii[atomType] else: generalAtomType = "%s*" % atomType[0] if radii.has_key(generalAtomType): radius = radii[generalAtomType] else: raise ContinuumElectrostaticsError( "Cannot find atomic radius for atom type %s" % atomType) systemRadii.append(radius) # . Prepare scratch space if not os.path.exists(self.pathScratch): try: os.makedirs(self.pathScratch) except: raise ContinuumElectrostaticsError( "Cannot create scratch directory %s" % self.pathScratch) # . Create subdirectories, if necessary if self.splitToDirectories: for site in self.sites: sitePqr = site.instances[0].sitePqr directory = os.path.dirname(sitePqr) if not os.path.exists(directory): try: os.makedirs(directory) except: raise ContinuumElectrostaticsError( "Cannot create directory %s" % directory) # . Write PQR, OGM and MGM files of all instances of all sites for site in self.sites: site._WriteMEADFiles(system, systemCharges, systemRadii) # . Write background PQR file PQRFile_FromSystem(self.pathPqrBack, system, selection=Selection(self.backAtomIndices), charges=systemCharges, radii=systemRadii) # . Write full-protein PQR file (to be used as eps2set_region) PQRFile_FromSystem(self.pathPqrProtein, system, selection=Selection(self.proteinAtomIndices), charges=systemCharges, radii=systemRadii) # . Write FPT-file lines = [] for siteIndex, site in enumerate(self.sites): for instanceIndex, instance in enumerate(site.instances): for atomIndex, charge in zip(site.siteAtomIndices, instance.charges): x, y, z = system.coordinates3[atomIndex] line = "%d %d %f %f %f %f\n" % ( siteIndex, instanceIndex, x, y, z, charge) lines.append(line) WriteInputFile(self.pathFptSites, lines) self.isFilesWritten = True
import math, os.path from pBabel import MOLFile_ToSystem from pCore import logFile, LogFileActive, Selection from pMolecule import ElectronicState, MMModelOPLS, NBModelFull #=================================================================================================================================== # . Parameters for system definitions. #=================================================================================================================================== # . Paths. _dataPath = os.path.join(os.getenv("PDYNAMO_PMOLECULE"), "data", "mol") # . Molecule definitions. _keywordLabels = ("label", "dataPath", "fileName", "qcCharge", "multiplicity", "qcSelection") _moleculeData = ( ( "Alanine Dipeptide" , _dataPath, "bAla_c7eq" , 0, 1, Selection.FromIterable ( range ( 10, 14 ) ) ), \ ( "Cyclohexane 6" , _dataPath, "cyclohexane" , 0, 1, Selection.FromIterable ( range ( 6 ) ) ), \ ( "Cyclohexane 9" , _dataPath, "cyclohexane" , 0, 1, Selection.FromIterable ( range ( 9 ) ) ), \ ( "Tyrosine Dipeptide 1", _dataPath, "tyrosineDipeptide", 0, 1, Selection.FromIterable ( range ( 6, 14 ) + range ( 22, 29 ) ) ), \ ( "Tyrosine Dipeptide 2", _dataPath, "tyrosineDipeptide", 1, 2, Selection.FromIterable ( range ( 6, 14 ) + range ( 22, 29 ) ) ), \ ( "Water Dimer 1" , _dataPath, "waterDimer_cs" , 0, 1, Selection.FromIterable ( range ( 3 ) ) ), \ ( "Water Dimer 2" , _dataPath, "waterDimer_cs" , 0, 1, Selection.FromIterable ( range ( 3, 6 ) ) ) ) #=================================================================================================================================== # . Class for a QC/MM test system. #=================================================================================================================================== class QCMMTestSystem(object): """QC/MM test system.""" def __init__(self, **kwargs): """Constructor."""
solution.DefineNBModel ( nbModel ) solution.Summary ( ) # . Refinement. if _Refine: # . Check energies. solute.Energy ( ) for system in ( solvent, solution ): system.DefineNBModel ( nbModel ) system.Energy ( ) # . Get selections for the protein atoms in the A and I chains. protein = AtomSelection.FromAtomPattern ( solution, "A:*:*" ) | AtomSelection.FromAtomPattern ( solution, "I:*:*" ) hydrogens = AtomSelection.FromAtomAttributes ( solution, "atomicNumber", 1 ) heavies = Selection.FromIterable ( protein - hydrogens ) protein = Selection.FromIterable ( protein ) # . Fix all protein atoms. solution.DefineFixedAtoms ( protein ) solution.Summary ( ) # . Optimization. if _Optimize: ConjugateGradientMinimize_SystemGeometry ( solution , maximumIterations = 200 , logFrequency = 10 , rmsGradientTolerance = 10.0 ) # . Define a normal deviate generator in a given state. normalDeviateGenerator = NormalDeviateGenerator.WithRandomNumberGenerator ( RandomNumberGenerator.WithSeed ( 517152 ) )
def CoordinateFluctuations(*arguments, **keywordArguments): """Calculate the coordinate fluctuations for selected particles.""" # . Initialization. fluctuations = None # . Get the trajectory and associated system data. (system, trajectories) = _GetSystemAndTrajectoriesFromArguments(*arguments) # . Get the selection and the size of the problem. selection = keywordArguments.pop("selection", None) if selection is None: selection = Selection.FromIterable(range(len(system.atoms))) n = len(selection) # . Get the average positions. averagePositions = keywordArguments.pop("averagePositions", None) if averagePositions is None: averagePositions = AveragePositions(trajectories, selection=selection) # . Various other options. anisotropic = keywordArguments.pop("anisotropic", False) asBFactors = keywordArguments.pop("asBFactors", False) _CheckForUnknownOptions(keywordArguments) # . Continue processing. if (n > 0) and (averagePositions is not None): # . Allocate space. displacement = Coordinates3.WithExtent(n) if anisotropic: fluctuations = Real2DArray.WithExtents(n, 6) else: fluctuations = Real1DArray.WithExtent(n) displacement.Set(0.0) fluctuations.Set(0.0) # . Loop over trajectory frames. numberFrames = 0 for trajectory in trajectories: trajectory.ReadHeader() while trajectory.RestoreOwnerData(): frame = system.coordinates3 if anisotropic: for (p, i) in enumerate(selection): dx = frame[i, 0] - averagePositions[p, 0] dy = frame[i, 1] - averagePositions[p, 1] dz = frame[i, 2] - averagePositions[p, 2] fluctuations[p, 0] += dx * dx fluctuations[p, 1] += dy * dx fluctuations[p, 2] += dy * dy fluctuations[p, 3] += dz * dx fluctuations[p, 4] += dz * dy fluctuations[p, 5] += dz * dz else: for (p, i) in enumerate(selection): fluctuations[p] += ( ( frame[i,0] - averagePositions[p,0] )**2 + \ ( frame[i,1] - averagePositions[p,1] )**2 + \ ( frame[i,2] - averagePositions[p,2] )**2 ) trajectory.ReadFooter() trajectory.Close() numberFrames += len(trajectory) # . Scale. if numberFrames > 0: fluctuations.Scale(1.0 / float(numberFrames)) # . Convert to B-factors if necessary. if asBFactors: conversionFactor = 8.0 * math.pi**2 if not anisotropic: conversionFactor /= 3.0 fluctuations.Scale(conversionFactor) # . Finish up. return fluctuations
def BuildCubicSolventBox ( molecule, nmolecules, log = logFile, moleculesize = None, excludeHydrogens = True, QRANDOMROTATION = True, randomNumberGenerator = None, scalesafety = 1.1 ): """Build a cubic solvent box.""" # . Get the number of molecules in each direction. nlinear = int ( math.ceil ( math.pow ( float ( nmolecules ), 1.0 / 3.0 ) ) ) # . Get the indices of the occupied sites. sites = sample ( range ( nlinear**3 ), nmolecules ) sites.sort ( ) # . Get the number of atoms in the molecule and an appropriate selection. natoms = len ( molecule.atoms ) selection = Selection.FromIterable ( range ( natoms ) ) # . Get a copy of molecule's coordinates (reorientated). coordinates3 = Clone ( molecule.coordinates3 ) coordinates3.ToPrincipalAxes ( ) # . Get the molecule size depending upon the input options. # . A molecule size has been specified. if moleculesize is not None: size = moleculesize # . Determine the size of the molecule as the diagonal distance across its enclosing orthorhombic box. else: radii = molecule.atoms.GetItemAttributes ( "vdwRadius" ) if excludeHydrogens: atomicNumbers = molecule.atoms.GetItemAttributes ( "atomicNumber" ) for ( i, atomicNumber ) in enumerate ( molecule.atoms.GetItemAttributes ( "atomicNumber" ) ): if atomicNumber == 1: radii[i] = 0.0 ( origin, extents ) = coordinates3.EnclosingOrthorhombicBox ( radii = radii ) size = extents.Norm2 ( ) * scalesafety # . Create the new system - temporarily resetting the coordinates. temporary3 = molecule.coordinates3 molecule.coordinates3 = coordinates3 solvent = MergeByAtom ( nmolecules * [ molecule ] ) molecule.coordinates3 = temporary3 # . Set the system symmetry. solvent.DefineSymmetry ( crystalClass = CrystalClassCubic ( ), a = size * float ( nlinear ) ) # . Set up for random rotations. if QRANDOMROTATION: if randomNumberGenerator is None: randomNumberGenerator = RandomNumberGenerator.WithRandomSeed ( ) rotation = Matrix33.Null ( ) # . Loop over the box sites. origin = 0.5 * float ( 1 - nlinear ) * size n = 0 translation = Vector3.Null ( ) for i in range ( nlinear ): translation[0] = origin + size * float ( i ) for j in range ( nlinear ): translation[1] = origin + size * float ( j ) for k in range ( nlinear ): if len ( sites ) == 0: break translation[2] = origin + size * float ( k ) # . Check for an occupied site. if sites[0] == n: sites.pop ( 0 ) # . Randomly rotate the coordinates. if QRANDOMROTATION: rotation.RandomRotation ( randomNumberGenerator ) solvent.coordinates3.Rotate ( rotation, selection = selection ) # . Translate the coordinates. solvent.coordinates3.Translate ( translation, selection = selection ) # . Increment the selection for the next molecule. selection.Increment ( natoms ) n += 1 # . Do some printing. if LogFileActive ( log ): summary = log.GetSummary ( ) summary.Start ( "Cubic Solvent Box Summary" ) summary.Entry ( "Number of Molecules", "{:d}" .format ( nmolecules ) ) summary.Entry ( "Density (kg m^-3)", "{:.3f}".format ( SystemDensity ( solvent ) ) ) summary.Entry ( "Box Side", "{:.3f}".format ( solvent.symmetryParameters.a ) ) summary.Entry ( "Molecule Size", "{:.3f}".format ( size ) ) summary.Stop ( ) # . Return the cubic system. return solvent