Beispiel #1
0
def test_contains_incompatible_units():
    """Make sure contains returns false when the units don't match."""
    dim = RealBounds(lower_bound=0, upper_bound=100, default_units="m")
    dim2 = RealBounds(lower_bound=0, upper_bound=100, default_units="kJ")
    dim3 = RealBounds(lower_bound=0, upper_bound=100, default_units='')
    assert not dim.contains(dim2)
    assert not dim.contains(dim3)
Beispiel #2
0
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'
Beispiel #3
0
def test_object_template_serde():
    """Test serde of an object template."""
    length_template = PropertyTemplate("Length", RealBounds(2.0, 3.5, 'cm'))
    sub_bounds = RealBounds(2.5, 3.0, 'cm')
    color_template = PropertyTemplate("Color", CategoricalBounds(["red", "green", "blue"]))
    # Properties are a mixture of property templates and [template, bounds], pairs
    block_template = MaterialTemplate("Block", properties=[[length_template, sub_bounds],
                                                           color_template])
    copy_template = MaterialTemplate.build(block_template.dump())
    assert copy_template == block_template

    # Tests below exercise similar code, but for measurement and process templates
    pressure_template = ConditionTemplate("pressure", RealBounds(0.1, 0.11, 'MPa'))
    index_template = ParameterTemplate("index", IntegerBounds(2, 10))
    meas_template = MeasurementTemplate("A measurement of length", properties=[length_template],
                                        conditions=[pressure_template], description="Description",
                                        parameters=[index_template], tags=["foo"])
    assert MeasurementTemplate.build(meas_template.dump()) == meas_template

    proc_template = ProcessTemplate("Make an object", parameters=[index_template],
                                    conditions=[pressure_template], allowed_labels=["Label"],
                                    allowed_names=["first sample", "second sample"])
    assert ProcessTemplate.build(proc_template.dump()) == proc_template

    # Check that serde still works if the template is a LinkByUID
    proc_template.conditions[0][0] = LinkByUID('id', pressure_template.uids['id'])
    assert ProcessTemplate.build(proc_template.dump()) == proc_template
Beispiel #4
0
def test_bounds_mismatch():
    """Test that a mismatch between the attribute and given bounds throws a ValueError."""
    attribute_bounds = RealBounds(0, 100, '')
    object_bounds = RealBounds(200, 300, '')
    cond_template = ConditionTemplate("a condition", bounds=attribute_bounds)
    with pytest.raises(ValueError):
        ProcessTemplate("a process template",
                        conditions=[[cond_template, object_bounds]])
Beispiel #5
0
def make_cake_templates():
    """Define all templates independently, as in the wild this will be an independent operation."""
    tmpl = dict()

    # Attributes
    tmpl['Cooking time'] = ConditionTemplate(
        name="Cooking time",
        description="The time elapsed during a cooking process",
        bounds=RealBounds(0, 7 * 24.0, "hr")
    )
    tmpl["Oven temperature setting"] = ParameterTemplate(
        name="Oven temperature setting",
        description="Where the knob points",
        bounds=RealBounds(0, 2000.0, "K")
    )
    tmpl["Oven temperature"] = ConditionTemplate(
        name="Oven temperature",
        description="Actual temperature measured by the thermocouple",
        bounds=RealBounds(0, 2000.0, "K")
    )

    tmpl["Tastiness"] = PropertyTemplate(
        name="Tastiness",
        description="Yumminess on a fairly arbitrary scale",
        bounds=IntegerBounds(lower_bound=1, upper_bound=10)
    )

    # Objects
    tmpl["Baking in an oven"] = ProcessTemplate(
        name="Baking in an oven",
        description='Using heat to promote chemical reactions in a material',
        allowed_labels=['precursor'],
        conditions=[(tmpl["Oven temperature"], RealBounds(0, 700, "degF"))],
        parameters=[(tmpl["Oven temperature setting"], RealBounds(100, 550, "degF"))]
    )

    tmpl["Taste test"] = MeasurementTemplate(
        name="Taste test",
        properties=[tmpl["Tastiness"]]
    )

    tmpl["Dessert"] = MaterialTemplate(
        name="Dessert",
        properties=[tmpl["Tastiness"]]
    )

    tmpl["Generic Material"] = MaterialTemplate(name="Generic")
    tmpl["Icing"] = ProcessTemplate(name="Icing",
                                    description='Applying a coating to a substrate',
                                    allowed_labels=['coating', 'substrate'])
    tmpl["Mixing"] = ProcessTemplate(name="Mixing",
                                     description='Physically combining ingredients',
                                     allowed_labels=['wet', 'dry', 'leavening', 'seasoning',
                                                     'sweetener', 'shortening', 'flavoring'])
    tmpl["Procurement"] = ProcessTemplate(name="Procurement",
                                          description="Buyin' stuff")

    return tmpl
