Application (NASA Rotor 37 compressor)

Post-processing of a CFD simulation with a multi-block structured cell-centered dataset.

This tutorial teaches how to build a post-processing on the NASA rotor 37 test case. Please download the associated data http://cerfacs.fr/antares/downloads/application1_tutorial_data.tgz

untar the archive in the working directory

copy the app1_rotor37.ipynb in the directory application1

Preliminary steps

import os, numpy, and antares packages

create a directory named OUTPUT

import os

import numpy as np

import antares

if not os.path.isdir('OUTPUT'):
    os.makedirs('OUTPUT')

Part I: Read Input Data

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.

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. Topological information contained in script_topo.py must also be read simultaneously. Note that to insure coherence with the topological data your zones must be named BlockXXXX.

r = antares.Reader('bin_tp')
r['filename'] = os.path.join('MESH', 'mesh_<zone>.dat')
r['zone_prefix'] = 'Block'
r['topology_file'] = os.path.join('script_topo.py')
r['shared'] = True
base = r.read()

Now add to your existing base the solution stored in files FLOW/flow_XXXX.dat (Tecplot binary format).

Note that data in solution files are at cell centers as they come from a cell-centered CFD solver.

r = antares.Reader('bin_tp')
r['base'] = base
r['filename'] = os.path.join('FLOW', 'flow_<zone>.dat')
r['zone_prefix'] = 'Block'
r['location'] = 'cell'
r.read()

Part II: Extract Skin Data

This part details the steps to extract data on the blade and hub in order to visualize static pressure skin distribution.

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.

Beforehand, we have to declare the computer model internal with the Base method set_computer_model().

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).

base.set_computer_model('internal')

base.compute('psta', location='cell')

myt = antares.Treatment('cell2node')
myt['base'] = base
myt['variables'] = ['psta']
myt.execute()

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. We would like to extract the data from this two families from the existing base to create a new base. To do that, you first have to create a new family containing the two existing families and add it to the base.

hub_and_blade_family = antares.Family()
hub_and_blade_family['HUB'] = base.families['HUB']
hub_and_blade_family['BLADE'] = base.families['BLADE']
base.families['HUB_and_BLADE'] = hub_and_blade_family

print(base.families)

Now that the new family has been created, create the base skin_base extracted from base using this family.

skin_base = base[base.families['HUB_and_BLADE']]
print(skin_base)

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.

To do so you will use the duplication treatment (see documentation for more information).

The base obtained after duplication will be named dupli_skin_base.

nb_dupli = 3

dupli = antares.Treatment('duplication')
dupli['base'] = skin_base
dupli['nb_duplication'] = nb_dupli
dupli['pitch'] = 2. * np.pi / 36.
dupli_skin_base = dupli.execute()

To finally visualize the skin data extracted, write the base dupli_skin_base in VTK binary format (compatible with Paraview software) in directory OUTPUT/SKIN/.

writer = antares.Writer('hdf_antares')
writer['base'] = dupli_skin_base
writer['filename'] = os.path.join('OUTPUT', 'skin_HUB_and_BLADE')
writer.dump()

Part III: Create Cut

This part will teach you how to extract the Mach number field on an axial geometrical cut.

We want to visualize the Mach number on a geometrical cut. Use the function compute() to compute this variable on your base.

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 Mach number at nodes from cell centered data.

base.compute('mach', location='cell')
myt = antares.Treatment('cell2node')
myt['base'] = base
myt['variables'] = ['mach']
myt.execute()

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.

plane_cut = antares.Treatment('cut')
plane_cut['base'] = base
plane_cut['type'] = 'plane'
plane_cut['origin'] = [4.5, 0., 0.]
plane_cut['normal'] = [1., 0., 0.]
cut_base = plane_cut.execute()

To finally visualize the cut, write the base cut_base in VTK binary format (compatible with Paraview software) in directory OUTPUT/XCUT/.

writer = antares.Writer('hdf_antares')
writer['base'] = cut_base
writer['filename'] = os.path.join('OUTPUT', 'cut_x')
writer.dump()

Part IV: Plot Data Over Line

The objective of this part is to plot the Mach number distribution in the wake at a given span.

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.

cylinder_cut = antares.Treatment('cut')
cylinder_cut['base'] = cut_base
cylinder_cut['type'] = 'cylinder'
cylinder_cut['origin'] = [0., 0., 0.]
cylinder_cut['radius'] = 21.
cylinder_cut['axis'] = 'x'
line_base = cylinder_cut.execute()

merge = antares.Treatment('merge')
merge['base'] = line_base
merge['duplicates_detection'] = True
line_base1 = merge.execute()

unw = antares.Treatment('unwrapline')
unw['base'] = line_base1
line_base = unw.execute()

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).

line_base.compute('theta')

import matplotlib.pyplot as plt
plt.plot(line_base[0][0]['theta'], line_base[0][0]['mach'], lw=2.5)
plt.grid()
plt.xlabel('{}'.format('theta'), fontsize=18)
plt.ylabel('{}'.format('mach'), fontsize=18)
plt.autoscale(axis='x')
plt.autoscale(axis='y')
plt.show()
plt.close()

Write the base line_base in directory OUTPUT/LINE/ in the column format.

writer = antares.Writer('column')
writer['base'] = line_base
writer['filename'] = os.path.join('OUTPUT', 'line.dat')
writer.dump()

Part V: Compute Operating Point

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.

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.

cut_base.compute('psta', location='cell')
t = antares.Treatment('integration')
t['base'] = cut_base
integral_base = t.execute()

massflow = integral_base[0][0]['rovx'][0]
pressure = integral_base[0][0]['psta'][0]
surface = integral_base[0][0]['volume'][0]

pressure /= surface
pressure *= 1.4

print('\n >>>  Operating point :')
print('        - massflow : %.2f' % massflow)
print('        - pressure ratio : %.2f' % pressure)
# >>>  Operating point :
#        - massflow : 13.74
#        - pressure ratio : 1.38