Example #1
0
def test_solvate_existing_structure_protocol():
    """Tests solvating a single methanol molecule in water."""

    methanol_substance = Substance()
    methanol_substance.add_component(Substance.Component('CO'),
                                     Substance.ExactAmount(1))

    water_substance = Substance()
    water_substance.add_component(Substance.Component('O'),
                                  Substance.MoleFraction(1.0))

    with tempfile.TemporaryDirectory() as temporary_directory:

        build_methanol_coordinates = BuildCoordinatesPackmol('build_methanol')
        build_methanol_coordinates.max_molecules = 1
        build_methanol_coordinates.substance = methanol_substance
        build_methanol_coordinates.execute(temporary_directory,
                                           ComputeResources())

        solvate_coordinates = SolvateExistingStructure('solvate_methanol')
        solvate_coordinates.max_molecules = 9
        solvate_coordinates.substance = water_substance
        solvate_coordinates.solute_coordinate_file = build_methanol_coordinates.coordinate_file_path
        solvate_coordinates.execute(temporary_directory, ComputeResources())
        solvated_pdb = PDBFile(solvate_coordinates.coordinate_file_path)

        assert solvated_pdb.topology.getNumResidues() == 10
Example #2
0
def create_dummy_substance(number_of_components, elements=None):
    """Creates a substance with a given number of components,
    each containing the specified elements.

    Parameters
    ----------
    number_of_components : int
        The number of components to add to the substance.
    elements : list of str
        The elements that each component should containt.

    Returns
    -------
    Substance
        The created substance.
    """
    if elements is None:
        elements = ['C']

    substance = Substance()

    mole_fraction = 1.0 / number_of_components

    for index in range(number_of_components):

        smiles_pattern = ''.join(elements * (index + 1))

        substance.add_component(Substance.Component(smiles_pattern),
                                Substance.MoleFraction(mole_fraction))

    return substance
Example #3
0
def test_filter_by_smiles():
    """A test to ensure that data sets may be filtered by which smiles their
    measured properties contain."""

    methanol_substance = Substance()
    methanol_substance.add_component(Substance.Component('CO'), Substance.MoleFraction(1.0))

    ethanol_substance = Substance()
    ethanol_substance.add_component(Substance.Component('CCO'), Substance.MoleFraction(1.0))

    property_a = create_dummy_property(Density)
    property_a.substance = methanol_substance

    property_b = create_dummy_property(Density)
    property_b.substance = ethanol_substance

    data_set = PhysicalPropertyDataSet()
    data_set.properties[methanol_substance.identifier] = [property_a]
    data_set.properties[ethanol_substance.identifier] = [property_b]

    data_set.filter_by_smiles('CO')

    assert data_set.number_of_properties == 1
    assert methanol_substance.identifier in data_set.properties
    assert ethanol_substance.identifier not in data_set.properties
def test_density_dielectric_merging():

    substance = Substance()
    substance.add_component(Substance.Component(smiles='C'),
                            Substance.MoleFraction())

    density = Density(thermodynamic_state=ThermodynamicState(temperature=298*unit.kelvin,
                                                             pressure=1*unit.atmosphere),
                      phase=PropertyPhase.Liquid,
                      substance=substance,
                      value=10*unit.gram/unit.mole,
                      uncertainty=1*unit.gram/unit.mole)

    dielectric = DielectricConstant(thermodynamic_state=ThermodynamicState(temperature=298*unit.kelvin,
                                                                           pressure=1*unit.atmosphere),
                                    phase=PropertyPhase.Liquid,
                                    substance=substance,
                                    value=10*unit.gram/unit.mole,
                                    uncertainty=1*unit.gram/unit.mole)

    density_schema = density.get_default_workflow_schema('SimulationLayer', WorkflowOptions())
    dielectric_schema = dielectric.get_default_workflow_schema('SimulationLayer', WorkflowOptions())

    density_metadata = Workflow.generate_default_metadata(density,
                                                          'smirnoff99Frosst-1.1.0.offxml',
                                                          [])

    dielectric_metadata = Workflow.generate_default_metadata(density,
                                                             'smirnoff99Frosst-1.1.0.offxml',
                                                             [])

    density_workflow = Workflow(density, density_metadata)
    density_workflow.schema = density_schema

    dielectric_workflow = Workflow(dielectric, dielectric_metadata)
    dielectric_workflow.schema = dielectric_schema

    workflow_graph = WorkflowGraph('')

    workflow_graph.add_workflow(density_workflow)
    workflow_graph.add_workflow(dielectric_workflow)

    merge_order_a = graph.topological_sort(density_workflow.dependants_graph)
    merge_order_b = graph.topological_sort(dielectric_workflow.dependants_graph)

    for protocol_id_A, protocol_id_B in zip(merge_order_a, merge_order_b):

        if protocol_id_A.find('extract_traj') < 0 and protocol_id_A.find('extract_stats') < 0:

            assert density_workflow.protocols[protocol_id_A].schema.json() == \
                   dielectric_workflow.protocols[protocol_id_B].schema.json()

        else:

            assert density_workflow.protocols[protocol_id_A].schema.json() != \
                   dielectric_workflow.protocols[protocol_id_B].schema.json()
