Example #1
0
    def test_model_returns_nan(self):
        # This tests model failure with scalar nan.
        # Quantity class has other more thorough tests.

        A = Symbol('a', ['A'], ['A'], units='dimensionless', shape=1)
        B = Symbol('b', ['B'], ['B'], units='dimensionless', shape=1)
        for sym in (B, A):
            Registry("symbols")[sym] = sym
            Registry("units")[sym] = sym.units
        get_config = {
            'name': 'equality',
            # 'connections': [{'inputs': ['b'], 'outputs': ['a']}],
            'equations': ['a = b'],
            # 'unit_map': {'a': "dimensionless", 'a': "dimensionless"}
            'variable_symbol_map': {
                "a": A,
                "b": B
            }
        }
        model = EquationModel(**get_config)
        out = model.evaluate(
            {'b': QuantityFactory.create_quantity(B, float('nan'))},
            allow_failure=True)
        self.assertFalse(out['successful'])
        self.assertEqual(out['message'],
                         'Evaluation returned invalid values (NaN)')
Example #2
0
 def test_clear_registries(self):
     Registry("to_clear")['entry'] = 'data'
     self.assertIn('to_clear', Registry.all_instances.keys())
     self.assertIn('entry', Registry("to_clear").keys())
     self.assertEqual(Registry("to_clear")['entry'], 'data')
     Registry.clear_all_registries()
     self.assertNotIn('to_clear', Registry.all_instances.keys())
Example #3
0
    def as_dict(self):
        """
        Returns object instance as a dictionary. Object can be reconstituted from this
        dictionary using from_dict().

        Returns: (dict) dictionary representation of the object

        """
        symbol = self._symbol_type
        if symbol.name in Registry("symbols").keys() and symbol == Registry("symbols")[symbol.name] and \
                symbol.is_builtin:
            symbol = self._symbol_type.name

        return {
            "@module": self.__class__.__module__,
            "@class": self.__class__.__name__,
            "internal_id": self._internal_id,
            "data_type": self._data_type,
            "symbol_type": symbol,
            "value": self._value,
            "units": self._units,
            "provenance": self._provenance,
            "tags": self._tags,
            "uncertainty": self._uncertainty
        }
Example #4
0
    def test_example_code_helper(self):
        example_model = Registry("models")['semi_empirical_mobility']

        # TODO: this is ugly, any way to fix it?
        example_code = """
from propnet.models import semi_empirical_mobility


K = 64
m_e = 0.009

semi_empirical_mobility.plug_in({
\t'K': K,
\t'm_e': m_e,
})
\"\"\"
returns {'mu_e': 8994.92312225673}
\"\"\"
"""
        self.assertEqual(example_model.example_code, example_code)

        for model in Registry("models").values():
            # A little weird, but otherwise you don't get the explicit error
            if model.is_builtin:
                try:
                    exec(model.example_code)
                except Exception as e:
                    raise e
Example #5
0
    def register(self, overwrite_registry=False):
        """
        Registers the symbol with the symbol registry.

        Args:
            overwrite_registry (bool): If a symbol with the same name
                as the current is already registered, `True` will overwrite
                the old symbol with the current and `False` will raise a
                KeyError.

        Raises:
            KeyError: if `overwrite_registry=False` and a symbol with the same
                name is already registered, this error is raised.

        """
        if not overwrite_registry and \
                (self.name in Registry("symbols").keys() or self.name in Registry("units").keys()):
            raise KeyError(
                "Symbol '{}' already exists in the symbol or unit registry".
                format(self.name))

        Registry("symbols")[self.name] = self
        Registry("units")[
            self.name] = self.units.format_babel() if self.units else None
        if self.default_value is not None:
            Registry("symbol_values")[self.name] = self.default_value
