コード例 #1
0
def test_material_spec():
    """Test that Process/Material Spec link survives serialization."""
    # Create a ProcessSpec
    proc_spec = ProcessSpec(name="a process spec", tags=["tag1", "tag2"])

    # Create MaterialSpec without a ProcessSpec
    prop = Property(name="The material is a solid",
                    value=DiscreteCategorical(probabilities="solid"))
    mat_spec = MaterialSpec(name="a material spec",
                            properties=PropertyAndConditions(prop))
    assert mat_spec.process is None, \
        "MaterialSpec should be initialized with no ProcessSpec, by default"

    # Assign a ProcessSpec to mat_spec, first ensuring that the type is enforced
    with pytest.raises(TypeError):
        mat_spec.process = 17
    mat_spec.process = proc_spec

    # Assert circular links
    assert dumps(proc_spec.output_material.process) == dumps(proc_spec), \
        "ProcessSpec should link to MaterialSpec that links back to itself"

    assert dumps(mat_spec.process.output_material) == dumps(mat_spec), \
        "MaterialSpec should link to ProcessSpec that links back to itself"

    # Make copies of both specs
    mat_spec_copy = loads(dumps(mat_spec))
    proc_spec_copy = loads(dumps(proc_spec))

    assert proc_spec_copy.output_material == mat_spec, \
        "Serialization should preserve link from ProcessSpec to MaterialSpec"

    assert mat_spec_copy.process == proc_spec, \
        "Serialization should preserve link from MaterialSpec to ProcessSpec"
コード例 #2
0
def test_material_run():
    """
    Test the ability to create a MaterialRun that is linked to a MaterialSpec.

    Make sure all enumerated values are respected, and check consistency after
    serializing and deserializing.
    """
    # Define a property, and make sure that an inappropriate value for origin throws ValueError
    with pytest.raises(ValueError):
        prop = Property(name="A property", origin="bad origin", value=NominalReal(17, units=''))

    # Create a MaterialSpec with a property
    prop = Property(name="A property", origin="specified", value=NominalReal(17, units=''))
    mat_spec = MaterialSpec(
        name="a specification for a material",
        properties=PropertyAndConditions(prop),
        notes="Funny lookin'"
    )

    # Make sure that when property is serialized, origin (an enumeration) is serialized as a string
    copy_prop = json.loads(dumps(mat_spec))
    copy_origin = copy_prop["context"][0]["properties"][0]['property']['origin']
    assert isinstance(copy_origin, str)

    # Create a MaterialRun, and make sure an inappropriate value for sample_type throws ValueError
    with pytest.raises(ValueError):
        mat = MaterialRun("name", spec=mat_spec, sample_type="imaginary")
    mat = MaterialRun("name", spec=mat_spec, sample_type="virtual")

    # ensure that serialization does not change the MaterialRun
    copy = loads(dumps(mat))
    assert dumps(copy) == dumps(mat), \
        "Material run is modified by serialization or deserialization"
コード例 #3
0
def test_build():
    """Test that build recreates the material."""
    spec = MaterialSpec("A spec",
                        properties=PropertyAndConditions(
                            property=Property("a property", value=NominalReal(3, ''))),
                        tags=["a tag"])
    mat = MaterialRun(name="a material", spec=spec)
    mat_dict = mat.as_dict()
    mat_dict['spec'] = mat.spec.as_dict()
    assert MaterialRun.build(mat_dict) == mat
コード例 #4
0
def test_mat_spec_properties(caplog):
    """Make sure template validations and level controls behave as expected."""
    prop_tmpl = PropertyTemplate("Name", bounds=IntegerBounds(0, 2))
    cond_tmpl = ConditionTemplate("Name", bounds=IntegerBounds(0, 2))
    mat_tmpl = MaterialTemplate("Material Template", properties=[[prop_tmpl, IntegerBounds(0, 1)]])
    mat_spec = MaterialSpec("Material Spec", template=mat_tmpl)
    good_prop = PropertyAndConditions(
        property=Property("Name", value=NominalInteger(1), template=prop_tmpl),
        conditions=[Condition("Name", value=NominalInteger(1), template=cond_tmpl)]
    )
    bad_prop = PropertyAndConditions(
        property=Property("Name", value=NominalInteger(2), template=prop_tmpl),
        conditions=[Condition("Name", value=NominalInteger(1), template=cond_tmpl)]
    )
    bad_cond = PropertyAndConditions(  # This will pass since we don't have a condition constraint
        property=Property("Name", value=NominalInteger(1), template=prop_tmpl),
        conditions=[Condition("Name", value=NominalInteger(2), template=cond_tmpl)]
    )
    with validation_level(WarningLevel.IGNORE):
        mat_spec.properties.append(good_prop)
        assert len(caplog.records) == 0, "Warning encountered on IGNORE"
        mat_spec.properties.append(bad_prop)
        assert len(caplog.records) == 0, "Warning encountered on IGNORE"
        mat_spec.properties.append(bad_cond)
        assert len(caplog.records) == 0, "Warning encountered on IGNORE"
    with validation_level(WarningLevel.WARNING):
        mat_spec.properties.append(good_prop)
        assert len(caplog.records) == 0, "Warning encountered on Good value"
        mat_spec.properties.append(bad_prop)
        assert len(caplog.records) == 1, "No warning encountered on Bad Value"
        mat_spec.properties.append(bad_cond)
        assert len(caplog.records) == 1, "Warning encountered on Bad condition"
    with validation_level(WarningLevel.FATAL):
        mat_spec.properties.append(good_prop)  # This is fine
        with pytest.raises(ValueError):
            mat_spec.properties.append(bad_prop)
        mat_spec.properties.append(bad_cond)  # This should probably not be fine
