Skip to content

Commit bf96e0d

Browse files
committed
Merge branch 'main' into copilot/add-copilot-instructions
2 parents d531ef0 + 2ecdda9 commit bf96e0d

15 files changed

Lines changed: 734 additions & 431 deletions

.github/copilot-instructions.md

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ synapse/
2121
│ ├── environment.yml # Conda dependencies for ML
2222
│ └── environment-lock.yml
2323
├── experiments/ # Experiment configs (cloned from private repos)
24+
├── tests/ # Integration tests (ML pipeline)
25+
│ ├── test_ml_pipeline.py # Full train/save/load ML lifecycle test
26+
│ └── check_model.py # Model checking utility
2427
├── dashboard.Dockerfile # Docker image for the GUI
2528
├── ml.Dockerfile # Docker image for ML training (CUDA 12.4)
2629
├── publish_container.py # Script to build & push Docker containers to NERSC registry
@@ -71,7 +74,20 @@ python publish_container.py --gui --ml
7174

7275
## Testing
7376

74-
There is **no automated test suite** in this repository — no pytest, unittest, or similar framework is configured. There are no test files. Validation is done manually by running the dashboard or ML training scripts.
77+
There is no pytest/unittest framework configured, but `tests/test_ml_pipeline.py` exercises the full ML lifecycle (training → upload to MLflow → download → accuracy check). It requires a local MLflow server:
78+
79+
```bash
80+
# Start a local MLflow server
81+
docker run -p 127.0.0.1:5000:5000 ghcr.io/mlflow/mlflow mlflow server --host 0.0.0.0
82+
83+
# Run the test from the repository root
84+
python tests/test_ml_pipeline.py
85+
86+
# Optionally restrict to a specific model type or config
87+
python tests/test_ml_pipeline.py --model NN --config_file experiments/synapse-bella-ip2
88+
```
89+
90+
Dashboard validation is done manually by running the application.
7591

7692
## CI/CD
7793