Example #6
0
def symbols_index():

    symbol_links = {}
    for symbol_name in Registry("symbols"):

        # group by tag
        symbol_type = Registry("symbols")[symbol_name].category
        display_name = Registry("symbols")[symbol_name].display_names[0]

        if symbol_type not in symbol_links:
            symbol_links[symbol_type] = []

        symbol_links[symbol_type].append(
            html.Div([
                dcc.Link("{}".format(display_name),
                         href='/property/{}'.format(symbol_name)),
                html.Br()
            ]))

    symbol_links_grouped = []
    for symbol_type, links in symbol_links.items():
        symbol_links_grouped += [
            html.H6(symbol_type.title()),
            html.Div(links),
            html.Br()
        ]

    return html.Div([
        html.H5('Currently supported symbols:'),
        html.Div(symbol_links_grouped),
        #html.Br(),
        #dcc.Link('< Back', href='/')
    ])
Example #7
0
    def test_basic_registry(self):
        test_reg = Registry("test")
        test_reg2 = Registry("test")
        test_reg3 = Registry("test2")

        self.assertIsInstance(test_reg, dict)
        self.assertTrue(test_reg is test_reg2)
        self.assertTrue(test_reg is not test_reg3)
Example #8
0
    def unregister(self):
        """
        Removes the symbol from all applicable registries.

        """
        Registry("symbols").pop(self.name, None)
        Registry("units").pop(self.name, None)
        Registry("symbol_values").pop(self.name, None)
Example #9
0
def parse_path(pathname, search=None):
    """Utility function to parse URL path for routing purposes etc.
    This function exists because the path has to be parsed in
    a few places for callbacks.

    Args:
      pathname (str): path from url
      search (str): query string from url

    Returns:
        (dict) dictionary containing 'mode' ('property', 'model' etc.),
        'value' (name of property etc.)

    """

    if pathname == '/' or pathname is None:
        return None

    mode = None  # 'property' or 'model'
    value = None  # property name / model name

    # TODO: get rid of this

    if pathname == '/model':
        mode = 'model'
    elif pathname.startswith('/model'):
        mode = 'model'
        for model in Registry("models").keys():
            if pathname.startswith('/model/{}'.format(model)):
                value = model
    elif pathname == '/property':
        mode = 'property'
    elif pathname.startswith('/property'):
        mode = 'property'
        for property_ in Registry("symbols").keys():
            if pathname.startswith('/property/{}'.format(property_)):
                value = property_
    elif pathname.startswith('/explore'):
        mode = 'explore'
    elif pathname.startswith('/plot'):
        mode = 'plot'
        if search:
            q_vals = parse_qs(urlsplit(search).query)
            value = {k: v[0] for k, v in q_vals.items()
                     if k in ('x', 'y', 'z') and v is not None}
    elif pathname.startswith('/generate'):
        mode = 'generate'
    elif pathname.startswith('/correlate'):
        mode = 'correlate'
    elif pathname.startswith('/refs'):
        mode = 'refs'
    elif pathname.startswith('/home'):
        mode = 'home'

    return {
        'mode': mode,
        'value': value
    }
Example #10
0
 def test_instantiate_all_models(self):
     models_to_test = []
     for model_name in Registry("models").keys():
         try:
             model = Registry("models").get(model_name)
             self.assertIsNotNone(model)
             models_to_test.append(model_name)
         except Exception as e:
             self.fail('Failed to load model {}: {}'.format(model_name, e))
Example #11
0
 def tearDownClass(cls):
     non_builtin_syms = [
         k for k, v in Registry("symbols").items() if not v.is_builtin
     ]
     for sym in non_builtin_syms:
         Registry("symbols").pop(sym)
         Registry("units").pop(sym)
     non_builtin_models = [
         k for k, v in Registry("models").items() if not v.is_builtin
     ]
     for model in non_builtin_models:
         Registry("models").pop(model)
Example #12
0
 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(
         Registry("symbols")['bulk_modulus'] in out,
         "Material did not get Symbol Types correctly.")
     self.assertTrue(
         Registry("symbols")['shear_modulus'] in out,
         "Material did not get Symbol Types correctly.")
Example #13
0
 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._quantities_by_symbol[Registry("symbols")
                                                 ['shear_modulus']]), 1,
         "Material did not remove the correct quantity.")
     self.material.remove_quantity(self.q2)
     self.assertEqual(
         len(self.material._quantities_by_symbol[Registry("symbols")
                                                 ['shear_modulus']]), 0,
         "Material did not remove the quantity correctly.")
