Skip to content

Commit 44d779c

Browse files
committed
Add Jupyter notebook for instance data visualization and update data generation process
1 parent fb3aab3 commit 44d779c

File tree

4 files changed

+128
-15
lines changed

4 files changed

+128
-15
lines changed

examples-proposed/024-aggregated-compute-ensemble/gen_data.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
#!/usr/bin/env python3
22
"""
33
Used to generate synthetic data as an example.
4+
5+
Writes two output files:
6+
7+
* `<instance ID>_solution.json`: contains the synthetic data
8+
* `<instance ID>_stats.csv`: contains provenance information about the run
9+
10+
The JSON file is, in turn, read by the a per-instance jupyter notebook
11+
available on the Portal to generate a plot of the data.
412
"""
513
import argparse
614
from typing import Any
@@ -9,7 +17,6 @@
917
from time import time
1018
from traceback import print_exc
1119
import numpy as np
12-
import matplotlib.pyplot as plt
1320

1421
from ipsframework.resourceHelper import get_platform_info
1522
from ipsframework.services import add_analysis_data_file
@@ -58,13 +65,7 @@ def main(instance: str,
5865
u_new[i] = u[i] + r * (u[i + 1] - 2 * u[i] + u[i - 1])
5966
u = u_new
6067

61-
# Plotting the result
62-
plt.plot(x, u)
63-
plt.xlabel("Position (x)")
64-
plt.ylabel("Temperature (u)")
65-
plt.title("Solution of 1D Heat Equation")
66-
plt.grid(True)
67-
plt.savefig(f"{instance}_solution.png")
68+
6869

6970
# Save some per-component stats
7071
stats_fname = f'{instance}_stats.csv'
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
{
2+
"cells": [
3+
{
4+
"metadata": {},
5+
"cell_type": "markdown",
6+
"source": [
7+
"# Instance base notebook\n",
8+
"\n",
9+
"This notebook replicates for each ensemble instance."
10+
],
11+
"id": "56c3997f94a366d5"
12+
},
13+
{
14+
"metadata": {
15+
"ExecuteTime": {
16+
"end_time": "2025-12-18T18:45:35.472364Z",
17+
"start_time": "2025-12-18T18:45:35.462785Z"
18+
}
19+
},
20+
"cell_type": "code",
21+
"source": [
22+
"import json\n",
23+
"from pathlib import Path\n",
24+
"\n",
25+
"%matplotlib notebook\n",
26+
"import matplotlib.pyplot as plt"
27+
],
28+
"id": "937aff95abd359fa",
29+
"outputs": [],
30+
"execution_count": 5
31+
},
32+
{
33+
"metadata": {
34+
"ExecuteTime": {
35+
"end_time": "2025-12-18T18:40:41.874866Z",
36+
"start_time": "2025-12-18T18:40:41.864743Z"
37+
}
38+
},
39+
"cell_type": "code",
40+
"source": [
41+
"# Find the JSON output from `gen_data.py` that was invoked as a sub-task. It will\n",
42+
"# follow the naming pattern `<instance ID>_solution.json`. It will contain two\n",
43+
"# arrays, `x` and `u`, which we will plot.\n",
44+
"solution_json_file = list(Path(\".\").rglob(\"*solution.json\"))\n",
45+
"\n",
46+
"if len(solution_json) != 1:\n",
47+
" raise RuntimeError(\n",
48+
" f\"Expected exactly one solution JSON file, found {len(solution_json_file)}\"\n",
49+
" )\n",
50+
"solution_json_file = solution_json_file[0]\n",
51+
"\n",
52+
"# Now read the JSON file and extract the data.\n",
53+
"with open(solution_json_file, \"r\") as f:\n",
54+
" solution_data = json.load(f)\n",
55+
"\n",
56+
"x = solution_data[\"x\"]\n",
57+
"u = solution_data[\"u\"]\n",
58+
"\n",
59+
"# Now plot the data.\n",
60+
"plt.plot(x, u)\n",
61+
"plt.xlabel(\"Position (x)\")\n",
62+
"plt.ylabel(\"Temperature (u)\")\n",
63+
"plt.title(\"Solution of 1D Heat Equation\")\n",
64+
"plt.grid(True)\n",
65+
"plt.savefig(f\"{instance}_solution.png\")"
66+
],
67+
"id": "b1a40da330ba6b3e",
68+
"outputs": [],
69+
"execution_count": 1
70+
},
71+
{
72+
"metadata": {},
73+
"cell_type": "code",
74+
"outputs": [],
75+
"execution_count": null,
76+
"source": "",
77+
"id": "66002c188c5ab473"
78+
}
79+
],
80+
"metadata": {
81+
"kernelspec": {
82+
"display_name": "Python 3",
83+
"language": "python",
84+
"name": "python3"
85+
},
86+
"language_info": {
87+
"codemirror_mode": {
88+
"name": "ipython",
89+
"version": 2
90+
},
91+
"file_extension": ".py",
92+
"mimetype": "text/x-python",
93+
"name": "python",
94+
"nbconvert_exporter": "python",
95+
"pygments_lexer": "ipython2",
96+
"version": "2.7.6"
97+
}
98+
},
99+
"nbformat": 4,
100+
"nbformat_minor": 5
101+
}

examples-proposed/024-aggregated-compute-ensemble/instance_component.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ def step(self, timestamp: float = 0.0, **keywords):
7171
self.services.info(f'{instance_id}: Completed MPI executable with '
7272
f'return value: {return_value}.')
7373

74-
# TODO temporarily commenting this out until the actual
75-
# example is ready to consider adding data files to the portal. This
76-
# originally came from code Lance wrote in a previous example.
77-
# try:
78-
# self.services.add_analysis_data_files([data_fname, stats_fname], timestamp)
79-
# except Exception:
80-
# print('did not add data files to portal, check logs')
74+
# Add the generated data JSON and CSV files to the portal
75+
try:
76+
self.services.add_analysis_data_files([f'{instance_id}_solution.json',
77+
f'{instance_id}_stats.csv'],
78+
replace=True)
79+
except Exception:
80+
print('did not add data files to portal, check logs')
8181

8282
self.services.info(f'{instance_id}: End of step of instance component.')

examples-proposed/024-aggregated-compute-ensemble/instance_driver.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,22 @@
55

66
from ipsframework import Component
77

8+
# The notebook that will be copied for each ensemble instance
9+
SOURCE_NOTEBOOK_NAME='instance_base_notebook.ipynb'
10+
811

912
class InstanceDriver(Component):
1013
"""
1114
Instance driver component that steps the main component
1215
"""
16+
def init(self, timestamp: float = 0.0, **keywords):
17+
self.services.stage_input_files([SOURCE_NOTEBOOK_NAME])
18+
19+
self.services.initialize_jupyter_notebook(
20+
dest_notebook_name='jupyterhub_instance_notebook.ipynb',
21+
source_notebook_path=SOURCE_NOTEBOOK_NAME,
22+
)
23+
1324

1425
def step(self, timestamp: float = 0.0, **keywords):
1526
instance_component = self.services.get_port('WORKER')

0 commit comments

Comments
 (0)