def test_multiple_amounts():

    substance = Substance()

    substance.add_component(Substance.Component('[Na+]'),
                            Substance.MoleFraction(0.75))
    substance.add_component(Substance.Component('[Na+]'),
                            Substance.ExactAmount(1))

    substance.add_component(Substance.Component('[Cl-]'),
                            Substance.MoleFraction(0.25))
    substance.add_component(Substance.Component('[Cl-]'),
                            Substance.ExactAmount(1))

    assert substance.number_of_components == 2

    sodium_amounts = substance.get_amounts('[Na+]')
    chlorine_amounts = substance.get_amounts('[Cl-]')

    assert len(sodium_amounts) == 2
    assert len(chlorine_amounts) == 2

    molecule_counts = substance.get_molecules_per_component(6)

    assert len(molecule_counts) == 2

    assert molecule_counts['[Na+]'] == 4
    assert molecule_counts['[Cl-]'] == 2
def test_add_mole_fractions():

    substance = Substance()

    substance.add_component(Substance.Component('C'),
                            Substance.MoleFraction(0.5))
    substance.add_component(Substance.Component('C'),
                            Substance.MoleFraction(0.5))

    assert substance.number_of_components == 1

    amounts = substance.get_amounts('C')

    assert len(amounts) == 1

    amount = next(iter(amounts))

    assert isinstance(amount, Substance.MoleFraction)
    assert np.isclose(amount.value, 1.0)
    def retrieve_simulation_data(self,
                                 substance,
                                 include_component_data=True,
                                 data_class=StoredSimulationData):

        substance_ids = {substance.identifier}

        # Find the substance identifiers of the substance components if
        # we should include component data.
        if isinstance(substance, Substance) and include_component_data is True:

            for component in substance.components:

                component_substance = Substance()
                component_substance.add_component(component,
                                                  Substance.MoleFraction())

                substance_ids.add(component_substance.identifier)

        return_data = {}

        for substance_id in substance_ids:

            if substance_id not in self._simulation_data_by_substance:
                continue

            return_data[substance_id] = []

            for data_key in self._simulation_data_by_substance[substance_id]:

                data_object, data_directory = self.retrieve_simulation_data_by_id(
                    data_key)

                if data_object is None:
                    continue

                if not isinstance(data_object, data_class):
                    continue

                return_data[substance_id].append((data_object, data_directory))

        return return_data