Example #14
0
 def setUpClass(cls):
     add_builtin_symbols_to_registry()
     # Create some test properties and a few base objects
     cls.q1 = QuantityFactory.create_quantity(
         Registry("symbols")['bulk_modulus'],
         ureg.Quantity.from_tuple([200, [['gigapascals', 1]]]))
     cls.q2 = QuantityFactory.create_quantity(
         Registry("symbols")['shear_modulus'],
         ureg.Quantity.from_tuple([100, [['gigapascals', 1]]]))
     cls.q3 = QuantityFactory.create_quantity(
         Registry("symbols")['bulk_modulus'],
         ureg.Quantity.from_tuple([300, [['gigapascals', 1]]]))
     cls.material = None
     cls.graph = Graph()
Example #15
0
    def test_model_register_unregister(self):
        A = Symbol('a', ['A'], ['A'], units='dimensionless', shape=1)
        B = Symbol('b', ['B'], ['B'], units='dimensionless', shape=1)
        C = Symbol('c', ['C'], ['C'], units='dimensionless', shape=1)
        D = Symbol('d', ['D'], ['D'], units='dimensionless', shape=1)
        m = EquationModel('equation_model_to_remove', ['a = b * 3'],
                          variable_symbol_map={
                              'a': A,
                              'b': B
                          })
        self.assertIn(m.name, Registry("models"))
        self.assertTrue(m.registered)
        m.unregister()
        self.assertNotIn(m.name, Registry("models"))
        self.assertFalse(m.registered)
        m.register()
        self.assertTrue(m.registered)
        with self.assertRaises(KeyError):
            m.register(overwrite_registry=False)

        m.unregister()
        m = EquationModel('equation_model_to_remove', ['a = b * 3'],
                          variable_symbol_map={
                              'a': A,
                              'b': B
                          },
                          register=False)
        self.assertNotIn(m.name, Registry("models"))
        self.assertFalse(m.registered)

        m.register()
        with self.assertRaises(KeyError):
            _ = EquationModel('equation_model_to_remove', ['a = b * 3'],
                              variable_symbol_map={
                                  'a': A,
                                  'b': B
                              },
                              register=True,
                              overwrite_registry=False)

        m_replacement = EquationModel('equation_model_to_remove',
                                      ['c = d * 3'],
                                      variable_symbol_map={
                                          'c': C,
                                          'd': D
                                      })

        m_registered = Registry("models")['equation_model_to_remove']
        self.assertIs(m_registered, m_replacement)
        self.assertIsNot(m_registered, m)
Example #16
0
 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(Registry("symbols")['bulk_modulus'])
     self.assertTrue(
         Registry("symbols")['shear_modulus']
         in self.material._quantities_by_symbol.keys(),
         "Material did not remove Symbol correctly.")
     self.assertTrue(
         self.q2 in self.material._quantities_by_symbol[Registry("symbols")
                                                        ['shear_modulus']],
         "Material did not remove Symbol correctly.")
     self.assertEqual(len(self.material._quantities_by_symbol), 1,
                      "Material did not remove Symbol correctly.")
Example #17
0
def validate(args):
    """Validates test data"""
    if args.name is not None:
        model = Registry("models")[args.name]
        if not args.test_data:
            test_wrapper(model.validate_from_preset_test, pdb)
            print("Model validated with test data")
            return True
    elif args.file is not None:
        if args.file.endswith(".yaml"):
            EquationModel.from_file(args.file)
        elif args.file.endswith(".py"):
            # This should define config
            with open(args.file) as this_file:
                code = compile(this_file.read(), args.file, 'exec')
                exec(code, globals())
            config = globals().get('config')
            model = PyModel(**config)

    if args.test_data is not None:
        td_data = loadfn(args.test_data)
        for td_datum in td_data:
            test_wrapper(model.test, args.pdb, **td_datum)
        print("{} validated with test data".format(model.name))
    return True
Example #18
0
 def test_validate_all_models(self):
     for model in Registry("models").values():
         if model._test_data is not None:
             self.assertTrue(model.validate_from_preset_test(), msg="{} model failed".format(model.name))
         else:
             self.assertFalse(model.is_builtin, msg="{} is a built-in model and "
                                                    "contains no test data".format(model.name))
