Guide 4 — The semantic layer#
This guide examines the JSON-LD that BattINFO produces, explains how it connects to EMMO, and shows how to work with it using RDF tools.
Estimated time: 20 minutes Prerequisites: Guide 2 or Guide 3
New words? The plain-language glossary decodes EMMO, IRI, JSON-LD, and the rest in two sentences each.
[1]:
import json
import warnings
from pathlib import Path
SCRATCH = Path("_scratch/guide-04")
SCRATCH.mkdir(parents=True, exist_ok=True)
from battinfo import CellSpec, publish
from battinfo.api import publish_record
cell_spec = CellSpec(
manufacturer="A123 Systems",
model="ANR26650M1-B",
format="cylindrical",
chemistry="Li-ion",
positive_electrode_basis="LFP",
negative_electrode_basis="graphite",
size_code="R26650",
properties={
"nominal_capacity": {"value": 2.5, "unit": "Ah"},
"nominal_voltage": {"value": 3.3, "unit": "V"},
"rated_energy": {"value": 8.25, "unit": "Wh"},
"mass": {"value": 76.0, "unit": "g"},
"diameter": {"value": 26.0, "unit": "mm"},
"height": {"value": 65.0, "unit": "mm"},
"internal_resistance":{"value": 6.0, "unit": "mΩ"},
"cycle_life": {"value_text": ">1000", "unit": "count"},
},
)
result = publish(cell_spec, destination="local", root=SCRATCH)
output = publish_record(
result.debug_paths["canonical_record_path"],
target_root=SCRATCH / "resolver",
)
jsonld_path = Path(output["output_dir"], "index.jsonld")
jsonld = json.loads(jsonld_path.read_text(encoding="utf-8"))
print("Ready. IRI:", result.canonical_iri)
<repo>\src\battinfo\transform\cell_spec_node.py:600: UserWarning: semantic.value_text_only: 'cycle_life' on https://w3id.org/battinfo/spec/423x-1t4f-8p2g-n9g3 carries only value_text - the JSON-LD export emits no numeric quantity value for it.
property_nodes = cell_spec_property_nodes(record.get("properties"), context_label=str(iri or name or "cell-spec"))
<repo>\src\battinfo\transform\cell_spec_node.py:600: UserWarning: semantic.value_text_only: 'cycle_life' on https://w3id.org/battinfo/spec/423x-1t4f-8p2g-n9g3 carries only value_text - the JSON-LD export emits no numeric quantity value for it.
property_nodes = cell_spec_property_nodes(record.get("properties"), context_label=str(iri or name or "cell-spec"))
<repo>\src\battinfo\transform\cell_spec_node.py:600: UserWarning: semantic.value_text_only: 'cycle_life' on https://w3id.org/battinfo/spec/423x-1t4f-8p2g-n9g3 carries only value_text - the JSON-LD export emits no numeric quantity value for it.
property_nodes = cell_spec_property_nodes(record.get("properties"), context_label=str(iri or name or "cell-spec"))
<repo>\src\battinfo\transform\cell_spec_node.py:600: UserWarning: semantic.value_text_only: 'cycle_life' on https://w3id.org/battinfo/spec/423x-1t4f-8p2g-n9g3 carries only value_text - the JSON-LD export emits no numeric quantity value for it.
property_nodes = cell_spec_property_nodes(record.get("properties"), context_label=str(iri or name or "cell-spec"))
Ready. IRI: https://w3id.org/battinfo/spec/423x-1t4f-8p2g-n9g3
The full resolver JSON-LD#
[2]:
print(json.dumps(jsonld, indent=2))
{
"@context": [
"https://w3id.org/emmo/domain/battery/context",
{
"schema": "https://schema.org/",
"csvw": "http://www.w3.org/ns/csvw#",
"battinfo": "https://w3id.org/battinfo/",
"skos": "http://www.w3.org/2004/02/skos/core#"
}
],
"@type": [
"BatteryCellSpecification",
"schema:ProductModel",
"schema:CreativeWork"
],
"@id": "https://w3id.org/battinfo/spec/423x-1t4f-8p2g-n9g3",
"schema:identifier": "423x-1t4f-8p2g-n9g3",
"schema:name": "A123 Systems ANR26650M1-B",
"schema:model": "ANR26650M1-B",
"schema:manufacturer": {
"@type": "schema:Organization",
"schema:name": "A123 Systems"
},
"schema:url": "https://www.battery-genome.org/registry/spec/423x-1t4f-8p2g-n9g3",
"isDescriptionFor": {
"@type": [
"BatteryCell",
"CylindricalBattery",
"LithiumIonBattery",
"LithiumIonIronPhosphateBattery",
"LithiumIonGraphiteBattery"
],
"@id": "https://w3id.org/battinfo/spec/423x-1t4f-8p2g-n9g3#described",
"skos:prefLabel": "A123 Systems ANR26650M1-B",
"hasProperty": [
{
"@type": [
"NominalCapacity",
"ConventionalProperty"
],
"skos:prefLabel": "NominalCapacity",
"hasNumericalPart": {
"@type": "RealData",
"hasNumberValue": 2.5
},
"hasMeasurementUnit": "https://w3id.org/emmo#AmpereHour"
},
{
"@type": [
"NominalVoltage",
"ConventionalProperty"
],
"skos:prefLabel": "NominalVoltage",
"hasNumericalPart": {
"@type": "RealData",
"hasNumberValue": 3.3
},
"hasMeasurementUnit": "https://w3id.org/emmo#Volt"
},
{
"@type": [
"RatedEnergy",
"ConventionalProperty"
],
"skos:prefLabel": "RatedEnergy",
"hasNumericalPart": {
"@type": "RealData",
"hasNumberValue": 8.25
},
"hasMeasurementUnit": "https://w3id.org/emmo#Watthour"
},
{
"@type": [
"Mass",
"ConventionalProperty"
],
"skos:prefLabel": "Mass",
"hasNumericalPart": {
"@type": "RealData",
"hasNumberValue": 76.0
},
"hasMeasurementUnit": "https://w3id.org/emmo#Gram"
},
{
"@type": [
"Diameter",
"ConventionalProperty"
],
"skos:prefLabel": "Diameter",
"hasNumericalPart": {
"@type": "RealData",
"hasNumberValue": 26.0
},
"hasMeasurementUnit": "https://w3id.org/emmo#MilliMetre"
},
{
"@type": [
"Height",
"ConventionalProperty"
],
"skos:prefLabel": "Height",
"hasNumericalPart": {
"@type": "RealData",
"hasNumberValue": 65.0
},
"hasMeasurementUnit": "https://w3id.org/emmo#MilliMetre"
},
{
"@type": [
"InternalResistance",
"ConventionalProperty"
],
"skos:prefLabel": "InternalResistance",
"hasNumericalPart": {
"@type": "RealData",
"hasNumberValue": 6.0
},
"hasMeasurementUnit": "https://w3id.org/emmo#MilliOhm"
},
{
"@type": [
"CycleLife",
"ConventionalProperty"
],
"skos:prefLabel": "CycleLife",
"hasStringValue": ">1000",
"hasMeasurementUnit": "https://w3id.org/emmo#EMMO_5ebd5e01_0ed3_49a2_a30d_cd05cbe72978"
}
],
"hasPositiveElectrode": {
"@type": "LithiumIronPhosphateElectrode"
},
"hasNegativeElectrode": {
"@type": "GraphiteElectrode"
}
},
"schema:size": "R26650",
"schema:schemaVersion": "0.2.0",
"schema:weight": {
"@type": "schema:QuantitativeValue",
"schema:value": 76.0,
"schema:unitText": "g"
},
"schema:height": {
"@type": "schema:QuantitativeValue",
"schema:value": 65.0,
"schema:unitText": "mm"
},
"schema:width": {
"@type": "schema:QuantitativeValue",
"schema:value": 26.0,
"schema:unitText": "mm"
},
"schema:depth": {
"@type": "schema:QuantitativeValue",
"schema:value": 26.0,
"schema:unitText": "mm"
},
"dcterms:source": {
"@type": "prov:Entity",
"dcterms:type": "datasheet",
"prov:generatedAtTime": "2026-10-14T15:44:23+00:00"
}
}
@context#
Maps short names to full IRIs. Every term — BatteryCell, hasNumericalPart, NominalCapacity — resolves to a UUID-based IRI in the EMMO domain-battery ontology. BattINFO bundles a local copy so processing works offline.
@id#
The permanent IRI for this cell spec, resolvable at https://w3id.org/battinfo/spec/{uid}.
@type stacking#
[3]:
print("@type classes:")
for t in jsonld["@type"]:
print(f" {t}")
@type classes:
BatteryCellSpecification
schema:ProductModel
schema:CreativeWork
The specification node (BatteryCellSpecification) carries three types:
Vocabulary |
Type |
Rationale |
|---|---|---|
EMMO |
|
Information entity describing a class of cells |
schema.org |
|
The catalogue entry: name, manufacturer, brand, codes |
schema.org |
|
The specification document as a creative artifact |
The physical EMMO classes derived from cell-spec fields are placed on the described cell under isDescriptionFor, an individual named <spec IRI>#described:
Source field |
Physical EMMO class (on |
|---|---|
|
|
|
|
|
|
|
|
(always) |
|
The electrode-basis classes are kinds of the chemistry’s class, so a basis adds its class only within the declared chemistry: graphite adds LithiumIonGraphiteBattery to a Li-ion cell and nothing to a K-ion cell, and an MnO2 positive adds LithiumManganeseDioxideBattery to a Li-MnO2 cell and nothing to an alkaline zinc cell.
Placing physical types on isDescriptionFor is semantically correct: the specification is an information entity, not a physical cell. The old pattern (putting BatteryCell directly on the specification @type) implied the specification IS a physical cell, which is wrong.
No manual annotation — derived entirely from plain-text field values.
hasProperty — the canonical EMMO quantity pattern#
isDescriptionFor — where physical EMMO types live#
Both the resolver JSON-LD and the full descriptor JSON-LD (produced by to_jsonld) carry the described battery under isDescriptionFor, on the individual <spec IRI>#described: the physical EMMO classes plus the hasProperty quantities and composition. The spec node keeps only catalogue and record facts, such as the name, manufacturer, model and identifiers.
This placement is semantically correct: the specification is an information entity, not a physical cell. Putting BatteryCell on the specification @type would assert the specification IS a physical cell — which is wrong.
hasDescription — the reverse link from cell instance to specification#
Cell instances (physical objects with serial numbers) carry hasDescription pointing to the specification IRI, plus schema:isVariantOf for schema.org alignment.
The directionality reflects how data is created: the cell spec is registered first and given a stable IRI; individual cells with serial numbers are created later and reference it. Both hasDescription (EMMO) and schema:isVariantOf (schema.org) express the same relationship in their respective vocabularies.
[4]:
# Show isDescriptionFor from the full descriptor pipeline
from battinfo.transform.json_to_jsonld import _descriptor_specification_to_jsonld
spec = {
"format": "cylindrical",
"chemistry": "Li-ion",
"positive_electrode_basis": "LFP",
"negative_electrode_basis": "graphite",
}
node = _descriptor_specification_to_jsonld(spec)
print("Specification @type:", node["@type"])
print("isDescriptionFor @type:", node["isDescriptionFor"]["@type"])
Specification @type: ['BatteryCellSpecification', 'schema:ProductModel', 'schema:CreativeWork']
isDescriptionFor @type: ['BatteryCell', 'CylindricalBattery', 'LithiumIonBattery', 'LithiumIonIronPhosphateBattery', 'LithiumIonGraphiteBattery']
[5]:
# Quantities live on the described battery, not the specification node.
described = jsonld.get("isDescriptionFor", {})
print("Quantitative properties:")
for prop in described.get("hasProperty", []):
types = prop["@type"]
class_name = types[0] if isinstance(types, list) else types
# A value stated as text, such as cycle_life ">1000", is a hasStringValue.
value = prop.get("hasNumericalPart", {}).get("hasNumberValue", prop.get("hasStringValue"))
unit = prop.get("hasMeasurementUnit", "").split("#")[-1]
print(f" {class_name}: {value} ({unit})")
Quantitative properties:
NominalCapacity: 2.5 (AmpereHour)
NominalVoltage: 3.3 (Volt)
RatedEnergy: 8.25 (Watthour)
Mass: 76.0 (Gram)
Diameter: 26.0 (MilliMetre)
Height: 65.0 (MilliMetre)
InternalResistance: 6.0 (MilliOhm)
CycleLife: >1000 (EMMO_5ebd5e01_0ed3_49a2_a30d_cd05cbe72978)
The pattern is:
hasProperty → NominalCapacity, ConventionalProperty
├── hasNumericalPart → RealData → hasNumberValue: 2.5
└── hasMeasurementUnit: <EMMO AmpereHour IRI>
This is the canonical EMMO quantity pattern — identical across all EMMO domain modules.
Validating JSON-LD#
[6]:
from battinfo.validate.jsonld import validate_jsonld_report
report = validate_jsonld_report(jsonld)
print("ok:", report.ok)
for issue in report.issues:
print(f" [{issue.severity}] {issue.code}: {issue.message}")
ok: True
Check |
What fails |
|---|---|
|
Bare |
RDF parse |
JSON-LD rdflib cannot parse into a valid RDF dataset |
URDNA2015 |
JSON-LD that cannot be canonically normalised |
Loading into an RDF graph#
[7]:
from rdflib import Graph
g = Graph()
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning, module="rdflib")
g.parse(str(jsonld_path), format="json-ld")
print(f"Triple count: {len(g)}")
Triple count: 105
[8]:
# All triples in the graph
for s, p, o in sorted(g):
s_l = str(s).split("/")[-1].split("#")[-1]
p_l = str(p).split("/")[-1].split("#")[-1]
o_l = str(o).split("/")[-1].split("#")[-1]
print(f" {s_l} → {p_l} → {o_l}")
N08e5e7952d47455d83f8e3a24e16cd76 → type → EMMO_18d180e4_5e3e_42f7_820c_e08951223486
N08e5e7952d47455d83f8e3a24e16cd76 → EMMO_faf79f53_749d_40b2_807c_d34244c192f4 → 6.0
N12e1f1ee1d92485698d7573d458d756b → type → QuantitativeValue
N12e1f1ee1d92485698d7573d458d756b → unitText → mm
N12e1f1ee1d92485698d7573d458d756b → value → 26.0
N151883a120d24a90838c9bab62ae0cc2 → type → Organization
N151883a120d24a90838c9bab62ae0cc2 → name → A123 Systems
N18f6bf99d77b4b69aff8b4d86a8ca57a → type → EMMO_c1c8ac3c_8a1c_4777_8e0b_14c1f9f9b0c6
N18f6bf99d77b4b69aff8b4d86a8ca57a → type → EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
N18f6bf99d77b4b69aff8b4d86a8ca57a → prefLabel → Diameter
N18f6bf99d77b4b69aff8b4d86a8ca57a → EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0 → N39f63f65db41470da74ff62e9a6402cc
N18f6bf99d77b4b69aff8b4d86a8ca57a → EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569 → MilliMetre
N1e972190df5743a29f10287adbc46d47 → type → datasheet
N1e972190df5743a29f10287adbc46d47 → type → Entity
N1e972190df5743a29f10287adbc46d47 → generatedAtTime → 2026-10-14T15:44:23+00:00
N376790ebe3094b3c889ca985f49ff445 → type → EMMO_18d180e4_5e3e_42f7_820c_e08951223486
N376790ebe3094b3c889ca985f49ff445 → EMMO_faf79f53_749d_40b2_807c_d34244c192f4 → 8.25
N39f63f65db41470da74ff62e9a6402cc → type → EMMO_18d180e4_5e3e_42f7_820c_e08951223486
N39f63f65db41470da74ff62e9a6402cc → EMMO_faf79f53_749d_40b2_807c_d34244c192f4 → 26.0
N3e122f8c655e4dc797f3246f8914b809 → type → EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
N3e122f8c655e4dc797f3246f8914b809 → type → electrochemistry_639b844a_e801_436b_985d_28926129ead6
N3e122f8c655e4dc797f3246f8914b809 → prefLabel → NominalVoltage
N3e122f8c655e4dc797f3246f8914b809 → EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0 → N605e1acac9a84154ad0f6dd63993c120
N3e122f8c655e4dc797f3246f8914b809 → EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569 → Volt
N46a5bcd5c8e34df29a4f0d2a1af76870 → type → EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
N46a5bcd5c8e34df29a4f0d2a1af76870 → type → electrochemistry_9bf40017_3f58_4030_ada7_cb37a3dfda2d
N46a5bcd5c8e34df29a4f0d2a1af76870 → prefLabel → InternalResistance
N46a5bcd5c8e34df29a4f0d2a1af76870 → EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0 → N08e5e7952d47455d83f8e3a24e16cd76
N46a5bcd5c8e34df29a4f0d2a1af76870 → EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569 → MilliOhm
N605e1acac9a84154ad0f6dd63993c120 → type → EMMO_18d180e4_5e3e_42f7_820c_e08951223486
N605e1acac9a84154ad0f6dd63993c120 → EMMO_faf79f53_749d_40b2_807c_d34244c192f4 → 3.3
N60f507420a884cbba84127b004569272 → type → electrochemistry_c831d963_629a_41ab_850f_97fb6841b739
N6cd8e46edd1b4cb1a6482ada3dac11ae → type → EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
N6cd8e46edd1b4cb1a6482ada3dac11ae → type → electrochemistry_ae782b14_88ce_4cdd_9418_12aca00be937
N6cd8e46edd1b4cb1a6482ada3dac11ae → prefLabel → CycleLife
N6cd8e46edd1b4cb1a6482ada3dac11ae → EMMO_02face50_43a1_40ce_a909_dfe54d5e186b → >1000
N6cd8e46edd1b4cb1a6482ada3dac11ae → EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569 → EMMO_5ebd5e01_0ed3_49a2_a30d_cd05cbe72978
N75dc4d47292b47798a764286e1671470 → type → EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
N75dc4d47292b47798a764286e1671470 → type → electrochemistry_8abde9d0_84f6_4b4f_a87e_86028a397100
N75dc4d47292b47798a764286e1671470 → prefLabel → NominalCapacity
N75dc4d47292b47798a764286e1671470 → EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0 → Nfa07829c2b2f4c259f198a2b041a74c1
N75dc4d47292b47798a764286e1671470 → EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569 → AmpereHour
N7ff5e782576e434f897bc5e4222ed9ef → type → EMMO_18d180e4_5e3e_42f7_820c_e08951223486
N7ff5e782576e434f897bc5e4222ed9ef → EMMO_faf79f53_749d_40b2_807c_d34244c192f4 → 76.0
N8d074ad53a904b078e9508d9b7fce40a → type → EMMO_08bcf1d6_e719_46c8_bb21_24bc9bf34dba
N8d074ad53a904b078e9508d9b7fce40a → type → EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
N8d074ad53a904b078e9508d9b7fce40a → prefLabel → Height
N8d074ad53a904b078e9508d9b7fce40a → EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0 → Nbef1ec248ace4bc5a6c677e65c28e366
N8d074ad53a904b078e9508d9b7fce40a → EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569 → MilliMetre
N9762895862844050a1f8edfc8d63d88f → type → QuantitativeValue
N9762895862844050a1f8edfc8d63d88f → unitText → mm
N9762895862844050a1f8edfc8d63d88f → value → 26.0
N9be06b0258824f208b41fc5c223f2721 → type → electrochemistry_1d0f15cb_d6b5_4c27_89ca_fe78adc1ce5b
Nbaaceedc78574533a756ec3691adfd78 → type → EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
Nbaaceedc78574533a756ec3691adfd78 → type → electrochemistry_da215d1a_196a_465f_9de8_89f6fbb76982
Nbaaceedc78574533a756ec3691adfd78 → prefLabel → RatedEnergy
Nbaaceedc78574533a756ec3691adfd78 → EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0 → N376790ebe3094b3c889ca985f49ff445
Nbaaceedc78574533a756ec3691adfd78 → EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569 → Watthour
Nbb9d9fba1d2c42928b3e821846dd808c → type → QuantitativeValue
Nbb9d9fba1d2c42928b3e821846dd808c → unitText → mm
Nbb9d9fba1d2c42928b3e821846dd808c → value → 65.0
Nbef1ec248ace4bc5a6c677e65c28e366 → type → EMMO_18d180e4_5e3e_42f7_820c_e08951223486
Nbef1ec248ace4bc5a6c677e65c28e366 → EMMO_faf79f53_749d_40b2_807c_d34244c192f4 → 65.0
Nbfc6d84cd34c4c89bfd2b90f2cb55794 → type → QuantitativeValue
Nbfc6d84cd34c4c89bfd2b90f2cb55794 → unitText → g
Nbfc6d84cd34c4c89bfd2b90f2cb55794 → value → 76.0
Nef43b6bc4f3d4d58991ac68ea854fda9 → type → EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
Nef43b6bc4f3d4d58991ac68ea854fda9 → type → EMMO_ed4af7ae_63a2_497e_bb88_2309619ea405
Nef43b6bc4f3d4d58991ac68ea854fda9 → prefLabel → Mass
Nef43b6bc4f3d4d58991ac68ea854fda9 → EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0 → N7ff5e782576e434f897bc5e4222ed9ef
Nef43b6bc4f3d4d58991ac68ea854fda9 → EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569 → Gram
Nfa07829c2b2f4c259f198a2b041a74c1 → type → EMMO_18d180e4_5e3e_42f7_820c_e08951223486
Nfa07829c2b2f4c259f198a2b041a74c1 → EMMO_faf79f53_749d_40b2_807c_d34244c192f4 → 2.5
423x-1t4f-8p2g-n9g3 → source → N1e972190df5743a29f10287adbc46d47
423x-1t4f-8p2g-n9g3 → type → CreativeWork
423x-1t4f-8p2g-n9g3 → type → ProductModel
423x-1t4f-8p2g-n9g3 → type → battery_1cfbba6c_8824_4932_a23e_2141483acef7
423x-1t4f-8p2g-n9g3 → depth → N9762895862844050a1f8edfc8d63d88f
423x-1t4f-8p2g-n9g3 → height → Nbb9d9fba1d2c42928b3e821846dd808c
423x-1t4f-8p2g-n9g3 → identifier → 423x-1t4f-8p2g-n9g3
423x-1t4f-8p2g-n9g3 → manufacturer → N151883a120d24a90838c9bab62ae0cc2
423x-1t4f-8p2g-n9g3 → model → ANR26650M1-B
423x-1t4f-8p2g-n9g3 → name → A123 Systems ANR26650M1-B
423x-1t4f-8p2g-n9g3 → schemaVersion → 0.2.0
423x-1t4f-8p2g-n9g3 → size → R26650
423x-1t4f-8p2g-n9g3 → url → 423x-1t4f-8p2g-n9g3
423x-1t4f-8p2g-n9g3 → weight → Nbfc6d84cd34c4c89bfd2b90f2cb55794
423x-1t4f-8p2g-n9g3 → width → N12e1f1ee1d92485698d7573d458d756b
423x-1t4f-8p2g-n9g3 → EMMO_f702bad4_fc77_41f0_a26d_79f6444fd4f3 → described
described → type → battery_04a4e5a4_e6fd_43af_b1ca_4a16d5f8886c
described → type → battery_2018e0da_4c25_46e9_83db_38431fc81ce0
described → type → battery_68ed592a_7924_45d0_a108_94d6275d57f0
described → type → battery_96addc62_ea04_449a_8237_4cd541dd8e5f
described → type → battery_ac604ecd_cc60_4b98_b57c_74cd5d3ccd40
described → prefLabel → A123 Systems ANR26650M1-B
described → EMMO_e1097637_70d2_4895_973f_2396f04fa204 → N18f6bf99d77b4b69aff8b4d86a8ca57a
described → EMMO_e1097637_70d2_4895_973f_2396f04fa204 → N3e122f8c655e4dc797f3246f8914b809
described → EMMO_e1097637_70d2_4895_973f_2396f04fa204 → N46a5bcd5c8e34df29a4f0d2a1af76870
described → EMMO_e1097637_70d2_4895_973f_2396f04fa204 → N6cd8e46edd1b4cb1a6482ada3dac11ae
described → EMMO_e1097637_70d2_4895_973f_2396f04fa204 → N75dc4d47292b47798a764286e1671470
described → EMMO_e1097637_70d2_4895_973f_2396f04fa204 → N8d074ad53a904b078e9508d9b7fce40a
described → EMMO_e1097637_70d2_4895_973f_2396f04fa204 → Nbaaceedc78574533a756ec3691adfd78
described → EMMO_e1097637_70d2_4895_973f_2396f04fa204 → Nef43b6bc4f3d4d58991ac68ea854fda9
described → electrochemistry_5d299271_3f68_494f_ab96_3db9acdd3138 → N60f507420a884cbba84127b004569272
described → electrochemistry_8e9cf965_9f92_46e8_b678_b50410ce3616 → N9be06b0258824f208b41fc5c223f2721
Combining multiple records in one graph#
[9]:
import battinfo
ws = battinfo.workspace(root=SCRATCH / "multi")
multi_spec = battinfo.CellSpec(
manufacturer="A123 Systems", model="ANR26650M1-B",
format="cylindrical", chemistry="Li-ion",
positive_electrode_basis="LFP", negative_electrode_basis="graphite",
properties={"nominal_capacity": {"value": 2.5, "unit": "Ah"}},
)
ws.add("cell", spec=multi_spec, serial_numbers=["a123-demo-multi-001"])
ws.save()
# Publish each saved record as a resolver artifact
from battinfo.api import publish_record as _publish_one
multi_records = SCRATCH / "multi" / ".battinfo" / "records"
multi_resolver = SCRATCH / "multi-resolver"
for record_file in sorted(multi_records.rglob("*.json")):
_publish_one(record_file, target_root=multi_resolver)
jsonld_files = list(multi_resolver.rglob("index.jsonld"))
g2 = Graph()
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning, module="rdflib")
for jf in jsonld_files:
g2.parse(str(jf), format="json-ld")
print(f"Combined graph: {len(g2)} triples from {len(jsonld_files)} files")
cell: a123-demo-multi-001 (IRI auto-assigned)
Saved 2 record(s) under <repo>\docs\guides\_scratch\guide-04\multi\.battinfo\records:
cell spec A123 Systems ANR26650M1-B [created] .battinfo\records\cell-spec\cell-spec-5jw5-wm4v-f9w9-gexv.json
cell a123-demo-multi-001 [created] .battinfo\records\cell-instance\cell-m4e7-03ha-8kcc-et8n.json
Next: ws.list(verbose=True) to inspect, or ws.publish() to publish.
Combined graph: 40 triples from 2 files
Mapping tables#
BattINFO’s semantic output is driven by three curated files:
File |
Role |
|---|---|
|
JSON key → EMMO class IRI |
|
Unit string → EMMO IRI |
|
format/chemistry/electrode → @type array |
The package ships a copy of each under battinfo/data/mappings/domain-battery/. That copy is what the library reads, and what the next cell opens.
[10]:
from importlib.resources import files
prop_map_file = files("battinfo.data") / "mappings" / "domain-battery" / "property_map.curated.json"
prop_map = json.loads(prop_map_file.read_text(encoding="utf-8"))
print(f"Property map version: {prop_map['version']}")
print(f"Curated entries: {len(prop_map['mappings'])}")
print()
for entry in prop_map["mappings"][:8]:
print(f" {entry['key']:42s} → {entry['class_pref_label']}")
print(" ...")
Property map version: 0.6.0
Curated entries: 117
ac_internal_resistance → ACInternalResistance
areal_mass → AreaDensity
available_volume → Volume
calendar_life → CalendarLife
cap_assembly_weight → Mass
capacity_fade → CapacityFadeRate
capacity_threshold_exhaustion → EndOfLifeCapacityThreshold
certified_usable_energy → RatedEnergy
...
Next#
Guide 5 — Descriptors: author research-grade cell descriptors and see richer electrode-level JSON-LD