def test_equality(): """Test that equality checks both bounds and units.""" value1 = UniformReal(0, 1, '') value2 = UniformReal(0, 1, 'cm') value3 = UniformReal(0, 2, '') assert value1 == value1 assert value1 != value2 assert value1 != value3 assert value1 != 0.5
def test_simple_deserialization(valid_data): """Ensure that a deserialized Process Spec looks sane.""" process_spec: ProcessSpec = ProcessSpec.build(valid_data) assert process_spec.uids == {'id': valid_data['uids']['id']} assert process_spec.tags == ['baking::cakes', 'danger::low'] assert process_spec.parameters[0] == Parameter(name='oven temp', value=UniformReal( 195, 205, ''), origin='specified') assert process_spec.conditions == [] assert process_spec.template == \ ProcessTemplate('the template', uids={'id': valid_data['template']['uids']['id']}, parameters=[ [ParameterTemplate('oven temp template', bounds=RealBounds(175, 225, ''), uids={'id': valid_data['template']['parameters'][0][0]['uids']['id']}), RealBounds(175, 225, '')] ], description='a long description', allowed_labels=['a', 'b'], allowed_names=['a name']) assert process_spec.name == 'Process 1' assert process_spec.notes == 'make sure to use oven mitts' assert process_spec.file_links == [ FileLink('cake_recipe.txt', 'www.baking.com') ] assert process_spec.typ == 'process_spec'
def test_access_data(): """Demonstrate and test access patterns within the data island.""" binders = { "Polyethylene Glycol 100M": 0.02, "Sodium lignosulfonate": 0.004, "Polyvinyl Acetate": 0.0001 } powders = {"Al2O3": 0.96} island = make_data_island( density=1.0, bulk_modulus=300.0, firing_temperature=750.0, binders=binders, powders=powders, tag="Me" ) # read the density value assert(island.measurements[0].properties[0].value == NominalReal(1.0, '')) # read the bulk modulus value assert(island.measurements[0].properties[1].value == NormalReal(300.0, 3.0, '')) # read the firing temperature assert(island.process.conditions[0].value == UniformReal(749.5, 750.5, 'degC')) assert(island.process.parameters[0].value == DiscreteCategorical({"hot": 1.0})) # read the quantity of alumina quantities = island.process.ingredients[0].material.process.conditions[0].value.quantities assert(list( keyfilter(lambda x: x == "Al2O3", quantities).values() )[0] == 0.96) # check that the serialization results in the correct number of objects in the preface # (note that neither measurements nor ingredients are serialized) assert(len(json.loads(dumps(island))["context"]) == 26)
def test_invalid_instance(): """Calling make_instance on a non-spec should throw a TypeError.""" not_specs = [ MeasurementRun("meas"), Condition("cond"), UniformReal(0, 1, ''), 'foo', 10 ] for not_spec in not_specs: with pytest.raises(TypeError): make_instance(not_spec)
def test_simple_deserialization(valid_data): """Ensure that a deserialized Process Run looks sane.""" process_run: ProcessRun = ProcessRun.build(valid_data) assert process_run.uids == {'id': valid_data['uids']['id'], 'my_id': 'process1-v1'} assert process_run.tags == ['baking::cakes', 'danger::low'] assert process_run.conditions[0] == Condition(name='oven temp', value=NominalReal(203.0, ''), origin='measured') assert process_run.parameters == [] assert process_run.file_links == [] assert process_run.template is None assert process_run.output_material is None assert process_run.spec == \ ProcessSpec(name="Spec for proc 1", uids={'id': valid_data['spec']['uids']['id']}, conditions=[Condition(name='oven temp', value=UniformReal(175, 225, ''), origin='specified')] ) assert process_run.name == 'Process 1' assert process_run.notes == 'make sure to use oven mitts' assert process_run.typ == 'process_run'
def test_bounds_order(): """Lower bound must be <= upper bound.""" UniformReal(4.4, 8.8, 'm') UniformReal(100.0, 100.0, 'm') with pytest.raises(AssertionError): UniformReal(23.2, 18.9, 'm')
assert frying.ingredients == [] oil.process = frying assert oil.process == frying assert boiling.ingredients == [potatoes] assert frying.ingredients == [oil] potatoes.process = frying assert potatoes.process == frying assert boiling.ingredients == [] assert set(frying.ingredients) == {oil, potatoes} VALID_QUANTITIES = [ NominalReal(14.0, ''), UniformReal(0.5, 0.6, 'm'), NormalReal(-0.3, 0.6, "kg") ] INVALID_QUANTITIES = [ NominalCategorical("blue"), NominalInteger(5), EmpiricalFormula("CH4"), 0.33, "0.5" ] @pytest.mark.parametrize("valid_quantity", VALID_QUANTITIES) def test_valid_quantities(valid_quantity): """
def test_invalid_bounds(): """Test that invalid bounds throw the appropriate error.""" with pytest.raises(ValueError): SampleAttributeTemplate(name="name") # Must have a bounds with pytest.raises(TypeError): SampleAttributeTemplate(name="name", bounds=UniformReal(0, 1, ''))
def make_data_island(density, bulk_modulus, firing_temperature, binders, powders, tag=None): """Helper function to create a relatively involved data island.""" binder_specs = keymap(lambda x: MaterialSpec(name=x), binders) powder_specs = keymap(lambda x: MaterialSpec(name=x), powders) binder_runs = keymap(lambda x: MaterialRun(spec=x), binder_specs) powder_runs = keymap(lambda x: MaterialRun(spec=x), powder_specs) all_input_materials = keymap(lambda x: x.spec.name, merge(binder_runs, powder_runs)) mixing_composition = Condition( name="composition", value=NominalComposition(all_input_materials) ) mixing_process = ProcessRun( tags=["mixing"], conditions=[mixing_composition] ) binder_ingredients = [] for run in binder_runs: binder_ingredients.append( IngredientRun( material=run, process=mixing_process, mass_fraction=NominalReal(binders[run.spec.name], ''), ) ) powder_ingredients = [] for run in powder_runs: powder_ingredients.append( IngredientRun( material=run, process=mixing_process, mass_fraction=NominalReal(powders[run.spec.name], ''), ) ) green_sample = MaterialRun(process=mixing_process) measured_firing_temperature = Condition( name="Firing Temperature", value=UniformReal(firing_temperature - 0.5, firing_temperature + 0.5, 'degC'), template=firing_temperature_template ) specified_firing_setting = Parameter( name="Firing setting", value=DiscreteCategorical("hot") ) firing_spec = ProcessSpec(template=firing_template) firing_process = ProcessRun( conditions=[measured_firing_temperature], parameters=[specified_firing_setting], spec=firing_spec ) IngredientRun( green_sample, process=firing_process, mass_fraction=NormalReal(1.0, 0.0, ''), volume_fraction=NormalReal(1.0, 0.0, ''), number_fraction=NormalReal(1.0, 0.0, '') ) measured_density = Property( name="Density", value=NominalReal(density, ''), template=density_template ) measured_modulus = Property( name="Bulk modulus", value=NormalReal(bulk_modulus, bulk_modulus / 100.0, '') ) measurement_spec = MeasurementSpec(template=measurement_template) measurement = MeasurementRun( properties=[measured_density, measured_modulus], spec=measurement_spec ) tags = [tag] if tag else [] material_spec = MaterialSpec(template=material_template) material_run = MaterialRun(process=firing_process, tags=tags, spec=material_spec) measurement.material = material_run return material_run
def make_cake(seed=None): """Define all objects that go into making a demo cake.""" if seed is not None: random.seed(seed) ###################################################################### # Parent Objects tmpl = make_cake_templates() cake_spec = make_cake_spec() ###################################################################### # Objects cake = make_instance(cake_spec) operators = ['gwash', 'jadams', 'thomasj', 'jmadison', 'jmonroe'] cake.process.source = PerformedSource(performed_by=random.choice(operators), performed_date='2015-03-14') # Replace Abstract/In General queue = [cake] while queue: item = queue.pop(0) item.name = item.name.replace('Abstract ', '').replace(', in General', '') if item.spec.tags is not None: item.tags = list(item.spec.tags) if item.spec.notes: # None or empty string item.notes = 'The spec says "{}"'.format(item.spec.notes) if isinstance(item, MaterialRun): queue.append(item.process) elif isinstance(item, ProcessRun): queue.extend(item.ingredients) if item.template.name == "Procurement": item.source = PerformedSource(performed_by='hamilton', performed_date='2015-02-17') else: item.source = cake.process.source elif isinstance(item, IngredientRun): queue.append(item.material) fuzz = 0.95 + 0.1 * random.random() if item.spec.absolute_quantity is not None: item.absolute_quantity = \ NormalReal(mean=fuzz * item.spec.absolute_quantity.nominal, std=0.05 * item.spec.absolute_quantity.nominal, units=item.spec.absolute_quantity.units) if item.spec.volume_fraction is not None: item.volume_fraction = \ NormalReal(mean=fuzz * item.spec.volume_fraction.nominal, std=0.05 * item.spec.volume_fraction.nominal, units=item.spec.volume_fraction.units) if item.spec.mass_fraction is not None: item.mass_fraction = \ UniformReal(lower_bound=(fuzz - 0.05) * item.spec.mass_fraction.nominal, upper_bound=(fuzz + 0.05) * item.spec.mass_fraction.nominal, units=item.spec.mass_fraction.units) if item.spec.number_fraction is not None: item.number_fraction = \ NormalReal(mean=fuzz * item.spec.number_fraction.nominal, std=0.05 * item.spec.number_fraction.nominal, units=item.spec.number_fraction.units) else: raise TypeError("Unexpected object in the queue") frosting = \ next(x.material for x in cake.process.ingredients if 'rosting' in x.name) baked = \ next(x.material for x in cake.process.ingredients if 'aked' in x.name) # Add measurements cake_taste = MeasurementRun(name='Final Taste', material=cake) cake_appearance = MeasurementRun(name='Final Appearance', material=cake) frosting_taste = MeasurementRun(name='Frosting Taste', material=frosting) frosting_sweetness = MeasurementRun(name='Frosting Sweetness', material=frosting) # and spec out the measurements cake_taste.spec = MeasurementSpec(name='Taste') cake_appearance.spec = MeasurementSpec(name='Appearance') frosting_taste.spec = cake_taste.spec # Taste frosting_sweetness.spec = MeasurementSpec(name='Sweetness') ###################################################################### # Let's add some attributes baked.process.conditions.append(Condition(name='Cooking time', template=tmpl['Cooking time'], origin=Origin.MEASURED, value=NominalReal(nominal=48, units='min'))) baked.spec.process.conditions.append(Condition(name='Cooking time', template=tmpl['Cooking time'], origin=Origin.SPECIFIED, value=NormalReal(mean=50, std=5, units='min'))) baked.process.conditions.append(Condition(name='Oven temperature', origin="measured", value=NominalReal(nominal=362, units='degF'))) baked.spec.process.parameters.append(Parameter(name='Oven temperature setting', template=tmpl['Oven temperature setting'], origin="specified", value=NominalReal(nominal=350, units='degF'))) cake_taste.properties.append(Property(name='Tastiness', origin=Origin.MEASURED, template=tmpl['Tastiness'], value=NominalInteger(nominal=5))) cake_appearance.properties.append(Property(name='Visual Appeal', origin=Origin.MEASURED, value=NominalInteger(nominal=5))) frosting_taste.properties.append(Property(name='Tastiness', origin=Origin.MEASURED, template=tmpl['Tastiness'], value=NominalInteger(nominal=4))) frosting_sweetness.properties.append(Property(name='Sweetness (Sucrose-basis)', origin=Origin.MEASURED, value=NominalReal(nominal=1.7, units=''))) baked.process.spec.template = tmpl['Baking in an oven'] cake_taste.spec.template = tmpl['Taste test'] frosting_taste.spec.template = tmpl['Taste test'] cake.spec.template = tmpl['Dessert'] frosting.spec.template = tmpl['Dessert'] # Code to force all scopes to 'id' set_uuids([cake, cake_taste, cake_appearance, frosting_taste, frosting_sweetness], name='id') id_queue = [x for x in cake.process.ingredients] while id_queue: x = id_queue.pop(0) set_uuids([x], name='id') id_queue += x.material.process.ingredients return cake