def process(self, mol, port): fragmentLabel = mol.GetTitle()+'_' +\ '_'.join(get_sd_data(mol, 'TORSION_ATOMS_ParentMol').split()) torsion_tag = 'TORSION_ATOMS_FRAGMENT' torsion_atoms_in_fragment = get_sd_data(mol, torsion_tag).split() dihedral_atom_indices = [int(x) - 1 for x in torsion_atoms_in_fragment] print(fragmentLabel, torsion_atoms_in_fragment, dihedral_atom_indices) try: dih, _ = get_dihedral(mol, dihedral_atom_indices) if self.args.best_conf: torsional_conformers = get_best_conf(mol, dih, self.args.num_points) else: torsional_conformers = gen_torsional_confs( mol, dih, self.args.num_points, include_input=False) if self.args.split_confs: for pose in split_confs(torsional_conformers): self.success.emit(pose) else: self.success.emit(torsional_conformers) self.log.info( '%d torsional conformers generated for fragment %s.' % (torsional_conformers.NumConfs(), fragmentLabel)) except Exception as e: self.log.error( "Could not generate conformers for fragment %s: %s" % (fragmentLabel, e)) self.failure.emit(mol)
def process(self, record, port): if record.has_value(self.args.in_mol_field): mol = record.get_value(self.args.in_mol_field) else: self.log.error("Could not find molecules in OEMolRecord") self.failure.emit(record) return conf = mol.GetActive() conf_title = get_sd_data(conf, "CONFORMER_LABEL") tor_atoms = get_sd_data(mol, "TORSION_ATOMS_ParentMol").split() parent_name = conf_title[:-3] dih_label = "_".join(str(x) for x in tor_atoms) conf_idx = int(conf_title[-2:]) if parent_name in self.fragment_library: if dih_label in self.fragment_library[parent_name]: self.fragment_library[parent_name][dih_label][ conf_idx ] = mol.CreateCopy() else: self.fragment_library[parent_name][dih_label] = [None] * 24 self.fragment_library[parent_name][dih_label][ conf_idx ] = mol.CreateCopy() else: self.fragment_library[parent_name] = {} self.fragment_library[parent_name][dih_label] = [None] * 24 self.fragment_library[parent_name][dih_label][conf_idx] = mol.CreateCopy()
def gen_starting_confs(mol, torsion_library, max_one_bond_away=True, num_conformers=MAX_CONFS, rms_cutoff=0.0, energy_window=25): # Identify the atoms in the dihedral TAGNAME = 'TORSION_ATOMS_FRAGMENT' if not has_sd_data(mol, TAGNAME): raise ValueError("Molecule does not have the SD Data Tag '{}'.".format(TAGNAME)) dihedralAtomIndices = [int(x)-1 for x in get_sd_data(mol, TAGNAME).split()] inDih = \ oechem.OEOrAtom(oechem.OEOrAtom(oechem.OEHasAtomIdx(dihedralAtomIndices[0]), oechem.OEHasAtomIdx(dihedralAtomIndices[1])), oechem.OEOrAtom(oechem.OEHasAtomIdx(dihedralAtomIndices[2]), oechem.OEHasAtomIdx(dihedralAtomIndices[3])) ) mol1 = mol.CreateCopy() mc_mol = oechem.OEMol(mol1) if num_conformers > 1: # Set criterion for rotatable bond if False and max_one_bond_away: # this max function makes this seem potentially broken only_one_bond_away = distance_predicate(dihedralAtomIndices[1], dihedralAtomIndices[2]) rotor_predicate = oechem.OEAndBond(only_one_bond_away, oechem.PyBondPredicate(isRotatableBond)) elif False: # this ONLY samples special bonds & neglects "regualr" torsions rotor_predicate = oechem.PyBondPredicate(isRotatableBond) else: # try this more general sampling, but leave prior versions untouched rotor_predicate = oechem.OEOrBond(oechem.OEIsRotor(), oechem.PyBondPredicate(isRotatableBond)) #Initialize conformer generator and multi-conformer library conf_generator = configure_omega(torsion_library, rotor_predicate, rms_cutoff, energy_window, num_conformers) # Generator conformers if not conf_generator(mc_mol, inDih): raise ValueError("Conformers cannot be generated.") logging.debug("Generated a total of %d conformers for %s.", mc_mol.NumConfs(), mol.GetTitle()) for conf_no, conf in enumerate(mc_mol.GetConfs()): conformer_label = mol.GetTitle()+'_' +\ '_'.join(get_sd_data(mol, 'TORSION_ATOMS_ParentMol').split()) +\ '_{:02d}'.format(conf_no) oechem.OESetSDData(conf, "CONFORMER_LABEL", conformer_label) conf.SetTitle(conformer_label) return mc_mol
def gen_torsional_confs(mol, dih, num_points, include_input=False): """Drives the primary torsion in the molecule and generates labeled torsional conformers. Inputs: mol - OEMol must have a 'CONFORMER_LABEL' in the sd_data """ angle_list = [2*i*oechem.Pi/num_points for i in range(num_points)] dih_atoms = [x for x in dih.GetAtoms()] # Create new output OEMol torsion_conformers = oechem.OEMol(mol) if not include_input: torsion_conformers.DeleteConfs() for conf_id, conf in enumerate(mol.GetConfs()): conf_name = get_sd_data(conf, 'CONFORMER_LABEL') for angle_idx, angle in enumerate(angle_list): angle_deg = int(round(angle*oechem.Rad2Deg)) oechem.OESetTorsion(conf, dih_atoms[0], dih_atoms[1], dih_atoms[2], dih_atoms[3], angle) new_conf = torsion_conformers.NewConf(conf) new_conf.SetDimension(3) new_conf_name = conf_name + '_{:02d}'.format(angle_idx) oechem.OESetSDData(new_conf, 'CONFORMER_LABEL', new_conf_name) oechem.OESetSDData(new_conf, 'TORSION_ANGLE', "{:.0f}".format(angle_deg)) new_conf.SetDoubleData('TORSION_ANGLE', angle_deg) new_conf.SetTitle('{}: Angle {:.0f}'.format(conf_name, angle_deg)) return torsion_conformers
def process(self, record, port): if record.has_value(self.args.in_mol_field): mol = record.get_value(self.args.in_mol_field) fragmentLabel = ( mol.GetTitle() + "_" + "_".join(get_sd_data(mol, "TORSION_ATOMS_ParentMol").split())) torsion_tag = "TORSION_ATOMS_FRAGMENT" torsion_atoms_in_fragment = get_sd_data(mol, torsion_tag).split() dihedral_atom_indices = [ int(x) - 1 for x in torsion_atoms_in_fragment ] try: dih, _ = get_dihedral(mol, dihedral_atom_indices) if self.args.best_conf: torsional_conformers = get_best_conf( mol, dih, self.args.num_points) else: torsional_conformers = gen_torsional_confs( mol, dih, self.args.num_points, include_input=False) if self.args.split_confs: for pose in split_confs(torsional_conformers): record = OEMolRecord() record.set_mol(pose) self.success.emit(record) else: record = OEMolRecord() record.set_mol(torsional_conformers) self.success.emit(torsional_conformers) self.log.info( "%d torsional conformers generated for fragment %s." % (torsional_conformers.NumConfs(), fragmentLabel)) except Exception as e: self.log.error( "Could not generate conformers for fragment %s: %s" % (fragmentLabel, e)) self.failure.emit(record) else: self.log.error("Could not find molecules in OEMolRecord!") self.failure.emit(record)
def process(self, record, port): if record.has_value(self.args.in_mol_field): mol = record.get_value(self.args.in_mol_field) fragmentLabel = ( mol.GetTitle() + "_" + "_".join(get_sd_data(mol, "TORSION_ATOMS_ParentMol").split())) try: starting_conformers = gen_starting_confs( mol, self.torsion_library, max_one_bond_away=True, num_conformers=self.args.max_confs, rms_cutoff=self.args.rms_cutoff, energy_window=self.args.energy_window, ) if self.args.split_output: for pose in split_confs(starting_conformers): pose_record = OEMolRecord() pose_record.set_mol(pose) self.success.emit(pose_record) else: multi_conf_record = OEMolRecord() multi_conf_record.set_mol(starting_conformers) self.success.emit(multi_conf_record) self.log.info( "%d starting conformers generated for fragment %s." % (starting_conformers.NumConfs(), fragmentLabel)) except Exception as e: self.log.error( "Could not generate conformers for fragment %s: %s" % (fragmentLabel, e)) self.failure.emit(record) else: self.log.error("Could not find molecules in OEMolRecord!") self.failure.emit(record)
def process(self, mol, port): """ The input to this cube will be an OEMol with one or more conformers with "CONFORMER_LABEL" SD Data of the form 'XY-1234567_1_2_3_4_00_00' """ num_confs = mol.NumConfs() last_conf = mol.GetActive() last_conf_name = oechem.OEGetSDData(last_conf, "CONFORMER_LABEL") self.log.info( "Processing conformer {} on {} at {:%Y-%m-%d %H:%M:%S}".format( last_conf_name, os.environ["HOSTNAME"], datetime.datetime.now())) if num_confs == self.args.num_points: self.success.emit(mol) self.log.info( "Completed scan for {} on {} at {:%Y-%m-%d %H:%M:%S}".format( mol.GetTitle(), os.environ["HOSTNAME"], datetime.datetime.now())) return if num_confs == 1 and not mol.HasData(self.conf_selection_tag): self.log.info( "Conformer {} is a fresh starting conformer on {} at {:%Y-%m-%d %H:%M:%S}" .format(mol.GetTitle(), os.environ["HOSTNAME"], datetime.datetime.now())) mol.SetIntData(self.conf_selection_tag, last_conf.GetIdx()) last_conf.SetDoubleData("TORSION_ANGLE", 0.0) oechem.OESetSDData(last_conf, "TORSION_ANGLE", "0.0") self.log.info( "Sending conformer {} to energy calculation from {} at {:%Y-%m-%d %H:%M:%S}" .format(last_conf_name, os.environ["HOSTNAME"], datetime.datetime.now())) self.to_energy_calc.emit(mol) return try: torsion_tag = "TORSION_ATOMS_FRAGMENT" torsion_atoms_in_fragment = get_sd_data(mol, torsion_tag).split() dihedral_atom_indices = [ int(x) - 1 for x in torsion_atoms_in_fragment ] dih, _ = get_dihedral(mol, dihedral_atom_indices) dih_atoms = [x for x in dih.GetAtoms()] # if the last energy calculation failed if not oechem.OEHasSDData(last_conf, "PSI4_ENERGY"): self.log.info( "Conformer {} found to have NO ENERGY on {} at {:%Y-%m-%d %H:%M:%S}" .format(last_conf_name, os.environ["HOSTNAME"], datetime.datetime.now())) mol.PopActive() last_conf = mol.GetActive() new_conf = mol.NewConf(last_conf) mol.PushActive(new_conf) conf_no = num_confs conformer_label = last_conf_name[:-3] + "_{:02d}".format(conf_no) oechem.OESetSDData(new_conf, "CONFORMER_LABEL", conformer_label) angle = num_confs * 2 * oechem.Pi / self.args.num_points angle_deg = oechem.Rad2Deg * angle new_conf.SetDoubleData("TORSION_ANGLE", angle_deg) oechem.OESetSDData(new_conf, "TORSION_ANGLE", "{:.1f}".format(angle_deg)) if not oechem.OESetTorsion(new_conf, dih_atoms[0], dih_atoms[1], dih_atoms[2], dih_atoms[3], angle): self.log.error( "Could not rotate conformer {} by {:.1f} on {} at {:%Y-%m-%d %H:%M:%S}" .format( last_conf_name, angle_deg, os.environ["HOSTNAME"], datetime.datetime.now(), )) mol.SetIntData(self.conf_selection_tag, new_conf.GetIdx()) self.log.info( "Sending conformer {} to energy calculation from {} at {:%Y-%m-%d %H:%M:%S}" .format(conformer_label, os.environ["HOSTNAME"], datetime.datetime.now())) self.to_energy_calc.emit(mol) except Exception as e: self.log.error( "COuld not drive torsion in conformer {} on {} at {:%Y-%m-%d %H:%M:%S}: {}" .format(last_conf_name, os.environ["HOSTNAME"], datetime.datetime.now(), e)) self.failure.emit(mol)
def process(self, record, port): if record.has_value(self.args.in_mol_field): mol = record.get_value(self.args.in_mol_field) else: self.log.error("Could not find molecules in OEMolRecord") self.failure.emit(record) return parent_torsion_tag = "TORSION_ATOMS_ParentMol" torsion_atoms_in_parent = get_sd_data(mol, parent_torsion_tag).split() dih_name = mol.GetTitle() + "_" + "_".join(torsion_atoms_in_parent) torsion_tag = "TORSION_ATOMS_FRAGMENT" torsion_atoms_in_fragment = get_sd_data(mol, torsion_tag).split() dihedral_atom_indices = [int(x) - 1 for x in torsion_atoms_in_fragment] if dihedral_atom_indices is None: self.log.warn("Unable to find labelled torsion in %s" % dih_name) self.failure.emit(record) return opt_basis = self.args.opt_basis spe_basis = self.args.spe_basis # If fragment contains S # use 6-31+G* instead of 6-31G* # use 6-31+G** instead of 6-31G** need_diffuse = False if oechem.OECount(mol, oechem.OEIsSulfur()) > 0: need_diffuse = True for atom in mol.GetAtoms(oechem.OEIsHeavy()): if atom.GetFormalCharge() < 0: need_diffuse = True if need_diffuse: if opt_basis == "6-31G*": self.log.warn( "Using 6-31+G* instead of 6-31G* as opt basis because fragment contains S." ) opt_basis = "6-31+G*" if spe_basis == "6-31G*": self.log.warn( "Using 6-31+G* instead of 6-31G* as spe basis because fragment contains S." ) spe_basis = "6-31+G*" if opt_basis == "6-31G**": self.log.warn( "Using 6-31+G** instead of 6-31G** as opt basis because fragment contains S." ) opt_basis = "6-31+G**" if spe_basis == "6-31G**": self.log.warn( "Using 6-31+G** instead of 6-31G** as spe basis because fragment contains S." ) spe_basis = "6-31+G**" try: if self.args.only_selected_conformer: conf_selection_tag = "SELECTED_CONFORMER" key_conf_id = mol.GetIntData(conf_selection_tag) for conf in mol.GetConfs(): if conf.GetIdx() != key_conf_id: continue conf_name = get_sd_data(conf, "CONFORMER_LABEL") else: conf_name = get_sd_data(mol, "CONFORMER_LABEL") time_stamp = "{:%Y-%m-%d %H:%M:%S}".format(datetime.datetime.now()) hostname = socket.gethostname() self.log.info("Starting psi4 calculation for %s on %s at %s" % (conf_name, hostname, time_stamp)) if self.args.only_selected_conformer: oechem.OESetSDData(conf, "%s start time" % self.name, time_stamp) else: oechem.OESetSDData(mol, "%s start time" % self.name, time_stamp) dih, _ = get_dihedral(mol, dihedral_atom_indices) calculate_energy( mol, dih, spe_method=self.args.spe_method, spe_basis=spe_basis, geom_opt_technique=self.args.geom_opt_technique, opt_method=self.args.opt_method, opt_basis=opt_basis, geom_maxiter=self.args.geom_maxiter, only_selected_conf=self.args.only_selected_conformer, molden_output=self.args.molden_output, **self.psi4opts) if self.args.only_selected_conformer: conf_selection_tag = "SELECTED_CONFORMER" key_conf_id = mol.GetIntData(conf_selection_tag) for conf in mol.GetConfs(): if conf.GetIdx() != key_conf_id: continue conf_name = get_sd_data(conf, "CONFORMER_LABEL") else: conf_name = get_sd_data(mol, "CONFORMER_LABEL") time_stamp = "{:%Y-%m-%d %H:%M:%S}".format(datetime.datetime.now()) hostname = socket.gethostname() self.log.info("Completed psi4 calculation for %s on %s at %s" % (conf_name, hostname, time_stamp)) if self.args.only_selected_conformer: oechem.OESetSDData(conf, "%s end time" % self.name, time_stamp) else: oechem.OESetSDData(mol, "%s end time" % self.name, time_stamp) optimized_mol_record = OEMolRecord() optimized_mol_record.set_mol(mol) self.success.emit(optimized_mol_record) except Exception as e: print(e) # traceback.print_stack() self.log.error("Error with {} {}".format(mol.GetTitle(), e)) self.failure.emit(record)
def construct_dihedral_energy_profile(torsion_conformers, num_points=24): angle_list = np.array([360 * i / num_points for i in range(num_points)]) num_confs = 0 profile = np.full(num_points, np.nan) for mol in torsion_conformers: if not mol: continue num_confs += 1 conf = mol.GetActive() conf_title = get_sd_data(conf, "CONFORMER_LABEL") tor_atoms = get_sd_data(mol, "TORSION_ATOMS_ParentMol").split() parent_name = conf_title[:-3] dih_label = "_".join(str(x) for x in tor_atoms) fragment_label = parent_name + "_" + dih_label angle_idx = int(conf_title[-2:]) profile[angle_idx] = np.float(get_sd_data(conf, "PSI4_ENERGY")) logging.debug("angle_idx: %d", angle_idx) logging.debug("Psi4 Energy: %f", float(get_sd_data(conf, "PSI4_ENERGY"))) # check for angles where no energies are available for angle in angle_list[np.all(np.isnan(profile))]: logging.warning( "Warning: No energies found for angle {:.1f} for fragment: {}". format(angle, fragment_label)) # calculate relative energies min_energy = np.nanmin(profile) profile -= min_energy profile[np.isnan(profile)] = -1 # set nans to -1 torsional_strain = np.column_stack((angle_list, profile)) # combine conformers output_conformers = oechem.OEMol(torsion_conformers[0]) output_conformers.DeleteConfs() title = fragment_label output_conformers.SetTitle(title) # setup normalization torsion_tag = "TORSION_ATOMS_FRAGMENT" torsion_atoms_in_fragment = get_sd_data(mol, torsion_tag).split() print(torsion_atoms_in_fragment) dihedral_atom_indices = [int(x) - 1 for x in torsion_atoms_in_fragment] dih, _ = get_dihedral(output_conformers, dihedral_atom_indices) for old_conf in torsion_conformers: if old_conf: new_conf = output_conformers.NewConf(old_conf) normalize_coordinates(new_conf, dih) oechem.OEClearSDData(new_conf) for dp in oechem.OEGetSDDataPairs(old_conf.GetActive()): if dp.GetTag() not in ["OEConfTitle", "CONFORMER_LABEL"]: oechem.OESetSDData(new_conf, dp.GetTag(), dp.GetValue()) torsion_angle = get_sd_data(old_conf, "TORSION_ANGLE") title = fragment_label + ": Angle " + torsion_angle new_conf.SetTitle(title) write_energy_profile_to_sddata(output_conformers, torsional_strain.copy()) # Calculate all possible torsion inchi keys for this fragment torsion_inchi_list = [] inchi_key = oechem.OECreateInChIKey(output_conformers) _, b, c, _ = get_torsion_oeatom_list(output_conformers) for a in b.GetAtoms(oechem.OEIsHeavy()): for d in c.GetAtoms(oechem.OEIsHeavy()): if a.GetIdx() == c.GetIdx() or d.GetIdx() == b.GetIdx(): continue torsion_inchi = inchi_key + get_modified_inchi_key( output_conformers, [a, b, c, d]) torsion_inchi_list.append(torsion_inchi) return output_conformers, torsional_strain, torsion_inchi_list
def gen_starting_confs( mol, torsion_library, max_one_bond_away=True, num_conformers=MAX_CONFS, rms_cutoff=0.0, energy_window=25, ): # Identify the atoms in the dihedral TAGNAME = "TORSION_ATOMS_FRAGMENT" if not has_sd_data(mol, TAGNAME): raise ValueError( "Molecule does not have the SD Data Tag '{}'.".format(TAGNAME)) dihedralAtomIndices = [ int(x) - 1 for x in get_sd_data(mol, TAGNAME).split() ] inDih = oechem.OEOrAtom( oechem.OEOrAtom( oechem.OEHasAtomIdx(dihedralAtomIndices[0]), oechem.OEHasAtomIdx(dihedralAtomIndices[1]), ), oechem.OEOrAtom( oechem.OEHasAtomIdx(dihedralAtomIndices[2]), oechem.OEHasAtomIdx(dihedralAtomIndices[3]), ), ) mol1 = mol.CreateCopy() mc_mol = oechem.OEMol(mol1) # Tag torsion atoms with their dihedral index for atom in mc_mol.GetAtoms(): if atom.GetIdx() == dihedralAtomIndices[0]: atom.SetData("dihidx", 0) if atom.GetIdx() == dihedralAtomIndices[1]: atom.SetData("dihidx", 1) if atom.GetIdx() == dihedralAtomIndices[2]: atom.SetData("dihidx", 2) if atom.GetIdx() == dihedralAtomIndices[3]: atom.SetData("dihidx", 3) if num_conformers > 1: # Set criterion for rotatable bond if False and max_one_bond_away: # this max function makes this seem potentially broken only_one_bond_away = distance_predicate(dihedralAtomIndices[1], dihedralAtomIndices[2]) rotor_predicate = oechem.OEAndBond( only_one_bond_away, oechem.PyBondPredicate(isRotatableBond)) elif False: # this ONLY samples special bonds & neglects "regualr" torsions rotor_predicate = oechem.PyBondPredicate(isRotatableBond) else: # try this more general sampling, but leave prior versions untouched rotor_predicate = oechem.OEOrBond( oechem.OEIsRotor(), oechem.PyBondPredicate(isRotatableBond)) # Initialize conformer generator and multi-conformer library conf_generator = configure_omega(torsion_library, rotor_predicate, rms_cutoff, energy_window, num_conformers) # Generator conformers if not conf_generator(mc_mol, inDih): raise ValueError("Conformers cannot be generated.") logging.debug( "Generated a total of %d conformers for %s.", mc_mol.NumConfs(), mol.GetTitle(), ) # Reassign new_didx = [-1, -1, -1, -1] for atom in mc_mol.GetAtoms(): if atom.HasData("dihidx"): new_didx[atom.GetData("dihidx")] = atom.GetIdx() oechem.OEClearSDData(mc_mol) oechem.OESetSDData(mc_mol, TAGNAME, " ".join(str(x + 1) for x in new_didx)) oechem.OESetSDData( mc_mol, "TORSION_ATOMS_ParentMol", get_sd_data(mol, "TORSION_ATOMS_ParentMol"), ) oechem.OESetSDData( mc_mol, "TORSION_ATOMPROP", f"cs1:0:1;1%{new_didx[0]+1}:1%{new_didx[1]+1}:1%{new_didx[2]+1}:1%{new_didx[3]+1}", ) for conf_no, conf in enumerate(mc_mol.GetConfs()): conformer_label = ( mol.GetTitle() + "_" + "_".join(get_sd_data(mol, "TORSION_ATOMS_ParentMol").split()) + "_{:02d}".format(conf_no)) oechem.OESetSDData(conf, "CONFORMER_LABEL", conformer_label) conf.SetTitle(conformer_label) return mc_mol
def calculate_energy(mol, dih, spe_method="SCF", spe_basis="6-31G", geom_opt_technique="None", opt_method="SCF", opt_basis="6-31G", geom_maxiter=100, only_selected_conf=False, molden_output=False, **psi4opts): """Calculates the energy for a single conformer at a single dihedral angle. """ # Argument validation if geom_opt_technique not in ["None", "QM", "MM"]: geom_opt_technique = "None" parent_torsion_tag = "TORSION_ATOMS_ParentMol" torsion_atoms_in_parent = get_sd_data(mol, parent_torsion_tag).split() dih_name = mol.GetTitle() + "_" + "_".join(torsion_atoms_in_parent) if only_selected_conf: conf_selection_tag = "SELECTED_CONFORMER" if not mol.HasData(conf_selection_tag): raise ValueError("Could not find 'SELECTED_CONFORMER' Tag in %s.", dih_name) key_conf_id = mol.GetIntData(conf_selection_tag) for conf in mol.GetConfs(): if only_selected_conf: if conf.GetIdx() != key_conf_id: continue conf_name = get_sd_data(conf, "CONFORMER_LABEL") if only_selected_conf: logging.debug("Only running psi4 calculation for %s" % conf_name) else: logging.debug("Running psi4 calculation for %s" % conf_name) angle_deg = conf.GetDoubleData("TORSION_ANGLE") normalize_coordinates(conf, dih) try: energy, psi_mol, wavefcn = psi4_calculation( conf, dih, conf_name, angle_deg, spe_method, spe_basis, geom_opt_technique, opt_method, opt_basis, geom_maxiter, **psi4opts) except ValueError as e: logging.error(e) raise ValueError( "Failed to run calculation for conformer %s angle %d.", conf_name, angle_deg, ) PSI4_OPT_METHOD_KEY = "PSI4_OPT_METHOD" PSI4_OPT_BASIS_KEY = "PSI4_OPT_BASIS" prev_opt_method = oechem.OEGetSDData(conf, PSI4_OPT_METHOD_KEY) if len(prev_opt_method) > 0: prev_opt_method += "_" prev_opt_basis = oechem.OEGetSDData(conf, PSI4_OPT_BASIS_KEY) if len(prev_opt_basis) > 0: prev_opt_basis += "_" complete_opt_method = prev_opt_method + str(opt_method) complete_opt_basis = prev_opt_basis + str(opt_basis) get_conf_from_psi4_mol(mol, psi_mol, conf) logging.debug("Completed psi4 calculation for %s with energy %f" % (conf_name, energy)) conf.SetEnergy(energy) oechem.OESetSDData(conf, "PSI4_ENERGY", str(energy)) conf.SetDoubleData("PSI4_ENERGY", energy) if geom_opt_technique == "QM": oechem.OESetSDData(conf, PSI4_OPT_METHOD_KEY, complete_opt_method) oechem.OESetSDData(conf, PSI4_OPT_BASIS_KEY, complete_opt_basis) oechem.OESetSDData(conf, "PSI4_SPE_METHOD", str(spe_method)) oechem.OESetSDData(conf, "PSI4_SPE_BASIS", str(spe_basis)) # write wavefuction if molden_output: wf_filename = "{}_{}.molden".format("wavefcn", conf_name) psi4.molden(wavefcn, wf_filename) try: with open(wf_filename, "r") as fptr: molden_data = fptr.read() conf.SetData("MOLDEN_DATA", molden_data) except IOError as e: print( "Unable to save wave function data ", wf_filename, " because of error: ", e, ) if psi4opts: save_sddata(mol, psi4opts)