def del_constraint(self, mol): if self.boundHit == "lower": n = self.boxList[self.box].lower.norm elif self.boundHit == "upper": n = self.boxList[self.box].upper.norm elif self.boundHit == "path": if self.pathNode == (len(self.path) - 1) or self.pathNode == len( self.path): segmentStart = self.path[self.pathNode - 1][0] segmentEnd = self.path[self.pathNode][0] # Total path distance up to current segment TotalDistance = self.path[self.pathNode][1] else: segmentStart = self.path[self.pathNode][0] segmentEnd = self.path[self.pathNode + 1][0] # Total path distance up to current segment TotalDistance = self.path[self.pathNode][1] # Projection along linear segment only SegDistance = self.s[2] - TotalDistance # Get vector for and length of linear segment vec = segmentEnd - segmentStart length = np.linalg.norm(vec) # finally get distance of projected point along vec plength = segmentStart + ((SegDistance / length) * vec) perpendicularPath = (self.s[0] - plength) n = perpendicularPath / np.linalg.norm(perpendicularPath) self.del_phi = ct.genBXDDel(mol, self.s[0], self.sInd, n) return self.del_phi
def convertToS(self, mol, activeS): # First get S S = ct.getDistMatrix(mol, activeS) if self.sInd == 0: self.sInd = S[1] self.reac = S[0] try: Snorm, project, node, dist = ct.projectPointOnPath( S[0], self.path, self.pathType, self.boxList[self.box].lower.norm, self.boxList[self.box].lower.D, self.reac, self.pathNode, self.reverse) except: Snorm = 0 project = 0 node = False dist = 0 return S[0], Snorm, project, node, dist
def convertStoBound(self, s1, s2): if self.fixToPath == False: b = self.convertStoBoundGeneral(s1, s2) else: s1vec = ct.projectPointOnPath(s1, self.path, self.pathType, self.boxList[self.box].lower.norm, self.boxList[self.box].lower.D, self.reac, self.pathNode, self.reverse) s2vec = ct.projectPointOnPath(s2, self.path, self.pathType, self.boxList[self.box].lower.norm, self.boxList[self.box].lower.D, self.reac, self.pathNode, self.reverse) if self.reverse: b = self.convertStoBoundOnPath(s1vec[1], s1vec[2], s1) else: b = self.convertStoBoundOnPath(s2vec[1], s2vec[2], s2) return b
def run(gl): #Read reactant definition if gl.StartType == 'file': Reac = read(gl.Start) elif gl.StartType == 'Smile': Reac = tl.getMolFromSmile(gl.Start) #Read product definition if gl.EndType == 'file': Prod = read(gl.End) elif gl.EndType == 'Smile': Prod = tl.getMolFromSmile(gl.End) #Set calculatiors #Reac = tl.setCalc(Reac,"DOS/", gl.trajMethod, gl.atomTypes) if gl.trajMethod == "openMM": Reac = tl.setCalc(Reac, "GenBXD/", gl.trajMethod, gl) else: Reac = tl.setCalc(Reac, "GenBXD/", gl.trajMethod, gl.trajLevel) Prod = tl.setCalc(Prod, "GenBXD/", gl.trajMethod, gl.trajLevel) # Partially minimise both reactant and product if gl.GenBXDrelax: min = BFGS(Reac) try: min.run(fmax=0.1, steps=20) except: min.run(fmax=0.1, steps=20) min2 = BFGS(Prod) try: min2.run(fmax=0.1, steps=20) except: min2.run(fmax=0.1, steps=20) # Get important interatomic distances if gl.CollectiveVarType == "changedBonds": cbs = ct.getChangedBonds2(Reac, Prod) elif gl.CollectiveVarType == "all": cbs = ct.getChangedBonds2(Reac, Prod) elif gl.CollectiveVarType == "specified": cbs = gl.CollectiveVar elif gl.CollectiveVarType == "file": cbs = gl.principalCoordinates #Get path to project along distPath = [] totalPathLength = 0 if gl.PathType == 'curve' or gl.PathType == 'gates': if gl.PathFile == 'none': Path = getPath(Reac, Prod, gl) else: Path = read(gl.PathFile, index=('::' + str(gl.pathStride))) distPath.append((ct.getDistMatrix(Path[0], cbs)[0], 0)) for i in range(1, len(Path)): l = np.linalg.norm( ct.getDistMatrix(Path[i], cbs)[0] - ct.getDistMatrix(Path[i - 1], cbs)[0]) totalPathLength += l distPath.append((ct.getDistMatrix(Path[i], cbs)[0], totalPathLength)) elif gl.PathType == 'linear': distPath = ct.getDistMatrix(Prod, cbs)[0] - ct.getDistMatrix( Reac, cbs)[0] if gl.PathType == 'curve' or gl.PathType == 'gates': pathFile = open('reducedPath.txt', 'w') for p in distPath: pathFile.write('s = ' + str(p[0]) + '\n') pathFile.close() # initialise then run trajectory t = ChemDyME.Trajectory.Trajectory(Reac, gl, os.getcwd(), 0, False) t.runGenBXD(Reac, Prod, gl.maxHits, gl.maxAdapSteps, gl.PathType, distPath, cbs, gl.decorrelationSteps, gl.histogramBins, totalPathLength, gl.fixToPath, gl.pathDistCutOff, gl.epsilon)
def getConectivity(self, mol): size = len(mol.get_positions()) dRef = ct.refBonds(mol) bondMat = ct.bondMatrix(dRef, mol) bondList = [] angleList = [] angleListTemp = [] dihedralList = [] LJList = [] fullBonds = [] #Loop through bond matrix and add any bonds to the list for i in range(0, size): bondedToAtom = [] for j in range(i, size): if bondMat[i][j] == 1.0: K, re_eq = self.getBondParams(i, j, self.types) bondList.append((i, j, K, re_eq)) bondedToAtom.append(j) fullBonds.append(bondedToAtom) #Loop through bond matrix and add any angles to the list #Must be a cleverer way to do this for i in range(0, size): for j in range(0, size): for k in range(0, size): if bondMat[i][j] == 1.0 and (bondMat[j][k] == 1.0) and i != k: if self.types[i] != self.types[k]: a, b = self.types[i], self.types[k] else: a, b = i, k if a <= b: K, theta_eq = self.getAngleParams( i, j, k, self.types) angleList.append((i, j, k, K, theta_eq)) if a > b: K, theta_eq = self.getAngleParams( k, j, i, self.types) angleList.append((k, j, i, K, theta_eq)) angleList = self.f7(angleList) for i in range(0, size): sigma, epsilon = self.getLJParams(i, self.types) LJList.append((sigma, epsilon)) #Loop through bond matrix and add any dihedral to the list for i in range(0, size): for j in range(i, size): for k in range(0, size): for l in range(0, size): if bondMat[i][j] == 1.0 and bondMat[j][ k] == 1.0 and bondMat[k][ l] == 1.0 and self.noDuplicates( [i, j, k, l]): a, b = self.types[i], self.types[l] if a > b: V1, V2, V3 = self.getDihedralParams( l, k, j, i, self.types) elif a <= b: V1, V2, V3 = self.getDihedralParams( i, j, k, l, self.types) if V1 != 0 or V2 != 0 or V3 != 0: dihedralList.append((i, j, k, l, V1, V2, V3)) return bondList, angleList, dihedralList, LJList
def del_constraint(self, mol): self.del_phi = ct.getCOMdel(mol, self.activeS) return self.del_phi
def getS(self, mol): self.COM = ct.getCOMdist(mol, self.activeS) return (self.COM, self.COM, self.COM)
def runNormal(p): try: # If additional atoms have been added then update baseline dictionary # This only occurs when an extra bimolecular channel is added if len(p) > 6: print("correcting baseline for bi reaction") sym = "".join(p[6].get_chemical_symbols()) TotSym2 = "".join(p[0].CombReac.get_chemical_symbols()) size = len(TotSym2) TotSym = TotSym2[:size - len(sym)] print(str(sym) + " " + str(TotSym)) base = p[0].energyDictionary[TotSym] p[0].energyDictionary[TotSym + sym] = p[0].TempBiEne(p[6]) + base with open('dict.pkl', 'wb') as handle: pickle.dump(p[0].energyDictionary, handle) print(str(base)) # Run Trajectory p[1].runTrajectory() print('trajectory done') print(p[1].productGeom) # Geom opt part # Optimise Product p[0].quickOptProd(p[1].productGeom, False) # Get prod Name and create directory prodpath = p[2] + '/' + str(p[0].ProdName) if p[0].ProdName != p[0].ReacName and not os.path.exists(prodpath): p[0].optProd(p[1].productGeom, False) # Get the indicies of the bonds which have either formed or broken over the course of the reaction try: changedBonds = CT.getChangedBonds(p[0].CombReac, p[0].CombProd) except: changedBonds = [] data = open(('AllData.txt'), "a") data.write('Reactant = ' + str(p[0].ReacName) + ' Product = ' + str(p[0].ProdName) + ' MD Steps = ' + str(p[1].numberOfSteps) + '\n') print('changesBonds ' + str(changedBonds)) print(str(p[0].ProdName)) # Check the reaction product is not the orriginal reactant if p[0].ProdName != p[0].ReacName: # Make Directory for product if not os.path.exists(prodpath): os.makedirs(prodpath) p[0].printProd(prodpath) # TS optimisation try: p[0].optTS(changedBonds, prodpath, p[1].MolList, p[1].TSpoint) except: # If TS opt fails for some reason, assume barrierless print('Couldnt opt TS at trans point') p[0].barrierlessReaction = True data = open(('MechanismData.txt'), "a") try: data.write( 'Reactant = ' + str(p[0].ReacName) + ' Product = ' + str(p[0].ProdName) + ' BarrierHeight = ' + str((p[0].forwardBarrier - p[0].reactantEnergy) * 96.45) + ' Reaction Energy = ' + str((p[0].productEnergy - p[0].reactantEnergy) * 96.45) + ' Spline = ' + str(p[0].spline) + '\n') except: data.write('Reactant = ' + str(p[0].ReacName) + ' Product = ' + str(p[0].ProdName) + ' BarrierHeight = ' + str((p[0].forwardBarrier - p[0].reactantEnergy) * 96.45) + ' Reaction Energy = ' + str((p[0].productEnergy - p[0].reactantEnergy) * 96.45)) printXML = True # check whether there is an alternate product # if p[0].checkAltProd == True and p[0].is_IntermediateProd == True: # p[0].optProd(p[1].productGeom, True) # Check some criteria before printing to xml # if Isomerisation check there is a TS if p[0].is_bimol_prod == False and p[ 0].is_bimol_reac == False and p[ 0].barrierlessReaction == True: printXML = True # Then check barrier isnt ridiculous if p[0].barrierlessReaction == False and (( (p[0].forwardBarrier - p[0].reactantEnergy) * 96.45) > 1600): printXML = False print('channel barrier too large') # Finally check that the product isnt higher in energy than the reactant in case of ILT if p[0].is_bimol_reac == True and p[ 0].barrierlessReaction == True and p[ 0].reactantEnergy < p[0].productEnergy: printXML = False if printXML == True: try: io.writeTSXML(p[0], p[3]) io.writeTSXML(p[0], p[3].replace('.xml', 'Full.xml')) try: io.writeTSXML2(p[0], p[3].replace('.xml', 'Full.xml')) except: pass except: print('Couldnt print TS1') tmppath = p[3].replace('/MESMER/mestemplate.xml', '/') tmppath = tmppath + p[0].ProdName if not os.path.exists(tmppath): io.writeMinXML(p[0], p[3], False, False) io.writeMinXML(p[0], p[3].replace('.xml', 'Full.xml'), False, False) if p[0].is_bimol_prod == True: io.writeMinXML(p[0], p[3], False, True) io.writeMinXML(p[0], p[3].replace('.xml', 'Full.xml'), False, True) try: io.writeCombXML(p[0], p[3]) io.writeCombXML( p[0], p[3].replace('.xml', 'Full.xml')) except: pass if not os.path.exists(tmppath + "/" + p[0].ReacName): if p[0].is_bimol_prod == False and p[ 0].is_bimol_reac == False and p[ 0].barrierlessReaction == True: p[0].barrierlessReaction = False print( 'Isomerisation reaction does not have defined barrier, print anyway but be cautious' ) io.writeReactionXML( p[0], p[3].replace('.xml', 'Full.xml'), False) elif p[0].is_bimol_prod == False: io.writeReactionXML(p[0], p[3], False) io.writeReactionXML( p[0], p[3].replace('.xml', 'Full.xml'), False) elif p[0].is_bimol_prod == True and (p[0].TScorrect or p[0].TS2correct): io.writeReactionXML(p[0], p[3], False) io.writeReactionXML( p[0], p[3].replace('.xml', 'Full.xml'), False) if (p[5].InitialBi == True): p[0].re_init_bi(p[5].cartesians, p[5].species) else: p[0].re_init(p[2]) except: if (p[5].InitialBi == True): p[0].re_init_bi(p[5].cartesians, p[5].species) else: p[0].re_init(p[2])
def run(glo): # Get path to current directory path = os.getcwd() # Check whether there is a directory for putting calcuation data in. If not create it if not os.path.exists(path + '/Raw'): os.mkdir(path + '/Raw') # Set restart bool for now glo.restart = True # Add system name to path syspath = path + '/' + glo.dirName # Make working directories for each core #Make working directories for each core for i in range(0, glo.cores): if not os.path.exists(path + '/Raw/' + str(i)): os.mkdir(path + '/Raw/' + str(i)) # Start counter which tracks the kinetic timescale mechanismRunTime = 0.0 #Set reaction instance reacs = dict( ("reac_" + str(i), rxn.Reaction(glo.cartesians, glo.species, i, glo)) for i in range(glo.cores)) # Initialise Master Equation object me = ChemDyME.MasterEq.MasterEq() # Open files for saving summary mainsumfile = open(('mainSummary.txt'), "a") # Base energy value energyDictionary = {} base_ene = 0.0 while mechanismRunTime < glo.maxSimulationTime: # Minimise starting Geom and write summary xml for channel if reacs['reac_0'].have_reactant == False: outputs = [] if __name__ == 'ChemDyME.Main': arguments = [] for i in range(0, glo.cores): name = 'reac_' + str(i) arguments.append(reacs[name]) p = multiprocessing.Pool(glo.cores) results = p.map(minReac, arguments) outputs = [result for result in results] for i in range(0, glo.cores): name = 'reac_' + str(i) reacs[name] = outputs[i] else: for i in range(0, glo.cores): name = 'reac_' + str(i) reacs[name].have_reactant = False # Update path for new minima minpath = syspath + '/' + reacs['reac_0'].ReacName # Get smiles name for initial geom and create directory for first minimum if not os.path.exists(minpath): os.makedirs(minpath) # Copy MESMER file from mes folder MESpath = syspath + '/MESMER/' symb = "".join(reacs['reac_0'].CombReac.get_chemical_symbols()) try: with open('dict.pkl', 'rb') as handle: energyDictionary = pickle.loads(handle.read()) except: pass if symb not in energyDictionary: d = {symb: reacs['reac_0'].reactantEnergy} energyDictionary.update(d) with open('dict.pkl', 'wb') as handle: pickle.dump(energyDictionary, handle) for i in range(0, glo.cores): reacs['reac_' + str(i)].energyDictionary = energyDictionary # If a MESMER file has not been created for the current minima then create one if not os.path.exists(MESpath): os.makedirs(MESpath) copyfile('mestemplate.xml', MESpath + 'mestemplate.xml') copyfile('mestemplate.xml', MESpath + 'mestemplateFull.xml') MESFullPath = MESpath + 'mestemplateFull.xml' MESpath = MESpath + 'mestemplate.xml' io.writeMinXML(reacs['reac_0'], MESpath, True, False) io.writeMinXML(reacs['reac_0'], MESFullPath, True, False) if reacs['reac_0'].is_bimol_reac == True: io.writeMinXML(reacs['reac_0'], MESpath, True, True) io.writeMinXML(reacs['reac_0'], MESFullPath, True, True) glo.restart = False else: MESFullPath = MESpath + 'mestemplateFull.xml' MESpath = MESpath + 'mestemplate.xml' # If this is a restart then need to find the next new product from the ME, otherwise start trajectories if glo.restart == False: reacs['reac_0'].printReac(minpath) for r in range(0, glo.ReactIters): tempPaths = dict(("tempPath_" + str(i), minpath + '/temp' + str(i) + '_' + str(r)) for i in range(glo.cores)) # Now set up tmp directory for each thread for i in range(0, glo.cores): if not os.path.exists(tempPaths[('tempPath_' + str(i))]): os.makedirs(tempPaths[('tempPath_' + str(i))]) if r % 2 == 0: glo.trajMethod = glo.trajMethod1 glo.trajLevel = glo.trajLevel1 else: glo.trajMethod = glo.trajMethod2 glo.trajLevel = glo.trajLevel2 # If this is the first species and it is a bimolecular channel, then initialise a bimolecular trajectory # Otherwise initialise unimolecular trajectory at minima if glo.InitialBi == True: trajs = dict( ("traj_" + str(i), ChemDyME.Trajectory.Trajectory( reacs[('reac_' + str(i))].CombReac, glo, tempPaths[( 'tempPath_' + str(i))], str(i), True)) for i in range(glo.cores)) else: trajs = dict( ("traj_" + str(i), ChemDyME.Trajectory.Trajectory( reacs[('reac_' + str(i))].CombReac, glo, tempPaths[( 'tempPath_' + str(i))], str(i), False)) for i in range(glo.cores)) if __name__ == "ChemDyME.Main": arguments1 = [] arguments2 = [] for i in range(0, glo.cores): name = 'reac_' + str(i) name2 = 'traj_' + str(i) arguments1.append(reacs[name]) arguments2.append(trajs[name2]) arguments = list( zip(arguments1, arguments2, [minpath] * glo.cores, [MESpath] * glo.cores, range(glo.cores), [glo] * glo.cores)) p = multiprocessing.Pool(glo.cores) p.map(runNormal, arguments) for i in range(0, glo.cores): r_symb = "".join( reacs['reac_' + str(i)].CombReac.get_chemical_symbols()) p_symb = "".join(reacs['reac_' + str(i)].Prod.get_chemical_symbols()) if p_symb not in energyDictionary: d = {p_symb: energyDictionary[r_symb]} energyDictionary.update(d) for i in range(0, glo.cores): reacs['reac_' + str(i)].energyDictionary = energyDictionary with open('dict.pkl', 'wb') as handle: pickle.dump(energyDictionary, handle) # run a master eqution to estimate the lifetime of the current species time = 0 for i in range(0, 10): try: me.runTillReac(MESpath) except: me.time = np.inf if me.time > time: time = me.time me.newSpeciesFound = False # check whether there is a possible bimolecular rection for current intermediate if len(glo.BiList) > 0 and glo.InitialBi == False: print("looking at list of bimolecular candidates") for b in range(0, len(glo.BiList)): print("getting chemical symbols") baseXYZ = reacs['reac_0'].CombReac.get_chemical_symbols() if me.time > (1.0 / float(glo.BiRates[b])): print( "assessing whether or not to look for bimolecular channel. Rate = " + str(float(glo.BiRates[b])) + " Mesmer reaction time = " + str(me.time)) glo.InitialBi = True xyz = CT.get_bi_xyz(reacs['reac_0'].CombReac, glo.BiList[b]) spec = np.append( baseXYZ, np.array(glo.BiList[b].get_chemical_symbols())) combinedMols = [ Atoms(symbols=spec, positions=xyz) for i in range(glo.cores) ] # Set reaction instance for i in range(glo.cores): reacs['reac_' + str(i)].re_init_bi(xyz, spec) for r in range(0, glo.ReactIters): bitempPaths = dict( ("bitempPath_" + str(i), minpath + '/temp' + str(i) + '_' + str(r)) for i in range(glo.cores)) # Now set up tmp directory for each thread for i in range(0, glo.cores): if not os.path.exists( bitempPaths[('bitempPath_' + str(i))]): os.makedirs(bitempPaths[('bitempPath_' + str(i))]) if r % 2 == 0: glo.trajMethod = glo.trajMethod1 glo.trajLevel = glo.trajLevel1 else: glo.trajMethod = glo.trajMethod2 glo.trajLevel = glo.trajLevel2 biTrajs = dict( ("traj_" + str(i), ChemDyME.Trajectory.Trajectory( combinedMols[i], glo, bitempPaths[( 'bitempPath_' + str(i))], str(i), True)) for i in range(glo.cores)) for i in range(0, glo.cores): biTrajs['traj_' + str(i)].fragIdx = (len(baseXYZ), len(xyz)) if __name__ == "ChemDyME.Main": arguments1 = [] arguments2 = [] for i in range(0, glo.cores): name = 'reac_' + str(i) name2 = 'traj_' + str(i) arguments1.append(reacs[name]) arguments2.append(biTrajs[name2]) arguments = list( zip(arguments1, arguments2, [minpath] * glo.cores, [MESpath] * glo.cores, range(glo.cores), [glo] * glo.cores, [glo.BiList[b]] * glo.cores)) p = multiprocessing.Pool(glo.cores) p.map(runNormal, arguments) energyDictionary = reacs['reac_0'].energyDictionary for i in range(0, glo.cores): r_symb = "".join(reacs[ 'reac_' + str(i)].CombReac.get_chemical_symbols()) p_symb = "".join( reacs['reac_' + str(i)].Prod.get_chemical_symbols()) if p_symb not in energyDictionary: d = {p_symb: energyDictionary[r_symb]} energyDictionary.update(d) for i in range(0, glo.cores): reacs[ 'reac_' + str(i)].energyDictionary = energyDictionary with open('dict.pkl', 'wb') as handle: pickle.dump(energyDictionary, handle) glo.InitialBi = False glo.restart = False glo.InitialBi = False while me.newSpeciesFound == False: me.runTillReac(MESpath) mechanismRunTime += me.time out = me.prodName + ' ' + str(mechanismRunTime) + '\n' mainsumfile.write(out) mainsumfile.flush() if not os.path.exists(syspath + '/' + me.prodName): os.makedirs(syspath + '/' + me.prodName) if os.path.exists(syspath + '/' + reacs['reac_0'].ReacName + '/' + me.prodName): for i in range(glo.cores): reacs['reac_' + str(i)].newReac( syspath + '/' + reacs['reac_' + str(i)].ReacName + '/' + me.prodName, me.prodName, False, True) else: print("cant find path " + str(syspath + '/' + reacs['reac_0'].ReacName + '/' + me.prodName)) try: for i in range(glo.cores): reacs['reac_' + str(i)].newReac( syspath + '/' + me.prodName, me.prodName, True, True) except: for i in range(glo.cores): reacs['reac_' + str(i)].newReacFromSMILE( me.prodName) io.update_me_start(me.prodName, me.ene, MESpath) me.newSpeciesFound = True else: if me.repeated() == True: me.equilCount += 1 if me.equilCount >= 250: mainsumfile.write('lumping' + ' ' + str(reacs['reac_0'].ReacName) + ' ' + str(me.prodName) + '\n') me.prodName = io.lumpSpecies(reacs['reac_0'].ReacName, me.prodName, MESpath, MESpath) if reacs['reac_0'].ReacName == me.prodName: me.ene = me.eneList[-2] mainsumfile.flush() me.equilCount = 1 minpath = syspath + '/' + me.prodName if os.path.exists(syspath + '/' + reacs['reac_0'].ReacName + '/' + me.prodName): for i in range(glo.cores): reacs['reac_' + str(i)].newReac( syspath + '/' + reacs['reac_' + str(i)].ReacName + '/' + me.prodName, me.prodName, False, False) else: try: for i in range(glo.cores): reacs['reac_' + str(i)].newReac( syspath + '/' + me.prodName, me.prodName, True, False) except: for i in range(glo.cores): reacs['reac_' + str(i)].newReacFromSMILE( me.prodName, False) io.update_me_start(me.prodName, me.ene, MESpath) me.newspeciesFound = False glo.restart = False mainsumfile.close()