Example #1
0
    def get_materials_for_mpids(self, mpids, filter_null_properties=True):
        """
        Retrieve a list of Materials from the materials
        Project for a given list of Materials Project IDs.

        Args:
            mpids: a list of Materials Project IDs

        Returns:

        """

        materials_properties = self.get_properties_for_mpids(
            mpids, filter_null_properties=filter_null_properties)
        materials = []

        for material_properties in materials_properties:
            material = Material()
            for property_name, property_value in material_properties.items():
                provenance = ProvenanceElement(source='Materials Project')
                quantity = Quantity(self.mapping[property_name],
                                    property_value,
                                    provenance=provenance)
                material.add_quantity(quantity)
            materials.append(material)

        return materials
    def evaluate(input_rows):

        quantities = [
            Quantity(symbol_type=ROW_IDX_TO_SYMBOL_NAME[idx],
                     value=ureg.parse_expression(row['Value']))
            for idx, row in enumerate(input_rows) if row['Value']
        ]
        material = Material()

        for quantity in quantities:
            material.add_quantity(quantity)

        graph = Graph()
        output_material = graph.evaluate(material)

        output_quantities = output_material.get_aggregated_quantities()
        print(output_quantities)

        output_rows = [{
            'Property': symbol.display_names[0],
            'Value': str(quantity.value),
            'Provenance': None
        } for symbol, quantity in output_quantities.items()]

        return output_rows
Example #3
0
    def evaluate(input_rows, data, aggregate):

        quantities = [
            QuantityFactory.create_quantity(
                symbol_type=ROW_IDX_TO_SYMBOL_NAME[idx],
                value=ureg.parse_expression(row['Editable Value']))
            for idx, row in enumerate(input_rows) if row['Editable Value']
        ]

        if data and len(data) > 0:
            quantities += json.loads(data, cls=MontyDecoder).values()

        if not quantities:
            raise PreventUpdate

        material = Material()

        for quantity in quantities:
            material.add_quantity(quantity)

        graph = Graph()
        output_material = graph.evaluate(material)

        if aggregate:
            output_quantities = output_material.get_aggregated_quantities(
            ).values()
        else:
            output_quantities = output_material.get_quantities()

        output_rows = [{
            'Property': quantity.symbol.display_names[0],
            'Value': quantity.pretty_string(sigfigs=3)
        } for quantity in output_quantities]

        output_table = dt.DataTable(id='output-table',
                                    rows=output_rows,
                                    editable=False)

        # TODO: clean up

        input_quantity_names = [q.symbol.name for q in quantities]
        derived_quantity_names = set(
            [q.symbol.name for q in output_quantities]) - \
                                 set(input_quantity_names)
        material_graph_data = graph_conversion(
            graph.get_networkx_graph(),
            nodes_to_highlight_green=input_quantity_names,
            nodes_to_highlight_yellow=list(derived_quantity_names))
        options = AESTHETICS['global_options']
        options['edges']['color'] = '#000000'
        output_graph = html.Div(GraphComponent(id='material-graph',
                                               graph=material_graph_data,
                                               options=options),
                                style={
                                    'width': '100%',
                                    'height': '400px'
                                })

        return [output_graph, html.Br(), output_table]
Example #4
0
 def setUp(self):
     # Create some test properties and a few base objects
     self.q1 = QuantityFactory.create_quantity(DEFAULT_SYMBOLS['bulk_modulus'],
                                               ureg.Quantity.from_tuple([200, [['gigapascals', 1]]]))
     self.q2 = QuantityFactory.create_quantity(DEFAULT_SYMBOLS['shear_modulus'],
                                               ureg.Quantity.from_tuple([100, [['gigapascals', 1]]]))
     self.q3 = QuantityFactory.create_quantity(DEFAULT_SYMBOLS['bulk_modulus'],
                                               ureg.Quantity.from_tuple([300, [['gigapascals', 1]]]))
     self.material = Material()
     self.graph = Graph()
Example #5
0
 def generate_canonical_material(c_symbols):
     """
     Generates a Material with appropriately attached Quantities.
     Args:
         c_symbols: (dict<str, Symbol>) dictionary of defined materials.
     Returns:
         (Material) material with properties loaded.
     """
     q1 = Quantity(c_symbols['A'], 19)
     q2 = Quantity(c_symbols['A'], 23)
     m = Material()
     m.add_quantity(q1)
     m.add_quantity(q2)
     return m
