{ "cells": [ { "cell_type": "markdown", "source": [ "# Application (NASA Rotor 37 compressor)\n", "## Post-processing of a CFD simulation with a multi-block structured cell-centered dataset.\n", "\n", "This tutorial teaches how to build a post-processing on the NASA rotor 37 test case. \n", "\n", "Please download the associated data https://cerfacs.fr/antares/downloads/application1_tutorial_data.tgz\n", "\n", "untar the archive in the working directory\n", "\n", "copy the app1_rotor37.ipynb in the directory application1" ], "metadata": { "slideshow": { "slide_type": "slide" } } }, { "cell_type": "markdown", "source": [ "# Preliminary steps\n", "\n", "import os, numpy, and antares packages\n", "\n", "create a directory named OUTPUT" ], "metadata": { "slideshow": { "slide_type": "slide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "import \n", "\n", "import \n", "\n", "import \n", "\n", "if :\n", " os." ], "outputs": [], "metadata": { "slideshow": { "slide_type": "fragment" } } }, { "cell_type": "markdown", "source": [ "# Part I: Read Input Data\n", "\n", "The first step is to create a base from the data of a CFD simulation of the NASA Rotor 37. This antares data structure will be used in the following post-processing. \n", "\n", "The first step is to create a Base named base by reading the grid from files MESH/mesh_XXXX.dat (Tecplot binary format) as shared data.\n", "\n", "Topological information contained in script_topo.py must also be read simultaneously.\n", "\n", "Note that to insure coherence with the topological data your zones must be named BlockXXXX." ], "metadata": { "slideshow": { "slide_type": "slide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "r = antares.\n", "r[] = os.path.join()\n", "r['zone_prefix'] = 'Block'\n", "r['topology_file'] = os.path.join('script_topo.py')\n", "r[] = \n", "base = " ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "Now add to your existing base the solution stored in files FLOW/flow_XXXX.dat (Tecplot binary format).\n", "\n", "Note that data in solution files are at cell centers as it comes from a cell-centered CFD solver." ], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "r = antares.\n", "r[] = \n", "r[] = os.path.join()\n", "r['zone_prefix'] = 'Block'\n", "r['location'] = 'cell'\n", "r.read()" ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "# Part II: Extract Skin Data\n", "\n", "This part details the steps to extract data on the blade and hub in order to visualize the static pressure skin distribution. \n", "\n", "As we want to visualize the static pressure on the hub and blade skin, this variable needs to be computed. To do so, we will use the Base method compute(). Look in Antares documentation to know how to use it. \n", "\n", "Beforehand, we have to declare the computer model internal with the Base method set_computer_model().\n", "\n", "Note that the variables needed for this computation are stored at cell centers. We would like to have the static pressure at nodes as for skin data extraction we only extract surface nodes (not volume cells). " ], "metadata": { "slideshow": { "slide_type": "slide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "base.\n", "\n", "base.compute(, location=)\n", "\n", "myt = antares.\n", "myt[] = \n", "myt[] = \n", "myt.execute()" ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "As topological information have been read in script_topo.py you can see that the base already contains families, in particular, the families HUB and BLADE.\n", "\n", "We would like to extract the data from this two families from the existing base to create a new base. \n", "\n", "To do that, you first have to create a new family containing the two existing families and add it to the base. " ], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "hub_and_blade_family = antares.\n", "hub_and_blade_family['HUB'] = base.\n", "hub_and_blade_family[] = \n", "base.families['HUB_and_BLADE'] = \n", "\n", "print(base.families)" ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "Now that the new family has been created, create the base skin_base extracted from base using this family. " ], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "skin_base = \n", "print(skin_base)" ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "As the dataset given contains only one blade from a rotor composed of 36 blades, we would like to duplicate the skin_base to visualize 3 blades for example.\n", "\n", "To do so you will use the duplication treatment (see documentation for more information). \n", "\n", "The base obtained after duplication will be named dupli_skin_base. " ], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "nb_dupli = \n", "\n", "dupli = antares.\n", "dupli[] = \n", "dupli[] = \n", "dupli[] = 2. * np.pi \n", "dupli_skin_base = " ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "To finally visualize the skin data extracted, write the base dupli_skin_base in VTK binary format or HDF antares format (compatible with Paraview software) in directory OUTPUT/SKIN/. " ], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "writer = antares.\n", "writer[] = \n", "writer[] = os.path.join()\n", "writer." ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "# Part III: Create Cut\n", "\n", "This part will teach you how to extract the Mach number field on an axial geometrical cut. \n", "\n", "We want to visualize the Mach number on a geometrical cut. Use the function compute() to compute this variable on your base.\n", "\n", "Because cell-centered data are not very suited for visualization (as most of visualization software are not able to perform smoothing when values are not stored at node) compute the Mach number at nodes from cell-centered data. " ], "metadata": { "slideshow": { "slide_type": "slide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "base.compute(, location=)\n", "\n", "myt = antares.\n", "myt[] = \n", "myt[] = \n", "myt." ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "Use the cut treatment (see documentation for more information) to perform a geometrical plane cut in your domain at a constant x value of 4.5. The resulting base will be named cut_base. " ], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "plane_cut = antares.\n", "plane_cut[] = \n", "plane_cut[] = \n", "plane_cut[] = \n", "plane_cut[] = \n", "cut_base = " ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "To finally visualize the cut, write the base cut_base in VTK binary format or HDF antares format (compatible with Paraview software) in directory OUTPUT/XCUT/. " ], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "writer = antares.\n", "writer[] = \n", "writer[] = os.path.join()\n", "writer." ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "# Part IV: Plot Data Over Line\n", "\n", "The objective of this part is to plot the Mach number distribution in the wake at a given span.\n", "\n", "We want now to vizualize the azimuthal Mach number distribution at a constant x value of 4.5 and a radius of 21. As we have already extracted the 'x'-cut in the base cut_base (tutorial part III), apply another cut treatment to extract values at constant radius. Then use the merge treatment (see documentation to learn how it works) to merge and the unwrapline treatment to reorganize the line points. The base obtained will be named line_base. " ], "metadata": { "slideshow": { "slide_type": "slide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "cylinder_cut = antares.\n", "cylinder_cut[] = \n", "cylinder_cut[] = \n", "cylinder_cut[] = \n", "cylinder_cut[] = \n", "cylinder_cut[] = \n", "line_base = \n", "\n", "merge = antares.\n", "merge[] = \n", "merge[] = \n", "line_base1 =\n", "\n", "unw = antares.\n", "unw[] = \n", "line_base = " ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "To visualize data stored in the base line_base use matplotlib. Plot the Mach number distribution versus theta (you will have to compute this variable as it is not in the base yet). " ], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "line_base.\n", "\n", "import matplotlib.pyplot as plt\n", "plt.plot(line_base[0][0]['theta'], line_base[0][0]['mach'], lw=2.5)\n", "plt.grid()\n", "plt.xlabel('{}'.format('theta'), fontsize=18)\n", "plt.ylabel('{}'.format('mach'), fontsize=18)\n", "plt.autoscale(axis='x')\n", "plt.autoscale(axis='y')\n", "plt.show()\n", "plt.close()" ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "Write the base line_base in directory OUTPUT/LINE/ in the column format. " ], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "writer = antares.\n", "writer[] = \n", "writer[] = os.path.join()\n", "writer." ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "markdown", "source": [ "# Part V: Compute Operating Point\n", "\n", "Finally, a common post-processing for turbomachinery is to compute the operating point, that is to say the massflow rate and pressure ratio between inlet and outlet of the blade row.\n", "\n", "Operating point in a compressor is defined by the pressure ratio between inlet and outlet and the massflow. To compute these two values, we need to compute the flux and the average pressure on a plane at the outlet (note that the inlet pressure is known as it is imposed in the simulation). You will use the plane at constant x of 4.5 extracted previously in base cut_base (tutorial part III). The inlet pressure is 1./gamma = 1./1.4." ], "metadata": { "slideshow": { "slide_type": "slide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "cut_base.compute(, location=)" ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } }, { "cell_type": "code", "execution_count": null, "source": [ "t = antares.\n", "t[] = \n", "integral_base = \n", "\n", "massflow = integral_base[0][0]['rovx'][0]\n", "pressure = integral_base[0][0]['psta'][0]\n", "surface = integral_base[0][0]['volume'][0]\n", "\n", "pressure /= surface\n", "pressure *= 1.4\n", "\n", "print('\\n >>> Operating point :')\n", "print(' - massflow : %.2f' % massflow)\n", "print(' - pressure ratio : %.2f' % pressure)\n", "# >>> Operating point :\n", "# - massflow : 13.74\n", "# - pressure ratio : 1.38\n" ], "outputs": [], "metadata": { "slideshow": { "slide_type": "subslide" } } } ], "metadata": { "celltoolbar": "Diaporama", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" }, "nbpresent": { "slides": { "046854bb-a4d0-4839-a656-3c29bfa2eafa": { "id": "046854bb-a4d0-4839-a656-3c29bfa2eafa", "prev": "84edf4c4-5c79-4186-a419-f1a524255c47", "regions": { "bcfe2215-71a6-4f03-bc3a-cf45c2756ec8": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "e1b15d2c-795f-406d-8130-b73f190da8ca", "part": "whole" }, "id": "bcfe2215-71a6-4f03-bc3a-cf45c2756ec8" } } }, "21beb54a-dbf4-4372-b741-72f75c45488b": { "id": "21beb54a-dbf4-4372-b741-72f75c45488b", "prev": "c5f9ef9c-fda9-4f64-81b0-8df95ac9a0e7", "regions": { "322dbed9-3442-4b1a-82cd-4322d9af373e": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "60bef50c-9fe4-4d42-a3b3-16dee2c569d4", "part": "whole" }, "id": "322dbed9-3442-4b1a-82cd-4322d9af373e" } } }, "31895f0d-c84f-48fd-9e46-3910f3a32871": { "id": "31895f0d-c84f-48fd-9e46-3910f3a32871", "prev": null, "regions": { "255b4f54-02eb-4c41-bf69-c668d8117399": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "3e2abaca-ff6d-4475-97f6-b43d1634e2c9", "part": "source" }, "id": "255b4f54-02eb-4c41-bf69-c668d8117399" } } }, "4090087b-dded-4a9e-a828-8f208228d474": { "id": "4090087b-dded-4a9e-a828-8f208228d474", "prev": "046854bb-a4d0-4839-a656-3c29bfa2eafa", "regions": { "e367bf97-6261-4623-b7dd-1694ad126099": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "42947e78-728f-4008-bd3d-d1f0110164a1", "part": "whole" }, "id": "e367bf97-6261-4623-b7dd-1694ad126099" } } }, "84edf4c4-5c79-4186-a419-f1a524255c47": { "id": "84edf4c4-5c79-4186-a419-f1a524255c47", "prev": "a209d110-660b-4251-a92e-e4d7a7e2f95d", "regions": { "e10c5d08-4e24-4045-a27d-d6901a4df427": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "e3738ad3-06a7-4974-873b-6385ed7f8b30", "part": "source" }, "id": "e10c5d08-4e24-4045-a27d-d6901a4df427" } } }, "a209d110-660b-4251-a92e-e4d7a7e2f95d": { "id": "a209d110-660b-4251-a92e-e4d7a7e2f95d", "prev": "31895f0d-c84f-48fd-9e46-3910f3a32871", "regions": { "50d5c9c8-cca1-4f70-b2b1-97961e71d2d3": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "1a128849-789e-4bad-8366-d5b57675e4d2", "part": "source" }, "id": "50d5c9c8-cca1-4f70-b2b1-97961e71d2d3" } } }, "c5f9ef9c-fda9-4f64-81b0-8df95ac9a0e7": { "id": "c5f9ef9c-fda9-4f64-81b0-8df95ac9a0e7", "prev": "4090087b-dded-4a9e-a828-8f208228d474", "regions": { "e4cbbebb-636e-4ef0-82ef-950cd5adb8af": { "attrs": { "height": 0.8, "width": 0.8, "x": 0.1, "y": 0.1 }, "content": { "cell": "73689d5a-c0db-4e1d-a0d6-16021b427eea", "part": "whole" }, "id": "e4cbbebb-636e-4ef0-82ef-950cd5adb8af" } } } }, "themes": {} } }, "nbformat": 4, "nbformat_minor": 2 }