UniSim Design to NeqSim Conversion Guide
This guide covers the complete workflow for converting process simulation models between Honeywell UniSim Design (or Aspen HYSYS) and NeqSim. It includes:
- Reading
.uscfiles and extracting process data via Windows COM automation - Transferring UniSim fluid packages as Eclipse E300 full-fluid files
- Converting UniSim models to NeqSim
ProcessSystemsimulations - Multiple output formats: JSON, Python scripts, Jupyter notebooks, EOT simulators
- Exporting NeqSim models back to UniSim
.uscfiles - Verifying converted models by comparing stream properties
- Troubleshooting common conversion issues
Prerequisites
| Requirement | Details |
|---|---|
| Operating System | Windows (COM automation requires Windows) |
| UniSim Design | R460+ installed and licensed (R510+ recommended) |
| Python | 3.8+ with pywin32 (pip install pywin32) |
| NeqSim | pip install neqsim (or local dev build) |
Install the required packages:
pip install pywin32 neqsim
For local development with the NeqSim repository:
# From the neqsim repo root
pip install -e devtools/
Architecture Overview
The conversion system consists of three main classes in devtools/unisim_reader.py and one class in devtools/unisim_writer.py:
| Class | Module | Purpose |
|---|---|---|
UniSimReader |
unisim_reader.py |
Opens .usc files via COM, extracts all process data |
UniSimToNeqSim |
unisim_reader.py |
Converts extracted model to NeqSim JSON, Python, or notebook |
UniSimComparator |
unisim_reader.py |
Compares UniSim vs NeqSim results for verification |
UniSimWriter |
unisim_writer.py |
Creates UniSim .usc files from NeqSim JSON exports |
Data Flow
UniSim .usc file
│
▼ (COM automation)
UniSimReader ──────► UniSimModel (Python dataclasses)
│
▼
UniSimToNeqSim
┌───────┼───────────────┐
▼ ▼ ▼
to_json() to_python() to_notebook()
│ │ │
▼ ▼ ▼
NeqSim JSON Python script Jupyter notebook
│
▼
ProcessSystem.fromJsonAndRun()
│
▼
Running NeqSim simulation
│
▼ (reverse direction)
ProcessSystem.toJson()
│
▼
UniSimWriter ──────► New .usc file
Part 1: UniSim to NeqSim (Reading .usc Files)
Quick Start
from devtools.unisim_reader import UniSimReader, UniSimToNeqSim
# Step 1: Read the UniSim file
with UniSimReader(visible=False) as reader:
model = reader.read(r"C:\path\to\model.usc")
# Step 2: Inspect what was extracted
print(model.summary())
# Step 3: Convert and run in NeqSim
converter = UniSimToNeqSim(model)
process = converter.build_and_run()
Step-by-Step Walkthrough
1. Reading the UniSim File
The UniSimReader opens UniSim Design via COM automation, pauses the solver, and extracts all process data:
from devtools.unisim_reader import UniSimReader
# Create reader (visible=True shows the UniSim GUI for debugging)
reader = UniSimReader(visible=False)
# Read a single file
model = reader.read(r"C:\Models\GasPlant.usc")
# Or read multiple files efficiently (one UniSim session)
models = reader.read_multiple([
r"C:\Models\GasPlant.usc",
r"C:\Models\OilProcess.usc",
])
# Always close when done (or use context manager)
reader.close()
Extracted data includes:
- Fluid packages: EOS type, component list, property package name, and E300 export paths
- Material streams: Temperature, pressure, flow rate, composition, density, molecular weight, vapour fraction, enthalpy
- Energy streams: Heat flow
- Unit operations: Type, feed/product connections, type-specific properties (efficiency, outlet pressure, duty, etc.)
- Sub-flowsheets: Recursively extracted with full connectivity
2. Inspecting the Extracted Model
# Human-readable summary
print(model.summary())
Example output:
UniSim Model: GasPlant.usc
Fluid Packages: 1
'Basis-1': Peng-Robinson (7 components)
Main Flowsheet: 'Main'
Streams: 13
Operations: 11
Sub-Flowsheets: 2
'Compression': 4 ops, 5 streams
'Dehydration': 3 ops, 4 streams
Operation types:
compressor: 3
coolerop: 2
sep3op: 2
valveop: 2
mixerop: 1
heatexop: 1
Access individual elements:
# All operations (including sub-flowsheets)
for op in model.all_operations():
print(f"{op.name}: {op.type_name} | feeds={op.feeds} | products={op.products}")
# All streams
for s in model.all_streams():
print(f"{s.name}: T={s.temperature_C}°C, P={s.pressure_bara} bara, "
f"flow={s.mass_flow_kgh} kg/h")
# Fluid package details
fp = model.fluid_packages[0]
print(f"EOS: {fp.property_package}")
print(f"Components: {fp.component_names}")
# Stream composition
for s in model.flowsheet.material_streams:
if s.composition:
print(f"\n{s.name}:")
for comp, frac in s.composition.items():
print(f" {comp}: {frac:.4f}")
3. Full-Fluid Transfer with E300
For serious UniSim-to-NeqSim verification, use the E300 full-fluid route. The
reader exports one E300 file per UniSim fluid package by default and the
generated build route loads the fluid with EclipseFluidReadWrite.read(...)
before calling ProcessSystem.fromJsonAndRun(json, fluid). This preserves
critical properties, molecular weights, acentric factors, binary interaction
coefficients, volume shifts, parachors, and pseudo-component properties that
component-name mapping alone cannot reproduce.
Important checks after E300 export:
| Check | Expected Result |
|---|---|
| E300 files written | One file per extracted UniSim fluid package |
| Generated JSON/Python | Contains the expected e300FilePath for the process fluid or area |
| Build route | Uses EclipseFluidReadWrite.read(...), not a component-name fallback fluid |
| Methane sanity check | Critical temperature about 190.7 K and critical pressure about 46.4 bara |
| Water sanity check | Critical temperature about 647.3 K and critical pressure about 221 bara |
| Missing acentric factors | Filled from package vectors or Edmister fallback when Tc, Pc, and boiling point exist |
E300 fluid parity is necessary but not sufficient for full model parity. Large UniSim models can still require reconciliation of virtual streams, spreadsheets, balance blocks, template operations, sub-flowsheet interface streams, compressor curves, and control logic before numerical stream matching is accepted.
3.1 Operation Handler Registry
The converter does not create one NeqSim class for every UniSim operation name.
Instead, devtools/unisim_reader.py uses a typed UniSimOperationHandler
registry. Each UniSim TypeName has:
| Field | Meaning |
|---|---|
neqsim_type |
Target NeqSim equipment type or converter pseudo-type |
strategy |
native, adapter, reference, control, column_internal, or skip |
stream_role |
material, reference, or none for topology reconstruction |
note |
Rationale included in generated JSON mapping summaries |
Generated JSON includes _unisim_operation_mapping, which lists each UniSim
operation type present in the imported case, the selected NeqSim type, strategy,
stream role, count, and note. This is the audit trail for why an operation was
mapped to native NeqSim physics, an adapter, a reference object, or comments.
4. Converting to NeqSim
The UniSimToNeqSim converter offers multiple output formats:
Option A: JSON Builder Format (for ProcessSystem.fromJsonAndRun)
import json
from devtools.unisim_reader import UniSimToNeqSim
converter = UniSimToNeqSim(model)
neqsim_json = converter.to_json()
# Save for inspection
with open("process.json", "w") as f:
json.dump(neqsim_json, f, indent=2)
# Check for warnings
for w in converter.warnings:
print(f"WARNING: {w}")
# Build and run directly
from neqsim import jneqsim
ProcessSystem = jneqsim.process.processmodel.ProcessSystem
result = ProcessSystem.fromJsonAndRun(json.dumps(neqsim_json))
if not result.isError():
process = result.getProcessSystem()
print(f"Units built: {process.size()}")
Option B: Standalone Python Script
Generates a complete, runnable Python file with explicit jneqsim API calls:
converter = UniSimToNeqSim(model)
python_code = converter.to_python(include_subflowsheets=True)
# Save to file
with open("gas_plant_process.py", "w") as f:
f.write(python_code)
print(f"Generated {len(python_code.splitlines())} lines of Python")
The generated script includes:
- All
jneqsimimports - Fluid/EOS definition with mapped composition and mixing rule
- Feed streams with temperature, pressure, and flow rate from UniSim
- All equipment in topological order (upstream before downstream)
- Equipment properties (efficiency, outlet pressure, etc.)
- Stream wiring through outlet stream references
- Auto-generated recycle blocks for forward-referenced streams
process.run()call
Option C: Jupyter Notebook
Interactive notebook with markdown explanations between code cells:
converter = UniSimToNeqSim(model)
converter.save_notebook("gas_plant.ipynb")
The notebook contains:
- Title and overview table (components, operations, EOS)
- Setup cell with imports
- Fluid creation with composition table
- Feed stream creation with properties table
- One markdown + code cell per equipment unit
- Process run cell
- Results summary cell
- Conversion warnings cell
Option D: EOT / ProcessPilot Simulator
For reinforcement learning and optimization frameworks:
converter = UniSimToNeqSim(model)
converter.save_eot_simulator("my_simulator.py", class_name="GasPlantSimulator")
# Also generate a demo notebook for the EOT simulator
nb = converter.to_eot_notebook(class_name="GasPlantSimulator")
with open("eot_demo.ipynb", "w") as f:
json.dump(nb, f, indent=1)
5. Command-Line Interface
# Print model summary
python devtools/unisim_reader.py C:\Models\file.usc --summary
# Output NeqSim JSON
python devtools/unisim_reader.py C:\Models\file.usc --json
# Generate Python script
python devtools/unisim_reader.py C:\Models\file.usc --python process.py
# Generate Jupyter notebook
python devtools/unisim_reader.py C:\Models\file.usc --notebook process.ipynb
# Generate EOT simulator + demo notebook
python devtools/unisim_reader.py C:\Models\file.usc --eot sim.py --eot-notebook demo.ipynb
# Fast extraction (topology only, no stream properties)
python devtools/unisim_reader.py C:\Models\file.usc --no-streams --summary
# Show UniSim GUI during extraction (debugging)
python devtools/unisim_reader.py C:\Models\file.usc --visible --summary
# Combined: multiple outputs in one command
python devtools/unisim_reader.py C:\Models\file.usc --python p.py --notebook n.ipynb --eot s.py
Part 2: NeqSim to UniSim (Writing .usc Files)
The UniSimWriter in devtools/unisim_writer.py creates UniSim Design simulations from NeqSim JSON exports.
Quick Start
from devtools.unisim_writer import UniSimWriter
# From a NeqSim JSON string (e.g., ProcessSystem.toJson())
writer = UniSimWriter(visible=True)
writer.build_from_json(neqsim_json_str, save_path="output.usc")
writer.close()
From a Running NeqSim ProcessSystem
from neqsim import jneqsim
# ... build and run your NeqSim process ...
ProcessSystem = jneqsim.process.processmodel.ProcessSystem
# process = ProcessSystem()
# ... add equipment ...
# process.run()
# Export to JSON
json_str = str(process.toJson())
# Create UniSim file
from devtools.unisim_writer import UniSimWriter
writer = UniSimWriter(visible=True)
writer.build_from_json(json_str, save_path="my_process.usc")
writer.close()
From a Multi-Area ProcessModel
from neqsim import jneqsim
# Multi-area process
ProcessModel = jneqsim.process.processmodel.ProcessModel
# plant = ProcessModel("Platform")
# plant.add("Separation", sep_process)
# plant.add("Compression", comp_process)
# plant.run()
json_str = str(plant.toJson())
writer = UniSimWriter(visible=True)
writer.build_from_json(json_str, save_path="platform.usc")
writer.close()
Using a Template File
For best results, open an existing licensed-saved .usc file as a template:
writer = UniSimWriter(visible=True, template_path=r"C:\Templates\blank.usc")
writer.build_from_json(neqsim_json_str, save_path="output.usc")
writer.close()
Reverse Mapping Tables
The writer uses reverse mappings to translate NeqSim names back to UniSim:
Component names (NeqSim to UniSim):
| NeqSim | UniSim |
|---|---|
nitrogen |
Nitrogen |
CO2 |
CO2 |
methane |
Methane |
ethane |
Ethane |
propane |
Propane |
i-butane |
i-Butane |
n-butane |
n-Butane |
water |
H2O |
MEG |
EGlycol |
TEG |
TEGlycol |
hydrogen |
Hydrogen |
H2S |
H2S |
EOS mapping (NeqSim to UniSim):
| NeqSim Model | UniSim Property Package |
|---|---|
SRK |
SRK |
PR |
Peng-Robinson |
CPA |
CPA |
GERG2008 |
GERG 2008 |
Equipment mapping (NeqSim to UniSim):
| NeqSim Type | UniSim TypeName |
|---|---|
ThrottlingValve |
valveop |
Separator |
flashtank |
ThreePhaseSeparator |
sep3op |
Mixer |
mixerop |
Splitter |
teeop |
Compressor |
compressor |
Cooler |
coolerop |
Heater |
heaterop |
Pump |
pumpop |
Expander |
expandop |
HeatExchanger |
heatexop |
Recycle |
recycle |
AdiabaticPipe |
pipeseg |
Mapping Reference
Component Name Mapping (UniSim to NeqSim)
The reader automatically maps UniSim component names to NeqSim database names:
| UniSim Name | NeqSim Name | Notes |
|---|---|---|
Nitrogen / N2 |
nitrogen |
|
CO2 / CarbonDioxide |
CO2 |
|
Methane / C1 |
methane |
|
Ethane / C2 |
ethane |
|
Propane / C3 |
propane |
|
i-Butane / iC4 |
i-butane |
|
n-Butane / nC4 |
n-butane |
|
i-Pentane / iC5 |
i-pentane |
|
n-Pentane / nC5 |
n-pentane |
|
n-Hexane / nC6 |
n-hexane |
|
n-Heptane / nC7 |
n-heptane |
|
n-Octane / nC8 |
n-octane |
|
n-Nonane / nC9 |
n-nonane |
|
n-Decane / nC10 |
nC10 |
|
nC11 - nC20 |
nC11 - nC20 |
Direct mapping |
H2O / Water |
water |
|
EGlycol |
MEG |
Mono-ethylene glycol |
TEGlycol |
TEG |
Triethylene glycol |
DEGlycol |
DEG |
Diethylene glycol |
MeOH / Methanol |
methanol |
|
Hydrogen / H2 |
hydrogen |
|
H2S |
H2S |
|
Oxygen / O2 |
oxygen |
|
Argon / Ar |
argon |
|
Helium / He |
helium |
|
Benzene |
benzene |
|
Toluene |
toluene |
|
CO / CarbonMonoxide |
CO |
|
NH3 / Ammonia |
ammonia |
|
Ethylene / Ethene |
ethylene |
|
Propylene / Propene |
propene |
|
DEAmine |
DEA |
|
MEAmine |
MEA |
|
MDEAmine |
MDEA |
|
12C3Oxide |
Not mapped | Propylene oxide not in NeqSim |
Hypothetical components (names ending with *, e.g., C7 GRAND*) are not mapped and require manual C7+ characterization in NeqSim.
Property Package / EOS Mapping (UniSim to NeqSim)
| UniSim Property Package | NeqSim EOS | Mixing Rule | Notes |
|---|---|---|---|
Peng-Robinson |
PR |
classic |
Most common for oil and gas |
SRK / Soave-Redlich-Kwong |
SRK |
classic |
|
CPA / CPA-SRK |
CPA |
10 |
Polar systems (water, glycols) |
Glycol Package |
CPA |
10 |
MEG/TEG systems |
GERG 2008 |
GERG2008 |
(built-in) | Natural gas metering |
Sour PR / Sour SRK |
PR / SRK |
classic |
H2S/CO2 systems |
ASME Steam |
SRK |
classic |
Fallback — water only |
MBWR |
SRK |
classic |
Fallback — no LKP in NeqSim |
NRTL / UNIQUAC / Wilson |
SRK |
classic |
Fallback — activity models |
DBR Amine Package |
SRK |
classic |
Fallback |
OLI |
SRK |
classic |
Fallback — electrolyte |
A warning is logged when a fallback mapping is used.
Operation Type Mapping (UniSim to NeqSim)
Core Process Equipment
| UniSim TypeName | NeqSim Type | Description |
|---|---|---|
valveop |
ThrottlingValve |
Pressure letdown valve |
sep3op |
ThreePhaseSeparator |
Three-phase separator |
flashtank |
Separator |
Two-phase flash drum |
mixerop |
Mixer |
Stream mixer |
teeop |
Splitter |
Stream splitter/tee |
compressor |
Compressor |
Gas compressor |
coolerop |
Cooler |
Cooler |
heaterop |
Heater |
Heater |
pumpop |
Pump |
Liquid pump |
expandop |
Expander |
Turboexpander |
heatexop |
HeatExchanger |
Shell-and-tube / plate HX |
pipeseg |
AdiabaticPipe |
Pipe segment |
recycle |
Recycle |
Recycle convergence block |
adjust |
Adjuster |
Process variable adjuster |
saturateop |
StreamSaturatorUtil |
Stream saturator |
Columns and Absorbers
| UniSim TypeName | NeqSim Type | Description |
|---|---|---|
fractop / distillation / columnop |
DistillationColumn |
Distillation column |
reboiledabsorber |
DistillationColumn |
Reboiled absorber |
absorberop / absorber |
Absorber or ComponentSplitter |
See glycol contactor rule below |
Glycol/TEG contactor rule: When an absorber has a name containing “glyc”, “teg”, or “dehydrat” (case-insensitive), the converter produces a ComponentSplitter instead of a DistillationColumn. This models water removal using split factors: [1.0, 1.0, ..., 0.0] where water (last component) is fully removed.
Reactors
| UniSim TypeName | NeqSim Type |
|---|---|
reactorop / gibbsreactorop / eqreactorop |
GibbsReactor |
convreactorop / conversionreactorop |
GibbsReactor |
pfreactorop / kineticreactorop |
PlugFlowReactor |
cstrop |
StirredTankReactor |
Skipped Operations
The handler registry separates reference/control/internal operations from material topology. These operations are recognized but do not become standalone physical equipment:
| UniSim TypeName | Reason |
|---|---|
spreadsheetop |
SpreadsheetBlock reference object; formulas need import/export cell extraction |
pidfbcontrolop |
Control logic, produces controller metadata or TODO comment |
surgecontroller |
Surge control, no standalone NeqSim equivalent |
partialcondenser / totalcondenser / traysection / bpreboiler |
Column internals (part of DistillationColumn) |
logicalop / selectop |
Logic operations |
The following stream-carrying UniSim placeholders are not skipped; they preserve topology through adapters:
| UniSim TypeName | NeqSim Type | Purpose |
|---|---|---|
balanceop |
UnisimCalculator |
Balance/topology pass-through with source-operation metadata |
virtualstreamop |
UnisimCalculator |
Virtual stream pass-through with an outlet stream for downstream wiring |
templateop |
SubFlowsheet / UnisimCalculator |
Process sub-flowsheet or placeholder interface; JSON factory aliases placeholder builds to UnisimCalculator |
When modifying topology reconstruction, use
UniSimReader.is_material_stream_operation(type_name) rather than adding local
non-stream lists. Unknown operation types are treated as material operations so
stream-carrying unsupported blocks remain visible as warnings.
Topology Reconstruction
The converter automatically reconstructs the process topology from UniSim’s stream-based connectivity:
How It Works
- Identify external feeds: Streams not produced by any operation become feed
Streamobjects - Build producer map: Maps each stream name to (operation, port)
- Topological sort: Kahn’s algorithm orders operations so upstream equipment is defined before downstream consumers
- Handle recycle loops: Forward reference placeholders break dependency cycles
Stream Wiring (Dot-Notation)
The converter uses dot-notation to reference equipment outlet streams:
| Producer Type | Stream | NeqSim Reference | API Call |
|---|---|---|---|
| Separator (gas) | 1st product | "Sep.gasOut" |
sep.getGasOutStream() |
| Separator (liquid) | 2nd product | "Sep.liquidOut" |
sep.getLiquidOutStream() |
| 3-Phase Sep (gas) | 1st product | "Sep.gasOut" |
sep.getGasOutStream() |
| 3-Phase Sep (oil) | 2nd product | "Sep.oilOut" |
sep.getOilOutStream() |
| 3-Phase Sep (water) | 3rd product | "Sep.waterOut" |
sep.getWaterOutStream() |
| Compressor | output | "Comp.outlet" |
comp.getOutletStream() |
| Cooler/Heater | output | "Cooler.outlet" |
cooler.getOutletStream() |
| Valve | output | "Valve.outlet" |
valve.getOutletStream() |
| Mixer | output | "Mixer.outlet" |
mixer.getOutletStream() |
| Splitter | nth output | "Split.split0" |
split.getSplitStream(int(0)) |
| HeatExchanger | shell out | "HX.hx0" |
hx.getOutStream(int(0)) |
| HeatExchanger | tube out | "HX.hx1" |
hx.getOutStream(int(1)) |
Forward Reference Handling (Recycle Loops)
When the topological sort detects cycles, the converter creates forward reference placeholders — temporary Stream objects that stand in for not-yet-created equipment outlets:
- Cycle detection: Back-edge producers become forward references
- Placeholder creation:
_fwd_XXXstreams are created with T, P, flow from UniSim data - Port-specific placeholders: Multi-outlet equipment (separators) gets per-port placeholders (e.g.,
_fwd_V100_gasOut,_fwd_V100_liquidOut) - Auto-recycle wiring: After the actual equipment is created,
Recycleobjects wire each real outlet back to its placeholder
Why port-specific placeholders matter: Without them, a valve downstream of a separator’s liquid outlet would incorrectly receive the combined feed placeholder, causing 500%+ flow deviations.
Example generated code for a recycle loop:
# Forward reference placeholder for separator V-100
_fwd_V_100_gasOut = Stream("V-100_gasOut_fwdref", fluid.clone())
_fwd_V_100_gasOut.setTemperature(15.0, "C")
_fwd_V_100_gasOut.setPressure(84.0, "bara")
_fwd_V_100_gasOut.setFlowRate(45000.0, "kg/hr")
process.add(_fwd_V_100_gasOut)
# ... downstream equipment uses _fwd_V_100_gasOut ...
# Actual separator (created later in topological order)
V_100 = Separator("V-100", cooled_feed)
process.add(V_100)
# Auto-recycle: wire actual outlet back to placeholder
_rcy_V_100_gasOut = Recycle("V-100_gasOut_loop")
_rcy_V_100_gasOut.addStream(V_100.getGasOutStream())
_rcy_V_100_gasOut.setOutletStream(_fwd_V_100_gasOut)
process.add(_rcy_V_100_gasOut)
Handling Sub-Flowsheets
UniSim uses sub-flowsheets (template operations) for modular process sections. The converter supports two strategies:
| Model Complexity | Strategy | When to Use |
|---|---|---|
| Main + 1-2 small sub-flowsheets | Flatten into single ProcessSystem |
Simple models |
| Main + 3+ sub-flowsheets | Separate ProcessSystem per area in ProcessModel |
Platform/plant models |
| Sub-flowsheet has own fluid package | Must be separate ProcessSystem |
Different thermodynamic bases |
Flattened Approach (Default)
By default, to_python(include_subflowsheets=True) flattens all sub-flowsheet operations into the main process:
converter = UniSimToNeqSim(model)
code = converter.to_python(include_subflowsheets=True)
ProcessModel Approach (Large Models)
For complex platform models (e.g., Grane with 6 sub-flowsheets):
from neqsim import jneqsim
ProcessModel = jneqsim.process.processmodel.ProcessModel
# Build each area as a separate ProcessSystem
plant = ProcessModel("Grane")
plant.add("Main", main_process)
plant.add("Breidablikk", breidablikk_process)
plant.add("LP_Inlet", lp_process)
plant.add("HP_Inlet", hp_process)
plant.add("DPC_Unit", dpc_process)
plant.run()
When sub-flowsheets use different fluid packages, verify that each process area is assigned the intended E300 file. A model can build structurally while still using the wrong default fluid in one area, so report the fluid-package mapping explicitly in the conversion summary.
Verification
Always verify the converted model by comparing UniSim and NeqSim stream results. Keep the verification split into separate gates:
| Gate | Meaning |
|---|---|
| E300 exported | UniSim fluid packages were extracted and written as E300 files |
| E300 loaded | The NeqSim build route loaded those files with EclipseFluidReadWrite.read(...) |
| Structural build | NeqSim units were created and wired, possibly with warnings |
| Numerical stream verification | Stream T/P/flow/property deviations are within acceptance limits |
Do not mark a conversion as verified only because the E300 files loaded or the process built. Those are prerequisites for the final numerical comparison.
Using the Comparator
from devtools.unisim_reader import UniSimComparator
comparator = UniSimComparator(model, neqsim_process)
comparisons = comparator.compare_streams()
comparator.print_report(comparisons)
Using Comparison Points
converter = UniSimToNeqSim(model)
comparison_points = converter.get_comparison_points()
for pt in comparison_points:
print(f"{pt['stream']}: T={pt['temperature_C']:.1f}°C, "
f"P={pt['pressure_bara']:.1f} bara")
Expected Deviations
| Property | Typical | Acceptable | Notes |
|---|---|---|---|
| Temperature | less than 1°C | less than 3°C | Flash calculation differences |
| Pressure | 0% | 0% | Should match exactly (input) |
| Mass flow | less than 0.1% | less than 1% | Mass balance differences |
| Density | less than 2% | less than 5% | EOS differences (PR vs SRK) |
| Vapour fraction | less than 0.02 | less than 0.05 | Phase split sensitivity |
| Compressor power | less than 5% | less than 10% | Efficiency model differences |
| Heat duty | less than 5% | less than 10% | Enthalpy model differences |
Factors Causing Deviations
- EOS alpha functions: UniSim PR-LK uses different alpha functions than NeqSim PR
- Binary interaction parameters: UniSim may have tuned BIPs that are not extracted
- Hypothetical components: Pseudo-component property estimation differs between tools
- Mixing rules: UniSim may use advanced mixing rules not available in NeqSim
- Transport properties: Different correlations for viscosity and thermal conductivity
- HeatExchanger pressure drops: NeqSim HeatExchanger does not model pressure drops; UniSim typically includes 0.5-1.0 bar per side
- HeatExchanger UA tuning: The
setUAvalue()parameter must be tuned case-by-case to match UniSim’s heat duty
UniSim COM Object Model Reference
For advanced users or debugging, here is the UniSim COM hierarchy:
Application
SimulationCases
Case
Solver (CanSolve, Converge)
BasisManager
FluidPackages[]
name, PropertyPackageName
Components[]
name
Flowsheet (main)
MaterialStreams[]
name
Temperature.GetValue("C")
Pressure.GetValue("bar")
MassFlow.GetValue("kg/h")
MolarFlow.GetValue("kgmole/h")
ComponentMolarFraction.GetValues()
EnergyStreams[]
name
HeatFlow.GetValue("kW")
Operations[]
name, TypeName
(connectivity varies by type — see below)
Flowsheets[] (sub-flowsheets, recursive)
COM Connectivity Patterns by Operation Type
Different UniSim operation types expose different COM properties for feed/product streams:
| Operation Type | Feed Property | Product Property |
|---|---|---|
| compressor, coolerop, heaterop, valveop, pumpop, expandop, recycle | FeedStream |
ProductStream |
| mixerop | Feeds[] (array) |
Product (singular!) |
| teeop | FeedStream |
Products[] (array) |
| flashtank, sep3op | Feeds[] (array) |
VapourProduct, LiquidProduct, WaterProduct |
| heatexop | ShellSideFeed/TubeSideFeed or Feeds[] |
ShellSideProduct/TubeSideProduct or Products[] |
Warning: Using op.Products on a mixer throws AttributeError. Use op.Product (singular) for mixers and op.VapourProduct/op.LiquidProduct for separators.
Key COM Patterns
import win32com.client
import time
# Start UniSim
app = win32com.client.dynamic.Dispatch('UnisimDesign.Application')
app.Visible = True
# Open case and pause solver
case = app.SimulationCases.Open(r'C:\path\to\file.usc')
time.sleep(3)
solver = case.Solver
solver.CanSolve = False
# Read stream data
fs = case.Flowsheet
stream = fs.MaterialStreams.Item(0)
temp_C = stream.Temperature.GetValue('C')
pres_bar = stream.Pressure.GetValue('bar')
flow_kgh = stream.MassFlow.GetValue('kg/h')
comp_fracs = stream.ComponentMolarFraction.GetValues()
# Read operation data
op = fs.Operations.Item(0)
print(f"Type: {op.TypeName}, Name: {op.name}")
# Clean up
case.Close()
app.Quit()
Exploring an Unknown UniSim File
Use the diagnostic tool devtools/explore_unisim_com.py to dump the complete COM object model from any .usc file:
python devtools/explore_unisim_com.py C:\Models\unknown_model.usc
This prints all fluid packages, components, streams, operations, and their properties — useful for understanding a new model before conversion.
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
pywintypes.com_error |
UniSim not installed or wrong version | Verify UniSim installation, check COM ProgID |
| Empty stream values | Stream not solved in UniSim | Open in UniSim GUI, run solver first |
-32767 values |
UniSim empty marker | Already filtered by reader (val > -30000) |
| COM timeout | Large model loading | Increase time.sleep() after .Open() |
| Wrong component count | Multiple fluid packages | Check which fluid package the stream uses |
| Critical properties off by factors | UniSim COM returned unexpected units | Request critical temperature and boiling point in C, critical pressure in kPa, then convert explicitly |
| Missing acentric factor | comp.AcentricFactor absent on COM object |
Use property-package vectors or Edmister fallback from Tc, Pc, and normal boiling point |
| E300 build succeeds but stream errors remain large | Process logic/topology mismatch | Check _unisim_operation_mapping, then reconcile virtual stream adapters, spreadsheets, balance blocks, template operations, and sub-flowsheet interfaces |
| Missing operations | Sub-flowsheet not recursed | Use model.all_operations() |
| Composition doesn’t sum to 1.0 | Hypothetical components excluded | Re-normalize after filtering |
| Compressor outlet T too low | Efficiency defaulted to 100% | Reader defaults to 75% if COM returns None |
| Valve flow 500%+ deviation | Wrong forward reference placeholder | Ensure port-specific placeholders (fixed in current version) |
| Recycle not converging | Many forward references | Try multiple process.run() calls or tune placeholder values |
| Column diverges | C3/C4-rich feed at low pressure | Known NeqSim solver limitation; build column outside ProcessSystem |
| HX outlet T off by 1-2°C | UA mismatch or no pressure drop | Tune UA value; NeqSim HX has no pressure drop model |
AttributeError on COM property |
Wrong property for operation type | Check TypeName and use correct COM pattern |
| COM E_ACCESSDENIED | Stale type-library cache | Clear %LOCALAPPDATA%\Temp\gen_py folder |
Complete Example: Gas Processing Plant
This end-to-end example reads a UniSim gas plant model and creates a verified NeqSim simulation:
import json
from devtools.unisim_reader import UniSimReader, UniSimToNeqSim, UniSimComparator
# 1. Read the UniSim file
with UniSimReader(visible=False) as reader:
model = reader.read(r"C:\Models\GasPlant.usc")
print(model.summary())
# 2. Convert to NeqSim
converter = UniSimToNeqSim(model)
# Check warnings
for w in converter.warnings:
print(f" WARNING: {w}")
for a in converter.assumptions:
print(f" ASSUMPTION: {a}")
# 3. Generate a standalone Python script (for code review)
python_code = converter.to_python(include_subflowsheets=True)
with open("gas_plant.py", "w") as f:
f.write(python_code)
# 4. Generate a Jupyter notebook (for interactive exploration)
converter.save_notebook("gas_plant.ipynb")
# 5. Build and run the NeqSim model via JSON
neqsim_json = converter.to_json()
from neqsim import jneqsim
ProcessSystem = jneqsim.process.processmodel.ProcessSystem
result = ProcessSystem.fromJsonAndRun(json.dumps(neqsim_json))
if not result.isError():
process = result.getProcessSystem()
print(f"\nNeqSim model built: {process.size()} units")
# 6. Verify results
comparator = UniSimComparator(model, process)
comparisons = comparator.compare_streams()
comparator.print_report(comparisons)
Related Documentation
- Process Simulation Package — Overview of NeqSim process simulation
- ProcessSystem and Flowsheet Management — How ProcessSystem and ProcessModel work
- Jupyter Development Workflow — Using notebooks for NeqSim development
- UniSim Conversion Notebook — Interactive example notebook
File Reference
| File | Purpose |
|---|---|
devtools/unisim_reader.py |
Core module: UniSimReader, UniSimToNeqSim, UniSimComparator, and the UniSimOperationHandler registry |
devtools/unisim_writer.py |
Reverse direction: UniSimWriter — NeqSim JSON to .usc |
devtools/explore_unisim_com.py |
Diagnostic tool: dump COM object model from any .usc file |
devtools/test_unisim_outputs.py |
Pure-Python regression tests for output modes, E300 fluid export, operation handler strategy, and mapping summaries (no COM needed) |
examples/notebooks/unisim_to_neqsim_conversion.ipynb |
Example notebook with test cases |