From c3b0cc8f42a3df25a0530365d026b5674b71727c Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Fri, 30 Oct 2026 20:22:39 +0000 Subject: [PATCH 1/6] Add documentation pages on the models A new Models section: what every model shares (the submodels, the fluid, the enthalpy method, the surface flux law, resolved or averaged storage along the flow path, power and energy), and a page for each family, the finned tube and the packed bed, with the geometry, the equations and the options. The pages are illustrated with diagrams drawn in TikZ, in docs/models/diagrams/, sharing a preamble with the PyTES colours. The SVGs built from them are committed, so the site builds without TeX; build.py rebuilds them, and CONTRIBUTING explains how. Co-Authored-By: Claude Opus 5.5 --- CONTRIBUTING.md | 9 + changelog.d/48.feature.md | 1 + docs/_static/pytes.css | 9 + docs/getting_started.md | 7 +- docs/index.md | 2 + docs/models/diagrams/build.py | 66 ++++ docs/models/diagrams/capsule.svg | 144 +++++++++ docs/models/diagrams/capsule.tex | 32 ++ docs/models/diagrams/finned_tube.svg | 284 +++++++++++++++++ docs/models/diagrams/finned_tube.tex | 45 +++ docs/models/diagrams/finned_tube_unit.svg | 184 +++++++++++ docs/models/diagrams/finned_tube_unit.tex | 44 +++ docs/models/diagrams/mush.svg | 308 ++++++++++++++++++ docs/models/diagrams/mush.tex | 42 +++ docs/models/diagrams/packed_bed.svg | 352 +++++++++++++++++++++ docs/models/diagrams/packed_bed.tex | 41 +++ docs/models/diagrams/pytes-diagrams.tex | 40 +++ docs/models/diagrams/resolved_averaged.svg | 345 ++++++++++++++++++++ docs/models/diagrams/resolved_averaged.tex | 39 +++ docs/models/diagrams/sharp_front.svg | 249 +++++++++++++++ docs/models/diagrams/sharp_front.tex | 32 ++ docs/models/finned_tube.md | 158 +++++++++ docs/models/index.md | 158 +++++++++ docs/models/packed_bed.md | 110 +++++++ 24 files changed, 2698 insertions(+), 3 deletions(-) create mode 100644 changelog.d/48.feature.md create mode 100644 docs/models/diagrams/build.py create mode 100644 docs/models/diagrams/capsule.svg create mode 100644 docs/models/diagrams/capsule.tex create mode 100644 docs/models/diagrams/finned_tube.svg create mode 100644 docs/models/diagrams/finned_tube.tex create mode 100644 docs/models/diagrams/finned_tube_unit.svg create mode 100644 docs/models/diagrams/finned_tube_unit.tex create mode 100644 docs/models/diagrams/mush.svg create mode 100644 docs/models/diagrams/mush.tex create mode 100644 docs/models/diagrams/packed_bed.svg create mode 100644 docs/models/diagrams/packed_bed.tex create mode 100644 docs/models/diagrams/pytes-diagrams.tex create mode 100644 docs/models/diagrams/resolved_averaged.svg create mode 100644 docs/models/diagrams/resolved_averaged.tex create mode 100644 docs/models/diagrams/sharp_front.svg create mode 100644 docs/models/diagrams/sharp_front.tex create mode 100644 docs/models/finned_tube.md create mode 100644 docs/models/index.md create mode 100644 docs/models/packed_bed.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6681c2..8d5e700 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -290,6 +290,15 @@ and open `docs/_build/html/index.html`. Any warning fails the build, here and in broken cross-reference, a malformed docstring, or a page missing from every table of contents. A new public module needs an entry in one of the pages of `docs/api/`. +The diagrams on the model pages are drawn in TikZ, in +[`docs/models/diagrams/`](docs/models/diagrams), with their colours and styles in a shared +preamble. The SVGs built from them are committed, so the site builds without TeX. After +changing a diagram, rebuild its SVG (this needs TeX with TikZ, and `dvisvgm`): + +```bash +python docs/models/diagrams/build.py capsule # or no name, for every diagram +``` + ## Releasing For maintainers. PyTES uses [semantic versioning](https://semver.org), with pre-releases diff --git a/changelog.d/48.feature.md b/changelog.d/48.feature.md new file mode 100644 index 0000000..ea5e696 --- /dev/null +++ b/changelog.d/48.feature.md @@ -0,0 +1 @@ +New documentation pages on the models: what every model shares, and a page for each family, the finned tube and the packed bed, with the geometry, the equations and the options, illustrated with diagrams drawn in TikZ (`docs/models/diagrams/`). diff --git a/docs/_static/pytes.css b/docs/_static/pytes.css index af0f8fd..7733a28 100644 --- a/docs/_static/pytes.css +++ b/docs/_static/pytes.css @@ -62,3 +62,12 @@ html[data-theme="dark"] { border-radius: 0.15em; box-shadow: 0 0 0 1px var(--pst-color-border, rgba(0, 0, 0, 0.25)); } + +/* Model diagrams (docs/models/diagrams) on a light card in both themes, undimmed in dark + mode (the dark-light class opts them out of the theme's filter) */ +.bd-content img.pytes-diagram { + background-color: #ffffff; + padding: 0.75rem; + border-radius: 0.4rem; + box-shadow: 0 0 0 1px var(--pst-color-border, rgba(0, 0, 0, 0.12)); +} diff --git a/docs/getting_started.md b/docs/getting_started.md index 3e5aa3e..74cd052 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -31,15 +31,16 @@ your own to `pybamm.Simulation` to change them. | Family | Models | Storage | |---|---|---| -| Finned tube | {class}`~pytes.SharpFrontModel`, {class}`~pytes.MushModel` | PCM around tubes with metal fins (homogenised or resolved) | -| Packed bed | {class}`~pytes.PackedBedModel` | a bed of spherical PCM capsules | +| [Finned tube](models/finned_tube.md) | {class}`~pytes.SharpFrontModel`, {class}`~pytes.MushModel` | PCM around tubes with metal fins (homogenised or resolved) | +| [Packed bed](models/packed_bed.md) | {class}`~pytes.PackedBedModel` | a bed of spherical PCM capsules | Every model takes `options={"storage along flow path": "averaged"}` for a faster variant with one storage cross-section standing for the average along the flow, and the packed bed takes `options={"storage element": "lumped"}` for capsules at a uniform temperature ([Lumped capsule](examples/lumped_capsule.ipynb)). Each model is a fixed composition of submodels (a fluid, a storage and a coupling, plus the device-level energy), listed in -`model.submodels`; `model.print_submodel_info()` describes them. +`model.submodels`; `model.print_submodel_info()` describes them. The +[model pages](models/index.md) give the geometry and the equations of each family. ## Conventions diff --git a/docs/index.md b/docs/index.md index aaeb4c2..3dcdd01 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,6 +17,7 @@ ordinary PyBaMM model, so PyBaMM's simulations, solvers and plots work on it dir - [**Getting started**](getting_started.md): install PyTES and run a first model. - [**Examples**](examples/index.md): getting started tutorials, and notebooks for each capability. +- [**Models**](models/index.md): the model families, their geometry and their equations. - [**Plot colours**](plot_colours.md): the PyTES colour cycles and colourmaps, and why. - [**API reference**](api/index.rst): models, submodels, experiments and the toolkit. - [**Design**](design/index.md): the decisions behind PyTES and the model contract. @@ -27,6 +28,7 @@ ordinary PyBaMM model, so PyBaMM's simulations, solvers and plots work on it dir getting_started examples/index +models/index plot_colours api/index design/index diff --git a/docs/models/diagrams/build.py b/docs/models/diagrams/build.py new file mode 100644 index 0000000..0d59e08 --- /dev/null +++ b/docs/models/diagrams/build.py @@ -0,0 +1,66 @@ +""" +Build the SVG model diagrams from their TikZ sources. + +Each ``.tex`` in this folder (other than the shared preamble) is compiled with +``latex`` and converted with ``dvisvgm`` to ``.svg`` next to it, with the text turned +into paths so that the SVGs need no fonts. The SVGs are committed, so the documentation +builds without TeX; rebuild them after changing a source:: + + python docs/models/diagrams/build.py # every diagram + python docs/models/diagrams/build.py capsule # only some + +Needs a TeX distribution with TikZ and the standalone class, and dvisvgm (on Debian or +Ubuntu: ``texlive-pictures texlive-latex-extra dvisvgm``). +""" + +import shutil +import subprocess +import sys +import tempfile +from pathlib import Path + +HERE = Path(__file__).parent +PREAMBLE = "pytes-diagrams.tex" + + +def build(source): + """Compile one TikZ source to an SVG next to it""" + with tempfile.TemporaryDirectory() as tmp: + shutil.copy(HERE / PREAMBLE, tmp) + shutil.copy(source, tmp) + result = subprocess.run( + ["latex", "-interaction=nonstopmode", "-halt-on-error", source.name], + cwd=tmp, + capture_output=True, + text=True, + ) + if result.returncode != 0: + sys.exit(f"{source.name}: latex failed\n{result.stdout[-2000:]}") + dvi = Path(tmp) / source.with_suffix(".dvi").name + svg = source.with_suffix(".svg") + subprocess.run( + [ + "dvisvgm", + "--no-fonts", + "--exact-bbox", + "--optimize", + str(dvi), + "-o", + str(svg), + ], + check=True, + capture_output=True, + ) + print(f"built {svg.relative_to(HERE)}") + + +def main(names): + sources = sorted(p for p in HERE.glob("*.tex") if p.name != PREAMBLE) + if names: + sources = [p for p in sources if p.stem in names] + for source in sources: + build(source) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/docs/models/diagrams/capsule.svg b/docs/models/diagrams/capsule.svg new file mode 100644 index 0000000..af2902d --- /dev/null +++ b/docs/models/diagrams/capsule.svg @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/models/diagrams/capsule.tex b/docs/models/diagrams/capsule.tex new file mode 100644 index 0000000..17424df --- /dev/null +++ b/docs/models/diagrams/capsule.tex @@ -0,0 +1,32 @@ +% One capsule of the packed bed, melting from its surface inwards +\documentclass[tikz, border=4pt]{standalone} +\input{pytes-diagrams} +\begin{document} +\begin{tikzpicture} + \def\R{2.2} + \def\front{1.35} + % The fluid around the capsule + \fill[fluidfill, rounded corners=6pt] (-3.6, -3.1) rectangle (3.6, 3.1); + \node[label, anchor=north west] at (-3.5, 3.0) {fluid at $T_f$}; + % Liquid shell and solid core + \draw[liquid] (0, 0) circle (\R); + \draw[pcm] (0, 0) circle (\front); + \draw[guide] (0, 0) circle (\front); + \node[note] at (0, 0.55) {solid}; + \node[note] at (0, 1.75) {liquid}; + \draw[pytesink, line width=0.4pt] ({\front*cos(250)}, {\front*sin(250)}) -- (-1.2, -2.6) + node[note, below] {melting front}; + % Coordinate and radius + \fill[pytesink] (0, 0) circle (1.5pt); + \draw[axis] (0, 0) -- (2.9, 0) node[label, above] {$r$}; + \draw[dimension] (0, 0) -- (-\R, 0) node[label, pos=0.75, above] {$R$}; + \node[note] at (0, -0.55) {$\partial T/\partial r = 0$}; + % Heat flux from the fluid through the surface + \foreach \a in {30, 90, 150, 210, 330} { + \draw[heat] ({(\R + 0.75)*cos(\a)}, {(\R + 0.75)*sin(\a)}) + -- ({(\R + 0.08)*cos(\a)}, {(\R + 0.08)*sin(\a)}); + } + \node[label, text=pytesorange, anchor=south east] at (3.55, -3.05) + {$q = h_c (T_f - T_s)$}; +\end{tikzpicture} +\end{document} diff --git a/docs/models/diagrams/finned_tube.svg b/docs/models/diagrams/finned_tube.svg new file mode 100644 index 0000000..d34b969 --- /dev/null +++ b/docs/models/diagrams/finned_tube.svg @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/models/diagrams/finned_tube.tex b/docs/models/diagrams/finned_tube.tex new file mode 100644 index 0000000..4aaf213 --- /dev/null +++ b/docs/models/diagrams/finned_tube.tex @@ -0,0 +1,45 @@ +% The finned-tube device: a section along the tubes and a section across them +\documentclass[tikz, border=4pt]{standalone} +\input{pytes-diagrams} +\begin{document} +\begin{tikzpicture} + % (a) Section along the tubes + \begin{scope} + \def\L{7.6} + \def\Hb{3.6} + \fill[pcmfill] (0, 0) rectangle (\L, \Hb); + \foreach \i in {0, ..., 20} { + \fill[metalfill] ({0.25 + 0.36*\i}, 0) rectangle ({0.29 + 0.36*\i}, \Hb); + } + \foreach \yc in {0.6, 1.8, 3.0} { + \draw[fluid] (-0.5, \yc - 0.17) rectangle (\L + 0.5, \yc + 0.17); + \draw[flow] (-1.3, \yc) -- (-0.55, \yc); + \draw[flow] (\L + 0.55, \yc) -- (\L + 1.3, \yc); + } + \draw[outline, line width=1pt] (0, 0) rectangle (\L, \Hb); + \node[label, anchor=east, align=right] at (-1.35, 1.8) {inlet\\$\dot m$, $T_\mathrm{in}$}; + \node[label, anchor=west, align=left] at (\L + 1.35, 1.8) {outlet\\$T_\mathrm{out}$}; + \draw[axis] (0, -0.55) -- (1.4, -0.55) node[label, right] {$z$}; + \draw[dimension] (0, -1.0) -- (\L, -1.0) node[label, midway, fill=white, inner sep=1.5pt] {$Z$}; + \node[note] at (\L/2, \Hb + 0.35) {section along the tubes: $N$ tubes, metal fins, PCM}; + \end{scope} + % (b) Section across the tubes, between two fins + \begin{scope}[shift={(11.2, 0)}] + \def\s{1.2} + \fill[pcmfill] (0, 0) rectangle (3*\s, 3*\s); + \foreach \i in {0, 1, 2} { + \foreach \j in {0, 1, 2} { + \draw[metal] ({(\i + 0.5)*\s}, {(\j + 0.5)*\s}) circle (0.2); + \draw[fluid] ({(\i + 0.5)*\s}, {(\j + 0.5)*\s}) circle (0.17); + } + } + \draw[outline, line width=1pt] (0, 0) rectangle (3*\s, 3*\s); + \draw[pytesorange, line width=0.9pt, dashed] (1.5*\s, 1.5*\s) circle (0.5*\s); + \draw[dimension] (1.5*\s, 1.5*\s) -- ++(-45:0.5*\s) + node[label, pos=1, below right, inner sep=1pt] {$R_f + D$}; + \node[note, text=pytesorange, anchor=north] at (1.5*\s, -0.15) + {the storage around one tube}; + \node[note] at (1.5*\s, 3*\s + 0.35) {section across the tubes}; + \end{scope} +\end{tikzpicture} +\end{document} diff --git a/docs/models/diagrams/finned_tube_unit.svg b/docs/models/diagrams/finned_tube_unit.svg new file mode 100644 index 0000000..7fe15fd --- /dev/null +++ b/docs/models/diagrams/finned_tube_unit.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/models/diagrams/finned_tube_unit.tex b/docs/models/diagrams/finned_tube_unit.tex new file mode 100644 index 0000000..a8c7604 --- /dev/null +++ b/docs/models/diagrams/finned_tube_unit.tex @@ -0,0 +1,44 @@ +% The storage around one tube: half a section along the tube, from its axis outwards +\documentclass[tikz, border=4pt]{standalone} +\input{pytes-diagrams} +\begin{document} +\begin{tikzpicture} + \def\L{7.0} + \def\Rf{0.7} + \def\D{3.0} + \def\dc{0.16} + \def\dm{1.0} + % Fluid in the tube, PCM, fins + \draw[fluid] (0, 0) rectangle (\L, \Rf); + \fill[pcmfill] (0, \Rf) rectangle (\L, \Rf + \D); + \foreach \i in {0, ..., 6} { + \draw[metal] ({0.5 + \i*\dm - \dc/2}, \Rf) rectangle ({0.5 + \i*\dm + \dc/2}, \Rf + \D); + } + \draw[outline] (0, \Rf) rectangle (\L, \Rf + \D); + \draw[outline, line width=1.1pt] (0, \Rf) -- (\L, \Rf); + \draw[symmetry] (-0.3, 0) -- (\L + 0.3, 0); + \node[note, anchor=west] at (\L + 0.3, 0) {tube axis}; + \draw[flow] (1.2, \Rf/2) -- (3.2, \Rf/2) node[label, right, text=pytesblue] {$\dot m / N$}; + % Labels of the materials and the boundaries + \node[note, fill=pcmfill, inner sep=1pt] at ({0.5 + 3.5*\dm}, \Rf + 0.55*\D) {PCM}; + \draw[pytesink, line width=0.4pt] ({0.5 + 5*\dm}, \Rf + 0.3*\D) -- (\L + 0.5, \Rf + 0.3*\D) + node[note, anchor=west] {fin}; + \draw[pytesink, line width=0.4pt] (\L - 0.2, \Rf) -- (\L + 0.5, \Rf + 0.45) + node[note, anchor=west] {tube wall}; + \node[note, anchor=west, align=left] at (\L + 0.3, \Rf + \D - 0.2) + {no flux: half way\\to the next tube}; + % Coordinates and dimensions + \draw[axis] (-1.6, 0) -- (-1.6, 1.3) node[label, left] {$y$}; + \draw[axis] (-1.6, 0) -- (-0.4, 0) node[label, below] {$z$}; + \draw[dimension] (-0.3, 0) -- (-0.3, \Rf) node[label, midway, left] {$R_f$}; + \draw[dimension] (-0.3, \Rf) -- (-0.3, \Rf + \D) node[label, midway, left] {$D$}; + \draw[dimension] ({0.5 + \dm}, \Rf + \D + 0.65) -- ({0.5 + 2*\dm}, \Rf + \D + 0.65) + node[label, midway, above] {$d_m$}; + \draw[guide] ({0.5 + \dm}, \Rf + \D) -- ({0.5 + \dm}, \Rf + \D + 0.8); + \draw[guide] ({0.5 + 2*\dm}, \Rf + \D) -- ({0.5 + 2*\dm}, \Rf + \D + 0.8); + \draw[->, pytesink, line width=0.5pt] ({0.5 + 4*\dm - \dc/2 - 0.45}, \Rf + \D + 0.4) + -- ({0.5 + 4*\dm - \dc/2}, \Rf + \D + 0.4); + \draw[->, pytesink, line width=0.5pt] ({0.5 + 4*\dm + \dc/2 + 0.45}, \Rf + \D + 0.4) + -- ({0.5 + 4*\dm + \dc/2}, \Rf + \D + 0.4) node[label, pos=0, right] {$d_c$}; +\end{tikzpicture} +\end{document} diff --git a/docs/models/diagrams/mush.svg b/docs/models/diagrams/mush.svg new file mode 100644 index 0000000..e41f1c5 --- /dev/null +++ b/docs/models/diagrams/mush.svg @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/models/diagrams/mush.tex b/docs/models/diagrams/mush.tex new file mode 100644 index 0000000..4e48a75 --- /dev/null +++ b/docs/models/diagrams/mush.tex @@ -0,0 +1,42 @@ +% The mush model: a fin and the PCM in the half-gap beside it, at one position along the tube +\documentclass[tikz, border=4pt]{standalone} +\input{pytes-diagrams} +\begin{document} +\begin{tikzpicture} + \def\fin{0.45} % half the fin thickness, d_c / 2 + \def\gap{4.2} % half the fin pitch, d_m / 2 + \def\Rf{0.0} + \def\D{4.0} + % Fluid along the wall, the fin, the PCM + \draw[fluid] (-0.3, -0.7) rectangle (\gap + 0.3, \Rf); + \draw[metal] (0, \Rf) rectangle (\fin, \Rf + \D); + \draw[pcm] (\fin, \Rf) rectangle (\gap, \Rf + \D); + \draw[outline, line width=1.1pt] (-0.3, \Rf) -- (\gap + 0.3, \Rf); + \draw[symmetry] (0, \Rf - 0.9) -- (0, \Rf + \D + 0.5); + \draw[symmetry] (\gap, \Rf - 0.9) -- (\gap, \Rf + \D + 0.5); + \node[note, anchor=south] at (0, \Rf + \D + 0.5) {fin centreline}; + \node[note, anchor=south] at (\gap, \Rf + \D + 0.5) {midplane}; + \node[label, text=pytesblue] at (\gap/2 + 0.4, \Rf - 0.35) {fluid, $T_f(z, t)$}; + % Heat paths: fluid to fin root, along the fin, into the PCM + \draw[heat] (\fin/2, \Rf - 0.55) -- (\fin/2, \Rf + 0.05); + \draw[heat] (\fin/2, \Rf + 0.4) -- (\fin/2, \Rf + 3.3); + \foreach \yc in {0.8, 1.8, 2.8} { + \draw[heat] (\fin + 0.05, \yc) -- (\fin + 1.1, \yc); + } + \node[note, fill=pcmfill, inner sep=1pt, align=center] at (2.9, 3.4) + {PCM: conduction in $x$\\at each $y$}; + \node[note, fill=pcmfill, inner sep=1pt, align=center] at (2.9, 1.3) + {$T = T_\mathrm{fin}$ at the fin face,\\no flux at the midplane}; + \node[note, anchor=east, align=right] at (-0.25, 2.0) + {fin: conduction in $y$,\\heated by the fluid at its root\\and cooled by the PCM}; + \node[note, anchor=east, align=right] at (-0.25, \Rf + \D) {no flux at the tip}; + % Coordinates and dimensions + \draw[axis] (\gap + 0.8, \Rf) -- (\gap + 0.8, \Rf + 1.2) node[label, above] {$y$}; + \draw[axis] (0, -1.4) -- (1.6, -1.4) node[label, right] {$x$}; + \draw[dimension] (0, \Rf + \D + 0.25) -- (\fin, \Rf + \D + 0.25); + \node[label, anchor=south west, inner sep=1pt] at (\fin, \Rf + \D + 0.2) {$d_c / 2$}; + \draw[dimension] (0, -1.85) -- (\gap, -1.85) node[label, midway, below] {$d_m / 2$}; + \draw[dimension] (\gap + 0.4, \Rf) -- (\gap + 0.4, \Rf + \D) + node[label, pos=0.6, right] {$D$}; +\end{tikzpicture} +\end{document} diff --git a/docs/models/diagrams/packed_bed.svg b/docs/models/diagrams/packed_bed.svg new file mode 100644 index 0000000..52a4271 --- /dev/null +++ b/docs/models/diagrams/packed_bed.svg @@ -0,0 +1,352 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/models/diagrams/packed_bed.tex b/docs/models/diagrams/packed_bed.tex new file mode 100644 index 0000000..604f204 --- /dev/null +++ b/docs/models/diagrams/packed_bed.tex @@ -0,0 +1,41 @@ +% The packed bed: capsules in a column, the fluid flowing through the voids +\documentclass[tikz, border=4pt]{standalone} +\input{pytes-diagrams} +\begin{document} +\begin{tikzpicture} + \def\W{3.2} + \def\Z{5.6} + \def\rc{0.26} + % Fluid in the voids, then the capsules in staggered rows + \fill[fluidfill] (0, 0) rectangle (\W, \Z); + \foreach \row in {0, ..., 10} { + \pgfmathsetmacro{\yc}{0.3 + 0.5*\row} + \pgfmathsetmacro{\shift}{mod(\row, 2) == 0 ? 0.3 : 0.56} + \foreach \col in {0, ..., 5} { + \pgfmathsetmacro{\xc}{\shift + 0.52*\col} + \ifdim \xc pt < 3.0pt + \draw[pcm] (\xc, \yc) circle (\rc); + \fi + } + } + \draw[outline, line width=1pt] (0, 0) rectangle (\W, \Z); + % One height: every capsule there is the same + \draw[pytesorange, line width=0.9pt, dashed] (-0.15, 2.52) rectangle (\W + 0.15, 3.08); + \draw[pytesorange, line width=0.5pt] (\W + 0.15, 2.8) -- (\W + 0.6, 2.8) + node[note, anchor=west, text=pytesorange, align=left] + {at each height, one capsule\\stands for all those there}; + % Flow + \draw[flow] (\W/2, -1.1) -- (\W/2, -0.1); + \node[label, anchor=north] at (\W/2, -1.1) {inlet: $\dot m$, $T_\mathrm{in}$}; + \draw[flow] (\W/2, \Z + 0.1) -- (\W/2, \Z + 1.1); + \node[label, anchor=south] at (\W/2, \Z + 1.1) {outlet: $T_\mathrm{out}$}; + % Coordinate and dimensions + \draw[axis] (-0.9, 0) -- (-0.9, 1.4) node[label, left] {$z$}; + \draw[dimension] (-0.45, 0) -- (-0.45, \Z) node[label, midway, left] {$Z$}; + \node[note, anchor=west, align=left] at (\W + 0.6, 4.6) + {cross-sectional area $A$\\porosity $\varepsilon$: volume\\fraction of the fluid}; + \node[note, anchor=west, align=left] at (\W + 0.6, 1.1) + {capsules of\\radius $R$}; + \draw[pytesink, line width=0.4pt] (\W + 0.6, 1.1) -- (2.86, 0.8); +\end{tikzpicture} +\end{document} diff --git a/docs/models/diagrams/pytes-diagrams.tex b/docs/models/diagrams/pytes-diagrams.tex new file mode 100644 index 0000000..a9c9578 --- /dev/null +++ b/docs/models/diagrams/pytes-diagrams.tex @@ -0,0 +1,40 @@ +% Shared preamble of the PyTES model diagrams: packages, colours and styles. +% Each diagram is a standalone document that inputs this file; build them with build.py. +\usepackage{amsmath} +\usepackage{bm} +\usetikzlibrary{arrows.meta, calc, decorations.pathreplacing, patterns, positioning} + +% The PyTES Thermal colour cycle (pytes.plotting.THERMAL) and tints of it +\definecolor{pytesorange}{HTML}{E8590C} +\definecolor{pytesblue}{HTML}{1F4E9C} +\definecolor{pytesteal}{HTML}{14A08A} +\definecolor{pytesamber}{HTML}{F0A930} +\definecolor{pytesplum}{HTML}{A23B72} +\definecolor{pytessky}{HTML}{88C7F0} +\definecolor{pytesink}{HTML}{36312E} + +% Materials: the heat transfer fluid, the PCM, the metal (fins and tubes) +\colorlet{fluidfill}{pytessky!45} +\colorlet{pcmfill}{pytesamber!30} +\colorlet{liquidfill}{pytesorange!35} +\colorlet{metalfill}{pytesink!35} +\colorlet{compositefill}{pcmfill!75!metalfill} + +\tikzset{ + >={Stealth[length=2.2mm]}, + every picture/.style={line join=round, line cap=round, font=\small}, + outline/.style={draw=pytesink, line width=0.6pt}, + fluid/.style={outline, fill=fluidfill}, + pcm/.style={outline, fill=pcmfill}, + liquid/.style={outline, fill=liquidfill}, + metal/.style={outline, fill=metalfill}, + composite/.style={outline, fill=compositefill}, + flow/.style={->, draw=pytesblue, line width=1.2pt}, + heat/.style={->, draw=pytesorange, line width=1.1pt}, + axis/.style={->, draw=pytesink, line width=0.7pt}, + dimension/.style={<->, >={Stealth[length=1.6mm]}, draw=pytesink, line width=0.5pt}, + guide/.style={draw=pytesink!60, line width=0.4pt, dashed}, + symmetry/.style={draw=pytesink, line width=0.5pt, dash dot}, + label/.style={text=pytesink, font=\small}, + note/.style={text=pytesink, font=\footnotesize, align=center}, +} diff --git a/docs/models/diagrams/resolved_averaged.svg b/docs/models/diagrams/resolved_averaged.svg new file mode 100644 index 0000000..135359b --- /dev/null +++ b/docs/models/diagrams/resolved_averaged.svg @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/models/diagrams/resolved_averaged.tex b/docs/models/diagrams/resolved_averaged.tex new file mode 100644 index 0000000..c53a7bf --- /dev/null +++ b/docs/models/diagrams/resolved_averaged.tex @@ -0,0 +1,39 @@ +% "storage along flow path": resolved (a storage at every position) or averaged (one storage) +\documentclass[tikz, border=4pt]{standalone} +\input{pytes-diagrams} +\begin{document} +\begin{tikzpicture} + \def\L{8.0} + % Resolved: one storage cross-section at each position, exchanging with the local fluid + \begin{scope}[shift={(0, 3.4)}] + \node[label, anchor=west, font=\small\bfseries] at (-0.2, 2.3) {resolved (default)}; + \draw[fluid] (0, 0) rectangle (\L, 0.55); + \draw[flow] (0.3, 0.275) -- (1.5, 0.275); + \foreach \i in {0, ..., 6} { + \draw[composite] ({0.25 + 1.1*\i}, 1.05) rectangle ({1.05 + 1.1*\i}, 1.85); + \draw[heat, <->] ({0.65 + 1.1*\i}, 0.6) -- ({0.65 + 1.1*\i}, 1.0); + } + \node[note, anchor=west, align=left] at (\L + 0.3, 1.2) + {storage at each $z$,\\heat with the local\\fluid, $T_f(z)$}; + \end{scope} + % Averaged: one storage cross-section for the whole flow path + \begin{scope} + \node[label, anchor=west, font=\small\bfseries] at (-0.2, 2.6) {averaged}; + \draw[fluid] (0, 0) rectangle (\L, 0.55); + \draw[flow] (0.3, 0.275) -- (1.5, 0.275); + \draw[composite] (\L/2 - 0.4, 1.45) rectangle (\L/2 + 0.4, 2.25); + \draw[decorate, decoration={brace, amplitude=6pt, mirror}, pytesink, line width=0.6pt] + (\L, 0.7) -- (0, 0.7); + \draw[heat, <->] (\L/2, 0.95) -- (\L/2, 1.4); + \node[note, anchor=west, text=pytesorange] at (\L/2 + 0.15, 1.1) + {$h_c (\bar T_f - T_s)$}; + \foreach \i in {0, ..., 14} { + \draw[->, pytesorange, line width=0.6pt, >={Stealth[length=1.2mm]}] + ({0.3 + 0.53*\i}, 0.58) -- ({0.3 + 0.53*\i}, 0.45); + } + \node[note, anchor=west, align=left] at (\L + 0.3, 1.25) + {one storage for the\\whole path, heat with\\the averaged fluid, $\bar T_f$;\\the fluid gains it\\uniformly along $z$}; + \end{scope} + \draw[axis] (0, -0.45) -- (1.2, -0.45) node[label, right] {$z$}; +\end{tikzpicture} +\end{document} diff --git a/docs/models/diagrams/sharp_front.svg b/docs/models/diagrams/sharp_front.svg new file mode 100644 index 0000000..f034cc2 --- /dev/null +++ b/docs/models/diagrams/sharp_front.svg @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/models/diagrams/sharp_front.tex b/docs/models/diagrams/sharp_front.tex new file mode 100644 index 0000000..d558694 --- /dev/null +++ b/docs/models/diagrams/sharp_front.tex @@ -0,0 +1,32 @@ +% The sharp-front model: the homogenised storage in (z, y) above the fluid in the tube +\documentclass[tikz, border=4pt]{standalone} +\input{pytes-diagrams} +\begin{document} +\begin{tikzpicture} + \def\L{7.0} + \def\Rf{0.7} + \def\D{2.8} + \draw[fluid] (0, 0) rectangle (\L, \Rf); + \draw[composite] (0, \Rf) rectangle (\L, \Rf + \D); + \draw[outline, line width=1.1pt] (0, \Rf) -- (\L, \Rf); + \draw[symmetry] (-0.3, 0) -- (\L + 0.3, 0); + \node[note, align=center] at (\L/2, \Rf + 0.62*\D) + {PCM and fins homogenised into one material,\\conduction in $y$ at each $z$}; + % Conduction in y at a few positions along the tube + \foreach \zc in {1.0, 2.6, 4.4, 6.0} { + \draw[heat, <->] (\zc, \Rf + 0.15) -- (\zc, \Rf + 0.95); + } + \draw[flow] (0.9, \Rf/2) -- (2.9, \Rf/2) node[label, right, text=pytesblue] {$h_f(z, t)$}; + % Boundary conditions + \node[note, anchor=south] at (\L/2, \Rf + \D + 0.05) {no flux, $\partial T/\partial y = 0$}; + \node[note, anchor=west, align=left, text=pytesorange] at (\L + 0.3, \Rf) + {wall, $y = R_f$:\\$-k\,\partial T/\partial y = h_c (T_f - T_s)$}; + \node[note, anchor=east, align=right] at (-0.4, \Rf/2) + {inlet:\\$h_f = h(T_\mathrm{in})$}; + \node[note, anchor=west] at (\L + 0.3, 0) {tube axis}; + % Coordinates + \draw[axis] (0, -0.45) -- (1.2, -0.45) node[label, right] {$z$}; + \draw[axis] (\L + 0.4, \Rf + 1.2) -- (\L + 0.4, \Rf + 2.4) node[label, right] {$y$}; + \draw[dimension] (0, -0.95) -- (\L, -0.95) node[label, midway, fill=white, inner sep=1.5pt] {$Z$}; +\end{tikzpicture} +\end{document} diff --git a/docs/models/finned_tube.md b/docs/models/finned_tube.md new file mode 100644 index 0000000..9773a03 --- /dev/null +++ b/docs/models/finned_tube.md @@ -0,0 +1,158 @@ +# Finned tube + +A finned-tube heat battery is a block of phase-change material (PCM) crossed by $N$ +parallel tubes that carry the heat transfer fluid. Thin metal fins, annular discs around +each tube, carry the heat into the PCM, which conducts poorly on its own. The family has +two models: the {class}`~pytes.SharpFrontModel`, which homogenises the fins and the PCM, +and the {class}`~pytes.MushModel`, which resolves them separately. + +## Geometry + +```{figure} diagrams/finned_tube.svg +:class: pytes-diagram dark-light +:width: 720px +:alt: A block of PCM crossed by parallel tubes, with fins across the tubes; and a section across the tubes, with the storage around one tube marked. + +The device, along and across the tubes. All the tubes are the same, so the models describe +one tube and the storage around it. +``` + +The models describe one tube and multiply the device totals by the number of tubes. The +storage around a tube reaches out to a radius $R_f + D$, about half the distance to the +next tube, where no heat crosses by symmetry. In the models, it is an annulus around the +tube. + +```{figure} diagrams/finned_tube_unit.svg +:class: pytes-diagram dark-light +:width: 600px +:alt: Half a section along one tube: the fluid in the tube, the tube wall, and above it the PCM with fins of thickness d_c every d_m, out to a distance D from the wall. + +The storage around one tube, in half a section along it: the fluid flows along the tube +($z$), and the fins and the PCM extend from the tube wall ($y = R_f$) to $y = R_f + D$. +``` + +| Symbol | Parameter | Meaning | +|---|---|---| +| $N$ | `"Number of tubes"` | tubes in the device, in parallel | +| $Z$ | `"Tube length [m]"` | length of the flow path | +| $R_f$ | `"Tube radius [m]"` | inner radius of a tube | +| $D$ | `"Storage depth [m]"` | extent of the storage from the tube wall | +| $d_c$ | `"Fin thickness [m]"` | thickness of a fin | +| $d_m$ | `"Fin pitch [m]"` | distance between the centres of consecutive fins | +| $\delta$ | $d_c / d_m$ | volume fraction of the fins | + +The positions are $z$, along the tube from the inlet; $y$, the distance from the tube axis, +from $R_f$ to $R_f + D$; and, in the mush model only, $x$, the distance from the centreline +of a fin, across the gap to the next one. + +The fluid flows in a tube of flow area $A_\mathrm{flow} = \pi R_f^2$, carrying $\dot m / N$ +(see [the fluid](index.md#the-heat-transfer-fluid)). Both models neglect conduction along +the tube in the storage, the thermal mass and resistance of the tube wall (other than the +heat transfer coefficient), and heat losses to the surroundings. + +## Sharp-front model + +```{figure} diagrams/sharp_front.svg +:class: pytes-diagram dark-light +:width: 640px +:alt: The homogenised storage above the fluid, with conduction in y at each z, a heat flux at the tube wall and no flux at the outer edge. + +The sharp-front model: the PCM and the fins as one material, conducting heat radially at +each position along the tube. +``` + +The PCM and the fins are homogenised into one composite material: its heat capacities are +volume averages, $\rho c = \delta\, \rho c_\mathrm{metal} + (1 - \delta)\, \rho c_\mathrm{PCM}$, +its latent heat is $(1 - \delta)\, \rho L_\mathrm{PCM}$, as only the PCM melts, and its +conductivity is $k = \delta\, k_\mathrm{metal} + (1 - \delta)\, k_\mathrm{PCM}$, the +parallel arrangement, for heat flowing along the fins. At each position $z$, heat is +conducted radially: + +$$ +\frac{\partial H}{\partial t} = \frac{1}{y} \frac{\partial}{\partial y} +\left( y\, k \frac{\partial T}{\partial y} \right), \qquad R_f < y < R_f + D, +$$ + +$$ +-k \frac{\partial T}{\partial y} \bigg|_{y = R_f} = h_c \left( T_f - T_s \right), +\qquad \frac{\partial T}{\partial y} \bigg|_{y = R_f + D} = 0, +$$ + +with $T_s = T|_{y = R_f}$. The fluid gains the heat that crosses the wall, +$q' = 2 \pi R_f\, h_c (T_s - T_f)$ per unit length of tube. With a sharp melting point and +no smoothing, the melting front is sharp, hence the name. + +## Mush model + +```{figure} diagrams/mush.svg +:class: pytes-diagram dark-light +:width: 520px +:alt: A fin and the PCM in the half-gap beside it: heat flows from the fluid into the fin root, along the fin, and from the fin into the PCM. + +The mush model, at one position along the tube: heat flows from the fluid into the root of +a fin, along the fin ($y$), and from the fin into the PCM on either side ($x$). By symmetry, +half a fin and half a gap are modelled. +``` + +The mush model resolves the fins and the PCM separately, at each position $z$ along the +tube. Heat flows from the fluid into the root of each fin, radially along the fin, and from +the fin into the PCM between it and the next fin. The PCM uses the properties of the PCM on +its own. By symmetry, half the gap is modelled, from the face of the fin +($x = d_c / 2$) to the midplane ($x = d_m / 2$). + +In the PCM, heat is conducted across the gap only, at each $y$: + +$$ +\frac{\partial H}{\partial t} = \frac{\partial}{\partial x} +\left( k \frac{\partial T}{\partial x} \right), \qquad +T \big|_{x = d_c / 2} = T_\mathrm{fin}, \qquad +\frac{\partial T}{\partial x} \bigg|_{x = d_m / 2} = 0. +$$ + +In the fins, heat is conducted radially, and the fin gains the heat the PCM on both sides +gives up through its faces: + +$$ +\frac{\partial H_\mathrm{fin}}{\partial t} = \frac{1}{y} \frac{\partial}{\partial y} +\left( y\, k_\mathrm{metal} \frac{\partial T_\mathrm{fin}}{\partial y} \right) ++ \frac{2}{d_c}\, k \frac{\partial T}{\partial x} \bigg|_{x = d_c / 2}, +\qquad R_f < y < R_f + D. +$$ + +The heat the fluid exchanges over one fin pitch of wall enters through the fin root alone, +so the flux into the root is $d_m / d_c$ times the flux at the wall, and no heat crosses the +tip: + +$$ +-k_\mathrm{metal} \frac{\partial T_\mathrm{fin}}{\partial y} \bigg|_{y = R_f} += \frac{d_m}{d_c}\, h_c \left( T_f - T_\mathrm{fin} \big|_{y = R_f} \right), +\qquad \frac{\partial T_\mathrm{fin}}{\partial y} \bigg|_{y = R_f + D} = 0. +$$ + +The fluid again gains $q' = 2 \pi R_f\, h_c (T_\mathrm{fin}|_{y = R_f} - T_f)$ per unit +length of tube. The PCM does not touch the tube wall, and no heat flows through it radially +or along the tube. + +The mush model is three-dimensional ($x$, $y$, $z$), and much slower than the sharp-front +model. With thin, closely spaced fins the two agree closely +([Tutorial 2](../examples/getting_started/tutorial_2_finned_tube_models.ipynb)); the mush +model is the one to use when the fins are thicker or further apart, or when the temperature +between the fins matters. + +## Options + +| Option | Values | +|---|---| +| `"storage along flow path"` | `"resolved"` (default), `"averaged"`: see [resolved or averaged](index.md#resolved-or-averaged-along-the-flow-path) | +| `"heat transfer coefficient"` | `"constant"` (default), `"Gnielinski"`: fully developed flow in a smooth tube ({class}`~pytes.submodels.Gnielinski`), with $\ell = 2 R_f$ | + +The averaged sharp-front model is one-dimensional ($y$), and the averaged mush model +two-dimensional ($x$, $y$). + +## Examples + +- [Tutorial 2: finned-tube models](../examples/getting_started/tutorial_2_finned_tube_models.ipynb) +- [Finned-tube models and their submodels](../examples/finned_tube_models.ipynb) +- [Heat transfer coefficient](../examples/heat_transfer_coefficient.ipynb) + +% TODO(maintainer): add the references for the origin of the sharp-front and mush models. diff --git a/docs/models/index.md b/docs/models/index.md new file mode 100644 index 0000000..6e9b172 --- /dev/null +++ b/docs/models/index.md @@ -0,0 +1,158 @@ +# Models + +PyTES models heat batteries in which a heat transfer fluid flows through or around a +separate storage medium. The models come in families, one per geometry: + +| Family | Models | Storage | +|---|---|---| +| [Finned tube](finned_tube.md) | {class}`~pytes.SharpFrontModel`, {class}`~pytes.MushModel` | a block of PCM with metal fins, crossed by tubes | +| [Packed bed](packed_bed.md) | {class}`~pytes.PackedBedModel` | a bed of spherical PCM capsules | + +This page describes what every model shares: how it is built, the equations of the fluid, +the storage and the coupling between them, and the power and energies. The family pages +describe the geometry and the equations specific to each family. + +```{toctree} +:maxdepth: 1 + +finned_tube +packed_bed +``` + +## How a model is built + +Every model is a fixed composition of submodels, chosen by its options: + +- the **fluid**, the heat transfer fluid flowing along the flow path; +- the **storage**, heat conduction in the storage medium; +- the **coupling**, the heat exchanged between the two at their common surface; +- the **device energy**, the power, the energies and the initial state of the whole device. + +A family may add submodels: the mush model resolves the fins as a second storage, with a +coupling between the fins and the PCM. `model.submodels` lists the submodels of a model, and +`model.print_submodel_info()` gives the variables each one needs and provides, its +parameters and its assumptions. + +The equations below are in SI units, as are the models. Every model describes one flow +path (one tube, or the whole bed) and multiplies the device totals by the number of flow +paths, $N$. + +## The heat transfer fluid + +The state of the fluid is its specific enthalpy $h_f(z, t)$, carried along the flow path +($0 < z < Z$) and heated by the storage: + +$$ +A_\mathrm{flow}\, \rho\, \frac{\partial h_f}{\partial t} ++ \frac{\dot m}{N} \frac{\partial h_f}{\partial z} = q', +\qquad h_f(0, t) = h(T_\mathrm{in}(t)), +$$ + +where $A_\mathrm{flow}$ is the flow area of one path, $\dot m$ the mass flow rate through the +whole device, and $q'$ the heat the fluid gains per unit length of the path, from the +coupling. The outlet temperature is $T_\mathrm{out} = T(h_f(Z, t))$. The fluid properties +come from a fluid-property object as functions of the enthalpy; for the liquids in PyTES +today, the density $\rho$ and the specific heat capacity $c_p$ are constant and +$h(T) = c_p (T - T_\mathrm{ref})$. Conduction and dispersion along the flow are neglected. + +## The storage: the enthalpy method + +Heat is conducted in the storage by the enthalpy method. The state is the enthalpy per unit +volume $H$, which includes the latent heat, and + +$$ +\frac{\partial H}{\partial t} = \nabla \cdot \left( k \nabla T \right), +$$ + +in the coordinates of the storage (cylindrical around a tube, spherical in a capsule, +Cartesian between two fins). The temperature $T(H)$ and the conductivity $k$ come from the +material. A phase-change material melts between its solidus $T_\mathrm{sol}$ and its +liquidus $T_\mathrm{liq}$, a melting range $\Delta T_m$ centred on the melting temperature +$T_m$: + +$$ +H(T) = +\begin{cases} +\rho c_s\, T, & T \le T_\mathrm{sol}, \\ +H_\mathrm{sol} + \left( \dfrac{\rho L}{\Delta T_m} + \overline{\rho c} \right) +(T - T_\mathrm{sol}), & T_\mathrm{sol} < T < T_\mathrm{liq}, \\ +H_\mathrm{liq} + \rho c_l\, (T - T_\mathrm{liq}), & T \ge T_\mathrm{liq}, +\end{cases} +$$ + +with $\rho c_s$ and $\rho c_l$ the volumetric heat capacities of the solid and the liquid, +$\overline{\rho c}$ their mean, and $\rho L$ the latent heat per unit volume. With +$\Delta T_m = 0$ the material has a sharp melting point: the temperature stays at $T_m$ +while the enthalpy crosses the latent heat. The liquid fraction is +$\phi = (H - H_\mathrm{sol}) / (H_\mathrm{liq} - H_\mathrm{sol})$, clipped to $[0, 1]$. +For speed, the corners of $T(H)$ at the solidus and the liquidus are rounded over a small +smoothing width, which may be set to zero. A sensible material, such as the metal of the +fins, has $H = \rho c\, T$. + +Convection in the liquid PCM and the change of volume on melting are neglected. + +## The coupling: heat at the surface + +At the surface between the fluid and the storage, the heat flux into the storage is given +by a surface flux law, by default Newton's law of cooling, + +$$ +q = h_c \left( T_f - T_s \right), +$$ + +with $T_f$ the fluid temperature, $T_s$ the storage temperature at the surface, and $h_c$ +the heat transfer coefficient. The coefficient is chosen with the option +`"heat transfer coefficient"`: `"constant"` (the default) takes it from the parameter +`"Heat transfer coefficient [W.m-2.K-1]"`; a correlation, such as `"Gnielinski"` for the +finned tubes or `"Wakao-Kaguei"` for the packed bed, computes it from a Nusselt number, +$h_c = \mathrm{Nu}\, k_f / \ell$, with $k_f$ the conductivity of the fluid and $\ell$ the +length of the correlation (the tube or the capsule diameter). + +The heat the fluid gains, $q'$, is taken from the storage's own discrete energy balance: +the heat that left the storage through its boundary. This is what makes energy conserved +exactly by the discretised model, whatever the flux law or the material. + +## Resolved or averaged along the flow path + +```{figure} diagrams/resolved_averaged.svg +:class: pytes-diagram dark-light +:width: 640px +:alt: Resolved: a storage cross-section at each position along the flow path, each exchanging heat with the local fluid. Averaged: one storage cross-section exchanging heat with the fluid averaged along the path. + +The option `"storage along flow path"`: a storage cross-section at every position along the +flow (resolved), or one that stands for their average (averaged). +``` + +By default the storage is **resolved**: there is a storage cross-section at every position +$z$, exchanging heat with the fluid there. With +`options={"storage along flow path": "averaged"}`, one storage cross-section stands for the +average along the flow path. It exchanges heat with the fluid averaged along the path, +$\bar h_f = \frac{1}{Z} \int_0^Z h_f \, \mathrm{d}z$, at the temperature +$\bar T_f = T(\bar h_f)$, and the heat it gives up is spread uniformly along the path: +$q'$ is the same at every $z$. This removes one dimension from the storage, so the averaged +models are much faster. They store and deliver the same energy, but cannot represent a +thermal front moving along the flow path ([Tutorial 2](../examples/getting_started/tutorial_2_finned_tube_models.ipynb)). + +## Power and energy + +The power of the device is defined from the enthalpy of the fluid, positive on discharge: + +$$ +P = \dot m \left( h_\mathrm{out} - h_\mathrm{in} \right), +\qquad E_\mathrm{discharged}(t) = \int_0^t P \, \mathrm{d}t'. +$$ + +The total thermal energy $E$ is the energy of the storage and the fluid in the whole device, +zero at the uniform state at the reference temperature. Without heat losses (none of the +models have them yet), $E(t) - E(0) = -E_\mathrm{discharged}(t)$, and the discretised +models meet this to round-off: the [conformance suite](../design/contract.md) checks it +for every model. + +The models have no state of charge: the energy a device holds depends on the temperatures +it works between, a choice of the user. {func}`pytes.energy_between` gives the energy +between two uniform temperatures. + +The device starts uniform at `"Initial temperature [K]"`, each material at its equilibrium +state there: solid at the melting temperature for a sharp melting point, partly liquid +within a melting range. To start from another state, use +`model.set_initial_conditions_from(solution)`. diff --git a/docs/models/packed_bed.md b/docs/models/packed_bed.md new file mode 100644 index 0000000..0e48a06 --- /dev/null +++ b/docs/models/packed_bed.md @@ -0,0 +1,110 @@ +# Packed bed + +A packed-bed heat battery is a column filled with capsules of phase-change material (PCM), +with the heat transfer fluid flowing through the voids between them. The large surface of +the capsules makes heat transfer easy, and the capsules are simple to make and replace. The +family has one model, {class}`~pytes.PackedBedModel`, with options for the capsules. + +## Geometry + +```{figure} diagrams/packed_bed.svg +:class: pytes-diagram dark-light +:width: 440px +:alt: A column of spherical capsules with the fluid flowing upwards through the voids; one height of the bed is marked, where one capsule stands for all those there. + +The packed bed. At each height, every capsule is the same, so one capsule stands for all +those at that height. +``` + +| Symbol | Parameter | Meaning | +|---|---|---| +| $Z$ | `"Bed length [m]"` | length of the bed along the flow | +| $A$ | `"Bed cross-sectional area [m2]"` | area of the bed cross-section | +| $\varepsilon$ | `"Bed porosity"` | volume fraction of the bed taken by the fluid | +| $R$ | `"Capsule radius [m]"` | outer radius of a capsule | + +The positions are $z$, along the bed from the inlet, and $r$, the distance from the centre +of a capsule, from 0 to $R$. The bed holds $(1 - \varepsilon) / (\tfrac{4}{3} \pi R^3)$ +capsules per unit volume, with $a = 3 (1 - \varepsilon) / R$ of capsule surface per unit +volume. + +The bed is a single flow path: the fluid flows through the voids, a flow area +$A_\mathrm{flow} = \varepsilon A$, carrying the whole mass flow rate $\dot m$ (see +[the fluid](index.md#the-heat-transfer-fluid)). The model neglects the capsule shell (its +thermal mass and resistance), conduction between capsules and along the bed in the PCM, +dispersion in the fluid along the bed, and heat losses to the surroundings. + +## Equations + +```{figure} diagrams/capsule.svg +:class: pytes-diagram dark-light +:width: 360px +:alt: A spherical capsule surrounded by fluid, with a liquid shell around a solid core and heat flowing in through its surface. + +One capsule, melting from its surface inwards. Heat enters through the surface and is +conducted radially. +``` + +At each height $z$, heat is conducted radially in a capsule: + +$$ +\frac{\partial H}{\partial t} = \frac{1}{r^2} \frac{\partial}{\partial r} +\left( r^2 k \frac{\partial T}{\partial r} \right), \qquad 0 < r < R, +$$ + +$$ +\frac{\partial T}{\partial r} \bigg|_{r = 0} = 0, \qquad +k \frac{\partial T}{\partial r} \bigg|_{r = R} = h_c \left( T_f - T_s \right), +$$ + +with $T_s = T|_{r = R}$, the temperature at the capsule surface. The fluid gains the heat +that leaves the capsules at that height, $q' = a A\, h_c (T_s - T_f)$ per unit length of +bed. + +## Lumped capsules + +With `options={"storage element": "lumped"}`, each capsule has a uniform temperature: one +enthalpy per capsule, heated through its surface, + +$$ +\frac{\mathrm{d} H}{\mathrm{d} t} = \frac{3}{R}\, h_c \left( T_f - T \right). +$$ + +This is much cheaper, and accurate when conduction inside a capsule is fast compared with +heat transfer at its surface, that is when the capsule's Biot number, $\mathrm{Bi} = h_c R / k$, +is small. `"lumped with Jeffreson"` puts part of the neglected internal resistance back, +through an effective coefficient $h_\mathrm{eff} = h_c / (1 + \mathrm{Bi} / 5)$ +({class}`~pytes.submodels.Jeffreson`), with $k$ the conductivity at the capsule's enthalpy. +The correction is exact for slow changes in a sensible sphere, and an approximation while +the PCM melts or freezes. + +## Options + +| Option | Values | +|---|---| +| `"storage along flow path"` | `"resolved"` (default), `"averaged"`: see [resolved or averaged](index.md#resolved-or-averaged-along-the-flow-path) | +| `"storage element"` | `"resolved"` (default), `"lumped"`, `"lumped with Jeffreson"` | +| `"heat transfer coefficient"` | `"constant"` (default), `"Wakao-Kaguei"`: $\mathrm{Nu} = 2 + 1.1\, \mathrm{Re}^{0.6} \mathrm{Pr}^{1/3}$ ({class}`~pytes.submodels.WakaoKaguei`), with $\ell = 2 R$ and the superficial velocity in $\mathrm{Re}$ | + +The options combine: an averaged bed of lumped capsules is one well-mixed capsule for the +whole bed. In this family, the cross-section averages along the bed (such as +`"Storage cross-section average temperature [K]"`) are the volume averages over a capsule. +The model also gives the device totals per unit cross-sectional area of the bed, such as +`"Power per unit area [W.m-2]"`. The averaged bed is the reduced model of the +[encapsulated-LTES](https://github.com/mmsg-warwick/encapsulated-LTES) repository. + +## Parameter sets + +The default parameter values are the experiments of +[Nallusamy et al. (2007)](https://doi.org/10.1016/j.renene.2006.04.015): a 47 l tank of +paraffin capsules, charged with water at 70 °C. A second set, `"Raul2018"`, gives the +experiments of [Raul et al. (2018)](https://doi.org/10.1016/j.applthermaleng.2018.07.123), +with a heat transfer oil at 180 °C. See {mod}`pytes.parameter_layers`. + +## Examples + +- [Tutorial 3: packed-bed models](../examples/getting_started/tutorial_3_packed_bed_models.ipynb) +- [Packed-bed model](../examples/packed_bed_models.ipynb), against the measurements of + Nallusamy et al. (2007) +- [Lumped capsule](../examples/lumped_capsule.ipynb) +- [Validation](../examples/validation.ipynb), against Schumann's analytical solution From 5a2237c503d03662616551451a24efcfb24cf805 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 20:23:55 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/models/diagrams/capsule.svg | 2 +- docs/models/diagrams/finned_tube.svg | 2 +- docs/models/diagrams/finned_tube_unit.svg | 2 +- docs/models/diagrams/mush.svg | 2 +- docs/models/diagrams/packed_bed.svg | 2 +- docs/models/diagrams/resolved_averaged.svg | 2 +- docs/models/diagrams/sharp_front.svg | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/models/diagrams/capsule.svg b/docs/models/diagrams/capsule.svg index af2902d..5f80f68 100644 --- a/docs/models/diagrams/capsule.svg +++ b/docs/models/diagrams/capsule.svg @@ -141,4 +141,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/finned_tube.svg b/docs/models/diagrams/finned_tube.svg index d34b969..ab1a0a6 100644 --- a/docs/models/diagrams/finned_tube.svg +++ b/docs/models/diagrams/finned_tube.svg @@ -281,4 +281,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/finned_tube_unit.svg b/docs/models/diagrams/finned_tube_unit.svg index 7fe15fd..a7978c4 100644 --- a/docs/models/diagrams/finned_tube_unit.svg +++ b/docs/models/diagrams/finned_tube_unit.svg @@ -181,4 +181,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/mush.svg b/docs/models/diagrams/mush.svg index e41f1c5..c32e44f 100644 --- a/docs/models/diagrams/mush.svg +++ b/docs/models/diagrams/mush.svg @@ -305,4 +305,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/packed_bed.svg b/docs/models/diagrams/packed_bed.svg index 52a4271..428f5dd 100644 --- a/docs/models/diagrams/packed_bed.svg +++ b/docs/models/diagrams/packed_bed.svg @@ -349,4 +349,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/resolved_averaged.svg b/docs/models/diagrams/resolved_averaged.svg index 135359b..ad9cfa6 100644 --- a/docs/models/diagrams/resolved_averaged.svg +++ b/docs/models/diagrams/resolved_averaged.svg @@ -342,4 +342,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/sharp_front.svg b/docs/models/diagrams/sharp_front.svg index f034cc2..b05aeed 100644 --- a/docs/models/diagrams/sharp_front.svg +++ b/docs/models/diagrams/sharp_front.svg @@ -246,4 +246,4 @@ - \ No newline at end of file + From a1e87c56424bdc3932d91a8768328005d517fd7e Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Sat, 31 Oct 2026 11:21:07 +0000 Subject: [PATCH 3/6] Link the example notebooks to each other and to the model pages The finned-tube and packed-bed notebooks link to their model page, with the sketches. Mentions of another notebook become links, each capability notebook points to the tutorial that introduces its subject, and Tutorials 2 to 5 end with a link to the next one. Tutorial 1 points to the next notebook for the finned-tube model. Co-Authored-By: Claude Opus 5.5 --- examples/advection_scheme.ipynb | 2 +- examples/design_study.ipynb | 5 ++-- examples/experiments.ipynb | 4 +++- examples/finned_tube_models.ipynb | 9 +++++--- .../tutorial_1_running_a_model.ipynb | 14 +++++------ .../tutorial_2_finned_tube_models.ipynb | 14 +++++++++-- .../tutorial_3_packed_bed_models.ipynb | 14 +++++++++-- .../tutorial_4_parameter_values.ipynb | 23 ++++++++++++------- .../getting_started/tutorial_5_plotting.ipynb | 11 +++++++-- .../tutorial_6_experiments.ipynb | 5 ++-- examples/heat_transfer_coefficient.ipynb | 3 +-- examples/lumped_capsule.ipynb | 2 +- examples/packed_bed_models.ipynb | 9 +++++--- examples/parameter_layers.ipynb | 4 +++- examples/plot_colours.ipynb | 4 +++- examples/validation.ipynb | 5 ++-- 16 files changed, 85 insertions(+), 43 deletions(-) diff --git a/examples/advection_scheme.ipynb b/examples/advection_scheme.ipynb index c778d1e..10b0492 100644 --- a/examples/advection_scheme.ipynb +++ b/examples/advection_scheme.ipynb @@ -65,7 +65,7 @@ "source": [ "## Against Schumann's solution\n", "\n", - "The sensible packed bed of the validation notebook: capsules conductive enough to be lumped,\n", + "The sensible packed bed of the [validation notebook](validation.ipynb): capsules conductive enough to be lumped,\n", "charged with fluid at 70 °C from 32 °C, against Schumann's analytical solution." ] }, diff --git a/examples/design_study.ipynb b/examples/design_study.ipynb index d1efedf..232c3b6 100644 --- a/examples/design_study.ipynb +++ b/examples/design_study.ipynb @@ -49,7 +49,7 @@ "## Same PCM, same storable energy\n", "\n", "The finned-tube unit is the default sharp-front model, with one tube. The packed bed takes the\n", - "same PCM, fluid and temperatures from it (parameters are layered by prefix, DESIGN D1), and\n", + "same PCM, fluid and temperatures from it (parameters are layered by prefix, DESIGN D1; see [parameter layers](parameter_layers.ipynb)), and\n", "its cross-section is sized with `energy_between` so that it stores the same energy between\n", "10 °C and 70 °C." ] @@ -109,8 +109,7 @@ "source": [ "## The same test for both\n", "\n", - "Both start full (uniform at 70 °C) and deliver 3 kW with water at 10 °C, the flow adjusted\n", - "to hold the power, until the outlet falls below 40 °C." + "Both start full (uniform at 70 °C) and deliver 3 kW with water at 10 °C, the flow adjusted to hold the power (see [experiments](experiments.ipynb)), until the outlet falls below 40 °C." ] }, { diff --git a/examples/experiments.ipynb b/examples/experiments.ipynb index b508510..4c20965 100644 --- a/examples/experiments.ipynb +++ b/examples/experiments.ipynb @@ -14,7 +14,9 @@ "cycles. The result is an ordinary `pybamm.Solution`.\n", "\n", "Power is positive on discharge (heat delivered by the battery), so a charge at constant\n", - "power uses a negative power." + "power uses a negative power.\n", + "\n", + "[Tutorial 6](getting_started/tutorial_6_experiments.ipynb) introduces experiments." ] }, { diff --git a/examples/finned_tube_models.ipynb b/examples/finned_tube_models.ipynb index c326822..1f95f1e 100644 --- a/examples/finned_tube_models.ipynb +++ b/examples/finned_tube_models.ipynb @@ -9,7 +9,11 @@ "\n", "PyTES models are fixed compositions of submodels: a fluid, a storage and a coupling, plus the\n", "device-level energy. This notebook shows how to inspect them, run a discharge, check the\n", - "invariant every model meets (exact energy conservation), and set the initial state." + "invariant every model meets (exact energy conservation), and set the initial state.\n", + "\n", + "For the geometry, the equations and the options of the finned-tube models, with a sketch of each, see the [Finned tube](https://pytes.readthedocs.io/en/latest/models/finned_tube.html) page of the documentation.\n", + "\n", + "[Tutorial 2](getting_started/tutorial_2_finned_tube_models.ipynb) introduces these models." ] }, { @@ -64,8 +68,7 @@ "source": [ "The model is an ordinary PyBaMM model, so `pybamm.Simulation` applies directly. By default\n", "the battery starts uniform at 70 °C (liquid) and is discharged with water at 10 °C. The model\n", - "has no cut-off: it runs to the final time, and cut-offs are the terminations of an\n", - "experiment (`pytes.experiments`)." + "has no cut-off: it runs to the final time, and cut-offs are the terminations of an experiment (`pytes.experiments`; see [experiments](experiments.ipynb))." ] }, { diff --git a/examples/getting_started/tutorial_1_running_a_model.ipynb b/examples/getting_started/tutorial_1_running_a_model.ipynb index 314a1f5..cb4bc8a 100644 --- a/examples/getting_started/tutorial_1_running_a_model.ipynb +++ b/examples/getting_started/tutorial_1_running_a_model.ipynb @@ -52,7 +52,7 @@ "metadata": {}, "source": [ "`SharpFrontModel` is a heat battery made of a block of phase-change material (PCM) with\n", - "aluminium fins, crossed by a tube carrying water. Every model comes with default parameter\n", + "aluminium fins, crossed by a tube carrying water (more on this in the next notebook). Every model comes with default parameter\n", "values, a mesh and a solver, so it runs as it is. For this model the defaults are a\n", "discharge: the battery starts fully charged, uniform at 70 °C, and water enters at 10 °C\n", "and 0.02 kg/s for one hour.\n", @@ -604,8 +604,8 @@ "description_allow_html": false, "disabled": false, "layout": "IPY_MODEL_dd9c56e38dde41e79f28823873bde50d", - "max": 1.0, - "min": 0.0, + "max": 1, + "min": 0, "orientation": "horizontal", "readout": true, "readout_format": ".2f", @@ -613,7 +613,7 @@ "style": "IPY_MODEL_a60c69842a5442c9b60687a2d384595e", "tabbable": null, "tooltip": null, - "value": 0.0 + "value": 0 } }, "9a017645f49546b6ab00f51826cdfd5f": { @@ -758,8 +758,8 @@ "description_allow_html": false, "disabled": false, "layout": "IPY_MODEL_19b5185ffe544d43aba35a93f0681afb", - "max": 1.0, - "min": 0.0, + "max": 1, + "min": 0, "orientation": "horizontal", "readout": true, "readout_format": ".2f", @@ -767,7 +767,7 @@ "style": "IPY_MODEL_74cfc97b0b5248589beaf80ceea4e99c", "tabbable": null, "tooltip": null, - "value": 0.0 + "value": 0 } } }, diff --git a/examples/getting_started/tutorial_2_finned_tube_models.ipynb b/examples/getting_started/tutorial_2_finned_tube_models.ipynb index 781907c..6ef6b59 100644 --- a/examples/getting_started/tutorial_2_finned_tube_models.ipynb +++ b/examples/getting_started/tutorial_2_finned_tube_models.ipynb @@ -18,7 +18,9 @@ "\n", "- $z$, along the tube from the inlet,\n", "- $y$, the distance from the tube axis, from $R_f$ to $R_f + D$,\n", - "- $x$, across the gap between two fins (only in the mush model)." + "- $x$, across the gap between two fins (only in the mush model).\n", + "\n", + "The [Finned tube](https://pytes.readthedocs.io/en/latest/models/finned_tube.html) page of the documentation describes the geometry, the equations and the options of these models in full, with a sketch of each." ] }, { @@ -150,7 +152,7 @@ "metadata": {}, "source": [ "`model.print_submodel_info()` lists, for each submodel, the variables it needs and\n", - "provides, its parameters and its assumptions.\n", + "provides, its parameters and its assumptions. To build a model from submodels of your own choice, see [composing models](../composing_models.ipynb).\n", "\n", "## The melting front\n", "\n", @@ -326,6 +328,14 @@ "Every variant has the same outputs, conserves energy exactly, and runs the same experiments\n", "(Tutorial 6). The next tutorial does the same for the packed-bed family." ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next: [Tutorial 3: packed-bed models](tutorial_3_packed_bed_models.ipynb)." + ], + "id": "267ceed3" } ], "metadata": { diff --git a/examples/getting_started/tutorial_3_packed_bed_models.ipynb b/examples/getting_started/tutorial_3_packed_bed_models.ipynb index 0935719..764d6c3 100644 --- a/examples/getting_started/tutorial_3_packed_bed_models.ipynb +++ b/examples/getting_started/tutorial_3_packed_bed_models.ipynb @@ -21,7 +21,9 @@ "- $r$, the distance from the centre of a capsule, from 0 to $R$.\n", "\n", "The default parameter values are the experiments of Nallusamy et al. (2007): a 47 l tank\n", - "of paraffin capsules, initially at 32 °C, charged with water at 70 °C." + "of paraffin capsules, initially at 32 °C, charged with water at 70 °C.\n", + "\n", + "The [Packed bed](https://pytes.readthedocs.io/en/latest/models/packed_bed.html) page of the documentation describes the geometry, the equations and the options of this model in full, with sketches." ] }, { @@ -251,7 +253,7 @@ "source": [ "## Resolved or averaged along the bed\n", "\n", - "As for the finned tubes, the option `\"storage along flow path\": \"averaged\"` replaces the\n", + "As for the finned tubes ([Tutorial 2](tutorial_2_finned_tube_models.ipynb)), the option `\"storage along flow path\": \"averaged\"` replaces the\n", "capsules along the bed with one capsule that stands for their average, exchanging heat with\n", "the fluid averaged along the bed." ] @@ -340,6 +342,14 @@ "capsule a uniform temperature instead of resolving it: much cheaper, and accurate for small\n", "or highly conductive capsules. See the [lumped capsule](../lumped_capsule.ipynb) example." ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next: [Tutorial 4: changing parameter values](tutorial_4_parameter_values.ipynb)." + ], + "id": "29da107f" } ], "metadata": { diff --git a/examples/getting_started/tutorial_4_parameter_values.ipynb b/examples/getting_started/tutorial_4_parameter_values.ipynb index 9a600f4..61ad6f7 100644 --- a/examples/getting_started/tutorial_4_parameter_values.ipynb +++ b/examples/getting_started/tutorial_4_parameter_values.ipynb @@ -134,8 +134,7 @@ "parameter values to the simulation. `model.default_parameter_values` returns a new copy\n", "each time, so the defaults are never changed.\n", "\n", - "Here the battery is discharged with twice the default flow, and with twice the flow and\n", - "four tubes instead of one." + "Here the battery is discharged with twice the default flow (which is the total flow into the device), and with twice the flow but now spread over four tubes instead of one." ] }, { @@ -508,6 +507,14 @@ "Layers also build an operation that suits a PCM, compose sets for other families and record\n", "the sources of every value: see the [parameter layers](../parameter_layers.ipynb) example." ] + }, + { + "cell_type": "markdown", + "id": "00cb51bb", + "metadata": {}, + "source": [ + "Next: [Tutorial 5: plotting](tutorial_5_plotting.ipynb)." + ] } ], "metadata": { @@ -648,8 +655,8 @@ "description_allow_html": false, "disabled": false, "layout": "IPY_MODEL_fc44197b6db943d7b9b3b04655cd0adc", - "max": 1.0, - "min": 0.0, + "max": 1, + "min": 0, "orientation": "horizontal", "readout": true, "readout_format": ".2f", @@ -657,7 +664,7 @@ "style": "IPY_MODEL_99e8544936ad4becbf1c07f3fdd13423", "tabbable": null, "tooltip": null, - "value": 0.0 + "value": 0 } }, "48f2a8a8223e43b3ae168b9eb47fcfe1": { @@ -883,8 +890,8 @@ "description_allow_html": false, "disabled": false, "layout": "IPY_MODEL_bbd4e1d08f5e44aaa623df433217448c", - "max": 1.0, - "min": 0.0, + "max": 1, + "min": 0, "orientation": "horizontal", "readout": true, "readout_format": ".2f", @@ -892,7 +899,7 @@ "style": "IPY_MODEL_0ca3de8063304ef3a0ab19c77fa6eaad", "tabbable": null, "tooltip": null, - "value": 0.0 + "value": 0 } }, "ac30d776f3cb475b8dfbba8e4471cc69": { diff --git a/examples/getting_started/tutorial_5_plotting.ipynb b/examples/getting_started/tutorial_5_plotting.ipynb index 1b5039c..50f59c5 100644 --- a/examples/getting_started/tutorial_5_plotting.ipynb +++ b/examples/getting_started/tutorial_5_plotting.ipynb @@ -13,8 +13,7 @@ "2. the standard plots of `pytes.plotting`, which compare designs the same way every time;\n", "3. your own matplotlib figures, from the values in the solution.\n", "\n", - "All three work on the same solutions. Here they are a discharge of the finned-tube battery\n", - "and a charge of the packed bed." + "All three work on the same solutions. Here they are a discharge of the finned-tube battery ([Tutorial 2](tutorial_2_finned_tube_models.ipynb)) and a charge of the packed bed ([Tutorial 3](tutorial_3_packed_bed_models.ipynb))." ] }, { @@ -343,6 +342,14 @@ " ax.legend(title=\"Height\")\n", " plt.show()" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next: [Tutorial 6: experiments](tutorial_6_experiments.ipynb)." + ], + "id": "14e2da59" } ], "metadata": { diff --git a/examples/getting_started/tutorial_6_experiments.ipynb b/examples/getting_started/tutorial_6_experiments.ipynb index 0fd0d87..dbf4184 100644 --- a/examples/getting_started/tutorial_6_experiments.ipynb +++ b/examples/getting_started/tutorial_6_experiments.ipynb @@ -56,8 +56,7 @@ "source": [ "## A first experiment\n", "\n", - "Temperatures are in kelvin, mass flow rates in kg/s and times in seconds. This step is the\n", - "default discharge of the earlier tutorials, water at 10 °C and 0.02 kg/s, but it stops when\n", + "Temperatures are in kelvin, mass flow rates in kg/s and times in seconds. This step is the default discharge of the earlier tutorials (see [Tutorial 2](tutorial_2_finned_tube_models.ipynb)), water at 10 °C and 0.02 kg/s, but it stops when\n", "the outlet falls below 40 °C, the lowest useful temperature for hot water, instead of after\n", "an hour." ] @@ -228,7 +227,7 @@ "id": "468d0810", "metadata": {}, "source": [ - "The whole experiment is one solution, so every plot of Tutorial 5 applies to it.\n", + "The whole experiment is one solution, so every plot of [Tutorial 5](tutorial_5_plotting.ipynb) applies to it.\n", "`solution.cycles` holds one solution per cycle, and `cycle.steps` one per step." ] }, diff --git a/examples/heat_transfer_coefficient.ipynb b/examples/heat_transfer_coefficient.ipynb index d1bf3e2..4520fda 100644 --- a/examples/heat_transfer_coefficient.ipynb +++ b/examples/heat_transfer_coefficient.ipynb @@ -340,8 +340,7 @@ "metadata": {}, "source": [ "A law that is not a Nusselt correlation, such as a wall resistance in series or a\n", - "nonlinear law, goes to the coupling through the composition API instead (see\n", - "`composing_models.ipynb`)." + "nonlinear law, goes to the coupling through the composition API instead (see [composing models](composing_models.ipynb))." ] } ], diff --git a/examples/lumped_capsule.ipynb b/examples/lumped_capsule.ipynb index 129adf2..5ced405 100644 --- a/examples/lumped_capsule.ipynb +++ b/examples/lumped_capsule.ipynb @@ -175,7 +175,7 @@ "Energy is conserved exactly whichever variant is used, and the lumped option combines with\n", "`\"storage along flow path\": \"averaged\"` (one well-mixed capsule for the whole bed) and with\n", "any heat transfer coefficient. On Schumann's benchmark, with sensible capsules, the lumped\n", - "bed is Schumann's model itself (see the validation notebook)." + "bed is Schumann's model itself (see the [validation notebook](validation.ipynb))." ] } ], diff --git a/examples/packed_bed_models.ipynb b/examples/packed_bed_models.ipynb index 8f6bce1..fc3ac4c 100644 --- a/examples/packed_bed_models.ipynb +++ b/examples/packed_bed_models.ipynb @@ -10,11 +10,14 @@ "`PackedBedModel` describes a bed of spherical PCM capsules with the heat transfer fluid\n", "flowing through the voids. At each point along the bed, heat conducts across a capsule\n", "(resolved radially) and into the fluid at its surface. It is built from the same submodels\n", - "as the finned-tube models, so it has the same outputs, conserves energy exactly and runs the\n", - "same experiments.\n", + "as the finned-tube models, so it has the same outputs, conserves energy exactly and runs the same [experiments](experiments.ipynb).\n", "\n", "The default parameters are the experiments of Nallusamy et al. (2007): a 47 l tank of\n", - "paraffin capsules in water, charged with water at 70 °C from 32 °C." + "paraffin capsules in water, charged with water at 70 °C from 32 °C.\n", + "\n", + "For the geometry, the equations and the options of the packed-bed model, with sketches, see the [Packed bed](https://pytes.readthedocs.io/en/latest/models/packed_bed.html) page of the documentation.\n", + "\n", + "[Tutorial 3](getting_started/tutorial_3_packed_bed_models.ipynb) introduces this model." ] }, { diff --git a/examples/parameter_layers.ipynb b/examples/parameter_layers.ipynb index 3cce64e..3151291 100644 --- a/examples/parameter_layers.ipynb +++ b/examples/parameter_layers.ipynb @@ -12,7 +12,9 @@ "and the storage element (DESIGN D1). Each layer holds its own parameter names, so one part\n", "of a set, such as the PCM, can be swapped without touching the rest. Each layer lists the\n", "sources of its values in `\"citations\"`, and a composed set is a plain\n", - "`pybamm.ParameterValues`." + "`pybamm.ParameterValues`.\n", + "\n", + "[Tutorial 4](getting_started/tutorial_4_parameter_values.ipynb) introduces parameter values and layers." ] }, { diff --git a/examples/plot_colours.ipynb b/examples/plot_colours.ipynb index be14feb..df704bf 100644 --- a/examples/plot_colours.ipynb +++ b/examples/plot_colours.ipynb @@ -17,7 +17,9 @@ " in `_r`) when `pytes.plotting` is imported.\n", "\n", "They are available but not yet the default: matplotlib's own colours apply until you ask for\n", - "these. This notebook shows each of them on a packed bed charge." + "these. This notebook shows each of them on a packed bed charge.\n", + "\n", + "[Tutorial 5](getting_started/tutorial_5_plotting.ipynb) introduces plotting PyTES solutions." ] }, { diff --git a/examples/validation.ipynb b/examples/validation.ipynb index 1bad7d0..3284ab3 100644 --- a/examples/validation.ipynb +++ b/examples/validation.ipynb @@ -9,8 +9,7 @@ "\n", "Two analytical solutions from `pytes.validation` check the packed-bed model: Schumann's\n", "solution for a bed of a sensible material, and the melting of a sphere (the spherical\n", - "Stefan problem). Both models are built from the packed bed's own submodels with\n", - "`pytes.ComposedModel`, swapping only what each benchmark needs." + "Stefan problem). Both models are built from the packed bed's own submodels with `pytes.ComposedModel` (see [composing models](composing_models.ipynb)), swapping only what each benchmark needs." ] }, { @@ -141,7 +140,7 @@ "With the default, second-order scheme the model is within 1 % of Schumann's solution on 50\n", "cells. On finer meshes about 0.3 % is left: the difference between a capsule that conducts\n", "heat and Schumann's lumped one. (With first-order upwinding, numerical diffusion leaves\n", - "1.3 % on 400 cells: see the advection scheme notebook.)" + "1.3 % on 400 cells: see the [advection scheme](advection_scheme.ipynb) notebook.)" ] }, { From 01671eb58d76b265e5f1844a628e83f29853474c Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Sat, 31 Oct 2026 11:26:25 +0000 Subject: [PATCH 4/6] Link Tutorial 1 to the other tutorials The list of tutorials, the pointer to the next notebook and the closing sentence become links, and the notebook ends with a link to Tutorial 2, as the others do. Co-Authored-By: Claude Opus 5.5 --- .../tutorial_1_running_a_model.ipynb | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/examples/getting_started/tutorial_1_running_a_model.ipynb b/examples/getting_started/tutorial_1_running_a_model.ipynb index cb4bc8a..11bb9d6 100644 --- a/examples/getting_started/tutorial_1_running_a_model.ipynb +++ b/examples/getting_started/tutorial_1_running_a_model.ipynb @@ -10,11 +10,11 @@ "This is the first of a series of short tutorials, each showing one thing:\n", "\n", "1. Running a model (this notebook)\n", - "2. Finned-tube models\n", - "3. Packed-bed models\n", - "4. Changing parameter values\n", - "5. Plotting\n", - "6. Experiments\n", + "2. [Finned-tube models](tutorial_2_finned_tube_models.ipynb)\n", + "3. [Packed-bed models](tutorial_3_packed_bed_models.ipynb)\n", + "4. [Changing parameter values](tutorial_4_parameter_values.ipynb)\n", + "5. [Plotting](tutorial_5_plotting.ipynb)\n", + "6. [Experiments](tutorial_6_experiments.ipynb)\n", "\n", "PyTES models are [PyBaMM](https://pybamm.org) models, so if you know PyBaMM you already\n", "know most of what follows. If you do not, nothing here assumes it.\n", @@ -52,7 +52,7 @@ "metadata": {}, "source": [ "`SharpFrontModel` is a heat battery made of a block of phase-change material (PCM) with\n", - "aluminium fins, crossed by a tube carrying water (more on this in the next notebook). Every model comes with default parameter\n", + "aluminium fins, crossed by a tube carrying water (more on this in the [next notebook](tutorial_2_finned_tube_models.ipynb)). Every model comes with default parameter\n", "values, a mesh and a solver, so it runs as it is. For this model the defaults are a\n", "discharge: the battery starts fully charged, uniform at 70 °C, and water enters at 10 °C\n", "and 0.02 kg/s for one hour.\n", @@ -225,8 +225,16 @@ "id": "1296e8c1", "metadata": {}, "source": [ - "The next two tutorials look at these two families of models in more detail." + "The next two tutorials look at these two families of models in more detail: [finned tubes](tutorial_2_finned_tube_models.ipynb) and [packed beds](tutorial_3_packed_bed_models.ipynb)." ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next: [Tutorial 2: finned-tube models](tutorial_2_finned_tube_models.ipynb)." + ], + "id": "39328f9e" } ], "metadata": { From 81c7a3ce411eaf8dfcc3a6119dced731a486919d Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Sat, 31 Oct 2026 16:24:18 +0000 Subject: [PATCH 5/6] Cite the model papers and brighten the model diagrams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cite Luckins and Brosa Planella (2025) for the finned-tube models, and Brosa Planella (2025) and Ismail and Henríquez (2002) for the packed bed. Move the mush diagram's labels inside the PCM and use stronger tints of the PyTES Thermal colours in every diagram. Co-Authored-By: Claude Opus 5.5 --- docs/models/diagrams/capsule.svg | 8 +- docs/models/diagrams/finned_tube.svg | 50 ++++---- docs/models/diagrams/finned_tube_unit.svg | 22 ++-- docs/models/diagrams/mush.svg | 16 +-- docs/models/diagrams/mush.tex | 4 +- docs/models/diagrams/packed_bed.svg | 126 ++++++++++----------- docs/models/diagrams/pytes-diagrams.tex | 10 +- docs/models/diagrams/resolved_averaged.svg | 22 ++-- docs/models/diagrams/sharp_front.svg | 6 +- docs/models/finned_tube.md | 16 ++- docs/models/packed_bed.md | 17 ++- 11 files changed, 159 insertions(+), 138 deletions(-) diff --git a/docs/models/diagrams/capsule.svg b/docs/models/diagrams/capsule.svg index 5f80f68..3316c58 100644 --- a/docs/models/diagrams/capsule.svg +++ b/docs/models/diagrams/capsule.svg @@ -42,7 +42,7 @@ - + @@ -53,9 +53,9 @@ - + - + @@ -141,4 +141,4 @@ - + \ No newline at end of file diff --git a/docs/models/diagrams/finned_tube.svg b/docs/models/diagrams/finned_tube.svg index ab1a0a6..66bd04b 100644 --- a/docs/models/diagrams/finned_tube.svg +++ b/docs/models/diagrams/finned_tube.svg @@ -49,8 +49,8 @@ - - + + @@ -73,7 +73,7 @@ - + @@ -81,7 +81,7 @@ - + @@ -89,7 +89,7 @@ - + @@ -180,42 +180,42 @@ - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -281,4 +281,4 @@ - + \ No newline at end of file diff --git a/docs/models/diagrams/finned_tube_unit.svg b/docs/models/diagrams/finned_tube_unit.svg index a7978c4..6e3979c 100644 --- a/docs/models/diagrams/finned_tube_unit.svg +++ b/docs/models/diagrams/finned_tube_unit.svg @@ -37,22 +37,22 @@ - + - - + + - + - + - + - + - + - + @@ -78,7 +78,7 @@ - + @@ -181,4 +181,4 @@ - + \ No newline at end of file diff --git a/docs/models/diagrams/mush.svg b/docs/models/diagrams/mush.svg index c32e44f..193391c 100644 --- a/docs/models/diagrams/mush.svg +++ b/docs/models/diagrams/mush.svg @@ -56,11 +56,11 @@ - + - + - + @@ -120,8 +120,8 @@ - - + + @@ -147,9 +147,9 @@ - + - + @@ -305,4 +305,4 @@ - + \ No newline at end of file diff --git a/docs/models/diagrams/mush.tex b/docs/models/diagrams/mush.tex index 4e48a75..2d8445f 100644 --- a/docs/models/diagrams/mush.tex +++ b/docs/models/diagrams/mush.tex @@ -23,9 +23,9 @@ \foreach \yc in {0.8, 1.8, 2.8} { \draw[heat] (\fin + 0.05, \yc) -- (\fin + 1.1, \yc); } - \node[note, fill=pcmfill, inner sep=1pt, align=center] at (2.9, 3.4) + \node[note, fill=pcmfill, inner sep=1pt, align=center] at (2.45, 3.4) {PCM: conduction in $x$\\at each $y$}; - \node[note, fill=pcmfill, inner sep=1pt, align=center] at (2.9, 1.3) + \node[note, fill=pcmfill, inner sep=1pt, align=center] at (2.45, 1.3) {$T = T_\mathrm{fin}$ at the fin face,\\no flux at the midplane}; \node[note, anchor=east, align=right] at (-0.25, 2.0) {fin: conduction in $y$,\\heated by the fluid at its root\\and cooled by the PCM}; diff --git a/docs/models/diagrams/packed_bed.svg b/docs/models/diagrams/packed_bed.svg index 428f5dd..2e0dea5 100644 --- a/docs/models/diagrams/packed_bed.svg +++ b/docs/models/diagrams/packed_bed.svg @@ -49,128 +49,128 @@ - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -349,4 +349,4 @@ - + \ No newline at end of file diff --git a/docs/models/diagrams/pytes-diagrams.tex b/docs/models/diagrams/pytes-diagrams.tex index a9c9578..27407c1 100644 --- a/docs/models/diagrams/pytes-diagrams.tex +++ b/docs/models/diagrams/pytes-diagrams.tex @@ -14,11 +14,11 @@ \definecolor{pytesink}{HTML}{36312E} % Materials: the heat transfer fluid, the PCM, the metal (fins and tubes) -\colorlet{fluidfill}{pytessky!45} -\colorlet{pcmfill}{pytesamber!30} -\colorlet{liquidfill}{pytesorange!35} -\colorlet{metalfill}{pytesink!35} -\colorlet{compositefill}{pcmfill!75!metalfill} +\colorlet{fluidfill}{pytessky!75} +\colorlet{pcmfill}{pytesamber!55} +\colorlet{liquidfill}{pytesorange!60} +\colorlet{metalfill}{pytesink!45} +\colorlet{compositefill}{pcmfill!85!metalfill} \tikzset{ >={Stealth[length=2.2mm]}, diff --git a/docs/models/diagrams/resolved_averaged.svg b/docs/models/diagrams/resolved_averaged.svg index ad9cfa6..e99f844 100644 --- a/docs/models/diagrams/resolved_averaged.svg +++ b/docs/models/diagrams/resolved_averaged.svg @@ -71,54 +71,54 @@ - + - + - + - + - + - + - + - + @@ -178,12 +178,12 @@ - + - + @@ -342,4 +342,4 @@ - + \ No newline at end of file diff --git a/docs/models/diagrams/sharp_front.svg b/docs/models/diagrams/sharp_front.svg index b05aeed..0235ef1 100644 --- a/docs/models/diagrams/sharp_front.svg +++ b/docs/models/diagrams/sharp_front.svg @@ -55,9 +55,9 @@ - + - + @@ -246,4 +246,4 @@ - + \ No newline at end of file diff --git a/docs/models/finned_tube.md b/docs/models/finned_tube.md index 9773a03..373ebff 100644 --- a/docs/models/finned_tube.md +++ b/docs/models/finned_tube.md @@ -4,7 +4,8 @@ A finned-tube heat battery is a block of phase-change material (PCM) crossed by parallel tubes that carry the heat transfer fluid. Thin metal fins, annular discs around each tube, carry the heat into the PCM, which conducts poorly on its own. The family has two models: the {class}`~pytes.SharpFrontModel`, which homogenises the fins and the PCM, -and the {class}`~pytes.MushModel`, which resolves them separately. +and the {class}`~pytes.MushModel`, which resolves them separately. Both are derived, by +homogenisation, in [Luckins and Brosa Planella (2025)](https://doi.org/10.1098/rspa.2025.0660). ## Geometry @@ -94,9 +95,10 @@ a fin, along the fin ($y$), and from the fin into the PCM on either side ($x$). half a fin and half a gap are modelled. ``` -The mush model resolves the fins and the PCM separately, at each position $z$ along the -tube. Heat flows from the fluid into the root of each fin, radially along the fin, and from -the fin into the PCM between it and the next fin. The PCM uses the properties of the PCM on +The mush model ([Luckins and Brosa Planella, 2025](https://doi.org/10.1098/rspa.2025.0660)) +resolves the fins and the PCM separately, at each position $z$ along the tube. Heat flows +from the fluid into the root of each fin, radially along the fin, and from the fin into the +PCM between it and the next fin. The PCM uses the properties of the PCM on its own. By symmetry, half the gap is modelled, from the face of the fin ($x = d_c / 2$) to the midplane ($x = d_m / 2$). @@ -155,4 +157,8 @@ two-dimensional ($x$, $y$). - [Finned-tube models and their submodels](../examples/finned_tube_models.ipynb) - [Heat transfer coefficient](../examples/heat_transfer_coefficient.ipynb) -% TODO(maintainer): add the references for the origin of the sharp-front and mush models. +## References + +- E. K. Luckins and F. Brosa Planella, Homogenized models for composite phase-change + materials, *Proceedings of the Royal Society A* **481**, 20250660 (2025), + [doi:10.1098/rspa.2025.0660](https://doi.org/10.1098/rspa.2025.0660). diff --git a/docs/models/packed_bed.md b/docs/models/packed_bed.md index 0e48a06..7ee9560 100644 --- a/docs/models/packed_bed.md +++ b/docs/models/packed_bed.md @@ -45,7 +45,11 @@ One capsule, melting from its surface inwards. Heat enters through the surface a conducted radially. ``` -At each height $z$, heat is conducted radially in a capsule: +The formulation follows +[Brosa Planella (2025)](https://doi.org/10.1016/j.ijheatmasstransfer.2024.126533), which +gives the details. Resolved along the bed, it is also known as the concentric dispersion +model ([Ismail and Henríquez, 2002](https://doi.org/10.1016/S1359-4311(02)00080-7)). At each +height $z$, heat is conducted radially in a capsule: $$ \frac{\partial H}{\partial t} = \frac{1}{r^2} \frac{\partial}{\partial r} @@ -108,3 +112,14 @@ with a heat transfer oil at 180 °C. See {mod}`pytes.parameter_layers`. Nallusamy et al. (2007) - [Lumped capsule](../examples/lumped_capsule.ipynb) - [Validation](../examples/validation.ipynb), against Schumann's analytical solution + +## References + +- F. Brosa Planella, A simple model for latent thermal energy storage systems with + encapsulated phase-change material, *International Journal of Heat and Mass Transfer* + **239**, 126533 (2025), + [doi:10.1016/j.ijheatmasstransfer.2024.126533](https://doi.org/10.1016/j.ijheatmasstransfer.2024.126533). +- K. A. R. Ismail and J. R. Henríquez, Numerical and experimental study of spherical + capsules packed bed latent heat storage system, *Applied Thermal Engineering* **22**, + 1705–1716 (2002), + [doi:10.1016/S1359-4311(02)00080-7](https://doi.org/10.1016/S1359-4311(02)00080-7). From 4bfcc3a99b0e460191c124abf1e9bb127602f3e3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 31 Oct 2026 16:24:30 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/models/diagrams/capsule.svg | 2 +- docs/models/diagrams/finned_tube.svg | 2 +- docs/models/diagrams/finned_tube_unit.svg | 2 +- docs/models/diagrams/mush.svg | 2 +- docs/models/diagrams/packed_bed.svg | 2 +- docs/models/diagrams/resolved_averaged.svg | 2 +- docs/models/diagrams/sharp_front.svg | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/models/diagrams/capsule.svg b/docs/models/diagrams/capsule.svg index 3316c58..0ae93e0 100644 --- a/docs/models/diagrams/capsule.svg +++ b/docs/models/diagrams/capsule.svg @@ -141,4 +141,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/finned_tube.svg b/docs/models/diagrams/finned_tube.svg index 66bd04b..392a85c 100644 --- a/docs/models/diagrams/finned_tube.svg +++ b/docs/models/diagrams/finned_tube.svg @@ -281,4 +281,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/finned_tube_unit.svg b/docs/models/diagrams/finned_tube_unit.svg index 6e3979c..b6137d9 100644 --- a/docs/models/diagrams/finned_tube_unit.svg +++ b/docs/models/diagrams/finned_tube_unit.svg @@ -181,4 +181,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/mush.svg b/docs/models/diagrams/mush.svg index 193391c..c1f909d 100644 --- a/docs/models/diagrams/mush.svg +++ b/docs/models/diagrams/mush.svg @@ -305,4 +305,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/packed_bed.svg b/docs/models/diagrams/packed_bed.svg index 2e0dea5..2d8ef8d 100644 --- a/docs/models/diagrams/packed_bed.svg +++ b/docs/models/diagrams/packed_bed.svg @@ -349,4 +349,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/resolved_averaged.svg b/docs/models/diagrams/resolved_averaged.svg index e99f844..fdb133d 100644 --- a/docs/models/diagrams/resolved_averaged.svg +++ b/docs/models/diagrams/resolved_averaged.svg @@ -342,4 +342,4 @@ - \ No newline at end of file + diff --git a/docs/models/diagrams/sharp_front.svg b/docs/models/diagrams/sharp_front.svg index 0235ef1..0aa0dd2 100644 --- a/docs/models/diagrams/sharp_front.svg +++ b/docs/models/diagrams/sharp_front.svg @@ -246,4 +246,4 @@ - \ No newline at end of file +