Class LNGHeatExchanger

All Implemented Interfaces:
Serializable, Runnable, AutoSizeable, CapacityConstrainedEquipment, HeaterInterface, MultiStreamHeatExchangerInterface, ProcessEquipmentInterface, TwoPortInterface, ProcessElementInterface, SimulationInterface, NamedInterface

public class LNGHeatExchanger extends MultiStreamHeatExchanger2
LNG cryogenic multi-stream heat exchanger model (plate-fin / brazed aluminium).

Provides a comprehensive set of capabilities for MCHE design and analysis:

  1. Rigorous H-T curves — TP-flash at every zone boundary (P1).
  2. Per-stream pressure drop — linear or correlated P interpolation (P2).
  3. Exergy analysis — zone-by-zone entropy generation and eta-II (P3).
  4. Adaptive zone refinement — auto-refines near phase boundaries (P4).
  5. Manglik-Bergles fin correlations — offset-strip j/f factors (P5).
  6. Two-phase pressure drop — Lockhart-Martinelli separated flow (P6).
  7. Dynamic cool-down transient — lumped thermal mass model (P7).
  8. Core sizing — BAHX L x W x H from duty and fin geometry (P8).
  9. Freeze-out detection — CO2 and heavy HC solid risk per zone (P9).
  10. Flow maldistribution — MITA correction factor (P10).
