Exemple #1
0
def test_to_pandas():
    """A test to ensure that data sets are convertable to pandas objects."""

    source = CalculationSource('Dummy', {})

    pure_substance = Substance.from_components('C')
    binary_substance = Substance.from_components('C', 'O')

    data_set = PhysicalPropertyDataSet()

    data_set.properties[pure_substance.identifier] = []
    data_set.properties[binary_substance.identifier] = []

    for temperature in [298 * unit.kelvin, 300 * unit.kelvin, 302 * unit.kelvin]:

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

        density_property = Density(thermodynamic_state=thermodynamic_state,
                                   phase=PropertyPhase.Liquid,
                                   substance=pure_substance,
                                   value=1 * unit.gram / unit.milliliter,
                                   uncertainty=0.11 * unit.gram / unit.milliliter,
                                   source=source)

        dielectric_property = DielectricConstant(thermodynamic_state=thermodynamic_state,
                                                 phase=PropertyPhase.Liquid,
                                                 substance=pure_substance,
                                                 value=1 * unit.dimensionless,
                                                 uncertainty=0.11 * unit.dimensionless,
                                                 source=source)

        data_set.properties[pure_substance.identifier].append(density_property)
        data_set.properties[pure_substance.identifier].append(dielectric_property)

    for temperature in [298 * unit.kelvin, 300 * unit.kelvin, 302 * unit.kelvin]:

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

        enthalpy_property = EnthalpyOfMixing(thermodynamic_state=thermodynamic_state,
                                             phase=PropertyPhase.Liquid,
                                             substance=binary_substance,
                                             value=1 * unit.kilojoules / unit.mole,
                                             uncertainty=0.11 * unit.kilojoules / unit.mole,
                                             source=source)

        excess_property = ExcessMolarVolume(thermodynamic_state=thermodynamic_state,
                                            phase=PropertyPhase.Liquid,
                                            substance=binary_substance,
                                            value=1 * unit.meter**3 / unit.mole,
                                            uncertainty=0.11 * unit.meter**3 / unit.mole,
                                            source=source)

        data_set.properties[binary_substance.identifier].append(enthalpy_property)
        data_set.properties[binary_substance.identifier].append(excess_property)

    data_set_pandas = data_set.to_pandas()

    assert data_set_pandas is not None
    assert len(data_set_pandas) == 6
    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()
Exemple #3
0
def test_weight_by_mole_fraction_protocol(component_smiles, value):

    full_substance = Substance.from_components('C', 'CC', 'CCC')
    component = Substance.from_components(component_smiles)

    mole_fraction = next(iter(full_substance.get_amounts(component_smiles))).value

    with tempfile.TemporaryDirectory() as temporary_directory:

        weight_protocol = WeightByMoleFraction('weight')
        weight_protocol.value = value
        weight_protocol.full_substance = full_substance
        weight_protocol.component = component

        result = weight_protocol.execute(temporary_directory, ComputeResources())

        assert not isinstance(result, PropertyEstimatorException)
        assert weight_protocol.weighted_value == value * mole_fraction
    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
