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 ReactionType(self, mol): oldbonds = np.count_nonzero(self.C) self.dRef = CT.refBonds(mol) self.C = CT.bondMatrix(self.dRef, mol) newbonds = np.count_nonzero(self.C) if oldbonds > newbonds: reacType = 'Dissociation' if oldbonds < newbonds: reacType = 'Association' if oldbonds == newbonds: reacType = 'Isomerisation' return reacType
def __init__(self, species, xyz): self.species = species # Get reference bonds self.dRef = ct.refBonds(species) self.dratio = self.dRef # Create bonding matrix self.bondMat = ct.bondMatrix(self.species, self.dRef, xyz, self.dratio) self.criteriaMet = False self.breakingBond = (0,0) self.makingBond = (0,0) self.bondMatTemp = self.bondMat self.secondCriteriaMet = False self.secondBreakingBond = (0,0) self.secondMakingBond = (0,0)
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 Update(self, xyz): self.bondMatTemp = ct.bondMatrix(self.species, self.dRef, xyz) atom1 = 0 atom2 = 0 atom3 = 0 for i in self.species.size: bond = 0.0 nonBond = 100.0 for j in self.species.size: if self.bondMat[i][j] == 1.0 and self.dratio > bond: bond = self.dratio atom1 = i atom2 = j if self.bondMat[i][j] == 0.0 and self.dratio[i][j] < nonBond: nonBond = self.dratio[i][j] atom3 = j if bond > nonBond: if self.criteriaMet is False: self.criteriaMet = True self.makingBond = (atom1,atom3) self.breakingBond = (atom1,atom2) else: self.secondCriteriaMet = True self.secondMakingBond = (atom1, atom3) self.secondBreakingBond = (atom1, atom2)
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 ReactionType(self, xyz): oldbonds = np.count_nonzero(self.bondMat) self.bondMat = ct.bondMatrix(self.species,self.dref, xyz) newbonds = np.count_nonzero(self.bondMat) if oldbonds > newbonds: reacType = 'Dissociation' if oldbonds < newbonds: reacType = 'Association' if oldbonds == newbonds: reacType = 'Isomerisation' return reacType
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 = 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 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 reinitialise(self, xyz): self.bondMat = ct.bondMatrix(self.species, self.dRef, xyz) self.criteriaMet = False self.breakingBond = (0,0) self.makingBond = (0,0) self.secondCriteriaMet = False
def reinitialise(self, mol): self.dRef = CT.refBonds(mol) self.C = CT.bondMatrix(self.dRef, mol) self.transitionIdices = np.zeros(3)
def __init__(self, mol): self.dRef = CT.refBonds(mol) self.C = CT.bondMatrix(self.dRef, mol) self.transitionIndices = np.zeros(3) self.criteriaMet = False
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()) TotSym = "".join(p[0].CombReac.get_chemical_symbols()) print(str(sym) + " " + str(TotSym)) base = p[0].energyDictionary[TotSym] p[0].energyDictionary[TotSym + sym] = p[0].TempBiEne(p[6]) + base print(str(base)) # Run Trajectory p[1].runTrajectory() print('trajectory done') print(p[1].productGeom) # Geom opt part # Optimise Product p[0].optProd(p[1].productGeom, False) #Get prod Name and create directory prodpath = p[2] + '/' + str(p[0].ProdName) #Get the indicies of the bonds which have either formed or broken over the course of the reaction changedBonds = CT.getChangedBonds(p[0].CombReac, p[0].CombProd) 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].optTSpoint(changedBonds, prodpath, p[1].MolList, p[1].TSpoint, 0) except: # If TS opt fails for some reason, assume barrierless print('Couldnt opt TS at trans point') p[0].barrierlessReaction = True printTS2 = False printXML = True if p[0].TScorrect != True: # See whether a dynamical path calculation or an NEB calculation has been specified to refine TS if p[5].printDynPath == True: try: p[0].optDynPath(changedBonds, prodpath, p[1].MolList, p[1].TSpoint) except: print("DynPath failed") elif p[5].printNEB == True: try: p[0].optNEB(changedBonds, prodpath, p[1].changePoints, p[1].MolList) except: print("NEB failed") if p[0].TS2correct == True: printTS2 = 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: p[0].barrierlessReaction = False printXML = True #Then check barrier isnt ridiculous if (((p[0].forwardBarrier - p[0].reactantEnergy) * 96.45) > 500): 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')) except: print('Couldnt print TS1') if printTS2 == True: try: io.writeTSXML2(p[0], p[3]) io.writeTSXML2(p[0], p[3].replace('.xml', 'Full.xml')) except: print('Couldnt print TS2') tmppath = p[3].replace('/MESMER/mestemplate.xml', '/') tmppath = tmppath + p[0].ProdName data = open(('MechanismData.txt'), "a") data.write('Reactant = ' + str(p[0].ReacName) + ' Product = ' + str(p[0].ProdName) + ' BarrierHeight = ' + str((p[0].forwardBarrier - p[0].reactantEnergy) * 96.45) + '\n') if not os.path.exists(tmppath): io.writeMinXML(p[0], p[3], False, False) if p[0].is_bimol_prod == True: io.writeMinXML(p[0], p[3], False, True) if not os.path.exists(tmppath + "/" + p[0].ReacName): io.writeReactionXML(p[0], p[3], printTS2) io.writeReactionXML(p[0], p[3].replace('.xml', 'Full.xml'), printTS2) if (p[5].InitialBi == True): p[0].re_init_bi(p[5].cartesians, p[5].species) else: p[0].re_init(p[2]) return p[0], p[1] except: if (p[5].InitialBi == True): p[0].re_init_bi(p[5].cartesians, p[5].species) else: p[0].re_init(p[2]) return p[0], p[1]
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 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 = MasterEq.MasterEq() # Open files for saving summary mainsumfile = open(('mainSummary.txt'), "a") while mechanismRunTime < glo.maxSimulationTime: # Minimise starting Geom and write summary xml for channel if reacs['reac_0'].have_reactant == False: outputs = [] if __name__ == '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[name].CombReac.get_chemical_symbols()) if reacs['reac_0'].energyDictionary[symb] == 0.0: for i in range(0, glo.cores): name = 'reac_' + str(i) d = {symb: reacs[name].reactantEnergy} reacs[name].energyDictionary.update(d) # 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: # Open files for saving summary sumfile = open((minpath + '/summary.txt'), "w") 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), 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), Trajectory.Trajectory( reacs[('reac_' + str(i))].CombReac, glo, tempPaths[( 'tempPath_' + str(i))], str(i), False)) for i in range(glo.cores)) results2 = [] outputs2 = [] if __name__ == "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) results2 = p.map(runNormal, arguments) outputs2 = [result for result in results2] for i in range(0, glo.cores): name = 'reac_' + str(i) reacs[name] = outputs2[i][0] sumfile.write( str(reacs[name].ProdName) + '_' + str(reacs[name].biProdName) + '\t' + str(reacs[name].forwardBarrier) + '\t' + str(outputs2[i][1].numberOfSteps)) sumfile.flush() # run a master eqution to estimate the lifetime of the current species me.runTillReac(MESpath) me.newSpeciesFound = False # check whether there is a possible bimolecular rection for current intermediate if len(glo.BiList) > 0 and glo.InitialBi == False: for i in range(0, len(glo.BiList)): baseXYZ = reacs['reac_0'].CombReac.get_chemical_symbols() if me.time > (1 / float(glo.BiRates[i])): print( "assessing whether or not to look for bimolecular channel. Rate = " + str(float(glo.BiRates[i])) + "Mesmer reaction time = " + str(me.time)) glo.InitialBi = True xyz = CT.get_bi_xyz(reacs['reac_0'].ReacName, glo.BiList[i]) spec = np.append( baseXYZ, np.array(glo.BiList[i].get_chemical_symbols())) combinedMol = Atoms(symbols=spec, positions=xyz) #Set reaction instance for j in range(0, glo.cores): name = 'reac_' + str(j) d = {symb: reacs[name].reactantEnergy} reacs[name].re_init_bi(xyz, spec) biTrajs = dict( ("traj_" + str(k), Trajectory.Trajectory( combinedMol, glo, tempPaths[( 'tempPath_' + str(k))], str(k), True)) for k in range(glo.cores)) biTempPaths = dict(("tempPath_" + str(k), minpath + '/temp' + str(j)) for k in range(glo.cores)) if __name__ == "Main": arguments1 = [] arguments2 = [] for j in range(0, glo.cores): name = 'reac_' + str(j) name2 = 'traj_' + str(j) biTrajs[name2].fragIdx = (len(baseXYZ), len(xyz)) 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[i]] * glo.cores)) p = multiprocessing.Pool(glo.cores) p.map(runNormal, arguments) glo.InitialBi = False # Run ME from the given minimum. While loop until species formed is new sumfile.close() glo.restart = False glo.InitialBi = False while me.newSpeciesFound == False: me.runTillReac(MESpath) mechanismRunTime += me.time out = me.prodName + ' ' + str(mechanismRunTime) + '\n' me.visitedList.append(me.prodName) mainsumfile.write(out) mainsumfile.flush() if not os.path.exists(syspath + '/' + me.prodName): os.makedirs(syspath + '/' + me.prodName) for i in range(0, glo.cores): if os.path.exists(syspath + '/' + reacs[('reac_' + str(i))].ReacName + '/' + me.prodName): reacs[('reac_' + str(i))].newReac( syspath + '/' + reacs[('reac_' + str(i))].ReacName + '/' + me.prodName, me.prodName, False) else: print("cant find path " + str(syspath + '/' + reacs[ ('reac_' + str(i))].ReacName + '/' + me.prodName)) try: reacs[('reac_' + str(i))].newReac( syspath + '/' + me.prodName, me.prodName, True) except: 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 >= 20: mainsumfile.write('lumping' + ' ' + str(reacs['reac_0'].ReacName) + ' ' + str(me.prodName) + '\n') me.prodName = io.lumpSpecies(reacs['reac_0'].ReacName, me.prodName, MESpath, MESpath) mainsumfile.flush() me.equilCount = 1 minpath = syspath + '/' + me.prodName for i in range(0, glo.cores): if os.path.exists(syspath + '/' + reacs[('reac_' + str(i))].ReacName + '/' + me.prodName): reacs[('reac_' + str(i))].newReac( syspath + '/' + reacs[('reac_' + str(i))].ReacName + '/' + me.prodName, me.prodName, False) else: try: reacs[('reac_' + str(i))].newReac( syspath + '/' + me.prodName, me.prodName, True) except: reacs[('reac_' + str(i))].newReacFromSMILE( me.prodName) io.update_me_start(me.prodName, me.ene, MESpath) me.newspeciesFound = False glo.restart = False mainsumfile.close()