Skip to content

Commit feccfd5

Browse files
authored
Merge pull request #209 from pathsim/pathsim-chem-support
Pathsim chem support
2 parents c170048 + 1019109 commit feccfd5

File tree

5 files changed

+266
-103
lines changed

5 files changed

+266
-103
lines changed

scripts/extract-blocks.py

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
try:
2323
from docutils.core import publish_parts
24+
2425
HAS_DOCUTILS = True
2526
except ImportError:
2627
HAS_DOCUTILS = False
@@ -30,6 +31,7 @@
3031
from pathsim.blocks import *
3132
from pathsim.subsystem import Subsystem, Interface
3233

34+
from pathsim_chem.tritium import *
3335

3436
# Block configuration - defines which blocks to extract and their categories
3537
BLOCK_CONFIG = {
@@ -100,6 +102,12 @@
100102
"Spectrum",
101103
],
102104
# Subsystem blocks are manually defined in subsystem.ts but we still extract their docstrings
105+
"Chemical": [
106+
"Process",
107+
"Bubbler4",
108+
"Splitter",
109+
"GLC",
110+
],
103111
}
104112

105113
# Extra blocks to extract docstrings from, but not auto-register
@@ -121,7 +129,6 @@
121129
"PinkNoise": {"maxInputs": 0, "maxOutputs": 1},
122130
"ChirpPhaseNoiseSource": {"maxInputs": 0, "maxOutputs": 1},
123131
"RandomNumberGenerator": {"maxInputs": 0, "maxOutputs": 1},
124-
125132
# Dynamic - vector passthrough (unlimited) unless specified
126133
"Integrator": {"maxInputs": None, "maxOutputs": None},
127134
"Differentiator": {"maxInputs": None, "maxOutputs": None},
@@ -137,7 +144,6 @@
137144
"ButterworthHighpassFilter": {"maxInputs": None, "maxOutputs": None},
138145
"ButterworthBandpassFilter": {"maxInputs": None, "maxOutputs": None},
139146
"ButterworthBandstopFilter": {"maxInputs": None, "maxOutputs": None},
140-
141147
# Algebraic
142148
"Adder": {"maxInputs": None, "maxOutputs": 1},
143149
"Multiplier": {"maxInputs": None, "maxOutputs": 1},
@@ -158,7 +164,6 @@
158164
"Switch": {"maxInputs": None, "maxOutputs": 1},
159165
"LUT": {"maxInputs": None, "maxOutputs": None},
160166
"LUT1D": {"maxInputs": 1, "maxOutputs": 1},
161-
162167
# Mixed
163168
"SampleHold": {},
164169
"FIR": {},
@@ -168,16 +173,32 @@
168173
"CounterUp": {"maxInputs": 1, "maxOutputs": 1},
169174
"CounterDown": {"maxInputs": 1, "maxOutputs": 1},
170175
"Relay": {"maxInputs": 1, "maxOutputs": 1},
171-
172176
# Recording - unlimited inputs, no outputs
173177
"Scope": {"maxInputs": None, "maxOutputs": 0},
174178
"Spectrum": {"maxInputs": None, "maxOutputs": 0},
175-
179+
"Splitter": {"maxInputs": 1, "maxOutputs": None},
176180
}
177181

178182
# Parameter overrides - PathSim handles all validation at runtime
179183
PARAM_OVERRIDES: dict[str, dict] = {}
180184

185+
# Input/output mapping overrides if can't be extracted automatically
186+
IO_OVERRIDES: dict[str, dict] = {
187+
"GLC": {
188+
"inputs": ["c_T_in", "flow_l", "y_T2_inlet", "flow_g"],
189+
"outputs": [
190+
"c_T_out",
191+
"y_T2_out",
192+
"eff",
193+
"P_out",
194+
"Q_l",
195+
"Q_g_out",
196+
"n_T_out_liquid",
197+
"n_T_out_gas",
198+
],
199+
}
200+
}
201+
181202

182203
def rst_to_html(rst_text: str) -> str:
183204
"""Convert RST docstring to HTML, preserving LaTeX math for KaTeX rendering."""
@@ -195,7 +216,7 @@ def rst_to_html(rst_text: str) -> str:
195216
# Use MathJax output mode to preserve LaTeX in <span class="math">
196217
# This allows client-side KaTeX rendering
197218
"math_output": "MathJax",
198-
}
219+
},
199220
)
200221
return parts["body"]
201222
except Exception as e:
@@ -299,7 +320,9 @@ def extract_block(block_name: str) -> dict | None:
299320
if name == "self":
300321
continue
301322

