Source code for ogstools.materiallib.core.material

# Copyright (c) 2012-2025, OpenGeoSys Community (http://www.opengeosys.org)
#            Distributed under a Modified BSD License.
#            See accompanying file LICENSE.txt or
#            http://www.opengeosys.org/project/license
#

from __future__ import annotations

import logging
from typing import Any

from ogstools.materiallib.schema.required_properties import (
    required_property_names,
)

from .property import MaterialProperty

logger = logging.getLogger(__name__)


[docs] class Material: """ Represents a single material. - Can be constructed directly from YAML raw data. - Provides access to all properties. - Supports filtering by process schemas or property names. """
[docs] def __init__(self, name: str, raw_data: dict[str, Any]): self.name = name self.raw = raw_data # full YAML (e.g. for debugging or export) self.properties: list[MaterialProperty] = [] self._parse_properties()
def _parse_properties(self) -> None: block = self.raw.get("properties", {}) if not block: logger.debug("Material %s has no properties", self.name) for prop_name, entries in block.items(): for entry in entries if isinstance(entries, list) else [entries]: type_ = entry.get( "type", "Constant" ) # Todo - Error if 'type' not found value = entry.get("value", None) extra = { k: v for k, v in entry.items() if k not in ("type", "value") } prop = MaterialProperty( name=prop_name, type_=type_, value=value, **extra ) self.properties.append(prop) # ----------------------- # Accessors # -----------------------
[docs] def property_names(self) -> list[str]: """ Returns a list of all property names of this material. """ return [p.name for p in self.properties]
# ----------------------- # Filters (dummy for now) # -----------------------
[docs] def filter_process(self, process_schema: dict[str, Any]) -> Material: """ Return a new Material containing only properties required by a given process schema. """ allowed = required_property_names(process_schema) return self.filter_properties(allowed)
[docs] def filter_properties(self, allowed: set[str]) -> Material: """ Return a new Material containing only the properties in 'allowed', preserving all extra fields (e.g. scope, unit). """ filtered_props = [p for p in self.properties if p.name in allowed] logger.debug( "Material %s: filtered %d/%d properties (%s)", self.name, len(filtered_props), len(self.properties), ", ".join(p.name for p in filtered_props), ) # Build a raw_data dict with lists if multiple entries share the same name raw_block: dict[str, list[dict[str, Any]]] = {} for p in filtered_props: entry = {"type": p.type, "value": p.value, **p.extra} raw_block.setdefault(p.name, []).append(entry) filtered_raw = {"name": self.name, "properties": raw_block} # Create a new Material that parses only the filtered_raw return Material(name=self.name, raw_data=filtered_raw)
# ----------------------- # Representation # ----------------------- def __repr__(self) -> str: return ( f"<Material '{self.name}' with {len(self.properties)} properties>" )