Example #19
0
    def as_dict(self):
        """
        Serializes object as a dictionary. Object can be reconstructed with from_dict().

        Returns:
            (dict): representation of object as a dictionary
        """
        symbol = self._symbol_type
        if symbol.name in Registry("symbols").keys() and symbol == Registry("symbols")[symbol.name] and \
                symbol.is_builtin:
            symbol = self._symbol_type.name
        else:
            symbol = symbol.as_dict()

        return {"symbol_type": symbol,
                "provenance": self.provenance.as_dict() if self.provenance else None,
                "tags": self.tags,
                "internal_id": self._internal_id}
Example #20
0
    def get_symbol_from_string(name):
        """
        Looks up Symbol from name in Registry("symbols") registry.

        Args:
            name: (str) the name of the Symbol object

        Returns: (Symbol) the Symbol object associated with the name

        """
        # Invoke default symbol if symbol is a string
        if not isinstance(name, str):
            raise TypeError("Expected str, encountered {}".format(type(name)))

        if name not in Registry("symbols").keys():
            raise ValueError("Symbol type {} not recognized".format(name))

        return Registry("symbols")[name]
Example #21
0
    def registered(self):
        """
        Indicates if a symbol is registered with the symbol registry.

        Returns:
            bool: True if the symbol is registered. False otherwise.

        """
        return self.name in Registry("symbols").keys()
Example #22
0
    def test_unit_handling(self):
        """
        Tests unit handling with a simple model that calculates the area of a rectangle as the
        product of two lengths.

        In this case the input lengths are provided in centimeters and meters.
        Tests whether the input units are properly coerced into canonical types.
        Tests whether the output units are properly set.
        Tests whether the model returns as predicted.
        Returns:
            None
        """
        L = Symbol('l', ['L'], ['L'],
                   units=[1.0, [['centimeter', 1.0]]],
                   shape=[1])
        A = Symbol('a', ['A'], ['A'],
                   units=[1.0, [['centimeter', 2.0]]],
                   shape=[1])

        for sym in (L, A):
            Registry("symbols")[sym] = sym
            Registry("units")[sym] = sym.units

        get_area_config = {
            'name': 'area',
            # 'connections': [{'inputs': ['l1', 'l2'], 'outputs': ['a']}],
            'equations': ['a = l1 * l2'],
            # 'unit_map': {'l1': "cm", "l2": "cm", 'a': "cm^2"}
            'variable_symbol_map': {
                "a": A,
                "l1": L,
                "l2": L
            }
        }
        model = EquationModel(**get_area_config)
        out = model.evaluate(
            {
                'l1': QuantityFactory.create_quantity(L, 1, 'meter'),
                'l2': QuantityFactory.create_quantity(L, 2)
            },
            allow_failure=False)

        self.assertTrue(math.isclose(out['a'].magnitude, 200.0))
        self.assertTrue(out['a'].units == A.units)
Example #23
0
    def process_item(self, item):
        quantities = []
        material = item.copy()

        containers = [c + '.quantities' for c in self.props
                      if pydash.get(material, c)] + ['inputs']

        for container in containers:
            for q in pydash.get(material, container) or []:
                this_q = q.copy()
                this_q['material_key'] = material['task_id']
                prov_inputs = pydash.get(this_q, 'provenance.inputs')
                if prov_inputs:
                    new_prov_inputs = [qq['internal_id'] for qq in prov_inputs]
                else:
                    new_prov_inputs = None
                pydash.set_(this_q, 'provenance.inputs', new_prov_inputs)
                quantities.append(this_q)

            pydash.set_(material, container,
                        [q['internal_id']
                         for q in pydash.get(material, container) or []])

            if container != 'inputs':
                prop = container.split(".")[0]
                units = Registry("units").get(prop)
                if units != pydash.get(material, [prop, 'units']):
                    pq_mean = ureg.Quantity(material[prop]['mean'],
                                            material[prop]['units']).to(units)
                    pq_std = ureg.Quantity(material[prop]['std'],
                                           material[prop]['units']).to(units)
                    material[prop]['mean'] = pq_mean.magnitude
                    material[prop]['std'] = pq_std.magnitude
                    material[prop]['units'] = pq_mean.units.format_babel()
            
        for q in quantities:
            units = Registry("units").get(q['symbol_type'])
            if q['units'] != units:
                pq = ureg.Quantity(q['value'], q['units']).to(units)
                q['value'] = pq.magnitude
                q['units'] = pq.units.format_babel()

        return quantities, material