Example #6
0
def import_materials(mp_ids, api_key=None):
    """
    Given a list of material ids, returns a list of Material objects with all
    available properties from the Materials Project.
    Args:
        mp_ids (list<str>): list of material ids whose information will be retrieved.
        api_key (str): api key to be used to conduct the query.
    Returns:
        (list<Material>): list of material objects with associated data.
    """
    mpr = MPRester(api_key)
    to_return = []
    query = mpr.query(criteria={"task_id": {
        '$in': mp_ids
    }},
                      properties=AVAILABLE_MP_PROPERTIES)
    for data in query:
        # properties of one mp-id
        mat = Material()
        tag_string = data['task_id']
        mat.add_property(Symbol('structure', data['structure'], [tag_string]))
        mat.add_property(
            Symbol('lattice_unit_cell', data['structure'].lattice.matrix,
                   [tag_string]))
        for key in data:
            if not data[
                    key] is None and key in PROPNET_FROM_MP_NAME_MAPPING.keys(
                    ):
                prop_type = DEFAULT_SYMBOL_TYPES[
                    PROPNET_FROM_MP_NAME_MAPPING[key]]
                p = Symbol(prop_type, data[key], [tag_string])
                mat.add_property(p)
        to_return.append(mat)
    return to_return
Example #7
0
    def process_item(self, item):
        # Define quantities corresponding to materials doc fields
        # Attach quantities to materials
        item = MontyDecoder().process_decoded(item)
        logger.info("Populating material for %s", item['task_id'])
        material = Material()
        for mkey, property_name in self.materials_symbol_map.items():
            value = get(item, mkey)
            if value:
                material.add_quantity(Quantity(property_name, value))

        # Add custom things, e. g. computed entry
        computed_entry = get_entry(item)
        material.add_quantity(Quantity("computed_entry", computed_entry))
        material.add_quantity(
            Quantity("external_identifier_mp", item['task_id']))

        input_quantities = material.get_quantities()

        # Use graph to generate expanded quantity pool
        logger.info("Evaluating graph for %s", item['task_id'])
        graph = Graph()
        graph.remove_models({
            "dimensionality_cheon":
            DEFAULT_MODEL_DICT['dimensionality_cheon'],
            "dimensionality_gorai":
            DEFAULT_MODEL_DICT['dimensionality_gorai']
        })
        new_material = graph.evaluate(material)

        # Format document and return
        logger.info("Creating doc for %s", item['task_id'])
        doc = {"inputs": [quantity.as_dict() for quantity in input_quantities]}
        for symbol, quantity in new_material.get_aggregated_quantities().items(
        ):
            all_qs = new_material._symbol_to_quantity[symbol]
            # Only add new quantities
            if len(all_qs) == 1 and list(all_qs)[0] in input_quantities:
                continue
            qs = [quantity.as_dict() for quantity in all_qs]
            sub_doc = {
                "quantities": qs,
                "mean": unumpy.nominal_values(quantity.value).tolist(),
                "std_dev": unumpy.std_devs(quantity.value).tolist(),
                "units": qs[0]['units'],
                "title": quantity._symbol_type.display_names[0]
            }
            doc[symbol.name] = sub_doc
        doc.update({
            "task_id": item["task_id"],
            "pretty_formula": item["pretty_formula"]
        })
        return jsanitize(doc, strict=True)