302-
default = None if param.default is inspect.Parameter.empty else param.default
323+
default = (
324+
None if param.default is inspect.Parameter.empty else param.default
325+
)
303326
param_type = infer_param_type(default)
304327

305328
param_info = {
@@ -319,8 +342,16 @@ def extract_block(block_name: str) -> dict | None:
319342
# Some blocks need arguments, try with defaults first
320343
instance = cls()
321344
# Register stores mapping in _mapping (private attribute)
322-
inputs = list(getattr(instance.inputs, "_mapping", {}).keys()) if hasattr(instance, "inputs") else []
323-
outputs = list(getattr(instance.outputs, "_mapping", {}).keys()) if hasattr(instance, "outputs") else []
345+
inputs = (
346+
list(getattr(instance.inputs, "_mapping", {}).keys())
347+
if hasattr(instance, "inputs")
348+
else []
349+
)
350+
outputs = (
351+
list(getattr(instance.outputs, "_mapping", {}).keys())
352+
if hasattr(instance, "outputs")
353+
else []
354+
)
324355
except Exception:
325356
# Fallback: just use empty ports, UI overrides will provide defaults
326357
inputs = []
@@ -340,7 +371,9 @@ def extract_block(block_name: str) -> dict | None:
340371
return None
341372

342373

343-
def generate_typescript(blocks: dict[str, dict], config: dict[str, list[str]], overrides: dict) -> str:
374+
def generate_typescript(
375+
blocks: dict[str, dict], config: dict[str, list[str]], overrides: dict
376+
) -> str:
344377
"""Generate TypeScript file content."""
345378
lines = [
346379
"// Auto-generated by scripts/extract-blocks.py - DO NOT EDIT",
@@ -384,10 +417,12 @@ def generate_typescript(blocks: dict[str, dict], config: dict[str, list[str]], o
384417
lines.append("")
385418

386419
# Add block config
387-
lines.append("export const blockConfig: Record<Exclude<NodeCategory, 'Subsystem'>, string[]> = {")
420+
lines.append(
421+
"export const blockConfig: Record<Exclude<NodeCategory, 'Subsystem'>, string[]> = {"
422+
)
388423
for category, block_names in config.items():
389424
names_str = ", ".join(f'"{name}"' for name in block_names)
390-
lines.append(f' {category}: [{names_str}],')
425+
lines.append(f" {category}: [{names_str}],")
391426
lines.append("};")
392427
lines.append("")
393428

@@ -419,13 +454,28 @@ def main():
419454
if block_data:
420455
extracted_blocks[block_name] = block_data
421456

457+
# Override inputs/outputs from IO_OVERRIDES
458+
for block_name, io_data in IO_OVERRIDES.items():
459+
if block_name in extracted_blocks:
460+
if "inputs" in io_data:
461+
extracted_blocks[block_name]["inputs"] = io_data["inputs"]
462+
if "outputs" in io_data:
463+
extracted_blocks[block_name]["outputs"] = io_data["outputs"]
464+
422465
print(f"Extracted {len(extracted_blocks)} blocks")
423466

424467
# Generate TypeScript
425468
ts_content = generate_typescript(extracted_blocks, BLOCK_CONFIG, UI_OVERRIDES)
426469

427470
# Write output file
428-
output_path = Path(__file__).parent.parent / "src" / "lib" / "nodes" / "generated" / "blocks.ts"
471+
output_path = (
472+
Path(__file__).parent.parent
473+
/ "src"
474+
/ "lib"
475+
/ "nodes"
476+
/ "generated"
477+
/ "blocks.ts"
478+
)
429479
output_path.parent.mkdir(parents=True, exist_ok=True)
430480
output_path.write_text(ts_content, encoding="utf-8")
431481

src/lib/constants/messages.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const PROGRESS_MESSAGES = {
66
LOADING_PYODIDE: 'Loading Pyodide...',
77
INSTALLING_DEPS: 'Installing NumPy and SciPy...',
88
INSTALLING_PATHSIM: 'Installing PathSim...',
9+
INSTALLING_PATHSIM_CHEM: 'Installing PathSim-Chem...',
910
STARTING_WORKER: 'Starting worker...',
1011
STARTING_SIMULATION: 'Starting simulation...'
1112
} as const;

0 commit comments

Comments
 (0)