コード例 #5
0
def add_attribute(target: Union[HasProperties, HasConditions, HasParameters],
                  template: Union[PropertyTemplate, ConditionTemplate, ParameterTemplate],
                  value: Union[BaseValue, str, float, int]
                  ) -> Union[Property, Condition, Parameter]:
    """
    Generate an attribute, and then add it attribute to a GEMD object.

    Parameters
    ----------
    target: BaseObject
        The object to attach the attribute to
    template: AttributeTemplate
        The AttributeTemplate for the attribute.
    value: Union[BaseValue, str, float, int])
        The value for the attribute.  Accepts any GEMD Value type, or will
        attempt to generate an appropriate Value given a str, float or int.

    Returns
    --------
    BaseAttribute
        The generated attribute

    """
    attribute = make_attribute(template=template, value=value)
    attr_class = type(attribute)

    if isinstance(target, MaterialSpec):
        if attr_class is Property:
            target.properties.append(PropertyAndConditions(property=attribute))
        elif attr_class is Condition:
            if len(target.properties) == 0:
                raise ValueError("Cannot add a condition to a MaterialSpec "
                                 "before it has at least one property.")
            target.properties[-1].conditions.append(attribute)
        else:
            raise ValueError(f"Attribute {attr_class} is incompatible with target {type(target)}.")
    else:  # All other target types
        if attr_class is Property and isinstance(target, HasProperties):
            target.properties.append(attribute)
        elif attr_class is Condition and isinstance(target, HasConditions):
            target.conditions.append(attribute)
        elif attr_class is Parameter and isinstance(target, HasParameters):
            target.parameters.append(attribute)
        else:
            raise ValueError(f"A {attr_class} cannot be added to a {type(target)}.")

    return attribute
コード例 #6
0
def test_dependencies():
    """Test that dependency lists make sense."""
    prop = PropertyTemplate(name="name", bounds=IntegerBounds(0, 1))
    cond = ConditionTemplate(name="name", bounds=IntegerBounds(0, 1))

    template = MaterialTemplate("measurement template")
    spec = MaterialSpec("A spec", template=template,
                        properties=[PropertyAndConditions(
                            property=Property("name", template=prop, value=NominalInteger(1)),
                            conditions=[
                                Condition("name", template=cond, value=NominalInteger(1))
                            ]
                        )])

    assert template in spec.all_dependencies()
    assert cond in spec.all_dependencies()
    assert prop in spec.all_dependencies()
コード例 #7
0
def test_equality():
    """Test that equality check works as expected."""
    spec = MaterialSpec("A spec",
                        properties=PropertyAndConditions(
                            property=Property("a property", value=NominalReal(3, ''))),
                        tags=["a tag"])
    mat1 = MaterialRun("A material", spec=spec)
    mat2 = MaterialRun("A material", spec=spec, tags=["A tag"])
    assert mat1 == deepcopy(mat1)
    assert mat1 != mat2
    assert mat1 != "A material"

    mat3 = deepcopy(mat1)
    assert mat1 == mat3, "Copy somehow failed"
    MeasurementRun("A measurement", material=mat3)
    assert mat1 != mat3

    mat4 = deepcopy(mat3)
    assert mat4 == mat3, "Copy somehow failed"
    mat4.measurements[0].tags.append('A tag')
    assert mat4 != mat3

    mat5 = next(x for x in flatten(mat4, 'test-scope') if isinstance(x, MaterialRun))
    assert mat5 == mat4, "Flattening removes measurement references, but that's okay"