Example #8
0
    def test_evaluate_single_material_degenerate_property(self):
        """
        Graph has one material on it: mat1
            mat1 has trivial degenerate properties relative permittivity and relative permeability
                2 experimental relative permittivity measurements
                2 experimental relative permeability measurements
        Determines if TestGraph1 is correctly evaluated using the evaluate method.
        We expect 4 refractive_index properties to be calculated as the following:
            sqrt(3), sqrt(5), sqrt(6), sqrt(10)
        """
        # Setup
        propnet = Graph()
        mat1 = Material()
        mat1.add_quantity(Quantity(DEFAULT_SYMBOLS['relative_permeability'],
                                   1))
        mat1.add_quantity(Quantity(DEFAULT_SYMBOLS['relative_permeability'],
                                   2))
        mat1.add_quantity(Quantity(DEFAULT_SYMBOLS['relative_permittivity'],
                                   3))
        mat1.add_quantity(Quantity(DEFAULT_SYMBOLS['relative_permittivity'],
                                   5))

        mat1_derived = propnet.evaluate(mat1)

        # Expected outputs
        s_outputs = []
        s_outputs.append(Quantity('relative_permeability', 1))
        s_outputs.append(Quantity('relative_permeability', 2))
        s_outputs.append(Quantity('relative_permittivity', 3))
        s_outputs.append(Quantity('relative_permittivity', 5))
        s_outputs.append(Quantity('refractive_index', 3**0.5))
        s_outputs.append(Quantity('refractive_index', 5**0.5))
        s_outputs.append(Quantity('refractive_index', 6**0.5))
        s_outputs.append(Quantity('refractive_index', 10**0.5))

        st_outputs = []
        st_outputs.append(DEFAULT_SYMBOLS['relative_permeability'])
        st_outputs.append(DEFAULT_SYMBOLS['relative_permittivity'])
        st_outputs.append(DEFAULT_SYMBOLS['refractive_index'])

        # Test
        for q_expected in s_outputs:
            q = None
            for q_derived in mat1_derived._symbol_to_quantity[
                    q_expected.symbol]:
                if q_derived == q_expected:
                    q = q_derived
            self.assertTrue(q is not None, "Quantity missing from evaluate.")
Example #9
0
 def test_add_default_quantities(self):
     material = Material(add_default_quantities=True)
     self.assertEqual(
         list(material['temperature'])[0], Quantity("temperature", 300))
     self.assertEqual(
         list(material['relative_permeability'])[0],
         Quantity("relative_permeability", 1))
Example #10
0
 def test_add_default_quantities(self):
     material = Material(add_default_quantities=True)
     self.assertEqual(list(material['temperature'])[0],
                      QuantityFactory.create_quantity("temperature", 300,
                                                      provenance=ProvenanceElement(model='default')))
     self.assertEqual(list(material['relative_permeability'])[0],
                      QuantityFactory.create_quantity("relative_permeability", 1,
                      provenance=ProvenanceElement(model='default')))
Example #11
0
 def test_get_sse(self):
     mats = [Material([Quantity("band_gap", n)]) for n in range(1, 5)]
     benchmarks = [{"band_gap": 1.1 * n} for n in range(1, 5)]
     err = get_sse(mats, benchmarks)
     test_val = sum([0.01 * n**2 for n in range(1, 5)])
     self.assertAlmostEqual(err, test_val)
     # Big dataset
     err = get_sse(self.evaluated, self.benchmarks)
     self.assertAlmostEqual(err, 173.5710251)
Example #12
0
 def setUp(self):
     path = os.path.join(TEST_DIR, "fitting_test_data.csv")
     test_data = pd.read_csv(path)
     graph = Graph()
     materials = [Material([QuantityFactory.create_quantity("band_gap", bg)])
                  for bg in test_data['band_gap']]
     self.evaluated = [graph.evaluate(mat) for mat in materials]
     self.benchmarks = [{"refractive_index": n}
                        for n in test_data['refractive_index']]
Example #13
0
    def get_materials_for_mpids(self, mpids, filter_null_values=True):
        """
        Retrieve a list of Materials from the materials
        Project for a given list of Materials Project IDs.

        Args:
            mpids: a list of Materials Project IDs

        Returns:

        """

        materials_quantities = self.get_quantities_for_mpids(
            mpids,
            filter_null_values=filter_null_values,
            include_date_created=True)
        materials = []

        for material_quantities in materials_quantities:
            material = Material()
            try:
                date_created = material_quantities.pop('created_at')
            except KeyError:
                date_created = None
            for symbol_name, value in material_quantities.items():
                provenance = ProvenanceElement(
                    source={
                        'source': 'Materials Project',
                        'source_key': material_quantities.get(
                            'material_id', None),
                        'date_created': date_created
                    })
                quantity = QuantityFactory.create_quantity(
                    self.mapping[symbol_name],
                    value,
                    units=Registry("units").get(self.mapping[symbol_name],
                                                None),
                    provenance=provenance)
                material.add_quantity(quantity)
            materials.append(material)

        return materials
