Skip to content

WIP: feat(yaml): introduce INTERSTAGE process system type and PRESSURE_CON…#1453

Draft
olelod wants to merge 1 commit intomainfrom
feat/yaml-interstage-types
Draft

WIP: feat(yaml): introduce INTERSTAGE process system type and PRESSURE_CON…#1453
olelod wants to merge 1 commit intomainfrom
feat/yaml-interstage-types

Conversation

@olelod
Copy link
Copy Markdown
Contributor

@olelod olelod commented Mar 23, 2026

Context

The existing YAML supports a MULTIPLE_STREAMS_AND_PRESSURES compressor train type for trains where additional streams are injected or extracted between stages, and where intermediate pressures must be controlled. This type is separate from COMMON_SHAFT and requires its own set of fields and mapper logic.

This PR is a design proposal for how the same physical concept — and more — can be expressed using the general PROCESS_SYSTEMS structure, without a dedicated train type.

Approach

The key design principle is full separation of equipment and operation:

  • PROCESS_SYSTEMS describes physical topology — compressors, how they are connected, and what anti-surge equipment is installed. No streams, no rates, no targets.
  • PROCESS_SIMULATIONS describes operational scenarios — what flows through the system, what pressure targets to hit, and how to achieve them.

A serial compressor train with interstage elements is expressed as a SERIAL process system containing an ordered list of named items. Six item types are supported:

Type Description
COMPRESSOR_STAGE A single compressor stage
PRESSURE_DROP Any element modelled as a fixed pressure drop
MIXER A stream injection point
SPLITTER A stream extraction point
SERIAL An ordered serial train
PARALLEL A parallel arrangement of serial trains

Anti-surge equipment (INDIVIDUAL_ASV or COMMON_ASV) is declared on the SERIAL train — it is physical equipment, not an operational choice. Defaults to INDIVIDUAL_ASV.

Segment constraints

Intermediate pressure targets are expressed in a CONSTRAINTS block on the simulation, keyed by item name. Each entry defines a segment boundary: the solver resolves all items up to and including that item as one segment.

Using the train name itself as a key targets the train outlet — independent of which stage happens to be last.

Each constraint requires:

  • OUTLET_PRESSURE: the pressure target [bara]
  • PRESSURE_CONTROL (optional): defaults to DOWNSTREAM_CHOKE for the train outlet, INDIVIDUAL_ASV_RATE for intermediate segments

Consistency between PRESSURE_CONTROL and the train's ANTI_SURGE is validated at parse time.

Validation

All cross-reference checks run at parse time in YamlAsset, before any domain calculations:

  • Every MIXER in the target train must have a stream in MIXER_STREAMS
  • Every SPLITTER in the target train must have a rate in SPLITTER_RATES
  • Every constraint must have OUTLET_PRESSURE set
  • Constraint keys must be item names in the train or the train name itself
  • COMMON_ASV pressure control requires COMMON_ASV on the train

Backward compatibility

A SERIAL train with a single constraint continues to use the existing solver path. Multi-constraint trains are resolved by MultiPressureSolver (separate work). No existing YAML is affected.

Mapping from YAML to domain is separate work.

Example YAML

INLET_STREAMS:
  feed_stream:
    FLUID_MODEL: dry_gas
    RATE:
      VALUE: SIM1;FEED_RATE
      UNIT: SM3_PER_DAY
  injection_stream:
    FLUID_MODEL: wet_gas
    RATE:
      VALUE: SIM1;INJECTION_RATE
      UNIT: SM3_PER_DAY
  train_a_stream:
    FLUID_MODEL: dry_gas
    RATE:
      VALUE: SIM1;TRAIN_A_RATE
      UNIT: SM3_PER_DAY
  train_a_injection_stream:
    FLUID_MODEL: wet_gas
    RATE:
      VALUE: SIM1;TRAIN_A_INJECTION_RATE
      UNIT: SM3_PER_DAY
  train_b_stream:
    FLUID_MODEL: dry_gas
    RATE:
      VALUE: SIM1;TRAIN_B_RATE
      UNIT: SM3_PER_DAY