def test_data_class_retrieval():
    """A simple test to that force fields can be stored and
    retrieved using the local storage backend."""

    substance = Substance()
    substance.add_component(Substance.Component('C'),
                            Substance.MoleFraction(1.0))

    with tempfile.TemporaryDirectory() as base_directory_path:

        storage_directory = os.path.join(base_directory_path, 'storage')
        local_storage = LocalFileStorage(storage_directory)

        for data_class_type in [DummyDataClass1, DummyDataClass2]:

            data_directory = os.path.join(base_directory_path,
                                          data_class_type.__name__)
            os.makedirs(data_directory, exist_ok=True)

            data_object = data_class_type()
            data_object.substance = substance

            local_storage.store_simulation_data(data_object, data_directory)

        retrieved_data_directories = local_storage.retrieve_simulation_data(
            substance, data_class=BaseStoredData)
        assert len(retrieved_data_directories[substance.identifier]) == 2

        retrieved_data_directories = local_storage.retrieve_simulation_data(
            substance, data_class=DummyDataClass1)
        assert len(retrieved_data_directories[substance.identifier]) == 1

        retrieved_data_directories = local_storage.retrieve_simulation_data(
            substance, data_class=DummyDataClass2)
        assert len(retrieved_data_directories[substance.identifier]) == 1

        retrieved_data_directories = local_storage.retrieve_simulation_data(
            substance, data_class=StoredSimulationData)
        assert len(retrieved_data_directories[substance.identifier]) == 0
Example #9
0
    def create_substance():
        test_substance = Substance()

        test_substance.add_component(Substance.Component('C', role=Substance.ComponentRole.Solute),
                                     Substance.ExactAmount(1))

        test_substance.add_component(Substance.Component('CC', role=Substance.ComponentRole.Ligand),
                                     Substance.ExactAmount(1))

        test_substance.add_component(Substance.Component('CCC', role=Substance.ComponentRole.Receptor),
                                     Substance.ExactAmount(1))

        test_substance.add_component(Substance.Component('O', role=Substance.ComponentRole.Solvent),
                                     Substance.MoleFraction(1.0))

        return test_substance
Example #10
0
def test_build_docked_coordinates_protocol():
    """Tests docking a methanol molecule into alpha-Cyclodextrin."""

    ligand_substance = Substance()
    ligand_substance.add_component(
        Substance.Component('CO', role=Substance.ComponentRole.Ligand),
        Substance.ExactAmount(1))

    # TODO: This test could likely be made substantially faster
    #       by storing the binary prepared receptor. Would this
    #       be in breach of any oe license terms?
    with tempfile.TemporaryDirectory() as temporary_directory:

        build_docked_coordinates = BuildDockedCoordinates('build_methanol')
        build_docked_coordinates.ligand_substance = ligand_substance
        build_docked_coordinates.number_of_ligand_conformers = 5
        build_docked_coordinates.receptor_coordinate_file = get_data_filename(
            'test/molecules/acd.mol2')
        build_docked_coordinates.execute(temporary_directory,
                                         ComputeResources())

        docked_pdb = PDBFile(
            build_docked_coordinates.docked_complex_coordinate_path)
        assert docked_pdb.topology.getNumResidues() == 2
Example #11
0
def _build_input_output_substances():
    """Builds sets if input and expected substances for the
    `test_build_coordinate_composition` test.

    Returns
    -------
    list of tuple of Substance and Substance
        A list of input and expected substances.
    """

    # Start with some easy cases
    substances = [
        (Substance.from_components('O'), Substance.from_components('O')),
        (Substance.from_components('O',
                                   'C'), Substance.from_components('O', 'C')),
        (Substance.from_components('O', 'C', 'CO'),
         Substance.from_components('O', 'C', 'CO'))
    ]

    # Handle some cases where rounding will need to occur.
    input_substance = Substance()
    input_substance.add_component(Substance.Component('O'),
                                  Substance.MoleFraction(0.41))
    input_substance.add_component(Substance.Component('C'),
                                  Substance.MoleFraction(0.59))

    expected_substance = Substance()
    expected_substance.add_component(Substance.Component('O'),
                                     Substance.MoleFraction(0.4))
    expected_substance.add_component(Substance.Component('C'),
                                     Substance.MoleFraction(0.6))

    substances.append((input_substance, expected_substance))

    input_substance = Substance()
    input_substance.add_component(Substance.Component('O'),
                                  Substance.MoleFraction(0.59))
    input_substance.add_component(Substance.Component('C'),
                                  Substance.MoleFraction(0.41))

    expected_substance = Substance()
    expected_substance.add_component(Substance.Component('O'),
                                     Substance.MoleFraction(0.6))
    expected_substance.add_component(Substance.Component('C'),
                                     Substance.MoleFraction(0.4))

    substances.append((input_substance, expected_substance))

    return substances
