Skip to content

Commit ca47ed9

Browse files
authored
Merge pull request #30 from FusionComputingLab/flux_averaging_example
Added example of flux averaging a 2D field
2 parents 9a61373 + 8f95d3a commit ca47ed9

4 files changed

Lines changed: 120 additions & 17 deletions

File tree

.github/workflows/notebooks.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ on:
88

99
jobs:
1010
notebooks:
11+
strategy:
12+
fail-fast: false
13+
timeout-minutes: 60
1114
if: ${{ github.event.label.name == 'ready-for-final-tests' }}
1215
runs-on: ubuntu-latest
1316
steps:

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,4 @@
130130
"dollarmath",
131131
]
132132

133-
nb_execution_timeout = 600
133+
nb_execution_timeout = 1200

examples/example03 - extracting_equilibrium_quantites.ipynb

Lines changed: 115 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"\n",
7070
"for key in current_values.keys():\n",
7171
" eq.tokamak[key].current = current_values[key]\n",
72+
"eq.tokamak[\"P6\"].current += 100\n",
7273
"\n",
7374
"# carry out forward solve\n",
7475
"GSStaticSolver.solve(eq=eq, \n",
@@ -920,7 +921,30 @@
920921
"ax2.grid(zorder=0, alpha=0.75)\n",
921922
"ax2.plot(psi_n, profiles.ffprime(psi_n), color='k', linewidth=1, marker='x', markersize=2, zorder=10)\n",
922923
"ax2.set_xlabel(r'$\\hat{\\psi}$')\n",
923-
"ax2.set_ylabel(r\"$FF'(\\hat{\\psi})$\")\n"
924+
"ax2.set_ylabel(r\"$FF'(\\hat{\\psi})$\")"
925+
]
926+
},
927+
{
928+
"cell_type": "code",
929+
"execution_count": null,
930+
"metadata": {},
931+
"outputs": [],
932+
"source": [
933+
"# plot the p and F profiles\n",
934+
"\n",
935+
"psi_n = eq.psiN_1D(N=65)\n",
936+
"\n",
937+
"fig1, (ax1, ax2) = plt.subplots(1, 2, figsize=(15,6), dpi=80)\n",
938+
"ax1.grid(zorder=0, alpha=0.75)\n",
939+
"ax1.plot(psi_n, profiles.pressure(psi_n), color='k', linewidth=1, marker='x', markersize=2, zorder=10)\n",
940+
"ax1.set_xlabel(r'$\\hat{\\psi}$')\n",
941+
"ax1.set_ylabel(r\"$p(\\hat{\\psi})$\")\n",
942+
"ax1.ticklabel_format(axis='y', scilimits=(0,0))\n",
943+
"\n",
944+
"ax2.grid(zorder=0, alpha=0.75)\n",
945+
"ax2.plot(psi_n, profiles.fpol(psi_n), color='k', linewidth=1, marker='x', markersize=2, zorder=10)\n",
946+
"ax2.set_xlabel(r'$\\hat{\\psi}$')\n",
947+
"ax2.set_ylabel(r\"$F(\\hat{\\psi})$\")\n"
924948
]
925949
},
926950
{
@@ -996,20 +1020,6 @@
9961020
"plt.tight_layout()"
9971021
]
9981022
},
999-
{
1000-
"cell_type": "code",
1001-
"execution_count": null,
1002-
"metadata": {},
1003-
"outputs": [],
1004-
"source": [
1005-
"# # plot 1D_jtor\n",
1006-
"# fig1, ax1 = plt.subplots(1, 1, figsize=(6,6), dpi=80)\n",
1007-
"# ax1.grid(zorder=0, alpha=0.75)\n",
1008-
"# ax1.plot(eq.psiN_1D(N=101), eq.jtor_1D(N=101), color='k', linewidth=1, marker='x', markersize=2, zorder=10)\n",
1009-
"# ax1.set_xlabel(r'$\\hat{\\psi}$')\n",
1010-
"# ax1.set_ylabel(r\"$J_{tor}(\\hat{\\psi})$\")"
1011-
]
1012-
},
10131023
{
10141024
"cell_type": "markdown",
10151025
"metadata": {},
@@ -1054,6 +1064,96 @@
10541064
"\n",
10551065
"plt.tight_layout()"
10561066
]
1067+
},
1068+
{
1069+
"cell_type": "markdown",
1070+
"metadata": {},
1071+
"source": [
1072+
"### Flux averaged quantities\n",
1073+
"\n",
1074+
"The `equilibrium` class provides a method to calculate the \"flux averaged\" value of a user-defined 2D scalar field $f(R,Z)$, using [line integrals](https://tutorial.math.lamar.edu/classes/calciii/LineIntegralsPtI.aspx), on a given (normalised) flux surface of $\\psi_n$ (within the last closed flux surface). The flux average $\\langle f \\rangle$ is given by\n",
1075+
"\n",
1076+
"$$\n",
1077+
"\\langle f \\rangle (\\psi_n) = \\frac{ \\int_{C(\\psi_n)} \\frac{f(R,Z)}{B_{\\text{pol}}(R,Z)}\\, ds}{ \\int_{C(\\psi_n)} \\frac{1}{B_{\\text{pol}}(R,Z)} \\, ds },\n",
1078+
"$$\n",
1079+
"\n",
1080+
"where:\n",
1081+
"- $f(R,Z)$ = 2D scalar field function (e.g. the plasma current density function $J_p(R,Z)$).\n",
1082+
"- $\\psi_n$ = value of normalised flux at which to evaluate line integrals.\n",
1083+
"- $C(\\psi_n)$ = curve of $(R, Z)$ points satisfying $\\psi_n = \\text{const}$ (i.e. a flux contour).\n",
1084+
"- $B_{\\text{pol}}(R,Z)$ = 2D scalar poloidal magnetic field function.\n",
1085+
"- $ds$ = the arc length element (where $ds = \\sqrt{(dR/dl)^2 + (dZ/dl)^2} dl$ and $l \\in [0,L]$ is a parameterised length going from the beginning to the end of the contour).\n",
1086+
"\n",
1087+
"The definition of the flux average was taken from [Song et al. (2024)](https://www.mdpi.com/2571-6182/7/4/45)."
1088+
]
1089+
},
1090+
{
1091+
"cell_type": "markdown",
1092+
"metadata": {},
1093+
"source": [
1094+
"Here we will calculate the flux averaged values of the plasma current density by first defining a function that returns the current density at arbitrary $(R,Z)$ locations. "
1095+
]
1096+
},
1097+
{
1098+
"cell_type": "code",
1099+
"execution_count": null,
1100+
"metadata": {},
1101+
"outputs": [],
1102+
"source": [
1103+
"from scipy.interpolate import RectBivariateSpline\n",
1104+
"\n",
1105+
"def f(R,Z):\n",
1106+
" jtor = RectBivariateSpline(eq.R_1D, eq.Z_1D, eq._profiles.jtor)\n",
1107+
" return jtor(R, Z, grid=False)"
1108+
]
1109+
},
1110+
{
1111+
"cell_type": "markdown",
1112+
"metadata": {},
1113+
"source": [
1114+
"Next we can call the method in the equilibrium object and plot the results. Given the notation above, we note that $\\psi_n$ and $\\hat{\\psi}$ are equivalent. "
1115+
]
1116+
},
1117+
{
1118+
"cell_type": "code",
1119+
"execution_count": null,
1120+
"metadata": {},
1121+
"outputs": [],
1122+
"source": [
1123+
"# call the method\n",
1124+
"flux_averaged_jtor, psi_n = eq.flux_averaged_function(\n",
1125+
" f=f,\n",
1126+
" psi_n=np.linspace(0.0,1.0,101)\n",
1127+
" )"
1128+
]
1129+
},
1130+
{
1131+
"cell_type": "code",
1132+
"execution_count": null,
1133+
"metadata": {},
1134+
"outputs": [],
1135+
"source": [
1136+
"# plot\n",
1137+
"fig1, ax1 = plt.subplots(1, 1, figsize=(6,6), dpi=80)\n",
1138+
"ax1.grid(zorder=0, alpha=0.75)\n",
1139+
"ax1.plot(psi_n, flux_averaged_jtor, color='k', linewidth=1, marker='x', markersize=2, zorder=10)\n",
1140+
"ax1.set_xlabel(r'$\\hat{\\psi}$')\n",
1141+
"ax1.set_ylabel(r\"$\\langle J_p \\rangle (\\hat{\\psi})$\")"
1142+
]
1143+
},
1144+
{
1145+
"cell_type": "code",
1146+
"execution_count": null,
1147+
"metadata": {},
1148+
"outputs": [],
1149+
"source": [
1150+
"# # for example you could flux average other quantities of interest\n",
1151+
"\n",
1152+
"# # 1/R\n",
1153+
"# def f(R,Z):\n",
1154+
"# g = RectBivariateSpline(eq.R_1D, eq.Z_1D, 1/eq.R)\n",
1155+
"# return g(R, Z, grid=False)"
1156+
]
10571157
}
10581158
],
10591159
"metadata": {

requirements-freegs4e.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
freegs4e~=0.10
1+
freegs4e~=0.11

0 commit comments

Comments
 (0)