Post-Processing

Review of Simulation Output

M-Star CFD generates open-source .vtk, .stl, and text files for visualization and analysis. The .vtk and .stl files can be rendered using any general purpose visualization software, including ParaView (https://www.paraview.org/) and VisIT (https://visit.llnl.gov). ParaView and VisIT are the primary visualization tools used and developed by leadership-class computing facilities.

VTK files are available to visualize

  • Fluid volumes

  • Fluid slices

  • Scalar volumes

  • Scalar slices

  • Particle fields

  • Bubble fields

STL files are available to visualize

  • Moving objects

  • Internal surfaces

  • Bounding surfaces

  • Free surfaces

Text files are available to study

  • Force data

  • Thermodynamic data

  • Blending data

  • Temperature data

  • Scalar field data

  • Fluid volume data

  • Runtime performance

M-Star Post

Overview

M-Star Post is a ParaView add-on that automatically renders visualization output and plots numerical data. These scripts operate directly on the slices.txt and volumes.txt files are printed to the /out directory created when executing the simulation.

M-Star Post is opened directly from the Windows Start Menu. When clicked, a ParaView window will open with M-Star Post scripts pre-installed and ready for execution.

These scripts appear as four buttons: -
  • MStarPost—renders a 3D movie showing fluid slices, scalar fields, moving/static surfaces, and particles/bubbles. This script also plots numerical output data.

  • MStarPost3D—renders a 3D movie showing fluid volume, moving/static surfaces, and particle/bubbles. No output plots are created.

  • ReloadAll—refreshes all data, updates plots and the animation sequence. This feature is useful when monitoring a simulation in progress.

  • DeleteAll—removes all rendered data. Does not delete from memory, just removes images/data from the rendering window.

MStarPost

MStarPost operates on slices.txt. Open this file in ParaView, and then click the MStarPost to initiate the post-processing routine. Press the green play button at the top of the ParaView window to create an animation sequence. MStarPost operates on the data saved in the /out directory.

MStarPost3D

MStarPost3D operates on volumes.txt. Open this file in ParaView, and then click the MStarPost3D to initiate the post-processing routine. Press the green play button at the top of the ParaView window to create an animation sequence. MStarPost operates on the data saved in the /out directory.

Note

  • ParaView version 5.4+ is recommended for use with the post-processing scripts

  • Keep your graphics card driver up-to-date

  • MStarPost and MStarPost3D can both operate on the boundaryConditions.txt file. This file summarizes the boundary conditions applied at the start of the simulation, and can be used to assess the reults of the flood fill routine.

Batch Processing in Paraview

Batch processing is the automated processing of data without user intervention. This may occur on a local desktop machine, or on a batch process on a remote server where only ssh access is available. Batch processing output data can lend itself to highly efficient work flows and eliminate repeated manual processing using GUI tools.

Quick Start

This section will quickly get you started with batch processing M-Star results using Paraview. A ready to run script is provided so you can immediately get started. This script automatically processes all slice data and outputs images for all available data for the last time step.

Prerequisites

  • M-Star simulation results have been created in a directory called out

  • Paraview is installed

Guide

  1. Download this paraview script and place it in a case directory

  2. Find the Paraview install path and make note of the full path to the /path/to/paraview/bin/pvpython executable.

  3. Open a new command prompt or terminal and navigate to your case directory that contains the solver input files and out directory

  4. Run the following command. Replace the pvpython path with your paraview install location noted from step (2)

    /path/to/paraview/bin/pvpython post_slices.py
    
  5. You should see some output from the script as it is running

  6. Results are output to a directory out/Renders

Bare Bones Script

This section will provide a minimal starting script for your own development. Additional explanation is given about paraview scripting itself and general concepts.

Setup

First you will need to import the paraview.simple python module and create a view:

from paraview.simple import *
view = CreateRenderView()
view.ViewSize = (600,400)

Load and show data

This following code loads in a out/Output/SliceY_0.250.pvd data file and shows it in the rendering view. The field_reader is a Paraview source proxy. It handles loading the data into the Paraview pipeline. A field_display variable is returned from the Show call. This object can be used to change how the object is displayed. This same pattern is used for all Paraview pipeline objects.:

field_reader = PVDReader(FileName="out/Output/SliceY_0.250.pvd")
field_display = Show(field_reader, view)

Add a text annotation

To further illustrate the data and display properties object pairing we have created a Text object and displayed it in the view. The field_text is the Paraview pipeline object that handles the data, in this case a text string Velocity. The field_text_display variable returned from the Show call can be used to change the font size and position in the render view.:

field_text = Text(Text="Velocity")
field_text_display = Show(field_text, view)
field_text_display.FontSize = 12
field_text_display.WindowLocation = "LowerLeftCorner"

Handling the camera position

The camera position determines the perspective of the displayed view. This can be tricky to get exactly right. In our example, the camera is positioned above the 3D slice. By default the camera “Focal Point”, what the camera is pointed at, is (0,0,0) so we do not need to change it here. The ResetCamera function call makes sure the entire scene is visible in the view. By default, the 3D rendering view camera uses a perspective mode. This type of view attempts to convey 3D scene depth by making close objects appear larger using a vanishing point at a finite distance.

camera = view.GetActiveCamera()
camera.SetPosition(0,1,0)
ResetCamera(view)

Coloring slices by field data

This is a main reason we go to all the effort to load our data into Paraview. We want to see it colored by a specified color scale to show flow structures or help us understand complex flow problems. The general approach to field coloring is to first change to the last time step, create our coloring scale from that data range, and apply our desired color scale.

Here we are coloring by velocity magnitude, which is associated with the Cell paraview data. Most M-Star data will output data as cell centered, so you typically want to show coloring by Cell centers. The “GetColorTransferFunction” returns the color scale itself for a given data channel. Here we instruct Paraview to use the Viridis color scale. The selection of color scale can be a topic of discussion all on its own. The Viridis color scale was developed by visualization experts and tends to look good. It also has the advantage of being accessible by color blind individuals.

Finally, the color bar itself is added to the 3D window. Positioning, font, and sizing can all be controlled by interacting with the “bar” variable here.

# Change to last time before creating the color scale
view.ViewTime = field_reader.TimestepValues[-1]
Render()

# Color the field data by a given cell data channel
ColorBy(rep=field_display, value=("CELLS", "Velocity Magnitude (m/s)"))

# Change the coloring preset to use the "Viridis" preset.
lt = GetColorTransferFunction("Velocity Magnitude (m/s)", field_display)
lt.ApplyPreset("Viridis (matplotlib)", True)

# Add the color scalar bar to the view
bar = CreateScalarBar(LookupTable=lt)
view.Representations.append(bar)

Interacting with time

To change the time shown in the rendering window, set the view.ViewTime field to the specified time. The available times can be accessed by on the source data itself. Here we using the last time step available. After changing the time step, you must call Render.

view.ViewTime = field_reader.TimestepValues[-1]
Render(view)

Save rendered images

Once you have setup the rendered view, you can save the image to disk. It is good practice to specify the image resolution explicitly as we have done here. This allows arbitrary sized images to be created. In the following code we are also preserving the aspect ratio of the rendering view window and outputing a large image with a width of 1080 pixels. This approach will help avoid upscaling low resolution images. Instead we will have larger images which will get down sampled when embedded in presentations or reports.

# Specify the output size of the images
aspect_ratio = float(view.ViewSize[1]) / float(view.ViewSize[0])
output_width = 1080
output_height = int(aspect_ratio * output_width)
SaveScreenshot("image.png", view, ImageResolution=(output_width, output_height))

Full Bare Bones Script

from paraview.simple import *

# This is the rendering view where the visualization appears
view = CreateRenderView()
view.ViewSize = (600,400)

# Load in the static walls stl file
stl_reader = STLReader(FileNames="out/Output/Walls.stl")
stl_display = Show(stl_reader, view)
stl_display.Representation = "Surface"
stl_display.Opacity = 0.2

# Load in the moving body PVD file
solid_reader = PVDReader(FileName="out/Output/SliceMovingBody_Moving Body.pvd")
solid_display = Show(solid_reader, view)

# Load in the field data file
field_reader = PVDReader(FileName="out/Output/SliceY_0.250.pvd")
field_display = Show(field_reader, view)

# Add a simple time annotation
annotime = AnnotateTimeFilter(Input=field_reader)
annotime_display = Show(annotime, view)
annotime_display.FontSize = 12

# Add a simple text annotation
field_text = Text(Text="Velocity")
field_text_display = Show(field_text, view)
field_text_display.FontSize = 12
field_text_display.WindowLocation = "LowerLeftCorner"

# Change the camera to look at the Y plane and then fit the view to the displayed data
camera = view.GetActiveCamera()
camera.SetPosition(0,1,0)
ResetCamera(view)

# Change to last time before creating the color scale
view.ViewTime = field_reader.TimestepValues[-1]
Render()

# Color the field data by a given cell data channel
ColorBy(rep=field_display, value=("CELLS", "Velocity Magnitude (m/s)"))

# Change the coloring preset to use the "Viridis" preset.
lt = GetColorTransferFunction("Velocity Magnitude (m/s)", field_display)
lt.ApplyPreset("Viridis (matplotlib)",True)

# Add the color scalar bar to the view
bar = CreateScalarBar(LookupTable=lt)
view.Representations.append(bar)

# Specify the output size of the images
aspect_ratio = float(view.ViewSize[1]) / float(view.ViewSize[0])
output_width = 1080
output_height = int(aspect_ratio * output_width)

# Specify the time steps to output
time_steps_to_render = []
time_steps_to_render = [ field_reader.TimestepValues[-1] ]
#time_steps_to_render = field_reader.TimestepValues

count = 0
for t in time_steps_to_render:
    fn = "output_{0}.png".format(count)
    view.ViewTime = t
    Render(view)
    SaveScreenshot(fn, view, ImageResolution=(output_width, output_height))
    count += 1

Additional Resources

The official Python Paraview documentation .

The Paraview Guide is a great resource . It is available on the download page of any Paraview release. Look for a “ParaViewGuide-5.X.Y.pdf” file in the Documentation section.

A lot can be learned by exporting python state files directly from Paraview. To do this, create an interesting visualization manually in paraview. Then go to File-Save State, and change the file type to “Python state file”. This will write out a python script that creates the view you just created.

Use the Python Shell in Paraview to learn about objects and the API itself. Open that with View-Python Shell. The shell opens up in the window. You can then interrogate your loaded data and see what fields are available. After loading some data into Paraview, type each command into the Python Shell:

d = GetActiveSource()

# What object do we have?
d

# What can I do with this object?
help(d)

# What cell arrays are available?
d.CellArrays