Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,29 @@ public class DistillationColumn extends ProcessEquipmentBaseClass implements Dis
private static final int POLISH_ITERATION_MARGIN = 6;
/** Multiplier governing how much the solver can extend beyond the nominal iteration budget. */
private static final int ITERATION_OVERFLOW_MULTIPLIER = 12;
/** Recommended base temperature tolerance for adaptive defaults. */
private static final double DEFAULT_TEMPERATURE_TOLERANCE = 4.0e-3;
/** Recommended base mass balance tolerance for adaptive defaults. */
private static final double DEFAULT_MASS_BALANCE_TOLERANCE = 1.6e-2;
/** Recommended base enthalpy balance tolerance for adaptive defaults. */
private static final double DEFAULT_ENTHALPY_BALANCE_TOLERANCE = 1.6e-2;
double condenserCoolingDuty = 10.0;
private double reboilerTemperature = 273.15;
private double condenserTemperature = 270.15;
double topTrayPressure = -1.0;

/** Temperature convergence tolerance. */
private double temperatureTolerance = 1.0e-3;
private double temperatureTolerance = DEFAULT_TEMPERATURE_TOLERANCE;
/** Mass balance convergence tolerance. */
private double massBalanceTolerance = 5.0e-3;
private double massBalanceTolerance = DEFAULT_MASS_BALANCE_TOLERANCE;
/** Enthalpy balance convergence tolerance. */
private double enthalpyBalanceTolerance = 5.0e-3;
private double enthalpyBalanceTolerance = DEFAULT_ENTHALPY_BALANCE_TOLERANCE;
/** Track whether temperature tolerance has been manually overridden. */
private boolean temperatureToleranceCustomized = false;
/** Track whether mass balance tolerance has been manually overridden. */
private boolean massBalanceToleranceCustomized = false;
/** Track whether enthalpy balance tolerance has been manually overridden. */
private boolean enthalpyBalanceToleranceCustomized = false;