PROCESS_SYSTEMS:
  - TYPE: COMPRESSOR_STAGE
    NAME: stage_1
    INLET_TEMPERATURE: 30
    COMPRESSOR: my_compressor

  - TYPE: PRESSURE_DROP
    NAME: interstage_pressure_drop
    PRESSURE_DROP: 3

  - TYPE: MIXER
    NAME: injection_point

  - TYPE: COMPRESSOR_STAGE
    NAME: stage_2
    INLET_TEMPERATURE: 40
    COMPRESSOR: my_compressor

  - TYPE: SPLITTER
    NAME: extraction_point

  - TYPE: COMPRESSOR_STAGE
    NAME: stage_3
    INLET_TEMPERATURE: 35
    COMPRESSOR: my_compressor

  - TYPE: SERIAL
    NAME: main_train
    ANTI_SURGE: INDIVIDUAL_ASV
    ITEMS:
      - stage_1
      - interstage_pressure_drop
      - injection_point
      - stage_2
      - extraction_point
      - stage_3

  - TYPE: COMPRESSOR_STAGE
    NAME: train_a_stage_1
    INLET_TEMPERATURE: 30
    COMPRESSOR: my_compressor

  - TYPE: MIXER
    NAME: train_a_injection_point

  - TYPE: COMPRESSOR_STAGE
    NAME: train_a_stage_2
    INLET_TEMPERATURE: 40
    COMPRESSOR: my_compressor

  - TYPE: SPLITTER
    NAME: train_a_extraction_point

  - TYPE: COMPRESSOR_STAGE
    NAME: train_a_stage_3
    INLET_TEMPERATURE: 35
    COMPRESSOR: my_compressor

  - TYPE: SERIAL
    NAME: train_a
    ANTI_SURGE: COMMON_ASV
    ITEMS:
      - train_a_stage_1
      - train_a_injection_point
      - train_a_stage_2
      - train_a_extraction_point
      - train_a_stage_3

  - TYPE: COMPRESSOR_STAGE
    NAME: train_b_stage
    INLET_TEMPERATURE: 30
    COMPRESSOR: my_compressor

  - TYPE: SERIAL
    NAME: train_b
    ANTI_SURGE: INDIVIDUAL_ASV
    ITEMS:
      - train_b_stage

  - TYPE: PARALLEL
    NAME: parallel_trains
    ITEMS:
      - train_a
      - train_b

PROCESS_SIMULATIONS:
  - NAME: sim_serial
    TARGET: main_train
    INLET_STREAM: feed_stream
    MIXER_STREAMS:
      injection_point: injection_stream
    SPLITTER_RATES:
      extraction_point:
        VALUE: SIM1;SPLIT_RATE
        UNIT: SM3_PER_DAY
    CONSTRAINTS:
      injection_point:
        OUTLET_PRESSURE: 50
        PRESSURE_CONTROL: DOWNSTREAM_CHOKE
      stage_2:
        OUTLET_PRESSURE: 80
      main_train:
        OUTLET_PRESSURE: 120

  - NAME: sim_parallel_individual
    TARGET: parallel_trains
    STREAM_DISTRIBUTION:
      METHOD: INDIVIDUAL_STREAMS
      INLET_STREAMS:
        - train_a_stream
        - train_b_stream
    MIXER_STREAMS:
      train_a_injection_point: train_a_injection_stream
    SPLITTER_RATES:
      train_a_extraction_point:
        VALUE: SIM1;TRAIN_A_SPLIT_RATE
        UNIT: SM3_PER_DAY
    CONSTRAINTS:
      train_a_injection_point:
        OUTLET_PRESSURE: 50
      train_a:
        OUTLET_PRESSURE: 120
        PRESSURE_CONTROL: COMMON_ASV
      train_b:
        OUTLET_PRESSURE: 120

  - NAME: sim_parallel_common
    TARGET: parallel_trains
    STREAM_DISTRIBUTION:
      METHOD: COMMON_STREAM
      INLET_STREAM: feed_stream
      SETTINGS:
        - RATE_FRACTIONS: [0.6, 0.4]
          OVERFLOW:
            - FROM_REFERENCE: train_a
              TO_REFERENCE: train_b
        - RATE_FRACTIONS: [0.5, 0.5]
        - RATE_FRACTIONS: [0.4, 0.6]
    MIXER_STREAMS:
      train_a_injection_point: train_a_injection_stream
    SPLITTER_RATES:
      train_a_extraction_point:
        VALUE: SIM1;TRAIN_A_SPLIT_RATE
        UNIT: SM3_PER_DAY
    CONSTRAINTS:
      train_a_injection_point:
        OUTLET_PRESSURE: 50
      train_a:
        OUTLET_PRESSURE: 120
        PRESSURE_CONTROL: COMMON_ASV
      train_b:
        OUTLET_PRESSURE: 120

