Best for
- USE WHEN: setting up distillation columns, troubleshooting convergence, selecting internals (trays/packing), sizing columns, or analyzing column performance.
equinor/neqsim/.github/skills/neqsim-distillation-design/SKILL.md
Distillation column design rules for NeqSim. USE WHEN: setting up distillation columns, troubleshooting convergence, selecting internals (trays/packing), sizing columns, or analyzing column performance. Covers DistillationColumn setup, solver selection, feed tray optimization, reflux ratio, and internals selection per industry standards.
Decision brief
Guide for distillation column modeling and design in NeqSim.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/equinor/neqsim --skill ".github/skills/neqsim-distillation-design"Inspect the Agent Skill "neqsim-distillation-design" from https://github.com/equinor/neqsim/blob/9e8d44a141bba600026d2229969b49af50f34237/.github/skills/neqsim-distillation-design/SKILL.md at commit 9e8d44a141bba600026d2229969b49af50f34237. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Review the “Column Setup Pattern” section in the pinned source before continuing.
Three knobs decide how long a column runs before it gives up. Getting them wrong is the usual cause of a column that burns minutes per solve inside a ProcessModel outer loop.
Three knobs decide how long a column runs before it gives up. Getting them wrong is the usual cause of a column that burns minutes per solve inside a ProcessModel outer loop.
solved() is not a single residual. It requires the solve status to be RIGOROUSCONVERGED or RECONCILEDPRODUCTS and every active residual gate to pass:
Review the “Solver Selection Guide” section in the pinned source before continuing.
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 97/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 136 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Guide for distillation column modeling and design in NeqSim.
import neqsim.process.equipment.distillation.DistillationColumn;
import neqsim.process.equipment.stream.Stream;
import neqsim.thermo.system.SystemSrkEos;
import neqsim.thermo.system.SystemInterface;
// Create feed
SystemInterface feed = new SystemSrkEos(273.15 + 50.0, 15.0);
feed.addComponent("methane", 0.10);
feed.addComponent("ethane", 0.25);
feed.addComponent("propane", 0.30);
feed.addComponent("n-butane", 0.20);
feed.addComponent("n-pentane", 0.15);
feed.setMixingRule("classic");
Stream feedStream = new Stream("feed", feed);
feedStream.setFlowRate(10000.0, "kg/hr");
feedStream.setTemperature(50.0, "C");
feedStream.setPressure(15.0, "bara");
feedStream.run();
// Create column (name, stages, hasCondenser, hasReboiler)
DistillationColumn column = new DistillationColumn("Deethanizer", 15, true, true);
column.addFeedStream(feedStream, 8); // Feed on stage 8
// Specifications
column.setCondenserTemperature(273.15 - 30.0); // Kelvin
column.getReboiler().setHeatInput(1e6); // Watts
// OR set reflux ratio:
// column.getCondenser().setRefluxRatio(2.5);
column.run();
// Direct substitution (default) - robust sequential tray sweeps
column.setSolverType(DistillationColumn.SolverType.DIRECT_SUBSTITUTION);
// Inside-Out — faster for ideal/near-ideal systems
column.setSolverType(DistillationColumn.SolverType.INSIDE_OUT);
// Adaptive matrix inside-out — bypasses matrix setup on small columns,
// tries a component-balance matrix warm start on larger columns, then
// finishes with rigorous inside-out polishing
column.setSolverType(DistillationColumn.SolverType.MATRIX_INSIDE_OUT);
// Damped substitution - for difficult convergence
column.setSolverType(DistillationColumn.SolverType.DAMPED_SUBSTITUTION);
// MESH residual monitor - for residual auditing
column.setSolverType(DistillationColumn.SolverType.MESH_RESIDUAL);
// Naphtali-Sandholm - guarded simultaneous MESH residual Newton solver
column.setSolverType(DistillationColumn.SolverType.NAPHTALI_SANDHOLM);
// Optional: seed stage temperatures as initial guesses only, not fixed specs
column.setSeedTemperature(3, 273.15 + 45.0);
// Adjust max iterations
column.setMaxNumberOfIterations(200);
Three knobs decide how long a column runs before it gives up. Getting them wrong
is the usual cause of a column that burns minutes per solve inside a
ProcessModel outer loop.
// 1. ITERATION BUDGET — setMaxNumberOfIterations(n) is only a SOFT FLOOR.
// The effective budget is max(n, 5 * numberOfTrays) and can still be expanded
// by the overflow/polish extensions. setMaxNumberOfIterations(10) on an
// 11-tray column therefore does NOT cap anything (11*5 = 55 -> ~187 with
// overflow). NeqSim logs a warning when the request is below the tray floor.
column.setMaxNumberOfIterations(20, true); // HARD cap (2-arg overload)
column.setHardIterationCap(true); // or flip the flag separately
column.getEffectiveMaxNumberOfIterations(); // what the solver will actually use
// 2. DAMPING — the adaptive controller clamps the sequential step at
// minSequentialRelaxation (default 0.5). setRelaxationFactor now lowers that
// floor when you ask for heavier damping, so a request below 0.5 takes effect
// instead of being silently clamped back. Use this to break limit cycles.
column.setRelaxationFactor(0.3);
column.setMinSequentialRelaxation(0.2); // explicit floor if needed
column.setMinInsideOutRelaxation(0.2); // inside-out tear streams
// 3. TOLERANCE — the default absolute temperature tolerance (~0.02-0.03 K) can
// be ~10x tighter than the enclosing ProcessModel boundary gate (1e-3
// relative ~ 0.27 K at 270 K), so the column keeps iterating on a residual
// the plant model already accepts. Align them:
column.setTemperatureToleranceRelative(1.0e-3); // returns the absolute K value
column.getReferenceTemperature(); // basis used for the conversion
Rule of thumb for a column inside a multi-area ProcessModel: set a hard
iteration cap, damp below 0.5 if the tray temperatures oscillate, and match the
column tolerance to the model tolerance passed to
ProcessModel.runUntilConverged(maxIter, tol).
solved() actually checkssolved() is not a single residual. It requires the solve status to be
RIGOROUS_CONVERGED or RECONCILED_PRODUCTS and every active residual gate
to pass:
| Gate | Source | Default tolerance |
|---|---|---|
| Temperature | mean per-tray change of the last sweep | ~0.02 K x complexity; NaN for simultaneous solvers, which then require the MESH gate instead |
| Mass | external feed/product balance | ~0.016 x complexity |
| Energy | tray enthalpy balance | not enforced by default (setEnforceEnergyBalanceTolerance(true)) |
| Internal traffic | max tray traffic / feed | 100 |
| Per-tray material balance | getLastTrayMaterialBalanceError() — summed absolute tray imbalance / tray throughput | getTrayMaterialBalanceTolerance(), default 0.02 |
| MESH infinity norm | all residual families | getMeshResidualTolerance(), default 1.0 |
The overall feed/product balance closing to machine precision does not mean
the column solved: each tray must close its own component balance too. Read
per-tray material imbalance in getConvergenceDiagnostics() before trusting
duties or a tray profile.
Do not gate on the MESH
material:infinity norm. Those entries scale each component by its own throughput, so a trace component going from 1e-25 to 1.2e-25 mol/hr reads as a 0.17 residual. UsegetLastTrayMaterialBalanceError(), which weights by tray throughput.
| System Type | Recommended Solver | Notes |
|---|---|---|
| Ideal HC (demethanizer, deethanizer) | INSIDE_OUT | Fast, robust |
| Larger HC fractionators | MATRIX_INSIDE_OUT | Adaptive: small columns bypass matrix overhead; larger columns try the matrix warm start before rigorous inside-out polishing |
| Non-ideal (alcohols, water) | DAMPED_SUBSTITUTION or DIRECT_SUBSTITUTION | More conservative for non-ideal K-values |
| Absorbers (no condenser/reboiler) | SUM_RATES or DIRECT_SUBSTITUTION | Flow-corrected updates can help absorber/stripper cases |
| Wide-boiling (C1 to C20+) | DAMPED_SUBSTITUTION | Increase iterations and monitor residuals |
| Cryogenic (< -100°C) | INSIDE_OUT with residual diagnostics | Careful with phase identification |
| Solver audit / residual convergence | MESH_RESIDUAL or NAPHTALI_SANDHOLM | MESH_RESIDUAL records diagnostics and enforces the MESH/product-draw gate by default; NAPHTALI_SANDHOLM attempts guarded simultaneous MESH correction |
| Bottom Spec | Top Spec | Comment |
|---|---|---|
| Reboiler duty | Condenser temperature | Most common |
| Reboiler duty | Reflux ratio | Alternative |
| Top product purity | Reboiler duty | Product-quality control |
| Bottom temperature | Reflux ratio | Direct T control |
// Common specification patterns
// Pattern 1: Condenser T + Reboiler duty
column.setCondenserTemperature(273.15 - 30.0);
column.getReboiler().setHeatInput(1.5e6);
// Pattern 2: Reflux ratio + Reboiler duty
column.getCondenser().setRefluxRatio(3.0);
column.getReboiler().setHeatInput(2.0e6);
// Pattern 3: Product quality plus boilup ratio
column.setTopProductPurity("ethane", 0.98);
column.setReboilerBoilupRatio(2.0);
column.run();
// Condenser and reboiler duties
double condenserDuty = column.getCondenser().getDuty(); // Watts
double reboilerDuty = column.getReboiler().getDuty(); // Watts
// Product streams
Stream overhead = (Stream) column.getGasOutStream();
Stream bottoms = (Stream) column.getLiquidOutStream();
// Stage temperatures and compositions
for (int stage = 0; stage < column.getTrays().size(); stage++) {
double stageTemp = column.getTray(stage).getTemperature() - 273.15;
// Composition on each stage
}
// Convergence metrics
int iterations = column.getLastIterationCount();
double massResidual = column.getLastMassResidual();
double energyResidual = column.getLastEnergyResidual();
boolean matrixWarmStartUsed = column.wasMatrixInsideOutWarmStartUsed();
boolean matrixWarmStartBypassed = column.wasMatrixInsideOutWarmStartBypassed();
int matrixIterations = column.getLastMatrixInsideOutIterationCount();
For binary or pseudo-binary separations:
$$ \log\left(\frac{N_R}{N_S}\right) = 0.206 \log\left[\left(\frac{B}{D}\right) \left(\frac{x_{HK,F}}{x_{LK,F}}\right)^2 \left(\frac{x_{LK,B}}{x_{HK,D}}\right)^2 \right] $$
Where $N_R$ = rectifying stages, $N_S$ = stripping stages, $B/D$ = bottoms/distillate ratio.
| Column Type | Feed Tray (from top) | Notes |
|---|---|---|
| Demethanizer | 40-60% of stages | Light key is very volatile |
| Deethanizer | 50-70% of stages | Moderate volatility |
| Depropanizer | 40-60% of stages | Balanced separation |
| Debutanizer | 50-60% of stages | Similar to depropanizer |
| Crude column | 60-80% of stages | Flash zone near bottom |
$$ N_{min} = \frac{\log\left(\frac{x_{LK,D}}{x_{HK,D}} \cdot \frac{x_{HK,B}}{x_{LK,B}}\right)}{\log(\alpha_{LK/HK})} $$
$$ R_{min} = \frac{1}{\alpha - 1}\left(\frac{x_D}{\alpha - \theta} - \frac{1 - x_D}{1 - \theta}\right) $$
| Problem | Solution |
|---|---|
| Column does not converge | Increase max iterations to 200-500 |
| Oscillating temperature profile | Reduce condenser/reboiler specs, use DAMPED_SUBSTITUTION; audit with MESH_RESIDUAL before trying NAPHTALI_SANDHOLM |
| Wrong product split | Check feed tray location and specifications |
| Negative flows on stages | Too many stages or wrong specifications |
| Condenser too cold | Check if subcooled liquid is physical (binary dewpoint) |
| Reboiler too hot | May be decomposing — check component stability |
$$ V_{flood} = K_{SB} \sqrt{\frac{\rho_L - \rho_V}{\rho_V}} $$
Where $K_{SB}$ = 0.03-0.07 m/s for trays, 0.02-0.05 for packing.
Design velocity = 70-85% of flooding.
// After running column, get phase properties for sizing
SystemInterface topFluid = column.getTray(0).getFluid();
topFluid.initProperties();
double rhoV = topFluid.getPhase("gas").getDensity("kg/m3");
double rhoL = topFluid.getPhase("oil").getDensity("kg/m3");
double Ksb = 0.05; // m/s for sieve trays
double Vflood = Ksb * Math.sqrt((rhoL - rhoV) / rhoV);
double Vdesign = 0.80 * Vflood;
double gasFlow = column.getGasOutStream().getFlowRate("m3/hr") / 3600.0;
double area = gasFlow / Vdesign;
double diameter = Math.sqrt(4.0 * area / Math.PI);
| Internals | When to Use | Typical HETP (m) |
|---|---|---|
| Sieve trays | General service, fouling | 0.5-0.7 |
| Valve trays | Variable turndown | 0.4-0.6 |
| Bubble cap trays | Low liquid rates | 0.5-0.8 |
| Random packing (Pall rings) | Low pressure drop, corrosive | 0.3-0.6 |
| Structured packing (Mellapak) | Vacuum, low ΔP | 0.2-0.5 |
Alternatives
coreyhaines31/marketingskills
When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program
coreyhaines31/marketingskills
When the user wants to reduce churn, build cancellation flows, set up save offers, recover failed payments, or implement retention strategies. Also use when the user mentions 'churn,' 'cancel flow,' 'offboarding,' 'save offer,' 'dunning,' 'failed payment recovery,' 'win-back,' 'retention,' 'exit survey,' 'pause subscription,' 'involuntary churn,' 'people keep canceling,' 'churn rate is too high,' 'how do I keep users,' or 'customers are leaving.' Use this whenever someone is losing subscribers o
prowler-cloud/prowler
PostgreSQL indexing best practices for Prowler: index design, partial indexes, partitioned table indexing, EXPLAIN ANALYZE validation, concurrent operations, monitoring, and maintenance. Trigger: When creating or modifying PostgreSQL indexes, analyzing query performance with EXPLAIN, debugging slow queries, reviewing index usage statistics, reindexing, dropping indexes, or working with partitioned table indexes. Also trigger when discussing index strategies, partial indexes, or index maintenance
JasonColapietro/suede-creator-skills
Suede-owned experimentation discipline for hypotheses, sample sizing, test duration, significance, and repeatable experiment programs. Use when comparing variants, deciding whether a result is reliable, or building an experiment backlog and cadence. NOT FOR: analytics instrumentation (use suede-analytics), post-click conversion diagnosis (use suede-site-alchemy), or writing the variant copy itself (use suede-copy).