Source code for pybamm.dispatch.entry_points
import importlib.metadata
import textwrap
from collections.abc import Callable, Mapping
[docs]
class EntryPoint(Mapping):
"""
A mapping interface for accessing PyBaMM models and parameter sets through entry points.
This class provides a unified way to load, and instantiate PyBaMM models
and parameter sets that have been registered as entry points.
Access via :py:data:`pybamm.parameter_sets` for parameter sets - provides access
to all registered battery parameter sets (e.g., 'Chen2020', 'Ai2020') that can
be used to parameterise battery models.
Access via :py:data:`pybamm.Model` for models - provides access to all registered
battery models (e.g., 'SPM', 'DFN').
.. attention::
This feature is currently experimental.
Examples
--------
Listing available parameter sets:
>>> import pybamm
>>> list(pybamm.parameter_sets) # doctest: +ELLIPSIS
['Ai2020', 'Chayambuka2022', ...]
Listing available models:
>>> import pybamm
>>> list(pybamm.dispatch.models) # doctest: +ELLIPSIS
['DFN', 'MPM', ...]
Get the docstring for a parameter set or model:
>>> print(pybamm.parameter_sets.get_docstring("Ai2020")) # doctest: +ELLIPSIS
<BLANKLINE>
Parameters for the Enertech cell (Ai2020), from the papers :footcite:t:`Ai2019`...
>>> print(pybamm.dispatch.models.get_docstring("SPM")) # doctest: +ELLIPSIS
<BLANKLINE>
Single Particle Model (SPM) of a lithium-ion battery...
"""
_instances = 0
def __init__(self, group):
"""Dict of entry points for parameter sets or models to lazily load as entry points"""
if not hasattr(
self, "initialized"
): # Ensure __init__ is called once per instance
self.initialized = True
EntryPoint._instances += 1
self._all_entries = dict()
self.group = group
for entry_point in self.get_entries(self.group):
self._all_entries[entry_point.name] = entry_point
[docs]
@staticmethod
def get_entries(group_name):
"""Wrapper for the importlib version logic"""
return importlib.metadata.entry_points(group=group_name)
def __new__(cls, group):
"""Ensure only two instances of entry points exist, one for parameter sets and the other for models"""
if EntryPoint._instances < 2:
cls.instance = super().__new__(cls)
return cls.instance
def _get_class(self, key) -> Callable:
"""Return the class without instantiating it"""
return self._load_entry_point(key)
def __getitem__(self, key) -> dict:
return self._load_entry_point(key)()
def _load_entry_point(self, key) -> Callable:
"""Check that ``key`` is a registered ``parameter_sets`` or ``models` ,
and return the entry point for the parameter set/model, loading it needed."""
if key not in self._all_entries:
raise KeyError(f"Unknown parameter set or model: {key}")
entry_point = self._all_entries[key]
try:
entry_point = self._all_entries[key] = entry_point.load()
except AttributeError:
# Parameter sets cannot be loaded so returning the default entry_point
pass
return entry_point
def __iter__(self):
return self._all_entries.__iter__()
def __len__(self) -> int:
return len(self._all_entries)
[docs]
def get_docstring(self, key):
"""Return the docstring for the ``key`` parameter set or model"""
return textwrap.dedent(self._load_entry_point(key).__doc__)
def __getattribute__(self, name):
return super().__getattribute__(name)
#: Singleton Instance of :class:EntryPoint initialised with pybamm_parameter_sets"""
parameter_sets = EntryPoint(group="pybamm_parameter_sets")
#: Singleton Instance of :class:EntryPoint initialised with pybamm_models"""
models = EntryPoint(group="pybamm_models")
def Model(model: str, *args, **kwargs):
"""
Returns the loaded model object
Note: This feature is in its experimental phase.
Parameters
----------
model : str
The model name or author name of the model mentioned at the model entry point.
*args
Additional positional arguments to pass to the model constructor.
**kwargs
Additional keyword arguments to pass to the model constructor.
Returns
-------
pybamm.model
Model object of the initialised model.
Examples
--------
Listing available models:
>>> import pybamm
>>> list(pybamm.dispatch.models) # doctest: +ELLIPSIS
['DFN', 'MPM', ...]
>>> pybamm.Model('SPM') # doctest: +SKIP
<pybamm.models.full_battery_models.lithium_ion.spm.SPM object>
"""
model_class = models._get_class(model)
return model_class(*args, **kwargs)