@@ -580,19 +580,43 @@ A warning is logged when a fallback mapping is used.
580580
581581## 5. Workflow: From .usc File to Running NeqSim Model
582582
583+ ### Full Mode (Default — Recommended)
584+
585+ All four output methods (` to_json() ` , ` build_and_run() ` , ` to_python() ` ,
586+ ` to_notebook() ` ) default to ** ` full_mode=True ` ** . This means:
587+
588+ 1 . ** Sub-flowsheet auto-classification** : Sub-flowsheets are classified as
589+ either "process" (shares streams with the main flowsheet) or "utility"
590+ (isolated). Only process sub-flowsheets are included.
591+ 2 . ** ProcessModel architecture** : The main flowsheet and each process
592+ sub-flowsheet become separate ` ProcessSystem ` objects composed inside a
593+ ` ProcessModel ` (multi-area plant model).
594+ 3 . ** E300 fluid loading** : When the ` UniSimReader.read(export_e300=True) `
595+ option was used (default), the converter uses ` EclipseFluidReadWrite.read() `
596+ to load the fluid with exact Tc, Pc, ω, MW, and BIPs from UniSim.
597+ 4 . ** Recycle tolerance** : All auto-generated Recycle objects have
598+ ` setTolerance(1e6) ` to prevent convergence blocking during initial runs.
599+
600+ To disable full mode and get only the main flowsheet operations:
601+
602+ ``` python
603+ converter = UniSimToNeqSim(model)
604+ python_code = converter.to_python(full_mode = False )
605+ ```
606+
583607### Quick Usage (Python)
584608
585609``` python
586610from devtools.unisim_reader import UniSimReader, UniSimToNeqSim, UniSimComparator
587611
588- # Step 1: Read the UniSim file
612+ # Step 1: Read the UniSim file (export_e300=True is default)
589613with UniSimReader(visible = False ) as reader:
590614 model = reader.read(r " path\t o\f ile. usc" )
591615
592616# Step 2: Inspect what was extracted
593617print (model.summary())
594618
595- # Step 3: Convert to NeqSim JSON
619+ # Step 3: Convert to NeqSim JSON (full_mode=True by default)
596620converter = UniSimToNeqSim(model)
597621neqsim_json = converter.to_json()
598622
@@ -623,7 +647,7 @@ Instead of JSON, generate a standalone Python script with explicit `jneqsim` API
623647
624648``` python
625649converter = UniSimToNeqSim(model)
626- python_code = converter.to_python(include_subflowsheets = True )
650+ python_code = converter.to_python() # full_mode =True by default
627651
628652# Save to file
629653with open (" process.py" , " w" ) as f:
@@ -638,7 +662,7 @@ The generated script is a **complete, runnable Python file** that includes:
6386624 . All equipment in ** topological order** (upstream before downstream)
6396635 . Equipment properties set via ` jneqsim ` API calls (efficiency, outlet pressure, etc.)
6406646 . Stream wiring through outlet stream references (e.g., ` separator.getGasOutStream() ` )
641- 7 . Sub-flowsheet operations (if ` include_subflowsheets =True` )
665+ 7 . Sub-flowsheet operations (included by default in ` full_mode =True` )
6426668 . ` process.run() ` call at the end
643667
644668The generated code uses ** direct NeqSim Java API calls** — no JSON intermediate.
@@ -661,12 +685,12 @@ overview):
661685
662686``` python
663687converter = UniSimToNeqSim(model)
664- converter.save_notebook(" process.ipynb" )
688+ converter.save_notebook(" process.ipynb" ) # full_mode=True by default
665689```
666690
667691Or get the raw dict (nbformat v4):
668692``` python
669- nb_dict = converter.to_notebook(include_subflowsheets = True )
693+ nb_dict = converter.to_notebook() # full_mode =True by default
670694```
671695
672696The notebook contains:
@@ -976,42 +1000,54 @@ them — the separator will use NeqSim defaults (zero entrainment).
9761000UniSim uses sub-flowsheets (template operations) for modular process sections.
9771001In NeqSim, these map to either:
9781002
979- 1 . ** Separate ProcessSystem objects** composed in a ` ProcessModule `
1003+ 1 . ** Separate ProcessSystem objects** composed in a ` ProcessModel `
98010042 . ** Flattened into the main ProcessSystem** (simpler but may not handle inter-area recycles)
9811005
1006+ ### Auto-Classification (full_mode=True, Default)
1007+
1008+ When ` full_mode=True ` (the default), the converter automatically classifies
1009+ sub-flowsheets into ** process** (shares material streams with the main
1010+ flowsheet) and ** utility** (isolated, e.g., heating/cooling medium loops).
1011+ Only process sub-flowsheets are included in the generated code.
1012+
1013+ Classification is done by ` classify_subflowsheets() ` :
1014+
1015+ ``` python
1016+ classification = converter.classify_subflowsheets()
1017+ # Returns: {'TPL1': 'process', 'TPL3': 'utility', 'COL1': 'process', ...}
1018+ process_sfs = converter.get_process_subflowsheets()
1019+ # Returns: ['TPL1', 'TPL2', 'TPL5', 'TPL7', 'COL1']
1020+ ```
1021+
1022+ A sub-flowsheet is classified as ** process** if any of its operations produce
1023+ or consume a stream that also appears in the main flowsheet or another process
1024+ sub-flowsheet. Otherwise it is ** utility** (typically heating/cooling medium,
1025+ flare, utility water systems).
1026+
9821027### Architecture Decision
9831028
9841029| Model Complexity | Strategy |
9851030| -----------------| ----------|
9861031| Main + 1-2 small sub-flowsheets | Flatten into single ProcessSystem |
987- | Main + 3+ sub-flowsheets | ProcessModule with separate ProcessSystems |
1032+ | Main + 3+ sub-flowsheets | ProcessModel with separate ProcessSystems |
9881033| Sub-flowsheet has own fluid package | Must be separate ProcessSystem |
9891034
990- ### Example: Large Platform Model Structure
1035+ ### Sub-Flowsheet to ProcessModel Mapping
9911036
992- ```
993- Main Flowsheet (146 operations)
994- ├── Satellite (18 operations) — well stream preparation
995- ├── LP_Inlet (16 operations) — low pressure inlet
996- ├── HP_Inlet (6 operations) — high pressure inlet
997- ├── TPL1 (6 operations) — test separator
998- ├── DPC_UNIT (20 operations) — dew point control
999- └── HM (41 operations) — heating medium system
1000- ```
1037+ In ` full_mode=True ` , each process sub-flowsheet becomes its own
1038+ ` ProcessSystem ` , all composed inside a ` ProcessModel ` :
10011039
1002- This would become:
10031040``` python
10041041from neqsim import jneqsim
1005- ProcessModule = jneqsim.process.processmodel.ProcessModule
1006-
1007- module = ProcessModule(" Platform" )
1008- module.add(main_process) # Main separation & compression
1009- module.add(satellite_process) # Satellite wells
1010- module.add(lp_inlet_process) # LP inlet
1011- module.add(hp_inlet_process) # HP inlet
1012- module.add(dpc_process) # Dew point control
1013- # HM (heating medium) typically not modeled in NeqSim
1014- module.run()
1042+ ProcessModel = jneqsim.process.processmodel.ProcessModel
1043+
1044+ plant = ProcessModel(" Platform" )
1045+ plant.add(" Main" , main_process)
1046+ plant.add(" TPL1" , tpl1_process)
1047+ plant.add(" TPL2" , tpl2_process)
1048+ plant.add(" COL1" , col1_process)
1049+ # Utility sub-flowsheets (TPL3, TPL4, TPL6) are excluded
1050+ plant.run()
10151051```
10161052
10171053---
@@ -1090,6 +1126,24 @@ python devtools/unisim_reader.py path/to/file.usc --visible --summary
10901126 must be tuned to match UniSim's heat duty. Counter-current heat balance
10911127 differences between UniSim and NeqSim typically produce 1–2°C deviation
10921128 on outlet temperatures.
1129+ 19 . ** Full ProcessModel timeout** — Large models with 5+ sub-flowsheets, 10+
1130+ recycles, and Adjusters may time out during ` plant.run() ` even with relaxed
1131+ recycle tolerances. Root cause is typically the combination of Adjuster
1132+ iteration, absorber column convergence, and multi-area coordination.
1133+ ** Workaround** : Test individual ProcessSystem areas or connected sub-paths
1134+ first, then build up incrementally. The connected main-path approach (no
1135+ recycles, manual feed data) runs in < 1 second for even large models.
1136+ 20 . ** Separator liquid MW deviation** — When UniSim separators have
1137+ ` has_water_product=False ` (2-product), the NeqSim ` Separator ` includes
1138+ water in the liquid phase. This causes liquid MW to be lower than UniSim's
1139+ value (water dilutes the MW). Using ` ThreePhaseSeparator ` overcorrects by
1140+ removing ALL water. Expect 20-40% liquid MW deviation at low/medium
1141+ pressures. Gas MW and temperatures are much more accurate.
1142+ 21 . ** Utility sub-flowsheets excluded** — In ` full_mode=True ` , sub-flowsheets
1143+ classified as "utility" (no shared streams with process flowsheet) are
1144+ excluded. This is correct for heating/cooling medium loops but may
1145+ miss utility systems that interact with process streams through
1146+ non-standard connections.
10931147
10941148---
10951149
@@ -1232,6 +1286,7 @@ class UniSimModel:
12321286| Case | File | Components | Operations | Converged | Notes |
12331287| ------| ------| -----------| ------------| -----------| -------|
12341288| TUTOR1 | ` TUTOR1.usc ` | 7 (N₂, CO₂, C₁–nC₄) | 13 | 11/13 streams | DePropanizer column diverges; upstream matches within 1°C. Notebook: ` examples/notebooks/tutor1_gas_processing.ipynb ` |
1289+ | R510 SG Cond | R510 model | 31 (lumped pseudo-C7+ through C30P* ) | 185 main + 8 sub-flowsheets (~ 250 total) | 78% isolated, 71% connected | PR-LK EOS with E300 BIPs. Full mode: 5 process + 3 utility sub-flowsheets |
12351290
12361291### TUTOR1 Lessons Learned
12371292
@@ -1260,3 +1315,77 @@ Key findings that apply to any UniSim conversion:
12601315 ADJ-1 (adjuster) are not needed for mass balance; safe to skip.
12611316
126213176 . ** Heating Value spreadsheet** : Property-only calculations; safe to skip.
1318+
1319+ ### R510 SG Condensation Model — Lessons Learned
1320+
1321+ The R510 SG Condensation model is a large-scale offshore processing model with
1322+ 31 components (including lumped pseudo-components C10-C11* through C30P* , aromatics,
1323+ and glycols), 8 sub-flowsheets, 13+ recycle loops, and ~ 250 total operations.
1324+ This is the first full-mode verified conversion with sub-flowsheet classification.
1325+
1326+ ** Model characteristics:**
1327+ - ** Fluid package** : PR-LK (Peng-Robinson Lee-Kesler) with 31 components
1328+ - ** Feed streams** : 3 feeds — "Reservoir oil" (MW=58.5, 1,950,684 kg/h),
1329+ "Formation water" (MW=18.0, 398,728 kg/h), "Res gas" (MW=19.6, 30,271 kg/h)
1330+ - ** Sub-flowsheets** : 5 process (TPL1, TPL2, TPL5, TPL7, COL1) +
1331+ 3 utility (TPL3, TPL4, TPL6)
1332+ - ** Generated code** : ~ 2000 lines of Python with ProcessModel architecture
1333+
1334+ #### Comparison Results
1335+
1336+ ** Isolated unit-by-unit** (each unit fed with correct UniSim inlet data):
1337+ - 97 GOOD (< 5% deviation), 9 WARN (5-15%), 30 BAD (> 15%), 66 SKIPPED
1338+ - ** 78% match rate** across 136 comparable stream properties
1339+
1340+ ** Connected main-path model** (17 units, no recycles, error propagation):
1341+ - 11 OK, 1 WARN, 5 BAD — ** 71% match rate** in 0.5 seconds
1342+ - Temperature accuracy: excellent (< 0.3°C for most streams)
1343+ - Gas MW matching: good (< 5%)
1344+ - Liquid MW: moderate deviation due to water handling (see below)
1345+
1346+ #### Key Findings
1347+
1348+ 1 . ** E300 fluid loading is essential for pseudo-components.** The ` read(export_e300=True) `
1349+ option extracts Tc, Pc, ω, MW, and BIPs for all 31 components including lumped
1350+ pseudo-components (C10-C11* , C12-C13* , etc.). Without E300 BIPs, phase split
1351+ deviations exceed 100% for heavy components.
1352+
1353+ 2 . ** Component name mapping for lumped pseudo-components.** UniSim uses names like
1354+ ` C10-C11* ` , ` C12-C13* ` , ` C14-C15* ` , ` C16-C18* ` , ` C19-C20* ` , ` C21-C23* ` ,
1355+ ` C24-C29* ` , ` C30P* ` . These map 1:1 to the same names in the E300 file.
1356+ Do NOT assume individual components (C10, C11, C12, ...) — the model uses
1357+ lumped groups.
1358+
1359+ 3 . ** Separator water handling (2-phase vs 3-phase).**
1360+ When UniSim's ` sep3op ` has ` has_water_product: False ` (all separators in R510),
1361+ use NeqSim ` Separator ` (2-phase), NOT ` ThreePhaseSeparator ` . The 2-phase Separator
1362+ gives combined oil+water liquid matching UniSim's 2-product behavior.
1363+ ` ThreePhaseSeparator ` removes ALL water, overcorrecting liquid MW
1364+ (e.g., 201.9 vs target 98.2, while 2-phase gives 66.2 — closer overall).
1365+
1366+ 4 . ** Compressor efficiency extraction fails for some models.** All 6 compressors
1367+ in R510 returned ` None ` for ` AdiabaticEfficiency ` from COM. The 75% isentropic
1368+ default causes 10-32°C outlet temperature deviations. To improve accuracy,
1369+ back-calculate efficiency from UniSim inlet/outlet data.
1370+
1371+ 5 . ** Recycle convergence.** Even with ` setTolerance(1e6) ` on all 13 recycles,
1372+ the full ProcessModel with 8 areas still times out. Root cause is likely the
1373+ combination of Adjusters, absorber columns, and multi-area iteration.
1374+ ** Workaround** : Test individual process areas or connected sub-paths first
1375+ (the 17-unit connected model runs in 0.5s). Build up to full model incrementally.
1376+
1377+ 6 . ** JSON key format.** The extracted JSON uses ` pressure_bara ` (not ` pressure_kPa ` )
1378+ and ` mass_flow_kgh ` (not ` mass_flow_kg_h ` ). When writing comparison scripts,
1379+ use these exact keys.
1380+
1381+ 7 . ** Sub-flowsheet mapping uses positional order.** When the JSON has sub-flowsheet
1382+ operations that cannot be matched by name or stream overlap, the reader falls
1383+ back to positional matching based on the original JSON order. This handles
1384+ cases where sub-flowsheet operation names are generic (e.g., ` MIX-100 ` appears
1385+ in both main and sub-flowsheet).
1386+
1387+ 8 . ** Temperature matching is the strongest comparison metric.** Temperatures
1388+ showed < 0.3°C deviation across the connected path. Gas-phase MW was within
1389+ 5% for most equipment. Use temperature as the primary validation metric;
1390+ MW and flow deviations are often caused by liquid-phase water handling
1391+ rather than thermodynamic model errors.
0 commit comments