processforge 0.2.22__tar.gz → 0.2.30__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of processforge might be problematic. Click here for more details.

Files changed (108) hide show
  1. {processforge-0.2.22/src/processforge.egg-info → processforge-0.2.30}/PKG-INFO +210 -27
  2. {processforge-0.2.22 → processforge-0.2.30}/README.md +207 -25
  3. {processforge-0.2.22 → processforge-0.2.30}/flowsheets/hydraulic-chain.json +3 -1
  4. {processforge-0.2.22 → processforge-0.2.30}/flowsheets/openmc/msre_eigenvalue.json +10 -13
  5. {processforge-0.2.22 → processforge-0.2.30}/pyproject.toml +4 -2
  6. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/__init__.py +1 -4
  7. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/analysis/dof.py +9 -9
  8. processforge-0.2.30/src/processforge/api/app.py +87 -0
  9. processforge-0.2.30/src/processforge/api/models.py +83 -0
  10. processforge-0.2.30/src/processforge/api/runner.py +164 -0
  11. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/api/serve.py +9 -9
  12. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/flowsheet.py +2 -1
  13. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/jacobian.py +19 -1
  14. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/solver.py +80 -15
  15. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/flowsheet.py +67 -5
  16. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/base.py +3 -3
  17. processforge-0.2.30/src/processforge/providers/coolprop_provider.py +85 -0
  18. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/manager.py +9 -6
  19. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/openmc_provider.py +90 -244
  20. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/result.py +21 -4
  21. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/schemas/flowsheet_schema.json +49 -51
  22. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/schemas/openmc/openmc_model.py +72 -0
  23. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/simulate.py +44 -15
  24. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/state.py +73 -8
  25. processforge-0.2.30/src/processforge/thermo.py +14 -0
  26. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/types.py +28 -36
  27. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/__init__.py +1 -2
  28. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/flash.py +7 -5
  29. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/heater.py +3 -4
  30. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/solver_unit.py +5 -7
  31. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/tank.py +4 -8
  32. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/utils/topology.py +3 -1
  33. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/utils/validate_flowsheet.py +110 -57
  34. {processforge-0.2.22 → processforge-0.2.30/src/processforge.egg-info}/PKG-INFO +210 -27
  35. {processforge-0.2.22 → processforge-0.2.30}/src/processforge.egg-info/SOURCES.txt +0 -4
  36. {processforge-0.2.22 → processforge-0.2.30}/src/processforge.egg-info/requires.txt +3 -1
  37. processforge-0.2.22/flowsheets/festim/festim_2d.json +0 -54
  38. processforge-0.2.22/flowsheets/festim/festim_dynamic_loop.json +0 -52
  39. processforge-0.2.22/src/processforge/api/app.py +0 -70
  40. processforge-0.2.22/src/processforge/api/models.py +0 -20
  41. processforge-0.2.22/src/processforge/api/runner.py +0 -95
  42. processforge-0.2.22/src/processforge/providers/coolprop_provider.py +0 -52
  43. processforge-0.2.22/src/processforge/providers/festim_provider.py +0 -697
  44. processforge-0.2.22/src/processforge/thermo.py +0 -73
  45. processforge-0.2.22/src/processforge/units/festim_membrane.py +0 -243
  46. {processforge-0.2.22 → processforge-0.2.30}/LICENSE +0 -0
  47. {processforge-0.2.22 → processforge-0.2.30}/MANIFEST.in +0 -0
  48. {processforge-0.2.22 → processforge-0.2.30}/flowsheets/closed-loop-chain.json +0 -0
  49. {processforge-0.2.22 → processforge-0.2.30}/setup.cfg +0 -0
  50. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/__main__.py +0 -0
  51. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/_schema.py +0 -0
  52. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/analysis/__init__.py +0 -0
  53. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/api/__init__.py +0 -0
  54. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/__init__.py +0 -0
  55. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/backends/__init__.py +0 -0
  56. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/backends/base.py +0 -0
  57. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/backends/casadi_backend.py +0 -0
  58. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/backends/pyomo_backend.py +0 -0
  59. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/backends/scipy_backend.py +0 -0
  60. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/mixin.py +0 -0
  61. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/stream_var.py +0 -0
  62. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/units/__init__.py +0 -0
  63. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/units/flash_eo.py +0 -0
  64. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/units/heater_eo.py +0 -0
  65. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/units/pipes_eo.py +0 -0
  66. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/units/pump_eo.py +0 -0
  67. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/units/strainer_eo.py +0 -0
  68. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/eo/units/valve_eo.py +0 -0
  69. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/fmu/__init__.py +0 -0
  70. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/fmu/_fmi_vars.py +0 -0
  71. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/fmu/builder.py +0 -0
  72. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/fmu/slave_template.py +0 -0
  73. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/modelica/__init__.py +0 -0
  74. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/modelica/mo_writer.py +0 -0
  75. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/modelica/omc_runner.py +0 -0
  76. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/modelica/transpiler.py +0 -0
  77. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/modelica/unit_equations.py +0 -0
  78. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/pcl/__init__.py +0 -0
  79. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/pcl/compiler.py +0 -0
  80. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/pcl/namespace.py +0 -0
  81. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/provenance.py +0 -0
  82. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/__init__.py +0 -0
  83. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/base_jacobian_mixin.py +0 -0
  84. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/cantera_jacobian.py +0 -0
  85. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/cantera_provider.py +0 -0
  86. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/jacobian_contributor.py +0 -0
  87. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/modelica_jacobian.py +0 -0
  88. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/modelica_provider.py +0 -0
  89. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/reference_state_registry.py +0 -0
  90. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/providers/registry.py +0 -0
  91. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/schemas/__init__.py +0 -0
  92. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/solver.py +0 -0
  93. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/cstr.py +0 -0
  94. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/pfr.py +0 -0
  95. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/pipes.py +0 -0
  96. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/provider_mixin.py +0 -0
  97. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/pump.py +0 -0
  98. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/solver.py +0 -0
  99. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/strainer.py +0 -0
  100. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/units/valve.py +0 -0
  101. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/utils/__init__.py +0 -0
  102. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/utils/flowsheet_diagram.py +0 -0
  103. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/utils/mermaid_diagram.py +0 -0
  104. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/utils/unit_consistency.py +0 -0
  105. {processforge-0.2.22 → processforge-0.2.30}/src/processforge/utils/validation.py +0 -0
  106. {processforge-0.2.22 → processforge-0.2.30}/src/processforge.egg-info/dependency_links.txt +0 -0
  107. {processforge-0.2.22 → processforge-0.2.30}/src/processforge.egg-info/entry_points.txt +0 -0
  108. {processforge-0.2.22 → processforge-0.2.30}/src/processforge.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: processforge
3
- Version: 0.2.22
3
+ Version: 0.2.30
4
4
  Summary: A Python-based process simulation framework for chemical engineering applications.
5
5
  Author-email: Process Forge Team <team@processforge.dev>
6
6
  License-Expression: BSD-3-Clause
@@ -21,7 +21,6 @@ Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
22
  Requires-Dist: numpy>=2.0
23
23
  Requires-Dist: scipy>=1.14
24
- Requires-Dist: coolprop>=6.6
25
24
  Requires-Dist: matplotlib>=3.9
26
25
  Requires-Dist: loguru>=0.7
27
26
  Requires-Dist: jsonschema>=4.20
@@ -46,6 +45,8 @@ Requires-Dist: OMPython>=4.0.0; extra == "modelica"
46
45
  Requires-Dist: fmpy>=0.3; extra == "modelica"
47
46
  Provides-Extra: cantera
48
47
  Requires-Dist: cantera>=3.0; extra == "cantera"
48
+ Provides-Extra: coolprop
49
+ Requires-Dist: coolprop>=6.6; extra == "coolprop"
49
50
  Provides-Extra: pcl
50
51
  Requires-Dist: pint>=0.24; extra == "pcl"
51
52
  Provides-Extra: dev
@@ -62,7 +63,7 @@ Dynamic: license-file
62
63
  # Processforge
63
64
 
64
65
 
65
- ![processforge-logo](images/processforge-logo.jpg)
66
+ ![processforge-logo](images/processforge-logo.svg)
66
67
 
67
68
  A Python-based process simulation framework for coupling different simulation engines.
68
69
 
@@ -75,12 +76,21 @@ A Python-based process simulation framework for coupling different simulation en
75
76
  - [Flowsheet Configuration](#flowsheet-configuration)
76
77
  - [Quick Start Examples](#quick-start-examples)
77
78
  - [Plan / Apply Workflow](#plan--apply-workflow-detail)
79
+ - [Running on the cloud](#running-on-the-cloud)
78
80
  - [Project Structure](#project-structure)
79
81
  - [Dependencies](#dependencies)
80
82
  - [License](#license)
81
83
 
82
84
  ## Features
83
85
 
86
+ ### Plan / Apply Workflow
87
+ - **`pf init`**: Initialises the `.processforge/` project directory and `outputs/` folder. Run once per project.
88
+ - **`pf plan`**: Validates the flowsheet (schema, DOF, Pint unit consistency), performs a structural diff against the last saved state (`+` added, `~` modified, `-` removed units), and generates a Mermaid diagram — all without running the solver.
89
+ - **`pf apply`**: Solves the flowsheet using the last converged state as a warm start. Falls back automatically to a step-wise homotopy/continuation solver if the direct Newton solve fails. Topology changes (added/removed units) trigger a cold start with a warning.
90
+ - **Snapshot Versioning**: Every successful `apply` creates a new numbered snapshot in `.pfstate/snapshots/`. Previous snapshots are never deleted, enabling rollback to any prior converged design.
91
+ - **Convergence Guardrails**: If both the direct solve and homotopy fail, the engine auto-reverts `latest` to the last good snapshot and writes a divergence debug report (`*_divergence.json`) with the final residual norm, drifted parameters, and solver statistics.
92
+ - **Dynamic t=0 from State**: `pf run` (dynamic mode) automatically loads the latest `.pfstate` converged values as the initial conditions for time-integration, replacing arbitrary feed defaults with a physically meaningful starting point.
93
+
84
94
  ### Core Capabilities
85
95
  - Steady-state EO (equation-oriented) and dynamic process simulations
86
96
  - Thermodynamic property calculations using CoolProp
@@ -111,14 +121,6 @@ A Python-based process simulation framework for coupling different simulation en
111
121
  - Connectivity checks (inlet sources, unused outlets, unreachable units)
112
122
  - Comprehensive logging for debugging
113
123
 
114
- ### Plan / Apply Workflow
115
- - **`pf init`**: Initialises the `.processforge/` project directory and `outputs/` folder. Run once per project.
116
- - **`pf plan`**: Validates the flowsheet (schema, DOF, Pint unit consistency), performs a structural diff against the last saved state (`+` added, `~` modified, `-` removed units), and generates a Mermaid diagram — all without running the solver.
117
- - **`pf apply`**: Solves the flowsheet using the last converged state as a warm start. Falls back automatically to a step-wise homotopy/continuation solver if the direct Newton solve fails. Topology changes (added/removed units) trigger a cold start with a warning.
118
- - **Snapshot Versioning**: Every successful `apply` creates a new numbered snapshot in `.pfstate/snapshots/`. Previous snapshots are never deleted, enabling rollback to any prior converged design.
119
- - **Convergence Guardrails**: If both the direct solve and homotopy fail, the engine auto-reverts `latest` to the last good snapshot and writes a divergence debug report (`*_divergence.json`) with the final residual norm, drifted parameters, and solver statistics.
120
- - **Dynamic t=0 from State**: `pf run` (dynamic mode) automatically loads the latest `.pfstate` converged values as the initial conditions for time-integration, replacing arbitrary feed defaults with a physically meaningful starting point.
121
-
122
124
  ## Available Unit Operations
123
125
 
124
126
  | Unit Type | Mode | Description | Key Parameters |
@@ -139,11 +141,15 @@ A Python-based process simulation framework for coupling different simulation en
139
141
  ### From PyPI
140
142
 
141
143
  ```bash
142
- # pip
144
+ # pip (core features)
143
145
  pip install processforge
144
146
 
145
- # uv
147
+ # uv (core features)
146
148
  uv add processforge
149
+
150
+ # with CoolProp thermodynamics (required for Heater, Flash)
151
+ pip install "processforge[coolprop]"
152
+ uv add "processforge[coolprop]"
147
153
  ```
148
154
 
149
155
  ### With EO solver backends (optional)
@@ -404,24 +410,201 @@ If both the direct Newton solve and the homotopy fallback fail to converge:
404
410
  2. A `*_divergence.json` report is written with the drifted parameters, final `||F||`, homotopy step history, and the last `x` vector for debugging.
405
411
 
406
412
 
407
- ## Running on the cloud
408
- To run a simulation on any cloud provider (AWS EC2, Google Cloud, etc.) with Docker installed:
413
+ ## Running on the cloud
409
414
 
410
- Pull the image:
411
- ```
415
+ Processforge can run simulation jobs on any cloud VM with Docker installed. Two modes are available:
416
+
417
+ - **Batch mode** — run a single flowsheet directly and store results locally or on S3.
418
+ - **API server mode** — start `pf-serve` for programmatic flowsheet submission.
419
+
420
+ ### Prerequisites
421
+
422
+ ```bash
412
423
  docker pull ghcr.io/urjanova/processforge:latest
413
424
  ```
414
- Run a simulation and map an output folder:
415
-
416
- ```Bash
417
- docker run -p 8080:8080 \
418
- -e AWS_ACCESS_KEY_ID=... \
419
- -e AWS_SECRET_ACCESS_KEY=... \
420
- -e AWS_DEFAULT_REGION=us-east-1 \
421
- ghcr.io/urjanova/processforge:latest \
422
- pf-serve
425
+
426
+ ### Step-by-step: Run a flowsheet via Docker (S3 results)
427
+
428
+ This runs `pf apply` in the container and uploads results to an S3-compatible bucket.
429
+
430
+ 1. **Prepare your flowsheet JSON** — save it to a local file, e.g. `./flowsheets/my-flowsheet.json`.
431
+
432
+ 2. **Set S3 environment variables** in your Docker run command.
433
+
434
+ 3. **Run the container:**
435
+
436
+ ```bash
437
+ docker run --rm \
438
+ -v "$(pwd)/flowsheets:/app/flowsheets" \
439
+ -e S3_ACCESS_KEY='XXXXXX' \
440
+ -e S3_SECRET_KEY='YYYYYYYYY' \
441
+ -e S3_ENDPOINT_URL='https://processforge-files.ams3.digitaloceanspaces.com' \
442
+ -e S3_REGION_NAME='ams3' \
443
+ -e S3_BUCKET_NAME='my-bucket' \
444
+ ghcr.io/urjanova/processforge:latest \
445
+ pf apply /app/flowsheets/my-flowsheet.json
446
+ ```
447
+
448
+ Results (Zarr store, pfstate snapshots) are uploaded to S3 under the configured bucket.
449
+
450
+ ### Step-by-step: Run the API server (pf-serve)
451
+
452
+ Start a persistent HTTP API that accepts flowsheet submissions:
453
+
454
+ 1. **Start the server:**
455
+
456
+ ```bash
457
+ docker run -d \
458
+ --name pf-api \
459
+ -p 9000:9000 \
460
+ -e S3_ACCESS_KEY='XXXXXX' \
461
+ -e S3_SECRET_KEY='YYYYYYYYY' \
462
+ -e S3_ENDPOINT_URL='https://processforge-files.nyc .digitaloceanspaces.com' \
463
+ -e S3_REGION_NAME='ams3' \
464
+ -e S3_BUCKET_NAME='my-bucket' \
465
+ ghcr.io/urjanova/processforge:latest \
466
+ pf-serve
467
+ ```
468
+
469
+ 2. **Submit a flowsheet via the API:**
470
+
471
+ ```bash
472
+ curl -X POST http://localhost:9000/run \
473
+ -H "Content-Type: application/json" \
474
+ -d @flowsheets/my-flowsheet.json
475
+ ```
476
+
477
+ 3. **Check job status** (replace `<job_id>` with the ID returned by the submission response):
478
+
479
+ ```bash
480
+ curl http://localhost:9000/status/<job_id>
481
+ ```
482
+
483
+ 4. **Retrieve results** — the results Zarr store and `.pfstate` snapshots are synced to your S3 bucket automatically on completion.
484
+
485
+ (Ensure you provide your S3-compatible credentials and endpoint URL; output and results will be synced directly to the specified bucket.)
486
+
487
+ <h3 id="openmc-in-containers">Step-by-step: Run OpenMC simulations in Docker</h3>
488
+
489
+ OpenMC simulations require nuclear cross-section data. The container's startup script (`scripts/fetch_openmc_data.sh`) downloads and caches these automatically.
490
+
491
+ | Asset | Typical size | Managed via |
492
+ |-------|-------------|-------------|
493
+ | Cross-section library (`cross_sections.xml` + HDF5 data) | 100 MB – 5 GB | `OPENMC_DATA_URL` |
494
+
495
+ **Step 1: Prepare a volume for cross-section data**
496
+
497
+ You can either:
498
+ - Use a **named Docker volume** (data persists across container restarts):
499
+ ```bash
500
+ docker volume create openmc_data
501
+ ```
502
+ - Use a **host directory**:
503
+ ```bash
504
+ mkdir -p /path/to/openmc_data
505
+ ```
506
+
507
+ **Step 2: Write your OpenMC flowsheet**
508
+
509
+ Use environment variable expansion so the container can find the cross-sections at runtime:
510
+
511
+ ```json
512
+ {
513
+ "providers": {
514
+ "openmc": {
515
+ "type": "openmc",
516
+ "cross_sections": "${OPENMC_DATA_ROOT}/cross_sections/cross_sections.xml"
517
+ }
518
+ },
519
+ "units": {
520
+ "reactor": {
521
+ "type": "SolverUnit",
522
+ "provider": "openmc",
523
+ "sim_type": "eigenvalue_csg",
524
+ "solver_config": {
525
+ "source_point": { "xyz": [0.0, 0.0, 0.0] },
526
+ "point_source_material": "salt",
527
+ "point_source_sphere_radius": 200.0,
528
+ "mesh_tallies": [...]
529
+ }
530
+ }
531
+ }
532
+ }
533
+ ```
534
+
535
+ The startup script exports `OPENMC_CROSS_SECTIONS` pointing to the downloaded library, so `${OPENMC_DATA_ROOT}` in your flowsheet is resolved automatically.
536
+
537
+ **Step 3: Run the simulation**
538
+
539
+ ```bash
540
+ docker run --rm \
541
+ -v openmc_data:/data \
542
+ -e OPENMC_DATA_URL='https://your-host.com/endfb-viii.0-hdf5.tar.gz' \
543
+ ghcr.io/urjanova/processforge:latest \
544
+ pf run /app/flowsheets/openmc/msre_eigenvalue.json
545
+ ```
546
+
547
+ The cross-sections are downloaded on first run and cached on the volume. Subsequent runs skip the download.
548
+
549
+ **Step 4 (optional): Use pre-downloaded cross-sections**
550
+
551
+ If you already have the library on your host machine, mount it directly and skip the download:
552
+
553
+ ```bash
554
+ docker run --rm \
555
+ -v /path/to/openmc_data:/data \
556
+ ghcr.io/urjanova/processforge:latest \
557
+ pf run /app/flowsheets/openmc/msre_eigenvalue.json
423
558
  ```
424
- (The -v flag ensures the .h5 or .xdmf files generated by OpenMC/FESTIM are saved to your actual hard drive, not lost inside the container.)
559
+
560
+ The container checks for `cross_sections.xml` at the expected location and uses it if present.
561
+
562
+ ### Step-by-step: pf-serve with OpenMC cross-sections (local)
563
+
564
+ Run the API server locally with OpenMC cross-section data so it can accept OpenMC flowsheet submissions.
565
+
566
+ 1. **Create a named volume for cross-sections:**
567
+
568
+ ```bash
569
+ docker volume create openmc_data
570
+ ```
571
+
572
+ 2. **Start pf-serve with the volume mounted and cross-section URL configured:**
573
+
574
+ ```bash
575
+ docker run -d \
576
+ --name pf-api \
577
+ -p 9000:9000 \
578
+ -v openmc_data:/data \
579
+ -e OPENMC_DATA_URL='https://your-host.com/endfb-viii.0-hdf5.tar.gz' \
580
+ ghcr.io/urjanova/processforge:latest \
581
+ pf-serve
582
+ ```
583
+
584
+ The startup script downloads cross-sections to the volume on first start. The server is ready once the container logs show the download completed.
585
+
586
+ 3. **Submit an OpenMC flowsheet to the API:**
587
+
588
+ ```bash
589
+ curl -X POST http://localhost:9000/run \
590
+ -H "Content-Type: application/json" \
591
+ -d @flowsheets/openmc/msre_eigenvalue.json
592
+ ```
593
+
594
+ 4. **Check the job status:**
595
+
596
+ ```bash
597
+ curl http://localhost:9000/status/<job_id>
598
+ ```
599
+
600
+ 5. **Stop the server when done:**
601
+
602
+ ```bash
603
+ docker stop pf-api && docker rm pf-api
604
+ ```
605
+
606
+ Results from completed jobs are stored inside the container; mount an output directory with `-v "$(pwd)/outputs:/app/outputs"` if you need them on the host.
607
+
425
608
  ## Logo credit
426
609
  Google Gemini / Nano Banana
427
610
 
@@ -1,7 +1,7 @@
1
1
  # Processforge
2
2
 
3
3
 
4
- ![processforge-logo](images/processforge-logo.jpg)
4
+ ![processforge-logo](images/processforge-logo.svg)
5
5
 
6
6
  A Python-based process simulation framework for coupling different simulation engines.
7
7
 
@@ -14,12 +14,21 @@ A Python-based process simulation framework for coupling different simulation en
14
14
  - [Flowsheet Configuration](#flowsheet-configuration)
15
15
  - [Quick Start Examples](#quick-start-examples)
16
16
  - [Plan / Apply Workflow](#plan--apply-workflow-detail)
17
+ - [Running on the cloud](#running-on-the-cloud)
17
18
  - [Project Structure](#project-structure)
18
19
  - [Dependencies](#dependencies)
19
20
  - [License](#license)
20
21
 
21
22
  ## Features
22
23
 
24
+ ### Plan / Apply Workflow
25
+ - **`pf init`**: Initialises the `.processforge/` project directory and `outputs/` folder. Run once per project.
26
+ - **`pf plan`**: Validates the flowsheet (schema, DOF, Pint unit consistency), performs a structural diff against the last saved state (`+` added, `~` modified, `-` removed units), and generates a Mermaid diagram — all without running the solver.
27
+ - **`pf apply`**: Solves the flowsheet using the last converged state as a warm start. Falls back automatically to a step-wise homotopy/continuation solver if the direct Newton solve fails. Topology changes (added/removed units) trigger a cold start with a warning.
28
+ - **Snapshot Versioning**: Every successful `apply` creates a new numbered snapshot in `.pfstate/snapshots/`. Previous snapshots are never deleted, enabling rollback to any prior converged design.
29
+ - **Convergence Guardrails**: If both the direct solve and homotopy fail, the engine auto-reverts `latest` to the last good snapshot and writes a divergence debug report (`*_divergence.json`) with the final residual norm, drifted parameters, and solver statistics.
30
+ - **Dynamic t=0 from State**: `pf run` (dynamic mode) automatically loads the latest `.pfstate` converged values as the initial conditions for time-integration, replacing arbitrary feed defaults with a physically meaningful starting point.
31
+
23
32
  ### Core Capabilities
24
33
  - Steady-state EO (equation-oriented) and dynamic process simulations
25
34
  - Thermodynamic property calculations using CoolProp
@@ -50,14 +59,6 @@ A Python-based process simulation framework for coupling different simulation en
50
59
  - Connectivity checks (inlet sources, unused outlets, unreachable units)
51
60
  - Comprehensive logging for debugging
52
61
 
53
- ### Plan / Apply Workflow
54
- - **`pf init`**: Initialises the `.processforge/` project directory and `outputs/` folder. Run once per project.
55
- - **`pf plan`**: Validates the flowsheet (schema, DOF, Pint unit consistency), performs a structural diff against the last saved state (`+` added, `~` modified, `-` removed units), and generates a Mermaid diagram — all without running the solver.
56
- - **`pf apply`**: Solves the flowsheet using the last converged state as a warm start. Falls back automatically to a step-wise homotopy/continuation solver if the direct Newton solve fails. Topology changes (added/removed units) trigger a cold start with a warning.
57
- - **Snapshot Versioning**: Every successful `apply` creates a new numbered snapshot in `.pfstate/snapshots/`. Previous snapshots are never deleted, enabling rollback to any prior converged design.
58
- - **Convergence Guardrails**: If both the direct solve and homotopy fail, the engine auto-reverts `latest` to the last good snapshot and writes a divergence debug report (`*_divergence.json`) with the final residual norm, drifted parameters, and solver statistics.
59
- - **Dynamic t=0 from State**: `pf run` (dynamic mode) automatically loads the latest `.pfstate` converged values as the initial conditions for time-integration, replacing arbitrary feed defaults with a physically meaningful starting point.
60
-
61
62
  ## Available Unit Operations
62
63
 
63
64
  | Unit Type | Mode | Description | Key Parameters |
@@ -78,11 +79,15 @@ A Python-based process simulation framework for coupling different simulation en
78
79
  ### From PyPI
79
80
 
80
81
  ```bash
81
- # pip
82
+ # pip (core features)
82
83
  pip install processforge
83
84
 
84
- # uv
85
+ # uv (core features)
85
86
  uv add processforge
87
+
88
+ # with CoolProp thermodynamics (required for Heater, Flash)
89
+ pip install "processforge[coolprop]"
90
+ uv add "processforge[coolprop]"
86
91
  ```
87
92
 
88
93
  ### With EO solver backends (optional)
@@ -343,24 +348,201 @@ If both the direct Newton solve and the homotopy fallback fail to converge:
343
348
  2. A `*_divergence.json` report is written with the drifted parameters, final `||F||`, homotopy step history, and the last `x` vector for debugging.
344
349
 
345
350
 
346
- ## Running on the cloud
347
- To run a simulation on any cloud provider (AWS EC2, Google Cloud, etc.) with Docker installed:
351
+ ## Running on the cloud
348
352
 
349
- Pull the image:
350
- ```
353
+ Processforge can run simulation jobs on any cloud VM with Docker installed. Two modes are available:
354
+
355
+ - **Batch mode** — run a single flowsheet directly and store results locally or on S3.
356
+ - **API server mode** — start `pf-serve` for programmatic flowsheet submission.
357
+
358
+ ### Prerequisites
359
+
360
+ ```bash
351
361
  docker pull ghcr.io/urjanova/processforge:latest
352
362
  ```
353
- Run a simulation and map an output folder:
354
-
355
- ```Bash
356
- docker run -p 8080:8080 \
357
- -e AWS_ACCESS_KEY_ID=... \
358
- -e AWS_SECRET_ACCESS_KEY=... \
359
- -e AWS_DEFAULT_REGION=us-east-1 \
360
- ghcr.io/urjanova/processforge:latest \
361
- pf-serve
363
+
364
+ ### Step-by-step: Run a flowsheet via Docker (S3 results)
365
+
366
+ This runs `pf apply` in the container and uploads results to an S3-compatible bucket.
367
+
368
+ 1. **Prepare your flowsheet JSON** — save it to a local file, e.g. `./flowsheets/my-flowsheet.json`.
369
+
370
+ 2. **Set S3 environment variables** in your Docker run command.
371
+
372
+ 3. **Run the container:**
373
+
374
+ ```bash
375
+ docker run --rm \
376
+ -v "$(pwd)/flowsheets:/app/flowsheets" \
377
+ -e S3_ACCESS_KEY='XXXXXX' \
378
+ -e S3_SECRET_KEY='YYYYYYYYY' \
379
+ -e S3_ENDPOINT_URL='https://processforge-files.ams3.digitaloceanspaces.com' \
380
+ -e S3_REGION_NAME='ams3' \
381
+ -e S3_BUCKET_NAME='my-bucket' \
382
+ ghcr.io/urjanova/processforge:latest \
383
+ pf apply /app/flowsheets/my-flowsheet.json
384
+ ```
385
+
386
+ Results (Zarr store, pfstate snapshots) are uploaded to S3 under the configured bucket.
387
+
388
+ ### Step-by-step: Run the API server (pf-serve)
389
+
390
+ Start a persistent HTTP API that accepts flowsheet submissions:
391
+
392
+ 1. **Start the server:**
393
+
394
+ ```bash
395
+ docker run -d \
396
+ --name pf-api \
397
+ -p 9000:9000 \
398
+ -e S3_ACCESS_KEY='XXXXXX' \
399
+ -e S3_SECRET_KEY='YYYYYYYYY' \
400
+ -e S3_ENDPOINT_URL='https://processforge-files.nyc .digitaloceanspaces.com' \
401
+ -e S3_REGION_NAME='ams3' \
402
+ -e S3_BUCKET_NAME='my-bucket' \
403
+ ghcr.io/urjanova/processforge:latest \
404
+ pf-serve
405
+ ```
406
+
407
+ 2. **Submit a flowsheet via the API:**
408
+
409
+ ```bash
410
+ curl -X POST http://localhost:9000/run \
411
+ -H "Content-Type: application/json" \
412
+ -d @flowsheets/my-flowsheet.json
413
+ ```
414
+
415
+ 3. **Check job status** (replace `<job_id>` with the ID returned by the submission response):
416
+
417
+ ```bash
418
+ curl http://localhost:9000/status/<job_id>
419
+ ```
420
+
421
+ 4. **Retrieve results** — the results Zarr store and `.pfstate` snapshots are synced to your S3 bucket automatically on completion.
422
+
423
+ (Ensure you provide your S3-compatible credentials and endpoint URL; output and results will be synced directly to the specified bucket.)
424
+
425
+ <h3 id="openmc-in-containers">Step-by-step: Run OpenMC simulations in Docker</h3>
426
+
427
+ OpenMC simulations require nuclear cross-section data. The container's startup script (`scripts/fetch_openmc_data.sh`) downloads and caches these automatically.
428
+
429
+ | Asset | Typical size | Managed via |
430
+ |-------|-------------|-------------|
431
+ | Cross-section library (`cross_sections.xml` + HDF5 data) | 100 MB – 5 GB | `OPENMC_DATA_URL` |
432
+
433
+ **Step 1: Prepare a volume for cross-section data**
434
+
435
+ You can either:
436
+ - Use a **named Docker volume** (data persists across container restarts):
437
+ ```bash
438
+ docker volume create openmc_data
439
+ ```
440
+ - Use a **host directory**:
441
+ ```bash
442
+ mkdir -p /path/to/openmc_data
443
+ ```
444
+
445
+ **Step 2: Write your OpenMC flowsheet**
446
+
447
+ Use environment variable expansion so the container can find the cross-sections at runtime:
448
+
449
+ ```json
450
+ {
451
+ "providers": {
452
+ "openmc": {
453
+ "type": "openmc",
454
+ "cross_sections": "${OPENMC_DATA_ROOT}/cross_sections/cross_sections.xml"
455
+ }
456
+ },
457
+ "units": {
458
+ "reactor": {
459
+ "type": "SolverUnit",
460
+ "provider": "openmc",
461
+ "sim_type": "eigenvalue_csg",
462
+ "solver_config": {
463
+ "source_point": { "xyz": [0.0, 0.0, 0.0] },
464
+ "point_source_material": "salt",
465
+ "point_source_sphere_radius": 200.0,
466
+ "mesh_tallies": [...]
467
+ }
468
+ }
469
+ }
470
+ }
471
+ ```
472
+
473
+ The startup script exports `OPENMC_CROSS_SECTIONS` pointing to the downloaded library, so `${OPENMC_DATA_ROOT}` in your flowsheet is resolved automatically.
474
+
475
+ **Step 3: Run the simulation**
476
+
477
+ ```bash
478
+ docker run --rm \
479
+ -v openmc_data:/data \
480
+ -e OPENMC_DATA_URL='https://your-host.com/endfb-viii.0-hdf5.tar.gz' \
481
+ ghcr.io/urjanova/processforge:latest \
482
+ pf run /app/flowsheets/openmc/msre_eigenvalue.json
483
+ ```
484
+
485
+ The cross-sections are downloaded on first run and cached on the volume. Subsequent runs skip the download.
486
+
487
+ **Step 4 (optional): Use pre-downloaded cross-sections**
488
+
489
+ If you already have the library on your host machine, mount it directly and skip the download:
490
+
491
+ ```bash
492
+ docker run --rm \
493
+ -v /path/to/openmc_data:/data \
494
+ ghcr.io/urjanova/processforge:latest \
495
+ pf run /app/flowsheets/openmc/msre_eigenvalue.json
362
496
  ```
363
- (The -v flag ensures the .h5 or .xdmf files generated by OpenMC/FESTIM are saved to your actual hard drive, not lost inside the container.)
497
+
498
+ The container checks for `cross_sections.xml` at the expected location and uses it if present.
499
+
500
+ ### Step-by-step: pf-serve with OpenMC cross-sections (local)
501
+
502
+ Run the API server locally with OpenMC cross-section data so it can accept OpenMC flowsheet submissions.
503
+
504
+ 1. **Create a named volume for cross-sections:**
505
+
506
+ ```bash
507
+ docker volume create openmc_data
508
+ ```
509
+
510
+ 2. **Start pf-serve with the volume mounted and cross-section URL configured:**
511
+
512
+ ```bash
513
+ docker run -d \
514
+ --name pf-api \
515
+ -p 9000:9000 \
516
+ -v openmc_data:/data \
517
+ -e OPENMC_DATA_URL='https://your-host.com/endfb-viii.0-hdf5.tar.gz' \
518
+ ghcr.io/urjanova/processforge:latest \
519
+ pf-serve
520
+ ```
521
+
522
+ The startup script downloads cross-sections to the volume on first start. The server is ready once the container logs show the download completed.
523
+
524
+ 3. **Submit an OpenMC flowsheet to the API:**
525
+
526
+ ```bash
527
+ curl -X POST http://localhost:9000/run \
528
+ -H "Content-Type: application/json" \
529
+ -d @flowsheets/openmc/msre_eigenvalue.json
530
+ ```
531
+
532
+ 4. **Check the job status:**
533
+
534
+ ```bash
535
+ curl http://localhost:9000/status/<job_id>
536
+ ```
537
+
538
+ 5. **Stop the server when done:**
539
+
540
+ ```bash
541
+ docker stop pf-api && docker rm pf-api
542
+ ```
543
+
544
+ Results from completed jobs are stored inside the container; mount an output directory with `-v "$(pwd)/outputs:/app/outputs"` if you need them on the host.
545
+
364
546
  ## Logo credit
365
547
  Google Gemini / Nano Banana
366
548
 
@@ -104,6 +104,8 @@
104
104
  },
105
105
  "simulation": {
106
106
  "mode": "steady",
107
- "backend": "scipy"
107
+ "t0": 0.0,
108
+ "tf": 20.0,
109
+ "dt": 1.0
108
110
  }
109
111
  }
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "metadata": {
3
- "name": "MSRE Eigenvalue — DAGMC geometry",
4
- "description": "Molten Salt Reactor Experiment eigenvalue simulation. Replicates openmc.py reference script. DAGMC geometry loaded from .h5m file. 7 materials matching h5m volume tags: graphite, inor, salt, inconel, helium, Graveyard, helium_comp.",
5
- "version": "1.1"
3
+ "name": "MSRE Eigenvalue — CSG geometry",
4
+ "description": "Molten Salt Reactor Experiment criticality calculation. Fission source at reactor centre inside a homogeneous salt sphere. 5 materials: graphite, inor, salt, inconel, helium.",
5
+ "version": "1.3"
6
6
  },
7
7
  "providers": {
8
8
  "openmc": {
9
9
  "type": "openmc",
10
10
  "output_dir": "outputs/openmc/msre_run",
11
- "cross_sections": "tmp_files/cross_sections/cross_sections.xml"
11
+ "cross_sections": "${OPENMC_DATA_ROOT}/cross_sections/cross_sections.xml"
12
12
  }
13
13
  },
14
14
  "materials": {
@@ -70,26 +70,23 @@
70
70
  { "name": "He4", "percent": 1.0, "percent_type": "ao" }
71
71
  ]
72
72
  }
73
-
74
73
  },
75
74
  "streams": {},
76
75
  "units": {
77
76
  "openmc_solver": {
78
77
  "type": "SolverUnit",
79
78
  "provider": "openmc",
80
- "material":3,
81
- "sim_type": "eigenvalue_dagmc",
79
+ "material": 3,
80
+ "sim_type": "eigenvalue_csg",
82
81
  "solver_config": {
83
- "dagmc_path": "/home/hrishiballal/Documents/Github/urjanova/processforge/tmp_files/geometry/msre_simple.h5m",
84
82
  "batches": 20,
85
83
  "inactive": 5,
86
84
  "particles": 20000,
87
- "run_mode": "eigenvalue",
88
- "source_box": {
89
- "lower_left": [-125, -125, 0],
90
- "upper_right": [ 125, 125, 500],
91
- "only_fissionable": true
85
+ "source_point": {
86
+ "xyz": [0.0, 0.0, 0.0]
92
87
  },
88
+ "point_source_sphere_radius": 200.0,
89
+ "point_source_material": "salt",
93
90
  "mesh_tallies": [
94
91
  {
95
92
  "tally_id": 1,
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "processforge"
7
- version = "0.2.22"
7
+ version = "0.2.30"
8
8
  description = "A Python-based process simulation framework for chemical engineering applications."
9
9
  readme = "README.md"
10
10
  license = "BSD-3-Clause"
@@ -27,7 +27,6 @@ keywords = ["process", "simulation", "chemical", "engineering", "flowsheet"]
27
27
  dependencies = [
28
28
  "numpy>=2.0",
29
29
  "scipy>=1.14",
30
- "coolprop>=6.6",
31
30
  "matplotlib>=3.9",
32
31
  "loguru>=0.7",
33
32
  "jsonschema>=4.20",
@@ -61,6 +60,9 @@ modelica = [
61
60
  cantera = [
62
61
  "cantera>=3.0",
63
62
  ]
63
+ coolprop = [
64
+ "coolprop>=6.6",
65
+ ]
64
66
  pcl = [
65
67
  "pint>=0.24",
66
68
  ]