def ParseZmatSection(self, line): """Parse the geometry (XYZ only for the moment).""" # . Get the terminator as the opening character of the current line. terminator = line[0:1] # . Initialization. atomicNumbers = [] xyz = [] nwarnings0 = self.nwarnings # . Loop until an end of section is reached. while True: items = self.GetTokens(converters=[ None, JaguarInputFileReader.ToFloat, JaguarInputFileReader.ToFloat, JaguarInputFileReader.ToFloat ]) # . The end found. if (len(items) == 1) and (items[0] == terminator): break # . An XYZ line. elif len(items) == 4: atomicNumber = PeriodicTable.AtomicNumber(items[0]) if atomicNumber > 0: atomicNumbers.append(atomicNumber) xyz.append((items[1], items[2], items[3])) # . Other lines. else: self.Warning("Unable to interpret geometry line.", True) # . Save the data if there have been no warnings. if nwarnings0 == self.nwarnings: self.atomicNumbers = atomicNumbers self.coordinates3 = Coordinates3.WithExtent(len(xyz)) for (i, (x, y, z)) in enumerate(xyz): self.coordinates3[i, 0] = x self.coordinates3[i, 1] = y self.coordinates3[i, 2] = z
def ParseGeometry(self): """Parse a geometry.""" self.GetLine() # .The Angstroms line. self.GetLine() # . The atoms heading. atomicNumbers = [] xyz = [] dummies = set() n = 0 while True: tokens = self.GetTokens() if (len(tokens) == 4): atomicNumber = PeriodicTable.AtomicNumber(tokens[0]) if (atomicNumber > 0): atomicNumbers.append(atomicNumber) x = float(tokens[1]) y = float(tokens[2]) z = float(tokens[3]) xyz.append((x, y, z)) else: dummies.add(n) n += 1 else: break if (len(atomicNumbers) > 0): self.atomicNumbers = atomicNumbers if self.coordinates3 is None: self.coordinates3 = Coordinates3.WithExtent(len(xyz)) for (i, (x, y, z)) in enumerate(xyz): self.coordinates3[i, 0] = x self.coordinates3[i, 1] = y self.coordinates3[i, 2] = z self.natoms = len(self.atomicNumbers) self.ngeometries += 1 self.dummies = dummies
def ParseAtomSection(self): """Parse the ATOM section.""" if hasattr(self, "natoms"): atomicCharges = Real1DArray.WithExtent(self.natoms) atomicCharges.Set(0.0) atomicNumbers = [] atomNames = [] xyz = Coordinates3.WithExtent(self.natoms) xyz.Set(0.0) for i in range(self.natoms): items = self.GetTokens(converters=[ int, None, float, float, float, None, None, None, float ]) if len(items) < 6: self.Warning("Invalid ATOM line.", True) else: atomicNumber = PeriodicTable.AtomicNumber(items[1]) if atomicNumber <= 0: atomicNumber = self.AtomicNumberFromAtomType(items[5]) atomicNumbers.append(atomicNumber) atomNames.append(items[1]) xyz[i, 0] = items[2] xyz[i, 1] = items[3] xyz[i, 2] = items[4] if len(items) >= 9: atomicCharges[i] = items[8] self.atomicCharges = atomicCharges self.atomicNumbers = atomicNumbers self.atomNames = atomNames self.xyz = xyz else: self.Warning("Unknown number of atoms in molecule.", True)
def Parse(self, log=logFile): """Parsing.""" if not self.QPARSED: # . Initialization. if LogFileActive(log): self.log = log # . Get the atom line format. atomlineformat = self.GetAtomLineFormat() # . Open the file. self.Open() # . Parse all the lines. try: # . Keyword line. self.title = self.GetLine() # . Number of atoms. items = self.GetTokens(converters=(int, )) natoms = items[0] # . The coordinate data. self.xyz = Coordinates3(natoms) for n in range(natoms): tokens = self.GetFixedFormatTokens(*atomlineformat) for i in range(3): self.xyz[n, i] = float(tokens[i + 3] * 10.0) # . Symmetry data. self.symmetryItems = self.GetTokens() except EOFError: pass # . Close the file. self.WarningStop() self.Close() # . Set the parsed flag and some other options. self.log = None self.QPARSED = True
def Parse(self, log=logFile): """Parse the data on the file.""" if not self.QPARSED: # . Initialization. if LogFileActive(log): self.log = log # . Open the file. self.Open() try: # . Number of atoms. items = self.GetTokens(converters=[int]) natoms = items[0] # . Title line. self.title = self.GetLine() # . XYZ lines. self.atomicNumbers = [] self.coordinates3 = Coordinates3.WithExtent(natoms) for i in range(natoms): items = self.GetTokens(converters=[ PeriodicTable.AtomicNumber, float, float, float ]) self.atomicNumbers.append(items[0]) self.coordinates3[i, 0] = items[1] self.coordinates3[i, 1] = items[2] self.coordinates3[i, 2] = items[3] except EOFError: pass # . Close the file. self.WarningStop() self.Close() # . Set the parsed flag and some other options. self.log = None self.QPARSED = True
def NormalModesTrajectory_SystemGeometry(system, trajectory, cycles=10, frames=21, mode=0, state=None, temperature=300.0): """Generate a normal mode trajectory.""" # . Get the state. if state is None: state = system.configuration.nmState # . Get state-related information. if state.freeAtoms == None: freeAtoms = range(len(system.atoms)) else: freeAtoms = state.freeAtoms frequencies = state.frequencies modes = state.modes # . Get the mode frequency. omega = math.fabs(frequencies[mode]) # . Calculate the number of frames. total = cycles * frames # . Check for a calculation. if (mode >= 0) and (mode < state.dimension) and ( omega > _LOWFREQUENCY) and (total > 0): # . Calculate the amplitude (in Angstroms). amplitude = math.sqrt( 2.0 * 1.0e-3 * CONSTANT_AVOGADRO_NUMBER * CONSTANT_BOLTZMANN * temperature) * (_TO_WAVENUMBERS / omega) # . Allocate space for the coordinates and mode. coordinates3 = Clone(system.coordinates3) displacement = Coordinates3.WithExtent(len(system.atoms)) displacement.Set(0.0) # . Get the displacement. for f in freeAtoms: displacement[f, 0] = modes[mode, 3 * f] displacement[f, 1] = modes[mode, 3 * f + 1] displacement[f, 2] = modes[mode, 3 * f + 2] # . Loop over the cycles and frames. # . Calculate the displacement prefactor using sine instead of cosine. trajectory.WriteHeader(temperature=temperature) for c in range(cycles): for f in range(frames): factor = amplitude * math.sin( 2.0 * math.pi * float(f) / float(frames)) coordinates3.CopyTo(system.coordinates3) system.coordinates3.AddScaledMatrix(factor, displacement) trajectory.WriteOwnerData() # . Finish up. trajectory.WriteFooter() trajectory.Close()
def Setup ( selfClass, qcAtoms, electronicState, nbState, job, scratch, deleteJobFiles = False, useRandomJob = False, useRandomScratch = False ): """Set up a state given the relevant data.""" self = selfClass ( ) # . QC atoms. # . Basic attributes. self.charge = electronicState.charge self.multiplicity = electronicState.multiplicity self.numberOfQCAtoms = len ( qcAtoms ) # . File paths. if useRandomJob: job = RandomString ( ) if useRandomScratch: self.scratchPath = os.path.join ( scratch, RandomString ( ) ) if not os.path.exists ( self.scratchPath ): os.mkdir ( self.scratchPath ) self.jobPath = os.path.join ( self.scratchPath, job ) else: self.scratchPath = None self.jobPath = os.path.join ( scratch, job ) self.engradPath = self.jobPath + ".engrad" self.inputPath = self.jobPath + ".inp" self.outputPath = self.jobPath + ".log" self.pcgradPath = self.jobPath + ".pcgrad" self.pcPath = self.jobPath + ".pc" # . Options. self.deleteJobFiles = deleteJobFiles # . Symbols. atomicNumbers = qcAtoms.GetAtomicNumbers ( ) self.symbols = [] for i in atomicNumbers: self.symbols.append ( PeriodicTable.Symbol ( i ) ) # . Array attributes. self.qcCoordinates3 = Coordinates3.WithExtent ( self.numberOfQCAtoms ) ; self.qcCoordinates3.Set ( 0.0 ) self.dipole = Vector3.Null ( ) self.qcGradients3 = Coordinates3.WithExtent ( self.numberOfQCAtoms ) ; self.qcGradients3.Set ( 0.0 ) self.chelpgCharges = Real1DArray.WithExtent ( self.numberOfQCAtoms ) ; self.chelpgCharges.Set ( 0.0 ) self.lowdinCharges = Real1DArray.WithExtent ( self.numberOfQCAtoms ) ; self.lowdinCharges.Set ( 0.0 ) self.lowdinSpins = Real1DArray.WithExtent ( self.numberOfQCAtoms ) ; self.lowdinSpins.Set ( 0.0 ) self.mullikenCharges = Real1DArray.WithExtent ( self.numberOfQCAtoms ) ; self.mullikenCharges.Set ( 0.0 ) self.mullikenSpins = Real1DArray.WithExtent ( self.numberOfQCAtoms ) ; self.mullikenSpins.Set ( 0.0 ) # . Orbital data. self.H**O = -1 self.LUMO = -1 self.orbitalEnergies = [] # . NB state. self.nbState = nbState return self
def IncludeSymmetryParameters ( self ): """Flag the symmetry parameters as variables.""" if ( self.system.symmetry is not None ) and ( self.system.symmetry.crystalClass is not None ): nvariables = len ( self.system.symmetry.crystalClass ) if nvariables > 0: self.fractional = Coordinates3.WithExtent ( self.ncoordinatevariables // 3 ) self.nsymmetryvariables = nvariables self.nvariables += nvariables self.QSYMMETRY = True
def ToCoordinates3 ( self ): """Return the coordinates.""" if self.QPARSED: coordinates3 = Coordinates3.WithExtent ( len ( self.atoms ) ) for ( i, datum ) in enumerate ( self.atoms ): coordinates3[i,0] = datum[4] coordinates3[i,1] = datum[5] coordinates3[i,2] = datum[6] return coordinates3 else: return None
def ToCoordinates3(self): """Return the coordinates.""" if self.QPARSED: coordinates3 = Coordinates3.WithExtent(len(self.atoms)) for (i, (aname, atomicNumber, x, y, z)) in enumerate(self.atoms): coordinates3[i, 0] = x coordinates3[i, 1] = y coordinates3[i, 2] = z return coordinates3 else: return None
def VerifyFixedAtomCoordinates(self, trial, log=logFile, reference=None, tolerance=1.0e-03): """Verify that the coordinates of fixed atoms in a trial set are the same as in a reference set.""" # . Initialization. fixedAtoms = None isOK = False if self.hardConstraints is not None: fixedAtoms = self.hardConstraints.fixedAtoms if reference is None: reference = self.coordinates3 # . Basic checks. if reference is None: message = "Missing reference coordinate set." elif trial is None: message = "Missing trial coordinate set." elif (trail.rows != len(system.atoms)) or (len(reference) != len(trial)): message = "Coordinate sets of incompatible size." elif fixedAtoms is None: isOK = True message = "No fixed atoms are defined." # . Check the coordinates. else: set1 = Coordinates3(len(fixedAtoms)) set1.Gather(reference, fixedAtoms) set2 = Coordinates3(len(fixedAtoms)) set2.Gather(other, fixedAtoms) set1.AddScaledMatrix(-1.0, set2) biggest = set1.AbsoluteMaximum() if biggest >= tolerance: message = "The maximum difference in the fixed atom coordinates, {:.6g}, is greater than the tolerance, {:.6g}.".format( biggest, tolerance) else: isOK = True message = "The fixed atom coordinates are compatible." # . Printing. if LogFileActive(log): log.Paragraph(message) # . Finish up. return isOK
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 GetGridPointCoordinates ( self ): """Return the grid point coordinates.""" if self.coordinates3 is None: coordinates3 = Coordinates3.WithExtent ( self.NumberOfPoints ( ) ) n = 0 for ix in range ( self.npoints[0] ): for iy in range ( self.npoints[1] ) : for iz in range ( self.npoints[2] ) : point = self.Point ( ix, iy, iz ) coordinates3[n,0] = point[0] coordinates3[n,1] = point[1] coordinates3[n,2] = point[2] n += 1 self.coordinates3 = coordinates3 return self.coordinates3
def ToCoordinates3(self, frameIndex=-1): """Return a coordinates3 object.""" coordinates3 = None if self.QPARSED: frame = self.frames[frameIndex] xyz = frame.GetItem("XYZ") if xyz is not None: coordinates3 = Coordinates3.WithExtent(len(xyz)) for (i, (x, y, z)) in enumerate(xyz): coordinates3[i, 0] = x coordinates3[i, 1] = y coordinates3[i, 2] = z frame.SetItem("Coordinates3", coordinates3) else: coordinates3 = frame.GetItem("Coordinates3") return coordinates3
def ExtractCoordinates ( self, table, tag ): """Extract coordinates from a table.""" x = table.RealColumnValues ( tag + "_x" ) y = table.RealColumnValues ( tag + "_y" ) z = table.RealColumnValues ( tag + "_z" ) if ( x is not None ) and ( y is not None ) and ( z is not None ): xyz = Coordinates3.WithExtent ( len ( x ) ) for ( i, ( u, v, w ) ) in enumerate ( zip ( x, y, z ) ): if ( u is None ) or ( v is None ) or ( w is None ): xyz.FlagCoordinateAsUndefined ( i ) else: xyz[i,0] = u xyz[i,1] = v xyz[i,2] = w else: xyz = None return xyz
def DefineQCLayer ( self, selection, qcModel, electronicState = None ): """Define a QC layer. A layer consists of two subsystems with the same atomic composition. One uses the new energy model and a weight of +1 whereas the second has the old energy model and a weight of -1. """ # . Get the latest defined system. if len ( self.subsystems ) > 0: number = len ( self.subsystems ) oldsystem = self.subsystems[-1].system else: number = 0 oldsystem = self.system # . Get the QC atom indices of the full system (excluding boundary atoms). try: oldqcset = set ( oldsystem.energyModel.qcAtoms.GetFullSelection ( ) ).difference ( set ( oldsystem.energyModel.qcAtoms.BoundaryAtomSelection ( ) ) ) except: raise ValueError ( "Unable to retrieve the previous system's QC atom indices." ) # . Map a subsystem's indices to those of the full system. if len ( self.subsystems ) > 0: mapping = self.subsystems[-1].selection unmapped = oldqcset oldqcset = set ( ) for i in unmapped: oldqcset.add ( mapping[i] ) # . Check that the selection is a subset of the previous one. newqcset = set ( selection ) if not newqcset.issubset ( oldqcset ): raise ValueError ( "The atoms in the new QC layer must be a subset of the QC atoms in the underlying system." ) # . Get the old QC model (which at this stage is known to exist). oldmodel = oldsystem.energyModel.qcModel # . Find the atomic numbers. atomicNumbers = self.system.atoms.GetItemAttributes ( "atomicNumber", selection = selection ) # . Find boundary atoms. boundaryAtoms = self.FindBoundaryAtoms ( selection, len ( atomicNumbers ) ) # . Extend atomicNumbers by the appropriate number of boundary atom hydrogens. atomicNumbers.extend ( len ( boundaryAtoms ) * [ 1 ] ) # . Define a basic QC system - it is cleaner to do this for a QC system from scratch without pruning, etc. system0 = System.FromAtoms ( atomicNumbers ) if electronicState is not None: system0.electronicState = electronicState system0.coordinates3 = Coordinates3.WithExtent ( len ( system0.atoms ) ) system0.coordinates3.Set ( 0.0 ) # . Define the subsystems of the layer. system1 = Clone ( system0 ) for ( i, ( system, model, weight ) ) in enumerate ( ( ( system0, oldmodel, -1.0 ), ( system1, qcModel, 1.0 ) ) ): system.label = "MultiLayer Objective Function Subsystem {:d} with Weight {:.1f}".format ( number+i, weight ) system.DefineQCModel ( model ) subsystem = MultiLayerSubsystem ( system, weight, selection, boundaryAtoms = boundaryAtoms ) subsystem.VariablesPut ( self.system.coordinates3 ) self.subsystems.append ( subsystem )
def LinearlyExpand(self, ninsert): """Expand a trajectory by inserting points determined by linear interpolation. |ninsert| is the number of points to insert between each pair of existing points. """ if not self.isWritable: raise IOError("Writing to trajectory that is not writeable.") if (ninsert > 0) and (self.frames > 1): # . Check for fixed atoms and get the first frame if necessary. hasFixedAtoms = (self.owner.hardConstraints is not None) and ( self.owner.hardConstraints.NumberOfFixedAtoms() > 0) if not hasFixedAtoms: reference = self.ReadFrame(frame=0, instance=Coordinates3) # . Calculate the number of new frames. nold = self.frames nnew = nold + (nold - 1) * ninsert # . Get space for the step. dxyz = Coordinates3.WithExtent(len(self.owner.atoms)) dxyz.Set(0.0) # . Loop over the frames in reverse order. xyz = self.ReadFrame(frame=nold - 1, instance=Coordinates3) if not hasFixedAtoms: xyz.Superimpose(reference) inew = nnew for n in range(nold - 2, -1, -1): # . Get the next reorientated frame. start = self.ReadFrame(frame=n, instance=Coordinates3) if not hasFixedAtoms: start.Superimpose(reference) # . Get the step. start.CopyTo(dxyz) dxyz.AddScaledMatrix(-1.0, xyz) dxyz.Scale(1.0 / float(ninsert + 1)) # . Write out the frames. inew -= 1 self.WriteFrame(xyz, frame=inew) for i in range(ninsert): inew -= 1 xyz.AddScaledMatrix(1.0, dxyz) self.WriteFrame(xyz, frame=inew) # print i, inew # . Make start the new stop. xyz = start # . Don't need to write out the last (first) frame as this is unchanged. # . Reset the number of frames. self.frames = nnew
def Parse(self, log=logFile): """Parse the data on the file.""" if not self.QPARSED: # . Initialization. if LogFileActive(log): self.log = log # . Open the file. self.Open() try: # . Keyword line. self.title = self.GetLine() # . Number of atoms. items = self.GetTokens(converters=(int, )) natoms = items[0] # . The coordinate data. items = self.GetFixedFormatArray(3 * natoms, _XYZNUMBER, _XYZWIDTH, converter=float, default=0.0) self.xyz = Coordinates3.WithExtent(natoms) for n in range(natoms): for i in range(3): self.xyz[n, i] = items[3 * n + i] # . Symmetry data - optional. items = self.GetFixedFormatArray(3, _SYMMETRYNUMBER, _SYMMETRYWIDTH, converter=float, default=0.0, QWARNING=False) self.symmetryParameters = SymmetryParameters() self.symmetryParameters.SetCrystalParameters( items[0], items[1], items[2], 90.0, 90.0, 90.0) except EOFError: pass # . Close the file. self.WarningStop() self.Close() # . Set the parsed flag and some other options. self.log = None self.QPARSED = True
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 _ParseXYZ ( self ): """Parse a Cartesian coordinate geometry specification.""" self.atomicNumbers = [] xyz = [] while True: tokens = self.GetTokens ( converters = [ MopacInputFileReader.GetAtomicNumber, float, None, float, None, float, None ] ) ntokens = len ( tokens ) if ntokens == 0: break elif ntokens >= 7: self.atomicNumbers.append ( tokens[0] ) xyz.append ( [ tokens[1], tokens[3], tokens[5] ] ) else: self.Warning ( "Insufficient number of tokens ({:d}) on Cartesian coordinate input line.".format ( ntokens ), True ) # . Create the coordinates. self.coordinates3 = Coordinates3.WithExtent ( len ( self.atomicNumbers ) ) self.coordinates3.Set ( 0.0 ) for ( i, ( x, y, z ) ) in enumerate ( xyz ): self.coordinates3[i,0] = x self.coordinates3[i,1] = y self.coordinates3[i,2] = z
def _ParseZMatrix ( self ): """Parse a Z-matrix geometry specification.""" converters = [ MopacInputFileReader.GetAtomicNumber, float, None, float, None, float, None ] ncards = 0 oldfatal = self.nfatal self.atomicNumbers = [] zmatrixcards = [] while True: tokens = self.GetTokens ( converters = converters ) ntokens = len ( tokens ) if ntokens == 0: break else: # . Append int to the converters for the first three cards. if ( ncards < 3 ): converters.append ( int ) # . Basic checks on cards and tokens. if ( ( ncards == 0 ) and ( ntokens >= 7 ) ) or ( ( ncards == 1 ) and ( ntokens >= 8 ) ) or ( ( ncards == 2 ) and ( ntokens >= 9 ) ) or ( ( ncards > 2 ) and ( ntokens >= 10 ) ): card = [ tokens[1], tokens[3], tokens[5] ] if ( ncards > 0 ): card.append ( tokens[7] - 1 ) if ( ncards > 1 ): card.append ( tokens[8] - 1 ) if ( ncards > 2 ): card.append ( tokens[9] - 1 ) # . Check that the atom number values are valid. QOK = True for i in card[3:]: QOK = QOK and ( i >= 0 ) and ( i < ncards ) if QOK: ncards += 1 self.atomicNumbers.append ( tokens[0] ) zmatrixcards.append ( card ) else: self.Warning ( "Invalid atom number specification on Z-matrix input line.", True ) else: self.Warning ( "Insufficient number of tokens ({:d}) on Z-matrix input line.".format ( ntokens ), True ) # . Create the coordinates if there have been no fatal errors during the reading process. if self.nfatal == oldfatal: self.coordinates3 = Coordinates3.WithExtent ( len ( self.atomicNumbers ) ) self.coordinates3.Set ( 0.0 ) direction = Vector3.Null ( ) for ( i, card ) in enumerate ( zmatrixcards ): if i == 1: direction.Set ( 0.0 ) direction[0] = 1.0 # direction.BasisVector ( 0 ) # . x-direction. QOK = self.coordinates3.BuildPointFromDistance ( i, card[3], card[0], direction ) elif i == 2: direction.Set ( 0.0 ) direction[1] = 1.0 # direction.BasisVector ( 1 ) # . y-direction. QOK = self.coordinates3.BuildPointFromDistanceAngle ( i, card[3], card[4], card[0], card[1], direction ) elif i > 2: QOK = self.coordinates3.BuildPointFromDistanceAngleDihedral ( i, card[3], card[4], card[5], card[0], card[1], card[2] ) # elif i > 1: # # . Check for co-linear atoms. # if math.fabs ( card[1] - 180.0 ) <= _LINEARTOLERANCE: # j = card[3] # k = card[4] # for c in range ( 3 ): # direction[c] = self.coordinates3[j,c] - self.coordinates3[k,c] # direction.Normalize ( ) # QOK = self.coordinates3.BuildPointFromDistance ( i, j, card[0], direction ) # else: # if i == 2: # direction.BasisVector ( 1 ) # . y-direction. # QOK = self.coordinates3.BuildPointFromDistanceAngle ( i, card[3], card[4], card[0], card[1], direction ) # else: # # . Check for linear atoms. # QOK = self.coordinates3.BuildPointFromDistanceAngleDihedral ( i, card[3], card[4], card[5], card[0], card[1], card[2] ) if not QOK: self.Warning ( "Unable to build Cartesian coordinates from Z-matrix card number {:d}.".format ( i+1 ), True ) break
def Energy(self, log=logFile, doGradients=False): """Calculate the energy and, optionally, the gradients for a system.""" # . Initialization. tStartEnergy = self.cpuTimer.Current() # . Do nothing if coordinates and an energy model are absent. if (self.coordinates3 is None) or (self.energyModel is None): return # . Set up configuration. self.configuration.ClearTemporaryAttributes() self.configuration.SetTemporaryAttribute("energyTerms", EnergyTerms()) # . Make this clearer here (no need to reallocate each time). if doGradients: g = Coordinates3.WithExtent(len(self.atoms)) g.Set(0.0) self.configuration.SetTemporaryAttribute("gradients3", g) if self.symmetry is not None: self.configuration.SetTemporaryAttribute( "symmetryParameterGradients", SymmetryParameterGradients()) # . Alias various data structures. em = self.energyModel et = self.configuration.energyTerms fa = None crd = self.configuration.coordinates3 grd = getattr(self.configuration, "gradients3", None) if self.hardConstraints is not None: fa = self.hardConstraints.fixedAtoms self.timings["Initialization"] += (self.cpuTimer.Current() - tStartEnergy) # . Calculate MM terms. if (em.mmModel is not None) and (em.mmTerms is not None): for mmterm in em.mmTerms: tStart = self.cpuTimer.Current() results = mmterm.Energy(crd, grd) et.Append(results) self.timings[results[0]] += (self.cpuTimer.Current() - tStart) # . Calculate NB terms. if em.nbModel is not None: tStart = self.cpuTimer.Current() em.nbModel.SetUp(em.mmAtoms, em.qcAtoms, em.ljParameters, em.ljParameters14, fa, em.interactions14, em.exclusions, self.symmetry, self.connectivity.isolates, self.configuration, log=log) tStop = self.cpuTimer.Current() self.timings["NB Set Up"] += (tStop - tStart) et.Extend(em.nbModel.Energy(self.configuration)) self.timings["NB Evaluation"] += (self.cpuTimer.Current() - tStop) # . Calculate QC and QC/MM electrostatic terms. if em.qcModel is not None: tStart = self.cpuTimer.Current() if (em.nbModel is not None): em.nbModel.QCMMPotentials(self.configuration) tStop = self.cpuTimer.Current() self.timings["QC/MM Potentials"] += (tStop - tStart) tStart = tStop et.Extend( em.qcModel.EnergyWithTimings(em.qcAtoms, em.qcParameters, self.electronicState, self.configuration, self.cpuTimer, self.timings, log=log)) tStop = self.cpuTimer.Current() self.timings["QC Evaluation"] += (tStop - tStart) if (em.nbModel is not None) and doGradients: tStart = tStop em.nbModel.QCMMGradients(self.configuration) self.timings["QC/MM Gradients"] += (self.cpuTimer.Current() - tStart) # . Calculate the soft constraint terms. if em.softConstraints is not None: tStart = self.cpuTimer.Current() (scEnergy, scState) = em.softConstraints.Energy(crd, grd) self.configuration.SetTemporaryAttribute("scState", scState) et.Append(scEnergy) self.timings["Soft Constraint"] += (self.cpuTimer.Current() - tStart) # . Calculate the total energy. tStart = self.cpuTimer.Current() et.Total() # . Zero out unnecessary gradient terms. if (fa is not None) and doGradients: grd.SetRowSelection(fa, 0.0) # . Print the energy terms if necessary. if LogFileActive(log): if doGradients: et.RMSGradient(grd.RMSValue()) et.Summary(log=log) # . Finish up. tStop = self.cpuTimer.Current() self.timings["Energy"] += (tStop - tStartEnergy) self.timings["Finalization"] += (tStop - tStart) self.numberOfEnergyCalls += 1 return et.potentialEnergy
def Parse(self, log=logFile): """Parsing.""" if not self.QPARSED: # . Initialization. if LogFileActive(log): self.log = log self.molrecords = [] # . Open the file. self.Open() # . Parse the data. try: # . Parse all entries. QCONTINUE = True while QCONTINUE: # . Header block. # . Molecule name. label = self.GetLine(QWARNING=False) # . Skip lines 1 and 2 which are not parsed. self.GetLine() self.GetLine() # . Connection table. # . Counts line - only atom and bond numbers are parsed. (natoms, nbonds) = self.GetFixedFormatTokens( (0, 3, int, 0), (3, 6, int, 0)) # . Initialize atom and coordinates data structures. atomicNumbers = [] bonds = [] charges = [] coordinates3 = Coordinates3.WithExtent(natoms) mchg = {} miso = {} mrad = {} coordinates3.Set(0.0) # . Read the atom lines. for n in range(natoms): (x, y, z, atomicNumber, charge) = self.GetFixedFormatTokens( (0, 10, float, 0.0), (10, 20, float, 0.0), (20, 30, float, 0.0), (31, 34, PeriodicTable.AtomicNumber, -1), (36, 39, int, 0)) atomicNumbers.append(atomicNumber) charges.append(_CHARGECODES.get(charge, 0)) coordinates3[n, 0] = x coordinates3[n, 1] = y coordinates3[n, 2] = z # . Read the bond lines. for n in range(nbonds): (atom1, atom2, code) = self.GetFixedFormatTokens( (0, 3, int, 0), (3, 6, int, 0), (6, 9, int, 0)) if (atom1 <= 0) or (atom1 > natoms) or ( atom2 <= 0) or (atom2 > natoms): self.Warning( "Bond atom indices out of range: {:d}, {:d}.". format(atom1, atom2), True) bonds.append((atom1 - 1, atom2 - 1, _MOLBONDTYPES.get(code, UndefinedBond()))) # . Properties lines. while True: line = self.GetLine() if line.startswith("M CHG"): self.ParsePropertiesLine(line, mchg) elif line.startswith("M ISO"): self.ParsePropertiesLine(line, miso) elif line.startswith("M RAD"): self.ParsePropertiesLine(line, mrad) elif line.startswith("M END"): break # . Store the data. self.molrecords.append( (label, atomicNumbers, bonds, charges, coordinates3, mchg, miso, mrad)) # . Check for an SDF terminator. QCONTINUE = False while True: line = self.GetLine(QWARNING=False) if line == "$$$$": QCONTINUE = True break except EOFError: pass # . Close the file. self.WarningStop() self.Close() # . Set the parsed flag and some other options. self.log = None self.QPARSED = True
def ToSystem(self, altLoc=_UNDEFINEDCHARACTER, modelNumber=_DEFAULTMODELNUMBER, embeddedHydrogens=False): """Return a system from the model.""" system = None if self.QFINALIZED: # . Initialization. index = 0 atomPaths = [] majorSeparator = Sequence.defaultAttributes["labelSeparator"] minorSeparator = Sequence.defaultAttributes["fieldSeparator"] systemAtoms = [] undefined = [] xyz = [] # . Loop over entities. entities = list(self.entities.values()) entities.sort(key=mmCIFModelEntity.GetIndex) entityLabels = {} for entity in entities: # . Entity label. if entity.asymlabel == _UNDEFINEDCHARACTER: entityLabel = _DefaultLabel else: entityLabel = entity.asymlabel if (entity.asymlabel != entity.label) and ( entity.label != _UNDEFINEDCHARACTER): entityLabel += (minorSeparator + entity.label) entityLabels[entity] = entityLabel # . Loop over components. components = list(entity.components.values()) components.sort(key=mmCIFModelComponent.GetIndex) for component in components: # . Component path. fields = [] for item in (component.name, component.sequencenumber, component.insertioncode): if item == _UNDEFINEDCHARACTER: fields.append(_DefaultLabel) else: fields.append(item) n = 3 for item in reversed(fields): if item == _DefaultLabel: n -= 1 else: break componentLabel = minorSeparator.join(fields[0:max(n, 1)]) # . Loop over atoms - putting hydrogens at the end if necessary. atoms = list(component.atoms.values()) if embeddedHydrogens: atoms.sort(key=mmCIFModelAtom.GetIndex) else: atoms.sort( key=mmCIFModelAtom.GetNonEmbeddedHydrogenIndex) # . Generate atoms and associated data. for atom in atoms: systemAtoms.append( Atom(atomicNumber=atom.atomicNumber, formalCharge=atom.formalCharge)) if atom.label == _UNDEFINEDCHARACTER: atomLabel = _DefaultLabel else: atomLabel = atom.label atomPaths.append(entityLabel + majorSeparator + componentLabel + majorSeparator + atomLabel) (QUNDEFINED, x, y, z) = atom.GetCoordinateData(altLoc, modelNumber) if QUNDEFINED: undefined.append(index) xyz.append((x, y, z)) index += 1 # . Make the sequence. sequence = Sequence.FromAtomPaths(atomPaths, atoms=systemAtoms) # . Make the system. system = System.FromSequence(sequence) if self.label is not None: system.label = self.label # . Coordinates. coordinates3 = Coordinates3.WithExtent(len(systemAtoms)) for (i, (x, y, z)) in enumerate(xyz): coordinates3[i, 0] = x coordinates3[i, 1] = y coordinates3[i, 2] = z system.coordinates3 = coordinates3 # . Undefined coordinates. if len(undefined) > 0: for i in undefined: system.coordinates3.FlagCoordinateAsUndefined(i) # . Define polymer data. for oldEntity in entities: if isinstance(oldEntity, mmCIFModelPolymerEntity): newEntity = system.sequence.childIndex.get( entityLabels[oldEntity]) system.sequence.linearPolymers.append ( SequenceLinearPolymer ( isCyclic = oldEntity.QCYCLIC , \ leftTerminalComponent = newEntity.children[ 0] , \ rightTerminalComponent = newEntity.children[-1] ) ) # . Finish up. return system
def Parse(self, log=logFile): """Parsing.""" if not self.QPARSED: # . Initialization. if LogFileActive(log): self.log = log # . Open the file. self.Open() # . Parse the data. try: # . Header. self.label = self.GetLine() # . More description - ignored. self.GetLine() # . First definition line. (natoms, ox, oy, oz) = self.GetFixedFormatTokens( (0, 5, int, 0), (5, 17, float, 0.0), (17, 29, float, 0.0), (29, 41, float, 0.0)) hasOrbitals = (natoms < 0) if hasOrbitals: natoms = abs(natoms) # . Grid axis definitions - number of points and increment vector. griddata = [] ngrid = 1 for (i, o) in enumerate((ox, oy, oz)): items = self.GetFixedFormatTokens( (0, 5, int, 0), (5, 17, float, 0.0), (17, 29, float, 0.0), (29, 41, float, 0.0)) n = items.pop(0) h = items.pop(i) * UNITS_LENGTH_BOHRS_TO_ANGSTROMS o *= UNITS_LENGTH_BOHRS_TO_ANGSTROMS if (items[0] != 0.0) or (items[1] != 0.0): self.Warning( "Unable to handle grids whose increment vectors are not aligned along the Cartesian axes.", False) griddata.append({ "bins": n, "binSize": h, "lower": o - 0.5 * h }) ngrid *= n # . Get the grid. self.grid = RegularGrid_FromDimensionData(griddata) # . Atom data. self.atomicNumbers = [] self.coordinates3 = Coordinates3.WithExtent(natoms) for i in range(natoms): (n, q, x, y, z) = self.GetFixedFormatTokens( (0, 5, int, 0), (5, 17, float, 0.0), (17, 29, float, 0.0), (29, 41, float, 0.0), (41, 53, float, 0.0)) self.atomicNumbers.append(n) self.coordinates3[i, 0] = x self.coordinates3[i, 1] = y self.coordinates3[i, 2] = z self.coordinates3.Scale(UNITS_LENGTH_BOHRS_TO_ANGSTROMS) # . Orbital data. if hasOrbitals: indices = self.GetTokens() for (i, index) in enumerate(indices): indices[i] = int(index) norbitals = indices.pop(0) if norbitals != len(indices): self.Warning( "The number of orbitals does not match the number of orbital indices.", True) self.orbitalindices = indices else: self.orbitalindices = None # . Field data. # . Unfortunately each row is written out separately so reading in has to be done by row as well. keys = [] if hasOrbitals: for index in self.orbitalindices: keys.append("Orbital {:d}".format(index)) else: keys.append("Density") self.fielddata = {} for key in keys: self.fielddata[key] = RealNDArray.WithExtents( *self.grid.shape) nfields = len(keys) if nfields == 1: fielddata = self.fielddata[keys[0]] # [] else: fielddata = [] for key in keys: fielddata.append(self.fielddata[key]) nitems = griddata[2]["bins"] * nfields for ix in range(griddata[0]["bins"]): for iy in range(griddata[1]["bins"]): newdata = self.GetFixedFormatArray(nitems, 6, 13, converter=float, default=0.0) if nfields == 1: # fielddata.extend ( newdata ) for iz in range(nitems): fielddata[ix, iy, iz] = newdata[iz] else: for ifield in range(nfields): for (iz, i) in enumerate( range(ifield, nitems, nfields)): fielddata[ifield][ix, iy, iz] = newdata[i] # for ifield in range ( nfields ): # fielddata[ifield].extend ( newdata[ifield::nfields] ) except EOFError: pass # . Close the file. self.WarningStop() self.Close() # . Set the parsed flag and some other options. self.log = None self.QPARSED = True
def Energy(self, log=logFile, doGradients=False): """Calculate the energy and, optionally, the gradients for a system.""" # . Do nothing if coordinates and an energy model are absent. if (self.coordinates3 is None) or (self.energyModel is None): return # . Set up configuration. self.configuration.ClearTemporaryAttributes() self.configuration.SetTemporaryAttribute("energyTerms", EnergyTerms()) # . Make this clearer here (no need to reallocate each time). if doGradients: g = Coordinates3.WithExtent(len(self.atoms)) g.Set(0.0) self.configuration.SetTemporaryAttribute("gradients3", g) if self.symmetry is not None: self.configuration.SetTemporaryAttribute( "symmetryParameterGradients", SymmetryParameterGradients()) # . Alias various data structures. em = self.energyModel et = self.configuration.energyTerms fa = None crd = self.configuration.coordinates3 grd = getattr(self.configuration, "gradients3", None) if self.hardConstraints is not None: fa = self.hardConstraints.fixedAtoms # . Calculate MM terms. if (em.mmModel is not None) and (em.mmTerms is not None): for mmterm in em.mmTerms: et.Append(mmterm.Energy(crd, grd)) # . Calculate NB terms. if em.nbModel is not None: em.nbModel.SetUp(em.mmAtoms, em.qcAtoms, em.ljParameters, em.ljParameters14, fa, em.interactions14, em.exclusions, self.symmetry, self.connectivity.isolates, self.configuration, log=log) et.Extend(em.nbModel.Energy(self.configuration)) # . Calculate QC and QC/MM electrostatic terms. if em.qcModel is not None: if (em.nbModel is not None): em.nbModel.QCMMPotentials(self.configuration) et.Extend( em.qcModel.Energy(em.qcAtoms, em.qcParameters, self.electronicState, self.configuration, log=log)) if (em.nbModel is not None) and doGradients: em.nbModel.QCMMGradients(self.configuration) # . Calculate the soft constraint terms. if em.softConstraints is not None: (scEnergy, scState) = em.softConstraints.Energy(crd, grd) self.configuration.SetTemporaryAttribute("scState", scState) et.Append(scEnergy) # . Calculate the total energy. et.Total() # . Zero out unnecessary gradient terms. if (fa is not None) and doGradients: grd.SetRowSelection(fa, 0.0) # . Print the energy terms if necessary. if LogFileActive(log): if doGradients: et.RMSGradient(grd.RMSValue()) et.Summary(log=log) return et.potentialEnergy
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 GenerateVanDerWaalsSurface(system, gridangularmomentum=21, log=logFile, qcAtomsOnly=False, scalingfactors=[1.0]): """Generate a superposition of van der Waals surfaces represented by grid points.""" # . QC atoms only (including link atoms). if qcAtomsOnly: qcAtoms = system.energyModel.qcAtoms atomicNumbers = qcAtoms.GetAtomicNumbers() coordinates3 = qcAtoms.GetCoordinates3(system.coordinates3) # . All atoms. else: atomicNumbers = system.atoms.GetItemAttributes("atomicNumber") coordinates3 = system.coordinates3 # . Find the number of atoms. natoms = len(atomicNumbers) # . Set radii. radii = Real1DArray.WithExtent(natoms) for (i, n) in enumerate(atomicNumbers): radii[i] = PeriodicTable.Element(n).vdwRadius # . Get the grid points for a single center. (basicgrid, weights) = LebedevLaikovGrid_GetGridPoints(gridangularmomentum) # . Allocate space for the possible number of grid points. npossible = natoms * basicgrid.rows * len(scalingfactors) gridPoints = Coordinates3.WithExtent(npossible) gridPoints.Set(0.0) # . Initialization. nfound = 0 atomgrid = Coordinates3.WithExtent(basicgrid.rows) translation = Vector3.Null() atomgrid.Set(0.0) # . Loop over scaling factors. for factor in scalingfactors: # . Loop over points. for i in range(natoms): # . Get the radius. iradius = factor * radii[i] # . Get the translation. translation[0] = coordinates3[i, 0] translation[1] = coordinates3[i, 1] translation[2] = coordinates3[i, 2] # . Get the scaled grid centered at the point. basicgrid.CopyTo(atomgrid) atomgrid.Scale(iradius) atomgrid.Translate(translation) # . Remove points that are within the current scaled radii of other points. for p in range(atomgrid.rows): QOK = True x = atomgrid[p, 0] y = atomgrid[p, 1] z = atomgrid[p, 2] for j in range(natoms): if j != i: dx = coordinates3[j, 0] - x dy = coordinates3[j, 1] - y dz = coordinates3[j, 2] - z jradius2 = (factor * radii[j])**2 if (dx**2 + dy**2 + dz**2) <= jradius2: QOK = False break if QOK: gridPoints[nfound, 0] = x gridPoints[nfound, 1] = y gridPoints[nfound, 2] = z nfound += 1 # . Reduce the array size if necessary. if nfound < npossible: newpoints = Coordinates3.WithExtent(nfound) for p in range(nfound): newpoints[p, 0] = gridPoints[p, 0] newpoints[p, 1] = gridPoints[p, 1] newpoints[p, 2] = gridPoints[p, 2] gridPoints = newpoints # . Create a system. # from pBabel import XYZFile_FromSystem # from pMolecule import System # ngrid = gridPoints.rows # junk = System ( ngrid * [ 1 ] ) # junk.coordinates3 = gridPoints # XYZFile_FromSystem ( "junk.xyz", junk ) # . Do some printing. if LogFileActive(log): summary = log.GetSummary() summary.Start("van der Waals Surface Generation Summary") summary.Entry("Atoms", "{:d}".format(natoms)) summary.Entry("Surfaces", "{:d}".format(len(scalingfactors))) summary.Entry("Found Points", "{:d}".format(nfound)) summary.Entry("Possible Points", "{:d}".format(npossible)) summary.Stop() # . Finish up. return gridPoints