processforge 0.2.10__tar.gz → 0.2.12__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.
Files changed (69) hide show
  1. {processforge-0.2.10/src/processforge.egg-info → processforge-0.2.12}/PKG-INFO +1 -1
  2. {processforge-0.2.10 → processforge-0.2.12}/pyproject.toml +1 -1
  3. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/flowsheet.py +8 -6
  4. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/schemas/flowsheet_schema.json +2 -1
  5. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/utils/validate_flowsheet.py +58 -58
  6. {processforge-0.2.10 → processforge-0.2.12/src/processforge.egg-info}/PKG-INFO +1 -1
  7. {processforge-0.2.10 → processforge-0.2.12}/LICENSE +0 -0
  8. {processforge-0.2.10 → processforge-0.2.12}/MANIFEST.in +0 -0
  9. {processforge-0.2.10 → processforge-0.2.12}/README.md +0 -0
  10. {processforge-0.2.10 → processforge-0.2.12}/flowsheets/archive/example_dynamic_hybrid.json +0 -0
  11. {processforge-0.2.10 → processforge-0.2.12}/flowsheets/archive/example_dynamic_tank.json +0 -0
  12. {processforge-0.2.10 → processforge-0.2.12}/flowsheets/archive/example_flash.json +0 -0
  13. {processforge-0.2.10 → processforge-0.2.12}/flowsheets/archive/hydraulic_chain.json +0 -0
  14. {processforge-0.2.10 → processforge-0.2.12}/flowsheets/closed-loop-chain.json +0 -0
  15. {processforge-0.2.10 → processforge-0.2.12}/flowsheets/hydraulic-chain.json +0 -0
  16. {processforge-0.2.10 → processforge-0.2.12}/setup.cfg +0 -0
  17. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/__init__.py +0 -0
  18. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/_schema.py +0 -0
  19. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/__init__.py +0 -0
  20. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/backends/__init__.py +0 -0
  21. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/backends/base.py +0 -0
  22. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/backends/casadi_backend.py +0 -0
  23. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/backends/pyomo_backend.py +0 -0
  24. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/backends/scipy_backend.py +0 -0
  25. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/flowsheet.py +0 -0
  26. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/jacobian.py +0 -0
  27. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/mixin.py +0 -0
  28. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/solver.py +0 -0
  29. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/stream_var.py +0 -0
  30. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/units/__init__.py +0 -0
  31. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/units/flash_eo.py +0 -0
  32. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/units/heater_eo.py +0 -0
  33. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/units/pipes_eo.py +0 -0
  34. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/units/pump_eo.py +0 -0
  35. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/units/strainer_eo.py +0 -0
  36. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/eo/units/valve_eo.py +0 -0
  37. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/fmu/__init__.py +0 -0
  38. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/fmu/_fmi_vars.py +0 -0
  39. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/fmu/builder.py +0 -0
  40. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/fmu/slave_template.py +0 -0
  41. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/modelica/__init__.py +0 -0
  42. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/modelica/mo_writer.py +0 -0
  43. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/modelica/omc_runner.py +0 -0
  44. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/modelica/transpiler.py +0 -0
  45. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/modelica/unit_equations.py +0 -0
  46. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/provenance.py +0 -0
  47. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/result.py +0 -0
  48. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/schemas/__init__.py +0 -0
  49. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/simulate.py +0 -0
  50. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/solver.py +0 -0
  51. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/thermo.py +0 -0
  52. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/units/__init__.py +0 -0
  53. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/units/flash.py +0 -0
  54. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/units/heater.py +0 -0
  55. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/units/pipes.py +0 -0
  56. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/units/pump.py +0 -0
  57. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/units/solver.py +0 -0
  58. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/units/strainer.py +0 -0
  59. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/units/tank.py +0 -0
  60. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/units/valve.py +0 -0
  61. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/utils/__init__.py +0 -0
  62. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/utils/flowsheet_diagram.py +0 -0
  63. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/utils/validation.py +0 -0
  64. {processforge-0.2.10 → processforge-0.2.12}/src/processforge/validate.py +0 -0
  65. {processforge-0.2.10 → processforge-0.2.12}/src/processforge.egg-info/SOURCES.txt +0 -0
  66. {processforge-0.2.10 → processforge-0.2.12}/src/processforge.egg-info/dependency_links.txt +0 -0
  67. {processforge-0.2.10 → processforge-0.2.12}/src/processforge.egg-info/entry_points.txt +0 -0
  68. {processforge-0.2.10 → processforge-0.2.12}/src/processforge.egg-info/requires.txt +0 -0
  69. {processforge-0.2.10 → processforge-0.2.12}/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.10