Example #12
0
def test_ligand_receptor_yank_protocol():

    full_substance = Substance()

    full_substance.add_component(
        Substance.Component(smiles='c1ccccc1',
                            role=Substance.ComponentRole.Receptor),
        Substance.ExactAmount(1))
    full_substance.add_component(
        Substance.Component(smiles='C', role=Substance.ComponentRole.Ligand),
        Substance.ExactAmount(1))
    full_substance.add_component(
        Substance.Component(smiles='O', role=Substance.ComponentRole.Solvent),
        Substance.MoleFraction(1.0))

    solute_substance = Substance()
    solute_substance.add_component(
        Substance.Component(smiles='C', role=Substance.ComponentRole.Ligand),
        Substance.ExactAmount(1))
    solute_substance.add_component(
        Substance.Component(smiles='O', role=Substance.ComponentRole.Solvent),
        Substance.MoleFraction(1.0))

    thermodynamic_state = ThermodynamicState(temperature=298.15 * unit.kelvin,
                                             pressure=1.0 * unit.atmosphere)

    with tempfile.TemporaryDirectory() as directory:

        with temporarily_change_directory(directory):

            force_field_path = 'ff.json'

            with open(force_field_path, 'w') as file:
                file.write(build_tip3p_smirnoff_force_field().json())

            complex_coordinate_path, complex_system_path = _setup_dummy_system(
                'full', full_substance, 3, force_field_path)

            ligand_coordinate_path, ligand_system_path = _setup_dummy_system(
                'ligand', solute_substance, 2, force_field_path)

            run_yank = LigandReceptorYankProtocol('yank')
            run_yank.substance = full_substance
            run_yank.thermodynamic_state = thermodynamic_state
            run_yank.number_of_iterations = 1
            run_yank.steps_per_iteration = 1
            run_yank.checkpoint_interval = 1
            run_yank.verbose = True
            run_yank.setup_only = True

            run_yank.ligand_residue_name = 'TMP'
            run_yank.receptor_residue_name = 'TMP'
            run_yank.solvated_ligand_coordinates = ligand_coordinate_path
            run_yank.solvated_ligand_system = ligand_system_path
            run_yank.solvated_complex_coordinates = complex_coordinate_path
            run_yank.solvated_complex_system = complex_system_path

            run_yank.force_field_path = force_field_path

            result = run_yank.execute('', ComputeResources())
            assert not isinstance(result, PropertyEstimatorException)