Exemple #5
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
def test_local_simulation_storage():
    """A simple test to that force fields can be stored and
    retrieved using the local storage backend."""

    substance = Substance.from_components(r'C', r'C/C=C/C=C/COC(=O)',
                                          r'CCOC(=O)/C=C(/C)\O')

    dummy_simulation_data = StoredSimulationData()

    dummy_simulation_data.thermodynamic_state = ThermodynamicState(
        298.0 * unit.kelvin, 1.0 * unit.atmosphere)

    dummy_simulation_data.statistical_inefficiency = 1.0
    dummy_simulation_data.force_field_id = 'tmp_ff_id'

    dummy_simulation_data.substance = substance

    with tempfile.TemporaryDirectory() as base_directory:

        temporary_data_directory = os.path.join(base_directory, 'temp_data')
        temporary_backend_directory = os.path.join(base_directory,
                                                   'storage_dir')

        os.makedirs(temporary_data_directory)
        os.makedirs(temporary_backend_directory)

        local_storage = LocalFileStorage(temporary_backend_directory)
        dummy_simulation_data.unique_id = local_storage.store_simulation_data(
            dummy_simulation_data, temporary_data_directory)

        retrieved_data_directories = local_storage.retrieve_simulation_data(
            substance)

        assert substance.identifier in retrieved_data_directories
        assert len(retrieved_data_directories[substance.identifier]) == 1

        retrieved_data, retrieved_data_directory = retrieved_data_directories[
            substance.identifier][0]

        assert dummy_simulation_data.thermodynamic_state == retrieved_data.thermodynamic_state
        assert dummy_simulation_data.statistical_inefficiency == retrieved_data.statistical_inefficiency
        assert dummy_simulation_data.force_field_id == retrieved_data.force_field_id
        assert dummy_simulation_data.substance == retrieved_data.substance

        local_storage_new = LocalFileStorage(temporary_backend_directory)

        retrieved_data, retrieved_data_directory = local_storage_new.retrieve_simulation_data_by_id(
            dummy_simulation_data.unique_id)

        assert retrieved_data is not None
        assert os.path.isdir(retrieved_data_directory)
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()
Exemple #8
0
def test_calculate_reduced_potential_openmm():

    substance = Substance.from_components('O')
    thermodynamic_state = ThermodynamicState(298 * unit.kelvin,
                                             1.0 * unit.atmosphere)

    with tempfile.TemporaryDirectory() as directory:
        force_field_path = path.join(directory, 'ff.json')

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

        build_coordinates = BuildCoordinatesPackmol('build_coordinates')
        build_coordinates.max_molecules = 10
        build_coordinates.mass_density = 0.05 * unit.grams / unit.milliliters
        build_coordinates.substance = substance
        build_coordinates.execute(directory, None)

        assign_parameters = BuildSmirnoffSystem(f'assign_parameters')
        assign_parameters.force_field_path = force_field_path
        assign_parameters.coordinate_file_path = build_coordinates.coordinate_file_path
        assign_parameters.substance = substance
        assign_parameters.execute(directory, None)

        reduced_potentials = CalculateReducedPotentialOpenMM(f'reduced_potentials')
        reduced_potentials.substance = substance
        reduced_potentials.thermodynamic_state = thermodynamic_state
        reduced_potentials.reference_force_field_paths = [force_field_path]
        reduced_potentials.system_path = assign_parameters.system_path
        reduced_potentials.trajectory_file_path = get_data_filename('test/trajectories/water.dcd')
        reduced_potentials.coordinate_file_path = get_data_filename('test/trajectories/water.pdb')
        reduced_potentials.kinetic_energies_path = get_data_filename('test/statistics/stats_pandas.csv')
        reduced_potentials.high_precision = False

        result = reduced_potentials.execute(directory, ComputeResources())

        assert not isinstance(result, PropertyEstimatorException)
        assert path.isfile(reduced_potentials.statistics_file_path)

        final_array = StatisticsArray.from_pandas_csv(reduced_potentials.statistics_file_path)
        assert ObservableType.ReducedPotential in final_array
def _setup_dummy_system(directory):

    force_field_path = path.join(directory, 'ff.json')

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

    substance = Substance.from_components('C')

    build_coordinates = BuildCoordinatesPackmol('build_coordinates')
    build_coordinates.max_molecules = 1
    build_coordinates.mass_density = 0.001 * unit.grams / unit.milliliters
    build_coordinates.substance = substance
    build_coordinates.execute(directory, None)

    assign_parameters = BuildSmirnoffSystem(f'assign_parameters')
    assign_parameters.force_field_path = force_field_path
    assign_parameters.coordinate_file_path = build_coordinates.coordinate_file_path
    assign_parameters.substance = substance
    assign_parameters.execute(directory, None)

    return build_coordinates.coordinate_file_path, assign_parameters.system_path
def test_gradient_reduced_potentials(use_subset):

    substance = Substance.from_components('O')
    thermodynamic_state = ThermodynamicState(298 * unit.kelvin,
                                             1.0 * unit.atmosphere)

    with tempfile.TemporaryDirectory() as directory:

        force_field_path = path.join(directory, 'ff.json')

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

        reduced_potentials = GradientReducedPotentials(f'reduced_potentials')
        reduced_potentials.substance = substance
        reduced_potentials.thermodynamic_state = thermodynamic_state
        reduced_potentials.reference_force_field_paths = [force_field_path]
        reduced_potentials.reference_statistics_path = get_data_filename(
            'test/statistics/stats_pandas.csv')
        reduced_potentials.force_field_path = force_field_path
        reduced_potentials.trajectory_file_path = get_data_filename(
            'test/trajectories/water.dcd')
        reduced_potentials.coordinate_file_path = get_data_filename(
            'test/trajectories/water.pdb')
        reduced_potentials.use_subset_of_force_field = use_subset
        reduced_potentials.enable_pbc = True
        reduced_potentials.parameter_key = ParameterGradientKey(
            'vdW', '[#1]-[#8X2H2+0:1]-[#1]', 'epsilon')

        result = reduced_potentials.execute(directory, ComputeResources())
        assert not isinstance(result, PropertyEstimatorException)

        assert path.isfile(reduced_potentials.forward_potentials_path)
        assert path.isfile(reduced_potentials.reverse_potentials_path)

        for reference_path in reduced_potentials.reference_force_field_paths:
            assert path.isfile(reference_path)