Example #14
0
    def evaluate(self, material, allow_model_failure=True):
        """
        Given a Material object as input, creates a new Material object
        to include all derivable properties.  Optional argument limits the
        scope of which models or properties are tested. Returns a
        reference to the new, augmented Material object.

        Args:
            material (Material): which material's properties will be expanded.
            allow_model_failure (Bool): whether to continue with graph evaluation
            if a model fails.

        Returns:
            (Material) reference to the newly derived material object.
        """
        logger.debug("Beginning evaluation")

        # Generate initial quantity set and pool
        new_quantities = material.get_quantities()
        quantity_pool = None

        # clear existing model evaluation statistics
        clear()

        # Derive new Quantities
        # Loop util no new Quantity objects are derived.
        logger.debug("Beginning main loop with quantities %s", new_quantities)
        while new_quantities:
            new_quantities, quantity_pool = self.derive_quantities(
                new_quantities,
                quantity_pool,
                allow_model_failure=allow_model_failure)

        # store model evaluation statistics
        self._timings = timings

        new_material = Material()
        new_material._symbol_to_quantity = quantity_pool
        return new_material
Example #15
0
 def setUpClass(cls):
     add_builtin_models_to_registry()
     # This is the visible light dataset used in the propnet paper
     path = os.path.join(TEST_DATA_DIR, "vis_bg_ri_data.csv")
     test_data = pd.read_csv(path)
     graph = Graph()
     materials = [
         Material([QuantityFactory.create_quantity("band_gap", bg)])
         for bg in test_data['Band Gap']
     ]
     cls.evaluated = [graph.evaluate(mat) for mat in materials]
     cls.benchmarks = [{
         "refractive_index": n
     } for n in test_data['Refractive Index']]
Example #16
0
 def test_get_provenance_graph(self):
     g = Graph()
     qs = [
         Quantity("bulk_modulus", 100),
         Quantity("shear_modulus", 50),
         Quantity("density", 8.96)
     ]
     mat = Material(qs)
     evaluated = g.evaluate(mat)
     # TODO: this should be tested more thoroughly
     out = list(evaluated['vickers_hardness'])[0]
     with tempfile.ScratchDir('.'):
         out.draw_provenance_graph("out.png")
     pgraph = out.get_provenance_graph()
     end = list(evaluated['vickers_hardness'])[0]
     shortest_lengths = nx.shortest_path_length(pgraph, qs[0])
     self.assertEqual(shortest_lengths[end], 4)
Example #17
0
    def transform_properties_to_material(self, material_data):
        """
        Produces a propnet Material object from a dictionary of AFLOW materials data.

        Args:
            material_data (dict): AFLOW materials data, keyed by AFLOW keyword, as
                Python native types, not as strings as they are stored in AFLOW.

        Returns:
            propnet.core.materials.Material: propnet material containing the AFLOW data
        """
        qs = []
        auid = material_data.get('auid')
        date_created = material_data.get('aflowlib_date')
        if date_created:
            date, tz = date_created.rsplit("GMT", 1)
            tz = "GMT{:+05d}".format(int(tz) * 100)
            date_object = datetime.strptime(date + tz, "%Y%m%d_%H:%M:%S_%Z%z")
            date_created = date_object.strftime("%Y-%m-%d %H:%M:%S")

        for prop, value in material_data.items():
            if value is not None and prop in self.mapping:
                provenance = ProvenanceElement(
                    source={'source': 'AFLOW',
                            'source_key': auid,
                            'date_created': date_created}
                )

                if prop in self.transform_func:
                    value = self.transform_func[prop](value)
                if value is None:
                    continue
                q = QuantityFactory.create_quantity(
                    self.mapping.get(prop),
                    value,
                    units=self.unit_map.get(prop), provenance=provenance
                )
                qs.append(q)

        return Material(qs)
