From 66b91c3f0b83849034e4139c561a1d88a9311f12 Mon Sep 17 00:00:00 2001 From: August Johansson Date: Fri, 20 Jun 2025 22:52:56 +0200 Subject: [PATCH 01/28] Include ttl (from web) as a file --- assets/battery-model-lithium-ion.ttl | 440 +++++++++++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 assets/battery-model-lithium-ion.ttl diff --git a/assets/battery-model-lithium-ion.ttl b/assets/battery-model-lithium-ion.ttl new file mode 100644 index 0000000..98e2a7b --- /dev/null +++ b/assets/battery-model-lithium-ion.ttl @@ -0,0 +1,440 @@ +@prefix : . +@prefix owl: . +@prefix rdf: . +@prefix xml: . +@prefix xsd: . +@prefix emmo: . +@prefix rdfs: . +@prefix skos: . +@prefix dcterms: . +@prefix annotations: . +@prefix electrochemistry: . +@base . + + rdf:type owl:Ontology ; + owl:versionIRI ; + owl:imports . + +################################################################# +# Annotation properties +################################################################# + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_0a5b99ee_995b_4899_a79b_925a4086da37 +:bmli_0a5b99ee_995b_4899_a79b_925a4086da37 rdf:type owl:AnnotationProperty ; + skos:prefLabel "bpxKey"@en ; + rdfs:subPropertyOf rdfs:label . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 +:bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 rdf:type owl:AnnotationProperty ; + skos:prefLabel "cidemodKey"@en ; + rdfs:subPropertyOf rdfs:label . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 +:bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 rdf:type owl:AnnotationProperty ; + skos:prefLabel "battmoKey"@en ; + rdfs:subPropertyOf rdfs:label . + + +################################################################# +# Classes +################################################################# + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_098f98dc_e015_4dbd_b358_a7ac3b3ecff3 +:modellib_098f98dc_e015_4dbd_b358_a7ac3b3ecff3 rdf:type owl:Class ; + rdfs:subClassOf emmo:EMMO_d5be1faf_0c56_4f5a_9b78_581e6dee949f ; + skos:prefLabel "InitialLithiumConcentrationInElectrolyte"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the initial amount concentration of lithium in an electrolyte"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Electrolyte','Initial concentration [mol.m-3]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['electrolyte','initial_concentration','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Electrolyte', 'species', 'nominalConcentration']"@en . + + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_0a1e73c5_e91b_4365_88d4_1e1f476bf776 +:modellib_0a1e73c5_e91b_4365_88d4_1e1f476bf776 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_a5571263_f153_448f_84a3_cd18092cf8fa ; + skos:prefLabel "PositiveElectrodeActiveMaterialVolumetricSurfaceArea"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Surface area per unit volume [m-1]']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','volumetricSurfaceArea']"@en. + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_0e2f4fe6_570a_4d13_81e9_de1d4f9987af +:modellib_0e2f4fe6_570a_4d13_81e9_de1d4f9987af rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_9c657fdc_b9d3_4964_907c_f9a6e8c5f52b ; + skos:prefLabel "NegativeElectrodeActiveMaterialOpenCircuitVoltage"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','OCP [V]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'OCP','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','openCircuitPotential']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_0ea21f71_d1bd_4714_a260_b991e6d4bcf7 +:modellib_0ea21f71_d1bd_4714_a260_b991e6d4bcf7 rdf:type owl:Class ; + rdfs:subClassOf emmo:EMMO_06448f64_8db6_4304_8b2c_e785dba82044 ; + skos:prefLabel "BatteryCellDensity"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the overall density of a lithium-ion battery cell, calculated as the quotient of the total mass and the total volume"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Density [kg.m-3]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['properties','density','value']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_1923575e_05b0_4b8b_8d58_0b2f2ba41c3e +:modellib_1923575e_05b0_4b8b_8d58_0b2f2ba41c3e rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_25dabdc2_68bf_4a38_8cbe_11be017358bc ; + skos:prefLabel "ElectrolyteConductivity"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Electrolyte','Conductivity [S.m-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['electrolyte','ionic_conductivity','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Electrolyte','ionicConductivity']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_21da0fe9_9fb6_4840_a12f_fbcc1ba84fb3 +:modellib_21da0fe9_9fb6_4840_a12f_fbcc1ba84fb3 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_f22bd1ec_faca_4335_92a5_a1687154c622 ; + skos:prefLabel "NegativeElectrodeLithiumStoichiometricCoefficientAtSOC0"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Minimum stoichiometry']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'stoichiometry0','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry0']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_404126e0_cb1b_44e4_98dc_2474185767a1 +:modellib_404126e0_cb1b_44e4_98dc_2474185767a1 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_0335e3f6_d1d8_4daa_8376_a9285f1bc9f1 ; + skos:prefLabel "PositiveElectrodeReactionRateConstant"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Reaction rate constant [mol.m-2.s-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'kinetic_constant','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','reactionRateConstant']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_43f77743_1af6_4a0f_9cc6_285c2a450549 +:modellib_43f77743_1af6_4a0f_9cc6_285c2a450549 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_ce74d2dc_d496_4116_b2fb_3e83d88bc744 ; + skos:prefLabel "PositiveElectrodeElectronicConductivity"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Conductivity [S.m-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','electronic_conductivity','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','ActiveMatrial','electronicConductivity']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_47288277_4aed_447e_b659_0c975d031406 +:modellib_47288277_4aed_447e_b659_0c975d031406 rdf:type owl:Class ; + rdfs:subClassOf emmo:EMMO_43003c86_9d15_433b_9789_ee2940920656 ; + skos:prefLabel "SeparatorThickness"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Separator','Thickness [m]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['separator','thickness','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Separator','thickness']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_4c274506_af5b_4ef1_8217_829ffd459f28 +:modellib_4c274506_af5b_4ef1_8217_829ffd459f28 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_37b24a94_cae0_4d7a_9519_9f7692dec607 ; + skos:prefLabel "LithiumDiffusivityInElectrolyte"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the diffusivity of lithium in an electrolyte"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Electrolyte','Diffusivity [m2.s-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['electrolyte','diffusion_constant','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Electrolyte','diffusionCoefficient']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_4d69edda_d2fa_40b0_9c1e_52e08debf578 +:modellib_4d69edda_d2fa_40b0_9c1e_52e08debf578 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_d7f8cab9_b035_4ecd_be63_292672572526 ; + skos:prefLabel "ActivationEnergyOfLithiumDiffusivityInPositiveElectrode"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the activation energy barrier in an Arrhenius expression for the diffusivity of lithium in the positive electrode"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Diffusivity activation energy [J.mol-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'diffusion_constant','arrhenius','activation_energy']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','SolidDiffusion','activationEnergyOfDiffusion']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_50247e71_75fe_4986_959e_fd06c6be98db +:modellib_50247e71_75fe_4986_959e_fd06c6be98db rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_37b24a94_cae0_4d7a_9519_9f7692dec607 ; + skos:prefLabel "LithiumDiffusivityInNegativeElectrode"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the diffusivity of lithium in the negative electrode"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Diffusivity [m2.s-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'diffusion_constant','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','SolidDiffusion','referenceDiffusionCoefficient']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_52ab4fdd_f945_4541_9ce6_cd6fd3a05861 +:modellib_52ab4fdd_f945_4541_9ce6_cd6fd3a05861 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_9c657fdc_b9d3_4964_907c_f9a6e8c5f52b ; + skos:prefLabel "PositiveElectrodeActiveMaterialOpenCircuitVoltage"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','OCP [V]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'OCP','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','openCircuitPotential']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_56b9cd1f_5397_4385_9292_30d93d9e7a05 +:modellib_56b9cd1f_5397_4385_9292_30d93d9e7a05 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_d7f8cab9_b035_4ecd_be63_292672572526 ; + skos:prefLabel "PostiveElectrodeActivationEnergyOfReaction"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Reaction rate constant activation energy [J.mol-1]']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','activationEnergyOfReaction']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_56de36fe_e8e1_486c_8d29_061ac8d28c13 + :modellib_56de36fe_e8e1_486c_8d29_061ac8d28c13 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_d7f8cab9_b035_4ecd_be63_292672572526 ; + skos:prefLabel "ActivationEnergyOfLithiumDiffusivityInElectrolyte"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the activation energy barrier in an Arrhenius expression for the diffusivity of lithium in an electrolyte"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Electrolyte','Diffusivity activation energy [J.mol-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['electrolyte','diffusion_constant','arrhenius','activation_energy']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_58400817_3282_46e5_942e_3a1538631403 +:modellib_58400817_3282_46e5_942e_3a1538631403 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_b92e382f_5109_4f60_ab5e_c89d340419a9 ; + skos:prefLabel "PositiveElectrodeActiveMaterialParticleRadius"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Particle radius [m]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'particle_radius','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','SolidDiffusion','particleRadius']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_5cb403c4_4f28_46cb_81c4_21c5c47ef14a +:modellib_5cb403c4_4f28_46cb_81c4_21c5c47ef14a rdf:type owl:Class ; + rdfs:subClassOf emmo:EMMO_3a6578ac_aee0_43b9_9bc6_1eb208c8c9a9 ; + skos:prefLabel "NegativeElectrodeCoatingPorosity"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Porosity']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','porosity','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','porosity']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_62f5beeb_6d1e_442a_8048_3ebe08882964 +:modellib_62f5beeb_6d1e_442a_8048_3ebe08882964 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_3b938708_e7e4_4ac0_a959_9c04306302e7 ; + skos:prefLabel "PositiveElectrodeCoatingThickness"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "thickness of the positive electrode coating"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Thickness [m]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','thickness','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','thickness']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_7481c4c9_c247_4248_a045_a1077230acba +:modellib_7481c4c9_c247_4248_a045_a1077230acba rdf:type owl:Class ; + rdfs:subClassOf emmo:EMMO_3a6578ac_aee0_43b9_9bc6_1eb208c8c9a9 ; + skos:prefLabel "PositiveElectrodeCoatingPorosity"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Porosity']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','porosity','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','porosity']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_80920875_62ac_4e29_b970_ec4316e76aa5 +:modellib_80920875_62ac_4e29_b970_ec4316e76aa5 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_f22bd1ec_faca_4335_92a5_a1687154c622 ; + skos:prefLabel "PositiveElectrodeLithiumStoichiometricCoefficientAtSOC0"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Minimum stoichiometry']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'stoichiometry1','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry0']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_86af4487_33c1_4562_a00b_3a8252ffe378 +:modellib_86af4487_33c1_4562_a00b_3a8252ffe378 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_d7f8cab9_b035_4ecd_be63_292672572526 ; + skos:prefLabel "ActivationEnergyOfLithiumDiffusivityInNegativeElectrode"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the activation energy barrier in an Arrhenius expression for the diffusivity of lithium in the negative electrode"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Diffusivity activation energy [J.mol-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'diffusion_constant','arrhenius','activation_energy']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','SolidDiffusion','activationEnergyOfDiffusion']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_8c16cb12_41c1_43bd_9e7c_2eea7b06a1f0 +:modellib_8c16cb12_41c1_43bd_9e7c_2eea7b06a1f0 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_d7f8cab9_b035_4ecd_be63_292672572526 ; + skos:prefLabel "ActivationEnergyOfElectrolyteConductivity"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the activation energy barrier in an Arrhenius expression for the ionic conductivity of an electrolyte"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Electrolyte','Conductivity activation energy [J.mol-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['electrolyte','ionic_conductivity','arrhenius','activation_energy']"@en . + + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_8c336ae9_1818_4b08_a660_4bb83b28351f +:modellib_8c336ae9_1818_4b08_a660_4bb83b28351f rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_38ab058e_3912_48c2_a7eb_76d25d000820 ; + skos:prefLabel "NegativeElectrodeLithiumStoichiometricCoefficientAtSOC100"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Maximum stoichiometry']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'stoichiometry1','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry100']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_99041897_5c08_40ed_9118_3e77e9b0e191 +:modellib_99041897_5c08_40ed_9118_3e77e9b0e191 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_38ab058e_3912_48c2_a7eb_76d25d000820 ; + skos:prefLabel "PositiveElectrodeLithiumStoichiometricCoefficientAtSOC100"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Maximum stoichiometry']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'stoichiometry0','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry100']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_9cba2158_26ba_4dd7_b082_ba66dbb960c7 +:modellib_9cba2158_26ba_4dd7_b082_ba66dbb960c7 rdf:type owl:Class ; + rdfs:subClassOf emmo:EMMO_b4f4ed28_d24c_4a00_9583_62ab839abeca ; + skos:prefLabel "BatteryCellLumpedSpecificHeatCapacity"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the lumped specific heat capacity of a battery cell"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Specific heat capacity [J.K-1.kg-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['properties','specific_heat','value']"@en . + + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_9d558b56_d3b8_429a_a4e2_d2ffab895e42 +:modellib_9d558b56_d3b8_429a_a4e2_d2ffab895e42 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_3bb5ae23_59fa_4bc7_9495_803eb6719f28 ; + skos:prefLabel "PositiveElectrodeEntropicChangeCoefficient"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Entropic change coefficient [V.K-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'entropy_coefficient','value']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_a4858e4d_dd3b_48ce_97ba_3eeb8571b633 +:modellib_a4858e4d_dd3b_48ce_97ba_3eeb8571b633 rdf:type owl:Class ; + rdfs:subClassOf emmo:EMMO_3a6578ac_aee0_43b9_9bc6_1eb208c8c9a9 ; + skos:prefLabel "SeparatorPorosity"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Separator','Porosity']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['separator','porosity','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Separator','porosity']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_b4184e46_c53c_47cc_9bfc_186fd77836a5 +:modellib_b4184e46_c53c_47cc_9bfc_186fd77836a5 rdf:type owl:Class ; + rdfs:subClassOf emmo:EMMO_f1a51559_aa3d_43a0_9327_918039f0dfed ; + skos:prefLabel "BatteryCellVolume"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the total volume of a battery cell, determined by its external dimensions"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Volume [m3]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['properties','volume','value']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_be3da3e2_58a9_4e58_adc2_7336d312717c +:modellib_be3da3e2_58a9_4e58_adc2_7336d312717c rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_ce74d2dc_d496_4116_b2fb_3e83d88bc744 ; + skos:prefLabel "NegativeElectrodeElectronicConductivity"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the electronic conductivity of the negative electrode"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Conductivity [S.m-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','electronic_conductivity','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','ActiveMatrial','electronicConductivity']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_bfe553c2_a63e_49b6_a209_0855dfc39724 +:modellib_bfe553c2_a63e_49b6_a209_0855dfc39724 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_b92e382f_5109_4f60_ab5e_c89d340419a9 ; + skos:prefLabel "NegativeElectrodeActiveMaterialParticleRadius"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Particle radius [m]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'particle_radius','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','SolidDiffusion','particleRadius']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_c5dcb1a2_f2cf_421a_b8ae_47a88a61fce3 +:modellib_c5dcb1a2_f2cf_421a_b8ae_47a88a61fce3 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_0335e3f6_d1d8_4daa_8376_a9285f1bc9f1 ; + skos:prefLabel "NegativeElectrodeReactionRateConstant"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Reaction rate constant [mol.m-2.s-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'kinetic_constant','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','reactionRateConstant']"@en . + + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_c5f9b91e_a770_4e9b_837e_fa2a76019111 + :modellib_c5f9b91e_a770_4e9b_837e_fa2a76019111 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_a5571263_f153_448f_84a3_cd18092cf8fa ; + skos:prefLabel "NegativeElectrodeActiveMaterialVolumetricSurfaceArea"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Surface area per unit volume [m-1]']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','volumetricSurfaceArea']"@en . + + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_c69a9d55_823f_4113_a305_ebc89dde7de3 + :modellib_c69a9d55_823f_4113_a305_ebc89dde7de3 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_47287d09_6108_45ca_ac65_8b9451b1065e ; + skos:prefLabel "PositiveElectrodeMaximumLithiumConcentration"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "maximum concentration of lithium in the positive electrode"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Maximum concentration [mol.m-3]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'maximum_concentration','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','saturationConcentration']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_ccde4e5f_ace4_41d1_b4d8_cbd63e6376e6 +:modellib_ccde4e5f_ace4_41d1_b4d8_cbd63e6376e6 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_05cf26ef_782a_4f66_a196_7004dd973f8e ; + skos:prefLabel "BatteryCellSurfaceArea"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the external surface area of a battery cell"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Parameterisation','Cell','External surface area [m2]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['properties','external_surface_area','value']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_cdc91ec0_9fc5_4551_bbd9_6824c2920124 +:modellib_cdc91ec0_9fc5_4551_bbd9_6824c2920124 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_3b938708_e7e4_4ac0_a959_9c04306302e7 ; + skos:prefLabel "NegativeElectrodeCoatingThickness"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "thickness of the negative electrode coating"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Thickness [m]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','thickness','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','thickness']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_e3e78df2_d568_4ab7_8c0d_d3a2ee3ae282 +:modellib_e3e78df2_d568_4ab7_8c0d_d3a2ee3ae282 rdf:type owl:Class ; + rdfs:subClassOf emmo:EMMO_d97b27cb_61a4_4568_a38b_4edd4f224acc ; + skos:prefLabel "LithiumTransportNumber"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "transport number of lithium ion in electrolyte"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Electrolyte','Cation transference number']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['electrolyte','transference_number','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Electrolyte','species', 'transferenceNumber']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_e59188bb_ce66_49f6_84aa_ecb98e76941e +:modellib_e59188bb_ce66_49f6_84aa_ecb98e76941e rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_37b24a94_cae0_4d7a_9519_9f7692dec607 ; + skos:prefLabel "LithiumDiffusivityInPositiveElectrode"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the diffusivity of lithium in the positive electrode"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Diffusivity [m2.s-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'diffusion_constant','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','SolidDiffusion','referenceDiffusionCoefficient']"@en . + + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_e808a26a_5812_49e9_894c_b793c7fe0c38 + :modellib_e808a26a_5812_49e9_894c_b793c7fe0c38 rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_47287d09_6108_45ca_ac65_8b9451b1065e ; + skos:prefLabel "NegativeElectrodeMaximumLithiumConcentration"@en ; + emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "maximum concentration of lithium in the negative electrode"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Maximum concentration [mol.m-3]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'maximum_concentration','value']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','saturationConcentration']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_eac57b09_5cc9_41d7_b2c8_40218d7fd47c +:modellib_eac57b09_5cc9_41d7_b2c8_40218d7fd47c rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_3bb5ae23_59fa_4bc7_9495_803eb6719f28 ; + skos:prefLabel "NegativeElectrodeEntropicChangeCoefficient"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Entropic change coefficient [V.K-1]']"@en ; + :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'entropy_coefficient','value']"@en . + + +### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_fda9539d_5232_471c_8945_b9a8ec7247fe +:modellib_fda9539d_5232_471c_8945_b9a8ec7247fe rdf:type owl:Class ; + rdfs:subClassOf electrochemistry:electrochemistry_d7f8cab9_b035_4ecd_be63_292672572526 ; + skos:prefLabel "NegativeElectrodeActivationEnergyOfReaction"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Reaction rate constant activation energy [J.mol-1]']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','activationEnergyOfReaction']"@en . + + + +################################################################# +# Annotations +################################################################# + + electrochemistry:electrochemistry_39a44af0_0e1a_4859_b550_bdabad64386e :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['simulation','initial_state','exterior_temperature','value']"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Ambient temperature [K]']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['ThermalModel','externalTemperature']"@en . + + +electrochemistry:electrochemistry_534dd59c_904c_45d9_8550_ae9d2eb6bbc9 :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['simulation','triggers','voltage','lower']"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Lower voltage cut-off [V]']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Control','lowerCutOffVoltage']"@en . + + +electrochemistry:electrochemistry_9c9b80a4_a00b_4b91_8e17_3a7831f2bf2f :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['simulation','initial_state','initial_temperature','value']"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Initial temperature [K]']"@en ; + :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['initT']"@en . + + +electrochemistry:electrochemistry_fa7790d6_07bb_4b0f_9965_55966828f5f3 :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['properties','area','value']"@en ; + :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Electrode area [m2]']"@en . + + +### Generated by the OWL API (version 4.5.9.2019-02-01T07:24:44Z) https://github.com/owlcs/owlapi From 4c932c678131a990232bbed63fccb064fb359835 Mon Sep 17 00:00:00 2001 From: August Johansson Date: Fri, 20 Jun 2025 22:53:08 +0200 Subject: [PATCH 02/28] Read ttl from file or web --- test.py | 98 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/test.py b/test.py index 3086a40..e168fa0 100644 --- a/test.py +++ b/test.py @@ -7,15 +7,23 @@ import re class OntologyParser: - def __init__(self, ontology_url): + def __init__(self, ontology_ref): self.graph = Graph() - response = requests.get(ontology_url) - response.raise_for_status() - self.graph.parse(data=response.text, format='ttl') + + if ontology_ref.startswith('http'): + response = requests.get(ontology_ref) + response.raise_for_status() + response_text = response.text + else: + with open(ontology_ref, 'r', encoding='utf-8') as f: + response_text = f.read().replace('\r\n', '\n') + # print(response_text) + self.graph.parse(data=response_text, format='ttl') self.key_map = { 'bpx': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_0a5b99ee_995b_4899_a79b_925a4086da37"), 'cidemod': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_1b718841_5d72_4071_bb71_fc4a754f5e30"), - 'battmo': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI + 'battmo.m': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI + 'battmo.jl': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI } def parse_key(self, key): @@ -183,63 +191,65 @@ def remove_high_level_defaults(self): self.defaults_used = {path for path in self.defaults_used if not any(k in path for k in ["Parameterisation", "Header"])} if __name__ == "__main__": - ontology_url = 'https://w3id.org/emmo/domain/battery-model-lithium-ion/latest' + #ontology_ref = 'https://w3id.org/emmo/domain/battery-model-lithium-ion/latest' + ontology_ref = 'assets/battery-model-lithium-ion.ttl' input_json_url = 'https://raw.githubusercontent.com/cidetec-energy-storage/cideMOD/main/data/data_Chen_2020/params_tuned_vOCPexpression.json' output_json_path = 'converted_battery_parameters.json' defaults_json_path = 'defaults_used.json' template_url = 'https://raw.githubusercontent.com/BIG-MAP/ModelMapper/main/assets/bpx_template.json' input_type = 'cidemod' - output_type = 'bpx' + #output_type = 'bpx' + output_type = 'battmo.m' # Initialize the OntologyParser - ontology_parser = OntologyParser(ontology_url) + ontology_parser = OntologyParser(ontology_ref) mappings = ontology_parser.get_mappings(input_type, output_type) print("Mappings:", json.dumps({str(k): str(v) for k, v in mappings.items()}, indent=4)) - # Load the input JSON file - input_data = JSONLoader.load(input_json_url) - print("Input Data:", json.dumps(input_data, indent=4)) + # # Load the input JSON file + # input_data = JSONLoader.load(input_json_url) + # print("Input Data:", json.dumps(input_data, indent=4)) + + # # Load the template JSON file + # template_data = JSONLoader.load(template_url) + # template_data.pop("Validation", None) # Remove validation if it exists in the template - # Load the template JSON file - template_data = JSONLoader.load(template_url) - template_data.pop("Validation", None) # Remove validation if it exists in the template + # # Map the parameters using the mappings from the ontology + # parameter_mapper = ParameterMapper(mappings, template_data, input_json_url, output_type, input_type) + # output_data = parameter_mapper.map_parameters(input_data) + # defaults_used_data = list(parameter_mapper.defaults_used) + # print("Output Data:", json.dumps(output_data, indent=4)) - # Map the parameters using the mappings from the ontology - parameter_mapper = ParameterMapper(mappings, template_data, input_json_url, output_type, input_type) - output_data = parameter_mapper.map_parameters(input_data) - defaults_used_data = list(parameter_mapper.defaults_used) - print("Output Data:", json.dumps(output_data, indent=4)) + # # Write the output JSON file + # JSONWriter.write(output_data, output_json_path) - # Write the output JSON file - JSONWriter.write(output_data, output_json_path) + # # Write the defaults used JSON file + # JSONWriter.write(defaults_used_data, defaults_json_path) - # Write the defaults used JSON file - JSONWriter.write(defaults_used_data, defaults_json_path) - - # Load the DFN model - model = pybamm.lithium_ion.DFN() + # # Load the DFN model + # model = pybamm.lithium_ion.DFN() - # Load the parameter values - parameter_values = pybamm.ParameterValues.create_from_bpx('converted_battery_parameters.json') + # # Load the parameter values + # parameter_values = pybamm.ParameterValues.create_from_bpx('converted_battery_parameters.json') - # Define the experiment: Charge from SOC=0.01, then discharge - experiment = pybamm.Experiment([ - ("Charge at C/5 until 4.2 V", - "Hold at 4.2 V until 1 mA", - "Rest for 1 hour", - "Discharge at C/5 until 2.5 V") - ]) + # # Define the experiment: Charge from SOC=0.01, then discharge + # experiment = pybamm.Experiment([ + # ("Charge at C/5 until 4.2 V", + # "Hold at 4.2 V until 1 mA", + # "Rest for 1 hour", + # "Discharge at C/5 until 2.5 V") + # ]) - # Create the simulation with the experiment - sim = pybamm.Simulation(model, experiment=experiment, parameter_values=parameter_values) + # # Create the simulation with the experiment + # sim = pybamm.Simulation(model, experiment=experiment, parameter_values=parameter_values) - # Define initial concentration in negative and positive electrodes - parameter_values["Initial concentration in negative electrode [mol.m-3]"] = 0.0279 * parameter_values["Maximum concentration in negative electrode [mol.m-3]"] - parameter_values["Initial concentration in positive electrode [mol.m-3]"] = 0.9084 * parameter_values["Maximum concentration in positive electrode [mol.m-3]"] + # # Define initial concentration in negative and positive electrodes + # parameter_values["Initial concentration in negative electrode [mol.m-3]"] = 0.0279 * parameter_values["Maximum concentration in negative electrode [mol.m-3]"] + # parameter_values["Initial concentration in positive electrode [mol.m-3]"] = 0.9084 * parameter_values["Maximum concentration in positive electrode [mol.m-3]"] - # Solve the simulation - sim.solve() + # # Solve the simulation + # sim.solve() - # Plot the results - sim.plot() + # # Plot the results + # sim.plot() From f508b761fc0c3d334afc27bc48a1f7727bb73748 Mon Sep 17 00:00:00 2001 From: August Johansson Date: Tue, 2 Sep 2025 12:38:33 +0200 Subject: [PATCH 03/28] Add missing comma --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index e168fa0..a10b3f4 100644 --- a/test.py +++ b/test.py @@ -22,7 +22,7 @@ def __init__(self, ontology_ref): self.key_map = { 'bpx': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_0a5b99ee_995b_4899_a79b_925a4086da37"), 'cidemod': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_1b718841_5d72_4071_bb71_fc4a754f5e30"), - 'battmo.m': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI + 'battmo.m': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40"), # Placeholder URI 'battmo.jl': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI } From c2b0754836ddaa2ee4c894c7cffef0f84e2ac39c Mon Sep 17 00:00:00 2001 From: August Johansson Date: Sat, 13 Dec 2025 22:14:47 +0100 Subject: [PATCH 04/28] from https://emmo-repo.github.io/domain-battery-model-lithium-ion/battery-model-lithium-ion.html and the context file https://github.com/emmo-repo/domain-battery/blob/master/context/context.json it seems like the battmo key is not 2c... but e5e... --- BatteryModelMapper/ontology_parser.py | 2 +- assets/battery-model-lithium-ion.ttl | 70 +++++++++++++-------------- test.py | 4 +- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/BatteryModelMapper/ontology_parser.py b/BatteryModelMapper/ontology_parser.py index f327bc1..17e7445 100644 --- a/BatteryModelMapper/ontology_parser.py +++ b/BatteryModelMapper/ontology_parser.py @@ -11,7 +11,7 @@ def __init__(self, ontology_url): self.key_map = { 'bpx': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_0a5b99ee_995b_4899_a79b_925a4086da37"), 'cidemod': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_1b718841_5d72_4071_bb71_fc4a754f5e30"), - 'battmo': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI + 'battmo': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14") # Placeholder URI } def parse_key(self, key): diff --git a/assets/battery-model-lithium-ion.ttl b/assets/battery-model-lithium-ion.ttl index 98e2a7b..bed114e 100644 --- a/assets/battery-model-lithium-ion.ttl +++ b/assets/battery-model-lithium-ion.ttl @@ -48,7 +48,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the initial amount concentration of lithium in an electrolyte"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Electrolyte','Initial concentration [mol.m-3]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['electrolyte','initial_concentration','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Electrolyte', 'species', 'nominalConcentration']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['Electrolyte', 'species', 'nominalConcentration']"@en . @@ -57,7 +57,7 @@ rdfs:subClassOf electrochemistry:electrochemistry_a5571263_f153_448f_84a3_cd18092cf8fa ; skos:prefLabel "PositiveElectrodeActiveMaterialVolumetricSurfaceArea"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Surface area per unit volume [m-1]']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','volumetricSurfaceArea']"@en. + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','ActiveMaterial','Interface','volumetricSurfaceArea']"@en. ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_0e2f4fe6_570a_4d13_81e9_de1d4f9987af @@ -66,7 +66,7 @@ skos:prefLabel "NegativeElectrodeActiveMaterialOpenCircuitVoltage"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','OCP [V]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'OCP','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','openCircuitPotential']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','ActiveMaterial','Interface','openCircuitPotential']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_0ea21f71_d1bd_4714_a260_b991e6d4bcf7 @@ -84,7 +84,7 @@ skos:prefLabel "ElectrolyteConductivity"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Electrolyte','Conductivity [S.m-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['electrolyte','ionic_conductivity','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Electrolyte','ionicConductivity']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['Electrolyte','ionicConductivity']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_21da0fe9_9fb6_4840_a12f_fbcc1ba84fb3 @@ -93,7 +93,7 @@ skos:prefLabel "NegativeElectrodeLithiumStoichiometricCoefficientAtSOC0"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Minimum stoichiometry']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'stoichiometry0','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry0']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry0']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_404126e0_cb1b_44e4_98dc_2474185767a1 @@ -102,7 +102,7 @@ skos:prefLabel "PositiveElectrodeReactionRateConstant"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Reaction rate constant [mol.m-2.s-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'kinetic_constant','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','reactionRateConstant']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','ActiveMaterial','Interface','reactionRateConstant']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_43f77743_1af6_4a0f_9cc6_285c2a450549 @@ -111,7 +111,7 @@ skos:prefLabel "PositiveElectrodeElectronicConductivity"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Conductivity [S.m-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','electronic_conductivity','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','ActiveMatrial','electronicConductivity']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','ActiveMatrial','electronicConductivity']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_47288277_4aed_447e_b659_0c975d031406 @@ -120,7 +120,7 @@ skos:prefLabel "SeparatorThickness"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Separator','Thickness [m]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['separator','thickness','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Separator','thickness']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['Separator','thickness']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_4c274506_af5b_4ef1_8217_829ffd459f28 @@ -130,7 +130,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the diffusivity of lithium in an electrolyte"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Electrolyte','Diffusivity [m2.s-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['electrolyte','diffusion_constant','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Electrolyte','diffusionCoefficient']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['Electrolyte','diffusionCoefficient']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_4d69edda_d2fa_40b0_9c1e_52e08debf578 @@ -140,7 +140,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the activation energy barrier in an Arrhenius expression for the diffusivity of lithium in the positive electrode"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Diffusivity activation energy [J.mol-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'diffusion_constant','arrhenius','activation_energy']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','SolidDiffusion','activationEnergyOfDiffusion']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','ActiveMaterial','SolidDiffusion','activationEnergyOfDiffusion']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_50247e71_75fe_4986_959e_fd06c6be98db @@ -150,7 +150,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the diffusivity of lithium in the negative electrode"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Diffusivity [m2.s-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'diffusion_constant','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','SolidDiffusion','referenceDiffusionCoefficient']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','ActiveMaterial','SolidDiffusion','referenceDiffusionCoefficient']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_52ab4fdd_f945_4541_9ce6_cd6fd3a05861 @@ -159,7 +159,7 @@ skos:prefLabel "PositiveElectrodeActiveMaterialOpenCircuitVoltage"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','OCP [V]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'OCP','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','openCircuitPotential']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','ActiveMaterial','Interface','openCircuitPotential']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_56b9cd1f_5397_4385_9292_30d93d9e7a05 @@ -167,7 +167,7 @@ rdfs:subClassOf electrochemistry:electrochemistry_d7f8cab9_b035_4ecd_be63_292672572526 ; skos:prefLabel "PostiveElectrodeActivationEnergyOfReaction"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Reaction rate constant activation energy [J.mol-1]']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','activationEnergyOfReaction']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','ActiveMaterial','Interface','activationEnergyOfReaction']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_56de36fe_e8e1_486c_8d29_061ac8d28c13 @@ -185,7 +185,7 @@ skos:prefLabel "PositiveElectrodeActiveMaterialParticleRadius"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Particle radius [m]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'particle_radius','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','SolidDiffusion','particleRadius']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','ActiveMaterial','SolidDiffusion','particleRadius']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_5cb403c4_4f28_46cb_81c4_21c5c47ef14a @@ -194,7 +194,7 @@ skos:prefLabel "NegativeElectrodeCoatingPorosity"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Porosity']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','porosity','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','porosity']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','porosity']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_62f5beeb_6d1e_442a_8048_3ebe08882964 @@ -204,7 +204,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "thickness of the positive electrode coating"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Thickness [m]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','thickness','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','thickness']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','thickness']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_7481c4c9_c247_4248_a045_a1077230acba @@ -213,7 +213,7 @@ skos:prefLabel "PositiveElectrodeCoatingPorosity"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Porosity']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','porosity','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','porosity']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','porosity']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_80920875_62ac_4e29_b970_ec4316e76aa5 @@ -222,7 +222,7 @@ skos:prefLabel "PositiveElectrodeLithiumStoichiometricCoefficientAtSOC0"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Minimum stoichiometry']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'stoichiometry1','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry0']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry0']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_86af4487_33c1_4562_a00b_3a8252ffe378 @@ -232,7 +232,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the activation energy barrier in an Arrhenius expression for the diffusivity of lithium in the negative electrode"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Diffusivity activation energy [J.mol-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'diffusion_constant','arrhenius','activation_energy']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','SolidDiffusion','activationEnergyOfDiffusion']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','ActiveMaterial','SolidDiffusion','activationEnergyOfDiffusion']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_8c16cb12_41c1_43bd_9e7c_2eea7b06a1f0 @@ -251,7 +251,7 @@ skos:prefLabel "NegativeElectrodeLithiumStoichiometricCoefficientAtSOC100"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Maximum stoichiometry']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'stoichiometry1','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry100']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry100']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_99041897_5c08_40ed_9118_3e77e9b0e191 @@ -260,7 +260,7 @@ skos:prefLabel "PositiveElectrodeLithiumStoichiometricCoefficientAtSOC100"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Maximum stoichiometry']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'stoichiometry0','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry100']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','ActiveMaterial','Interface','guestStoichiometry100']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_9cba2158_26ba_4dd7_b082_ba66dbb960c7 @@ -287,7 +287,7 @@ skos:prefLabel "SeparatorPorosity"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Separator','Porosity']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['separator','porosity','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Separator','porosity']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['Separator','porosity']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_b4184e46_c53c_47cc_9bfc_186fd77836a5 @@ -306,7 +306,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the electronic conductivity of the negative electrode"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Conductivity [S.m-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','electronic_conductivity','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','ActiveMatrial','electronicConductivity']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','ActiveMatrial','electronicConductivity']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_bfe553c2_a63e_49b6_a209_0855dfc39724 @@ -315,7 +315,7 @@ skos:prefLabel "NegativeElectrodeActiveMaterialParticleRadius"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Particle radius [m]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'particle_radius','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','SolidDiffusion','particleRadius']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','ActiveMaterial','SolidDiffusion','particleRadius']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_c5dcb1a2_f2cf_421a_b8ae_47a88a61fce3 @@ -324,7 +324,7 @@ skos:prefLabel "NegativeElectrodeReactionRateConstant"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Reaction rate constant [mol.m-2.s-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'kinetic_constant','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','reactionRateConstant']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','ActiveMaterial','Interface','reactionRateConstant']"@en . @@ -333,7 +333,7 @@ rdfs:subClassOf electrochemistry:electrochemistry_a5571263_f153_448f_84a3_cd18092cf8fa ; skos:prefLabel "NegativeElectrodeActiveMaterialVolumetricSurfaceArea"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Surface area per unit volume [m-1]']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','volumetricSurfaceArea']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','ActiveMaterial','Interface','volumetricSurfaceArea']"@en . @@ -344,7 +344,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "maximum concentration of lithium in the positive electrode"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Maximum concentration [mol.m-3]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'maximum_concentration','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','Interface','saturationConcentration']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','ActiveMaterial','Interface','saturationConcentration']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_ccde4e5f_ace4_41d1_b4d8_cbd63e6376e6 @@ -363,7 +363,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "thickness of the negative electrode coating"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Thickness [m]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','thickness','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','thickness']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','thickness']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_e3e78df2_d568_4ab7_8c0d_d3a2ee3ae282 @@ -373,7 +373,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "transport number of lithium ion in electrolyte"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Electrolyte','Cation transference number']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['electrolyte','transference_number','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Electrolyte','species', 'transferenceNumber']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['Electrolyte','species', 'transferenceNumber']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_e59188bb_ce66_49f6_84aa_ecb98e76941e @@ -383,7 +383,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the diffusivity of lithium in the positive electrode"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Diffusivity [m2.s-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','active_materials',0,'diffusion_constant','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['PositiveElectrode','Coating','ActiveMaterial','SolidDiffusion','referenceDiffusionCoefficient']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','ActiveMaterial','SolidDiffusion','referenceDiffusionCoefficient']"@en . @@ -394,7 +394,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "maximum concentration of lithium in the negative electrode"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Maximum concentration [mol.m-3]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','active_materials',0,'maximum_concentration','value']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','saturationConcentration']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','ActiveMaterial','Interface','saturationConcentration']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_eac57b09_5cc9_41d7_b2c8_40218d7fd47c @@ -410,7 +410,7 @@ rdfs:subClassOf electrochemistry:electrochemistry_d7f8cab9_b035_4ecd_be63_292672572526 ; skos:prefLabel "NegativeElectrodeActivationEnergyOfReaction"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Reaction rate constant activation energy [J.mol-1]']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['NegativeElectrode','Coating','ActiveMaterial','Interface','activationEnergyOfReaction']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','ActiveMaterial','Interface','activationEnergyOfReaction']"@en . @@ -420,17 +420,17 @@ electrochemistry:electrochemistry_39a44af0_0e1a_4859_b550_bdabad64386e :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['simulation','initial_state','exterior_temperature','value']"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Ambient temperature [K]']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['ThermalModel','externalTemperature']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['ThermalModel','externalTemperature']"@en . electrochemistry:electrochemistry_534dd59c_904c_45d9_8550_ae9d2eb6bbc9 :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['simulation','triggers','voltage','lower']"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Lower voltage cut-off [V]']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['Control','lowerCutOffVoltage']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['Control','lowerCutOffVoltage']"@en . electrochemistry:electrochemistry_9c9b80a4_a00b_4b91_8e17_3a7831f2bf2f :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['simulation','initial_state','initial_temperature','value']"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Initial temperature [K]']"@en ; - :bmli_2c718841_6d73_5082_bb81_gc5b754f6e40 "['initT']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['initT']"@en . electrochemistry:electrochemistry_fa7790d6_07bb_4b0f_9965_55966828f5f3 :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['properties','area','value']"@en ; diff --git a/test.py b/test.py index a10b3f4..1cf6374 100644 --- a/test.py +++ b/test.py @@ -22,8 +22,8 @@ def __init__(self, ontology_ref): self.key_map = { 'bpx': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_0a5b99ee_995b_4899_a79b_925a4086da37"), 'cidemod': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_1b718841_5d72_4071_bb71_fc4a754f5e30"), - 'battmo.m': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40"), # Placeholder URI - 'battmo.jl': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI + 'battmo.m': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14"), + # 'battmo.jl': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI } def parse_key(self, key): From 346755d63a577ef39ed153ca0d1ab0edc1cba761 Mon Sep 17 00:00:00 2001 From: August Johansson Date: Thu, 18 Dec 2025 10:53:59 +0100 Subject: [PATCH 05/28] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 824b241..e60b881 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ test_pybamm.py # Ignore the virtual environment folder venv/ +env/ # Byte-compiled / optimized / DLL files __pycache__/ From 3e115825dd3acecbbe02d3ea2222267b7b535867 Mon Sep 17 00:00:00 2001 From: August Johansson Date: Thu, 18 Dec 2025 11:12:12 +0100 Subject: [PATCH 06/28] Work on jsonld --- test.py | 192 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 149 insertions(+), 43 deletions(-) diff --git a/test.py b/test.py index 1cf6374..0d0869b 100644 --- a/test.py +++ b/test.py @@ -5,24 +5,36 @@ from rdflib import Graph, URIRef from jsonschema import validate, ValidationError import re +import os +from urllib.parse import urlparse +from pathlib import Path +from rdflib import Literal +from rdflib.namespace import RDF + class OntologyParser: def __init__(self, ontology_ref): self.graph = Graph() - if ontology_ref.startswith('http'): + if ontology_ref.startswith("http"): response = requests.get(ontology_ref) response.raise_for_status() response_text = response.text else: - with open(ontology_ref, 'r', encoding='utf-8') as f: - response_text = f.read().replace('\r\n', '\n') + with open(ontology_ref, "r", encoding="utf-8") as f: + response_text = f.read().replace("\r\n", "\n") # print(response_text) - self.graph.parse(data=response_text, format='ttl') + self.graph.parse(data=response_text, format="ttl") self.key_map = { - 'bpx': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_0a5b99ee_995b_4899_a79b_925a4086da37"), - 'cidemod': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_1b718841_5d72_4071_bb71_fc4a754f5e30"), - 'battmo.m': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14"), + "bpx": URIRef( + "https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_0a5b99ee_995b_4899_a79b_925a4086da37" + ), + "cidemod": URIRef( + "https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_1b718841_5d72_4071_bb71_fc4a754f5e30" + ), + "battmo.m": URIRef( + "https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14" + ), # 'battmo.jl': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI } @@ -37,7 +49,9 @@ def get_mappings(self, input_type, output_type): input_key = self.key_map.get(input_type) output_key = self.key_map.get(output_type) if not input_key or not output_key: - raise ValueError(f"Invalid input or output type: {input_type}, {output_type}") + raise ValueError( + f"Invalid input or output type: {input_type}, {output_type}" + ) mappings = {} for subject in self.graph.subjects(): @@ -53,12 +67,25 @@ def get_mappings(self, input_type, output_type): print(f"Mapping added: {tuple(input_value)} -> {tuple(output_value)}") return mappings + class JSONLoader: @staticmethod - def load(json_url): - response = requests.get(json_url) - response.raise_for_status() - return response.json() + def load(source): + # Accept Path or str + source = Path(source) + + # If it looks like a URL → load from web + if urlparse(str(source)).scheme in ("http", "https"): + response = requests.get(str(source)) + response.raise_for_status() + return response.json() + + # Else → treat as local file + if not source.is_file(): + raise ValueError(f"File does not exist: {source}") + + return json.loads(source.read_text(encoding="utf-8")) + class JSONValidator: @staticmethod @@ -71,12 +98,14 @@ def validate(data, schema_url): print(f"JSON validation error: {e.message}") raise + class JSONWriter: @staticmethod def write(data, output_path): - with open(output_path, 'w') as file: + with open(output_path, "w") as file: json.dump(data, file, indent=4) + class ParameterMapper: def __init__(self, mappings, template, input_url, output_type, input_type): self.mappings = mappings @@ -89,11 +118,11 @@ def __init__(self, mappings, template, input_url, output_type, input_type): def map_parameters(self, input_data): output_data = self.template.copy() for input_key, output_key in self.mappings.items(): - value = self.get_value_from_path(input_data, input_key) + value = get_value_from_path(input_data, input_key) if value is not None: if isinstance(value, str): value = self.replace_variables(value) - if self.input_type == 'cidemod' and 'kinetic_constant' in input_key: + if self.input_type == "cidemod" and "kinetic_constant" in input_key: value = self.scale_kinetic_constant(value) self.set_value_from_path(output_data, output_key, value) self.remove_default_from_used(output_key) @@ -103,8 +132,8 @@ def map_parameters(self, input_data): def replace_variables(self, value): if isinstance(value, str): - value = re.sub(r'\bx_s\b', 'x', value) - value = re.sub(r'\bc_e\b', 'x', value) + value = re.sub(r"\bx_s\b", "x", value) + value = re.sub(r"\bc_e\b", "x", value) return value def scale_kinetic_constant(self, value): @@ -128,7 +157,8 @@ def get_all_paths(self, data, path=""): paths.update(self.get_all_paths(item, current_path)) return paths - def get_value_from_path(self, data, keys): + @staticmethod + def get_value_from_path(data, keys): try: for key in keys: if isinstance(key, str): @@ -162,7 +192,9 @@ def set_value_from_path(self, data, keys, value): final_key = keys[-1] if isinstance(final_key, str): final_key = final_key.strip() - if isinstance(final_key, int) or (isinstance(final_key, str) and final_key.isdigit()): + if isinstance(final_key, int) or ( + isinstance(final_key, str) and final_key.isdigit() + ): final_key = int(final_key) data[final_key] = value print(f"Set value for path {keys}: {value}") @@ -183,42 +215,117 @@ def set_bpx_header(self, data): "BPX": 0.1, "Title": "An autoconverted parameter set using BatteryModelMapper", "Description": f"This data set was automatically generated from {self.input_url}. Please check carefully.", - "Model": "DFN" + "Model": "DFN", } data.pop("Validation", None) def remove_high_level_defaults(self): - self.defaults_used = {path for path in self.defaults_used if not any(k in path for k in ["Parameterisation", "Header"])} + self.defaults_used = { + path + for path in self.defaults_used + if not any(k in path for k in ["Parameterisation", "Header"]) + } + + +RDF_JSON = URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON") + + +def export_jsonld( + ontology_parser: OntologyParser, input_type: str, input_data: dict, output_path: str +): + input_key = ontology_parser.key_map.get(input_type) + if not input_key: + raise ValueError(f"Invalid input type: {input_type}") + + out_g = Graph() + out_g.namespace_manager = ontology_parser.graph.namespace_manager + + added = 0 + mapped = 0 + + for subject in ontology_parser.graph.subjects(): + raw_path_literal = None + input_path = None + + for predicate, obj in ontology_parser.graph.predicate_objects(subject): + if predicate == input_key: + raw_path_literal = str(obj) + input_path = ontology_parser.parse_key(raw_path_literal) + break + + if not input_path: + continue + mapped += 1 + + value = ParameterMapper.get_value_from_path(input_data, input_path) + + # Always include the mapping path (so you can see what matched) + out_g.add((subject, input_key, Literal(raw_path_literal))) + + # Only add a value triple if we actually found one + if value is not None: + if isinstance(value, (dict, list)): + out_g.add( + (subject, RDF.value, Literal(json.dumps(value), datatype=RDF_JSON)) + ) + else: + out_g.add((subject, RDF.value, Literal(value))) + added += 1 + + print( + f"[jsonld] subjects-with-path: {mapped}, values-found: {added}, triples: {len(out_g)}" + ) + out_g.serialize(destination=output_path, format="json-ld", indent=4) + if __name__ == "__main__": - #ontology_ref = 'https://w3id.org/emmo/domain/battery-model-lithium-ion/latest' - ontology_ref = 'assets/battery-model-lithium-ion.ttl' - input_json_url = 'https://raw.githubusercontent.com/cidetec-energy-storage/cideMOD/main/data/data_Chen_2020/params_tuned_vOCPexpression.json' - output_json_path = 'converted_battery_parameters.json' - defaults_json_path = 'defaults_used.json' - template_url = 'https://raw.githubusercontent.com/BIG-MAP/ModelMapper/main/assets/bpx_template.json' - input_type = 'cidemod' - #output_type = 'bpx' - output_type = 'battmo.m' + # ontology_ref = "https://w3id.org/emmo/domain/battery-model-lithium-ion/latest" + ontology_ref = "assets/battery-model-lithium-ion.ttl" + # input_json = "https://raw.githubusercontent.com/cidetec-energy-storage/cideMOD/main/data/data_Chen_2020/params_tuned_vOCPexpression.json" + input_json = "/tmp/h0b-opt.json" + output_json_path = "converted_battery_parameters.json" + defaults_json_path = "defaults_used.json" + template_url = "https://raw.githubusercontent.com/BIG-MAP/ModelMapper/main/assets/bpx_template.json" + # input_type = "cidemod" + input_type = "battmo.m" + # output_type = 'bpx' + # output_type = "battmo.m" + output_type = "jsonld" # Initialize the OntologyParser ontology_parser = OntologyParser(ontology_ref) - mappings = ontology_parser.get_mappings(input_type, output_type) - print("Mappings:", json.dumps({str(k): str(v) for k, v in mappings.items()}, indent=4)) - # # Load the input JSON file - # input_data = JSONLoader.load(input_json_url) + # Load the input JSON file + input_data = JSONLoader.load(input_json) # print("Input Data:", json.dumps(input_data, indent=4)) - # # Load the template JSON file - # template_data = JSONLoader.load(template_url) - # template_data.pop("Validation", None) # Remove validation if it exists in the template + if output_type == "jsonld": + + output_jsonld_path = "converted_battery_parameters.jsonld" + export_jsonld(ontology_parser, input_type, input_data, output_jsonld_path) + print(f"Wrote JSON-LD to {output_jsonld_path}") + + else: - # # Map the parameters using the mappings from the ontology - # parameter_mapper = ParameterMapper(mappings, template_data, input_json_url, output_type, input_type) - # output_data = parameter_mapper.map_parameters(input_data) - # defaults_used_data = list(parameter_mapper.defaults_used) - # print("Output Data:", json.dumps(output_data, indent=4)) + mappings = ontology_parser.get_mappings(input_type, output_type) + print( + "Mappings:", + json.dumps({str(k): str(v) for k, v in mappings.items()}, indent=4), + ) + + # Load the template JSON file + template_data = JSONLoader.load(template_url) + template_data.pop( + "Validation", None + ) # Remove validation if it exists in the template + + # Map the parameters using the mappings from the ontology + parameter_mapper = ParameterMapper( + mappings, template_data, input_json, output_type, input_type + ) + output_data = parameter_mapper.map_parameters(input_data) + defaults_used_data = list(parameter_mapper.defaults_used) + print("Output Data:", json.dumps(output_data, indent=4)) # # Write the output JSON file # JSONWriter.write(output_data, output_json_path) @@ -243,7 +350,6 @@ def remove_high_level_defaults(self): # # Create the simulation with the experiment # sim = pybamm.Simulation(model, experiment=experiment, parameter_values=parameter_values) - # # Define initial concentration in negative and positive electrodes # parameter_values["Initial concentration in negative electrode [mol.m-3]"] = 0.0279 * parameter_values["Maximum concentration in negative electrode [mol.m-3]"] # parameter_values["Initial concentration in positive electrode [mol.m-3]"] = 0.9084 * parameter_values["Maximum concentration in positive electrode [mol.m-3]"] From 8c9cbc944a5f83b156ea95e56d31b018241cbe06 Mon Sep 17 00:00:00 2001 From: August Johansson Date: Thu, 18 Dec 2025 12:29:59 +0100 Subject: [PATCH 07/28] Fix some battmo bugs in the ttl --- assets/battery-model-lithium-ion.ttl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/battery-model-lithium-ion.ttl b/assets/battery-model-lithium-ion.ttl index bed114e..f4cbc05 100644 --- a/assets/battery-model-lithium-ion.ttl +++ b/assets/battery-model-lithium-ion.ttl @@ -111,7 +111,7 @@ skos:prefLabel "PositiveElectrodeElectronicConductivity"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Positive electrode','Conductivity [S.m-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['positive_electrode','electronic_conductivity','value']"@en ; - :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','ActiveMatrial','electronicConductivity']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['PositiveElectrode','Coating','electronicConductivity']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_47288277_4aed_447e_b659_0c975d031406 @@ -306,7 +306,7 @@ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "the electronic conductivity of the negative electrode"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Negative electrode','Conductivity [S.m-1]']"@en ; :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['negative_electrode','electronic_conductivity','value']"@en ; - :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','ActiveMatrial','electronicConductivity']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['NegativeElectrode','Coating','electronicConductivity']"@en . ### https://w3id.org/emmo/domain/battery-model-lithium-ion#modellib_bfe553c2_a63e_49b6_a209_0855dfc39724 @@ -425,7 +425,7 @@ electrochemistry:electrochemistry_534dd59c_904c_45d9_8550_ae9d2eb6bbc9 :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['simulation','triggers','voltage','lower']"@en ; :bmli_0a5b99ee_995b_4899_a79b_925a4086da37 "['Parameterisation','Cell','Lower voltage cut-off [V]']"@en ; - :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['Control','lowerCutOffVoltage']"@en . + :bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14 "['Control','lowerCutoffVoltage']"@en . electrochemistry:electrochemistry_9c9b80a4_a00b_4b91_8e17_3a7831f2bf2f :bmli_1b718841_5d72_4071_bb71_fc4a754f5e30 "['simulation','initial_state','initial_temperature','value']"@en ; From 729a551d49d96cdfec176dc02012d5cde59368e8 Mon Sep 17 00:00:00 2001 From: August Johansson Date: Thu, 18 Dec 2025 12:30:19 +0100 Subject: [PATCH 08/28] testing but disabling porosity calculation --- test.py | 55 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/test.py b/test.py index 0d0869b..d571c77 100644 --- a/test.py +++ b/test.py @@ -172,7 +172,7 @@ def get_value_from_path(data, keys): return None return data except (KeyError, IndexError, ValueError, TypeError) as e: - print(f"Error accessing key {key} in path {keys}: {e}") + print(f"Warning: accessing key {key} in path {keys}: {e}") return None def set_value_from_path(self, data, keys, value): @@ -227,6 +227,24 @@ def remove_high_level_defaults(self): } +def fix_battmo_porosity(label, input_path, input_data): + if ( + label == "PositiveElectrodeCoatingPorosity" + or label == "NegativeElectrodeCoatingPorosity" + ): + # Get the volume fraction of active material in the positive electrode coating + vf_path = list(input_path) + vf_path[-1] = "volumeFraction" + vf_value = ParameterMapper.get_value_from_path(input_data, vf_path) + if vf_value is None: + ValueError( + f"Could not find volumeFraction for porosity calculcation for {label}" + ) + else: + porosity = 1.0 - vf_value + return porosity + + RDF_JSON = URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON") @@ -257,20 +275,31 @@ def export_jsonld( continue mapped += 1 + # # Get the skos::prefLabel + # for predicate, obj in ontology_parser.graph.predicate_objects(subject): + # if str(predicate) == "http://www.w3.org/2004/02/skos/core#prefLabel": + # label = str(obj) + # break + # else: + # label = "unknown" + + # if input_type == "battmo.m" and "porosity" in input_path: + # value = fix_battmo_porosity(label, input_path, input_data) + + # print(f"[jsonld] Mapping subject {subject} using path {input_path}") + value = ParameterMapper.get_value_from_path(input_data, input_path) + if value is None: + continue - # Always include the mapping path (so you can see what matched) - out_g.add((subject, input_key, Literal(raw_path_literal))) - - # Only add a value triple if we actually found one - if value is not None: - if isinstance(value, (dict, list)): - out_g.add( - (subject, RDF.value, Literal(json.dumps(value), datatype=RDF_JSON)) - ) - else: - out_g.add((subject, RDF.value, Literal(value))) - added += 1 + # Emit the *actual value*, not the path string + if isinstance(value, (dict, list)): + out_g.add( + (subject, RDF.value, Literal(json.dumps(value), datatype=RDF_JSON)) + ) + else: + out_g.add((subject, RDF.value, Literal(value))) + added += 1 print( f"[jsonld] subjects-with-path: {mapped}, values-found: {added}, triples: {len(out_g)}" From 548620d38cb88815054e10ab0347cf0c88149b8f Mon Sep 17 00:00:00 2001 From: August Johansson Date: Thu, 18 Dec 2025 13:11:52 +0100 Subject: [PATCH 09/28] refactor --- jsonld_exporter.py | 189 +++++++++++++++++++++++++++++++++ ontologyparser.py | 68 ++++++++++++ parametermapper.py | 119 +++++++++++++++++++++ test.py | 258 ++------------------------------------------- 4 files changed, 387 insertions(+), 247 deletions(-) create mode 100644 jsonld_exporter.py create mode 100644 ontologyparser.py create mode 100644 parametermapper.py diff --git a/jsonld_exporter.py b/jsonld_exporter.py new file mode 100644 index 0000000..53569ab --- /dev/null +++ b/jsonld_exporter.py @@ -0,0 +1,189 @@ +from parametermapper import ParameterMapper +from rdflib.namespace import SKOS, RDFS, RDF, OWL +from rdflib import BNode +import json + + +def find_unit_class(graph, parameter_class, hasMeasurementUnit): + """ + Return the EMMO unit class (URIRef) for a parameter class, + based on owl:Restriction on hasMeasurementUnit. + """ + for sc in graph.objects(parameter_class, RDFS.subClassOf): + if isinstance(sc, BNode) and (sc, RDF.type, OWL.Restriction) in graph: + if graph.value(sc, OWL.onProperty) == hasMeasurementUnit: + return graph.value(sc, OWL.someValuesFrom) or graph.value( + sc, OWL.allValuesFrom + ) + return None + + +def find_unit_symbol(graph, unit_class, hasSymbolValue): + if unit_class is None: + return None + for sym in graph.objects(unit_class, hasSymbolValue): + return str(sym) + return None + + +def _get_emmo_supertype(g, cls): + """ + Find the first direct rdfs:subClassOf that looks like an EMMO class. + """ + for sup in g.objects(cls, RDFS.subClassOf): + s = str(sup) + if "emmo" in s.lower() and "EMMO_" in s: + return sup + return None + + +def _curie(g, term): + """Return a CURIE if possible, otherwise the full IRI as a string.""" + try: + return g.namespace_manager.normalizeUri(term) + except Exception: + return str(term) + + +def _get_rdfs_label(g, term): + for lbl in g.objects(term, RDFS.label): + return str(lbl) + return None + + +def _find_by_prefLabel(g, label: str): + for s in g.subjects(SKOS.prefLabel, None): + for lbl in g.objects(s, SKOS.prefLabel): + if str(lbl) == label: + return s + return None + + +def _get_prefLabel(g, term): + for lbl in g.objects(term, SKOS.prefLabel): + return str(lbl) + return None + + +def _find_unit_for_class(g, cls, hasMeasurementUnit_uri): + for sc in g.objects(cls, RDFS.subClassOf): + if isinstance(sc, BNode) and (sc, RDF.type, OWL.Restriction) in g: + if g.value(sc, OWL.onProperty) == hasMeasurementUnit_uri: + return g.value(sc, OWL.someValuesFrom) or g.value(sc, OWL.allValuesFrom) + return None + + +def _find_symbol_for_unit(g, unit_cls, hasSymbolValue_uri): + if unit_cls is None: + return None + for sym in g.objects(unit_cls, hasSymbolValue_uri): + return str(sym) + return None + + +def export_jsonld( + ontology_parser, + input_type: str, + input_data: dict, + output_path: str, + cell_id: str = "BattMo", + cell_type: str = "PouchCell", +): + """ + Export mapped parameters as structured JSON-LD using EMMO/Battery context. + """ + g = ontology_parser.graph + input_key = ontology_parser.key_map.get(input_type) + if not input_key: + raise ValueError(f"Invalid input type: {input_type}") + + # Resolve ontology properties by label + hasMeasurementUnit = _find_by_prefLabel(g, "hasMeasurementUnit") + hasNumericalPart = _find_by_prefLabel(g, "hasNumericalPart") + hasNumericalValue = _find_by_prefLabel(g, "hasNumericalValue") + hasSymbolValue = _find_by_prefLabel(g, "hasSymbolValue") + + out = { + "@context": "https://w3id.org/emmo/domain/battery/context", + "@graph": {"@id": cell_id, "@type": cell_type, "hasProperty": []}, + } + + for subject in g.subjects(): + # find battmo.m path + path = None + for p, o in g.predicate_objects(subject): + if p == input_key: + path = ontology_parser.parse_key(str(o)) + break + if not path: + continue + + value = ParameterMapper.get_value_from_path(input_data, path) + if value is None: + continue + + try: + numeric = float(value) + except (TypeError, ValueError): + continue + + # Resolve ontology predicates (once, outside the loop ideally) + hasMeasurementUnit = _find_by_prefLabel(g, "hasMeasurementUnit") + hasSymbolValue = _find_by_prefLabel(g, "hasSymbolValue") + + # --- find unit from ontology --- + unit_class = find_unit_class(g, subject, hasMeasurementUnit) + unit_symbol = find_unit_symbol(g, unit_class, hasSymbolValue) + + unit_label = _get_prefLabel(g, unit_class) + unit_type = _curie(g, unit_class) if unit_class else None + + unit_cls = _find_unit_for_class(g, subject, hasMeasurementUnit) + symbol = _find_symbol_for_unit(g, unit_cls, hasSymbolValue) + unit_label = _get_prefLabel(g, unit_cls) + + # prop_label = _get_prefLabel(g, subject) or str(subject) + + # prop = { + # "@type": prop_label, + # "hasNumericalPart": {"@type": "Real", "hasNumericalValue": numeric}, + # } + + # Use the ontology class IRI/CURIE as the primary type + param_type = _curie(g, subject) + + # Add an EMMO supertype as an additional @type (optional but matches your request) + emmo_type_node = _get_emmo_supertype(g, subject) + types = [param_type] + if emmo_type_node is not None: + types.append(_curie(g, emmo_type_node)) + + # Labels: prefer SKOS prefLabel, fallback to rdfs:label, fallback to CURIE/IRI + label = _get_prefLabel(g, subject) or _get_rdfs_label(g, subject) or param_type + + prop = { + # "@type": types if len(types) > 1 else types[0], + "@type": _curie(g, subject), + # "@id": _curie(g, subject), + # “rdfs label for the description” + # If you want it literally as rdfs:label in the output: + "rdfs:label": label, + "hasNumericalPart": {"@type": "Real", "hasNumericalValue": numeric}, + } + + if unit_class is not None: + prop["hasMeasurementUnit"] = {"@type": unit_type} + if unit_symbol is not None: + prop["hasMeasurementUnit"]["hasSymbolValue"] = unit_symbol + + # if unit_cls is not None: + # prop["hasMeasurementUnit"] = { + # "@type": f"emmo:{unit_label}" if unit_label else str(unit_cls) + # } + # if symbol is not None: + # prop["hasMeasurementUnit"]["hasSymbolValue"] = symbol + + out["@graph"]["hasProperty"].append(prop) + + with open(output_path, "w", encoding="utf-8") as f: + json.dump(out, f, indent=2) diff --git a/ontologyparser.py b/ontologyparser.py new file mode 100644 index 0000000..470c8dd --- /dev/null +++ b/ontologyparser.py @@ -0,0 +1,68 @@ +from rdflib import Graph, URIRef, OWL +from rdflib.namespace import RDF +import ast + +class OntologyParser: + def __init__(self, ontology_ref): + self.graph = Graph() + + if ontology_ref.startswith("http"): + response = requests.get(ontology_ref) + response.raise_for_status() + response_text = response.text + else: + with open(ontology_ref, "r", encoding="utf-8") as f: + response_text = f.read().replace("\r\n", "\n") + # print(response_text) + self.graph.parse(data=response_text, format="ttl") + self.key_map = { + "bpx": URIRef( + "https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_0a5b99ee_995b_4899_a79b_925a4086da37" + ), + "cidemod": URIRef( + "https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_1b718841_5d72_4071_bb71_fc4a754f5e30" + ), + "battmo.m": URIRef( + "https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14" + ), + # 'battmo.jl': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI + } + self._load_imports() + + def _load_imports(self): + # Follow owl:imports and parse them into the same graph + for ont in list(self.graph.subjects(RDF.type, OWL.Ontology)): + for imp in self.graph.objects(ont, OWL.imports): + try: + self.graph.parse(str(imp)) + except Exception as e: + print(f"Warning: failed to load import {imp}: {e}") + + def parse_key(self, key): + try: + return ast.literal_eval(key) + except (ValueError, SyntaxError) as e: + print(f"Error parsing key: {key} - {e}") + return [] + + def get_mappings(self, input_type, output_type): + input_key = self.key_map.get(input_type) + output_key = self.key_map.get(output_type) + if not input_key or not output_key: + raise ValueError( + f"Invalid input or output type: {input_type}, {output_type}" + ) + + mappings = {} + for subject in self.graph.subjects(): + input_value = None + output_value = None + for predicate, obj in self.graph.predicate_objects(subject): + if predicate == input_key: + input_value = self.parse_key(str(obj)) + elif predicate == output_key: + output_value = self.parse_key(str(obj)) + if input_value and output_value: + mappings[tuple(input_value)] = tuple(output_value) + print(f"Mapping added: {tuple(input_value)} -> {tuple(output_value)}") + return mappings diff --git a/parametermapper.py b/parametermapper.py new file mode 100644 index 0000000..ae00c9f --- /dev/null +++ b/parametermapper.py @@ -0,0 +1,119 @@ +class ParameterMapper: + def __init__(self, mappings, template, input_url, output_type, input_type): + self.mappings = mappings + self.template = template + self.input_url = input_url + self.output_type = output_type + self.input_type = input_type + self.defaults_used = set(self.get_all_paths(template)) + + def map_parameters(self, input_data): + output_data = self.template.copy() + for input_key, output_key in self.mappings.items(): + value = get_value_from_path(input_data, input_key) + if value is not None: + if isinstance(value, str): + value = self.replace_variables(value) + if self.input_type == "cidemod" and "kinetic_constant" in input_key: + value = self.scale_kinetic_constant(value) + self.set_value_from_path(output_data, output_key, value) + self.remove_default_from_used(output_key) + self.set_bpx_header(output_data) + self.remove_high_level_defaults() + return output_data + + def replace_variables(self, value): + if isinstance(value, str): + value = re.sub(r"\bx_s\b", "x", value) + value = re.sub(r"\bc_e\b", "x", value) + return value + + def scale_kinetic_constant(self, value): + try: + return value * 1e6 + except TypeError: + print(f"Error scaling kinetic_constant value: {value}") + return value + + def get_all_paths(self, data, path=""): + paths = set() + if isinstance(data, dict): + for key, value in data.items(): + current_path = f"{path}.{key}" if path else key + paths.add(current_path) + paths.update(self.get_all_paths(value, current_path)) + elif isinstance(data, list): + for i, item in enumerate(data): + current_path = f"{path}[{i}]" + paths.add(current_path) + paths.update(self.get_all_paths(item, current_path)) + return paths + + @staticmethod + def get_value_from_path(data, keys): + try: + for key in keys: + if isinstance(key, str): + key = key.strip() + if isinstance(data, dict): + data = data[key] + elif isinstance(data, list): + key = int(key) # Convert key to integer for list index + data = data[key] + else: + return None + return data + except (KeyError, IndexError, ValueError, TypeError) as e: + print(f"Warning: accessing key {key} in path {keys}: {e}") + return None + + def set_value_from_path(self, data, keys, value): + try: + for key in keys[:-1]: + if isinstance(key, str): + key = key.strip() + if isinstance(key, int) or key.isdigit(): + key = int(key) + while len(data) <= key: + data.append({}) + data = data[key] + else: + if key not in data: + data[key] = {} + data = data[key] + final_key = keys[-1] + if isinstance(final_key, str): + final_key = final_key.strip() + if isinstance(final_key, int) or ( + isinstance(final_key, str) and final_key.isdigit() + ): + final_key = int(final_key) + data[final_key] = value + print(f"Set value for path {keys}: {value}") + except (KeyError, IndexError, ValueError, TypeError) as e: + print(f"Error setting value for path {keys}: {e}") + + def remove_default_from_used(self, keys): + path = "Parameterisation" + for key in keys: + if isinstance(key, str): + path += f".{key.strip()}" + elif isinstance(key, int): + path += f"[{key}]" + self.defaults_used.discard(path) + + def set_bpx_header(self, data): + data["Header"] = { + "BPX": 0.1, + "Title": "An autoconverted parameter set using BatteryModelMapper", + "Description": f"This data set was automatically generated from {self.input_url}. Please check carefully.", + "Model": "DFN", + } + data.pop("Validation", None) + + def remove_high_level_defaults(self): + self.defaults_used = { + path + for path in self.defaults_used + if not any(k in path for k in ["Parameterisation", "Header"]) + } diff --git a/test.py b/test.py index d571c77..d8c3dbf 100644 --- a/test.py +++ b/test.py @@ -1,71 +1,13 @@ import json -import ast import requests -import pybamm -from rdflib import Graph, URIRef from jsonschema import validate, ValidationError import re import os from urllib.parse import urlparse from pathlib import Path -from rdflib import Literal -from rdflib.namespace import RDF - - -class OntologyParser: - def __init__(self, ontology_ref): - self.graph = Graph() - - if ontology_ref.startswith("http"): - response = requests.get(ontology_ref) - response.raise_for_status() - response_text = response.text - else: - with open(ontology_ref, "r", encoding="utf-8") as f: - response_text = f.read().replace("\r\n", "\n") - # print(response_text) - self.graph.parse(data=response_text, format="ttl") - self.key_map = { - "bpx": URIRef( - "https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_0a5b99ee_995b_4899_a79b_925a4086da37" - ), - "cidemod": URIRef( - "https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_1b718841_5d72_4071_bb71_fc4a754f5e30" - ), - "battmo.m": URIRef( - "https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_e5e86474_8623_48ea_a1cf_502bdb10aa14" - ), - # 'battmo.jl': URIRef("https://w3id.org/emmo/domain/battery-model-lithium-ion#bmli_2c718841_6d73_5082_bb81_gc5b754f6e40") # Placeholder URI - } - - def parse_key(self, key): - try: - return ast.literal_eval(key) - except (ValueError, SyntaxError) as e: - print(f"Error parsing key: {key} - {e}") - return [] - - def get_mappings(self, input_type, output_type): - input_key = self.key_map.get(input_type) - output_key = self.key_map.get(output_type) - if not input_key or not output_key: - raise ValueError( - f"Invalid input or output type: {input_type}, {output_type}" - ) - - mappings = {} - for subject in self.graph.subjects(): - input_value = None - output_value = None - for predicate, obj in self.graph.predicate_objects(subject): - if predicate == input_key: - input_value = self.parse_key(str(obj)) - elif predicate == output_key: - output_value = self.parse_key(str(obj)) - if input_value and output_value: - mappings[tuple(input_value)] = tuple(output_value) - print(f"Mapping added: {tuple(input_value)} -> {tuple(output_value)}") - return mappings +from ontologyparser import OntologyParser +from parametermapper import ParameterMapper +from jsonld_exporter import export_jsonld class JSONLoader: @@ -106,127 +48,6 @@ def write(data, output_path): json.dump(data, file, indent=4) -class ParameterMapper: - def __init__(self, mappings, template, input_url, output_type, input_type): - self.mappings = mappings - self.template = template - self.input_url = input_url - self.output_type = output_type - self.input_type = input_type - self.defaults_used = set(self.get_all_paths(template)) - - def map_parameters(self, input_data): - output_data = self.template.copy() - for input_key, output_key in self.mappings.items(): - value = get_value_from_path(input_data, input_key) - if value is not None: - if isinstance(value, str): - value = self.replace_variables(value) - if self.input_type == "cidemod" and "kinetic_constant" in input_key: - value = self.scale_kinetic_constant(value) - self.set_value_from_path(output_data, output_key, value) - self.remove_default_from_used(output_key) - self.set_bpx_header(output_data) - self.remove_high_level_defaults() - return output_data - - def replace_variables(self, value): - if isinstance(value, str): - value = re.sub(r"\bx_s\b", "x", value) - value = re.sub(r"\bc_e\b", "x", value) - return value - - def scale_kinetic_constant(self, value): - try: - return value * 1e6 - except TypeError: - print(f"Error scaling kinetic_constant value: {value}") - return value - - def get_all_paths(self, data, path=""): - paths = set() - if isinstance(data, dict): - for key, value in data.items(): - current_path = f"{path}.{key}" if path else key - paths.add(current_path) - paths.update(self.get_all_paths(value, current_path)) - elif isinstance(data, list): - for i, item in enumerate(data): - current_path = f"{path}[{i}]" - paths.add(current_path) - paths.update(self.get_all_paths(item, current_path)) - return paths - - @staticmethod - def get_value_from_path(data, keys): - try: - for key in keys: - if isinstance(key, str): - key = key.strip() - if isinstance(data, dict): - data = data[key] - elif isinstance(data, list): - key = int(key) # Convert key to integer for list index - data = data[key] - else: - return None - return data - except (KeyError, IndexError, ValueError, TypeError) as e: - print(f"Warning: accessing key {key} in path {keys}: {e}") - return None - - def set_value_from_path(self, data, keys, value): - try: - for key in keys[:-1]: - if isinstance(key, str): - key = key.strip() - if isinstance(key, int) or key.isdigit(): - key = int(key) - while len(data) <= key: - data.append({}) - data = data[key] - else: - if key not in data: - data[key] = {} - data = data[key] - final_key = keys[-1] - if isinstance(final_key, str): - final_key = final_key.strip() - if isinstance(final_key, int) or ( - isinstance(final_key, str) and final_key.isdigit() - ): - final_key = int(final_key) - data[final_key] = value - print(f"Set value for path {keys}: {value}") - except (KeyError, IndexError, ValueError, TypeError) as e: - print(f"Error setting value for path {keys}: {e}") - - def remove_default_from_used(self, keys): - path = "Parameterisation" - for key in keys: - if isinstance(key, str): - path += f".{key.strip()}" - elif isinstance(key, int): - path += f"[{key}]" - self.defaults_used.discard(path) - - def set_bpx_header(self, data): - data["Header"] = { - "BPX": 0.1, - "Title": "An autoconverted parameter set using BatteryModelMapper", - "Description": f"This data set was automatically generated from {self.input_url}. Please check carefully.", - "Model": "DFN", - } - data.pop("Validation", None) - - def remove_high_level_defaults(self): - self.defaults_used = { - path - for path in self.defaults_used - if not any(k in path for k in ["Parameterisation", "Header"]) - } - - def fix_battmo_porosity(label, input_path, input_data): if ( label == "PositiveElectrodeCoatingPorosity" @@ -245,68 +66,6 @@ def fix_battmo_porosity(label, input_path, input_data): return porosity -RDF_JSON = URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON") - - -def export_jsonld( - ontology_parser: OntologyParser, input_type: str, input_data: dict, output_path: str -): - input_key = ontology_parser.key_map.get(input_type) - if not input_key: - raise ValueError(f"Invalid input type: {input_type}") - - out_g = Graph() - out_g.namespace_manager = ontology_parser.graph.namespace_manager - - added = 0 - mapped = 0 - - for subject in ontology_parser.graph.subjects(): - raw_path_literal = None - input_path = None - - for predicate, obj in ontology_parser.graph.predicate_objects(subject): - if predicate == input_key: - raw_path_literal = str(obj) - input_path = ontology_parser.parse_key(raw_path_literal) - break - - if not input_path: - continue - mapped += 1 - - # # Get the skos::prefLabel - # for predicate, obj in ontology_parser.graph.predicate_objects(subject): - # if str(predicate) == "http://www.w3.org/2004/02/skos/core#prefLabel": - # label = str(obj) - # break - # else: - # label = "unknown" - - # if input_type == "battmo.m" and "porosity" in input_path: - # value = fix_battmo_porosity(label, input_path, input_data) - - # print(f"[jsonld] Mapping subject {subject} using path {input_path}") - - value = ParameterMapper.get_value_from_path(input_data, input_path) - if value is None: - continue - - # Emit the *actual value*, not the path string - if isinstance(value, (dict, list)): - out_g.add( - (subject, RDF.value, Literal(json.dumps(value), datatype=RDF_JSON)) - ) - else: - out_g.add((subject, RDF.value, Literal(value))) - added += 1 - - print( - f"[jsonld] subjects-with-path: {mapped}, values-found: {added}, triples: {len(out_g)}" - ) - out_g.serialize(destination=output_path, format="json-ld", indent=4) - - if __name__ == "__main__": # ontology_ref = "https://w3id.org/emmo/domain/battery-model-lithium-ion/latest" ontology_ref = "assets/battery-model-lithium-ion.ttl" @@ -330,9 +89,14 @@ def export_jsonld( if output_type == "jsonld": - output_jsonld_path = "converted_battery_parameters.jsonld" - export_jsonld(ontology_parser, input_type, input_data, output_jsonld_path) - print(f"Wrote JSON-LD to {output_jsonld_path}") + export_jsonld( + ontology_parser=ontology_parser, + input_type=input_type, + input_data=input_data, + output_path="file.jsonld", + cell_id="BattMo", + cell_type="PouchCell", + ) else: From dd83bee80052e80380a1f419ebf060b7da0c0fa5 Mon Sep 17 00:00:00 2001 From: August Johansson Date: Thu, 18 Dec 2025 14:36:30 +0100 Subject: [PATCH 10/28] working on units and ocps --- jsonld_exporter.py | 437 +++++++++++++++++++++++++++++++++------------ 1 file changed, 323 insertions(+), 114 deletions(-) diff --git a/jsonld_exporter.py b/jsonld_exporter.py index 53569ab..e60f3d8 100644 --- a/jsonld_exporter.py +++ b/jsonld_exporter.py @@ -1,189 +1,398 @@ -from parametermapper import ParameterMapper -from rdflib.namespace import SKOS, RDFS, RDF, OWL -from rdflib import BNode import json - - -def find_unit_class(graph, parameter_class, hasMeasurementUnit): +from typing import Any, Dict, List, Optional, Set, Union +from rdflib import BNode, URIRef +from rdflib.namespace import RDF, RDFS, OWL, SKOS + +from collections import Counter +from rdflib.namespace import RDF, OWL +from collections import Counter +from rdflib.namespace import RDF, OWL + + +def _is_number_like(v: Any) -> bool: + if isinstance(v, (int, float)) and not isinstance(v, bool): + return True + if isinstance(v, str): + s = v.strip() + if not s: + return False + try: + float(s) + return True + except ValueError: + return False + return False + + +def print_unit_predicate_fillers(g, unit_pred, top=10): + restrictions = list(g.subjects(RDF.type, OWL.Restriction)) + fillers = [] + for r in restrictions: + if g.value(r, OWL.onProperty) == unit_pred: + f = g.value(r, OWL.someValuesFrom) or g.value(r, OWL.allValuesFrom) + if f: + fillers.append(f) + c = Counter(fillers) + print("[units] top fillers for inferred unit_pred:") + for f, n in c.most_common(top): + print(" ", n, f) + + +def infer_unit_predicate(g): """ - Return the EMMO unit class (URIRef) for a parameter class, - based on owl:Restriction on hasMeasurementUnit. + Infer which owl:onProperty is used for measurement units by looking for + restrictions where the filler (someValuesFrom/allValuesFrom) repeats a lot. + Unit classes tend to be reused across many parameters (e.g., UnitOne, Metre, Second). """ - for sc in graph.objects(parameter_class, RDFS.subClassOf): - if isinstance(sc, BNode) and (sc, RDF.type, OWL.Restriction) in graph: - if graph.value(sc, OWL.onProperty) == hasMeasurementUnit: - return graph.value(sc, OWL.someValuesFrom) or graph.value( - sc, OWL.allValuesFrom - ) - return None + restrictions = list(g.subjects(RDF.type, OWL.Restriction)) + if not restrictions: + return None + + # Count (onProperty -> how many times its filler repeats) + onp_to_fillers = {} + for r in restrictions: + onp = g.value(r, OWL.onProperty) + filler = g.value(r, OWL.someValuesFrom) or g.value(r, OWL.allValuesFrom) + if onp is None or filler is None: + continue + onp_to_fillers.setdefault(onp, []).append(filler) + # Score each onProperty by "repetition" of fillers: + # units repeat a lot -> high concentration on a few fillers + scores = {} + for onp, fillers in onp_to_fillers.items(): + c = Counter(fillers) + # sum of squares emphasizes repetition on the same few fillers + scores[onp] = sum(n * n for n in c.values()) -def find_unit_symbol(graph, unit_class, hasSymbolValue): - if unit_class is None: + if not scores: return None - for sym in graph.objects(unit_class, hasSymbolValue): - return str(sym) - return None + best = max(scores.items(), key=lambda kv: kv[1])[0] + return best -def _get_emmo_supertype(g, cls): - """ - Find the first direct rdfs:subClassOf that looks like an EMMO class. - """ - for sup in g.objects(cls, RDFS.subClassOf): - s = str(sup) - if "emmo" in s.lower() and "EMMO_" in s: - return sup - return None + +# ----------------------------- +# Small RDF helpers +# ----------------------------- -def _curie(g, term): - """Return a CURIE if possible, otherwise the full IRI as a string.""" +def _localname(u: URIRef) -> str: + s = str(u) + return s.rsplit("#", 1)[-1].rsplit("/", 1)[-1] + + +def _curie(g, term: URIRef) -> str: + """Return a CURIE if namespace bindings exist, otherwise full IRI string.""" try: return g.namespace_manager.normalizeUri(term) except Exception: return str(term) -def _get_rdfs_label(g, term): - for lbl in g.objects(term, RDFS.label): - return str(lbl) +def _first_literal_str(g, subj: URIRef, pred: URIRef) -> Optional[str]: + for o in g.objects(subj, pred): + return str(o) return None -def _find_by_prefLabel(g, label: str): - for s in g.subjects(SKOS.prefLabel, None): - for lbl in g.objects(s, SKOS.prefLabel): - if str(lbl) == label: - return s - return None +def _label(g, term: URIRef) -> str: + """Prefer skos:prefLabel, then rdfs:label, else CURIE/IRI.""" + return ( + _first_literal_str(g, term, SKOS.prefLabel) + or _first_literal_str(g, term, RDFS.label) + or _curie(g, term) + ) -def _get_prefLabel(g, term): - for lbl in g.objects(term, SKOS.prefLabel): - return str(lbl) +def _find_any_predicate_by_localname(g, candidates: Set[str]) -> Optional[URIRef]: + """ + Find a predicate URI in the graph whose local name matches any candidate. + This avoids relying on skos:prefLabel existing on properties. + """ + for p in set(g.predicates()): + if _localname(p) in candidates: + return p return None -def _find_unit_for_class(g, cls, hasMeasurementUnit_uri): +# ----------------------------- +# JSON path getter (silent) +# ----------------------------- + + +def _get_value_from_path(data: Any, keys: List[Any]) -> Any: + """ + Safely traverse dict/list according to keys. + Returns None if missing/invalid; never prints. + """ + cur = data + try: + for k in keys: + if isinstance(k, str): + k = k.strip() + if isinstance(cur, dict): + cur = cur[k] + elif isinstance(cur, list): + cur = cur[int(k)] + else: + return None + return cur + except (KeyError, IndexError, ValueError, TypeError): + return None + + +# ----------------------------- +# Unit extraction from OWL restrictions +# ----------------------------- + + +def _iter_restrictions(g, cls: URIRef): + """ + Yield blank-node restrictions linked via rdfs:subClassOf or owl:equivalentClass. + """ + # rdfs:subClassOf _:bnode for sc in g.objects(cls, RDFS.subClassOf): if isinstance(sc, BNode) and (sc, RDF.type, OWL.Restriction) in g: - if g.value(sc, OWL.onProperty) == hasMeasurementUnit_uri: - return g.value(sc, OWL.someValuesFrom) or g.value(sc, OWL.allValuesFrom) + yield sc + + # owl:equivalentClass _:bnode + for ec in g.objects(cls, OWL.equivalentClass): + if isinstance(ec, BNode) and (ec, RDF.type, OWL.Restriction) in g: + yield ec + + +def _find_unit_class( + g, parameter_class: URIRef, unit_pred: Optional[URIRef] +) -> Optional[URIRef]: + """ + Look for OWL restriction on unit_pred: + [ a owl:Restriction ; + owl:onProperty unit_pred ; + owl:someValuesFrom UNIT ] or allValuesFrom UNIT + """ + if unit_pred is None: + return None + + for r in _iter_restrictions(g, parameter_class): + onp = g.value(r, OWL.onProperty) + if onp != unit_pred: + continue + unit = g.value(r, OWL.someValuesFrom) or g.value(r, OWL.allValuesFrom) + if isinstance(unit, URIRef): + return unit return None -def _find_symbol_for_unit(g, unit_cls, hasSymbolValue_uri): - if unit_cls is None: +def _find_unit_symbol( + g, unit_class: URIRef, symbol_pred: Optional[URIRef] +) -> Optional[str]: + """ + Try to read unit symbol from the unit class via symbol_pred. + If ontology doesn't model it that way, this returns None. + """ + if symbol_pred is None: return None - for sym in g.objects(unit_cls, hasSymbolValue_uri): - return str(sym) + for o in g.objects(unit_class, symbol_pred): + return str(o) return None +# ----------------------------- +# Main exporter +# ----------------------------- + + def export_jsonld( ontology_parser, input_type: str, - input_data: dict, + input_data: Dict[str, Any], output_path: str, cell_id: str = "BattMo", cell_type: str = "PouchCell", + debug_units: bool = False, ): """ - Export mapped parameters as structured JSON-LD using EMMO/Battery context. + Export mapped parameters as structured JSON-LD: + + { + "@context": "https://w3id.org/emmo/domain/battery/context", + "@graph": { + "@id": "BattMo", + "@type": "PouchCell", + "hasProperty": [ ... ] + } + } + + Each property: + "@type": + "rdfs:label":