Beispiel #1
0
    def _get_solvent_dictionary(self):
        """Returns a dictionary of the solvent which will be serialized
        to a yaml file and passed to YANK. In most cases, this should
        just be passing force field settings over, such as PME settings.

        Returns
        -------
        dict of str and Any
            A yaml compatible dictionary of YANK solvents.
        """

        with open(self.force_field_path, 'r') as file:
            force_field_source = SmirnoffForceFieldSource.parse_json(
                file.read())

        force_field = force_field_source.to_force_field()
        charge_method = force_field.get_parameter_handler(
            'Electrostatics').method

        if charge_method.lower() != 'pme':
            raise ValueError(
                'Currently only PME electrostatics are supported.')

        return {
            'default': {
                'nonbonded_method': charge_method,
            }
        }
Beispiel #2
0
def build_tip3p_smirnoff_force_field():
    """Combines the smirnoff99Frosst and tip3p offxml files
    into a single one which can be consumed by the property
    estimator.

    Returns
    -------
    SmirnoffForceFieldSource
        The force field containing both smirnoff99Frosst-1.1.0
        and TIP3P parameters
    """
    from openforcefield.typing.engines.smirnoff import ForceField

    smirnoff_force_field_path = 'smirnoff99Frosst-1.1.0.offxml'
    tip3p_force_field_path = get_data_filename('forcefield/tip3p.offxml')

    smirnoff_force_field_with_tip3p = ForceField(smirnoff_force_field_path,
                                                 tip3p_force_field_path)

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

    force_field_source = SmirnoffForceFieldSource.from_path(
        'smirnoff99Frosst-1.1.0.offxml')

    with tempfile.TemporaryDirectory() as temporary_directory:

        local_storage = LocalFileStorage(temporary_directory)

        force_field_id = local_storage.store_force_field(force_field_source)
        retrieved_force_field = local_storage.retrieve_force_field(
            force_field_id)

        force_field_string = force_field_source.json()
        retrieved_force_field_string = retrieved_force_field.json()

        assert force_field_string == retrieved_force_field_string

        local_storage_new = LocalFileStorage(temporary_directory)
        assert local_storage_new.has_force_field(force_field_source)
Beispiel #4
0
def main():

    setup_timestamp_logging()

    # Load in the force field
    force_field_path = 'smirnoff99Frosst-1.1.0.offxml'
    force_field_source = SmirnoffForceFieldSource.from_path(force_field_path)

    # Load in the data set containing a single dielectric
    # property.
    with open('pure_data_set.json') as file:
        data_set = PhysicalPropertyDataSet.parse_json(file.read())

    data_set.filter_by_property_types('DielectricConstant')

    # Set up the server object which run the calculations.
    setup_server(backend_type=BackendType.LocalGPU,
                 max_number_of_workers=1,
                 port=8001)

    # Request the estimates.
    property_estimator = client.PropertyEstimatorClient(
        client.ConnectionOptions(server_port=8001))

    options = PropertyEstimatorOptions()
    options.allowed_calculation_layers = ['SimulationLayer']

    options.workflow_options = {
        'DielectricConstant': {
            'SimulationLayer':
            WorkflowOptions(WorkflowOptions.ConvergenceMode.NoChecks),
            'ReweightingLayer':
            WorkflowOptions(WorkflowOptions.ConvergenceMode.NoChecks)
        }
    }

    parameter_gradient_keys = [
        ParameterGradientKey(tag='vdW', smirks='[#6X4:1]',
                             attribute='epsilon'),
        ParameterGradientKey(tag='vdW',
                             smirks='[#6X4:1]',
                             attribute='rmin_half')
    ]

    request = property_estimator.request_estimate(
        property_set=data_set,
        force_field_source=force_field_source,
        options=options,
        parameter_gradient_keys=parameter_gradient_keys)

    # Wait for the results.
    results = request.results(True, 5)

    # Save the result to file.
    with open('dielectric_simulation.json', 'wb') as file:

        json_results = json.dumps(results,
                                  sort_keys=True,
                                  indent=2,
                                  separators=(',', ': '),
                                  cls=TypedJSONEncoder)

        file.write(json_results.encode('utf-8'))

    # Attempt to reweight the cached data.
    options.allowed_calculation_layers = ['ReweightingLayer']

    request = property_estimator.request_estimate(
        property_set=data_set,
        force_field_source=force_field_source,
        options=options,
        parameter_gradient_keys=parameter_gradient_keys)

    # Wait for the results.
    results = request.results(True, 5)

    # Save the result to file.
    with open('dielectric_reweight.json', 'wb') as file:

        json_results = json.dumps(results,
                                  sort_keys=True,
                                  indent=2,
                                  separators=(',', ': '),
                                  cls=TypedJSONEncoder)

        file.write(json_results.encode('utf-8'))