Example #18
0
class MaterialTest(unittest.TestCase):
    def setUp(self):
        # Create some test properties and a few base objects
        self.q1 = Quantity(
            DEFAULT_SYMBOLS['bulk_modulus'],
            ureg.Quantity.from_tuple([200, [['gigapascals', 1]]]))
        self.q2 = Quantity(
            DEFAULT_SYMBOLS['shear_modulus'],
            ureg.Quantity.from_tuple([100, [['gigapascals', 1]]]))
        self.q3 = Quantity(
            DEFAULT_SYMBOLS['bulk_modulus'],
            ureg.Quantity.from_tuple([300, [['gigapascals', 1]]]))
        self.material = Material()
        self.graph = Graph()

    def test_material_setup(self):
        self.assertTrue(
            len(self.material._symbol_to_quantity) == 0,
            "Material not initialized properly.")

    def test_material_add_quantity(self):
        self.material.add_quantity(self.q1)
        self.assertEqual(len(self.material._symbol_to_quantity), 1,
                         "Material did not add the quantity.")
        self.material.add_quantity(self.q2)
        self.assertEqual(len(self.material._symbol_to_quantity), 2,
                         "Material did not add quantity to itself.")

    def test_material_remove_quantity(self):
        self.material.add_quantity(self.q1)
        self.material.add_quantity(self.q2)
        self.material.remove_quantity(self.q1)
        self.assertEqual(
            len(self.material._symbol_to_quantity[
                DEFAULT_SYMBOLS['shear_modulus']]), 1,
            "Material did not remove the correct quantity.")
        self.material.remove_quantity(self.q2)
        self.assertEqual(
            len(self.material._symbol_to_quantity[
                DEFAULT_SYMBOLS['shear_modulus']]), 0,
            "Material did not remove the quantity correctly.")

    def test_material_remove_symbol(self):
        self.material.add_quantity(self.q1)
        self.material.add_quantity(self.q2)
        self.material.add_quantity(self.q3)
        self.material.remove_symbol(DEFAULT_SYMBOLS['bulk_modulus'])
        self.assertTrue(
            DEFAULT_SYMBOLS['shear_modulus']
            in self.material._symbol_to_quantity.keys(),
            "Material did not remove Symbol correctly.")
        self.assertTrue(
            self.q2 in self.material._symbol_to_quantity[
                DEFAULT_SYMBOLS['shear_modulus']],
            "Material did not remove Symbol correctly.")
        self.assertEqual(len(self.material._symbol_to_quantity), 1,
                         "Material did not remove Symbol correctly.")

    def test_get_symbols(self):
        self.material.add_quantity(self.q1)
        self.material.add_quantity(self.q2)
        self.material.add_quantity(self.q3)
        out = self.material.get_symbols()
        self.assertEqual(len(out), 2,
                         "Material did not get Symbol Types correctly.")
        self.assertTrue(DEFAULT_SYMBOLS['bulk_modulus'] in out,
                        "Material did not get Symbol Types correctly.")
        self.assertTrue(DEFAULT_SYMBOLS['shear_modulus'] in out,
                        "Material did not get Symbol Types correctly.")

    def test_get_quantities(self):
        self.material.add_quantity(self.q1)
        self.material.add_quantity(self.q2)
        self.material.add_quantity(self.q3)
        out = self.material.get_quantities()
        self.assertTrue(all([q in out for q in [self.q1, self.q2, self.q3]]),
                        "Material did not get Quantity objects correctly.")

    def test_get_aggregated_quantities(self):
        self.material.add_quantity(self.q1)
        self.material.add_quantity(self.q2)
        self.material.add_quantity(self.q3)
        agg = self.material.get_aggregated_quantities()
Example #19
0
 def setUp(self):
     self.material = Material()
Example #20
0
 def test_derive_quantities(self):
     # Simple one quantity test
     quantity = Quantity("band_gap", 3.2)
     graph = Graph()
     new, qpool = graph.derive_quantities([quantity])
     new_mat = graph.evaluate(Material([quantity]))
