.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/plot_patches.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_plot_patches.py: Boundary patches on a block =========================== Boundary conditions in ember are applied through *patches*: labelled regions on the faces of a :class:`ember.block.Block` that carry inlet, outlet, periodic or rotating-wall data. This example builds an annular duct block, attaches a patch to each face, configures the boundary data, and draws the block with its patches coloured by type. Patches index a constant-:math:`i`, :math:`j` or :math:`k` face of the block, so the parent block must already have its coordinates set before a patch is attached -- the patch needs the geometry to identify the span and pitch directions of the surface of revolution. .. GENERATED FROM PYTHON SOURCE LINES 16-25 .. code-block:: Python import numpy as np import matplotlib.pyplot as plt from matplotlib.patches import Patch as LegendPatch import ember.block import ember.patch from ember import util .. GENERATED FROM PYTHON SOURCE LINES 26-32 Annular duct geometry --------------------- A block spanning a short axial length of an annulus: ``i`` runs axially, ``j`` radially across the span, and ``k`` circumferentially across one pitch. The coordinates are set first so that patches can attach to it. .. GENERATED FROM PYTHON SOURCE LINES 32-36 .. code-block:: Python block = ember.block.Block(shape=(8, 5, 7)) block.set_xrt(util.linmesh3((0.0, 1.0), (0.9, 1.1), (0.0, 0.35), block.shape)) .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 37-44 Creating and attaching patches ------------------------------ Each patch names the constant face it occupies (``i=0`` is the first axial plane, ``i=-1`` the last) and an optional label. Omitting the other two indices spans the whole face. Patches live in the block's ``patches`` collection and can be added one at a time or in bulk. .. GENERATED FROM PYTHON SOURCE LINES 44-73 .. code-block:: Python block.patches.append(ember.patch.InletPatch(i=0, label="inflow")) block.patches.append(ember.patch.OutletPatch(i=-1, label="outflow")) block.patches.extend( [ ember.patch.PeriodicPatch(k=0, label="lower"), ember.patch.PeriodicPatch(k=-1, label="upper"), ] ) block.patches.append(ember.patch.RotatingPatch(j=0, label="hub")) # Patches are retrievable by index, by label, or by type. print(f"{len(block.patches)} patches attached") print("by label:", block.patches["inflow"]) print( "by type: ", len(block.patches.inlet), "inlet,", len(block.patches.periodic), "periodic", ) # Once attached, the constant dimension, shape and point count are known. for patch in block.patches: print( f" {patch.label:>8}: {type(patch).__name__:14} " f"const_dim={patch.const_dim} shape={patch.shape} size={patch.size}" ) .. rst-class:: sphx-glr-script-out .. code-block:: none 5 patches attached by label: InletPatch(i=(0, 0), j=(0, -1), k=(0, -1), label='inflow') by type: 1 inlet, 2 periodic inflow: InletPatch const_dim=0 shape=(1, 5, 7) size=35 outflow: OutletPatch const_dim=0 shape=(1, 5, 7) size=35 lower: PeriodicPatch const_dim=2 shape=(8, 5, 1) size=40 upper: PeriodicPatch const_dim=2 shape=(8, 5, 1) size=40 hub: RotatingPatch const_dim=1 shape=(8, 1, 7) size=56 .. GENERATED FROM PYTHON SOURCE LINES 74-81 Configuring boundary data ------------------------- Inlet patches take stagnation conditions and flow angles, uniform or varying across the patch (any input broadcasting to the patch shape). Outlet patches take a static pressure, optionally throttled to a target mass flow with a PID controller. Rotating patches take an angular velocity. .. GENERATED FROM PYTHON SOURCE LINES 81-99 .. code-block:: Python inlet = block.patches["inflow"] inlet.set_Po_To_Alpha_Beta(Po=2e5, To=1200.0, Alpha=0.0, Beta=0.0) # A radial stagnation-temperature profile across the span (j direction). _, nj, _ = inlet.shape To_profile = np.linspace(1100.0, 1300.0, nj).reshape(1, nj, 1) inlet.set_Po_To_Alpha_Beta(To=To_profile) print(f"Inlet To varies {float(inlet.To.min()):.0f}--{float(inlet.To.max()):.0f} K") outlet = block.patches["outflow"] outlet.set_P(1e5) # Static pressure [Pa]; an initial guess if throttling outlet.set_throttle(mdot_target=3.0, K_pid=(1.0, 0.1, 0.0)) # PID throttle to mdot hub = block.patches["hub"] hub.set_Omega(500.0) # rad/s print(f"Hub speed: {hub.rpm:.0f} rpm") .. rst-class:: sphx-glr-script-out .. code-block:: none Inlet To varies 1100--1300 K Hub speed: 4775 rpm .. GENERATED FROM PYTHON SOURCE LINES 100-106 Extracting data on a patch -------------------------- Every patch exposes a ``slice`` that indexes its face out of the parent block, either as a 2-D sub-block (with all properties available) or applied directly to a property array. .. GENERATED FROM PYTHON SOURCE LINES 106-114 .. code-block:: Python inlet_face = block[inlet.slice] # 2-D sub-block on the inlet face print(f"Inlet face block shape: {inlet_face.shape}") print( f"Same coordinates direct from the array: " f"{np.array_equal(inlet_face.x, block.x[inlet.slice])}" ) .. rst-class:: sphx-glr-script-out .. code-block:: none Inlet face block shape: (1, 5, 7) Same coordinates direct from the array: True .. GENERATED FROM PYTHON SOURCE LINES 115-123 Visualising the patched block ----------------------------- Drawing each patch on its face shows how the boundaries tile the block. A light wireframe of the whole block places each patch extent within the full domain -- including the casing face, which carries no patch here. Cartesian coordinates follow from :math:`y = r\cos\theta`, :math:`z = r\sin\theta`; each patch face is one singleton-dimension slice. .. GENERATED FROM PYTHON SOURCE LINES 123-180 .. code-block:: Python colours = { "InletPatch": "C0", "OutletPatch": "C3", "PeriodicPatch": "C2", "RotatingPatch": "C1", } def to_xyz(b): """Cartesian coordinates of a block, with any singleton axes removed.""" x, r, t = np.asarray(b.x), np.asarray(b.r), np.asarray(b.t) return x.squeeze(), (r * np.cos(t)).squeeze(), (r * np.sin(t)).squeeze() def block_edges(b): """The twelve edges of a block, as sub-blocks tracing the actual nodes.""" ends = (0, -1) edges = [b[:, j, k] for j in ends for k in ends] # along i edges += [b[i, :, k] for i in ends for k in ends] # along j edges += [b[i, j, :] for i in ends for j in ends] # along k return edges fig = plt.figure(figsize=(7, 5)) ax = fig.add_subplot(111, projection="3d") # Wireframe of the whole block (curved circumferential edges traced), drawn # heavier than the patch faces are translucent so the full extent reads through. for edge in block_edges(block): ax.plot(*to_xyz(edge), color="0.3", lw=1.2) for patch in block.patches: X, Y, Z = to_xyz(block[patch.slice]) ax.plot_surface( X, Y, Z, color=colours[type(patch).__name__], alpha=0.55, edgecolor="k", linewidth=0.2, ) ax.set_xlabel("$x$ [m]") ax.set_ylabel("$y$ [m]") ax.set_zlabel("$z$ [m]") ax.view_init(elev=20, azim=125) legend = {type(p).__name__: p for p in block.patches} # one entry per type ax.legend( handles=[LegendPatch(facecolor=colours[name], label=name) for name in legend], loc="upper left", ) fig.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_plot_patches_001.png :alt: plot patches :srcset: /auto_examples/images/sphx_glr_plot_patches_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.183 seconds) .. _sphx_glr_download_auto_examples_plot_patches.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_patches.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_patches.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_patches.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_