Distillation Equipment
Documentation for distillation column equipment in NeqSim process simulation.
Table of Contents
- Overview
- Column Types
- Configuration
- Builder Pattern
- Solver Options
- Column Specifications
- Diagnostics and Residuals
- Usage Examples
Overview
Location: neqsim.process.equipment.distillation
Classes:
DistillationColumn- Main distillation columnSimpleTray- Individual trayCondenser- Column condenserReboiler- Column reboiler
Basic Usage
import neqsim.process.equipment.distillation.DistillationColumn;
// Create column with 10 trays, reboiler, and condenser
DistillationColumn column = new DistillationColumn("Deethanizer", 10, true, true);
column.addFeedStream(feedStream, 5); // Feed on tray 5
column.setCondenserTemperature(273.15 + 40.0); // Kelvin
column.setReboilerTemperature(273.15 + 120.0); // Kelvin
column.run();
// Get products
Stream overhead = column.getGasOutStream();
Stream bottoms = column.getLiquidOutStream();
Builder Pattern
For complex column configurations, use the fluent Builder API:
import neqsim.process.equipment.distillation.DistillationColumn;
import neqsim.process.equipment.distillation.DistillationColumn.SolverType;
// Build column with fluent API
DistillationColumn column = DistillationColumn.builder("Deethanizer")
.numberOfTrays(15)
.withCondenserAndReboiler()
.topPressure(25.0, "bara")
.bottomPressure(26.0, "bara")
.temperatureTolerance(0.001)
.massBalanceTolerance(0.01)
.maxIterations(100)
.solverType(SolverType.INSIDE_OUT)
.internalDiameter(2.5)
.addFeedStream(feedStream, 8)
.build();
column.run();
Builder Methods
| Method | Description |
|---|---|
numberOfTrays(int) |
Set number of simple trays (excluding condenser/reboiler) |
withCondenser() |
Add condenser at top |
withReboiler() |
Add reboiler at bottom |
withCondenserAndReboiler() |
Add both |
topPressure(double, String) |
Set top pressure with unit |
bottomPressure(double, String) |
Set bottom pressure with unit |
pressure(double, String) |
Set same pressure top and bottom |
temperatureTolerance(double) |
Convergence tolerance for temperature |
massBalanceTolerance(double) |
Convergence tolerance for mass balance |
tolerance(double) |
Set all tolerances at once |
maxIterations(int) |
Maximum solver iterations |
solverType(SolverType) |
Set solver algorithm |
directSubstitution() |
Use direct substitution solver |
dampedSubstitution() |
Use damped substitution solver |
insideOut() |
Use inside-out solver |
relaxationFactor(double) |
Damping factor for solver |
internalDiameter(double) |
Column internal diameter (meters) |
multiPhaseCheck(boolean) |
Enable/disable multi-phase check |
addFeedStream(Stream, int) |
Add feed stream to specified tray |
topSpecification(ColumnSpecification) |
Set top product specification |
bottomSpecification(ColumnSpecification) |
Set bottom product specification |
topProductPurity(String, double) |
Shortcut: top product purity for named component |
bottomProductPurity(String, double) |
Shortcut: bottom product purity for named component |
build() |
Build the configured column |
Column Configuration
Number of Trays
// Constructor: (name, numTrays, hasReboiler, hasCondenser)
DistillationColumn column = new DistillationColumn("T-100", 20, true, true);
Feed Location
// Single feed
column.addFeedStream(feed, 10); // Tray 10 from bottom
// Multiple feeds
column.addFeedStream(feed1, 8);
column.addFeedStream(feed2, 12);
Condenser Type
// Total condenser
column.setCondenserType("total");
// Partial condenser (vapor overhead)
column.setCondenserType("partial");
Side Draws
// Liquid side draw
column.addSideDraw(7, "liquid", 100.0, "kg/hr");
// Vapor side draw
column.addSideDraw(15, "vapor", 50.0, "kg/hr");
Operating Specifications
Temperature Specifications
// Condenser temperature
column.setCondenserTemperature(273.15 + 40.0); // Kelvin
// Reboiler temperature
column.setReboilerTemperature(273.15 + 120.0); // Kelvin
Pressure Profile
// Top pressure
column.setTopPressure(15.0); // bara
// Bottom pressure (or pressure drop)
column.setBottomPressure(16.0); // bara
Reflux Specifications
// Reflux ratio
column.setCondenserRefluxRatio(3.0);
// Condenser duty
column.getCondenser().setHeatInput(-5000000.0); // W (negative = cooling)
Reboiler Specifications
// Reboiler duty
column.getReboiler().setHeatInput(6000000.0); // W
// Boilup ratio
column.setReboilerBoilupRatio(2.5);
Column Specifications
NeqSim supports flexible column specifications through the ColumnSpecification class.
Instead of specifying condenser/reboiler temperatures or duties directly, you can
specify desired product quality targets and NeqSim will adjust operating conditions
automatically using a secant-method outer loop.
Specification Types
| Type | Description | Example |
|---|---|---|
PRODUCT_PURITY |
Mole-fraction purity of a component in a product stream | 95 mol% ethane overhead |
REFLUX_RATIO |
Condenser reflux ratio (L/D) | Reflux ratio of 3.5 |
COMPONENT_RECOVERY |
Fraction of feed component recovered in a product (0–1) | 99% ethane recovery overhead |
PRODUCT_FLOW_RATE |
Total molar flow rate of a product stream (kmol/h) | 100 kmol/h overhead |
DUTY |
Condenser or reboiler duty (W) | Reboiler duty 5 MW |
Product Purity Specification
// Specify top and bottom product purities
column.setTopProductPurity("ethane", 0.95); // 95 mol% ethane overhead
column.setBottomProductPurity("propane", 0.98); // 98 mol% propane in bottoms
column.run(); // Outer loop adjusts condenser/reboiler temperatures
Component Recovery Specification
// Recover 99% of feed ethane in the overhead product
column.setTopComponentRecovery("ethane", 0.99);
column.run();
Reflux and Boilup Ratio
// Set reflux ratio (applied directly, no outer loop needed)
column.setCondenserRefluxRatio(3.5);
// Set boilup ratio
column.setReboilerBoilupRatio(2.0);
column.run();
Product Flow Rate Specification
// Set overhead flow rate target
column.setTopProductFlowRate(100.0); // kmol/h
column.run();
Using ColumnSpecification Directly
import neqsim.process.equipment.distillation.ColumnSpecification;
import neqsim.process.equipment.distillation.ColumnSpecification.SpecificationType;
import neqsim.process.equipment.distillation.ColumnSpecification.ProductLocation;
// Create a custom specification
ColumnSpecification topSpec = new ColumnSpecification(
SpecificationType.PRODUCT_PURITY,
ProductLocation.TOP,
0.95, // target value
"ethane" // component name
);
topSpec.setTolerance(1e-3); // convergence tolerance
topSpec.setMaxIterations(30); // max outer-loop iterations
column.setTopSpecification(topSpec);
column.run();
Builder Pattern with Specifications
DistillationColumn column = DistillationColumn.builder("Deethanizer")
.numberOfTrays(25)
.withCondenserAndReboiler()
.topPressure(25.0, "bara")
.insideOut()
.addFeedStream(feed, 12)
.topProductPurity("ethane", 0.95)
.bottomProductPurity("propane", 0.98)
.build();
column.run();
How It Works
For direct specifications (reflux ratio, duty), the values are applied on the condenser or reboiler before the inner column solver runs.
For iterative specifications (product purity, component recovery, product flow rate), NeqSim wraps the inner solver in a secant-method outer loop that:
- Runs the column with initial temperature guesses
- Evaluates the specification error (current − target)
- Adjusts condenser or reboiler temperature using the secant update
- Repeats until the error is within tolerance (default 1e-4)
Solver Options
Available Solvers
| Solver type | Strategy | Typical use |
|---|---|---|
DIRECT_SUBSTITUTION |
Classic tray-by-tray substitution without extra damping. | Default choice for simple and well-posed columns. |
DAMPED_SUBSTITUTION |
Sequential substitution with an initial fixed relaxation factor. | Stiffer cases where direct substitution overshoots. |
INSIDE_OUT |
Inside-out style flow correction with K-value tracking and polishing. | General process work, deethanizers, and multi-feed columns. |
WEGSTEIN |
Accelerated successive substitution after a warm-up phase. | Well-conditioned columns where faster convergence is useful. |
SUM_RATES |
Flow-corrected tearing method using sum-rate style updates. | Absorbers, strippers, and flow-sensitive columns. |
NEWTON |
Tray-temperature correction accelerator with finite-difference Jacobian and line search. | Difficult temperature convergence cases. This is not a full simultaneous MESH Newton solver. |
MESH_RESIDUAL |
Runs inside-out initialization with Newton polishing and records full MESH residual diagnostics. | Auditing material, equilibrium, summation, energy, and specification residuals before future rigorous solver work. |
Convergence Settings
| Method | Purpose |
|---|---|
setMaxNumberOfIterations(int) |
Set the minimum requested solver iteration limit; the column may use a larger adaptive limit for complex cases. |
setTemperatureTolerance(double) |
Override the adaptive average tray-temperature tolerance in Kelvin. |
setMassBalanceTolerance(double) |
Override the adaptive relative mass-balance tolerance. |
setEnthalpyBalanceTolerance(double) |
Override the adaptive relative enthalpy-balance tolerance. |
setEnforceEnergyBalanceTolerance(boolean) |
Require the energy residual to pass before solved() returns true. Disabled by default for backward compatibility. |
setRelaxationFactor(double) |
Set the starting relaxation factor for DAMPED_SUBSTITUTION. |
setMeshResidualTolerance(double) |
Set the scaled MESH residual norm tolerance used by the optional MESH convergence gate. |
setEnforceMeshResidualTolerance(boolean) |
Require the latest MESH residual vector to pass before solved() returns true. Disabled by default. |
Initialization
Column initialization is automatic. init() runs the feed streams, places any unassigned feed near
the closest tray temperature, seeds a pressure profile from top and bottom pressure settings, and
links the neighboring vapor and liquid streams used by the tray sweeps. User-controlled condenser
and reboiler temperatures or duties remain the main practical way to influence the starting profile.
Diagnostics and Residuals
Every DistillationColumn.run() records scalar convergence metrics and a scaled MESH residual
vector for the final column state. The residual vector groups equations into material,
equilibrium, summation, energy, and active specification residuals.
| Getter | Description |
|---|---|
getLastIterationCount() |
Number of iterations used by the active solver. |
getLastTemperatureResidual() |
Average tray-temperature residual in Kelvin. |
getLastMassResidual() |
Relative mass-balance residual. |
getLastEnergyResidual() |
Relative enthalpy-balance residual. |
getLastSpecificationResidual() |
Largest absolute active top/bottom specification residual. |
getLastMeshResidualNorm() |
Infinity norm of the full scaled MESH residual vector. |
getLastMeshMaterialResidualNorm() |
Infinity norm of component material residuals. |
getLastMeshEquilibriumResidualNorm() |
Infinity norm of fugacity-equilibrium residuals. |
getLastMeshSummationResidualNorm() |
Infinity norm of vapor/liquid mole-fraction summation residuals. |
getLastMeshEnergyResidualNorm() |
Infinity norm of tray energy residuals. |
getLastMeshSpecificationResidualNorm() |
Infinity norm of active specification residuals. |
getLastMeshResidualVector() |
Copy of the full residual vector, ordered by internal equation metadata. |
The optional MESH residual convergence gate is off by default. Enable it when a workflow should treat the full residual vector as part of the convergence contract rather than as diagnostics only.
Column Results
Tray-by-Tray Profiles
column.run();
// Temperature profile
for (int i = 0; i < column.getTrays().size(); i++) {
double temperatureC = column.getTray(i).getTemperature() - 273.15;
double vaporFlow = column.getTray(i).getVaporFlowRate("kg/hr");
double liquidFlow = column.getTray(i).getLiquidFlowRate("kg/hr");
System.out.println("Tray " + i + ": " + temperatureC + " C, V=" + vaporFlow
+ " kg/hr, L=" + liquidFlow + " kg/hr");
}
Duties
double Qcond = column.getCondenser().getDuty(); // W
double Qreb = column.getReboiler().getDuty(); // W
System.out.println("Condenser duty: " + (-Qcond/1e6) + " MW");
System.out.println("Reboiler duty: " + (Qreb/1e6) + " MW");
Separation Performance
// Product purities
double overheadEthaneMoleFraction = overhead.getFluid().getComponent("ethane").getx();
double bottomsPropaneMoleFraction = bottoms.getFluid().getComponent("propane").getx();
Example: NGL Fractionation
Deethanizer
// Feed: NGL from gas plant
SystemInterface ngl = new SystemSrkEos(273.15 + 30, 25.0);
ngl.addComponent("methane", 0.02);
ngl.addComponent("ethane", 0.25);
ngl.addComponent("propane", 0.35);
ngl.addComponent("i-butane", 0.10);
ngl.addComponent("n-butane", 0.18);
ngl.addComponent("n-pentane", 0.10);
ngl.setMixingRule("classic");
Stream feed = new Stream("NGL Feed", ngl);
feed.setFlowRate(5000.0, "kg/hr");
ProcessSystem process = new ProcessSystem();
process.add(feed);
// Deethanizer column
DistillationColumn deethanizer = new DistillationColumn("Deethanizer", 25, true, true);
deethanizer.addFeedStream(feed, 12);
deethanizer.setTopPressure(25.0); // bara
deethanizer.setCondenserTemperature(273.15 - 10.0); // Kelvin
deethanizer.setReboilerTemperature(273.15 + 100.0); // Kelvin
deethanizer.setSolverType(DistillationColumn.SolverType.INSIDE_OUT);
process.add(deethanizer);
process.run();
// Results
Stream ethaneProduct = deethanizer.getGasOutStream();
Stream c3plusProduct = deethanizer.getLiquidOutStream();
System.out.println("Ethane product:");
System.out.println(" Flow: " + ethaneProduct.getFlowRate("kg/hr") + " kg/hr");
System.out.println(" C2 purity: " +
ethaneProduct.getFluid().getComponent("ethane").getx() * 100 + " mol%");
System.out.println("C3+ product:");
System.out.println(" Flow: " + c3plusProduct.getFlowRate("kg/hr") + " kg/hr");
System.out.println(" C2 content: " +
c3plusProduct.getFluid().getComponent("ethane").getx() * 100 + " mol%");
Depropanizer
// Feed from deethanizer bottoms
DistillationColumn depropanizer = new DistillationColumn("Depropanizer", 30, true, true);
depropanizer.addFeedStream(c3plusProduct, 15);
depropanizer.setTopPressure(18.0); // bara
depropanizer.setCondenserTemperature(273.15 + 45.0); // Kelvin
depropanizer.setReboilerTemperature(273.15 + 110.0); // Kelvin
process.add(depropanizer);
process.run();
Stream propaneProduct = depropanizer.getGasOutStream();
Stream c4plusProduct = depropanizer.getLiquidOutStream();
Absorber Column
For absorption without reboiler:
DistillationColumn absorber = new DistillationColumn("Absorber", 10, false, false);
absorber.addFeedStream(gasStream, 1); // Gas at bottom
absorber.addFeedStream(leanSolvent, 10); // Solvent at top
absorber.run();
Stream richSolvent = absorber.getLiquidOutStream();
Stream sweetGas = absorber.getGasOutStream();
Stripper Column
For stripping without condenser:
DistillationColumn stripper = new DistillationColumn("Stripper", 8, false, true);
stripper.addFeedStream(richSolvent, 1);
stripper.setReboilerTemperature(273.15 + 120.0); // Kelvin
stripper.run();
Stream acidGas = stripper.getGasOutStream();
Stream leanSolvent = stripper.getLiquidOutStream();
Related Documentation
- Process Package - Package overview
- Heat Exchangers - Condensers and reboilers
- Absorbers - Absorption columns