def main():

    setup_timestamp_logging()

    # Load in the force field
    force_field_path = 'smirnoff99Frosst-1.1.0.offxml'
    force_field_source = SmirnoffForceFieldSource.from_path(force_field_path)

    # Create a data set containing three solvation free energies.
    data_set = _create_data_set()

    # Set up the compute backend which will run the calculations.
    working_directory = 'working_directory'
    storage_directory = 'storage_directory'

    queue_resources = QueueWorkerResources(
        number_of_threads=1,
        number_of_gpus=1,
        preferred_gpu_toolkit=QueueWorkerResources.GPUToolkit.CUDA,
        per_thread_memory_limit=5 * unit.gigabyte,
        wallclock_time_limit="05:59")

    worker_script_commands = [
        'conda activate propertyestimator', 'module load cuda/10.1'
    ]

    calculation_backend = DaskLSFBackend(
        minimum_number_of_workers=1,
        maximum_number_of_workers=3,
        resources_per_worker=queue_resources,
        queue_name='gpuqueue',
        setup_script_commands=worker_script_commands,
        adaptive_interval='1000ms',
        adaptive_class=CustomAdaptive)

    # Set up a backend to cache simulation data in.
    storage_backend = LocalFileStorage(storage_directory)

    # Spin up the server object.
    PropertyEstimatorServer(calculation_backend=calculation_backend,
                            storage_backend=storage_backend,
                            port=8005,
                            working_directory=working_directory)

    # Request the estimates.
    property_estimator = client.PropertyEstimatorClient(
        client.ConnectionOptions(server_port=8005))

    options = PropertyEstimatorOptions()
    options.allowed_calculation_layers = ['SimulationLayer']

    workflow_options = WorkflowOptions(
        WorkflowOptions.ConvergenceMode.NoChecks)

    options.workflow_options = {
        'SolvationFreeEnergy': {
            'SimulationLayer': workflow_options
        }
    }
    options.workflow_schemas = {
        'SolvationFreeEnergy': {
            'SimulationLayer': _get_fixed_lambda_schema(workflow_options)
        }
    }

    request = property_estimator.request_estimate(
        property_set=data_set,
        force_field_source=force_field_source,
        options=options)

    # Wait for the results.
    results = request.results(True, 5)

    # Save the result to file.
    with open('solvation_free_energy_simulation.json', 'wb') as file:

        json_results = json.dumps(results,
                                  sort_keys=True,
                                  indent=2,
                                  separators=(',', ': '),
                                  cls=TypedJSONEncoder)

        file.write(json_results.encode('utf-8'))
