-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathsolver.py
More file actions
64 lines (48 loc) · 2.26 KB
/
solver.py
File metadata and controls
64 lines (48 loc) · 2.26 KB
1
2
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import abc
import dataclasses
from collections.abc import Callable, Sequence
from dataclasses import dataclass, field
from enum import Enum
from typing import Generic, Self, TypeVar
from libecalc.domain.process.process_solver.configuration import Configuration, OperatingConfiguration, SimulationUnitId
from libecalc.domain.process.process_system.process_system import ProcessSystemId
from libecalc.domain.process.process_system.process_unit import ProcessUnitId
from libecalc.domain.process.value_objects.fluid_stream import FluidStream
TConfiguration = TypeVar("TConfiguration")
class SolverFailureStatus(str, Enum):
ABOVE_MAXIMUM_FLOW_RATE = "ABOVE_MAXIMUM_FLOW_RATE"
BELOW_MINIMUM_FLOW_RATE = "BELOW_MINIMUM_FLOW_RATE"
MAXIMUM_ACHIEVABLE_DISCHARGE_PRESSURE_BELOW_TARGET = "MAXIMUM_ACHIEVABLE_DISCHARGE_PRESSURE_BELOW_TARGET"
MINIMUM_ACHIEVABLE_DISCHARGE_PRESSURE_ABOVE_TARGET = "MINIMUM_ACHIEVABLE_DISCHARGE_PRESSURE_ABOVE_TARGET"
@dataclass
class OutsideCapacityEvent:
status: SolverFailureStatus
source_id: ProcessUnitId
actual_value: float | None = None
boundary_value: float | None = None
@dataclass
class TargetNotAchievableEvent:
status: SolverFailureStatus
achievable_value: float
target_value: float
source_id: ProcessSystemId | None = None
def with_source_id(self, source_id: ProcessSystemId) -> Self:
return dataclasses.replace(self, source_id=source_id)
SolverFailureEvent = OutsideCapacityEvent | TargetNotAchievableEvent
@dataclass
class Solution(Generic[TConfiguration]):
success: bool
configuration: TConfiguration
failure_event: SolverFailureEvent | None = field(default=None)
def get_configuration(
self: "Solution[Sequence[Configuration[OperatingConfiguration]]]",
unit_id: SimulationUnitId,
) -> OperatingConfiguration:
"""Find a configuration value by unit ID."""
for config in self.configuration:
if config.simulation_unit_id == unit_id:
return config.value # type: ignore[return-value]
raise ValueError(f"No configuration found for unit {unit_id}.")
class Solver(abc.ABC, Generic[TConfiguration]):
@abc.abstractmethod
def solve(self, func: Callable[[TConfiguration], FluidStream]) -> Solution[TConfiguration]: ...