Skip to content

Biological Components API

pyadm1.components.biological.digester.Digester

Bases: Component

Digester component using ADM1 model.

This component wraps the ADM1 implementation and can be connected to other digesters or components in series/parallel.

Attributes:

feedstock (Feedstock): Feedstock object for substrate management.
V_liq (float): Liquid volume in m³.
V_gas (float): Gas volume in m³.
T_ad (float): Operating temperature in K.
adm1 (ADM1): ADM1 model instance.
simulator (Simulator): Simulator for ADM1.
adm1_state (List[float]): Current ADM1 state vector (37 dimensions).
Q_substrates (List[float]): Substrate feed rates in m³/d.

Example:

>>> feedstock = Feedstock(feeding_freq=48)
>>> digester = Digester("dig1", feedstock, V_liq=2000, V_gas=300)
>>> digester.initialize({"adm1_state": initial_state, "Q_substrates": [15, 10, 0, 0, 0, 0, 0, 0, 0, 0]})
Source code in pyadm1/components/biological/digester.py
class Digester(Component):
    """
    Digester component using ADM1 model.

    This component wraps the ADM1 implementation and can be
    connected to other digesters or components in series/parallel.

    Attributes:

        feedstock (Feedstock): Feedstock object for substrate management.
        V_liq (float): Liquid volume in m³.
        V_gas (float): Gas volume in m³.
        T_ad (float): Operating temperature in K.
        adm1 (ADM1): ADM1 model instance.
        simulator (Simulator): Simulator for ADM1.
        adm1_state (List[float]): Current ADM1 state vector (37 dimensions).
        Q_substrates (List[float]): Substrate feed rates in m³/d.

    Example:

        >>> feedstock = Feedstock(feeding_freq=48)
        >>> digester = Digester("dig1", feedstock, V_liq=2000, V_gas=300)
        >>> digester.initialize({"adm1_state": initial_state, "Q_substrates": [15, 10, 0, 0, 0, 0, 0, 0, 0, 0]})
    """

    def __init__(
        self,
        component_id: str,
        feedstock: Feedstock,
        V_liq: float = 1977.0,
        V_gas: float = 304.0,
        T_ad: float = 308.15,
        name: Optional[str] = None,
    ):
        """
        Initialize digester component.

        Args:
            component_id (str): Unique identifier.
            feedstock (Feedstock): Feedstock object for substrate management.
            V_liq (float): Liquid volume in m³. Defaults to 1977.0.
            V_gas (float): Gas volume in m³. Defaults to 304.0.
            T_ad (float): Operating temperature in K. Defaults to 308.15 (35°C).
            name (Optional[str]): Human-readable name. Defaults to component_id.
        """
        super().__init__(component_id, ComponentType.DIGESTER, name)

        self.feedstock = feedstock
        self.V_liq = V_liq
        self.V_gas = V_gas
        self.T_ad = T_ad

        # Initialize ADM1
        self.adm1 = ADM1(feedstock)
        self.adm1.V_liq = V_liq
        self.adm1._V_gas = V_gas
        self.adm1._T_ad = T_ad

        self.simulator = Simulator(self.adm1)

        # Gas storage attached to this digester (created per-digester)
        storage_id = f"{self.component_id}_storage"
        # create a low-pressure membrane storage sized roughly proportional to V_gas
        # capacity_m3 is in m³ STP; use V_gas as a baseline
        self.gas_storage: GasStorage = GasStorage(
            component_id=storage_id,
            storage_type="membrane",
            capacity_m3=max(50.0, float(self.V_gas)),  # sensible minimum
            p_min_bar=0.95,
            p_max_bar=1.05,
            initial_fill_fraction=0.1,
            name=f"{self.name} Gas Storage",
        )

        # ADM1 state vector (37 dimensions)
        self.adm1_state: List[float] = []

        # Substrate feed rates [m³/d]
        self.Q_substrates: List[float] = [0] * 10

    def initialize(self, initial_state: Optional[Dict[str, Any]] = None) -> None:
        """
        Initialize digester state.

        Args:
            initial_state (Optional[Dict[str, Any]]): Initial state with keys:
                - 'adm1_state': ADM1 state vector (37 dims)
                - 'Q_substrates': Substrate feed rates
                If None, uses default initialization.
        """
        if initial_state is None:
            # Default initialization
            self.adm1_state = [0.01] * 37
        else:
            if "adm1_state" in initial_state:
                self.adm1_state = initial_state["adm1_state"]
            if "Q_substrates" in initial_state:
                self.Q_substrates = initial_state["Q_substrates"]

        self.state = {
            "adm1_state": self.adm1_state,
            "Q_substrates": self.Q_substrates,
            "Q_gas": 0.0,
            "Q_ch4": 0.0,
            "Q_co2": 0.0,
            "pH": 7.0,
            "VFA": 0.0,
            "TAC": 0.0,
        }

        # initialize gas storage (keep separate state namespace)
        try:
            gs_state = None
            if initial_state and "gas_storage" in initial_state:
                gs_state = initial_state["gas_storage"]
            self.gas_storage.initialize(gs_state)
        except Exception as e:
            print(e)
            self.gas_storage.initialize()

        # Mark as initialized
        self._initialized = True

    def step(self, t: float, dt: float, inputs: Dict[str, Any]) -> Dict[str, Any]:
        """
        Perform one simulation time step.

        Args:
            t (float): Current time in days.
            dt (float): Time step in days.
            inputs (Dict[str, Any]): Input data with keys:
                - 'Q_substrates': Fresh substrate feed rates [m³/d]
                - 'Q_in': Influent from previous digester [m³/d]
                - 'state_in': ADM1 state from previous digester (if connected)

        Returns:
            Dict[str, Any]: Output data with keys:
                - 'Q_out': Effluent flow rate [m³/d]
                - 'state_out': ADM1 state vector for next digester
                - 'Q_gas': Biogas production [m³/d]
                - 'Q_ch4': Methane production [m³/d]
                - 'Q_co2': CO2 production [m³/d]
                - 'pH': pH value
                - 'VFA': VFA concentration [g/L]
                - 'TAC': TAC concentration [g CaCO3/L]
        """
        # Get substrate feed or influent from previous stage
        if "Q_substrates" in inputs:
            self.Q_substrates = inputs["Q_substrates"]

        # Create influent stream
        # If connected to previous digester, mix with its effluent
        if "state_in" in inputs and "Q_in" in inputs:
            # TODO: Implement mixing of substrate feed with previous stage effluent
            # For now, just use substrate feed
            pass

        # Update ADM1 influent
        self.adm1.create_influent(self.Q_substrates, int(t / dt))

        # Simulate ADM1
        t_span = [t, t + dt]
        self.adm1_state = self.simulator.simulate_AD_plant(t_span, self.adm1_state)

        # Calculate gas production
        q_gas, q_ch4, q_co2, p_gas = self.adm1.calc_gas(
            self.adm1_state[33],  # pi_Sh2
            self.adm1_state[34],  # pi_Sch4
            self.adm1_state[35],  # pi_Sco2
            self.adm1_state[36],  # pTOTAL
        )

        # Update state
        self.state["adm1_state"] = self.adm1_state
        self.state["Q_gas"] = q_gas
        self.state["Q_ch4"] = q_ch4
        self.state["Q_co2"] = q_co2

        # Calculate process indicators (if available via DLL)
        try:
            self.state["pH"] = ADMstate.calcPHOfADMstate(self.adm1_state)
            self.state["VFA"] = ADMstate.calcVFAOfADMstate(self.adm1_state, "gHAceq/l").Value
            self.state["TAC"] = ADMstate.calcTACOfADMstate(self.adm1_state, "gCaCO3eq/l").Value
        except Exception as e:
            # Fallback if DLL not available
            print(f"Warning: Could not calculate process indicators: {e}")

        # Prepare output
        Q_out = np.sum(self.Q_substrates)

        # --- integrate with attached gas storage ---
        gs_inputs = {
            "Q_gas_in_m3_per_day": q_gas,  # ✓ This is correct - daily gas production
            "Q_gas_out_m3_per_day": 0.0,  # Storage not drained by digester directly
            "vent_to_flare": True,
        }

        gs_outputs = self.gas_storage.step(t=t, dt=dt, inputs=gs_inputs)

        # Store the gas input for potential second-pass access
        self.gas_storage.outputs_data["Q_gas_in_m3_per_day"] = q_gas

        # --- digester outputs ---
        self.outputs_data = {
            "Q_out": Q_out,
            "state_out": self.adm1_state,
            "Q_gas": q_gas,
            "Q_ch4": q_ch4,
            "Q_co2": q_co2,
            "pH": self.state.get("pH", 7.0),
            "VFA": self.state.get("VFA", 0.0),
            "TAC": self.state.get("TAC", 0.0),
            # gas sent to storage
            "Q_gas_to_storage_m3_per_day": q_gas,
            # inline storage diagnostics
            "gas_storage": {
                "component_id": self.gas_storage.component_id,
                "stored_volume_m3": gs_outputs["stored_volume_m3"],
                "pressure_bar": gs_outputs["pressure_bar"],
                "vented_volume_m3": gs_outputs["vented_volume_m3"],
                "Q_gas_supplied_m3_per_day": gs_outputs["Q_gas_supplied_m3_per_day"],
            },
        }

        return self.outputs_data

    def to_dict(self) -> Dict[str, Any]:
        """
        Serialize to dictionary.

        Returns:
            Dict[str, Any]: Component configuration as dictionary.
        """
        return {
            "component_id": self.component_id,
            "component_type": self.component_type.value,
            "name": self.name,
            "V_liq": self.V_liq,
            "V_gas": self.V_gas,
            "T_ad": self.T_ad,
            "inputs": self.inputs,
            "outputs": self.outputs,
            "state": self.state,
        }

    @classmethod
    def from_dict(cls, config: Dict[str, Any], feedstock: Feedstock) -> "Digester":
        """
        Create from dictionary.

        Args:
            config (Dict[str, Any]): Component configuration.
            feedstock (Feedstock): Feedstock object.

        Returns:
            Digester: Initialized digester component.
        """
        digester = cls(
            component_id=config["component_id"],
            feedstock=feedstock,
            V_liq=config.get("V_liq", 1977.0),
            V_gas=config.get("V_gas", 304.0),
            T_ad=config.get("T_ad", 308.15),
            name=config.get("name"),
        )

        digester.inputs = config.get("inputs", [])
        digester.outputs = config.get("outputs", [])

        if "state" in config:
            digester.initialize(config["state"])

        return digester

    def apply_calibration_parameters(self, parameters: dict) -> None:
        """
        Apply calibration parameters to this digester.

        Stores parameters for use during simulation. These override the
        substrate-dependent parameters calculated from feedstock.

        Args:
            parameters: Parameter values as {param_name: value}.

        Example:
            >>> digester.apply_calibration_parameters({
            ...     'k_dis': 0.55,
            ...     'Y_su': 0.105,
            ...     'k_hyd_ch': 11.0
            ... })
        """
        if not hasattr(self, "_calibration_params"):
            self._calibration_params = {}

        self._calibration_params.update(parameters)

        # Also store in ADM1 instance for access during simulation
        self.adm1._calibration_params = self._calibration_params.copy()

        if hasattr(self, "_verbose") and self._verbose:
            print(f"Applied {len(parameters)} calibration parameters to digester '{self.component_id}'")

    def get_calibration_parameters(self) -> dict:
        """
        Get currently applied calibration parameters.

        Returns:
            dict: Current calibration parameters as {param_name: value}.

        Example:
            >>> params = digester.get_calibration_parameters()
            >>> print(params)
            {'k_dis': 0.55, 'Y_su': 0.105}
        """
        if hasattr(self, "_calibration_params"):
            return self._calibration_params.copy()
        return {}

    def clear_calibration_parameters(self) -> None:
        """
        Clear all calibration parameters and revert to default substrate-dependent values.

        Example:
            >>> digester.clear_calibration_parameters()
        """
        if hasattr(self, "_calibration_params"):
            del self._calibration_params

        if hasattr(self.adm1, "_calibration_params"):
            del self.adm1._calibration_params

        if hasattr(self, "_verbose") and self._verbose:
            print(f"Cleared calibration parameters from digester '{self.component_id}'")

Functions

__init__(component_id, feedstock, V_liq=1977.0, V_gas=304.0, T_ad=308.15, name=None)

Initialize digester component.

Parameters:

Name Type Description Default
component_id str

Unique identifier.

required
feedstock Feedstock

Feedstock object for substrate management.

required
V_liq float

Liquid volume in m³. Defaults to 1977.0.

1977.0
V_gas float

Gas volume in m³. Defaults to 304.0.

304.0
T_ad float

Operating temperature in K. Defaults to 308.15 (35°C).

308.15
name Optional[str]

Human-readable name. Defaults to component_id.

None
Source code in pyadm1/components/biological/digester.py
def __init__(
    self,
    component_id: str,
    feedstock: Feedstock,
    V_liq: float = 1977.0,
    V_gas: float = 304.0,
    T_ad: float = 308.15,
    name: Optional[str] = None,
):
    """
    Initialize digester component.

    Args:
        component_id (str): Unique identifier.
        feedstock (Feedstock): Feedstock object for substrate management.
        V_liq (float): Liquid volume in m³. Defaults to 1977.0.
        V_gas (float): Gas volume in m³. Defaults to 304.0.
        T_ad (float): Operating temperature in K. Defaults to 308.15 (35°C).
        name (Optional[str]): Human-readable name. Defaults to component_id.
    """
    super().__init__(component_id, ComponentType.DIGESTER, name)

    self.feedstock = feedstock
    self.V_liq = V_liq
    self.V_gas = V_gas
    self.T_ad = T_ad

    # Initialize ADM1
    self.adm1 = ADM1(feedstock)
    self.adm1.V_liq = V_liq
    self.adm1._V_gas = V_gas
    self.adm1._T_ad = T_ad

    self.simulator = Simulator(self.adm1)

    # Gas storage attached to this digester (created per-digester)
    storage_id = f"{self.component_id}_storage"
    # create a low-pressure membrane storage sized roughly proportional to V_gas
    # capacity_m3 is in m³ STP; use V_gas as a baseline
    self.gas_storage: GasStorage = GasStorage(
        component_id=storage_id,
        storage_type="membrane",
        capacity_m3=max(50.0, float(self.V_gas)),  # sensible minimum
        p_min_bar=0.95,
        p_max_bar=1.05,
        initial_fill_fraction=0.1,
        name=f"{self.name} Gas Storage",
    )

    # ADM1 state vector (37 dimensions)
    self.adm1_state: List[float] = []

    # Substrate feed rates [m³/d]
    self.Q_substrates: List[float] = [0] * 10

