Skip to content

Commit 44c7d4c

Browse files
authored
Add example notebooks (#25)
* Expose Heat model through heat package * Add example notebooks * List examples directory and update build instructions * Fix typo * Run black, isort, and flake8
1 parent 1329f47 commit 44c7d4c

6 files changed

Lines changed: 578 additions & 10 deletions

File tree

README.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ Tests of the BMI are provided.
3030
This repository is organized with the following directories:
3131

3232
*heat*
33-
Holds the model and the BMI for the model
33+
Source code for the model and its BMI
34+
35+
*examples*
36+
Jupyter Notebooks that demonstrate how to run the model through its BMI
3437

3538
*tests*
3639
Tests that cover the BMI of the model
@@ -45,20 +48,20 @@ This example can be built and installed on Linux, macOS, and Windows.
4548
* Python 3
4649
* The Python BMI bindings. Follow the build and install directions
4750
given in the `README`_ in that repository. You can choose to install
48-
them from source, or through pip, or conda.
51+
them from source, or through `pip` or `conda`.
4952

5053
To build/install this example from source,
5154
using the current Python BMI version, run
5255

5356
.. code-block:: bash
5457
55-
$ make install
58+
$ pip install -e .
5659
5760
To run the tests,
5861

5962
.. code-block:: bash
6063
61-
$ pip install -r requirements.txt
64+
$ pip install -r requirements-testing.txt
6265
$ make test
6366
6467

examples/run-model-from-bmi.ipynb

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Run the `Heat` model through its BMI"
8+
]
9+
},
10+
{
11+
"cell_type": "markdown",
12+
"metadata": {},
13+
"source": [
14+
"`Heat` models the diffusion of temperature on a uniform rectangular plate with Dirichlet boundary conditions. View the source code for the [model](https://github.com/csdms/bmi-example-python/blob/master/heat/heat.py) and its [BMI](https://github.com/csdms/bmi-example-python/blob/master/heat/bmi_heat.py) on GitHub."
15+
]
16+
},
17+
{
18+
"cell_type": "markdown",
19+
"metadata": {},
20+
"source": [
21+
"Start by importing `os`, `numpy` and the `Heat` BMI:"
22+
]
23+
},
24+
{
25+
"cell_type": "code",
26+
"execution_count": null,
27+
"metadata": {},
28+
"outputs": [],
29+
"source": [
30+
"import os\n",
31+
"import numpy as np\n",
32+
"\n",
33+
"from heat import BmiHeat"
34+
]
35+
},
36+
{
37+
"cell_type": "markdown",
38+
"metadata": {},
39+
"source": [
40+
"Create an instance of the model's BMI."
41+
]
42+
},
43+
{
44+
"cell_type": "code",
45+
"execution_count": null,
46+
"metadata": {},
47+
"outputs": [],
48+
"source": [
49+
"x = BmiHeat()"
50+
]
51+
},
52+
{
53+
"cell_type": "markdown",
54+
"metadata": {},
55+
"source": [
56+
"What's the name of this model?"
57+
]
58+
},
59+
{
60+
"cell_type": "code",
61+
"execution_count": null,
62+
"metadata": {},
63+
"outputs": [],
64+
"source": [
65+
"print(x.get_component_name())"
66+
]
67+
},
68+
{
69+
"cell_type": "markdown",
70+
"metadata": {},
71+
"source": [
72+
"Start the `Heat` model through its BMI using a configuration file:"
73+
]
74+
},
75+
{
76+
"cell_type": "code",
77+
"execution_count": null,
78+
"metadata": {},
79+
"outputs": [],
80+
"source": [
81+
"cat heat.yaml"
82+
]
83+
},
84+
{
85+
"cell_type": "code",
86+
"execution_count": null,
87+
"metadata": {},
88+
"outputs": [],
89+
"source": [
90+
"x.initialize(\"heat.yaml\")"
91+
]
92+
},
93+
{
94+
"cell_type": "markdown",
95+
"metadata": {},
96+
"source": [
97+
"Check the time information for the model."
98+
]
99+
},
100+
{
101+
"cell_type": "code",
102+
"execution_count": null,
103+
"metadata": {},
104+
"outputs": [],
105+
"source": [
106+
"print(\"Start time:\", x.get_start_time())\n",
107+
"print(\"End time:\", x.get_end_time())\n",
108+
"print(\"Current time:\", x.get_current_time())\n",
109+
"print(\"Time step:\", x.get_time_step())\n",
110+
"print(\"Time units:\", x.get_time_units())"
111+
]
112+
},
113+
{
114+
"cell_type": "markdown",
115+
"metadata": {},
116+
"source": [
117+
"Show the input and output variables for the component (aside on [Standard Names](https://csdms.colorado.edu/wiki/CSDMS_Standard_Names)):"
118+
]
119+
},
120+
{
121+
"cell_type": "code",
122+
"execution_count": null,
123+
"metadata": {},
124+
"outputs": [],
125+
"source": [
126+
"print(x.get_input_var_names())\n",
127+
"print(x.get_output_var_names())"
128+
]
129+
},
130+
{
131+
"cell_type": "markdown",
132+
"metadata": {},
133+
"source": [
134+
"Next, get the identifier for the grid on which the temperature variable is defined:"
135+
]
136+
},
137+
{
138+
"cell_type": "code",
139+
"execution_count": null,
140+
"metadata": {},
141+
"outputs": [],
142+
"source": [
143+
"grid_id = x.get_var_grid(\"plate_surface__temperature\")\n",
144+
"print(\"Grid id:\", grid_id)"
145+
]
146+
},
147+
{
148+
"cell_type": "markdown",
149+
"metadata": {},
150+
"source": [
151+
"Then get the grid attributes:"
152+
]
153+
},
154+
{
155+
"cell_type": "code",
156+
"execution_count": null,
157+
"metadata": {},
158+
"outputs": [],
159+
"source": [
160+
"print(\"Grid type:\", x.get_grid_type(grid_id))\n",
161+
"\n",
162+
"rank = x.get_grid_rank(grid_id)\n",
163+
"print(\"Grid rank:\", rank)\n",
164+
"\n",
165+
"shape = np.ndarray(rank, dtype=int)\n",
166+
"x.get_grid_shape(grid_id, shape)\n",
167+
"print(\"Grid shape:\", shape)\n",
168+
"\n",
169+
"spacing = np.ndarray(rank, dtype=float)\n",
170+
"x.get_grid_spacing(grid_id, spacing)\n",
171+
"print(\"Grid spacing:\", spacing)"
172+
]
173+
},
174+
{
175+
"cell_type": "markdown",
176+
"metadata": {},
177+
"source": [
178+
"These commands are made somewhat un-Pythonic by the generic design of the BMI."
179+
]
180+
},
181+
{
182+
"cell_type": "markdown",
183+
"metadata": {},
184+
"source": [
185+
"Through the model's BMI, zero out the initial temperature field, except for an impulse near the middle.\n",
186+
"Note that *set_value* expects a one-dimensional array for input."
187+
]
188+
},
189+
{
190+
"cell_type": "code",
191+
"execution_count": null,
192+
"metadata": {},
193+
"outputs": [],
194+
"source": [
195+
"temperature = np.zeros(shape)\n",
196+
"temperature[3, 4] = 100.0\n",
197+
"x.set_value(\"plate_surface__temperature\", temperature)"
198+
]
199+
},
200+
{
201+
"cell_type": "markdown",
202+
"metadata": {},
203+
"source": [
204+
"Check that the temperature field has been updated. Note that *get_value* expects a one-dimensional array to receive output."
205+
]
206+
},
207+
{
208+
"cell_type": "code",
209+
"execution_count": null,
210+
"metadata": {},
211+
"outputs": [],
212+
"source": [
213+
"temperature_flat = np.empty_like(temperature).flatten()\n",
214+
"x.get_value(\"plate_surface__temperature\", temperature_flat)\n",
215+
"print(temperature_flat.reshape(shape))"
216+
]
217+
},
218+
{
219+
"cell_type": "markdown",
220+
"metadata": {},
221+
"source": [
222+
"Now advance the model by a single time step:"
223+
]
224+
},
225+
{
226+
"cell_type": "code",
227+
"execution_count": null,
228+
"metadata": {},
229+
"outputs": [],
230+
"source": [
231+
"x.update()"
232+
]
233+
},
234+
{
235+
"cell_type": "markdown",
236+
"metadata": {},
237+
"source": [
238+
"View the new state of the temperature field:"
239+
]
240+
},
241+
{
242+
"cell_type": "code",
243+
"execution_count": null,
244+
"metadata": {},
245+
"outputs": [],
246+
"source": [
247+
"x.get_value(\"plate_surface__temperature\", temperature_flat)\n",
248+
"print(temperature_flat.reshape(shape))"
249+
]
250+
},
251+
{
252+
"cell_type": "markdown",
253+
"metadata": {},
254+
"source": [
255+
"There's diffusion!"
256+
]
257+
},
258+
{
259+
"cell_type": "markdown",
260+
"metadata": {},
261+
"source": [
262+
"Advance the model to some distant time:"
263+
]
264+
},
265+
{
266+
"cell_type": "code",
267+
"execution_count": null,
268+
"metadata": {},
269+
"outputs": [],
270+
"source": [
271+
"distant_time = 2.0\n",
272+
"while x.get_current_time() < distant_time:\n",
273+
" x.update()"
274+
]
275+
},
276+
{
277+
"cell_type": "markdown",
278+
"metadata": {},
279+
"source": [
280+
"View the final state of the temperature field:"
281+
]
282+
},
283+
{
284+
"cell_type": "code",
285+
"execution_count": null,
286+
"metadata": {},
287+
"outputs": [],
288+
"source": [
289+
"np.set_printoptions(formatter={\"float\": \"{: 5.1f}\".format})\n",
290+
"x.get_value(\"plate_surface__temperature\", temperature_flat)\n",
291+
"print(temperature_flat.reshape(shape))"
292+
]
293+
},
294+
{
295+
"cell_type": "markdown",
296+
"metadata": {},
297+
"source": [
298+
"Note that temperature isn't conserved on the plate:"
299+
]
300+
},
301+
{
302+
"cell_type": "code",
303+
"execution_count": null,
304+
"metadata": {},
305+
"outputs": [],
306+
"source": [
307+
"print(temperature_flat.sum())"
308+
]
309+
},
310+
{
311+
"cell_type": "markdown",
312+
"metadata": {},
313+
"source": [
314+
"End the model:"
315+
]
316+
},
317+
{
318+
"cell_type": "code",
319+
"execution_count": null,
320+
"metadata": {},
321+
"outputs": [],
322+
"source": [
323+
"x.finalize()"
324+
]
325+
}
326+
],
327+
"metadata": {
328+
"kernelspec": {
329+
"display_name": "Python 3 (ipykernel)",
330+
"language": "python",
331+
"name": "python3"
332+
},
333+
"language_info": {
334+
"codemirror_mode": {
335+
"name": "ipython",
336+
"version": 3
337+
},
338+
"file_extension": ".py",
339+
"mimetype": "text/x-python",
340+
"name": "python",
341+
"nbconvert_exporter": "python",
342+
"pygments_lexer": "ipython3",
343+
"version": "3.10.5"
344+
}
345+
},
346+
"nbformat": 4,
347+
"nbformat_minor": 1
348+
}

0 commit comments

Comments
 (0)