Example #21
0
    def process(self, item):
        if self.graph_parallel and not self.allow_child_process and \
                current_process().name != "MainProcess":
            logger.warning(
                "It appears derive_quantities() is running "
                "in a child process, possibly in a parallelized "
                "Runner.\nThis is not recommended and will deteriorate "
                "performance.")
        # Define quantities corresponding to materials doc fields
        # Attach quantities to materials
        item = MontyDecoder().process_decoded(item)
        logger.info("Populating material for %s", item['task_id'])
        material = Material()

        if 'created_at' in item.keys():
            date_created = item['created_at']
        else:
            date_created = None

        provenance = ProvenanceElement(
            source={
                "source": self.source_name,
                "source_key": item['task_id'],
                "date_created": date_created
            })

        for mkey, property_name in self.materials_symbol_map.items():
            value = pydash.get(item, mkey)
            if value:
                material.add_quantity(
                    QuantityFactory.create_quantity(
                        property_name,
                        value,
                        units=Registry("units").get(property_name, None),
                        provenance=provenance))

        # Add custom things, e. g. computed entry
        computed_entry = get_entry(item)
        if computed_entry:
            material.add_quantity(
                QuantityFactory.create_quantity("computed_entry",
                                                computed_entry,
                                                provenance=provenance))
        else:
            logger.info("Unable to create computed entry for {}".format(
                item['task_id']))
        material.add_quantity(
            QuantityFactory.create_quantity("external_identifier_mp",
                                            item['task_id'],
                                            provenance=provenance))

        input_quantities = material.symbol_quantities_dict

        # Use graph to generate expanded quantity pool
        logger.info("Evaluating graph for %s", item['task_id'])

        new_material = self._graph_evaluator.evaluate(
            material, timeout=self.graph_timeout)

        # Format document and return
        logger.info("Creating doc for %s", item['task_id'])
        # Gives the initial inputs that were used to derive properties of a
        # certain material.

        doc = {
            "inputs": [
                StorageQuantity.from_quantity(q)
                for q in chain.from_iterable(input_quantities.values())
            ]
        }

        for symbol, quantities in new_material.symbol_quantities_dict.items():
            # If no new quantities of a given symbol were derived (i.e. if the initial
            # input quantity/ies is/are the only one/s listed in the new material) then don't add
            # that quantity to the propnet entry document as a derived quantity.
            if len(quantities) == len(input_quantities[symbol]):
                continue
            sub_doc = {}
            try:
                # Write out all quantities as dicts including the
                # internal ID for provenance tracing
                qs = [
                    jsanitize(StorageQuantity.from_quantity(q), strict=True)
                    for q in quantities
                ]
            except AttributeError as ex:
                # Check to see if this is an error caused by an object
                # that is not JSON serializable
                msg = ex.args[0]
                if "object has no attribute 'as_dict'" in msg:
                    # Write error to db and logger
                    errmsg = "Quantity of Symbol '{}' is not ".format(symbol.name) + \
                        "JSON serializable. Cannot write quantities to database!"
                    logger.error(errmsg)
                    sub_doc['error'] = errmsg
                    qs = []
                else:
                    # If not, re-raise the error
                    raise ex
            sub_doc['quantities'] = qs
            doc[symbol.name] = sub_doc

        aggregated_quantities = new_material.get_aggregated_quantities()

        for symbol, quantity in aggregated_quantities.items():
            if symbol.name not in doc:
                # No new quantities were derived
                continue
            # Store mean and std dev for aggregated quantities
            sub_doc = {
                "mean": unumpy.nominal_values(quantity.value).tolist(),
                "std_dev": unumpy.std_devs(quantity.value).tolist(),
                "units":
                quantity.units.format_babel() if quantity.units else None,
                "title": quantity.symbol.display_names[0]
            }
            # Symbol Name -> Sub_Document, listing all Quantities of that type.
            doc[symbol.name].update(sub_doc)

        doc.update({
            "task_id": item["task_id"],
            "pretty_formula": item.get("pretty_formula"),
            "deprecated": item.get("deprecated", False)
        })

        if self.include_sandboxed:
            doc.update({'sbxn': item.get("sbxn", [])})

        return jsanitize(doc, strict=True)