Example #13
0
def test_solvation_yank_protocol(solvent_smiles):

    full_substance = Substance()

    full_substance.add_component(
        Substance.Component(smiles='CO', role=Substance.ComponentRole.Solute),
        Substance.ExactAmount(1))
    full_substance.add_component(
        Substance.Component(smiles=solvent_smiles,
                            role=Substance.ComponentRole.Solvent),
        Substance.MoleFraction(1.0))

    solvent_substance = Substance()
    solvent_substance.add_component(
        Substance.Component(smiles=solvent_smiles,
                            role=Substance.ComponentRole.Solvent),
        Substance.MoleFraction(1.0))

    solute_substance = Substance()
    solute_substance.add_component(
        Substance.Component(smiles='CO', role=Substance.ComponentRole.Solute),
        Substance.ExactAmount(1))

    thermodynamic_state = ThermodynamicState(temperature=298.15 * unit.kelvin,
                                             pressure=1.0 * unit.atmosphere)

    with tempfile.TemporaryDirectory() as directory:

        with temporarily_change_directory(directory):

            force_field_path = 'ff.json'

            with open(force_field_path, 'w') as file:
                file.write(build_tip3p_smirnoff_force_field().json())

            solvated_coordinate_path, solvated_system_path = _setup_dummy_system(
                'full', full_substance, 2, force_field_path)

            vacuum_coordinate_path, vacuum_system_path = _setup_dummy_system(
                'vacuum', solute_substance, 1, force_field_path)

            run_yank = SolvationYankProtocol('yank')
            run_yank.solute = solute_substance
            run_yank.solvent_1 = solvent_substance
            run_yank.solvent_2 = Substance()
            run_yank.thermodynamic_state = thermodynamic_state
            run_yank.number_of_iterations = 1
            run_yank.steps_per_iteration = 1
            run_yank.checkpoint_interval = 1
            run_yank.verbose = True
            run_yank.setup_only = True
            run_yank.solvent_1_coordinates = solvated_coordinate_path
            run_yank.solvent_1_system = solvated_system_path
            run_yank.solvent_2_coordinates = vacuum_coordinate_path
            run_yank.solvent_2_system = vacuum_system_path

            run_yank.electrostatic_lambdas_1 = [1.00]
            run_yank.steric_lambdas_1 = [1.00]
            run_yank.electrostatic_lambdas_2 = [1.00]
            run_yank.steric_lambdas_2 = [1.00]

            result = run_yank.execute('', ComputeResources())
            assert not isinstance(result, PropertyEstimatorException)
    def _rebuild_substance(self, number_of_molecules):
        """Rebuilds the `Substance` object which the protocol will create coordinates.

        This may not be the same as the input system due to the finite number of molecules
        to be added causing rounding of mole fractions.

        Parameters
        ----------
        number_of_molecules: list of int
            The number of each component which should be added to the system.

        Returns
        -------
        Substance
            The substance which contains the corrected component amounts.
        """

        new_amounts = defaultdict(list)

        total_number_of_molecules = sum(number_of_molecules)

        # Handle any exact amounts.
        for component in self.substance.components:

            exact_amounts = [amount for amount in self.substance.get_amounts(component) if
                             isinstance(amount, Substance.ExactAmount)]

            if len(exact_amounts) == 0:
                continue

            total_number_of_molecules -= exact_amounts[0].value
            new_amounts[component].append(exact_amounts[0])

        # Recompute the mole fractions.
        total_mole_fraction = 0.0
        number_of_new_mole_fractions = 0

        for index, component in enumerate(self.substance.components):

            mole_fractions = [amount for amount in self.substance.get_amounts(component) if
                              isinstance(amount, Substance.MoleFraction)]

            if len(mole_fractions) == 0:
                continue

            molecule_count = number_of_molecules[index]

            if component in new_amounts:
                molecule_count -= new_amounts[component][0].value

            new_mole_fraction = molecule_count / total_number_of_molecules
            new_amounts[component].append(Substance.MoleFraction(new_mole_fraction))

            total_mole_fraction += new_mole_fraction
            number_of_new_mole_fractions += 1

        if not np.isclose(total_mole_fraction, 1.0) and number_of_new_mole_fractions > 0:
            raise ValueError('The new mole fraction does not equal 1.0')

        output_substance = Substance()

        for component, amounts in new_amounts.items():

            for amount in amounts:
                output_substance.add_component(component, amount)

        return output_substance
