Пример #1
0
def test_system_subset_vdw():

    # Create a dummy topology
    topology = Molecule.from_smiles("Cl").to_topology()

    # Create the system subset.
    system, parameter_value = system_subset(
        parameter_key=ParameterGradientKey("vdW", "[#1:1]", "epsilon"),
        force_field=hydrogen_chloride_force_field(True, True),
        topology=topology,
        scale_amount=0.5,
    )

    assert system.getNumForces() == 1
    assert system.getNumParticles() == 2

    charge_0, sigma_0, epsilon_0 = system.getForce(0).getParticleParameters(0)
    charge_1, sigma_1, epsilon_1 = system.getForce(0).getParticleParameters(1)

    assert np.isclose(charge_0.value_in_unit(simtk_unit.elementary_charge),
                      0.0)
    assert np.isclose(charge_1.value_in_unit(simtk_unit.elementary_charge),
                      0.0)

    assert np.isclose(sigma_0.value_in_unit(simtk_unit.angstrom), 2.0)
    assert np.isclose(sigma_1.value_in_unit(simtk_unit.angstrom), 1.0)

    assert np.isclose(epsilon_0.value_in_unit(simtk_unit.kilojoules_per_mole),
                      2.0)
    assert np.isclose(epsilon_1.value_in_unit(simtk_unit.kilojoules_per_mole),
                      0.5)
Пример #2
0
    def _compute_charge_derivatives(self, n_atoms: int):

        d_charge_d_theta = {key: np.zeros(n_atoms) for key in self.gradient_parameters}

        if len(self.gradient_parameters) > 0 and not isinstance(
            self.parameterized_system.force_field, SmirnoffForceFieldSource
        ):
            raise ValueError(
                "Derivates can only be computed for systems parameterized with "
                "SMIRNOFF force fields."
            )

        force_field = self.parameterized_system.force_field.to_force_field()
        topology = self.parameterized_system.topology

        for key in self.gradient_parameters:

            reverse_system, reverse_value = system_subset(key, force_field, topology)
            forward_system, forward_value = system_subset(
                key, force_field, topology, 0.1
            )

            reverse_value = openmm_quantity_to_pint(reverse_value)
            forward_value = openmm_quantity_to_pint(forward_value)

            reverse_charges = self._extract_charges(reverse_system)
            forward_charges = self._extract_charges(forward_system)

            if reverse_charges is None and forward_charges is None:
                d_charge_d_theta[key] /= forward_value.units

            else:
                d_charge_d_theta[key] = (forward_charges - reverse_charges) / (
                    forward_value - reverse_value
                )

        return d_charge_d_theta
Пример #3
0
def test_system_subset_library_charge():

    force_field = hydrogen_chloride_force_field(True, False)

    # Ensure a zero charge after perturbation.
    force_field.get_parameter_handler(
        "LibraryCharges").parameters["[#1:1]"].charge1 = (
            1.5 * simtk_unit.elementary_charge)

    # Create a dummy topology
    topology = Molecule.from_smiles("Cl").to_topology()

    # Create the system subset.
    system, parameter_value = system_subset(
        parameter_key=ParameterGradientKey("LibraryCharges", "[#17:1]",
                                           "charge1"),
        force_field=force_field,
        topology=topology,
        scale_amount=0.5,
    )

    assert system.getNumForces() == 1
    assert system.getNumParticles() == 2

    charge_0, sigma_0, epsilon_0 = system.getForce(0).getParticleParameters(0)
    charge_1, sigma_1, epsilon_1 = system.getForce(0).getParticleParameters(1)

    assert np.isclose(charge_0.value_in_unit(simtk_unit.elementary_charge),
                      -1.5)
    assert np.isclose(charge_1.value_in_unit(simtk_unit.elementary_charge),
                      1.5)

    assert np.isclose(sigma_0.value_in_unit(simtk_unit.angstrom), 10.0)
    assert np.isclose(sigma_1.value_in_unit(simtk_unit.angstrom), 10.0)

    assert np.isclose(epsilon_0.value_in_unit(simtk_unit.kilojoules_per_mole),
                      0.0)
    assert np.isclose(epsilon_1.value_in_unit(simtk_unit.kilojoules_per_mole),
                      0.0)
Пример #4
0
def test_system_subset_charge_increment():

    pytest.skip(
        "This test will fail until the SMIRNOFF charge increment handler allows "
        "N - 1 charges to be specified.")

    # Create a dummy topology
    topology = Molecule.from_smiles("Cl").to_topology()

    # Create the system subset.
    system, parameter_value = system_subset(
        parameter_key=ParameterGradientKey("ChargeIncrementModel",
                                           "[#1:1]-[#17:2]",
                                           "charge_increment1"),
        force_field=hydrogen_chloride_force_field(False, True),
        topology=topology,
        scale_amount=0.5,
    )

    assert system.getNumForces() == 1
    assert system.getNumParticles() == 2

    charge_0, sigma_0, epsilon_0 = system.getForce(0).getParticleParameters(0)
    charge_1, sigma_1, epsilon_1 = system.getForce(0).getParticleParameters(1)

    assert not np.isclose(charge_0.value_in_unit(simtk_unit.elementary_charge),
                          -1.0)
    assert np.isclose(charge_1.value_in_unit(simtk_unit.elementary_charge),
                      1.0)

    assert np.isclose(sigma_0.value_in_unit(simtk_unit.angstrom), 10.0)
    assert np.isclose(sigma_1.value_in_unit(simtk_unit.angstrom), 10.0)

    assert np.isclose(epsilon_0.value_in_unit(simtk_unit.kilojoules_per_mole),
                      0.0)
    assert np.isclose(epsilon_1.value_in_unit(simtk_unit.kilojoules_per_mole),
                      0.0)