def test_template_assignment():
    """Test that an object and its attributes can both be assigned templates."""
    humidity_template = ConditionTemplate("Humidity",
                                          RealBounds(0.5, 0.75, ""))
    template = ProcessTemplate(
        "Dry", conditions=[[humidity_template,
                            RealBounds(0.5, 0.65, "")]])
    ProcessSpec("Dry a polymer",
                template=template,
                conditions=[
                    Condition("Humidity",
                              value=NominalReal(0.6, ""),
                              template=humidity_template)
                ])
Beispiel #7
0
def test_constructor_error():
    """Test that invalid real bounds cannot be constructed."""
    with pytest.raises(ValueError):
        RealBounds()

    with pytest.raises(ValueError):
        RealBounds(0, float("inf"), "meter")

    with pytest.raises(ValueError):
        RealBounds(None, 10, '')

    with pytest.raises(ValueError):
        RealBounds(0, 100)

    with pytest.raises(ValueError):
        RealBounds(100, 0, "m")
Beispiel #8
0
def test_invalid_assignment():
    """Invalid assignments to `process` or `material` throw a TypeError."""
    with pytest.raises(TypeError):
        IngredientRun(material=RealBounds(0, 5.0, ''))
    with pytest.raises(TypeError):
        IngredientRun(process="process")
    with pytest.raises(TypeError):
        IngredientRun(spec=5)
Beispiel #9
0
def test_contains():
    """Test basic contains logic."""
    bounds = CompositionBounds(components={"spam", "eggs"})
    assert bounds.contains(CompositionBounds(components={"spam"}))
    assert not bounds.contains(CompositionBounds(components={"foo"}))
    assert not bounds.contains(RealBounds(0.0, 2.0, ''))
    assert not bounds.contains(None)
    with pytest.raises(TypeError):
        bounds.contains({"spam"})
Beispiel #10
0
def test_contains():
    """Test basic contains logic."""
    bounds = CategoricalBounds(categories={"spam", "eggs"})
    assert bounds.contains(CategoricalBounds(categories={"spam"}))
    assert not bounds.contains(CategoricalBounds(categories={"spam", "foo"}))
    assert not bounds.contains(RealBounds(0.0, 2.0, ''))
    assert not bounds.contains(None)
    with pytest.raises(TypeError):
        bounds.contains({"spam", "eggs"})
Beispiel #11
0
def test_type_mismatch():
    """Test that incompatible types cannot be matched against RealBounds."""
    bounds = RealBounds(0, 1, default_units="meters")
    assert not bounds.contains(IntegerBounds(0, 1))
    assert not bounds.contains(None)
    with pytest.raises(TypeError):
        bounds.contains([.33, .66])
def test_condition_template():
    """Test creation and serde of condition templates."""
    bounds = RealBounds(2.5, 10.0, default_units='cm')
    template = ConditionTemplate("Chamber width",
                                 bounds=bounds,
                                 description="width of chamber")
    assert template.uids is not None  # uids should be added automatically

    # Take template through a serde cycle and ensure that it is unchanged
    assert ConditionTemplate.build(template.dump()) == template
    # A more complicated cycle that goes through both taurus and citrine-python serde.
    assert ConditionTemplate.build(loads(dumps(
        template.dump())).as_dict()) == template
Beispiel #13
0
def test_attribute_serde():
    """An attribute with a link to an attribute template should be copy-able."""
    prop_tmpl = PropertyTemplate(name='prop_tmpl',
                                 bounds=RealBounds(0, 2, 'm')
                                 )
    prop = Property(name='prop',
                    template=prop_tmpl,
                    value=NominalReal(1, 'm')
                    )
    meas_spec = MeasurementSpec("a spec")
    meas = MeasurementRun("a measurement", spec=meas_spec, properties=[prop])
    assert loads(dumps(prop)) == prop
    assert loads(dumps(meas)) == meas
    assert isinstance(prop.template, PropertyTemplate)