Example #24
0
 def test_model_formatting(self):
     # TODO: clean up tests (self.assertNotNone), test reference format too
     for model in Registry("models").values():
         if not model.is_builtin:
             continue
         self.assertIsNotNone(model.name)
         msg = "{} has invalid property".format(model.name)
         self.assertIsNotNone(model.categories, msg=msg)
         self.assertIsNotNone(model.description, msg=msg)
         self.assertIsNotNone(model.variable_symbol_map, msg=msg)
         self.assertIsNotNone(model.implemented_by, msg=msg)
         self.assertNotEqual(model.implemented_by, [], msg=msg)
         self.assertTrue(isinstance(model.variable_symbol_map, dict), msg=msg)
         self.assertTrue(len(model.variable_symbol_map.keys()) > 0, msg=msg)
         for key in model.variable_symbol_map.keys():
             self.assertTrue(isinstance(key, str), 'Invalid variable_symbol_map key: ' + str(key))
             self.assertTrue(
                 isinstance(model.variable_symbol_map[key], str)
                 and model.variable_symbol_map[key] in Registry("symbols").keys(), msg=msg)
         self.assertTrue(
             model.connections is not None and isinstance(model.connections, list) and len(model.connections) > 0,
             msg=msg)
         for reference in model.references:
             self.assertTrue(reference.startswith('@'), msg=msg)
         for item in model.connections:
             self.assertIsNotNone(item, msg=msg)
             self.assertTrue(isinstance(item, dict), msg=msg)
             self.assertTrue('inputs' in item.keys(), msg=msg)
             self.assertTrue('outputs' in item.keys(), msg=msg)
             self.assertIsNotNone(item['inputs'], msg=msg)
             self.assertIsNotNone(item['outputs'], msg=msg)
             self.assertTrue(isinstance(item['inputs'], list), msg=msg)
             self.assertTrue(isinstance(item['outputs'], list), msg=msg)
             self.assertTrue(len(item['inputs']) > 0, msg=msg)
             self.assertTrue(len(item['outputs']) > 0, msg=msg)
             for in_symb in item['inputs']:
                 self.assertIsNotNone(in_symb, msg=msg)
                 self.assertTrue(isinstance(in_symb, str), msg=msg)
                 self.assertTrue(in_symb in model.variable_symbol_map.keys(), msg=msg)
             for out_symb in item['outputs']:
                 self.assertIsNotNone(out_symb, msg=msg)
                 self.assertIsNotNone(isinstance(out_symb, str), msg=msg)
                 self.assertTrue(out_symb in model.variable_symbol_map.keys(), msg=msg)
Example #25
0
def add_builtin_symbols_to_registry():
    for f in _DEFAULT_SYMBOL_TYPE_FILES:
        d = loadfn(f)
        d['is_builtin'] = True
        d['overwrite_registry'] = True
        symbol_type = Symbol.from_dict(d)
        if "{}.yaml".format(symbol_type.name) not in f:
            raise ValueError('Name/filename mismatch in {}'.format(f))

    # This is just to enable importing this module
    for name, symbol in Registry("symbols").items():
        if symbol.is_builtin:
            globals()[name] = symbol
Example #26
0
    def as_dict(self):
        """
        Gives the dictionary representation of this object, excluding value,
        units, and uncertainty.

        Returns: (dict) dictionary representation of this object for serialization

        """
        symbol = self._symbol_type
        if symbol.name in Registry("symbols").keys() and symbol == Registry("symbols")[symbol.name] and \
                symbol.is_builtin:
            symbol = self._symbol_type.name

        return {
            "@module": self.__class__.__module__,
            "@class": self.__class__.__name__,
            "data_type": self._data_type,
            "symbol_type": symbol,
            "internal_id": self._internal_id,
            "tags": self._tags,
            "provenance": self._provenance
        }