Example #22
0
    def evaluate(input_rows, data, aggregate):

        quantities = []

        for idx, row in enumerate(input_rows):
            if row['Editable Value']:
                try:
                    value = ureg.parse_expression(row['Editable Value'])
                    units = Registry("units").get(ROW_IDX_TO_SYMBOL_NAME[idx])
                    value.ito(units)
                except Exception:
                    # Someone put an invalid value in the table
                    # TODO: Make error known to the user
                    raise PreventUpdate
                q = QuantityFactory.create_quantity(
                    symbol_type=ROW_IDX_TO_SYMBOL_NAME[idx], value=value)
                quantities.append(q)

        if data and len(data) > 0:
            quantities += json.loads(data, cls=MontyDecoder).values()

        if not quantities:
            raise PreventUpdate

        material = Material()

        for quantity in quantities:
            material.add_quantity(quantity)

        output_material = graph_evaluator.evaluate(material, timeout=5)

        if aggregate:
            aggregated_quantities = output_material.get_aggregated_quantities()
            non_aggregatable_quantities = [
                v for v in output_material.get_quantities()
                if v.symbol not in aggregated_quantities
            ]
            output_quantities = list(
                aggregated_quantities.values()) + non_aggregatable_quantities
        else:
            output_quantities = output_material.get_quantities()

        output_rows = [{
            'Property': quantity.symbol.display_names[0],
            'Value': quantity.pretty_string(sigfigs=3)
        } for quantity in output_quantities]

        output_table = dt.DataTable(id='output-table',
                                    data=output_rows,
                                    columns=[{
                                        'id': val,
                                        'name': val
                                    } for val in ('Property', 'Value')],
                                    editable=False,
                                    **DATA_TABLE_STYLE)

        # TODO: clean up

        input_quantity_names = [q.symbol for q in quantities]
        derived_quantity_names = \
            set([q.symbol for q in output_quantities]) - \
            set(input_quantity_names)

        models_evaluated = set(
            output_q.provenance.model
            for output_q in output_material.get_quantities())
        models_evaluated = [
            Registry("models").get(m) for m in models_evaluated
            if Registry("models").get(m) is not None
        ]

        material_graph_data = graph_conversion(
            propnet_nx_graph,
            derivation_pathway={
                'inputs': input_quantity_names,
                'outputs': list(derived_quantity_names),
                'models': models_evaluated
            })

        output_graph = html.Div(children=[
            dcc.Checklist(id='material-graph-options',
                          options=[{
                              'label': 'Show models',
                              'value': 'show_models'
                          }, {
                              'label': 'Show properties',
                              'value': 'show_properties'
                          }],
                          value=['show_properties'],
                          labelStyle={'display': 'inline-block'}),
            Cytoscape(id='material-graph',
                      elements=material_graph_data,
                      stylesheet=GRAPH_STYLESHEET,
                      layout=GRAPH_LAYOUT_CONFIG,
                      **GRAPH_SETTINGS['full_view'])
        ])

        return [output_graph, html.Br(), output_table]
Example #23
0
    def process_item(self, item):
        # Define quantities corresponding to materials doc fields
        # Attach quantities to materials
        item = MontyDecoder().process_decoded(item)
        logger.info("Populating material for %s", item['task_id'])
        material = Material()

        if 'created_at' in item.keys():
            date_created = item['created_at']
        else:
            date_created = ""

        provenance = ProvenanceElement(
            source={
                "source": self.source_name,
                "source_key": item['task_id'],
                "date_created": date_created
            })

        for mkey, property_name in self.materials_symbol_map.items():
            value = get(item, mkey)
            if value:
                material.add_quantity(
                    QuantityFactory.create_quantity(property_name,
                                                    value,
                                                    provenance=provenance))

        # Add custom things, e. g. computed entry
        computed_entry = get_entry(item)
        material.add_quantity(
            QuantityFactory.create_quantity("computed_entry",
                                            computed_entry,
                                            provenance=provenance))
        material.add_quantity(
            QuantityFactory.create_quantity("external_identifier_mp",
                                            item['task_id'],
                                            provenance=provenance))

        input_quantities = material.get_quantities()

        # Use graph to generate expanded quantity pool
        logger.info("Evaluating graph for %s", item['task_id'])
        graph = Graph()
        graph.remove_models({
            "dimensionality_cheon":
            DEFAULT_MODEL_DICT['dimensionality_cheon'],
            "dimensionality_gorai":
            DEFAULT_MODEL_DICT['dimensionality_gorai']
        })
        new_material = graph.evaluate(material)

        # Format document and return
        logger.info("Creating doc for %s", item['task_id'])
        # Gives the initial inputs that were used to derive properties of a
        # certain material.

        doc = {
            "inputs":
            [StorageQuantity.from_quantity(q) for q in input_quantities]
        }
        for symbol, quantity in new_material.get_aggregated_quantities().items(
        ):
            all_qs = new_material._symbol_to_quantity[symbol]
            # Only add new quantities
            # TODO: Condition insufficiently general.
            #       Can end up with initial quantities added as "new quantities"
            if len(all_qs) == 1 and list(all_qs)[0] in input_quantities:
                continue
            # Write out all quantities as dicts including the
            # internal ID for provenance tracing
            qs = [StorageQuantity.from_quantity(q).as_dict() for q in all_qs]
            # THE listing of all Quantities of a given symbol.
            sub_doc = {
                "quantities": qs,
                "mean": unumpy.nominal_values(quantity.value).tolist(),
                "std_dev": unumpy.std_devs(quantity.value).tolist(),
                "units":
                quantity.units.format_babel() if quantity.units else None,
                "title": quantity._symbol_type.display_names[0]
            }
            # Symbol Name -> Sub_Document, listing all Quantities of that type.
            doc[symbol.name] = sub_doc

        doc.update({
            "task_id": item["task_id"],
            "pretty_formula": item["pretty_formula"]
        })
        return jsanitize(doc, strict=True)
