Skip to content

refactor: introduce FeasibilitySolver and StreamDistributionItem - #1457

Merged
frodehk merged 7 commits into
mainfrom
refactor/introduce-has-validity
Apr 7, 2026
Merged

refactor: introduce FeasibilitySolver and StreamDistributionItem#1457
frodehk merged 7 commits into
mainfrom
refactor/introduce-has-validity

Conversation

@frodehk

@frodehk frodehk commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Introduces FeasibilitySolver to calculate how much rate exceeds a compressor train's capacity, and connects it to stream distribution via a thin StreamDistributionItem adapter. Renames HasCapacity to HasExcessRate with a FluidStream-based interface.

Architecture

Three layers with distinct responsibilities:

Class Responsibility Location
FeasibilitySolver Calculates excess rate for a given inlet stream and target pressure. Orchestrates OutletPressureSolver and queries compressor stone walls. domain/process/process_solver/
StreamDistributionItem Thin adapter — binds a FeasibilitySolver to a fixed target_pressure and implements HasExcessRate + HasValidity. presentation/yaml/mappers/
HasExcessRate (was HasCapacity) Interface used by CommonStreamDistribution to query overflow. Now takes a FluidStream instead of (rate, pressure). domain/process/stream_distribution/

What changed

New: FeasibilitySolver (process_solver/feasibility_solver.py)

  • Single public method: get_excess_rate(inlet_stream, target_pressure) → float
  • Internally calls OutletPressureSolver.find_solution(). If the solver succeeds, excess is 0. If it fails, applies the failed solution's configuration and finds the bottleneck compressor's stone wall limit.

New: StreamDistributionItem (presentation/yaml/mappers/process_simulation_mapper.py)

  • Implements HasExcessRate and HasValidity
  • Binds target_pressure so stream distribution interfaces only need an inlet_stream
  • is_valid(stream) = get_excess_rate(stream) == 0.0

Renamed: HasCapacityHasExcessRate

  • get_unhandled_rate(rate, pressure)get_excess_rate(inlet_stream: FluidStream)

Usage

feasibility_solver = FeasibilitySolver(
    outlet_pressure_solver=solver,
    compressors=compressors,
    runner=runner,
)

item = StreamDistributionItem(
    feasibility_solver=feasibility_solver,
    target_pressure=pressure_constraint,
)

PrioritiesStreamDistribution calls item.is_valid(stream) to pick the first feasible setting.
CommonStreamDistribution calls item.get_excess_rate(stream) to route overflow between trains.

Refs:
equinor/ecalc-internal#1634
equinor/ecalc-internal#1635


Type of Work

  • Patch: X.Y.Z+1. NEGLIGIBLE visible changes, does not change input or output - OR changes behaviour. Use chore:, refactor: etc
  • Minor: X.Y+1.Z. Minor changes, might ADD new input (YAML), or other backwards-compatible changes. Use feat:, fix:
  • Major: X+1.Y.Z. Major and most likely BREAKING changes, wo. backwards compatibility, or removing temporary backwards compatibility functionality. Use ! or BREAKING:.

See here (internal): https://github.com/equinor/ecalc-internal/discussions/1044

Have you remembered and considered?

  • IF FEAT: I have remembered to update documentation
  • IF FIX OR FEAT: I have remembered to update manual changelog (docs/drafts/next.draft.md)
  • IF BREAKING: I have remembered to update migration guide (docs/docs/migration_guides/)
  • IF BREAKING: I have committed with BREAKING: in footer or ! in header
  • I have added tests (if not, comment why)
  • I have used conventional commits syntax (if you squash, make sure that conventional commit is used)
  • I have included the Github issue nr in the footer!

What is this PR all about?

What else did you consider?

Between the lines?

@frodehk frodehk self-assigned this Mar 25, 2026
@frodehk
frodehk requested a review from a team as a code owner March 25, 2026 11:39
@frodehk frodehk changed the title refactor: implement has validtiy and capacity refactor: implement HasValidity and HasCapacity Mar 25, 2026
Comment thread src/libecalc/presentation/yaml/mappers/process_simulation_mapper.py Outdated
Comment thread src/libecalc/presentation/yaml/mappers/process_simulation_mapper.py Outdated
Comment thread src/libecalc/presentation/yaml/mappers/process_simulation_mapper.py Outdated
@frodehk
frodehk force-pushed the refactor/introduce-has-validity branch from 8765f65 to ee5465e Compare March 26, 2026 09:19
@frodehk frodehk changed the title refactor: implement HasValidity and HasCapacity refactor: implement HasValidity and HasExcessRate Mar 27, 2026
@frodehk frodehk changed the title refactor: implement HasValidity and HasExcessRate refactor: introduce FeasibilitySolver and StreamDistributionItem (HasValidity and HasExcessRate) Mar 27, 2026
@frodehk frodehk changed the title refactor: introduce FeasibilitySolver and StreamDistributionItem (HasValidity and HasExcessRate) refactor: introduce FeasibilitySolver and StreamDistributionItem Mar 27, 2026
self,
inlet_stream: FluidStream,
items: dict[T, HasCapacity],
items: dict[T, HasExcessRate],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking CommonStreamDistribution would use FeasibilitySolver directly, so passing target_pressure in addition. Not sure if that matters much, but it would remove the HasExcessRate interface which might be a bit confusing. It's unclear that excess rate depends on target pressure in that interface.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point about clarity. However, if we remove the StreamDistributionItem (HasValidity, HasExcessCapacity), CommonStreamDistribution needs to keep track of two dictionaries (feasibility solvers, target pressures) - and I guess tests will be "heavier" (need to build OutletPressureSolver, ProcessRunner, compressors etc.). Another thing is that PrioritiesStreamDistribution is using HasValidity. Without StreamDistributionItem I assume PrioritiesStreamDistribution also needs to take feasibility solvers and target pressures.

Can it be an alternative to have a clearer docstring in the HasExcessRate interface, to clarify the target pressure dependency?

@frodehk
frodehk merged commit 6e7b4ea into main Apr 7, 2026
24 checks passed
@frodehk
frodehk deleted the refactor/introduce-has-validity branch April 7, 2026 11:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants