Skip to the content.

Adjusters

Documentation for adjuster equipment in NeqSim process simulation.

Table of Contents


Overview

Location: neqsim.process.equipment.util

Class: Adjuster

Adjusters are iterative solvers that modify one process variable to achieve a target specification. They are essential for solving design problems where:

NeqSim supports two configuration modes:

  1. Standard Mode: Using predefined variable names (setAdjustedVariable, setTargetVariable)
  2. Functional Interface Mode: Using lambda expressions for complete flexibility

Adjuster Class

Basic Usage

import neqsim.process.equipment.util.Adjuster;

// Create adjuster
Adjuster adjuster = new Adjuster("Temperature Controller");

// Set the variable to adjust
adjuster.setAdjustedVariable(heater, "outTemperature");

// Set the target specification
adjuster.setTargetVariable(stream, "temperature", 80.0, "C");

// Add to process
process.add(adjuster);
process.run();

// Get the adjusted value
double adjustedTemp = heater.getOutTemperature("C");

Configuration

Adjusted Variables

The variable that the adjuster will modify:

Equipment Variable Description
Heater/Cooler "duty" Heat duty (W)
Heater/Cooler "outTemperature" Outlet temperature
Compressor "outletPressure" Discharge pressure
Valve "outletPressure" Outlet pressure
Valve "percentValveOpening" Valve position
Splitter "splitFactor" Split ratio
Stream "flowRate" Flow rate
// Examples
adjuster.setAdjustedVariable(heater, "duty");
adjuster.setAdjustedVariable(compressor, "outletPressure");
adjuster.setAdjustedVariable(valve, "percentValveOpening");
adjuster.setAdjustedVariable(splitter, "splitFactor", 0);  // First split

Target Variables

The specification to be achieved:

Equipment Variable Description
Stream "temperature" Stream temperature
Stream "pressure" Stream pressure
Stream "flowRate" Stream flow rate
Stream "moleFraction" Component mole fraction
Separator "liquidLevel" Liquid level fraction
Any Custom User-defined property
// Examples
adjuster.setTargetVariable(stream, "temperature", 80.0, "C");
adjuster.setTargetVariable(separator, "liquidLevel", 0.5);
adjuster.setTargetVariable(stream, "moleFraction", 0.02, "CO2");

Solver Settings

// Maximum iterations
adjuster.setMaximumIterations(100);

// Convergence tolerance
adjuster.setTolerance(1e-6);

// Bounds on adjusted variable
adjuster.setMinimumValue(-1e7);  // Lower bound
adjuster.setMaximumValue(1e7);   // Upper bound

// Step size for numerical derivatives
adjuster.setStepSize(0.001);

Functional Interface Mode

For complex scenarios where standard variable names are insufficient, the Adjuster supports functional interfaces (lambda expressions) for complete flexibility. This allows you to:

Functional Interface Methods

Method Signature Description
setAdjustedValueSetter Consumer<Double> Lambda to set the adjusted value
setAdjustedValueGetter Supplier<Double> Lambda to get the current adjusted value
setTargetValueCalculator Supplier<Double> Lambda to calculate the target (measured) value
setTargetValue double The setpoint that the target should reach

Basic Structure

Adjuster adjuster = new Adjuster("adjuster");

// Set the setpoint (what targetValueCalculator should return)
adjuster.setTargetValue(desiredValue);

// Set bounds for the adjusted variable
adjuster.setMinAdjustedValue(minValue);
adjuster.setMaxAdjustedValue(maxValue);

// Lambda: How to SET the adjusted variable
adjuster.setAdjustedValueSetter((val) -> {
    // Your logic to set the value
    equipment.setSomeProperty(val);
});

// Lambda: How to GET the current adjusted variable value
adjuster.setAdjustedValueGetter(() -> {
    // Your logic to get the current value
    return equipment.getSomeProperty();
});

// Lambda: How to CALCULATE the measured variable (compared to setpoint)
adjuster.setTargetValueCalculator(() -> {
    // Your logic to calculate current target value
    return someCalculation();
});

Example: Splitter Flow Control

Adjust a splitter’s second outlet flow rate to achieve a target flow in the first outlet:

// Create process equipment
Stream feed = new Stream("feed", fluid);
feed.setFlowRate(1000.0, "kg/hr");

Splitter splitter = new Splitter("splitter", feed);
splitter.setSplitNumber(2);
splitter.setSplitFactors(new double[] {0.5, 0.5});

Stream stream1 = new Stream("stream1", splitter.getSplitStream(0));
Stream stream2 = new Stream("stream2", splitter.getSplitStream(1));

// Create adjuster with functional interfaces
Adjuster adjuster = new Adjuster("Flow Adjuster");

// Setpoint: we want stream1 to have 800 kg/hr
adjuster.setTargetValue(800.0);

// Bounds: stream2 flow must be between 0 and 1000 kg/hr
adjuster.setMinAdjustedValue(0.0);
adjuster.setMaxAdjustedValue(1000.0);

// Setter: Adjust the flow rate of stream2 via splitter
// Note: Splitter.setFlowRates uses -1 for "calculate this one"
adjuster.setAdjustedValueSetter((val) -> {
    splitter.setFlowRates(new double[] {-1, val}, "kg/hr");
});

// Getter: Get current flow rate of stream2
adjuster.setAdjustedValueGetter(() -> {
    return splitter.getSplitStream(1).getFlowRate("kg/hr");
});

