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)
C:\t\bi-v5\src\battinfo\transform\cell_spec_node.py:583: UserWarning: semantic.value_text_only: 'cycle_life' on https://w3id.org/battinfo/spec/wckm-y5a4-he0k-2scd carries only value_text - the JSON-LD export emits no numeric quantity value for it.
  property_nodes = cell_spec_property_nodes(
C:\t\bi-v5\src\battinfo\transform\cell_spec_node.py:583: UserWarning: semantic.value_text_only: 'cycle_life' on https://w3id.org/battinfo/spec/wckm-y5a4-he0k-2scd carries only value_text - the JSON-LD export emits no numeric quantity value for it.
  property_nodes = cell_spec_property_nodes(
C:\t\bi-v5\src\battinfo\transform\cell_spec_node.py:583: UserWarning: semantic.value_text_only: 'cycle_life' on https://w3id.org/battinfo/spec/wckm-y5a4-he0k-2scd carries only value_text - the JSON-LD export emits no numeric quantity value for it.
  property_nodes = cell_spec_property_nodes(
C:\t\bi-v5\src\battinfo\transform\cell_spec_node.py:583: UserWarning: semantic.value_text_only: 'cycle_life' on https://w3id.org/battinfo/spec/wckm-y5a4-he0k-2scd carries only value_text - the JSON-LD export emits no numeric quantity value for it.
  property_nodes = cell_spec_property_nodes(
Ready. IRI: https://w3id.org/battinfo/spec/wckm-y5a4-he0k-2scd

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/wckm-y5a4-he0k-2scd",
  "schema:identifier": "wckm-y5a4-he0k-2scd",
  "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/wckm-y5a4-he0k-2scd",
  "isDescriptionFor": {
    "@type": [
      "BatteryCell",
      "CylindricalBattery",
      "LithiumIonBattery",
      "LithiumIonIronPhosphateBattery",
      "LithiumIonGraphiteBattery"
    ],
    "@id": "https://w3id.org/battinfo/spec/wckm-y5a4-he0k-2scd#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": [
          "NominalEnergy",
          "ConventionalProperty"
        ],
        "skos:prefLabel": "NominalEnergy",
        "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-09-15T14:08:34+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 an isDescriptionFor anonymous node:

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

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 on an isDescriptionFor anonymous node: the physical EMMO classes plus the hasProperty quantities and composition. The spec node keeps only catalogue and record facts:

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}")
  N035a2b79d8a9401cb8bd447b3c31d220  →  type  →  QuantitativeValue
  N035a2b79d8a9401cb8bd447b3c31d220  →  unitText  →  mm
  N035a2b79d8a9401cb8bd447b3c31d220  →  value  →  26.0
  N12ecfba392224a38b9eb33a42793a424  →  type  →  EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
  N12ecfba392224a38b9eb33a42793a424  →  type  →  electrochemistry_19e27aa3_0970_43a6_86d3_e3cdd956134d
  N12ecfba392224a38b9eb33a42793a424  →  prefLabel  →  NominalEnergy
  N12ecfba392224a38b9eb33a42793a424  →  EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0  →  N1c3521fcc0d944a6bab386af8553bdb4
  N12ecfba392224a38b9eb33a42793a424  →  EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569  →  Watthour
  N1c3521fcc0d944a6bab386af8553bdb4  →  type  →  EMMO_18d180e4_5e3e_42f7_820c_e08951223486
  N1c3521fcc0d944a6bab386af8553bdb4  →  EMMO_faf79f53_749d_40b2_807c_d34244c192f4  →  8.25
  N2b72064745a04e8582cf6624aff4e568  →  type  →  EMMO_08bcf1d6_e719_46c8_bb21_24bc9bf34dba
  N2b72064745a04e8582cf6624aff4e568  →  type  →  EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
  N2b72064745a04e8582cf6624aff4e568  →  prefLabel  →  Height
  N2b72064745a04e8582cf6624aff4e568  →  EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0  →  Ne42e0301b0844dc6be47f09c3351de87
  N2b72064745a04e8582cf6624aff4e568  →  EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569  →  MilliMetre
  N31280bdf35bd4995bee2cf86048e650f  →  type  →  EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
  N31280bdf35bd4995bee2cf86048e650f  →  type  →  electrochemistry_ae782b14_88ce_4cdd_9418_12aca00be937
  N31280bdf35bd4995bee2cf86048e650f  →  prefLabel  →  CycleLife
  N31280bdf35bd4995bee2cf86048e650f  →  EMMO_02face50_43a1_40ce_a909_dfe54d5e186b  →  >1000
  N31280bdf35bd4995bee2cf86048e650f  →  EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569  →  EMMO_5ebd5e01_0ed3_49a2_a30d_cd05cbe72978
  N31a756347a20439084866840de8d5f1e  →  type  →  EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
  N31a756347a20439084866840de8d5f1e  →  type  →  electrochemistry_8abde9d0_84f6_4b4f_a87e_86028a397100
  N31a756347a20439084866840de8d5f1e  →  prefLabel  →  NominalCapacity
  N31a756347a20439084866840de8d5f1e  →  EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0  →  N6ee211c2b8754db58f22b31c49134c94
  N31a756347a20439084866840de8d5f1e  →  EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569  →  AmpereHour
  N41d93455a3a94559bd4376c872767a3c  →  type  →  EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
  N41d93455a3a94559bd4376c872767a3c  →  type  →  electrochemistry_9bf40017_3f58_4030_ada7_cb37a3dfda2d
  N41d93455a3a94559bd4376c872767a3c  →  prefLabel  →  InternalResistance
  N41d93455a3a94559bd4376c872767a3c  →  EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0  →  Na59130a49409487d8a572f0329bf2e11
  N41d93455a3a94559bd4376c872767a3c  →  EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569  →  MilliOhm
  N50b9dc0d1f43466bb9e7021a987f401c  →  type  →  EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
  N50b9dc0d1f43466bb9e7021a987f401c  →  type  →  electrochemistry_639b844a_e801_436b_985d_28926129ead6
  N50b9dc0d1f43466bb9e7021a987f401c  →  prefLabel  →  NominalVoltage
  N50b9dc0d1f43466bb9e7021a987f401c  →  EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0  →  Nad3f681fa168492f91d7efd75a9d945f
  N50b9dc0d1f43466bb9e7021a987f401c  →  EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569  →  Volt
  N5f908c41a6c047d6bbbd82a9a6261f1d  →  type  →  QuantitativeValue
  N5f908c41a6c047d6bbbd82a9a6261f1d  →  unitText  →  mm
  N5f908c41a6c047d6bbbd82a9a6261f1d  →  value  →  65.0
  N65c6689ee02f474eafc5893525cd885b  →  type  →  QuantitativeValue
  N65c6689ee02f474eafc5893525cd885b  →  unitText  →  g
  N65c6689ee02f474eafc5893525cd885b  →  value  →  76.0
  N6a8dcca5ff7e4cb2a9f4a17a94a2a3f9  →  type  →  EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
  N6a8dcca5ff7e4cb2a9f4a17a94a2a3f9  →  type  →  EMMO_ed4af7ae_63a2_497e_bb88_2309619ea405
  N6a8dcca5ff7e4cb2a9f4a17a94a2a3f9  →  prefLabel  →  Mass
  N6a8dcca5ff7e4cb2a9f4a17a94a2a3f9  →  EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0  →  Ne149892ece8b43c0a548f1d6855e6d21
  N6a8dcca5ff7e4cb2a9f4a17a94a2a3f9  →  EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569  →  Gram
  N6c748f92d0f7473a8239f20f916db1e0  →  type  →  QuantitativeValue
  N6c748f92d0f7473a8239f20f916db1e0  →  unitText  →  mm
  N6c748f92d0f7473a8239f20f916db1e0  →  value  →  26.0
  N6ee211c2b8754db58f22b31c49134c94  →  type  →  EMMO_18d180e4_5e3e_42f7_820c_e08951223486
  N6ee211c2b8754db58f22b31c49134c94  →  EMMO_faf79f53_749d_40b2_807c_d34244c192f4  →  2.5
  N8eccc37a8f3c4796a5da751996640a5a  →  type  →  electrochemistry_c831d963_629a_41ab_850f_97fb6841b739
  Na164114e26534709a463badb0412db73  →  type  →  Organization
  Na164114e26534709a463badb0412db73  →  name  →  A123 Systems
  Na16a57b34dc148979772cddf397b992e  →  type  →  EMMO_c1c8ac3c_8a1c_4777_8e0b_14c1f9f9b0c6
  Na16a57b34dc148979772cddf397b992e  →  type  →  EMMO_d8aa8e1f_b650_416d_88a0_5118de945456
  Na16a57b34dc148979772cddf397b992e  →  prefLabel  →  Diameter
  Na16a57b34dc148979772cddf397b992e  →  EMMO_8ef3cd6d_ae58_4a8d_9fc0_ad8f49015cd0  →  Nf2dea97416874d93940f496ac3b0d155
  Na16a57b34dc148979772cddf397b992e  →  EMMO_bed1d005_b04e_4a90_94cf_02bc678a8569  →  MilliMetre
  Na59130a49409487d8a572f0329bf2e11  →  type  →  EMMO_18d180e4_5e3e_42f7_820c_e08951223486
  Na59130a49409487d8a572f0329bf2e11  →  EMMO_faf79f53_749d_40b2_807c_d34244c192f4  →  6.0
  Nad3f681fa168492f91d7efd75a9d945f  →  type  →  EMMO_18d180e4_5e3e_42f7_820c_e08951223486
  Nad3f681fa168492f91d7efd75a9d945f  →  EMMO_faf79f53_749d_40b2_807c_d34244c192f4  →  3.3
  Ne149892ece8b43c0a548f1d6855e6d21  →  type  →  EMMO_18d180e4_5e3e_42f7_820c_e08951223486
  Ne149892ece8b43c0a548f1d6855e6d21  →  EMMO_faf79f53_749d_40b2_807c_d34244c192f4  →  76.0
  Ne347b88e04e04438a6e654557e309dfa  →  type  →  datasheet
  Ne347b88e04e04438a6e654557e309dfa  →  type  →  Entity
  Ne347b88e04e04438a6e654557e309dfa  →  generatedAtTime  →  2026-09-15T14:08:34+00:00
  Ne42e0301b0844dc6be47f09c3351de87  →  type  →  EMMO_18d180e4_5e3e_42f7_820c_e08951223486
  Ne42e0301b0844dc6be47f09c3351de87  →  EMMO_faf79f53_749d_40b2_807c_d34244c192f4  →  65.0
  Nf272fe8d46404e4fb911748e7723899c  →  type  →  electrochemistry_1d0f15cb_d6b5_4c27_89ca_fe78adc1ce5b
  Nf2dea97416874d93940f496ac3b0d155  →  type  →  EMMO_18d180e4_5e3e_42f7_820c_e08951223486
  Nf2dea97416874d93940f496ac3b0d155  →  EMMO_faf79f53_749d_40b2_807c_d34244c192f4  →  26.0
  wckm-y5a4-he0k-2scd  →  source  →  Ne347b88e04e04438a6e654557e309dfa
  wckm-y5a4-he0k-2scd  →  type  →  CreativeWork
  wckm-y5a4-he0k-2scd  →  type  →  ProductModel
  wckm-y5a4-he0k-2scd  →  type  →  battery_1cfbba6c_8824_4932_a23e_2141483acef7
  wckm-y5a4-he0k-2scd  →  depth  →  N6c748f92d0f7473a8239f20f916db1e0
  wckm-y5a4-he0k-2scd  →  height  →  N5f908c41a6c047d6bbbd82a9a6261f1d
  wckm-y5a4-he0k-2scd  →  identifier  →  wckm-y5a4-he0k-2scd
  wckm-y5a4-he0k-2scd  →  manufacturer  →  Na164114e26534709a463badb0412db73
  wckm-y5a4-he0k-2scd  →  model  →  ANR26650M1-B
  wckm-y5a4-he0k-2scd  →  name  →  A123 Systems ANR26650M1-B
  wckm-y5a4-he0k-2scd  →  schemaVersion  →  0.2.0
  wckm-y5a4-he0k-2scd  →  size  →  R26650
  wckm-y5a4-he0k-2scd  →  url  →  wckm-y5a4-he0k-2scd
  wckm-y5a4-he0k-2scd  →  weight  →  N65c6689ee02f474eafc5893525cd885b
  wckm-y5a4-he0k-2scd  →  width  →  N035a2b79d8a9401cb8bd447b3c31d220
  wckm-y5a4-he0k-2scd  →  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  →  N12ecfba392224a38b9eb33a42793a424
  described  →  EMMO_e1097637_70d2_4895_973f_2396f04fa204  →  N2b72064745a04e8582cf6624aff4e568
  described  →  EMMO_e1097637_70d2_4895_973f_2396f04fa204  →  N31280bdf35bd4995bee2cf86048e650f
  described  →  EMMO_e1097637_70d2_4895_973f_2396f04fa204  →  N31a756347a20439084866840de8d5f1e
  described  →  EMMO_e1097637_70d2_4895_973f_2396f04fa204  →  N41d93455a3a94559bd4376c872767a3c
  described  →  EMMO_e1097637_70d2_4895_973f_2396f04fa204  →  N50b9dc0d1f43466bb9e7021a987f401c
  described  →  EMMO_e1097637_70d2_4895_973f_2396f04fa204  →  N6a8dcca5ff7e4cb2a9f4a17a94a2a3f9
  described  →  EMMO_e1097637_70d2_4895_973f_2396f04fa204  →  Na16a57b34dc148979772cddf397b992e
  described  →  electrochemistry_5d299271_3f68_494f_ab96_3db9acdd3138  →  N8eccc37a8f3c4796a5da751996640a5a
  described  →  electrochemistry_8e9cf965_9f92_46e8_b678_b50410ce3616  →  Nf272fe8d46404e4fb911748e7723899c

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" / "examples"
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 C:\t\bi-v5\docs\guides\_scratch\guide-04\multi\.battinfo\records:
  cell spec   A123 Systems ANR26650M1-B            [unchanged]  .battinfo\records\cell-spec\cell-spec-e4t5-w9re-mpq6-8g7e.json
  cell        a123-demo-multi-001                  [unchanged]  .battinfo\records\cell-instance\cell-aaqe-rvbd-c0b6-p1k3.json

  Next: ws.list(verbose=True) to inspect, or ws.publish() to publish.
Combined graph: 0 triples from 0 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/QUDT IRI

assets/mappings/domain-battery/entity_type_map.json

format/chemistry/electrode → @type array

[10]:
prop_map = json.loads(
    # Repo files sit two levels up from this notebook.
    Path("../../assets/mappings/domain-battery/property_map.curated.json").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.4.0
Curated entries: 81

  ac_internal_resistance                     → ACInternalResistance
  available_volume                           → Volume
  calendar_life                              → CalendarLife
  cap_assembly_weight                        → Mass
  capacity_fade                              → CapacityFadeRate
  capacity_threshold_exhaustion              → EndOfLifeCapacityThreshold
  certified_usable_energy                    → NominalEnergy
  charging_capacity                          → ChargingCapacity
  ...

Next#