def write_fb_target_abinitio(self, records): """ Write a list of {'energy': xxx, 'molecule': xxx, 'name': xxx} records into a new target folder """ # prepare folder for writing target_name = 'abinitio_bond_angles' target_folder = os.path.join(self.out_folder, target_name) os.mkdir(target_folder) os.chdir(target_folder) # load data into a fb Molecule out_m = Molecule() out_m.elem = self.m.elem.copy() out_m.xyzs = [] out_m.qm_energies = [] out_m.comms = [] for record in records: qcmol = record['molecule'] energy = record['energy'] name = record.get('name', 'created by FBTargetBuilder') m = self.qc_molecule_to_fb_molecule(qcmol) assert m.elem == out_m.elem, 'Elements list of resulting qcmol is not consistent with self.m' # append geometry out_m.xyzs.append(m.xyzs[0]) # append energy out_m.qm_energies.append(energy) # append name out_m.comms.append(name) # write output print( f"Writing {len(records)} frames into targets/abinitio_bond_angles/traj.xyz" ) out_m.write('traj.xyz') print( f"Writing {len(records)} frames into targets/abinitio_bond_angles/qdata.txt" ) out_m.write('qdata.txt')
def read_quantum(): Result = None os.chdir('calcs') for i in range(M.ns): dnm = eval(formstr % i) print("\rNow in directory %i" % i, end=' ') if os.path.exists(dnm): os.chdir(dnm) if os.path.exists('qchem.out'): Output = Molecule('qchem.out') if os.path.exists('plot.esp'): ESP = Molecule('plot.esp') #print ESP.Data.keys() Output.qm_espxyzs = list(ESP.qm_espxyzs) Output.qm_espvals = list(ESP.qm_espvals) #Output += Molecule('plot.esp') if Result == None: Result = Output else: Result += Output else: raise Exception("The output file %s doesn't exist." % os.path.abspath('qchem.out')) os.chdir('..') else: raise Exception("The subdirectory %s doesn't exist." % os.path.abspath(dnm)) os.chdir('..') return Result
def QChem_Dielectric_Energy(fnm,wq): QCIn = Molecule(fnm) for i in range(QCIn.na): # Q-Chem crashes if it doesn't recognize the chemical element if QCIn.Data['elem'][i] in ['M','L']: QCIn.Data['elem'][i] = 'He' CalcDir=os.path.splitext(fnm)[0]+".d" GoInto(CalcDir) digits = len(str(QCIn.ns)) for i in range(QCIn.ns): sdir = "%%0%ii" % digits % i GoInto(sdir) QCIn.write("qchem.in",select=i) queue_up(wq,"qchem40 qchem.in qchem.out",input_files=["qchem.in"],output_files=["qchem.out"],verbose=False) Leave(sdir) wq_wait(wq,verbose=False) PCM_Energies = [] for i in range(QCIn.ns): sdir = "%%0%ii" % digits % i GoInto(sdir) for line in open("qchem.out"): if "PCM electrostatic energy" in line: PCM_Energies.append(float(line.split()[-2])) Leave(sdir) Leave(CalcDir) return np.array(PCM_Energies) * 2625.5
def validate_qdata_file(self, filename): os.chdir(self._folder) self.qdata_filename = filename if self.qdata_filename != 'qdata.txt': return {'success': False, 'error': 'Only qdata.txt is recognized by ForceBalance. Please rename file to qdata.txt'} assert hasattr(self, 'coords_filename'), 'self.coords_filename does not exist, validate coords file first' try: m = Molecule(self.coords_filename) m1 = Molecule(self.qdata_filename) if len(m1) != len(m): ret = {'success': False, 'error': f'Number of frames {len(m1)} does not match coords file ({len(m)})'} elif m1.na != m.na: ret = {'success': False, 'error': f'Number of atoms ({m1.na}) does not match coords file ({m.na})'} elif len(m1.qm_energies) != len(m): ret = {'success': False, 'error': f'Number of qm eneriges ({len(m1.qm_energies)}) does not match number of frames ({len(m)})'} ret = { 'success': True, 'n_energies': len(m1.qm_energies), } # gradiants are optional if hasattr(m1, 'qm_grads'): if len(m1.qm_grads) != len(m): ret = {'success': False, 'error': f'Number of qm gradiants ({len(m1.qm_energies)}) does not match number of frames ({len(m)})'} else: ret['n_grads'] = len(m1.qm_grads) except Exception as e: print(e) ret = {'success': False, 'error': str(e)} return ret
def readsrc(self, **kwargs): """ Called by __init__ ; read files from the source directory. """ self.leapcmd = onefile(kwargs.get('leapcmd'), 'leap', err=True) self.absleap = os.path.abspath(self.leapcmd) # Name of the molecule, currently just call it a default name. self.mname = 'molecule' if 'mol' in kwargs: self.mol = kwargs['mol'] elif 'coords' in kwargs: crdfile = onefile(kwargs.get('coords'), None, err=True) self.mol = Molecule(crdfile, build_topology=False) # AMBER has certain PDB requirements, so we will absolutely require one. needpdb = True # if hasattr(self, 'mol') and all([i in self.mol.Data.keys() for i in ["chain", "atomname", "resid", "resname", "elem"]]): # needpdb = False # Determine the PDB file name. # If 'pdb' is provided to Engine initialization, it will be used to # copy over topology information (chain, atomname etc.). If mol/coords # is not provided, then it will also provide the coordinates. pdbfnm = onefile(kwargs.get('pdb'), 'pdb' if needpdb else None, err=needpdb) if pdbfnm != None: mpdb = Molecule(pdbfnm, build_topology=False) if hasattr(self, 'mol'): for i in ["chain", "atomname", "resid", "resname", "elem"]: self.mol.Data[i] = mpdb.Data[i] else: self.mol = copy.deepcopy(mpdb) self.abspdb = os.path.abspath(pdbfnm)
def main(): M = Molecule(argv[1]) tempfnm = argv[3] if len(argv) >= 4 else None if tempfnm != None: M.add_quantum(tempfnm) print M.Data.keys() M.write(argv[2])
def check_connectivity(bond_set, filename): """ Check if the connectivity in the molecule file is consistent with geometry Using force balance Molecule.build_bonds() for this first draft This can be improved by OpenEye or other methods """ fbmol = Molecule(filename) fbmol.build_bonds() new_bonds = set(fbmol.bonds) return bond_set == new_bonds
def __init__(self, molecule=None): # molecule.py can not parse psi4 input yet, so we use self.load_psi4_input() as a walk around if molecule is None: # create a fake molecule molecule = Molecule() molecule.elem = ['H'] molecule.xyzs = [[[0, 0, 0]]] super(Psi4, self).__init__(molecule) self.threads = None
def __init__(self,options,tgt_opts,forcefield): super(BindingEnergy,self).__init__(options,tgt_opts,forcefield) self.set_option(None, None, 'inter_txt', os.path.join(self.tgtdir,tgt_opts['inter_txt'])) self.global_opts, self.sys_opts, self.inter_opts = parse_interactions(self.inter_txt) # If the global option doesn't exist in the system / interaction, then it is copied over. for opt in self.global_opts: for sys in self.sys_opts: if opt not in self.sys_opts[sys]: self.sys_opts[sys][opt] = self.global_opts[opt] for inter in self.inter_opts: if opt not in self.inter_opts[inter]: self.inter_opts[inter][opt] = self.global_opts[opt] for inter in self.inter_opts: if 'energy_unit' in self.inter_opts[inter] and self.inter_opts[inter]['energy_unit'].lower() not in ['kilocalorie_per_mole', 'kilocalories_per_mole']: logger.error('Usage of physical units is has been removed, please provide all binding energies in kcal/mole\n') raise RuntimeError self.inter_opts[inter]['reference_physical'] = self.inter_opts[inter]['energy'] if tgt_opts['energy_denom'] == 0.0: self.set_option(None, None, 'energy_denom', val=np.std(np.array([val['reference_physical'] for val in self.inter_opts.values()]))) else: self.set_option(None, None, 'energy_denom', val=tgt_opts['energy_denom']) self.set_option(None, None, 'rmsd_denom', val=tgt_opts['rmsd_denom']) self.set_option(tgt_opts,'cauchy') self.set_option(tgt_opts,'attenuate') ## LPW 2018-02-11: This is set to True if the target calculates ## a single-point property over several existing snapshots. self.loop_over_snapshots = False logger.info("The energy denominator is: %s\n" % str(self.energy_denom)) logger.info("The RMSD denominator is: %s\n" % str(self.rmsd_denom)) if self.cauchy: logger.info("Each contribution to the interaction energy objective function will be scaled by 1.0 / ( denom**2 + reference**2 )\n") if self.attenuate: logger.error('attenuate and cauchy are mutually exclusive\n') raise RuntimeError elif self.attenuate: logger.info("Repulsive interactions beyond energy_denom will be scaled by 1.0 / ( denom**2 + (reference-denom)**2 )\n") ## Build keyword dictionaries to pass to engine. engine_args = OrderedDict(list(self.OptionDict.items()) + list(options.items())) del engine_args['name'] ## Create engine objects. self.engines = OrderedDict() for sysname,sysopt in self.sys_opts.items(): M = Molecule(os.path.join(self.root, self.tgtdir, sysopt['geometry'])) if 'select' in sysopt: atomselect = np.array(uncommadash(sysopt['select'])) M = M.atom_select(atomselect) if self.FF.rigid_water: M.rigid_water() self.engines[sysname] = self.engine_(target=self, mol=M, name=sysname, tinker_key=os.path.join(sysopt['keyfile']), **engine_args)
def __init__(self, mol2_file, client_conf_file, scan_conf_file=None): self.m = Molecule(mol2_file) self.qc_mol = self.fb_molecule_to_qc_molecule(self.m) # create a client from config file self.client = ptl.FractalClient.from_file(client_conf_file) # load scan config from scan_conf_file self.scan_conf = self.load_scan_conf(scan_conf_file) # create output folder self.out_folder = os.path.realpath('targets') if os.path.exists('targets'): raise OSError( "Folder targets/ already exist. Please delete the prevous one") os.mkdir(self.out_folder)
def optimize(self, shot=0, method="newton", crit=1e-4): """ Optimize the geometry and align the optimized geometry to the starting geometry. """ 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 Energy_RMSD(systems): tinkerhome = os.environ["TINKERPATH"] f1 = open("runAna.sh", "w") f2 = open("runMin.sh", "w") i = 0 for sys_ in systems: opts = systems[sys_] optimize = (opts['optimize'] if 'optimize' in opts else False) if not optimize: if (i+1)%24 == 0: cmd = "rm -f %s.out\n%s/analyze %s.xyz -k %s.key E > %s.out \n"%(sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 else: cmd = "rm -f %s.out\n%s/analyze %s.xyz -k %s.key E > %s.out & \n"%(sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 f1.write(cmd) else: if (i+1)%24 == 0: cmd = "rm -f %s.xyz_2 %s.out \n%s/optimize %s.xyz -k %s.key 0.0001 > %s.out \n"%(sys_, sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 else: cmd = "rm -f %s.xyz_2 %s.out \n%s/optimize %s.xyz -k %s.key 0.0001 > %s.out & \n"%(sys_, sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 f2.write(cmd) f1.write("wait\n") f2.write("wait\n") f1.close() f2.close() os.system("sh runAna.sh") os.system("sh runMin.sh") for sys_ in systems: while not os.path.isfile(os.path.join(os.getcwd(), sys_ + ".out")): time.sleep(1.0) Es = {} RMSDs = {} for sys_ in systems: energ = 0.0 rmsd = 0.0 for line in open("%s.out"%sys_).readlines(): if "Total Potential Energy" in line: energ = float(line.split()[-2].replace('D','e')) Es[sys_] = energ RMSDs[sys_] = 0.0 if "Final Function Value :" in line: energ = float(line.split()[-1].replace('D','e')) Es[sys_] = energ M1 = Molecule("%s.xyz" % sys_, ftype="tinker") M2 = Molecule("%s.xyz_2" % sys_, ftype="tinker") M1 += M2 RMSDs[sys_] = M1.ref_rmsd(0)[1] return Es,RMSDs
def __init__(self,options,tgt_opts,forcefield): super(BindingEnergy,self).__init__(options,tgt_opts,forcefield) self.set_option(None, None, 'inter_txt', os.path.join(self.tgtdir,tgt_opts['inter_txt'])) self.global_opts, self.sys_opts, self.inter_opts = parse_interactions(self.inter_txt) # If the global option doesn't exist in the system / interaction, then it is copied over. for opt in self.global_opts: for sys in self.sys_opts: if opt not in self.sys_opts[sys]: self.sys_opts[sys][opt] = self.global_opts[opt] for inter in self.inter_opts: if opt not in self.inter_opts[inter]: self.inter_opts[inter][opt] = self.global_opts[opt] for inter in self.inter_opts: if 'energy_unit' in self.inter_opts[inter] and self.inter_opts[inter]['energy_unit'].lower() not in ['kilocalorie_per_mole', 'kilocalories_per_mole']: logger.error('Usage of physical units is has been removed, please provide all binding energies in kcal/mole\n') raise RuntimeError self.inter_opts[inter]['reference_physical'] = self.inter_opts[inter]['energy'] if tgt_opts['energy_denom'] == 0.0: self.set_option(None, None, 'energy_denom', val=np.std(np.array([val['reference_physical'] for val in self.inter_opts.values()]))) else: self.set_option(None, None, 'energy_denom', val=tgt_opts['energy_denom']) self.set_option(None, None, 'rmsd_denom', val=tgt_opts['rmsd_denom']) self.set_option(tgt_opts,'cauchy') self.set_option(tgt_opts,'attenuate') logger.info("The energy denominator is: %s\n" % str(self.energy_denom)) logger.info("The RMSD denominator is: %s\n" % str(self.rmsd_denom)) if self.cauchy: logger.info("Each contribution to the interaction energy objective function will be scaled by 1.0 / ( denom**2 + reference**2 )\n") if self.attenuate: logger.error('attenuate and cauchy are mutually exclusive\n') raise RuntimeError elif self.attenuate: logger.info("Repulsive interactions beyond energy_denom will be scaled by 1.0 / ( denom**2 + (reference-denom)**2 )\n") ## Build keyword dictionaries to pass to engine. engine_args = OrderedDict(self.OptionDict.items() + options.items()) del engine_args['name'] ## Create engine objects. self.engines = OrderedDict() for sysname,sysopt in self.sys_opts.items(): M = Molecule(os.path.join(self.root, self.tgtdir, sysopt['geometry'])) if 'select' in sysopt: atomselect = np.array(uncommadash(sysopt['select'])) M = M.atom_select(atomselect) if self.FF.rigid_water: M.rigid_water() self.engines[sysname] = self.engine_(target=self, mol=M, name=sysname, tinker_key=os.path.join(sysopt['keyfile']), **engine_args)
def main(): M = Molecule(opts.coords) if len(M.molecules) != 1: raise RuntimeError( 'Input coordinates must be a single contiguous molecule') if opts.phi1 == None: raise RuntimeError( 'phi1 (the first quartet of atoms) must be provided') xyzout = [] commout = [] xyzcsh = [] commcsh = [] if opts.phi2 != None: # Two dimensional scan for inc1 in range(0, 360, opts.scan): for inc2 in range(0, 360, opts.scan): xyzrot, clash = get_rotated_xyz(M, [opts.phi1, opts.phi2], [inc1, inc2]) print(inc1, inc2, "Clash" if clash else "Ok") comm = "Dihedrals %s, %s set to %i, %i" % (str( opts.phi1), str(opts.phi2), inc1, inc2) if clash: xyzcsh.append(xyzrot.copy()) commcsh.append(comm) else: xyzout.append(xyzrot.copy()) commout.append(comm) else: # One dimensional scan for inc1 in range(0, 360, opts.scan): xyzrot, clash = get_rotated_xyz(M, [opts.phi1], [inc1]) print(inc1, "Clash" if clash else "Ok") comm = "Dihedral %s set to %i" % (str(opts.phi1), inc1) if clash: xyzcsh.append(xyzrot.copy()) commcsh.append(comm) else: xyzout.append(xyzrot.copy()) commout.append(comm) if len(xyzout) > 0: M.xyzs = xyzout M.comms = commout M.write( os.path.splitext(opts.coords)[0] + "_out" + os.path.splitext(opts.coords)[1]) if len(xyzcsh) > 0: M.xyzs = xyzcsh M.comms = commcsh M.write( os.path.splitext(opts.coords)[0] + "_clash" + os.path.splitext(opts.coords)[1])
def calc_new(self, coords, dirname): if not os.path.exists(dirname): os.makedirs(dirname) Gro = Molecule("conf.gro") Gro.xyzs[0] = coords.reshape(-1, 3) * 0.529 cwd = os.getcwd() shutil.copy2("topol.top", dirname) shutil.copy2("shot.mdp", dirname) os.chdir(dirname) Gro.write("coords.gro") G = GMX(coords="coords.gro", gmx_top="topol.top", gmx_mdp="shot.mdp") EF = G.energy_force() Energy = EF[0, 0] / eqcgmx Gradient = EF[0, 1:] / fqcgmx os.chdir(cwd) return Energy, Gradient
def __init__(self,options,tgt_opts,forcefield): super(BindingEnergy,self).__init__(options,tgt_opts,forcefield) self.set_option(None, None, 'inter_txt', os.path.join(self.tgtdir,tgt_opts['inter_txt'])) self.global_opts, self.sys_opts, self.inter_opts = parse_interactions(self.inter_txt) # If the global option doesn't exist in the system / interaction, then it is copied over. for opt in self.global_opts: for sys in self.sys_opts: if opt not in self.sys_opts[sys]: self.sys_opts[sys][opt] = self.global_opts[opt] for inter in self.inter_opts: if opt not in self.inter_opts[inter]: self.inter_opts[inter][opt] = self.global_opts[opt] for inter in self.inter_opts: if 'energy_unit' in self.inter_opts[inter] and self.inter_opts[inter]['energy_unit'].lower() not in ['kilocalorie_per_mole', 'kilocalories_per_mole']: logger.error('Usage of physical units is has been removed, please provide all binding energies in kcal/mole\n') raise RuntimeError self.inter_opts[inter]['reference_physical'] = self.inter_opts[inter]['energy'] if tgt_opts['energy_denom'] == 0.0: self.set_option(None, None, 'energy_denom', val=np.std(np.array([val['reference_physical'] for val in self.inter_opts.values()]))) else: self.set_option(None, None, 'energy_denom', val=tgt_opts['energy_denom']) self.set_option(None, None, 'rmsd_denom', val=tgt_opts['rmsd_denom']) self.set_option(tgt_opts,'attenuate') ## LPW 2018-02-11: This is set to True if the target calculates ## a single-point property over several existing snapshots. self.loop_over_snapshots = False logger.info("The energy denominator is: %s\n" % str(self.energy_denom)) logger.info("The RMSD denominator is: %s\n" % str(self.rmsd_denom)) if self.attenuate: denom = self.energy_denom logger.info("Interaction energies more positive than %.1f will have reduced weight going as: 1.0 / (%.1f^2 + (energy-%.1f)^2)\n" % (denom, denom, denom)) ## Build keyword dictionaries to pass to engine. engine_args = OrderedDict(list(self.OptionDict.items()) + list(options.items())) engine_args.pop('name', None) ## Create engine objects. self.engines = OrderedDict() for sysname,sysopt in self.sys_opts.items(): M = Molecule(os.path.join(self.root, self.tgtdir, sysopt['geometry'])) if 'select' in sysopt: atomselect = np.array(uncommadash(sysopt['select'])) M = M.atom_select(atomselect) if self.FF.rigid_water: M.rigid_water() self.engines[sysname] = self.engine_(target=self, mol=M, name=sysname, tinker_key=os.path.join(sysopt['keyfile']), **engine_args)
def check_connectivity(filename): """ Check if the connectivity in the molecule file is consistent with geometry Using force balance Molecule.build_bonds() for this first draft This can be improved by OpenEye or other methods """ fbmol = Molecule(filename) orig_bonds = set(fbmol.bonds) # for b1, b2 in fbmol.bonds: # bond = (b1, b2) if b1 < b2 else (b2, b1) # orig_bonds.add(bond) fbmol.build_bonds() new_bonds = set(fbmol.bonds) # for b1, b2 in fbmol.bonds: # bond = (b1, b2) if b1 < b2 else (b2, b1) # new_bonds.add(bond) return orig_bonds == new_bonds
def _build_internal_coordinates(self): from geometric.internal import PrimitiveInternalCoordinates m = Molecule(os.path.join(self.tgtdir, "input.mol2")) IC = PrimitiveInternalCoordinates(m) self.IC = IC
def load_psi4_input(self, psi4in): """ Psi4 input file parser, only support xyz coordinates for now """ coords = [] elems = [] found_molecule, found_geo, found_gradient = False, False, False psi4_temp = [ ] # store a template of the input file for generating new ones for line in open(psi4in): if 'molecule' in line: found_molecule = True psi4_temp.append(line) elif found_molecule is True: ls = line.split() if len(ls) == 4: if found_geo == False: found_geo = True psi4_temp.append("$!geometry@here") # parse the xyz format elems.append(ls[0]) coords.append(ls[1:4]) else: psi4_temp.append(line) if '}' in line: found_molecule = False else: psi4_temp.append(line) if "gradient(" in line: found_gradient = True if found_gradient == False: raise RuntimeError( "Psi4 inputfile %s should have gradient() command." % psi4in) self.M = Molecule() self.M.elem = elems self.M.xyzs = [np.array(coords, dtype=np.float64)] self.psi4_temp = psi4_temp
def read_molecules_from_optgeo_target(target_fol): # read all molecules from an optgeo target folder res = {} with open(os.path.join(target_fol, 'notes.txt')) as fnote: for line in fnote: ls = line.split() if len(ls) == 7 and ls[-1] == 'SUCCESS': assert ls[3] == 'molecule_id' mol_id = ls[4] fnm_pre = ls[0] # read content of mol2 file mol2_fnm = fnm_pre + '.mol2' with open(os.path.join(target_fol, mol2_fnm)) as fmol2: mol2_str = fmol2.read() # read content of pdb file pdb_fnm = fnm_pre + '.pdb' with open(os.path.join(target_fol, pdb_fnm)) as f: pdb_str = f.read() # read QM geometry from xyz file xyz_fnm = fnm_pre + '.xyz' m = Molecule(os.path.join(target_fol, xyz_fnm)) data = { 'mol2_str': mol2_str, 'pdb_str': pdb_str, 'qm_geo': m.xyzs[0] } res[mol_id] = data return res
def validate_gro_file(self, filename): """ Validate gro file, this is the first step and we save the molecule object """ os.chdir(self._folder) self.gro_filename = filename try: m = Molecule(self.gro_filename) pdb_string = '\n'.join(m.write_pdb(range(m.na))) ret = { 'success': True, 'n_shots': len(m), 'n_atoms': m.na, 'pdbString': pdb_string, } except Exception as e: print(e) ret = {'success': False, 'error': str(e)} return ret
def readsrc(self, **kwargs): """ Called by __init__ ; read files from the source directory. """ self.key = onefile('key', kwargs['tinker_key'] if 'tinker_key' in kwargs else None) self.prm = onefile('prm', kwargs['tinker_prm'] if 'tinker_prm' in kwargs else None) if 'mol' in kwargs: self.mol = kwargs['mol'] elif 'coords' in kwargs: if kwargs['coords'].endswith('.xyz'): self.mol = Molecule(kwargs['coords'], ftype="tinker") else: self.mol = Molecule(kwargs['coords']) else: arcfile = onefile('arc') if not arcfile: raise RuntimeError('Cannot determine which .arc file to use') self.mol = Molecule(arcfile)
def readsrc(self, **kwargs): """ Called by __init__ ; read files from the source directory. """ self.key = onefile("key", kwargs["tinker_key"] if "tinker_key" in kwargs else None) self.prm = onefile("prm", kwargs["tinker_prm"] if "tinker_prm" in kwargs else None) if "mol" in kwargs: self.mol = kwargs["mol"] elif "coords" in kwargs: if kwargs["coords"].endswith(".xyz"): self.mol = Molecule(kwargs["coords"], ftype="tinker") else: self.mol = Molecule(kwargs["coords"]) else: arcfile = onefile("arc") if not arcfile: raise RuntimeError("Cannot determine which .arc file to use") self.mol = Molecule(arcfile)
def gather_generations(): shots = Molecule('shots.gro') qdata = Molecule('qdata.txt') A1 = np.array(shots.xyzs) A2 = np.array(qdata.xyzs) if A1.shape != A2.shape: raise Exception('shots.gro and qdata.txt appear to contain different data') elif np.max(np.abs((A1 - A2).flatten())) > 1e-4: raise Exception('shots.gro and qdata.txt appear to contain different xyz coordinates') shots.qm_energies = qdata.qm_energies shots.qm_forces = qdata.qm_forces shots.qm_espxyzs = qdata.qm_espxyzs shots.qm_espvals = qdata.qm_espvals First = True if First: All = shots else: All += shots return All
def validate_pdb_file(self, filename): os.chdir(self._folder) self.pdb_filename = filename try: m = Molecule(self.pdb_filename) ret = {'success': True } except Exception as e: print(e) ret = {'success': False, 'error': str(e)} return ret
def _build_internal_coordinates(self): "Build internal coordinates system with geometric.internal.PrimitiveInternalCoordinates" # geometric module is imported to build internal coordinates # importing here will avoid import error for calculations not using this target from geometric.internal import PrimitiveInternalCoordinates, Distance, Angle, Dihedral, OutOfPlane self.internal_coordinates = OrderedDict() for sysname, sysopt in self.sys_opts.items(): geofile = os.path.join(self.root, self.tgtdir, sysopt['geometry']) topfile = os.path.join(self.root, self.tgtdir, sysopt['topology']) # logger.info("Building internal coordinates from file: %s\n" % topfile) m0 = Molecule(geofile) m = Molecule(topfile) p_IC = PrimitiveInternalCoordinates(m) # here we explicitly pick the bonds, angles and dihedrals to evaluate ic_bonds, ic_angles, ic_dihedrals, ic_impropers = [], [], [], [] for ic in p_IC.Internals: if isinstance(ic, Distance): ic_bonds.append(ic) elif isinstance(ic, Angle): ic_angles.append(ic) elif isinstance(ic, Dihedral): ic_dihedrals.append(ic) elif isinstance(ic, OutOfPlane): ic_impropers.append(ic) # compute and store reference values pos_ref = m0.xyzs[0] vref_bonds = np.array([ic.value(pos_ref) for ic in ic_bonds]) vref_angles = np.array( [ic.value(pos_ref) * RADIAN_2_DEGREE for ic in ic_angles]) vref_dihedrals = np.array( [ic.value(pos_ref) * RADIAN_2_DEGREE for ic in ic_dihedrals]) vref_impropers = np.array( [ic.value(pos_ref) * RADIAN_2_DEGREE for ic in ic_impropers]) self.internal_coordinates[sysname] = { 'ic_bonds': ic_bonds, 'ic_angles': ic_angles, 'ic_dihedrals': ic_dihedrals, 'ic_impropers': ic_impropers, 'vref_bonds': vref_bonds, 'vref_angles': vref_angles, 'vref_dihedrals': vref_dihedrals, 'vref_impropers': vref_impropers, }
def __init__(self, options, tgt_opts, forcefield): super(TorsionProfileTarget, self).__init__(options, tgt_opts, forcefield) if not os.path.exists(os.path.join(self.tgtdir, 'metadata.json')): raise RuntimeError( 'TorsionProfileTarget needs torsion drive metadata.json file') with open(os.path.join(self.tgtdir, 'metadata.json')) as f: self.metadata = json.load(f) self.ndim = len(self.metadata['dihedrals']) self.freeze_atoms = sorted( set(itertools.chain(*self.metadata['dihedrals']))) ## Read in the coordinate files and get topology information from PDB if hasattr(self, 'pdb') and self.pdb is not None: self.mol = Molecule(os.path.join(self.root, self.tgtdir, self.coords), top=(os.path.join(self.root, self.tgtdir, self.pdb))) else: self.mol = Molecule( os.path.join(self.root, self.tgtdir, self.coords)) ## Number of snapshots. self.ns = len(self.mol) ## Option for how much data to write to disk. self.set_option(tgt_opts, 'writelevel', 'writelevel') ## Harmonic restraint for non-torsion atoms in kcal/mol. self.set_option(tgt_opts, 'restrain_k', 'restrain_k') ## Attenuate the weights as a function of energy self.set_option(tgt_opts, 'attenuate', 'attenuate') ## Energy denominator for objective function self.set_option(tgt_opts, 'energy_denom', 'energy_denom') ## Set upper cutoff energy self.set_option(tgt_opts, 'energy_upper', 'energy_upper') ## Read in the reference data. self.read_reference_data() ## Build keyword dictionaries to pass to engine. engine_args = OrderedDict( list(self.OptionDict.items()) + list(options.items())) engine_args.pop('name', None) ## Create engine object. engine_args['freeze_atoms'] = self.freeze_atoms self.engine = self.engine_(target=self, mol=self.mol, **engine_args)
def prepare_temp_directory(self, options, tgt_opts): abstempdir = os.path.join(self.root,self.tempdir) if self.FF.rigid_water: self.optprog = "optrigid" #LinkFile(os.path.join(self.root,self.tgtdir,"rigid.key"),os.path.join(abstempdir,"rigid.key")) else: self.optprog = "optimize" # Link the necessary programs into the temporary directory LinkFile(os.path.join(options['tinkerpath'],"analyze"),os.path.join(abstempdir,"analyze")) LinkFile(os.path.join(options['tinkerpath'],self.optprog),os.path.join(abstempdir,self.optprog)) LinkFile(os.path.join(options['tinkerpath'],"superpose"),os.path.join(abstempdir,"superpose")) # Link the run parameter file # The master file might be unneeded?? for sysname,sysopt in self.sys_opts.items(): if self.FF.rigid_water: # Make every water molecule rigid # WARNING: Hard coded values here! M = Molecule(os.path.join(self.root, self.tgtdir, sysopt['geometry']),ftype="tinker") for a in range(0, len(M.xyzs[0]), 3): flex = M.xyzs[0] wat = flex[a:a+3] com = wat.mean(0) wat -= com o = wat[0] h1 = wat[1] h2 = wat[2] r1 = h1 - o r2 = h2 - o r1 /= Np.linalg.norm(r1) r2 /= Np.linalg.norm(r2) # Obtain unit vectors. ex = r1 + r2 ey = r1 - r2 ex /= Np.linalg.norm(ex) ey /= Np.linalg.norm(ey) Bond = 0.9572 Ang = Np.pi * 104.52 / 2 / 180 cosx = Np.cos(Ang) cosy = Np.sin(Ang) h1 = o + Bond*ex*cosx + Bond*ey*cosy h2 = o + Bond*ex*cosx - Bond*ey*cosy rig = Np.array([o, h1, h2]) + com M.xyzs[0][a:a+3] = rig M.write(os.path.join(abstempdir,sysopt['geometry']),ftype="tinker") else: M = Molecule(os.path.join(self.root, self.tgtdir, sysopt['geometry']),ftype="tinker") if 'select' in sysopt: atomselect = Np.array(uncommadash(sysopt['select'])) #atomselect = eval("Np.arange(M.na)"+sysopt['select']) M = M.atom_select(atomselect) M.write(os.path.join(abstempdir,sysname+".xyz"),ftype="tinker") write_key_with_prm(os.path.join(self.root,self.tgtdir,sysopt['keyfile']),os.path.join(abstempdir,sysname+".key"),ffobj=self.FF)
def get_target_objective_data(self, target_name, opt_iter): """ Read objective data for a target and an optimization iteration from the tmp folder """ res = {} target_options = self.input_options['tgt_opts'].get(target_name, None) if target_options is None: res['error'] = f"target {target_name} not found" print(f"get_target_objective_data: {res['error']}") return res # check the tmp folder for this target folder = os.path.join(self.tmp_folder, target_name, f'iter_{opt_iter:04d}') if not os.path.isdir(folder): res['error'] = f"tmp folder {folder} not found" print(f"get_target_objective_data: {res['error']}") return res # get target type specific objective information target_type = target_options['type'] if target_type.lower().startswith('abinitio'): # read energy compare data energy_compare_file = os.path.join(folder, 'EnergyCompare.txt') if not os.path.isfile(energy_compare_file): res['error'] = f"file {energy_compare_file} not found" print(f"get_target_objective_data: {res['error']}") return res energy_compare_data = np.loadtxt(energy_compare_file) res['qm_energies'] = energy_compare_data[:, 0].tolist() res['mm_energies'] = energy_compare_data[:, 1].tolist() res['diff'] = energy_compare_data[:, 2].tolist() res['weights'] = energy_compare_data[:, 3].tolist() # read molecule geometry mol_file = os.path.join(folder, 'coords.xyz') m = Molecule(mol_file) # generate pdb string if 'resname' not in m.Data: m.Data['resname'] = ['MOL'] * m.na m.Data['resid'] = [1] * m.na res['pdbString'] = '\n'.join(m.write_pdb(range(m.na))) else: res['error'] = f"get objective data for target type {target_type} not implemented" print(f"get_target_objective_data: {res['error']}") return res return res
def readsrc(self, **kwargs): """ Called by __init__ ; read files from the source directory. """ self.key = onefile(kwargs.get('tinker_key'), 'key') self.prm = onefile(kwargs.get('tinker_prm'), 'prm') if 'mol' in kwargs: self.mol = kwargs['mol'] else: crdfile = onefile(kwargs.get('coords'), 'arc', err=True) self.mol = Molecule(crdfile)
def readsrc(self, **kwargs): """ Called by __init__ ; read files from the source directory. """ self.key = onefile(kwargs.get("tinker_key"), "key") self.prm = onefile(kwargs.get("tinker_prm"), "prm") if "mol" in kwargs: self.mol = kwargs["mol"] else: crdfile = onefile(kwargs.get("coords"), "arc", err=True) self.mol = Molecule(crdfile)
def validate_coords_file(self, filename): """ Validate coords xyz file, this is the first step and we save the molecule object """ os.chdir(self._folder) self.coords_filename = filename try: m = Molecule(self.coords_filename) # generate pdb string if 'resname' not in m.Data: m.Data['resname'] = ['MOL'] * m.na m.Data['resid'] = [1] * m.na pdb_string = '\n'.join(m.write_pdb(range(m.na))) ret = { 'success': True, 'n_shots': len(m), 'n_atoms': m.na, 'pdbString': pdb_string, } except Exception as e: print(e) ret = {'success': False, 'error': str(e)} return ret
def write_torsion_target(procedure, target_name, removing_unreal=False): """ Fetch data from a QCArchive procedure and write as a ForceBalance Target folder Input: ------ procedure: qcfractal.interface.orm.torsiondrive_orm.TorsionDriveORM An object that represents a computation target_name: string Folder name to write the ForceBalance target removing_unreal: bool, default False If true, remove the atoms that are not "real" """ # check if the target folder name exists if os.path.exists(target_name): raise RuntimeError(f"Target folder {target_name} already exists") # form a Molecule object from the first torsion grid data grid_molecules = procedure.final_molecules() grid_energies = procedure.final_energies() data = next(iter(grid_molecules.values())) elem = data['symbols'] bonds = [(b[0], b[1]) for b in data['connectivity']] # remove the "unreal" atoms? removing_unreal = removing_unreal and (not all(data['real'])) if removing_unreal: elem = [e for e, f in zip(elem, data['real']) if f is True] bonds = [(b[0], b[1]) for b in bonds if data['real'][b[0]] and data['real'][b[1]]] # form the Molecule object m = Molecule() m.Data = { 'elem': elem, 'bonds': bonds, 'name': data['name'], 'xyzs': [], 'qm_energies': [], 'comms': [] } # load all frames for grid_id, data in grid_molecules.items(): geo = np.array(data['geometry']).reshape(-1, 3) * bohr2ang if removing_unreal: geo = geo[data['real']] m.Data['xyzs'].append(geo) energy = grid_energies[grid_id] m.Data['qm_energies'].append(energy) m.Data['comms'].append(f'{data["name"]} at torsion grid {grid_id}') # write the data os.mkdir(target_name) os.chdir(target_name) m.write('qdata.txt') m.write('geo.xyz') os.chdir('..')
def write_molecule_files(molecule, name, test_ff=None): qcjson_mol = molecule.dict(encoding='json') oemol = cmiles.utils.load_molecule(qcjson_mol) # write the mol2 file and xyz file for ext in ['xyz', 'mol2']: ofs.open(f'{name}.{ext}') oechem.OEWriteMolecule(ofs, oemol) ofs.close() success = True err_msg = "" # test if bonds changed bond_set = {(a, b) for a, b, v in molecule.connectivity} if not check_connectivity(bond_set, f'{name}.mol2'): success = False err_msg = "Bonds changed after rebuild" if not os.path.exists('../err_bonds_changed'): os.mkdir('../err_bonds_changed') shutil.move(f'{name}.mol2', f'../err_bonds_changed/{name}.mol2') os.remove(f'{name}.xyz') # test if can be created by the test_ff if success == True and test_ff != None: from openforcefield.topology import Molecule as Off_Molecule from openforcefield.topology import Topology as Off_Topology try: off_molecule = Off_Molecule.from_file(f'{name}.mol2') off_topology = Off_Topology.from_molecules(off_molecule) test_ff.create_openmm_system(off_topology) except Exception as e: success = False err_msg = str(e) if not os.path.exists('../error_mol2s'): os.mkdir('../error_mol2s') shutil.move(f'{name}.mol2', f'../error_mol2s/{name}.mol2') os.remove(f'{name}.xyz') if success == True: # use ForceBalance Molecule to generate pdb file # because the oechem.OEWriteMolecule will mess up with atom indices fbmol = Molecule(f'{name}.mol2') fbmol.write(f'{name}.pdb') return success, err_msg
def qc_molecule_to_fb_molecule(self, qc_molecule): """ Convert an qcportal.Molecule object to a forcebalance.molecule.Molecule object""" m = Molecule() m.elem = [Elements[i] for i in qc_molecule.atomic_numbers] m.xyzs = [qc_molecule.geometry * bohr2ang] m.molecular_charge = qc_molecule.molecular_charge m.mult = qc_molecule.molecular_multiplicity return m
def main(): import argparse parser = argparse.ArgumentParser() parser.add_argument("infile", help='Input mol2 file for a single molecule') parser.add_argument("-o", "--outfile", default='dihedral_list.json', help='Output json file containing definition of dihedrals') args = parser.parse_args() molecule = Molecule(args.infile) selector = DihedralSelector(molecule) dihedral_list = selector.find_dihedrals() print(f"Found {len(dihedral_list)} dihedrals") for d in dihedral_list: print(d) selector.write_dihedrals(dihedral_list, args.outfile)
def main(): M = Molecule(opts.coords) if len(M.molecules) != 1: raise RuntimeError('Input coordinates must be a single contiguous molecule') if opts.phi1 == None: raise RuntimeError('phi1 (the first quartet of atoms) must be provided') xyzout = [] commout = [] xyzcsh = [] commcsh = [] if opts.phi2 != None: # Two dimensional scan for inc1 in range(0, 360, opts.scan): for inc2 in range(0, 360, opts.scan): xyzrot, clash = get_rotated_xyz(M, [opts.phi1, opts.phi2], [inc1, inc2]) print(inc1, inc2, "Clash" if clash else "Ok") comm = "Dihedrals %s, %s set to %i, %i" % (str(opts.phi1), str(opts.phi2), inc1, inc2) if clash: xyzcsh.append(xyzrot.copy()) commcsh.append(comm) else: xyzout.append(xyzrot.copy()) commout.append(comm) else: # One dimensional scan for inc1 in range(0, 360, opts.scan): xyzrot, clash = get_rotated_xyz(M, [opts.phi1], [inc1]) print(inc1, "Clash" if clash else "Ok") comm = "Dihedral %s set to %i" % (str(opts.phi1), inc1) if clash: xyzcsh.append(xyzrot.copy()) commcsh.append(comm) else: xyzout.append(xyzrot.copy()) commout.append(comm) if len(xyzout) > 0: M.xyzs = xyzout M.comms = commout M.write(os.path.splitext(opts.coords)[0]+"_out"+os.path.splitext(opts.coords)[1]) if len(xyzcsh) > 0: M.xyzs = xyzcsh M.comms = commcsh M.write(os.path.splitext(opts.coords)[0]+"_clash"+os.path.splitext(opts.coords)[1])
def main(): M = Molecule(sys.argv[1]) MyG = build_graph(M) QMat, Suffix = get_equivalent_atoms(MyG) M2 = Mol2.mol2_set(sys.argv[1]).compounds.items()[0][1] NewQ = charge_as_array(M2, QMat) update_mol2(M2, NewQ, Suffix) if len(sys.argv) >= 3: with open(sys.argv[2], 'w') as f: print >> f, M2 print >> f, Ending else: print M2 print Ending
def read_sdf_to_fb_mol(filename): """ read sdf file and return ForceBalance.molecule.Molecule object """ from forcebalance.molecule import Molecule, Elements import numpy as np mol_list = read_split_mols(filename) assert len(mol_list) == 1, 'file contains multiple molecules' oe_mol = mol_list[0] # create a new molecule fb_mol = Molecule() # load elems fb_mol.elem = [Elements[a.GetAtomicNum()] for a in oe_mol.GetAtoms()] noa = len(fb_mol.elem) # load coordinates coords_dict = oe_mol.GetCoords() fb_mol.xyzs = [np.array([coords_dict[i] for i in range(noa)])] # load bonds bonds, bond_orders = [], [] for oe_bond in oe_mol.GetBonds(): idx_a = oe_bond.GetBgnIdx() idx_b = oe_bond.GetEndIdx() bond = (idx_a, idx_b) if idx_a <= idx_b else (idx_b, idx_a) bonds.append(bond) bond_orders.append(oe_bond.GetOrder()) fb_mol.bonds = bonds fb_mol.bond_orders = bond_orders # load atomic formal charges atomic_formal_charges = [a.GetFormalCharge() for a in oe_mol.GetAtoms()] molecular_charge = sum(atomic_formal_charges) fb_mol.Data['molecular_charge'] = molecular_charge fb_mol.Data['atomic_formal_charges'] = atomic_formal_charges # set the oe_mol as one attribute fb_mol.oe_mol = oe_mol # set the cmiles id mapped_smiles = cmiles.utils.mol_to_smiles(oe_mol) fb_mol.Data['cmiles_id'] = cmiles.generator.get_molecule_ids(mapped_smiles) return fb_mol
def main(): # create molecule m = Molecule(opts.xyz_file) # write to pdb m.write(tf) # read into mdtraj p = mdtraj.load(tf) # get list of hydrogens to remove c_ndx = [i.index for i in p.topology.atoms if i.name in c_strip] tail_atms = [y for (x, y) in m.Data['bonds'] if x in c_ndx] tail_h = [i for i in tail_atms if i not in c_ndx] # throw out some hydrogens atoms_to_keep = [b.index for b in p.topology.atoms if b.index not in tail_h] p.restrict_atoms(atoms_to_keep) p.save(op) # hella circular x = Molecule(op) x.write(opts.out_gro)
import numpy as np from forcebalance.molecule import Molecule from forcebalance.readfrq import read_frq_gen # Frequency output file. fout = sys.argv[1] # Mode number, starting from 1. modenum = int(sys.argv[2]) if modenum == 0: raise RuntimeError("Start mode number from one, please") frqs, modes, intens, elem, xyz = read_frq_gen(fout) M = Molecule() M.elem = elem[:] M.xyzs = [] xmode = modes[modenum - 1] xmode /= (np.linalg.norm(xmode)/np.sqrt(M.na)) xmode *= 0.3 # Reasonable vibrational amplitude spac = np.linspace(0, 1, 101) disp = np.concatenate((spac, spac[::-1][1:], -1*spac[1:], -1*spac[::-1][1:-1])) for i in disp: M.xyzs.append(xyz+i*xmode.reshape(-1,3)) M.comms = ['Vibrational Mode %i Frequency %.3f Displacement %.3f' % (modenum, frqs[modenum-1], disp[i]*(np.linalg.norm(xmode)/np.sqrt(M.na))) for i in range(len(M))]
class AMBER(Engine): """ Engine for carrying out general purpose AMBER calculations. """ def __init__(self, name="amber", **kwargs): ## Keyword args that aren't in this list are filtered out. self.valkwd = ['amberhome', 'pdb', 'mol2', 'frcmod', 'leapcmd'] super(AMBER,self).__init__(name=name, **kwargs) 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 readsrc(self, **kwargs): """ Called by __init__ ; read files from the source directory. """ self.leapcmd = onefile(kwargs.get('leapcmd'), 'leap', err=True) self.absleap = os.path.abspath(self.leapcmd) # Name of the molecule, currently just call it a default name. self.mname = 'molecule' if 'mol' in kwargs: self.mol = kwargs['mol'] elif 'coords' in kwargs: crdfile = onefile(kwargs.get('coords'), None, err=True) self.mol = Molecule(crdfile, build_topology=False) # AMBER has certain PDB requirements, so we will absolutely require one. needpdb = True # if hasattr(self, 'mol') and all([i in self.mol.Data.keys() for i in ["chain", "atomname", "resid", "resname", "elem"]]): # needpdb = False # Determine the PDB file name. # If 'pdb' is provided to Engine initialization, it will be used to # copy over topology information (chain, atomname etc.). If mol/coords # is not provided, then it will also provide the coordinates. pdbfnm = onefile(kwargs.get('pdb'), 'pdb' if needpdb else None, err=needpdb) if pdbfnm != None: mpdb = Molecule(pdbfnm, build_topology=False) if hasattr(self, 'mol'): for i in ["chain", "atomname", "resid", "resname", "elem"]: self.mol.Data[i] = mpdb.Data[i] else: self.mol = copy.deepcopy(mpdb) self.abspdb = os.path.abspath(pdbfnm) # Write the PDB that AMBER is going to read in. # This may or may not be identical to the one used to initialize the engine. # self.mol.write('%s.pdb' % self.name) # self.abspdb = os.path.abspath('%s.pdb' % self.name) def callamber(self, command, stdin=None, print_to_screen=False, print_command=False, **kwargs): """ Call TINKER; prepend the amberhome to calling the TINKER program. """ csplit = command.split() # Sometimes the engine changes dirs and the inpcrd/prmtop go missing, so we link it. # Prepend the AMBER path to the program call. prog = os.path.join(self.amberhome, "bin", csplit[0]) csplit[0] = prog # No need to catch exceptions since failed AMBER calculations will return nonzero exit status. o = _exec(' '.join(csplit), stdin=stdin, print_to_screen=print_to_screen, print_command=print_command, rbytes=1024, **kwargs) return o def leap(self, name=None, delcheck=False): if not os.path.exists(self.leapcmd): LinkFile(self.absleap, self.leapcmd) pdb = os.path.basename(self.abspdb) if not os.path.exists(pdb): LinkFile(self.abspdb, pdb) if name == None: name = self.name write_leap(self.leapcmd, mol2=self.mol2, frcmod=self.frcmod, pdb=pdb, prefix=name, spath=self.spath, delcheck=delcheck) self.callamber("tleap -f %s_" % self.leapcmd) 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 evaluate_(self, crdin, force=False): """ Utility function for computing energy and forces using AMBER. Inputs: crdin: AMBER .mdcrd file name. force: Switch for parsing the force. (Currently it always calculates the forces.) Outputs: Result: Dictionary containing energies (and optionally) forces. """ force_mdin="""Loop over conformations and compute energy and force (use ioutfnm=1 for netcdf, ntb=0 for no box) &cntrl imin = 5, ntb = 0, cut=9, nstlim = 0, nsnb = 0 / &debugf do_debugf = 1, dumpfrc = 1 / """ with wopen("%s-force.mdin" % self.name) as f: print >> f, force_mdin ## This line actually runs AMBER. self.leap(delcheck=True) self.callamber("sander -i %s-force.mdin -o %s-force.mdout -p %s.prmtop -c %s.inpcrd -y %s -O" % (self.name, self.name, self.name, self.name, crdin)) ParseMode = 0 Result = {} Energies = [] Forces = [] Force = [] for line in open('forcedump.dat'): line = line.strip() sline = line.split() if ParseMode == 1: if len(sline) == 1 and isfloat(sline[0]): Energies.append(float(sline[0]) * 4.184) ParseMode = 0 if ParseMode == 2: if len(sline) == 3 and all(isfloat(sline[i]) for i in range(3)): Force += [float(sline[i]) * 4.184 * 10 for i in range(3)] if len(Force) == 3*self.qmatoms: Forces.append(np.array(Force)) Force = [] ParseMode = 0 if line == '0 START of Energies': ParseMode = 1 elif line == '1 Total Force': ParseMode = 2 Result["Energy"] = np.array(Energies[1:]) Result["Force"] = np.array(Forces[1:]) return Result def energy_force_one(self, shot): """ Computes the energy and force using TINKER for one snapshot. """ self.mol[shot].write("%s.xyz" % self.name, ftype="tinker") Result = self.evaluate_("%s.xyz" % self.name, force=True) return np.hstack((Result["Energy"].reshape(-1,1), Result["Force"])) def energy(self): """ Computes the energy using TINKER over a trajectory. """ if hasattr(self, 'md_trajectory') : x = self.md_trajectory else: x = "%s-all.crd" % self.name self.mol.write(x, ftype="tinker") return self.evaluate_(x)["Energy"] def energy_force(self): """ Computes the energy and force using AMBER over a trajectory. """ if hasattr(self, 'md_trajectory') : x = self.md_trajectory else: x = "%s-all.crd" % self.name Result = self.evaluate_(x, force=True) return np.hstack((Result["Energy"].reshape(-1,1), Result["Force"])) def energy_dipole(self): """ Computes the energy and dipole using TINKER over a trajectory. """ logger.error('Dipole moments are not yet implemented in AMBER interface') raise NotImplementedError if hasattr(self, 'md_trajectory') : x = self.md_trajectory else: x = "%s.xyz" % self.name self.mol.write(x, ftype="tinker") Result = self.evaluate_(x, dipole=True) return np.hstack((Result["Energy"].reshape(-1,1), Result["Dipole"])) 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 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 multipole_moments(self, shot=0, optimize=True, polarizability=False): logger.error('Multipole moments are not yet implemented in AMBER interface') raise NotImplementedError """ Return the multipole moments of the 1st snapshot in Debye and Buckingham units. """ # This line actually runs TINKER if optimize: self.optimize(shot, crit=1e-6) o = self.calltinker("analyze %s.xyz_2 M" % (self.name)) else: self.mol[shot].write('%s.xyz' % self.name, ftype="tinker") o = self.calltinker("analyze %s.xyz M" % (self.name)) # Read the TINKER output. qn = -1 ln = 0 for line in o: s = line.split() if "Dipole X,Y,Z-Components" in line: dipole_dict = OrderedDict(zip(['x','y','z'], [float(i) for i in s[-3:]])) elif "Quadrupole Moment Tensor" in line: qn = ln quadrupole_dict = OrderedDict([('xx',float(s[-3]))]) elif qn > 0 and ln == qn + 1: quadrupole_dict['xy'] = float(s[-3]) quadrupole_dict['yy'] = float(s[-2]) elif qn > 0 and ln == qn + 2: quadrupole_dict['xz'] = float(s[-3]) quadrupole_dict['yz'] = float(s[-2]) quadrupole_dict['zz'] = float(s[-1]) ln += 1 calc_moments = OrderedDict([('dipole', dipole_dict), ('quadrupole', quadrupole_dict)]) if polarizability: if optimize: o = self.calltinker("polarize %s.xyz_2" % (self.name)) else: o = self.calltinker("polarize %s.xyz" % (self.name)) # Read the TINKER output. pn = -1 ln = 0 polarizability_dict = OrderedDict() for line in o: s = line.split() if "Total Polarizability Tensor" in line: pn = ln elif pn > 0 and ln == pn + 2: polarizability_dict['xx'] = float(s[-3]) polarizability_dict['yx'] = float(s[-2]) polarizability_dict['zx'] = float(s[-1]) elif pn > 0 and ln == pn + 3: polarizability_dict['xy'] = float(s[-3]) polarizability_dict['yy'] = float(s[-2]) polarizability_dict['zy'] = float(s[-1]) elif pn > 0 and ln == pn + 4: polarizability_dict['xz'] = float(s[-3]) polarizability_dict['yz'] = float(s[-2]) polarizability_dict['zz'] = float(s[-1]) ln += 1 calc_moments['polarizability'] = polarizability_dict os.system("rm -rf *.xyz_* *.[0-9][0-9][0-9]") return calc_moments 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 interaction_energy(self, fraga, fragb): """ Calculate the interaction energy for two fragments. """ logger.error('Interaction energy is not yet implemented in AMBER interface') raise NotImplementedError self.A = TINKER(name="A", mol=self.mol.atom_select(fraga), tinker_key="%s.key" % self.name, tinkerpath=self.tinkerpath) self.B = TINKER(name="B", mol=self.mol.atom_select(fragb), tinker_key="%s.key" % self.name, tinkerpath=self.tinkerpath) # Interaction energy needs to be in kcal/mol. return (self.energy() - self.A.energy() - self.B.energy()) / 4.184 def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, nequil=0, nsave=1000, minimize=True, anisotropic=False, threads=1, verbose=False, **kwargs): """ Method for running a molecular dynamics simulation. Required arguments: nsteps = (int) Number of total time steps timestep = (float) Time step in FEMTOSECONDS temperature = (float) Temperature control (Kelvin) pressure = (float) Pressure control (atmospheres) nequil = (int) Number of additional time steps at the beginning for equilibration nsave = (int) Step interval for saving and printing data minimize = (bool) Perform an energy minimization prior to dynamics threads = (int) Specify how many OpenMP threads to use Returns simulation data: Rhos = (array) Density in kilogram m^-3 Potentials = (array) Potential energies Kinetics = (array) Kinetic energies Volumes = (array) Box volumes Dips = (3xN array) Dipole moments EComps = (dict) Energy components """ logger.error('Molecular dynamics not yet implemented in AMBER interface') raise NotImplementedError md_defs = OrderedDict() md_opts = OrderedDict() # Print out averages only at the end. md_opts["printout"] = nsave md_opts["openmp-threads"] = threads # Langevin dynamics for temperature control. if temperature != None: md_defs["integrator"] = "stochastic" else: md_defs["integrator"] = "beeman" md_opts["thermostat"] = None # Periodic boundary conditions. if self.pbc: md_opts["vdw-correction"] = '' if temperature != None and pressure != None: md_defs["integrator"] = "beeman" md_defs["thermostat"] = "bussi" md_defs["barostat"] = "montecarlo" if anisotropic: md_opts["aniso-pressure"] = '' elif pressure != None: warn_once("Pressure is ignored because temperature is turned off.") else: if pressure != None: warn_once("Pressure is ignored because pbc is set to False.") # Use stochastic dynamics for the gas phase molecule. # If we use the regular integrators it may miss # six degrees of freedom in calculating the kinetic energy. md_opts["barostat"] = None eq_opts = deepcopy(md_opts) if self.pbc and temperature != None and pressure != None: eq_opts["integrator"] = "beeman" eq_opts["thermostat"] = "bussi" eq_opts["barostat"] = "berendsen" if minimize: if verbose: logger.info("Minimizing the energy...") self.optimize(method="bfgs", crit=1) os.system("mv %s.xyz_2 %s.xyz" % (self.name, self.name)) if verbose: logger.info("Done\n") # Run equilibration. if nequil > 0: write_key("%s-eq.key" % self.name, eq_opts, "%s.key" % self.name, md_defs) if verbose: printcool("Running equilibration dynamics", color=0) if self.pbc and pressure != None: self.calltinker("dynamic %s -k %s-eq %i %f %f 4 %f %f" % (self.name, self.name, nequil, timestep, float(nsave*timestep)/1000, temperature, pressure), print_to_screen=verbose) else: self.calltinker("dynamic %s -k %s-eq %i %f %f 2 %f" % (self.name, self.name, nequil, timestep, float(nsave*timestep)/1000, temperature), print_to_screen=verbose) os.system("rm -f %s.arc" % (self.name)) # Run production. if verbose: printcool("Running production dynamics", color=0) write_key("%s-md.key" % self.name, md_opts, "%s.key" % self.name, md_defs) if self.pbc and pressure != None: odyn = self.calltinker("dynamic %s -k %s-md %i %f %f 4 %f %f" % (self.name, self.name, nsteps, timestep, float(nsave*timestep/1000), temperature, pressure), print_to_screen=verbose) else: odyn = self.calltinker("dynamic %s -k %s-md %i %f %f 2 %f" % (self.name, self.name, nsteps, timestep, float(nsave*timestep/1000), temperature), print_to_screen=verbose) # Gather information. os.system("mv %s.arc %s-md.arc" % (self.name, self.name)) self.md_trajectory = "%s-md.arc" % self.name edyn = [] kdyn = [] temps = [] for line in odyn: s = line.split() if 'Current Potential' in line: edyn.append(float(s[2])) if 'Current Kinetic' in line: kdyn.append(float(s[2])) if len(s) > 0 and s[0] == 'Temperature' and s[2] == 'Kelvin': temps.append(float(s[1])) # Potential and kinetic energies converted to kJ/mol. edyn = np.array(edyn) * 4.184 kdyn = np.array(kdyn) * 4.184 temps = np.array(temps) if verbose: logger.info("Post-processing to get the dipole moments\n") oanl = self.calltinker("analyze %s-md.arc" % self.name, stdin="G,E,M", print_to_screen=False) # Read potential energy and dipole from file. eanl = [] dip = [] mass = 0.0 ecomp = OrderedDict() havekeys = set() first_shot = True for ln, line in enumerate(oanl): strip = line.strip() s = line.split() if 'Total System Mass' in line: mass = float(s[-1]) if 'Total Potential Energy : ' in line: eanl.append(float(s[4])) if 'Dipole X,Y,Z-Components :' in line: dip.append([float(s[i]) for i in range(-3,0)]) if first_shot: for key in eckeys: if strip.startswith(key): if key in ecomp: ecomp[key].append(float(s[-2])*4.184) else: ecomp[key] = [float(s[-2])*4.184] if key in havekeys: first_shot = False havekeys.add(key) else: for key in havekeys: if strip.startswith(key): if key in ecomp: ecomp[key].append(float(s[-2])*4.184) else: ecomp[key] = [float(s[-2])*4.184] for key in ecomp: ecomp[key] = np.array(ecomp[key]) ecomp["Potential Energy"] = edyn ecomp["Kinetic Energy"] = kdyn ecomp["Temperature"] = temps ecomp["Total Energy"] = edyn+kdyn # Energies in kilojoules per mole eanl = np.array(eanl) * 4.184 # Dipole moments in debye dip = np.array(dip) # Volume of simulation boxes in cubic nanometers # Conversion factor derived from the following: # In [22]: 1.0 * gram / mole / (1.0 * nanometer)**3 / AVOGADRO_CONSTANT_NA / (kilogram/meter**3) # Out[22]: 1.6605387831627252 conv = 1.6605387831627252 if self.pbc: vol = np.array([BuildLatticeFromLengthsAngles(*[float(j) for j in line.split()]).V \ for line in open("%s-md.arc" % self.name).readlines() \ if (len(line.split()) == 6 and isfloat(line.split()[1]) \ and all([isfloat(i) for i in line.split()[:6]]))]) / 1000 rho = conv * mass / vol else: vol = None rho = None prop_return = OrderedDict() prop_return.update({'Rhos': rho, 'Potentials': edyn, 'Kinetics': kdyn, 'Volumes': vol, 'Dips': dip, 'Ecomps': ecomp}) return prop_return
class Lipid(Target): """ Subclass of Target for lipid property matching.""" def __init__(self,options,tgt_opts,forcefield): # Initialize base class super(Lipid,self).__init__(options,tgt_opts,forcefield) # Weight of the density self.set_option(tgt_opts,'w_rho',forceprint=True) # Weight of the thermal expansion coefficient self.set_option(tgt_opts,'w_alpha',forceprint=True) # Weight of the isothermal compressibility self.set_option(tgt_opts,'w_kappa',forceprint=True) # Weight of the isobaric heat capacity self.set_option(tgt_opts,'w_cp',forceprint=True) # Weight of the dielectric constant self.set_option(tgt_opts,'w_eps0',forceprint=True) # Weight of the area per lipid self.set_option(tgt_opts,'w_al',forceprint=True) # Weight of the bilayer isothermal compressibility self.set_option(tgt_opts,'w_lkappa',forceprint=True) # Weight of the deuterium order parameter self.set_option(tgt_opts,'w_scd',forceprint=True) # Normalize the property contributions to the objective function self.set_option(tgt_opts,'w_normalize',forceprint=True) # Optionally pause on the zeroth step self.set_option(tgt_opts,'manual') # Number of time steps in the lipid "equilibration" run self.set_option(tgt_opts,'lipid_eq_steps',forceprint=True) # Number of time steps in the lipid "production" run self.set_option(tgt_opts,'lipid_md_steps',forceprint=True) # Number of time steps in the gas "equilibration" run self.set_option(tgt_opts,'gas_eq_steps',forceprint=False) # Number of time steps in the gas "production" run self.set_option(tgt_opts,'gas_md_steps',forceprint=False) # Cutoff for nonbonded interactions in the liquid if tgt_opts['nonbonded_cutoff'] is not None: self.set_option(tgt_opts,'nonbonded_cutoff') # Cutoff for vdW interactions if different from other nonbonded interactions if tgt_opts['vdw_cutoff'] is not None: self.set_option(tgt_opts,'vdw_cutoff') # Time step length (in fs) for the lipid production run self.set_option(tgt_opts,'lipid_timestep',forceprint=True) # Time interval (in ps) for writing coordinates self.set_option(tgt_opts,'lipid_interval',forceprint=True) # Time step length (in fs) for the gas production run self.set_option(tgt_opts,'gas_timestep',forceprint=True) # Time interval (in ps) for writing coordinates self.set_option(tgt_opts,'gas_interval',forceprint=True) # Minimize the energy prior to running any dynamics self.set_option(tgt_opts,'minimize_energy',forceprint=True) # Isolated dipole (debye) for analytic self-polarization correction. self.set_option(tgt_opts,'self_pol_mu0',forceprint=True) # Molecular polarizability (ang**3) for analytic self-polarization correction. self.set_option(tgt_opts,'self_pol_alpha',forceprint=True) # Set up the simulation object for self-polarization correction. self.do_self_pol = (self.self_pol_mu0 > 0.0 and self.self_pol_alpha > 0.0) # Enable anisotropic periodic box self.set_option(tgt_opts,'anisotropic_box',forceprint=True) # Whether to save trajectories (0 = never, 1 = delete after good step, 2 = keep all) self.set_option(tgt_opts,'save_traj') #======================================# # Variables which are set here # #======================================# ## LPW 2018-02-11: This is set to True if the target calculates ## a single-point property over several existing snapshots. self.loop_over_snapshots = False # List of trajectory files that may be deleted if self.save_traj == 1. self.last_traj = [] # Extra files to be copied back at the end of a run. self.extra_output = [] # Read the reference data self.read_data() # Read in lipid starting coordinates. if 'n_ic' in self.RefData: # Linked IC folder into the temp-directory. self.nptfiles += ["IC"] # Store IC frames in a dictionary. self.lipid_mols = OrderedDict() self.lipid_mols_new = OrderedDict() for pt in self.PhasePoints: pt_label = "IC/%sK-%s%s" % (pt[0], pt[1], pt[2]) if not os.path.exists(os.path.join(self.root, self.tgtdir, pt_label, self.lipid_coords)): raise RuntimeError("Initial condition files don't exist; please provide IC directory") # Create molecule object for each IC. all_ic = Molecule(os.path.join(self.root, self.tgtdir, pt_label, self.lipid_coords)) self.lipid_mols[pt] = [] n_uniq_ic = int(self.RefData['n_ic'][pt]) if n_uniq_ic > len(all_ic): raise RuntimeError("Number of frames in initial conditions .gro file is less than the number of parallel simulations requested in data.csv") # Index ICs by pressure and temperature in a dictionary. for ic in range(n_uniq_ic): self.lipid_mols[pt].append(all_ic[ic]) else: # Read in lipid starting coordinates. if not os.path.exists(os.path.join(self.root, self.tgtdir, self.lipid_coords)): logger.error("%s doesn't exist; please provide lipid_coords option\n" % self.lipid_coords) raise RuntimeError self.lipid_mol = Molecule(os.path.join(self.root, self.tgtdir, self.lipid_coords), toppbc=True) # Extra files to be linked into the temp-directory. self.nptfiles += [self.lipid_coords] # Scripts to be copied from the ForceBalance installation directory. self.scripts += ['npt_lipid.py'] # Prepare the temporary directory. self.prepare_temp_directory() # Build keyword dictionary to pass to engine. if self.do_self_pol: self.gas_engine_args.update(self.OptionDict) self.gas_engine_args.update(options) del self.gas_engine_args['name'] # Create engine object for gas molecule to do the polarization correction. self.gas_engine = self.engine_(target=self, mol=self.gas_mol, name="selfpol", **self.gas_engine_args) # Don't read indicate.log when calling meta_indicate() self.read_indicate = False self.write_indicate = False # Don't read objective.p when calling meta_get() self.read_objective = False #======================================# # UNDER DEVELOPMENT # #======================================# # Put stuff here that I'm not sure about. :) np.set_printoptions(precision=4, linewidth=100) np.seterr(under='ignore') ## Saved force field mvals for all iterations self.SavedMVal = {} ## Saved trajectories for all iterations and all temperatures self.SavedTraj = defaultdict(dict) ## Evaluated energies for all trajectories (i.e. all iterations and all temperatures), using all mvals self.MBarEnergy = defaultdict(lambda:defaultdict(dict)) def prepare_temp_directory(self): """ Prepare the temporary directory by copying in important files. """ abstempdir = os.path.join(self.root,self.tempdir) for f in self.nptfiles: LinkFile(os.path.join(self.root, self.tgtdir, f), os.path.join(abstempdir, f)) for f in self.scripts: LinkFile(os.path.join(os.path.split(__file__)[0],"data",f),os.path.join(abstempdir,f)) def read_data(self): # Read the 'data.csv' file. The file should contain guidelines. with open(os.path.join(self.tgtdir,'data.csv'),'rU') as f: R0 = list(csv.reader(f)) # All comments are erased. R1 = [[sub('#.*$','',word) for word in line] for line in R0 if len(line[0]) > 0 and line[0][0] != "#"] # All empty lines are deleted and words are converted to lowercase. R = [[wrd.lower() for wrd in line] for line in R1 if any([len(wrd) for wrd in line]) > 0] global_opts = OrderedDict() found_headings = False known_vars = ['mbar','rho','hvap','alpha','kappa','cp','eps0','cvib_intra', 'cvib_inter','cni','devib_intra','devib_inter', 'al', 'scd', 'n_ic', 'lkappa'] self.RefData = OrderedDict() for line in R: if line[0] == "global": # Global options are mainly denominators for the different observables. if isfloat(line[2]): global_opts[line[1]] = float(line[2]) elif line[2].lower() == 'false': global_opts[line[1]] = False elif line[2].lower() == 'true': global_opts[line[1]] = True elif not found_headings: found_headings = True headings = line if len(set(headings)) != len(headings): logger.error('Column headings in data.csv must be unique\n') raise RuntimeError if 'p' not in headings: logger.error('There must be a pressure column heading labeled by "p" in data.csv\n') raise RuntimeError if 't' not in headings: logger.error('There must be a temperature column heading labeled by "t" in data.csv\n') raise RuntimeError elif found_headings: try: # Temperatures are in kelvin. t = [float(val) for head, val in zip(headings,line) if head == 't'][0] # For convenience, users may input the pressure in atmosphere or bar. pval = [float(val.split()[0]) for head, val in zip(headings,line) if head == 'p'][0] punit = [val.split()[1] if len(val.split()) >= 1 else "atm" for head, val in zip(headings,line) if head == 'p'][0] unrec = set([punit]).difference(['atm','bar']) if len(unrec) > 0: logger.error('The pressure unit %s is not recognized, please use bar or atm\n' % unrec[0]) raise RuntimeError # This line actually reads the reference data and inserts it into the RefData dictionary of dictionaries. for head, val in zip(headings,line): if head == 't' or head == 'p' : continue if isfloat(val): self.RefData.setdefault(head,OrderedDict([]))[(t,pval,punit)] = float(val.strip()) elif val.lower() == 'true': self.RefData.setdefault(head,OrderedDict([]))[(t,pval,punit)] = True elif val.lower() == 'false': self.RefData.setdefault(head,OrderedDict([]))[(t,pval,punit)] = False elif head == 'scd': self.RefData.setdefault(head,OrderedDict([]))[(t,pval,punit)] = np.array(list(map(float, val.split()))) except: logger.error(line + '\n') logger.error('Encountered an error reading this line!\n') raise RuntimeError else: logger.error(line + '\n') logger.error('I did not recognize this line!\n') raise RuntimeError # Check the reference data table for validity. default_denoms = defaultdict(int) PhasePoints = None RefData_copy = copy.deepcopy(self.RefData) for head in self.RefData: if head == 'n_ic': continue if head not in known_vars+[i+"_wt" for i in known_vars]: # Only hard-coded properties may be recognized. logger.error("The column heading %s is not recognized in data.csv\n" % head) raise RuntimeError if head in known_vars: if head+"_wt" not in self.RefData: # If the phase-point weights are not specified in the reference data file, initialize them all to one. RefData_copy[head+"_wt"] = OrderedDict([(key, 1.0) for key in self.RefData[head]]) wts = np.array(list(RefData_copy[head+"_wt"].values())) dat = np.array(list(self.RefData[head].values())) # S_cd specifies an array of averages (one for each tail node). Find avg over axis 0. avg = np.average(dat, weights=wts, axis=0) if len(wts) > 1: # If there is more than one data point, then the default denominator is the # standard deviation of the experimental values. if head == 'scd': default_denoms[head+"_denom"] = np.average(np.sqrt(np.dot(wts, (dat-avg)**2)/wts.sum())) else: default_denoms[head+"_denom"] = np.sqrt(np.dot(wts, (dat-avg)**2)/wts.sum()) else: # If there is only one data point, then the denominator is just the single # data point itself. if head == 'scd': default_denoms[head+"_denom"] = np.average(np.sqrt(np.abs(dat[0]))) else: default_denoms[head+"_denom"] = np.sqrt(np.abs(dat[0])) self.PhasePoints = list(self.RefData[head].keys()) # This prints out all of the reference data. # printcool_dictionary(self.RefData[head],head) self.RefData = RefData_copy # Create labels for the directories. self.Labels = ["%.2fK-%.1f%s" % i for i in self.PhasePoints] logger.debug("global_opts:\n%s\n" % str(global_opts)) logger.debug("default_denoms:\n%s\n" % str(default_denoms)) for opt in global_opts: if "_denom" in opt: # Record entries from the global_opts dictionary so they can be retrieved from other methods. self.set_option(global_opts,opt,default=default_denoms[opt]) else: self.set_option(global_opts,opt) def check_files(self, there): there = os.path.abspath(there) havepts = 0 if all([i in os.listdir(there) for i in self.Labels]): for d in os.listdir(there): if d in self.Labels: if os.path.exists(os.path.join(there, d, 'npt_result.p')): havepts += 1 if (float(havepts)/len(self.Labels)) > 0.75: return 1 else: return 0 def npt_simulation(self, temperature, pressure, simnum): """ Submit a NPT simulation to the Work Queue. """ wq = getWorkQueue() if not os.path.exists('npt_result.p'): link_dir_contents(os.path.join(self.root,self.rundir),os.getcwd()) self.last_traj += [os.path.join(os.getcwd(), i) for i in self.extra_output] self.lipid_mol[simnum%len(self.lipid_mol)].write(self.lipid_coords, ftype='tinker' if self.engname == 'tinker' else None) cmdstr = '%s python npt_lipid.py %s %.3f %.3f' % (self.nptpfx, self.engname, temperature, pressure) if wq is None: logger.info("Running condensed phase simulation locally.\n") logger.info("You may tail -f %s/npt.out in another terminal window\n" % os.getcwd()) _exec(cmdstr, copy_stderr=True, outfnm='npt.out') else: queue_up(wq, command = cmdstr+' &> npt.out', input_files = self.nptfiles + self.scripts + ['forcebalance.p'], output_files = ['npt_result.p', 'npt.out'] + self.extra_output, tgt=self) def polarization_correction(self,mvals): d = self.gas_engine.get_multipole_moments(optimize=True)['dipole'] if not in_fd(): logger.info("The molecular dipole moment is % .3f debye\n" % np.linalg.norm(d)) # Taken from the original OpenMM interface code, this is how we calculate the conversion factor. # dd2 = ((np.linalg.norm(d)-self.self_pol_mu0)*debye)**2 # eps0 = 8.854187817620e-12 * coulomb**2 / newton / meter**2 # epol = 0.5*dd2/(self.self_pol_alpha*angstrom**3*4*np.pi*eps0)/(kilojoule_per_mole/AVOGADRO_CONSTANT_NA) # In [2]: eps0 = 8.854187817620e-12 * coulomb**2 / newton / meter**2 # In [7]: 1.0 * debye ** 2 / (1.0 * angstrom**3*4*np.pi*eps0) / (kilojoule_per_mole/AVOGADRO_CONSTANT_NA) # Out[7]: 60.240179789402056 convert = 60.240179789402056 dd2 = (np.linalg.norm(d)-self.self_pol_mu0)**2 epol = 0.5*convert*dd2/self.self_pol_alpha return epol def indicate(self): AGrad = hasattr(self, 'Gp') PrintDict = OrderedDict() def print_item(key, heading, physunit): if self.Xp[key] > 0: printcool_dictionary(self.Pp[key], title='%s %s%s\nTemperature Pressure Reference Calculated +- Stdev Delta Weight Term ' % (self.name, heading, " (%s) " % physunit if physunit else ""), bold=True, color=4, keywidth=15) bar = printcool("%s objective function: % .3f%s" % (heading, self.Xp[key], ", Derivative:" if AGrad else "")) if AGrad: self.FF.print_map(vals=self.Gp[key]) logger.info(bar) PrintDict[heading] = "% 10.5f % 8.3f % 14.5e" % (self.Xp[key], self.Wp[key], self.Xp[key]*self.Wp[key]) print_item("Rho", "Density", "kg m^-3") print_item("Alpha", "Thermal Expansion Coefficient", "10^-4 K^-1") print_item("Kappa", "Isothermal Compressibility", "10^-6 bar^-1") print_item("Cp", "Isobaric Heat Capacity", "cal mol^-1 K^-1") print_item("Eps0", "Dielectric Constant", None) print_item("Al", "Average Area per Lipid", "nm^2") print_item("Scd", "Deuterium Order Parameter", None) print_item("LKappa", "Bilayer Isothermal Compressibility", "mN/m") PrintDict['Total'] = "% 10s % 8s % 14.5e" % ("","",self.Objective) Title = "%s Condensed Phase Properties:\n %-20s %40s" % (self.name, "Property Name", "Residual x Weight = Contribution") printcool_dictionary(PrintDict,color=4,title=Title,keywidth=31) return def objective_term(self, points, expname, calc, err, grad, name="Quantity", SubAverage=False): if expname in self.RefData: exp = self.RefData[expname] Weights = self.RefData[expname+"_wt"] Denom = getattr(self,expname+"_denom") else: # If the reference data doesn't exist then return nothing. return 0.0, np.zeros(self.FF.np), np.zeros((self.FF.np,self.FF.np)), None Sum = sum(Weights.values()) for i in Weights: Weights[i] /= Sum logger.info("Weights have been renormalized to " + str(sum(Weights.values())) + "\n") # Use least-squares or hyperbolic (experimental) objective. LeastSquares = True logger.info("Physical quantity %s uses denominator = % .4f\n" % (name, Denom)) if not LeastSquares: # If using a hyperbolic functional form # we still want the contribution to the # objective function to be the same when # Delta = Denom. Denom /= 3 ** 0.5 Objective = 0.0 Gradient = np.zeros(self.FF.np) Hessian = np.zeros((self.FF.np,self.FF.np)) Objs = {} GradMap = [] avgCalc = 0.0 avgExp = 0.0 avgGrad = np.zeros(self.FF.np) for i, PT in enumerate(points): avgCalc += Weights[PT]*calc[PT] avgExp += Weights[PT]*exp[PT] avgGrad += Weights[PT]*grad[PT] for i, PT in enumerate(points): if SubAverage: G = grad[PT]-avgGrad Delta = calc[PT] - exp[PT] - avgCalc + avgExp else: G = grad[PT] Delta = calc[PT] - exp[PT] if hasattr(Delta, "__len__"): Delta = np.average(Delta) if LeastSquares: # Least-squares objective function. ThisObj = Weights[PT] * Delta ** 2 / Denom**2 Objs[PT] = ThisObj ThisGrad = 2.0 * Weights[PT] * Delta * G / Denom**2 GradMap.append(G) Objective += ThisObj Gradient += ThisGrad # Gauss-Newton approximation to the Hessian. Hessian += 2.0 * Weights[PT] * (np.outer(G, G)) / Denom**2 else: # L1-like objective function. D = Denom S = Delta**2 + D**2 ThisObj = Weights[PT] * (S**0.5-D) / Denom ThisGrad = Weights[PT] * (Delta/S**0.5) * G / Denom ThisHess = Weights[PT] * (1/S**0.5-Delta**2/S**1.5) * np.outer(G,G) / Denom Objs[PT] = ThisObj GradMap.append(G) Objective += ThisObj Gradient += ThisGrad Hessian += ThisHess GradMapPrint = [["#PhasePoint"] + self.FF.plist] for PT, g in zip(points,GradMap): GradMapPrint.append([' %8.2f %8.1f %3s' % PT] + ["% 9.3e" % i for i in g]) o = wopen('gradient_%s.dat' % name) for line in GradMapPrint: print(' '.join(line), file=o) o.close() Delta = np.array([calc[PT] - exp[PT] for PT in points]) delt = {PT : r for PT, r in zip(points,Delta)} if expname == 'scd': print_out = OrderedDict([(' %8.2f %8.1f %3s' % PT, '\n %s' % (' '.join('\t \t \t %9.6f %9.6f +- %-7.6f % 7.6f \n' % F for F in zip(exp[PT], calc[PT], flat(err[PT]), delt[PT])))) for PT in calc]) else: print_out = OrderedDict([(' %8.2f %8.1f %3s' % PT, "%9.3f %9.3f +- %-7.3f % 7.3f % 9.5f % 9.5f" % (exp[PT],calc[PT],err[PT],delt[PT],Weights[PT],Objs[PT])) for PT in calc]) return Objective, Gradient, Hessian, print_out def submit_jobs(self, mvals, AGrad=True, AHess=True): # This routine is called by Objective.stage() will run before "get". # It submits the jobs to the Work Queue and the stage() function will wait for jobs to complete. # # First dump the force field to a pickle file lp_dump((self.FF,mvals,self.OptionDict,AGrad),'forcebalance.p') # Give the user an opportunity to copy over data from a previous (perhaps failed) run. if (not self.evaluated) and self.manual: warn_press_key("Now's our chance to fill the temp directory up with data!\n(Considering using 'read' or 'continue' for better checkpointing)", timeout=7200) # If self.save_traj == 1, delete the trajectory files from a previous good optimization step. if self.evaluated and self.goodstep and self.save_traj < 2: for fn in self.last_traj: if os.path.exists(fn): os.remove(fn) self.last_traj = [] # Set up and run the NPT simulations. snum = 0 for label, pt in zip(self.Labels, self.PhasePoints): T = pt[0] P = pt[1] Punit = pt[2] if Punit == 'bar': P *= 1.0 / 1.01325 if not os.path.exists(label): os.makedirs(label) os.chdir(label) if 'n_ic' in self.RefData: n_uniq_ic = int(self.RefData['n_ic'][pt]) # Loop over parallel trajectories. for trj in range(n_uniq_ic): rel_trj = "trj_%i" % trj # Create directories for each parallel simulation. if not os.path.exists(rel_trj): os.makedirs(rel_trj) os.chdir(rel_trj) # Pull each simulation molecule from the lipid_mols dictionary. # lipid_mols is a dictionary of paths to either the initial # geometry files, or the geometries from the final frame of the # previous iteration. self.lipid_mol = self.lipid_mols[pt][trj] self.lipid_mol.write(self.lipid_coords) if not self.lipid_coords in self.nptfiles: self.nptfiles += [self.lipid_coords] self.npt_simulation(T,P,snum) os.chdir('..') else: self.npt_simulation(T,P,snum) os.chdir('..') snum += 1 def get(self, mvals, AGrad=True, AHess=True): """ Fitting of lipid bulk properties. This is the current major direction of development for ForceBalance. Basically, fitting the QM energies / forces alone does not always give us the best simulation behavior. In many cases it makes more sense to try and reproduce some experimentally known data as well. In order to reproduce experimentally known data, we need to run a simulation and compare the simulation result to experiment. The main challenge here is that the simulations are computationally intensive (i.e. they require energy and force evaluations), and furthermore the results are noisy. We need to run the simulations automatically and remotely (i.e. on clusters) and a good way to calculate the derivatives of the simulation results with respect to the parameter values. This function contains some experimentally known values of the density and enthalpy of vaporization (Hvap) of lipid water. It launches the density and Hvap calculations on the cluster, and gathers the results / derivatives. The actual calculation of results / derivatives is done in a separate file. After the results come back, they are gathered together to form an objective function. @param[in] mvals Mathematical parameter values @param[in] AGrad Switch to turn on analytic gradient @param[in] AHess Switch to turn on analytic Hessian @return Answer Contribution to the objective function """ mbar_verbose = False Answer = {} Results = {} Points = [] # These are the phase points for which data exists. BPoints = [] # These are the phase points for which we are doing MBAR for the condensed phase. tt = 0 for label, PT in zip(self.Labels, self.PhasePoints): if 'n_ic' in self.RefData: self.lipid_mols[PT] = [Molecule(last_frame) for last_frame in self.lipid_mols[PT]] n_uniq_ic = int(self.RefData['n_ic'][PT]) for ic in range(n_uniq_ic): if os.path.exists('./%s/trj_%s/npt_result.p' % (label, ic)): # Read in each each parallel simulation's data, and concatenate each property time series. ts = lp_load('./%s/trj_%s/npt_result.p' % (label, ic)) if ic == 0: ts_concat = list(ts) else: for d_arr in range(len(ts)): if isinstance(ts[d_arr], np.ndarray): # Gradients need a unique append format. if d_arr == 5: ts_concat[d_arr] = np.append(ts_concat[d_arr], ts[d_arr], axis = 1) else: ts_concat[d_arr] = np.append(ts_concat[d_arr], ts[d_arr], axis = 0) if isinstance(ts_concat[d_arr], list): ts_concat[d_arr] = [np.append(ts_concat[d_arr][i], ts[d_arr][i], axis = 1) for i in range(len(ts_concat[d_arr]))] # Write concatenated time series to a pickle file. if ic == (int(n_uniq_ic) - 1): lp_dump((ts_concat), './%s/npt_result.p' % label) if os.path.exists('./%s/npt_result.p' % label): logger.info('Reading information from ./%s/npt_result.p\n' % label) Points.append(PT) Results[tt] = lp_load('./%s/npt_result.p' % label) tt += 1 else: logger.warning('The file ./%s/npt_result.p does not exist so we cannot read it\n' % label) pass # for obs in self.RefData: # del self.RefData[obs][PT] if len(Points) == 0: logger.error('The lipid simulations have terminated with \x1b[1;91mno readable data\x1b[0m - this is a problem!\n') raise RuntimeError # Assign variable names to all the stuff in npt_result.p Rhos, Vols, Potentials, Energies, Dips, Grads, GDips, \ Rho_errs, Alpha_errs, Kappa_errs, Cp_errs, Eps0_errs, NMols, Als, Al_errs, Scds, Scd_errs, LKappa_errs = ([Results[t][i] for t in range(len(Points))] for i in range(18)) # Determine the number of molecules if len(set(NMols)) != 1: logger.error(str(NMols)) logger.error('The above list should only contain one number - the number of molecules\n') raise RuntimeError else: NMol = list(set(NMols))[0] R = np.array(list(itertools.chain(*list(Rhos)))) V = np.array(list(itertools.chain(*list(Vols)))) E = np.array(list(itertools.chain(*list(Energies)))) Dx = np.array(list(itertools.chain(*list(d[:,0] for d in Dips)))) Dy = np.array(list(itertools.chain(*list(d[:,1] for d in Dips)))) Dz = np.array(list(itertools.chain(*list(d[:,2] for d in Dips)))) G = np.hstack(tuple(Grads)) GDx = np.hstack(tuple(gd[0] for gd in GDips)) GDy = np.hstack(tuple(gd[1] for gd in GDips)) GDz = np.hstack(tuple(gd[2] for gd in GDips)) A = np.array(list(itertools.chain(*list(Als)))) S = np.array(list(itertools.chain(*list(Scds)))) Rho_calc = OrderedDict([]) Rho_grad = OrderedDict([]) Rho_std = OrderedDict([]) Alpha_calc = OrderedDict([]) Alpha_grad = OrderedDict([]) Alpha_std = OrderedDict([]) Kappa_calc = OrderedDict([]) Kappa_grad = OrderedDict([]) Kappa_std = OrderedDict([]) Cp_calc = OrderedDict([]) Cp_grad = OrderedDict([]) Cp_std = OrderedDict([]) Eps0_calc = OrderedDict([]) Eps0_grad = OrderedDict([]) Eps0_std = OrderedDict([]) Al_calc = OrderedDict([]) Al_grad = OrderedDict([]) Al_std = OrderedDict([]) LKappa_calc = OrderedDict([]) LKappa_grad = OrderedDict([]) LKappa_std = OrderedDict([]) Scd_calc = OrderedDict([]) Scd_grad = OrderedDict([]) Scd_std = OrderedDict([]) # The unit that converts atmospheres * nm**3 into kj/mol :) pvkj=0.061019351687175 # Run MBAR using the total energies. Required for estimates that use the kinetic energy. BSims = len(BPoints) Shots = len(Energies[0]) Shots_m = [len(i) for i in Energies] N_k = np.ones(BSims)*Shots # Use the value of the energy for snapshot t from simulation k at potential m U_kln = np.zeros([BSims,BSims,Shots]) for m, PT in enumerate(BPoints): T = PT[0] P = PT[1] / 1.01325 if PT[2] == 'bar' else PT[1] beta = 1. / (kb * T) for k in range(BSims): # The correct Boltzmann factors include PV. # Note that because the Boltzmann factors are computed from the conditions at simulation "m", # the pV terms must be rescaled to the pressure at simulation "m". kk = Points.index(BPoints[k]) U_kln[k, m, :] = Energies[kk] + P*Vols[kk]*pvkj U_kln[k, m, :] *= beta W1 = None if len(BPoints) > 1: logger.info("Running MBAR analysis on %i states...\n" % len(BPoints)) mbar = pymbar.MBAR(U_kln, N_k, verbose=mbar_verbose, relative_tolerance=5.0e-8) W1 = mbar.getWeights() logger.info("Done\n") elif len(BPoints) == 1: W1 = np.ones((BPoints*Shots,BPoints)) W1 /= BPoints*Shots def fill_weights(weights, phase_points, mbar_points, snapshots): """ Fill in the weight matrix with MBAR weights where MBAR was run, and equal weights otherwise. """ new_weights = np.zeros([len(phase_points)*snapshots,len(phase_points)]) for m, PT in enumerate(phase_points): if PT in mbar_points: mm = mbar_points.index(PT) for kk, PT1 in enumerate(mbar_points): k = phase_points.index(PT1) logger.debug("Will fill W2[%i:%i,%i] with W1[%i:%i,%i]\n" % (k*snapshots,k*snapshots+snapshots,m,kk*snapshots,kk*snapshots+snapshots,mm)) new_weights[k*snapshots:(k+1)*snapshots,m] = weights[kk*snapshots:(kk+1)*snapshots,mm] else: logger.debug("Will fill W2[%i:%i,%i] with equal weights\n" % (m*snapshots,(m+1)*snapshots,m)) new_weights[m*snapshots:(m+1)*snapshots,m] = 1.0/snapshots return new_weights W2 = fill_weights(W1, Points, BPoints, Shots) if self.do_self_pol: EPol = self.polarization_correction(mvals) GEPol = np.array([(f12d3p(fdwrap(self.polarization_correction, mvals, p), h = self.h, f0 = EPol)[0] if p in self.pgrad else 0.0) for p in range(self.FF.np)]) bar = printcool("Self-polarization correction to \nenthalpy of vaporization is % .3f kJ/mol%s" % (EPol, ", Derivative:" if AGrad else "")) if AGrad: self.FF.print_map(vals=GEPol) logger.info(bar) for i, PT in enumerate(Points): T = PT[0] P = PT[1] / 1.01325 if PT[2] == 'bar' else PT[1] PV = P*V*pvkj H = E + PV # The weights that we want are the last ones. W = flat(W2[:,i]) C = weight_info(W, PT, np.ones(len(Points), dtype=int)*Shots, verbose=mbar_verbose) Gbar = flat(np.dot(G,col(W))) mBeta = -1/kb/T Beta = 1/kb/T kT = kb*T # Define some things to make the analytic derivatives easier. def avg(vec): return np.dot(W,vec) def covde(vec): return flat(np.dot(G,col(W*vec))) - avg(vec)*Gbar def deprod(vec): return flat(np.dot(G,col(W*vec))) ## Density. Rho_calc[PT] = np.dot(W,R) Rho_grad[PT] = mBeta*(flat(np.dot(G,col(W*R))) - np.dot(W,R)*Gbar) ## Ignore enthalpy. ## Thermal expansion coefficient. Alpha_calc[PT] = 1e4 * (avg(H*V)-avg(H)*avg(V))/avg(V)/(kT*T) GAlpha1 = -1 * Beta * deprod(H*V) * avg(V) / avg(V)**2 GAlpha2 = +1 * Beta * avg(H*V) * deprod(V) / avg(V)**2 GAlpha3 = deprod(V)/avg(V) - Gbar GAlpha4 = Beta * covde(H) Alpha_grad[PT] = 1e4 * (GAlpha1 + GAlpha2 + GAlpha3 + GAlpha4)/(kT*T) ## Isothermal compressibility. bar_unit = 0.06022141793 * 1e6 Kappa_calc[PT] = bar_unit / kT * (avg(V**2)-avg(V)**2)/avg(V) GKappa1 = +1 * Beta**2 * avg(V**2) * deprod(V) / avg(V)**2 GKappa2 = -1 * Beta**2 * avg(V) * deprod(V**2) / avg(V)**2 GKappa3 = +1 * Beta**2 * covde(V) Kappa_grad[PT] = bar_unit*(GKappa1 + GKappa2 + GKappa3) ## Isobaric heat capacity. Cp_calc[PT] = 1000/(4.184*NMol*kT*T) * (avg(H**2) - avg(H)**2) if hasattr(self,'use_cvib_intra') and self.use_cvib_intra: logger.debug("Adding " + str(self.RefData['devib_intra'][PT]) + " to the heat capacity\n") Cp_calc[PT] += self.RefData['devib_intra'][PT] if hasattr(self,'use_cvib_inter') and self.use_cvib_inter: logger.debug("Adding " + str(self.RefData['devib_inter'][PT]) + " to the heat capacity\n") Cp_calc[PT] += self.RefData['devib_inter'][PT] 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) Cp_grad[PT] = GCp1 + GCp2 + GCp3 ## Static dielectric constant. prefactor = 30.348705333964077 D2 = avg(Dx**2)+avg(Dy**2)+avg(Dz**2)-avg(Dx)**2-avg(Dy)**2-avg(Dz)**2 Eps0_calc[PT] = 1.0 + prefactor*(D2/avg(V))/T GD2 = 2*(flat(np.dot(GDx,col(W*Dx))) - avg(Dx)*flat(np.dot(GDx,col(W)))) - Beta*(covde(Dx**2) - 2*avg(Dx)*covde(Dx)) GD2 += 2*(flat(np.dot(GDy,col(W*Dy))) - avg(Dy)*flat(np.dot(GDy,col(W)))) - Beta*(covde(Dy**2) - 2*avg(Dy)*covde(Dy)) GD2 += 2*(flat(np.dot(GDz,col(W*Dz))) - avg(Dz)*flat(np.dot(GDz,col(W)))) - Beta*(covde(Dz**2) - 2*avg(Dz)*covde(Dz)) Eps0_grad[PT] = prefactor*(GD2/avg(V) - mBeta*covde(V)*D2/avg(V)**2)/T ## Average area per lipid Al_calc[PT] = np.dot(W,A) Al_grad[PT] = mBeta*(flat(np.dot(G,col(W*A))) - np.dot(W,A)*Gbar) ## Bilayer Isothermal compressibility. A_m2 = A * 1e-18 kbT = 1.3806488e-23 * T LKappa_calc[PT] = (1e3 * 2 * kbT / 128) * (avg(A_m2) / (avg(A_m2**2)-avg(A_m2)**2)) al_avg = avg(A_m2) al_sq_avg = avg(A_m2**2) al_avg_sq = al_avg**2 al_var = al_sq_avg - al_avg_sq GLKappa1 = covde(A_m2) / al_var GLKappa2 = (al_avg / al_var**2) * (covde(A_m2**2) - (2 * al_avg * covde(A))) LKappa_grad[PT] = (1e3 * 2 * kbT / 128) * (GLKappa1 - GLKappa2) ## Deuterium order parameter Scd_calc[PT] = np.dot(W,S) # LPW: In case I did not do the conversion correctly, the line of code previously here was: # Scd_grad[PT] = mBeta * (flat(np.average(np.mat(G) * (S * W[:, np.newaxis]), axis = 1)) - np.average(np.average(S * W[:, np.newaxis], axis = 0), axis = 0) * Gbar) Scd_grad[PT] = mBeta * (flat(np.average(np.dot(G, (S * W[:, np.newaxis])), axis = 1)) - np.average(np.average(S * W[:, np.newaxis], axis = 0), axis = 0) * Gbar) ## Estimation of errors. Rho_std[PT] = np.sqrt(sum(C**2 * np.array(Rho_errs)**2)) Alpha_std[PT] = np.sqrt(sum(C**2 * np.array(Alpha_errs)**2)) * 1e4 Kappa_std[PT] = np.sqrt(sum(C**2 * np.array(Kappa_errs)**2)) * 1e6 Cp_std[PT] = np.sqrt(sum(C**2 * np.array(Cp_errs)**2)) Eps0_std[PT] = np.sqrt(sum(C**2 * np.array(Eps0_errs)**2)) Al_std[PT] = np.sqrt(sum(C**2 * np.array(Al_errs)**2)) # LPW: In case I did not do the conversion correctly, the line of code previously here was: # Scd_std[PT] = np.sqrt(sum(np.mat(C**2) * np.array(Scd_errs)**2)) Scd_std[PT] = np.sqrt(sum(np.dot(row(C**2), np.array(Scd_errs)**2))) LKappa_std[PT] = np.sqrt(sum(C**2 * np.array(LKappa_errs)**2)) * 1e6 # Get contributions to the objective function X_Rho, G_Rho, H_Rho, RhoPrint = self.objective_term(Points, 'rho', Rho_calc, Rho_std, Rho_grad, name="Density") X_Alpha, G_Alpha, H_Alpha, AlphaPrint = self.objective_term(Points, 'alpha', Alpha_calc, Alpha_std, Alpha_grad, name="Thermal Expansion") X_Kappa, G_Kappa, H_Kappa, KappaPrint = self.objective_term(Points, 'kappa', Kappa_calc, Kappa_std, Kappa_grad, name="Compressibility") X_Cp, G_Cp, H_Cp, CpPrint = self.objective_term(Points, 'cp', Cp_calc, Cp_std, Cp_grad, name="Heat Capacity") X_Eps0, G_Eps0, H_Eps0, Eps0Print = self.objective_term(Points, 'eps0', Eps0_calc, Eps0_std, Eps0_grad, name="Dielectric Constant") X_Al, G_Al, H_Al, AlPrint = self.objective_term(Points, 'al', Al_calc, Al_std, Al_grad, name="Avg Area per Lipid") X_Scd, G_Scd, H_Scd, ScdPrint = self.objective_term(Points, 'scd', Scd_calc, Scd_std, Scd_grad, name="Deuterium Order Parameter") X_LKappa, G_LKappa, H_LKappa, LKappaPrint = self.objective_term(Points, 'lkappa', LKappa_calc, LKappa_std, LKappa_grad, name="Bilayer Compressibility") Gradient = np.zeros(self.FF.np) Hessian = np.zeros((self.FF.np,self.FF.np)) if X_Rho == 0: self.w_rho = 0.0 if X_Alpha == 0: self.w_alpha = 0.0 if X_Kappa == 0: self.w_kappa = 0.0 if X_Cp == 0: self.w_cp = 0.0 if X_Eps0 == 0: self.w_eps0 = 0.0 if X_Al == 0: self.w_al = 0.0 if X_Scd == 0: self.w_scd = 0.0 if X_LKappa == 0: self.w_lkappa = 0.0 if self.w_normalize: w_tot = self.w_rho + self.w_alpha + self.w_kappa + self.w_cp + self.w_eps0 + self.w_al + self.w_scd + self.w_lkappa else: w_tot = 1.0 w_1 = self.w_rho / w_tot w_3 = self.w_alpha / w_tot w_4 = self.w_kappa / w_tot w_5 = self.w_cp / w_tot w_6 = self.w_eps0 / w_tot w_7 = self.w_al / w_tot w_8 = self.w_scd / w_tot w_9 = self.w_lkappa / w_tot Objective = w_1 * X_Rho + w_3 * X_Alpha + w_4 * X_Kappa + w_5 * X_Cp + w_6 * X_Eps0 + w_7 * X_Al + w_8 * X_Scd + w_9 * X_LKappa if AGrad: Gradient = w_1 * G_Rho + w_3 * G_Alpha + w_4 * G_Kappa + w_5 * G_Cp + w_6 * G_Eps0 + w_7 * G_Al + w_8 * G_Scd + w_9 * G_LKappa if AHess: Hessian = w_1 * H_Rho + w_3 * H_Alpha + w_4 * H_Kappa + w_5 * H_Cp + w_6 * H_Eps0 + w_7 * H_Al + w_8 * H_Scd + w_9 * H_LKappa if not in_fd(): self.Xp = {"Rho" : X_Rho, "Alpha" : X_Alpha, "Kappa" : X_Kappa, "Cp" : X_Cp, "Eps0" : X_Eps0, "Al" : X_Al, "Scd" : X_Scd, "LKappa" : X_LKappa} self.Wp = {"Rho" : w_1, "Alpha" : w_3, "Kappa" : w_4, "Cp" : w_5, "Eps0" : w_6, "Al" : w_7, "Scd" : w_8, "LKappa" : w_9} self.Pp = {"Rho" : RhoPrint, "Alpha" : AlphaPrint, "Kappa" : KappaPrint, "Cp" : CpPrint, "Eps0" : Eps0Print, "Al" : AlPrint, "Scd" : ScdPrint, "LKappa": LKappaPrint} if AGrad: self.Gp = {"Rho" : G_Rho, "Alpha" : G_Alpha, "Kappa" : G_Kappa, "Cp" : G_Cp, "Eps0" : G_Eps0, "Al" : G_Al, "Scd" : G_Scd, "LKappa" : G_LKappa} self.Objective = Objective Answer = {'X':Objective, 'G':Gradient, 'H':Hessian} return Answer
def is_backbone(dac): return dac[1:3] in [["N", "CT"], ["CT", "C"], ["C", "N"], ["CT", "N"], ["C", "CT"], ["N", "C"]] print AACodes allbac = [] allaac = [] alldac = [] aadac = {} for iAA, AA in enumerate(AACodes): print "Detecting parameters for", AA anac = build_atomname_to_atomclass(AA) anac.update(build_atomname_to_atomclass("ACE")) anac.update(build_atomname_to_atomclass("NME")) M = Molecule(os.path.join(AADirs[iAA], "all.gro")) aadac[AA] = [] for i in M.atomname: if i not in anac.keys(): print "%s not in list of atom names" % i for d in M.find_dihedrals(): if all([M.atomname[i] in anac for i in d]): dac = [anac[M.atomname[i]] for i in d] if not is_backbone(dac): for mult in range(1, 7): dstr = "#define torsion_%s_%s_%s_%s_%s_mult%i 0.0 0.0 %i" % ( AA, dac[0], dac[1], dac[2], dac[3],
#!/usr/bin/env python from forcebalance.molecule import Molecule from forcebalance.nifty import _exec import os np="" if "CORES_PER_WORKER" in os.environ and int(os.environ["CORES_PER_WORKER"]) > 1: np=" -np %i" % int(os.environ["CORES_PER_WORKER"]) _exec("touch opt.xyz") _exec("touch energy.txt") _exec("rm -f qchem.out.prev") _exec("touch qchem.out.prev") qcin = Molecule("qchem.in", ftype="qcin") qcin.edit_qcrems({'geom_opt_max_cycles':'100'}) qcin.write("qchem.in") _exec("qchem42 %s qchem.in qchem.out &> qchem.err" % np) def special_criterion(): mk = 0 mx = 0 Cnvgd = {} for ln, line in enumerate(open("qchem.out").readlines()): if "Maximum optimization cycles reached" in line: mx = 1 if "Maximum Tolerance Cnvgd?" in line: mk = ln if mk > 0 and ln > mk and ln <= mk+3: s = line.split() try:
class TINKER(Engine): """ Engine for carrying out general purpose TINKER calculations. """ def __init__(self, name="tinker", **kwargs): ## Keyword args that aren't in this list are filtered out. self.valkwd = ['tinker_key', 'tinkerpath', 'tinker_prm'] self.warn_vn = False super(TINKER,self).__init__(name=name, **kwargs) def setopts(self, **kwargs): """ Called by __init__ ; Set TINKER-specific options. """ ## The directory containing TINKER executables (e.g. dynamic) if 'tinkerpath' in kwargs: self.tinkerpath = kwargs['tinkerpath'] if not os.path.exists(os.path.join(self.tinkerpath,"dynamic")): warn_press_key("The 'dynamic' executable indicated by %s doesn't exist! (Check tinkerpath)" \ % os.path.join(self.tinkerpath,"dynamic")) else: warn_once("The 'tinkerpath' option was not specified; using default.") if which('mdrun') == '': warn_press_key("Please add TINKER executables to the PATH or specify tinkerpath.") self.tinkerpath = which('dynamic') def readsrc(self, **kwargs): """ Called by __init__ ; read files from the source directory. """ self.key = onefile(kwargs.get('tinker_key'), 'key') self.prm = onefile(kwargs.get('tinker_prm'), 'prm') if 'mol' in kwargs: self.mol = kwargs['mol'] else: crdfile = onefile(kwargs.get('coords'), 'arc', err=True) self.mol = Molecule(crdfile) def calltinker(self, command, stdin=None, print_to_screen=False, print_command=False, **kwargs): """ Call TINKER; prepend the tinkerpath to calling the TINKER program. """ csplit = command.split() # Sometimes the engine changes dirs and the key goes missing, so we link it. if "%s.key" % self.name in csplit and not os.path.exists("%s.key" % self.name): LinkFile(self.abskey, "%s.key" % self.name) prog = os.path.join(self.tinkerpath, csplit[0]) csplit[0] = prog o = _exec(' '.join(csplit), stdin=stdin, print_to_screen=print_to_screen, print_command=print_command, rbytes=1024, **kwargs) # Determine the TINKER version number. for line in o[:10]: if "Version" in line: vw = line.split()[2] if len(vw.split('.')) <= 2: vn = float(vw) else: vn = float(vw.split('.')[:2]) vn_need = 6.3 try: if vn < vn_need: if self.warn_vn: warn_press_key("ForceBalance requires TINKER %.1f - unexpected behavior with older versions!" % vn_need) self.warn_vn = True except: logger.error("Unable to determine TINKER version number!\n") raise RuntimeError for line in o[-10:]: # Catch exceptions since TINKER does not have exit status. if "TINKER is Unable to Continue" in line: for l in o: logger.error("%s\n" % l) time.sleep(1) logger.error("TINKER may have crashed! (See above output)\nThe command was: %s\nThe directory was: %s\n" % (' '.join(csplit), os.getcwd())) raise RuntimeError break for line in o: if 'D+' in line: logger.info(line+'\n') warn_press_key("TINKER returned a very large floating point number! (See above line; will give error on parse)") return o def prepare(self, pbc=False, **kwargs): """ Called by __init__ ; prepare the temp directory and figure out the topology. """ # Call TINKER but do nothing to figure out the version number. o = self.calltinker("dynamic", persist=1, print_error=False) self.rigid = False ## Attempt to set some TINKER options. tk_chk = [] tk_opts = OrderedDict([("digits", "10"), ("archive", "")]) tk_defs = OrderedDict() prmtmp = False if hasattr(self,'FF'): if not os.path.exists(self.FF.tinkerprm): # 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)) if self.FF.rigid_water: tk_opts["rattle"] = "water" self.rigid = True if self.FF.amoeba_pol == 'mutual': tk_opts['polarization'] = 'mutual' if self.FF.amoeba_eps != None: tk_opts['polar-eps'] = str(self.FF.amoeba_eps) else: tk_defs['polar-eps'] = '1e-6' elif self.FF.amoeba_pol == 'direct': tk_opts['polarization'] = 'direct' else: warn_press_key("Using TINKER without explicitly specifying AMOEBA settings. Are you sure?") self.prm = self.FF.tinkerprm prmfnm = self.FF.tinkerprm elif self.prm: prmfnm = self.prm else: prmfnm = None # Periodic boundary conditions may come from the TINKER .key file. keypbc = False minbox = 1e10 if self.key: for line in open(os.path.join(self.srcdir, self.key)).readlines(): s = line.split() if len(s) > 0 and s[0].lower() == 'a-axis': keypbc = True minbox = float(s[1]) if len(s) > 0 and s[0].lower() == 'b-axis' and float(s[1]) < minbox: minbox = float(s[1]) if len(s) > 0 and s[0].lower() == 'c-axis' and float(s[1]) < minbox: minbox = float(s[1]) if keypbc and (not pbc): warn_once("Deleting PBC options from the .key file.") tk_opts['a-axis'] = None tk_opts['b-axis'] = None tk_opts['c-axis'] = None tk_opts['alpha'] = None tk_opts['beta'] = None tk_opts['gamma'] = None if pbc: if (not keypbc) and 'boxes' not in self.mol.Data: logger.error("Periodic boundary conditions require either (1) a-axis to be in the .key file or (b) boxes to be in the coordinate file.\n") raise RuntimeError self.pbc = pbc if pbc: tk_opts['ewald'] = '' if minbox <= 10: warn_press_key("Periodic box is set to less than 10 Angstroms across") # TINKER likes to use up to 7.0 Angstrom for PME cutoffs rpme = 0.05*(float(int(minbox - 1))) if minbox <= 15 else 7.0 tk_defs['ewald-cutoff'] = "%f" % rpme # TINKER likes to use up to 9.0 Angstrom for vdW cutoffs rvdw = 0.05*(float(int(minbox - 1))) if minbox <= 19 else 9.0 tk_defs['vdw-cutoff'] = "%f" % rvdw if (minbox*0.5 - rpme) > 2.5 and (minbox*0.5 - rvdw) > 2.5: tk_defs['neighbor-list'] = '' elif (minbox*0.5 - rpme) > 2.5: tk_defs['mpole-list'] = '' else: tk_opts['ewald'] = None tk_opts['ewald-cutoff'] = None tk_opts['vdw-cutoff'] = None # This seems to have no effect on the kinetic energy. # tk_opts['remove-inertia'] = '0' write_key("%s.key" % self.name, tk_opts, os.path.join(self.srcdir, self.key) if self.key else None, tk_defs, verbose=False, prmfnm=prmfnm) self.abskey = os.path.abspath("%s.key") self.mol[0].write(os.path.join("%s.xyz" % self.name), ftype="tinker") ## If the coordinates do not come with TINKER suffixes then throw an error. self.mol.require('tinkersuf') ## Call analyze to read information needed to build the atom lists. o = self.calltinker("analyze %s.xyz P,C" % (self.name), stdin="ALL") ## Parse the output of analyze. mode = 0 self.AtomMask = [] self.AtomLists = defaultdict(list) ptype_dict = {'atom': 'A', 'vsite': 'D'} G = nx.Graph() for line in o: s = line.split() if len(s) == 0: continue if "Atom Type Definition Parameters" in line: mode = 1 if mode == 1: if isint(s[0]): mode = 2 if mode == 2: if isint(s[0]): mass = float(s[5]) self.AtomLists['Mass'].append(mass) if mass < 1.0: # Particles with mass less than one count as virtual sites. self.AtomLists['ParticleType'].append('D') else: self.AtomLists['ParticleType'].append('A') self.AtomMask.append(mass >= 1.0) else: mode = 0 if "List of 1-2 Connected Atomic Interactions" in line: mode = 3 if mode == 3: if isint(s[0]): mode = 4 if mode == 4: if isint(s[0]): a = int(s[0]) b = int(s[1]) G.add_node(a) G.add_node(b) G.add_edge(a, b) else: mode = 0 # Use networkx to figure out a list of molecule numbers. if len(G.nodes()) > 0: # The following code only works in TINKER 6.2 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)] else: grouped = [i.L() for i in self.mol.molecules] self.AtomLists['MoleculeNumber'] = [[i in g for g in grouped].index(1) for i in range(self.mol.na)] if prmtmp: for f in self.FF.fnms: os.unlink(f) def optimize(self, shot=0, method="newton", crit=1e-4): """ Optimize the geometry and align the optimized geometry to the starting geometry. """ 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 evaluate_(self, xyzin, force=False, dipole=False): """ Utility function for computing energy, and (optionally) forces and dipoles using TINKER. Inputs: xyzin: TINKER .xyz file name. force: Switch for calculating the force. dipole: Switch for calculating the dipole. Outputs: Result: Dictionary containing energies, forces and/or dipoles. """ Result = OrderedDict() # If we want the dipoles (or just energies), analyze is the way to go. if dipole or (not force): oanl = self.calltinker("analyze %s -k %s" % (xyzin, self.name), stdin="G,E,M", print_to_screen=False) # Read potential energy and dipole from file. eanl = [] dip = [] for line in oanl: s = line.split() if 'Total Potential Energy : ' in line: eanl.append(float(s[4]) * 4.184) if dipole: if 'Dipole X,Y,Z-Components :' in line: dip.append([float(s[i]) for i in range(-3,0)]) Result["Energy"] = np.array(eanl) Result["Dipole"] = np.array(dip) # If we want forces, then we need to call testgrad. if force: E = [] F = [] Fi = [] o = self.calltinker("testgrad %s -k %s y n n" % (xyzin, self.name)) i = 0 ReadFrc = 0 for line in o: s = line.split() if "Total Potential Energy" in line: E.append(float(s[4]) * 4.184) if "Cartesian Gradient Breakdown over Individual Atoms" in line: ReadFrc = 1 if ReadFrc and len(s) == 6 and all([s[0] == 'Anlyt',isint(s[1]),isfloat(s[2]),isfloat(s[3]),isfloat(s[4]),isfloat(s[5])]): ReadFrc = 2 if self.AtomMask[i]: Fi += [-1 * float(j) * 4.184 * 10 for j in s[2:5]] i += 1 if ReadFrc == 2 and len(s) < 6: ReadFrc = 0 F.append(Fi) Fi = [] i = 0 Result["Energy"] = np.array(E) Result["Force"] = np.array(F) return Result def energy_force_one(self, shot): """ Computes the energy and force using TINKER for one snapshot. """ self.mol[shot].write("%s.xyz" % self.name, ftype="tinker") Result = self.evaluate_("%s.xyz" % self.name, force=True) return np.hstack((Result["Energy"].reshape(-1,1), Result["Force"])) def energy(self): """ Computes the energy using TINKER over a trajectory. """ if hasattr(self, 'md_trajectory') : x = self.md_trajectory else: x = "%s.xyz" % self.name self.mol.write(x, ftype="tinker") return self.evaluate_(x)["Energy"] def energy_force(self): """ Computes the energy and force using TINKER over a trajectory. """ if hasattr(self, 'md_trajectory') : x = self.md_trajectory else: x = "%s.xyz" % self.name self.mol.write(x, ftype="tinker") Result = self.evaluate_(x, force=True) return np.hstack((Result["Energy"].reshape(-1,1), Result["Force"])) def energy_dipole(self): """ Computes the energy and dipole using TINKER over a trajectory. """ if hasattr(self, 'md_trajectory') : x = self.md_trajectory else: x = "%s.xyz" % self.name self.mol.write(x, ftype="tinker") Result = self.evaluate_(x, dipole=True) return np.hstack((Result["Energy"].reshape(-1,1), Result["Dipole"])) def normal_modes(self, shot=0, optimize=True): # This line actually runs TINKER 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 multipole_moments(self, shot=0, optimize=True, polarizability=False): """ Return the multipole moments of the 1st snapshot in Debye and Buckingham units. """ # This line actually runs TINKER if optimize: self.optimize(shot, crit=1e-6) o = self.calltinker("analyze %s.xyz_2 M" % (self.name)) else: self.mol[shot].write('%s.xyz' % self.name, ftype="tinker") o = self.calltinker("analyze %s.xyz M" % (self.name)) # Read the TINKER output. qn = -1 ln = 0 for line in o: s = line.split() if "Dipole X,Y,Z-Components" in line: dipole_dict = OrderedDict(zip(['x','y','z'], [float(i) for i in s[-3:]])) elif "Quadrupole Moment Tensor" in line: qn = ln quadrupole_dict = OrderedDict([('xx',float(s[-3]))]) elif qn > 0 and ln == qn + 1: quadrupole_dict['xy'] = float(s[-3]) quadrupole_dict['yy'] = float(s[-2]) elif qn > 0 and ln == qn + 2: quadrupole_dict['xz'] = float(s[-3]) quadrupole_dict['yz'] = float(s[-2]) quadrupole_dict['zz'] = float(s[-1]) ln += 1 calc_moments = OrderedDict([('dipole', dipole_dict), ('quadrupole', quadrupole_dict)]) if polarizability: if optimize: o = self.calltinker("polarize %s.xyz_2" % (self.name)) else: o = self.calltinker("polarize %s.xyz" % (self.name)) # Read the TINKER output. pn = -1 ln = 0 polarizability_dict = OrderedDict() for line in o: s = line.split() if "Molecular Polarizability Tensor" in line: pn = ln elif pn > 0 and ln == pn + 2: polarizability_dict['xx'] = float(s[-3]) polarizability_dict['yx'] = float(s[-2]) polarizability_dict['zx'] = float(s[-1]) elif pn > 0 and ln == pn + 3: polarizability_dict['xy'] = float(s[-3]) polarizability_dict['yy'] = float(s[-2]) polarizability_dict['zy'] = float(s[-1]) elif pn > 0 and ln == pn + 4: polarizability_dict['xz'] = float(s[-3]) polarizability_dict['yz'] = float(s[-2]) polarizability_dict['zz'] = float(s[-1]) ln += 1 calc_moments['polarizability'] = polarizability_dict os.system("rm -rf *.xyz_* *.[0-9][0-9][0-9]") print polarizability print calc_moments return calc_moments 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. """ 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 interaction_energy(self, fraga, fragb): """ Calculate the interaction energy for two fragments. """ self.A = TINKER(name="A", mol=self.mol.atom_select(fraga), tinker_key="%s.key" % self.name, tinkerpath=self.tinkerpath) self.B = TINKER(name="B", mol=self.mol.atom_select(fragb), tinker_key="%s.key" % self.name, tinkerpath=self.tinkerpath) # Interaction energy needs to be in kcal/mol. return (self.energy() - self.A.energy() - self.B.energy()) / 4.184 def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, nequil=0, nsave=1000, minimize=True, anisotropic=False, threads=1, verbose=False, **kwargs): """ Method for running a molecular dynamics simulation. Required arguments: nsteps = (int) Number of total time steps timestep = (float) Time step in FEMTOSECONDS temperature = (float) Temperature control (Kelvin) pressure = (float) Pressure control (atmospheres) nequil = (int) Number of additional time steps at the beginning for equilibration nsave = (int) Step interval for saving and printing data minimize = (bool) Perform an energy minimization prior to dynamics threads = (int) Specify how many OpenMP threads to use Returns simulation data: Rhos = (array) Density in kilogram m^-3 Potentials = (array) Potential energies Kinetics = (array) Kinetic energies Volumes = (array) Box volumes Dips = (3xN array) Dipole moments EComps = (dict) Energy components """ md_defs = OrderedDict() md_opts = OrderedDict() # Print out averages only at the end. md_opts["printout"] = nsave md_opts["openmp-threads"] = threads # Langevin dynamics for temperature control. if temperature != None: md_defs["integrator"] = "stochastic" else: md_defs["integrator"] = "beeman" md_opts["thermostat"] = None # Periodic boundary conditions. if self.pbc: md_opts["vdw-correction"] = '' if temperature != None and pressure != None: md_defs["integrator"] = "beeman" md_defs["thermostat"] = "bussi" md_defs["barostat"] = "montecarlo" if anisotropic: md_opts["aniso-pressure"] = '' elif pressure != None: warn_once("Pressure is ignored because temperature is turned off.") else: if pressure != None: warn_once("Pressure is ignored because pbc is set to False.") # Use stochastic dynamics for the gas phase molecule. # If we use the regular integrators it may miss # six degrees of freedom in calculating the kinetic energy. md_opts["barostat"] = None eq_opts = deepcopy(md_opts) if self.pbc and temperature != None and pressure != None: eq_opts["integrator"] = "beeman" eq_opts["thermostat"] = "bussi" eq_opts["barostat"] = "berendsen" if minimize: if verbose: logger.info("Minimizing the energy...") self.optimize(method="bfgs", crit=1) os.system("mv %s.xyz_2 %s.xyz" % (self.name, self.name)) if verbose: logger.info("Done\n") # Run equilibration. if nequil > 0: write_key("%s-eq.key" % self.name, eq_opts, "%s.key" % self.name, md_defs) if verbose: printcool("Running equilibration dynamics", color=0) if self.pbc and pressure != None: self.calltinker("dynamic %s -k %s-eq %i %f %f 4 %f %f" % (self.name, self.name, nequil, timestep, float(nsave*timestep)/1000, temperature, pressure), print_to_screen=verbose) else: self.calltinker("dynamic %s -k %s-eq %i %f %f 2 %f" % (self.name, self.name, nequil, timestep, float(nsave*timestep)/1000, temperature), print_to_screen=verbose) os.system("rm -f %s.arc" % (self.name)) # Run production. if verbose: printcool("Running production dynamics", color=0) write_key("%s-md.key" % self.name, md_opts, "%s.key" % self.name, md_defs) if self.pbc and pressure != None: odyn = self.calltinker("dynamic %s -k %s-md %i %f %f 4 %f %f" % (self.name, self.name, nsteps, timestep, float(nsave*timestep/1000), temperature, pressure), print_to_screen=verbose) else: odyn = self.calltinker("dynamic %s -k %s-md %i %f %f 2 %f" % (self.name, self.name, nsteps, timestep, float(nsave*timestep/1000), temperature), print_to_screen=verbose) # Gather information. os.system("mv %s.arc %s-md.arc" % (self.name, self.name)) self.md_trajectory = "%s-md.arc" % self.name edyn = [] kdyn = [] temps = [] for line in odyn: s = line.split() if 'Current Potential' in line: edyn.append(float(s[2])) if 'Current Kinetic' in line: kdyn.append(float(s[2])) if len(s) > 0 and s[0] == 'Temperature' and s[2] == 'Kelvin': temps.append(float(s[1])) # Potential and kinetic energies converted to kJ/mol. edyn = np.array(edyn) * 4.184 kdyn = np.array(kdyn) * 4.184 temps = np.array(temps) if verbose: logger.info("Post-processing to get the dipole moments\n") oanl = self.calltinker("analyze %s-md.arc" % self.name, stdin="G,E,M", print_to_screen=False) # Read potential energy and dipole from file. eanl = [] dip = [] mass = 0.0 ecomp = OrderedDict() havekeys = set() first_shot = True for ln, line in enumerate(oanl): strip = line.strip() s = line.split() if 'Total System Mass' in line: mass = float(s[-1]) if 'Total Potential Energy : ' in line: eanl.append(float(s[4])) if 'Dipole X,Y,Z-Components :' in line: dip.append([float(s[i]) for i in range(-3,0)]) if first_shot: for key in eckeys: if strip.startswith(key): if key in ecomp: ecomp[key].append(float(s[-2])*4.184) else: ecomp[key] = [float(s[-2])*4.184] if key in havekeys: first_shot = False havekeys.add(key) else: for key in havekeys: if strip.startswith(key): if key in ecomp: ecomp[key].append(float(s[-2])*4.184) else: ecomp[key] = [float(s[-2])*4.184] for key in ecomp: ecomp[key] = np.array(ecomp[key]) ecomp["Potential Energy"] = edyn ecomp["Kinetic Energy"] = kdyn ecomp["Temperature"] = temps ecomp["Total Energy"] = edyn+kdyn # Energies in kilojoules per mole eanl = np.array(eanl) * 4.184 # Dipole moments in debye dip = np.array(dip) # Volume of simulation boxes in cubic nanometers # Conversion factor derived from the following: # In [22]: 1.0 * gram / mole / (1.0 * nanometer)**3 / AVOGADRO_CONSTANT_NA / (kilogram/meter**3) # Out[22]: 1.6605387831627252 conv = 1.6605387831627252 if self.pbc: vol = np.array([BuildLatticeFromLengthsAngles(*[float(j) for j in line.split()]).V \ for line in open("%s-md.arc" % self.name).readlines() \ if (len(line.split()) == 6 and isfloat(line.split()[1]) \ and all([isfloat(i) for i in line.split()[:6]]))]) / 1000 rho = conv * mass / vol else: vol = None rho = None prop_return = OrderedDict() prop_return.update({'Rhos': rho, 'Potentials': edyn, 'Kinetics': kdyn, 'Volumes': vol, 'Dips': dip, 'Ecomps': ecomp}) return prop_return
def cand(dih): # Make sure two center atoms aren't out of order if (dih[1] > dih[2]): return (dih[3], dih[2], dih[1], dih[0]) # Two center atoms are equal but 1st and 4th are out of order elif dih[1] == dih[2] and dih[0] > dih[3]: return (dih[3], dih[2], dih[1], dih[0]) else: return dih hilite = set() for dnm in os.listdir("../targets"): if 'SER' not in dnm: continue if 'chi1chi2' in dnm: continue print dnm M = Molecule(os.path.join("../targets", dnm, 'all.arc')) atomtypes = [int(suf.split()[0]) for suf in M.tinkersuf] # for ia, a in enumerate(atomtypes): # print ia, acdict[a], acnames[acdict[a]] set_dclass = set() for dih in M.find_dihedrals(): dclass = cand(tuple(acdict[atomtypes[i]] for i in dih)) # Do not highlight backbone torsions. if dclass[1] in exc_mid and dclass[2] in exc_mid: continue # Do not highlight methyl hydrogens. if dclass[0] in exc_end or dclass[3] in exc_end: continue hilite.add(tdict[dclass]) tatoms[tdict[dclass]].append(dih) set_dclass.add(dclass) for d in sorted(list(set_dclass)): print d
def do_quantum(wq_port): M = Molecule('shots.gro') M.add_quantum('../settings/qchem.in') # Special hack to add TIP3P waters. if os.path.exists('waters.gro'): print("Found waters.gro, loading as external waters and adding SPC charges.") Mext = Molecule('waters.gro') Q = col([-0.82 if (i%3==0) else 0.41 for i in range(Mext.na)]) Qext = [np.hstack((xyz, Q)) for xyz in Mext.xyzs] M.qm_extchgs = Qext # End special hack. digits = len(str(len(M)-1)) formstr = '\"%%0%ii\"' % digits def read_quantum(): Result = None os.chdir('calcs') for i in range(M.ns): dnm = eval(formstr % i) print("\rNow in directory %i" % i, end=' ') if os.path.exists(dnm): os.chdir(dnm) if os.path.exists('qchem.out'): Output = Molecule('qchem.out') if os.path.exists('plot.esp'): ESP = Molecule('plot.esp') #print ESP.Data.keys() Output.qm_espxyzs = list(ESP.qm_espxyzs) Output.qm_espvals = list(ESP.qm_espvals) #Output += Molecule('plot.esp') if Result == None: Result = Output else: Result += Output else: raise Exception("The output file %s doesn't exist." % os.path.abspath('qchem.out')) os.chdir('..') else: raise Exception("The subdirectory %s doesn't exist." % os.path.abspath(dnm)) os.chdir('..') return Result def run_quantum(): ESP = create_esp_surfaces(M) work_queue.set_debug_flag('all') wq = work_queue.WorkQueue(wq_port, exclusive=False, shutdown=False) wq.specify_name('forcebalance') os.makedirs('calcs') os.chdir('calcs') for i in range(M.ns): dnm = eval(formstr % i) os.makedirs(dnm) os.chdir(dnm) M.edit_qcrems({'igdesp':len(ESP[i])}) M.write("qchem.in", select=i) ESPBohr = np.array(ESP[i]) / bohr2ang np.savetxt('ESPGrid',ESPBohr) print("Queueing up job", dnm) queue_up(wq, command = 'qchem40 qchem.in qchem.out', input_files = ["qchem.in", "ESPGrid"], output_files = ["qchem.out", "plot.esp", "efield.dat"], verbose=False) os.chdir('..') for i in range(M.ns): wq_wait(wq) os.chdir('..') if os.path.exists('calcs'): print("calcs directory exists. Reading calculation results.") Result = read_quantum() else: print("calcs directory doesn't exist. Setting up and running calculations.") run_quantum() print("Now reading calculation results.") Result = read_quantum() print("Writing results to qdata.txt.") Result.write('qdata.txt') return Result
#!/usr/bin/env python from builtins import range from forcebalance.molecule import Molecule import os, sys # Load in the Gromacs .gro file to be converted to TINKER format. M = Molecule(sys.argv[1]) # Build the line suffix for the TINKER format. tinkersuf = [] for i in range(M.na): if i%3==0: tinkersuf.append("%5i %5i %5i" % (1, i+2, i+3)) else: tinkersuf.append("%5i %5i" % (2, i-i%3+1)) M.tinkersuf = tinkersuf # Delete the periodic box. del M.Data['boxes'] # Write the TINKER output format. M.write(os.path.splitext(sys.argv[1])[0]+'.xyz', ftype='tinker')
def __init__(self,options,tgt_opts,forcefield): # Initialize base class super(Lipid,self).__init__(options,tgt_opts,forcefield) # Weight of the density self.set_option(tgt_opts,'w_rho',forceprint=True) # Weight of the thermal expansion coefficient self.set_option(tgt_opts,'w_alpha',forceprint=True) # Weight of the isothermal compressibility self.set_option(tgt_opts,'w_kappa',forceprint=True) # Weight of the isobaric heat capacity self.set_option(tgt_opts,'w_cp',forceprint=True) # Weight of the dielectric constant self.set_option(tgt_opts,'w_eps0',forceprint=True) # Weight of the area per lipid self.set_option(tgt_opts,'w_al',forceprint=True) # Weight of the bilayer isothermal compressibility self.set_option(tgt_opts,'w_lkappa',forceprint=True) # Weight of the deuterium order parameter self.set_option(tgt_opts,'w_scd',forceprint=True) # Normalize the property contributions to the objective function self.set_option(tgt_opts,'w_normalize',forceprint=True) # Optionally pause on the zeroth step self.set_option(tgt_opts,'manual') # Number of time steps in the lipid "equilibration" run self.set_option(tgt_opts,'lipid_eq_steps',forceprint=True) # Number of time steps in the lipid "production" run self.set_option(tgt_opts,'lipid_md_steps',forceprint=True) # Number of time steps in the gas "equilibration" run self.set_option(tgt_opts,'gas_eq_steps',forceprint=False) # Number of time steps in the gas "production" run self.set_option(tgt_opts,'gas_md_steps',forceprint=False) # Cutoff for nonbonded interactions in the liquid if tgt_opts['nonbonded_cutoff'] is not None: self.set_option(tgt_opts,'nonbonded_cutoff') # Cutoff for vdW interactions if different from other nonbonded interactions if tgt_opts['vdw_cutoff'] is not None: self.set_option(tgt_opts,'vdw_cutoff') # Time step length (in fs) for the lipid production run self.set_option(tgt_opts,'lipid_timestep',forceprint=True) # Time interval (in ps) for writing coordinates self.set_option(tgt_opts,'lipid_interval',forceprint=True) # Time step length (in fs) for the gas production run self.set_option(tgt_opts,'gas_timestep',forceprint=True) # Time interval (in ps) for writing coordinates self.set_option(tgt_opts,'gas_interval',forceprint=True) # Minimize the energy prior to running any dynamics self.set_option(tgt_opts,'minimize_energy',forceprint=True) # Isolated dipole (debye) for analytic self-polarization correction. self.set_option(tgt_opts,'self_pol_mu0',forceprint=True) # Molecular polarizability (ang**3) for analytic self-polarization correction. self.set_option(tgt_opts,'self_pol_alpha',forceprint=True) # Set up the simulation object for self-polarization correction. self.do_self_pol = (self.self_pol_mu0 > 0.0 and self.self_pol_alpha > 0.0) # Enable anisotropic periodic box self.set_option(tgt_opts,'anisotropic_box',forceprint=True) # Whether to save trajectories (0 = never, 1 = delete after good step, 2 = keep all) self.set_option(tgt_opts,'save_traj') #======================================# # Variables which are set here # #======================================# ## LPW 2018-02-11: This is set to True if the target calculates ## a single-point property over several existing snapshots. self.loop_over_snapshots = False # List of trajectory files that may be deleted if self.save_traj == 1. self.last_traj = [] # Extra files to be copied back at the end of a run. self.extra_output = [] # Read the reference data self.read_data() # Read in lipid starting coordinates. if 'n_ic' in self.RefData: # Linked IC folder into the temp-directory. self.nptfiles += ["IC"] # Store IC frames in a dictionary. self.lipid_mols = OrderedDict() self.lipid_mols_new = OrderedDict() for pt in self.PhasePoints: pt_label = "IC/%sK-%s%s" % (pt[0], pt[1], pt[2]) if not os.path.exists(os.path.join(self.root, self.tgtdir, pt_label, self.lipid_coords)): raise RuntimeError("Initial condition files don't exist; please provide IC directory") # Create molecule object for each IC. all_ic = Molecule(os.path.join(self.root, self.tgtdir, pt_label, self.lipid_coords)) self.lipid_mols[pt] = [] n_uniq_ic = int(self.RefData['n_ic'][pt]) if n_uniq_ic > len(all_ic): raise RuntimeError("Number of frames in initial conditions .gro file is less than the number of parallel simulations requested in data.csv") # Index ICs by pressure and temperature in a dictionary. for ic in range(n_uniq_ic): self.lipid_mols[pt].append(all_ic[ic]) else: # Read in lipid starting coordinates. if not os.path.exists(os.path.join(self.root, self.tgtdir, self.lipid_coords)): logger.error("%s doesn't exist; please provide lipid_coords option\n" % self.lipid_coords) raise RuntimeError self.lipid_mol = Molecule(os.path.join(self.root, self.tgtdir, self.lipid_coords), toppbc=True) # Extra files to be linked into the temp-directory. self.nptfiles += [self.lipid_coords] # Scripts to be copied from the ForceBalance installation directory. self.scripts += ['npt_lipid.py'] # Prepare the temporary directory. self.prepare_temp_directory() # Build keyword dictionary to pass to engine. if self.do_self_pol: self.gas_engine_args.update(self.OptionDict) self.gas_engine_args.update(options) del self.gas_engine_args['name'] # Create engine object for gas molecule to do the polarization correction. self.gas_engine = self.engine_(target=self, mol=self.gas_mol, name="selfpol", **self.gas_engine_args) # Don't read indicate.log when calling meta_indicate() self.read_indicate = False self.write_indicate = False # Don't read objective.p when calling meta_get() self.read_objective = False #======================================# # UNDER DEVELOPMENT # #======================================# # Put stuff here that I'm not sure about. :) np.set_printoptions(precision=4, linewidth=100) np.seterr(under='ignore') ## Saved force field mvals for all iterations self.SavedMVal = {} ## Saved trajectories for all iterations and all temperatures self.SavedTraj = defaultdict(dict) ## Evaluated energies for all trajectories (i.e. all iterations and all temperatures), using all mvals self.MBarEnergy = defaultdict(lambda:defaultdict(dict))
espval.append(float(s[3])) elif len(espxyz) > 0: # After reading in a block of ESPs, don't read any more. ESPMode = -1 if line.strip().startswith("Geometry (in Angstrom)"): XMode = 1 EMode = len(elem) == 0 if 'Electrostatic Potential' in line.strip() and ESPMode == 0: ESPMode = 1 if len(xyzs) == 0: raise Exception('%s has length zero' % psiout) return xyzs, elem, espxyz, espval xyzs, elem, espxyz, espval = read_psi_xyzesp(sys.argv[1]) M = Molecule() M.xyzs = xyzs M.elem = elem M.write('%s.xyz' % os.path.splitext(sys.argv[1])[0]) EM = Molecule() EM.xyzs = [np.array(espxyz) * 0.52917721092] EM.elem = ['H' for i in range(len(espxyz))] EM.write('%s.espx' % os.path.splitext(sys.argv[1])[0], ftype="xyz") M.qm_espxyzs = EM.xyzs M.qm_espvals = [np.array(espval)] M.write("qdata.txt") np.savetxt('%s.esp' % os.path.splitext(sys.argv[1])[0], espval)
def main(): topfnm = argv[3] if len(argv) >= 4 else None M = Molecule(argv[1], top=topfnm) M.write(argv[2])