Пример #1
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(.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
Пример #2
0
    def _fit(self):
        from copy import deepcopy

        # Save the initial parameters
        vector = self._paramsToVector(self.parameters, self._parameterizable_dihedral_atomtypes)
        if self.zeroed_parameters:
            vector[:] = 0

        # Evaluate the MM potential with this dihedral zeroed out
        # The objective function will try to fit to the delta between
        # the QM potential and this modified MM potential
        for key in self._parameterizable_dihedral_atomtypes:
            for term in self.parameters.dihedral_types[key]:
                term.phi_k = 0

        # Now evaluate the FF without the dihedral being fitted
        self._target_energies = []
        ff = FFEvaluate(self.molecule, self.parameters)
        for rotamer_coords, ref_energies in zip(self._coords, self._reference_energies):
            energies = ref_energies - np.array([ff.run(coords[:, :, 0])['total'] for coords in rotamer_coords])
            energies -= np.min(energies)
            self._target_energies.append(energies)
        self._all_target_energies = np.concatenate(self._target_energies)

        # Optimize the parameters
        logger.info('Start parameter optimization')
        # vector = self._optimize_CRS2_LM(vector)  # TODO this should work better, but it doesn't
        vector = self._optimize_random_search(vector)
        logger.info('Final RMSD: %f kcal/mol' % self._objective(vector, None))
        logger.info('Finished parameter optimization')

        # Update the target dihedral with the optimized parameters
        self._vectorToParams(self.parameters, self._parameterizable_dihedral_atomtypes, vector)

        return self.loss
Пример #3
0
    def _fit(self):
        from copy import deepcopy

        # Save the initial parameters
        vector = self._paramsToVector(self.parameters, self._parameterizable_dihedral_atomtypes)
        if self.zeroed_parameters:
            vector[:] = 0

        # Evaluate the MM potential with this dihedral zeroed out
        # The objective function will try to fit to the delta between
        # the QM potential and this modified MM potential
        for key in self._parameterizable_dihedral_atomtypes:
            for term in self.parameters.dihedral_types[key]:
                term.phi_k = 0

        # Now evaluate the FF without the dihedral being fitted
        self._target_energies = []
        ff = FFEvaluate(self.molecule, self.parameters)
        for rotamer_coords, ref_energies in zip(self._coords, self._reference_energies):
            energies = ref_energies - np.array([ff.calculateEnergies(coords[:, :, 0])['total'] for coords in rotamer_coords])
            energies -= np.min(energies)
            self._target_energies.append(energies)
        self._all_target_energies = np.concatenate(self._target_energies)

        # Optimize the parameters
        logger.info('Start parameter optimization')
        # vector = self._optimize_CRS2_LM(vector)  # TODO this should work better, but it doesn't
        vector = self._optimize_random_search(vector)
        logger.info('Final RMSD: %f kcal/mol' % self._objective(vector, None))
        logger.info('Finished parameter optimization')

        # Update the target dihedral with the optimized parameters
        self._vectorToParams(self.parameters, self._parameterizable_dihedral_atomtypes, vector)

        return self.loss
Пример #4
0
    def _setup(self):

        if len(self.dihedrals) != len(self.qm_results):
            raise ValueError('The number of dihedral and QM result sets has to be the same!')

        # Get dihedral names
        self._names = ['-'.join(self.molecule.name[dihedral]) for dihedral in self.dihedrals]

        # Get all equivalent dihedrals
        all_equivalent_dihedrals = detectParameterizableDihedrals(self.molecule)
        all_equivalent_dihedrals = {tuple(dihedrals[0]): dihedrals for dihedrals in all_equivalent_dihedrals}

        # Choose the selected dihedrals
        equivalent_dihedrals = []
        for dihedral, name in zip(self.dihedrals, self._names):
            if tuple(dihedral) not in all_equivalent_dihedrals:
                raise ValueError('{} is not a parameterizable dihedral!'.format(name))
            equivalent_dihedrals.append(all_equivalent_dihedrals[tuple(dihedral)])

        # Get dihedral atom types
        self._dihedral_atomtypes = [findDihedralType(tuple(self.molecule.atomtype[dihedral]), self.parameters) for dihedral in self.dihedrals]

        # Get reference QM energies and rotamer coordinates
        self._reference_energies = []
        self._coords = []
        for results in self.qm_results:
            self._reference_energies.append(np.array([result.energy for result in results]))
            self._coords.append([result.coords for result in results])

        # Calculate dihedral angle values
        # [# of scans, # of dihedrals, # of conformations, # of equivalents]
        self._angle_values = []
        for scan_coords in self._coords:
            scan_angle_values = []
            for equivalent_indices in equivalent_dihedrals:
                angle_values = []
                for coords in scan_coords:
                    angle_values.append([dihedralAngle(coords[indices, :, 0]) for indices in equivalent_indices])
                scan_angle_values.append(np.array(angle_values))
            self._angle_values.append(scan_angle_values)

        # Calculated initial MM energies
        ff = FFEvaluate(self.molecule, self.parameters)
        self._initial_energies = []
        for scan_coords in self._coords:
            energies = [ff.calculateEnergies(coords[:, :, 0])['total'] for coords in scan_coords]
            self._initial_energies.append(np.array(energies))

        # Make result directories
        os.makedirs(self.result_directory, exist_ok=True)
Пример #5
0
def printEnergies(molecule, parameters, filename):
    from htmd.ffevaluation.ffevaluate import FFEvaluate
    assert molecule.numFrames == 1
    energies = FFEvaluate(molecule, parameters).run(molecule.coords[:, :, 0])

    string = '''
== Diagnostic Energies ==

Bond     : {BOND_ENERGY}
Angle    : {ANGLE_ENERGY}
Dihedral : {DIHEDRAL_ENERGY}
Improper : {IMPROPER_ENERGY}
Electro  : {ELEC_ENERGY}
VdW      : {VDW_ENERGY}

'''.format(BOND_ENERGY=energies['bond'],
           ANGLE_ENERGY=energies['angle'],
           DIHEDRAL_ENERGY=energies['dihedral'],
           IMPROPER_ENERGY=energies['improper'],
           ELEC_ENERGY=energies['elec'],
           VDW_ENERGY=energies['vdw'])

    sys.stdout.write(string)
    with open(filename, 'w') as file_:
        file_.write(string)
Пример #6
0
def _printEnergies(molecule, parameters, filename):

    from htmd.ffevaluation.ffevaluate import FFEvaluate

    energies = FFEvaluate(molecule,
                          parameters).calculateEnergies(molecule.coords[:, :,
                                                                        0])

    string = '''
== Diagnostic Energies ==

Bond     : {BOND_ENERGY:12.6g} kcal/mol
Angle    : {ANGLE_ENERGY:12.6g} kcal/mol
Dihedral : {DIHEDRAL_ENERGY:12.6g} kcal/mol
Improper : {IMPROPER_ENERGY:12.6g} kcal/mol
Electro  : {ELEC_ENERGY:12.6g} kcal/mol
VdW      : {VDW_ENERGY:12.6g} kcal/mol

'''.format(BOND_ENERGY=energies['bond'],
           ANGLE_ENERGY=energies['angle'],
           DIHEDRAL_ENERGY=energies['dihedral'],
           IMPROPER_ENERGY=energies['improper'],
           ELEC_ENERGY=energies['elec'],
           VDW_ENERGY=energies['vdw'])

    for line in string.split('\n'):
        logger.info(line)
    with open(filename, 'w') as file_:
        file_.write(string)
    logger.info('Write energy file: {}'.format(filename))
Пример #7
0
    def _evaluateConstTermsPerDihedral(self, parameters):
        # Evaluate MM energies
        const_energies = []
        for idihed in range(self.numDihedrals):
            # Zero the current dihedral values to calculate all other "constant" terms
            modified_parameters = copy.deepcopy(parameters)
            atomtypes = self._dihedral_atomtypes[idihed]
            for term in modified_parameters.dihedral_types[atomtypes]:
                term.phi_k = 0
                assert term.per > 0 # Guard from messing up with improp
                    
            ff = FFEvaluate(self.molecule, modified_parameters)
            scan_coords = self._coords[idihed]
            energies = [ff.calculateEnergies(coords[:, :, 0])['total'] for coords in scan_coords]
            const_energies.append(np.array(energies))

        return const_energies
Пример #8
0
    def _check(self):

        # Evaluate the fitted energies
        self._fitted_energies = []
        ffeval = FFEvaluate(self.molecule, self.parameters)
        for scan_coords in self._coords:
            energies = [ffeval.calculateEnergies(coords[:, :, 0])['total'] for coords in scan_coords]
            self._fitted_energies.append(np.array(energies))

        # Check the self-consistency of fitting
        reference_energies = np.concatenate(self._reference_energies)
        reference_energies -= np.mean(reference_energies)
        fitted_energies = np.concatenate(self._fitted_energies)
        fitted_energies -= np.mean(fitted_energies)
        loss = np.sqrt(np.mean((fitted_energies - reference_energies)**2))
        # HACK: without searches, the offset is not computed. So the test will not pass!
        if self.num_iterations != 0:
            assert np.isclose(self.loss, loss, rtol=0, atol=1e-2)
Пример #9
0
    def _setup(self):

        if len(self.dihedrals) != len(self.qm_results):
            raise ValueError('The number of dihedral and QM result sets has to be the same!')

        # Get dihedral names
        self._names = ['-'.join(self.molecule.name[dihedral]) for dihedral in self.dihedrals]

        # Get equivalent dihedral atom indices
        self._equivalent_indices = []
        for idihed, dihedral in enumerate(self.dihedrals):
            found = False
            for parameterizableDihedral in self._parameterizable_dihedrals:
                if np.all(list(parameterizableDihedral[0]) == dihedral):
                    self._equivalent_indices.append(parameterizableDihedral)
                    found = True
                    break
            if not found:
                raise ValueError('%s is not recognized as a parameterizable dihedral\n' % self._names[idihed])

        # Get reference QM energies and rotamer coordinates
        self._valid_qm_results = self._getValidQMResults()
        self._reference_energies = []
        self._coords = []
        for results in self._valid_qm_results:
            self._reference_energies.append(np.array([result.energy for result in results]))
            self._coords.append([result.coords for result in results])

        # Calculate dihedral angle values for the fitted equivalent dihedral
        self._angle_values = []
        for rotamer_coords, equivalent_indices in zip(self._coords, self._equivalent_indices):
            angle_values = []
            for coords in rotamer_coords:
                angle_values.append([np.rad2deg(dihedralAngle(coords[indices, :, 0])) for indices in equivalent_indices])
            self._angle_values.append(np.array(angle_values))
        self._angle_values_rad = [np.deg2rad(angle_values)[:, :, None] for angle_values in self._angle_values]

        self._parameterizable_dihedral_atomtypes = [tuple(self.molecule.atomtype[idx]) for idx in self.dihedrals]

        # Calculated initial MM energies
        ff = FFEvaluate(self.molecule, self.parameters)
        self._initial_energies = []
        for rotamer_coords in self._coords:
            self._initial_energies.append(np.array([ff.calculateEnergies(coords[:, :, 0])['total'] for coords in rotamer_coords]))
Пример #10
0
    def _setup(self):

        if len(self.dihedrals) != len(self.qm_results):
            raise ValueError('The number of dihedral and QM result sets has to be the same!')

        # Get dihedral names
        self._names = ['-'.join(self.molecule.name[dihedral]) for dihedral in self.dihedrals]

        # Get equivalent dihedral atom indices
        self._equivalent_indices = []
        for idihed, dihedral in enumerate(self.dihedrals):
            found = False
            for parameterizableDihedral in self._parameterizable_dihedrals:
                if np.all(list(parameterizableDihedral[0]) == dihedral):
                    self._equivalent_indices.append(parameterizableDihedral)
                    found = True
                    break
            if not found:
                raise ValueError('%s is not recognized as a parameterizable dihedral\n' % self._names[idihed])

        # Get reference QM energies and rotamer coordinates
        self._valid_qm_results = self._getValidQMResults()
        self._reference_energies = []
        self._coords = []
        for results in self._valid_qm_results:
            self._reference_energies.append(np.array([result.energy for result in results]))
            self._coords.append([result.coords for result in results])

        # Calculate dihedral angle values for the fitted equivalent dihedral
        self._angle_values = []
        for rotamer_coords, equivalent_indices in zip(self._coords, self._equivalent_indices):
            angle_values = []
            for coords in rotamer_coords:
                angle_values.append([np.rad2deg(dihedralAngle(coords[indices, :, 0])) for indices in equivalent_indices])
            self._angle_values.append(np.array(angle_values))
        self._angle_values_rad = [np.deg2rad(angle_values)[:, :, None] for angle_values in self._angle_values]

        self._parameterizable_dihedral_atomtypes = [tuple(self.molecule.atomtype[idx]) for idx in self.dihedrals]

        # Calculated initial MM energies
        ff = FFEvaluate(self.molecule, self.parameters)
        self._initial_energies = []
        for rotamer_coords in self._coords:
            self._initial_energies.append(np.array([ff.run(coords[:, :, 0])['total'] for coords in rotamer_coords]))
Пример #11
0
    def _check(self):

        # Evaluate the fitted energies
        self._fitted_energies = []
        ffeval = FFEvaluate(self.molecule, self.parameters)
        for rotamer_coords in self._coords:
            self._fitted_energies.append(np.array([ffeval.calculateEnergies(coords[:, :, 0])['total'] for coords in rotamer_coords]))

        # TODO make the self-consistency test numerically robust
        #reference_energies = np.concatenate([energies - np.mean(energies) for energies in self._reference_energies])
        #fitted_energies = np.concatenate([energies - np.mean(energies) for energies in self._fitted_energies])
        #check_loss = np.sqrt(np.mean((fitted_energies - reference_energies)**2))
        #assert np.isclose(self.loss, check_loss)

        if self.result_directory:
            os.makedirs(self.result_directory, exist_ok=True)
            self.plotConformerEnergies()
            for idihed in range(len(self.dihedrals)):
                self.plotDihedralEnergies(idihed)
Пример #12
0
    def _check(self):

        # Evaluate the fitted energies
        self._fitted_energies = []
        ffeval = FFEvaluate(self.molecule, self.parameters)
        for rotamer_coords in self._coords:
            self._fitted_energies.append(np.array([ffeval.run(coords[:, :, 0])['total'] for coords in rotamer_coords]))

        # TODO make the self-consistency test numerically robust
        #reference_energies = np.concatenate([energies - np.mean(energies) for energies in self._reference_energies])
        #fitted_energies = np.concatenate([energies - np.mean(energies) for energies in self._fitted_energies])
        #check_loss = np.sqrt(np.mean((fitted_energies - reference_energies)**2))
        #assert np.isclose(self.loss, check_loss)

        if self.result_directory:
            os.makedirs(self.result_directory, exist_ok=True)
            self.plotConformerEnergies()
            for idihed in range(len(self.dihedrals)):
                self.plotDihedralEnergies(idihed)
Пример #13
0
    def _evaluateConstTerms(self):
        """
        Evalutate constant MM terms
        """

        parameters = copy.deepcopy(self.parameters)

        # Disable parameterizable (i.e. non-constant) terms
        for atomtypes in self._dihedral_atomtypes:
            for term in parameters.dihedral_types[atomtypes]:
                term.phi_k = 0
                assert term.per > 0 # Guard from messing up with improper dihedrals

        # Evaluate MM energies
        const_energies = []
        ff = FFEvaluate(self.molecule, parameters)
        for scan_coords in self._coords:
            energies = [ff.calculateEnergies(coords[:, :, 0])['total'] for coords in scan_coords]
            const_energies.append(np.array(energies))

        return const_energies
Пример #14
0
            mol.charge = chargebackup.copy()
            if len(psfFile):
                struct = parmed.charmm.CharmmPsfFile(psfFile[0])
                prm = parmed.charmm.CharmmParameterSet(*prmFiles)
                fromstruct = False
                keepForces(prm, struct, mol, forces=force)
            elif len(prmtopFile):
                struct = parmed.load_file(prmtopFile[0])
                prm = parmed.amber.AmberParameterSet().from_structure(struct)
                fromstruct = True
                keepForces(prm, struct, mol, forces=force)
                keepForcesAmber(struct, mol, forces=force)

            energies, forces, atmnrg = FFEvaluate(mol,
                                                  prm,
                                                  fromstruct=fromstruct,
                                                  cutoff=cutoff,
                                                  rfa=rfa).calculate(
                                                      mol.coords, mol.box)
            energies = FFEvaluate.formatEnergies(energies[:, 0])
            forces = forces[:, :, 0].squeeze()
            omm_energies, omm_forces = openmm_energy(prm,
                                                     struct,
                                                     coords,
                                                     box=mol.box,
                                                     cutoff=cutoff)
            ediff = compareEnergies(energies, omm_energies, abstol=abstol)
            print('  ', force, 'Energy diff:', ediff, 'Force diff:',
                  compareForces(forces, omm_forces))

        if len(psfFile):
            struct = parmed.charmm.CharmmPsfFile(psfFile[0])
Пример #15
0
        chargebackup = mol.charge.copy()
        for force in ('angle', 'bond', 'dihedral', 'lennardjones', 'electrostatic'):
            mol.charge = chargebackup.copy()
            if len(psfFile):
                struct = parmed.charmm.CharmmPsfFile(psfFile[0])
                prm = parmed.charmm.CharmmParameterSet(*prmFiles)
                keepForces(prm, struct, mol, forces=force)
            elif len(prmtopFile):
                struct = parmed.load_file(prmtopFile[0])
                prm = parmed.amber.AmberParameterSet().from_structure(struct)
                keepForces(prm, struct, mol, forces=force)
                keepForcesAmber(struct, mol, forces=force)

            energies, forces, atmnrg = FFEvaluate(mol, prm, cutoff=cutoff, rfa=rfa).calculate(mol.coords, mol.box)
            energies = FFEvaluate.formatEnergies(energies[:, 0])
            forces = forces[:, :, 0].squeeze()
            omm_energies, omm_forces = openmm_energy(prm, struct, coords, box=mol.box, cutoff=cutoff)
            ediff = compareEnergies(energies, omm_energies, abstol=abstol)
            print('  ', force, 'Energy diff:', ediff, 'Force diff:', compareForces(forces, omm_forces))

        if len(psfFile):
            struct = parmed.charmm.CharmmPsfFile(psfFile[0])
            prm = parmed.charmm.CharmmParameterSet(*prmFiles)
            keepForces(prm, struct, mol)
        elif len(prmtopFile):
            struct = parmed.load_file(prmtopFile[0])
            prm = parmed.amber.AmberParameterSet().from_structure(struct)
            keepForces(prm, struct, mol)
            keepForcesAmber(struct, mol)
        energies, forces, atmnrg = FFEvaluate(mol, prm, cutoff=cutoff, rfa=rfa).calculate(mol.coords, mol.box)