Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1248182
working Sankey diagrams
erwanp Jun 9, 2025
8ec6bdf
option to Select mechanisms (from all Cantera folder, from Name, from…
erwanp Jun 9, 2025
6810d16
display Cantera error if it fails during calculation
erwanp Jun 9, 2025
3d02f3b
fix error when selecting mfc
erwanp Jun 9, 2025
c35d9d9
reset min/max zoom to 0.5/2
erwanp Jun 9, 2025
db10a36
hide SimulationResults until calculations are done
erwanp Jun 9, 2025
810cee8
fix make qa
erwanp Jun 9, 2025
ebd79b7
Fixed Sankey Callback Return Values; Fixed Division by Zero in ctuti…
erwanp Jun 9, 2025
c203818
implemented a comprehensive solution that eliminates the global conv…
erwanp Jun 9, 2025
9c17dca
Merge pull request #5 from parks4/add/sankey-diagrams
erwanp Jun 9, 2025
afa8bcf
add dark theme mode
erwanp Jun 9, 2025
4a7ade6
auto-system dark mode for Plots & Sankey
erwanp Jun 9, 2025
f939177
make
erwanp Jun 9, 2025
f953089
Merge pull request #6 from parks4/add/dark-mode
erwanp Jun 9, 2025
5dc2af9
add yaml config wip
erwanp Jun 9, 2025
2fc187e
add config file loading; and tests
erwanp Jun 9, 2025
4fa8f51
define new YAML format with 🪨 STONE standard
erwanp Jun 9, 2025
f4f0338
finish & fixed YAML conversion (including inline editing)
erwanp Jun 9, 2025
cc465e6
clean
erwanp Jun 9, 2025
58c8f24
Merge branch 'main' of https://github.com/parks4/boulder
erwanp Jun 10, 2025
5ec631d
Merge branch 'main' into add/yaml-config
erwanp Jun 10, 2025
43ebb4b
fixed tests?
erwanp Jun 10, 2025
82f2aec
Merge branch 'main' of https://github.com/parks4/boulder
erwanp Jun 10, 2025
f81b8c7
add yaml config wip
erwanp Jun 9, 2025
9b38cd3
add config file loading; and tests
erwanp Jun 9, 2025
5e15a37
define new YAML format with 🪨 STONE standard
erwanp Jun 9, 2025
8c5e56c
finish & fixed YAML conversion (including inline editing)
erwanp Jun 9, 2025
bcb4498
clean
erwanp Jun 9, 2025
3eef71a
fixed tests?
erwanp Jun 10, 2025
0830f2c
highlight of Node from Sankey mostly working, seems there are problem…
erwanp Jun 10, 2025
067770b
Fixed Sankey; now has same id & same order as the simulation. And sim…
erwanp Jun 10, 2025
3c17945
Merge branch 'add/yaml-config' of https://github.com/parks4/boulder i…
erwanp Jun 14, 2025
84a8911
removed returning success notificatinos
erwanp Jun 14, 2025
6a16286
fix UI freezing problems (see #7) by removing animation fadeout in mo…
erwanp Jun 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .cursorignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
example_config.yaml # Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv)
*.yaml
60 changes: 30 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ A web-based tool for visually constructing and simulating Cantera ReactorNet sys
- Support for flow devices (MassFlowController, Valve)
- Real-time property editing
- Simulation capabilities with time-series plots
- JSON configuration import/export
- YAML configuration files with 🪨 STONE standard (elegant format)

![screenshot](https://private-user-images.githubusercontent.com/16088743/452821416-9d904892-a17c-4c60-8efa-c2aa7abf7da8.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDk0NjYzMDUsIm5iZiI6MTc0OTQ2NjAwNSwicGF0aCI6Ii8xNjA4ODc0My80NTI4MjE0MTYtOWQ5MDQ4OTItYTE3Yy00YzYwLThlZmEtYzJhYTdhYmY3ZGE4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTA2MDklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwNjA5VDEwNDY0NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWE5NTAzYzllYjVhODc2Njc1ZWM5N2NiODBkMjMxOWMwNmNjNzcyNDBlMThhY2U1YzlhMmFlZDVhOThhMzQ1ODYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.P-wD297SHbNk1nuTgsBof3vmKukntOBWRnpgi7e774o)

Expand Down Expand Up @@ -42,37 +42,37 @@ pip install -e . # install in editable mode
- Run simulations
- View results

## Configuration Format

The application uses a JSON-based configuration format:

```json
{
"components": [
{
"id": "reactor1",
"type": "IdealGasReactor",
"properties": {
"temperature": 1000,
"pressure": 101325,
"composition": "CH4:1,O2:2,N2:7.52"
}
}
],
"connections": [
{
"id": "mfc1",
"type": "MassFlowController",
"source": "res1",
"target": "reactor1",
"properties": {
"mass_flow_rate": 0.1
}
}
]
}
## YAML Configuration with 🪨 STONE Standard

Boulder uses **YAML format with 🪨 STONE standard** (**Structured Type-Oriented Network Expressions**) - an elegant configuration format where component types become keys containing their properties:

```yaml
metadata:
name: "Reactor Configuration"
version: "1.0"

simulation:
mechanism: "gri30.yaml"
time_step: 0.001
max_time: 10.0

components:
- id: reactor1
IdealGasReactor:
temperature: 1000 # K
pressure: 101325 # Pa
composition: "CH4:1,O2:2,N2:7.52"

connections:
- id: mfc1
MassFlowController:
mass_flow_rate: 0.1 # kg/s
source: res1
target: reactor1
```

See [`examples/README.md`](examples/README.md) for comprehensive YAML with 🪨 STONE standard documentation and examples.

## Supported Components

### Reactors
Expand Down
121 changes: 7 additions & 114 deletions boulder/callbacks/clientside_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,118 +5,6 @@

def register_callbacks(app) -> None: # type: ignore
"""Register client-side callbacks."""
# Custom edge creation from custom event
app.clientside_callback(
"""
function(n_clicks) {
if (!window.cy) return null;

// Listen for the create-edge event
if (!window._edgeListenerAdded) {
window._edgeListenerAdded = true;
window.addEventListener('create-edge', function(e) {
const { source, target } = e.detail;
// Add the edge to Cytoscape
window.cy.add({
group: 'edges',
data: {
source: source,
target: target,
label: 'New Edge' // You can customize this
}
});
});
}
return null;
}
""",
Output("reactor-graph", "tapEdgeData"),
Input("reactor-graph", "tapNode"),
prevent_initial_call=True,
)

# Setup client-side callback to handle edge creation
app.clientside_callback(
"""
function(n_clicks) {
// This is a trigger to create an initial placeholder
return [];
}
""",
Output("hidden-edge-data", "children"),
Input("reactor-graph", "id"),
prevent_initial_call=True,
)

# Update the store when an edge is created
app.clientside_callback(
"""
function(n_clicks) {
// Initialize event listener if not done already
if (!window.edgeEventInitialized) {
window.edgeEventInitialized = true;

document.addEventListener('edgeCreate', function(e) {
if (e && e.detail) {
console.log('Edge creation event received:', e.detail);
// Update the store with new edge data
window.dash_clientside.no_update = false;
return e.detail;
}
return window.dash_clientside.no_update;
});
}

// Initially return no update
return window.dash_clientside.no_update;
}
""",
Output("edge-added-store", "data"),
Input("initialization-trigger", "children"),
prevent_initial_call=True,
)

# Edgehandles setup
app.clientside_callback(
"""
function(n_intervals) {
if (window.edgehandles_setup_complete) {
return window.dash_clientside.no_update;
}
const cy = (
document.getElementById('reactor-graph') &&
document.getElementById('reactor-graph')._cyreg &&
document.getElementById('reactor-graph')._cyreg.cy
);
if (!cy || typeof cy.edgehandles !== 'function') {
console.log("Waiting for Cytoscape and the .edgehandles() function...");
return window.dash_clientside.no_update;
}
// --- One-time setup ---
window.boulder_edge_queue = [];
document.addEventListener('boulder_edge_created', e => {
window.boulder_edge_queue.push(e.detail);
});
const eh = cy.edgehandles({
preview: true, snap: true,
complete: (sourceNode, targetNode, addedEles) => {
document.dispatchEvent(new CustomEvent('boulder_edge_created', {
detail: { source: sourceNode.id(), target: targetNode.id(), ts: Date.now() }
}));
}
});
document.addEventListener('keydown', e => { if (e.key === 'Shift') eh.enable(); });
document.addEventListener('keyup', e => { if (e.key === 'Shift') eh.disable(); });
eh.disable();
window.edgehandles_setup_complete = true;
console.log('Edgehandles initialized.');
return window.dash_clientside.no_update;
}
""",
Output("init-dummy-output", "children"),
Input("init-interval", "n_intervals"),
)

# Keyboard shortcut for Ctrl+Enter
app.clientside_callback(
"""
Expand All @@ -125,9 +13,14 @@ def register_callbacks(app) -> None: # type: ignore
window._boulder_keyboard_shortcut = true;
document.addEventListener('keydown', function(e) {
if (e.ctrlKey && e.key === 'Enter') {
// Check if Add Reactor modal is open
// Check if Add Reactor modal is open and MFC modal is not
var addReactorModal = document.getElementById('add-reactor-modal');
if (addReactorModal && addReactorModal.classList.contains('show')) {
var addMFCModal = document.getElementById('add-mfc-modal');
if (
addReactorModal &&
addReactorModal.classList.contains('show') &&
(!addMFCModal || !addMFCModal.classList.contains('show'))
) {
var btn = document.getElementById('add-reactor');
if (btn && !btn.disabled) btn.click();
} else {
Expand Down
Loading
Loading