processforge 0.2.30__tar.gz → 0.2.38__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 (112) hide show
  1. processforge-0.2.38/PKG-INFO +140 -0
  2. processforge-0.2.38/README.md +82 -0
  3. {processforge-0.2.30 → processforge-0.2.38}/flowsheets/closed-loop-chain.json +1 -1
  4. processforge-0.2.38/flowsheets/festim/hydrogen_transport_1d.json +70 -0
  5. {processforge-0.2.30 → processforge-0.2.38}/flowsheets/hydraulic-chain.json +1 -1
  6. {processforge-0.2.30 → processforge-0.2.38}/flowsheets/openmc/msre_eigenvalue.json +2 -1
  7. {processforge-0.2.30 → processforge-0.2.38}/pyproject.toml +4 -10
  8. processforge-0.2.38/src/processforge/compose.py +47 -0
  9. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/flowsheet.py +11 -47
  10. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/jacobian.py +7 -4
  11. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/solver.py +0 -1
  12. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/flowsheet.py +149 -162
  13. processforge-0.2.38/src/processforge/lock.py +41 -0
  14. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/__init__.py +2 -1
  15. processforge-0.2.38/src/processforge/providers/festim_provider.py +411 -0
  16. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/manager.py +95 -50
  17. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/openmc_provider.py +8 -1
  18. processforge-0.2.38/src/processforge/providers/registry.py +185 -0
  19. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/result.py +3 -5
  20. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/schemas/flowsheet_schema.json +18 -6
  21. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/schemas/openmc/openmc_model.py +2 -2
  22. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/simulate.py +283 -20
  23. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/state.py +19 -6
  24. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/types.py +121 -1
  25. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/__init__.py +3 -0
  26. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/cstr.py +5 -0
  27. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/flash.py +9 -6
  28. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/heater.py +9 -5
  29. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/pfr.py +4 -0
  30. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/pipes.py +4 -0
  31. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/pump.py +4 -0
  32. processforge-0.2.38/src/processforge/units/registry.py +24 -0
  33. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/solver_unit.py +4 -0
  34. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/strainer.py +4 -0
  35. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/tank.py +4 -0
  36. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/valve.py +4 -0
  37. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/utils/validate_flowsheet.py +158 -11
  38. processforge-0.2.38/src/processforge.egg-info/PKG-INFO +140 -0
  39. {processforge-0.2.30 → processforge-0.2.38}/src/processforge.egg-info/SOURCES.txt +10 -6
  40. {processforge-0.2.30 → processforge-0.2.38}/src/processforge.egg-info/entry_points.txt +0 -1
  41. {processforge-0.2.30 → processforge-0.2.38}/src/processforge.egg-info/requires.txt +2 -7
  42. processforge-0.2.38/tests/test_festim_provider.py +596 -0
  43. processforge-0.2.38/tests/test_init.py +256 -0
  44. processforge-0.2.38/tests/test_providers.py +318 -0
  45. processforge-0.2.38/tests/test_state.py +125 -0
  46. processforge-0.2.30/PKG-INFO +0 -615
  47. processforge-0.2.30/README.md +0 -553
  48. processforge-0.2.30/src/processforge/api/app.py +0 -87
  49. processforge-0.2.30/src/processforge/api/models.py +0 -83
  50. processforge-0.2.30/src/processforge/api/runner.py +0 -164
  51. processforge-0.2.30/src/processforge/api/serve.py +0 -41
  52. processforge-0.2.30/src/processforge/providers/registry.py +0 -52
  53. processforge-0.2.30/src/processforge/utils/__init__.py +0 -0
  54. processforge-0.2.30/src/processforge.egg-info/PKG-INFO +0 -615
  55. {processforge-0.2.30 → processforge-0.2.38}/LICENSE +0 -0
  56. {processforge-0.2.30 → processforge-0.2.38}/MANIFEST.in +0 -0
  57. {processforge-0.2.30 → processforge-0.2.38}/setup.cfg +0 -0
  58. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/__init__.py +0 -0
  59. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/__main__.py +0 -0
  60. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/_schema.py +0 -0
  61. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/analysis/__init__.py +0 -0
  62. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/analysis/dof.py +0 -0
  63. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/__init__.py +0 -0
  64. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/backends/__init__.py +0 -0
  65. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/backends/base.py +0 -0
  66. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/backends/casadi_backend.py +0 -0
  67. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/backends/pyomo_backend.py +0 -0
  68. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/backends/scipy_backend.py +0 -0
  69. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/mixin.py +0 -0
  70. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/stream_var.py +0 -0
  71. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/units/__init__.py +0 -0
  72. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/units/flash_eo.py +0 -0
  73. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/units/heater_eo.py +0 -0
  74. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/units/pipes_eo.py +0 -0
  75. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/units/pump_eo.py +0 -0
  76. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/units/strainer_eo.py +0 -0
  77. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/eo/units/valve_eo.py +0 -0
  78. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/fmu/__init__.py +0 -0
  79. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/fmu/_fmi_vars.py +0 -0
  80. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/fmu/builder.py +0 -0
  81. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/fmu/slave_template.py +0 -0
  82. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/modelica/__init__.py +0 -0
  83. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/modelica/mo_writer.py +0 -0
  84. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/modelica/omc_runner.py +0 -0
  85. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/modelica/transpiler.py +0 -0
  86. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/modelica/unit_equations.py +0 -0
  87. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/pcl/__init__.py +0 -0
  88. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/pcl/compiler.py +0 -0
  89. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/pcl/namespace.py +0 -0
  90. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/provenance.py +0 -0
  91. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/base.py +0 -0
  92. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/base_jacobian_mixin.py +0 -0
  93. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/cantera_jacobian.py +0 -0
  94. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/cantera_provider.py +0 -0
  95. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/coolprop_provider.py +0 -0
  96. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/jacobian_contributor.py +0 -0
  97. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/modelica_jacobian.py +0 -0
  98. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/modelica_provider.py +0 -0
  99. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/providers/reference_state_registry.py +0 -0
  100. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/schemas/__init__.py +0 -0
  101. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/solver.py +0 -0
  102. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/thermo.py +0 -0
  103. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/provider_mixin.py +0 -0
  104. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/units/solver.py +0 -0
  105. {processforge-0.2.30/src/processforge/api → processforge-0.2.38/src/processforge/utils}/__init__.py +0 -0
  106. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/utils/flowsheet_diagram.py +0 -0
  107. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/utils/mermaid_diagram.py +0 -0
  108. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/utils/topology.py +0 -0
  109. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/utils/unit_consistency.py +0 -0
  110. {processforge-0.2.30 → processforge-0.2.38}/src/processforge/utils/validation.py +0 -0
  111. {processforge-0.2.30 → processforge-0.2.38}/src/processforge.egg-info/dependency_links.txt +0 -0
  112. {processforge-0.2.30 → processforge-0.2.38}/src/processforge.egg-info/top_level.txt +0 -0
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: processforge
3
+ Version: 0.2.38
4
+ Summary: A Python-based process simulation framework for chemical engineering applications.
5
+ Author-email: Processforge Team <team@processforge.dev>
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/urjanova/processforge
8
+ Project-URL: Repository, https://github.com/urjanova/processforge
9
+ Project-URL: Issues, https://github.com/urjanova/processforge/issues
10
+ Keywords: process,simulation,chemical,engineering,flowsheet
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Requires-Python: >=3.12
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: numpy>=2.0
23
+ Requires-Dist: pydantic>=2.0
24
+ Requires-Dist: scipy>=1.14
25
+ Requires-Dist: matplotlib>=3.9
26
+ Requires-Dist: loguru>=0.7
27
+ Requires-Dist: jsonschema>=4.20
28
+ Requires-Dist: graphviz>=0.20
29
+ Requires-Dist: pandas>=2.2
30
+ Requires-Dist: zarr>=3.0
31
+ Requires-Dist: coolprop>=7.2.0
32
+ Provides-Extra: eo
33
+ Requires-Dist: pyomo>=6.7; extra == "eo"
34
+ Provides-Extra: eo-casadi
35
+ Requires-Dist: pyomo>=6.7; extra == "eo-casadi"
36
+ Requires-Dist: casadi>=3.6; extra == "eo-casadi"
37
+ Provides-Extra: fmu
38
+ Requires-Dist: pythonfmu>=0.6; extra == "fmu"
39
+ Provides-Extra: modelica
40
+ Requires-Dist: OMPython>=4.0.0; extra == "modelica"
41
+ Requires-Dist: fmpy>=0.3; extra == "modelica"
42
+ Provides-Extra: cantera
43
+ Requires-Dist: cantera>=3.0; extra == "cantera"
44
+ Provides-Extra: coolprop
45
+ Requires-Dist: coolprop>=6.6; extra == "coolprop"
46
+ Provides-Extra: pcl
47
+ Requires-Dist: pint>=0.24; extra == "pcl"
48
+ Provides-Extra: dev
49
+ Requires-Dist: pytest>=7.0; extra == "dev"
50
+ Requires-Dist: black; extra == "dev"
51
+ Requires-Dist: flake8; extra == "dev"
52
+ Requires-Dist: build; extra == "dev"
53
+ Requires-Dist: twine; extra == "dev"
54
+ Provides-Extra: docs
55
+ Requires-Dist: sphinx; extra == "docs"
56
+ Requires-Dist: sphinx-rtd-theme; extra == "docs"
57
+ Dynamic: license-file
58
+
59
+ # Processforge
60
+
61
+ ![processforge-logo](images/processforge-logo.svg)
62
+
63
+ A lightweight Python framework for process simulation, coupling hydraulic, thermal, and reactor workflows.
64
+
65
+ ## Install
66
+
67
+ Install the `pf` command-line tool with [uv](https://docs.astral.sh/uv/):
68
+
69
+ ```bash
70
+ uv tool install processforge
71
+ ```
72
+
73
+ For CoolProp-backed units:
74
+
75
+ ```bash
76
+ uv tool install "processforge[coolprop]"
77
+ ```
78
+
79
+ Optional solver backends:
80
+
81
+ ```bash
82
+ uv tool install "processforge[eo]"
83
+ uv tool install "processforge[eo-casadi]"
84
+ uv tool install "processforge[modelica]"
85
+ ```
86
+
87
+ ## Quick start
88
+
89
+ 1. **Install the tool**
90
+
91
+ ```bash
92
+ uv tool install processforge
93
+ ```
94
+
95
+ 2. **Download an example flowsheet**
96
+
97
+ ```bash
98
+ curl -O https://raw.githubusercontent.com/urjanova/processforge/master/flowsheets/hydraulic-chain.json
99
+ ```
100
+
101
+ 3. **Initialize, plan, and apply**
102
+
103
+ ```bash
104
+ pf init
105
+ pf plan hydraulic-chain.json
106
+ pf apply hydraulic-chain.json
107
+ ```
108
+
109
+ `plan` validates the flowsheet (schema, DOF, units) without running the solver; `apply` solves it and stores a snapshot.
110
+
111
+ 4. **Look at the output**
112
+
113
+ `pf apply` writes results under `outputs/`:
114
+ - `*_results.zarr` — simulation results store
115
+ - `*_validation.xlsx` — validation report
116
+ - `*.pfstate/` — versioned snapshot store with a `latest` pointer
117
+
118
+ For flowsheets with Tank units (dynamic), use `pf run` instead of `pf apply` to solve with the SM solver.
119
+
120
+ ## Python API
121
+
122
+ ```python
123
+ from processforge import EOFlowsheet, validate_flowsheet
124
+ config = validate_flowsheet("flowsheets/hydraulic-chain.json")
125
+ fs = EOFlowsheet(config, backend="scipy")
126
+ results = fs.run()
127
+ ```
128
+
129
+ ## Usage and Docker
130
+ Processforge is also available as Docker images, and can be run in the cloud. See the [usage guide](docs/usage.md) for CLI commands, workflows, Docker, and cloud notes.
131
+
132
+ ## Flowsheets
133
+ The core of Processforge is the flowsheet JSON format, which defines materials, units, and recycle rules. See below for more information on the formats and example flowsheets.
134
+ - [docs/flowsheets.md](docs/flowsheets.md) : flowsheet JSON format, materials, units, and recycle rules
135
+ - [flowsheets/](flowsheets/) : example flowsheets shipped with the repo
136
+
137
+
138
+ ## License
139
+
140
+ BSD 3-Clause License
@@ -0,0 +1,82 @@
1
+ # Processforge
2
+
3
+ ![processforge-logo](images/processforge-logo.svg)
4
+
5
+ A lightweight Python framework for process simulation, coupling hydraulic, thermal, and reactor workflows.
6
+
7
+ ## Install
8
+
9
+ Install the `pf` command-line tool with [uv](https://docs.astral.sh/uv/):
10
+
11
+ ```bash
12
+ uv tool install processforge
13
+ ```
14
+
15
+ For CoolProp-backed units:
16
+
17
+ ```bash
18
+ uv tool install "processforge[coolprop]"
19
+ ```
20
+
21
+ Optional solver backends:
22
+
23
+ ```bash
24
+ uv tool install "processforge[eo]"
25
+ uv tool install "processforge[eo-casadi]"
26
+ uv tool install "processforge[modelica]"
27
+ ```
28
+
29
+ ## Quick start
30
+
31
+ 1. **Install the tool**
32
+
33
+ ```bash
34
+ uv tool install processforge
35
+ ```
36
+
37
+ 2. **Download an example flowsheet**
38
+
39
+ ```bash
40
+ curl -O https://raw.githubusercontent.com/urjanova/processforge/master/flowsheets/hydraulic-chain.json
41
+ ```
42
+
43
+ 3. **Initialize, plan, and apply**
44
+
45
+ ```bash
46
+ pf init
47
+ pf plan hydraulic-chain.json
48
+ pf apply hydraulic-chain.json
49
+ ```
50
+
51
+ `plan` validates the flowsheet (schema, DOF, units) without running the solver; `apply` solves it and stores a snapshot.
52
+
53
+ 4. **Look at the output**
54
+
55
+ `pf apply` writes results under `outputs/`:
56
+ - `*_results.zarr` — simulation results store
57
+ - `*_validation.xlsx` — validation report
58
+ - `*.pfstate/` — versioned snapshot store with a `latest` pointer
59
+
60
+ For flowsheets with Tank units (dynamic), use `pf run` instead of `pf apply` to solve with the SM solver.
61
+
62
+ ## Python API
63
+
64
+ ```python
65
+ from processforge import EOFlowsheet, validate_flowsheet
66
+ config = validate_flowsheet("flowsheets/hydraulic-chain.json")
67
+ fs = EOFlowsheet(config, backend="scipy")
68
+ results = fs.run()
69
+ ```
70
+
71
+ ## Usage and Docker
72
+ Processforge is also available as Docker images, and can be run in the cloud. See the [usage guide](docs/usage.md) for CLI commands, workflows, Docker, and cloud notes.
73
+
74
+ ## Flowsheets
75
+ The core of Processforge is the flowsheet JSON format, which defines materials, units, and recycle rules. See below for more information on the formats and example flowsheets.
76
+ - [docs/flowsheets.md](docs/flowsheets.md) : flowsheet JSON format, materials, units, and recycle rules
77
+ - [flowsheets/](flowsheets/) : example flowsheets shipped with the repo
78
+
79
+
80
+ ## License
81
+
82
+ BSD 3-Clause License
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "material_mixes": {
47
47
  "Benzene_Toluene_Mix": {
48
- "friendly_material_mix_id": 1,
48
+ "id": 1,
49
49
  "percent_type": "ao",
50
50
  "components": [
51
51
  {"name": "Benzene", "fraction": 0.5},
@@ -0,0 +1,70 @@
1
+ {
2
+ "metadata": {
3
+ "name": "FESTIM Hydrogen Transport — 1D Diffusion",
4
+ "description": "Simple 1D hydrogen diffusion through a slab. Fixed concentration BCs: c=1 on left, c=0 on right. D_0=1 m²/s, E_D=0 eV, T=300 K.",
5
+ "version": "1.0"
6
+ },
7
+ "providers": {
8
+ "festim": {
9
+ "type": "festim",
10
+ "url": "http://localhost:9002",
11
+ "output_dir": "festim"
12
+ }
13
+ },
14
+ "materials": {
15
+ "default": {
16
+ "id": 1,
17
+ "extra": {
18
+ "D_0": 1,
19
+ "E_D": 0.0
20
+ }
21
+ }
22
+ },
23
+ "streams": {},
24
+ "units": {
25
+ "festim_solver": {
26
+ "type": "SolverUnit",
27
+ "provider": "festim",
28
+ "sim_type": "hydrogen_transport",
29
+ "mesh": {
30
+ "vertices": [0.0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01]
31
+ },
32
+ "species": [
33
+ { "name": "H" }
34
+ ],
35
+ "subdomains": {
36
+ "volume": [
37
+ { "id": 1, "borders": [0.0, 0.01], "material": "default" }
38
+ ],
39
+ "surface": [
40
+ { "id": 2, "x": 0.0 },
41
+ { "id": 3, "x": 0.01 }
42
+ ]
43
+ },
44
+ "boundary_conditions": [
45
+ { "type": "fixed_concentration", "subdomain_id": 2, "species": "H", "value": 1 },
46
+ { "type": "fixed_concentration", "subdomain_id": 3, "species": "H", "value": 0 }
47
+ ],
48
+ "exports": [
49
+ { "type": "vtx_species", "field": "H", "filename": "hydrogen_concentration.bp", "times": "milestones" },
50
+ { "type": "profile_1d", "field": "H", "volume_id": 1, "times": "milestones" }
51
+ ],
52
+ "solver_config": {
53
+ "atol": 1e-10,
54
+ "rtol": 1e-10,
55
+ "final_time": 2,
56
+ "temperature": 300,
57
+ "stepsize": {
58
+ "initial_value": 0.05,
59
+ "growth_factor": 1.1,
60
+ "cutback_factor": 0.9,
61
+ "target_nb_iterations": 4,
62
+ "milestones": [0.05, 0.1, 0.2, 0.5, 1]
63
+ }
64
+ }
65
+ }
66
+ },
67
+ "simulation": {
68
+ "mode": "steady"
69
+ }
70
+ }
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "material_mixes": {
24
24
  "Water_Toluene_Mix": {
25
- "friendly_material_mix_id": 1,
25
+ "id": 1,
26
26
  "percent_type": "ao",
27
27
  "components": [
28
28
  {"name": "Water", "fraction": 0.8},
@@ -7,7 +7,8 @@
7
7
  "providers": {
8
8
  "openmc": {
9
9
  "type": "openmc",
10
- "output_dir": "outputs/openmc/msre_run",
10
+ "url": "http://localhost:9001",
11
+ "output_dir": "openmc/msre_run",
11
12
  "cross_sections": "${OPENMC_DATA_ROOT}/cross_sections/cross_sections.xml"
12
13
  }
13
14
  },
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "processforge"
7
- version = "0.2.30"
7
+ version = "0.2.38"
8
8
  description = "A Python-based process simulation framework for chemical engineering applications."
9
9
  readme = "README.md"
10
10
  license = "BSD-3-Clause"
11
11
  license-files = ["LICENSE"]
12
12
  requires-python = ">=3.12"
13
13
  authors = [
14
- {name = "Process Forge Team", email = "team@processforge.dev"},
14
+ {name = "Processforge Team", email = "team@processforge.dev"},
15
15
  ]
16
16
  classifiers = [
17
17
  "Development Status :: 3 - Alpha",
@@ -26,6 +26,7 @@ classifiers = [
26
26
  keywords = ["process", "simulation", "chemical", "engineering", "flowsheet"]
27
27
  dependencies = [
28
28
  "numpy>=2.0",
29
+ "pydantic>=2.0",
29
30
  "scipy>=1.14",
30
31
  "matplotlib>=3.9",
31
32
  "loguru>=0.7",
@@ -33,16 +34,10 @@ dependencies = [
33
34
  "graphviz>=0.20",
34
35
  "pandas>=2.2",
35
36
  "zarr>=3.0",
37
+ "coolprop>=7.2.0",
36
38
  ]
37
39
 
38
40
  [project.optional-dependencies]
39
- api = [
40
- "fastapi>=0.110",
41
- "uvicorn[standard]>=0.29",
42
- "boto3>=1.34",
43
- "s3fs>=2024.3",
44
- "pydantic>=2.0",
45
- ]
46
41
  eo = [
47
42
  "pyomo>=6.7",
48
43
  ]
@@ -86,7 +81,6 @@ Issues = "https://github.com/urjanova/processforge/issues"
86
81
  [project.scripts]
87
82
  processforge = "processforge.simulate:main"
88
83
  pf = "processforge.simulate:main"
89
- pf-serve = "processforge.api.serve:main"
90
84
 
91
85
  [tool.setuptools.packages.find]
92
86
  where = ["src"]
@@ -0,0 +1,47 @@
1
+ """Generate docker-compose.yml for containerized providers."""
2
+ from __future__ import annotations
3
+
4
+ import os
5
+
6
+ COMPOSE_FILENAME = "docker-compose.yml"
7
+ COMPOSE_HEADER = (
8
+ "# Auto-generated by pf init — do not edit manually.\n"
9
+ "# Re-generate: pf init <flowsheet.json>\n"
10
+ )
11
+
12
+
13
+ def _compose_path(pf_dir: str) -> str:
14
+ return os.path.join(pf_dir, COMPOSE_FILENAME)
15
+
16
+
17
+ def generate_compose(
18
+ pf_dir: str,
19
+ containerized_providers: dict[str, dict],
20
+ outputs_dir: str = "outputs",
21
+ ) -> None:
22
+ """Generate docker-compose.yml for providers that need Docker.
23
+
24
+ Args:
25
+ pf_dir: Path to .processforge/ directory.
26
+ containerized_providers: Dict of provider_name -> {"url": ..., "docker_image": ..., "port": ...}.
27
+ outputs_dir: Host directory to mount as /data in containers.
28
+ """
29
+ if not containerized_providers:
30
+ return
31
+
32
+ lines = [COMPOSE_HEADER, "services:"]
33
+ for name, info in containerized_providers.items():
34
+ image = info["docker_image"]
35
+ port = info.get("port") or 9000
36
+ lines.append(f" {name}:")
37
+ lines.append(f" image: {image}")
38
+ lines.append(f" ports:")
39
+ lines.append(f' - "{port}:{port}"')
40
+ lines.append(f" volumes:")
41
+ lines.append(f' - "${{PROCESSFORGE_OUTPUT_DIR:-{outputs_dir}}}:/data"')
42
+ lines.append("")
43
+
44
+ os.makedirs(pf_dir, exist_ok=True)
45
+ path = _compose_path(pf_dir)
46
+ with open(path, "w", encoding="utf-8") as f:
47
+ f.write("\n".join(lines))
@@ -2,10 +2,14 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  from copy import deepcopy
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  import numpy as np
7
8
  from loguru import logger
8
9
 
10
+ if TYPE_CHECKING:
11
+ from ..providers.manager import ProviderMap
12
+
9
13
  from .jacobian import GlobalJacobianManager
10
14
  from .solver import EOSolver
11
15
  from ..types import SnapshotState
@@ -43,7 +47,7 @@ class EOFlowsheet:
43
47
  or sim_cfg.get("default_backend", "scipy")
44
48
  )
45
49
  self._unit_objects: dict = {}
46
- self._provider_map: dict = {}
50
+ self._provider_map: ProviderMap | None = None
47
51
  self.solver_tol: float = 1e-6
48
52
  self.solver_max_iter: int = 50
49
53
 
@@ -141,55 +145,15 @@ class EOFlowsheet:
141
145
 
142
146
  return manager
143
147
 
144
- def _build_units(self, provider_map: dict | None = None) -> dict:
145
- """Instantiate unit objects using the same factory logic as Flowsheet."""
146
- from processforge.units.pump import Pump
147
- from processforge.units.valve import Valve
148
- from processforge.units.strainer import Strainer
149
- from processforge.units.pipes import Pipes
150
- from processforge.units.heater import Heater
151
- from processforge.units.flash import Flash
152
- from processforge.units.solver_unit import SolverUnit
153
-
154
- unit_types = {
155
- "Pump": (Pump, "kwargs"),
156
- "Valve": (Valve, "kwargs"),
157
- "Strainer": (Strainer, "kwargs"),
158
- "Pipes": (Pipes, "kwargs"),
159
- "Heater": (Heater, "params"),
160
- "Flash": (Flash, "params"),
161
- "SolverUnit": (SolverUnit, "kwargs"),
162
- }
163
-
164
- from processforge.providers.manager import get_unit_provider
165
- _pm = provider_map or {}
148
+ def _build_units(self, provider_map: ProviderMap | None = None) -> dict:
149
+ """Instantiate unit objects using the shared registry."""
150
+ from ..flowsheet import _build_unit, _merge_provider_types
151
+ _merge_provider_types(provider_map)
166
152
 
167
153
  units = {}
168
154
  for unit_name, unit_cfg in self.config["units"].items():
169
- unit_type = unit_cfg["type"]
170
- if unit_type not in unit_types:
171
- raise ValueError(f"Unknown unit type '{unit_type}'.")
172
- cls, style = unit_types[unit_type]
173
-
174
- exclude = {"type", "in", "out", "provider"}
175
- if unit_type == "Flash":
176
- # Flash uses out_vap / out_liq — exclude both from kwargs
177
- exclude |= {"out_vap", "out_liq"}
178
-
179
- params = {k: v for k, v in unit_cfg.items() if k not in exclude}
180
- if style == "params":
181
- # Heater / Flash use __init__(name, params_dict)
182
- unit = cls(unit_name, params)
183
- else:
184
- unit = cls(unit_name, **params)
185
-
186
- # Attach provider so EO residuals can route thermo calls.
187
- if _pm:
188
- unit._provider = get_unit_provider(_pm, unit_cfg)
189
-
190
- units[unit_name] = unit
191
- logger.info(f"Built unit '{unit_name}' ({unit_type})")
192
-
155
+ units[unit_name] = _build_unit(unit_name, unit_cfg, provider_map)
156
+ logger.info(f"Built unit '{unit_name}' ({unit_cfg['type']})")
193
157
  return units
194
158
 
195
159
  def _check_provider_backend_compat(self) -> None:
@@ -376,14 +376,17 @@ class GlobalJacobianManager:
376
376
  """
377
377
  Return column groups that can be perturbed simultaneously.
378
378
 
379
- Two columns can be grouped if they never appear together in the same
380
- residual block. Here we use the conservative grouping: one group per
381
- stream, where columns within the same stream block are perturbed together.
379
+ Each group contains a single column so that the finite-difference
380
+ Jacobian correctly captures the derivative of each variable
381
+ independently. Perturbing multiple variables in a stream block
382
+ simultaneously produces identical dF vectors for every column in
383
+ the group, which yields a rank-deficient Jacobian.
382
384
  """
383
385
  groups: list[list[int]] = []
384
386
  for sv in self._streams.values():
385
387
  o = sv.global_offset
386
- groups.append(list(range(o, o + sv.n_vars)))
388
+ for i in range(sv.n_vars):
389
+ groups.append([o + i])
387
390
  return groups
388
391
 
389
392
  @property
@@ -163,7 +163,6 @@ def solve_with_homotopy(
163
163
  )
164
164
 
165
165
  import numpy as np
166
- x_sol, converged, stats = solver.solve(manager, x0)
167
166
 
168
167
  if not isinstance(state, SnapshotState):
169
168
  x0 = np.array(state["x"])