def _create_data_set():
    """Create a small data set of three properties taken from the
    FreeSolv data set: https://github.com/mobleylab/FreeSolv.

    Returns
    -------
    PhysicalPropertyDataSet
        The data set of three select FreeSolv properties.
    """

    butan_1_ol = Substance()
    butan_1_ol.add_component(
        Substance.Component('CCCCO', role=Substance.ComponentRole.Solute),
        Substance.ExactAmount(1))
    butan_1_ol.add_component(
        Substance.Component('O', role=Substance.ComponentRole.Solvent),
        Substance.MoleFraction(1.0))

    butan_1_ol_property = SolvationFreeEnergy(
        thermodynamic_state=ThermodynamicState(298.15 * unit.kelvin,
                                               1.0 * unit.atmosphere),
        phase=PropertyPhase.Liquid,
        substance=butan_1_ol,
        value=-4.72 * unit.kilocalorie / unit.mole,
        uncertainty=0.6 * unit.kilocalorie / unit.mole,
        source=MeasurementSource(doi=' 10.1021/ct050097l'))

    methyl_propanoate = Substance()
    methyl_propanoate.add_component(
        Substance.Component('CCC(=O)OC', role=Substance.ComponentRole.Solute),
        Substance.ExactAmount(1))
    methyl_propanoate.add_component(
        Substance.Component('O', role=Substance.ComponentRole.Solvent),
        Substance.MoleFraction(1.0))

    methyl_propanoate_property = SolvationFreeEnergy(
        thermodynamic_state=ThermodynamicState(298.15 * unit.kelvin,
                                               1.0 * unit.atmosphere),
        phase=PropertyPhase.Liquid,
        substance=methyl_propanoate,
        value=-2.93 * unit.kilocalorie / unit.mole,
        uncertainty=0.6 * unit.kilocalorie / unit.mole,
        source=MeasurementSource(doi=' 10.1021/ct050097l'))

    benzamide = Substance()
    benzamide.add_component(
        Substance.Component('c1ccc(cc1)C(=O)N',
                            role=Substance.ComponentRole.Solute),
        Substance.ExactAmount(1))
    benzamide.add_component(
        Substance.Component('O', role=Substance.ComponentRole.Solvent),
        Substance.MoleFraction(1.0))

    benzamide_property = SolvationFreeEnergy(
        thermodynamic_state=ThermodynamicState(298.15 * unit.kelvin,
                                               1.0 * unit.atmosphere),
        phase=PropertyPhase.Liquid,
        substance=benzamide,
        value=-11.0 * unit.kilocalorie / unit.mole,
        uncertainty=0.2 * unit.kilocalorie / unit.mole,
        source=MeasurementSource(doi=' 10.1021/ct050097l'))

    data_set = PhysicalPropertyDataSet()
    data_set.properties[butan_1_ol.identifier] = [butan_1_ol_property]
    data_set.properties[methyl_propanoate.identifier] = [
        methyl_propanoate_property
    ]
    data_set.properties[benzamide.identifier] = [benzamide_property]

    return data_set
