コード例 #1
0
ファイル: test_parmed_openmm.py プロジェクト: ParmEd/ParmEd
    def test_write_xml_parameters_methanol_ions_energy(self):
        """ Test writing XML parameter files from Charmm parameter files, reading them back into OpenMM ForceField, and computing energy of methanol and NaCl """

        params = openmm.OpenMMParameterSet.from_parameterset(
                pmd.charmm.CharmmParameterSet(get_fn('par_all36_cgenff.prm'),
                                              get_fn('top_all36_cgenff.rtf'),
                                              get_fn('toppar_water_ions.str')) # WARNING: contains duplicate water templates
        )
        del params.residues['TP3M'] # Delete to avoid duplicate water template topologies
        ffxml_filename = get_fn('charmm_conv.xml', written=True)
        params.write(ffxml_filename,
                     provenance=dict(
                         OriginalFile='par_all36_cgenff.prm, top_all36_cgenff.rtf, toppar_water_ions.str',
                         Reference='MacKerrell'
                     )
        )
        forcefield = app.ForceField(ffxml_filename)
        # Parameterize methanol and ions in vacuum
        pdbfile = app.PDBFile(get_fn('methanol_ions.pdb'))
        system = forcefield.createSystem(pdbfile.topology, nonbondedMethod=app.NoCutoff)
        integrator = mm.VerletIntegrator(1.0*u.femtoseconds)
        context = mm.Context(system, integrator, CPU)
        context.setPositions(pdbfile.positions)
        ffxml_potential = context.getState(getEnergy=True).getPotentialEnergy() / u.kilocalories_per_mole
        del context, integrator
        # Compute energy via ParmEd reader
        psf = CharmmPsfFile(get_fn('methanol_ions.psf'))
        system = psf.createSystem(params)
        integrator = mm.VerletIntegrator(1.0*u.femtoseconds)
        context = mm.Context(system, integrator, CPU)
        context.setPositions(pdbfile.positions)
        parmed_potential = context.getState(getEnergy=True).getPotentialEnergy() / u.kilocalories_per_mole
        del context, integrator
        # Ensure potentials are almost equal
        self.assertAlmostEqual(ffxml_potential, parmed_potential)
コード例 #2
0
    def test_write_xml_parameters_methanol_ions_energy(self):
        """ Test writing XML parameter files from Charmm parameter files, reading them back into OpenMM ForceField, and computing energy of methanol and NaCl """

        params = openmm.OpenMMParameterSet.from_parameterset(
                pmd.charmm.CharmmParameterSet(get_fn('par_all36_cgenff.prm'),
                                              get_fn('top_all36_cgenff.rtf'),
                                              get_fn('toppar_water_ions.str')) # WARNING: contains duplicate water templates
        )
        del params.residues['TP3M'] # Delete to avoid duplicate water template topologies
        ffxml_filename = get_fn('charmm_conv.xml', written=True)
        params.write(ffxml_filename,
                     provenance=dict(
                         OriginalFile='par_all36_cgenff.prm, top_all36_cgenff.rtf, toppar_water_ions.str',
                         Reference='MacKerrell'
                     )
        )
        forcefield = app.ForceField(ffxml_filename)
        # Parameterize methanol and ions in vacuum
        pdbfile = app.PDBFile(get_fn('methanol_ions.pdb'))
        system = forcefield.createSystem(pdbfile.topology, nonbondedMethod=app.NoCutoff)
        integrator = mm.VerletIntegrator(1.0*u.femtoseconds)
        context = mm.Context(system, integrator, CPU)
        context.setPositions(pdbfile.positions)
        ffxml_potential = context.getState(getEnergy=True).getPotentialEnergy() / u.kilocalories_per_mole
        del context, integrator
        # Compute energy via ParmEd reader
        psf = CharmmPsfFile(get_fn('methanol_ions.psf'))
        system = psf.createSystem(params)
        integrator = mm.VerletIntegrator(1.0*u.femtoseconds)
        context = mm.Context(system, integrator, CPU)
        context.setPositions(pdbfile.positions)
        parmed_potential = context.getState(getEnergy=True).getPotentialEnergy() / u.kilocalories_per_mole
        del context, integrator
        # Ensure potentials are almost equal
        self.assertAlmostEqual(ffxml_potential, parmed_potential)