コード例 #8
0
def test_mixins():
    """Measurement templates have all 3 mixin traits."""
    obj = MeasurementTemplate(
        "Name",
        properties=[PropertyTemplate("Name", bounds=IntegerBounds(0, 1))],
        conditions=[ConditionTemplate("Name", bounds=IntegerBounds(0, 1))],
        parameters=[ParameterTemplate("Name", bounds=IntegerBounds(0, 1))],
    )
    with pytest.raises(TypeError):
        obj.properties.append(
            ConditionTemplate("3", bounds=IntegerBounds(0, 5)))
    with pytest.raises(TypeError):
        obj.properties.append(
            ParameterTemplate("3", bounds=IntegerBounds(0, 5)))

    with pytest.raises(TypeError):
        obj.conditions.append(PropertyTemplate("3", bounds=IntegerBounds(0,
                                                                         5)))
    with pytest.raises(TypeError):
        obj.conditions.append(
            ParameterTemplate("3", bounds=IntegerBounds(0, 5)))

    with pytest.raises(TypeError):
        obj.parameters.append(
            ConditionTemplate("3", bounds=IntegerBounds(0, 5)))
    with pytest.raises(TypeError):
        obj.parameters.append(PropertyTemplate("3", bounds=IntegerBounds(0,
                                                                         5)))

    with pytest.raises(TypeError):  # You passed a `scalar` to extend
        obj.properties.extend((PropertyTemplate("3",
                                                bounds=IntegerBounds(0, 5)),
                               IntegerBounds(1, 3)))

    with pytest.raises(ValueError):  # You passed a `scalar` to extend
        obj.properties = (PropertyTemplate("3", bounds=IntegerBounds(1, 3)),
                          IntegerBounds(0, 5))

    obj.properties.append(
        (PropertyTemplate("2", bounds=IntegerBounds(0,
                                                    5)), IntegerBounds(1, 3)))
    obj.properties.extend([
        PropertyTemplate("3", bounds=IntegerBounds(0, 5)),
        (PropertyTemplate("4", bounds=IntegerBounds(0,
                                                    5)), IntegerBounds(1, 3))
    ])
    obj.conditions.insert(1, ConditionTemplate("2", bounds=IntegerBounds(0,
                                                                         1)))
    obj.parameters[0] = ParameterTemplate("Name", bounds=IntegerBounds(0, 1))

    for x in (obj.properties, obj.conditions, obj.parameters):
        assert isinstance(x, ValidList)
        for y in x:
            assert isinstance(y, list)
            assert len(y) == 2
            assert isinstance(y[0], AttributeTemplate)
            if y[1] is not None:
                assert isinstance(y[1], BaseBounds)

    second = MeasurementTemplate(
        "Name",
        properties=[
            PropertyTemplate("Name", bounds=IntegerBounds(0, 1)),
            IntegerBounds(0, 1)
        ],
        conditions=[
            ConditionTemplate("Name", bounds=IntegerBounds(0, 1)),
            IntegerBounds(0, 1)
        ],
        parameters=[
            ParameterTemplate("Name", bounds=IntegerBounds(0, 1)),
            IntegerBounds(0, 1)
        ],
    )
    assert len(second.properties) == 1
    assert len(second.conditions) == 1
    assert len(second.parameters) == 1

    good_val = NominalInteger(1)
    bad_val = NominalInteger(2)

    assert second.validate_condition(Condition("Other name",
                                               value=good_val,
                                               template=second.conditions[0][0])), \
        "Condition with template and good value didn't validate."
    assert not second.validate_condition(Condition("Other name",
                                                   value=bad_val,
                                                   template=second.conditions[0][0])), \
        "Condition with template and bad value DID validate."
    assert second.validate_parameter(Parameter("Other name",
                                               value=good_val,
                                               template=second.parameters[0][0])), \
        "Parameter with template and good value didn't validate."
    assert not second.validate_parameter(Parameter("Other name",
                                                   value=bad_val,
                                                   template=second.parameters[0][0])), \
        "Parameter with template and bad value DID validate."
    assert second.validate_property(Property("Other name",
                                             value=good_val,
                                             template=second.properties[0][0])), \
        "Property with template and good value didn't validate."
    assert not second.validate_property(Property("Other name",
                                                 value=bad_val,
                                                 template=second.properties[0][0])), \
        "Property with template and bad value DID validate."

    assert second.validate_condition(Condition("Name", value=good_val)), \
        "Condition without template and good value didn't validate."
    assert not second.validate_condition(Condition("Name", value=bad_val)), \
        "Condition without template and bad value DID validate."
    assert second.validate_parameter(Parameter("Name", value=good_val)), \
        "Parameter without template and good value didn't validate."
    assert not second.validate_parameter(Parameter("Name", value=bad_val)), \
        "Parameter without template and bad value DID validate."
    assert second.validate_property(Property("Name", value=good_val)), \
        "Property without template and good value didn't validate."
    assert not second.validate_property(Property("Name", value=bad_val)), \
        "Property without template and bad value DID validate."

    assert second.validate_condition(Condition("Other name", value=bad_val)), \
        "Unmatched condition and bad value didn't validate."
    assert second.validate_parameter(Parameter("Other name", value=bad_val)), \
        "Unmatched parameter and bad value didn't validate."
    assert second.validate_property(Property("Other name", value=bad_val)), \
        "Unmatched property and bad value didn't validate."

    second.conditions[0][1] = None
    second.parameters[0][1] = None
    second.properties[0][1] = None
    assert second.validate_condition(Condition("Name", value=good_val)), \
        "Condition and good value with passthrough didn't validate."
    assert second.validate_parameter(Parameter("Name", value=good_val)), \
        "Parameter and good value with passthrough didn't validate."
    assert second.validate_property(Property("Name", value=good_val)), \
        "Property and good value with passthrough didn't validate."
    assert second.validate_property(
        PropertyAndConditions(property=Property("Name", value=good_val))), \
        "PropertyAndConditions didn't fall back to Property."
