Source code for ogstools.materiallib.core.components
# 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 pathlib import Path
import yaml  # type: ignore[import]
# from ogstools.definitions import MATERIALS_DIR
import ogstools.definitions as defs
from .component import Component
from .material import Material
from .property import MaterialProperty
[docs]
class Components:
[docs]
    def __init__(
        self,
        phase_type: str,
        gas_component: Material,
        liquid_component: Material,
        process: str,
        Diffusion_coefficient: float | None = None,
    ):
        self.phase_type = phase_type
        self.gas_properties: list[MaterialProperty] = gas_component.properties
        self.liquid_properties: list[MaterialProperty] = (
            liquid_component.properties
        )
        self.process = process
        self.gas_component = gas_component
        self.liquid_component = liquid_component
        if self.phase_type == "AqueousLiquid":
            gas_role = "Solute"
            liquid_role = "Solvent"
        elif self.phase_type == "Gas":
            gas_role = "Carrier"
            liquid_role = "Vapour"
        else:
            msg = f"Unsupported phase_type: {self.phase_type}"
            raise ValueError(msg)
        D = (
            Diffusion_coefficient
            if Diffusion_coefficient is not None
            else self.get_binary_diffusion_coefficient(self.phase_type)
        )
        self.gas_component_obj = self._create_component(
            self.gas_component, gas_role, D
        )
        self.liquid_component_obj = self._create_component(
            self.liquid_component, liquid_role, D
        ) 
[docs]
    def get_binary_diffusion_coefficient(self, phase: str) -> float:
        """
        Retrieves the binary diffusion coefficient D [m²/s] for a specific component pair
        in either the liquid or gas phase.
        In the liquid phase, this typically describes a gas (e.g. CO2) diffusing in a solvent
        like water. In the gas phase, it typically describes a vapor (e.g. H2O) diffusing in a
        carrier gas like CO₂.
        Parameters:
            phase (str): Either "liquid" or "gas". Indicates the phase in which diffusion
                        occurs.
        Returns:
            float: Binary diffusion coefficient in [m²/s].
        Raises:
            ValueError: If the component pair is not found.
        """
        if phase == "AqueousLiquid":
            # Solute (gas component) diffuses in solvent (liquid component)
            solvent = self.liquid_component.name
            solute = self.gas_component.name
        elif phase == "Gas":
            # Solute (liquid component) evaporates into solvent (gas component)
            solvent = self.gas_component.name
            solute = self.liquid_component.name
        else:
            msg = f"Invalid phase '{phase}'. Must be 'AqueousLiquid' or 'Gas'."
            raise ValueError(msg)
        file_path = Path(defs.MATERIALS_DIR) / "diffusion_coefficients.yml"
        with file_path.open() as f:
            data = yaml.safe_load(f)
        try:
            return float(data[phase][solvent][solute])
        except KeyError:
            pass
        try:
            return float(data[phase][solute][solvent])
        except KeyError as err:
            msg = (
                f"No {phase}-phase diffusion coefficient found for the pair "
                f"'{solvent} / {solute}' in {file_path}"
            )
            raise ValueError(msg) from err 
    def _create_component(
        self, material: Material, role: str, D: float
    ) -> Component:
        return Component(
            material,
            self.phase_type,
            role,
            self.process,
            diffusion_coefficient=D,
        )
    # -----------------------
    # Representation
    # -----------------------
    def __repr__(self) -> str:
        lines = [f"<Components for phase '{self.phase_type}'>"]
        for comp in [self.gas_component_obj, self.liquid_component_obj]:
            for line in repr(comp).splitlines():
                lines.append("  " + line)
        return "\n".join(lines)