Source code for ogstools.ogs6py.media
# 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 typing import Any
from lxml import etree as ET
from ogstools.ogs6py import build_tree
[docs]
class Media(build_tree.BuildTree):
    """
    Class for defining a media material properties."
    """
[docs]
    def __init__(self, tree: ET.ElementTree) -> None:
        self.tree = tree
        self.root = self.tree.getroot()
        self.media = self.populate_tree(self.root, "media", overwrite=True)
        self.properties: dict[str, list[str]] = {
            "AverageMolarMass": [],
            "BishopsSaturationCutoff": ["cutoff_value"],
            "BishopsPowerLaw": ["exponent"],
            "CapillaryPressureRegularizedVanGenuchten": [
                "exponent",
                "p_b",
                "residual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "CapillaryPressureVanGenuchten": [
                "exponent",
                "maximum_capillary_pressurep_b",
                "residual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "ClausiusClapeyron": [
                "critical_pressure",
                "critical_temperature",
                "reference_pressure",
                "reference_temperature",
                "triple_pressure",
                "triple_temperature",
            ],
            "Constant": ["value"],
            "Curve": ["curve", "independent_variable"],
            "DupuitPermeability": ["parameter_name"],
            "EffectiveThermalConductivityPorosityMixing": [],
            "EmbeddedFracturePermeability": [
                "intrinsic_permeability",
                "initial_aperture",
                "mean_frac_distance",
                "threshold_strain",
                "fracture_normal",
                "fracture_rotation_xy",
                "fracture_rotation_yz",
            ],
            "Function": ["value"],
            "Exponential": ["offset", "reference_value"],
            "GasPressureDependentPermeability": [
                "initial_permeability",
                "a1",
                "a2",
                "pressure_threshold",
                "minimum_permeability",
                "maximum_permeability",
            ],
            "IdealGasLaw": [],
            "IdealGasLawBinaryMixture": [],
            "KozenyCarmanModel": ["intitial_permeability", "initial_prosity"],
            "Linear": ["reference_value"],
            "LinearSaturationSwellingStress": [
                "coefficient",
                "reference_saturation",
            ],
            "LinearWaterVapourLatentHeat": [],
            "OrthotropicEmbeddedFracturePermeability": [
                "intrinsic_permeability",
                "mean_frac_distances",
                "threshold_strains",
                "fracture_normals",
                "fracture_rotation_xy",
                "fracture_rotation_yz",
                "jacobian_factor",
            ],
            "Parameter": ["parameter_name"],
            "PermeabilityMohrCoulombFailureIndexModel": [
                "cohesion",
                "fitting_factor",
                "friction_angle",
                "initial_ppermeability",
                "maximum_permeability",
                "reference_permeability",
                "tensile_strength_parameter",
            ],
            "PermeabilityOrthotropicPowerLaw": [
                "exponents",
                "intrinsic_permeabilities",
            ],
            "PorosityFromMassBalance": [
                "initial_porosity",
                "maximal_porosity",
                "minimal_porosity",
            ],
            "RelPermBrooksCorey": [
                "lambda",
                "min_relative_permeabilityresidual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "RelPermBrooksCoreyNonwettingPhase": [
                "lambda",
                "min_relative_permeabilityresidual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "RelPermLiakopoulos": [],
            "RelativePermeabilityNonWettingVanGenuchten": [
                "exponent",
                "minimum_relative_permeability",
                "residual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "RelativePermeabilityUdell": [
                "min_relative_permeability",
                "residual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "RelativePermeabilityUdellNonwettingPhase": [
                "min_relative_permeability",
                "residual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "RelativePermeabilityVanGenuchten": [
                "exponent",
                "minimum_relative_permeability_liquid",
                "residual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "RelativePermeabilityNonWettingPhaseVanGenuchtenMualem": [
                "exponent",
                "min_relative_permeability",
                "residual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "SaturationBrooksCorey": [
                "entry_pressure",
                "lambda",
                "residual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "SaturationDependentSwelling": [
                "exponents",
                "lower_saturation_limit",
                "swelling_pressures",
                "upper_saturation_limit",
            ],
            "SaturationDependentThermalConductivity": ["dry", "wet"],
            "SaturationExponential": [
                "exponent",
                "maximum_capillary_pressure",
                "residual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "SaturationLiakopoulos": [],
            "SaturationWeightedThermalConductivity": [
                "mean_type",
                "dry_thermal_conductivity",
                "wet_thermal_conductivity",
            ],
            "SaturationVanGenuchten": [
                "exponent",
                "p_b",
                "residual_gas_saturation",
                "residual_liquid_saturation",
            ],
            "SoilThermalConductivitySomerton": [
                "dry_thermal_conductivity",
                "wet_thermal_conductivity",
            ],
            "StrainDependentPermeability": [
                "initial_permeability",
                "b1",
                "b2",
                "b3",
                "minimum_permeability",
                "maximum_permeability",
            ],
            "TemperatureDependentDiffusion": [
                "activation_energy",
                "reference_diffusion",
                "reference_temperature",
            ],
            "TransportPorosityFromMassBalance": [
                "initial_porosity",
                "maximal_porosity",
                "minimal_porosity",
            ],
            "VapourDiffusionFEBEX": [],
            "VapourDiffusionPMQ": [],
            "VermaPruessModel": [
                "critical_porosity",
                "exponent",
                "initial_permeability",
                "initial_porosity",
            ],
            "WaterVapourDensity": [],
            "WaterDensityIAPWSIF97Region1": [],
            "WaterVapourLatentHeatWithCriticalTemperature": [],
        }
    def _generate_generic_property(
        self, property_: ET.Element, args: dict[str, Any]
    ) -> None:
        for parameter in self.properties[args["type"]]:
            self.populate_tree(property_, parameter, text=args[parameter])
    def _generate_linear_property(
        self, property_: ET.Element, args: dict[str, Any]
    ) -> None:
        for parameter in self.properties[args["type"]]:
            self.populate_tree(property_, parameter, text=args[parameter])
        for var, param in args["independent_variables"].items():
            ind_var = self.populate_tree(property_, "independent_variable")
            self.populate_tree(ind_var, "variable_name", text=var)
            attributes = ["reference_condition", "slope"]
            for attrib in attributes:
                self.populate_tree(ind_var, attrib, text=str(param[attrib]))
    def _generate_function_property(
        self, property_: ET.Element, args: dict[str, Any]
    ) -> None:
        for parameter in self.properties[args["type"]]:
            value = self.populate_tree(
                property_, parameter, text=args[parameter]
            )
        self.populate_tree(value, "expression", text=args["expression"])
        for dvar in args["dvalues"]:
            dvalue = self.populate_tree(property_, "dvalue")
            self.populate_tree(dvalue, "variable_name", text=dvar)
            self.populate_tree(
                dvalue, "expression", text=args["dvalues"][dvar]["expression"]
            )
    def _generate_exponential_property(
        self, property_: ET.Element, args: dict[str, Any]
    ) -> None:
        for parameter in self.properties[args["type"]]:
            self.populate_tree(property_, parameter, text=args[parameter])
        exponent = self.populate_tree(property_, "exponent")
        self.populate_tree(
            exponent, "variable_name", text=args["exponent"]["variable_name"]
        )
        attributes = ["reference_condition", "factor"]
        for attrib in attributes:
            self.populate_tree(
                exponent, attrib, text=str(args["exponent"][attrib])
            )
    def _build_mpl_tree(self, args: dict) -> ET.Element:
        if "medium_id" not in args:
            args["medium_id"] = "0"
        medium = None
        for entry in self.media.findall("./medium"):
            if entry.get("id") == args["medium_id"]:
                medium = entry
        if medium is None:
            medium = self.populate_tree(
                self.media, "medium", attr={"id": args["medium_id"]}
            )
        if "phase_type" in args:
            phases = self.get_child_tag(medium, "phases")
            if phases is None:
                phases = self.populate_tree(medium, "phases")
            phase = self.get_child_tag_for_type(
                phases, "phase", args["phase_type"]
            )
            if phase is None:
                phase = self.populate_tree(phases, "phase")
                self.populate_tree(phase, "type", text=args["phase_type"])
                if "component_name" in args:
                    components = self.populate_tree(phase, "components")
                    component = self.populate_tree(components, "component")
                    self.populate_tree(
                        component, "name", text=args["component_name"]
                    )
                    properties = self.populate_tree(component, "properties")
                else:
                    properties = self.populate_tree(phase, "properties")
            else:
                if "component_name" in args:
                    components = self.get_child_tag(phase, "components")
                    if components is None:
                        components = self.populate_tree(phase, "components")
                    component = self.get_child_tag_for_type(
                        components,
                        "component",
                        args["component_name"],
                        subtag="name",
                    )
                    if component is None:
                        component = self.populate_tree(components, "component")
                        self.populate_tree(
                            component, "name", text=args["component_name"]
                        )
                    properties = self.populate_tree(
                        component, "properties", overwrite=True
                    )
                else:
                    properties = self.get_child_tag(phase, "properties")
        else:
            properties = self.get_child_tag(medium, "properties")
            if properties is None:
                properties = self.populate_tree(medium, "properties")
        return properties
[docs]
    def add_property(self, **args: Any) -> None:
        """
        Adds a property to medium/phase.
        Parameters
        ----------
        medium_id : `int` or `str`
        phase_type : `str` optional
        component_name : `str` optional
        name : `str`
        type : `str`
        value : `float` or `str`
        exponent : `float` or `str`
        cutoff_value : `float` or `str`
        independent_variable : `str`
        reference_condition : `float` or `str`
        reference_value : `float` or `str`
        slope : `float` or `str`
        parameter_name : `str`
        """
        self._convertargs(args)
        properties = self._build_mpl_tree(args)
        property_ = self.populate_tree(properties, "property")
        base_property_param = ["name", "type"]
        for param in base_property_param:
            self.populate_tree(property_, param, text=args[param])
        try:
            if args["type"] == "Linear":
                self._generate_linear_property(property_, args)
            elif args["type"] == "Exponential":
                self._generate_exponential_property(property_, args)
            elif args["type"] == "Function":
                self._generate_function_property(property_, args)
            else:
                self._generate_generic_property(property_, args)
        except KeyError:
            print("Material property parameters incomplete for")
            if "phase_type" in args:
                print(
                    f"Medium {args['medium_id']}->{args['phase_type']}->{args['name']}[{args['type']}]"
                )
            else:
                print(
                    f"Medium {args['medium_id']}->{args['name']}[{args['type']}]"
                )
 
    