Beispiel #1
0
    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)
Beispiel #2
0
    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()
Beispiel #3
0
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
Beispiel #4
0
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)
Beispiel #7
0
    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)
Beispiel #8
0
    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)
Beispiel #9
0
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
Beispiel #10
0
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
Beispiel #11
0
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)