Skip to the content.

Adsorption Recipes

Practical recipes for common adsorption simulation tasks in NeqSim. Each recipe is self-contained with ready-to-use Java code.

Prerequisites: See Adsorption Isotherm Models for thermodynamic theory and Adsorption Bed for process simulation details.


Quick Reference

Recipe Use Case
Evaluate a Single Isotherm Get loading for one gas on one solid
Compare Adsorbent Materials Screen materials for a separation
Multi-Component Competitive Adsorption Extended Langmuir/Sips for mixtures
Steady-State Bed Sizing Quick bed performance estimate
Transient Breakthrough Curve Track concentration front propagation
PSA Cycle Simulation Full pressure swing cycle
TSA Cycle Simulation Full temperature swing cycle
Effect of Temperature on Adsorption Isotherm sensitivity study
Bed in a Process Flowsheet Integrate with compressors, coolers, etc.
Capillary Condensation in Mesopores Kelvin equation for mesoporous materials

Recipe 1: Evaluate a Single Isotherm

Calculate equilibrium loading of CO$_2$ on Zeolite 13X at various pressures.

import neqsim.physicalproperties.interfaceproperties.solidadsorption.LangmuirAdsorption;
import neqsim.thermo.system.SystemSrkEos;

// Create gas system at 25°C
for (double pressure = 1.0; pressure <= 20.0; pressure += 1.0) {
    SystemSrkEos system = new SystemSrkEos(298.15, pressure);
    system.addComponent("CO2", 1.0);
    system.setMixingRule("classic");
    system.init(0);

    LangmuirAdsorption model = new LangmuirAdsorption(system);
    model.setSolidMaterial("Zeolite 13X");
    model.calcAdsorption(0);

    double loading = model.getSurfaceExcess(0); // mol/kg
    System.out.printf("P=%5.1f bar  q=%.3f mol/kg  coverage=%.3f%n",
        pressure, loading, model.getCoverage(0));
}

Recipe 2: Compare Adsorbent Materials

Screen multiple adsorbents for CO$_2$ removal at process conditions.

import neqsim.physicalproperties.interfaceproperties.solidadsorption.LangmuirAdsorption;
import neqsim.thermo.system.SystemSrkEos;

String[] materials = {"AC", "Zeolite 13X", "Zeolite 5A", "MOF HKUST-1",
                      "Silica Gel", "AC Calgon F400", "Alumina"};

SystemSrkEos system = new SystemSrkEos(298.15, 10.0);
system.addComponent("CO2", 0.10);
system.addComponent("methane", 0.90);
system.setMixingRule("classic");
system.init(0);

System.out.printf("%-20s  %10s  %10s%n", "Material", "CO2 (mol/kg)", "CH4 (mol/kg)");
System.out.printf("%-20s  %10s  %10s%n", "--------", "-----------", "-----------");

for (String material : materials) {
    LangmuirAdsorption model = new LangmuirAdsorption(system);
    model.setSolidMaterial(material);
    model.calcAdsorption(0);

    System.out.printf("%-20s  %10.3f  %10.3f%n",
        material,
        model.getSurfaceExcess("CO2"),
        model.getSurfaceExcess("methane"));
}

Recipe 3: Multi-Component Competitive Adsorption

Use the Extended Langmuir model for competitive CO$_2$/CH$_4$/N$_2$ adsorption.

import neqsim.physicalproperties.interfaceproperties.solidadsorption.LangmuirAdsorption;
import neqsim.thermo.system.SystemSrkEos;

SystemSrkEos system = new SystemSrkEos(298.15, 10.0);
system.addComponent("methane", 0.85);
system.addComponent("CO2", 0.10);
system.addComponent("nitrogen", 0.05);
system.setMixingRule("classic");
system.init(0);

LangmuirAdsorption model = new LangmuirAdsorption(system);
model.setSolidMaterial("Zeolite 13X");
model.calcExtendedLangmuir(0);  // multi-component competition

for (int i = 0; i < system.getPhase(0).getNumberOfComponents(); i++) {
    String name = system.getPhase(0).getComponent(i).getComponentName();
    double loading = model.getSurfaceExcess(i);
    double moleFrac = model.getAdsorbedPhaseMoleFraction(i);
    System.out.printf("%-10s  q=%.4f mol/kg  x_ads=%.4f%n", name, loading, moleFrac);
}

// CO2/CH4 selectivity
double selectivity = model.getSelectivity(1, 0, 0); // CO2 over CH4
System.out.printf("CO2/CH4 selectivity: %.1f%n", selectivity);

Recipe 4: Steady-State Bed Sizing