def test_object_template_validation():
    """Test that attribute templates are validated against given bounds."""
    length_template = PropertyTemplate("Length", RealBounds(2.0, 3.5, 'cm'))
    dial_template = ConditionTemplate("dial", IntegerBounds(0, 5))
    color_template = ParameterTemplate(
        "Color", CategoricalBounds(["red", "green", "blue"]))

    with pytest.raises(ValueError):
        MaterialTemplate(
            "Block",
            properties=[[length_template,
                         RealBounds(3.0, 4.0, 'cm')]])

    with pytest.raises(ValueError):
        ProcessTemplate(
            "a process",
            conditions=[[color_template,
                         CategoricalBounds(["zz"])]])

    with pytest.raises(ValueError):
        MeasurementTemplate("A measurement",
                            parameters=[[dial_template,
                                         IntegerBounds(-3, -1)]])
def test_simple_deserialization(valid_data, attribute_list):
    for (key, Attribute, AttributeTemplate) in attribute_list:
        valid_data['type'] = key
        valid_data['template']['type'] = key + '_template'
        attribute: Attribute = Attribute.build(valid_data)
        assert attribute.name == 'mass'
        assert attribute.notes == 'This is a note'
        assert attribute.value == NominalReal(5.0, units='gram')
        assert attribute.template == \
               AttributeTemplate('mass', uids={'id': valid_data['template']['uids']['id']},
                                 description='mass of object', bounds=RealBounds(0.0, 20.0, 'gram')
                                 )
        assert attribute.origin == 'measured'
        assert attribute.file_links == []
        assert attribute.typ == key
Beispiel #16
0
def test_recursive_foreach():
    """Test that recursive_foreach() applies a method to every object."""
    new_tag = "Extra tag"

    def func(base_ent):
        """Adds a specific tag to the object."""
        base_ent.tags.extend([new_tag])
        return

    param_template = ParameterTemplate("a param template", bounds=RealBounds(0, 100, ''))
    meas_template = MeasurementTemplate("Measurement template", parameters=[param_template])
    parameter = Parameter(name="A parameter", value=NormalReal(mean=17, std=1, units=''))
    measurement = MeasurementSpec(name="name", parameters=parameter, template=meas_template)
    test_dict = {"foo": measurement}
    recursive_foreach(test_dict, func, apply_first=True)

    for ent in [param_template, meas_template, measurement]:
        assert new_tag in ent.tags
Beispiel #17
0
def test_recursive_foreach():
    """Test that recursive foreach will actually walk through a material history."""
    mat_run = MaterialRun("foo")
    process_run = ProcessRun("bar")
    IngredientRun(process=process_run, material=mat_run)
    output = MaterialRun(process=process_run)

    # property templates are trickier than templates because they are referenced in attributes
    template = PropertyTemplate("prop", bounds=RealBounds(0, 1, ""))
    prop = Property("prop", value=NominalReal(1.0, ""), template=template)
    MeasurementRun("check", material=output, properties=prop)

    types = []
    recursive_foreach(output, lambda x: types.append(x.typ))

    expected = [
        "ingredient_run", "material_run", "material_run", "process_run",
        "measurement_run", "property_template"
    ]
    assert sorted(types) == sorted(expected)
