def test_invalid_constructor():
    """Test types in constructor."""
    with pytest.raises(ValueError):
        CompositionBounds(components="foo")

    with pytest.raises(ValueError):
        CompositionBounds(components={1, 2})
def test_components():
    """Test components setter."""
    assert CompositionBounds().components == set()
    assert CompositionBounds(components={"foo", "bar"}).components == {
        "foo", "bar"
    }
    assert CompositionBounds(components=["foo", "bar"]).components == {
        "foo", "bar"
    }
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"})
def test_numpy():
    """Test that ndarrays, Series work as well."""
    assert len(array_like()) < 5  # In case we extend at some point

    if len(array_like()) > 2:  # Test numpy
        import numpy as np

        np_bounds = CompositionBounds(components=np.array(["spam", "eggs"], dtype=object))
        np_copy = loads(dumps(np_bounds))
        assert np_copy == np_bounds

    if len(array_like()) > 3:  # Test pandas
        import pandas as pd

        pd_bounds = CompositionBounds(components=pd.Series(["spam", "eggs"]))
        pd_copy = loads(dumps(pd_bounds))
        assert pd_copy == pd_bounds
Beispiel #5
0
def make_templates(template_scope=DEMO_TEMPLATE_SCOPE):
    """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={template_scope: 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={template_scope: name},
                         tags=['citrine::demo::template::object'],
                         **kw_args)

    return tmpl
Beispiel #6
0
def make_strehlow_table(compounds):
    """
    Headers and content for the output of make_strehlow_objects.

    Note that this is supposed to be mimicking the transformation of a set of Material Histories
    into a Training Table, and as such we are missing the column definition component of the query
    that created this particular result set.

    :param compounds: a list of MaterialRun objects from the make_strehlow_objects method
    :return:
    """
    # Stash templates in convenience variables
    for comp in compounds:
        if comp.spec.properties:
            chem_tmpl = comp.spec.properties[0].property.template
            break

    chem_mat_tmpl = compounds[0].spec.template

    tmpl = dict()

    properties = compounds[0].measurements[0].spec.template.properties
    conditions = compounds[0].measurements[0].spec.template.conditions
    parameters = compounds[0].measurements[0].spec.template.parameters
    for attr in (properties + conditions + parameters):
        tmpl[attr[0].name] = attr[0]

    # Consider how to specify relevant data pathing here
    output = {'headers': [], 'content': []}

    # "Chemical" is supposed to be the unifying characterization of all the root elements of the
    # Material Histories, but that can't be the spec name because the spec is Compound specific --
    # that's where the chemical is defined
    output['headers'].append(
        {'name': [chem_mat_tmpl.name,
                  "Display name"  # It would be good to derive this from the structure somehow
                  ],
         'primitive': True
         }
    )
    output['headers'].append(
        {'name': [chem_mat_tmpl.name,
                  chem_tmpl.name
                  ],
         'primitive': False,
         'bounds': CompositionBounds()
         }
    )
    terms = ["Band gap", "Temperature derivative of band gap", "Temperature", "Color",
             "Lasing", "Cathodoluminescence", "Mechanical luminescence", "Photoluminescence",
             "Electroluminescence", "Thermoluminescence", "Transition", "Bands",
             "Electric field polarization", "Crystallinity", "Morphology", "Phase",
             'Crystal system']

    for term in terms:
        output['headers'].append(
            {'name': [chem_mat_tmpl.name,
                      term
                      ],
             'primitive': False,
             'bounds': tmpl[term].bounds
             }
        )

    for comp in compounds:
        row = [comp.spec.name]
        x = list(filter(lambda y: y.name == chem_tmpl.name, comp.spec.properties))
        if x:
            row.append(x[0].value)
        else:
            row.append(None)

        for term in terms:
            x = list(filter(lambda y: y.name == term,
                            comp.measurements[0].properties + comp.measurements[0].conditions))
            if x:
                row.append(x[0].value)
            else:
                row.append(None)

        output['content'].append(row)

    return output
def test_json():
    """Test serialization (components is encoded as a list)."""
    bounds = CompositionBounds(components={"spam", "eggs"})
    copy = loads(dumps(bounds))
    assert copy == bounds
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"})

    from gemd.entity.value import NominalComposition

    assert bounds.contains(NominalComposition({"spam": 0.2, "eggs": 0.8}))
    assert not bounds.contains(NominalComposition({"foo": 1.0}))