def test_base_layer(): properties_to_estimate = [ create_dummy_property(Density), create_dummy_property(Density), ] dummy_options = RequestOptions() batch = server.Batch() batch.queued_properties = properties_to_estimate batch.options = dummy_options batch.force_field_id = "" batch.options.calculation_schemas = { "Density": { "DummyCalculationLayer": CalculationLayerSchema() } } with tempfile.TemporaryDirectory() as temporary_directory: with temporarily_change_directory(temporary_directory): # Create a simple calculation backend to test with. test_backend = DaskLocalCluster() test_backend.start() # Create a simple storage backend to test with. test_storage = LocalFileStorage() layer_directory = "dummy_layer" makedirs(layer_directory) def dummy_callback(returned_request): assert len(returned_request.estimated_properties) == 1 assert len(returned_request.exceptions) == 2 dummy_layer = DummyCalculationLayer() dummy_layer.schedule_calculation( test_backend, test_storage, layer_directory, batch, dummy_callback, True, )
def test_workflow_schema_merging( calculation_layer, property_type, workflow_merge_function ): """Tests that two of the exact the same calculations get merged into one by the `WorkflowGraph`.""" schema = registered_calculation_schemas[calculation_layer][property_type] if callable(schema): schema = schema() if not isinstance(schema, WorkflowCalculationSchema): pytest.skip("Not a `WorkflowCalculationSchema`.") property_class = getattr(openff.evaluator.properties, property_type) dummy_property = create_dummy_property(property_class) global_metadata = create_dummy_metadata(dummy_property, calculation_layer) workflow_a = Workflow(global_metadata, "workflow_a") workflow_a.schema = schema.workflow_schema workflow_b = Workflow(global_metadata, "workflow_b") workflow_b.schema = schema.workflow_schema workflow_graph = workflow_merge_function(workflow_a, workflow_b) workflow_graph_a = workflow_a.to_graph() workflow_graph_b = workflow_b.to_graph() dependants_graph_a = workflow_graph_a._protocol_graph._build_dependants_graph( workflow_graph_a.protocols, False, apply_reduction=True ) dependants_graph_b = workflow_graph_b._protocol_graph._build_dependants_graph( workflow_graph_b.protocols, False, apply_reduction=True ) ordered_dict_a = OrderedDict(sorted(dependants_graph_a.items())) ordered_dict_a = {key: sorted(value) for key, value in ordered_dict_a.items()} ordered_dict_b = OrderedDict(sorted(dependants_graph_b.items())) ordered_dict_b = {key: sorted(value) for key, value in ordered_dict_b.items()} merge_order_a = graph.topological_sort(ordered_dict_a) merge_order_b = graph.topological_sort(ordered_dict_b) assert len(workflow_graph.protocols) == len(workflow_a.protocols) for protocol_id in workflow_a.protocols: assert protocol_id in workflow_graph.protocols for protocol_id_A, protocol_id_B in zip(merge_order_a, merge_order_b): assert protocol_id_A == protocol_id_B assert ( workflow_a.protocols[protocol_id_A].schema.json() == workflow_b.protocols[protocol_id_B].schema.json() )
def test_properties_by_type(): density = create_dummy_property(Density) dielectric = create_dummy_property(DielectricConstant) data_set = PhysicalPropertyDataSet() data_set.add_properties(density, dielectric) densities = [x for x in data_set.properties_by_type("Density")] assert len(densities) == 1 assert densities[0] == density dielectrics = [ x for x in data_set.properties_by_type("DielectricConstant") ] assert len(dielectrics) == 1 assert dielectrics[0] == dielectric
def test_sources_substances(): physical_property = create_dummy_property(Density) data_set = PhysicalPropertyDataSet() data_set.add_properties(physical_property) assert next(iter(data_set.sources)) == physical_property.source assert next(iter(data_set.substances)) == physical_property.substance
def test_launch_batch(): # Set up a dummy data set data_set = PhysicalPropertyDataSet() data_set.add_properties(create_dummy_property(Density), create_dummy_property(Density)) batch = Batch() batch.force_field_id = "" batch.options = RequestOptions() batch.options.calculation_layers = ["QuickCalculationLayer"] batch.options.calculation_schemas = { "Density": { "QuickCalculationLayer": CalculationLayerSchema() } } batch.parameter_gradient_keys = [] batch.queued_properties = [*data_set] batch.validate() with tempfile.TemporaryDirectory() as directory: with temporarily_change_directory(directory): with DaskLocalCluster() as calculation_backend: server = EvaluatorServer( calculation_backend=calculation_backend, working_directory=directory, ) server._queued_batches[batch.id] = batch server._launch_batch(batch) while len(batch.queued_properties) > 0: sleep(0.01) assert len(batch.estimated_properties) == 1 assert len(batch.unsuccessful_properties) == 1
def test_serialization(): """A test to ensure that data sets are JSON serializable.""" data_set = PhysicalPropertyDataSet() data_set.add_properties(create_dummy_property(Density)) data_set_json = data_set.json() parsed_data_set = PhysicalPropertyDataSet.parse_json(data_set_json) assert len(data_set) == len(parsed_data_set) parsed_data_set_json = parsed_data_set.json() assert parsed_data_set_json == data_set_json
def test_protocol_replacement(force_field_source, expected_protocol_type): data_set = PhysicalPropertyDataSet() for property_type in property_types: physical_property = create_dummy_property(property_type) data_set.add_properties(physical_property) options = EvaluatorClient.default_request_options(data_set, force_field_source) options_json = options.json(format=True) assert options_json.find('BaseBuildSystem"') < 0 assert options_json.find(expected_protocol_type) >= 0
def test_physical_property_state_methods(): dummy_property = create_dummy_property(Density) property_state = dummy_property.__getstate__() recreated_property = Density() recreated_property.__setstate__(property_state) recreated_state = recreated_property.__getstate__() original_json = json.dumps(property_state, cls=TypedJSONEncoder) recreated_json = json.dumps(recreated_state, cls=TypedJSONEncoder) assert original_json == recreated_json
def test_serialize_layer_result(): """Tests that the `CalculationLayerResult` can be properly serialized and deserialized.""" dummy_result = CalculationLayerResult() dummy_result.physical_property = create_dummy_property(Density) dummy_result.exceptions = [EvaluatorException()] dummy_result.data_to_store = [("dummy_object_path", "dummy_directory")] dummy_result_json = json.dumps(dummy_result, cls=TypedJSONEncoder) recreated_result = json.loads(dummy_result_json, cls=TypedJSONDecoder) recreated_result_json = json.dumps(recreated_result, cls=TypedJSONEncoder) assert recreated_result_json == dummy_result_json
def test_nested_replicators(): dummy_schema = WorkflowSchema() dummy_protocol = DummyReplicableProtocol("dummy_$(rep_a)_$(rep_b)") dummy_protocol.replicated_value_a = ReplicatorValue("rep_a") dummy_protocol.replicated_value_b = ReplicatorValue("rep_b") dummy_schema.protocol_schemas = [dummy_protocol.schema] replicator_a = ProtocolReplicator(replicator_id="rep_a") replicator_a.template_values = ["a", "b"] replicator_b = ProtocolReplicator(replicator_id="rep_b") replicator_b.template_values = [1, 2] dummy_schema.protocol_replicators = [replicator_a, replicator_b] dummy_schema.validate() dummy_property = create_dummy_property(Density) dummy_metadata = Workflow.generate_default_metadata( dummy_property, "smirnoff99Frosst-1.1.0.offxml", []) dummy_workflow = Workflow(dummy_metadata, "") dummy_workflow.schema = dummy_schema assert len(dummy_workflow.protocols) == 4 assert dummy_workflow.protocols["dummy_0_0"].replicated_value_a == "a" assert dummy_workflow.protocols["dummy_0_1"].replicated_value_a == "a" assert dummy_workflow.protocols["dummy_1_0"].replicated_value_a == "b" assert dummy_workflow.protocols["dummy_1_1"].replicated_value_a == "b" assert dummy_workflow.protocols["dummy_0_0"].replicated_value_b == 1 assert dummy_workflow.protocols["dummy_0_1"].replicated_value_b == 2 assert dummy_workflow.protocols["dummy_1_0"].replicated_value_b == 1 assert dummy_workflow.protocols["dummy_1_1"].replicated_value_b == 2 print(dummy_workflow.schema)
def test_default_options(): """Test creating the default estimation options.""" data_set = PhysicalPropertyDataSet() force_field_source = SmirnoffForceFieldSource.from_path( "smirnoff99Frosst-1.1.0.offxml") for property_type in property_types: physical_property = create_dummy_property(property_type) data_set.add_properties(physical_property) options = EvaluatorClient.default_request_options(data_set, force_field_source) options.validate() assert len(options.calculation_layers) == 2 assert len(options.calculation_schemas) == len(property_types) assert all( len(x) == len(options.calculation_layers) for x in options.calculation_schemas.values())
def test_advanced_nested_replicators(): dummy_schema = WorkflowSchema() replicator_a = ProtocolReplicator(replicator_id="replicator_a") replicator_a.template_values = ["a", "b"] replicator_b = ProtocolReplicator( replicator_id=f"replicator_b_{replicator_a.placeholder_id}") replicator_b.template_values = ProtocolPath( f"dummy_list[{replicator_a.placeholder_id}]", "global") dummy_protocol = DummyReplicableProtocol(f"dummy_" f"{replicator_a.placeholder_id}_" f"{replicator_b.placeholder_id}") dummy_protocol.replicated_value_a = ReplicatorValue(replicator_a.id) dummy_protocol.replicated_value_b = ReplicatorValue(replicator_b.id) dummy_schema.protocol_schemas = [dummy_protocol.schema] dummy_schema.protocol_replicators = [replicator_a, replicator_b] dummy_schema.validate() dummy_property = create_dummy_property(Density) dummy_metadata = Workflow.generate_default_metadata( dummy_property, "smirnoff99Frosst-1.1.0.offxml", []) dummy_metadata["dummy_list"] = [[1], [2]] dummy_workflow = Workflow(dummy_metadata, "") dummy_workflow.schema = dummy_schema assert len(dummy_workflow.protocols) == 2 assert dummy_workflow.protocols["dummy_0_0"].replicated_value_a == "a" assert dummy_workflow.protocols["dummy_0_0"].replicated_value_b == 1 assert dummy_workflow.protocols["dummy_1_0"].replicated_value_a == "b" assert dummy_workflow.protocols["dummy_1_0"].replicated_value_b == 2
def test_group_replicators(): dummy_schema = WorkflowSchema() replicator_id = "replicator" dummy_replicated_protocol = DummyInputOutputProtocol( f"dummy_$({replicator_id})") dummy_replicated_protocol.input_value = ReplicatorValue(replicator_id) dummy_group = ProtocolGroup("dummy_group") dummy_group.add_protocols(dummy_replicated_protocol) dummy_protocol_single_value = DummyInputOutputProtocol( f"dummy_single_$({replicator_id})") dummy_protocol_single_value.input_value = ProtocolPath( "output_value", dummy_group.id, dummy_replicated_protocol.id) dummy_protocol_list_value = AddValues("dummy_list") dummy_protocol_list_value.values = ProtocolPath( "output_value", dummy_group.id, dummy_replicated_protocol.id) dummy_schema.protocol_schemas = [ dummy_group.schema, dummy_protocol_single_value.schema, dummy_protocol_list_value.schema, ] replicator = ProtocolReplicator(replicator_id) replicator.template_values = [ (1.0 * unit.kelvin).plus_minus(1.0 * unit.kelvin), (2.0 * unit.kelvin).plus_minus(2.0 * unit.kelvin), ] dummy_schema.protocol_replicators = [replicator] dummy_schema.validate() dummy_property = create_dummy_property(Density) dummy_metadata = Workflow.generate_default_metadata( dummy_property, "smirnoff99Frosst-1.1.0.offxml", []) dummy_workflow = Workflow(dummy_metadata, "") dummy_workflow.schema = dummy_schema assert len(dummy_workflow.protocols) == 4 assert (dummy_workflow.protocols[dummy_group.id].protocols["dummy_0"]. input_value.value == replicator.template_values[0].value) assert (dummy_workflow.protocols[dummy_group.id].protocols["dummy_1"]. input_value.value == replicator.template_values[1].value) assert dummy_workflow.protocols[ "dummy_single_0"].input_value == ProtocolPath("output_value", dummy_group.id, "dummy_0") assert dummy_workflow.protocols[ "dummy_single_1"].input_value == ProtocolPath("output_value", dummy_group.id, "dummy_1") assert len(dummy_workflow.protocols["dummy_list"].values) == 2 assert dummy_workflow.protocols["dummy_list"].values[0] == ProtocolPath( "output_value", dummy_group.id, "dummy_0") assert dummy_workflow.protocols["dummy_list"].values[1] == ProtocolPath( "output_value", dummy_group.id, "dummy_1")
def test_workflow_layer(): """Test the `WorkflowLayer` calculation layer. As the `SimulationLayer` is the simplest implementation of the abstract layer, we settle for testing this.""" properties_to_estimate = [ create_dummy_property(Density), create_dummy_property(Density), ] # Create a very simple workflow which just returns some placeholder # value. estimated_value = Observable( (1 * unit.kelvin).plus_minus(0.1 * unit.kelvin)) protocol_a = DummyProtocol("protocol_a") protocol_a.input_value = estimated_value schema = WorkflowSchema() schema.protocol_schemas = [protocol_a.schema] schema.final_value_source = ProtocolPath("output_value", protocol_a.id) layer_schema = SimulationSchema() layer_schema.workflow_schema = schema options = RequestOptions() options.add_schema("SimulationLayer", "Density", layer_schema) batch = server.Batch() batch.queued_properties = properties_to_estimate batch.options = options with tempfile.TemporaryDirectory() as directory: with temporarily_change_directory(directory): # Create a directory for the layer. layer_directory = "simulation_layer" os.makedirs(layer_directory) # Set-up a simple storage backend and add a force field to it. force_field = SmirnoffForceFieldSource.from_path( "smirnoff99Frosst-1.1.0.offxml") storage_backend = LocalFileStorage() batch.force_field_id = storage_backend.store_force_field( force_field) # Create a simple calculation backend to test with. with DaskLocalCluster() as calculation_backend: def dummy_callback(returned_request): assert len(returned_request.estimated_properties) == 2 assert len(returned_request.exceptions) == 0 simulation_layer = SimulationLayer() simulation_layer.schedule_calculation( calculation_backend, storage_backend, layer_directory, batch, dummy_callback, True, )
def test_physical_property_id_generation(): dummy_property_1 = create_dummy_property(Density) dummy_property_2 = create_dummy_property(Density) assert dummy_property_1.id != dummy_property_2.id