Beispiel #18
0
 }, "<Material spec 'foo'>"),
 (MaterialTemplate, {
     'name': 'foo'
 }, "<Material template 'foo'>"),
 (MeasurementRun, {
     'name': 'foo'
 }, "<Measurement run 'foo'>"),
 (MeasurementSpec, {
     'name': 'foo'
 }, "<Measurement spec 'foo'>"),
 (MeasurementTemplate, {
     'name': 'foo'
 }, "<Measurement template 'foo'>"),
 (ParameterTemplate, {
     'name': 'foo',
     'bounds': RealBounds(0, 1, '')
 }, "<Parameter template 'foo'>"),
 (ProcessRun, {
     'name': 'foo'
 }, "<Process run 'foo'>"),
 (ProcessSpec, {
     'name': 'foo'
 }, "<Process spec 'foo'>"),
 (ProcessTemplate, {
     'name': 'foo'
 }, "<Process template 'foo'>"),
 (PropertyTemplate, {
     'name': 'foo',
     'bounds': RealBounds(0, 1, '')
 }, "<Property template 'foo'>"),
 (ConditionTemplate, {
Beispiel #19
0
def make_templates():
    """Build all templates needed for the table."""
    tmpl = dict()

    # Attribute Templates
    attribute_feed = {
        "Formula": [
            PropertyTemplate,
            CompositionBounds(components=EmpiricalFormula.all_elements())
        ],
        "Crystallinity": [
            ConditionTemplate,
            CategoricalBounds(
                ['Amorphous', 'Polycrystalline', 'Single crystalline'])
        ],
        "Color": [
            PropertyTemplate,
            CategoricalBounds([
                'Amber', 'Black', 'Blue', 'Bluish', 'Bronze', 'Brown',
                'Brown-Black', 'Copper-Red', 'Dark Brown', 'Dark Gray',
                'Dark Green', 'Dark Red', 'Gray', 'Light Gray', 'Ocher',
                'Orange', 'Orange-Red', 'Pale Yellow', 'Red', 'Red-Yellow',
                'Violet', 'White', 'Yellow', 'Yellow-Orange', 'Yellow-White'
            ])
        ],
        "Band gap": [
            PropertyTemplate,
            RealBounds(lower_bound=0.001, upper_bound=100, default_units='eV')
        ],
        "Temperature": [
            ConditionTemplate,
            RealBounds(lower_bound=1, upper_bound=1000, default_units='K')
        ],
        "Temperature derivative of band gap": [
            PropertyTemplate,
            RealBounds(lower_bound=-0.01,
                       upper_bound=0.01,
                       default_units='eV/K')
        ],
        "Lasing": [PropertyTemplate,
                   CategoricalBounds(['True', 'False'])],
        "Cathodoluminescence":
        [PropertyTemplate,
         CategoricalBounds(['True', 'False'])],
        "Mechanical luminescence":
        [PropertyTemplate,
         CategoricalBounds(['True', 'False'])],
        "Photoluminescence":
        [PropertyTemplate,
         CategoricalBounds(['True', 'False'])],
        "Electroluminescence":
        [PropertyTemplate,
         CategoricalBounds(['True', 'False'])],
        "Thermoluminescence":
        [PropertyTemplate,
         CategoricalBounds(['True', 'False'])],
        "Morphology":
        [ConditionTemplate,
         CategoricalBounds(['Thin film', 'Bulk'])],
        "Electric field polarization": [
            ConditionTemplate,
            CategoricalBounds([
                'Parallel to A axis', 'Parallel to B axis',
                'Parallel to C axis', 'Perpendicular to B axis',
                'Perpendicular to C axis'
            ])
        ],
        "Phase": [
            ConditionTemplate,
            CategoricalBounds([
                'A', 'B', 'B1', 'B2', 'Fused quartz', 'Natural diamond',
                'Rutile', 'Sapphire', 'Synthetic quartz'
            ])
        ],
        "Crystal system": [
            ConditionTemplate,
            CategoricalBounds([
                'Cubic', 'Hexagonal', 'Orthorhombic', 'Tetragonal', 'Trigonal'
            ])
        ],
        "Transition": [
            ConditionTemplate,
            CategoricalBounds(['Direct', 'Excitonic', 'Indirect'])
        ],
        "Bands": [
            ConditionTemplate,
            CategoricalBounds([
                'G1 to X1', 'G15 to G1', 'G15 to X1', 'G25 to G1',
                'G25 to G12', 'G25 to G15', 'G6 to G8', 'G8 to G6+',
                'L6+ to L6-'
            ])
        ]
    }
    for (name, (typ, bounds)) in attribute_feed.items():
        assert name not in tmpl
        tmpl[name] = typ(name=name,
                         bounds=bounds,
                         uids={DEMO_SCOPE + '-template': name},
                         tags=['citrine::demo::template::attribute'])

    # Object Templates
    object_feed = {
        "Sample preparation": [ProcessTemplate, dict()],
        "Chemical": [MaterialTemplate, {
            "properties": [tmpl["Formula"]]
        }],
        "Band gap measurement": [
            MeasurementTemplate, {
                "properties": [
                    tmpl["Band gap"],
                    tmpl["Temperature derivative of band gap"], tmpl["Color"],
                    tmpl["Lasing"], tmpl["Cathodoluminescence"],
                    tmpl["Mechanical luminescence"], tmpl["Photoluminescence"],
                    tmpl["Electroluminescence"], tmpl["Thermoluminescence"]
                ],
                "conditions": [
                    tmpl["Temperature"], tmpl["Crystallinity"],
                    tmpl["Morphology"], tmpl["Electric field polarization"],
                    tmpl["Phase"], tmpl["Crystal system"], tmpl["Transition"],
                    tmpl["Bands"]
                ]
            }
        ],
    }
    for (name, (typ, kw_args)) in object_feed.items():
        assert name not in tmpl
        tmpl[name] = typ(name=name,
                         uids={DEMO_SCOPE + '-template': name},
                         tags=['citrine::demo::template::object'],
                         **kw_args)

    return tmpl
Beispiel #20
0
"""For entities that hve quantities."""
from taurus.entity.bounds.real_bounds import RealBounds
from taurus.entity.value.continuous_value import ContinuousValue

fraction_bounds = RealBounds(lower_bound=0.0, upper_bound=1.0, default_units='')


class HasQuantities(object):
    """Mixin-trait that includes the mass, volume, number fraction, and absolute quantity."""

    def __init__(self, mass_fraction=None, volume_fraction=None, number_fraction=None,
                 absolute_quantity=None):

        self._mass_fraction = None
        self.mass_fraction = mass_fraction

        self._volume_fraction = None
        self.volume_fraction = volume_fraction

        self._number_fraction = None
        self.number_fraction = number_fraction

        self._absolute_quantity = None
        self.absolute_quantity = absolute_quantity

    @property
    def mass_fraction(self):
        """Get mass fraction."""
        return self._mass_fraction

    @mass_fraction.setter
Beispiel #21
0
def test_json():
    """Test that json serialization round robins to the identity."""
    template = PropertyTemplate(name="foo", bounds=RealBounds(0, 1, ""))
    copy = loads(dumps(template))
    assert copy == template
Beispiel #22
0
from taurus.entity.object import MeasurementRun, MaterialRun, ProcessRun, ProcessSpec,\
    MeasurementSpec, MaterialSpec
from taurus.entity.template.condition_template import ConditionTemplate
from taurus.entity.template.material_template import MaterialTemplate
from taurus.entity.template.measurement_template import MeasurementTemplate
from taurus.entity.template.process_template import ProcessTemplate
from taurus.entity.template.property_template import PropertyTemplate
from taurus.entity.value.discrete_categorical import DiscreteCategorical
from taurus.entity.value.nominal_composition import NominalComposition
from taurus.entity.value.nominal_real import NominalReal
from taurus.entity.value.normal_real import NormalReal
from taurus.entity.value.uniform_real import UniformReal

density_template = PropertyTemplate(
    name="Density",
    bounds=RealBounds(lower_bound=0, upper_bound=1.0e9, default_units='')
)
firing_temperature_template = ConditionTemplate(
    name="Firing Temperature",
    bounds=RealBounds(lower_bound=0, upper_bound=1.0e9, default_units='degC')
)

measurement_template = MeasurementTemplate(properties=density_template)
firing_template = ProcessTemplate(
    name="Firing in a kiln",
    conditions=(firing_temperature_template, RealBounds(lower_bound=500, upper_bound=1000,
                                                        default_units='degC'))
)
material_template = MaterialTemplate(
    name="Some ceramic thing",
    properties=density_template
Beispiel #23
0
def test_incompatible_types():
    """Make sure that incompatible types aren't contained or validated."""
    int_bounds = IntegerBounds(0, 1)

    assert not int_bounds.contains(RealBounds(0.0, 1.0, ''))
Beispiel #24
0
from taurus.entity.attribute.parameter import Parameter
from taurus.entity.attribute.property import Property
from taurus.entity.bounds.categorical_bounds import CategoricalBounds
from taurus.entity.bounds.real_bounds import RealBounds
from taurus.entity.object import MaterialRun, MeasurementRun
from taurus.entity.template.condition_template import ConditionTemplate
from taurus.entity.template.parameter_template import ParameterTemplate
from taurus.entity.template.property_template import PropertyTemplate
from taurus.entity.value.discrete_categorical import DiscreteCategorical
from taurus.entity.value.nominal_real import NominalReal
from taurus.entity.value.normal_real import NormalReal

known_properties = {
    "density": PropertyTemplate(
        name="density",
        bounds=RealBounds(lower_bound=0.0, upper_bound=1000.0, default_units='g / cm^3')
    ),
    "kinematic viscosity": PropertyTemplate(
        name="kinematic viscosity",
        bounds=RealBounds(lower_bound=0.0, upper_bound=10.0**40, default_units="m^2 / s")
    )
}

known_conditions = {
    "temperature": ConditionTemplate(
        name="temperature",
        bounds=RealBounds(lower_bound=0.0, upper_bound=1000.0, default_units='K')
    )
}

known_parameters = {
Beispiel #25
0
def test_contains_no_units():
    """Make sure contains handles boundsless values."""
    dim = RealBounds(lower_bound=0, upper_bound=100, default_units="")
    dim2 = RealBounds(lower_bound=0, upper_bound=100, default_units="")
    assert dim.contains(dim2)
Beispiel #26
0
def test_contains():
    """Make sure unit conversions are applied to bounds for contains."""
    dim = RealBounds(lower_bound=0, upper_bound=100, default_units="degC")
    dim2 = RealBounds(lower_bound=33, upper_bound=200, default_units="degF")
    assert dim.contains(dim2)