Source code for sproclib.unit.reactor.batch.batch_reactor

"""
Batch Reactor Model for SPROCLIB

This module provides a batch reactor model with
reaction kinetics and thermal dynamics.

Author: Thorsten Gressling <gressling@paramus.ai>
License: MIT License
"""

import numpy as np
import logging
from ...base import ProcessModel

[docs] class BatchReactor(ProcessModel): """Batch reactor model with heating/cooling."""
[docs] def __init__( self, V: float = 100.0, # Reactor volume [L] k0: float = 7.2e10, # Pre-exponential factor [1/min] Ea: float = 72750.0, # Activation energy [J/mol] delta_H: float = -52000.0, # Heat of reaction [J/mol] rho: float = 1000.0, # Density [kg/m³] cp: float = 4180.0, # Heat capacity [J/kg·K] U: float = 500.0, # Heat transfer coefficient [W/m²·K] A: float = 5.0, # Heat transfer area [m²] name: str = "BatchReactor" ): """ Initialize batch reactor. Args: V: Reactor volume [L] k0: Pre-exponential factor [1/min] Ea: Activation energy [J/mol] delta_H: Heat of reaction [J/mol] rho: Density [kg/m³] cp: Heat capacity [J/kg·K] U: Heat transfer coefficient [W/m²·K] A: Heat transfer area [m²] name: Model name """ super().__init__(name) self.V = V self.k0 = k0 self.Ea = Ea self.delta_H = delta_H self.rho = rho self.cp = cp self.U = U self.A = A self.parameters = { 'V': V, 'k0': k0, 'Ea': Ea, 'delta_H': delta_H, 'rho': rho, 'cp': cp, 'U': U, 'A': A }
[docs] def reaction_rate(self, CA: float, T: float) -> float: """ Calculate reaction rate using Arrhenius equation. Args: CA: Concentration [mol/L] T: Temperature [K] Returns: Reaction rate [mol/L·min] """ R = 8.314 # Gas constant [J/mol·K] k = self.k0 * np.exp(-self.Ea / (R * T)) return k * CA # First-order reaction
[docs] def dynamics(self, t: float, x: np.ndarray, u: np.ndarray) -> np.ndarray: """ Batch reactor dynamics. State variables: x[0]: Concentration [mol/L] x[1]: Temperature [K] Input variables: u[0]: Jacket temperature [K] Args: t: Time x: [CA, T] u: [Tj] Returns: [dCA/dt, dT/dt] """ CA = max(0.0, x[0]) T = max(250.0, x[1]) Tj = u[0] # Jacket temperature # Reaction rate r = self.reaction_rate(CA, T) # Material balance: dCA/dt = -r dCAdt = -r # Energy balance: dT/dt = (-ΔH*r)/(ρ*cp) + UA(Tj-T)/(ρ*cp*V) heat_generation = (-self.delta_H * r) / (self.rho * self.cp) heat_transfer = (self.U * self.A * (Tj - T)) / (self.rho * self.cp * self.V) dTdt = heat_generation + heat_transfer return np.array([dCAdt, dTdt])
[docs] def steady_state(self, u: np.ndarray) -> np.ndarray: """ Batch reactor doesn't have a traditional steady state. Returns initial conditions for given jacket temperature. Args: u: [Tj] Returns: Initial conditions [CA0, T0] """ # Return typical initial conditions # In practice, this would be the loaded conditions CA0 = 1.0 # Initial concentration [mol/L] T0 = u[0] if len(u) > 0 else 300.0 # Start at jacket temperature return np.array([CA0, T0])
[docs] def calculate_conversion(self, CA: float, CA0: float = 1.0) -> float: """ Calculate conversion based on initial and current concentration. Args: CA: Current concentration [mol/L] CA0: Initial concentration [mol/L] Returns: Conversion fraction """ if CA0 > 0: conversion = (CA0 - CA) / CA0 else: conversion = 0.0 return max(0.0, min(1.0, conversion))
[docs] def batch_time_to_conversion(self, target_conversion: float, CA0: float = 1.0, T_avg: float = 350.0) -> float: """ Estimate time to reach target conversion (isothermal approximation). Args: target_conversion: Target conversion fraction CA0: Initial concentration [mol/L] T_avg: Average temperature [K] Returns: Time to reach conversion [min] """ if target_conversion <= 0 or target_conversion >= 1: return 0.0 # For first-order reaction: CA = CA0 * exp(-k*t) # Conversion X = 1 - CA/CA0 = 1 - exp(-k*t) # t = -ln(1-X) / k R = 8.314 k = self.k0 * np.exp(-self.Ea / (R * T_avg)) if k > 0: time_required = -np.log(1 - target_conversion) / k else: time_required = float('inf') return time_required
[docs] def describe(self) -> dict: """ Introspect metadata for documentation and algorithm querying. Returns: dict: Metadata about the BatchReactor model including algorithms, parameters, equations, and usage information. """ return { 'type': 'BatchReactor', 'description': 'Batch reactor with Arrhenius kinetics and thermal dynamics', 'category': 'reactor', 'algorithms': { 'reaction_kinetics': 'Arrhenius equation: k = k0 * exp(-Ea/RT)', 'material_balance': 'dCA/dt = -k(T)*CA', 'energy_balance': 'dT/dt = (-ΔH*r)/(ρ*cp) + UA(Tj-T)/(ρ*cp*V)', 'batch_time': 't = -ln(1-X) / k for isothermal first-order reaction' }, 'parameters': { 'V': {'value': self.V, 'units': 'L', 'description': 'Reactor volume'}, 'k0': {'value': self.k0, 'units': '1/min', 'description': 'Arrhenius pre-exponential factor'}, 'Ea': {'value': self.Ea, 'units': 'J/mol', 'description': 'Activation energy'}, 'delta_H': {'value': self.delta_H, 'units': 'J/mol', 'description': 'Heat of reaction'}, 'rho': {'value': self.rho, 'units': 'kg/m³', 'description': 'Density'}, 'cp': {'value': self.cp, 'units': 'J/kg·K', 'description': 'Heat capacity'}, 'U': {'value': self.U, 'units': 'W/m²·K', 'description': 'Heat transfer coefficient'}, 'A': {'value': self.A, 'units': 'm²', 'description': 'Heat transfer area'} }, 'state_variables': { 'CA': 'Concentration [mol/L]', 'T': 'Temperature [K]' }, 'inputs': { 'Tj': 'Jacket temperature [K]' }, 'outputs': { 'CA': 'Concentration [mol/L]', 'T': 'Temperature [K]', 'conversion': 'Conversion fraction', 'reaction_rate': 'Reaction rate [mol/L/min]' }, 'valid_ranges': { 'V': {'min': 1.0, 'max': 50000.0, 'units': 'L'}, 'T': {'min': 250.0, 'max': 600.0, 'units': 'K'}, 'CA': {'min': 0.0, 'max': 100.0, 'units': 'mol/L'}, 'conversion': {'min': 0.0, 'max': 0.99, 'units': '-'} }, 'applications': [ 'Batch chemical production', 'Pharmaceutical manufacturing', 'Specialty chemicals', 'Process development', 'Reaction kinetics studies' ], 'limitations': [ 'Perfect mixing assumption', 'Single reaction assumed', 'Constant physical properties', 'No mass transfer limitations', 'Isothermal jacket assumption' ] }