Skip to the content.

Jupyter Development Workflow

Use Jupyter notebooks to interactively test NeqSim Java code as you write it. Edit a Java file, re-run a cell, and see results immediately — no JAR rebuild needed.

Overview

The neqsim_dev_setup module (in devtools/) provides three functions:

Function Purpose
neqsim_init() Start the JVM with the project classpath
neqsim_classes() Import commonly used Java classes into a namespace
neqsim_compile() Compile and optionally restart the kernel

Prerequisites

  1. Java JDK installed and on PATH (or JAVA_HOME set)
  2. Python venv with JPype installed (pip install jpype1)
  3. NeqSim compiled at least once (mvnw.cmd compile or mvnw.cmd package -DskipTests)

One-time setup

From the project root with your venv active:

pip install -e devtools/

This installs neqsim_dev_setup as an editable package — the module points at the actual file in devtools/, so any edits you make to it are picked up immediately (after a kernel restart).

Quick start

Create a new notebook anywhere and add two cells:

# Cell 1 — JVM lifecycle
from neqsim_dev_setup import neqsim_init, neqsim_classes
ns = neqsim_init(recompile=True)
# Cell 2 — class imports
ns = neqsim_classes(ns)

Then use Java classes via the ns namespace:

fluid = ns.SystemSrkEos(273.15 + 25.0, 60.0)
fluid.addComponent("methane", 0.9)
fluid.addComponent("ethane", 0.1)
fluid.setMixingRule("classic")

How it works in detail

The classpath

neqsim_init() starts a JVM with this classpath (in priority order):

  1. target/classes/ — your latest compiled .class files
  2. src/main/resources/ — database files, CSV data, component tables
  3. target/neqsim-*.jar — the shaded JAR with all third-party dependencies (EJML, Commons Math, etc.) The Maven shade plugin produces this as the main artifact; original-neqsim-*.jar, *-sources.jar, and *-javadoc.jar are excluded automatically.

Because target/classes/ comes first, any class you recompile immediately shadows the version inside the shaded JAR.

The JVM lifecycle

JPype (the Python-Java bridge) can only start the JVM once per Python process. Once classes are loaded, they cannot be reloaded. This means:

This is why Cell 1 is self-contained — it always does the right thing regardless of kernel state.

The namespace object

neqsim_init() returns a types.SimpleNamespace with two attributes:

neqsim_classes(ns) then populates this namespace with commonly used classes:

Attribute Java class
ns.SystemSrkEos neqsim.thermo.system.SystemSrkEos
ns.SystemPrEos neqsim.thermo.system.SystemPrEos
ns.SystemSrkCPAstatoil neqsim.thermo.system.SystemSrkCPAstatoil
ns.ThermodynamicOperations neqsim.thermodynamicoperations.ThermodynamicOperations
ns.ProcessSystem neqsim.process.processmodel.ProcessSystem
ns.Stream neqsim.process.equipment.stream.Stream
ns.Separator neqsim.process.equipment.separator.Separator
ns.ThreePhaseSeparator neqsim.process.equipment.separator.ThreePhaseSeparator
ns.Compressor neqsim.process.equipment.compressor.Compressor
ns.Cooler neqsim.process.equipment.heatexchanger.Cooler
ns.Heater neqsim.process.equipment.heatexchanger.Heater
ns.HeatExchanger neqsim.process.equipment.heatexchanger.HeatExchanger
ns.Mixer neqsim.process.equipment.mixer.Mixer
ns.Splitter neqsim.process.equipment.splitter.Splitter
ns.ThrottlingValve neqsim.process.equipment.valve.ThrottlingValve
ns.AdiabaticPipe neqsim.process.equipment.pipeline.AdiabaticPipe
ns.PipeBeggsAndBrills neqsim.process.equipment.pipeline.PipeBeggsAndBrills
ns.Pump neqsim.process.equipment.pump.Pump
ns.Manifold neqsim.process.equipment.manifold.Manifold
ns.StreamSaturatorUtil neqsim.process.equipment.util.StreamSaturatorUtil
ns.Recycle neqsim.process.equipment.util.Recycle
ns.Adjuster neqsim.process.equipment.util.Adjuster

Importing additional classes

You don’t need to modify neqsim_dev_setup.py to use more classes. In your notebook, use either approach:

# Add to ns namespace (consistent prefix)
ns.DistillationColumn = ns.JClass(
    "neqsim.process.equipment.distillation.DistillationColumn"
)

# Or import into a local variable (no prefix)
import jpype
DistillationColumn = jpype.JClass(
    "neqsim.process.equipment.distillation.DistillationColumn"
)

Inner classes and enums use $ notation:

SolverType = ns.JClass(
    "neqsim.process.equipment.distillation.DistillationColumn$SolverType"
)

Java standard library classes work too:

ArrayList = ns.JClass("java.util.ArrayList")
HashMap = ns.JClass("java.util.HashMap")

Compilation

Pass recompile=True to neqsim_init():

ns = neqsim_init(recompile=True)

This runs mvnw.cmd compile -q before starting the JVM. Compilation typically takes 30-60 seconds.

Manual

Compile from a terminal and then run the init cell without recompile:

mvnw.cmd compile -q
ns = neqsim_init(recompile=False)

Standalone compile + restart

Use neqsim_compile() to compile and restart from any cell:

from neqsim_dev_setup import neqsim_compile
neqsim_compile()  # compiles + restarts kernel

The edit-compile-test cycle

1. Edit Java code in VS Code
2. Re-run Cell 1 (neqsim_init with recompile=True)
   → Compiles your changes
   → Restarts kernel (if JVM was running)
   → Cell 1 re-executes on fresh kernel
3. Run Cell 2 (neqsim_classes)
   → Imports classes from freshly compiled code
4. Run your test cells
   → Uses the updated Java classes

Why not use the neqsim Python package directly?

The neqsim-python package (pip install neqsim) bundles a released JAR. It’s great for end users but has two limitations for development:

  1. Stale code — it uses the published JAR, not your local changes
  2. Namespace conflictfrom neqsim.thermo... import hits the Python package, not the Java package. That’s why we use jpype.JClass() with fully qualified class names instead.

The devtools/ approach loads classes directly from target/classes/, giving you instant access to any Java change you compile.

Project root detection

The module auto-detects the project root relative to its own location:

_PROJECT_ROOT = Path(__file__).resolve().parent.parent
# devtools/neqsim_dev_setup.py → parent = devtools/ → parent = project root

You can override this per notebook:

ns = neqsim_init(project_root="/path/to/other/neqsim")

Troubleshooting

Problem Cause Fix
ImportError: cannot import name 'neqsim_classes' Stale __pycache__ or old module cached Restart kernel; delete __pycache__ dirs
ModuleNotFoundError: No module named 'neqsim_dev_setup' Package not installed Run pip install -e devtools/
FileNotFoundError: No NeqSim JAR found Never built the full project Run mvnw.cmd package -DskipTests
RuntimeError: Maven compile failed Java compilation error Check the error output; fix the Java code
Kernel shows “crashed” after re-run Expected — do_shutdown(restart=True) triggers this Normal behavior; kernel restarts and re-runs
JVMNotFoundException No JDK found Install JDK and set JAVA_HOME

File locations

File Path Purpose
Module devtools/neqsim_dev_setup.py JVM bootstrap + class imports
Package config devtools/pyproject.toml Makes it pip-installable
Example notebook examples/notebooks/neqsim_dev.ipynb Working demo
This guide docs/development/jupyter_development_workflow.md Detailed docs