-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(PR #37) Updating the schemas and cycling workchain
The battery schema has been updated to account for most, if not all robot output fields. This was primarily motivated by the need for electrode weights during visualization (capacity normalization), then expanded to account for all fields in case needed in the future (and also, for good measure). The cycling workchain was adjusted accordingly. Unrelated to the schemas but also included here, the new group label field was added to the workchain to support auto-generating experiment groups on submission.
- Loading branch information
Showing
8 changed files
with
134 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,107 +1,101 @@ | ||
from datetime import datetime | ||
from enum import Flag | ||
from typing import Literal, Optional | ||
from typing import Literal, Optional, Set | ||
|
||
from pydantic import BaseModel, NonNegativeFloat, PositiveFloat, root_validator | ||
from pydantic import BaseModel, NonNegativeFloat, PositiveInt | ||
|
||
from .utils import extract_schema_types | ||
|
||
|
||
class BatteryComposition(BaseModel): # TypedDict? | ||
description: Optional[str] = None | ||
cathode: Optional[str] = None | ||
anode: Optional[str] = None | ||
electrolyte: Optional[str] = None | ||
|
||
class Config: | ||
# exclude fields from export, to avoid validation errors when reloaded | ||
fields = { | ||
'cathode': { | ||
'exclude': True | ||
}, | ||
'anode': { | ||
'exclude': True | ||
}, | ||
'electrolyte': { | ||
'exclude': True | ||
}, | ||
} | ||
|
||
@root_validator | ||
def validate_composition(cls, values): | ||
""" | ||
Check that components are not specified if 'description' is specified | ||
then build components from a 'description' string, or vice versa. | ||
# TODO: what to do if 'description' is not in the C|E|A format? | ||
""" | ||
if values['description']: | ||
if any(values[key] for key in ('cathode', 'anode', 'electrolyte')): | ||
raise ValueError("You cannot specify a 'description' and any component at the same time.") | ||
values['description'] = values['description'].strip() | ||
components = list(map(str.strip, values['description'].split('|'))) | ||
if len(components) == 3: | ||
values['cathode'], values['electrolyte'], values['anode'] = components | ||
else: | ||
values['cathode'], values['electrolyte'], values['anode'] = (None, None, None) | ||
# raise ValueError( | ||
# "Composition 'description' does not have 3 components (i.e. {cathode}|{electrolyte}|{anode}).") | ||
elif any(values[key] for key in ('cathode', 'anode', 'electrolyte')): | ||
for key in ('cathode', 'anode', 'electrolyte'): | ||
values[key] = values[key].strip() | ||
values['description'] = f"{values['cathode']}|{values['electrolyte']}|{values['anode']}" | ||
else: | ||
raise ValueError("You must specify either a string 'description' or the components.") | ||
return values | ||
|
||
|
||
class BatteryCapacity(BaseModel): # TypedDict? | ||
nominal: PositiveFloat | ||
class Component(BaseModel): | ||
description: Optional[str] | ||
|
||
|
||
class Diameter(BaseModel): | ||
nominal: NonNegativeFloat | ||
actual: Optional[NonNegativeFloat] | ||
units: Literal["mAh", "Ah"] | ||
units: Literal["mm"] = "mm" | ||
|
||
|
||
class BatteryMetadata(BaseModel): | ||
name: str | ||
creation_datetime: datetime | ||
creation_process: str | ||
class Capacity(BaseModel): | ||
nominal: NonNegativeFloat | ||
actual: Optional[NonNegativeFloat] | ||
units: Literal["mAh", "Ah"] = "mAh" | ||
|
||
|
||
class BatterySpecs(BaseModel): | ||
""" | ||
Battery specification schema. | ||
""" | ||
manufacturer: str | ||
composition: BatteryComposition | ||
form_factor: str | ||
capacity: BatteryCapacity | ||
class Electrolyte(Component): | ||
formula: str | ||
position: PositiveInt | ||
amount: NonNegativeFloat | ||
|
||
# manufacturer, form_factor: | ||
# should we use a Literal or a validator to check that they are one of the available ones? | ||
|
||
# add pre-validator to specify capacity as str (e.g. '4.8 mAh')? | ||
class ElectrodeWeight(BaseModel): | ||
total: NonNegativeFloat | ||
collector: NonNegativeFloat | ||
net: Optional[NonNegativeFloat] | ||
units: Literal["mg", "g"] = "mg" | ||
|
||
|
||
class BatterySample(BatterySpecs): | ||
""" | ||
Battery sample schema. | ||
""" | ||
battery_id: int | ||
metadata: BatteryMetadata | ||
class Electrode(Component): | ||
formula: str | ||
position: PositiveInt | ||
diameter: Diameter | ||
weight: ElectrodeWeight | ||
capacity: Capacity | ||
|
||
|
||
class Separator(Component): | ||
name: str # ? use `Literal` of available? | ||
diameter: Diameter | ||
|
||
|
||
class Spacer(Component): | ||
value: NonNegativeFloat | ||
units: Literal["mm"] = "mm" | ||
|
||
|
||
class Composition(BaseModel): | ||
description: Optional[str] | ||
anode: Electrode | ||
cathode: Electrode | ||
electrolyte: Electrolyte | ||
separator: Separator | ||
spacer: Spacer | ||
|
||
|
||
class BatterySpecs(BaseModel): | ||
case: str # ? use `Literal` of available? | ||
manufacturer: str # ? use `Literal` of available? | ||
composition: Composition | ||
capacity: Capacity | ||
np_ratio: Optional[str] | ||
|
||
|
||
class BatteryMetadata(BaseModel): | ||
name: str | ||
groups: Set[str] = {"all-samples"} | ||
batch: str = "" | ||
subbatch: str = "0" | ||
creation_datetime: datetime | ||
creation_process: str | ||
|
||
|
||
class ChargeState(Flag): | ||
"""Defines the charge state of a battery.""" | ||
CHARGED = True | ||
DISCHARGED = False | ||
|
||
|
||
class BatteryState(BatterySample): | ||
""" | ||
Battery state schema. | ||
""" | ||
state_id: int | ||
class BatteryState(BaseModel): | ||
used = False | ||
charged: ChargeState = ChargeState.CHARGED | ||
|
||
|
||
class BatterySample(BaseModel): | ||
id: int | ||
# state: BatteryState # TODO move to metadata? | ||
specs: BatterySpecs | ||
metadata: BatteryMetadata | ||
|
||
|
||
BatterySpecsJsonTypes = extract_schema_types(BatterySpecs) | ||
BatterySampleJsonTypes = extract_schema_types(BatterySample) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters