processforge 0.3.14__tar.gz → 0.3.16__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.
- {processforge-0.3.14/src/processforge.egg-info → processforge-0.3.16}/PKG-INFO +1 -1
- processforge-0.3.16/flowsheets/coupled/msre_coupled.json +172 -0
- {processforge-0.3.14 → processforge-0.3.16}/flowsheets/openmc/msre_eigenvalue.json +20 -28
- {processforge-0.3.14 → processforge-0.3.16}/pyproject.toml +1 -1
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/__init__.py +1 -1
- processforge-0.3.16/src/processforge/coupling.py +183 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/flowsheet.py +139 -29
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/container_client.py +1 -1
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/festim_provider.py +1 -4
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/openmc_provider.py +310 -49
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/schemas/festim/festim_model.py +0 -3
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/schemas/openmc/openmc_model.py +116 -36
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/types.py +6 -4
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/base.py +11 -2
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/solver_unit.py +32 -3
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/utils/validate_flowsheet.py +116 -14
- {processforge-0.3.14 → processforge-0.3.16/src/processforge.egg-info}/PKG-INFO +1 -1
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge.egg-info/SOURCES.txt +3 -0
- processforge-0.3.16/tests/test_coupling.py +251 -0
- {processforge-0.3.14 → processforge-0.3.16}/tests/test_festim_provider.py +0 -2
- {processforge-0.3.14 → processforge-0.3.16}/tests/test_openmc_provider.py +170 -35
- {processforge-0.3.14 → processforge-0.3.16}/tests/test_types.py +4 -4
- {processforge-0.3.14 → processforge-0.3.16}/LICENSE +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/MANIFEST.in +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/README.md +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/flowsheets/closed-loop-chain.json +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/flowsheets/custom/crimson/MUWS_HB.json +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/flowsheets/custom/simple_hyrdaulic_scheme.json +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/flowsheets/festim/hydrogen_transport_1d.json +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/flowsheets/festim/tds_tungsten.json +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/flowsheets/hydraulic-chain.json +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/setup.cfg +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/__main__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/_schema.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/analysis/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/analysis/dof.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/api/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/api/serve.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/apply.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/common.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/diagram.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/display.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/export_fmu.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/export_modelica.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/init.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/plan.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/run.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/cli/validate.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/compose.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/backends/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/backends/base.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/backends/casadi_backend.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/backends/pyomo_backend.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/backends/scipy_backend.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/flowsheet.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/jacobian.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/mixin.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/solver.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/stream_var.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/units/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/units/flash_eo.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/units/heater_eo.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/units/pipes_eo.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/units/pump_eo.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/units/strainer_eo.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/eo/units/valve_eo.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/fmu/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/fmu/_fmi_vars.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/fmu/builder.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/fmu/slave_template.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/lock.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/modelica/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/modelica/mo_writer.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/modelica/omc_runner.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/modelica/transpiler.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/modelica/unit_equations.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/output_collector.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/pcl/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/pcl/compiler.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/pcl/namespace.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/persistence/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/persistence/archive.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/persistence/artifact_store.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/provenance.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/base.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/base_jacobian_mixin.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/cantera_jacobian.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/cantera_provider.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/coolprop_provider.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/jacobian_contributor.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/manager.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/modelica_jacobian.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/modelica_provider.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/reference_state_registry.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/providers/registry.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/quantity.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/result.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/result_schema.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/schemas/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/schemas/flowsheet_schema.json +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/simulate.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/solver.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/state.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/thermo.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/cstr.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/flash.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/heater.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/pfr.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/pipes.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/pump.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/registry.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/strainer.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/tank.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/units/valve.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/utils/__init__.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/utils/flowsheet_diagram.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/utils/mermaid_diagram.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/utils/s3_upload.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/utils/topology.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/utils/unit_consistency.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge/utils/validation.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge.egg-info/dependency_links.txt +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge.egg-info/entry_points.txt +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge.egg-info/requires.txt +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/src/processforge.egg-info/top_level.txt +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/tests/test_cli.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/tests/test_festim_schema.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/tests/test_init.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/tests/test_providers.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/tests/test_s3_upload.py +0 -0
- {processforge-0.3.14 → processforge-0.3.16}/tests/test_state.py +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
{
|
|
2
|
+
"metadata": {
|
|
3
|
+
"name": "MSRE coupled neutronics + thermal (CoolProp thermo source)",
|
|
4
|
+
"description": "Demonstrates cross-engine parameter coupling using the per-unit 'inputs' block. A CoolProp-backed heater produces the 'coolant' stream; its temperature feeds both the OpenMC reactor material temperature and the FESTIM thermal model. The OpenMC reactor's fission power then drives a second OpenMC fixed-source unit, exercising the iterative coupling resolver (units are resolved in topological order and converged over iterations).",
|
|
5
|
+
"version": "1.0"
|
|
6
|
+
},
|
|
7
|
+
"providers": {
|
|
8
|
+
"openmc": {
|
|
9
|
+
"type": "openmc",
|
|
10
|
+
"url": "http://localhost:9001",
|
|
11
|
+
"output_dir": "openmc/msre_coupled_run",
|
|
12
|
+
"cross_sections": "${OPENMC_DATA_ROOT}/cross_sections/cross_sections.xml"
|
|
13
|
+
},
|
|
14
|
+
"festim": {
|
|
15
|
+
"type": "festim",
|
|
16
|
+
"url": "http://localhost:9002",
|
|
17
|
+
"output_dir": "festim/msre_coupled_run"
|
|
18
|
+
},
|
|
19
|
+
"coolprop": {
|
|
20
|
+
"type": "coolprop"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"materials": {
|
|
24
|
+
"graphite": {
|
|
25
|
+
"id": 1,
|
|
26
|
+
"density": 2.26,
|
|
27
|
+
"density_units": "g/cm3",
|
|
28
|
+
"temperature": 300.0,
|
|
29
|
+
"elements": [{ "element": "C", "percent": 1.0, "percent_type": "ao" }]
|
|
30
|
+
},
|
|
31
|
+
"inconel": {
|
|
32
|
+
"id": 4,
|
|
33
|
+
"density": 8.9,
|
|
34
|
+
"density_units": "g/cm3",
|
|
35
|
+
"temperature": 300.0,
|
|
36
|
+
"elements": [
|
|
37
|
+
{ "element": "Ni", "percent": 0.72, "percent_type": "ao" },
|
|
38
|
+
{ "element": "Cr", "percent": 0.20, "percent_type": "ao" },
|
|
39
|
+
{ "element": "Fe", "percent": 0.08, "percent_type": "ao" }
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"salt": {
|
|
43
|
+
"id": 3,
|
|
44
|
+
"density": 2.2,
|
|
45
|
+
"density_units": "g/cm3",
|
|
46
|
+
"temperature": 300.0,
|
|
47
|
+
"depletable": true,
|
|
48
|
+
"nuclides": [
|
|
49
|
+
{ "name": "Li7", "percent": 0.335000, "percent_type": "ao" },
|
|
50
|
+
{ "name": "U235", "percent": 0.000527, "percent_type": "ao" },
|
|
51
|
+
{ "name": "U238", "percent": 0.001053, "percent_type": "ao" }
|
|
52
|
+
],
|
|
53
|
+
"elements": [
|
|
54
|
+
{ "element": "F", "percent": 0.534653, "percent_type": "ao" },
|
|
55
|
+
{ "element": "Be", "percent": 0.076667, "percent_type": "ao" },
|
|
56
|
+
{ "element": "Zr", "percent": 0.010000, "percent_type": "ao" }
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"tungsten": {
|
|
60
|
+
"id": 6,
|
|
61
|
+
"extra": { "D_0": 1, "E_D": 0.0 }
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"streams": {
|
|
65
|
+
"feed": {
|
|
66
|
+
"T": 900.0,
|
|
67
|
+
"P": 101325.0,
|
|
68
|
+
"flowrate": 1.0,
|
|
69
|
+
"z": { "salt": 1.0 }
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"units": {
|
|
73
|
+
"coolant_heater": {
|
|
74
|
+
"type": "Heater",
|
|
75
|
+
"provider": "coolprop",
|
|
76
|
+
"material": 1,
|
|
77
|
+
"in": "feed",
|
|
78
|
+
"out": "coolant",
|
|
79
|
+
"solver_config": { "delta_T": 0.0 }
|
|
80
|
+
},
|
|
81
|
+
"openmc_reactor": {
|
|
82
|
+
"type": "SolverUnit",
|
|
83
|
+
"provider": "openmc",
|
|
84
|
+
"sim_type": "eigenvalue_reactor",
|
|
85
|
+
"material": 3,
|
|
86
|
+
"solver_config": {
|
|
87
|
+
"batches": 20,
|
|
88
|
+
"inactive": 5,
|
|
89
|
+
"particles": 20000
|
|
90
|
+
},
|
|
91
|
+
"geometry_config": {
|
|
92
|
+
"type": "reactor_core",
|
|
93
|
+
"core_radius": 72.5,
|
|
94
|
+
"core_height": 160.0,
|
|
95
|
+
"reflector_thickness": 50.0,
|
|
96
|
+
"core_material": "salt",
|
|
97
|
+
"reflector_material": "graphite",
|
|
98
|
+
"vessel_material": "inconel",
|
|
99
|
+
"source_point": { "xyz": [0.0, 0.0, 0.0] }
|
|
100
|
+
},
|
|
101
|
+
"inputs": {
|
|
102
|
+
"solver_config.temperature_default": { "ref": "coolant.T", "as_unit": "K" }
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"thermal": {
|
|
106
|
+
"type": "SolverUnit",
|
|
107
|
+
"provider": "festim",
|
|
108
|
+
"sim_type": "hydrogen_transport_tds",
|
|
109
|
+
"material": 6,
|
|
110
|
+
"solver_config": {
|
|
111
|
+
"mesh": {
|
|
112
|
+
"vertices": [0.0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01]
|
|
113
|
+
},
|
|
114
|
+
"subdomains": {
|
|
115
|
+
"volume": [
|
|
116
|
+
{ "id": 1, "borders": [0.0, 0.01], "material": "tungsten" }
|
|
117
|
+
],
|
|
118
|
+
"surface": [
|
|
119
|
+
{ "id": 2, "x": 0.0 },
|
|
120
|
+
{ "id": 3, "x": 0.01 }
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
"species": [
|
|
124
|
+
{ "name": "H", "mobile": true }
|
|
125
|
+
],
|
|
126
|
+
"boundary_conditions": [
|
|
127
|
+
{ "type": "fixed_concentration", "subdomain": 2, "species": "H", "value": 1 },
|
|
128
|
+
{ "type": "fixed_concentration", "subdomain": 3, "species": "H", "value": 0 }
|
|
129
|
+
],
|
|
130
|
+
"exports": [
|
|
131
|
+
{ "type": "profile_1d", "field": "H", "volume": 1, "times": [0.05, 0.1, 0.2, 0.5, 1] }
|
|
132
|
+
],
|
|
133
|
+
"atol": 1e-10,
|
|
134
|
+
"rtol": 1e-10,
|
|
135
|
+
"final_time": 2,
|
|
136
|
+
"temperature": 300,
|
|
137
|
+
"stepsize": {
|
|
138
|
+
"initial_value": 0.05,
|
|
139
|
+
"growth_factor": 1.1,
|
|
140
|
+
"cutback_factor": 0.9,
|
|
141
|
+
"target_nb_iterations": 4,
|
|
142
|
+
"milestones": [0.05, 0.1, 0.2, 0.5, 1]
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"inputs": {
|
|
146
|
+
"solver_config.temperature": { "ref": "coolant.T", "as_unit": "K" }
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
"openmc_source": {
|
|
150
|
+
"type": "SolverUnit",
|
|
151
|
+
"provider": "openmc",
|
|
152
|
+
"sim_type": "fixed_source_point",
|
|
153
|
+
"material": 3,
|
|
154
|
+
"solver_config": {
|
|
155
|
+
"batches": 20,
|
|
156
|
+
"inactive": 5,
|
|
157
|
+
"particles": 20000
|
|
158
|
+
},
|
|
159
|
+
"geometry_config": {
|
|
160
|
+
"source_point": { "xyz": [0.0, 0.0, 0.0] },
|
|
161
|
+
"sphere_radius": 200.0,
|
|
162
|
+
"sphere_material": "salt"
|
|
163
|
+
},
|
|
164
|
+
"inputs": {
|
|
165
|
+
"solver_config.source_strength": { "ref": "openmc_reactor.power", "as_unit": "W" }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"simulation": {
|
|
170
|
+
"mode": "steady"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"metadata": {
|
|
3
|
-
"name": "MSRE Eigenvalue —
|
|
4
|
-
"description": "Molten Salt Reactor Experiment criticality calculation
|
|
5
|
-
"version": "1.
|
|
3
|
+
"name": "MSRE Eigenvalue — approximate reactor geometry",
|
|
4
|
+
"description": "Molten Salt Reactor Experiment criticality calculation using an approximate cylindrical reactor-core geometry (salt core, graphite reflector, inconel vessel, helium gap, inor structure). Uses all 5 declared materials. Fission source at reactor centre.",
|
|
5
|
+
"version": "1.4"
|
|
6
6
|
},
|
|
7
7
|
"providers": {
|
|
8
8
|
"openmc": {
|
|
@@ -78,34 +78,26 @@
|
|
|
78
78
|
"type": "SolverUnit",
|
|
79
79
|
"provider": "openmc",
|
|
80
80
|
"material": 3,
|
|
81
|
-
"sim_type": "
|
|
81
|
+
"sim_type": "eigenvalue_reactor",
|
|
82
82
|
"solver_config": {
|
|
83
83
|
"batches": 20,
|
|
84
84
|
"inactive": 5,
|
|
85
|
-
"particles": 20000
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
"tally_id": 2,
|
|
102
|
-
"name": "flux2",
|
|
103
|
-
"lower_left": [-175, -10, -50],
|
|
104
|
-
"upper_right": [ 175, 10, 400],
|
|
105
|
-
"dimension": [400, 1, 400],
|
|
106
|
-
"scores": ["flux", "fission"]
|
|
107
|
-
}
|
|
108
|
-
]
|
|
85
|
+
"particles": 20000
|
|
86
|
+
},
|
|
87
|
+
"geometry_config": {
|
|
88
|
+
"type": "reactor_core",
|
|
89
|
+
"core_radius": 72.5,
|
|
90
|
+
"core_height": 160.0,
|
|
91
|
+
"reflector_thickness": 50.0,
|
|
92
|
+
"vessel_thickness": 5.0,
|
|
93
|
+
"gap_thickness": 3.0,
|
|
94
|
+
"structure_thickness": 10.0,
|
|
95
|
+
"core_material": "salt",
|
|
96
|
+
"reflector_material": "graphite",
|
|
97
|
+
"vessel_material": "inconel",
|
|
98
|
+
"gap_material": "helium",
|
|
99
|
+
"structure_material": "inor",
|
|
100
|
+
"source_point": {"xyz": [0.0, 0.0, 0.0]}
|
|
109
101
|
}
|
|
110
102
|
}
|
|
111
103
|
},
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "processforge"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.16"
|
|
8
8
|
description = "A Python-based process simulation framework for chemical engineering applications."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "BSD-3-Clause"
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Multi-physics coupling resolver for Processforge flowsheets.
|
|
2
|
+
|
|
3
|
+
This module implements *parameter-reference coupling* between heterogeneous
|
|
4
|
+
solver units (OpenMC neutronics, FESTIM thermal, CoolProp thermo, …). Each
|
|
5
|
+
solver unit may declare an ``inputs`` block mapping a dotted configuration
|
|
6
|
+
path to a reference to another unit's (or stream's) output field::
|
|
7
|
+
|
|
8
|
+
"inputs": {
|
|
9
|
+
"solver_config.heat_source": {"ref": "openmc_solver.power", "as_unit": "W"},
|
|
10
|
+
"solver_config.temperature": {"ref": "thermal.temperature", "reduce": "mean", "as_unit": "K"}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
A single shared :class:`ParameterStore` collects every unit/stream output as a
|
|
14
|
+
unit-bearing :class:`~processforge.quantity.Quantity` (the same ``Quantity``
|
|
15
|
+
type every engine already emits — see Phase 5A). The :class:`CouplingResolver`
|
|
16
|
+
then, for each consumer unit and each declared input:
|
|
17
|
+
|
|
18
|
+
1. looks the referenced ``<unit>.<field>`` quantity up in the store,
|
|
19
|
+
2. reduces array-valued fields to a scalar (``mean`` / ``sum`` / ``max`` /
|
|
20
|
+
``min`` — the natural choice for uniform coupling),
|
|
21
|
+
3. converts units through the process-wide ``pint`` registry, and
|
|
22
|
+
4. injects the bare magnitude into the consumer's config at the dotted path.
|
|
23
|
+
|
|
24
|
+
Because solver units run in topological order, a single forward pass resolves
|
|
25
|
+
acyclic couplings; cyclic couplings (e.g. neutronics power ↔ thermal
|
|
26
|
+
temperature) converge via the iterative loop in :mod:`processforge.flowsheet`.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import re
|
|
32
|
+
from typing import Any, Optional
|
|
33
|
+
|
|
34
|
+
from loguru import logger
|
|
35
|
+
|
|
36
|
+
from .quantity import Quantity, ureg
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
"CouplingError",
|
|
40
|
+
"ParameterStore",
|
|
41
|
+
"CouplingResolver",
|
|
42
|
+
"deep_merge",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class CouplingError(ValueError):
|
|
47
|
+
"""Raised when a coupling reference cannot be resolved."""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_REF_RE = re.compile(r"^(?P<src>[A-Za-z0-9_]+)\.(?P<field>[A-Za-z0-9_]+)$")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _reduce_value(value: Any, mode: str) -> float:
|
|
54
|
+
"""Collapse an (optionally array) value to a scalar for uniform coupling."""
|
|
55
|
+
if isinstance(value, (list, tuple)):
|
|
56
|
+
arr = [float(x) for x in value]
|
|
57
|
+
if not arr:
|
|
58
|
+
return 0.0
|
|
59
|
+
if mode == "sum":
|
|
60
|
+
return sum(arr)
|
|
61
|
+
if mode == "max":
|
|
62
|
+
return max(arr)
|
|
63
|
+
if mode == "min":
|
|
64
|
+
return min(arr)
|
|
65
|
+
return sum(arr) / len(arr)
|
|
66
|
+
if value is None:
|
|
67
|
+
return 0.0
|
|
68
|
+
return float(value)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _convert(scalar: float, from_unit: str, to_unit: Optional[str]) -> float:
|
|
72
|
+
"""Convert *scalar* from *from_unit* to *to_unit* via the shared registry."""
|
|
73
|
+
if not to_unit or not from_unit:
|
|
74
|
+
return float(scalar)
|
|
75
|
+
try:
|
|
76
|
+
return float(ureg.Quantity(float(scalar), from_unit).to(to_unit).magnitude)
|
|
77
|
+
except Exception as exc: # noqa: BLE001
|
|
78
|
+
logger.warning(
|
|
79
|
+
f"Coupling unit conversion {from_unit} -> {to_unit} failed ({exc}); "
|
|
80
|
+
f"using raw magnitude {scalar}."
|
|
81
|
+
)
|
|
82
|
+
return float(scalar)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _deep_set(d: dict, dotted_path: str, value: Any) -> None:
|
|
86
|
+
"""Set *value* at *dotted_path* inside nested dict *d*, creating maps."""
|
|
87
|
+
parts = dotted_path.split(".")
|
|
88
|
+
cur = d
|
|
89
|
+
for p in parts[:-1]:
|
|
90
|
+
nxt = cur.get(p)
|
|
91
|
+
if not isinstance(nxt, dict):
|
|
92
|
+
nxt = {}
|
|
93
|
+
cur[p] = nxt
|
|
94
|
+
cur = nxt
|
|
95
|
+
cur[parts[-1]] = value
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def deep_merge(base: dict, overrides: dict) -> dict:
|
|
99
|
+
"""Recursively merge *overrides* into a copy of *base*."""
|
|
100
|
+
out = dict(base)
|
|
101
|
+
for k, v in (overrides or {}).items():
|
|
102
|
+
if isinstance(v, dict) and isinstance(out.get(k), dict):
|
|
103
|
+
out[k] = deep_merge(out[k], v)
|
|
104
|
+
else:
|
|
105
|
+
out[k] = v
|
|
106
|
+
return out
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class ParameterStore:
|
|
110
|
+
"""Registry of unit/stream output quantities, keyed by ``<src>.<field>``."""
|
|
111
|
+
|
|
112
|
+
def __init__(self) -> None:
|
|
113
|
+
self._quantities: dict[str, Quantity] = {}
|
|
114
|
+
|
|
115
|
+
def register(self, src: str, field: str, quantity: Quantity) -> None:
|
|
116
|
+
self._quantities[f"{src}.{field}"] = quantity
|
|
117
|
+
|
|
118
|
+
def register_unit(self, unit_name: str, engine_output: Any) -> None:
|
|
119
|
+
"""Register every field of an :class:`EngineOutput`."""
|
|
120
|
+
for field in getattr(engine_output, "fields", []) or []:
|
|
121
|
+
self.register(unit_name, field.name, field.quantity)
|
|
122
|
+
|
|
123
|
+
def register_stream(
|
|
124
|
+
self,
|
|
125
|
+
stream_name: str,
|
|
126
|
+
stream_dict: dict,
|
|
127
|
+
thermo_fields: Optional[dict] = None,
|
|
128
|
+
) -> None:
|
|
129
|
+
"""Register stream scalars (T in K, P in Pa) and any thermo fields."""
|
|
130
|
+
if "T" in stream_dict:
|
|
131
|
+
self.register(
|
|
132
|
+
stream_name, "T", Quantity(value=float(stream_dict["T"]), unit="K")
|
|
133
|
+
)
|
|
134
|
+
if "P" in stream_dict:
|
|
135
|
+
self.register(
|
|
136
|
+
stream_name, "P", Quantity(value=float(stream_dict["P"]), unit="Pa")
|
|
137
|
+
)
|
|
138
|
+
for fname, q in (thermo_fields or {}).items():
|
|
139
|
+
if isinstance(q, Quantity):
|
|
140
|
+
self.register(stream_name, fname, q)
|
|
141
|
+
|
|
142
|
+
def get(self, ref: str) -> Optional[Quantity]:
|
|
143
|
+
return self._quantities.get(ref)
|
|
144
|
+
|
|
145
|
+
def __contains__(self, ref: str) -> bool:
|
|
146
|
+
return ref in self._quantities
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class CouplingResolver:
|
|
150
|
+
"""Resolve a unit's ``inputs`` block against a :class:`ParameterStore`."""
|
|
151
|
+
|
|
152
|
+
def __init__(self, store: ParameterStore) -> None:
|
|
153
|
+
self.store = store
|
|
154
|
+
|
|
155
|
+
def resolve(self, spec: dict) -> float:
|
|
156
|
+
ref = spec.get("ref") if isinstance(spec, dict) else None
|
|
157
|
+
if not ref:
|
|
158
|
+
raise CouplingError("coupling spec missing 'ref'")
|
|
159
|
+
if not _REF_RE.match(ref):
|
|
160
|
+
raise CouplingError(
|
|
161
|
+
f"invalid coupling ref '{ref}' (expected '<unit>.<field>')"
|
|
162
|
+
)
|
|
163
|
+
quantity = self.store.get(ref)
|
|
164
|
+
if quantity is None:
|
|
165
|
+
raise CouplingError(f"coupling ref '{ref}' not found in store")
|
|
166
|
+
reduced = _reduce_value(quantity.value, spec.get("reduce", "mean"))
|
|
167
|
+
return _convert(reduced, quantity.unit, spec.get("as_unit"))
|
|
168
|
+
|
|
169
|
+
def build_overrides(self, inputs: dict):
|
|
170
|
+
"""Return ``(nested_overrides, injected_scalars)`` for a unit.
|
|
171
|
+
|
|
172
|
+
*nested_overrides* mirrors the dotted input paths and is deep-merged
|
|
173
|
+
into the unit config before the provider runs. *injected_scalars*
|
|
174
|
+
maps each local path to the resolved float, used for convergence
|
|
175
|
+
checking by the flowsheet driver.
|
|
176
|
+
"""
|
|
177
|
+
overrides: dict = {}
|
|
178
|
+
injected: dict = {}
|
|
179
|
+
for path, spec in (inputs or {}).items():
|
|
180
|
+
value = self.resolve(spec)
|
|
181
|
+
_deep_set(overrides, path, value)
|
|
182
|
+
injected[path] = value
|
|
183
|
+
return overrides, injected
|