/** Available solving strategies for the column. */
public enum SolverType {
Expand Down Expand Up @@ -428,9 +440,9 @@ private void solveSequential(UUID id, double initialRelaxation) {
int overflowBand = Math.max(overflowIncrement, numberOfTrays);
int maxIterationLimit = Math.max(iterationLimit, maxNumberOfIterations)
+ overflowBand * ITERATION_OVERFLOW_MULTIPLIER;
double baseTempTolerance = temperatureTolerance;
double baseMassTolerance = massBalanceTolerance;
double baseEnergyTolerance = enthalpyBalanceTolerance;
double baseTempTolerance = getEffectiveTemperatureTolerance();
double baseMassTolerance = getEffectiveMassBalanceTolerance();
double baseEnergyTolerance = getEffectiveEnthalpyBalanceTolerance();
double polishTempTolerance = Math.min(baseTempTolerance, TEMPERATURE_POLISH_TARGET);
double polishMassTolerance = Math.min(baseMassTolerance, MASS_POLISH_TARGET);
double polishEnergyTolerance = Math.min(baseEnergyTolerance, ENERGY_POLISH_TARGET);
Expand Down Expand Up @@ -501,9 +513,9 @@ private void solveSequential(UUID id, double initialRelaxation) {
massEnergyEvaluated = true;
}

double tempScaled = err / temperatureTolerance;
double massScaled = massErr / massBalanceTolerance;
double energyScaled = energyErr / enthalpyBalanceTolerance;
double tempScaled = err / baseTempTolerance;
double massScaled = massErr / baseMassTolerance;
double energyScaled = energyErr / baseEnergyTolerance;
double combinedResidual = Math.max(tempScaled, massScaled);
if (Double.isFinite(energyScaled)) {
combinedResidual =
Expand Down Expand Up @@ -582,6 +594,90 @@ private int computeIterationLimit() {
return Math.max(Math.max(1, maxNumberOfIterations), trayBasedLimit);
}

/**
* Derive the effective temperature tolerance based on column complexity unless overridden.
*
* @return adaptive temperature tolerance in Kelvin
*/
private double getEffectiveTemperatureTolerance() {
if (temperatureToleranceCustomized) {
return temperatureTolerance;
}
return DEFAULT_TEMPERATURE_TOLERANCE * computeToleranceComplexityMultiplier();
}

/**
* Derive the effective mass balance tolerance based on column complexity unless overridden.
*
* @return adaptive mass balance tolerance (relative)
*/
private double getEffectiveMassBalanceTolerance() {
if (massBalanceToleranceCustomized) {
return massBalanceTolerance;
}
return DEFAULT_MASS_BALANCE_TOLERANCE * computeToleranceComplexityMultiplier();
}

/**
* Derive the effective enthalpy balance tolerance based on column complexity unless overridden.
*
* @return adaptive energy balance tolerance (relative)
*/
private double getEffectiveEnthalpyBalanceTolerance() {
if (enthalpyBalanceToleranceCustomized) {
return enthalpyBalanceTolerance;
}
return DEFAULT_ENTHALPY_BALANCE_TOLERANCE * computeToleranceComplexityMultiplier();
}

/**
* Estimate a scaling factor that reflects the degree of distillation complexity.
*
* <p>The factor increases with the number of theoretical stages and independent feed streams and
* is bounded to avoid overly loose convergence criteria.</p>
*
* @return scaling multiplier for recommended tolerances
*/
private double computeToleranceComplexityMultiplier() {
int stageCount = Math.max(1, getEffectiveStageCount());
double stageMultiplier = 1.0 + Math.max(0, stageCount - 3) * 0.06;

int feedCount = Math.max(0, getTotalFeedCount());
double feedMultiplier = 1.0 + Math.max(0, feedCount - 1) * 0.25;

double combined = Math.max(stageMultiplier, feedMultiplier);
return Math.min(2.5, combined);
}

/**
* Count the number of simple trays, excluding optional reboiler and condenser sections.
*
* @return effective number of equilibrium stages
*/
private int getEffectiveStageCount() {
int stageCount = numberOfTrays;
if (hasReboiler && stageCount > 0) {
stageCount--;
}
if (hasCondenser && stageCount > 0) {
stageCount--;
}
return Math.max(0, stageCount);
}

/**
* Count connected feed streams across all trays.
*
* @return total number of feeds currently attached to the column
*/
private int getTotalFeedCount() {
int total = 0;
for (List<StreamInterface> feeds : feedStreams.values()) {
total += feeds.size();
}
return total;
}

/**
* Decide whether mass and energy balance residuals should be recomputed this iteration.
*
Expand Down Expand Up @@ -700,9 +796,9 @@ private void solveInsideOut(UUID id) {
int overflowBand = Math.max(overflowIncrement, numberOfTrays);
int maxIterationLimit = Math.max(iterationLimit, maxNumberOfIterations)
+ overflowBand * ITERATION_OVERFLOW_MULTIPLIER;
double baseTempTolerance = temperatureTolerance;
double baseMassTolerance = massBalanceTolerance;
double baseEnergyTolerance = enthalpyBalanceTolerance;
double baseTempTolerance = getEffectiveTemperatureTolerance();
double baseMassTolerance = getEffectiveMassBalanceTolerance();
double baseEnergyTolerance = getEffectiveEnthalpyBalanceTolerance();
double polishTempTolerance = Math.min(baseTempTolerance, TEMPERATURE_POLISH_TARGET);
double polishMassTolerance = Math.min(baseMassTolerance, MASS_POLISH_TARGET);
double polishEnergyTolerance = Math.min(baseEnergyTolerance, ENERGY_POLISH_TARGET);
Expand Down Expand Up @@ -770,9 +866,9 @@ private void solveInsideOut(UUID id) {
massEnergyEvaluated = true;
}

double tempScaled = err / temperatureTolerance;
double massScaled = massErr / massBalanceTolerance;
double energyScaled = energyErr / enthalpyBalanceTolerance;
double tempScaled = err / baseTempTolerance;
double massScaled = massErr / baseMassTolerance;
double energyScaled = energyErr / baseEnergyTolerance;
double combinedResidual = Math.max(tempScaled, massScaled);
if (Double.isFinite(energyScaled)) {
combinedResidual =
Expand Down Expand Up @@ -882,11 +978,11 @@ public void runBroyden(UUID id) {

int baseIterationLimit = computeIterationLimit();
int iterationLimit = baseIterationLimit;
int polishIterationLimit = baseIterationLimit
+ Math.max(POLISH_ITERATION_MARGIN, (int) Math.ceil(0.5 * numberOfTrays));
double baseTempTolerance = temperatureTolerance;
double baseMassTolerance = massBalanceTolerance;
double baseEnergyTolerance = enthalpyBalanceTolerance;
int polishIterationLimit = baseIterationLimit
+ Math.max(POLISH_ITERATION_MARGIN, (int) Math.ceil(0.5 * numberOfTrays));
double baseTempTolerance = getEffectiveTemperatureTolerance();
double baseMassTolerance = getEffectiveMassBalanceTolerance();
double baseEnergyTolerance = getEffectiveEnthalpyBalanceTolerance();
double polishTempTolerance = Math.min(baseTempTolerance, TEMPERATURE_POLISH_TARGET);
double polishMassTolerance = Math.min(baseMassTolerance, MASS_POLISH_TARGET);
double polishEnergyTolerance = Math.min(baseEnergyTolerance, ENERGY_POLISH_TARGET);
Expand Down Expand Up @@ -1105,7 +1201,7 @@ public void setBottomPressure(double bottomPressure) {
/** {@inheritDoc} */
@Override
public boolean solved() {
return (err < temperatureTolerance);
return (err < getEffectiveTemperatureTolerance());
}

/**
Expand Down Expand Up @@ -1159,7 +1255,25 @@ public double getLastSolveTimeSeconds() {
* @return mass balance tolerance
*/
public double getMassBalanceTolerance() {
return massBalanceTolerance;
return getEffectiveMassBalanceTolerance();
}

/**
* Control whether the solver enforces the energy balance tolerance when determining convergence.
*
* @param enforce {@code true} to require the energy residual to satisfy the configured tolerance
*/
public void setEnforceEnergyBalanceTolerance(boolean enforce) {
this.enforceEnergyBalanceTolerance = enforce;
}

/**
* Check if the solver currently enforces the energy balance tolerance during convergence checks.
*
* @return {@code true} if the energy residual must satisfy its tolerance before convergence
*/
public boolean isEnforceEnergyBalanceTolerance() {
return enforceEnergyBalanceTolerance;
}

/**
Expand All @@ -1186,7 +1300,7 @@ public boolean isEnforceEnergyBalanceTolerance() {
* @return enthalpy balance tolerance
*/
public double getEnthalpyBalanceTolerance() {
return enthalpyBalanceTolerance;
return getEffectiveEnthalpyBalanceTolerance();
}

/**
Expand All @@ -1195,7 +1309,7 @@ public double getEnthalpyBalanceTolerance() {
* @return temperature tolerance in Kelvin
*/
public double getTemperatureTolerance() {
return temperatureTolerance;
return getEffectiveTemperatureTolerance();
}

/**
Expand Down Expand Up @@ -1360,6 +1474,7 @@ public void setDoInitializion(boolean doInitializion) {
*/
public void setTemperatureTolerance(double tol) {
this.temperatureTolerance = tol;
this.temperatureToleranceCustomized = true;
}

/**
Expand All @@ -1369,6 +1484,7 @@ public void setTemperatureTolerance(double tol) {
*/
public void setMassBalanceTolerance(double tol) {
this.massBalanceTolerance = tol;
this.massBalanceToleranceCustomized = true;
}

/**
Expand All @@ -1378,6 +1494,19 @@ public void setMassBalanceTolerance(double tol) {
*/
public void setEnthalpyBalanceTolerance(double tol) {
this.enthalpyBalanceTolerance = tol;
this.enthalpyBalanceToleranceCustomized = true;
}

/**
* Restore adaptive default tolerances, discarding manual overrides.
*/
public void resetToleranceOverrides() {
temperatureToleranceCustomized = false;
massBalanceToleranceCustomized = false;
enthalpyBalanceToleranceCustomized = false;
temperatureTolerance = DEFAULT_TEMPERATURE_TOLERANCE;
massBalanceTolerance = DEFAULT_MASS_BALANCE_TOLERANCE;
enthalpyBalanceTolerance = DEFAULT_ENTHALPY_BALANCE_TOLERANCE;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void testRun() {
column.setTopPressure(1.12);
column.setBottomPressure(1.12);
column.setInternalDiameter(0.56);
column.setMaxNumberOfIterations(40);
column.setMaxNumberOfIterations(30);
column.run();

double waterFlowRateInColumn =
Expand Down Expand Up @@ -153,7 +153,7 @@ public void deethanizerTest() {
column.getReboiler().setOutTemperature(105.0 + 273.15);
column.setTopPressure(30.0);
column.setBottomPressure(32.0);
column.setMaxNumberOfIterations(50);
column.setMaxNumberOfIterations(35);
column.run();
column.run();

Expand Down Expand Up @@ -201,6 +201,7 @@ public void debutanizerTest() {
column.getReboiler().setOutTemperature(gasToDbutanizer.getTemperature() + 50.0);
column.setTopPressure(9.0);
column.setBottomPressure(13.0);
column.setMaxNumberOfIterations(30);
column.run();
// ((Condenser) column.getCondenser()).getProductOutStream().getFluid().prettyPrint();

Expand Down Expand Up @@ -239,7 +240,7 @@ public void insideOutSolverMatchesStandardOnDeethanizerCase() {
direct.getReboiler().setOutTemperature(105.0 + 273.15);
direct.setTopPressure(30.0);
direct.setBottomPressure(32.0);
direct.setMaxNumberOfIterations(50);
direct.setMaxNumberOfIterations(35);
direct.run();

Stream insideOutFeed = new Stream("insideOutFeed", baseGas.clone());
Expand All @@ -251,7 +252,7 @@ public void insideOutSolverMatchesStandardOnDeethanizerCase() {
insideOut.getReboiler().setOutTemperature(105.0 + 273.15);
insideOut.setTopPressure(30.0);
insideOut.setBottomPressure(32.0);
insideOut.setMaxNumberOfIterations(50);
insideOut.setMaxNumberOfIterations(35);
insideOut.setSolverType(DistillationColumn.SolverType.INSIDE_OUT);
insideOut.run();

Expand Down
Loading