{
"cells": [
{
"cell_type": "markdown",
"id": "b40cde8e-a20e-4904-bfec-753a7d82a300",
"metadata": {},
"source": [
"# How to discretize equations \n",
"\n",
"Now we demonstrate how to discretize a PDE object.\n",
"\n",
"Pre-coded sample objects are stored in `sample` attribute of *phyem*. Invoke these samples by"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "d603a38d-c76a-4cf6-b5fc-bbd27c54db4f",
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-18T10:32:44.104942Z",
"iopub.status.busy": "2025-11-18T10:32:44.104784Z",
"iopub.status.idle": "2025-11-18T10:32:45.793130Z",
"shell.execute_reply": "2025-11-18T10:32:45.792596Z"
},
"is_executing": true,
"tags": []
},
"outputs": [],
"source": [
"import phyem as ph # import the phyem package\n",
"ph.config._set_matplot_block(False)\n",
"samples = ph.samples"
]
},
{
"cell_type": "markdown",
"id": "498e0ee3-b788-4265-81a9-ce957c466895",
"metadata": {},
"source": [
"The partial differential equations of the canocical linear por-Hamiltonian are pre-coded. Call it through"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "a343b362-5677-42d7-8dc2-cdb3cca95e45",
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-18T10:32:45.829505Z",
"iopub.status.busy": "2025-11-18T10:32:45.829117Z",
"iopub.status.idle": "2025-11-18T10:32:45.833317Z",
"shell.execute_reply": "2025-11-18T10:32:45.832599Z"
},
"is_executing": true,
"tags": []
},
"outputs": [],
"source": [
"oph = samples.pde_canonical_pH(n=3, p=3, periodic=True)[0] # where o on `oph` means outer"
]
},
{
"cell_type": "markdown",
"id": "702b2712-bd83-468e-9478-3e9c608d1a55",
"metadata": {},
"source": [
"Check `oph`, *outer oriented port-Hamiltonian*, with"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "8fd0eb4d-6350-4268-a3a3-c905926b46a4",
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-18T10:32:45.895569Z",
"iopub.status.busy": "2025-11-18T10:32:45.895070Z",
"iopub.status.idle": "2025-11-18T10:32:46.325851Z",
"shell.execute_reply": "2025-11-18T10:32:46.325076Z"
},
"is_executing": true,
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"<Figure size 800x600 with 1 Axes>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"oph.pr()"
]
},
{
"cell_type": "markdown",
"id": "95eaceec-a95e-4da5-82c7-7e7b1a8770a5",
"metadata": {},
"source": [
"We can take out the knowns and label them by"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "6bb4c1e9-e284-4de6-bf5a-746a707fb08f",
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-18T10:32:46.412528Z",
"iopub.status.busy": "2025-11-18T10:32:46.412171Z",
"iopub.status.idle": "2025-11-18T10:32:46.415403Z",
"shell.execute_reply": "2025-11-18T10:32:46.414823Z"
},
"is_executing": true,
"tags": []
},
"outputs": [],
"source": [
"a3, b2 = oph.unknowns"
]
},
{
"cell_type": "markdown",
"id": "4c0f26a4-49b6-4d3c-aca3-e355f35449c9",
"metadata": {},
"source": [
"We now test `oph` with test functions from the spaces where `a3` and `b2` come from, and label the test functions by $v^3$ and $u^2$,"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "01e41ea7-fbd8-4e0a-80e0-771bd1498ded",
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-18T10:32:46.459801Z",
"iopub.status.busy": "2025-11-18T10:32:46.459468Z",
"iopub.status.idle": "2025-11-18T10:32:46.462635Z",
"shell.execute_reply": "2025-11-18T10:32:46.461957Z"
},
"is_executing": true,
"tags": []
},
"outputs": [],
"source": [
"wf = oph.test_with(oph.unknowns, sym_repr=[r'v^3', r'u^2'])"
]
},
{
"cell_type": "markdown",
"id": "a627673d-fbaa-4b35-9f4b-7184f265d382",
"metadata": {
"tags": []
},
"source": [
"Now, we apply integration by parts to the term indexed by `'1-1'`."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "fec1529c-8a7a-4b5a-9e4c-0c4580f06729",
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-18T10:32:46.506880Z",
"iopub.status.busy": "2025-11-18T10:32:46.506515Z",
"iopub.status.idle": "2025-11-18T10:32:46.509728Z",
"shell.execute_reply": "2025-11-18T10:32:46.509058Z"
},
"is_executing": true,
"tags": []
},
"outputs": [],
"source": [
"wf = wf.derive.integration_by_parts('1-1')"
]
},
{
"cell_type": "markdown",
"id": "65b936bb-c33f-4a14-a0cc-c67ae5d1c00f",
"metadata": {
"tags": []
},
"source": [
"We now apply a particular discretization to this weak formulation,"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "99d09aa1-ef0f-48ae-b104-bb128fd380bb",
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-18T10:32:46.552529Z",
"iopub.status.busy": "2025-11-18T10:32:46.552100Z",
"iopub.status.idle": "2025-11-18T10:32:46.559850Z",
"shell.execute_reply": "2025-11-18T10:32:46.559214Z"
},
"is_executing": true,
"tags": []
},
"outputs": [],
"source": [
"td = wf.td\n",
"td.set_time_sequence() # initialize a time sequence\n",
"td.define_abstract_time_instants('k-1', 'k-1/2', 'k')\n",
"td.differentiate('0-0', 'k-1', 'k')\n",
"td.average('0-1', b2, ['k-1', 'k'])\n",
"\n",
"td.differentiate('1-0', 'k-1', 'k')\n",
"td.average('1-1', a3, ['k-1', 'k'])\n",
"dt = td.time_sequence.make_time_interval('k-1', 'k')\n",
"\n",
"wf = td()\n",
"\n",
"wf.unknowns = [\n",
" a3 @ td.time_sequence['k'],\n",
" b2 @ td.time_sequence['k'],\n",
"]\n",
"\n",
"wf = wf.derive.split(\n",
" '0-0', 'f0',\n",
" [a3 @ td.ts['k'], a3 @ td.ts['k-1']],\n",
" ['+', '-'],\n",
" factors=[1/dt, 1/dt],\n",
")\n",
"\n",
"wf = wf.derive.split(\n",
" '0-2', 'f0',\n",
" [ph.d(b2 @ td.ts['k-1']), ph.d(b2 @ td.ts['k'])],\n",
" ['+', '+'],\n",
" factors=[1/2, 1/2],\n",
")\n",
"\n",
"wf = wf.derive.split(\n",
" '1-0', 'f0',\n",
" [b2 @ td.ts['k'], b2 @ td.ts['k-1']],\n",
" ['+', '-'],\n",
" factors=[1/dt, 1/dt]\n",
")\n",
"\n",
"wf = wf.derive.split(\n",
" '1-2', 'f0',\n",
" [a3 @ td.ts['k-1'], a3 @ td.ts['k']],\n",
" ['+', '+'],\n",
" factors=[1/2, 1/2],\n",
")\n",
"\n",
"wf = wf.derive.rearrange(\n",
" {\n",
" 0: '0, 3 = 2, 1',\n",
" 1: '3, 0 = 2, 1',\n",
" }\n",
")"
]
},
{
"cell_type": "markdown",
"id": "a0de472f-32b1-4c27-93cc-0abe5cbab7b9",
"metadata": {},
"source": [
"We now can write the weak formulation with matrix proxies. Before doing that, we need to "
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "5e30efae-221f-4969-b285-243686f4c1f9",
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-18T10:32:46.614941Z",
"iopub.status.busy": "2025-11-18T10:32:46.614607Z",
"iopub.status.idle": "2025-11-18T10:32:46.619994Z",
"shell.execute_reply": "2025-11-18T10:32:46.619302Z"
},
"is_executing": true,
"tags": []
},
"outputs": [],
"source": [
"ph.space.finite(3)\n",
"mp = wf.mp()"
]
},
{
"cell_type": "markdown",
"id": "2bf04ccc-e555-4eed-9eae-3dc55f1ac324",
"metadata": {},
"source": [
"The matrix format of the weak formulation leads to a linear system,"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "7bffe47c-a9bd-4bcf-95e8-f8ccf14a0ada",
"metadata": {
"execution": {
"iopub.execute_input": "2025-11-18T10:32:46.662091Z",
"iopub.status.busy": "2025-11-18T10:32:46.661714Z",
"iopub.status.idle": "2025-11-18T10:32:46.747389Z",
"shell.execute_reply": "2025-11-18T10:32:46.746548Z"
},
"is_executing": true,
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"<Figure size 1200x600 with 1 Axes>"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ls = mp.ls()\n",
"ls.pr()"
]
},
{
"cell_type": "markdown",
"id": "ba265f8a-8b4f-4704-af51-2e9cc45a222c",
"metadata": {},
"source": [
"Note that, till this moment, everything is still abstract. To do the numerical simulation, we need to bring them to a particular implementation, for example, the `msepy`, standing for *mimetic spectral elements python*, by calling `ph.fem.apply` function, which will be shown in other notebooks."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}