Esempio n. 1
0
 def test_apply_material_to_graph(self):
     g = Graph()
     new_mat = g.evaluate(self.mat)
     # TODO:
     # For some reason Travis and this version are not commensurate
     # 257 != 263, should resolve this
     self.assertGreater(len(new_mat.get_quantities()), 250)
    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
Esempio n. 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]
Esempio n. 4
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']]
Esempio n. 5
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)
Esempio n. 6
0
    def test_evaluate_cyclic(self):
        """
        Tests the evaluation algorithm on a cyclic graph.
        The canonical graph and the canonical material are used for this test.
        """
        symbols = GraphTest.generate_canonical_symbols()
        models = GraphTest.generate_canonical_models()
        material = GraphTest.generate_canonical_material(symbols)
        g = Graph(symbol_types=symbols, models=models, composite_models=dict())
        material_derived = g.evaluate(material)

        expected_quantities = [
            # Starting
            Quantity(symbols['A'], 19),
            Quantity(symbols['A'], 23),

            # Derives -1 (M1)
            Quantity(symbols['B'], 38),
            Quantity(symbols['B'], 46),
            Quantity(symbols['C'], 57),
            Quantity(symbols['C'], 69),
            # Derives -2 (M3, M1)
            Quantity(symbols['F'], 266),
            Quantity(symbols['F'], 322),
            # Derives -2 (M4, M1)
            Quantity(symbols['D'], 23826),
            Quantity(symbols['D'], 28842),
            Quantity(symbols['D'], 34914),

            # Derives -1 (M2)
            Quantity(symbols['G'], 95),
            Quantity(symbols['G'], 115),
            # Derives -2 (M5, M1, M2)
            Quantity(symbols['D'], 70395),
            Quantity(symbols['D'], 85215),
            Quantity(symbols['D'], 103155),
        ]

        self.assertTrue(
            material == GraphTest.generate_canonical_material(symbols),
            "evaluate() mutated the original material argument.")

        derived_quantities = material_derived.get_quantities()
        self.assertTrue(
            len(expected_quantities) == len(derived_quantities),
            "Evaluate did not correctly derive outputs.")
        for q in expected_quantities:
            self.assertTrue(
                q in material_derived._symbol_to_quantity[q.symbol],
                "Evaluate failed to derive all outputs.")
            self.assertTrue(q in derived_quantities)
Esempio n. 7
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']]
Esempio n. 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.")
Esempio n. 9
0
    def test_evaluate_constraints(self):
        """
        Tests the evaluation algorithm on a non-cyclic graph involving
        constraints.  The canonical graph and the canonical material are
        used for this test.
        """
        model4 = EquationModel(name="model4",
                               equations=["D=B*C*11"],
                               constraints=["G==0"])

        symbols = GraphTest.generate_canonical_symbols()
        models = GraphTest.generate_canonical_models()
        models['model4'] = model4
        del models['model6']
        material = GraphTest.generate_canonical_material(symbols)
        g = Graph(symbol_types=symbols, models=models, composite_models=dict())
        material_derived = g.evaluate(material)

        expected_quantities = [
            Quantity(symbols['A'], 19),
            Quantity(symbols['A'], 23),
            Quantity(symbols['B'], 38),
            Quantity(symbols['B'], 46),
            Quantity(symbols['C'], 57),
            Quantity(symbols['C'], 69),
            Quantity(symbols['G'], 95),
            Quantity(symbols['G'], 115),
            Quantity(symbols['F'], 266),
            Quantity(symbols['F'], 322),
            Quantity(symbols['D'], 70395),
            Quantity(symbols['D'], 85215),
            Quantity(symbols['D'], 103155)
        ]

        self.assertTrue(
            material == GraphTest.generate_canonical_material(symbols),
            "evaluate() mutated the original material argument.")

        derived_quantities = material_derived.get_quantities()
        self.assertTrue(
            len(expected_quantities) == len(derived_quantities),
            "Evaluate did not correctly derive outputs.")
        for q in expected_quantities:
            self.assertTrue(
                q in material_derived._symbol_to_quantity[q.symbol],
                "Evaluate failed to derive all outputs.")
            self.assertTrue(q in derived_quantities)