コード例 #3
0
    def test_create_simple_system(self):
        psf = CharmmPsfFile(get_fn("ala3_solv_drude.psf"))
        crd = CharmmCrdFile(get_fn("ala3_solv_drude.crd"))

        params = CharmmParameterSet(
            get_fn("toppar_drude_master_protein_2013e.str"))

        system = psf.createSystem(params)
コード例 #4
0
for coord in coords:
    min_crds[0] = min(min_crds[0], coord[0])
    min_crds[1] = min(min_crds[1], coord[1])
    min_crds[2] = min(min_crds[2], coord[2])
    max_crds[0] = max(max_crds[0], coord[0])
    max_crds[1] = max(max_crds[1], coord[1])
    max_crds[2] = max(max_crds[2], coord[2])

psf_solvate_1 = CharmmPsfFile('../structure/butane_solvated.psf')
psf_solvate_1.box = (max_crds[0] - min_crds[0], max_crds[1] - min_crds[1],
                     max_crds[2] - min_crds[2], 90.0, 90.0, 90.0)
database['solvated']['structure_1'] = psf_solvate_1
psf_solvate_1.load_parameters(param_1, copy_parameters=False)
system_solvate_1 = psf_solvate_1.createSystem(
    nonbondedMethod=app.PME,
    constraints=app.HBonds,
    nonbondedCutoff=12.0 * u.angstroms,
    switchDistance=10.0 * u.angstroms)
database['solvated']['system_1'] = system_solvate_1

psf_solvate_2 = CharmmPsfFile('../structure/butane_solvated.psf')
psf_solvate_2.box = (max_crds[0] - min_crds[0], max_crds[1] - min_crds[1],
                     max_crds[2] - min_crds[2], 90.0, 90.0, 90.0)
database['solvated']['structure_2'] = psf_solvate_2
psf_solvate_2.load_parameters(param_2, copy_parameters=False)
system_solvate_2 = psf_solvate_2.createSystem(
    nonbondedMethod=app.PME,
    constraints=app.HBonds,
    nonbondedCutoff=12.0 * u.angstroms,
    switchDistance=10.0 * u.angstroms)
