From 4fab0e0880d9c344337637ad7f62c12e4311577a Mon Sep 17 00:00:00 2001 From: Logan Ward Date: Wed, 8 May 2024 10:12:21 -0400 Subject: [PATCH 1/9] Prototype for mapping schema terms to ontology --- batdata/schemas/__init__.py | 2 ++ batdata/schemas/ontology.py | 55 ++++++++++++++++++++++++++++++++++ pyproject.toml | 1 + tests/schemas/test_ontology.py | 12 ++++++++ 4 files changed, 70 insertions(+) create mode 100644 batdata/schemas/ontology.py create mode 100644 tests/schemas/test_ontology.py diff --git a/batdata/schemas/__init__.py b/batdata/schemas/__init__.py index eb34ccd..0b0a930 100644 --- a/batdata/schemas/__init__.py +++ b/batdata/schemas/__init__.py @@ -21,6 +21,8 @@ class BatteryMetadata(BaseModel, extra=Extra.allow): " as it is intended to be used by the battery data provider.") comments: Optional[str] = Field(None, description="Long form comments describing the test") version: str = Field(__version__, description="Version of this metadata") + is_measurement: bool = Field(True, description="Whether the data was created observationally as opposed to a computer simulation", + iri="https://w3id.org/emmo#EMMO_463bcfda_867b_41d9_a967_211d4d437cfb") # Fields that describe the test protocol cycler: Optional[str] = Field(None, description='Name of the cycling machine') diff --git a/batdata/schemas/ontology.py b/batdata/schemas/ontology.py new file mode 100644 index 0000000..ad60bfe --- /dev/null +++ b/batdata/schemas/ontology.py @@ -0,0 +1,55 @@ +"""Tools used for linking terms in our data format to the BattINFO ontology""" +from dataclasses import dataclass, field +from functools import cache +from typing import Type + +from ontopy import World +from pydantic import BaseModel + +_battinfo_url = 'https://raw.githubusercontent.com/emmo-repo/domain-battery/master/battery-inferred.ttl' + + +@cache +def load_battinfo(): + return World().get_ontology(_battinfo_url).load() + + +@dataclass +class TermInfo: + """Information about a term as referenced from the BattINFO ontology""" + + name: str + """Name of the matching term""" + iri: str = field(repr=False) + """IRI of the term""" + elucidation: str = field(repr=False) + """Explanation of the term""" + + +def cross_reference_terms(model: Type[BaseModel]) -> dict[str, TermInfo]: + """Gather the descriptions of fields from our schema which + are cross-referenced to a term within the BattINFO/EMMO ontologies + + Args: + model: Schema object to be cross-referenced + Returns: + Mapping between metadata fields in elucidation field from the ontology + """ + + # Load the BattINFO ontology + battinfo = load_battinfo() + + # Loop over each field in the schema + terms = {} + for name, attr in model.model_fields.items(): + # Map to the term in the ontology if known + if attr.json_schema_extra is not None and (iri := attr.json_schema_extra.get('iri')) is not None: + term = battinfo.search_one(iri=iri) + if term is None: + raise ValueError(f'Count not find matching term for {name} with iri={iri}') + + anno = term.get_annotations() + if (eluc := anno.get('elucidation')) is not None: + terms[name] = TermInfo(name=str(term), iri=iri, elucidation=eluc) + + return terms diff --git a/pyproject.toml b/pyproject.toml index 4fd9bf2..e711989 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ dependencies = [ "h5py == 3.*", "scythe-extractors >= 0.1", "pyarrow >= 15", + "ontopy", "xlrd" ] diff --git a/tests/schemas/test_ontology.py b/tests/schemas/test_ontology.py new file mode 100644 index 0000000..5b0c190 --- /dev/null +++ b/tests/schemas/test_ontology.py @@ -0,0 +1,12 @@ +"""Test the ability to resolve cross-references from the ontology""" + +from batdata.schemas import BatteryMetadata +from batdata.schemas.ontology import cross_reference_terms + + +def test_crossref(): + terms = cross_reference_terms(BatteryMetadata) + assert 'is_measurement' in terms + assert terms['is_measurement'].name == 'emmo.Measurement' + assert 'EMMO' in terms['is_measurement'].iri + assert 'well defined mesurement procedure.' in terms['is_measurement'].iri From a07b0b2aa2fdd94340fb45073deacab7c92b3a41 Mon Sep 17 00:00:00 2001 From: Logan Ward Date: Wed, 8 May 2024 10:24:56 -0400 Subject: [PATCH 2/9] Install the EMMO python package --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e711989..42e7656 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ dependencies = [ "h5py == 3.*", "scythe-extractors >= 0.1", "pyarrow >= 15", - "ontopy", + "EMMOntoPy", "xlrd" ] From 244a74cd81806d4f3c3c379b0e185faf1f0a627d Mon Sep 17 00:00:00 2001 From: Logan Ward Date: Wed, 8 May 2024 11:11:23 -0400 Subject: [PATCH 3/9] Fix ontology test --- batdata/schemas/ontology.py | 2 +- tests/schemas/test_ontology.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/batdata/schemas/ontology.py b/batdata/schemas/ontology.py index ad60bfe..722b831 100644 --- a/batdata/schemas/ontology.py +++ b/batdata/schemas/ontology.py @@ -50,6 +50,6 @@ def cross_reference_terms(model: Type[BaseModel]) -> dict[str, TermInfo]: anno = term.get_annotations() if (eluc := anno.get('elucidation')) is not None: - terms[name] = TermInfo(name=str(term), iri=iri, elucidation=eluc) + terms[name] = TermInfo(name=str(term), iri=iri, elucidation=str(eluc[0])) return terms diff --git a/tests/schemas/test_ontology.py b/tests/schemas/test_ontology.py index 5b0c190..0a14278 100644 --- a/tests/schemas/test_ontology.py +++ b/tests/schemas/test_ontology.py @@ -9,4 +9,4 @@ def test_crossref(): assert 'is_measurement' in terms assert terms['is_measurement'].name == 'emmo.Measurement' assert 'EMMO' in terms['is_measurement'].iri - assert 'well defined mesurement procedure.' in terms['is_measurement'].iri + assert 'well defined mesurement procedure.' in terms['is_measurement'].elucidation From 9d0e853b5dfc13567412b56f00405bc92185fa85 Mon Sep 17 00:00:00 2001 From: Logan Ward Date: Wed, 8 May 2024 12:48:53 -0400 Subject: [PATCH 4/9] Add ability to look up descendants of terms --- batdata/schemas/ontology.py | 32 ++++++++++++++++++++++++++------ tests/schemas/test_ontology.py | 8 +++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/batdata/schemas/ontology.py b/batdata/schemas/ontology.py index 722b831..8b8a288 100644 --- a/batdata/schemas/ontology.py +++ b/batdata/schemas/ontology.py @@ -1,9 +1,10 @@ """Tools used for linking terms in our data format to the BattINFO ontology""" from dataclasses import dataclass, field from functools import cache -from typing import Type +from typing import Type, List, Optional from ontopy import World +from owlready2 import Thing from pydantic import BaseModel _battinfo_url = 'https://raw.githubusercontent.com/emmo-repo/domain-battery/master/battery-inferred.ttl' @@ -22,9 +23,17 @@ class TermInfo: """Name of the matching term""" iri: str = field(repr=False) """IRI of the term""" - elucidation: str = field(repr=False) + elucidation: Optional[str] = field(repr=False) """Explanation of the term""" + @classmethod + def from_thing(cls, thing: Thing): + # Retrieve the description, as provided by EMMO + eluc = thing.get_annotations().get('elucidation') + if eluc is not None: + eluc = str(eluc) + return TermInfo(name=str(thing), iri=thing.iri, elucidation=eluc) + def cross_reference_terms(model: Type[BaseModel]) -> dict[str, TermInfo]: """Gather the descriptions of fields from our schema which @@ -47,9 +56,20 @@ def cross_reference_terms(model: Type[BaseModel]) -> dict[str, TermInfo]: term = battinfo.search_one(iri=iri) if term is None: raise ValueError(f'Count not find matching term for {name} with iri={iri}') - - anno = term.get_annotations() - if (eluc := anno.get('elucidation')) is not None: - terms[name] = TermInfo(name=str(term), iri=iri, elucidation=str(eluc[0])) + terms[name] = TermInfo.from_thing(term) return terms + + +def gather_descendants(term: Type[Thing]) -> List[TermInfo]: + """Get descriptions of the descendants of a certain base type + + Args: + term: Term for which to gather all descendants + Returns: + List of descriptions of the descendants + """ + + return [ + TermInfo.from_thing(d) for d in term.descendants(include_self=False) + ] diff --git a/tests/schemas/test_ontology.py b/tests/schemas/test_ontology.py index 0a14278..f64ff3c 100644 --- a/tests/schemas/test_ontology.py +++ b/tests/schemas/test_ontology.py @@ -1,7 +1,7 @@ """Test the ability to resolve cross-references from the ontology""" from batdata.schemas import BatteryMetadata -from batdata.schemas.ontology import cross_reference_terms +from batdata.schemas.ontology import cross_reference_terms, gather_descendants, load_battinfo def test_crossref(): @@ -10,3 +10,9 @@ def test_crossref(): assert terms['is_measurement'].name == 'emmo.Measurement' assert 'EMMO' in terms['is_measurement'].iri assert 'well defined mesurement procedure.' in terms['is_measurement'].elucidation + + +def test_descendants(): + bi = load_battinfo() + desc = [t.name for t in gather_descendants(bi.PhysicsBasedSimulation)] + assert 'emmo.StandaloneModelSimulation' in desc From 81e559663a9a221b1f661e35eb229239607a00c5 Mon Sep 17 00:00:00 2001 From: Logan Ward Date: Wed, 8 May 2024 13:28:00 -0400 Subject: [PATCH 5/9] Add metadata fields for simulation --- batdata/schemas/__init__.py | 6 ++- batdata/schemas/modeling.py | 44 +++++++++++++++++ batdata/schemas/ontology.py | 33 +++++++++++-- docs/schemas.md | 87 ++++++++++++++++++++++++++++++++++ tests/schemas/test_ontology.py | 10 +++- 5 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 batdata/schemas/modeling.py create mode 100644 docs/schemas.md diff --git a/batdata/schemas/__init__.py b/batdata/schemas/__init__.py index 0b0a930..6ffbac5 100644 --- a/batdata/schemas/__init__.py +++ b/batdata/schemas/__init__.py @@ -4,6 +4,7 @@ from pydantic import BaseModel, Field, AnyUrl, Extra +from batdata.schemas.modeling import ModelMetadata from batdata.schemas.battery import BatteryDescription from batdata.version import __version__ @@ -20,7 +21,7 @@ class BatteryMetadata(BaseModel, extra=Extra.allow): name: Optional[str] = Field(None, description="Name of the cell. Any format for the name is acceptable," " as it is intended to be used by the battery data provider.") comments: Optional[str] = Field(None, description="Long form comments describing the test") - version: str = Field(__version__, description="Version of this metadata") + version: str = Field(__version__, description="Version of this metadata. Set by the battery-data-toolkit") is_measurement: bool = Field(True, description="Whether the data was created observationally as opposed to a computer simulation", iri="https://w3id.org/emmo#EMMO_463bcfda_867b_41d9_a967_211d4d437cfb") @@ -33,6 +34,9 @@ class BatteryMetadata(BaseModel, extra=Extra.allow): # Field that describe the battery assembly battery: Optional[BatteryDescription] = Field(None, description="Description of the battery being tested") + # Fields that describe source of synthetic data + modeling: ModelMetadata = Field(None, description="Description of simulation approach") + # Fields that describe the source of data source: Optional[str] = Field(None, description="Organization who created this data") dataset_name: Optional[str] = Field(None, description="Name of a larger dataset this data is associated with") diff --git a/batdata/schemas/modeling.py b/batdata/schemas/modeling.py new file mode 100644 index 0000000..3392b6a --- /dev/null +++ b/batdata/schemas/modeling.py @@ -0,0 +1,44 @@ +"""Metadata which describes how data produced by models were generated""" +from typing import Optional, List +from enum import Enum + +from pydantic import BaseModel, Field, AnyUrl + + +class ModelTypes(str, Enum): + """Type of computational method""" + + physics = 'physics' + """A computational application that uses a physical model to predict the behaviour of a system, + providing a identifiable analogy with the original object. + + IRI: https://w3id.org/emmo#EMMO_8d4962d7_9608_44f7_a2f1_82a4bb173f4a""" + data: 'data' + """A computational application that uses existing data to predict the behaviour of a system + without providing a identifiable analogy with the original object. + + IRI: https://w3id.org/emmo#EMMO_a4b14b83_9392_4a5f_a2e8_b2b58793f59b""" + + empirical: 'empirical' + """A computational application that uses an empiric equation to predict the behaviour of a system + without relying on the knowledge of the actual physical phenomena occurring in the object. + + IRI: https://w3id.org/emmo#EMMO_67c70dcd_2adf_4e6c_b3f8_f33dd1512487""" + + +class ModelMetadata(BaseModel): + """Describe the type and version of a computational tool used to generate battery data""" + + # High-level information about the code + name: str = Field(..., description='Name of the software') + version: Optional[str] = Field(..., description='Version of the software if known') + type: Optional[ModelTypes] = Field(None, description='Type of the computational method it implements.') + reference: Optional[List[AnyUrl]] = Field(None, description='List of references associated with the software') + + # Details for physics based simulation + model_type: Optional[List[str]] = Field(None, description='Type of mathematical model(s) being used in physics simulation.' + 'Use terms defined in BattINFO, such as "BatteryEquivalentCircuitModel".', + root_iri='https://w3id.org/emmo#EMMO_f7ed665b_c2e1_42bc_889b_6b42ed3a36f0') + simulation_type: Optional[str] = Field(None, description='Type of simulation being performed. ' + 'Use terms defined in BattINFO, such as "TightlyCoupledModelsSimulation"', + root_iri='https://w3id.org/emmo#EMMO_e97af6ec_4371_4bbc_8936_34b76e33302f') diff --git a/batdata/schemas/ontology.py b/batdata/schemas/ontology.py index 8b8a288..c87a1f0 100644 --- a/batdata/schemas/ontology.py +++ b/batdata/schemas/ontology.py @@ -1,7 +1,7 @@ """Tools used for linking terms in our data format to the BattINFO ontology""" from dataclasses import dataclass, field from functools import cache -from typing import Type, List, Optional +from typing import Type, List, Optional, Union from ontopy import World from owlready2 import Thing @@ -61,15 +61,42 @@ def cross_reference_terms(model: Type[BaseModel]) -> dict[str, TermInfo]: return terms -def gather_descendants(term: Type[Thing]) -> List[TermInfo]: +def resolve_term(name_or_iri: str) -> Thing: + """Resolve the Term object associated with a string + + Args: + name_or_iri: The preferred label or the IRI of a term in the ontology + Returns: + Thing matching the term + """ + + # Attempt to find it + bi = load_battinfo() + if name_or_iri.startswith('https://'): + term = bi.search_one(iri=name_or_iri) + t = 'IRI' + else: + term = bi.search_one(prefLabel=name_or_iri) + t = 'name' + + if term is None: + raise ValueError(f'Could not find the {t}={name_or_iri}') + return term + + +def gather_descendants(term: Union[Type[Thing], str]) -> List[TermInfo]: """Get descriptions of the descendants of a certain base type Args: - term: Term for which to gather all descendants + term: Term for which to gather all descendants. Either the class object itself or its preferred label or IRI Returns: List of descriptions of the descendants """ + # Resolve the term object, if needed + if isinstance(term, str): + term = resolve_term(term) + return [ TermInfo.from_thing(d) for d in term.descendants(include_self=False) ] diff --git a/docs/schemas.md b/docs/schemas.md new file mode 100644 index 0000000..3896e53 --- /dev/null +++ b/docs/schemas.md @@ -0,0 +1,87 @@ +# Battery Data Schemas + +The metadata schemas used by `batdata` standardize how we describe the source of battery datasets. +Metadata are held as part of the `BatteryDataset` object and saved within the file formats +produced by `batdata` to ensure that the provenance of a dataset is kept alongside the actual data. + + +## Understanding the Metadata + +The metadata we employ in `batdata` follows the style of the JSON or XML data structures which are ubiquitous +in scientific computation and data infrastructure. + +We recommend creating the metadata for a battery through the Python interface. +Start by creating a `BatteryMetadata` object. There are no required fields, but you should always give your data a name. + +```python +from batdata.schemas import BatteryMetadata + +metadata = BatteryMetadata( + name='test-cell', +) +``` + +The metadata is a nested document where different types of information are grouped together into sub objects. +For example, the details about the battery being tested are in `BatteryDescription` + +```python +from batdata.schemas.battery import BatteryDescription +from batdata.schemas import BatteryMetadata + +metadata = BatteryMetadata( + name='test-cell', + battery=BatteryDescription( + manufacturer='famous', + nominal_capacity=1., + ) +) +``` + +See the [schemas module](https://github.com/ROVI-org/battery-data-toolkit/tree/main/batdata/schemas) +for a full accounting of the available fields in our schema. + +> TODO: Render the schemas into an easier-to-read format + +Feel free to add your own fields to any part fo the schema. +The schema is a continual work in progress and the battery-data-toolkit will +store your new fields. +Consider adding [an Issue](https://github.com/ROVI-org/battery-data-toolkit/issues) to our GitHub +if you find you use a term enough that we should add it to the schema. + +### Source of Terminology + +We use terms from [BattINFO ontology](https://big-map.github.io/BattINFO/index.html) wherever possible. + +Fields in the schema whose names correspond to a BattINFO term are marked +with the "IRI" of the field, which points to a website containing the description. + +Fields whose values should be terms from the BattINFO ontology are marked with the root of the terms. +For example, the `model_type` field of `ModelMetadata` can be any type of +[MathematicalModel](https://emmo-repo.github.io/emmo.html#EMMO_f7ed665b_c2e1_42bc_889b_6b42ed3a36f0). +Look them up using some utilities in `batdata`. + +```python +from batdata.schemas.ontology import gather_descendants + +print(gather_descendants('MathematicalModel')) +``` + +> TODO: Render the options in web-hosted documentation as well + +## Column Datasets + +The columns of datasets are described in the [cycling module](https://github.com/ROVI-org/battery-data-toolkit/blob/main/batdata/schemas/cycling.py). + +Use the descriptions here when formatting your dataset, playing attention to the sign conventions and units for each column. + +Record columns that are not defined in our schema in the `*_columns` fields +of the `BatteryMetadata`. + +```python +from batdata.schemas import BatteryMetadata + +metadata = BatteryMetadata( + name='test_cell', + raw_data_columns={'new_signal': 'A column not yet defined in our schemas.'} +) +``` diff --git a/tests/schemas/test_ontology.py b/tests/schemas/test_ontology.py index f64ff3c..35aeaae 100644 --- a/tests/schemas/test_ontology.py +++ b/tests/schemas/test_ontology.py @@ -1,7 +1,7 @@ """Test the ability to resolve cross-references from the ontology""" from batdata.schemas import BatteryMetadata -from batdata.schemas.ontology import cross_reference_terms, gather_descendants, load_battinfo +from batdata.schemas.ontology import cross_reference_terms, gather_descendants, load_battinfo, resolve_term def test_crossref(): @@ -12,7 +12,15 @@ def test_crossref(): assert 'well defined mesurement procedure.' in terms['is_measurement'].elucidation +def test_resolve(): + assert resolve_term('PhysicsBasedSimulation') is not None + assert resolve_term('https://w3id.org/emmo#EMMO_f7ed665b_c2e1_42bc_889b_6b42ed3a36f0') is not None + + def test_descendants(): bi = load_battinfo() desc = [t.name for t in gather_descendants(bi.PhysicsBasedSimulation)] assert 'emmo.StandaloneModelSimulation' in desc + + desc = [t.name for t in gather_descendants('PhysicsBasedSimulation')] + assert 'emmo.StandaloneModelSimulation' in desc From 4bd93a34bab067cb97bbf04c3e23ce957c1850c7 Mon Sep 17 00:00:00 2001 From: Logan Ward Date: Wed, 8 May 2024 13:34:44 -0400 Subject: [PATCH 6/9] Make the modeling metadata optional --- batdata/schemas/__init__.py | 6 +++--- batdata/schemas/battery.py | 10 +++++----- batdata/schemas/modeling.py | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/batdata/schemas/__init__.py b/batdata/schemas/__init__.py index 6ffbac5..cc3288d 100644 --- a/batdata/schemas/__init__.py +++ b/batdata/schemas/__init__.py @@ -2,14 +2,14 @@ from datetime import date from typing import List, Tuple, Optional, Dict -from pydantic import BaseModel, Field, AnyUrl, Extra +from pydantic import BaseModel, Field, AnyUrl from batdata.schemas.modeling import ModelMetadata from batdata.schemas.battery import BatteryDescription from batdata.version import __version__ -class BatteryMetadata(BaseModel, extra=Extra.allow): +class BatteryMetadata(BaseModel, extra='allow'): """Representation for the metadata about a battery The metadata captures the information about what experiment was run @@ -35,7 +35,7 @@ class BatteryMetadata(BaseModel, extra=Extra.allow): battery: Optional[BatteryDescription] = Field(None, description="Description of the battery being tested") # Fields that describe source of synthetic data - modeling: ModelMetadata = Field(None, description="Description of simulation approach") + modeling: Optional[ModelMetadata] = Field(None, description="Description of simulation approach") # Fields that describe the source of data source: Optional[str] = Field(None, description="Organization who created this data") diff --git a/batdata/schemas/battery.py b/batdata/schemas/battery.py index 399b3a7..68e31fa 100644 --- a/batdata/schemas/battery.py +++ b/batdata/schemas/battery.py @@ -1,10 +1,10 @@ """Schemas associated with the components of a battery""" from typing import Optional, List -from pydantic import BaseModel, Field, Extra +from pydantic import BaseModel, Field -class ElectrodeDescription(BaseModel, extra=Extra.allow): +class ElectrodeDescription(BaseModel, extra='allow'): """Description of an electrode""" name: str = Field(..., description='Short description of the electrolyte type') @@ -20,7 +20,7 @@ class ElectrodeDescription(BaseModel, extra=Extra.allow): porosity: Optional[float] = Field(None, description='Relative volume of the electrode occupied by gas (units: %)', ge=0, le=100) -class ElectrolyteAdditive(BaseModel, extra=Extra.allow): +class ElectrolyteAdditive(BaseModel, extra='allow'): """Additive to the electrolyte""" name: str = Field(..., description='Name of the additive') @@ -28,14 +28,14 @@ class ElectrolyteAdditive(BaseModel, extra=Extra.allow): units: Optional[float] = Field(None, description='Units of the amount') -class ElectrolyteDescription(BaseModel, extra=Extra.allow): +class ElectrolyteDescription(BaseModel, extra='allow'): """Description of the electrolyte""" name: str = Field(..., description='Short description of the electrolyte types') additives: List[ElectrolyteAdditive] = Field(default_factory=list, help='Any additives present in the electrolyte') -class BatteryDescription(BaseModel, extra=Extra.allow): +class BatteryDescription(BaseModel, extra='allow'): """Description of the entire battery""" # Overall design information diff --git a/batdata/schemas/modeling.py b/batdata/schemas/modeling.py index 3392b6a..144513d 100644 --- a/batdata/schemas/modeling.py +++ b/batdata/schemas/modeling.py @@ -26,7 +26,7 @@ class ModelTypes(str, Enum): IRI: https://w3id.org/emmo#EMMO_67c70dcd_2adf_4e6c_b3f8_f33dd1512487""" -class ModelMetadata(BaseModel): +class ModelMetadata(BaseModel, extra='allow'): """Describe the type and version of a computational tool used to generate battery data""" # High-level information about the code From 19257bd84d6522dc8f424b3f33b447471090c805 Mon Sep 17 00:00:00 2001 From: Logan Ward Date: Wed, 8 May 2024 14:04:37 -0400 Subject: [PATCH 7/9] Rename fields to respect plurals, avoid reserved words --- batdata/schemas/battery.py | 3 ++- batdata/schemas/modeling.py | 8 ++++---- batdata/schemas/ontology.py | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/batdata/schemas/battery.py b/batdata/schemas/battery.py index 68e31fa..fe3bbee 100644 --- a/batdata/schemas/battery.py +++ b/batdata/schemas/battery.py @@ -51,4 +51,5 @@ class BatteryDescription(BaseModel, extra='allow'): electrolyte: ElectrolyteDescription = Field(None, description="Name of the electrolyte material") # Performance information - nominal_capacity: float = Field(None, description="Rated capacity of the battery. Units: A-hr") + nominal_capacity: float = Field(None, description="Rated capacity of the battery. Units: A-hr", + iri="https://w3id.org/emmo/domain/electrochemistry#electrochemistry_9b3b4668_0795_4a35_9965_2af383497a26") diff --git a/batdata/schemas/modeling.py b/batdata/schemas/modeling.py index 144513d..9c68d42 100644 --- a/batdata/schemas/modeling.py +++ b/batdata/schemas/modeling.py @@ -33,12 +33,12 @@ class ModelMetadata(BaseModel, extra='allow'): name: str = Field(..., description='Name of the software') version: Optional[str] = Field(..., description='Version of the software if known') type: Optional[ModelTypes] = Field(None, description='Type of the computational method it implements.') - reference: Optional[List[AnyUrl]] = Field(None, description='List of references associated with the software') + references: Optional[List[AnyUrl]] = Field(None, description='List of references associated with the software') # Details for physics based simulation - model_type: Optional[List[str]] = Field(None, description='Type of mathematical model(s) being used in physics simulation.' - 'Use terms defined in BattINFO, such as "BatteryEquivalentCircuitModel".', - root_iri='https://w3id.org/emmo#EMMO_f7ed665b_c2e1_42bc_889b_6b42ed3a36f0') + models: Optional[List[str]] = Field(None, description='Type of mathematical model(s) being used in physics simulation.' + 'Use terms defined in BattINFO, such as "BatteryEquivalentCircuitModel".', + root_iri='https://w3id.org/emmo#EMMO_f7ed665b_c2e1_42bc_889b_6b42ed3a36f0') simulation_type: Optional[str] = Field(None, description='Type of simulation being performed. ' 'Use terms defined in BattINFO, such as "TightlyCoupledModelsSimulation"', root_iri='https://w3id.org/emmo#EMMO_e97af6ec_4371_4bbc_8936_34b76e33302f') diff --git a/batdata/schemas/ontology.py b/batdata/schemas/ontology.py index c87a1f0..fa097b1 100644 --- a/batdata/schemas/ontology.py +++ b/batdata/schemas/ontology.py @@ -31,7 +31,7 @@ def from_thing(cls, thing: Thing): # Retrieve the description, as provided by EMMO eluc = thing.get_annotations().get('elucidation') if eluc is not None: - eluc = str(eluc) + eluc = str(eluc[0]) return TermInfo(name=str(thing), iri=thing.iri, elucidation=eluc) From 956c805fd06add6e06d69af385fa21d01e23d4dc Mon Sep 17 00:00:00 2001 From: Logan Ward Date: Wed, 8 May 2024 14:13:47 -0400 Subject: [PATCH 8/9] Fix typo in defining the enum --- batdata/schemas/modeling.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/batdata/schemas/modeling.py b/batdata/schemas/modeling.py index 9c68d42..c10da28 100644 --- a/batdata/schemas/modeling.py +++ b/batdata/schemas/modeling.py @@ -13,13 +13,13 @@ class ModelTypes(str, Enum): providing a identifiable analogy with the original object. IRI: https://w3id.org/emmo#EMMO_8d4962d7_9608_44f7_a2f1_82a4bb173f4a""" - data: 'data' + data = 'data' """A computational application that uses existing data to predict the behaviour of a system without providing a identifiable analogy with the original object. IRI: https://w3id.org/emmo#EMMO_a4b14b83_9392_4a5f_a2e8_b2b58793f59b""" - empirical: 'empirical' + empirical = 'empirical' """A computational application that uses an empiric equation to predict the behaviour of a system without relying on the knowledge of the actual physical phenomena occurring in the object. From b22a341d9bf2063912a7308a9caf746b564ba039 Mon Sep 17 00:00:00 2001 From: Logan Ward Date: Wed, 8 May 2024 14:40:29 -0400 Subject: [PATCH 9/9] Make the electrolyte description optional --- batdata/schemas/battery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/batdata/schemas/battery.py b/batdata/schemas/battery.py index fe3bbee..febc090 100644 --- a/batdata/schemas/battery.py +++ b/batdata/schemas/battery.py @@ -48,7 +48,7 @@ class BatteryDescription(BaseModel, extra='allow'): # Materials description anode: Optional[ElectrodeDescription] = Field(None, description="Name of the anode material") cathode: Optional[ElectrodeDescription] = Field(None, description="Name of the cathode material") - electrolyte: ElectrolyteDescription = Field(None, description="Name of the electrolyte material") + electrolyte: Optional[ElectrolyteDescription] = Field(None, description="Name of the electrolyte material") # Performance information nominal_capacity: float = Field(None, description="Rated capacity of the battery. Units: A-hr",