Пример #5
0
def _compute_gradients(
    gradient_parameters: List[ParameterGradientKey],
    observables: ObservableFrame,
    force_field: "ForceField",
    thermodynamic_state: ThermodynamicState,
    topology: "Topology",
    trajectory: "Trajectory",
    compute_resources: ComputeResources,
    enable_pbc: bool = True,
    perturbation_amount: float = 0.0001,
):
    """Computes the gradients of the provided observables with respect to
    the set of specified force field parameters using the central difference
    finite difference method.

    Notes
    -----
    The ``observables`` object will be modified in-place.

    Parameters
    ----------
    gradient_parameters
        The parameters to differentiate with respect to.
    observables
        The observables to differentiate.
    force_field
        The full set force field parameters which contain the parameters to
        differentiate.
    thermodynamic_state
        The state at which the trajectory was sampled
    topology
        The topology of the system the observables were collected for.
    trajectory
        The trajectory over which the observables were collected.
    compute_resources
        The compute resources available for the computations.
    enable_pbc
        Whether PBC should be enabled when re-evaluating system energies.
    perturbation_amount
        The amount to perturb for the force field parameter by.
    """

    from simtk import openmm

    gradients = defaultdict(list)
    observables.clear_gradients()

    if enable_pbc:
        # Make sure the PBC are set on the topology otherwise the cut-off will be
        # set incorrectly.
        topology.box_vectors = trajectory.openmm_boxes(0)

    for parameter_key in gradient_parameters:

        # Build the slightly perturbed systems.
        reverse_system, reverse_parameter_value = system_subset(
            parameter_key, force_field, topology, -perturbation_amount)
        forward_system, forward_parameter_value = system_subset(
            parameter_key, force_field, topology, perturbation_amount)

        # Perform a cheap check to try and catch most cases where the systems energy
        # does not depend on this parameter.
        reverse_xml = openmm.XmlSerializer.serialize(reverse_system)
        forward_xml = openmm.XmlSerializer.serialize(forward_system)

        if not enable_pbc:
            disable_pbc(reverse_system)
            disable_pbc(forward_system)

        reverse_parameter_value = openmm_quantity_to_pint(
            reverse_parameter_value)
        forward_parameter_value = openmm_quantity_to_pint(
            forward_parameter_value)

        # Evaluate the energies using the reverse and forward sub-systems.
        if reverse_xml != forward_xml:
            reverse_energies = _evaluate_energies(
                thermodynamic_state,
                reverse_system,
                trajectory,
                compute_resources,
                enable_pbc,
            )
            forward_energies = _evaluate_energies(
                thermodynamic_state,
                forward_system,
                trajectory,
                compute_resources,
                enable_pbc,
            )
        else:

            zeros = np.zeros(len(trajectory))

            reverse_energies = forward_energies = ObservableFrame({
                ObservableType.PotentialEnergy:
                ObservableArray(
                    zeros * unit.kilojoule / unit.mole,
                    [
                        ParameterGradient(
                            key=parameter_key,
                            value=(zeros * unit.kilojoule / unit.mole /
                                   reverse_parameter_value.units),
                        )
                    ],
                ),
                ObservableType.ReducedPotential:
                ObservableArray(
                    zeros * unit.dimensionless,
                    [
                        ParameterGradient(
                            key=parameter_key,
                            value=(zeros * unit.dimensionless /
                                   reverse_parameter_value.units),
                        )
                    ],
                ),
            })

        potential_gradient = ParameterGradient(
            key=parameter_key,
            value=(forward_energies[ObservableType.PotentialEnergy].value -
                   reverse_energies[ObservableType.PotentialEnergy].value) /
            (forward_parameter_value - reverse_parameter_value),
        )
        reduced_potential_gradient = ParameterGradient(
            key=parameter_key,
            value=(forward_energies[ObservableType.ReducedPotential].value -
                   reverse_energies[ObservableType.ReducedPotential].value) /
            (forward_parameter_value - reverse_parameter_value),
        )

        gradients[ObservableType.PotentialEnergy].append(potential_gradient)
        gradients[ObservableType.TotalEnergy].append(potential_gradient)
        gradients[ObservableType.Enthalpy].append(potential_gradient)
        gradients[ObservableType.ReducedPotential].append(
            reduced_potential_gradient)

        if ObservableType.KineticEnergy in observables:
            gradients[ObservableType.KineticEnergy].append(
                ParameterGradient(
                    key=parameter_key,
                    value=(
                        np.zeros(potential_gradient.value.shape) *
                        observables[ObservableType.KineticEnergy].value.units /
                        reverse_parameter_value.units),
                ))
        if ObservableType.Density in observables:
            gradients[ObservableType.Density].append(
                ParameterGradient(
                    key=parameter_key,
                    value=(np.zeros(potential_gradient.value.shape) *
                           observables[ObservableType.Density].value.units /
                           reverse_parameter_value.units),
                ))
        if ObservableType.Volume in observables:
            gradients[ObservableType.Volume].append(
                ParameterGradient(
                    key=parameter_key,
                    value=(np.zeros(potential_gradient.value.shape) *
                           observables[ObservableType.Volume].value.units /
                           reverse_parameter_value.units),
                ))

    for observable_type in observables:

        observables[observable_type] = ObservableArray(
            value=observables[observable_type].value,
            gradients=gradients[observable_type],
        )