def setopts(self, **kwargs): """ Called by __init__ ; Set AMBER-specific options. """ ## The directory containing TINKER executables (e.g. dynamic) if 'amberhome' in kwargs: self.amberhome = kwargs['amberhome'] if not os.path.exists(os.path.join(self.amberhome,"sander")): warn_press_key("The 'sander' executable indicated by %s doesn't exist! (Check amberhome)" \ % os.path.join(self.amberhome,"sander")) else: warn_once("The 'amberhome' option was not specified; using default.") if which('sander') == '': warn_press_key("Please add AMBER executables to the PATH or specify amberhome.") self.amberhome = os.path.split(which('sander'))[0] with wopen('.quit.leap') as f: print >> f, 'quit' # AMBER search path self.spath = [] for line in self.callamber('tleap -f .quit.leap'): if 'Adding' in line and 'to search path' in line: self.spath.append(line.split('Adding')[1].split()[0]) os.remove('.quit.leap')
def driver(self): ## Actually run PSI4. if not in_fd() and CheckBasis(): logger.info("Now checking for linear dependencies.\n") _exec("cp %s %s.bak" % (self.GBSfnm, self.GBSfnm), print_command=False) ln0 = self.write_nested_destroy(self.GBSfnm, self.FF.linedestroy_save) o = wopen(".lindep.dat") for line in open(self.DATfnm).readlines(): s = line.split("#")[0].split() if len(s) == 3 and s[0].lower() == 'basis' and s[1].lower() == 'file': print >> o, "basis file %s" % self.GBSfnm else: print >> o, line, o.close() _exec("mv .lindep.dat %s" % self.DATfnm, print_command=False) _exec("psi4 %s" % self.DATfnm, print_command=False) LI = GBS_Reader() LI_lines = {} ## Read in the commented linindep.gbs file and ensure that these same lines are commented in the new .gbs file for line in open('linindep.gbs'): LI.feed(line,linindep=True) key = '.'.join([str(i) for i in LI.element,LI.amom,LI.basis_number[LI.element],LI.contraction_number]) if LI.isdata: if key in LI_lines: logger.info("Duplicate key found:\n") logger.info("%s\n" % key) logger.info(str(LI_lines[key])) logger.info(line) warn_press_key("In %s, the LI_lines dictionary should not contain repeated keys!" % __file__) LI_lines[key] = (line, LI.destroy)
def setopts(self, **kwargs): """ Called by __init__ ; Set AMBER-specific options. """ ## The directory containing TINKER executables (e.g. dynamic) if 'amberhome' in kwargs: self.amberhome = kwargs['amberhome'] if not os.path.exists(os.path.join(self.amberhome, "sander")): warn_press_key("The 'sander' executable indicated by %s doesn't exist! (Check amberhome)" \ % os.path.join(self.amberhome,"sander")) else: warn_once( "The 'amberhome' option was not specified; using default.") if which('sander') == '': warn_press_key( "Please add AMBER executables to the PATH or specify amberhome." ) self.amberhome = os.path.split(which('sander'))[0] with wopen('.quit.leap') as f: print >> f, 'quit' # AMBER search path self.spath = [] for line in self.callamber('tleap -f .quit.leap'): if 'Adding' in line and 'to search path' in line: self.spath.append(line.split('Adding')[1].split()[0]) os.remove('.quit.leap')
def __init__(self, options, tgt_opts, forcefield): super(THCDF_Psi4, self).__init__(options, tgt_opts, forcefield) # Parse the input.dat file to figure out the elements and molecules MolSection = False ElemList = [] self.Molecules = [] self.throw_outs = [] for line in open(os.path.join(self.root, self.tgtdir, "input.dat")).readlines(): line = line.strip() s = line.split() if len(s) >= 3 and s[0].lower() == 'molecule' and s[2] == '{': MolSection = True self.Molecules.append(s[1]) elif len(s) >= 1 and s[0] == '}': MolSection = False elif MolSection and len(s) >= 4 and match( "^[A-Za-z]+$", s[0]) and isfloat(s[1]) and isfloat( s[2]) and isfloat(s[3]): ElemList.append(s[0].capitalize()) self.Elements = set(ElemList) xgrad = [] for p in self.pgrad: Pelem = [] for pid in self.FF.plist[p].split(): # Extract the chemical element. Pelem.append(pid.split(':')[1].split(',')[0].split('=')[1]) Pelem = set(Pelem) if len(self.Elements.intersection(Pelem)) == 0: xgrad.append(p) for p in xgrad: self.pgrad.remove(p) ## Psi4 basis set file gbslist = [i for i in self.FF.fnms if os.path.splitext(i)[1] == '.gbs'] if len(gbslist) != 1: warn_press_key( "In %s, you should only have exactly one .gbs file in the list of force field files!" % __file__) self.GBSfnm = gbslist[0] ## Psi4 input file for calculation of linear dependencies ## This is actually a file in 'forcefield' until we can figure out a better system if CheckBasis(): datlist = [ i for i in self.FF.fnms if os.path.splitext(i)[1] == '.dat' ] if len(datlist) != 1: warn_press_key( "In %s, you should only have exactly one .dat file in the list of force field files!" % __file__) self.DATfnm = datlist[0] ## Prepare the temporary directory self.prepare_temp_directory(options, tgt_opts)
def read(self,mvals,AGrad=False,AHess=False): """ Read data from disk for the initial optimization step if the user has provided the directory to the "read" option. """ mvals1 = np.loadtxt('mvals.txt') if len(mvals) > 0 and (np.max(np.abs(mvals1 - mvals)) > 1e-3): warn_press_key("mvals from mvals.txt does not match up with get! (Are you reading data from a previous run?)\nmvals(call)=%s mvals(disk)=%s" % (mvals, mvals1)) return lp_load('objective.p')
def prepare_temp_directory(self, options, tgt_opts): os.environ["GMX_NO_SOLV_OPT"] = "TRUE" os.environ["GMX_NO_ALLVSALL"] = "TRUE" abstempdir = os.path.join(self.root,self.tempdir) if options['gmxpath'] == None or options['gmxsuffix'] == None: warn_press_key('Please set the options gmxpath and gmxsuffix in the input file!') if not os.path.exists(os.path.join(options['gmxpath'],"mdrun"+options['gmxsuffix'])): warn_press_key('The mdrun executable pointed to by %s doesn\'t exist! (Check gmxpath and gmxsuffix)' % os.path.join(options['gmxpath'],"mdrun"+options['gmxsuffix'])) # Link the necessary programs into the temporary directory LinkFile(os.path.join(options['gmxpath'],"mdrun"+options['gmxsuffix']),os.path.join(abstempdir,"mdrun")) LinkFile(os.path.join(options['gmxpath'],"grompp"+options['gmxsuffix']),os.path.join(abstempdir,"grompp")) LinkFile(os.path.join(options['gmxpath'],"trjconv"+options['gmxsuffix']),os.path.join(abstempdir,"trjconv")) # Link the run files LinkFile(os.path.join(self.root,self.tgtdir,"conf.gro"),os.path.join(abstempdir,"conf.gro")) LinkFile(os.path.join(self.root,self.tgtdir,"grompp.mdp"),os.path.join(abstempdir,"grompp.mdp")) LinkFile(os.path.join(self.root,self.tgtdir,"topol.top"),os.path.join(abstempdir,"topol.top"))
def read(self,mvals,AGrad=False,AHess=False): """ Read data from disk for the initial optimization step if the user has provided the directory to the "read" option. """ mvals1 = np.loadtxt('mvals.txt') if mvals1.shape != mvals.shape: warn_press_key("mvals from forcebalance.p has different shape compared to internal values!\nmvals(call)=%s mvals(disk)=%s" % (mvals, mvals1)) elif len(mvals1) > 0 and (np.max(np.abs(mvals1 - mvals)) > 1e-3): warn_press_key("mvals from forcebalance.p does not match up with internal values! (Are you reading data from a previous run?)\nmvals(call)=%s mvals(disk)=%s" % (mvals, mvals1)) return lp_load('objective.p')
def prepare_temp_directory(self,options,tgt_opts): """ Prepare the temporary directory by copying in important files. """ os.environ["GMX_NO_SOLV_OPT"] = "TRUE" os.environ["GMX_NO_ALLVSALL"] = "TRUE" abstempdir = os.path.join(self.root,self.tempdir) if options['gmxpath'] == None or options['gmxsuffix'] == None: warn_press_key('Please set the options gmxpath and gmxsuffix in the input file!') if not os.path.exists(os.path.join(options['gmxpath'],"mdrun"+options['gmxsuffix'])): warn_press_key('The mdrun executable pointed to by %s doesn\'t exist! (Check gmxpath and gmxsuffix)' % os.path.join(options['gmxpath'],"mdrun"+options['gmxsuffix'])) # Link the necessary programs into the temporary directory LinkFile(os.path.join(os.path.split(__file__)[0],"data","npt.py"),os.path.join(abstempdir,"npt.py")) LinkFile(os.path.join(os.path.split(__file__)[0],"data","rungmx.sh"),os.path.join(abstempdir,"rungmx.sh")) # Link the run files for phase in ["liquid","gas"]: LinkFile(os.path.join(self.root,self.tgtdir,"%s.mdp" % phase),os.path.join(abstempdir,"%s.mdp" % phase)) LinkFile(os.path.join(self.root,self.tgtdir,"%s.top" % phase),os.path.join(abstempdir,"%s.top" % phase)) LinkFile(os.path.join(self.root,self.tgtdir,"%s.gro" % phase),os.path.join(abstempdir,"%s.gro" % phase))
def interaction_driver_all(self, dielectric=False): """ Computes the energy and force using GROMACS for a trajectory. This does not require GROMACS-X2. """ # Remove backup files. rm_gmx_baks(os.getcwd()) # Do the interacting calculation. _exec(["./grompp", "-f", "interaction.mdp", "-n", "index.ndx"], print_command=False) _exec(["./mdrun", "-nt", "1", "-rerunvsite", "-rerun", "all.gro"], print_command=False) # Gather information _exec(["./g_energy","-xvg","no"], print_command=False, stdin="Potential\n") Interact = array([float(l.split()[1]) for l in open('energy.xvg').readlines()]) # Do the excluded calculation. _exec(["./grompp", "-f", "excluded.mdp", "-n", "index.ndx"], print_command=False) _exec(["./mdrun", "-nt", "1", "-rerunvsite", "-rerun", "all.gro"], print_command=False) # Gather information _exec(["./g_energy","-xvg","no"], print_command=False, stdin="Potential\n") Excluded = array([float(l.split()[1]) for l in open('energy.xvg').readlines()]) # The interaction energy. M = Interact - Excluded # Now we have the MM interaction energy. # We need the COSMO component of the interaction energy now... if dielectric: traj_dimer = deepcopy(self.traj) traj_dimer.add_quantum("qtemp_D.in") traj_dimer.write("qchem_dimer.in",ftype="qcin") traj_monoA = deepcopy(self.traj) traj_monoA.add_quantum("qtemp_A.in") traj_monoA.write("qchem_monoA.in",ftype="qcin") traj_monoB = deepcopy(self.traj) traj_monoB.add_quantum("qtemp_B.in") traj_monoB.write("qchem_monoB.in",ftype="qcin") wq = getWorkQueue() if wq == None: warn_press_key("To proceed past this point, a Work Queue must be present") print "Computing the dielectric energy" Diel_D = QChem_Dielectric_Energy("qchem_dimer.in",wq) Diel_A = QChem_Dielectric_Energy("qchem_monoA.in",wq) # The dielectric energy for a water molecule should never change. if hasattr(self,"Diel_B"): Diel_B = self.Diel_B else: Diel_B = QChem_Dielectric_Energy("qchem_monoB.in",self.wq) self.Diel_B = Diel_B self.Dielectric = Diel_D - Diel_A - Diel_B M += self.Dielectric return M
def __init__(self,options,tgt_opts,forcefield): super(THCDF_Psi4,self).__init__(options,tgt_opts,forcefield) # Parse the input.dat file to figure out the elements and molecules MolSection = False ElemList = [] self.Molecules = [] self.throw_outs = [] for line in open(os.path.join(self.root,self.tgtdir,"input.dat")).readlines(): line = line.strip() s = line.split() if len(s) >= 3 and s[0].lower() == 'molecule' and s[2] == '{': MolSection = True self.Molecules.append(s[1]) elif len(s) >= 1 and s[0] == '}': MolSection = False elif MolSection and len(s) >= 4 and match("^[A-Za-z]+$",s[0]) and isfloat(s[1]) and isfloat(s[2]) and isfloat(s[3]): ElemList.append(capitalize(s[0])) self.Elements = set(ElemList) xgrad = [] for p in self.pgrad: Pelem = [] for pid in self.FF.plist[p].split(): # Extract the chemical element. Pelem.append(pid.split(':')[1].split(',')[0].split('=')[1]) Pelem = set(Pelem) if len(self.Elements.intersection(Pelem)) == 0: xgrad.append(p) for p in xgrad: self.pgrad.remove(p) ## Psi4 basis set file gbslist = [i for i in self.FF.fnms if os.path.splitext(i)[1] == '.gbs'] if len(gbslist) != 1: warn_press_key("In %s, you should only have exactly one .gbs file in the list of force field files!" % __file__) self.GBSfnm = gbslist[0] ## Psi4 input file for calculation of linear dependencies ## This is actually a file in 'forcefield' until we can figure out a better system if CheckBasis(): datlist = [i for i in self.FF.fnms if os.path.splitext(i)[1] == '.dat'] if len(datlist) != 1: warn_press_key("In %s, you should only have exactly one .dat file in the list of force field files!" % __file__) self.DATfnm = datlist[0] ## Prepare the temporary directory self.prepare_temp_directory(options,tgt_opts)
def energy_rmsd(self, shot=0, optimize=True): """ Calculate energy of the selected structure (optionally minimize and return the minimized energy and RMSD). In kcal/mol. """ logger.error( 'Geometry optimization is not yet implemented in AMBER interface') raise NotImplementedError rmsd = 0.0 # This line actually runs TINKER # xyzfnm = sysname+".xyz" if optimize: E_, rmsd = self.optimize(shot) o = self.calltinker("analyze %s.xyz_2 E" % self.name) #---- # Two equivalent ways to get the RMSD, here for reference. #---- # M1 = Molecule("%s.xyz" % self.name, ftype="tinker") # M2 = Molecule("%s.xyz_2" % self.name, ftype="tinker") # M1 += M2 # rmsd = M1.ref_rmsd(0)[1] #---- # oo = self.calltinker("superpose %s.xyz %s.xyz_2 1 y u n 0" % (self.name, self.name)) # for line in oo: # if "Root Mean Square Distance" in line: # rmsd = float(line.split()[-1]) #---- os.system("rm %s.xyz_2" % self.name) else: o = self.calltinker("analyze %s.xyz E" % self.name) # Read the TINKER output. E = None for line in o: if "Total Potential Energy" in line: E = float(line.split()[-2].replace('D', 'e')) if E == None: logger.error( "Total potential energy wasn't encountered when calling analyze!\n" ) raise RuntimeError if optimize and abs(E - E_) > 0.1: warn_press_key( "Energy from optimize and analyze aren't the same (%.3f vs. %.3f)" % (E, E_)) return E, rmsd
def prepare_temp_directory(self, options, tgt_opts): os.environ["GMX_NO_SOLV_OPT"] = "TRUE" abstempdir = os.path.join(self.root,self.tempdir) if options['gmxpath'] == None or options['gmxsuffix'] == None: warn_press_key('Please set the options gmxpath and gmxsuffix in the input file!') if not os.path.exists(os.path.join(options['gmxpath'],"mdrun"+options['gmxsuffix'])): warn_press_key('The mdrun executable pointed to by %s doesn\'t exist! (Check gmxpath and gmxsuffix)' % os.path.join(options['gmxpath'],"mdrun"+options['gmxsuffix'])) # Link the necessary programs into the temporary directory LinkFile(os.path.join(options['gmxpath'],"mdrun"+options['gmxsuffix']),os.path.join(abstempdir,"mdrun")) LinkFile(os.path.join(options['gmxpath'],"grompp"+options['gmxsuffix']),os.path.join(abstempdir,"grompp")) LinkFile(os.path.join(options['gmxpath'],"g_energy"+options['gmxsuffix']),os.path.join(abstempdir,"g_energy")) # Link the run files LinkFile(os.path.join(self.root,self.tgtdir,"index.ndx"),os.path.join(abstempdir,"index.ndx")) #LinkFile(os.path.join(self.root,self.tgtdir,"shot.mdp"),os.path.join(abstempdir,"shot.mdp")) LinkFile(os.path.join(self.root,self.tgtdir,self.topfnm),os.path.join(abstempdir,self.topfnm)) # Write the trajectory to the temp-directory self.traj.write(os.path.join(abstempdir,"all.gro"),select=range(self.ns)) # Print out the first conformation in all.gro to use as conf.gro self.traj.write(os.path.join(abstempdir,"conf.gro"),select=[0])
def energy_rmsd(self, shot=0, optimize=True): """ Calculate energy of the selected structure (optionally minimize and return the minimized energy and RMSD). In kcal/mol. """ logger.error('Geometry optimization is not yet implemented in AMBER interface') raise NotImplementedError rmsd = 0.0 # This line actually runs TINKER # xyzfnm = sysname+".xyz" if optimize: E_, rmsd = self.optimize(shot) o = self.calltinker("analyze %s.xyz_2 E" % self.name) #---- # Two equivalent ways to get the RMSD, here for reference. #---- # M1 = Molecule("%s.xyz" % self.name, ftype="tinker") # M2 = Molecule("%s.xyz_2" % self.name, ftype="tinker") # M1 += M2 # rmsd = M1.ref_rmsd(0)[1] #---- # oo = self.calltinker("superpose %s.xyz %s.xyz_2 1 y u n 0" % (self.name, self.name)) # for line in oo: # if "Root Mean Square Distance" in line: # rmsd = float(line.split()[-1]) #---- os.system("rm %s.xyz_2" % self.name) else: o = self.calltinker("analyze %s.xyz E" % self.name) # Read the TINKER output. E = None for line in o: if "Total Potential Energy" in line: E = float(line.split()[-2].replace('D','e')) if E == None: logger.error("Total potential energy wasn't encountered when calling analyze!\n") raise RuntimeError if optimize and abs(E-E_) > 0.1: warn_press_key("Energy from optimize and analyze aren't the same (%.3f vs. %.3f)" % (E, E_)) return E, rmsd
def __init__(self,options,tgt_opts,forcefield): super(Liquid_GMX,self).__init__(options,tgt_opts,forcefield) # Number of threads in mdrun self.set_option(tgt_opts,'mdrun_threads') self.liquid_fnm = "liquid.gro" self.liquid_conf = Molecule(os.path.join(self.root, self.tgtdir,"liquid.gro")) self.liquid_traj = None self.gas_fnm = "gas.gro" if os.path.exists(os.path.join(self.root, self.tgtdir,"all.gro")): self.liquid_traj = Molecule(os.path.join(self.root, self.tgtdir,"all.gro")) print "Found collection of starting conformations, length %i!" % len(self.liquid_traj) if self.do_self_pol: warn_press_key("Self-polarization correction not implemented yet when using GMX") # Command prefix. self.nptpfx = 'sh rungmx.sh' # Suffix to command string for launching NPT simulations. self.nptsfx += ["--nt %i" % self.mdrun_threads] # List of extra files to upload to Work Queue. self.nptfiles += ['rungmx.sh', 'liquid.top', 'liquid.mdp', 'gas.top', 'gas.mdp'] # MD engine argument supplied to command string for launching NPT simulations. self.engine = "gromacs" # Send back the trajectory file. if self.save_traj > 0: self.extra_output = ['liquid-md.trr']
def __init__(self,options,tgt_opts,forcefield): super(Liquid_GMX,self).__init__(options,tgt_opts,forcefield) # self.DynDict = OrderedDict() # self.DynDict_New = OrderedDict() if self.do_self_pol: warn_press_key("Self-polarization correction not implemented yet when using GMX")
def parse_optgeo_options(filename): """ Parse an optgeo_options.txt file into specific OptGeoTarget Target Options""" logger.info("Reading optgeo options from file: %s\n" % filename) global_opts = OrderedDict() sys_opts = OrderedDict() section = None section_opts = OrderedDict() with open(filename) as f: for ln, line in enumerate(f, 1): # Anything after "#" is a comment line = line.split("#", maxsplit=1)[0].strip() if not line: continue ls = line.split() key = ls[0].lower() if key[0] == "$": # section sign $ if key == '$end': if section is None: warn_press_key( "Line %i: Encountered $end before any section." % ln) elif section == 'global': # global options read finish global_opts = section_opts elif section == 'system': # check if system section contains name if 'name' not in section_opts: warn_press_key( "Line %i: You need to specify a name for the system section ending." % ln) elif section_opts['name'] in sys_opts: warn_press_key( "Line %i: A system named %s already exists in Systems" % (ln, section_opts['name'])) else: sys_opts[section_opts['name']] = section_opts section = None section_opts = OrderedDict() else: if section is not None: warn_press_key( "Line %i: Encountered section start %s before previous section $end." % (ln, key)) if key == '$global': section = 'global' elif key == '$system': section = 'system' else: warn_press_key( "Line %i: Encountered unsupported section name %s " % (ln, key)) else: # put normal key-value options into section_opts if key in ['name', 'geometry', 'topology']: if len(ls) != 2: warn_press_key( "Line %i: one value expected for key %s" % (ln, key)) if section == 'global': warn_press_key( "Line %i: key %s should not appear in $global section" % (ln, key)) section_opts[key] = ls[1] elif key in [ 'bond_denom', 'angle_denom', 'dihedral_denom', 'improper_denom' ]: if len(ls) != 2: warn_press_key( "Line %i: one value expected for key %s" % (ln, key)) section_opts[key] = float(ls[1]) elif key == 'mol2': # special parsing for mol2 option for SMIRNOFF engine # the value is a list of filenames section_opts[key] = ls[1:] # apply a few default global options global_opts.setdefault('bond_denom', 0.02) global_opts.setdefault('angle_denom', 3) global_opts.setdefault('dihedral_denom', 10.0) global_opts.setdefault('improper_denom', 10.0) # copy global options into each system for sys_name, sys_opt_dict in sys_opts.items(): for k, v in global_opts.items(): # do not overwrite system options sys_opt_dict.setdefault(k, v) for k in ['name', 'geometry', 'topology']: if k not in sys_opt_dict: warn_press_key( "key %s missing in system section named %s" % (k, sys_name)) return sys_opts
def driver(self): ## Actually run PSI4. if not in_fd() and CheckBasis(): logger.info("Now checking for linear dependencies.\n") _exec("cp %s %s.bak" % (self.GBSfnm, self.GBSfnm), print_command=False) ln0 = self.write_nested_destroy(self.GBSfnm, self.FF.linedestroy_save) o = wopen(".lindep.dat") for line in open(self.DATfnm).readlines(): s = line.split("#")[0].split() if len(s) == 3 and s[0].lower() == 'basis' and s[1].lower() == 'file': print("basis file %s" % self.GBSfnm, file=o) else: print(line, end=' ', file=o) o.close() _exec("mv .lindep.dat %s" % self.DATfnm, print_command=False) _exec("psi4 %s" % self.DATfnm, print_command=False) LI = GBS_Reader() LI_lines = {} ## Read in the commented linindep.gbs file and ensure that these same lines are commented in the new .gbs file for line in open('linindep.gbs'): LI.feed(line,linindep=True) key = '.'.join([str(i) for i in (LI.element,LI.amom,LI.basis_number[LI.element],LI.contraction_number)]) if LI.isdata: if key in LI_lines: logger.info("Duplicate key found:\n") logger.info("%s\n" % key) logger.info(str(LI_lines[key])) logger.info(line) warn_press_key("In %s, the LI_lines dictionary should not contain repeated keys!" % __file__) LI_lines[key] = (line, LI.destroy) ## Now build a "Frankenstein" .gbs file composed of the original .gbs file but with data from the linindep.gbs file! FK = GBS_Reader() FK_lines = [] self.FF.linedestroy_this = [] self.FF.prmdestroy_this = [] for ln, line in enumerate(open(self.GBSfnm).readlines()): FK.feed(line) key = '.'.join([str(i) for i in (FK.element,FK.amom,FK.basis_number[FK.element],FK.contraction_number)]) if FK.isdata and key in LI_lines: if LI_lines[key][1]: logger.info("Destroying line %i (originally %i): " % (ln, ln0[ln])) logger.info(line) self.FF.linedestroy_this.append(ln) for p_destroy in [i for i, fld in enumerate(self.FF.pfields) if any([subfld[0] == self.GBSfnm and subfld[1] == ln0[ln] for subfld in fld])]: logger.info("Destroying parameter %i located at line %i (originally %i) with fields given by: %s" % (p_destroy, ln, ln0[ln], str(self.FF.pfields[p_destroy]))) self.FF.prmdestroy_this.append(p_destroy) FK_lines.append(LI_lines[key][0]) else: FK_lines.append(line) o = wopen('franken.gbs') for line in FK_lines: print(line, end=' ', file=o) o.close() _exec("cp %s.bak %s" % (self.GBSfnm, self.GBSfnm), print_command=False) if len(list(itertools.chain(*(self.FF.linedestroy_save + [self.FF.linedestroy_this])))) > 0: logger.info("All lines removed: " + self.FF.linedestroy_save + [self.FF.linedestroy_this] + '\n') logger.info("All prms removed: " + self.FF.prmdestroy_save + [self.FF.prmdestroy_this] + '\n') self.write_nested_destroy(self.GBSfnm, self.FF.linedestroy_save + [self.FF.linedestroy_this]) _exec("psi4", print_command=False, outfnm="psi4.stdout") if not in_fd(): for line in open('psi4.stdout').readlines(): if "MP2 Energy:" in line: self.MP2_Energy = float(line.split()[-1]) elif "DF Energy:" in line: self.DF_Energy = float(line.split()[-1]) Ans = np.array([[float(i) for i in line.split()] for line in open("objective.dat").readlines()]) os.unlink("objective.dat") return Ans
def parse_interactions(input_file): """ Parse through the interactions input file. @param[in] input_file The name of the input file. """ # Three dictionaries of return variables. Systems = OrderedDict() Interactions = OrderedDict() Globals = {} InterNum = 0 InterName = "I0" InterDict = {} SystemName = None SystemDict = {} logger.info("Reading interactions from file: %s\n" % input_file) section = "NONE" fobj = open(input_file).readlines() for ln, line in enumerate(fobj): # Anything after "#" is a comment line = line.split("#")[0].strip() s = line.split() # Skip over blank lines if len(s) == 0: continue key = s[0].lower() # If line starts with a $, this signifies that we're in a new section. if re.match('^\$',line): word = re.sub('^\$','',line).upper() if word == "END": # End of a section, time to reinitialize variables. if section == "GLOBAL": pass elif section == "SYSTEM": if SystemName is None: warn_press_key("You need to specify a name for the system on line %i" % ln) elif SystemName in Systems: warn_press_key("A system named %s already exists in Systems" % SystemName) Systems[SystemName] = SystemDict SystemName = None SystemDict = {} elif section == "INTERACTION": if InterName in InterDict: warn_press_key("A system named %s already exists in InterDict" % InterName) Interactions[InterName] = InterDict InterNum += 1 InterName = "I%i" % InterNum InterDict = {} else: warn_press_key("Encountered $end for unsupported section %s on line %i" % (word, ln)) section = "NONE" elif section == "NONE": section = word else: warn_press_key("Encountered section keyword %s when already in section %s" % (word, section)) elif section == "GLOBAL": if key in ['keyfile', 'energy_unit']: Globals[key] = s[1] elif key == 'optimize': if len(s) == 1 or s[1].lower() in ['y','yes','true']: logger.info("Optimizing ALL systems by default\n") Globals[key] = True else: Globals[key] = False else: warn_press_key("Encountered unsupported key %s in section %s on line %i" % (key, section, ln)) elif section == "SYSTEM": if key == 'name': SystemName = s[1] elif key == 'geometry': SystemDict[key] = s[1] elif key == 'rmsd_weight': SystemDict[key] = float(s[1]) elif key == 'select': SystemDict[key] = s[1] elif key == 'optimize': if len(s) == 1 or s[1].lower() in ['y','yes','true']: SystemDict[key] = True logger.info("Optimizing system %s\n" % SystemName) else: SystemDict[key] = False else: warn_press_key("Encountered unsupported key %s in section %s on line %i" % (key, section, ln)) elif section == "INTERACTION": if key == 'name': InterName = s[1] elif key == 'equation': InterDict[key] = ' '.join(s[1:]) elif key == 'energy': InterDict[key] = float(s[1]) elif key == 'weight': InterDict[key] = float(s[1]) else: warn_press_key("Encountered unsupported key %s in section %s on line %i" % (key, section, ln)) return Globals, Systems, Interactions
def prepare(self, pbc=False, **kwargs): """ Called by __init__ ; prepare the temp directory and figure out the topology. """ if hasattr(self, 'FF'): if not (os.path.exists(self.FF.amber_frcmod) and os.path.exists(self.FF.amber_mol2)): # If the parameter files don't already exist, create them for the purpose of # preparing the engine, but then delete them afterward. prmtmp = True self.FF.make(np.zeros(self.FF.np)) # Currently force field object only allows one mol2 and frcmod file although this can be lifted. self.mol2 = [self.FF.amber_mol2] self.frcmod = [self.FF.amber_frcmod] if 'mol2' in kwargs: logger.error( "FF object is provided, which overrides mol2 keyword argument" ) raise RuntimeError if 'frcmod' in kwargs: logger.error( "FF object is provided, which overrides frcmod keyword argument" ) raise RuntimeError else: prmtmp = False self.mol2 = listfiles(kwargs.get('mol2'), 'mol2', err=True) self.frcmod = listfiles(kwargs.get('frcmod'), 'frcmod', err=True) # Figure out the topology information. self.leap() o = self.callamber("rdparm %s.prmtop" % self.name, stdin="printAtoms\nprintBonds\nexit\n", persist=True, print_error=False) # Once we do this, we don't need the prmtop and inpcrd anymore os.unlink("%s.inpcrd" % self.name) os.unlink("%s.prmtop" % self.name) os.unlink("leap.log") mode = 'None' self.AtomLists = defaultdict(list) G = nx.Graph() for line in o: s = line.split() if 'Atom' in line: mode = 'Atom' elif 'Bond' in line: mode = 'Bond' elif 'RDPARM MENU' in line: continue elif 'EXITING' in line: break elif len(s) == 0: continue elif mode == 'Atom': # Based on parsing lines like these: """ 327: HA -0.01462 1.0 ( 23:HIP ) H1 E 328: CB -0.33212 12.0 ( 23:HIP ) CT 3 329: HB2 0.10773 1.0 ( 23:HIP ) HC E 330: HB3 0.10773 1.0 ( 23:HIP ) HC E 331: CG 0.18240 12.0 ( 23:HIP ) CC B """ # Based on variable width fields. atom_number = int(line.split(':')[0]) atom_name = line.split()[1] atom_charge = float(line.split()[2]) atom_mass = float(line.split()[3]) rnn = line.split('(')[1].split(')')[0].split(':') residue_number = int(rnn[0]) residue_name = rnn[1] atom_type = line.split(')')[1].split()[0] self.AtomLists['Name'].append(atom_name) self.AtomLists['Charge'].append(atom_charge) self.AtomLists['Mass'].append(atom_mass) self.AtomLists['ResidueNumber'].append(residue_number) self.AtomLists['ResidueName'].append(residue_name) # Not sure if this works G.add_node(atom_number) elif mode == 'Bond': a, b = (int(i) for i in (line.split('(')[1].split(')')[0].split(','))) G.add_edge(a, b) self.AtomMask = [a == 'A' for a in self.AtomLists['ParticleType']] # Use networkx to figure out a list of molecule numbers. # gs = nx.connected_component_subgraphs(G) # tmols = [gs[i] for i in np.argsort(np.array([min(g.nodes()) for g in gs]))] # mnodes = [m.nodes() for m in tmols] # self.AtomLists['MoleculeNumber'] = [[i+1 in m for m in mnodes].index(1) for i in range(self.mol.na)] ## Write out the trajectory coordinates to a .mdcrd file. # I also need to write the trajectory if 'boxes' in self.mol.Data.keys(): warn_press_key( "Writing %s-all.crd file with no periodic box information" % self.name) del self.mol.Data['boxes'] if hasattr(self, 'target') and hasattr(self.target, 'shots'): self.qmatoms = target.qmatoms self.mol.write("%s-all.crd" % self.name, select=range(self.target.shots), ftype="mdcrd") else: self.qmatoms = self.mol.na self.mol.write("%s-all.crd" % self.name, ftype="mdcrd") if prmtmp: for f in self.FF.fnms: os.unlink(f)
def main(): """ Run the script with -h for help Usage: python npt_tinker.py input.xyz [-k input.key] liquid_production_steps liquid_timestep liquid_interval temperature(K) pressure(atm) """ if not os.path.exists(args.liquid_xyzfile): warn_press_key("Warning: %s does not exist, script cannot continue" % args.liquid_xyzfile) # Set up some conversion factors # All units are in kJ/mol N = niterations # Conversion factor for kT derived from: # In [6]: 1.0 / ((1.0 * kelvin * BOLTZMANN_CONSTANT_kB * AVOGADRO_CONSTANT_NA) / kilojoule_per_mole) # Out[6]: 120.27221251395186 T = temperature mBeta = -120.27221251395186 / temperature Beta = 120.27221251395186 / temperature kT = 0.0083144724712202 * temperature # Conversion factor for pV derived from: # In [14]: 1.0 * atmosphere * nanometer ** 3 * AVOGADRO_CONSTANT_NA / kilojoule_per_mole # Out[14]: 0.061019351687175 pcon = 0.061019351687175 # Load the force field in from the ForceBalance pickle. FF,mvals,h,AGrad = lp_load(open('forcebalance.p')) # Create the force field XML files. FF.make(mvals) #=================================================================# # Get the number of molecules from the liquid xyz file. # #=================================================================# xin = "%s" % args.liquid_xyzfile + ("" if args.liquid_keyfile == None else " -k %s" % args.liquid_keyfile) cmdstr = "./analyze %s" % xin oanl = _exec(cmdstr,stdin="G",print_command=True,print_to_screen=True) molflag = False for line in oanl: if 'Number of Molecules' in line: if not molflag: NMol = int(line.split()[-1]) molflag = True else: raise Exception("TINKER output contained more than one line with the words 'Number of Molecules'") if molflag: print "Detected %i Molecules" % NMol if not molflag: raise Exception("Failed to detect the number of molecules") #=================================================================# # Run the simulation for the full system and analyze the results. # #=================================================================# Rhos, Potentials, Kinetics, Volumes, Dips = run_simulation(args.liquid_xyzfile,args.liquid_keyfile,tstep=timestep,nstep=nsteps,neq=nequiliterations,npr=niterations,verbose=True) Energies = Potentials + Kinetics V = Volumes pV = pressure * Volumes H = Energies + pV # Get the energy and dipole gradients. print "Post-processing the liquid simulation snapshots." G, GDx, GDy, GDz = energy_dipole_derivatives(mvals,h,FF,args.liquid_xyzfile,args.liquid_keyfile,AGrad) print #==============================================# # Now run the simulation for just the monomer. # #==============================================# _a, mPotentials, mKinetics, _b, _c = run_simulation(args.gas_xyzfile,args.gas_keyfile,tstep=m_timestep,nstep=m_nsteps,neq=m_nequiliterations,npr=m_niterations,pbc=False) mEnergies = mPotentials + mKinetics mN = len(mEnergies) print "Post-processing the gas simulation snapshots." mG = energy_derivatives(mvals,h,FF,args.gas_xyzfile,args.gas_keyfile,AGrad) print numboots = 1000 def bootstats(func,inputs): # Calculate error using bootstats method dboot = [] for i in range(numboots): newins = {k : v[np.random.randint(len(v),size=len(v))] for k,v in inputs.items()} dboot.append(np.mean(func(**newins))) return func(**inputs),np.std(np.array(dboot)) def calc_arr(b = None, **kwargs): # This tomfoolery is required because of Python syntax; # default arguments must come after nondefault arguments # and kwargs must come at the end. This function is used # in bootstrap error calcs and also in derivative calcs. if 'arr' in kwargs: arr = kwargs['arr'] if b == None: b = np.ones(len(arr),dtype=float) return bzavg(arr,b) # The density in kg/m^3. # Note: Not really necessary to use bootstrap here, but good to # demonstrate the principle. Rho_avg, Rho_err = bootstats(calc_arr,{'arr':Rhos}) Rho_err *= np.sqrt(statisticalInefficiency(Rhos)) print "The finite difference step size is:",h # The first density derivative GRho = mBeta * (flat(np.mat(G) * col(Rhos)) / N - np.mean(Rhos) * np.mean(G, axis=1)) FDCheck = False Sep = printcool("Density: % .4f +- % .4f kg/m^3, Analytic Derivative" % (Rho_avg, Rho_err)) FF.print_map(vals=GRho) print Sep if FDCheck: Sep = printcool("Numerical Derivative:") GRho1 = property_derivatives(mvals, h, FF, args.liquid_xyzfile, args.liquid_keyfile, kT, calc_arr, {'arr':Rhos}) FF.print_map(vals=GRho1) Sep = printcool("Difference (Absolute, Fractional):") absfrac = ["% .4e % .4e" % (i-j, (i-j)/j) for i,j in zip(GRho, GRho1)] FF.print_map(vals=absfrac) # The enthalpy of vaporization in kJ/mol. Ene_avg, Ene_err = bootstats(calc_arr,{'arr':Energies}) mEne_avg, mEne_err = bootstats(calc_arr,{'arr':mEnergies}) pV_avg, pV_err = bootstats(calc_arr,{'arr':pV}) Ene_err *= np.sqrt(statisticalInefficiency(Energies)) mEne_err *= np.sqrt(statisticalInefficiency(mEnergies)) pV_err *= np.sqrt(statisticalInefficiency(pV)) Hvap_avg = mEne_avg - Ene_avg / NMol + kT - np.mean(pV) / NMol Hvap_err = np.sqrt(Ene_err**2 / NMol**2 + mEne_err**2 + pV_err**2/NMol**2) # Build the first Hvap derivative. GHvap = np.mean(G,axis=1) GHvap += mBeta * (flat(np.mat(G) * col(Energies)) / N - Ene_avg * np.mean(G, axis=1)) GHvap /= NMol GHvap -= np.mean(mG,axis=1) GHvap -= mBeta * (flat(np.mat(mG) * col(mEnergies)) / N - mEne_avg * np.mean(mG, axis=1)) GHvap *= -1 GHvap -= mBeta * (flat(np.mat(G) * col(pV)) / N - np.mean(pV) * np.mean(G, axis=1)) / NMol print "Box total energy:", np.mean(Energies) print "Monomer total energy:", np.mean(mEnergies) Sep = printcool("Enthalpy of Vaporization: % .4f +- %.4f kJ/mol, Derivatives below" % (Hvap_avg, Hvap_err)) FF.print_map(vals=GHvap) print Sep # Define some things to make the analytic derivatives easier. Gbar = np.mean(G,axis=1) def covde(vec): return flat(np.mat(G)*col(vec))/N - Gbar*np.mean(vec) def avg(vec): return np.mean(vec) ## Thermal expansion coefficient and bootstrap error estimation def calc_alpha(b = None, **kwargs): if 'h_' in kwargs: h_ = kwargs['h_'] if 'v_' in kwargs: v_ = kwargs['v_'] if b == None: b = np.ones(len(v_),dtype=float) return 1/(kT*T) * (bzavg(h_*v_,b)-bzavg(h_,b)*bzavg(v_,b))/bzavg(v_,b) Alpha, Alpha_err = bootstats(calc_alpha,{'h_':H, 'v_':V}) Alpha_err *= np.sqrt(max(statisticalInefficiency(V),statisticalInefficiency(H))) ## Thermal expansion coefficient analytic derivative GAlpha1 = mBeta * covde(H*V) / avg(V) GAlpha2 = Beta * avg(H*V) * covde(V) / avg(V)**2 GAlpha3 = flat(np.mat(G)*col(V))/N/avg(V) - Gbar GAlpha4 = Beta * covde(H) GAlpha = (GAlpha1 + GAlpha2 + GAlpha3 + GAlpha4)/(kT*T) Sep = printcool("Thermal expansion coefficient: % .4e +- %.4e K^-1\nAnalytic Derivative:" % (Alpha, Alpha_err)) FF.print_map(vals=GAlpha) if FDCheck: GAlpha_fd = property_derivatives(mvals, h, FF, args.liquid_xyzfile, args.liquid_keyfile, kT, calc_alpha, {'h_':H,'v_':V}) Sep = printcool("Numerical Derivative:") FF.print_map(vals=GAlpha_fd) Sep = printcool("Difference (Absolute, Fractional):") absfrac = ["% .4e % .4e" % (i-j, (i-j)/j) for i,j in zip(GAlpha, GAlpha_fd)] FF.print_map(vals=absfrac) ## Isothermal compressibility # In [15]: 1.0*bar*nanometer**3/kilojoules_per_mole/item # Out[15]: 0.06022141792999999 bar_unit = 0.06022141793 def calc_kappa(b=None, **kwargs): if 'v_' in kwargs: v_ = kwargs['v_'] if b == None: b = np.ones(len(v_),dtype=float) return bar_unit / kT * (bzavg(v_**2,b)-bzavg(v_,b)**2)/bzavg(v_,b) Kappa, Kappa_err = bootstats(calc_kappa,{'v_':V}) Kappa_err *= np.sqrt(statisticalInefficiency(V)) ## Isothermal compressibility analytic derivative Sep = printcool("Isothermal compressibility: % .4e +- %.4e bar^-1\nAnalytic Derivative:" % (Kappa, Kappa_err)) GKappa1 = -1 * Beta**2 * avg(V) * covde(V**2) / avg(V)**2 GKappa2 = +1 * Beta**2 * avg(V**2) * covde(V) / avg(V)**2 GKappa3 = +1 * Beta**2 * covde(V) GKappa = bar_unit*(GKappa1 + GKappa2 + GKappa3) FF.print_map(vals=GKappa) if FDCheck: GKappa_fd = property_derivatives(mvals, h, FF, args.liquid_xyzfile, args.liquid_keyfile, kT, calc_kappa, {'v_':V}) Sep = printcool("Numerical Derivative:") FF.print_map(vals=GKappa_fd) Sep = printcool("Difference (Absolute, Fractional):") absfrac = ["% .4e % .4e" % (i-j, (i-j)/j) for i,j in zip(GKappa, GKappa_fd)] FF.print_map(vals=absfrac) ## Isobaric heat capacity def calc_cp(b=None, **kwargs): if 'h_' in kwargs: h_ = kwargs['h_'] if b == None: b = np.ones(len(h_),dtype=float) Cp_ = 1/(NMol*kT*T) * (bzavg(h_**2,b) - bzavg(h_,b)**2) Cp_ *= 1000 / 4.184 return Cp_ Cp, Cp_err = bootstats(calc_cp, {'h_':H}) Cp_err *= np.sqrt(statisticalInefficiency(H)) ## Isobaric heat capacity analytic derivative GCp1 = 2*covde(H) * 1000 / 4.184 / (NMol*kT*T) GCp2 = mBeta*covde(H**2) * 1000 / 4.184 / (NMol*kT*T) GCp3 = 2*Beta*avg(H)*covde(H) * 1000 / 4.184 / (NMol*kT*T) GCp = GCp1 + GCp2 + GCp3 Sep = printcool("Isobaric heat capacity: % .4e +- %.4e cal mol-1 K-1\nAnalytic Derivative:" % (Cp, Cp_err)) FF.print_map(vals=GCp) if FDCheck: GCp_fd = property_derivatives(mvals, h, FF, args.liquid_xyzfile, args.liquid_keyfile, kT, calc_cp, {'h_':H}) Sep = printcool("Numerical Derivative:") FF.print_map(vals=GCp_fd) Sep = printcool("Difference (Absolute, Fractional):") absfrac = ["% .4e % .4e" % (i-j, (i-j)/j) for i,j in zip(GCp,GCp_fd)] FF.print_map(vals=absfrac) ## Dielectric constant # eps0 = 8.854187817620e-12 * coulomb**2 / newton / meter**2 # epsunit = 1.0*(debye**2) / nanometer**3 / BOLTZMANN_CONSTANT_kB / kelvin # prefactor = epsunit/eps0/3 prefactor = 30.348705333964077 def calc_eps0(b=None, **kwargs): if 'd_' in kwargs: # Dipole moment vector. d_ = kwargs['d_'] if 'v_' in kwargs: # Volume. v_ = kwargs['v_'] if b == None: b = np.ones(len(v_),dtype=float) dx = d_[:,0] dy = d_[:,1] dz = d_[:,2] D2 = bzavg(dx**2,b)-bzavg(dx,b)**2 D2 += bzavg(dy**2,b)-bzavg(dy,b)**2 D2 += bzavg(dz**2,b)-bzavg(dz,b)**2 return prefactor*D2/bzavg(v_,b)/T Eps0, Eps0_err = bootstats(calc_eps0,{'d_':Dips, 'v_':V}) Eps0 += 1.0 Eps0_err *= np.sqrt(np.mean([statisticalInefficiency(Dips[:,0]),statisticalInefficiency(Dips[:,1]),statisticalInefficiency(Dips[:,2])])) ## Dielectric constant analytic derivative Dx = Dips[:,0] Dy = Dips[:,1] Dz = Dips[:,2] D2 = avg(Dx**2)+avg(Dy**2)+avg(Dz**2)-avg(Dx)**2-avg(Dy)**2-avg(Dz)**2 GD2 = 2*(flat(np.mat(GDx)*col(Dx))/N - avg(Dx)*(np.mean(GDx,axis=1))) - Beta*(covde(Dx**2) - 2*avg(Dx)*covde(Dx)) GD2 += 2*(flat(np.mat(GDy)*col(Dy))/N - avg(Dy)*(np.mean(GDy,axis=1))) - Beta*(covde(Dy**2) - 2*avg(Dy)*covde(Dy)) GD2 += 2*(flat(np.mat(GDz)*col(Dz))/N - avg(Dz)*(np.mean(GDz,axis=1))) - Beta*(covde(Dz**2) - 2*avg(Dz)*covde(Dz)) GEps0 = prefactor*(GD2/avg(V) - mBeta*covde(V)*D2/avg(V)**2)/T Sep = printcool("Dielectric constant: % .4e +- %.4e\nAnalytic Derivative:" % (Eps0, Eps0_err)) FF.print_map(vals=GEps0) if FDCheck: GEps0_fd = property_derivatives(mvals, h, FF, args.liquid_xyzfile, args.liquid_keyfile, kT, calc_eps0, {'d_':Dips,'v_':V}) Sep = printcool("Numerical Derivative:") FF.print_map(vals=GEps0_fd) Sep = printcool("Difference (Absolute, Fractional):") absfrac = ["% .4e % .4e" % (i-j, (i-j)/j) for i,j in zip(GEps0,GEps0_fd)] FF.print_map(vals=absfrac) ## Print the final force field. pvals = FF.make(mvals) with open(os.path.join('npt_result.p'),'w') as f: lp_dump((Rhos, Volumes, Potentials, Energies, Dips, G, [GDx, GDy, GDz], mPotentials, mEnergies, mG, Rho_err, Hvap_err, Alpha_err, Kappa_err, Cp_err, Eps0_err, NMol),f)
def step(self, xk, data, trust): """ Computes the next step in the parameter space. There are lots of tricks here that I will document later. @param[in] G The gradient @param[in] H The Hessian @param[in] trust The trust radius """ from scipy import optimize X, G, H = (data['X0'], data['G0'], data['H0']) if self.bhyp else (data['X'], data['G'], data['H']) H1 = H.copy() H1 = np.delete(H1, self.excision, axis=0) H1 = np.delete(H1, self.excision, axis=1) Eig = eig(H1)[0] # Diagonalize Hessian Emin = min(Eig) if Emin < self.eps: # Mix in SD step if Hessian minimum eigenvalue is negative # Experiment. Adj = max(self.eps, 0.01*abs(Emin)) - Emin logger.info("Hessian has a small or negative eigenvalue (%.1e), mixing in some steepest descent (%.1e) to correct this.\n" % (Emin, Adj)) logger.info("Eigenvalues are:\n") ### pvec1d(Eig) ### H += Adj*np.eye(H.shape[0]) if self.bhyp: G = np.delete(G, self.excision) H = np.delete(H, self.excision, axis=0) H = np.delete(H, self.excision, axis=1) xkd = np.delete(xk, self.excision) if self.Objective.Penalty.fmul != 0.0: warn_press_key("Using the multiplicative hyperbolic penalty is discouraged!") # This is the gradient and Hessian without the contributions from the hyperbolic constraint. Obj0 = {'X':X,'G':G,'H':H} class Hyper(object): def __init__(self, HL, Penalty): self.H = HL.copy() self.dx = 1e10 * np.ones(len(HL),dtype=float) self.Val = 0 self.Grad = np.zeros(len(HL),dtype=float) self.Hess = np.zeros((len(HL),len(HL)),dtype=float) self.Penalty = Penalty def _compute(self, dx): self.dx = dx.copy() Tmp = np.mat(self.H)*col(dx) Reg_Term = self.Penalty.compute(xkd+flat(dx), Obj0) self.Val = (X + np.dot(dx, G) + 0.5*row(dx)*Tmp + Reg_Term[0] - data['X'])[0,0] self.Grad = flat(col(G) + Tmp) + Reg_Term[1] def compute_val(self, dx): if norm(dx - self.dx) > 1e-8: self._compute(dx) return self.Val def compute_grad(self, dx): if norm(dx - self.dx) > 1e-8: self._compute(dx) return self.Grad def compute_hess(self, dx): if norm(dx - self.dx) > 1e-8: self._compute(dx) return self.Hess def hyper_solver(L): dx0 = np.zeros(len(xkd),dtype=float) #dx0 = np.delete(dx0, self.excision) # HL = H + (L-1)**2*np.diag(np.diag(H)) # Attempt to use plain Levenberg HL = H + (L-1)**2*np.eye(len(H)) HYP = Hyper(HL, self.Objective.Penalty) try: Opt1 = optimize.fmin_bfgs(HYP.compute_val,dx0,fprime=HYP.compute_grad,gtol=1e-5,full_output=True,disp=0) except: Opt1 = optimize.fmin(HYP.compute_val,dx0,full_output=True,disp=0) try: Opt2 = optimize.fmin_bfgs(HYP.compute_val,-xkd,fprime=HYP.compute_grad,gtol=1e-5,full_output=True,disp=0) except: Opt2 = optimize.fmin(HYP.compute_val,-xkd,full_output=True,disp=0) #Opt2 = optimize.fmin(HYP.compute_val,-xkd,full_output=True,disp=0) dx1, sol1 = Opt1[0], Opt1[1] dx2, sol2 = Opt2[0], Opt2[1] dxb, sol = (dx1, sol1) if sol1 <= sol2 else (dx2, sol2) for i in self.excision: # Reinsert deleted coordinates - don't take a step in those directions dxb = np.insert(dxb, i, 0) return dxb, sol else: # G0 and H0 are used for determining the expected function change. G0 = G.copy() H0 = H.copy() G = np.delete(G, self.excision) H = np.delete(H, self.excision, axis=0) H = np.delete(H, self.excision, axis=1) logger.debug("Inverting Hessian:\n") ### logger.debug(" G:\n") ### pvec1d(G,precision=5, loglevel=DEBUG) ### logger.debug(" H:\n") ### pmat2d(H,precision=5, loglevel=DEBUG) ### Hi = invert_svd(np.mat(H)) dx = flat(-1 * Hi * col(G)) logger.debug(" dx:\n") ### pvec1d(dx,precision=5, loglevel=DEBUG) ### # dxa = -solve(H, G) # Take Newton Raphson Step ; use -1*G if want steepest descent. # dxa = flat(dxa) # print " dxa:" ### # pvec1d(dxa,precision=5) ### logger.info('\n') ### for i in self.excision: # Reinsert deleted coordinates - don't take a step in those directions dx = np.insert(dx, i, 0) def para_solver(L): # Levenberg-Marquardt # HT = H + (L-1)**2*np.diag(np.diag(H)) # Attempt to use plain Levenberg HT = H + (L-1)**2*np.eye(len(H)) logger.debug("Inverting Scaled Hessian:\n") ### logger.debug(" G:\n") ### pvec1d(G,precision=5, loglevel=DEBUG) ### logger.debug(" HT: (Scal = %.4f)\n" % (1+(L-1)**2)) ### pmat2d(HT,precision=5, loglevel=DEBUG) ### Hi = invert_svd(np.mat(HT)) dx = flat(-1 * Hi * col(G)) logger.debug(" dx:\n") ### pvec1d(dx,precision=5, loglevel=DEBUG) ### # dxa = -solve(HT, G) # dxa = flat(dxa) # print " dxa:" ### # pvec1d(dxa,precision=5) ### # print ### sol = flat(0.5*row(dx)*np.mat(H)*col(dx))[0] + np.dot(dx,G) for i in self.excision: # Reinsert deleted coordinates - don't take a step in those directions dx = np.insert(dx, i, 0) return dx, sol def solver(L): return hyper_solver(L) if self.bhyp else para_solver(L) def trust_fun(L): N = norm(solver(L)[0]) logger.debug("\rL = %.4e, Hessian diagonal addition = %.4e: found length %.4e, objective is %.4e\n" % (L, (L-1)**2, N, (N - trust)**2)) return (N - trust)**2 def search_fun(L): # Evaluate ONLY the objective function. Most useful when # the objective is cheap, but the derivative is expensive. dx, sol = solver(L) # dx is how much the step changes from the previous step. # This is our trial step. xk_ = dx + xk Result = self.Objective.Full(xk_,0,verbose=False)['X'] - data['X'] logger.info("Searching! Hessian diagonal addition = %.4e, L = % .4e, length %.4e, result %.4e\n" % ((L-1)**2,L,norm(dx),Result)) return Result if self.trust0 > 0: # This is the trust region code. bump = False dx, expect = solver(1) dxnorm = norm(dx) if dxnorm > trust: bump = True # Tried a few optimizers here, seems like Brent works well. # Okay, the problem with Brent is that the tolerance is fractional. # If the optimized value is zero, then it takes a lot of meaningless steps. LOpt = optimize.brent(trust_fun,brack=(self.lmg,self.lmg*4),tol=1e-6) ### Result = optimize.fmin_powell(trust_fun,3,xtol=self.search_tol,ftol=self.search_tol,full_output=1,disp=0) ### LOpt = Result[0] dx, expect = solver(LOpt) dxnorm = norm(dx) logger.info("\rLevenberg-Marquardt: %s step found (length %.3e), % .8f added to Hessian diagonal\n" % ('hyperbolic-regularized' if self.bhyp else 'Newton-Raphson', dxnorm, (LOpt-1)**2)) else: # This is the nonlinear search code. # First obtain a step that is the same length as the provided trust radius. LOpt = optimize.brent(trust_fun,brack=(self.lmg,self.lmg*4),tol=1e-6) bump = False Result = optimize.brent(search_fun,brack=(LOpt,LOpt*4),tol=self.search_tol,full_output=1) ### optimize.fmin(search_fun,0,xtol=1e-8,ftol=data['X']*0.1,full_output=1,disp=0) ### Result = optimize.fmin_powell(search_fun,3,xtol=self.search_tol,ftol=self.search_tol,full_output=1,disp=0) dx, _ = solver(Result[0]) expect = Result[1] ## Decide which parameters to redirect. ## Currently not used. if self.Objective.Penalty.ptyp in [3,4,5]: self.FF.make_redirect(dx+xk) return dx, expect, bump
def MainOptimizer(self,b_BFGS=0): """ The main ForceBalance adaptive trust-radius pseudo-Newton optimizer. Tried and true in many situations. :) Usually this function is called with the BFGS or NewtonRaphson method. The NewtonRaphson method is consistently the best method I have, because I always provide at least an approximate Hessian to the objective function. The BFGS method is vestigial and currently does not work. BFGS is a pseudo-Newton method in the sense that it builds an approximate Hessian matrix from the gradient information in previous steps; Newton-Raphson requires the actual Hessian matrix. However, the algorithms are similar in that they both compute the step by inverting the Hessian and multiplying by the gradient. The method adaptively changes the step size. If the step is sufficiently good (i.e. the objective function goes down by a large fraction of the predicted decrease), then the step size is increased; if the step is bad, then it rejects the step and tries again. The optimization is terminated after either a function value or step size tolerance is reached. @param[in] b_BFGS Switch to use BFGS (True) or Newton-Raphson (False) """ if any(['liquid' in tgt.name.lower() for tgt in self.Objective.Targets]) and self.conv_obj < 1e-3: warn_press_key("Condensed phase targets detected - may not converge with current choice of convergence_objective (%.e)\nRecommended range is 1e-2 - 1e-1 for this option." % self.conv_obj) # Parameters for the adaptive trust radius a = self.adapt_fac # Default value is 0.5, decrease to make more conservative. Zero to turn off all adaptive. b = self.adapt_damp # Default value is 0.5, increase to make more conservative printcool( "Main Optimizer\n%s Mode%s" % ("BFGS" if b_BFGS else "Newton-Raphson", " (Static Radius)" if a == 0.0 else " (Adaptive Radius)"), ansi=1, bold=1) # First, set a bunch of starting values Ord = 1 if b_BFGS else 2 #Ord = 2 global ITERATION_NUMBER ITERATION_NUMBER = 0 global GOODSTEP Best_Step = 1 if all(i in self.chk for i in ['xk','X','G','H','ehist','x_best','xk_prev','trust']): logger.info("Reading initial objective, gradient, Hessian from checkpoint file\n") xk, X, G, H, ehist = self.chk['xk'], self.chk['X'], self.chk['G'], self.chk['H'], self.chk['ehist'] X_best, xk_prev, trust = self.chk['x_best'], self.chk['xk_prev'], self.chk['trust'] else: xk = self.mvals0.copy() logger.info('\n') data = self.Objective.Full(xk,Ord,verbose=True) X, G, H = data['X'], data['G'], data['H'] ehist = np.array([X]) xk_prev = xk.copy() trust = abs(self.trust0) X_best = X X_prev = X G_prev = G.copy() H_stor = H.copy() ndx = 0.0 color = "\x1b[1m" nxk = norm(xk) ngr = norm(G) Quality = 0.0 restep = False GOODSTEP = 1 Ord = 1 if b_BFGS else 2 while 1: # Loop until convergence is reached. ## Put data into the checkpoint file self.chk = {'xk': xk, 'X' : X, 'G' : G, 'H': H, 'ehist': ehist, 'x_best': X_best,'xk_prev': xk_prev, 'trust': trust} if self.wchk_step: self.writechk() stdfront = len(ehist) > self.hist and np.std(np.sort(ehist)[:self.hist]) or (len(ehist) > 0 and np.std(ehist) or 0.0) stdfront *= 2 logger.info("%6s%12s%12s%12s%14s%12s%12s\n" % ("Step", " |k| "," |dk| "," |grad| "," -=X2=- ","Delta(X2)", "StepQual")) logger.info("%6i%12.3e%12.3e%12.3e%s%14.5e\x1b[0m%12.3e% 11.3f\n\n" % (ITERATION_NUMBER, nxk, ndx, ngr, color, X, stdfront, Quality)) # Check the convergence criteria if ngr < self.conv_grd: logger.info("Convergence criterion reached for gradient norm (%.2e)\n" % self.conv_grd) break if ITERATION_NUMBER == self.maxstep: logger.info("Maximum number of optimization steps reached (%i)\n" % ITERATION_NUMBER) break if ndx < self.conv_stp and ITERATION_NUMBER > 0 and not restep: logger.info("Convergence criterion reached in step size (%.2e)\n" % self.conv_stp) break if stdfront < self.conv_obj and len(ehist) > self.hist and not restep: # Factor of two is so [0,1] stdev is normalized to 1 logger.info("Convergence criterion reached for objective function (%.2e)\n" % self.conv_obj) break if self.print_grad: bar = printcool("Total Gradient",color=4) self.FF.print_map(vals=G,precision=8) logger.info(bar) if self.print_hess: bar = printcool("Total Hessian",color=4) pmat2d(H,precision=8) logger.info(bar) for key, val in self.Objective.ObjDict.items(): if Best_Step: self.Objective.ObjDict_Last[key] = val restep = False dx, dX_expect, bump = self.step(xk, data, trust) old_pk = self.FF.create_pvals(xk) old_xk = xk.copy() # Increment the iteration counter. ITERATION_NUMBER += 1 # Take a step in the parameter space. xk += dx if self.print_vals: pk = self.FF.create_pvals(xk) dp = pk - old_pk bar = printcool("Mathematical Parameters (Current + Step = Next)",color=5) self.FF.print_map(vals=["% .4e %s %.4e = % .4e" % (old_xk[i], '+' if dx[i] >= 0 else '-', abs(dx[i]), xk[i]) for i in range(len(xk))]) logger.info(bar) bar = printcool("Physical Parameters (Current + Step = Next)",color=5) self.FF.print_map(vals=["% .4e %s %.4e = % .4e" % (old_pk[i], '+' if dp[i] >= 0 else '-', abs(dp[i]), pk[i]) for i in range(len(pk))]) logger.info(bar) # Evaluate the objective function and its derivatives. data = self.Objective.Full(xk,Ord,verbose=True) X, G, H = data['X'], data['G'], data['H'] ndx = norm(dx) nxk = norm(xk) ngr = norm(G) drc = abs(flat(dx)).argmax() dX_actual = X - X_prev try: Quality = dX_actual / dX_expect except: logger.warning("Warning: Step size of zero detected (i.e. wrong direction). Try reducing the finite_difference_h parameter\n") Quality = 1.0 # This is a step length of zero. if Quality <= 0.25 and X < (X_prev + self.err_tol) and self.trust0 > 0: # If the step quality is bad, then we should decrease the trust radius. trust = max(ndx*(1./(1+a)), self.mintrust) logger.info("Low quality step, reducing trust radius to % .4e\n" % trust) if Quality >= 0.75 and bump and self.trust0 > 0: # If the step quality is good, then we should increase the trust radius. # The 'a' factor is how much we should grow or shrink the trust radius each step # and the 'b' factor determines how closely we are tied down to the original value. # Recommend values 0.5 and 0.5 trust += a*trust*np.exp(-b*(trust/self.trust0 - 1)) if X > (X_prev + self.err_tol): Best_Step = 0 # Toggle switch for rejection (experimenting with no rejection) Rejects = True GOODSTEP = 0 Reevaluate = True trust = max(ndx*(1./(1+a)), self.mintrust) logger.info("Rejecting step and reducing trust radius to % .4e\n" % trust) if Rejects: xk = xk_prev.copy() if Reevaluate: restep = True color = "\x1b[91m" logger.info("%6s%12s%12s%12s%14s%12s%12s\n" % ("Step", " |k| "," |dk| "," |grad| "," -=X2=- ","Delta(X2)", "StepQual")) logger.info("%6i%12.3e%12.3e%12.3e%s%14.5e\x1b[0m%12.3e% 11.3f\n\n" % (ITERATION_NUMBER, nxk, ndx, ngr, color, X, stdfront, Quality)) printcool("Objective function rises!\nRe-evaluating at the previous point..",color=1) ITERATION_NUMBER += 1 data = self.Objective.Full(xk,Ord,verbose=True) GOODSTEP = 1 X, G, H = data['X'], data['G'], data['H'] X_prev = X dx *= 0 ndx = norm(dx) nxk = norm(xk) ngr = norm(G) Quality = 0.0 color = "\x1b[0m" else: color = "\x1b[91m" G = G_prev.copy() H = H_stor.copy() data = deepcopy(datastor) continue else: GOODSTEP = 1 if X > X_best: Best_Step = 0 color = "\x1b[95m" else: Best_Step = 1 color = "\x1b[92m" X_best = X ehist = np.append(ehist, X) # Hessian update for BFGS. if b_BFGS: Hnew = H_stor.copy() Dx = col(xk - xk_prev) Dy = col(G - G_prev) Mat1 = (Dy*Dy.T)/(Dy.T*Dx)[0,0] Mat2 = ((Hnew*Dx)*(Hnew*Dx).T)/(Dx.T*Hnew*Dx)[0,0] Hnew += Mat1-Mat2 H = Hnew.copy() data['H'] = H.copy() datastor= deepcopy(data) G_prev = G.copy() H_stor = H.copy() xk_prev = xk.copy() X_prev = X if len(self.FF.parmdestroy_this) > 0: self.FF.parmdestroy_save.append(self.FF.parmdestroy_this) self.FF.linedestroy_save.append(self.FF.linedestroy_this) bar = printcool("Final objective function value\nFull: % .6e Un-penalized: % .6e" % (data['X'],data['X0']), '@', bold=True, color=2) return xk
def driver(self): ## Actually run PSI4. if not in_fd() and CheckBasis(): logger.info("Now checking for linear dependencies.\n") _exec("cp %s %s.bak" % (self.GBSfnm, self.GBSfnm), print_command=False) ln0 = self.write_nested_destroy(self.GBSfnm, self.FF.linedestroy_save) o = wopen(".lindep.dat") for line in open(self.DATfnm).readlines(): s = line.split("#")[0].split() if len(s) == 3 and s[0].lower() == 'basis' and s[1].lower( ) == 'file': print("basis file %s" % self.GBSfnm, file=o) else: print(line, end=' ', file=o) o.close() _exec("mv .lindep.dat %s" % self.DATfnm, print_command=False) _exec("psi4 %s" % self.DATfnm, print_command=False) LI = GBS_Reader() LI_lines = {} ## Read in the commented linindep.gbs file and ensure that these same lines are commented in the new .gbs file for line in open('linindep.gbs'): LI.feed(line, linindep=True) key = '.'.join([ str(i) for i in (LI.element, LI.amom, LI.basis_number[LI.element], LI.contraction_number) ]) if LI.isdata: if key in LI_lines: logger.info("Duplicate key found:\n") logger.info("%s\n" % key) logger.info(str(LI_lines[key])) logger.info(line) warn_press_key( "In %s, the LI_lines dictionary should not contain repeated keys!" % __file__) LI_lines[key] = (line, LI.destroy) ## Now build a "Frankenstein" .gbs file composed of the original .gbs file but with data from the linindep.gbs file! FK = GBS_Reader() FK_lines = [] self.FF.linedestroy_this = [] self.FF.prmdestroy_this = [] for ln, line in enumerate(open(self.GBSfnm).readlines()): FK.feed(line) key = '.'.join([ str(i) for i in (FK.element, FK.amom, FK.basis_number[FK.element], FK.contraction_number) ]) if FK.isdata and key in LI_lines: if LI_lines[key][1]: logger.info("Destroying line %i (originally %i): " % (ln, ln0[ln])) logger.info(line) self.FF.linedestroy_this.append(ln) for p_destroy in [ i for i, fld in enumerate(self.FF.pfields) if any([ subfld[0] == self.GBSfnm and subfld[1] == ln0[ln] for subfld in fld ]) ]: logger.info( "Destroying parameter %i located at line %i (originally %i) with fields given by: %s" % (p_destroy, ln, ln0[ln], str(self.FF.pfields[p_destroy]))) self.FF.prmdestroy_this.append(p_destroy) FK_lines.append(LI_lines[key][0]) else: FK_lines.append(line) o = wopen('franken.gbs') for line in FK_lines: print(line, end=' ', file=o) o.close() _exec("cp %s.bak %s" % (self.GBSfnm, self.GBSfnm), print_command=False) if len( list( itertools.chain(*(self.FF.linedestroy_save + [self.FF.linedestroy_this])))) > 0: logger.info("All lines removed: " + self.FF.linedestroy_save + [self.FF.linedestroy_this] + '\n') logger.info("All prms removed: " + self.FF.prmdestroy_save + [self.FF.prmdestroy_this] + '\n') self.write_nested_destroy( self.GBSfnm, self.FF.linedestroy_save + [self.FF.linedestroy_this]) _exec("psi4", print_command=False, outfnm="psi4.stdout") if not in_fd(): for line in open('psi4.stdout').readlines(): if "MP2 Energy:" in line: self.MP2_Energy = float(line.split()[-1]) elif "DF Energy:" in line: self.DF_Energy = float(line.split()[-1]) Ans = np.array([[float(i) for i in line.split()] for line in open("objective.dat").readlines()]) os.unlink("objective.dat") return Ans
def write_leap(fnm, mol2=[], frcmod=[], pdb=None, prefix='amber', spath=[], delcheck=False): """ Parse and edit an AMBER LEaP input file. Output file is written to inputfile_ (with trailing underscore.) """ have_fmod = [] have_mol2 = [] # The lines that will be printed out to actually run tleap line_out = [] aload = ['loadamberparams', 'source', 'loadoff'] aload_eq = ['loadmol2'] spath.append('.') for line in open(fnm): # Skip comment lines if line.strip().startswith('#'): continue line = line.split('#')[0] s = line.split() ll = line.lower() ls = line.lower().split() # Check to see if all files being loaded are in the search path if '=' in line: if ll.split('=')[1].split()[0] in aload_eq: if not any( [os.path.exists(os.path.join(d, s[-1])) for d in spath]): logger.error("The file in this line cannot be loaded : " + line.strip()) raise RuntimeError elif len(ls) > 0 and ls[0] in aload: if not any([os.path.exists(os.path.join(d, s[-1])) for d in spath]): logger.error("The file in this line cannot be loaded : " + line.strip()) raise RuntimeError if len(s) >= 2 and ls[0] == 'loadamberparams': have_fmod.append(s[1]) if len(s) >= 2 and 'loadmol2' in ll: have_mol2.append(s[-1]) if len(s) >= 2 and 'loadpdb' in ll: # Adopt the AMBER molecule name from the loadpdb line. ambername = line.split('=')[0].strip() # If we pass in our own PDB, then this line is replaced. if pdb != None: line = '%s = loadpdb %s\n' % (ambername, pdb) if len(s) >= 1 and ls[0] == 'check' and delcheck: # Skip over check steps if so decreed line = "# " + line if 'saveamberparm' in ll: # We'll write the saveamberparm line ourselves continue if len(s) >= 1 and ls[0] == 'quit': # Don't write the quit line. break if not line.endswith('\n'): line += '\n' line_out.append(line) # Sanity checks: If frcmod and mol2 files are provided to this function, # they should be in the leap.cmd file as well. There should be exactly # one PDB file being loaded. for i in frcmod: if i not in have_fmod: warn_press_key("WARNING: %s is not being loaded in %s" % (i, fnm)) for i in mol2: if i not in have_mol2: warn_press_key("WARNING: %s is not being loaded in %s" % (i, fnm)) fout = fnm + '_' line_out.append('saveamberparm %s %s.prmtop %s.inpcrd\n' % (ambername, prefix, prefix)) line_out.append('quit\n') with wopen(fout) as f: print >> f, ''.join(line_out)
def write_leap(fnm, mol2=[], frcmod=[], pdb=None, prefix='amber', spath = [], delcheck=False): """ Parse and edit an AMBER LEaP input file. Output file is written to inputfile_ (with trailing underscore.) """ have_fmod = [] have_mol2 = [] # The lines that will be printed out to actually run tleap line_out = [] aload = ['loadamberparams', 'source', 'loadoff'] aload_eq = ['loadmol2'] spath.append('.') for line in open(fnm): # Skip comment lines if line.strip().startswith('#') : continue line = line.split('#')[0] s = line.split() ll = line.lower() ls = line.lower().split() # Check to see if all files being loaded are in the search path if '=' in line: if ll.split('=')[1].split()[0] in aload_eq: if not any([os.path.exists(os.path.join(d, s[-1])) for d in spath]): logger.error("The file in this line cannot be loaded : " + line.strip()) raise RuntimeError elif len(ls) > 0 and ls[0] in aload: if not any([os.path.exists(os.path.join(d, s[-1])) for d in spath]): logger.error("The file in this line cannot be loaded : " + line.strip()) raise RuntimeError if len(s) >= 2 and ls[0] == 'loadamberparams': have_fmod.append(s[1]) if len(s) >= 2 and 'loadmol2' in ll: have_mol2.append(s[-1]) if len(s) >= 2 and 'loadpdb' in ll: # Adopt the AMBER molecule name from the loadpdb line. ambername = line.split('=')[0].strip() # If we pass in our own PDB, then this line is replaced. if pdb != None: line = '%s = loadpdb %s\n' % (ambername, pdb) if len(s) >= 1 and ls[0] == 'check' and delcheck: # Skip over check steps if so decreed line = "# " + line if 'saveamberparm' in ll: # We'll write the saveamberparm line ourselves continue if len(s) >= 1 and ls[0] == 'quit': # Don't write the quit line. break if not line.endswith('\n') : line += '\n' line_out.append(line) # Sanity checks: If frcmod and mol2 files are provided to this function, # they should be in the leap.cmd file as well. There should be exactly # one PDB file being loaded. for i in frcmod: if i not in have_fmod: warn_press_key("WARNING: %s is not being loaded in %s" % (i, fnm)) for i in mol2: if i not in have_mol2: warn_press_key("WARNING: %s is not being loaded in %s" % (i, fnm)) fout = fnm+'_' line_out.append('saveamberparm %s %s.prmtop %s.inpcrd\n' % (ambername, prefix, prefix)) line_out.append('quit\n') with wopen(fout) as f: print >> f, ''.join(line_out)
def parse_interactions(input_file): """ Parse through the interactions input file. @param[in] input_file The name of the input file. """ # Three dictionaries of return variables. Systems = OrderedDict() Interactions = OrderedDict() Globals = {} InterNum = 0 InterName = "I0" InterDict = {} SystemName = None SystemDict = {} logger.info("Reading interactions from file: %s\n" % input_file) section = "NONE" fobj = open(input_file).readlines() for ln, line in enumerate(fobj): # Anything after "#" is a comment line = line.split("#")[0].strip() s = line.split() # Skip over blank lines if len(s) == 0: continue key = s[0].lower() # If line starts with a $, this signifies that we're in a new section. if re.match('^\$',line): word = re.sub('^\$','',line).upper() if word == "END": # End of a section, time to reinitialize variables. if section == "GLOBAL": pass elif section == "SYSTEM": if SystemName == None: warn_press_key("You need to specify a name for the system on line %i" % ln) elif SystemName in Systems: warn_press_key("A system named %s already exists in Systems" % SystemName) Systems[SystemName] = SystemDict SystemName = None SystemDict = {} elif section == "INTERACTION": if InterName in InterDict: warn_press_key("A system named %s already exists in InterDict" % InterName) Interactions[InterName] = InterDict InterNum += 1 InterName = "I%i" % InterNum InterDict = {} else: warn_press_key("Encountered $end for unsupported section %s on line %i" % (word, ln)) section = "NONE" elif section == "NONE": section = word else: warn_press_key("Encountered section keyword %s when already in section %s" % (word, section)) elif section == "GLOBAL": if key in ['keyfile', 'energy_unit']: Globals[key] = s[1] elif key == 'optimize': if len(s) == 1 or s[1].lower() in ['y','yes','true']: logger.info("Optimizing ALL systems by default\n") Globals[key] = True else: Globals[key] = False else: warn_press_key("Encountered unsupported key %s in section %s on line %i" % (key, section, ln)) elif section == "SYSTEM": if key == 'name': SystemName = s[1] elif key == 'geometry': SystemDict[key] = s[1] elif key == 'rmsd_weight': SystemDict[key] = float(s[1]) elif key == 'select': SystemDict[key] = s[1] elif key == 'optimize': if len(s) == 1 or s[1].lower() in ['y','yes','true']: SystemDict[key] = True logger.info("Optimizing system %s\n" % SystemName) else: SystemDict[key] = False else: warn_press_key("Encountered unsupported key %s in section %s on line %i" % (key, section, ln)) elif section == "INTERACTION": if key == 'name': InterName = s[1] elif key == 'equation': InterDict[key] = ' '.join(s[1:]) elif key == 'energy': InterDict[key] = float(s[1]) elif key == 'weight': InterDict[key] = float(s[1]) else: warn_press_key("Encountered unsupported key %s in section %s on line %i" % (key, section, ln)) return Globals, Systems, Interactions
def prepare(self, pbc=False, **kwargs): """ Called by __init__ ; prepare the temp directory and figure out the topology. """ if hasattr(self,'FF'): if not (os.path.exists(self.FF.amber_frcmod) and os.path.exists(self.FF.amber_mol2)): # If the parameter files don't already exist, create them for the purpose of # preparing the engine, but then delete them afterward. prmtmp = True self.FF.make(np.zeros(self.FF.np)) # Currently force field object only allows one mol2 and frcmod file although this can be lifted. self.mol2 = [self.FF.amber_mol2] self.frcmod = [self.FF.amber_frcmod] if 'mol2' in kwargs: logger.error("FF object is provided, which overrides mol2 keyword argument") raise RuntimeError if 'frcmod' in kwargs: logger.error("FF object is provided, which overrides frcmod keyword argument") raise RuntimeError else: prmtmp = False self.mol2 = listfiles(kwargs.get('mol2'), 'mol2', err=True) self.frcmod = listfiles(kwargs.get('frcmod'), 'frcmod', err=True) # Figure out the topology information. self.leap() o = self.callamber("rdparm %s.prmtop" % self.name, stdin="printAtoms\nprintBonds\nexit\n", persist=True, print_error=False) # Once we do this, we don't need the prmtop and inpcrd anymore os.unlink("%s.inpcrd" % self.name) os.unlink("%s.prmtop" % self.name) os.unlink("leap.log") mode = 'None' self.AtomLists = defaultdict(list) G = nx.Graph() for line in o: s = line.split() if 'Atom' in line: mode = 'Atom' elif 'Bond' in line: mode = 'Bond' elif 'RDPARM MENU' in line: continue elif 'EXITING' in line: break elif len(s) == 0: continue elif mode == 'Atom': # Based on parsing lines like these: """ 327: HA -0.01462 1.0 ( 23:HIP ) H1 E 328: CB -0.33212 12.0 ( 23:HIP ) CT 3 329: HB2 0.10773 1.0 ( 23:HIP ) HC E 330: HB3 0.10773 1.0 ( 23:HIP ) HC E 331: CG 0.18240 12.0 ( 23:HIP ) CC B """ # Based on variable width fields. atom_number = int(line.split(':')[0]) atom_name = line.split()[1] atom_charge = float(line.split()[2]) atom_mass = float(line.split()[3]) rnn = line.split('(')[1].split(')')[0].split(':') residue_number = int(rnn[0]) residue_name = rnn[1] atom_type = line.split(')')[1].split()[0] self.AtomLists['Name'].append(atom_name) self.AtomLists['Charge'].append(atom_charge) self.AtomLists['Mass'].append(atom_mass) self.AtomLists['ResidueNumber'].append(residue_number) self.AtomLists['ResidueName'].append(residue_name) # Not sure if this works G.add_node(atom_number) elif mode == 'Bond': a, b = (int(i) for i in (line.split('(')[1].split(')')[0].split(','))) G.add_edge(a, b) self.AtomMask = [a == 'A' for a in self.AtomLists['ParticleType']] # Use networkx to figure out a list of molecule numbers. # gs = nx.connected_component_subgraphs(G) # tmols = [gs[i] for i in np.argsort(np.array([min(g.nodes()) for g in gs]))] # mnodes = [m.nodes() for m in tmols] # self.AtomLists['MoleculeNumber'] = [[i+1 in m for m in mnodes].index(1) for i in range(self.mol.na)] ## Write out the trajectory coordinates to a .mdcrd file. # I also need to write the trajectory if 'boxes' in self.mol.Data.keys(): warn_press_key("Writing %s-all.crd file with no periodic box information" % self.name) del self.mol.Data['boxes'] if hasattr(self, 'target') and hasattr(self.target,'shots'): self.qmatoms = target.qmatoms self.mol.write("%s-all.crd" % self.name, select=range(self.target.shots), ftype="mdcrd") else: self.qmatoms = self.mol.na self.mol.write("%s-all.crd" % self.name, ftype="mdcrd") if prmtmp: for f in self.FF.fnms: os.unlink(f)