database['solvated']['system_2'] = system_solvate_2
コード例 #5
0
def compare_energies(system_name,
                     pdb_filename,
                     psf_filename,
                     ffxml_filenames,
                     toppar_filenames,
                     box_vectors_filename=None,
                     system_kwargs=None,
                     tolerance=1e-5,
                     units=u.kilojoules_per_mole,
                     write_serialized_xml=False):
    """
    Compare energies between (pdb, psf, toppar) loaded via ParmEd and (pdb, ffxml) loaded by OpenMM ForceField

    Parameters
    ----------
    system_name : str
        Name of the test system
    pdb_filename : str
        Name of PDB file that should contain CRYST entry and PDB format compliant CONECT records for HETATM residues.
    psf_filename : str
        CHARMM PSF file
    ffxml_filenames : list of str
        List of OpenMM ffxml files
    toppar_filenames : list of CHARMM toppar filenames to load into CharmmParameterSet
        List of CHARMM toppar files
    box_vectors_filename : str, optional, default=None
        If specified, read box vectors from a file like step2.1_waterbox.prm
    system_kwargs : dict, optional, default=None
        Keyword arguments to pass to CharmmPsfFile.createSystem() and ForceField.CreateSystem() when constructing System objects for energy comparison
    tolerance : float, optional, default=1e-5
        Relative energy discrepancy tolerance
    units : simtk.unit.Unit
        Unit to use for energy comparison
    write_serialized_xml : bool, optional, default=False
        If True, will write out serialized System XML files for OpenMM systems to aid debugging.

    """

    is_periodic = False
    if (system_kwargs is not None) and ('nonbondedMethod'
                                        in system_kwargs) and (
                                            system_kwargs['nonbondedMethod']
                                            in [app.CutoffPeriodic, app.PME]):
        is_periodic = True

    # Load PDB file
    pdbfile = app.PDBFile(pdb_filename)

    # Read box vectors
    if box_vectors_filename:
        box_vectors = read_box_vectors(box_vectors_filename)
        pdbfile.topology.setPeriodicBoxVectors(box_vectors)
    else:
        box_vectors = pdbfile.topology.getPeriodicBoxVectors()

    # Load CHARMM system through OpenMM
    openmm_toppar = app.CharmmParameterSet(*toppar_filenames)
    openmm_psf = app.CharmmPsfFile(psf_filename)
    # Set box vectors
    if is_periodic:
        openmm_psf.setBox(box_vectors[0][0], box_vectors[1][1],
                          box_vectors[2][2])
    openmm_system = openmm_psf.createSystem(openmm_toppar, **system_kwargs)
    openmm_structure = openmm.load_topology(openmm_psf.topology,
                                            openmm_system,
                                            xyz=pdbfile.positions)
    #openmm_energies = openmm.energy_decomposition_system(openmm_structure, openmm_system, nrg=units)
    #print('OpenMM CHARMM loader energy components : %s' % str(openmm_energies))
    openmm_total_energy = compute_potential(openmm_system,
                                            pdbfile.positions) / units

    # Load CHARMM system through ParmEd
    parmed_toppar = CharmmParameterSet(*toppar_filenames)
    parmed_structure = CharmmPsfFile(psf_filename)
    #structure.load_parameters(toppar)
    parmed_structure.positions = pdbfile.positions
    # Set box vectors
    if is_periodic:
        parmed_structure.box = (box_vectors[0][0] / u.angstroms,
                                box_vectors[1][1] / u.angstroms,
                                box_vectors[2][2] / u.angstroms, 90, 90, 90)
    parmed_system = parmed_structure.createSystem(parmed_toppar,
                                                  **system_kwargs)
    #parmed_energies = openmm.energy_decomposition_system(parmed_structure, parmed_system, nrg=units)
    #print('ParmEd CHARMM loader energy components : %s' % str(parmed_energies))
    parmed_total_energy = compute_potential(parmed_system,
                                            pdbfile.positions) / units

    # Delete H-H bonds from waters and retreive updated topology and positions
    modeller = app.Modeller(openmm_psf.topology, pdbfile.positions)
    hhbonds = [
        b for b in modeller.topology.bonds()
        if b[0].element == app.element.hydrogen
        and b[1].element == app.element.hydrogen
    ]
    modeller.delete(hhbonds)
    ffxml_topology = modeller.topology

    # OpenMM system with ffxml
    ff = app.ForceField(*ffxml_filenames)
    ffxml_system = ff.createSystem(ffxml_topology, **system_kwargs)
    ffxml_structure = openmm.load_topology(ffxml_topology,
                                           ffxml_system,
                                           xyz=pdbfile.positions)
    #ffxml_energies = openmm.energy_decomposition_system(ffxml_structure, ffxml_system, nrg=units)
    #print('ffxml energy components : %s' % str(ffxml_energies))
    ffxml_total_energy = compute_potential(ffxml_system,
                                           pdbfile.positions) / units

    write_serialized_xml = True  # DEBUG
    if write_serialized_xml:
        print('Writing serialized XML files...')
        write_serialized_system(system_name + '.charmm.system.xml',
                                openmm_system)
        write_serialized_system(system_name + '.parmed.system.xml',
                                parmed_system)
        write_serialized_system(system_name + '.openmm.system.xml',
                                ffxml_system)

    print('-' * 100)
    print('')
    print('OpenMM CHARMM reader total energy: %14.3f' % openmm_total_energy)
    print('ParmEd CHARMM reader total energy: %14.3f' % parmed_total_energy)
    print('OPENMM ffxml total energy:         %14.3f' % ffxml_total_energy)
    print('TOTAL ERROR:                       %14.3f' %
          (ffxml_total_energy - openmm_total_energy))
    print('')

    print('-' * 100)

    # TODO : Automate comparison
    return

    # calc rel energies and assert
    rel_energies = []
    for i, j in zip(ffxml_energies, parmed_energies):
        if i[0] != j[0]:
            raise Exception('Mismatch in energy tuples naming.')
        if abs(i[1]) > NEARLYZERO:
            rel_energies.append((i[0], abs((i[1] - j[1]) / i[1])))
        else:
            if abs(j[1]) > NEARLYZERO:
                raise AssertionError(
                    'One of the CHARMM %s energies (%s) for %s is zero, '
                    'while the corresponding OpenMM energy is non-zero' %
                    (system_name, i[0], ffxml))
            rel_energies.append((i[0], 0))

    dihedrals_done = False
    for i in rel_energies:
        if i[0] != 'PeriodicTorsionForce':
            if i[1] > tolerance:
                raise AssertionError(
                    '%s energies (%s, %f) outside of allowed tolerance (%f) for %s'
                    % (system_name, i[0], i[1], tolerance, ffxml))
        else:
            if not dihedrals_done:
                if i[1] > tolerance:
                    raise AssertionError(
                        '%s energies (%s, %f) outside of allowed tolerance (%f) for %s'
                        % (system_name, i[0], i[1], tolerance, ffxml))
                dihedrals_done = True
            else:  #impropers
                if i[1] > improper_tolerance:
                    raise AssertionError(
                        '%s energies (%s-impropers, %f) outside of allowed tolerance (%f) for %s'
                        % (system_name, i[0], i[1], improper_tolerance, ffxml))

    # logging
    if not no_log:
        charmm_energies_log = dict()
        omm_energies_log = dict()
        rel_energies_log = dict()
        charmm_energies_log['ffxml_name'] = ffxml
        charmm_energies_log['test_system'] = system_name
        charmm_energies_log['data_type'] = 'CHARMM'
        charmm_energies_log['units'] = units
        omm_energies_log['ffxml_name'] = ffxml
        omm_energies_log['test_system'] = system_name
        omm_energies_log['data_type'] = 'OpenMM'
        omm_energies_log['units'] = units
        rel_energies_log['ffxml_name'] = ffxml
        rel_energies_log['test_system'] = system_name
        rel_energies_log['data_type'] = 'abs((CHARMM-OpenMM)/CHARMM)'
        dihedrals_done = False
        for item in amber_energies:
            if item[0] == 'PeriodicTorsionForce' and not dihedrals_done:
                charmm_energies_log['PeriodicTorsionForce_dihedrals'] = item[1]
                dihedrals_done = True
            elif item[0] == 'PeriodicTorsionForce' and dihedrals_done:
                charmm_energies_log['PeriodicTorsionForce_impropers'] = item[1]
            elif item[0] == 'CMMotionRemover':
                continue
            else:
                charmm_energies_log[item[0]] = item[1]
        dihedrals_done = False
        for item in omm_energies:
            if item[0] == 'PeriodicTorsionForce' and not dihedrals_done:
                omm_energies_log['PeriodicTorsionForce_dihedrals'] = item[1]
                dihedrals_done = True
            elif item[0] == 'PeriodicTorsionForce' and dihedrals_done:
                omm_energies_log['PeriodicTorsionForce_impropers'] = item[1]
            elif item[0] == 'CMMotionRemover':
                continue
            else:
                omm_energies_log[item[0]] = item[1]
        dihedrals_done = False
        for item in rel_energies:
            if item[0] == 'PeriodicTorsionForce' and not dihedrals_done:
                rel_energies_log['PeriodicTorsionForce_dihedrals'] = item[1]
                dihedrals_done = True
            elif item[0] == 'PeriodicTorsionForce' and dihedrals_done:
                rel_energies_log['PeriodicTorsionForce_impropers'] = item[1]
            elif item[0] == 'CMMotionRemover':
                continue
            else:
                rel_energies_log[item[0]] = item[1]

        logger.log(charmm_energies_log)
        logger.log(omm_energies_log)
        logger.log(rel_energies_log)
