From da1cd322aadd9d517dff06821a2e2b8f5effb0bc Mon Sep 17 00:00:00 2001 From: daklauss Date: Tue, 25 Mar 2025 13:23:10 +0100 Subject: [PATCH 01/13] Fix cipipeline so ruff only works once --- .github/workflows/ruff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index 9e78eb7..a64669d 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -1,5 +1,5 @@ name: Ruff -on: [ push, pull_request ] +on: [ push ] jobs: ruff: runs-on: ubuntu-latest From e9d5f8d7a152eb8bed3707dc8b8b534c1f2beda2 Mon Sep 17 00:00:00 2001 From: daklauss Date: Tue, 25 Mar 2025 13:31:51 +0100 Subject: [PATCH 02/13] Add preview=true option --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0b02cfd..99dd00c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,6 +72,6 @@ line-length = 88 indent-width = 4 [tool.ruff.lint] -# preview = true +preview = true select = ["E", "F", "W", "D"] ignore = ["F401", "D212", "D100"] From d61c130abf039c1d5fe7b9d284f4aaaa96c40224 Mon Sep 17 00:00:00 2001 From: daklauss Date: Tue, 25 Mar 2025 13:55:35 +0100 Subject: [PATCH 03/13] Add ruff github action+fix --- .github/workflows/ruff.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index a64669d..ba002db 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -1,17 +1,10 @@ name: Ruff -on: [ push ] +on: [ push, pull_request ] jobs: ruff: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Install Python - uses: actions/setup-python@v5 + - uses: astral-sh/ruff-action@v3 with: - python-version: "3.11" - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install ruff - - name: Run Ruff - run: ruff check --output-format=github . + args: check --output-format=github \ No newline at end of file From 7fce1d7f5834257dad3f2c9421aecc2725db4ffd Mon Sep 17 00:00:00 2001 From: daklauss Date: Tue, 25 Mar 2025 14:32:02 +0100 Subject: [PATCH 04/13] Add pre-commit-config.yaml --- .pre-commit-config.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..1a16f59 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +repos: +- repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.11.2 + hooks: + # Run the linter. + - id: ruff + # Run the formatter. + - id: ruff-format \ No newline at end of file From 03659511440770848657dfa18844b5eba0dd752e Mon Sep 17 00:00:00 2001 From: daklauss Date: Tue, 25 Mar 2025 14:36:47 +0100 Subject: [PATCH 05/13] Ignore rule D203 to fix warning of inconsistent rules --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 99dd00c..2654e76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,4 +74,4 @@ indent-width = 4 [tool.ruff.lint] preview = true select = ["E", "F", "W", "D"] -ignore = ["F401", "D212", "D100"] +ignore = ["F401", "D212", "D203", "D100"] From daeb057ec6ffe116601dea8df3d02dd9a382b5d6 Mon Sep 17 00:00:00 2001 From: daklauss Date: Wed, 26 Mar 2025 10:18:11 +0100 Subject: [PATCH 06/13] Fix Formating.... --- CADETPythonSimulator/__init__.py | 1 + CADETPythonSimulator/componentsystem.py | 57 +- CADETPythonSimulator/coupling_interface.py | 13 +- CADETPythonSimulator/distribution_base.py | 36 +- CADETPythonSimulator/residual.py | 62 ++- CADETPythonSimulator/solver.py | 66 +-- CADETPythonSimulator/state.py | 52 +- CADETPythonSimulator/system.py | 99 ++-- CADETPythonSimulator/unit_operation.py | 607 +++++++++------------ CADETPythonSimulator/viscosity.py | 35 +- tests/test_distribution.py | 28 +- tests/test_field.py | 6 + tests/test_rejection.py | 26 +- tests/test_residual.py | 149 ++--- tests/test_simulation.py | 37 +- tests/test_solver.py | 283 +++++----- tests/test_state.py | 449 +++++++-------- tests/test_system.py | 237 +++++--- tests/test_unit_operation.py | 339 +++++------- tests/test_viscosity.py | 42 +- 20 files changed, 1161 insertions(+), 1463 deletions(-) diff --git a/CADETPythonSimulator/__init__.py b/CADETPythonSimulator/__init__.py index d0bf1da..9bf3f5a 100644 --- a/CADETPythonSimulator/__init__.py +++ b/CADETPythonSimulator/__init__.py @@ -1,3 +1,4 @@ """Version information.""" + name = "CADET-Python-Simulator" __version__ = "0.0.1" diff --git a/CADETPythonSimulator/componentsystem.py b/CADETPythonSimulator/componentsystem.py index 95491f1..947686a 100644 --- a/CADETPythonSimulator/componentsystem.py +++ b/CADETPythonSimulator/componentsystem.py @@ -81,16 +81,18 @@ class CPSComponent(Component): """ - def __init__(self, - name=None, - species=None, - charge=None, - molecular_weight=None, - density=None, - molecular_volume=None, - viscosity=None, - pure_density=None, - specific_cake_resistance=None): + def __init__( + self, + name=None, + species=None, + charge=None, + molecular_weight=None, + density=None, + molecular_volume=None, + viscosity=None, + pure_density=None, + specific_cake_resistance=None, + ): """Construct CPSComponent.""" self.name = name self._species = [] @@ -104,7 +106,7 @@ def __init__(self, molecular_volume, viscosity, pure_density, - specific_cake_resistance + specific_cake_resistance, ) elif isinstance(species, str): self.add_species( @@ -115,7 +117,7 @@ def __init__(self, molecular_volume, viscosity, pure_density, - specific_cake_resistance + specific_cake_resistance, ) elif isinstance(species, list): if charge is None: @@ -141,7 +143,7 @@ def __init__(self, molecular_volume[i], viscosity[i], pure_density[i], - specific_cake_resistance[i] + specific_cake_resistance[i], ) else: raise CADETPythonSimError("Could not determine number of species") @@ -182,6 +184,7 @@ def specific_cake_resistance(self): """List of float or None: specific cake resistance of the subspecies.""" return [spec.specific_cake_resistance for spec in self.species] + class CPSComponentSystem(ComponentSystem): """ Component System Class. @@ -228,16 +231,16 @@ class CPSComponentSystem(ComponentSystem): """ def __init__( - self, - components=None, - name=None, - charges=None, - molecular_weights=None, - densities=None, - molecular_volume=None, - viscosities=None, - specific_cake_resistances=None - ): + self, + components=None, + name=None, + charges=None, + molecular_weights=None, + densities=None, + molecular_volume=None, + viscosities=None, + specific_cake_resistances=None, + ): """ Initialize the ComponentSystem object. @@ -295,7 +298,6 @@ def __init__( if specific_cake_resistances is None: specific_cake_resistances = n_comp * [None] - for i, comp in enumerate(components): self.add_component( comp, @@ -304,7 +306,7 @@ def __init__( density=densities[i], molecular_volume=molecular_volume[i], viscosity=viscosities[i], - specific_cake_resistance=specific_cake_resistances[i] + specific_cake_resistance=specific_cake_resistances[i], ) @wraps(CPSComponent.__init__) @@ -327,8 +329,7 @@ def add_component(self, component, *args, **kwargs): if component.name in self.names: raise CADETPythonSimError( - f"Component '{component.name}' " - "already exists in ComponentSystem." + f"Component '{component.name}' already exists in ComponentSystem." ) self._components.append(component) @@ -356,7 +357,7 @@ def viscosities(self): """list: List of species viscosity.""" viscosities = [] for comp in self.components: - viscosities +=comp.viscosity + viscosities += comp.viscosity return viscosities diff --git a/CADETPythonSimulator/coupling_interface.py b/CADETPythonSimulator/coupling_interface.py index 9193edc..157fbde 100644 --- a/CADETPythonSimulator/coupling_interface.py +++ b/CADETPythonSimulator/coupling_interface.py @@ -10,18 +10,19 @@ class CouplingInterface(abc.ABC): def get_coupled_state( self, origin_list: list[(dict, float)], - state: str - ) -> np.ndarray: + state: str, + ) -> np.ndarray: """Calculate new state for destination_unit.""" class WeightedAverageCoupling(CouplingInterface): """Implements the Coupling Interface for average Coupling.""" - def get_coupled_state(self, - origin_list: list[(dict, float)], - state: str - ) -> np.ndarray: + def get_coupled_state( + self, + origin_list: list[(dict, float)], + state: str, + ) -> np.ndarray: """Calculate new state for destination_unit with average Coupling.""" ret = np.zeros(origin_list[0][0][state].shape) rate_tot = 0 diff --git a/CADETPythonSimulator/distribution_base.py b/CADETPythonSimulator/distribution_base.py index 01d7774..83d6762 100644 --- a/CADETPythonSimulator/distribution_base.py +++ b/CADETPythonSimulator/distribution_base.py @@ -3,13 +3,15 @@ from CADETPythonSimulator.componentsystem import CPSComponentSystem from CADETPythonSimulator.exception import CADETPythonSimError + class DistributionBase: """Small wrapper class for implementing Distributions for Boundary Conditions.""" - def get_distribution(t: float, section_nr: int)->np.ndarray: + def get_distribution(t: float, section_nr: int) -> np.ndarray: """Abtract class to call.""" pass + class ConstantVolumeDistribution(DistributionBase): """Implements DistributionBase for a Constant Volume Distribution.""" @@ -29,26 +31,19 @@ def __init__(self, component_system: CPSComponentSystem, c: npt.ArrayLike): n = [i for i in self.c] m = [ - n_i * self.component_system.molecular_weights[i] - for i, n_i in enumerate(n) - ] - V = [ - m_i / self.component_system.densities[i] - for i, m_i in enumerate(m) + n_i * self.component_system.molecular_weights[i] for i, n_i in enumerate(n) ] + V = [m_i / self.component_system.densities[i] for i, m_i in enumerate(m)] V_solvent = 1 - sum(V) - if V_solvent<0: + if V_solvent < 0: raise CADETPythonSimError( "Last species Volume is negative. Misconfigured Simulation" - ) + ) V.append(V_solvent) - self.V_dist = [ - i / sum(V) - for i in V - ] + self.V_dist = [i / sum(V) for i in V] def get_distribution(self, t, sec) -> list[float]: """Return Constant Volume Distribution.""" @@ -72,27 +67,20 @@ def __init__(self, component_system: CPSComponentSystem, c: npt.ArrayLike): self.component_system = component_system n = [i for i in c] - m = [ - n_i * component_system.molecular_weights[i] - for i, n_i in enumerate(n) - ] - V = [ - m_i / component_system.densities[i] - for i, m_i in enumerate(m) - ] + m = [n_i * component_system.molecular_weights[i] for i, n_i in enumerate(n)] + V = [m_i / component_system.densities[i] for i, m_i in enumerate(m)] V_solvent = 1 - sum(V) - if V_solvent<0: + if V_solvent < 0: raise CADETPythonSimError( "Last species Volume is negative. Misconfigured Simulation" - ) + ) m_solvent = component_system.densities[-1] * V_solvent n_solvent = m_solvent / component_system.molecular_weights[-1] self.c = [*c, n_solvent] - def get_distribution(self, t, sec) -> list[float]: """Return Constant Concentrations.""" return self.c diff --git a/CADETPythonSimulator/residual.py b/CADETPythonSimulator/residual.py index bcb97a2..68a1b96 100644 --- a/CADETPythonSimulator/residual.py +++ b/CADETPythonSimulator/residual.py @@ -6,11 +6,8 @@ def calculate_residual_volume_cstr( - V: float, - V_dot: float, - Q_in: float, - Q_out: float - ) -> float: + V: float, V_dot: float, Q_in: float, Q_out: float +) -> float: """ Calculate the residual equations of the volume of a CSTR. @@ -36,15 +33,16 @@ def calculate_residual_volume_cstr( return V_dot - Q_in + Q_out + def calculate_residual_concentration_cstr( - c: np.ndarray, - c_dot: np.ndarray, - V: float, - V_dot: float, - Q_in: float, - Q_out: float, - c_in: np.ndarray - ) -> np.ndarray: + c: np.ndarray, + c_dot: np.ndarray, + V: float, + V_dot: float, + Q_in: float, + Q_out: float, + c_in: np.ndarray, +) -> np.ndarray: """ Calculate the residual equations of the concentration of a CSTR. @@ -71,20 +69,22 @@ def calculate_residual_concentration_cstr( return c_dot * V + V_dot * c - Q_in * c_in + Q_out * c + def calculate_residual_visc_cstr(): """Calculate the residual of the Viscosity equation of the CSTR.""" warnings.warn("Viscosity of CSTR not yet implemented") return 0 + def calculate_residual_cake_vol_def( - V: float, - rejection: np.ndarray, - densities: np.ndarray, - molecular_weights: np.ndarray, - c_in: np.ndarray, - V_C: float - ) -> float: + V: float, + rejection: np.ndarray, + densities: np.ndarray, + molecular_weights: np.ndarray, + c_in: np.ndarray, + V_C: float, +) -> float: """ Residual equation for the Cake Volume. @@ -106,15 +106,16 @@ def calculate_residual_cake_vol_def( """ return -V_C + V * np.sum(rejection * c_in * molecular_weights / densities) + def calculate_residual_press_easy_def( - V_dot_Perm: float, - V_C: float, - deltap: float, - A: float, - mu: float, - Rm: float, - alpha: float - ) -> float: + V_dot_Perm: float, + V_C: float, + deltap: float, + A: float, + mu: float, + Rm: float, + alpha: float, +) -> float: """ Calculate the residual equations. @@ -139,9 +140,10 @@ def calculate_residual_press_easy_def( Specific cake resistance """ - hyd_resistance = (Rm + alpha*V_C/A) * mu + hyd_resistance = (Rm + alpha * V_C / A) * mu + + return deltap * A - V_dot_Perm * hyd_resistance - return deltap * A - V_dot_Perm* hyd_resistance def calculate_residual_visc_def(): """Calculate the residual of the Viscosity equation of the CSTR.""" diff --git a/CADETPythonSimulator/solver.py b/CADETPythonSimulator/solver.py index bd0b495..389eefb 100644 --- a/CADETPythonSimulator/solver.py +++ b/CADETPythonSimulator/solver.py @@ -40,7 +40,7 @@ def _setup_sections(self, sections): previous_end = section.end self.sections = sections - def initialize_solver(self, solver: str = 'ida') -> NoReturn: + def initialize_solver(self, solver: str = "ida") -> NoReturn: """ Initialize solver. @@ -50,7 +50,7 @@ def initialize_solver(self, solver: str = 'ida') -> NoReturn: Solver to use for integration. The default is `ida`. """ - if solver not in ['ida']: + if solver not in ["ida"]: raise ValueError(f"{solver} is not a supported solver.") self.solver = dae(solver, self._compute_residual) @@ -66,12 +66,8 @@ def system(self, system: SystemBase) -> NoReturn: self._system = system def _compute_residual( - self, - t: float, - y: np.ndarray, - y_dot: np.ndarray, - r: np.ndarray - ) -> NoReturn: + self, t: float, y: np.ndarray, y_dot: np.ndarray, r: np.ndarray + ) -> NoReturn: """ Compute residual of the system. @@ -106,19 +102,19 @@ def initialize_solution_recorder(self) -> NoReturn: for state_name, state in unit.states.items(): self.unit_solutions[unit.name][state_name]: dict[str, dict] = {} for entry, dim in state.entries.items(): - self.unit_solutions[unit.name][state_name][entry]:\ - dict[str, np.ndarray] = {} - self.unit_solutions[unit.name][state_name][entry]['values'] =\ + self.unit_solutions[unit.name][state_name][entry]: dict[ + str, np.ndarray + ] = {} + self.unit_solutions[unit.name][state_name][entry]["values"] = ( np.empty((0, dim)) - self.unit_solutions[unit.name][state_name][entry]['derivatives'] =\ + ) + self.unit_solutions[unit.name][state_name][entry]["derivatives"] = ( np.empty((0, dim)) + ) def write_solution( - self, - times: np.ndarray, - y_history: np.ndarray, - y_dot_history: np.ndarray - ) -> NoReturn: + self, times: np.ndarray, y_history: np.ndarray, y_dot_history: np.ndarray + ) -> NoReturn: """ Update the solution recorder for each unit with the current state. @@ -146,9 +142,9 @@ def write_solution( ydot = y_dot_history[:, it:itp] sol_tuple["values"] = np.concatenate((sol_tuple["values"], y)) - sol_tuple["derivatives"] = np.concatenate(( - sol_tuple["derivatives"], ydot - )) + sol_tuple["derivatives"] = np.concatenate( + (sol_tuple["derivatives"], ydot) + ) it = itp self.time_solutions = np.concatenate((self.time_solutions, times)) @@ -166,11 +162,7 @@ def initialize_system(self): """Initialize System.""" self.system.initialize_initial_values() - def solve_section( - self, - section: Dict, - last_section=False, - ) -> NoReturn: + def solve_section(self, section: Dict, last_section=False) -> NoReturn: """ Solve a time section of the differential-algebraic equation system. @@ -187,9 +179,7 @@ def solve_section( """ self._update_unit_operation_parameters( - section.start, - section.end, - section.section_states, + section.start, section.end, section.section_states ) self._system.update_system_connectivity(section.connections) self._system.initialize_initial_values(section.start) @@ -198,9 +188,7 @@ def solve_section( y_initial = self._system.y y_initial_dot = self._system.y_dot - output = self.solver.solve( - section_solution_times, y_initial, y_initial_dot - ) + output = self.solver.solve(section_solution_times, y_initial, y_initial_dot) y_history = output.values.y y_dot_history = output.values.ydot @@ -236,14 +224,13 @@ def get_section_solution_times(self, section: Dict) -> np.ndarray: return np.arange(start, end, time_resolution) def _update_unit_operation_parameters( - self, - start: float, - end: float, - unit_operation_parameters: dict[ - UnitOperationBase | str, - dict[str, npt.ArrayLike] - ] - ) -> np.ndarray: + self, + start: float, + end: float, + unit_operation_parameters: dict[ + UnitOperationBase | str, dict[str, npt.ArrayLike] + ], + ) -> np.ndarray: """ Update time dependent unit operation parameters. @@ -268,4 +255,3 @@ def _update_unit_operation_parameters( raise CADETPythonSimError(f"Unit {unit} is not Part of the System.") unit.update_parameters(start, end, parameters) - diff --git a/CADETPythonSimulator/state.py b/CADETPythonSimulator/state.py index caaca33..984ef86 100644 --- a/CADETPythonSimulator/state.py +++ b/CADETPythonSimulator/state.py @@ -31,16 +31,16 @@ class State(Structure): """ name = String() - s = SizedNdArray(size='shape') + s = SizedNdArray(size="shape") def __init__( - self, - name: str, - dimensions: dict[str, int], - entries: dict[str, int], - n_inlet_ports: int = 0, - n_outlet_ports: int = 0, - ) -> NoReturn: + self, + name: str, + dimensions: dict[str, int], + entries: dict[str, int], + n_inlet_ports: int = 0, + n_outlet_ports: int = 0, + ) -> NoReturn: """Init a state.""" self.name = name self.dimensions = dimensions @@ -89,7 +89,7 @@ def shape(self) -> tuple[int, ...]: """Tuple of int: Return the complete shape of the state array.""" shape = self.dimension_shape + (self.n_entries,) if isinstance(shape, int): - shape = (shape, ) + shape = (shape,) return shape @property @@ -166,10 +166,8 @@ def validate_coupling_structure(self, coupling_structure: dict[str, int]) -> boo return flag def set_inlet_port_state( - self, - inlet_port_state: dict[str, np.ndarray], - port_index: int - ) -> NoReturn: + self, inlet_port_state: dict[str, np.ndarray], port_index: int + ) -> NoReturn: """ Set the state for a specified inlet port. @@ -211,10 +209,7 @@ def set_inlet_port_state( for component, entry in inlet_port_state.items(): s_split[component][slice_tuple] = entry - def get_outlet_port_state( - self, - port_index: int - ) -> dict[str, np.ndarray]: + def get_outlet_port_state(self, port_index: int) -> dict[str, np.ndarray]: """ Retrieve the state for a specified outlet port. @@ -287,7 +282,7 @@ def __getitem__(self, entry) -> np.ndarray: try: return self.s_split[entry] except KeyError: - raise KeyError('Not a valid state.') + raise KeyError("Not a valid state.") def __setitem__(self, entry, value: np.ndarray) -> None: """ @@ -309,7 +304,7 @@ def __setitem__(self, entry, value: np.ndarray) -> None: """ if entry not in self.entries: - raise KeyError('Not a valid state.') + raise KeyError("Not a valid state.") self.s_split[entry][:] = value @@ -341,14 +336,15 @@ def __repr__(self) -> str: # %% + def state_factory( - instance: Any, - name: str, - dimensions: tuple[int], - entries: dict[str, int | str], - n_inlet_ports: int | str = 0, - n_outlet_ports: int | str = 0, - ) -> State: + instance: Any, + name: str, + dimensions: tuple[int], + entries: dict[str, int | str], + n_inlet_ports: int | str = 0, + n_outlet_ports: int | str = 0, +) -> State: """ Initialize a State instance. @@ -370,9 +366,7 @@ def state_factory( Number of outlet Ports """ - dimensions = { - dim: getattr(instance, dim) for dim in dimensions - } + dimensions = {dim: getattr(instance, dim) for dim in dimensions} entries = { entry: ( n_entries if isinstance(n_entries, int) else getattr(instance, n_entries) diff --git a/CADETPythonSimulator/system.py b/CADETPythonSimulator/system.py index 3f6e348..afce0a2 100644 --- a/CADETPythonSimulator/system.py +++ b/CADETPythonSimulator/system.py @@ -9,7 +9,7 @@ from CADETPythonSimulator.state import State, state_factory from CADETPythonSimulator.coupling_interface import ( CouplingInterface, - WeightedAverageCoupling + WeightedAverageCoupling, ) from CADETProcess.dataStructure import Structure @@ -17,6 +17,7 @@ from CADETPythonSimulator.unit_operation import UnitOperationBase from CADETPythonSimulator.componentsystem import CPSComponentSystem + class SystemBase(Structure): """Base Class Structure for a System.""" @@ -31,8 +32,9 @@ def __init__(self, unit_operations: list[UnitOperationBase]): self._t_zero: Optional[float] = None if not self._coupling_state_structure: - self._coupling_state_structure: Optional[dict[str, CouplingInterface]]\ - = None + self._coupling_state_structure: Optional[dict[str, CouplingInterface]] = ( + None + ) self._setup_unit_operations(unit_operations) @property @@ -43,9 +45,9 @@ def unit_operations(self) -> dict[str, UnitOperationBase]: @property def n_dof(self) -> int: """int: Total number of degrees of freedom.""" - return sum([ - unit_operation.n_dof for unit_operation in self.unit_operations.values() - ]) + return sum( + [unit_operation.n_dof for unit_operation in self.unit_operations.values()] + ) @property def n_comp(self) -> int: @@ -76,9 +78,9 @@ def _setup_connectivity(self): for port in range(unit[1].n_outlet_ports): origin_unit_ports[i_unit][port] = origin_counter origin_index_unit_operations[origin_counter] = { - 'unit': i_unit, - 'port': port, - 'name': unit[0], + "unit": i_unit, + "port": port, + "name": unit[0], } origin_counter += 1 self.origin_unit_ports = origin_unit_ports @@ -94,16 +96,16 @@ def _setup_connectivity(self): for port in range(unit[1].n_inlet_ports): destination_unit_ports[i_unit][port] = destination_counter destination_index_unit_operations[destination_counter] = { - 'unit': i_unit, - 'port': port, - 'name': unit[0], + "unit": i_unit, + "port": port, + "name": unit[0], } destination_counter += 1 self.destination_unit_ports = destination_unit_ports self.destination_index_unit_operations = destination_index_unit_operations self.n_destination_ports = destination_counter - def _setup_unit_operations(self, unit_operations : list[UnitOperationBase]): + def _setup_unit_operations(self, unit_operations: list[UnitOperationBase]): """ Set up unit operations. @@ -116,7 +118,7 @@ def _setup_unit_operations(self, unit_operations : list[UnitOperationBase]): list of UnitOperation that are part of the System """ - #TODO: check if all unit_operation satisfy the system + # TODO: check if all unit_operation satisfy the system self._component_system = unit_operations[0].component_system for unit in unit_operations: @@ -139,9 +141,9 @@ def states(self) -> dict[str, dict[str, State]]: @property def y(self) -> np.ndarray: """np.ndarray: State array flattened into one dimension.""" - return np.concatenate([ - unit_operation.y for unit_operation in self.unit_operations.values() - ]) + return np.concatenate( + [unit_operation.y for unit_operation in self.unit_operations.values()] + ) @y.setter def y(self, y: np.ndarray) -> NoReturn: @@ -155,9 +157,9 @@ def y(self, y: np.ndarray) -> NoReturn: @property def y_init(self) -> np.ndarray: """np.ndarray: State array flattened into one dimension.""" - return np.concatenate([ - unit_operation.y_init for unit_operation in self.unit_operations.values() - ]) + return np.concatenate( + [unit_operation.y_init for unit_operation in self.unit_operations.values()] + ) @y_init.setter def y_init(self, y_init: np.ndarray) -> NoReturn: @@ -179,9 +181,9 @@ def state_derivatives(self) -> dict[str, dict[str, State]]: @property def y_dot(self) -> np.ndarray: """np.ndarray: State derivative array flattened into one dimension.""" - return np.concatenate([ - unit_operation.y_dot for unit_operation in self.unit_operations.values() - ]) + return np.concatenate( + [unit_operation.y_dot for unit_operation in self.unit_operations.values()] + ) @y_dot.setter def y_dot(self, y_dot: np.ndarray) -> NoReturn: @@ -203,9 +205,9 @@ def residuals(self) -> dict[str, dict[str, State]]: @property def r(self) -> np.ndarray: """np.ndarray: Residual array flattened into one dimension.""" - return np.concatenate([ - unit_operation.r for unit_operation in self.unit_operations.values() - ]) + return np.concatenate( + [unit_operation.r for unit_operation in self.unit_operations.values()] + ) @r.setter def r(self, r: np.ndarray) -> NoReturn: @@ -263,12 +265,7 @@ def set_rates(self) -> NoReturn: """ raise NotImplementedError("SystemBase is abstract.") - def compute_residual( - self, - t: float, - y: np.ndarray, - y_dot: np.ndarray - ) -> NoReturn: + def compute_residual(self, t: float, y: np.ndarray, y_dot: np.ndarray) -> NoReturn: """ Compute the residual for the differential-algebraic equations system. @@ -289,9 +286,7 @@ def compute_residual( for unit_operation in self.unit_operations.values(): unit_operation.compute_residual(t) - def couple_unit_operations( - self, - ) -> NoReturn: + def couple_unit_operations(self) -> NoReturn: """ Couple unit operations for set parameters. @@ -309,26 +304,25 @@ def couple_unit_operations( if Q_destination_total == 0: continue - destination_info = \ - self.destination_index_unit_operations[destination_port_index] - destination_unit = self.unit_operations[destination_info['name']] - destination_port = destination_info['port'] + destination_info = self.destination_index_unit_operations[ + destination_port_index + ] + destination_unit = self.unit_operations[destination_info["name"]] + destination_port = destination_info["port"] unit_Q_list = [] for origin_port_index, Q_destination in enumerate(Q_destinations): if Q_destination == 0: continue origin_info = self.origin_index_unit_operations[origin_port_index] - origin_unit = self.unit_operations[origin_info['name']] - origin_port = origin_info['port'] + origin_unit = self.unit_operations[origin_info["name"]] + origin_port = origin_info["port"] unit_Q_list.append( (origin_unit.get_outlet_state_flat(origin_port), Q_destination) ) s_new = self.coupled_state_func(unit_Q_list) - destination_unit.set_inlet_state_flat( - s_new, destination_port - ) + destination_unit.set_inlet_state_flat(s_new, destination_port) def coupled_state_func(self, unit_Q_list: list[dict, float]) -> dict: """ @@ -397,8 +391,9 @@ def _compute_connectivity_matrix(self, connections: list) -> np.ndarray: destination_unit = connection[1] destination_port = connection[3] - destination_index =\ - self.destination_unit_ports[destination_unit][destination_port] + destination_index = self.destination_unit_ports[destination_unit][ + destination_port + ] rate = connection[4] @@ -432,9 +427,7 @@ class FlowSystem(SystemBase): def __init__(self, unit_operations: list[UnitOperationBase]): """Construct FlowSystem Object.""" - self.coupling_state_structure={ - 'c': WeightedAverageCoupling() - } + self.coupling_state_structure = {"c": WeightedAverageCoupling()} super().__init__(unit_operations) def set_rates(self) -> NoReturn: @@ -448,11 +441,11 @@ def set_rates(self) -> NoReturn: """ for dest_i, Q_n in enumerate(self.connectivity): - unit_operation = self.destination_index_unit_operations[dest_i]['name'] - unit_port = self.destination_index_unit_operations[dest_i]['port'] + unit_operation = self.destination_index_unit_operations[dest_i]["name"] + unit_port = self.destination_index_unit_operations[dest_i]["port"] self.unit_operations[unit_operation].set_Q_in_port(unit_port, np.sum(Q_n)) for origin_i, Q_n in enumerate(self.connectivity.T): - unit_operation = self.origin_index_unit_operations[origin_i]['name'] - unit_port = self.origin_index_unit_operations[origin_i]['port'] + unit_operation = self.origin_index_unit_operations[origin_i]["name"] + unit_port = self.origin_index_unit_operations[origin_i]["port"] self.unit_operations[unit_operation].set_Q_out_port(unit_port, np.sum(Q_n)) diff --git a/CADETPythonSimulator/unit_operation.py b/CADETPythonSimulator/unit_operation.py index 0ce1f04..04247d6 100644 --- a/CADETPythonSimulator/unit_operation.py +++ b/CADETPythonSimulator/unit_operation.py @@ -8,7 +8,12 @@ from CADETProcess.processModel import ComponentSystem from CADETProcess.dataStructure import Structure from CADETProcess.dataStructure import ( - Typed, String, UnsignedInteger, UnsignedFloat, SizedUnsignedNdArray, NdPolynomial + Typed, + String, + UnsignedInteger, + UnsignedFloat, + SizedUnsignedNdArray, + NdPolynomial, ) from CADETProcess.dynamicEvents import Section @@ -21,14 +26,15 @@ calculate_residual_visc_cstr, calculate_residual_press_easy_def, calculate_residual_cake_vol_def, - calculate_residual_visc_def - ) + calculate_residual_visc_def, +) from CADETPythonSimulator.rejection import RejectionBase from CADETPythonSimulator.cake_compressibility import CakeCompressibilityBase from CADETPythonSimulator.viscosity import LogarithmicMixingViscosity, ViscosityBase from CADETPythonSimulator.distribution_base import DistributionBase + class UnitOperationBase(Structure): """ Base class for unit operations. @@ -64,9 +70,7 @@ def __init__(self, component_system, name, *args, **kwargs): self._Q_in: Optional[np.ndarray] = None self._Q_out: Optional[np.ndarray] = None - self._coupling_state_structure = { - 'c': component_system.n_comp - } + self._coupling_state_structure = {"c": component_system.n_comp} @property def n_dof(self) -> int: @@ -130,10 +134,12 @@ def state_derivatives(self) -> dict[str, State]: @property def y_dot(self) -> np.ndarray: """np.ndarray: State derivative array flattened into one dimension.""" - return np.concatenate([ + return np.concatenate( + [ state_derivative.s_flat for state_derivative in self.state_derivatives.values() - ]) + ] + ) @y_dot.setter def y_dot(self, y_dot: np.ndarray) -> NoReturn: @@ -146,10 +152,12 @@ def y_dot(self, y_dot: np.ndarray) -> NoReturn: @property def y_init(self) -> np.ndarray: """np.ndarray: State derivative array flattened into one dimension.""" - return np.concatenate([ + return np.concatenate( + [ state_derivative.s_flat for state_derivative in self.state_derivatives.values() - ]) + ] + ) @y_init.setter def y_init(self, y_init: np.ndarray) -> NoReturn: @@ -170,9 +178,7 @@ def residuals(self) -> dict[str, State]: @property def r(self) -> np.ndarray: """np.ndarray: Residual array flattened into one dimension.""" - return np.concatenate([ - residual.s_flat for residual in self.residuals.values() - ]) + return np.concatenate([residual.s_flat for residual in self.residuals.values()]) @r.setter def r(self, r: np.ndarray) -> NoReturn: @@ -270,9 +276,7 @@ def n_dof_coupling(self) -> int: @property def inlet_ports(self) -> dict[str, int]: """dict: Number of inlet ports per state.""" - return { - state.name: state.n_inlet_ports for state in self.states.values() - } + return {state.name: state.n_inlet_ports for state in self.states.values()} @property def n_inlet_ports(self) -> int: @@ -282,9 +286,7 @@ def n_inlet_ports(self) -> int: @property def outlet_ports(self) -> dict[str, int]: """dict: Number of outlet ports per state.""" - return { - state.name: state.n_outlet_ports for state in self.states.values() - } + return {state.name: state.n_outlet_ports for state in self.states.values()} @property def n_outlet_ports(self) -> int: @@ -300,27 +302,24 @@ def port_mapping(self) -> dict[int, str]: counter = 0 for mapped_state, n_ports in self.inlet_ports.items(): for port in range(n_ports): - port_mapping['inlet'][counter] = {} - port_mapping['inlet'][counter]['mapped_state'] = mapped_state - port_mapping['inlet'][counter]['port_index'] = port + port_mapping["inlet"][counter] = {} + port_mapping["inlet"][counter]["mapped_state"] = mapped_state + port_mapping["inlet"][counter]["port_index"] = port counter += 1 counter = 0 for mapped_state, n_ports in self.outlet_ports.items(): for port in range(n_ports): - port_mapping['outlet'][counter] = {} - port_mapping['outlet'][counter]['mapped_state'] = mapped_state - port_mapping['outlet'][counter]['port_index'] = port + port_mapping["outlet"][counter] = {} + port_mapping["outlet"][counter]["mapped_state"] = mapped_state + port_mapping["outlet"][counter]["port_index"] = port counter += 1 return dict(port_mapping) def set_inlet_state( - self, - inlet_state: dict[str, np.ndarray], - state: str, - state_port_index: int - ) -> NoReturn: + self, inlet_state: dict[str, np.ndarray], state: str, state_port_index: int + ) -> NoReturn: """ Set the state of the unit operation inlet for a given port. @@ -347,10 +346,8 @@ def set_inlet_state( state.set_inlet_port_state(inlet_state, state_port_index) def set_inlet_state_flat( - self, - inlet_state: dict[str, np.ndarray], - unit_port_index: int - ) -> NoReturn: + self, inlet_state: dict[str, np.ndarray], unit_port_index: int + ) -> NoReturn: """ Set the state of the unit operation inlet for a given port. @@ -362,17 +359,15 @@ def set_inlet_state_flat( The index of the unit operation inlet port. """ - port_info = self.port_mapping['inlet'][unit_port_index] + port_info = self.port_mapping["inlet"][unit_port_index] self.set_inlet_state( - inlet_state, port_info['mapped_state'], port_info['port_index'] + inlet_state, port_info["mapped_state"], port_info["port_index"] ) def get_outlet_state( - self, - state: str, - state_port_index: int - ) -> dict[str, np.ndarray]: + self, state: str, state_port_index: int + ) -> dict[str, np.ndarray]: """ Get the state of the unit operation outlet for a given port. @@ -401,10 +396,7 @@ def get_outlet_state( return state.get_outlet_port_state(state_port_index) - def get_outlet_state_flat( - self, - unit_port_index: int - ) -> dict[str, np.ndarray]: + def get_outlet_state_flat(self, unit_port_index: int) -> dict[str, np.ndarray]: """ Get the state of the unit operation outlet for a given port. @@ -419,15 +411,12 @@ def get_outlet_state_flat( A dictionary mapping each state entry to the values at the outlet port. """ - port_info = self.port_mapping['outlet'][unit_port_index] + port_info = self.port_mapping["outlet"][unit_port_index] - return self.get_outlet_state(port_info['mapped_state'], port_info['port_index']) + return self.get_outlet_state(port_info["mapped_state"], port_info["port_index"]) @abstractmethod - def compute_residual( - self, - t: float, - ) -> NoReturn: + def compute_residual(self, t: float) -> NoReturn: """ Calculate the residual of the unit operation at time `t`. @@ -445,11 +434,8 @@ def section_dependent_parameters(self) -> list[str]: return self._section_dependent_parameters def update_parameters( - self, - start: float, - end: float, - parameters: dict[str, float | np.ndarray] - ) -> NoReturn: + self, start: float, end: float, parameters: dict[str, float | np.ndarray] + ) -> NoReturn: """ Update parameters. @@ -473,13 +459,11 @@ def update_parameters( setattr(self, param, value) if param in self.section_dependent_parameters: coeffs = getattr(self, param) - self.parameter_sections[param] =\ - Section(start, end, coeffs, is_polynomial) + self.parameter_sections[param] = Section( + start, end, coeffs, is_polynomial + ) - def get_parameter_values_at_time( - self, - t: float, - ) -> dict[str, np.typing.ArrayLike]: + def get_parameter_values_at_time(self, t: float) -> dict[str, np.typing.ArrayLike]: """ Get parameter values at t. @@ -541,24 +525,17 @@ class Inlet(UnitOperationBase): """ - c_poly = NdPolynomial(size=('n_comp', 4), default=0) + c_poly = NdPolynomial(size=("n_comp", 4), default=0) viscosity = UnsignedFloat() - _parameters = ['c_poly'] - _polynomial_parameters = ['c_poly'] - _section_dependent_parameters = ['c_poly'] + _parameters = ["c_poly"] + _polynomial_parameters = ["c_poly"] + _section_dependent_parameters = ["c_poly"] - outlet = { - 'dimensions': (), - 'entries': {'c': 'n_comp'}, - 'n_outlet_ports': 1, - } - _state_structures = ['outlet'] + outlet = {"dimensions": (), "entries": {"c": "n_comp"}, "n_outlet_ports": 1} + _state_structures = ["outlet"] - def compute_residual( - self, - t: float - ) -> NoReturn: + def compute_residual(self, t: float) -> NoReturn: """ Calculate the residual of the unit operation at time `t`. @@ -569,9 +546,9 @@ def compute_residual( """ t_K = t - c = self.states['outlet']['c'] + c = self.states["outlet"]["c"] t_poly = np.array([1, t_K, t_K**2, t_K**3]) - self.residuals['outlet']['c'] = self.c_poly @ t_poly - c + self.residuals["outlet"]["c"] = self.c_poly @ t_poly - c def initialize_initial_values(self, t_zero: float): """ @@ -585,9 +562,10 @@ def initialize_initial_values(self, t_zero: float): """ t_zero = 0 t_poly = np.array([1, t_zero, t_zero**2, t_zero**3]) - self.states['outlet']['c'] = self.c_poly @ t_poly - t_poly = np.array([0, 1, 2*t_zero, 3*t_zero**2]) - self.state_derivatives['outlet']['c'] = self.c_poly @ t_poly + self.states["outlet"]["c"] = self.c_poly @ t_poly + t_poly = np.array([0, 1, 2 * t_zero, 3 * t_zero**2]) + self.state_derivatives["outlet"]["c"] = self.c_poly @ t_poly + class DistributionInlet(UnitOperationBase): """ @@ -603,19 +581,12 @@ class DistributionInlet(UnitOperationBase): distribution_function = Typed(ty=DistributionBase) section_number = Typed(ty=int) - outlet = { - 'dimensions': (), - 'entries': {'c': 'n_comp'}, - 'n_outlet_ports': 1, - } - _state_structures = ['outlet'] - _parameters = ['section_number'] - _section_dependent_parameters = ['section_number'] + outlet = {"dimensions": (), "entries": {"c": "n_comp"}, "n_outlet_ports": 1} + _state_structures = ["outlet"] + _parameters = ["section_number"] + _section_dependent_parameters = ["section_number"] - def compute_residual( - self, - t: float - ) -> NoReturn: + def compute_residual(self, t: float) -> NoReturn: """ Calculate the residual of the unit operation at time `t`. @@ -625,15 +596,15 @@ def compute_residual( Time at which to evaluate the residual. """ - c = self.states['outlet']['c'] + c = self.states["outlet"]["c"] nr = self.section_number xi = self.distribution_function.get_distribution(t, nr) molecular_weights = np.array(self.component_system.molecular_weights) densities = np.array(self.component_system.densities) - ci = xi*densities / molecular_weights + ci = xi * densities / molecular_weights - self.residuals['outlet']['c'] = ci - c + self.residuals["outlet"]["c"] = ci - c def initialize_initial_values(self, t_zero: float): """ @@ -645,14 +616,14 @@ def initialize_initial_values(self, t_zero: float): Time to initialize the values """ - nr = self.parameters['section_number'] + nr = self.parameters["section_number"] xi = self.distribution_function.get_distribution(t_zero, nr) molecular_weights = np.array(self.component_system.molecular_weights) densities = np.array(self.component_system.densities) - ci = xi*densities / molecular_weights + ci = xi * densities / molecular_weights - self.states['outlet']['c'] = ci + self.states["outlet"]["c"] = ci class ConcentrationDistributionInlet(UnitOperationBase): @@ -669,19 +640,12 @@ class ConcentrationDistributionInlet(UnitOperationBase): distribution_function = Typed(ty=DistributionBase) section_number = Typed(ty=int) - outlet = { - 'dimensions': (), - 'entries': {'c': 'n_comp'}, - 'n_outlet_ports': 1, - } - _state_structures = ['outlet'] - _parameters = ['section_number'] - _section_dependent_parameters = ['section_number'] + outlet = {"dimensions": (), "entries": {"c": "n_comp"}, "n_outlet_ports": 1} + _state_structures = ["outlet"] + _parameters = ["section_number"] + _section_dependent_parameters = ["section_number"] - def compute_residual( - self, - t: float - ) -> NoReturn: + def compute_residual(self, t: float) -> NoReturn: """ Calculate the residual of the unit operation at time `t`. @@ -691,11 +655,11 @@ def compute_residual( Time at which to evaluate the residual. """ - c = self.states['outlet']['c'] + c = self.states["outlet"]["c"] nr = self.section_number ci = self.distribution_function.get_distribution(t, nr) - self.residuals['outlet']['c'] = ci - c + self.residuals["outlet"]["c"] = ci - c def initialize_initial_values(self, t_zero: float): """ @@ -707,26 +671,19 @@ def initialize_initial_values(self, t_zero: float): Time to initialize the values """ - nr = self.parameters['section_number'] + nr = self.parameters["section_number"] ci = self.distribution_function.get_distribution(t_zero, nr) - self.states['outlet']['c'] = ci + self.states["outlet"]["c"] = ci class Outlet(UnitOperationBase): """System outlet.""" - inlet = { - 'dimensions': (), - 'entries': {'c': 'n_comp'}, - 'n_inlet_ports': 1, - } - _state_structures = ['inlet'] + inlet = {"dimensions": (), "entries": {"c": "n_comp"}, "n_inlet_ports": 1} + _state_structures = ["inlet"] - def compute_residual( - self, - t: float - ) -> NoReturn: + def compute_residual(self, t: float) -> NoReturn: """ Calculate the residual of the unit operation at time `t`. @@ -736,28 +693,21 @@ def compute_residual( Time at which to evaluate the residual. """ - self.residuals['inlet']['c'] -= self.states['inlet']['c'] + self.residuals["inlet"]["c"] -= self.states["inlet"]["c"] class Cstr(UnitOperationBase): """Continuous stirred tank reactor.""" - inlet = { - 'dimensions': (), - 'entries': {'c': 'n_comp'}, - 'n_inlet_ports': 1, - } + inlet = {"dimensions": (), "entries": {"c": "n_comp"}, "n_inlet_ports": 1} bulk = { - 'dimensions': (), - 'entries': {'c': 'n_comp', 'Volume': 1}, - 'n_outlet_ports': 1, + "dimensions": (), + "entries": {"c": "n_comp", "Volume": 1}, + "n_outlet_ports": 1, } - _state_structures = ['inlet', 'bulk'] + _state_structures = ["inlet", "bulk"] - def compute_residual( - self, - t: float, - ) -> NoReturn: + def compute_residual(self, t: float) -> NoReturn: """ Calculate the residual of the unit operation at time `t`. @@ -767,27 +717,27 @@ def compute_residual( Time at which to evaluate the residual. """ - c_in = self.states['inlet']['c'] + c_in = self.states["inlet"]["c"] # c_in_dot = self.state_derivatives['inlet']['c'] - c = self.states['bulk']['c'] - c_dot = self.state_derivatives['bulk']['c'] + c = self.states["bulk"]["c"] + c_dot = self.state_derivatives["bulk"]["c"] - V = self.states['bulk']['Volume'] - V_dot = self.state_derivatives['bulk']['Volume'] + V = self.states["bulk"]["Volume"] + V_dot = self.state_derivatives["bulk"]["Volume"] # Handle inlet DOFs, which are simply copied to the residual - self.residuals['inlet']['c'] -= c_in + self.residuals["inlet"]["c"] -= c_in # Handle bulk/outlet DOFs Q_in = self.Q_in[0] Q_out = self.Q_out[0] - self.residuals['bulk']['c'] = calculate_residual_concentration_cstr( + self.residuals["bulk"]["c"] = calculate_residual_concentration_cstr( c, c_dot, V, V_dot, Q_in, Q_out, c_in ) - self.residuals['bulk']['Volume'] = calculate_residual_volume_cstr( + self.residuals["bulk"]["Volume"] = calculate_residual_volume_cstr( V, V_dot, Q_in, Q_out ) @@ -803,14 +753,17 @@ def initialize_initial_values(self, t_zero: float): """ Q_in = self.Q_in[0] Q_out = self.Q_out[0] - V = self.states['bulk']['Volume'] + V = self.states["bulk"]["Volume"] V_dot = Q_in - Q_out - c_in = self.states['inlet']['c'] - c = self.states['bulk']['c'] + c_in = self.states["inlet"]["c"] + c = self.states["bulk"]["c"] + + self.state_derivatives["bulk"]["c"] = ( + -V_dot / V * c + Q_in / V * c_in - Q_out / V * c + ) + self.state_derivatives["bulk"]["volume"] = V_dot + self.state_derivatives["inlet"]["c"] = np.zeros(self.n_comp) - self.state_derivatives['bulk']['c'] = - V_dot/V*c + Q_in/V*c_in - Q_out/V*c - self.state_derivatives['bulk']['volume'] = V_dot - self.state_derivatives['inlet']['c'] = np.zeros(self.n_comp) class DeadEndFiltration(UnitOperationBase): """ @@ -830,49 +783,23 @@ class DeadEndFiltration(UnitOperationBase): """ inlet = { - 'dimensions': {}, - 'entries': { - 'c': 'n_comp', - 'n': 'n_comp' - }, - 'n_inlet_ports': 1, - } - permeate = { - 'dimensions': (), - 'entries': { - 'c': 'n_comp', - 'n': 'n_comp', - 'V': 1, - }, - } - retentate = { - 'dimensions': (), - 'entries': { - 'c': 'n_comp', - 'n': 'n_comp', - 'V': 1, - } + "dimensions": {}, + "entries": {"c": "n_comp", "n": "n_comp"}, + "n_inlet_ports": 1, } + permeate = {"dimensions": (), "entries": {"c": "n_comp", "n": "n_comp", "V": 1}} + retentate = {"dimensions": (), "entries": {"c": "n_comp", "n": "n_comp", "V": 1}} cake = { - 'dimensions': (), - 'entries': { - 'c': 'n_comp', - 'n': 'n_comp', - 'V': 1, - 'pressure': 1 - }, + "dimensions": (), + "entries": {"c": "n_comp", "n": "n_comp", "V": 1, "pressure": 1}, } permeate_tank = { - 'dimensions': (), - 'entries': { - 'c': 'n_comp', - 'n': 'n_comp', - 'V': 1, - }, - 'n_outlet_ports': 1, + "dimensions": (), + "entries": {"c": "n_comp", "n": "n_comp", "V": 1}, + "n_outlet_ports": 1, } - _state_structures = ['inlet', 'permeate', 'retentate', 'cake', 'permeate_tank'] + _state_structures = ["inlet", "permeate", "retentate", "cake", "permeate_tank"] membrane_area = UnsignedFloat() membrane_resistance = UnsignedFloat() @@ -880,136 +807,129 @@ class DeadEndFiltration(UnitOperationBase): viscosity_model = Typed(ty=ViscosityBase) _parameters = [ - 'membrane_area', - 'membrane_resistance', - 'rejection_model', - 'viscosity_model' + "membrane_area", + "membrane_resistance", + "rejection_model", + "viscosity_model", ] - def compute_residual( - self, - t: float, - ) -> NoReturn: + def compute_residual(self, t: float) -> NoReturn: """Calculate the Residuum for DEF.""" Q_in = self.Q_in[0] Q_out = self.Q_out[0] - c_in = self.states['inlet']['c'] - n_in_dot = self.state_derivatives['inlet']['n'] + c_in = self.states["inlet"]["c"] + n_in_dot = self.state_derivatives["inlet"]["n"] - c_R = self.states['retentate']['c'] - n_R_dot = self.state_derivatives['retentate']['n'] - Q_R = self.state_derivatives['retentate']['V'] + c_R = self.states["retentate"]["c"] + n_R_dot = self.state_derivatives["retentate"]["n"] + Q_R = self.state_derivatives["retentate"]["V"] - c_P = self.states['permeate']['c'] - n_P_dot = self.state_derivatives['permeate']['n'] - Q_P = self.state_derivatives['permeate']['V'] + c_P = self.states["permeate"]["c"] + n_P_dot = self.state_derivatives["permeate"]["n"] + Q_P = self.state_derivatives["permeate"]["V"] + vol_cake = self.states["cake"]["V"] + vol_cake_dot = self.state_derivatives["cake"]["V"] + n_C_dot = self.state_derivatives["cake"]["n"] + n_C = self.states["cake"]["n"] + c_C = self.states["cake"]["c"] + c_C_dot = self.state_derivatives["cake"]["c"] + delta_p = self.states["cake"]["pressure"] - - vol_cake = self.states['cake']['V'] - vol_cake_dot = self.state_derivatives['cake']['V'] - n_C_dot = self.state_derivatives['cake']['n'] - n_C = self.states['cake']['n'] - c_C = self.states['cake']['c'] - c_C_dot = self.state_derivatives['cake']['c'] - delta_p = self.states['cake']['pressure'] - - c_PT = self.states['permeate_tank']['c'] - c_PT_dot = self.state_derivatives['permeate_tank']['c'] - n_PT = self.states['permeate_tank']['n'] - vol_PT = self.states['permeate_tank']['V'] - vol_PT_dot = self.state_derivatives['permeate_tank']['V'] + c_PT = self.states["permeate_tank"]["c"] + c_PT_dot = self.state_derivatives["permeate_tank"]["c"] + n_PT = self.states["permeate_tank"]["n"] + vol_PT = self.states["permeate_tank"]["V"] + vol_PT_dot = self.state_derivatives["permeate_tank"]["V"] # parameters molecular_weights = np.array(self.component_system.molecular_weights) densities = np.array(self.component_system.densities) viscosities = np.array(self.component_system.viscosities) - membrane_area = self.parameters['membrane_area'] - membrane_resistance = self.parameters['membrane_resistance'] - specific_cake_resistance =\ - np.array(self.component_system.specific_cake_resistances) + membrane_area = self.parameters["membrane_area"] + membrane_resistance = self.parameters["membrane_resistance"] + specific_cake_resistance = np.array( + self.component_system.specific_cake_resistances + ) rejection = np.array( - [ - self.rejection_model.get_rejection(mw)\ - for mw in molecular_weights - ] - ) + [self.rejection_model.get_rejection(mw) for mw in molecular_weights] + ) # Inlet Equations - self.residuals['inlet']['c'] -= c_in - self.residuals['inlet']['n'] = n_in_dot - Q_in * c_in + self.residuals["inlet"]["c"] -= c_in + self.residuals["inlet"]["n"] = n_in_dot - Q_in * c_in # Equations for permeate and retentate - self.residuals['retentate']['n'] = n_R_dot - rejection * n_in_dot - self.residuals['permeate']['n'] = n_P_dot - (1 - rejection) * n_in_dot + self.residuals["retentate"]["n"] = n_R_dot - rejection * n_in_dot + self.residuals["permeate"]["n"] = n_P_dot - (1 - rejection) * n_in_dot - self.residuals['retentate']['V'] = \ - Q_R - np.sum(n_R_dot * molecular_weights / densities) - self.residuals['permeate']['V'] = \ - Q_P - np.sum(n_P_dot * molecular_weights / densities) + self.residuals["retentate"]["V"] = Q_R - np.sum( + n_R_dot * molecular_weights / densities + ) + self.residuals["permeate"]["V"] = Q_P - np.sum( + n_P_dot * molecular_weights / densities + ) if Q_R > 1e-16: - self.residuals['retentate']['c'] = \ - c_R - n_R_dot / Q_R + self.residuals["retentate"]["c"] = c_R - n_R_dot / Q_R else: - self.residuals['retentate']['c'] = c_R + self.residuals["retentate"]["c"] = c_R if Q_P > 1e-16: - self.residuals['permeate']['c'] = \ - c_P - n_P_dot / Q_P + self.residuals["permeate"]["c"] = c_P - n_P_dot / Q_P else: - self.residuals['permeate']['c'] = c_P - + self.residuals["permeate"]["c"] = c_P # Cake equations - self.residuals['cake']['V'] = \ - vol_cake - np.sum(n_C * molecular_weights / densities) - self.residuals['cake']['n'] = n_C_dot - n_R_dot + self.residuals["cake"]["V"] = vol_cake - np.sum( + n_C * molecular_weights / densities + ) + self.residuals["cake"]["n"] = n_C_dot - n_R_dot if vol_cake > 1e-16: - self.residuals['cake']['c'] = \ + self.residuals["cake"]["c"] = ( c_C_dot - (n_C_dot - c_C * vol_cake_dot) / vol_cake + ) else: - self.residuals['cake']['c'] = c_C_dot + self.residuals["cake"]["c"] = c_C_dot # Permeate tank equations - c_tank_dot_new =\ - (n_P_dot - Q_out * c_PT - vol_PT_dot * c_PT) / vol_PT + c_tank_dot_new = (n_P_dot - Q_out * c_PT - vol_PT_dot * c_PT) / vol_PT - self.residuals['permeate_tank']['c'] = c_PT_dot - c_tank_dot_new + self.residuals["permeate_tank"]["c"] = c_PT_dot - c_tank_dot_new - self.residuals['permeate_tank']['V'] =\ - vol_PT_dot - Q_P + Q_out + self.residuals["permeate_tank"]["V"] = vol_PT_dot - Q_P + Q_out - self.residuals['permeate_tank']['n'] = n_PT - c_PT * vol_PT + self.residuals["permeate_tank"]["n"] = n_PT - c_PT * vol_PT - #Pressure equation + # Pressure equation if not np.sum(n_P_dot) < 1e-16: + fractions = n_P_dot / sum(n_P_dot) - fractions = n_P_dot/sum(n_P_dot) - - viscosity =\ - self.viscosity_model.get_mixture_viscosity(viscosities, fractions) + viscosity = self.viscosity_model.get_mixture_viscosity( + viscosities, fractions + ) component_volume = n_C * molecular_weights / densities cake_resistance = np.sum( specific_cake_resistance * densities * component_volume / membrane_area ) - self.residuals['cake']['pressure'] = \ - delta_p - viscosity * Q_P\ - *(membrane_resistance + cake_resistance) / membrane_area + self.residuals["cake"]["pressure"] = ( + delta_p + - viscosity + * Q_P + * (membrane_resistance + cake_resistance) + / membrane_area + ) else: - self.residuals['cake']['pressure'] = delta_p - - - + self.residuals["cake"]["pressure"] = delta_p @property def y_init(self) -> np.ndarray: @@ -1038,11 +958,13 @@ def y_init(self, y_init: np.ndarray) -> NoReturn: for entry, dim in state_derivative.entries.items(): sub_end_index = sub_start_index + dim if state != "pressure": - self.state_derivatives[state][entry] =\ - y_init[sub_start_index:sub_end_index] + self.state_derivatives[state][entry] = y_init[ + sub_start_index:sub_end_index + ] else: - self.states[state][entry] =\ - y_init[sub_start_index:sub_end_index] + self.states[state][entry] = y_init[ + sub_start_index:sub_end_index + ] sub_start_index = sub_end_index start_index = end_index @@ -1051,93 +973,89 @@ def initialize_initial_values(self, t_zero: float): molecular_weights = np.array(self.component_system.molecular_weights) densities = np.array(self.component_system.densities) viscosities = np.array(self.component_system.viscosities) - membrane_area = self.parameters['membrane_area'] - membrane_resistance = self.parameters['membrane_resistance'] - specific_cake_resistance =\ - np.array(self.component_system.specific_cake_resistances) + membrane_area = self.parameters["membrane_area"] + membrane_resistance = self.parameters["membrane_resistance"] + specific_cake_resistance = np.array( + self.component_system.specific_cake_resistances + ) Q_in = self.Q_in[0] Q_out = self.Q_out[0] - c_in = self.states['inlet']['c'] + c_in = self.states["inlet"]["c"] n_in_dot = Q_in * c_in - self.state_derivatives['inlet']['n'] = n_in_dot + self.state_derivatives["inlet"]["n"] = n_in_dot rejection = np.array( - [ - self.rejection_model.get_rejection(mw)\ - for mw in molecular_weights - ] - ) + [self.rejection_model.get_rejection(mw) for mw in molecular_weights] + ) n_cake_dot = rejection * n_in_dot - self.state_derivatives['retentate']['n'] = n_cake_dot - self.state_derivatives['cake']['n'] = n_cake_dot + self.state_derivatives["retentate"]["n"] = n_cake_dot + self.state_derivatives["cake"]["n"] = n_cake_dot vol_cake_dot = np.sum(molecular_weights * n_cake_dot / densities) - self.state_derivatives['cake']['V'] = vol_cake_dot - self.state_derivatives['retentate']['V'] = vol_cake_dot + self.state_derivatives["cake"]["V"] = vol_cake_dot + self.state_derivatives["retentate"]["V"] = vol_cake_dot if vol_cake_dot > 1e-16: - self.states['retentate']['c'] = n_cake_dot/vol_cake_dot + self.states["retentate"]["c"] = n_cake_dot / vol_cake_dot else: - self.states['retentate']['c'][:] = 0.0 + self.states["retentate"]["c"][:] = 0.0 - vol_cake = self.states['cake']['V'] - n_cake = self.states['cake']['n'] + vol_cake = self.states["cake"]["V"] + n_cake = self.states["cake"]["n"] if vol_cake > 1e-16: - self.states['cake']['c'] = n_cake + self.states["cake"]["c"] = n_cake else: - self.states['cake']['c'][:] = 0 + self.states["cake"]["c"][:] = 0 n_P_dot = (1 - rejection) * n_in_dot - self.state_derivatives['permeate']['n'] = n_P_dot + self.state_derivatives["permeate"]["n"] = n_P_dot Q_P = np.sum(n_P_dot * molecular_weights / densities) - self.state_derivatives['permeate']['V'] = Q_P + self.state_derivatives["permeate"]["V"] = Q_P if Q_P > 1e-16: - self.states['permeate']['c'] = n_P_dot / Q_P + self.states["permeate"]["c"] = n_P_dot / Q_P else: - self.states['permeate']['c'][:] = 0.0 + self.states["permeate"]["c"][:] = 0.0 - c_PT = self.states['permeate_tank']['c'] - V_PT = self.states['permeate_tank']['V'] + c_PT = self.states["permeate_tank"]["c"] + V_PT = self.states["permeate_tank"]["V"] - self.states['permeate_tank']['n'] = c_PT * V_PT + self.states["permeate_tank"]["n"] = c_PT * V_PT V_PT_dot = Q_P - Q_out - c_PT_dot =\ - (n_P_dot - Q_out * c_PT - V_PT_dot * c_PT) / V_PT + c_PT_dot = (n_P_dot - Q_out * c_PT - V_PT_dot * c_PT) / V_PT - self.state_derivatives['permeate_tank']['c'] = c_PT_dot + self.state_derivatives["permeate_tank"]["c"] = c_PT_dot - self.state_derivatives['permeate_tank']['V'] = V_PT_dot + self.state_derivatives["permeate_tank"]["V"] = V_PT_dot if not np.sum(n_P_dot) < 1e-16: + fractions = n_P_dot / sum(n_P_dot) - fractions = n_P_dot/sum(n_P_dot) - - viscosity =\ - self.viscosity_model.get_mixture_viscosity(viscosities, fractions) + viscosity = self.viscosity_model.get_mixture_viscosity( + viscosities, fractions + ) - n_C = self.states['cake']['n'] + n_C = self.states["cake"]["n"] component_volume = n_C * molecular_weights / densities cake_resistance = np.sum( specific_cake_resistance * densities * component_volume / membrane_area ) - self.states['cake']['pressure'] = \ - viscosity * Q_P * (membrane_resistance + cake_resistance)\ + self.states["cake"]["pressure"] = ( + viscosity + * Q_P + * (membrane_resistance + cake_resistance) / membrane_area + ) else: - self.states['cake']['pressure'] = 0 - - - - + self.states["cake"]["pressure"] = 0 class CrossFlowFiltration(UnitOperationBase): @@ -1160,40 +1078,33 @@ class CrossFlowFiltration(UnitOperationBase): n_axial = UnsignedInteger(default=10) retentate = { - 'dimensions': ('n_axial', ), - 'entries': {'c': 'n_comp', 'viscosity': 1, 'Volume': 1}, - 'n_inlet_ports': 1, - 'n_outlet_ports': 1, + "dimensions": ("n_axial",), + "entries": {"c": "n_comp", "viscosity": 1, "Volume": 1}, + "n_inlet_ports": 1, + "n_outlet_ports": 1, } permeate = { - 'dimensions': ('n_axial', ), - 'entries': {'c': 'n_comp', 'viscosity': 1, 'Volume': 1}, - 'n_outlet_ports': 1, + "dimensions": ("n_axial",), + "entries": {"c": "n_comp", "viscosity": 1, "Volume": 1}, + "n_outlet_ports": 1, } - _state_structures = ['retentate', 'permeate'] + _state_structures = ["retentate", "permeate"] rejection_model = Typed(ty=RejectionBase) membrane_area = UnsignedFloat() membrane_resistance = UnsignedFloat() - _parameters = [ - 'membrane_area', - 'membrane_resistance', - ] + _parameters = ["membrane_area", "membrane_resistance"] def __init__(self, component_system, name, *args, **kwargs): """Construct CFF.""" super().__init__(component_system, name, *args, **kwargs) - self.coupling_state_structure['viscosity'] = 1 + self.coupling_state_structure["viscosity"] = 1 def compute_residual( - self, - t: float, - y: np.ndarray, - y_dot: np.ndarray, - residual: np.ndarray - ) -> NoReturn: + self, t: float, y: np.ndarray, y_dot: np.ndarray, residual: np.ndarray + ) -> NoReturn: """ Calculate the residual of the unit operation at time `t`. @@ -1232,30 +1143,26 @@ class _2DGRM(UnitOperationBase): n_particle = UnsignedInteger(default=5) bulk = { - 'dimensions': ('n_radial', 'n_axial'), - 'entries': {'c': 'n_comp', 'viscosity': 1}, - 'n_inlet_ports': 'n_radial', - 'n_outlet_ports': 'n_radial', + "dimensions": ("n_radial", "n_axial"), + "entries": {"c": "n_comp", "viscosity": 1}, + "n_inlet_ports": "n_radial", + "n_outlet_ports": "n_radial", } particle = { - 'dimensions': ('n_radial', 'n_axial', 'n_particle'), - 'entries': {'c': 'n_comp', 'viscosity': 1, 'q': 'n_comp'}, - 'n_outlet_ports': 1, + "dimensions": ("n_radial", "n_axial", "n_particle"), + "entries": {"c": "n_comp", "viscosity": 1, "q": "n_comp"}, + "n_outlet_ports": 1, } flux = { - 'dimensions': ('n_radial', 'n_axial', ), - 'entries': {'c': 'n_comp'}, - 'n_outlet_ports': 1, + "dimensions": ("n_radial", "n_axial"), + "entries": {"c": "n_comp"}, + "n_outlet_ports": 1, } - _state_structures = ['bulk', 'particle', 'flux'] + _state_structures = ["bulk", "particle", "flux"] def compute_residual( - self, - t: float, - y: np.ndarray, - y_dot: np.ndarray, - residual: np.ndarray - ) -> NoReturn: + self, t: float, y: np.ndarray, y_dot: np.ndarray, residual: np.ndarray + ) -> NoReturn: """ Calculate the residual of the unit operation at time `t`. diff --git a/CADETPythonSimulator/viscosity.py b/CADETPythonSimulator/viscosity.py index 6641844..d447e89 100644 --- a/CADETPythonSimulator/viscosity.py +++ b/CADETPythonSimulator/viscosity.py @@ -10,8 +10,8 @@ class ViscosityBase(Structure): @abstractmethod def get_mixture_viscosity( - self, viscosities: np.ndarray, fractions: np.ndarray - ) -> float: + self, viscosities: np.ndarray, fractions: np.ndarray + ) -> float: """ Calculate mixed viscosity with given viscosities and volume fractions. @@ -31,25 +31,22 @@ def get_mixture_viscosity( pass def _validate_viscosities_input( - self, - viscosities: np.ndarray, - fractions: np.ndarray - ) -> None: - if not np.all(viscosities, where=[0]) or not np.all(fractions, where=[0])\ - or len(viscosities) != len(fractions): + self, viscosities: np.ndarray, fractions: np.ndarray + ) -> None: + if ( + not np.all(viscosities, where=[0]) + or not np.all(fractions, where=[0]) + or len(viscosities) != len(fractions) + ): raise ValueError( "Viscosities and fractions lists must be of the same length." ) if not np.isclose(np.sum(fractions), 1): - raise ValueError( - "Sum of volume fractions must be 1." - ) + raise ValueError("Sum of volume fractions must be 1.") def _remove_nan_viscosities( - self, - viscosities: np.ndarray, - fractions: np.ndarray, - ) -> tuple[np.ndarray, np.ndarray]: + self, viscosities: np.ndarray, fractions: np.ndarray + ) -> tuple[np.ndarray, np.ndarray]: non_nan_indices = ~np.isnan(viscosities) viscosities = viscosities[non_nan_indices] @@ -65,8 +62,8 @@ class AverageViscosity(ViscosityBase): """Calculate mixed viscosity using the average mean.""" def get_mixture_viscosity( - self, viscosities: np.ndarray, fractions: np.ndarray - ) -> float: + self, viscosities: np.ndarray, fractions: np.ndarray + ) -> float: """ Calculate mixed viscosity using the arithmetic mean. @@ -94,8 +91,8 @@ class LogarithmicMixingViscosity(ViscosityBase): """Calculate mixed viscosity using the logarithmic mixing rule.""" def get_mixture_viscosity( - self, viscosities: np.ndarray, fractions: np.ndarray - ) -> float: + self, viscosities: np.ndarray, fractions: np.ndarray + ) -> float: """ Calculate mixed viscosity using the logarithmic mixing rule. diff --git a/tests/test_distribution.py b/tests/test_distribution.py index 256bd40..c42b5b1 100644 --- a/tests/test_distribution.py +++ b/tests/test_distribution.py @@ -3,8 +3,9 @@ from CADETPythonSimulator.componentsystem import CPSComponentSystem from CADETPythonSimulator.distribution_base import ( - ConstantVolumeDistribution, ConstantConcentrationDistribution - ) + ConstantVolumeDistribution, + ConstantConcentrationDistribution, +) from CADETPythonSimulator.exception import CADETPythonSimError component_system = CPSComponentSystem( @@ -13,25 +14,16 @@ densities=[1, 1], molecular_weights=[1, 2], viscosities=[1, 1], - specific_cake_resistances=[1,1] - ) + specific_cake_resistances=[1, 1], +) + @pytest.mark.parametrize( "distribution, component_system, concentration, expected", [ - ( - ConstantVolumeDistribution, - component_system, - [1], - [1, 0] - ), - ( - ConstantConcentrationDistribution, - component_system, - [1], - [1, 0] - ) - ] + (ConstantVolumeDistribution, component_system, [1], [1, 0]), + (ConstantConcentrationDistribution, component_system, [1], [1, 0]), + ], ) class TestDistribution: """Test Class for Distribution.""" @@ -44,6 +36,6 @@ def test_getter(self, distribution, component_system, concentration, expected): def test_error(self, distribution, component_system, concentration, expected): """Test Error Throwing.""" with pytest.raises(ValueError): - distribution(component_system, [1,1]) + distribution(component_system, [1, 1]) with pytest.raises(CADETPythonSimError): distribution(component_system, [10000]) diff --git a/tests/test_field.py b/tests/test_field.py index 887d2ad..e8ed99e 100644 --- a/tests/test_field.py +++ b/tests/test_field.py @@ -7,6 +7,7 @@ # %% Testing utilities + def assert_equal(value, expected, message=""): """Assert equality.""" message = f"Test failed: {message}. Expected {expected}, got {value}." @@ -21,6 +22,7 @@ def assert_shape(shape, expected_shape, message=""): # %% Initialization + def test_field_initialization(): """Test initialization of Field class.""" # Scalar field @@ -57,6 +59,7 @@ def test_field_initialization(): # %% Plotting + def test_plotting(): """Test Field plotting results.""" # 1D Plot @@ -102,6 +105,7 @@ def test_plotting(): # %% Slicing + def test_field_slicing(): """Test Field slicing.""" dimensions = {"axial": np.linspace(0, 10, 11), "radial": np.linspace(0, 5, 6)} @@ -124,6 +128,7 @@ def test_field_slicing(): # %% Normalization + def test_field_normalization(): """Test Field normalization.""" # Define dimensions and data @@ -152,6 +157,7 @@ def test_field_normalization(): # %% Interpolation and Resampling + def test_temperature_use_case(): """Test examplary use case of interpolating temperature from a Field.""" temperature_profile_dimensions = { diff --git a/tests/test_rejection.py b/tests/test_rejection.py index 929d696..520c5d2 100644 --- a/tests/test_rejection.py +++ b/tests/test_rejection.py @@ -1,27 +1,19 @@ import numpy as np import pytest -from CADETPythonSimulator.rejection import ( - RejectionBase, StepCutOff -) +from CADETPythonSimulator.rejection import StepCutOff TestCaseCutof = { - "model": StepCutOff, - "model_param": { - "cutoff_weight": 0.5 - }, - "weights": [0, 0.5, 1], - "expected": [0, 1, 1] - } + "model": StepCutOff, + "model_param": {"cutoff_weight": 0.5}, + "weights": [0, 0.5, 1], + "expected": [0, 1, 1], +} -@pytest.mark.parametrize( - "parameters", - [ - TestCaseCutof - ] -) -class TestRejection(): + +@pytest.mark.parametrize("parameters", [TestCaseCutof]) +class TestRejection: """Test Class to test all rejection Models.""" def test_get_rejection(self, parameters): diff --git a/tests/test_residual.py b/tests/test_residual.py index 80d4f71..66cb6c5 100644 --- a/tests/test_residual.py +++ b/tests/test_residual.py @@ -5,7 +5,7 @@ calculate_residual_volume_cstr, calculate_residual_concentration_cstr, calculate_residual_cake_vol_def, - calculate_residual_press_easy_def + calculate_residual_press_easy_def, ) from CADETPythonSimulator.exception import CADETPythonSimError @@ -19,65 +19,65 @@ "V_dot": 2, "Q_in": 3, "Q_out": 4, - "c_in": np.array([7, 8, 9]) + "c_in": np.array([7, 8, 9]), }, - "expected": np.array([-11, -7, -3]) + "expected": np.array([-11, -7, -3]), } # Flow in and out are equal, concentrations are equal TestCaseCSTRConc_equal = { "values": { - "c": np.array([0.1,]), - "c_dot": np.array([0,]), + "c": np.array([0.1]), + "c_dot": np.array([0]), "V": 1, "V_dot": 0, "Q_in": 1, "Q_out": 1, - "c_in": np.array([0.1,]) + "c_in": np.array([0.1]), }, - "expected": np.array([0,]) + "expected": np.array([0]), } # Flow in and out are equal, concentrations differ TestCaseCSTRConc_diffcin = { "values": { - "c": np.array([0.1,]), - "c_dot": np.array([0,]), + "c": np.array([0.1]), + "c_dot": np.array([0]), "V": 1.0, "V_dot": 0.0, "Q_in": 1.0, "Q_out": 1.0, - "c_in": np.array([0.2,]) + "c_in": np.array([0.2]), }, - "expected": np.array([-0.1,]) + "expected": np.array([-0.1]), } # Flow in and out differ, concentrations are equal TestCaseCSTRConc_diffvol = { "values": { - "c": np.array([0.1,]), - "c_dot": np.array([0,]), + "c": np.array([0.1]), + "c_dot": np.array([0]), "V": 1.0, "V_dot": 1.0, "Q_in": 2.0, "Q_out": 1.0, - "c_in": np.array([0.1,]) + "c_in": np.array([0.1]), }, - "expected": np.array([0,]) + "expected": np.array([0]), } # Flow in and out differ, concentrations differ TestCaseCSTRConc_diffvolc = { "values": { - "c": np.array([0.1,]), - "c_dot": np.array([0.2,]), + "c": np.array([0.1]), + "c_dot": np.array([0.2]), "V": 1.0, "V_dot": 1.0, "Q_in": 2.0, "Q_out": 1.0, - "c_in": np.array([0.2,]) + "c_in": np.array([0.2]), }, - "expected": np.array([0,]) + "expected": np.array([0]), } @@ -88,10 +88,10 @@ TestCaseCSTRConc_equal, TestCaseCSTRConc_diffcin, TestCaseCSTRConc_diffvol, - TestCaseCSTRConc_diffvolc - ] + TestCaseCSTRConc_diffvolc, + ], ) -class TestResidualConcCSTR(): +class TestResidualConcCSTR: """Class to test the Residual concentration function for cstr.""" def test_calculation_concentration_cstr(self, parameters): @@ -100,64 +100,33 @@ def test_calculation_concentration_cstr(self, parameters): np.testing.assert_array_almost_equal( calculate_residual_concentration_cstr(*param_vec_conc), - parameters["expected"] + parameters["expected"], ) # Arbitrary parameter values -TestCaseVol = { - "values": { - "V": 1, - "V_dot": 2, - "Q_in": 3, - "Q_out": 4, - }, - "expected": 3 -} +TestCaseVol = {"values": {"V": 1, "V_dot": 2, "Q_in": 3, "Q_out": 4}, "expected": 3} # Flow in and out are equal TestCaseVol_equal = { - "values": { - "V": 1, - "V_dot": 0, - "Q_in": 1, - "Q_out": 1, - }, - "expected": 0 + "values": {"V": 1, "V_dot": 0, "Q_in": 1, "Q_out": 1}, + "expected": 0, } # Flow in is larger than flow out TestCaseVol_inge = { - "values": { - "V": 1, - "V_dot": 1, - "Q_in": 2, - "Q_out": 1, - }, - "expected": 0 + "values": {"V": 1, "V_dot": 1, "Q_in": 2, "Q_out": 1}, + "expected": 0, } # Flow in is sameller than flow out TestCaseVol_inle = { - "values": { - "V": 1, - "V_dot": -1, - "Q_in": 1, - "Q_out": 2, - }, - "expected": 0 + "values": {"V": 1, "V_dot": -1, "Q_in": 1, "Q_out": 2}, + "expected": 0, } # Residual does not depend on volume -TestCaseVol_vol = { - "values": { - "V": 1, - "V_dot": 0, - "Q_in": 0, - "Q_out": 0, - }, - "expected": 0 -} +TestCaseVol_vol = {"values": {"V": 1, "V_dot": 0, "Q_in": 0, "Q_out": 0}, "expected": 0} @pytest.mark.parametrize( @@ -167,10 +136,10 @@ def test_calculation_concentration_cstr(self, parameters): TestCaseVol_equal, TestCaseVol_inge, TestCaseVol_inle, - TestCaseVol_vol - ] + TestCaseVol_vol, + ], ) -class TestResidualVolCSTR(): +class TestResidualVolCSTR: """Test class vor the residual volume function.""" def test_calculation_cstr(self, parameters): @@ -187,9 +156,9 @@ def test_calculation_cstr(self, parameters): "rejection": np.array([1, 1]), "molar_volume": np.array([1, 1]), "c_in": np.array([0.5, 0.5]), - "V_dot_C": 1.0 + "V_dot_C": 1.0, }, - "expected": 0 + "expected": 0, } @@ -200,9 +169,9 @@ def test_calculation_cstr(self, parameters): "rejection": np.array([0, 0]), "molar_volume": np.array([1, 1]), "c_in": np.array([0.5, 0.5]), - "V_dot_C": 0.0 + "V_dot_C": 0.0, }, - "expected": 0 + "expected": 0, } # Testcase 3: Membrane rejects only Component 2 @@ -212,9 +181,9 @@ def test_calculation_cstr(self, parameters): "rejection": np.array([0, 1]), "molar_volume": np.array([1, 1]), "c_in": np.array([0.5, 0.5]), - "V_dot_C": 0.5 + "V_dot_C": 0.5, }, - "expected": 0 + "expected": 0, } # Testcase 4: Component 2 is larger then 1 @@ -224,9 +193,9 @@ def test_calculation_cstr(self, parameters): "rejection": np.array([1, 1]), "molar_volume": np.array([0.5, 1]), "c_in": np.array([0.5, 0.5]), - "V_dot_C": 0.75 + "V_dot_C": 0.75, }, - "expected": 0 + "expected": 0, } @@ -236,19 +205,18 @@ def test_calculation_cstr(self, parameters): TestCaseDEFCake_rejects_all, TestCaseDEFCake_rejects_not, TestCaseDEFCake_rejects_2, - TestCaseDEFCake_C2_le_C1 - ] + TestCaseDEFCake_C2_le_C1, + ], ) @pytest.mark.skip(reason="completly different residual TODO: TESTING") -class TestResidualCakeVolDEF(): +class TestResidualCakeVolDEF: """Class for testing the CAKE volume residual fucntion.""" def test_calculation_def(self, parameters): """Test the residual cake function.""" param_vec_cake_vol = parameters["values"].values() np.testing.assert_equal( - calculate_residual_cake_vol_def(*param_vec_cake_vol), - parameters["expected"] + calculate_residual_cake_vol_def(*param_vec_cake_vol), parameters["expected"] ) @@ -263,7 +231,7 @@ def test_calculation_def(self, parameters): "Rm": 1, "alpha": 1, }, - "expected": 0 + "expected": 0, } # Case 2 : No cake yet @@ -277,19 +245,15 @@ def test_calculation_def(self, parameters): "Rm": 1, "alpha": 1, }, - "expected": 0 + "expected": 0, } @pytest.mark.parametrize( - "parameters", - [ - TestCaseDEFPressureDrop, - TestCaseDEFPressureDrop_no_cake - ] + "parameters", [TestCaseDEFPressureDrop, TestCaseDEFPressureDrop_no_cake] ) @pytest.mark.skip(reason="completly different residual TODO: TESTING") -class TestResidualPressureDropDEF(): +class TestResidualPressureDropDEF: """Test class for the residual pressure prop of dead end filtration model.""" def test_calculation_def(self, parameters): @@ -307,19 +271,14 @@ def test_calculation_def(self, parameters): "V_dot": 2, "Q_in": 3, "Q_out": 4, - "c_in": np.array([7, 8, 9]) + "c_in": np.array([7, 8, 9]), }, - "expected": np.array([-11, -7, -3]) + "expected": np.array([-11, -7, -3]), } -@pytest.mark.parametrize( - "parameters", - [ - TestCaseConcError - ] -) -class TestResidualError(): +@pytest.mark.parametrize("parameters", [TestCaseConcError]) +class TestResidualError: """Test class for error handling.""" def test_calculation_vol_cstr_error(self, parameters): diff --git a/tests/test_simulation.py b/tests/test_simulation.py index 774738f..0ba5753 100644 --- a/tests/test_simulation.py +++ b/tests/test_simulation.py @@ -3,11 +3,14 @@ from CADETPythonSimulator.distribution_base import ( - ConstantVolumeDistribution, ConstantConcentrationDistribution + ConstantVolumeDistribution, + ConstantConcentrationDistribution, ) from CADETPythonSimulator.unit_operation import ( - DistributionInlet, Outlet, DeadEndFiltration + DistributionInlet, + Outlet, + DeadEndFiltration, ) from CADETPythonSimulator.system import FlowSystem from CADETPythonSimulator.solver import Solver @@ -24,7 +27,7 @@ def setup_filter_sim(): densities=[1100, 1100, 1000], molecular_weights=[1e6, 8e4, 18], viscosities=[np.nan, np.nan, 0.001], - specific_cake_resistances=[1e6, 1e6, 0] + specific_cake_resistances=[1e6, 1e6, 0], ) # Concidering c3 is unknown. @@ -34,7 +37,7 @@ def setup_filter_sim(): inlet = DistributionInlet(component_system=component_system, name="inlet") inlet.distribution_function = concentration_distribution - rejectionmodell = StepCutOff(cutoff_weight=2*8e4) + rejectionmodell = StepCutOff(cutoff_weight=2 * 8e4) viscositymodell = LogarithmicMixingViscosity() filter_obj = DeadEndFiltration( component_system=component_system, @@ -43,22 +46,14 @@ def setup_filter_sim(): viscosity_model=viscositymodell, membrane_area=1, membrane_resistance=1, - ) + ) - #outlet = Outlet(component_system=component_system, name="outlet") + # outlet = Outlet(component_system=component_system, name="outlet") unit_operation_list = [inlet, filter_obj] system = FlowSystem(unit_operations=unit_operation_list) - section = [ - { - 'start': 0, - 'end': 11, - 'connections': [ - [0, 1, 0, 0, 1], - ], - } - ] + section = [{"start": 0, "end": 11, "connections": [[0, 1, 0, 0, 1]]}] system.initialize_state() @@ -71,18 +66,14 @@ def setup_filter_sim(): Setting startingvolume and accoding Concentrations are necessary. Permeate Tank must not be empty. """ - system.states['deadendfilter']['permeate_tank']['V'] = 1e-9 - system.states['deadendfilter']['permeate_tank']['c'] = c_init + system.states["deadendfilter"]["permeate_tank"]["V"] = 1e-9 + system.states["deadendfilter"]["permeate_tank"]["c"] = c_init solver = Solver(system, section) return solver -@pytest.mark.parametrize( - "setup_func, expected", - [ - (setup_filter_sim, 3), - ] -) + +@pytest.mark.parametrize("setup_func, expected", [(setup_filter_sim, 3)]) class Testsimulation: """Class tries to run an actual Simulation.""" diff --git a/tests/test_solver.py b/tests/test_solver.py index 81e1f87..9219f9e 100644 --- a/tests/test_solver.py +++ b/tests/test_solver.py @@ -4,7 +4,10 @@ from typing import NoReturn, Optional from test_unit_operation import ( - InletFixture, OutletFixture, CstrFixture, DeadEndFiltrationFixture + InletFixture, + OutletFixture, + CstrFixture, + DeadEndFiltrationFixture, ) from CADETProcess.dataStructure import Structure from CADETPythonSimulator.system import SystemBase, FlowSystem @@ -33,35 +36,19 @@ def __init__(self, system=None, sections=None, *args, **kwargs): if sections is None: sections = [ { - 'start': 0, - 'end': 10, - 'connections': [ - [0, 1, 1e-3], - [1, 2, 1e-3], - ], - 'section_states': { - 'inlet': { - 'c_poly': [ - [1, 0, 0, 0], - [2, 0, 0, 0], - ], - }, + "start": 0, + "end": 10, + "connections": [[0, 1, 1e-3], [1, 2, 1e-3]], + "section_states": { + "inlet": {"c_poly": [[1, 0, 0, 0], [2, 0, 0, 0]]} }, }, { - 'start': 10, - 'end': 12, - 'connections': [ - [0, 1, 1e-3], - [1, 2, 0.5e-3], - ], - 'section_states': { - 'inlet': { - 'c_poly': [ - [0, 1, 0, 0], - [1, 0, 0, 0], - ], - }, + "start": 10, + "end": 12, + "connections": [[0, 1, 1e-3], [1, 2, 0.5e-3]], + "section_states": { + "inlet": {"c_poly": [[0, 1, 0, 0], [1, 0, 0, 0]]} }, }, ] @@ -81,7 +68,7 @@ def __init__(self, unit_operations=None, *args, **kwargs): unit_operations = [ InletFixture(), DeadEndFiltrationFixture(), - OutletFixture() + OutletFixture(), ] super().__init__(unit_operations, *args, **kwargs) @@ -90,166 +77,162 @@ def __init__(self, unit_operations=None, *args, **kwargs): # %% State Structure solver_fixture_obj = SolverFixture() -rej_obj = \ - solver_fixture_obj.system.unit_operations['dead_end_filtration'].rejection_model -viscosity_obj = \ - solver_fixture_obj.system.unit_operations['dead_end_filtration'].viscosity_model +rej_obj = solver_fixture_obj.system.unit_operations[ + "dead_end_filtration" +].rejection_model +viscosity_obj = solver_fixture_obj.system.unit_operations[ + "dead_end_filtration" +].viscosity_model + + @pytest.mark.parametrize( "solver, expected", [ ( solver_fixture_obj, { - 'n_dof': 29, - 'unit_solution': { - 'inlet': { - 'outlet': { - 'c': { - 'values': np.array([[0., 1.], [0., 2.]]), - 'derivatives': np.array([[0., 2.], [0., 4.]]) - }, + "n_dof": 29, + "unit_solution": { + "inlet": { + "outlet": { + "c": { + "values": np.array([[0.0, 1.0], [0.0, 2.0]]), + "derivatives": np.array([[0.0, 2.0], [0.0, 4.0]]), + } } }, - 'dead_end_filtration': { - 'inlet':{ - 'c': { - 'values': np.array([[2., 3.], [4., 6.]]), - 'derivatives': np.array([[4., 6.], [8., 12.]]), + "dead_end_filtration": { + "inlet": { + "c": { + "values": np.array([[2.0, 3.0], [4.0, 6.0]]), + "derivatives": np.array([[4.0, 6.0], [8.0, 12.0]]), }, - 'n': { - 'values': np.array([[4., 5.], [8., 10.]]), - 'derivatives': np.array([[8., 10.], [16., 20.]]), + "n": { + "values": np.array([[4.0, 5.0], [8.0, 10.0]]), + "derivatives": np.array([[8.0, 10.0], [16.0, 20.0]]), }, }, - 'permeate': { - 'c': { - 'values': np.array([[6., 7.], [12., 14.]]), - 'derivatives': np.array([[12., 14. ], [24., 28.]]), + "permeate": { + "c": { + "values": np.array([[6.0, 7.0], [12.0, 14.0]]), + "derivatives": np.array([[12.0, 14.0], [24.0, 28.0]]), }, - 'n': { - 'values': np.array([[8., 9.], [16., 18.]]), - 'derivatives': np.array([[16., 18.], [32., 36]]), + "n": { + "values": np.array([[8.0, 9.0], [16.0, 18.0]]), + "derivatives": np.array([[16.0, 18.0], [32.0, 36]]), }, - 'V': { - 'values': np.array([[10.], [20.]]), - 'derivatives': np.array([[20.], [40.]]), + "V": { + "values": np.array([[10.0], [20.0]]), + "derivatives": np.array([[20.0], [40.0]]), }, }, - 'retentate': { - 'c': { - 'values': np.array([[11., 12.], [22., 24.]]), - 'derivatives': np.array([[22., 24.], [44., 48.]]), + "retentate": { + "c": { + "values": np.array([[11.0, 12.0], [22.0, 24.0]]), + "derivatives": np.array([[22.0, 24.0], [44.0, 48.0]]), }, - 'n': { - 'values': np.array([[13., 14.], [26., 28.]]), - 'derivatives': np.array([[26., 28.], [52., 56]]), + "n": { + "values": np.array([[13.0, 14.0], [26.0, 28.0]]), + "derivatives": np.array([[26.0, 28.0], [52.0, 56]]), }, - 'V': { - 'values': np.array([[15.], [30.]]), - 'derivatives': np.array([[30.], [60.]]), + "V": { + "values": np.array([[15.0], [30.0]]), + "derivatives": np.array([[30.0], [60.0]]), }, }, - 'cake': { - 'c': { - 'values': np.array([[16., 17.], [32., 34.]]), - 'derivatives': np.array([[32., 34.], [64., 68.]]), + "cake": { + "c": { + "values": np.array([[16.0, 17.0], [32.0, 34.0]]), + "derivatives": np.array([[32.0, 34.0], [64.0, 68.0]]), }, - 'n':{ - 'values': np.array([[18., 19.], [36., 38.]]), - 'derivatives': np.array([[36., 38.], [72., 76.]]), + "n": { + "values": np.array([[18.0, 19.0], [36.0, 38.0]]), + "derivatives": np.array([[36.0, 38.0], [72.0, 76.0]]), }, - 'V': { - 'values': np.array([[20.], [40.]]), - 'derivatives': np.array([[40.], [80.]]), + "V": { + "values": np.array([[20.0], [40.0]]), + "derivatives": np.array([[40.0], [80.0]]), }, - 'pressure': { - 'values': np.array([[21.], [42.]]), - 'derivatives': np.array([[42.], [84.]]), + "pressure": { + "values": np.array([[21.0], [42.0]]), + "derivatives": np.array([[42.0], [84.0]]), }, }, - 'permeate_tank': { - 'c': { - 'values': np.array([[22., 23.], [44., 46.]]), - 'derivatives': np.array([[44., 46.], [88., 92.]]), + "permeate_tank": { + "c": { + "values": np.array([[22.0, 23.0], [44.0, 46.0]]), + "derivatives": np.array([[44.0, 46.0], [88.0, 92.0]]), }, - 'n':{ - 'values': np.array([[24., 25.], [48., 50.]]), - 'derivatives': np.array([[48., 50.], [96., 100.]]), + "n": { + "values": np.array([[24.0, 25.0], [48.0, 50.0]]), + "derivatives": np.array([[48.0, 50.0], [96.0, 100.0]]), }, - 'V': { - 'values': np.array([[26.], [52.]]), - 'derivatives': np.array([[52.], [104.]]), - }, - } - }, - 'outlet': { - 'inlet': { - 'c': { - 'values': np.array([[27., 28.], [54., 56.]]), - 'derivatives': np.array([[54., 56.], [108., 112]]), + "V": { + "values": np.array([[26.0], [52.0]]), + "derivatives": np.array([[52.0], [104.0]]), }, }, }, + "outlet": { + "inlet": { + "c": { + "values": np.array([[27.0, 28.0], [54.0, 56.0]]), + "derivatives": np.array([[54.0, 56.0], [108.0, 112]]), + } + } + }, }, - 'section_states': { + "section_states": { 0: { - 'parameters_start': { - 'inlet': { - 'c_poly': np.array([1., 2.]), - }, - 'dead_end_filtration': { - 'rejection_model': rej_obj, - 'viscosity_model': viscosity_obj, - 'membrane_area': 1, - 'membrane_resistance': 1 + "parameters_start": { + "inlet": {"c_poly": np.array([1.0, 2.0])}, + "dead_end_filtration": { + "rejection_model": rej_obj, + "viscosity_model": viscosity_obj, + "membrane_area": 1, + "membrane_resistance": 1, }, - 'outlet': {}, + "outlet": {}, }, - 'parameters_end': { - 'inlet': { - 'c_poly': np.array([1., 2.]), + "parameters_end": { + "inlet": {"c_poly": np.array([1.0, 2.0])}, + "dead_end_filtration": { + "rejection_model": rej_obj, + "viscosity_model": viscosity_obj, + "membrane_area": 1, + "membrane_resistance": 1, }, - 'dead_end_filtration': { - 'rejection_model': rej_obj, - 'viscosity_model': viscosity_obj, - 'membrane_area': 1, - 'membrane_resistance': 1 - }, - 'outlet': {}, + "outlet": {}, }, }, 1: { - 'parameters_start': { - 'inlet': { - 'c_poly': np.array([0., 1.]), - }, - 'dead_end_filtration': { - 'rejection_model': rej_obj, - 'viscosity_model': viscosity_obj, - 'membrane_area': 1, - 'membrane_resistance': 1, + "parameters_start": { + "inlet": {"c_poly": np.array([0.0, 1.0])}, + "dead_end_filtration": { + "rejection_model": rej_obj, + "viscosity_model": viscosity_obj, + "membrane_area": 1, + "membrane_resistance": 1, }, - 'outlet': {}, + "outlet": {}, }, - 'parameters_end': { - 'inlet': { - 'c_poly': np.array([2., 1.]), - }, - 'dead_end_filtration': { - 'rejection_model': rej_obj, - 'viscosity_model': viscosity_obj, - 'membrane_area': 1, - 'membrane_resistance': 1, + "parameters_end": { + "inlet": {"c_poly": np.array([2.0, 1.0])}, + "dead_end_filtration": { + "rejection_model": rej_obj, + "viscosity_model": viscosity_obj, + "membrane_area": 1, + "membrane_resistance": 1, }, - 'outlet': {}, + "outlet": {}, }, }, }, }, - ), - ] + ) + ], ) -class TestSolver(): +class TestSolver: """Testing the Solver Object.""" def test_solution_recorder(self, solver: Solver, expected): @@ -277,29 +260,29 @@ def test_solution_recorder(self, solver: Solver, expected): for sol_type, sol_array in sol.items(): np.testing.assert_almost_equal( sol_array, - expected['unit_solution'][unit][state][d_of][sol_type] + expected["unit_solution"][unit][state][d_of][sol_type], ) def test_parameters(self, solver: Solver, expected): """Test updating of parameters.""" for i_sec, section in enumerate(solver.sections): solver._update_unit_operation_parameters( - section['start'], section['end'], section['section_states'] + section["start"], section["end"], section["section_states"] ) for unit in solver.system.unit_operations.values(): - expected_values = expected['section_states'][i_sec] + expected_values = expected["section_states"][i_sec] - values_start = unit.get_parameter_values_at_time(section['start']) + values_start = unit.get_parameter_values_at_time(section["start"]) np.testing.assert_equal( - values_start, expected_values['parameters_start'][str(unit)] + values_start, expected_values["parameters_start"][str(unit)] ) - values_end = unit.get_parameter_values_at_time(section['end']) + values_end = unit.get_parameter_values_at_time(section["end"]) np.testing.assert_equal( - values_end, expected_values['parameters_end'][str(unit)] + values_end, expected_values["parameters_end"][str(unit)] ) diff --git a/tests/test_state.py b/tests/test_state.py index 1179729..0069a02 100644 --- a/tests/test_state.py +++ b/tests/test_state.py @@ -8,346 +8,266 @@ [ ( { - 'name': 'outlet', - 'dimensions': {}, - 'entries': {'c': 2, 'viscosity': 1}, - 'n_outlet_ports': 1, + "name": "outlet", + "dimensions": {}, + "entries": {"c": 2, "viscosity": 1}, + "n_outlet_ports": 1, }, { - 'dimension_shape': (), - 'n_dimensions': 0, - 'n_cells': 1, - 'n_entries': 3, - 'shape': (3,), - 'n_dof': 3, - 'n_inlet_ports': 0, - 'inlet_port_mapping': None, - 'n_outlet_ports': 1, - 'outlet_port_mapping': None, - 's_split': { - 'c': { - 'slice': np.s_[:], - 'value': [0, 1] - }, - 'viscosity': { - 'slice': np.s_[:], - 'value': [2], - }, - }, - 'outlet_state': { - 0: { - 'c': [0, 1], - 'viscosity': [2] - }, + "dimension_shape": (), + "n_dimensions": 0, + "n_cells": 1, + "n_entries": 3, + "shape": (3,), + "n_dof": 3, + "n_inlet_ports": 0, + "inlet_port_mapping": None, + "n_outlet_ports": 1, + "outlet_port_mapping": None, + "s_split": { + "c": {"slice": np.s_[:], "value": [0, 1]}, + "viscosity": {"slice": np.s_[:], "value": [2]}, }, + "outlet_state": {0: {"c": [0, 1], "viscosity": [2]}}, }, ), ( { - 'name': 'inlet', - 'dimensions': {}, - 'entries': {'c': 2, 'viscosity': 1}, - 'n_inlet_ports': 1, + "name": "inlet", + "dimensions": {}, + "entries": {"c": 2, "viscosity": 1}, + "n_inlet_ports": 1, }, { - 'dimension_shape': (), - 'n_dimensions': 0, - 'n_cells': 1, - 'n_entries': 3, - 'shape': (3,), - 'n_dof': 3, - 'n_inlet_ports': 1, - 'inlet_port_mapping': None, - 'n_outlet_ports': 0, - 'outlet_port_mapping': None, - 's_split': { - 'c': { - 'slice': np.s_[:], - 'value': [0, 1] - }, - 'viscosity': { - 'slice': np.s_[:], - 'value': [2], - }, - }, - 'inlet_state': { - 0: { - 'slice': np.s_[:], - 'value': [.1, .2, .3], - }, + "dimension_shape": (), + "n_dimensions": 0, + "n_cells": 1, + "n_entries": 3, + "shape": (3,), + "n_dof": 3, + "n_inlet_ports": 1, + "inlet_port_mapping": None, + "n_outlet_ports": 0, + "outlet_port_mapping": None, + "s_split": { + "c": {"slice": np.s_[:], "value": [0, 1]}, + "viscosity": {"slice": np.s_[:], "value": [2]}, }, + "inlet_state": {0: {"slice": np.s_[:], "value": [0.1, 0.2, 0.3]}}, }, ), ( { - 'name': 'permeate', - 'dimensions': {'axial': 10}, - 'entries': {'c': 2, 'viscosity': 1}, - 'n_outlet_ports': 1, + "name": "permeate", + "dimensions": {"axial": 10}, + "entries": {"c": 2, "viscosity": 1}, + "n_outlet_ports": 1, }, { - 'dimension_shape': (10,), - 'n_dimensions': 1, - 'n_cells': 10, - 'n_entries': 3, - 'shape': (10, 3), - 'n_dof': 30, - 'n_inlet_ports': 0, - 'inlet_port_mapping': None, - 'n_outlet_ports': 1, - 'outlet_port_mapping': None, - 's_split': { - 'c': { - 'slice': np.s_[:], - 'value': [ - [ 0, 1], - [ 3, 4], - [ 6, 7], - [ 9, 10], + "dimension_shape": (10,), + "n_dimensions": 1, + "n_cells": 10, + "n_entries": 3, + "shape": (10, 3), + "n_dof": 30, + "n_inlet_ports": 0, + "inlet_port_mapping": None, + "n_outlet_ports": 1, + "outlet_port_mapping": None, + "s_split": { + "c": { + "slice": np.s_[:], + "value": [ + [0, 1], + [3, 4], + [6, 7], + [9, 10], [12, 13], [15, 16], [18, 19], [21, 22], [24, 25], - [27, 28] + [27, 28], ], }, - 'viscosity': { - 'slice': np.s_[:], - 'value': [ - [ 2], - [ 5], - [ 8], + "viscosity": { + "slice": np.s_[:], + "value": [ + [2], + [5], + [8], [11], [14], [17], [20], [23], [26], - [29] - ] - }, - }, - 'outlet_state': { - 0: { - 'c': [27, 28], - 'viscosity': [29] + [29], + ], }, }, + "outlet_state": {0: {"c": [27, 28], "viscosity": [29]}}, }, ), ( { - 'name': 'bulk', - 'dimensions': {'axial': 10}, - 'entries': {'c': 2, 'viscosity': 1}, - 'n_inlet_ports': 1, - 'n_outlet_ports': 1, + "name": "bulk", + "dimensions": {"axial": 10}, + "entries": {"c": 2, "viscosity": 1}, + "n_inlet_ports": 1, + "n_outlet_ports": 1, }, { - 'dimension_shape': (10,), - 'n_dimensions': 1, - 'n_cells': 10, - 'n_entries': 3, - 'shape': (10, 3), - 'n_dof': 30, - 'n_inlet_ports': 1, - 'inlet_port_mapping': None, - 'n_outlet_ports': 1, - 'outlet_port_mapping': None, - 's_split': { - 'c': { - 'slice': np.s_[:], - 'value': [ - [ 0, 1], - [ 3, 4], - [ 6, 7], - [ 9, 10], + "dimension_shape": (10,), + "n_dimensions": 1, + "n_cells": 10, + "n_entries": 3, + "shape": (10, 3), + "n_dof": 30, + "n_inlet_ports": 1, + "inlet_port_mapping": None, + "n_outlet_ports": 1, + "outlet_port_mapping": None, + "s_split": { + "c": { + "slice": np.s_[:], + "value": [ + [0, 1], + [3, 4], + [6, 7], + [9, 10], [12, 13], [15, 16], [18, 19], [21, 22], [24, 25], - [27, 28] + [27, 28], ], }, - 'viscosity': { - 'slice': np.s_[:], - 'value': [ - [ 2], - [ 5], - [ 8], + "viscosity": { + "slice": np.s_[:], + "value": [ + [2], + [5], + [8], [11], [14], [17], [20], [23], [26], - [29] - ] + [29], + ], }, }, - 'inlet_state': { + "inlet_state": { 0: { - 'slice': np.s_[:], - 'value': [ - [.1, .2, .3], - [ 3, 4, 5], - [ 6, 7, 8], - [ 9, 10, 11], + "slice": np.s_[:], + "value": [ + [0.1, 0.2, 0.3], + [3, 4, 5], + [6, 7, 8], + [9, 10, 11], [12, 13, 14], [15, 16, 17], [18, 19, 20], [21, 22, 23], [24, 25, 26], - [27, 28, 29]], - }, - }, - 'outlet_state': { - 0: { - 'c': [27, 28], - 'viscosity': [29] - }, + [27, 28, 29], + ], + } }, - } + "outlet_state": {0: {"c": [27, 28], "viscosity": [29]}}, + }, ), ( { - 'name': '_2d_bulk', - 'dimensions': {'axial': 10, 'radial': 3}, - 'entries': {'c': 2, 'viscosity': 1}, - 'n_inlet_ports': 'radial', - 'n_outlet_ports': 'radial', + "name": "_2d_bulk", + "dimensions": {"axial": 10, "radial": 3}, + "entries": {"c": 2, "viscosity": 1}, + "n_inlet_ports": "radial", + "n_outlet_ports": "radial", }, { - 'dimension_shape': (10, 3), - 'n_dimensions': 2, - 'n_cells': 30, - 'n_entries': 3, - 'shape': (10, 3, 3), - 'n_dof': 90, - 'n_inlet_ports': 3, - 'inlet_port_mapping': 'radial', - 'n_outlet_ports': 3, - 'outlet_port_mapping': 'radial', - 's_split': { - 'c': { - 'slice': np.s_[0:3, 0:3, :], - 'value': [ - [[ 0, 1], - [ 3, 4], - [ 6, 7]], - - [[ 9, 10], - [12, 13], - [15, 16]], - - [[18, 19], - [21, 22], - [24, 25]] + "dimension_shape": (10, 3), + "n_dimensions": 2, + "n_cells": 30, + "n_entries": 3, + "shape": (10, 3, 3), + "n_dof": 90, + "n_inlet_ports": 3, + "inlet_port_mapping": "radial", + "n_outlet_ports": 3, + "outlet_port_mapping": "radial", + "s_split": { + "c": { + "slice": np.s_[0:3, 0:3, :], + "value": [ + [[0, 1], [3, 4], [6, 7]], + [[9, 10], [12, 13], [15, 16]], + [[18, 19], [21, 22], [24, 25]], ], }, - 'viscosity': { - 'slice': np.s_[0:3, 0:3, :], - 'value': [ - [[ 2], - [ 5], - [ 8]], - - [[11], - [14], - [17]], - - [[20], - [23], - [26]] + "viscosity": { + "slice": np.s_[0:3, 0:3, :], + "value": [ + [[2], [5], [8]], + [[11], [14], [17]], + [[20], [23], [26]], ], }, }, - 'inlet_state': { + "inlet_state": { 0: { - 'slice': np.s_[0:3, 0:3, :], - 'value': [ - [[.1, .2, .3], - [ 3, 4, 5], - [ 6, 7, 8]], - - [[ 9, 10, 11], - [12, 13, 14], - [15, 16, 17]], - - [[18, 19, 20], - [21, 22, 23], - [24, 25, 26]] - ] + "slice": np.s_[0:3, 0:3, :], + "value": [ + [[0.1, 0.2, 0.3], [3, 4, 5], [6, 7, 8]], + [[9, 10, 11], [12, 13, 14], [15, 16, 17]], + [[18, 19, 20], [21, 22, 23], [24, 25, 26]], + ], }, 1: { - 'slice': np.s_[0:3, 0:3, :], - 'value': [ - [[.1, .2, .3], - [.1, .2, .3], - [ 6, 7, 8]], - - [[ 9, 10, 11], - [12, 13, 14], - [15, 16, 17]], - - [[18, 19, 20], - [21, 22, 23], - [24, 25, 26]] - ] + "slice": np.s_[0:3, 0:3, :], + "value": [ + [[0.1, 0.2, 0.3], [0.1, 0.2, 0.3], [6, 7, 8]], + [[9, 10, 11], [12, 13, 14], [15, 16, 17]], + [[18, 19, 20], [21, 22, 23], [24, 25, 26]], + ], }, 2: { - 'slice': np.s_[0:3, 0:3, :], - 'value': [ - [[.1, .2, .3], - [.1, .2, .3], - [.1, .2, .3]], - - [[ 9, 10, 11], - [12, 13, 14], - [15, 16, 17]], - - [[18, 19, 20], - [21, 22, 23], - [24, 25, 26]] - ] + "slice": np.s_[0:3, 0:3, :], + "value": [ + [[0.1, 0.2, 0.3], [0.1, 0.2, 0.3], [0.1, 0.2, 0.3]], + [[9, 10, 11], [12, 13, 14], [15, 16, 17]], + [[18, 19, 20], [21, 22, 23], [24, 25, 26]], + ], }, }, - 'outlet_state': { - 0: { - 'c': [81, 82], - 'viscosity': [83], - }, - 1: { - 'c': [84, 85], - 'viscosity': [86], - }, - 2: { - 'c': [87, 88], - 'viscosity': [89], - }, + "outlet_state": { + 0: {"c": [81, 82], "viscosity": [83]}, + 1: {"c": [84, 85], "viscosity": [86]}, + 2: {"c": [87, 88], "viscosity": [89]}, }, }, ), - ] + ], ) -class TestState(): +class TestState: """Test state class.""" def test_state_dimensions(self, state_config, expected): """Test if state parameters are set correctly.""" state = State(**state_config) - assert state.dimension_shape == expected['dimension_shape'] - assert state.n_dimensions == expected['n_dimensions'] - assert state.n_cells == expected['n_cells'] - assert state.n_entries == expected['n_entries'] - assert state.shape == expected['shape'] - assert state.n_dof == expected['n_dof'] - assert state.n_inlet_ports == expected['n_inlet_ports'] - assert state.inlet_port_mapping == expected['inlet_port_mapping'] - assert state.n_outlet_ports == expected['n_outlet_ports'] - assert state.outlet_port_mapping == expected['outlet_port_mapping'] + assert state.dimension_shape == expected["dimension_shape"] + assert state.n_dimensions == expected["n_dimensions"] + assert state.n_cells == expected["n_cells"] + assert state.n_entries == expected["n_entries"] + assert state.shape == expected["shape"] + assert state.n_dof == expected["n_dof"] + assert state.n_inlet_ports == expected["n_inlet_ports"] + assert state.inlet_port_mapping == expected["inlet_port_mapping"] + assert state.n_outlet_ports == expected["n_outlet_ports"] + assert state.outlet_port_mapping == expected["outlet_port_mapping"] def test_s_split(self, state_config, expected): """Tests if state spltitting works as intended.""" @@ -359,14 +279,11 @@ def test_s_split(self, state_config, expected): np.testing.assert_array_equal(state.s_flat, new_state.reshape(-1)) s_split = state.s_split - for entry, slice_information in expected['s_split'].items(): - split_slice = s_split[entry][slice_information['slice']] - np.testing.assert_array_equal(split_slice, slice_information['value']) + for entry, slice_information in expected["s_split"].items(): + split_slice = s_split[entry][slice_information["slice"]] + np.testing.assert_array_equal(split_slice, slice_information["value"]) - s_in = { - 'c': [.1, .2], - 'viscosity': [.3], - } + s_in = {"c": [0.1, 0.2], "viscosity": [0.3]} if state.n_inlet_ports == 0: with pytest.raises(Exception): state.set_inlet_port_state(s_in, 0) @@ -374,9 +291,9 @@ def test_s_split(self, state_config, expected): for port in range(state.n_inlet_ports): state.set_inlet_port_state(s_in, port) - slice_information = expected['inlet_state'][port] - state_slice = state.s[slice_information['slice']] - np.testing.assert_array_equal(state_slice, slice_information['value']) + slice_information = expected["inlet_state"][port] + state_slice = state.s[slice_information["slice"]] + np.testing.assert_array_equal(state_slice, slice_information["value"]) if state.n_outlet_ports == 0: with pytest.raises(Exception): @@ -384,7 +301,7 @@ def test_s_split(self, state_config, expected): else: for port in range(state.n_outlet_ports): s_out = state.get_outlet_port_state(port) - np.testing.assert_equal(s_out, expected['outlet_state'][port]) + np.testing.assert_equal(s_out, expected["outlet_state"][port]) # %% Test coupling structure diff --git a/tests/test_system.py b/tests/test_system.py index cf19429..c82fc3f 100644 --- a/tests/test_system.py +++ b/tests/test_system.py @@ -11,124 +11,132 @@ ( SystemFixture(), { - 'n_dof': 29, - 'unit_slices': { - 'inlet': slice(0, 2, None), - 'dead_end_filtration': slice(2, 11, None), - 'outlet': slice(11, 13, None), + "n_dof": 29, + "unit_slices": { + "inlet": slice(0, 2, None), + "dead_end_filtration": slice(2, 11, None), + "outlet": slice(11, 13, None), }, - 'unit_solution': { - 'inlet': { - 'c_out': np.array([[0., 1.], [0., 2.]]), - 'c_out_dot': np.array([[ 0., 2.], [0., 4.]]), + "unit_solution": { + "inlet": { + "c_out": np.array([[0.0, 1.0], [0.0, 2.0]]), + "c_out_dot": np.array([[0.0, 2.0], [0.0, 4.0]]), }, - 'dead_end_filtration': { - 'c_in': np.array([[ 2., 3.], [4., 6.]]), - 'c_in_dot': np.array([[ 4., 6.], [8., 12.]]), - 'Vp': np.array([[ 4.], [8.]]), - 'Vp_dot': np.array([[8.], [16.]]), - 'Rc': np.array([[5.], [10.]]), - 'Rc_dot': np.array([[10.], [20.]]), - 'mc': np.array([[6., 7.], [12., 14.]]), - 'mc_dot': np.array([[12., 14.], [24., 28.]]), - 'c_out': np.array([[8., 9.], [16., 18.]]), - 'c_out_dot': np.array([[16., 18.], [32., 36.]]), + "dead_end_filtration": { + "c_in": np.array([[2.0, 3.0], [4.0, 6.0]]), + "c_in_dot": np.array([[4.0, 6.0], [8.0, 12.0]]), + "Vp": np.array([[4.0], [8.0]]), + "Vp_dot": np.array([[8.0], [16.0]]), + "Rc": np.array([[5.0], [10.0]]), + "Rc_dot": np.array([[10.0], [20.0]]), + "mc": np.array([[6.0, 7.0], [12.0, 14.0]]), + "mc_dot": np.array([[12.0, 14.0], [24.0, 28.0]]), + "c_out": np.array([[8.0, 9.0], [16.0, 18.0]]), + "c_out_dot": np.array([[16.0, 18.0], [32.0, 36.0]]), }, - 'outlet': { - 'c_in': np.array([[10., 11.], [20., 22.]]), - 'c_in_dot': np.array([[20., 22.], [40., 44.]]), + "outlet": { + "c_in": np.array([[10.0, 11.0], [20.0, 22.0]]), + "c_in_dot": np.array([[20.0, 22.0], [40.0, 44.0]]), }, }, - 'section_states': { + "section_states": { 0: { - 'parameters_start': { - 'inlet': { - 'c': np.array([1., 2.]), - }, - 'dead_end_filtration': {}, - 'outlet': {}, + "parameters_start": { + "inlet": {"c": np.array([1.0, 2.0])}, + "dead_end_filtration": {}, + "outlet": {}, }, - 'parameters_end': { - 'inlet': { - 'c': np.array([1., 2.]), - }, - 'dead_end_filtration': {}, - 'outlet': {}, + "parameters_end": { + "inlet": {"c": np.array([1.0, 2.0])}, + "dead_end_filtration": {}, + "outlet": {}, }, }, 1: { - 'parameters_start': { - 'inlet': { - 'c': np.array([0., 1.]), - }, - 'dead_end_filtration': {}, - 'outlet': {}, + "parameters_start": { + "inlet": {"c": np.array([0.0, 1.0])}, + "dead_end_filtration": {}, + "outlet": {}, }, - 'parameters_end': { - 'inlet': { - 'c': np.array([2., 1.]), - }, - 'dead_end_filtration': {}, - 'outlet': {}, + "parameters_end": { + "inlet": {"c": np.array([2.0, 1.0])}, + "dead_end_filtration": {}, + "outlet": {}, }, }, }, }, - ), - ] + ) + ], ) -class TestSystem(): +class TestSystem: """Test Class for system.""" def test_system_structure(self, system, expected): """Test system structure.""" - assert system.n_dof == expected['n_dof'] + assert system.n_dof == expected["n_dof"] # %% System Connectivity + @pytest.mark.parametrize( "system, connections, expected_matrix, expected_state", [ ( SystemFixture(), [[0, 1, 0, 0, 1e-3], [1, 2, 0, 0, 1e-3]], + [[0.001, 0.0], [0.0, 0.001]], [ - [0.001, 0. ], - [0. , 0.001] - ], - [ - 0, 1, 0, 1, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 22, 23 + 0, + 1, + 0, + 1, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 22, + 23, ], - ), - ] + ) + ], # TODO: Add tests with split/combined streams. # TODO: Add tests with recycling streams. => Iteration required? # TODO: Add tests with multiple ports. ) -class TestSystemConnectivity(): +class TestSystemConnectivity: """Test system connectivity class.""" def test_connections_matrix( - self, - system: SystemBase, - connections, - expected_matrix, - expected_state - ): + self, system: SystemBase, connections, expected_matrix, expected_state + ): """Test for computing the connectivity.""" system._compute_connectivity_matrix(connections) np.testing.assert_almost_equal(system._connectivity, expected_matrix) def test_coupling( - self, - system: SystemBase, - connections, - expected_matrix, - expected_state - ): + self, system: SystemBase, connections, expected_matrix, expected_state + ): """Test for updating and coupling the system connectivity.""" y = np.arange(system.n_dof) y_dot = 2 * y @@ -140,6 +148,7 @@ def test_coupling( system.couple_unit_operations() np.testing.assert_almost_equal(system.y, expected_state) + @pytest.mark.parametrize( "system, connections, initial_values, expected_state", [ @@ -147,32 +156,80 @@ def test_coupling( SystemFixture(), [[0, 1, 0, 0, 1e-3], [1, 2, 0, 0, 1e-3]], [ - 0, 1, 0, 1, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 22, 23 + 0, + 1, + 0, + 1, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 22, + 23, ], [ - 0, 1, 0, 1, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 22, 23 + 0, + 1, + 0, + 1, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 22, + 23, ], - ), - ] + ) + ], ) -class TestSystemInitializeInitialValue(): +class TestSystemInitializeInitialValue: """Class to test the Initialization of Initial Values.""" def test_initialize( - self, - system: SystemBase, - connections, - initial_values, - expected_state - ): + self, system: SystemBase, connections, initial_values, expected_state + ): """Test to check calculation of Initial Values.""" system.y = initial_values system.update_system_connectivity(connections) - #system.initialize_initial_values(0) + # system.initialize_initial_values(0) # %% TODO: System Residual diff --git a/tests/test_unit_operation.py b/tests/test_unit_operation.py index 2ab2862..66ecd4b 100644 --- a/tests/test_unit_operation.py +++ b/tests/test_unit_operation.py @@ -7,10 +7,12 @@ from CADETPythonSimulator.unit_operation import ( UnitOperationBase, - Inlet, Outlet, + Inlet, + Outlet, Cstr, - DeadEndFiltration, CrossFlowFiltration, - _2DGRM + DeadEndFiltration, + CrossFlowFiltration, + _2DGRM, ) from CADETPythonSimulator.rejection import StepCutOff @@ -26,25 +28,18 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.add_component( - 'A', - molecular_weight=1e3, - density=1e3, - molecular_volume=1, - viscosity=1 - ) + "A", molecular_weight=1e3, density=1e3, molecular_volume=1, viscosity=1 + ) self.add_component( - 'B', - molecular_weight=10e3, - density=1e3, - molecular_volume=1, - viscosity=1 - ) + "B", molecular_weight=10e3, density=1e3, molecular_volume=1, viscosity=1 + ) class UnitOperationFixture(UnitOperationBase): """Unit Operation Fixture Class for testing purpose.""" class_cps = TwoComponentFixture() + def __init__(self, component_system, name, *args, **kwargs): """Initialize the unit operation.""" if component_system is None: @@ -60,18 +55,19 @@ def initialize_state(self) -> NoReturn: super().initialize_state() self.add_section() + class InletFixture(UnitOperationFixture, Inlet): """Inlet fixture class for testing purpose, inherits from UnitOperationFixture.""" def __init__( - self, - component_system=None, - name='inlet', - c_poly=None, - viscosity=1e-3, - *args, - **kwargs - ): + self, + component_system=None, + name="inlet", + c_poly=None, + viscosity=1e-3, + *args, + **kwargs, + ): """Initialize class for inlet fixture.""" super().__init__(component_system, name, *args, **kwargs) @@ -85,13 +81,13 @@ def add_section(self, c_poly=None, start=0, end=1): """For testing purpose, c_poly is set.""" if c_poly is None: c_poly = self.c_poly - self.update_parameters(start, end, {'c_poly': c_poly}) + self.update_parameters(start, end, {"c_poly": c_poly}) class OutletFixture(UnitOperationFixture, Outlet): """Oulet fixture class for testing purpose, inherits from UnitOperationFixture.""" - def __init__(self, component_system=None, name='outlet', *args, **kwargs): + def __init__(self, component_system=None, name="outlet", *args, **kwargs): """Initialize the outlet fixture.""" super().__init__(component_system, name, *args, **kwargs) @@ -99,7 +95,7 @@ def __init__(self, component_system=None, name='outlet', *args, **kwargs): class CstrFixture(UnitOperationFixture, Cstr): """Cstr fixture class for testing purpose, inherits from UnitOperationFixture.""" - def __init__(self, component_system=None, name='cstr', *args, **kwargs): + def __init__(self, component_system=None, name="cstr", *args, **kwargs): """Initialize the cstr fixture.""" super().__init__(component_system, name, *args, **kwargs) @@ -107,18 +103,19 @@ def __init__(self, component_system=None, name='cstr', *args, **kwargs): class DeadEndFiltrationFixture(UnitOperationFixture, DeadEndFiltration): """DEF fixture class for testing purpose, inherits from UnitOperationFixture.""" - def __init__(self, - component_system=None, - name='dead_end_filtration', - membrane_area=1, - membrane_resistance=1, - specific_cake_resistance=1, - solution_viscosity=1, - rejection_model=StepCutOff(cutoff_weight=0), - viscosity_model=LogarithmicMixingViscosity(), - *args, - **kwargs - ): + def __init__( + self, + component_system=None, + name="dead_end_filtration", + membrane_area=1, + membrane_resistance=1, + specific_cake_resistance=1, + solution_viscosity=1, + rejection_model=StepCutOff(cutoff_weight=0), + viscosity_model=LogarithmicMixingViscosity(), + *args, + **kwargs, + ): """Initialize DEF fixture with default parameter and default rejection.""" super().__init__(component_system, name, *args, **kwargs) @@ -133,14 +130,15 @@ def __init__(self, class CrossFlowFiltrationFixture(UnitOperationFixture, CrossFlowFiltration): """CFF fixture class for testing purpose, inherits from UnitOperationFixture.""" - def __init__(self, - component_system=None, - name='cross_flow_filtration', - membrane_area=1, - membrane_resistance=1e-9, - *args, - **kwargs - ): + def __init__( + self, + component_system=None, + name="cross_flow_filtration", + membrane_area=1, + membrane_resistance=1e-9, + *args, + **kwargs, + ): """Initialize CFF fixture with default parameter and defaultrejection.""" super().__init__(component_system, name, *args, **kwargs) @@ -149,117 +147,79 @@ def __init__(self, class _2DGRMFixture(UnitOperationFixture, _2DGRM): - def __init__(self, - component_system=None, - name='2DGRM', - *args, - **kwargs - ): + def __init__(self, component_system=None, name="2DGRM", *args, **kwargs): super().__init__(component_system, name, *args, **kwargs) # %% Unit Operation State Structure + @pytest.mark.parametrize( "unit_operation, expected", [ ( InletFixture(), { - 'n_inlet_ports': 0, - 'n_outlet_ports': 1, - 'n_dof': 2, - 'states': { - 'outlet': [0., 1.], - }, - 'outlet_state': { - 0: { - 'c': [0., 1.], - }, - }, + "n_inlet_ports": 0, + "n_outlet_ports": 1, + "n_dof": 2, + "states": {"outlet": [0.0, 1.0]}, + "outlet_state": {0: {"c": [0.0, 1.0]}}, }, - ), ( OutletFixture(), { - 'n_inlet_ports': 1, - 'n_outlet_ports': 0, - 'n_dof': 2, - 'states': { - 'inlet': [0., 1.], - }, - 'inlet_state': { - 0: { - 'slice': np.s_[:], - 'value': [.1, .2], - }, - }, + "n_inlet_ports": 1, + "n_outlet_ports": 0, + "n_dof": 2, + "states": {"inlet": [0.0, 1.0]}, + "inlet_state": {0: {"slice": np.s_[:], "value": [0.1, 0.2]}}, }, ), ( CstrFixture(), { - 'n_inlet_ports': 1, - 'n_outlet_ports': 1, - 'n_dof': 5, - 'states': { - 'inlet': [0., 1.], - 'bulk': [2., 3., 4.], - }, - 'inlet_state': { - 0: { - 'slice': np.s_[:], - 'value': [.1, .2, 2., 3., 4.], - }, - }, - 'outlet_state': { - 0: { - 'c': [2., 3.], - 'Volume': [4.], - }, + "n_inlet_ports": 1, + "n_outlet_ports": 1, + "n_dof": 5, + "states": {"inlet": [0.0, 1.0], "bulk": [2.0, 3.0, 4.0]}, + "inlet_state": { + 0: {"slice": np.s_[:], "value": [0.1, 0.2, 2.0, 3.0, 4.0]} }, + "outlet_state": {0: {"c": [2.0, 3.0], "Volume": [4.0]}}, }, ), ( DeadEndFiltrationFixture(), { - 'n_inlet_ports': 1, - 'n_outlet_ports': 1, - 'n_dof': 25, - 'states': { - 'inlet': [0., 1., 2., 3.], - 'permeate': [4., 5., 6., 7., 8.], - 'retentate': [9., 10., 11., 12., 13.], - 'cake': [14., 15., 16., 17., 18., 19.], - 'permeate_tank': [20., 21., 22., 23., 24.], + "n_inlet_ports": 1, + "n_outlet_ports": 1, + "n_dof": 25, + "states": { + "inlet": [0.0, 1.0, 2.0, 3.0], + "permeate": [4.0, 5.0, 6.0, 7.0, 8.0], + "retentate": [9.0, 10.0, 11.0, 12.0, 13.0], + "cake": [14.0, 15.0, 16.0, 17.0, 18.0, 19.0], + "permeate_tank": [20.0, 21.0, 22.0, 23.0, 24.0], }, - 'inlet_state': { - 0: { - 'slice': np.s_[0:4], - 'value': [.1, .2, 2., 3.], - }, - }, - 'outlet_state': { - 0: { - 'c': [20., 21], - 'n': [22., 23.], - 'V': [24], - }, + "inlet_state": { + 0: {"slice": np.s_[0:4], "value": [0.1, 0.2, 2.0, 3.0]} }, + "outlet_state": {0: {"c": [20.0, 21], "n": [22.0, 23.0], "V": [24]}}, }, ), ( CrossFlowFiltrationFixture(), { - 'n_inlet_ports': 1, - 'n_outlet_ports': 2, - 'n_dof': 80, - 'states': { - 'retentate': [ - [ 0, 1, 2, 3], - [ 4, 5, 6, 7], - [ 8, 9, 10, 11], + "n_inlet_ports": 1, + "n_outlet_ports": 2, + "n_dof": 80, + "states": { + "retentate": [ + [0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23], @@ -268,7 +228,7 @@ def __init__(self, [32, 33, 34, 35], [36, 37, 38, 39], ], - 'permeate': [ + "permeate": [ [40, 41, 42, 43], [44, 45, 46, 47], [48, 49, 50, 51], @@ -281,23 +241,15 @@ def __init__(self, [76, 77, 78, 79], ], }, - 'inlet_state': { + "inlet_state": { 0: { - 'slice': np.s_[0:10], - 'value': [.1, .2, .3, 3., 4., 5., 6., 7., 8., 9.], - }, + "slice": np.s_[0:10], + "value": [0.1, 0.2, 0.3, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0], + } }, - 'outlet_state': { - 0: { - 'c': [36., 37.], - 'viscosity': [38.], - 'Volume': [39.], - }, - 1: { - 'c': [76., 77.], - 'viscosity': [78.], - 'Volume': [79.], - }, + "outlet_state": { + 0: {"c": [36.0, 37.0], "viscosity": [38.0], "Volume": [39.0]}, + 1: {"c": [76.0, 77.0], "viscosity": [78.0], "Volume": [79.0]}, }, }, ), @@ -335,7 +287,7 @@ def __init__(self, # }, # }, # ), - ] + ], ) class TestUnitStateStructure: """Test class for unit state structure.""" @@ -348,9 +300,9 @@ def test_initialize(self, unit_operation: UnitOperationBase, expected: dict): def test_state_structure(self, unit_operation: UnitOperationBase, expected: dict): """Initialize the unit operation and test structure.""" unit_operation.initialize_state() - assert unit_operation.n_inlet_ports == expected['n_inlet_ports'] - assert unit_operation.n_outlet_ports == expected['n_outlet_ports'] - assert unit_operation.n_dof == expected['n_dof'] + assert unit_operation.n_inlet_ports == expected["n_inlet_ports"] + assert unit_operation.n_outlet_ports == expected["n_outlet_ports"] + assert unit_operation.n_dof == expected["n_dof"] def test_states(self, unit_operation: UnitOperationBase, expected: dict): """Test state and directly state setting.""" @@ -358,18 +310,13 @@ def test_states(self, unit_operation: UnitOperationBase, expected: dict): unit_operation.y = y_new for name, state in unit_operation.states.items(): - np.testing.assert_equal(state.s, expected['states'][name]) + np.testing.assert_equal(state.s, expected["states"][name]) def test_set_inlet_state(self, unit_operation: UnitOperationBase, expected: dict): """Test set_inlet_state_flat function.""" - s_in = { - 'c': [.1, .2], - } - if 'viscosity' in unit_operation.coupling_state_structure: - s_in = { - 'c': [.1, .2], - 'viscosity': [.3], - } + s_in = {"c": [0.1, 0.2]} + if "viscosity" in unit_operation.coupling_state_structure: + s_in = {"c": [0.1, 0.2], "viscosity": [0.3]} if unit_operation.n_inlet_ports == 0: with pytest.raises(Exception): unit_operation.set_inlet_port_state(s_in, 0) @@ -377,9 +324,9 @@ def test_set_inlet_state(self, unit_operation: UnitOperationBase, expected: dict for port in range(unit_operation.n_inlet_ports): unit_operation.set_inlet_state_flat(s_in, port) - slice_information = expected['inlet_state'][port] - state_slice = unit_operation.y[slice_information['slice']] - np.testing.assert_array_equal(state_slice, slice_information['value']) + slice_information = expected["inlet_state"][port] + state_slice = unit_operation.y[slice_information["slice"]] + np.testing.assert_array_equal(state_slice, slice_information["value"]) def test_get_outlet_state(self, unit_operation: UnitOperationBase, expected: dict): """Test getter for outlet state.""" @@ -389,7 +336,7 @@ def test_get_outlet_state(self, unit_operation: UnitOperationBase, expected: dic else: for port in range(unit_operation.n_outlet_ports): s_out = unit_operation.get_outlet_state_flat(port) - np.testing.assert_equal(s_out, expected['outlet_state'][port]) + np.testing.assert_equal(s_out, expected["outlet_state"][port]) @pytest.mark.parametrize( @@ -412,48 +359,35 @@ def test_get_outlet_state(self, unit_operation: UnitOperationBase, expected: dic ( CstrFixture(), { - 'states': { - 'inlet': { - 'c': np.array([7, 8]), - }, - 'bulk': { - 'c': np.array([1, 2]), - 'Volume': 1 - } + "states": { + "inlet": {"c": np.array([7, 8])}, + "bulk": {"c": np.array([1, 2]), "Volume": 1}, }, - 'state_derivatives': { - 'inlet': { - 'c': [6, 7] - }, - 'bulk': { - 'c': np.array([4, 5]), - 'Volume': 2 - } + "state_derivatives": { + "inlet": {"c": [6, 7]}, + "bulk": {"c": np.array([4, 5]), "Volume": 2}, }, - 'Q_in': [3], - 'Q_out': [4] + "Q_in": [3], + "Q_out": [4], }, [ ( "calculate_residual_concentration_cstr", - lambda c, c_dot, V, V_dot, Q_in, Q_out, c_in: - c_dot * V + V_dot * c - Q_in * c_in + Q_out * c + lambda c, c_dot, V, V_dot, Q_in, Q_out, c_in: c_dot * V + + V_dot * c + - Q_in * c_in + + Q_out * c, ), ( "calculate_residual_volume_cstr", - lambda V, V_dot, Q_in, Q_out: V_dot - Q_in + Q_out - ) + lambda V, V_dot, Q_in, Q_out: V_dot - Q_in + Q_out, + ), ], { - 'inlet': { - 'c': np.array([-7, -8]) - }, - 'bulk': { - 'c': np.array([-11, -7]), - 'Volume': 3 - } - } - ), + "inlet": {"c": np.array([-7, -8])}, + "bulk": {"c": np.array([-11, -7]), "Volume": 3}, + }, + ) # ( # DeadEndFiltrationFixture(), # { @@ -515,43 +449,42 @@ def test_get_outlet_state(self, unit_operation: UnitOperationBase, expected: dic # }, # }, # ), - ] + ], ) -class TestUnitResidual(): +class TestUnitResidual: """Test class for resdiual related functions of unit operations.""" def test_unit_residual( - self, - monkeypatch, - unit_operation: UnitOperationBase, - case: dict, - residualfunc: dict, - expected: dict - ) -> NoReturn: + self, + monkeypatch, + unit_operation: UnitOperationBase, + case: dict, + residualfunc: dict, + expected: dict, + ) -> NoReturn: """Test the residual of unit operations.""" unit_operation.initialize_state() for funcname, func in residualfunc: - monkeypatch.setattr('CADETPythonSimulator.unit_operation.'+funcname, func) + monkeypatch.setattr("CADETPythonSimulator.unit_operation." + funcname, func) - for state, values in case['states'].items(): + for state, values in case["states"].items(): for dof, new_value in values.items(): unit_operation.states[state][dof] = new_value - for state, values in case['state_derivatives'].items(): + for state, values in case["state_derivatives"].items(): for dof, new_value in values.items(): unit_operation.state_derivatives[state][dof] = new_value - unit_operation.Q_in = case['Q_in'] - unit_operation.Q_out = case['Q_out'] + unit_operation.Q_in = case["Q_in"] + unit_operation.Q_out = case["Q_out"] unit_operation.compute_residual(3) for unit_module, module_dict in expected.items(): for property, value in module_dict.items(): np.testing.assert_equal( - value, - unit_operation.residuals[unit_module][property] + value, unit_operation.residuals[unit_module][property] ) diff --git a/tests/test_viscosity.py b/tests/test_viscosity.py index 6cbb3d2..ee230b9 100644 --- a/tests/test_viscosity.py +++ b/tests/test_viscosity.py @@ -2,7 +2,9 @@ import pytest from CADETPythonSimulator.viscosity import ( - AverageViscosity, LogarithmicMixingViscosity, ViscosityBase + AverageViscosity, + LogarithmicMixingViscosity, + ViscosityBase, ) @@ -21,7 +23,8 @@ def validate_viscosities_input(self, viscosities, fractions): """Access to private Method.""" return self._validate_viscosities_input(viscosities, fractions) -@pytest.mark.parametrize('Modul', [ViscosityDummy()]) + +@pytest.mark.parametrize("Modul", [ViscosityDummy()]) class TestViscosityBase: """Class to test methods of Base Class.""" @@ -30,13 +33,9 @@ def test_nan_viscosities(self, Modul): viscosity_obj = Modul np.testing.assert_equal( viscosity_obj.remove_nan_viscosities( - np.array([np.nan, 1, np.nan, 2]), - np.array([0.25, 0.25, 0.25, 0.25]) + np.array([np.nan, 1, np.nan, 2]), np.array([0.25, 0.25, 0.25, 0.25]) ), - ( - np.array([1 ,2]), - np.array([0.5, 0.5]) - ) + (np.array([1, 2]), np.array([0.5, 0.5])), ) def test_validate_input(self, Modul): @@ -57,30 +56,29 @@ def test_validate_input(self, Modul): [ ( AverageViscosity(), - np.array([0., 1., 2., 3.]), + np.array([0.0, 1.0, 2.0, 3.0]), np.array([0.25, 0.25, 0.25, 0.25]), - 1.5 + 1.5, ), ( LogarithmicMixingViscosity(), - np.array([1., 1., 2., 3.]), + np.array([1.0, 1.0, 2.0, 3.0]), np.array([0.25, 0.25, 0.25, 0.25]), - np.exp(0.25 * np.log(2) + 0.25 * np.log(3)) - ) - ] + np.exp(0.25 * np.log(2) + 0.25 * np.log(3)), + ), + ], ) class TestViscosityCalculation: """Testclass for viscosity calculation.""" def test_viscosity_calculation( - self, - model: ViscosityBase, - viscosities: np.ndarray, - fractions: np.ndarray, - expected: float - ): + self, + model: ViscosityBase, + viscosities: np.ndarray, + fractions: np.ndarray, + expected: float, + ): """Test Calculation.""" np.testing.assert_allclose( - model.get_mixture_viscosity(viscosities, fractions), - expected + model.get_mixture_viscosity(viscosities, fractions), expected ) From 957b91e926b71f2f50224ad7dd03e8daeb3c7608 Mon Sep 17 00:00:00 2001 From: daklauss Date: Wed, 30 Apr 2025 09:10:08 +0200 Subject: [PATCH 07/13] Rmv ruff format --- .pre-commit-config.yaml | 6 ++---- pyproject.toml | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1a16f59..2cfceb4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.11.2 + rev: v0.11.7 hooks: # Run the linter. - - id: ruff - # Run the formatter. - - id: ruff-format \ No newline at end of file + - id: ruff \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 2654e76..e64cd1a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,6 +68,7 @@ version = { attr = "CADETPythonSimulator.__version__" } [tool.ruff] # Same as Black. +src = ["CADETPythonSimulator"] line-length = 88 indent-width = 4 From 5a3db4a1553d2d49c9ed6d525ab58643cb845f35 Mon Sep 17 00:00:00 2001 From: daklauss Date: Wed, 30 Apr 2025 09:20:58 +0200 Subject: [PATCH 08/13] Fix test format --- tests/test_system.py | 93 +++----------------------------------------- 1 file changed, 6 insertions(+), 87 deletions(-) diff --git a/tests/test_system.py b/tests/test_system.py index c82fc3f..af0991e 100644 --- a/tests/test_system.py +++ b/tests/test_system.py @@ -88,35 +88,8 @@ def test_system_structure(self, system, expected): [[0, 1, 0, 0, 1e-3], [1, 2, 0, 0, 1e-3]], [[0.001, 0.0], [0.0, 0.001]], [ - 0, - 1, - 0, - 1, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 22, - 23, + 0, 1, 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 22, 23, ], ) ], @@ -156,66 +129,12 @@ def test_coupling( SystemFixture(), [[0, 1, 0, 0, 1e-3], [1, 2, 0, 0, 1e-3]], [ - 0, - 1, - 0, - 1, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 22, - 23, + 0, 1, 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 22, 23, ], [ - 0, - 1, - 0, - 1, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 22, - 23, + 0, 1, 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 22, 23, ], ) ], From 13d1b3183d01255e281f481de1baaf4fee1aaf81 Mon Sep 17 00:00:00 2001 From: daklauss Date: Wed, 30 Apr 2025 09:28:47 +0200 Subject: [PATCH 09/13] Add tests to ruff --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e64cd1a..fcdd8d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,7 +68,8 @@ version = { attr = "CADETPythonSimulator.__version__" } [tool.ruff] # Same as Black. -src = ["CADETPythonSimulator"] +src = ["CADETPythonSimulator", "tests"] + line-length = 88 indent-width = 4 From 8eb3e122a72f7dd1a3844fad5b72aa1d130ebb84 Mon Sep 17 00:00:00 2001 From: daklauss Date: Wed, 30 Apr 2025 10:12:06 +0200 Subject: [PATCH 10/13] Ruff on push only on dev/master --- .github/workflows/ruff.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index ba002db..0f4e142 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -1,5 +1,10 @@ name: Ruff -on: [ push, pull_request ] +on: + push: + branches: + - master + - dev + pull_request: jobs: ruff: runs-on: ubuntu-latest From ce0d0d7c371a828801917cc23d36654ae62ed693 Mon Sep 17 00:00:00 2001 From: daklauss Date: Wed, 30 Apr 2025 10:19:48 +0200 Subject: [PATCH 11/13] Rmv ignoring rule F401 for unused imports --- CADETPythonSimulator/componentsystem.py | 2 +- CADETPythonSimulator/coupling_interface.py | 1 - CADETPythonSimulator/field.py | 3 +-- CADETPythonSimulator/solver.py | 2 +- CADETPythonSimulator/system.py | 5 +---- CADETPythonSimulator/unit_operation.py | 13 +++---------- pyproject.toml | 2 +- tests/test_distribution.py | 1 - tests/test_simulation.py | 1 - tests/test_solver.py | 5 ++--- 10 files changed, 10 insertions(+), 25 deletions(-) diff --git a/CADETPythonSimulator/componentsystem.py b/CADETPythonSimulator/componentsystem.py index 947686a..effd7d6 100644 --- a/CADETPythonSimulator/componentsystem.py +++ b/CADETPythonSimulator/componentsystem.py @@ -1,4 +1,4 @@ -from CADETProcess.processModel import ComponentSystem, Component, Species +from CADETProcess.processModel import ComponentSystem, Component from CADETProcess.dataStructure import UnsignedFloat, String, Integer from CADETProcess.dataStructure import Structure diff --git a/CADETPythonSimulator/coupling_interface.py b/CADETPythonSimulator/coupling_interface.py index 157fbde..cdcbc62 100644 --- a/CADETPythonSimulator/coupling_interface.py +++ b/CADETPythonSimulator/coupling_interface.py @@ -1,6 +1,5 @@ import abc import numpy as np -from CADETPythonSimulator.unit_operation import UnitOperationBase class CouplingInterface(abc.ABC): diff --git a/CADETPythonSimulator/field.py b/CADETPythonSimulator/field.py index 59875df..841c903 100644 --- a/CADETPythonSimulator/field.py +++ b/CADETPythonSimulator/field.py @@ -1,9 +1,8 @@ -from typing import NoReturn, Optional, Union +from typing import Optional, Union import numpy as np import numpy.typing as npt import matplotlib.pyplot as plt -from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import RegularGridInterpolator diff --git a/CADETPythonSimulator/solver.py b/CADETPythonSimulator/solver.py index 389eefb..b625608 100644 --- a/CADETPythonSimulator/solver.py +++ b/CADETPythonSimulator/solver.py @@ -6,7 +6,7 @@ from scikits.odes.dae import dae from CADETProcess.dataStructure import Structure -from CADETPythonSimulator.exception import NotInitializedError, CADETPythonSimError +from CADETPythonSimulator.exception import CADETPythonSimError from CADETPythonSimulator.unit_operation import UnitOperationBase from CADETPythonSimulator.system import SystemBase diff --git a/CADETPythonSimulator/system.py b/CADETPythonSimulator/system.py index afce0a2..13ac838 100644 --- a/CADETPythonSimulator/system.py +++ b/CADETPythonSimulator/system.py @@ -1,12 +1,9 @@ from typing import NoReturn, Optional -import abc from addict import Dict import numpy as np -import numpy.typing as npt -import scipy.optimize as scipyopt -from CADETPythonSimulator.state import State, state_factory +from CADETPythonSimulator.state import State from CADETPythonSimulator.coupling_interface import ( CouplingInterface, WeightedAverageCoupling, diff --git a/CADETPythonSimulator/unit_operation.py b/CADETPythonSimulator/unit_operation.py index 04247d6..97ffe7a 100644 --- a/CADETPythonSimulator/unit_operation.py +++ b/CADETPythonSimulator/unit_operation.py @@ -1,36 +1,29 @@ from abc import abstractmethod from collections import defaultdict -from typing import Any, NoReturn, Optional +from typing import NoReturn, Optional import numpy as np import numpy.typing as npt -from CADETProcess.processModel import ComponentSystem from CADETProcess.dataStructure import Structure from CADETProcess.dataStructure import ( Typed, String, UnsignedInteger, UnsignedFloat, - SizedUnsignedNdArray, NdPolynomial, ) from CADETProcess.dynamicEvents import Section from CADETPythonSimulator.componentsystem import CPSComponentSystem -from CADETPythonSimulator.exception import NotInitializedError, CADETPythonSimError +from CADETPythonSimulator.exception import NotInitializedError from CADETPythonSimulator.state import State, state_factory from CADETPythonSimulator.residual import ( calculate_residual_volume_cstr, calculate_residual_concentration_cstr, - calculate_residual_visc_cstr, - calculate_residual_press_easy_def, - calculate_residual_cake_vol_def, - calculate_residual_visc_def, ) from CADETPythonSimulator.rejection import RejectionBase -from CADETPythonSimulator.cake_compressibility import CakeCompressibilityBase -from CADETPythonSimulator.viscosity import LogarithmicMixingViscosity, ViscosityBase +from CADETPythonSimulator.viscosity import ViscosityBase from CADETPythonSimulator.distribution_base import DistributionBase diff --git a/pyproject.toml b/pyproject.toml index fcdd8d8..22143d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,4 +76,4 @@ indent-width = 4 [tool.ruff.lint] preview = true select = ["E", "F", "W", "D"] -ignore = ["F401", "D212", "D203", "D100"] +ignore = ["D212", "D203", "D100"] diff --git a/tests/test_distribution.py b/tests/test_distribution.py index c42b5b1..b1b1f3a 100644 --- a/tests/test_distribution.py +++ b/tests/test_distribution.py @@ -1,4 +1,3 @@ -import numpy as np import pytest from CADETPythonSimulator.componentsystem import CPSComponentSystem diff --git a/tests/test_simulation.py b/tests/test_simulation.py index 0ba5753..af4f847 100644 --- a/tests/test_simulation.py +++ b/tests/test_simulation.py @@ -9,7 +9,6 @@ from CADETPythonSimulator.unit_operation import ( DistributionInlet, - Outlet, DeadEndFiltration, ) from CADETPythonSimulator.system import FlowSystem diff --git a/tests/test_solver.py b/tests/test_solver.py index 9219f9e..22abdc5 100644 --- a/tests/test_solver.py +++ b/tests/test_solver.py @@ -1,16 +1,15 @@ import numpy as np import pytest from addict import Dict -from typing import NoReturn, Optional +from typing import Optional from test_unit_operation import ( InletFixture, OutletFixture, - CstrFixture, DeadEndFiltrationFixture, ) from CADETProcess.dataStructure import Structure -from CADETPythonSimulator.system import SystemBase, FlowSystem +from CADETPythonSimulator.system import FlowSystem from CADETPythonSimulator.solver import Solver From f542530397b40f3b9b95d04c0797cf4a20b24284 Mon Sep 17 00:00:00 2001 From: daklauss Date: Wed, 30 Apr 2025 12:10:34 +0200 Subject: [PATCH 12/13] Add dev optional dependency --- pyproject.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 22143d3..0ced428 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,11 @@ docs = [ "numpydoc>=1.5.0", "myst-nb>=0.17.1", ] +dev = [ + "CADET-Python-Simulator.testing", + "CADET-Python-Simulator.docs", + "ruff", +] [tool.pytest.ini_options] From 235d1ecbac2921d2605de21923b6c4021f3aaf0d Mon Sep 17 00:00:00 2001 From: daklauss Date: Mon, 5 May 2025 09:51:37 +0200 Subject: [PATCH 13/13] Restructure optional dependencies into dependency-groups --- .github/workflows/pipeline.yml | 2 +- pyproject.toml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 526e420..7726523 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -43,7 +43,7 @@ jobs: - name: Install run: | python -m pip install --upgrade pip - pip install -e ./[testing] + pip install -e . --group testing - name: Test if: always() diff --git a/pyproject.toml b/pyproject.toml index 0ced428..aef9bdd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ homepage = "https://jugit.fz-juelich.de/IBG-1/ModSim/cadet/CADET-Python-Simulato "Bug Tracker" = "https://jugit.fz-juelich.de/IBG-1/ModSim/cadet/CADET-Python-Simulator/Issues" -[project.optional-dependencies] +[dependency-groups] testing = [ "setuptools", "pytest", @@ -56,8 +56,8 @@ docs = [ "myst-nb>=0.17.1", ] dev = [ - "CADET-Python-Simulator.testing", - "CADET-Python-Simulator.docs", + {include-group = "testing"}, + {include-group = "docs"}, "ruff", ]