Quick estimate of adsorption bed performance without transient simulation.

import neqsim.process.equipment.adsorber.AdsorptionBed;
import neqsim.process.equipment.stream.Stream;
import neqsim.thermo.system.SystemSrkEos;

SystemSrkEos gas = new SystemSrkEos(298.15, 10.0);
gas.addComponent("methane", 0.85);
gas.addComponent("CO2", 0.10);
gas.addComponent("nitrogen", 0.05);
gas.setMixingRule("classic");

Stream feed = new Stream("Feed", gas);
feed.setFlowRate(5000.0, "kg/hr");
feed.run();

AdsorptionBed bed = new AdsorptionBed("CO2 Adsorber", feed);
bed.setBedDiameter(1.5);
bed.setBedLength(4.0);
bed.setAdsorbentMaterial("Zeolite 13X");
bed.setIsothermType(IsothermType.LANGMUIR);
bed.setKLDF(0.05);
bed.setCalculateSteadyState(true);  // default
bed.run();

System.out.println("Adsorbent mass: " + bed.getAdsorbentMass() + " kg");
System.out.println("Bed volume: " + bed.getBedVolume() + " m³");
System.out.println("Pressure drop: " + bed.getPressureDrop() + " Pa");

// Check outlet CO2 level
Stream outlet = (Stream) bed.getOutletStream();
double outletCO2 = outlet.getFluid().getPhase(0).getComponent("CO2").getx();
System.out.printf("Outlet CO2 mole fraction: %.6f%n", outletCO2);

Recipe 5: Transient Breakthrough Curve

Track how the concentration front propagates through the bed and detect breakthrough.

import neqsim.process.equipment.adsorber.AdsorptionBed;
import neqsim.process.equipment.stream.Stream;
import neqsim.thermo.system.SystemSrkEos;
import java.util.UUID;

// Setup (same as Recipe 4 feed)
SystemSrkEos gas = new SystemSrkEos(298.15, 10.0);
gas.addComponent("methane", 0.85);
gas.addComponent("CO2", 0.10);
gas.addComponent("nitrogen", 0.05);
gas.setMixingRule("classic");

Stream feed = new Stream("Feed", gas);
feed.setFlowRate(5000.0, "kg/hr");
feed.run();

AdsorptionBed bed = new AdsorptionBed("Breakthrough Test", feed);
bed.setBedDiameter(1.5);
bed.setBedLength(4.0);
bed.setAdsorbentMaterial("Zeolite 13X");
bed.setIsothermType(IsothermType.LANGMUIR);
bed.setKLDF(0.05);
bed.setNumberOfCells(100);
bed.setCalculateSteadyState(false);  // Enable transient mode
bed.setBreakthroughThreshold(0.05);

// Run transient simulation
double dt = 1.0;
UUID id = UUID.randomUUID();

System.out.printf("%8s  %12s  %12s  %10s%n", "Time(s)", "CO2_out/in", "MTZ(m)", "Avg_q");
for (int step = 0; step < 600; step++) {
    bed.runTransient(dt, id);

    if (step % 30 == 0) {
        double[] outConc = bed.getConcentrationProfile(1); // CO2
        double outletRatio = outConc[outConc.length - 1]
            / Math.max(outConc[0], 1e-20);
        double mtz = bed.getMassTransferZoneLength(1);
        double avgQ = bed.getAverageLoading(1);
        System.out.printf("%8.0f  %12.6f  %12.3f  %10.4f%n",
            bed.getElapsedTime(), outletRatio, mtz, avgQ);
    }

    if (bed.hasBreakthrough()) {
        System.out.printf("BREAKTHROUGH at t=%.1f s%n", bed.getBreakthroughTime());
        break;
    }
}

Recipe 6: PSA Cycle Simulation

Simulate a complete Pressure Swing Adsorption cycle for CO$_2$ removal.

import neqsim.process.equipment.adsorber.AdsorptionBed;
import neqsim.process.equipment.adsorber.AdsorptionCycleController;
import neqsim.process.equipment.adsorber.AdsorptionCycleController.CyclePhase;
import neqsim.process.equipment.stream.Stream;
import neqsim.thermo.system.SystemSrkEos;
import java.util.UUID;

// Feed gas
SystemSrkEos gas = new SystemSrkEos(298.15, 10.0);
gas.addComponent("methane", 0.90);
gas.addComponent("CO2", 0.10);
gas.setMixingRule("classic");

Stream feed = new Stream("PSA Feed", gas);
feed.setFlowRate(2000.0, "kg/hr");
feed.run();