コード例 #6
0
class ToyModel(object):
    """
    Toy model of 4 carbons to test torsionfit

    Attributes
    ----------
    synthetic_energy: simtk.units.Quantity((n_increments), unit=kilojoule/mole)
    true_value: parmed.topologyobjects.DihedralTypeList (the dihedral parameters used to calculate synthetic energy)
    initital_value: parmed.topologyobjects.DihedralTypeList (dihedral parameters used to initialize pymc model)
    torsion_scan: torsionfit.TorsionScanSet
    model: torsionfit.TorsionFitModel

    The default toy model has randomized true and initial dihedral parameters. This can be changed by passing a
    parmed.topologyobjects.DihedralTypeList to true_value and/or initial_value when initializing a model instance.

    """

    def __init__(self, true_value=None, initial_value=None, n_increments=18, rj=True, sample_phase=False,
                 continuous=False):
        self._param = CharmmParameterSet(get_fun('toy.str'))
        self._struct = CharmmPsfFile(get_fun('toy.psf'))
        self._pdb = app.PDBFile(get_fun('toy.pdb'))
        self._topology = md.load_psf(get_fun('toy.psf'))
        self.synthetic_energy = units.Quantity()
        self._positions = units.Quantity()
        self._platform = mm.Platform.getPlatformByName('Reference')

        # Replace ('CG331', 'CG321', 'CG321', 'CG331') torsion with true_value
        self._dih_type = ('CG331', 'CG321', 'CG321', 'CG331')
        original_torsion = self._param.dihedral_types[self._dih_type]
        if true_value is not None:
            if type(true_value) == DihedralTypeList:
                dih_tlist = true_value
            elif type(true_value) == DihedralType:
                dih_tlist = DihedralTypeList()
                dih_tlist.append(true_value)
        else:
            dih_tlist = self._randomize_dih_param(return_dih=True)
        self.true_value = copy.deepcopy(dih_tlist)
        self._param.dihedral_types[self._dih_type] = dih_tlist

        # parametrize toy
        self._struct.load_parameters(self._param, copy_parameters=False)
        self._struct.positions = self._pdb.positions

        # generate synthetic torsion scan
        self._torsion_scan(n_increments=n_increments)

        # initialize parameter
        if initial_value is not None:
            if type(initial_value) == DihedralTypeList:
                dih_tlist = initial_value
            if type(initial_value) == DihedralType:
                dih_tlist = DihedralTypeList()
                dih_tlist.append(initial_value)
            elif initial_value == 'cgenff':
                dih_tlist = original_torsion
        else:
            dih_tlist = self._randomize_dih_param(return_dih=True)

        self.initial_value = copy.deepcopy(dih_tlist)
        self._param.dihedral_types[self._dih_type] = dih_tlist

        # create torsionfit.TorsionScanSet
        torsions = np.zeros((len(self._positions), 4))
        torsions[:] = [1, 2, 3, 4]
        direction = None
        steps = None
        self.scan_set = ScanSet.QMDataBase(positions=self._positions.value_in_unit(units.nanometers),
                                           topology=self._topology, structure=self._struct, torsions=torsions,
                                           steps=steps, directions=direction,
                                           qm_energies=self.synthetic_energy.value_in_unit(units.kilojoules_per_mole))

        self.model = model.TorsionFitModel(param=self._param, frags=self.scan_set, platform=self._platform,
                                           param_to_opt=[self._dih_type], rj=rj, continuous_phase=continuous,
                                           sample_phase=sample_phase)

    def _spher2cart(self, r, theta, phi):
        """convert spherical to cartesian coordinates

        Paramters:
        r: bond length
        theta: bond angle
        phi: dihedral angle

        returns:
        cartesian coordinates
        """
        x = r * np.sin(theta) * np.cos(phi)
        y = r * np.sin(theta) * np.sin(phi)
        z = r * np.cos(theta)
        return [x, y, z]

    def _torsion_scan(self, n_increments):
        """
        Generate positions and energy for torsion scan
        Parameters:
            n_increments: int. how many points to scan
        """
        n_increments = n_increments
        n_atoms = 4
        phis = np.arange(-np.pi, +np.pi, np.pi/n_increments)
        positions = np.zeros((len(phis), n_atoms, 3))

        # Get bond length in nm
        for bond in self._struct.bonds:
            if bond.atom1.type == bond.atom2.type:
                length = units.Quantity(value=bond.type.req * 0.1, unit=units.nanometers) # convert to nm
        # Get angle in radians
        for angle in self._struct.angles:
            if angle.atom1.type == angle.atom2.type:
                theta = units.Quantity(value=angle.type.theteq * (np.pi/180.0), unit=units.radians)

        atom1_coords = self._spher2cart(length.value_in_unit(units.nanometer), theta.value_in_unit(units.radian), phis[0])
        for i, phi in enumerate(phis):
            atom3_coords = self._spher2cart(length.value_in_unit(units.nanometer), theta.value_in_unit(units.radian), phi)
            atom3_coords[-1] = abs(atom3_coords[-1]) + length._value
            positions[i] = [atom1_coords,
                [0.000, 0.000, 0.000],
                [0.000, 0.000, length._value],
                atom3_coords]
        self._positions = units.Quantity(value=positions, unit=units.nanometer) # put units back in

        # calculate energy
        self.synthetic_energy = units.Quantity(value=np.zeros((len(positions))), unit=units.kilojoules_per_mole)
        platform = mm.Platform.getPlatformByName('Reference')
        integrator = mm.VerletIntegrator(0.004*units.picoseconds)
        system = self._struct.createSystem()
        context = mm.Context(system, integrator, platform)
        for i, conf in enumerate(self._positions):
            context.setPositions(conf)
            state = context.getState(getEnergy=True)
            energy = state.getPotentialEnergy()
            self.synthetic_energy[i] = energy + units.Quantity(value=np.random.normal(0, 1.0), unit=units.kilojoules_per_mole)

    def _randomize_dih_param(self, return_dih=False):
        """
        generates random dihedral parameters

        """
        dih_tlist = DihedralTypeList()
        multiplicities = [1, 2, 3, 4, 6]
        terms = np.random.randint(1, 5+1)
        np.random.shuffle(multiplicities)
        for i in range(terms):
            k = np.random.uniform(0.0, 20.0)
            n = multiplicities[i]
            phase = np.random.randint(0, 1+1)
            if phase == 1:
                phase = 180
            dih_tlist.append(DihedralType(k, n, phase, 1.00, 1.00))
        self._param.dihedral_types[self._dih_type] = dih_tlist
        if return_dih:
            _dih_tlist = copy.deepcopy(dih_tlist)
            return _dih_tlist

    def save_torsion_values(self, filename=None):
        """

        Parameters
        ----------
        filename : str
            file to save torsion values. Default is None. If None, return np.array

        Returns
        -------
        dih_param: np.array
            array containing torison parameters
        """
        dih_param = np.ones(shape=(2, 6, 3)) * np.nan
        for i, dih in enumerate(self.true_value):
            dih_param[0, i, 0] = dih.per
            dih_param[0, i, 1] = dih.phi_k
            dih_param[0, i, 2] = dih.phase

        for j, dih in enumerate(self.initial_value):
            dih_param[1, j, 0] = dih.per
            dih_param[1, j, 1] = dih.phi_k
            dih_param[1, j, 2] = dih.phase

        if filename is not None:
            np.save(filename, dih_param)
        else:
            return dih_param

    @staticmethod
    def from_dih_params(filename=None, dih_params=None, rj=False, continuous=False, n_increments=13, sample_phase=False):
        """

        Parameters
        ----------
        filename : str
            name of file with serialized dihedral parameters
        rj : bool
            Flag if using reversible jump. Default it True
        continuous : bool
            Flag if sampling continuous phase. Default is False
        n_increments : int
            incermentation of torsion drive
        sample_phase : bool
            Flag if sampling phase. Default is False (K is allowed to go negative when sample_phase is False)

        Returns
        -------
        ToyModel with true and initial value from saved file.

        """
        if filename is None and dih_params is None:
            msg = 'You must provide either an npy file or a numpy array with true and initial values for the toy model'
            raise Exception(msg)
        if filename is not None:
            dih_params = np.load(filename)
        dih_tlist_true = DihedralTypeList()
        dih_tlist_init = DihedralTypeList()

        true = dih_params[0]
        init = dih_params[1]

        for dih in true:
            if not np.isnan(dih[0]):
                dih_tlist_true.append(DihedralType(per=dih[0], phi_k=dih[1], phase=dih[2]))

        for dih in init:
            if not np.isnan(dih[0]):
                dih_tlist_init.append(DihedralType(per=dih[0], phi_k=dih[1], phase=dih[2]))

        return ToyModel(true_value=dih_tlist_true, initial_value=dih_tlist_init, rj=rj, continuous=continuous,
                        n_increments=n_increments, sample_phase=sample_phase)