3
+ Version: 0.2.12
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "processforge"
7
- version = "0.2.10"
7
+ version = "0.2.12"
8
8
  description = "A Python-based process simulation framework for chemical engineering applications."
9
9
  readme = "README.md"
10
10
  license = "BSD-3-Clause"
@@ -85,14 +85,16 @@ class Flowsheet:
85
85
  if not unit_class:
86
86
  logger.error(f"Unknown unit type: {unit_type}")
87
87
  raise ValueError(f"Unknown unit type: {unit_type}")
88
- self.units[unit_name] = unit_class(
88
+ _UNIT_META_KEYS = {"type", "in", "out", "material", "material_mix"}
89
+ unit = unit_class(
89
90
  unit_name,
90
- **{
91
- k: v
92
- for k, v in unit_config.items()
93
- if k not in ["type", "in", "out"]
94
- },
91
+ **{k: v for k, v in unit_config.items() if k not in _UNIT_META_KEYS},
95
92
  )
93
+ if "material" in unit_config:
94
+ unit.material = unit_config["material"]
95
+ if "material_mix" in unit_config:
96
+ unit.material_mix = unit_config["material_mix"]
97
+ self.units[unit_name] = unit
96
98
  logger.info(f"Built unit {unit_name} of type {unit_type}")
97
99
 
98
100
  def _get_unit_inlets(self, unit_name):
@@ -157,7 +157,8 @@
157
157
  "required": [
158
158
  "type",
159
159
  "in",
160
- "out"
160
+ "out",
161
+ "material"
161
162
  ],
162
163
  "properties": {
163
164
  "type": {
@@ -154,82 +154,82 @@ def _check_pipe_linkage(config):
154
154
 
155
155
  def _check_material_semantics(config):
156
156
  """
157
- Validate OpenMC-compatible material definitions when present. No-op if absent.
157
+ Validate material definitions and enforce that every unit has a valid material.
158
158
 
159
159
  Checks:
160
- 1. density_units values are valid OpenMC units (when present).
160
+ 1. density_units values are valid OpenMC units (when materials section is present).
161
161
  2. friendly_material_id values are unique across all materials.
162
162
  3. material_mixes component names resolve to entries in materials.
163
163
  4. material_mixes fraction sum equals 1.0 (only when all fractions are provided).
164
164
  5. Stream z-keys resolve to defined materials (when materials section is present).
165
- 6. Unit material field references a valid friendly_material_id (when present).
165
+ 6. Every unit must have a material field referencing a valid friendly_material_id.
166
166
  """
167
- materials = config.get("materials")
168
- if not materials:
169
- return True
170
-
171
- material_mixes = config.get("material_mixes", {})
172
- all_material_names = set(materials.keys())
167
+ materials = config.get("materials", {})
173
168
  valid_ids = {mat_def["friendly_material_id"] for mat_def in materials.values()}
174
169
 
175
- # 1. density_units validity — only checked when the field is present
176
- for mat_name, mat_def in materials.items():
177
- units = mat_def.get("density_units")
178
- if units is not None and units not in _VALID_DENSITY_UNITS:
179
- raise ValueError(
180
- f"❌ Material '{mat_name}' has invalid density_units '{units}'. "
181
- f"Must be one of: {sorted(_VALID_DENSITY_UNITS)}"
182
- )
170
+ if materials:
171
+ all_material_names = set(materials.keys())
172
+ material_mixes = config.get("material_mixes", {})
183
173
 
184
- # 2. friendly_material_id uniqueness
185
- ids = [mat_def["friendly_material_id"] for mat_def in materials.values()]
186
- if len(ids) != len(set(ids)):
187
- seen, dupes = set(), set()
188
- for i in ids:
189
- if i in seen:
190
- dupes.add(i)
191
- seen.add(i)
192
- raise ValueError(
193
- f"❌ Duplicate friendly_material_id values found: {sorted(dupes)}"
194
- )
195
-
196
- # 3 & 4. Mix component name resolution and fraction sum
197
- for mix_name, mix_def in material_mixes.items():
198
- fractions = []
199
- for component in mix_def.get("components", []):
200
- comp_name = component["name"]
201
- if comp_name not in all_material_names:
174
+ # 1. density_units validity — only checked when the field is present
175
+ for mat_name, mat_def in materials.items():
176
+ units = mat_def.get("density_units")
177
+ if units is not None and units not in _VALID_DENSITY_UNITS:
202
178
  raise ValueError(
203
- f"❌ material_mixes['{mix_name}'] references '{comp_name}', "
204
- f"which is not defined in materials."
179
+ f"❌ Material '{mat_name}' has invalid density_units '{units}'. "
180
+ f"Must be one of: {sorted(_VALID_DENSITY_UNITS)}"
205
181
  )
206
- if "fraction" in component:
207
- fractions.append(component["fraction"])
208
182
 
209
- components = mix_def.get("components", [])
210
- if len(fractions) == len(components) and fractions:
211
- frac_sum = sum(fractions)
212
- if abs(frac_sum - 1.0) > 1e-6:
213
- raise ValueError(
214
- f"❌ material_mixes['{mix_name}'] component fractions sum to "
215
- f"{frac_sum:.8f}, expected 1.0."
216
- )
217
-
218
- # 5. Stream z-keys resolve to materials
219
- for stream_name, stream_def in config.get("streams", {}).items():
220
- for comp_name in stream_def.get("z", {}):
221
- if comp_name not in all_material_names:
222
- raise ValueError(
223
- f"❌ Stream '{stream_name}' z-key '{comp_name}' is not defined in materials."
224
- )
183
+ # 2. friendly_material_id uniqueness
184
+ ids = [mat_def["friendly_material_id"] for mat_def in materials.values()]
185
+ if len(ids) != len(set(ids)):
186
+ seen, dupes = set(), set()
187
+ for i in ids:
188
+ if i in seen:
189
+ dupes.add(i)
190
+ seen.add(i)
191
+ raise ValueError(
192
+ f"❌ Duplicate friendly_material_id values found: {sorted(dupes)}"
193
+ )
225
194
 
226
- # 6. Unit material references resolve to a valid friendly_material_id
195
+ # 3 & 4. Mix component name resolution and fraction sum
196
+ for mix_name, mix_def in material_mixes.items():
197
+ fractions = []
198
+ for component in mix_def.get("components", []):
199
+ comp_name = component["name"]
200
+ if comp_name not in all_material_names:
201
+ raise ValueError(
202
+ f"❌ material_mixes['{mix_name}'] references '{comp_name}', "
203
+ f"which is not defined in materials."
204
+ )
205
+ if "fraction" in component:
206
+ fractions.append(component["fraction"])
207
+
208
+ components = mix_def.get("components", [])
209
+ if len(fractions) == len(components) and fractions:
210
+ frac_sum = sum(fractions)
211
+ if abs(frac_sum - 1.0) > 1e-6:
212
+ raise ValueError(
213
+ f"❌ material_mixes['{mix_name}'] component fractions sum to "
214
+ f"{frac_sum:.8f}, expected 1.0."
215
+ )
216
+
217
+ # 5. Stream z-keys resolve to materials
218
+ for stream_name, stream_def in config.get("streams", {}).items():
219
+ for comp_name in stream_def.get("z", {}):
220
+ if comp_name not in all_material_names:
221
+ raise ValueError(
222
+ f"❌ Stream '{stream_name}' z-key '{comp_name}' is not defined in materials."
223
+ )
224
+
225
+ # 6. Every unit must reference a valid friendly_material_id
226
+ hint = " (no materials section defined)" if not materials else ""
227
227
  for unit_name, unit_def in config.get("units", {}).items():
228
228
  mat_id = unit_def.get("material")
229
- if mat_id is not None and mat_id not in valid_ids:
229
+ if mat_id not in valid_ids:
230
230
  raise ValueError(
231
231
  f"❌ Unit '{unit_name}' references material id {mat_id}, "
232
- f"which does not match any friendly_material_id in materials."
232
+ f"which does not match any friendly_material_id in materials{hint}."
233
233
  )
234
234
 
235
235
  return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: processforge
3
- Version: 0.2.10
3
+ Version: 0.2.12
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
File without changes
File without changes
File without changes
File without changes