def optimize(self, shot=0, method="newton", crit=1e-4): """ Optimize the geometry and align the optimized geometry to the starting geometry. """ logger.error( 'Geometry optimizations are not yet implemented in AMBER interface' ) raise NotImplementedError # Code from tinkerio.py if os.path.exists('%s.xyz_2' % self.name): os.unlink('%s.xyz_2' % self.name) self.mol[shot].write('%s.xyz' % self.name, ftype="tinker") if method == "newton": if self.rigid: optprog = "optrigid" else: optprog = "optimize" elif method == "bfgs": if self.rigid: optprog = "minrigid" else: optprog = "minimize" o = self.calltinker("%s %s.xyz %f" % (optprog, self.name, crit)) # Silently align the optimized geometry. M12 = Molecule("%s.xyz" % self.name, ftype="tinker") + Molecule( "%s.xyz_2" % self.name, ftype="tinker") if not self.pbc: M12.align(center=False) M12[1].write("%s.xyz_2" % self.name, ftype="tinker") rmsd = M12.ref_rmsd(0)[1] cnvgd = 0 mode = 0 for line in o: s = line.split() if len(s) == 0: continue if "Optimally Conditioned Variable Metric Optimization" in line: mode = 1 if "Limited Memory BFGS Quasi-Newton Optimization" in line: mode = 1 if mode == 1 and isint(s[0]): mode = 2 if mode == 2: if isint(s[0]): E = float(s[1]) else: mode = 0 if "Normal Termination" in line: cnvgd = 1 if not cnvgd: for line in o: logger.info(str(line) + '\n') logger.info( "The minimization did not converge in the geometry optimization - printout is above.\n" ) return E, rmsd
def parse_atomtype_line(line): """ Parses the 'atomtype' line. Parses lines like this:\n <tt> opls_135 CT 6 12.0107 0.0000 A 3.5000e-01 2.7614e-01\n C 12.0107 0.0000 A 3.7500e-01 4.3932e-01\n Na 11 22.9897 0.0000 A 6.068128070229e+03 2.662662556402e+01 0.0000e+00 ; PARM 5 6\n </tt> Look at all the variety! @param[in] line Input line. @return answer Dictionary containing:\n atom type\n bonded atom type (if any)\n atomic number (if any)\n atomic mass\n charge\n particle type\n force field parameters\n number of optional fields """ # First split the line up to the comment. We don't care about the comment at this time sline = line.split(';')[0].split() # The line must contain at least six fields to be considered data. if len(sline) < 6: return # Using variable "wrd" because the line has a variable number of fields # Can you think of a better way? wrd = 0 bonus = 0 atomtype = sline[wrd] batomtype = sline[wrd] wrd += 1 # The bonded atom type, a pecularity of OPLS-AA # Test if it begins with a letter. Seems to work. :) if re.match('[A-Za-z]',sline[wrd]): batomtype = sline[wrd] wrd += 1 bonus += 1 # Now to test if the next line is an atomic number or a mass. # Atomic numbers never have decimals... atomicnum = -1 if isint(sline[wrd]): atomicnum = int(sline[wrd]) wrd += 1 bonus += 1 # The mass can be overridden in the 'atoms' section. mass = float(sline[wrd]) wrd += 1 # Atom types have a default charge though this is almost always overridden chg = float(sline[wrd]) wrd += 1 # Particle type. Actual atom or virtual site? ptp = sline[wrd] wrd += 1 param = [float(i) for i in sline[wrd:]] answer = {'atomtype':atomtype, 'batomtype':batomtype, 'atomicnum':atomicnum, 'mass':mass, 'chg':chg, 'ptp':ptp, 'param':param, 'bonus':bonus} return answer
def optimize(self, shot=0, method="newton", crit=1e-4): """ Optimize the geometry and align the optimized geometry to the starting geometry. """ logger.error('Geometry optimizations are not yet implemented in AMBER interface') raise NotImplementedError # Code from tinkerio.py if os.path.exists('%s.xyz_2' % self.name): os.unlink('%s.xyz_2' % self.name) self.mol[shot].write('%s.xyz' % self.name, ftype="tinker") if method == "newton": if self.rigid: optprog = "optrigid" else: optprog = "optimize" elif method == "bfgs": if self.rigid: optprog = "minrigid" else: optprog = "minimize" o = self.calltinker("%s %s.xyz %f" % (optprog, self.name, crit)) # Silently align the optimized geometry. M12 = Molecule("%s.xyz" % self.name, ftype="tinker") + Molecule("%s.xyz_2" % self.name, ftype="tinker") if not self.pbc: M12.align(center=False) M12[1].write("%s.xyz_2" % self.name, ftype="tinker") rmsd = M12.ref_rmsd(0)[1] cnvgd = 0 mode = 0 for line in o: s = line.split() if len(s) == 0: continue if "Optimally Conditioned Variable Metric Optimization" in line: mode = 1 if "Limited Memory BFGS Quasi-Newton Optimization" in line: mode = 1 if mode == 1 and isint(s[0]): mode = 2 if mode == 2: if isint(s[0]): E = float(s[1]) else: mode = 0 if "Normal Termination" in line: cnvgd = 1 if not cnvgd: for line in o: logger.info(str(line) + '\n') logger.info("The minimization did not converge in the geometry optimization - printout is above.\n") return E, rmsd
def is_mol2_atom(line): s = line.split() if len(s) < 9: return False return all([ isint(s[0]), isfloat(s[2]), isfloat(s[3]), isfloat(s[4]), isfloat(s[8]) ])
def normal_modes(self, shot=0, optimize=True): logger.error('Normal modes are not yet implemented in AMBER interface') raise NotImplementedError # Copied from tinkerio.py if optimize: self.optimize(shot, crit=1e-6) o = self.calltinker("vibrate %s.xyz_2 a" % (self.name)) else: warn_once("Asking for normal modes without geometry optimization?") self.mol[shot].write('%s.xyz' % self.name, ftype="tinker") o = self.calltinker("vibrate %s.xyz a" % (self.name)) # Read the TINKER output. The vibrational frequencies are ordered. # The six modes with frequencies closest to zero are ignored readev = False calc_eigvals = [] calc_eigvecs = [] for line in o: s = line.split() if "Vibrational Normal Mode" in line: freq = float(s[-2]) readev = False calc_eigvals.append(freq) calc_eigvecs.append([]) elif "Atom" in line and "Delta X" in line: readev = True elif readev and len(s) == 4 and all( [isint(s[0]), isfloat(s[1]), isfloat(s[2]), isfloat(s[3])]): calc_eigvecs[-1].append([float(i) for i in s[1:]]) calc_eigvals = np.array(calc_eigvals) calc_eigvecs = np.array(calc_eigvecs) # Sort by frequency absolute value and discard the six that are closest to zero calc_eigvecs = calc_eigvecs[np.argsort(np.abs(calc_eigvals))][6:] calc_eigvals = calc_eigvals[np.argsort(np.abs(calc_eigvals))][6:] # Sort again by frequency calc_eigvecs = calc_eigvecs[np.argsort(calc_eigvals)] calc_eigvals = calc_eigvals[np.argsort(calc_eigvals)] os.system("rm -rf *.xyz_* *.[0-9][0-9][0-9]") return calc_eigvals, calc_eigvecs
def feed(self, line, linindep=False): """ Feed in a line. @param[in] line The line of data """ if linindep: if match('^ *!', line): self.destroy = True else: self.destroy = False line = sub('^ *!', '', line) line = line.split('!')[0].strip() s = line.split() self.ln += 1 # No sense in doing anything for an empty line or a comment line. if len(s) == 0 or match('^ *!', line): return None, None # Now go through all the cases. if match('^[A-Za-z][A-Za-z]? +[0-9]$', line): # This is supposed to match the element line. For example 'Li 0' self.element = s[0].capitalize() self.isdata = False self.destroy = False elif len(s) == 3 and match('[SPDFGH]+', s[0]) and isint( s[1]) and isfloat(s[2]): self.amom = s[0] if self.amom == self.last_amom: self.basis_number[self.element] += 1 else: self.basis_number[self.element] = 0 self.last_amom = self.amom self.contraction_number = -1 self.isdata = True # This is supposed to match a line like 'P 1 1.00' elif len(s) == 2 and isfloat(s[0]) and isfloat(s[1]): self.contraction_number += 1 self.isdata = True else: self.isdata = False self.destroy = False
def feed(self, line, linindep=False): """ Feed in a line. @param[in] line The line of data """ if linindep: if match('^ *!',line): self.destroy = True else: self.destroy = False line = sub('^ *!','',line) line = line.split('!')[0].strip() s = line.split() self.ln += 1 # No sense in doing anything for an empty line or a comment line. if len(s) == 0 or match('^ *!',line): return None, None # Now go through all the cases. if match('^[A-Za-z][A-Za-z]? +[0-9]$',line): # This is supposed to match the element line. For example 'Li 0' self.element = capitalize(s[0]) self.isdata = False self.destroy = False elif len(s) == 3 and match('[SPDFGH]+',s[0]) and isint(s[1]) and isfloat(s[2]): self.amom = s[0] if self.amom == self.last_amom: self.basis_number[self.element] += 1 else: self.basis_number[self.element] = 0 self.last_amom = self.amom self.contraction_number = -1 self.isdata = True # This is supposed to match a line like 'P 1 1.00' elif len(s) == 2 and isfloat(s[0]) and isfloat(s[1]): self.contraction_number += 1 self.isdata = True else: self.isdata = False self.destroy = False
def normal_modes(self, shot=0, optimize=True): logger.error('Normal modes are not yet implemented in AMBER interface') raise NotImplementedError # Copied from tinkerio.py if optimize: self.optimize(shot, crit=1e-6) o = self.calltinker("vibrate %s.xyz_2 a" % (self.name)) else: warn_once("Asking for normal modes without geometry optimization?") self.mol[shot].write('%s.xyz' % self.name, ftype="tinker") o = self.calltinker("vibrate %s.xyz a" % (self.name)) # Read the TINKER output. The vibrational frequencies are ordered. # The six modes with frequencies closest to zero are ignored readev = False calc_eigvals = [] calc_eigvecs = [] for line in o: s = line.split() if "Vibrational Normal Mode" in line: freq = float(s[-2]) readev = False calc_eigvals.append(freq) calc_eigvecs.append([]) elif "Atom" in line and "Delta X" in line: readev = True elif readev and len(s) == 4 and all([isint(s[0]), isfloat(s[1]), isfloat(s[2]), isfloat(s[3])]): calc_eigvecs[-1].append([float(i) for i in s[1:]]) calc_eigvals = np.array(calc_eigvals) calc_eigvecs = np.array(calc_eigvecs) # Sort by frequency absolute value and discard the six that are closest to zero calc_eigvecs = calc_eigvecs[np.argsort(np.abs(calc_eigvals))][6:] calc_eigvals = calc_eigvals[np.argsort(np.abs(calc_eigvals))][6:] # Sort again by frequency calc_eigvecs = calc_eigvecs[np.argsort(calc_eigvals)] calc_eigvals = calc_eigvals[np.argsort(calc_eigvals)] os.system("rm -rf *.xyz_* *.[0-9][0-9][0-9]") return calc_eigvals, calc_eigvecs
def feed(self, line, linindep=False): """ Feed in a line. @param[in] line The line of data """ line = line.split('!')[0].strip() s = line.split() self.ln += 1 # No sense in doing anything for an empty line or a comment line. if len(s) == 0 or match('^ *!',line): return None, None # Now go through all the cases. if match('^[A-Za-z][A-Za-z]? +[0-9]$',line): # This is supposed to match the element line. For example 'Li 0' self.element = capitalize(s[0]) self.radii[self.element] = float(s[1]) self.isdata = False self.point = 0 elif len(s) >= 2 and isint(s[0]) and isfloat(s[1]): self.point += 1 self.isdata = True else: self.isdata = False
def feed(self, line, linindep=False): """ Feed in a line. @param[in] line The line of data """ line = line.split('!')[0].strip() s = line.split() self.ln += 1 # No sense in doing anything for an empty line or a comment line. if len(s) == 0 or match('^ *!', line): return None, None # Now go through all the cases. if match('^[A-Za-z][A-Za-z]? +[0-9]$', line): # This is supposed to match the element line. For example 'Li 0' self.element = s[0].capitalize() self.radii[self.element] = float(s[1]) self.isdata = False self.point = 0 elif len(s) >= 2 and isint(s[0]) and isfloat(s[1]): self.point += 1 self.isdata = True else: self.isdata = False
QDict[i] = float("%.4f" % Q) # Try to zero out the atomic charge. print( "The following code aims to get an integer-charge molecule using precision 4 floating points." ) TQ = sum([QDict[T[i]] for i in range(na)]) print("All atom types have been selected; molecule has a net charge of %.4f" % TQ) Corr1 = (float("%.4f" % (-1 * TQ / na))) choice = input( "Create overall integer charge (enter integer), enter your own (enter float), or skip this step (hit Enter)? --> " ) + " " #if 'y' == choice[0] or 'Y' == choice[0]: if isint(choice.strip()): WantQ = int(choice) Corr1 = (float("%.4f" % ((WantQ - 1 * TQ) / na))) for i in QDict: QDict[i] += Corr1 TQ = sum([QDict[T[i]] for i in range(na)]) print("Adding a charge of %.4f to each atom" % Corr1) print( "Now all atom types have been selected; molecule has a net charge of %.4f" % TQ) else: try: Corr1 = float(choice) for i in QDict: QDict[i] += Corr1 TQ = sum([QDict[T[i]] for i in range(na)])
def is_mol2_atom(line): s = line.split() if len(s) < 9: return False return all([isint(s[0]), isfloat(s[2]), isfloat(s[3]), isfloat(s[4]), isfloat(s[8])])
COM = "OPLS " + OPLSExplanations[sline[0]] BAT[i] = i OPLSNicks[BAT[i]] = SelectedLine.split()[1] TEDict[BAT[i]] = Element M[i] = [ANum,PeriodicTable[Element],SIG,EPS,COM] QDict[i] = float("%.4f" % Q) # Try to zero out the atomic charge. print "The following code aims to get an integer-charge molecule using precision 4 floating points." TQ = sum([QDict[T[i]] for i in range(na)]) print "All atom types have been selected; molecule has a net charge of %.4f" % TQ Corr1 = (float("%.4f" % (-1*TQ/na))) choice = raw_input("Create overall integer charge (enter integer), enter your own (enter float), or skip this step (hit Enter)? --> ") + " " #if 'y' == choice[0] or 'Y' == choice[0]: if isint(choice.strip()): WantQ = int(choice) Corr1 = (float("%.4f" % ((WantQ - 1*TQ)/na))) for i in QDict: QDict[i] += Corr1 TQ = sum([QDict[T[i]] for i in range(na)]) print "Adding a charge of %.4f to each atom" % Corr1 print "Now all atom types have been selected; molecule has a net charge of %.4f" % TQ else: try: Corr1 = float(choice) for i in QDict: QDict[i] += Corr1 TQ = sum([QDict[T[i]] for i in range(na)]) print "Now all atom types have been selected; molecule has a net charge of %.4f" % TQ except: print "You didn't enter a number, exiting this section"