示例#1
0
    def retrieve(self):

        prmtop = self._get_prmtop()
        system = prmtop.createSystem()
        groups = {force.getForceGroup() for force in system.getForces()}

        if self.optimize:
            if self.restrained_dihedrals is not None:
                restraint = openmm.PeriodicTorsionForce()
                restraint.setForceGroup(max(groups) + 1)

                for dihedral in self.restrained_dihedrals:
                    restraint.addTorsion(*tuple(map(int, dihedral)),
                                         periodicity=1,
                                         phase=0,
                                         k=-1000 * unit.kilocalorie_per_mole)

                system.addForce(restraint)

        simulation = app.Simulation(
            prmtop.topology,
            system,
            openmm.VerletIntegrator(1 * unit.femtosecond),
            openmm.Platform.getPlatformByName("CPU"),
        )

        results = []
        molecule_copy = self.molecule.copy()
        for iframe in range(self.molecule.numFrames):
            self.molecule.frame = iframe
            molecule_copy.frame = iframe

            directory = os.path.join(self.directory, "%05d" % iframe)
            os.makedirs(directory, exist_ok=True)
            pickleFile = os.path.join(directory, "data.pkl")

            if self._completed(directory):
                with open(pickleFile, "rb") as fd:
                    results.append(pickle.load(fd))
                logger.info("Loading QM data from %s" % pickleFile)
                continue

            simulation.context.setPositions(
                self.molecule.coords[:, :, iframe] * unit.angstrom)
            if self.optimize:
                if self.restrained_dihedrals is not None:
                    for i, dihedral in enumerate(self.restrained_dihedrals):
                        ref_angle = np.rad2deg(
                            dihedralAngle(self.molecule.coords[dihedral, :,
                                                               iframe]))
                        parameters = restraint.getTorsionParameters(i)
                        parameters[5] = ref_angle * unit.degree
                        restraint.setTorsionParameters(i, *parameters)
                    restraint.updateParametersInContext(simulation.context)
                simulation.minimizeEnergy(tolerance=0.001 *
                                          unit.kilocalorie_per_mole)
            state = simulation.context.getState(getEnergy=True,
                                                getPositions=True,
                                                groups=groups)

            result = QMResult()
            result.charge = self.charge
            result.errored = False
            result.energy = state.getPotentialEnergy().value_in_unit(
                unit.kilocalorie_per_mole)
            result.coords = (state.getPositions(asNumpy=True).value_in_unit(
                unit.angstrom).reshape((-1, 3, 1)))
            result.dipole = getDipole(self.molecule)

            if self.esp_points is not None:
                assert self.molecule.numFrames == 1
                result.esp_points = self.esp_points
                distances = cdist(result.esp_points,
                                  result.coords[:, :, 0])  # Angstrom
                distances *= (const.physical_constants["Bohr radius"][0] /
                              const.angstrom)  # Angstrom --> Bohr
                result.esp_values = np.dot(
                    np.reciprocal(distances),
                    self.molecule.charge)  # Hartree/Bohr

            results.append(result)

            with open(pickleFile, "wb") as fd:
                pickle.dump(result, fd)

            self.molecule.write(os.path.join(
                directory, "mol-init.mol2"))  # Write an optimiz
            molecule_copy.coords[:, :, iframe] = result.coords[:, :, 0]
            molecule_copy.write(os.path.join(directory,
                                             "mol.mol2"))  # Write an optimiz

        return results