@olelod olelod force-pushed the feat/yaml-interstage-types branch from 2f01beb to 507f040 Compare March 23, 2026 12:18
Comment on lines +115 to +122
class YamlInterstageProcessSystem(YamlBase):
type: Literal["INTERSTAGE"]
name: ProcessSystemReference
items: list[YamlInterstageItem] = Field(
default_factory=list,
title="ITEMS",
description="Ordered list of choke, mixer, and splitter units at this interstage location.",
)
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.

Do we actually need this? Can we instead just have a list of units in addition to CompressorStages when setting up the train?

type: Literal["SERIAL"]
name: ProcessSystemReference
items: list[YamlItem[YamlCompressorStageProcessSystem]]
items: list[YamlItem[YamlCompressorStageProcessSystem | YamlInterstageProcessSystem]]
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.

Suggested change
items: list[YamlItem[YamlCompressorStageProcessSystem | YamlInterstageProcessSystem]]
items: list[YamlItem[YamlCompressorStageProcessSystem | YamlInterstageChoke | YamlInterstageSplitter | YamlInterstageMixer]]


class YamlProcessConstraints(YamlBase):
outlet_pressure: YamlExpressionType | None = Field(
discharge_pressure: YamlExpressionType | None = Field(
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.

Should we use discharge instead of inlet? inlet/outlet seems to work for streams, is it different for pressure?

title="DISCHARGE_PRESSURE",
description="Target discharge pressure [bara].",
)
pressure_control: YamlPressureControl | None = Field(
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.

Will constraint, anti-surge and pressure control always go hand-in-hand?

I think we also should consider introducing a type for constraint, maybe switch to a list. That gives us more flexibility in case we need to introduce different constraints.

If combining constraint and 'how to solve' like this we should also consider a different name than constraint

@olelod olelod force-pushed the feat/yaml-interstage-types branch 2 times, most recently from 9fa2c2a to 043a36d Compare April 7, 2026 08:20
All types live in yaml_process_system.py. Topology types first,
simulation types after.

Process system topology (PROCESS_SYSTEMS):
- COMPRESSOR_STAGE: single compressor stage with inlet temperature
- PRESSURE_DROP: interstage pressure drop element
- MIXER: stream injection point (topology only, one mixer for each stream injected)
- SPLITTER: stream extraction point (topology only, one splitter for each stream extracted)
- SERIAL: ordered list of named item references; carries ANTI_SURGE
  (INDIVIDUAL_ASV or COMMON_ASV, defaults to INDIVIDUAL_ASV)

Interstage types (PRESSURE_DROP, MIXER, SPLITTER) are new — they allow
expressing the legacy multiple streams compressor trains in the new Yaml

Process simulation (PROCESS_SIMULATIONS):
  TARGETS: list of YamlSimulationTarget, each with:
    - TARGET: reference to a SERIAL process system
    - CONSTRAINTS: map of item name / train name -> YamlSegmentConstraint
      (constraints carry both OUTLET_PRESSURE and PRESSURE_CONTROL and they allow expressing
       the legacy multiple pressures compressor train in the new Yaml. Now also with more than
       one interstage pressure)
    - MIXER_STREAMS: map of mixer name -> inlet stream ref
    - SPLITTER_RATES: map of splitter name -> extraction rate
  STREAM_DISTRIBUTION: required; COMMON_STREAM or INDIVIDUAL_STREAMS
    (both accept StreamRef | YamlInletStream)

Serial = 1 target, parallel = N targets — implicit from count.

Validators in YamlAsset (parse-time):
- Every simulation target must reference a known SERIAL process system
- Every train must have an outlet constraint (keyed by train name)
- Every MIXER in a train must have a MIXER_STREAMS entry per target
- Every SPLITTER in a train must have a SPLITTER_RATES entry per target
- Constraint keys must be item names in the train or the train name itself
- Constraints must appear in topological order (matching SERIAL.items)
- UPSTREAM_CHOKE only valid on the first constraint in topological order
- DOWNSTREAM_CHOKE only valid on the last constraint in topological order
@olelod olelod force-pushed the feat/yaml-interstage-types branch from 043a36d to 08d553e Compare April 8, 2026 11:03
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