apply_calibration_parameters(parameters)

Apply calibration parameters to this digester.

Stores parameters for use during simulation. These override the substrate-dependent parameters calculated from feedstock.

Parameters:

Name Type Description Default
parameters dict

Parameter values as {param_name: value}.

required
Example

digester.apply_calibration_parameters({ ... 'k_dis': 0.55, ... 'Y_su': 0.105, ... 'k_hyd_ch': 11.0 ... })

Source code in pyadm1/components/biological/digester.py
def apply_calibration_parameters(self, parameters: dict) -> None:
    """
    Apply calibration parameters to this digester.

    Stores parameters for use during simulation. These override the
    substrate-dependent parameters calculated from feedstock.

    Args:
        parameters: Parameter values as {param_name: value}.

    Example:
        >>> digester.apply_calibration_parameters({
        ...     'k_dis': 0.55,
        ...     'Y_su': 0.105,
        ...     'k_hyd_ch': 11.0
        ... })
    """
    if not hasattr(self, "_calibration_params"):
        self._calibration_params = {}

    self._calibration_params.update(parameters)

    # Also store in ADM1 instance for access during simulation
    self.adm1._calibration_params = self._calibration_params.copy()

    if hasattr(self, "_verbose") and self._verbose:
        print(f"Applied {len(parameters)} calibration parameters to digester '{self.component_id}'")