示例#2
0
def _fit_charges(mol, args, qm, atom_types):

    from parameterize.charge import (
        fitGasteigerCharges,
        fitChargesWithAntechamber,
        fitESPCharges,
        symmetrizeCharges,
    )
    from parameterize.parameterization.util import (
        guessBondType,
        getFixedChargeAtomIndices,
        getDipole,
        _qm_method_name,
    )
    from parameterize.parameterization.detect import detectEquivalentAtoms

    logger.info("=== Atomic charge fitting ===")
    logger.info("Method: {}".format(args.charge_type))

    if args.charge_type == "None":

        # TODO move to argument validation
        if len(args.fix_charge) > 0:
            logger.warning("Flag --fix-charge does not have effect!")

        logger.info("Atomic charges are taken from {}".format(args.filename))

    elif args.charge_type == "Gasteiger":

        # TODO move to argument validation
        if len(args.fix_charge) > 0:
            logger.warning("Flag --fix-charge does not have effect!")

        # TODO move to _prepare_molecule
        if np.any(mol.bondtype == "un"):
            logger.info("Guessing bond types")
            mol = guessBondType(mol)

        mol = fitGasteigerCharges(mol, atom_types=atom_types)

        charge = int(round(np.sum(mol.charge)))
        if args.charge != charge:
            logger.warning(
                f"Molecular charge is {args.charge}, but Gasteiger atomic charges add up to {charge}!"
            )
            args.charge = charge

    elif args.charge_type == "AM1-BCC":

        # TODO move to argument validation
        if len(args.fix_charge) > 0:
            logger.warning("Flag --fix-charge does not have effect!")

        mol = fitChargesWithAntechamber(mol, type="bcc", molCharge=args.charge)
        mol = symmetrizeCharges(mol)

    elif args.charge_type == "ESP":

        # Detect equivalent atom groups
        logger.info("Equivalent atom groups:")
        atom_groups = [
            group for group in detectEquivalentAtoms(mol)[0] if len(group) > 1
        ]
        for atom_group in atom_groups:
            logger.info("    {}".format(", ".join(mol.name[list(atom_group)])))

        # Select the atoms with fixed charges
        fixed_atom_indices = getFixedChargeAtomIndices(mol, args.fix_charge)

        # Create an ESP directory
        espDir = os.path.join(args.outdir, "esp", _qm_method_name(qm))
        os.makedirs(espDir, exist_ok=True)

        charge = int(round(np.sum(mol.charge)))
        if args.charge != charge:
            logger.warning(
                "Molecular charge is set to {}, but atomic charges add up to {}"
                "".format(args.charge, charge))
            if len(args.fix_charge) > 0:
                raise RuntimeError(
                    "Flag --fix-charge cannot be used when atomic charges are inconsistent with passed "
                    "molecular charge {}".format(args.charge))
            mol.charge[:] = args.charge / mol.numAtoms

        # Set random number generator seed
        if args.seed:
            np.random.seed(args.seed)

        # Fit ESP charges
        mol, extra = fitESPCharges(mol, qm, espDir, fixed=fixed_atom_indices)

        # Print QM dipole
        logger.info(
            "QM dipole: {:6.3f} {:6.3f} {:6.3f}; total: {:6.3f}".format(
                *extra["qm_dipole"]))

    else:
        raise ValueError()

    # Print MM dipole
    mm_dipole = getDipole(mol)
    logger.info("MM dipole: {:6.3f} {:6.3f} {:6.3f}; total: {:6.3f}".format(
        *mm_dipole))

    # Print the new charges
    logger.info("Atomic charges:")
    for name, charge in zip(mol.name, mol.charge):
        logger.info("   {:4s}: {:6.3f}".format(name, charge))
    logger.info("Molecular charge: {:6.3f}".format(np.sum(mol.charge)))

    return mol
示例#3
0
    def retrieve(self):

        ff = FFEvaluate(self.molecule, self._parameters)

        results = []
        for iframe in range(self.molecule.numFrames):
            self.molecule.frame = iframe

            directory = os.path.join(self.directory, "%05d" % iframe)
            os.makedirs(directory, exist_ok=True)
            pickleFile = os.path.join(directory, "data.pkl")

            if self._completed(directory):
                with open(pickleFile, "rb") as fd:
                    result = pickle.load(fd)
                logger.info("Loading QM data from %s" % pickleFile)

            else:
                result = QMResult()
                result.errored = False
                result.coords = self.molecule.coords[:, :,
                                                     iframe:iframe + 1].copy()

                if self.optimize:
                    opt = nlopt.opt(nlopt.LN_COBYLA, result.coords.size)
                    opt.set_min_objective(lambda x, _: ff.calculateEnergies(
                        x.reshape((-1, 3)))["total"])
                    if self.restrained_dihedrals is not None:
                        for dihedral in self.restrained_dihedrals:
                            indices = dihedral.copy()
                            ref_angle = dihedralAngle(
                                self.molecule.coords[indices, :, iframe])

                            def constraint(x, _):
                                coords = x.reshape((-1, 3))
                                angle = dihedralAngle(coords[indices])
                                return np.sin(0.5 * (angle - ref_angle))

                            opt.add_equality_constraint(constraint)
                    opt.set_xtol_abs(1e-3)  # Similar to Psi4 default
                    opt.set_maxeval(1000 * opt.get_dimension())
                    opt.set_initial_step(1e-3)
                    result.coords = opt.optimize(
                        result.coords.ravel()).reshape((-1, 3, 1))
                    logger.info("Optimization status: %d" %
                                opt.last_optimize_result())

                result.energy = ff.calculateEnergies(result.coords[:, :,
                                                                   0])["total"]
                result.dipole = getDipole(self.molecule)

                if self.optimize:
                    assert (opt.last_optimum_value() == result.energy
                            )  # A self-consistency test

                # Compute ESP values
                if self.esp_points is not None:
                    assert self.molecule.numFrames == 1
                    result.esp_points = self.esp_points
                    distances = cdist(result.esp_points,
                                      result.coords[:, :, 0])  # Angstrom
                    distances *= (const.physical_constants["Bohr radius"][0] /
                                  const.angstrom)  # Angstrom --> Bohr
                    result.esp_values = np.dot(
                        np.reciprocal(distances),
                        self.molecule.charge)  # Hartree/Bohr

                with open(pickleFile, "wb") as fd:
                    pickle.dump(result, fd)

            results.append(result)

        return results