Esempio n. 10
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)
Esempio n. 11
0
    def test_provenance(self):
        model4 = EquationModel(name="model4", equations=["D=B*C*11"], constraints=["G==0"])
        symbols = GraphTest.generate_canonical_symbols()
        models = GraphTest.generate_canonical_models()
        models['model4'] = model4
        del models['model6']
        material = GraphTest.generate_canonical_material(symbols)
        g = Graph(symbol_types=symbols, models=models, composite_models=dict())
        material_derived = g.evaluate(material)

        expected_quantities = [
            Quantity(symbols['A'], 19),
            Quantity(symbols['A'], 23),
            Quantity(symbols['B'], 38),
            Quantity(symbols['B'], 46),
            Quantity(symbols['C'], 57),
            Quantity(symbols['C'], 69),
            Quantity(symbols['G'], 95),
            Quantity(symbols['G'], 115),
            Quantity(symbols['F'], 266),
            Quantity(symbols['F'], 322),
            Quantity(symbols['D'], 70395),
            Quantity(symbols['D'], 85215),
            Quantity(symbols['D'], 103155)
        ]

        for q in material_derived._symbol_to_quantity[symbols['A']]:
            self.assertTrue(q._provenance is None)
        for q in material_derived._symbol_to_quantity[symbols['B']]:
            if q.value == 38:
                self.assertTrue(q._provenance.model is models['model1'].name,
                                "provenance improperly calculated")
                self.assertTrue(expected_quantities[0] in q._provenance.inputs,
                                "provenance improperly calculated")
            else:
                self.assertTrue(q._provenance.model is models['model1'].name,
                                "provenance improperly calculated")
                self.assertTrue(expected_quantities[1] in q._provenance.inputs,
                                "provenance improperly calculated")
        for q in material_derived._symbol_to_quantity[symbols['C']]:
            if q.value == 57:
                self.assertTrue(q._provenance.model is models['model1'].name,
                                "provenance improperly calculated")
                self.assertTrue(expected_quantities[0] in q._provenance.inputs,
                                "provenance improperly calculated")
            else:
                self.assertTrue(q._provenance.model is models['model1'].name,
                                "provenance improperly calculated")
                self.assertTrue(expected_quantities[1] in q._provenance.inputs,
                                "provenance improperly calculated")
        for q in material_derived._symbol_to_quantity[symbols['G']]:
            if q.value == 95:
                self.assertTrue(q._provenance.model is models['model2'].name,
                                "provenance improperly calculated")
                self.assertTrue(expected_quantities[0] in q._provenance.inputs,
                                "provenance improperly calculated")
            else:
                self.assertTrue(q._provenance.model is models['model2'].name,
                                "provenance improperly calculated")
                self.assertTrue(expected_quantities[1] in q._provenance.inputs,
                                "provenance improperly calculated")
        for q in material_derived._symbol_to_quantity[symbols['D']]:
            if q.value == 70395:
                self.assertTrue(q._provenance.model is models['model5'].name,
                                "provenance improperly calculated")
                self.assertTrue(expected_quantities[4] in q._provenance.inputs,
                                "provenance improperly calculated")
                self.assertTrue(expected_quantities[6] in q._provenance.inputs,
                                "provenance improperly calculated")