Exemple #11
0
def generate_trajectories():
    """Generates trajectories to subsample.
    """

    setup_timestamp_logging()

    logger = logging.getLogger()

    substance = Substance.from_components('C(C(C(C(C(F)(F)Br)(F)F)(F)F)(F)F)(C(C(C(F)(F)F)(F)F)(F)F)(F)F')

    logger.info('Building system.')

    build_system = BuildSmirnoffSystem('build_system')
    build_system.coordinate_file_path = 'coords.pdb'
    build_system.substance = substance
    build_system.force_field_path = 'smirnoff99Frosst-1.1.0.offxml'
    build_system.execute('', None)

    logger.info('System built.')

    production_simulation = RunOpenMMSimulation(f'production_simulation')
    production_simulation.steps_per_iteration = 500
    production_simulation.output_frequency = 1
    production_simulation.timestep = 2.0 * unit.femtosecond
    production_simulation.thermodynamic_state = ThermodynamicState(temperature=298.15*unit.kelvin,
                                                                   pressure=1.0*unit.atmosphere)
    production_simulation.input_coordinate_file = 'coords.pdb'
    production_simulation.system_path = 'system.xml'

    compute_resources = ComputeResources(number_of_threads=4)

    logger.info(f'Simulation started.')
    production_simulation_schema = production_simulation.schema
    production_simulation.execute('', compute_resources)
    production_simulation.schema = production_simulation_schema
    logger.info(f'Simulation finished.')
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
Exemple #13
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
Exemple #14
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)
Exemple #15
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)
Exemple #16
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
Exemple #17
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
    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