clear_calibration_parameters()

Clear all calibration parameters and revert to default substrate-dependent values.

Example

digester.clear_calibration_parameters()

Source code in pyadm1/components/biological/digester.py
def clear_calibration_parameters(self) -> None:
    """
    Clear all calibration parameters and revert to default substrate-dependent values.

    Example:
        >>> digester.clear_calibration_parameters()
    """
    if hasattr(self, "_calibration_params"):
        del self._calibration_params

    if hasattr(self.adm1, "_calibration_params"):
        del self.adm1._calibration_params

    if hasattr(self, "_verbose") and self._verbose:
        print(f"Cleared calibration parameters from digester '{self.component_id}'")

from_dict(config, feedstock) classmethod

Create from dictionary.

Parameters:

Name Type Description Default
config Dict[str, Any]

Component configuration.

required
feedstock Feedstock

Feedstock object.

required

Returns:

Name Type Description
Digester Digester

Initialized digester component.

Source code in pyadm1/components/biological/digester.py
@classmethod
def from_dict(cls, config: Dict[str, Any], feedstock: Feedstock) -> "Digester":
    """
    Create from dictionary.

    Args:
        config (Dict[str, Any]): Component configuration.
        feedstock (Feedstock): Feedstock object.

    Returns:
        Digester: Initialized digester component.
    """
    digester = cls(
        component_id=config["component_id"],
        feedstock=feedstock,
        V_liq=config.get("V_liq", 1977.0),
        V_gas=config.get("V_gas", 304.0),
        T_ad=config.get("T_ad", 308.15),
        name=config.get("name"),
    )

    digester.inputs = config.get("inputs", [])
    digester.outputs = config.get("outputs", [])

    if "state" in config:
        digester.initialize(config["state"])

    return digester

get_calibration_parameters()

Get currently applied calibration parameters.

Returns:

Name Type Description
dict dict

Current calibration parameters as {param_name: value}.

Example

params = digester.get_calibration_parameters() print(params)

Source code in pyadm1/components/biological/digester.py
def get_calibration_parameters(self) -> dict:
    """
    Get currently applied calibration parameters.

    Returns:
        dict: Current calibration parameters as {param_name: value}.

    Example:
        >>> params = digester.get_calibration_parameters()
        >>> print(params)
        {'k_dis': 0.55, 'Y_su': 0.105}
    """
    if hasattr(self, "_calibration_params"):
        return self._calibration_params.copy()
    return {}

initialize(initial_state=None)

Initialize digester state.

Parameters:

Name Type Description Default
initial_state Optional[Dict[str, Any]]

Initial state with keys: - 'adm1_state': ADM1 state vector (37 dims) - 'Q_substrates': Substrate feed rates If None, uses default initialization.

None
Source code in pyadm1/components/biological/digester.py
def initialize(self, initial_state: Optional[Dict[str, Any]] = None) -> None:
    """
    Initialize digester state.

    Args:
        initial_state (Optional[Dict[str, Any]]): Initial state with keys:
            - 'adm1_state': ADM1 state vector (37 dims)
            - 'Q_substrates': Substrate feed rates
            If None, uses default initialization.
    """
    if initial_state is None:
        # Default initialization
        self.adm1_state = [0.01] * 37
    else:
        if "adm1_state" in initial_state:
            self.adm1_state = initial_state["adm1_state"]
        if "Q_substrates" in initial_state:
            self.Q_substrates = initial_state["Q_substrates"]

    self.state = {
        "adm1_state": self.adm1_state,
        "Q_substrates": self.Q_substrates,
        "Q_gas": 0.0,
        "Q_ch4": 0.0,
        "Q_co2": 0.0,
        "pH": 7.0,
        "VFA": 0.0,
        "TAC": 0.0,
    }

    # initialize gas storage (keep separate state namespace)
    try:
        gs_state = None
        if initial_state and "gas_storage" in initial_state:
            gs_state = initial_state["gas_storage"]
        self.gas_storage.initialize(gs_state)
    except Exception as e:
        print(e)
        self.gas_storage.initialize()

    # Mark as initialized
    self._initialized = True

step(t, dt, inputs)

Perform one simulation time step.

Parameters:

Name Type Description Default
t float

Current time in days.

required
dt float

Time step in days.

required
inputs Dict[str, Any]

Input data with keys: - 'Q_substrates': Fresh substrate feed rates [m³/d] - 'Q_in': Influent from previous digester [m³/d] - 'state_in': ADM1 state from previous digester (if connected)

required

Returns:

Type Description
Dict[str, Any]

Dict[str, Any]: Output data with keys: - 'Q_out': Effluent flow rate [m³/d] - 'state_out': ADM1 state vector for next digester - 'Q_gas': Biogas production [m³/d] - 'Q_ch4': Methane production [m³/d] - 'Q_co2': CO2 production [m³/d] - 'pH': pH value - 'VFA': VFA concentration [g/L] - 'TAC': TAC concentration [g CaCO3/L]