// Target Calculator: Get flow rate of stream1 (what we're controlling)
adjuster.setTargetValueCalculator(() -> {
    return stream1.getFlowRate("kg/hr");
});

// Add to process
ProcessSystem process = new ProcessSystem();
process.add(feed);
process.add(splitter);
process.add(stream1);
process.add(stream2);
process.add(adjuster);
process.run();

// Result: stream1 = 800 kg/hr, stream2 = 200 kg/hr

Example: Custom Temperature Control

Adjust temperature to achieve a target product of flow × temperature:

Stream inletStream = new Stream("inlet", fluid);
inletStream.setFlowRate(100.0, "kg/hr");
inletStream.setTemperature(200.0, "K");

Adjuster adjuster = new Adjuster("Custom Adjuster");

// Setpoint: flow × temperature = 30000
adjuster.setTargetValue(30000.0);
adjuster.setMinAdjustedValue(100.0);   // Min temp 100 K
adjuster.setMaxAdjustedValue(500.0);   // Max temp 500 K

// Setter: Adjust temperature
adjuster.setAdjustedValueSetter((val) -> {
    inletStream.setTemperature(val, "K");
});

// Getter: Get current temperature
adjuster.setAdjustedValueGetter(() -> {
    return inletStream.getTemperature("K");
});

// Target Calculator: flow × temperature
adjuster.setTargetValueCalculator(() -> {
    return inletStream.getFlowRate("kg/hr") * inletStream.getTemperature("K");
});

ProcessSystem process = new ProcessSystem();
process.add(inletStream);
process.add(adjuster);
process.run();

// Result: temperature adjusts to 300 K (100 × 300 = 30000)

Equipment-Based Functional Interfaces

For cleaner code when working with specific equipment, use the equipment-aware signatures:

// Set the equipment references
adjuster.setAdjustedVariable(inletStream);
adjuster.setTargetVariable(inletStream);

// Setter with equipment reference
adjuster.setAdjustedValueSetter((equipment, val) -> {
    Stream s = (Stream) equipment;
    s.setTemperature(val, "K");
});

// Getter with equipment reference
adjuster.setAdjustedValueGetter((equipment) -> {
    Stream s = (Stream) equipment;
    return s.getTemperature("K");
});

// Target calculator with equipment reference
adjuster.setTargetValueCalculator((equipment) -> {
    Stream s = (Stream) equipment;
    return s.getFlowRate("kg/hr") * s.getTemperature("K");
});

When to Use Functional Interfaces

Scenario Recommended Approach
Standard properties (temperature, pressure, flow) Standard mode with setAdjustedVariable
Properties not in predefined list Functional interface mode
Complex calculations for target Use setTargetValueCalculator
Adjusting one equipment to affect another Functional interface mode
Multiple variables combined in target Functional interface mode
Conditional logic in getting/setting Functional interface mode

Usage Examples

Temperature Control

// Adjust heater duty to achieve target outlet temperature
Adjuster tempControl = new Adjuster("TC-100");
tempControl.setAdjustedVariable(heater, "duty");
tempControl.setTargetVariable(heater.getOutletStream(), "temperature", 100.0, "C");
process.add(tempControl);

Dew Point Control

// Adjust cooler to achieve hydrocarbon dew point
Adjuster dewPointControl = new Adjuster("HCDP Controller");
dewPointControl.setAdjustedVariable(cooler, "outTemperature");
dewPointControl.setTargetPhaseCondition(stream, "cricondenbar", 50.0, "bara");
process.add(dewPointControl);

Product Purity

// Adjust column reflux to achieve product purity
Adjuster purityControl = new Adjuster("Purity Controller");
purityControl.setAdjustedVariable(column, "refluxRatio");
purityControl.setTargetVariable(overhead, "moleFraction", 0.99, "methane");
process.add(purityControl);

Separator Level Control

// Adjust outlet valve to maintain liquid level
Adjuster levelControl = new Adjuster("LC-100");
levelControl.setAdjustedVariable(outletValve, "percentValveOpening");
levelControl.setTargetVariable(separator, "liquidLevel", 0.5);
process.add(levelControl);

Flow Split Optimization

// Adjust split ratio to achieve target flow in branch
Adjuster flowControl = new Adjuster("FC-100");
flowControl.setAdjustedVariable(splitter, "splitFactor", 0);
flowControl.setTargetVariable(branchStream, "flowRate", 5000.0, "kg/hr");
process.add(flowControl);

Multiple Adjusters

When using multiple adjusters, add them in order of priority:

// First adjuster (higher priority)
Adjuster adj1 = new Adjuster("Primary");
adj1.setAdjustedVariable(heater, "duty");
adj1.setTargetVariable(stream1, "temperature", 80.0, "C");
process.add(adj1);

// Second adjuster (solved after first converges)
Adjuster adj2 = new Adjuster("Secondary");
adj2.setAdjustedVariable(cooler, "duty");
adj2.setTargetVariable(stream2, "temperature", 30.0, "C");
process.add(adj2);

Troubleshooting

Convergence Issues

// Increase iterations
adjuster.setMaximumIterations(200);

// Widen bounds
adjuster.setMinimumValue(-1e8);
adjuster.setMaximumValue(1e8);

// Check if converged
if (!adjuster.isConverged()) {
    System.out.println("Adjuster did not converge");
    System.out.println("Current error: " + adjuster.getError());
}

Infeasible Specifications

Some specifications may be physically impossible:

Check that specifications are achievable before troubleshooting solver settings.