Exemple #20
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
Exemple #21
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
    def get_default_simulation_workflow_schema(options=None):
        """Returns the default workflow to use when estimating this property
        from direct simulations.

        Parameters
        ----------
        options: WorkflowOptions
            The default options to use when setting up the estimation workflow.

        Returns
        -------
        WorkflowSchema
            The schema to follow when estimating this property.
        """

        # Setup the fully solvated systems.
        build_full_coordinates = coordinates.BuildCoordinatesPackmol(
            'build_solvated_coordinates')
        build_full_coordinates.substance = ProtocolPath('substance', 'global')
        build_full_coordinates.max_molecules = 2000

        assign_full_parameters = forcefield.BuildSmirnoffSystem(
            f'assign_solvated_parameters')
        assign_full_parameters.force_field_path = ProtocolPath(
            'force_field_path', 'global')
        assign_full_parameters.substance = ProtocolPath('substance', 'global')
        assign_full_parameters.coordinate_file_path = ProtocolPath(
            'coordinate_file_path', build_full_coordinates.id)

        # Perform a quick minimisation of the full system to give
        # YANK a better starting point for its minimisation.
        energy_minimisation = simulation.RunEnergyMinimisation(
            'energy_minimisation')
        energy_minimisation.system_path = ProtocolPath(
            'system_path', assign_full_parameters.id)
        energy_minimisation.input_coordinate_file = ProtocolPath(
            'coordinate_file_path', build_full_coordinates.id)

        equilibration_simulation = simulation.RunOpenMMSimulation(
            'equilibration_simulation')
        equilibration_simulation.ensemble = Ensemble.NPT
        equilibration_simulation.steps_per_iteration = 100000
        equilibration_simulation.output_frequency = 10000
        equilibration_simulation.timestep = 2.0 * unit.femtosecond
        equilibration_simulation.thermodynamic_state = ProtocolPath(
            'thermodynamic_state', 'global')
        equilibration_simulation.system_path = ProtocolPath(
            'system_path', assign_full_parameters.id)
        equilibration_simulation.input_coordinate_file = ProtocolPath(
            'output_coordinate_file', energy_minimisation.id)

        # Create a substance which only contains the solute (e.g. for the
        # vacuum phase simulations).
        filter_solvent = miscellaneous.FilterSubstanceByRole('filter_solvent')
        filter_solvent.input_substance = ProtocolPath('substance', 'global')
        filter_solvent.component_role = Substance.ComponentRole.Solvent

        filter_solute = miscellaneous.FilterSubstanceByRole('filter_solute')
        filter_solute.input_substance = ProtocolPath('substance', 'global')
        filter_solute.component_role = Substance.ComponentRole.Solute

        # Setup the solute in vacuum system.
        build_vacuum_coordinates = coordinates.BuildCoordinatesPackmol(
            'build_vacuum_coordinates')
        build_vacuum_coordinates.substance = ProtocolPath(
            'filtered_substance', filter_solute.id)
        build_vacuum_coordinates.max_molecules = 1

        assign_vacuum_parameters = forcefield.BuildSmirnoffSystem(
            f'assign_parameters')
        assign_vacuum_parameters.force_field_path = ProtocolPath(
            'force_field_path', 'global')
        assign_vacuum_parameters.substance = ProtocolPath(
            'filtered_substance', filter_solute.id)
        assign_vacuum_parameters.coordinate_file_path = ProtocolPath(
            'coordinate_file_path', build_vacuum_coordinates.id)

        # Set up the protocol to run yank.
        run_yank = yank.SolvationYankProtocol('run_solvation_yank')
        run_yank.solute = ProtocolPath('filtered_substance', filter_solute.id)
        run_yank.solvent_1 = ProtocolPath('filtered_substance',
                                          filter_solvent.id)
        run_yank.solvent_2 = Substance()
        run_yank.thermodynamic_state = ProtocolPath('thermodynamic_state',
                                                    'global')
        run_yank.steps_per_iteration = 500
        run_yank.checkpoint_interval = 50
        run_yank.solvent_1_coordinates = ProtocolPath(
            'output_coordinate_file', equilibration_simulation.id)
        run_yank.solvent_1_system = ProtocolPath('system_path',
                                                 assign_full_parameters.id)
        run_yank.solvent_2_coordinates = ProtocolPath(
            'coordinate_file_path', build_vacuum_coordinates.id)
        run_yank.solvent_2_system = ProtocolPath('system_path',
                                                 assign_vacuum_parameters.id)

        # Set up the group which will run yank until the free energy has been determined to within
        # a given uncertainty
        conditional_group = groups.ConditionalGroup(f'conditional_group')
        conditional_group.max_iterations = 20

        if options.convergence_mode != WorkflowOptions.ConvergenceMode.NoChecks:

            condition = groups.ConditionalGroup.Condition()
            condition.condition_type = groups.ConditionalGroup.ConditionType.LessThan
            condition.right_hand_value = ProtocolPath('target_uncertainty',
                                                      'global')
            condition.left_hand_value = ProtocolPath(
                'estimated_free_energy.uncertainty', conditional_group.id,
                run_yank.id)

            conditional_group.add_condition(condition)

        # Define the total number of iterations that yank should run for.
        total_iterations = miscellaneous.MultiplyValue('total_iterations')
        total_iterations.value = 2000
        total_iterations.multiplier = ProtocolPath('current_iteration',
                                                   conditional_group.id)

        # Make sure the simulations gets extended after each iteration.
        run_yank.number_of_iterations = ProtocolPath('result',
                                                     total_iterations.id)

        conditional_group.add_protocols(total_iterations, run_yank)

        # Define the full workflow schema.
        schema = WorkflowSchema(property_type=SolvationFreeEnergy.__name__)
        schema.id = '{}{}'.format(SolvationFreeEnergy.__name__, 'Schema')

        schema.protocols = {
            build_full_coordinates.id: build_full_coordinates.schema,
            assign_full_parameters.id: assign_full_parameters.schema,
            energy_minimisation.id: energy_minimisation.schema,
            equilibration_simulation.id: equilibration_simulation.schema,
            filter_solvent.id: filter_solvent.schema,
            filter_solute.id: filter_solute.schema,
            build_vacuum_coordinates.id: build_vacuum_coordinates.schema,
            assign_vacuum_parameters.id: assign_vacuum_parameters.schema,
            conditional_group.id: conditional_group.schema
        }

        schema.final_value_source = ProtocolPath('estimated_free_energy',
                                                 conditional_group.id,
                                                 run_yank.id)
        return schema
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)
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
Exemple #25
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
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)
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()