Source code in pyadm1/components/biological/digester.py
def step(self, t: float, dt: float, inputs: Dict[str, Any]) -> Dict[str, Any]:
    """
    Perform one simulation time step.

    Args:
        t (float): Current time in days.
        dt (float): Time step in days.
        inputs (Dict[str, Any]): Input data with keys:
            - 'Q_substrates': Fresh substrate feed rates [m³/d]
            - 'Q_in': Influent from previous digester [m³/d]
            - 'state_in': ADM1 state from previous digester (if connected)

    Returns:
        Dict[str, Any]: Output data with keys:
            - 'Q_out': Effluent flow rate [m³/d]
            - 'state_out': ADM1 state vector for next digester
            - 'Q_gas': Biogas production [m³/d]
            - 'Q_ch4': Methane production [m³/d]
            - 'Q_co2': CO2 production [m³/d]
            - 'pH': pH value
            - 'VFA': VFA concentration [g/L]
            - 'TAC': TAC concentration [g CaCO3/L]
    """
    # Get substrate feed or influent from previous stage
    if "Q_substrates" in inputs:
        self.Q_substrates = inputs["Q_substrates"]

    # Create influent stream
    # If connected to previous digester, mix with its effluent
    if "state_in" in inputs and "Q_in" in inputs:
        # TODO: Implement mixing of substrate feed with previous stage effluent
        # For now, just use substrate feed
        pass

    # Update ADM1 influent
    self.adm1.create_influent(self.Q_substrates, int(t / dt))

    # Simulate ADM1
    t_span = [t, t + dt]
    self.adm1_state = self.simulator.simulate_AD_plant(t_span, self.adm1_state)

    # Calculate gas production
    q_gas, q_ch4, q_co2, p_gas = self.adm1.calc_gas(
        self.adm1_state[33],  # pi_Sh2
        self.adm1_state[34],  # pi_Sch4
        self.adm1_state[35],  # pi_Sco2
        self.adm1_state[36],  # pTOTAL
    )

    # Update state
    self.state["adm1_state"] = self.adm1_state
    self.state["Q_gas"] = q_gas
    self.state["Q_ch4"] = q_ch4
    self.state["Q_co2"] = q_co2

    # Calculate process indicators (if available via DLL)
    try:
        self.state["pH"] = ADMstate.calcPHOfADMstate(self.adm1_state)
        self.state["VFA"] = ADMstate.calcVFAOfADMstate(self.adm1_state, "gHAceq/l").Value
        self.state["TAC"] = ADMstate.calcTACOfADMstate(self.adm1_state, "gCaCO3eq/l").Value
    except Exception as e:
        # Fallback if DLL not available
        print(f"Warning: Could not calculate process indicators: {e}")

    # Prepare output
    Q_out = np.sum(self.Q_substrates)

    # --- integrate with attached gas storage ---
    gs_inputs = {
        "Q_gas_in_m3_per_day": q_gas,  # ✓ This is correct - daily gas production
        "Q_gas_out_m3_per_day": 0.0,  # Storage not drained by digester directly
        "vent_to_flare": True,
    }

    gs_outputs = self.gas_storage.step(t=t, dt=dt, inputs=gs_inputs)

    # Store the gas input for potential second-pass access
    self.gas_storage.outputs_data["Q_gas_in_m3_per_day"] = q_gas

    # --- digester outputs ---
    self.outputs_data = {
        "Q_out": Q_out,
        "state_out": self.adm1_state,
        "Q_gas": q_gas,
        "Q_ch4": q_ch4,
        "Q_co2": q_co2,
        "pH": self.state.get("pH", 7.0),
        "VFA": self.state.get("VFA", 0.0),
        "TAC": self.state.get("TAC", 0.0),
        # gas sent to storage
        "Q_gas_to_storage_m3_per_day": q_gas,
        # inline storage diagnostics
        "gas_storage": {
            "component_id": self.gas_storage.component_id,
            "stored_volume_m3": gs_outputs["stored_volume_m3"],
            "pressure_bar": gs_outputs["pressure_bar"],
            "vented_volume_m3": gs_outputs["vented_volume_m3"],
            "Q_gas_supplied_m3_per_day": gs_outputs["Q_gas_supplied_m3_per_day"],
        },
    }

    return self.outputs_data

to_dict()

Serialize to dictionary.

Returns:

Type Description
Dict[str, Any]

Dict[str, Any]: Component configuration as dictionary.

Source code in pyadm1/components/biological/digester.py
def to_dict(self) -> Dict[str, Any]:
    """
    Serialize to dictionary.

    Returns:
        Dict[str, Any]: Component configuration as dictionary.
    """
    return {
        "component_id": self.component_id,
        "component_type": self.component_type.value,
        "name": self.name,
        "V_liq": self.V_liq,
        "V_gas": self.V_gas,
        "T_ad": self.T_ad,
        "inputs": self.inputs,
        "outputs": self.outputs,
        "state": self.state,
    }

pyadm1.components.biological.hydrolysis.Hydrolysis

Bases: Component

Hydrolysis tank component (stub for future implementation).

This component models a separate hydrolysis stage in a multi-stage biogas plant.

Attributes:

Name Type Description
component_id

Unique identifier for the component.

feedstock

Feedstock object for substrate management.

V_liq

Liquid volume of the tank [m³].

T_ad

Operating temperature [K].

name

Optional human-readable name.

