xref: /libCEED/examples/python/tutorial-2-elemrestriction.ipynb (revision 7d38c034d40a24f4b961cafe9ae1ebfab6a4cf3f)
1edab6123Sjeremylt{
2edab6123Sjeremylt "cells": [
3edab6123Sjeremylt  {
4edab6123Sjeremylt   "cell_type": "markdown",
5edab6123Sjeremylt   "metadata": {},
6edab6123Sjeremylt   "source": [
7edab6123Sjeremylt    "# libCEED for Python examples\n",
8edab6123Sjeremylt    "\n",
9edab6123Sjeremylt    "This is a tutorial to illustrate the main feautures of the Python interface for [libCEED](https://github.com/CEED/libCEED/), the low-level API library for efficient high-order discretization methods developed by the co-design [Center for Efficient Exascale Discretizations](https://ceed.exascaleproject.org/) (CEED) of the [Exascale Computing Project](https://www.exascaleproject.org/) (ECP).\n",
10edab6123Sjeremylt    "\n",
1113964f07SJed Brown    "While libCEED's focus is on high-order finite/spectral element method implementations, the approach is mostly algebraic and thus applicable to other discretizations in factored form, as explained in the [user manual](https://libceed.org/)."
12edab6123Sjeremylt   ]
13edab6123Sjeremylt  },
14edab6123Sjeremylt  {
15edab6123Sjeremylt   "cell_type": "markdown",
16edab6123Sjeremylt   "metadata": {},
17edab6123Sjeremylt   "source": [
18edab6123Sjeremylt    "## Setting up libCEED for Python\n",
19edab6123Sjeremylt    "\n",
20edab6123Sjeremylt    "Install libCEED for Python by running"
21edab6123Sjeremylt   ]
22edab6123Sjeremylt  },
23edab6123Sjeremylt  {
24edab6123Sjeremylt   "cell_type": "code",
25edab6123Sjeremylt   "execution_count": null,
26edab6123Sjeremylt   "metadata": {},
27edab6123Sjeremylt   "outputs": [],
28edab6123Sjeremylt   "source": [
29edab6123Sjeremylt    "! python -m pip install libceed"
30edab6123Sjeremylt   ]
31edab6123Sjeremylt  },
32edab6123Sjeremylt  {
33edab6123Sjeremylt   "cell_type": "markdown",
34edab6123Sjeremylt   "metadata": {},
35edab6123Sjeremylt   "source": [
36edab6123Sjeremylt    "## CeedElemRestriction\n",
37edab6123Sjeremylt    "\n",
3813964f07SJed Brown    "Here we show some basic examples to illustrate the `libceed.ElemRestriction` class. In libCEED, a `libceed.ElemRestriction` groups the degrees of freedom (dofs) of the local vector according to the different elements they belong to (see [the API documentation](https://libceed.org/en/latest/libCEEDapi.html#finite-element-operator-decomposition)).\n",
39edab6123Sjeremylt    "\n",
40edab6123Sjeremylt    "Here we illustrate the simple creation and application of a `libceed.ElemRestriction`, with user provided dof indices"
41edab6123Sjeremylt   ]
42edab6123Sjeremylt  },
43edab6123Sjeremylt  {
44edab6123Sjeremylt   "cell_type": "code",
45edab6123Sjeremylt   "execution_count": null,
46edab6123Sjeremylt   "metadata": {},
47edab6123Sjeremylt   "outputs": [],
48edab6123Sjeremylt   "source": [
49edab6123Sjeremylt    "import libceed\n",
50edab6123Sjeremylt    "import numpy as np\n",
51edab6123Sjeremylt    "\n",
52edab6123Sjeremylt    "# In this 1D example, the dofs are indexed as\n",
53edab6123Sjeremylt    "#\n",
54edab6123Sjeremylt    "# Restriction input:\n",
55edab6123Sjeremylt    "#  x --  x --  x --  x\n",
56edab6123Sjeremylt    "# 10 -- 11 -- 12 -- 13\n",
57edab6123Sjeremylt    "#\n",
58edab6123Sjeremylt    "# Restriction output:\n",
59edab6123Sjeremylt    "#  x --  x |  x --  x | x --  x\n",
60edab6123Sjeremylt    "# 10 -- 11 | 11 -- 12 | 12 -- 13\n",
61edab6123Sjeremylt    "\n",
62edab6123Sjeremylt    "ceed = libceed.Ceed()\n",
63edab6123Sjeremylt    "\n",
64*235e4399SJeremy L Thompson    "num_elem = 3\n",
65edab6123Sjeremylt    "\n",
66*235e4399SJeremy L Thompson    "x = ceed.Vector(num_elem+1)\n",
67*235e4399SJeremy L Thompson    "a = np.arange(10, 10 + num_elem+1, dtype=\"float64\")\n",
68edab6123Sjeremylt    "x.set_array(a, cmode=libceed.USE_POINTER)\n",
69edab6123Sjeremylt    "\n",
70*235e4399SJeremy L Thompson    "indices = np.zeros(2*num_elem, dtype=\"int32\")\n",
71*235e4399SJeremy L Thompson    "for i in range(num_elem):\n",
72*235e4399SJeremy L Thompson    "  indices[2*i+0] = i\n",
73*235e4399SJeremy L Thompson    "  indices[2*i+1] = i+1\n",
74edab6123Sjeremylt    "    \n",
75*235e4399SJeremy L Thompson    "r = ceed.ElemRestriction(num_elem, 2, 1, 1, num_elem+1, indices, cmode=libceed.USE_POINTER)\n",
76edab6123Sjeremylt    "\n",
77*235e4399SJeremy L Thompson    "y = ceed.Vector(2*num_elem)\n",
78edab6123Sjeremylt    "y.set_value(0)\n",
79edab6123Sjeremylt    "\n",
80edab6123Sjeremylt    "r.apply(x, y)\n",
81edab6123Sjeremylt    "\n",
82edab6123Sjeremylt    "with y.array_read() as y_array:\n",
83edab6123Sjeremylt    "  print('y =', y_array)\n"
84edab6123Sjeremylt   ]
85edab6123Sjeremylt  },
86edab6123Sjeremylt  {
87edab6123Sjeremylt   "cell_type": "markdown",
88edab6123Sjeremylt   "metadata": {},
89edab6123Sjeremylt   "source": [
90edab6123Sjeremylt    "* In the following example, we illustrate how to extract the multiplicity of indices in an element restriction"
91edab6123Sjeremylt   ]
92edab6123Sjeremylt  },
93edab6123Sjeremylt  {
94edab6123Sjeremylt   "cell_type": "code",
95edab6123Sjeremylt   "execution_count": null,
96edab6123Sjeremylt   "metadata": {},
97edab6123Sjeremylt   "outputs": [],
98edab6123Sjeremylt   "source": [
99edab6123Sjeremylt    "# In this 1D example, there are four nodes per element\n",
100edab6123Sjeremylt    "# \n",
101edab6123Sjeremylt    "#  x -- o -- o -- x -- o -- o -- x -- o -- o -- x\n",
102edab6123Sjeremylt    "\n",
103*235e4399SJeremy L Thompson    "num_elem = 3\n",
104edab6123Sjeremylt    "\n",
105*235e4399SJeremy L Thompson    "indices = np.zeros(4*num_elem, dtype=\"int32\")\n",
106edab6123Sjeremylt    "\n",
107*235e4399SJeremy L Thompson    "for i in range(num_elem):\n",
108*235e4399SJeremy L Thompson    "  indices[4*i+0] = i*3+0\n",
109*235e4399SJeremy L Thompson    "  indices[4*i+1] = i*3+1\n",
110*235e4399SJeremy L Thompson    "  indices[4*i+2] = i*3+2\n",
111*235e4399SJeremy L Thompson    "  indices[4*i+3] = i*3+3\n",
112edab6123Sjeremylt    "\n",
113*235e4399SJeremy L Thompson    "r = ceed.ElemRestriction(num_elem, 4, 1, 1, 3*num_elem+1, indices, cmode=libceed.USE_POINTER)\n",
114edab6123Sjeremylt    "\n",
115edab6123Sjeremylt    "mult = r.get_multiplicity()\n",
116edab6123Sjeremylt    "\n",
117edab6123Sjeremylt    "with mult.array_read() as m_array:\n",
118edab6123Sjeremylt    "  print('mult =', m_array)\n"
119edab6123Sjeremylt   ]
120edab6123Sjeremylt  },
121edab6123Sjeremylt  {
122edab6123Sjeremylt   "cell_type": "markdown",
123edab6123Sjeremylt   "metadata": {},
124edab6123Sjeremylt   "source": [
12513964f07SJed Brown    "* In the following example, we illustrate the creation and use of a strided (identity) element restriction. Strided restrictions are typically used for data stored at quadrature points or for vectors stored in the [E-vector](https://libceed.org/en/latest/libCEEDapi.html#finite-element-operator-decomposition) format, such as in Discontinuous Galerkin approximations."
126edab6123Sjeremylt   ]
127edab6123Sjeremylt  },
128edab6123Sjeremylt  {
129edab6123Sjeremylt   "cell_type": "code",
130edab6123Sjeremylt   "execution_count": null,
131edab6123Sjeremylt   "metadata": {},
132edab6123Sjeremylt   "outputs": [],
133edab6123Sjeremylt   "source": [
134edab6123Sjeremylt    "# In this 1D example, the dofs are indexed as\n",
135edab6123Sjeremylt    "#\n",
136edab6123Sjeremylt    "# Restriction input:\n",
137edab6123Sjeremylt    "#   x   --   x   --   x\n",
138edab6123Sjeremylt    "# 10-11 -- 12-13 -- 14-15\n",
139edab6123Sjeremylt    "#\n",
140edab6123Sjeremylt    "# Restriction output:\n",
141edab6123Sjeremylt    "#  x --  x |  x --  x |  x --  x\n",
142edab6123Sjeremylt    "# 10 -- 11 | 12 -- 13 | 14 -- 15\n",
143edab6123Sjeremylt    "\n",
144*235e4399SJeremy L Thompson    "num_elem = 3\n",
145edab6123Sjeremylt    "\n",
146*235e4399SJeremy L Thompson    "x = ceed.Vector(2*num_elem)\n",
147*235e4399SJeremy L Thompson    "a = np.arange(10, 10 + 2*num_elem, dtype=\"float64\")\n",
148edab6123Sjeremylt    "x.set_array(a, cmode=libceed.USE_POINTER)\n",
149edab6123Sjeremylt    "\n",
150edab6123Sjeremylt    "strides = np.array([1, 2, 2], dtype=\"int32\")\n",
151edab6123Sjeremylt    "\n",
152*235e4399SJeremy L Thompson    "r = ceed.StridedElemRestriction(num_elem, 2, 1, 2*num_elem, strides)\n",
153edab6123Sjeremylt    "\n",
154*235e4399SJeremy L Thompson    "y = ceed.Vector(2*num_elem)\n",
155edab6123Sjeremylt    "y.set_value(0)\n",
156edab6123Sjeremylt    "\n",
157edab6123Sjeremylt    "r.apply(x, y)\n",
158edab6123Sjeremylt    "\n",
159edab6123Sjeremylt    "with y.array_read() as y_array:\n",
160edab6123Sjeremylt    "  print('y =', y_array)\n"
161edab6123Sjeremylt   ]
162edab6123Sjeremylt  },
163edab6123Sjeremylt  {
164edab6123Sjeremylt   "cell_type": "markdown",
165edab6123Sjeremylt   "metadata": {},
166edab6123Sjeremylt   "source": [
167edab6123Sjeremylt    "* In the following example, we illustrate the creation and view of a blocked strided (identity) element restriction"
168edab6123Sjeremylt   ]
169edab6123Sjeremylt  },
170edab6123Sjeremylt  {
171edab6123Sjeremylt   "cell_type": "code",
172edab6123Sjeremylt   "execution_count": null,
173edab6123Sjeremylt   "metadata": {},
174edab6123Sjeremylt   "outputs": [],
175edab6123Sjeremylt   "source": [
176edab6123Sjeremylt    "# In this 1D example, there are three elements (four nodes in total) \n",
177edab6123Sjeremylt    "# \n",
178edab6123Sjeremylt    "#  x -- x -- x -- x\n",
179edab6123Sjeremylt    "\n",
180*235e4399SJeremy L Thompson    "num_elem = 3\n",
181edab6123Sjeremylt    "\n",
182edab6123Sjeremylt    "strides = np.array([1, 2, 2], dtype=\"int32\")\n",
183edab6123Sjeremylt    "\n",
184*235e4399SJeremy L Thompson    "r = ceed.BlockedStridedElemRestriction(num_elem, 2, 2, 1, 2*(num_elem+1), strides)\n",
185edab6123Sjeremylt    "\n",
186edab6123Sjeremylt    "print(r)"
187edab6123Sjeremylt   ]
188edab6123Sjeremylt  },
189edab6123Sjeremylt  {
190edab6123Sjeremylt   "cell_type": "markdown",
191edab6123Sjeremylt   "metadata": {},
192edab6123Sjeremylt   "source": [
193edab6123Sjeremylt    "### Advanced topics"
194edab6123Sjeremylt   ]
195edab6123Sjeremylt  },
196edab6123Sjeremylt  {
197edab6123Sjeremylt   "cell_type": "markdown",
198edab6123Sjeremylt   "metadata": {},
199edab6123Sjeremylt   "source": [
200edab6123Sjeremylt    "* In the following example (intended for backend developers), we illustrate the creation of a blocked element restriction (from an L-vector to an E-vector) and its transpose (inverse operation, from an E-vector to an L-vector)"
201edab6123Sjeremylt   ]
202edab6123Sjeremylt  },
203edab6123Sjeremylt  {
204edab6123Sjeremylt   "cell_type": "code",
205edab6123Sjeremylt   "execution_count": null,
206edab6123Sjeremylt   "metadata": {},
207edab6123Sjeremylt   "outputs": [],
208edab6123Sjeremylt   "source": [
209edab6123Sjeremylt    "# In this 1D example, the dofs are indexed as\n",
210edab6123Sjeremylt    "# \n",
211edab6123Sjeremylt    "#  x --  x --  x --  x --  x --  x --  x --  x --  x\n",
212edab6123Sjeremylt    "# 10 -- 11 -- 12 -- 13 -- 14 -- 15 -- 16 -- 17 -- 18\n",
213edab6123Sjeremylt    "# \n",
214edab6123Sjeremylt    "# We block elements into groups of 5:\n",
215edab6123Sjeremylt    "#  ________________________________________________________________________________________\n",
216edab6123Sjeremylt    "# |                   block 0:                            |         block 1:               |\n",
217edab6123Sjeremylt    "# |     e0    |    e1    |    e2    |    e3    |    e4    |    e0    |    e1    |    e2    |\n",
218edab6123Sjeremylt    "# |                                                       |                                |\n",
219edab6123Sjeremylt    "# |  x --  x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x  -- x |\n",
220edab6123Sjeremylt    "# | 10 -- 11  | 11   12  | 12   13  | 13   14  | 14   15  | 15   16  | 16   17  |  17   18 |\n",
221edab6123Sjeremylt    "#\n",
222edab6123Sjeremylt    "# Intermediate logical representation:\n",
223edab6123Sjeremylt    "#  ______________________________________________________________________________\n",
224edab6123Sjeremylt    "# |               block 0:               |               block 1:               |\n",
225edab6123Sjeremylt    "# |     node0:                 node1:    |     node0:                 node1:    |\n",
226edab6123Sjeremylt    "# | 10-11-12-13-14        11-12-13-14-15 | 15-16-17- *- *        16-17-18- *- * |\n",
227edab6123Sjeremylt    "# | e0 e1 e2 e3 e4        e0 e1 e2 e3 e4 | e0 e1 e2 e3 e4        e0 e1 e2 e3 e4 |\n",
228edab6123Sjeremylt    "#\n",
229edab6123Sjeremylt    "# Forward restriction output:\n",
230edab6123Sjeremylt    "#  ______________________________________________________________________________\n",
231edab6123Sjeremylt    "# |               block 0:               |               block 1:               |\n",
232edab6123Sjeremylt    "# |     node0:                 node1:    |     node0:                 node1:    |\n",
233edab6123Sjeremylt    "# | 10-11-12-13-14        11-12-13-14-15 | 15-16-17-17-17        16-17-18-18-18 |\n",
234edab6123Sjeremylt    "# | e0 e1 e2 e3 e4        e0 e1 e2 e3 e4 | e0 e1 e2 e3 e4        e0 e1 e2 e3 e4 |\n",
235edab6123Sjeremylt    "\n",
236*235e4399SJeremy L Thompson    "num_elem = 8\n",
237*235e4399SJeremy L Thompson    "block_size = 5\n",
238edab6123Sjeremylt    "\n",
239*235e4399SJeremy L Thompson    "x = ceed.Vector(num_elem+1)\n",
240*235e4399SJeremy L Thompson    "a = np.arange(10, 10 + num_elem+1, dtype=\"float64\")\n",
241edab6123Sjeremylt    "x.set_array(a, cmode=libceed.USE_POINTER)\n",
242edab6123Sjeremylt    "\n",
243*235e4399SJeremy L Thompson    "indices = np.zeros(2*num_elem, dtype=\"int32\")\n",
244*235e4399SJeremy L Thompson    "for i in range(num_elem):\n",
245*235e4399SJeremy L Thompson    "  indices[2*i+0] = i\n",
246*235e4399SJeremy L Thompson    "  indices[2*i+1] = i+1\n",
247edab6123Sjeremylt    "\n",
248*235e4399SJeremy L Thompson    "r = ceed.BlockedElemRestriction(num_elem, 2, block_size, 1, 1, num_elem+1, indices,\n",
249edab6123Sjeremylt    "                                cmode=libceed.USE_POINTER)\n",
250edab6123Sjeremylt    "\n",
251*235e4399SJeremy L Thompson    "y = ceed.Vector(2*block_size*2)\n",
252edab6123Sjeremylt    "y.set_value(0)\n",
253edab6123Sjeremylt    "\n",
254edab6123Sjeremylt    "r.apply(x, y)\n",
255edab6123Sjeremylt    "\n",
256edab6123Sjeremylt    "with y.array_read() as y_array:\n",
257edab6123Sjeremylt    "  print('y =', y_array)\n",
258edab6123Sjeremylt    "\n",
259edab6123Sjeremylt    "x.set_value(0)\n",
260edab6123Sjeremylt    "r.T.apply(y, x)\n",
261edab6123Sjeremylt    "\n",
262edab6123Sjeremylt    "with x.array_read() as x_array:\n",
263edab6123Sjeremylt    "  print('x =', x_array)"
264edab6123Sjeremylt   ]
265edab6123Sjeremylt  },
266edab6123Sjeremylt  {
267edab6123Sjeremylt   "cell_type": "markdown",
268edab6123Sjeremylt   "metadata": {},
269edab6123Sjeremylt   "source": [
270edab6123Sjeremylt    "* In the following example (intended for backend developers), we illustrate the creation and application of a blocked element restriction (from an L-vector to an E-vector) and its transpose (inverse operation, from an E-vector to an L-vector)"
271edab6123Sjeremylt   ]
272edab6123Sjeremylt  },
273edab6123Sjeremylt  {
274edab6123Sjeremylt   "cell_type": "code",
275edab6123Sjeremylt   "execution_count": null,
276edab6123Sjeremylt   "metadata": {},
277edab6123Sjeremylt   "outputs": [],
278edab6123Sjeremylt   "source": [
279edab6123Sjeremylt    "# In this 1D example, the dofs are indexed as\n",
280edab6123Sjeremylt    "# \n",
281edab6123Sjeremylt    "#  x --  x --  x --  x --  x --  x --  x --  x --  x\n",
282edab6123Sjeremylt    "# 10 -- 11 -- 12 -- 13 -- 14 -- 15 -- 16 -- 17 -- 18\n",
283edab6123Sjeremylt    "#\n",
284edab6123Sjeremylt    "# We block elements into groups of 5:\n",
285edab6123Sjeremylt    "#  ________________________________________________________________________________________\n",
286edab6123Sjeremylt    "# |                   block 0:                            |         block 1:               |\n",
287edab6123Sjeremylt    "# |     e0    |    e1    |    e2    |    e3    |    e4    |    e0    |    e1    |    e2    |\n",
288edab6123Sjeremylt    "# |                                                       |                                |\n",
289edab6123Sjeremylt    "# |  x --  x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x -- x  |  x  -- x |\n",
290edab6123Sjeremylt    "# | 10 -- 11  | 11   12  | 12   13  | 13   14  | 14   15  | 15   16  | 16   17  |  17   18 |\n",
291edab6123Sjeremylt    "#\n",
292edab6123Sjeremylt    "# Intermediate logical representation (extraction of block1 only in this case):\n",
293edab6123Sjeremylt    "#  _______________________________________\n",
294edab6123Sjeremylt    "# |               block 1:               |\n",
295edab6123Sjeremylt    "# |     node0:                 node1:    |\n",
296edab6123Sjeremylt    "# | 15-16-17- *- *        16-17-18- *- * |\n",
297edab6123Sjeremylt    "# | e0 e1 e2 e3 e4        e0 e1 e2 e3 e4 |\n",
298edab6123Sjeremylt    "#\n",
299edab6123Sjeremylt    "# Forward restriction output:\n",
300edab6123Sjeremylt    "#  _______________________________________\n",
301edab6123Sjeremylt    "# |               block 1:               |\n",
302edab6123Sjeremylt    "# |     node0:                 node1:    |\n",
303edab6123Sjeremylt    "# | 15-16-17-17-17        16-17-18-18-18 |\n",
304edab6123Sjeremylt    "# | e0 e1 e2 e3 e4        e0 e1 e2 e3 e4 |\n",
305edab6123Sjeremylt    "\n",
306*235e4399SJeremy L Thompson    "num_elem = 8\n",
307*235e4399SJeremy L Thompson    "block_size = 5\n",
308edab6123Sjeremylt    "\n",
309*235e4399SJeremy L Thompson    "x = ceed.Vector(num_elem+1)\n",
310*235e4399SJeremy L Thompson    "a = np.arange(10, 10 + num_elem+1, dtype=\"float64\")\n",
311edab6123Sjeremylt    "x.set_array(a, cmode=libceed.USE_POINTER)\n",
312edab6123Sjeremylt    "\n",
313*235e4399SJeremy L Thompson    "indices = np.zeros(2*num_elem, dtype=\"int32\")\n",
314*235e4399SJeremy L Thompson    "for i in range(num_elem):\n",
315*235e4399SJeremy L Thompson    "  indices[2*i+0] = i\n",
316*235e4399SJeremy L Thompson    "  indices[2*i+1] = i+1\n",
317edab6123Sjeremylt    "\n",
318*235e4399SJeremy L Thompson    "r = ceed.BlockedElemRestriction(num_elem, 2, block_size, 1, 1, num_elem+1, indices,\n",
319edab6123Sjeremylt    "                                cmode=libceed.USE_POINTER)\n",
320edab6123Sjeremylt    "\n",
321*235e4399SJeremy L Thompson    "y = ceed.Vector(block_size*2)\n",
322edab6123Sjeremylt    "y.set_value(0)\n",
323edab6123Sjeremylt    "\n",
324edab6123Sjeremylt    "r.apply_block(1, x, y)\n",
325edab6123Sjeremylt    "\n",
326edab6123Sjeremylt    "with y.array_read() as y_array:\n",
327edab6123Sjeremylt    "  print('y =', y_array)\n",
328edab6123Sjeremylt    "\n",
329edab6123Sjeremylt    "x.set_value(0)\n",
330edab6123Sjeremylt    "r.T.apply_block(1, y, x)\n",
331edab6123Sjeremylt    "\n",
332edab6123Sjeremylt    "with x.array_read() as array:\n",
333edab6123Sjeremylt    "  print('x =', x_array)"
334edab6123Sjeremylt   ]
335edab6123Sjeremylt  },
336edab6123Sjeremylt  {
337edab6123Sjeremylt   "cell_type": "markdown",
338edab6123Sjeremylt   "metadata": {},
339edab6123Sjeremylt   "source": [
340edab6123Sjeremylt    "Note that the nodes at the boundary between elements have multiplicty 2, while the internal nodes and the outer boundary nodes, have multiplicity 1."
341edab6123Sjeremylt   ]
342edab6123Sjeremylt  }
343edab6123Sjeremylt ],
344edab6123Sjeremylt "metadata": {
345edab6123Sjeremylt  "kernelspec": {
346*235e4399SJeremy L Thompson   "display_name": "Python 3 (ipykernel)",
347edab6123Sjeremylt   "language": "python",
348edab6123Sjeremylt   "name": "python3"
349edab6123Sjeremylt  },
350edab6123Sjeremylt  "language_info": {
351edab6123Sjeremylt   "codemirror_mode": {
352edab6123Sjeremylt    "name": "ipython",
353edab6123Sjeremylt    "version": 3
354edab6123Sjeremylt   },
355edab6123Sjeremylt   "file_extension": ".py",
356edab6123Sjeremylt   "mimetype": "text/x-python",
357edab6123Sjeremylt   "name": "python",
358edab6123Sjeremylt   "nbconvert_exporter": "python",
359edab6123Sjeremylt   "pygments_lexer": "ipython3",
360*235e4399SJeremy L Thompson   "version": "3.13.2"
361edab6123Sjeremylt  }
362edab6123Sjeremylt },
363edab6123Sjeremylt "nbformat": 4,
364edab6123Sjeremylt "nbformat_minor": 4
365edab6123Sjeremylt}
366