| name | run_flash_experiments |
| description | Execute NeqSim flash calculations in batch mode, collect metrics, and produce |
Skill: Run Flash Experiments
Purpose
Execute NeqSim flash calculations in batch mode, collect metrics, and produce
structured result files for paper-quality benchmarking.
When to Use
- Running a benchmark suite designed by the
design_flash_benchmark skill
- Comparing baseline vs candidate algorithms
- Generating raw data for the validation agent
Execution Procedure
Step 1: Load Benchmark Config
import json
with open("benchmark_config.json") as f:
config = json.load(f)
Step 2: Generate All Cases
import numpy as np
from itertools import product
def generate_all_cases(config):
"""Generate all benchmark cases from config."""
cases = []
case_id = 0
for family in config["families"]:
base = family["base_composition"]
names = list(base.keys())
alpha = np.array([base[n] for n in names]) * family["dirichlet_concentration"]
np.random.seed(42)
compositions = [base]
for _ in range(family["n_composition_variants"] - 1):
x = np.random.dirichlet(alpha)
compositions.append(dict(zip(names, x.tolist())))
T_vals = np.linspace(family["T_range_K"][0], family["T_range_K"][1], family["n_T"])
P_vals = np.logspace(
np.log10(family["P_range_bara"][0]),
np.log10(family["P_range_bara"][1]),
family["n_P"]
)
for comp in compositions:
for T, P in product(T_vals, P_vals):
cases.append({
"case_id": f"{family['name'][:2].upper()}-{case_id:05d}",
"family": family["name"],
"components": comp,
"T_K": float(T),
"P_bara": float(P)
})
case_id += 1
return cases
Step 3: Run Single Flash Case
import time
from tools.neqsim_bootstrap import get_jneqsim
jneqsim = get_jneqsim()
SystemSrkEos = jneqsim.thermo.system.SystemSrkEos
SystemPrEos = jneqsim.thermo.system.SystemPrEos
ThermodynamicOperations = jneqsim.thermodynamicoperations.ThermodynamicOperations
EOS_MAP = {
"SRK": SystemSrkEos,
"PR": SystemPrEos,
}
def run_flash_case(case, eos_name="SRK", timing_repeats=3):
"""Run a single TPflash and return metrics."""
EosClass = EOS_MAP[eos_name]
fluid = EosClass(case["T_K"], case["P_bara"])
for comp_name, frac in case["components"].items():
fluid.addComponent(comp_name, frac)
fluid.setMixingRule("classic")
ops = ThermodynamicOperations(fluid)
try:
ops.TPflash()
except Exception:
pass
times_ns = []
for _ in range(timing_repeats):
fluid2 = fluid.clone()
ops2 = ThermodynamicOperations(fluid2)
t0 = time.perf_counter_ns()
try:
ops2.TPflash()
elapsed = time.perf_counter_ns() - t0
times_ns.append(elapsed)
fluid2.initProperties()
n_phases = int(fluid2.getNumberOfPhases())
beta_vapor = float(fluid2.getBeta(0)) if n_phases > 0 else 0.0
converged =
error =
Exception e:
elapsed = time.perf_counter_ns() - t0
times_ns.append(elapsed)
n_phases = -
beta_vapor = -
converged =
error = (e)
median_time_ms = (np.median(times_ns)) /
{
: [],
: [],
: eos_name,
: [],
: [],
: converged,
: (median_time_ms, ),
: n_phases,
: (beta_vapor, ) beta_vapor >= ,
: error
}
Step 4: Run Full Suite
import json
import os
from pathlib import Path
def run_benchmark_suite(config, algorithm_name, results_dir):
"""Run the complete benchmark suite."""
cases = generate_all_cases(config)
results_path = Path(results_dir) / "raw"
results_path.mkdir(parents=True, exist_ok=True)
output_file = results_path / f"{algorithm_name}_results.jsonl"
n_converged = 0
n_total = 0
failures = []
with open(output_file, "w") as f:
for i, case in enumerate(cases):
result = run_flash_case(case, eos_name=config["eos_models"][0])
result["algorithm"] = algorithm_name
f.write(json.dumps(result) + "\n")
n_total += 1
if result["converged"]:
n_converged += 1
else:
failures.append(result)
if (i + 1) % 100 == 0:
print(f" Progress: {i+1}/{len(cases)} "
f"({n_converged}/{n_total} converged)")
summary = {
: algorithm_name,
: config[][],
: n_total,
: n_converged,
: n_total - n_converged,
: ( * n_converged / n_total, )
}
(Path(results_dir) / , ) f:
json.dump(summary, f, indent=)
(Path(results_dir) / , ) f:
json.dump(failures, f, indent=)
summary
Step 5: Record Metadata
import platform
import subprocess
def record_metadata(results_dir):
"""Record benchmark environment metadata."""
metadata = {
"date": "2026-03-31",
"hostname": platform.node(),
"os": platform.platform(),
"python": platform.python_version(),
"java": "OpenJDK 17",
"cpu": platform.processor(),
"neqsim_version": "3.3.0",
"random_seed": 42
}
try:
result = subprocess.run(
["git", "rev-parse", "HEAD"],
capture_output=True, text=True
)
metadata["git_commit"] = result.stdout.strip()
except Exception:
metadata["git_commit"] = "unknown"
with open(Path(results_dir) / "benchmark_metadata.json", "w") as f:
json.dump(metadata, f, indent=2)
Output Files
| File | Format | Content |
|---|
raw/<algorithm>_results.jsonl | JSONL | One result per line, all cases |
summary_<algorithm>.json | JSON | Aggregate statistics |
failures_<algorithm>.json | JSON | Failed case details |
benchmark_metadata.json | JSON | Environment info |
Error Handling
- Java exception: Catch, record error message, mark as failed
- Timeout: Set a 10-second per-case timeout
- NaN/Inf results: Detect and mark as failed
- Memory issues: Run in batches of 500, flush results to disk
Performance Tips
- Use
fluid.clone() instead of recreating from scratch
- Warm up the JVM before timing
- Report median of 3 runs, not mean (avoids GC outliers)
- Run baseline and candidate interleaved, not sequentially