Source code in pyadm1/components/biological/hydrolysis.py
class Hydrolysis(Component):
    """
    Hydrolysis tank component (stub for future implementation).

    This component models a separate hydrolysis stage in a multi-stage
    biogas plant.

    Attributes:
        component_id: Unique identifier for the component.
        feedstock: Feedstock object for substrate management.
        V_liq: Liquid volume of the tank [m³].
        T_ad: Operating temperature [K].
        name: Optional human-readable name.
    """

    def __init__(
        self,
        component_id: str,
        feedstock: Feedstock,
        V_liq: float = 500.0,
        T_ad: float = 318.15,
        name: Optional[str] = None,
    ):
        """
        Initialize the Hydrolysis tank.

        Args:
            component_id: Unique identifier.
            feedstock: Feedstock object.
            V_liq: Liquid volume [m³].
            T_ad: Operating temperature [K].
            name: Optional name.
        """
        super().__init__(component_id, ComponentType.DIGESTER, name)
        self.feedstock = feedstock
        self.V_liq = V_liq
        self.T_ad = T_ad

    def initialize(self, initial_state: Optional[Dict[str, Any]] = None) -> None:
        """
        Initialize the component state.

        Args:
            initial_state: Optional dictionary containing initial state values.
        """
        self.state = {}

    def step(self, t: float, dt: float, inputs: Dict[str, Any]) -> Dict[str, Any]:
        """
        Execute one simulation time step.

        Args:
            t: Current simulation time [days].
            dt: Time step size [days].
            inputs: Dictionary of input values from other components.

        Returns:
            Dictionary of output values.
        """
        return {}

    def to_dict(self) -> Dict[str, Any]:
        """
        Serialize the component to a dictionary.

        Returns:
            Dictionary containing component configuration.
        """
        return {
            "component_id": self.component_id,
            "component_type": self.component_type.value,
        }

    @classmethod
    def from_dict(cls, config: Dict[str, Any], feedstock: Feedstock) -> "Hydrolysis":
        """
        Create a Hydrolysis instance from a configuration dictionary.

        Args:
            config: Configuration dictionary.
            feedstock: Feedstock object.

        Returns:
            A new Hydrolysis instance.
        """
        return cls(config["component_id"], feedstock)

Functions

__init__(component_id, feedstock, V_liq=500.0, T_ad=318.15, name=None)

Initialize the Hydrolysis tank.

Parameters:

Name Type Description Default
component_id str

Unique identifier.

required
feedstock Feedstock

Feedstock object.

required
V_liq float

Liquid volume [m³].

500.0
T_ad float

Operating temperature [K].

318.15
name Optional[str]

Optional name.

None
Source code in pyadm1/components/biological/hydrolysis.py
def __init__(
    self,
    component_id: str,
    feedstock: Feedstock,
    V_liq: float = 500.0,
    T_ad: float = 318.15,
    name: Optional[str] = None,
):
    """
    Initialize the Hydrolysis tank.

    Args:
        component_id: Unique identifier.
        feedstock: Feedstock object.
        V_liq: Liquid volume [m³].
        T_ad: Operating temperature [K].
        name: Optional name.
    """
    super().__init__(component_id, ComponentType.DIGESTER, name)
    self.feedstock = feedstock
    self.V_liq = V_liq
    self.T_ad = T_ad

from_dict(config, feedstock) classmethod

Create a Hydrolysis instance from a configuration dictionary.

Parameters:

Name Type Description Default
config Dict[str, Any]

Configuration dictionary.

required
feedstock Feedstock

Feedstock object.

required

Returns:

Type Description
Hydrolysis

A new Hydrolysis instance.

Source code in pyadm1/components/biological/hydrolysis.py
@classmethod
def from_dict(cls, config: Dict[str, Any], feedstock: Feedstock) -> "Hydrolysis":
    """
    Create a Hydrolysis instance from a configuration dictionary.

    Args:
        config: Configuration dictionary.
        feedstock: Feedstock object.

    Returns:
        A new Hydrolysis instance.
    """
    return cls(config["component_id"], feedstock)

initialize(initial_state=None)

Initialize the component state.

Parameters:

Name Type Description Default
initial_state Optional[Dict[str, Any]]

Optional dictionary containing initial state values.

None
Source code in pyadm1/components/biological/hydrolysis.py
def initialize(self, initial_state: Optional[Dict[str, Any]] = None) -> None:
    """
    Initialize the component state.

    Args:
        initial_state: Optional dictionary containing initial state values.
    """
    self.state = {}

step(t, dt, inputs)

Execute one simulation time step.

Parameters:

Name Type Description Default
t float

Current simulation time [days].

required
dt float

Time step size [days].

required
inputs Dict[str, Any]

Dictionary of input values from other components.

required

Returns:

Type Description
Dict[str, Any]

Dictionary of output values.

Source code in pyadm1/components/biological/hydrolysis.py
def step(self, t: float, dt: float, inputs: Dict[str, Any]) -> Dict[str, Any]:
    """
    Execute one simulation time step.

    Args:
        t: Current simulation time [days].
        dt: Time step size [days].
        inputs: Dictionary of input values from other components.

    Returns:
        Dictionary of output values.
    """
    return {}

to_dict()

Serialize the component to a dictionary.

Returns:

Type Description
Dict[str, Any]

Dictionary containing component configuration.

Source code in pyadm1/components/biological/hydrolysis.py
def to_dict(self) -> Dict[str, Any]:
    """
    Serialize the component to a dictionary.

    Returns:
        Dictionary containing component configuration.
    """
    return {
        "component_id": self.component_id,
        "component_type": self.component_type.value,
    }

pyadm1.components.biological.separator.Separator

Bases: Component

Solid-liquid separator component (stub for future implementation).

This component models mechanical separation of digestate into solid and liquid fractions.

Attributes:

Name Type Description
component_id

Unique identifier.

separation_efficiency

Efficiency of solid removal (0-1).

name

Optional name.

Source code in pyadm1/components/biological/separator.py
class Separator(Component):
    """
    Solid-liquid separator component (stub for future implementation).

    This component models mechanical separation of digestate into solid
    and liquid fractions.

    Attributes:
        component_id: Unique identifier.
        separation_efficiency: Efficiency of solid removal (0-1).
        name: Optional name.
    """

    def __init__(
        self,
        component_id: str,
        separation_efficiency: float = 0.95,
        name: Optional[str] = None,
    ):
        """
        Initialize the Separator.

        Args:
            component_id: Unique identifier.
            separation_efficiency: Separation efficiency (default: 0.95).
            name: Optional name.
        """
        super().__init__(component_id, ComponentType.SEPARATOR, name)
        self.separation_efficiency = separation_efficiency

    def initialize(self, initial_state: Optional[Dict[str, Any]] = None) -> None:
        """
        Initialize component state.

        Args:
            initial_state: Optional initial state.
        """
        self.state = {}

    def step(self, t: float, dt: float, inputs: Dict[str, Any]) -> Dict[str, Any]:
        """
        Execute one simulation step.

        Args:
            t: Current time [days].
            dt: Time step [days].
            inputs: Input dictionary.

        Returns:
            Output dictionary.
        """
        return {}

    def to_dict(self) -> Dict[str, Any]:
        """
        Serialize to dictionary.

        Returns:
            Configuration dictionary.
        """
        return {
            "component_id": self.component_id,
            "component_type": self.component_type.value,
        }

    @classmethod
    def from_dict(cls, config: Dict[str, Any]) -> "Separator":
        """
        Create instance from dictionary.

        Args:
            config: Configuration dictionary.

        Returns:
            New Separator instance.
        """
        return cls(config["component_id"])

Functions

__init__(component_id, separation_efficiency=0.95, name=None)

Initialize the Separator.

Parameters:

Name Type Description Default
component_id str

Unique identifier.

required
separation_efficiency float

Separation efficiency (default: 0.95).

0.95
name Optional[str]

Optional name.

None
Source code in pyadm1/components/biological/separator.py
def __init__(
    self,
    component_id: str,
    separation_efficiency: float = 0.95,
    name: Optional[str] = None,
):
    """
    Initialize the Separator.

    Args:
        component_id: Unique identifier.
        separation_efficiency: Separation efficiency (default: 0.95).
        name: Optional name.
    """
    super().__init__(component_id, ComponentType.SEPARATOR, name)
    self.separation_efficiency = separation_efficiency

from_dict(config) classmethod

Create instance from dictionary.

Parameters:

Name Type Description Default
config Dict[str, Any]

Configuration dictionary.

required

Returns:

Type Description
Separator

New Separator instance.

Source code in pyadm1/components/biological/separator.py
@classmethod
def from_dict(cls, config: Dict[str, Any]) -> "Separator":
    """
    Create instance from dictionary.

    Args:
        config: Configuration dictionary.

    Returns:
        New Separator instance.
    """
    return cls(config["component_id"])

initialize(initial_state=None)

Initialize component state.

Parameters:

Name Type Description Default
initial_state Optional[Dict[str, Any]]

Optional initial state.

None
Source code in pyadm1/components/biological/separator.py
def initialize(self, initial_state: Optional[Dict[str, Any]] = None) -> None:
    """
    Initialize component state.

    Args:
        initial_state: Optional initial state.
    """
    self.state = {}

step(t, dt, inputs)

Execute one simulation step.

Parameters:

Name Type Description Default
t float

Current time [days].

required
dt float

Time step [days].

required
inputs Dict[str, Any]

Input dictionary.

required

Returns:

Type Description
Dict[str, Any]

Output dictionary.

Source code in pyadm1/components/biological/separator.py
def step(self, t: float, dt: float, inputs: Dict[str, Any]) -> Dict[str, Any]:
    """
    Execute one simulation step.

    Args:
        t: Current time [days].
        dt: Time step [days].
        inputs: Input dictionary.

    Returns:
        Output dictionary.
    """
    return {}

to_dict()

Serialize to dictionary.

Returns:

Type Description
Dict[str, Any]

Configuration dictionary.

Source code in pyadm1/components/biological/separator.py
def to_dict(self) -> Dict[str, Any]:
    """
    Serialize to dictionary.

    Returns:
        Configuration dictionary.
    """
    return {
        "component_id": self.component_id,
        "component_type": self.component_type.value,
    }