コード例 #9
0
def make_cake_spec(tmpl=None):
    """Define a recipe for making a cake."""
    ###############################################################################################
    # Templates
    if tmpl is None:
        tmpl = make_cake_templates()

    def _make_ingredient(*, material, process, **kwargs):
        """Convenience method to utilize material fields in creating an ingredient's arguments."""
        return IngredientSpec(name=material.name.lower(),
                              tags=list(material.tags),
                              material=material,
                              process=process,
                              uids={
                                  DEMO_SCOPE:
                                  "{}--{}".format(material.uids[DEMO_SCOPE],
                                                  process.uids[DEMO_SCOPE])
                              },
                              **kwargs)

    def _make_material(*, material_name, template, process_tmpl_name,
                       process_kwargs, **material_kwargs):
        """Convenience method to reuse material name in creating a material's arguments."""
        process_name = "{} {}".format(process_tmpl_name, material_name)
        return MaterialSpec(
            name=material_name,
            uids={DEMO_SCOPE: material_name.lower().replace(' ', '-')},
            template=template,
            process=ProcessSpec(
                name=process_name,
                uids={DEMO_SCOPE: process_name.lower().replace(' ', '-')},
                template=tmpl[process_tmpl_name],
                **process_kwargs),
            **material_kwargs)

    ###############################################################################################
    # Objects
    cake_obj = _make_material(
        material_name="Cake",
        process_tmpl_name="Icing",
        process_kwargs={
            "tags": ['spreading'],
            "notes": 'The act of covering a baked output with frosting'
        },
        template=tmpl["Dessert"],
        properties=[
            PropertyAndConditions(
                Property(name="Tastiness",
                         value=NominalInteger(5),
                         template=tmpl["Tastiness"],
                         origin="specified"))
        ],
        file_links=FileLink(
            filename="Becky's Butter Cake",
            url='https://www.landolakes.com/recipe/16730/becky-s-butter-cake/'
        ),
        tags=['cake::butter cake', 'dessert::baked::cake', 'iced::chocolate'],
        notes=
        'Butter cake recipe reminiscent of the 1-2-3-4 cake that Grandma may have baked.'
    )

    ########################
    frosting = _make_material(
        material_name="Frosting",
        process_tmpl_name="Mixing",
        process_kwargs={
            "tags": ['mixing'],
            "parameters": [
                Parameter(name='Mixer speed setting',
                          template=tmpl['Mixer speed setting'],
                          origin='specified',
                          value=NominalInteger(2))
            ],
            "notes":
            'Combining ingredients to make a sweet frosting'
        },
        template=tmpl["Dessert"],
        tags=['frosting::chocolate', 'topping::chocolate'],
        notes='Chocolate frosting')
    _make_ingredient(material=frosting,
                     notes='Seems like a lot of frosting',
                     labels=['coating'],
                     process=cake_obj.process,
                     absolute_quantity=NominalReal(nominal=0.751, units='kg'))

    baked_cake = _make_material(
        material_name="Baked Cake",
        process_tmpl_name="Baking",
        process_kwargs={
            "tags": ['oven::baking'],
            "conditions": [
                Condition(name='Cooking time',
                          template=tmpl['Cooking time'],
                          origin=Origin.SPECIFIED,
                          value=NormalReal(mean=50, std=5, units='min'))
            ],
            "parameters": [
                Parameter(name='Oven temperature setting',
                          template=tmpl['Oven temperature setting'],
                          origin="specified",
                          value=NominalReal(nominal=350, units='degF'))
            ],
            "notes":
            'Using heat to convert batter into a solid matrix'
        },
        template=tmpl["Baked Good"],
        properties=[
            PropertyAndConditions(
                property=Property(name="Toothpick test",
                                  value=NominalCategorical("completely clean"),
                                  template=tmpl["Toothpick test"])),
            PropertyAndConditions(
                property=Property(name="Color",
                                  value=NominalCategorical("Golden brown"),
                                  template=tmpl["Color"],
                                  origin="specified"))
        ],
        tags=['substrate'],
        notes='The cakey part of the cake')
    _make_ingredient(material=baked_cake,
                     labels=['substrate'],
                     process=cake_obj.process)

    ########################
    batter = _make_material(
        material_name="Batter",
        process_tmpl_name="Mixing",
        process_kwargs={
            "tags": ['mixing'],
            "parameters": [
                Parameter(name='Mixer speed setting',
                          template=tmpl['Mixer speed setting'],
                          origin='specified',
                          value=NominalInteger(2))
            ],
            "notes":
            'Combining ingredients to make a baking feedstock'
        },
        template=tmpl["Generic Material"],
        tags=['mixture'],
        notes='The fluid that converts to cake with heat')
    _make_ingredient(material=batter,
                     labels=['precursor'],
                     process=baked_cake.process)

    ########################
    wetmix = _make_material(
        material_name="Wet Ingredients",
        process_tmpl_name="Mixing",
        process_kwargs={
            "tags": ['mixing'],
            "parameters": [
                Parameter(name='Mixer speed setting',
                          template=tmpl['Mixer speed setting'],
                          origin='specified',
                          value=NominalInteger(2))
            ],
            "notes":
            'Combining wet ingredients to make a baking feedstock'
        },
        template=tmpl["Generic Material"],
        tags=["mixture"],
        notes='The wet fraction of a batter')
    _make_ingredient(material=wetmix, labels=['wet'], process=batter.process)

    drymix = _make_material(
        material_name="Dry Ingredients",
        process_tmpl_name="Mixing",
        process_kwargs={
            "tags": ['mixing'],
            "notes": 'Combining dry ingredients to make a baking feedstock'
        },
        template=tmpl["Generic Material"],
        tags=["mixture"],
        notes='The dry fraction of a batter')
    _make_ingredient(material=drymix,
                     labels=['dry'],
                     process=batter.process,
                     absolute_quantity=NominalReal(nominal=3.052,
                                                   units='cups'))

    ########################
    flour = _make_material(
        material_name="Flour",
        process_tmpl_name="Procuring",
        process_kwargs={
            "tags": ['purchase::dry-goods'],
            "notes": 'Purchasing all purpose flour'
        },
        template=tmpl["Nutritional Material"],
        properties=[
            PropertyAndConditions(
                property=Property(name="Nutritional Information",
                                  value=NominalComposition({
                                      "dietary-fiber":
                                      1,
                                      "sugars":
                                      1,
                                      "other-carbohydrate":
                                      20,
                                      "protein":
                                      4,
                                      "other":
                                      4
                                  }),
                                  template=tmpl["Nutritional Information"],
                                  origin="specified"),
                conditions=Condition(name="Serving Size",
                                     value=NominalReal(30, 'g'),
                                     template=tmpl["Sample Mass"],
                                     origin="specified"))
        ],
        tags=['raw material', 'flour', 'dry-goods'],
        notes='All-purpose flour')
    _make_ingredient(
        material=flour,
        labels=['dry'],
        process=drymix.process,
        volume_fraction=NominalReal(nominal=0.9829, units='')  # 3 cups
    )

    baking_powder = _make_material(
        material_name="Baking Powder",
        process_tmpl_name="Procuring",
        process_kwargs={
            "tags": ['purchase::dry-goods'],
            "notes": 'Purchasing baking powder'
        },
        template=tmpl["Generic Material"],
        tags=['raw material', 'leavening', 'dry-goods'],
        notes='Leavening agent for cake')
    _make_ingredient(
        material=baking_powder,
        labels=['leavening', 'dry'],
        process=drymix.process,
        volume_fraction=NominalReal(nominal=0.0137, units='')  # 2 teaspoons
    )

    salt = _make_material(material_name="Salt",
                          process_tmpl_name="Procuring",
                          process_kwargs={
                              "tags": ['purchase::dry-goods'],
                              "notes": 'Purchasing salt'
                          },
                          template=tmpl["Formulaic Material"],
                          tags=['raw material', 'seasoning', 'dry-goods'],
                          notes='Plain old NaCl',
                          properties=[
                              PropertyAndConditions(
                                  Property(name='Formula',
                                           value=EmpiricalFormula("NaCl")))
                          ])
    _make_ingredient(
        material=salt,
        labels=['dry', 'seasoning'],
        process=drymix.process,
        volume_fraction=NominalReal(nominal=0.0034, units='')  # 1/2 teaspoon
    )

    sugar = _make_material(
        material_name="Sugar",
        process_tmpl_name="Procuring",
        process_kwargs={
            "tags": ['purchase::dry-goods'],
            "notes": 'Purchasing granulated sugar'
        },
        template=tmpl["Formulaic Material"],
        tags=['raw material', 'sweetener', 'dry-goods'],
        notes='Sugar',
        properties=[
            PropertyAndConditions(
                Property(name="Formula", value=EmpiricalFormula("C12H22O11"))),
            PropertyAndConditions(
                Property(name='SMILES',
                         value=Smiles(
                             "C(C1C(C(C(C(O1)OC2(C(C(C(O2)CO)O)O)CO)O)O)O)O"),
                         template=tmpl["Molecular Structure"]))
        ])
    _make_ingredient(material=sugar,
                     labels=['wet', 'sweetener'],
                     process=wetmix.process,
                     absolute_quantity=NominalReal(nominal=2, units='cups'))

    butter = _make_material(
        material_name="Butter",
        process_tmpl_name="Procuring",
        process_kwargs={
            "tags": ['purchase::produce'],
            "notes": 'Purchasing butter'
        },
        template=tmpl["Generic Material"],
        tags=['raw material', 'produce', 'shortening', 'dairy'],
        notes='Shortening for making rich, buttery baked goods')
    _make_ingredient(material=butter,
                     labels=['wet', 'shortening'],
                     process=wetmix.process,
                     absolute_quantity=NominalReal(nominal=1, units='cups'))
    _make_ingredient(
        material=butter,
        labels=['shortening'],
        process=frosting.process,
        mass_fraction=NominalReal(nominal=0.1434,
                                  units='')  # 1/2 c @ 0.911 g/cc
    )

    eggs = _make_material(material_name="Eggs",
                          process_tmpl_name="Procuring",
                          process_kwargs={
                              "tags": ['purchase::produce'],
                              "notes": 'Purchasing eggs'
                          },
                          template=tmpl["Generic Material"],
                          tags=[
                              'raw material',
                              'produce',
                          ],
                          notes='A custard waiting to happen')
    _make_ingredient(material=eggs,
                     labels=['wet'],
                     process=wetmix.process,
                     absolute_quantity=NominalReal(nominal=4, units=''))

    vanilla = _make_material(
        material_name="Vanilla",
        process_tmpl_name="Procuring",
        process_kwargs={
            "tags": ['purchase::solution'],
            "notes": 'Purchasing vanilla'
        },
        template=tmpl["Generic Material"],
        tags=['raw material', 'seasoning'],
        notes=
        'Vanilla Extract is mostly alcohol but the most important component '
        'is vanillin (see attached structure)',
        properties=[
            PropertyAndConditions(
                Property(
                    name='Component Structure',
                    value=InChI(
                        "InChI=1S/C8H8O3/c1-11-8-4-6(5-9)2-3-7(8)10/h2-5,10H,1H3"
                    ),
                    template=tmpl["Molecular Structure"]))
        ])
    _make_ingredient(material=vanilla,
                     labels=['wet', 'flavoring'],
                     process=wetmix.process,
                     absolute_quantity=NominalReal(nominal=2,
                                                   units='teaspoons'))
    _make_ingredient(
        material=vanilla,
        labels=['flavoring'],
        process=frosting.process,
        mass_fraction=NominalReal(nominal=0.0231,
                                  units='')  # 2 tsp @ 0.879 g/cc
    )

    milk = _make_material(material_name="Milk",
                          process_tmpl_name="Procuring",
                          process_kwargs={
                              "tags": ['purchase::produce'],
                              "notes": 'Purchasing milk'
                          },
                          template=tmpl["Generic Material"],
                          tags=['raw material', 'produce', 'dairy'],
                          notes='')
    _make_ingredient(material=milk,
                     labels=['wet'],
                     process=batter.process,
                     absolute_quantity=NominalReal(nominal=1, units='cup'))
    _make_ingredient(
        material=milk,
        labels=[],
        process=frosting.process,
        mass_fraction=NominalReal(nominal=0.0816,
                                  units='')  # 1/4 c @ 1.037 g/cc
    )

    chocolate = _make_material(material_name="Chocolate",
                               process_tmpl_name="Procuring",
                               process_kwargs={
                                   "tags": ['purchase::dry-goods'],
                                   "notes": 'Purchasing chocolate'
                               },
                               template=tmpl["Generic Material"],
                               tags=['raw material'],
                               notes='')
    _make_ingredient(
        material=chocolate,
        labels=['flavoring'],
        process=frosting.process,
        mass_fraction=NominalReal(nominal=0.1132, units='')  # 3 oz.
    )

    powder_sugar = _make_material(
        material_name="Powdered Sugar",
        process_tmpl_name="Procuring",
        process_kwargs={
            "tags": ['purchase::dry-goods'],
            "notes": 'Purchasing powdered sugar'
        },
        template=tmpl["Generic Material"],
        tags=['raw material', 'sweetener', 'dry-goods'],
        notes='Granulated sugar mixed with corn starch')
    _make_ingredient(
        material=powder_sugar,
        labels=['flavoring'],
        process=frosting.process,
        mass_fraction=NominalReal(nominal=0.6387,
                                  units='')  # 4 c @ 30 g/ 0.25 cups
    )

    return cake_obj