def test_base_simulation_protocols():
    """Tests that the commonly chain build coordinates, assigned topology,
    energy minimise and perform simulation are able to work together without
    raising an exception."""

    water_substance = Substance()
    water_substance.add_component(Substance.Component(smiles='O'),
                                  Substance.MoleFraction())

    thermodynamic_state = ThermodynamicState(298 * unit.kelvin,
                                             1 * unit.atmosphere)

    with tempfile.TemporaryDirectory() as temporary_directory:

        force_field_source = build_tip3p_smirnoff_force_field()
        force_field_path = path.join(temporary_directory, 'ff.offxml')

        with open(force_field_path, 'w') as file:
            file.write(force_field_source.json())

        build_coordinates = BuildCoordinatesPackmol('')

        # Set the maximum number of molecules in the system.
        build_coordinates.max_molecules = 10
        # and the target density (the default 1.0 g/ml is normally fine)
        build_coordinates.mass_density = 0.05 * unit.grams / unit.milliliters
        # and finally the system which coordinates should be generated for.
        build_coordinates.substance = water_substance

        # Build the coordinates, creating a file called output.pdb
        result = build_coordinates.execute(temporary_directory, None)
        assert not isinstance(result, PropertyEstimatorException)

        # Assign some smirnoff force field parameters to the
        # coordinates
        print('Assigning some parameters.')
        assign_force_field_parameters = BuildSmirnoffSystem('')

        assign_force_field_parameters.force_field_path = force_field_path
        assign_force_field_parameters.coordinate_file_path = path.join(
            temporary_directory, 'output.pdb')
        assign_force_field_parameters.substance = water_substance

        result = assign_force_field_parameters.execute(temporary_directory,
                                                       None)
        assert not isinstance(result, PropertyEstimatorException)

        # Do a simple energy minimisation
        print('Performing energy minimisation.')
        energy_minimisation = RunEnergyMinimisation('')

        energy_minimisation.input_coordinate_file = path.join(
            temporary_directory, 'output.pdb')
        energy_minimisation.system_path = assign_force_field_parameters.system_path

        result = energy_minimisation.execute(temporary_directory,
                                             ComputeResources())
        assert not isinstance(result, PropertyEstimatorException)

        npt_equilibration = RunOpenMMSimulation('npt_equilibration')

        npt_equilibration.ensemble = Ensemble.NPT

        npt_equilibration.steps_per_iteration = 20  # Debug settings.
        npt_equilibration.output_frequency = 2  # Debug settings.

        npt_equilibration.thermodynamic_state = thermodynamic_state

        npt_equilibration.input_coordinate_file = path.join(
            temporary_directory, 'minimised.pdb')
        npt_equilibration.system_path = assign_force_field_parameters.system_path

        result = npt_equilibration.execute(temporary_directory,
                                           ComputeResources())
        assert not isinstance(result, PropertyEstimatorException)

        extract_density = ExtractAverageStatistic('extract_density')

        extract_density.statistics_type = ObservableType.Density
        extract_density.statistics_path = path.join(temporary_directory,
                                                    'statistics.csv')

        result = extract_density.execute(temporary_directory,
                                         ComputeResources())
        assert not isinstance(result, PropertyEstimatorException)

        extract_dielectric = ExtractAverageDielectric('extract_dielectric')

        extract_dielectric.thermodynamic_state = thermodynamic_state

        extract_dielectric.input_coordinate_file = path.join(
            temporary_directory, 'input.pdb')
        extract_dielectric.trajectory_path = path.join(temporary_directory,
                                                       'trajectory.dcd')
        extract_dielectric.system_path = assign_force_field_parameters.system_path

        result = extract_dielectric.execute(temporary_directory,
                                            ComputeResources())
        assert not isinstance(result, PropertyEstimatorException)

        extract_uncorrelated_trajectory = ExtractUncorrelatedTrajectoryData(
            'extract_traj')

        extract_uncorrelated_trajectory.statistical_inefficiency = extract_density.statistical_inefficiency
        extract_uncorrelated_trajectory.equilibration_index = extract_density.equilibration_index
        extract_uncorrelated_trajectory.input_coordinate_file = path.join(
            temporary_directory, 'input.pdb')
        extract_uncorrelated_trajectory.input_trajectory_path = path.join(
            temporary_directory, 'trajectory.dcd')

        result = extract_uncorrelated_trajectory.execute(
            temporary_directory, ComputeResources())
        assert not isinstance(result, PropertyEstimatorException)

        extract_uncorrelated_statistics = ExtractUncorrelatedStatisticsData(
            'extract_stats')

        extract_uncorrelated_statistics.statistical_inefficiency = extract_density.statistical_inefficiency
        extract_uncorrelated_statistics.equilibration_index = extract_density.equilibration_index
        extract_uncorrelated_statistics.input_statistics_path = path.join(
            temporary_directory, 'statistics.csv')

        result = extract_uncorrelated_statistics.execute(
            temporary_directory, ComputeResources())
        assert not isinstance(result, PropertyEstimatorException)
class FilterSubstanceByRole(BaseProtocol):
    """A protocol which takes a substance as input, and returns a substance which only
    contains components whose role match a given criteria.
    """

    input_substance = protocol_input(docstring='The substance to filter.',
                                     type_hint=Substance,
                                     default_value=UNDEFINED)

    component_role = protocol_input(
        docstring='The role to filter substance components against.',
        type_hint=Substance.ComponentRole,
        default_value=UNDEFINED)

    expected_components = protocol_input(
        docstring='The number of components expected to remain after filtering. '
        'An exception is raised if this number is not matched.',
        type_hint=int,
        default_value=UNDEFINED,
        optional=True)

    filtered_substance = protocol_output(docstring='The filtered substance.',
                                         type_hint=Substance)

    def execute(self, directory, available_resources):

        filtered_components = []
        total_mole_fraction = 0.0

        for component in self.input_substance.components:

            if component.role != self.component_role:
                continue

            filtered_components.append(component)

            amounts = self.input_substance.get_amounts(component)

            for amount in amounts:

                if not isinstance(amount, Substance.MoleFraction):
                    continue

                total_mole_fraction += amount.value

        if (self.expected_components != UNDEFINED
                and self.expected_components != len(filtered_components)):

            return PropertyEstimatorException(
                directory=directory,
                message=f'The filtered substance does not contain the expected '
                f'number of components ({self.expected_components}) - '
                f'{filtered_components}')

        inverse_mole_fraction = 1.0 if np.isclose(
            total_mole_fraction, 0.0) else 1.0 / total_mole_fraction

        self.filtered_substance = Substance()

        for component in filtered_components:

            amounts = self.input_substance.get_amounts(component)

            for amount in amounts:

                if isinstance(amount, Substance.MoleFraction):
                    amount = Substance.MoleFraction(amount.value *
                                                    inverse_mole_fraction)

                self.filtered_substance.add_component(component, amount)

        return self._get_output_dictionary()