Esempio n. 12
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]))
Esempio n. 13
0
class PropnetBuilder(MapBuilder):
    """
    Basic builder for running propnet derivations on various properties
    """
    def __init__(self,
                 materials,
                 propstore,
                 materials_symbol_map=None,
                 criteria=None,
                 source_name="",
                 include_deprecated=False,
                 include_sandboxed=False,
                 graph_parallel=False,
                 max_graph_workers=None,
                 graph_timeout=None,
                 allow_child_process=False,
                 **kwargs):
        """
        Args:
            materials (Store): store of materials properties
            materials_symbol_map (dict): mapping of keys in materials
                store docs to symbols
            propstore (Store): store of propnet properties
            criteria (dict): criteria for Mongodb find() query specifying
                criteria for records to process
            source_name (str): identifier for record source
            include_deprecated (bool): True processes materials marked as
                deprecated via the "deprecated" field. False skips those materials.
                If an entry does not have the "deprecated" field, it will be processed.
                Note that False will create a logical "and" with any criteria specified
                in "criteria". Default: False
            include_sandboxed (bool): True processes materials regardless of their MP
                sandbox. Note that False will create a logical "and" with any criteria specified
                in "criteria". False restricts materials to the "core" sandbox. Default: False
            graph_parallel (bool): True runs the graph algorithm in parallel with
                the number of workers specified by max_workers. Default: False (serial)
                Note: there will be no substantial speed-up from using a parallel
                runner with a parallel builder if there are long-running model evaluations
                that don't get timed out using the timeout keyword.
            max_graph_workers (int): number of processes to spawn for parallel graph
                evaluation. Note that graph evaluation speed-up tops out at 3-4
                parallel processes. If the builder is run in a parallel maggma Runner,
                each will spawn max_workers number of processes to evaluate.
                For 4 parallel graph processes running on 3 parallel runners, this will spawn:
                1 main runner process + 3 parallel runners + (3 parallel
                runners * 4 graph processes) = 16 total processes
            graph_timeout (int): number of seconds after which to timeout per property
                (available only on Unix-based systems). Default: None (no limit)
            allow_child_process (bool): If True, the user will be warned when graph_parallel
                is True and the builder is being run in a child process, usually
                indicating the builder is being run in a parallelized Runner, which is
                not recommended due to inefficiency in having to re-fork the graph processes
                with every new material. False suppresses this warning.
            **kwargs: kwargs for builder
        """
        self.materials = materials
        self.propstore = propstore

        self.include_deprecated = include_deprecated
        self.include_sandboxed = include_sandboxed

        filters = []
        if criteria:
            filters.append(criteria)

        if not include_deprecated:
            deprecated_filter = {
                "$or": [{
                    "deprecated": {
                        "$exists": False
                    }
                }, {
                    "deprecated": False
                }]
            }
            filters.append(deprecated_filter)

        if not include_sandboxed:
            sandboxed_filter = {'sbxn': 'core'}
            filters.append(sandboxed_filter)

        if len(filters) > 1:
            self.criteria = {'$and': filters}
        else:
            self.criteria = filters[0] if filters else None

        self.materials_symbol_map = materials_symbol_map \
                                    or MPRester.mapping
        if source_name == "":
            # Because this builder is not fully general, will keep this here
            self.source_name = "Materials Project"
        else:
            self.source_name = source_name

        self.graph_parallel = graph_parallel
        if not graph_parallel and max_graph_workers is not None:
            raise ValueError("Cannot specify max_workers with parallel=False")
        self.max_graph_workers = max_graph_workers

        self.graph_timeout = graph_timeout
        self.allow_child_process = allow_child_process
        self._graph_evaluator = Graph(parallel=graph_parallel,
                                      max_workers=max_graph_workers)

        props = list(self.materials_symbol_map.keys())
        props += [
            "task_id", "pretty_formula", "run_type", "is_hubbard",
            "pseudo_potential", "hubbards", "potcar_symbols", "oxide_type",
            "final_energy", "unit_cell_formula", "created_at", "deprecated",
            "sbxn"
        ]
        props = list(set(props))

        super(PropnetBuilder, self).__init__(source=materials,
                                             target=propstore,
                                             query=self.criteria,
                                             ufn=self.process,
                                             projection=props,
                                             **kwargs)

    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)
Esempio n. 14
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)
Esempio n. 15
0
def retrieve_material(n_clicks, query, derive_properties):
    """
    Gets the material view from options

    Args:
        n_clicks (int): load material click
        formula (string): formula to find
        derive_properties ([str]): list of derivation options

    Returns:
        Div of graph component with fulfilled options

    """
    if n_clicks is None:
        return ""

    log.info("Fetching data from MP for query {}".format(query))
    if query.startswith("mp-") or query.startswith("mvc-"):
        mpid = query
    else:
        mpid = mpr.get_mpid_from_formula(query)
    material = mpr.get_material_for_mpid(mpid)
    if not material:
        return "Material not found."
    log.info("Retrieved material {} for formula {}".format(
        mpid, material['pretty_formula']))

    log.debug("Adding material to graph.")
    p = Graph()
    material_quantity_names = [
        q.symbol.name for q in material.get_quantities()
    ]
    g = p.graph

    if 'derive' in derive_properties:
        log.info("Deriving quantities for {}".format(mpid))
        material = p.evaluate(material)

        if 'aggregate' in derive_properties:
            log.debug("Aggregating quantities for material {}".format(mpid))
            # TODO: get aggregated quantities should return a list
            quantities = material.get_aggregated_quantities().items()
        else:
            quantities = [(q.symbol, q) for q in material.get_quantities()]
    else:
        quantities = [(q.symbol, q) for q in material.get_quantities()]

    rows = []
    for symbol, quantity in quantities:
        rows.append({
            'Symbol': symbol.display_names[0],
            'Value': quantity.pretty_string(3),
            # TODO: node.node_value.value? this has to make sense
            # 'Units': str(node.node_value.symbol.unit_as_string)
        })

    table = dt.DataTable(rows=rows,
                         row_selectable=True,
                         filterable=True,
                         sortable=True,
                         editable=False,
                         selected_row_indices=[],
                         id='datatable')
    derived_quantity_names = set([symbol.name for symbol, quantity in quantities]) -\
        set(material_quantity_names)
    material_graph_data = graph_conversion(
        g,
        nodes_to_highlight_green=material_quantity_names,
        nodes_to_highlight_yellow=list(derived_quantity_names))
    options = AESTHETICS['global_options']
    options['edges']['color'] = '#000000'
    material_graph_component = html.Div(GraphComponent(
        id='material-graph', graph=material_graph_data, options=options),
                                        style={
                                            'width': '100%',
                                            'height': '400px'
                                        })

    return html.Div(
        [html.H3('Graph'), material_graph_component,
         html.H3('Table'), table])