コード例 #10
0
ファイル: cake.py プロジェクト: ventura-rivera/gemd-python
def make_cake_spec(tmpl=None):
    """Define a recipe for making a cake."""
    ###############################################################################################
    # Templates
    if tmpl is None:
        tmpl = make_cake_templates()

    count = dict()

    def ingredient_kwargs(material):
        # Pulls the elements of a material that all ingredients consume out
        count[material.name] = count.get(material.name, 0) + 1
        return {
            "name":
            "{} input{}".format(material.name.replace('Abstract ', ''),
                                " (Again)" * (count[material.name] - 1)),
            "tags":
            list(material.tags),
            "material":
            material
        }

    ###############################################################################################
    # Objects
    cake = MaterialSpec(
        name="Abstract Cake",
        template=tmpl["Dessert"],
        process=ProcessSpec(
            name='Icing Cake, in General',
            template=tmpl["Icing"],
            tags=['spreading'],
            notes='The act of covering a baked output with frosting'),
        properties=[
            PropertyAndConditions(
                Property(name="Tastiness",
                         value=NominalInteger(5),
                         template=tmpl["Tastiness"],
                         origin="specified"))
        ],
        file_links=FileLink(
            filename="Becky's Butter Cake",
            url='https://www.landolakes.com/recipe/16730/becky-s-butter-cake/'
        ),
        tags=['cake::butter cake', 'dessert::baked::cake', 'iced::chocolate'],
        notes=
        'Butter cake recipe reminiscent of the 1-2-3-4 cake that Grandma may have baked.'
    )

    ########################
    frosting = MaterialSpec(
        name="Abstract Frosting",
        template=tmpl["Dessert"],
        process=ProcessSpec(
            name='Mixing Frosting, in General',
            template=tmpl["Mixing"],
            tags=['mixing'],
            notes='Combining ingredients to make a sweet frosting'),
        tags=['frosting::chocolate', 'topping::chocolate'],
        notes='Chocolate frosting')
    IngredientSpec(**ingredient_kwargs(frosting),
                   notes='Seems like a lot of frosting',
                   labels=['coating'],
                   process=cake.process,
                   absolute_quantity=NominalReal(nominal=0.751, units='kg'))

    baked_cake = MaterialSpec(
        name="Abstract Baked Cake",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Baking, in General',
            template=tmpl["Baking in an oven"],
            tags=['oven::baking'],
            notes='Using heat to convert batter into a solid matrix'),
        tags=[],
        notes='The cakey part of the cake')
    IngredientSpec(**ingredient_kwargs(baked_cake),
                   labels=['substrate'],
                   process=cake.process)

    ########################
    batter = MaterialSpec(
        name="Abstract Batter",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Mixing Batter, in General',
            template=tmpl["Mixing"],
            tags=['mixing'],
            notes='Combining ingredients to make a baking feedstock'),
        tags=[],
        notes='The fluid that converts to cake with heat')
    IngredientSpec(**ingredient_kwargs(batter),
                   labels=['precursor'],
                   process=baked_cake.process)

    ########################
    wetmix = MaterialSpec(
        name="Abstract Wet Mix",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Mixing Wet, in General',
            template=tmpl["Mixing"],
            tags=['mixing'],
            notes='Combining wet ingredients to make a baking feedstock'),
        tags=[],
        notes='The wet fraction of a batter')
    IngredientSpec(**ingredient_kwargs(wetmix),
                   labels=['wet'],
                   process=batter.process)

    drymix = MaterialSpec(
        name="Abstract Dry Mix",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Mixing Dry, in General',
            template=tmpl["Mixing"],
            tags=['mixing'],
            notes='Combining dry ingredients to make a baking feedstock'),
        tags=[],
        notes='The dry fraction of a batter')
    IngredientSpec(**ingredient_kwargs(drymix),
                   labels=['dry'],
                   process=batter.process,
                   absolute_quantity=NominalReal(nominal=3.052, units='cups'))

    ########################
    flour = MaterialSpec(
        name="Abstract Flour",
        template=tmpl["Nutritional Material"],
        properties=[
            PropertyAndConditions(
                property=Property(name="Nutritional Information",
                                  value=NominalComposition({
                                      "dietary-fiber":
                                      1,
                                      "sugars":
                                      1,
                                      "other-carbohydrate":
                                      20,
                                      "protein":
                                      4,
                                      "other":
                                      4
                                  }),
                                  template=tmpl["Nutritional Information"],
                                  origin="specified"),
                conditions=Condition(name="Serving Size",
                                     value=NominalReal(30, 'g'),
                                     template=tmpl["Sample Mass"],
                                     origin="specified"))
        ],
        process=ProcessSpec(name='Buying Flour, in General',
                            template=tmpl["Procurement"],
                            tags=['purchase::dry-goods'],
                            notes='Purchasing all purpose flour'),
        tags=[],
        notes='All-purpose flour')
    IngredientSpec(
        **ingredient_kwargs(flour),
        labels=['dry'],
        process=drymix.process,
        volume_fraction=NominalReal(nominal=0.9829, units='')  # 3 cups
    )

    baking_powder = MaterialSpec(name="Abstract Baking Powder",
                                 template=tmpl["Generic Material"],
                                 process=ProcessSpec(
                                     name='Buying Baking Powder, in General',
                                     template=tmpl["Procurement"],
                                     tags=['purchase::dry-goods'],
                                     notes='Purchasing baking powder'),
                                 tags=[],
                                 notes='Leavening agent for cake')
    IngredientSpec(
        **ingredient_kwargs(baking_powder),
        labels=['leavening', 'dry'],
        process=drymix.process,
        volume_fraction=NominalReal(nominal=0.0137, units='')  # 2 teaspoons
    )

    salt = MaterialSpec(name="Abstract Salt",
                        template=tmpl["Formulaic Material"],
                        process=ProcessSpec(name='Buying Salt, in General',
                                            template=tmpl["Procurement"],
                                            tags=['purchase::dry-goods'],
                                            notes='Purchasing salt'),
                        tags=[],
                        notes='Plain old NaCl',
                        properties=[
                            PropertyAndConditions(
                                Property(name='Formula',
                                         value=EmpiricalFormula("NaCl")))
                        ])
    IngredientSpec(
        **ingredient_kwargs(salt),
        labels=['dry', 'seasoning'],
        process=drymix.process,
        volume_fraction=NominalReal(nominal=0.0034, units='')  # 1/2 teaspoon
    )

    sugar = MaterialSpec(
        name="Abstract Sugar",
        template=tmpl["Formulaic Material"],
        process=ProcessSpec(name='Buying Sugar, in General',
                            template=tmpl["Procurement"],
                            tags=['purchase::dry-goods'],
                            notes='Purchasing all purpose flour'),
        tags=[],
        notes='Sugar',
        properties=[
            PropertyAndConditions(
                Property(name="Formula", value=EmpiricalFormula("C12H22O11"))),
            PropertyAndConditions(
                Property(name='SMILES',
                         value=Smiles(
                             "C(C1C(C(C(C(O1)OC2(C(C(C(O2)CO)O)O)CO)O)O)O)O"),
                         template=tmpl["Molecular Structure"]))
        ])
    IngredientSpec(**ingredient_kwargs(sugar),
                   labels=['wet', 'sweetener'],
                   process=wetmix.process,
                   absolute_quantity=NominalReal(nominal=2, units='cups'))

    butter = MaterialSpec(
        name="Abstract Butter",
        template=tmpl["Generic Material"],
        process=ProcessSpec(name='Buying Butter, in General',
                            template=tmpl["Procurement"],
                            tags=['purchase::produce'],
                            notes='Purchasing butter'),
        tags=[],
        notes='Shortening for making rich, buttery baked goods')
    IngredientSpec(**ingredient_kwargs(butter),
                   labels=['wet', 'shortening'],
                   process=wetmix.process,
                   absolute_quantity=NominalReal(nominal=1, units='cups'))
    IngredientSpec(
        **ingredient_kwargs(butter),
        labels=['shortening'],
        process=frosting.process,
        mass_fraction=NominalReal(nominal=0.1434,
                                  units='')  # 1/2 c @ 0.911 g/cc
    )

    eggs = MaterialSpec(name="Abstract Eggs",
                        template=tmpl["Generic Material"],
                        process=ProcessSpec(name='Buying Eggs, in General',
                                            template=tmpl["Procurement"],
                                            tags=['purchase::produce'],
                                            notes='Purchasing eggs'),
                        tags=[],
                        notes='')
    IngredientSpec(**ingredient_kwargs(eggs),
                   labels=['wet'],
                   absolute_quantity=NominalReal(nominal=4, units=''))

    vanilla = MaterialSpec(
        name="Abstract Vanilla",
        template=tmpl["Generic Material"],
        process=ProcessSpec(name='Buying Vanilla, in General',
                            template=tmpl["Procurement"],
                            tags=['purchase::dry-goods'],
                            notes='Purchasing vanilla'),
        tags=[],
        notes=
        'Vanilla Extract is mostly alcohol but the most important component '
        'is vanillin (see attached structure)',
        properties=[
            PropertyAndConditions(
                Property(
                    name='Component Structure',
                    value=InChI(
                        "InChI=1S/C8H8O3/c1-11-8-4-6(5-9)2-3-7(8)10/h2-5,10H,1H3"
                    ),
                    template=tmpl["Molecular Structure"]))
        ])
    IngredientSpec(**ingredient_kwargs(vanilla),
                   labels=['wet', 'flavoring'],
                   process=wetmix.process,
                   absolute_quantity=NominalReal(nominal=2, units='teaspoons'))
    IngredientSpec(
        **ingredient_kwargs(vanilla),
        labels=['flavoring'],
        process=frosting.process,
        mass_fraction=NominalReal(nominal=0.0231,
                                  units='')  # 2 tsp @ 0.879 g/cc
    )

    milk = MaterialSpec(name="Abstract Milk",
                        template=tmpl["Generic Material"],
                        process=ProcessSpec(name='Buying Milk, in General',
                                            template=tmpl["Procurement"],
                                            tags=['purchase::produce'],
                                            notes='Purchasing milk'),
                        tags=[],
                        notes='')
    IngredientSpec(**ingredient_kwargs(milk),
                   labels=['wet'],
                   process=batter.process,
                   absolute_quantity=NominalReal(nominal=1, units='cup'))
    IngredientSpec(
        **ingredient_kwargs(milk),
        labels=[],
        process=frosting.process,
        mass_fraction=NominalReal(nominal=0.0816,
                                  units='')  # 1/4 c @ 1.037 g/cc
    )

    chocolate = MaterialSpec(name="Abstract Chocolate",
                             template=tmpl["Generic Material"],
                             process=ProcessSpec(
                                 name='Buying Chocolate, in General',
                                 template=tmpl["Procurement"],
                                 tags=['purchase::dry-goods'],
                                 notes='Purchasing chocolate'),
                             tags=[],
                             notes='')
    IngredientSpec(
        **ingredient_kwargs(chocolate),
        labels=['flavoring'],
        process=frosting.process,
        mass_fraction=NominalReal(nominal=0.1132, units='')  # 3 oz.
    )

    powder_sugar = MaterialSpec(
        name="Abstract Powdered Sugar",
        template=tmpl["Generic Material"],
        process=ProcessSpec(name='Buying Powdered Sugar, in General',
                            template=tmpl["Procurement"],
                            tags=['purchase::dry-goods'],
                            notes='Purchasing powdered sugar'),
        tags=[],
        notes='Granulated sugar mixed with corn starch')
    IngredientSpec(
        **ingredient_kwargs(powder_sugar),
        labels=['flavoring'],
        process=frosting.process,
        mass_fraction=NominalReal(nominal=0.6387,
                                  units='')  # 4 c @ 30 g/ 0.25 cups
    )

    # Crawl tree and annotate with uids; only add ids if there's nothing there
    recursive_foreach(
        cake, lambda obj: obj.uids or obj.add_uid(DEMO_SCOPE, obj.name))

    return cake