Comprehensive documentation for control valves in NeqSim process simulation.
Table of Contents
- Overview
- Check Valve
- Level Control Valve
- Pressure Control Valve
- ESD Valve
- PSD Valve
- Dynamic Simulation
- API Reference
Overview
Location: neqsim.process.equipment.valve
NeqSim provides specialized control valves for process automation and safety systems:
| Class | Description | Typical Application |
|---|---|---|
CheckValve |
Non-return valve | Pump/compressor protection |
LevelControlValve |
Level regulation | Separator liquid discharge |
PressureControlValve |
Pressure regulation | Gas pressure letdown |
ESDValve |
Emergency shutdown | Process isolation |
PSDValve |
Process shutdown | Overpressure protection |
LevelControlValve and PressureControlValve extend ThrottlingValve through ControlValve and add an embedded incremental proportional command. Safety-valve subclasses have separate qualification limits described below.
Check Valve
A check valve (non-return valve) prevents reverse flow automatically based on differential pressure.
Features
- Automatic operation based on differential pressure
- Configurable cracking pressure (minimum ΔP to open)
- Zero leakage when closed (ideal model)
- Minimal pressure drop when fully open
Applications
- Pump discharge protection
- Compressor discharge protection
- Parallel equipment isolation
- Gravity drainage systems
- Siphon prevention
Java Example
import neqsim.process.equipment.valve.CheckValve;
// Create check valve on pump discharge
CheckValve checkValve = new CheckValve("CV-101", pumpDischargeStream);
checkValve.setCrackingPressure(0.2); // Opens at 0.2 bar differential
checkValve.setCv(250.0); // Flow coefficient when fully open
checkValve.run();
// Check valve state
if (checkValve.isOpen()) {
System.out.println("Forward flow - valve open");
double flowRate = checkValve.getOutletStream().getFlowRate("kg/hr");
} else {
System.out.println("Reverse flow blocked - valve closed");
}
Python Example
from neqsim import jneqsim
CheckValve = jneqsim.process.equipment.valve.CheckValve
# Create check valve
check_valve = CheckValve("CV-101", pump_discharge)
check_valve.setCrackingPressure(0.2) # 0.2 bar
check_valve.setCv(250.0)
check_valve.run()
print(f"Valve open: {check_valve.isOpen()}")
print(f"Cracking pressure: {check_valve.getCrackingPressure()} bar")
Key Methods
| Method | Description |
|---|---|
setCrackingPressure(double) |
Set minimum ΔP to open valve (bar) |
getCrackingPressure() |
Get cracking pressure |
isOpen() |
Check if valve is currently open |
Level Control Valve
A level control valve (LCV) modulates opening to maintain vessel level at setpoint.
Features
- Automatic level control with proportional action
- Configurable level setpoint (0-100%)
- Direct or reverse control action
- Adjustable controller gain
- Fail-safe position configuration
Control Actions
| Action | Description | Use Case |
|---|---|---|
| DIRECT | Increasing measured level increases opening and outflow | Liquid discharge (most common) |
| REVERSE | Increasing measured level decreases opening | Process-specific inverse configurations |
Java Example
import neqsim.process.equipment.valve.LevelControlValve;
import neqsim.process.equipment.valve.LevelControlValve.ControlAction;
// Create separator with liquid outlet
Separator separator = new Separator("V-101", feedStream);
Stream liquidOut = separator.getLiquidOutStream();
// Create level control valve
LevelControlValve lcv = new LevelControlValve("LCV-101", liquidOut);
lcv.setLevelSetpoint(50.0); // Control to 50% level
lcv.setControllerGain(3.0); // Proportional gain
lcv.setControlAction(ControlAction.DIRECT);
lcv.setMeasuredLevel(45.0); // Current level from transmitter
lcv.setCv(150.0);
lcv.run();
System.out.println("Valve opening: " + lcv.getPercentValveOpening() + "%");
System.out.println("Level error: " + lcv.getControlError() + "%");
Python Example
from neqsim import jneqsim
LevelControlValve = jneqsim.process.equipment.valve.LevelControlValve
# Create level control valve on separator liquid outlet
lcv = LevelControlValve("LCV-101", separator.getLiquidOutStream())
lcv.setLevelSetpoint(50.0) # 50% level setpoint
lcv.setControllerGain(3.0) # Proportional gain
lcv.setMeasuredLevel(45.0) # Current measured level
lcv.setCv(150.0)
lcv.run()
print(f"Valve opening: {lcv.getPercentValveOpening()}%")
print(f"Control error: {lcv.getControlError()}%")
Key Methods
| Method | Description |
|---|---|
setLevelSetpoint(double) |
Set target level (0-100%) |
setMeasuredLevel(double) |
Update measured level from transmitter |
setControllerGain(double) |
Set proportional gain (1-10 typical) |
setControlAction(ControlAction) |
DIRECT or REVERSE |
getControlError() |
Get setpoint - measured level |
setFailSafePosition(double) |
Position on loss of signal (%) |
Pressure Control Valve
A pressure control valve (PCV) modulates opening to maintain pressure at setpoint.
Features
- Automatic pressure control
- Multiple control modes (downstream, upstream, differential)
- Proportional control action
- Min/max opening limits
Control Modes
| Mode | Description | Application |
|---|---|---|
| DOWNSTREAM | Control outlet pressure | Gas letdown stations |
| UPSTREAM | Control inlet pressure | Back-pressure control |
| DIFFERENTIAL | Control ΔP across valve | Flow control |
Java Example
import neqsim.process.equipment.valve.PressureControlValve;
import neqsim.process.equipment.valve.PressureControlValve.ControlMode;
// Create pressure control valve
PressureControlValve pcv = new PressureControlValve("PCV-101", hpGasStream);
pcv.setPressureSetpoint(25.0); // Control to 25 bara downstream
pcv.setControlMode(ControlMode.DOWNSTREAM);
pcv.setControllerGain(5.0); // Proportional gain
pcv.setCv(300.0);
pcv.run();
System.out.println("Valve opening: " + pcv.getPercentValveOpening() + "%");
System.out.println("Outlet pressure: " + pcv.getOutletStream().getPressure("bara") + " bara");
System.out.println("Control error: " + pcv.getControlError() + " bar");
Python Example
from neqsim import jneqsim
PressureControlValve = jneqsim.process.equipment.valve.PressureControlValve
# Create pressure control valve for gas letdown
pcv = PressureControlValve("PCV-101", hp_gas_stream)
pcv.setPressureSetpoint(25.0) # 25 bara target
pcv.setControllerGain(5.0)
pcv.setCv(300.0)
pcv.run()
print(f"Outlet pressure: {pcv.getOutletStream().getPressure('bara'):.1f} bara")
Key Methods
| Method | Description |
|---|---|
setPressureSetpoint(double) |
Set target pressure (bara) |
setControlMode(ControlMode) |
DOWNSTREAM, UPSTREAM, DIFFERENTIAL |
setControllerGain(double) |
Proportional gain (1-10 typical) |
getProcessVariable() |
Get measured pressure |
getControlError() |
Get setpoint - PV |
setAutoMode(boolean) |
Enable/disable automatic control |
ESD Valve
An ESD valve (Emergency Shutdown Valve / Isolation Valve XV) is a fail-closed valve for emergency isolation.
Features
- Fail-safe design: fails to closed position
- Energize-to-open operation
- Configurable stroke time (closure time)
- Partial stroke testing capability
- SIL rating support
- Status feedback for monitoring
Design Philosophy
| State | Description |
|---|---|
| Energized | Valve is open (normal operation) |
| De-energized | Valve closes (emergency or loss of power) |
Java Example
import neqsim.process.equipment.valve.ESDValve;
import java.util.UUID;
// Create ESD inlet valve (normally open)
ESDValve esdValve = new ESDValve("ESD-XV-101", feedStream);
esdValve.setStrokeTime(10.0); // 10 seconds to close
esdValve.setCv(500.0); // Large Cv for minimal ΔP when open
// Normal operation - valve open
esdValve.energize();
esdValve.run();
System.out.println("Normal: Valve " + (esdValve.isEnergized() ? "OPEN" : "CLOSED"));
// Emergency shutdown
esdValve.deEnergize(); // Triggers closure
// Dynamic simulation of closure
double dt = 0.5; // 0.5 second time steps
for (double t = 0; t <= 12.0; t += dt) {
esdValve.runTransient(dt, UUID.randomUUID());
System.out.printf("t=%.1f s: Opening = %.1f%%%n",
t, esdValve.getPercentValveOpening());
}
Integration with ESD Controller
// ESD controller monitors process conditions
if (pressure > highPressureSetpoint || fireDetected || manualESDActivated) {
esdValve.deEnergize(); // Initiate emergency closure
}
Python Example
from neqsim import jneqsim
import uuid
ESDValve = jneqsim.process.equipment.valve.ESDValve
# Create ESD valve
esd_valve = ESDValve("ESD-XV-101", feed_stream)
esd_valve.setStrokeTime(10.0) # 10 seconds closure
esd_valve.setCv(500.0)
# Normal operation
esd_valve.energize()
esd_valve.run()
# Emergency shutdown
esd_valve.deEnergize()
# Simulate closure
dt = 0.5
for i in range(25):
esd_valve.runTransient(dt, uuid.uuid4())
print(f"Opening: {esd_valve.getPercentValveOpening():.1f}%")
Key Methods
| Method | Description |
|---|---|
energize() |
Power actuator - allows valve to open |
deEnergize() |
Remove power - initiates closure |
isEnergized() |
Check energization state |
setStrokeTime(double) |
Set closure time (seconds) |
getStrokeTime() |
Get closure time |
setFailSafePosition(double) |
Position on de-energize (0=closed) |
startPartialStrokeTest() |
Initiate PST |
hasTripCompleted() |
Check if closure is complete |
PSD Valve
A PSD valve (Process Shutdown Valve) automatically closes on high-high (HIHI) pressure alarm.
Features
- Links to pressure transmitter
- Automatic closure on HIHI alarm
- Fast closure time (default 2 seconds)
- Manual reset required after trip
- Trip state tracking
Java Example
import neqsim.process.equipment.valve.PSDValve;
import neqsim.process.measurementdevice.PressureTransmitter;
import neqsim.process.alarm.AlarmConfig;
// Create pressure transmitter with alarm configuration
PressureTransmitter PT = new PressureTransmitter("PT-101", separatorInlet);
PT.setAlarmConfig(AlarmConfig.builder()
.highHighLimit(55.0)
.deadband(1.0)
.delay(0.5)
.unit("bara")
.build());
// Create PSD valve linked to transmitter
PSDValve psdValve = new PSDValve("PSD-101", feedStream);
psdValve.linkToPressureTransmitter(PT);
psdValve.setClosureTime(2.0); // 2 seconds fast closure
// In dynamic simulation loop
for (int i = 0; i < 100; i++) {
process.runTransient(0.1, UUID.randomUUID());
if (psdValve.hasTripped()) {
System.out.println("PSD valve tripped on HIHI alarm!");
break;
}
}
// Reset after alarm clears (operator action)
psdValve.reset();
Python Example
from neqsim import jneqsim
PSDValve = jneqsim.process.equipment.valve.PSDValve
# Create PSD valve
psd_valve = PSDValve("PSD-101", feed_stream)
psd_valve.linkToPressureTransmitter(pressure_transmitter)
psd_valve.setClosureTime(2.0) # Fast closure
# Check trip status
if psd_valve.hasTripped():
print("Valve tripped on HIHI!")
# After condition clears
psd_valve.reset()
Key Methods
| Method | Description |
|---|---|
linkToPressureTransmitter(MeasurementDeviceInterface) |
Connect to PT |
setClosureTime(double) |
Set closure time (seconds) |
hasTripped() |
Check if valve has tripped |
reset() |
Reset trip state (requires operator action) |
setTripEnabled(boolean) |
Enable/disable automatic trip |
getPressureTransmitter() |
Get linked transmitter |
Dynamic Simulation
ThrottlingValve, ControlValve, LevelControlValve, PressureControlValve, ESDValve, and BlowdownValve have qualified transient paths. Other subclasses must be audited individually; inheriting from a qualified valve does not by itself establish complete dynamic or transaction coverage.
Valve Travel Dynamics
// Configure valve travel times
valve.setOpeningTravelTime(5.0); // 5 seconds to fully open
valve.setClosingTravelTime(3.0); // 3 seconds to fully close
// Simulate opening
valve.setTargetPercentValveOpening(100.0); // Command full open
for (double t = 0; t <= 6.0; t += 0.1) {
valve.runTransient(0.1, UUID.randomUUID());
System.out.printf("t=%.1f: Actual opening = %.1f%%%n",
t, valve.getPercentValveOpening());
}
Transactional actuator steps
ThrottlingValve, the field-free ControlValve specialization, LevelControlValve,
PressureControlValve, ESDValve, and BlowdownValve participate in ProcessSystem transient
step transactions. Their snapshots retain
the actual and requested opening, travel model, deadband, stiction and hysteresis memory, flow and
thermodynamic cache, outlet-stream state, physical-step identifier, embedded LCV/PCV setpoint,
measurement, mode, gain, error and scan identity, and the ESD/blowdown state machine. Attached base
PID controllers remain separate transaction participants; the process
transaction validates and restores both objects without replacing either one.
Rollback also restores the active sizing method’s choked-flow switch and $x_T$ factor in place.
Keep the mechanical design, sizing method, and other sizing configuration fixed during a trial.
Every attached controller must be independently enumerated; a duplicate controller tag that hides
an attached controller blocks transaction coverage. Subclasses of ESDValve and BlowdownValve
must extend the snapshot and explicitly qualify their own state before participating.
Physical-step idempotency is explicit and default-off for legacy compatibility:
valve.setPhysicalStepIdempotencyEnabled(true);
When enabled, one non-null physical-step UUID advances actuator state at most once. Repeating a hydraulic calculation with the same UUID can update flow state but cannot apply travel, trip time, embedded control command, blowdown time, or trip time twice. Rejected full-step/two-half-step trials restore the control, actuator, and safety state before retry. When disabled, legacy loops that reuse one UUID across multiple physical timesteps continue to advance on every call.
For FIRST_ORDER_LAG, the implemented step is the exact constant-command response
The regression benchmark uses $x_0=20\%$, $u=80\%$, and $\tau=4\ \mathrm{s}$; one-second and 0.125-second steps give the same eight-second endpoint to $10^{-10}$ percentage points. Separate tests qualify asymmetric rate limits, deadband, breakaway stiction, reversal hysteresis, fail-close ESD travel, commanded blowdown opening, rollback/replay, and controller-chain coverage.
Other ThrottlingValve subclasses currently fail the transaction coverage audit until they extend
the snapshot for their own mutable state. This explicitly includes HIPPSValve and PSDValve;
their legacy non-transactional execution remains available. Transaction coverage establishes deterministic modeled response only. It does not
establish valve sizing, actuator vendor qualification, SIL, voting, independence, proof-test
interval, or suitability for a project safety function.
Embedded LCV/PCV scan contract and limits
For a dynamic LCV scan, the caller first publishes the measured level with
setMeasuredLevel(). The valve then computes the incremental command, applies actuator travel and
nonlinearities, and solves the pressure-flow relation. A direct-acting discharge LCV uses
so a measured level above setpoint opens the valve. The valve does not discover a separator or level transmitter implicitly; the tagged study model must wire and schedule that measurement.
A dynamic PCV samples the inlet/outlet pressure state from the preceding process scan, computes its
command, and then runs the actuator and hydraulics once. This is an explicit one-scan measurement
delay. Downstream mode opens for pressure below setpoint; upstream and differential modes close for
pressure below setpoint. When outlet pressure is imposed with setOutletPressure(), it is an
algebraic boundary: changing opening changes flow but cannot make the imposed pressure respond. A
closed pressure-control study therefore needs a qualified pressure inventory downstream or
upstream. An attached external controller has final authority in the base actuator scan; do not
combine it with the embedded automatic command unless that ownership is intentional.
The regression contract checks documented command direction against actual valve flow, exact first-order actuator response, one control update per UUID, mass closure, in-place rollback/replay, complete transaction coverage, and Java restart equivalence. These tests qualify modeled response; they do not supply transmitter filtering/delay, fail-action actuation, controller tuning, vendor rangeability, or project safety-credit evidence.
Level Control Dynamic Response
// Simulate level disturbance
double level = 50.0;
double dt = 1.0;
for (int i = 0; i < 100; i++) {
// Disturbance at t=20s
if (i == 20) level = 70.0;
lcv.setMeasuredLevel(level);
lcv.runTransient(dt, UUID.randomUUID());
// Level responds to valve opening
double flowOut = lcv.getOutletStream().getFlowRate("kg/hr");
level = level - (flowOut - inflow) * dt / vesselVolume;
System.out.printf("t=%d: Level=%.1f%%, Opening=%.1f%%%n",
i, level, lcv.getPercentValveOpening());
}
API Reference
Common Base Methods (from ThrottlingValve)
| Method | Description |
|---|---|
setCv(double, String) |
Set flow coefficient (“US” or “SI”) |
getCv(String) |
Get flow coefficient |
setOutletPressure(double, String) |
Set outlet pressure |
setPercentValveOpening(double) |
Set valve position (0-100%) |
getPercentValveOpening() |
Get commanded position |
run() |
Execute steady-state calculation |
runTransient(double dt, UUID id) |
Execute dynamic step |
Valve Sizing
// Size valve for service
valve.setCv(calculateRequiredCv(flow, dP, fluid));
valve.setValveCharacteristic("equal_percentage");
// Check valve selection
double maxCv = valve.getCv("US");
double actualCv = valve.getActualCv(); // At current opening
double rangeability = maxCv / actualCv;
Related Documentation
- Valve Equipment - Throttling valve and safety valve documentation
- HIPPS Implementation - High Integrity Pressure Protection
- Dynamic Simulation - Transient simulation guide
- Process Controllers - PID controller documentation