Example #24
0
class MaterialTest(unittest.TestCase):

    def setUp(self):
        # Create some test properties and a few base objects
        self.q1 = QuantityFactory.create_quantity(DEFAULT_SYMBOLS['bulk_modulus'],
                                                  ureg.Quantity.from_tuple([200, [['gigapascals', 1]]]))
        self.q2 = QuantityFactory.create_quantity(DEFAULT_SYMBOLS['shear_modulus'],
                                                  ureg.Quantity.from_tuple([100, [['gigapascals', 1]]]))
        self.q3 = QuantityFactory.create_quantity(DEFAULT_SYMBOLS['bulk_modulus'],
                                                  ureg.Quantity.from_tuple([300, [['gigapascals', 1]]]))
        self.material = Material()
        self.graph = Graph()

    def test_material_setup(self):
        self.assertTrue(len(self.material._symbol_to_quantity) == 0,
                        "Material not initialized properly.")

    def test_material_add_quantity(self):
        self.material.add_quantity(self.q1)
        self.assertEqual(len(self.material._symbol_to_quantity), 1,
                         "Material did not add the quantity.")
        self.material.add_quantity(self.q2)
        self.assertEqual(len(self.material._symbol_to_quantity), 2,
                         "Material did not add quantity to itself.")

    def test_material_remove_quantity(self):
        self.material.add_quantity(self.q1)
        self.material.add_quantity(self.q2)
        self.material.remove_quantity(self.q1)
        self.assertEqual(
            len(self.material._symbol_to_quantity[DEFAULT_SYMBOLS['shear_modulus']]),
            1, "Material did not remove the correct quantity.")
        self.material.remove_quantity(self.q2)
        self.assertEqual(
            len(self.material._symbol_to_quantity[DEFAULT_SYMBOLS['shear_modulus']]),
            0, "Material did not remove the quantity correctly.")

    def test_material_remove_symbol(self):
        self.material.add_quantity(self.q1)
        self.material.add_quantity(self.q2)
        self.material.add_quantity(self.q3)
        self.material.remove_symbol(DEFAULT_SYMBOLS['bulk_modulus'])
        self.assertTrue(
            DEFAULT_SYMBOLS['shear_modulus'] in self.material._symbol_to_quantity.keys(),
            "Material did not remove Symbol correctly.")
        self.assertTrue(
            self.q2 in self.material._symbol_to_quantity[DEFAULT_SYMBOLS['shear_modulus']],
            "Material did not remove Symbol correctly.")
        self.assertEqual(len(self.material._symbol_to_quantity), 1,
                         "Material did not remove Symbol correctly.")

    def test_get_symbols(self):
        self.material.add_quantity(self.q1)
        self.material.add_quantity(self.q2)
        self.material.add_quantity(self.q3)
        out = self.material.get_symbols()
        self.assertEqual(
            len(out), 2, "Material did not get Symbol Types correctly.")
        self.assertTrue(DEFAULT_SYMBOLS['bulk_modulus'] in out,
                        "Material did not get Symbol Types correctly.")
        self.assertTrue(DEFAULT_SYMBOLS['shear_modulus'] in out,
                        "Material did not get Symbol Types correctly.")

    def test_get_quantities(self):
        self.material.add_quantity(self.q1)
        self.material.add_quantity(self.q2)
        self.material.add_quantity(self.q3)
        out = self.material.get_quantities()
        self.assertTrue(all([q in out for q in [self.q1, self.q2, self.q3]]),
                        "Material did not get Quantity objects correctly.")

    def test_get_aggregated_quantities(self):
        self.material.add_quantity(self.q1)
        self.material.add_quantity(self.q2)
        self.material.add_quantity(self.q3)
        agg = self.material.get_aggregated_quantities()
        # TODO: add a meaningful test here

    def test_add_default_quantities(self):
        material = Material(add_default_quantities=True)
        self.assertEqual(list(material['temperature'])[0],
                         QuantityFactory.create_quantity("temperature", 300,
                                                         provenance=ProvenanceElement(model='default')))
        self.assertEqual(list(material['relative_permeability'])[0],
                         QuantityFactory.create_quantity("relative_permeability", 1,
                         provenance=ProvenanceElement(model='default')))