Version:
4.0
Author:
NeqSim
See Also:
  • Field Details

    • serialVersionUID

      private static final long serialVersionUID
      See Also:
    • logger

      private static final org.apache.logging.log4j.Logger logger
    • DEFAULT_REFERENCE_TEMP_K

      private static final double DEFAULT_REFERENCE_TEMP_K
      Default reference temperature for exergy calculations: 15 deg C (288.15 K).
      See Also:
    • CO2_FREEZE_TEMP_C

      private static final double CO2_FREEZE_TEMP_C
      CO2 triple point temperature in deg C (-56.6 deg C).
      See Also:
    • MERCURY_SAFE_LIMIT_PPB

      private static final double MERCURY_SAFE_LIMIT_PPB
      Mercury safe limit in ppb for aluminium BAHX.
      See Also:
    • numberOfZones

      private int numberOfZones
      Number of axial zones for discretisation.
    • exchangerType

      private String exchangerType
      Exchanger type description.
    • referenceTemperatureK

      private double referenceTemperatureK
      Reference temperature for exergy calculations (K).
    • adaptiveRefinement

      private boolean adaptiveRefinement
      Whether to enable adaptive zone refinement (P4).
    • maxAdaptiveZones

      private int maxAdaptiveZones
      Maximum zones after adaptive refinement (P4).
    • adaptiveThresholdFactor

      private double adaptiveThresholdFactor
      Enthalpy gradient threshold for adaptive refinement (P4).
    • flowMaldistributionFactor

      private double flowMaldistributionFactor
      Flow maldistribution factor applied to MITA (P10). 1.0 = ideal.
    • maxAllowableThermalGradient

      private double maxAllowableThermalGradient
      Maximum allowable thermal gradient in deg C per meter (thermal stress).
    • streamFinGeometry

      private List<LNGHeatExchanger.FinGeometry> streamFinGeometry
      Fin geometry per stream (P5), null entries use no fin correlation.
    • coreGeometry

      private LNGHeatExchanger.CoreGeometry coreGeometry
      Core geometry for sizing (P8).
    • coreThermalMassKJK

      private double coreThermalMassKJK
      Core thermal mass in kJ/K for transient model (P7).
    • registeredIsHot

      private List<Boolean> registeredIsHot
      Whether each registered stream is hot (true) or cold (false).
    • streamPressureDrops

      private List<Double> streamPressureDrops
      Pressure drop per registered stream (bar). Zero means isobaric.
    • pendingIsHot

      private List<Boolean> pendingIsHot
      Manual hot/cold hints for pending streams (before registration).
    • streamCount

      private int streamCount
      Number of registered streams (tracked because parent has no accessor).
    • pendingStreams

      private transient List<StreamInterface> pendingStreams
      Pending streams from addInStream() or list constructor.
    • minimumInternalTemperatureApproach

      private double minimumInternalTemperatureApproach
      Minimum internal temperature approach across all zones (deg C).
    • mitaZoneIndex

      private int mitaZoneIndex
      Zone index (0-based from cold end) where MITA occurs.
    • uaPerZone

      private double[] uaPerZone
      Per-zone UA values (W/K).
    • mitaPerZone

      private double[] mitaPerZone
      Per-zone minimum temperature approach (deg C).
    • hotCompositeCurve

      private double[][] hotCompositeCurve
      Hot composite curve [nPoints][2]: col 0 = cumulative duty (kW), col 1 = temp (deg C).
    • coldCompositeCurve

      private double[][] coldCompositeCurve
      Cold composite curve [nPoints][2]: col 0 = cumulative duty (kW), col 1 = temp (deg C).
    • exergyDestructionPerZone

      private double[] exergyDestructionPerZone
      Per-zone exergy destruction (kW).
    • totalExergyDestruction

      private double totalExergyDestruction
      Total exergy destruction across all zones (kW).
    • secondLawEfficiency

      private double secondLawEfficiency
      Second-law (exergetic) efficiency, dimensionless 0–1.
    • freezeOutRiskPerZone

      private boolean[] freezeOutRiskPerZone
      Per-zone CO2 freeze-out risk flag (P9).
    • zoneTempProfileHotC

      private double[] zoneTempProfileHotC
      Per-zone temperature in deg C for freeze-out assessment (P9).
    • zoneTempProfileColdC

      private double[] zoneTempProfileColdC
      Per-zone temperature in deg C for freeze-out assessment - cold side (P9).
    • thermalGradientPerZone

      private double[] thermalGradientPerZone
      Per-zone thermal gradient in deg C per metre (thermal stress).
    • thermalStressWarning

      private boolean thermalStressWarning
      Whether any thermal-stress warning was triggered.
    • computedStreamDP

      private double[] computedStreamDP
      Per-stream detailed pressure drop from correlations in bar (P5/P6).
    • streamJFactor

      private double[] streamJFactor
      Per-stream j-factor results (P5).
    • streamFFactor

      private double[] streamFFactor
      Per-stream f-factor results (P5).
    • transientResults

      private List<LNGHeatExchanger.TransientPoint> transientResults
      Cool-down transient results (P7).
    • mercuryRiskPresent

      private boolean mercuryRiskPresent
      Mercury risk assessment result.
    • mercuryRiskMessage

      private String mercuryRiskMessage
      Mercury risk detail message.
  • Constructor Details

    • LNGHeatExchanger

      public LNGHeatExchanger(String name)
      Constructor for LNGHeatExchanger.
      Parameters:
      name - name of the heat exchanger
    • LNGHeatExchanger

      public LNGHeatExchanger(String name, List<StreamInterface> inStreams)
      Constructor for LNGHeatExchanger with initial streams.

      Streams are auto-classified as hot or cold based on inlet temperature when run(UUID) is called. The hotter stream(s) become hot and the colder one(s) become cold.

      Parameters:
      name - name of the heat exchanger
      inStreams - list of inlet streams
  • Method Details

    • addInStream

      public void addInStream(StreamInterface inStream)
      Adds an inlet stream to the heat exchanger.

      Stores the stream for deferred registration. The stream will be auto-classified as hot or cold based on its inlet temperature when run(UUID) is called.

      Specified by:
      addInStream in interface MultiStreamHeatExchangerInterface
      Overrides:
      addInStream in class MultiStreamHeatExchanger2
      Parameters:
      inStream - Input stream to be added
    • addInStreamMSHE

      public void addInStreamMSHE(StreamInterface inStream, String streamType, Double outletTemp)
      Adds an inlet stream to the multi-stream heat exchanger.

      Also tracks the stream type and initialises pressure drop to zero.

      Overrides:
      addInStreamMSHE in class MultiStreamHeatExchanger2
      Parameters:
      inStream - a StreamInterface object
      streamType - a String object
      outletTemp - a Double object
    • setStreamIsHot

      public void setStreamIsHot(int streamIndex, boolean isHot)
      Classify a pending stream as hot (being cooled) or cold (being heated).

      Must be called after addInStream(StreamInterface) and before run(UUID). If not called, the exchanger will auto-classify based on inlet temperatures.

      Parameters:
      streamIndex - 0-based index in the pending stream list
      isHot - true if the stream is hot (will be cooled)
    • setNumberOfZones

      public void setNumberOfZones(int zones)
      Set the number of axial zones for discretisation.
      Parameters:
      zones - number of zones (must be > 0)
    • getNumberOfZones

      public int getNumberOfZones()
      Get the number of axial zones.
      Returns:
      number of zones
    • setExchangerType

      public void setExchangerType(String type)
      Set the exchanger type description.
      Parameters:
      type - exchanger type (e.g. "BAHX", "PCHE", "CWHE")
    • getExchangerType

      public String getExchangerType()
      Get the exchanger type description.
      Returns:
      exchanger type string
    • setStreamPressureDrop

      public void setStreamPressureDrop(int streamIndex, double deltaPBar)
      Set the pressure drop for a specific stream (Priority 2).

      Pressure is linearly interpolated from inlet to outlet during the rigorous zone analysis. This shifts saturation temperatures and affects pinch location, typically by 1–3 deg C for LNG exchangers.

      Parameters:
      streamIndex - 0-based index of the registered stream
      deltaPBar - pressure drop in bar (positive value)
    • getStreamPressureDrop

      public double getStreamPressureDrop(int streamIndex)
      Get the pressure drop for a specific stream.
      Parameters:
      streamIndex - 0-based index
      Returns:
      pressure drop in bar
    • setReferenceTemperature

      public void setReferenceTemperature(double tempC)
      Set the reference (dead-state) temperature for exergy calculations.
      Parameters:
      tempC - reference temperature in degrees Celsius (default 15 deg C)
    • getReferenceTemperature

      public double getReferenceTemperature()
      Get the reference temperature for exergy calculations.
      Returns:
      reference temperature in degrees Celsius
    • setAdaptiveRefinement

      public void setAdaptiveRefinement(boolean enabled)
      Enable or disable adaptive zone refinement near phase boundaries (P4).

      When enabled, zones where the enthalpy gradient changes by more than setAdaptiveThresholdFactor(double) times the average are automatically subdivided.

      Parameters:
      enabled - true to enable adaptive refinement
    • getAdaptiveRefinement

      public boolean getAdaptiveRefinement()
      Get whether adaptive zone refinement is enabled.
      Returns:
      true if adaptive refinement is enabled
    • setMaxAdaptiveZones

      public void setMaxAdaptiveZones(int max)
      Set the maximum number of zones after adaptive refinement (P4).
      Parameters:
      max - maximum zone count (must be greater than numberOfZones)
    • getMaxAdaptiveZones

      public int getMaxAdaptiveZones()
      Get the maximum number of zones after adaptive refinement.
      Returns:
      maximum adaptive zone count
    • setAdaptiveThresholdFactor

      public void setAdaptiveThresholdFactor(double factor)
      Set the threshold factor for adaptive zone refinement (P4).

      A zone is refined when its enthalpy gradient exceeds this factor times the average gradient. Default is 2.0.

      Parameters:
      factor - threshold factor (must be > 1.0)
    • getAdaptiveThresholdFactor

      public double getAdaptiveThresholdFactor()
      Get the adaptive threshold factor.
      Returns:
      threshold factor
    • setFlowMaldistributionFactor

      public void setFlowMaldistributionFactor(double factor)
      Set the flow maldistribution correction factor (P10).

      Applies a penalty factor to the effective UA per zone and adjusts the computed MITA. A value of 1.0 means ideal (no maldistribution). Typical BAHX maldistribution factors range from 0.85 to 0.95.

      Parameters:
      factor - correction factor, 0 < factor <= 1.0
    • getFlowMaldistributionFactor

      public double getFlowMaldistributionFactor()
      Get the flow maldistribution correction factor.
      Returns:
      correction factor (1.0 = ideal)
    • setMaxAllowableThermalGradient

      public void setMaxAllowableThermalGradient(double gradientCPerM)
      Set the maximum allowable thermal gradient for stress assessment.

      Typical limit for aluminium BAHX is 5 deg C/m per API 662 Part II guidelines. The assessment compares the actual zone-by-zone gradient against this limit and flags warnings.

      Parameters:
      gradientCPerM - maximum gradient in deg C per metre of core length
    • getMaxAllowableThermalGradient

      public double getMaxAllowableThermalGradient()
      Get the maximum allowable thermal gradient.
      Returns:
      limit in deg C per metre
    • setStreamFinGeometry

      public void setStreamFinGeometry(int streamIndex, LNGHeatExchanger.FinGeometry fin)
      Set the fin geometry for a specific stream (P5).

      When fin geometry is set, the Manglik-Bergles correlations for offset-strip fins are used to compute heat-transfer and friction factors. These are also used by core sizing (P8).

      Parameters:
      streamIndex - 0-based stream index
      fin - fin geometry object
    • getStreamFinGeometry

      public LNGHeatExchanger.FinGeometry getStreamFinGeometry(int streamIndex)
      Get the fin geometry for a specific stream.
      Parameters:
      streamIndex - 0-based stream index
      Returns:
      fin geometry, or null if not set
    • setCoreGeometry

      public void setCoreGeometry(LNGHeatExchanger.CoreGeometry geom)
      Set the core geometry for sizing and transient analysis (P8, P7).
      Parameters:
      geom - core geometry object
    • getCoreGeometry

      public LNGHeatExchanger.CoreGeometry getCoreGeometry()
      Get the core geometry (may be populated by sizeCore()).
      Returns:
      core geometry object
    • setCoreThermalMass

      public void setCoreThermalMass(double thermalMassKJK)
      Set the core thermal mass for transient cool-down analysis (P7).

      The thermal mass is the product of core metal mass and specific heat capacity (m * Cp). Typical aluminium BAHX: ~2700 kg/m3 * 0.9 kJ/(kg K) = 2430 kJ/(m3 K).

      Parameters:
      thermalMassKJK - core thermal mass in kJ/K
    • getCoreThermalMass

      public double getCoreThermalMass()
      Get the core thermal mass.
      Returns:
      thermal mass in kJ/K
    • getMITA

      public double getMITA()
      Get the minimum internal temperature approach (MITA) across all zones.
      Returns:
      MITA in degrees (same value in K and C for a temperature difference)
    • getMITA

      public double getMITA(String unit)
      Get the MITA in the specified unit.
      Parameters:
      unit - temperature unit ("K", "C") — delta-T is identical in both
      Returns:
      MITA value
    • getMITAZoneIndex

      public int getMITAZoneIndex()
      Get the zone index (0-based from cold end) where MITA occurs.
      Returns:
      zone index, or -1 if not yet computed
    • getUAPerZone

      public double[] getUAPerZone()
      Get the per-zone UA values.
      Returns:
      array of UA values (W/K), length = numberOfZones
    • getMITAPerZone

      public double[] getMITAPerZone()
      Get the per-zone MITA values.
      Returns:
      array of temperature approaches (deg C), length = numberOfZones
    • getHotCompositeCurve

      public double[][] getHotCompositeCurve()
      Get the hot composite curve data (from rigorous zone-by-zone flash).
      Returns:
      2D array [numberOfZones+1][2] where col 0 = cumulative duty (kW) from cold end and col 1 = temperature (deg C)
    • getColdCompositeCurve

      public double[][] getColdCompositeCurve()
      Get the cold composite curve data (from rigorous zone-by-zone flash).
      Returns:
      2D array [numberOfZones+1][2] where col 0 = cumulative duty (kW) from cold end and col 1 = temperature (deg C)
    • getExergyDestructionPerZone

      public double[] getExergyDestructionPerZone()
      Get the per-zone exergy destruction (Priority 3).
      Returns:
      array of exergy destruction values (kW), length = numberOfZones
    • getTotalExergyDestruction

      public double getTotalExergyDestruction()
      Get the total exergy destruction across all zones.
      Returns:
      total exergy destruction in kW
    • getSecondLawEfficiency

      public double getSecondLawEfficiency()
      Get the second-law (exergetic) efficiency.

      Defined as the ratio of exergy gained by cold streams to exergy released by hot streams:

      eta_II = (exergy_gained_cold) / (exergy_released_hot)

      Returns:
      second-law efficiency, dimensionless (0 to 1). Typical LNG MCHE: 0.85–0.95.
    • getFreezeOutRiskPerZone

      public boolean[] getFreezeOutRiskPerZone()
      Get the per-zone CO2 freeze-out risk flags (P9).
      Returns:
      boolean array; true if freeze-out risk exists in that zone
    • hasFreezeOutRisk

      public boolean hasFreezeOutRisk()
      Check if any zone has a freeze-out risk.
      Returns:
      true if at least one zone has freeze-out risk
    • getThermalGradientPerZone

      public double[] getThermalGradientPerZone()
      Get the per-zone thermal gradient in deg C per metre of core length.
      Returns:
      array of thermal gradients (deg C/m), length = numberOfZones
    • hasThermalStressWarning

      public boolean hasThermalStressWarning()
      Check if any zone exceeds the allowable thermal gradient.
      Returns:
      true if a thermal stress warning was triggered
    • getComputedStreamDP

      public double[] getComputedStreamDP()
      Get the computed detailed pressure drop per stream from correlations (P5/P6).

      Only populated when fin geometry is set for a stream. Returns the sum of single-phase (Manglik-Bergles) and two-phase (Lockhart-Martinelli) contributions.

      Returns:
      array of computed pressure drops (bar), one per stream
    • getStreamJFactor

      public double[] getStreamJFactor()
      Get the average Colburn j-factor per stream from Manglik-Bergles correlation (P5).
      Returns:
      array of j-factors, one per stream (0.0 if fin geometry not set)
    • getStreamFFactor

      public double[] getStreamFFactor()
      Get the average Fanning friction factor per stream from Manglik-Bergles (P5).
      Returns:
      array of f-factors, one per stream (0.0 if fin geometry not set)
    • getTransientResults

      public List<LNGHeatExchanger.TransientPoint> getTransientResults()
      Get the cool-down transient results (P7).
      Returns:
      list of transient data points (time, metal temp, fluid temp, duty)
    • isMercuryRiskPresent

      public boolean isMercuryRiskPresent()
      Check if a mercury risk was flagged for aluminium BAHX.
      Returns:
      true if mercury concentration exceeds the safe limit
    • getMercuryRiskMessage

      public String getMercuryRiskMessage()
      Get the mercury risk assessment message.
      Returns:
      message string (empty if no risk)
    • generateFeasibilityReport

      public HeatExchangerDesignFeasibilityReport generateFeasibilityReport()
      Generate a complete design feasibility report for this BAHX.

      The report includes mechanical design (ASME VIII Div.1, ALPEMA), cost estimation (CAPEX, OPEX), supplier matching, and feasibility checks (temperature, pressure, mercury, freeze-out, thermal stress, MITA, exergy efficiency).

      Returns:
      the feasibility report with verdict, issues, suppliers, cost, and mechanical design
    • getZoneTempProfileHotC

      public double[] getZoneTempProfileHotC()
      Get the hot-side zone temperature profile in deg C (P9).
      Returns:
      array of temperatures per zone boundary, from cold end to hot end
    • getZoneTempProfileColdC

      public double[] getZoneTempProfileColdC()
      Get the cold-side zone temperature profile in deg C (P9).
      Returns:
      array of temperatures per zone boundary, from cold end to hot end
    • run

      public void run(UUID id)

      In this method all thermodynamic and unit operations will be calculated in a steady state calculation.

      Specified by:
      run in interface SimulationInterface
      Overrides:
      run in class MultiStreamHeatExchanger2
      Parameters:
      id - UUID
    • registerPendingStreams

      private void registerPendingStreams()
      Register pending streams with the parent, auto-classifying as hot or cold.
    • computeRigorousZoneData

      private void computeRigorousZoneData()
      Rigorous zone-by-zone analysis with TP-flash at every zone boundary.

      This is the core method that distinguishes this class from the parent. For each stream, the temperature range is divided into numberOfZones intervals and a full TP-flash is performed at each boundary. This captures the non-linear enthalpy-temperature relationship across phase transitions (methane condensation, MR evaporation), which is where the MITA pinch typically occurs in LNG exchangers.

      Includes adaptive zone refinement (P4), freeze-out detection (P9), flow maldistribution (P10), and thermal stress assessment.

    • buildUniformFractions

      private List<Double> buildUniformFractions(int zones)
      Build uniform fractional positions from 0.0 to 1.0.
      Parameters:
      zones - number of zones
      Returns:
      list of nPoints = zones+1 fraction values
    • computeAdaptiveFractions

      private List<Double> computeAdaptiveFractions(List<Double> uniformFracs)
      Refine zone fractions near phase boundaries where enthalpy gradient is steep (P4).

      Uses a first-pass enthalpy scan on the first stream to detect zones where |dH/dT| exceeds adaptiveThresholdFactor times the average gradient. Such zones are bisected to improve resolution near phase transitions.

      Parameters:
      uniformFracs - initial uniform fraction list
      Returns:
      refined fraction list with additional points near phase boundaries
    • manglikBerglesOSF

      private double[] manglikBerglesOSF(double re, LNGHeatExchanger.FinGeometry fin)
      Compute Colburn j-factor and Fanning f-factor for offset-strip fins.

      Manglik and Bergles (1995) correlations valid for 120 < Re < 10,000. Parameters are dimensionless ratios derived from fin geometry.

      Parameters:
      re - Reynolds number based on hydraulic diameter
      fin - fin geometry
      Returns:
      double array [j, f] where j = Colburn factor, f = Fanning friction factor
    • lockhartMartinelliPhiL2

      private double lockhartMartinelliPhiL2(double x, double rhoL, double rhoG, double muL, double muG)
      Compute two-phase pressure drop multiplier using the Lockhart-Martinelli separated flow model.

      The Martinelli parameter X_tt for turbulent-turbulent flow is computed from quality, density, and viscosity ratios. The two-phase multiplier phi_L squared is then evaluated using the Chisholm (1967) C-parameter correlation.

      Parameters:
      x - vapour quality (mass fraction), 0 to 1
      rhoL - liquid density in kg/m3
      rhoG - gas density in kg/m3
      muL - liquid viscosity in Pa s
      muG - gas viscosity in Pa s
      Returns:
      two-phase multiplier phi_L squared (dimensionless, >= 1.0)
    • computeDetailedPressureDrop

      private void computeDetailedPressureDrop(double[][] streamDensity, double[][] streamViscosity, double[][] streamVapFrac, double[] massFlowKgS, int effectiveZones)
      Compute detailed pressure drop per stream using Manglik-Bergles (P5) and Lockhart-Martinelli (P6) correlations.
      Parameters:
      streamDensity - density at each zone boundary [stream][point] in kg/m3
      streamViscosity - viscosity at each zone boundary [stream][point] in Pa s
      streamVapFrac - vapour fraction at each zone boundary [stream][point]
      massFlowKgS - mass flow rate per stream in kg/s
      effectiveZones - number of zones used
    • runCooldownTransient

      public void runCooldownTransient(double targetTempC, double ambientTempC, int timeSteps, double totalTimeHours)
      Run a simplified cool-down transient analysis (P7).

      Uses a lumped thermal mass model: the core metal temperature decreases from ambient toward the cold fluid temperature as the cooling utility flows through the exchanger. The energy balance at each time step is:

        m_metal * Cp_metal * dT_metal/dt = -UA * (T_metal - T_fluid)
      

      The core thermal mass and UA must be set before calling this method.

      Parameters:
      targetTempC - target metal temperature in deg C
      ambientTempC - initial metal temperature (ambient) in deg C
      timeSteps - number of time steps for the simulation
      totalTimeHours - total simulation duration in hours
    • sizeCore

      public void sizeCore()
      Size the BAHX core from total UA and fin geometry (P8).

      Calculates the required core dimensions (Length x Width x Height) from the total UA requirement and fin geometry. The method assumes the Manglik-Bergles heat-transfer coefficient for the first stream with fin geometry set.

      The design procedure follows Chart Industries and Linde BAHX sizing guidelines:

      1. Compute total UA from zone analysis
      2. Estimate average h from j-factor and fluid properties
      3. Required area A = UA / h
      4. Core volume = A / beta (surface area density)
      5. Distribute volume into L x W x H with aspect ratio constraints

      Also computes core weight assuming aluminium 3003 alloy density (2730 kg/m3) and typical void fraction of 0.3 (70% metal fraction including headers and bars).

    • assessMercuryRisk

      public void assessMercuryRisk(double mercuryPPB)
      Assess mercury attack risk for aluminium BAHX.

      Mercury attacks aluminium through liquid metal embrittlement (LME), forming amalgam that destroys the brazed joints. The industry limit for mercury in feed gas to aluminium BAHX is typically less than 0.01 microg/Nm3 (10 nanogram/Nm3 or ~10 ppt).

      This method checks the mercury concentration against the safe limit and flags a warning if the BAHX material is aluminium.

      Parameters:
      mercuryPPB - mercury concentration in ppb (parts per billion by volume)
    • compositeTemp

      private double compositeTemp(double[] inletTempC, double[] outletTempC, double[] massFlowKgS, boolean hotSide, int posFromColdEnd)
      Compute mass-flow-weighted composite temperature at a given position from cold end.
      Parameters:
      inletTempC - inlet temperatures in deg C per stream
      outletTempC - outlet temperatures in deg C per stream
      massFlowKgS - mass flow rates in kg/s per stream
      hotSide - true for hot composite, false for cold composite
      posFromColdEnd - position index from cold end (0 to numberOfZones)
      Returns:
      weighted average temperature in deg C
    • compositeTempAdaptive

      private double compositeTempAdaptive(double[][] streamTempC, double[] massFlowKgS, boolean hotSide, int effectiveZones, int posFromColdEnd)
      Compute mass-flow-weighted composite temperature using pre-computed per-zone temperatures.

      Used with adaptive zone refinement where zone positions are non-uniform.

      Parameters:
      streamTempC - pre-computed temperatures per stream per zone point
      massFlowKgS - mass flow rates in kg/s per stream
      hotSide - true for hot composite, false for cold composite
      effectiveZones - total number of effective zones
      posFromColdEnd - position index from cold end (0 to effectiveZones)
      Returns:
      weighted average temperature in deg C