// Adsorption bed
AdsorptionBed bed = new AdsorptionBed("PSA Bed", feed);
bed.setBedDiameter(1.2);
bed.setBedLength(3.5);
bed.setAdsorbentMaterial("Zeolite 13X");
bed.setAdsorbentBulkDensity(620.0);
bed.setIsothermType(IsothermType.LANGMUIR);
bed.setKLDF(0.05);
bed.setNumberOfCells(80);
bed.setCalculateSteadyState(false);

// PSA cycle: 5 min adsorption, 30s blowdown, 1 min purge, 30s repress
AdsorptionCycleController controller = new AdsorptionCycleController(bed);
controller.configurePSA(300.0, 30.0, 60.0, 30.0, 1.0);

// Run 3 complete cycles
double dt = 0.5;
UUID id = UUID.randomUUID();
double totalTime = 3 * 420.0; // 3 cycles × 420 s/cycle

for (double t = 0; t < totalTime; t += dt) {
    controller.advance(dt, id);
    bed.runTransient(dt, id);

    // Log every 30 seconds
    if (Math.abs(t % 30.0) < dt / 2) {
        System.out.printf("t=%6.0f s  Phase=%-15s  CO2_avg=%.3f mol/kg  Cycles=%d%n",
            t, controller.getCurrentPhase(),
            bed.getAverageLoading(1),
            controller.getCompletedCycles());
    }
}

System.out.printf("Completed %d PSA cycles%n", controller.getCompletedCycles());

Recipe 7: TSA Cycle Simulation

Simulate a Temperature Swing Adsorption cycle for gas dehydration.

import neqsim.process.equipment.adsorber.AdsorptionBed;
import neqsim.process.equipment.adsorber.AdsorptionCycleController;
import neqsim.process.equipment.stream.Stream;
import neqsim.thermo.system.SystemSrkEos;
import java.util.UUID;

// Wet gas feed
SystemSrkEos gas = new SystemSrkEos(303.15, 50.0); // 30°C, 50 bar
gas.addComponent("methane", 0.95);
gas.addComponent("water", 0.005);
gas.addComponent("CO2", 0.03);
gas.addComponent("ethane", 0.015);
gas.setMixingRule("classic");

Stream feed = new Stream("TSA Feed", gas);
feed.setFlowRate(10000.0, "kg/hr");
feed.run();

// Molecular sieve bed
AdsorptionBed bed = new AdsorptionBed("Dehydration Bed", feed);
bed.setBedDiameter(2.0);
bed.setBedLength(5.0);
bed.setAdsorbentMaterial("Zeolite 4A");
bed.setAdsorbentBulkDensity(700.0);
bed.setIsothermType(IsothermType.LANGMUIR);
bed.setKLDF(0.02);
bed.setNumberOfCells(60);
bed.setCalculateSteadyState(false);

// TSA: 30 min adsorption, 10 min heating at 250°C, 5 min cooling
AdsorptionCycleController controller = new AdsorptionCycleController(bed);
controller.configureTSA(1800.0, 600.0, 300.0, 523.15); // 250°C desorption

// Run 1 full cycle
double dt = 1.0;
UUID id = UUID.randomUUID();

for (double t = 0; t < 2700.0; t += dt) {
    controller.advance(dt, id);
    bed.runTransient(dt, id);
}

System.out.printf("Water avg loading after cycle: %.4f mol/kg%n",
    bed.getAverageLoading(1)); // water component index

Recipe 8: Effect of Temperature on Adsorption

Study how temperature affects equilibrium loading (basis for TSA design).

import neqsim.physicalproperties.interfaceproperties.solidadsorption.LangmuirAdsorption;
import neqsim.thermo.system.SystemSrkEos;

double pressure = 5.0; // bar

System.out.printf("%8s  %12s  %12s%n", "T (°C)", "CO2 (mol/kg)", "K (1/bar)");
for (double tempC = 0; tempC <= 200; tempC += 10) {
    double tempK = 273.15 + tempC;
    SystemSrkEos system = new SystemSrkEos(tempK, pressure);
    system.addComponent("CO2", 1.0);
    system.setMixingRule("classic");
    system.init(0);

    LangmuirAdsorption model = new LangmuirAdsorption(system);
    model.setSolidMaterial("Zeolite 13X");
    model.calcAdsorption(0);

    System.out.printf("%8.0f  %12.4f  %12.6f%n",
        tempC, model.getSurfaceExcess(0), model.getKLangmuir(0));
}
// Expect: loading decreases monotonically with temperature
// The ratio of loading at 25°C vs 200°C = working capacity for TSA