Example #18
0
    def _build_workflow_graph(working_directory, properties,
                              target_force_field_path, stored_data_paths,
                              parameter_gradient_keys, options):
        """Construct a workflow graph, containing all of the workflows which should
        be followed to estimate a set of properties by reweighting.

        Parameters
        ----------
        working_directory: str
            The local directory in which to store all local,
            temporary calculation data from this graph.
        properties : list of PhysicalProperty
            The properties to attempt to compute.
        target_force_field_path : str
            The path to the target force field parameters to use in the workflow.
        stored_data_paths: dict of str and tuple(str, str)
            A dictionary partitioned by substance identifiers, whose values
            are a tuple of a path to a stored simulation data object, and
            its corresponding force field path.
        parameter_gradient_keys: list of ParameterGradientKey
            A list of references to all of the parameters which all observables
            should be differentiated with respect to.
        options: PropertyEstimatorOptions
            The options to run the workflows with.
        """
        workflow_graph = WorkflowGraph(working_directory)

        for property_to_calculate in properties:

            if (not isinstance(property_to_calculate, IReweightable) or
                    not isinstance(property_to_calculate, IWorkflowProperty)):
                # Only properties which implement the IReweightable and
                # IWorkflowProperty interfaces can be reweighted
                continue

            property_type = type(property_to_calculate).__name__

            if property_type not in options.workflow_schemas:

                logging.warning('The reweighting layer does not support {} '
                                'workflows.'.format(property_type))

                continue

            if ReweightingLayer.__name__ not in options.workflow_schemas[
                    property_type]:
                continue

            schema = options.workflow_schemas[property_type][
                ReweightingLayer.__name__]
            workflow_options = options.workflow_options[property_type].get(
                ReweightingLayer.__name__)

            global_metadata = Workflow.generate_default_metadata(
                property_to_calculate, target_force_field_path,
                parameter_gradient_keys, workflow_options)

            substance_id = property_to_calculate.substance.identifier
            data_class_type = property_to_calculate.required_data_class

            if (substance_id not in stored_data_paths
                    or data_class_type not in stored_data_paths[substance_id]):

                # We haven't found and cached data which is compatible with this property.
                continue

            global_metadata['full_system_data'] = stored_data_paths[
                substance_id][data_class_type]
            global_metadata['component_data'] = []

            if property_to_calculate.multi_component_property:

                has_data_for_property = True

                for component in property_to_calculate.substance.components:

                    temporary_substance = Substance()
                    temporary_substance.add_component(
                        component, amount=Substance.MoleFraction())

                    if (temporary_substance.identifier not in stored_data_paths
                            or data_class_type not in stored_data_paths[
                                temporary_substance.identifier]):

                        has_data_for_property = False
                        break

                    global_metadata['component_data'].append(stored_data_paths[
                        temporary_substance.identifier][data_class_type])

                if not has_data_for_property:
                    continue

            workflow = Workflow(property_to_calculate, global_metadata)
            workflow.schema = schema

            from propertyestimator.properties import CalculationSource
            workflow.physical_property.source = CalculationSource(
                fidelity=ReweightingLayer.__name__, provenance={})

            workflow_graph.add_workflow(workflow)

        return workflow_graph