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

BatteryCellSpecification

Information entity describing a class of cells

schema.org

schema:ProductModel

The catalogue entry: name, manufacturer, brand, codes

schema.org

schema:CreativeWork

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 isDescriptionFor)

format: "cylindrical"

CylindricalBattery

chemistry: "Li-ion"

LithiumIonBattery

positive_electrode_basis: "LFP"

LithiumIonIronPhosphateBattery

negative_electrode_basis: "graphite"

LithiumIonGraphiteBattery

(always)

BatteryCell

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.

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

@type term check

Bare @type value not in EMMO context

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

assets/mappings/domain-battery/property_map.curated.json

JSON key → EMMO class IRI

assets/mappings/domain-battery/unit_map.curated.json

Unit string → EMMO IRI

assets/mappings/domain-battery/entity_type_map.json

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#