@@ -84,31 +100,31 @@ The only CI workflow is **CodeQL Advanced** (`.github/workflows/codeql.yml`), wh
84100
- Built on [Trame](https://kitware.github.io/trame/) — a Python framework for interactive web applications.
85101
- Uses the **manager pattern**: each feature area has a dedicated `*_manager.py` class that handles its UI components and business logic.
86102
- `state_manager.py` manages the global Trame server, state, and controller.
87-
- Data flows through MongoDB (PyMongo) for experiment and simulation data.
88-
- Data flows through MLflow for ML models.
103+
- Data flows through MongoDB (PyMongo) for experiment and simulation data.
104+
- Data flows through MLflow for ML models.
89105
- NERSC Superfacility API integration is in `sfapi_manager.py`.
90106

91107
### ML Training
92108

93109
- `train_model.py` supports three model types: Gaussian Process (GP), Neural Network (NN), and Ensemble.
94110
- Uses PyTorch, BoTorch, and GPyTorch for model training.
95111
- CUDA is auto-detected for GPU acceleration.
96-
- Models are serialized and stored in an MLflow tracking server.
112+
- Models are serialized and stored in an MLflow tracking server.
97113

98114
### Data Storage
99115

100-
- **MongoDB** is used for persistent data from experiments and simulations.
101-
- **MLflow** is used for persistent data from ML models.
116+
- **MongoDB** is used for persistent data from experiments and simulations.
117+
- **MLflow** is used for persistent data from ML models.
102118
- Database access requires SSH tunneling to NERSC when running locally.
103-
- Environment variables: `SF_DB_HOST`, `SF_DB_READONLY_PASSWORD` (dashboard), `SF_DB_ADMIN_PASSWORD` (ML training).
119+
- Environment variables: `SF_DB_HOST` (dashboard), `SF_DB_READONLY_PASSWORD` (dashboard and ML training), `AM_SC_API_KEY` (dashboard and ML training, required when MLflow tracking_uri is AmSC).
104120

105121
## Common Pitfalls and Workarounds
106122

107123
1. **No `pyproject.toml` or `ruff.toml`**: Ruff uses default rules. Do not create these files unless the project explicitly adopts them.
108124
2. **Conda, not pip**: Dependencies are managed via `conda` and `conda-lock`, not `pip`. Do not add `requirements.txt` or modify `pyproject.toml` for dependencies. Update `environment.yml` in the relevant component directory and regenerate the lock file.
109125
3. **Separate environments**: The dashboard and ML components have independent Conda environments (`synapse-gui` and `synapse-ml`). Changes to dependencies must be made in the correct `environment.yml`.
110126
4. **Docker builds from root**: Dockerfiles reference paths relative to the repository root. Always run `docker build` from the repository root directory.
111-
5. **No test infrastructure**: Since there is no test framework, validate changes by running the linter (`ruff check .`) and verifying logic through code review.
127+
5. **Limited test infrastructure**: There is no pytest/unittest framework, but `tests/test_ml_pipeline.py` can validate ML changes end-to-end (requires a local MLflow server). Always run the linter (`ruff check .`) and verify logic through code review.
112128
6. **Experiment configs are external**: The `experiments/` directory contains cloned private repositories. These are not checked into this repository (excluded via `.gitignore`).
113129
7. **NERSC-specific infrastructure**: Much of the deployment depends on NERSC services (Spin, Superfacility API, Perlmutter). Code changes affecting deployment or data access should be tested against NERSC services when possible.
114130

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
33
# Ruff version
4-
rev: v0.15.2
4+
rev: v0.15.7
55
hooks:
66
# Run the linter
77
- id: ruff-check

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ To display ML predictions, the application requires the following:
2525
- **Simulation and experimental data points**: Each data point consists of values for the scalar inputs and outputs defined in the experiment configuration file.
2626
Data points are stored in a [MongoDB](https://www.mongodb.com/) database, where each experiment is represented by a separate collection.
2727
Experimental and simulation data points are stored in the same collection and are distinguished by the `experimental_flag` attribute.
28-
- **ML models**: Machine learning models that interpolate between data points and are stored in a separate MongoDB collection named `models`.
28+
- **ML models**: Machine learning models that interpolate between data points and are stored in [MLflow](https://mlflow.org/).
2929
- **Simulation movies** (optional): For certain experiments, users can click on simulation data points to visualize simulation movies.
3030
The corresponding MP4 files are stored in the Perlmutter shared file system at `/global/cfs/cdirs/m558/superfacility/simulation_data`.
3131
This directory is mounted on the container image running on Spin.

dashboard/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,11 @@ conda-lock install --name synapse-gui environment-lock.yml
5454

5555
2. Move to the [dashboard/](./) directory.
5656

57-
3. Set up the database settings (read-only):
57+
3. Set up the database settings (read-only) and the AmSC MLflow API key:
5858
```bash
5959
export SF_DB_HOST='127.0.0.1'
6060
export SF_DB_READONLY_PASSWORD='your_password_here' # Use SINGLE quotes around the password!
61+
export AM_SC_API_KEY='your_amsc_api_key_here' # Required when MLflow tracking_uri is AmSC
6162
```
6263

6364
4. Activate the conda environment `synapse-gui`:
@@ -85,11 +86,11 @@ conda-lock install --name synapse-gui environment-lock.yml
8586

8687
4. Run the Docker container:
8788
```bash
88-
docker run --network=host -v /etc/localtime:/etc/localtime -v $PWD/ml:/app/ml -e SF_DB_HOST='127.0.0.1' -e SF_DB_READONLY_PASSWORD='your_password_here' synapse-gui
89+
docker run --network=host -v /etc/localtime:/etc/localtime -v $PWD/ml:/app/ml -e SF_DB_HOST='127.0.0.1' -e SF_DB_READONLY_PASSWORD='your_password_here' -e AM_SC_API_KEY='your_amsc_api_key_here' synapse-gui
8990
```
9091
For debugging, you can enter the container without starting the app:
9192
```bash
92-
docker run --network=host -v /etc/localtime:/etc/localtime -v $PWD/ml:/app/ml -e SF_DB_HOST='127.0.0.1' -e SF_DB_READONLY_PASSWORD='your_password_here' -it synapse-gui bash
93+
docker run --network=host -v /etc/localtime:/etc/localtime -v $PWD/ml:/app/ml -e SF_DB_HOST='127.0.0.1' -e SF_DB_READONLY_PASSWORD='your_password_here' -e AM_SC_API_KEY='your_amsc_api_key_here' -it synapse-gui bash
9394
```
9495
Note that `-v /etc/localtime:/etc/localtime` is necessary to synchronize the time zone in the container with the host machine.
9596

dashboard/app.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from trame.ui.vuetify3 import SinglePageWithDrawerLayout
77
from trame.widgets import plotly, router, vuetify3 as vuetify, html
88

9-
from model_manager import ModelManager
9+
from model_manager import ModelManager, model_type_tag_dict
1010
from outputs_manager import OutputManager
1111
from optimization_manager import OptimizationManager
1212
from parameters_manager import ParametersManager
@@ -16,6 +16,7 @@
1616
from error_manager import error_panel, add_error
1717
from utils import (
1818
data_depth_panel,
19+
load_config_dict,
1920
load_experiments,
2021
load_database,
2122
load_data,
@@ -64,14 +65,18 @@ def update(
6465
state.experiment
6566
)
6667
# load data
67-
db = load_database(state.experiment)
68-
exp_data, sim_data = load_data(db)
68+
config_dict = load_config_dict(state.experiment)
69+
db = load_database(config_dict)
70+
exp_data, sim_data = load_data(db, state.experiment, state.experiment_date_range)
6971
# reset output
7072
if reset_output:
7173
out_manager = OutputManager(output_variables)
7274
# reset model
7375
if reset_model:
74-
mod_manager = ModelManager(db)
76+
mod_manager = ModelManager(
77+
config_dict=config_dict,
78+
model_type_tag=model_type_tag_dict[state.model_type],
79+
)
7580
opt_manager = OptimizationManager(mod_manager)
7681
# reset parameters
7782
if reset_parameters:
@@ -257,7 +262,8 @@ def find_simulation(event, db):
257262

258263

259264
def open_simulation_dialog(event):
260-
db = load_database(state.experiment)
265+
config_dict = load_config_dict(state.experiment)
266+
db = load_database(config_dict)
261267
try:
262268
data_directory, file_path = find_simulation(event, db)
263269
state.simulation_video = file_path.endswith(".mp4")

dashboard/error_manager.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
from trame.widgets import vuetify3 as vuetify, html
2-
from state_manager import state
2+
from state_manager import state, server
33

44

55
def add_error(title, msg):
6+
if not server.running:
7+
# Outside of a Trame app (e.g. check_model.py), raise a Python error
8+
# to surface the error to the caller.
9+
raise RuntimeError(f"{title}: {msg}")
10+
# Otherwise: Inside a Trame app, add the error to the state.
611
state.errors.append(
712
{
813
"id": state.error_counter,

0 commit comments

Comments
 (0)