Example #27
0
def fit_model_scores(materials,
                     benchmarks,
                     models=None,
                     init_scores=None,
                     constrain_sum=False):
    """
    Fits a set of model scores to a set of benchmark data

    Args:
        materials ([Material]): list of evaluated materials containing
            symbols for benchmarking
        benchmarks ([{Symbol or str: float}]): list of dicts, keyed by Symbol
            or symbol name containing benchmark data for each material in ``materials``.
        models ([Model or str]): list of models which should have their
            scores adjusted in the aggregation weighting scheme
        init_scores ({str: float}): initial scores for minimization procedure.
            If unspecified, all scores are equal. Scores are normalized to sum of
            scores.
        constrain_sum (bool): True constrains the sum of weights to 1, False
            removes this constraint. Default: False (no constraint)

    Returns:
        {str: float} scores corresponding to those which minimize
            SSE for the benchmarked dataset

    """
    # Probably not smart to have ALL available models in the list. That's a lot of DOF.
    # TODO: Perhaps write a method to produce a list of models in the provenance trees
    #       of the symbols to be benchmarked. Should be easy with the caching we have for provenance.
    model_list = models or list(Registry("models").keys())

    def f(f_scores):
        model_score_dict = {m: s for m, s in zip(model_list, f_scores)}
        return get_sse(materials, benchmarks, model_score_dict)

    scores = OrderedDict((m, 1) for m in model_list)
    scores.update(init_scores or {})
    x0 = np.array(list(scores.values()))
    x0 = x0 / np.sum(x0)
    bounds = Bounds([0] * len(x0), [1] * len(x0))
    if constrain_sum:
        constraint = [LinearConstraint([1] * len(x0), [1], [1])]
    else:
        constraint = []
    result = minimize(f,
                      x0=x0,
                      method='trust-constr',
                      bounds=bounds,
                      constraints=constraint)
    vec = [s for s in result.x]
    return OrderedDict(zip(model_list, vec))
Example #28
0
    def add_default_quantities(self):
        """
        Adds any default symbols which are not present in the graph

        Returns:
            None
        """
        new_syms = set(Registry("symbol_values").keys())
        new_syms -= set(self._quantities_by_symbol.keys())
        for sym in new_syms:
            quantity = QuantityFactory.from_default(sym)
            logger.warning("Adding default {} quantity with value {}".format(
                sym, quantity))
            self.add_quantity(quantity)
Example #29
0
    def test_symbol_register_unregister(self):
        A = Symbol('a', ['A'], ['A'], units='dimensionless', shape=1)

        self.assertIn(A.name, Registry("symbols"))
        self.assertTrue(A.registered)
        A.unregister()
        self.assertNotIn(A.name, Registry("symbols"))
        self.assertFalse(A.registered)
        A.register()
        self.assertTrue(A.registered)
        with self.assertRaises(KeyError):
            A.register(overwrite_registry=False)

        A.unregister()
        A = Symbol('a', ['A'], ['A'],
                   units='dimensionless',
                   shape=1,
                   register=False)
        self.assertNotIn(A.name, Registry("symbols"))
        self.assertFalse(A.registered)

        A.register()
        with self.assertRaises(KeyError):
            _ = Symbol('a', ['A'], ['A'],
                       units='dimensionless',
                       shape=1,
                       register=True,
                       overwrite_registry=False)

        A_replacement = Symbol('a', ['A^*'], ['A^*'],
                               units='kilogram',
                               shape=1)

        A_registered = Registry("symbols")['a']
        self.assertIs(A_registered, A_replacement)
        self.assertIsNot(A_registered, A)
Example #30
0
    def from_default(symbol):
        """
        Method to invoke a default quantity from a symbol name

        Args:
            symbol (Symbol or str): symbol or string corresponding to
                the symbol name

        Returns:
            BaseQuantity corresponding to default quantity from default
        """
        val = Registry("symbol_values").get(symbol)
        if val is None:
            raise ValueError("No default value for {}".format(symbol))
        prov = ProvenanceElement(model='default')
        return QuantityFactory.create_quantity(symbol, val, provenance=prov)