Material Property Access#

This example shows the structured property access introduced for materiallib materials:

  • from_file()

  • material.medium.property(name)

  • material.phase.property(name)

  • material.component.property(name)

  • material_property.parameter(name)

The API mirrors the grouped YAML structure of material definitions and avoids manual searches through flat property lists.

The example also shows how wrapped parameter values with uncertainty metadata are exposed as ParameterValue objects.

from pathlib import Path

import yaml  # type: ignore[import]

import ogstools as ot
from ogstools.materiallib.core.material import Material
from ogstools.materiallib.core.property import ParameterValue

model_dir = ot.definitions.temp_dir("materiallib", "user-guide")

Example material#

We create one small grouped-domain material with:

  • two medium properties,

  • a medium parameter with wrapped uncertainty metadata,

  • a phase property with a plain scalar parameter,

  • a component property with a plain scalar parameter.

porosity = {
    "type": "Constant",
    "value": {
        "base_value": 0.15,
        "distribution": {
            "type": "uniform",
            "lower": 0.10,
            "upper": 0.20,
        },
    },
}

storage = {"type": "Constant", "value": 1.2e-10}

density = {"type": "Constant", "value": 999.1}

molar_mass = {"type": "Constant", "value": 18.01528}

medium_properties = {
    "porosity": porosity,
    "storage": storage,
}

phase_properties = {
    "density": density,
}

component_properties = {
    "molar_mass": molar_mass,
}

material_data = {
    "name": "demo_material",
    "domains": [
        {"domain": "medium", "properties": medium_properties},
        {"domain": "phase", "properties": phase_properties},
        {"domain": "component", "properties": component_properties},
    ],
}

material_file = Path(model_dir) / "demo_material.yml"
material_file.write_text(
    yaml.safe_dump(material_data, sort_keys=False), encoding="utf-8"
)

print(material_file.read_text(encoding="utf-8"))
name: demo_material
domains:
- domain: medium
  properties:
    porosity:
      type: Constant
      value:
        base_value: 0.15
        distribution:
          type: uniform
          lower: 0.1
          upper: 0.2
    storage:
      type: Constant
      value: 1.2e-10
- domain: phase
  properties:
    density:
      type: Constant
      value: 999.1
- domain: component
  properties:
    molar_mass:
      type: Constant
      value: 18.01528

Load the material#

The material is loaded with from_file().

material = Material.from_file(material_file)
print(material)
<Material 'demo_material' with 4 properties>
  porosity (Constant)
  value: ParameterValue(base_value=0.15, distribution=UniformDistribution(lower=0.1, upper=0.2))
  domain: medium
  storage (Constant)
  value: ParameterValue(base_value=1.2e-10, distribution=None)
  domain: medium
  density (Constant)
  value: ParameterValue(base_value=999.1, distribution=None)
  domain: phase
  molar_mass (Constant)
  value: ParameterValue(base_value=18.01528, distribution=None)
  domain: component

Domain-based property navigation#

The new structured navigation follows the top-level material domains: medium, phase, and component. This makes grouped YAML domains directly accessible in Python.

medium_property = material.medium.property("porosity")
storage_property = material.medium.property("storage")
phase_property = material.phase.property("density")
component_property = material.component.property("molar_mass")

print("Medium porosity:", medium_property)
print("Medium storage:", storage_property)
print("Phase density:", phase_property)
print("Component molar mass:", component_property)
Medium porosity: porosity (Constant)
  value: ParameterValue(base_value=0.15, distribution=UniformDistribution(lower=0.1, upper=0.2))
  domain: medium
Medium storage: storage (Constant)
  value: ParameterValue(base_value=1.2e-10, distribution=None)
  domain: medium
Phase density: density (Constant)
  value: ParameterValue(base_value=999.1, distribution=None)
  domain: phase
Component molar mass: molar_mass (Constant)
  value: ParameterValue(base_value=18.01528, distribution=None)
  domain: component

Parameter access#

Parameters can now be accessed explicitly from a property object.

They are exposed uniformly as ParameterValue.

porosity_value = medium_property.parameter("value")
storage_value = storage_property.parameter("value")
phase_density = phase_property.parameter("value")
component_molar_mass = component_property.parameter("value")

print("Porosity parameter:", porosity_value)
print("Storage parameter:", storage_value)
print("Phase density parameter:", phase_density)
print("Component molar mass parameter:", component_molar_mass)
Porosity parameter: ParameterValue(base_value=0.15, distribution=UniformDistribution(lower=0.1, upper=0.2))
Storage parameter: ParameterValue(base_value=1.2e-10, distribution=None)
Phase density parameter: ParameterValue(base_value=999.1, distribution=None)
Component molar mass parameter: ParameterValue(base_value=18.01528, distribution=None)

Wrapped uncertainty values#

Wrapped parameter values are returned as ParameterValue and expose both the deterministic value used for export and the optional distribution object.

assert isinstance(porosity_value, ParameterValue)
assert isinstance(storage_value, ParameterValue)

print("Base value:", porosity_value.base_value)
print("Storage base value:", storage_value.base_value)

if porosity_value.distribution is not None:
    print("Distribution type:", type(porosity_value.distribution).__name__)
    print("Lower bound:", porosity_value.distribution.lower)
    print("Upper bound:", porosity_value.distribution.upper)
Base value: 0.15
Storage base value: 1.2e-10
Distribution type: UniformDistribution
Lower bound: 0.1
Upper bound: 0.2

Total running time of the script: (0 minutes 0.004 seconds)