Recipe 9: Bed in a Process Flowsheet

Integrate the adsorption bed with other NeqSim process equipment.

import neqsim.process.equipment.adsorber.AdsorptionBed;
import neqsim.process.equipment.compressor.Compressor;
import neqsim.process.equipment.heatexchanger.Cooler;
import neqsim.process.equipment.separator.Separator;
import neqsim.process.equipment.stream.Stream;
import neqsim.process.processmodel.ProcessSystem;
import neqsim.thermo.system.SystemSrkEos;

// Create feed
SystemSrkEos gas = new SystemSrkEos(298.15, 5.0);
gas.addComponent("methane", 0.85);
gas.addComponent("CO2", 0.10);
gas.addComponent("nitrogen", 0.05);
gas.setMixingRule("classic");

Stream feed = new Stream("Raw Gas", gas);
feed.setFlowRate(5000.0, "kg/hr");

// Compress feed to adsorption pressure
Compressor comp = new Compressor("Feed Compressor", feed);
comp.setOutletPressure(20.0);

// Cool after compression
Cooler cooler = new Cooler("Aftercooler", comp.getOutletStream());
cooler.setOutTemperature(298.15);

// Adsorption bed
AdsorptionBed bed = new AdsorptionBed("CO2 Adsorber", cooler.getOutletStream());
bed.setBedDiameter(1.5);
bed.setBedLength(4.0);
bed.setAdsorbentMaterial("Zeolite 13X");
bed.setIsothermType(IsothermType.LANGMUIR);
bed.setKLDF(0.05);

// Build and run process
ProcessSystem process = new ProcessSystem();
process.add(feed);
process.add(comp);
process.add(cooler);
process.add(bed);
process.run();

// Results
Stream outlet = (Stream) bed.getOutletStream();
System.out.println("Outlet CO2: "
    + outlet.getFluid().getPhase(0).getComponent("CO2").getx());
System.out.println("Compressor power: " + comp.getPower("kW") + " kW");
System.out.println("Cooler duty: " + cooler.getDuty() + " W");

Recipe 10: Capillary Condensation in Mesopores

Calculate condensation onset and condensate amounts in mesoporous silica.

import neqsim.physicalproperties.interfaceproperties.solidadsorption.CapillaryCondensationModel;
import neqsim.thermo.system.SystemSrkEos;

SystemSrkEos system = new SystemSrkEos(298.15, 5.0);
system.addComponent("n-butane", 1.0);
system.setMixingRule("classic");
system.init(0);
system.init(1);

CapillaryCondensationModel ccModel = new CapillaryCondensationModel(system);
ccModel.setMeanPoreRadius(4.0);     // nm
ccModel.setPoreRadiusStdDev(1.5);   // nm
ccModel.setTotalPoreVolume(0.8);    // cm³/g
ccModel.setPoreType(CapillaryCondensationModel.PoreType.CYLINDRICAL);

ccModel.calcCapillaryCondensation(0);

System.out.println("Kelvin radius: " + ccModel.getKelvinRadius(0) + " nm");
System.out.println("Condensate amount: " + ccModel.getCondensateAmount(0) + " mol/g");
System.out.println("Saturation pressure: " + ccModel.getSaturationPressure(0) + " bar");

Tips and Common Pitfalls

1. Always Set the Mixing Rule

Without a mixing rule, the thermodynamic system will not calculate fugacities correctly, and adsorption models will give wrong results.

system.setMixingRule("classic"); // Required!

2. Temperature in Kelvin

NeqSim uses Kelvin internally. Always add 273.15 when specifying temperatures in Celsius.

SystemSrkEos system = new SystemSrkEos(273.15 + 25.0, 10.0); // 25°C, 10 bar

3. Transient Mode Must Be Enabled

By default, AdsorptionBed runs in steady-state mode. For breakthrough curves, MTZ analysis, or PSA/TSA cycles, you must switch to transient:

bed.setCalculateSteadyState(false);

4. Grid Resolution vs Speed

More cells give better accuracy but slower simulation. Start with 50 cells for design studies, increase to 100+ for final analysis.

5. kLDF Sensitivity

The LDF coefficient is the most critical tuning parameter. Too low and the front barely moves; too high and the front is sharp but may cause numerical oscillation. Start with 0.01–0.05 and calibrate against experimental breakthrough data.

6. Desorption Requires Pressure or Temperature Change

Simply setting setDesorptionMode(true) without a pressure or temperature change may not drive sufficient desorption. NeqSim defaults to atmospheric pressure (1.01325 bara) when no explicit desorption pressure is set, but for TSA you must specify the desorption temperature.