Beispiel #6
0
    def request_estimate(self,
                         property_set,
                         force_field_source,
                         options=None,
                         parameter_gradient_keys=None):
        """Requests that a PropertyEstimatorServer attempt to estimate the
        provided property set using the supplied force field and estimator options.

        Parameters
        ----------
        property_set : PhysicalPropertyDataSet
            The set of properties to attempt to estimate.
        force_field_source : ForceFieldSource or openforcefield.typing.engines.smirnoff.ForceField
            The source of the force field parameters to use for the calculations.
        options : PropertyEstimatorOptions, optional
            A set of estimator options. If None, default options
            will be used.
        parameter_gradient_keys: list of ParameterGradientKey, optional
            A list of references to all of the parameters which all observables
            should be differentiated with respect to.

        Returns
        -------
        PropertyEstimatorClient.Request
            An object which will provide access the the results of the request.
        """
        from openforcefield.typing.engines import smirnoff

        if property_set is None or force_field_source is None:

            raise ValueError('Both a data set and force field source must be '
                             'present to compute physical properties.')

        if options is None:
            options = PropertyEstimatorOptions()

        if isinstance(force_field_source, smirnoff.ForceField):
            force_field_source = SmirnoffForceFieldSource.from_object(
                force_field_source)

        if len(options.allowed_calculation_layers) == 0:
            raise ValueError(
                'A submission contains no allowed calculation layers.')

        properties_list = []
        property_types = set()

        # Refactor the properties into a list, and extract the types
        # of properties to be estimated (e.g 'Denisty', 'DielectricConstant').
        for substance_tag in property_set.properties:

            for physical_property in property_set.properties[substance_tag]:

                properties_list.append(physical_property)

                type_name = type(physical_property).__name__

                if type_name not in registered_properties:
                    raise ValueError(
                        f'The property estimator does not support {type_name} properties.'
                    )

                if type_name in property_types:
                    continue

                property_types.add(type_name)

        if options.workflow_options is None:
            options.workflow_options = {}

        # Assign default workflows in the cases where the user hasn't
        # provided one, and validate all of the workflows to be used
        # in the estimation.
        for type_name in property_types:

            if type_name not in options.workflow_schemas:
                options.workflow_schemas[type_name] = {}

            if type_name not in options.workflow_options:
                options.workflow_options[type_name] = {}

            for calculation_layer in options.allowed_calculation_layers:

                property_type = registered_properties[type_name]()

                if (calculation_layer
                        not in options.workflow_options[type_name] or
                        options.workflow_options[type_name][calculation_layer]
                        is None):

                    options.workflow_options[type_name][
                        calculation_layer] = WorkflowOptions()

                if (calculation_layer
                        not in options.workflow_schemas[type_name] or
                        options.workflow_schemas[type_name][calculation_layer]
                        is None):

                    default_schema = property_type.get_default_workflow_schema(
                        calculation_layer,
                        options.workflow_options[type_name][calculation_layer])

                    options.workflow_schemas[type_name][
                        calculation_layer] = default_schema

                workflow = options.workflow_schemas[type_name][
                    calculation_layer]

                if workflow is None:
                    # Not all properties may support every calculation layer.
                    continue

                # Handle the cases where some protocol types should be replaced with
                # others.
                workflow.replace_protocol_types(
                    options.workflow_options[type_name]
                    [calculation_layer].protocol_replacements)

                # Will raise the correct exception for non-valid interfaces.
                workflow.validate_interfaces()

                # Enforce the global option of whether to allow merging or not.
                for protocol_schema_name in workflow.protocols:

                    protocol_schema = workflow.protocols[protocol_schema_name]

                    if not options.allow_protocol_merging:
                        protocol_schema.inputs['.allow_merging'] = False

        submission = PropertyEstimatorSubmission(
            properties=properties_list,
            force_field_source=force_field_source,
            options=options,
            parameter_gradient_keys=parameter_gradient_keys)

        request_id = IOLoop.current().run_sync(
            lambda: self._send_calculations_to_server(submission))

        request_object = PropertyEstimatorClient.Request(
            request_id, self._connection_options, self)

        return request_object
def main():
    """The main script which will create an estimation server, request
    the curated data set be estimated for each force field of interest,
    wait for the calculations to be complete, and save the results.
    """

    setup_timestamp_logging()
    logger = logging.getLogger()

    # Define those force fields to use in the calculations
    force_field_sources = {
        'smirnoff99frosst 1.1.0':
        SmirnoffForceFieldSource.from_path('smirnoff99Frosst-1.1.0.offxml'),
        'parsley 0.0.9':
        SmirnoffForceFieldSource.from_path('smirnoff_release_1_v0_0_9.offxml'),
        'parsley rc 1':
        SmirnoffForceFieldSource.from_path('openff_hbonds-1.0.0-RC1.offxml'),
        'gaff 1.81':
        TLeapForceFieldSource(leap_source='leaprc.gaff'),
        'gaff 2.11':
        TLeapForceFieldSource(leap_source='leaprc.gaff2')
    }

    # Set up the server object which will run the calculations.
    setup_server(max_number_of_workers=50)

    # Set up the client which will request the estimates.
    estimator_client = PropertyEstimatorClient()

    # Load in the data set to estimate.
    with open('curated_data_set.json') as file:
        data_set = PhysicalPropertyDataSet.parse_json(file.read())

    # Specify the estimation options
    protocol_replacements = {
        'gaff_1': {
            'BuildSmirnoffSystem': 'BuildTLeapSystem'
        },
        'gaff_2': {
            'BuildSmirnoffSystem': 'BuildTLeapSystem'
        }
    }

    requests = {}

    # Request estimates using each force field, storing the request
    # object used to query the status of the results.
    for force_field_key in force_field_sources:

        force_field_source = force_field_sources[force_field_key]

        options = get_estimation_options(
            protocol_replacements.get(force_field_key, {}))

        requests[force_field_key] = estimator_client.request_estimate(
            property_set=data_set,
            force_field_source=force_field_source,
            options=options)

    # Wait for the results.
    should_run = True
    finished_force_fields = []

    while should_run:

        sleep(60)

        for force_field_key in force_field_sources:

            if force_field_key in finished_force_fields:
                continue

            results = requests[force_field_key].results(False)

            if isinstance(results, PropertyEstimatorResult) and len(
                    results.queued_properties) > 0:
                continue

            logger.info(f'The server has completed {force_field_key}.')

            # Save the result to file.
            save_results(force_field_key, results)
            finished_force_fields.append(force_field_key)

        if len(finished_force_fields) == len(force_field_sources):
            should_run = False