Computational fluid dynamics (CFD) is an indispensable tool in aerospace engineering. These expensive simulations produce a large amount of three-dimensional flow data, and in order to gain understanding from the results we employ interactive visualization. We generally use purpose-built desktop applications such as Tecplot or Ensight to do this. However, the software is expensive and this makes it difficult to share results (other than in simple 2D renderings). In this post, I will demonstrate how to create web-based, interactive, 3D visualizations of surface pressure data using a free and open-source software stack.
Check out this example result from one of my earlier research papers! (Flexible Formulation of Spatial Integration Constraints in Aerodynamic Shape Optimization )
I’m very impressed with the plotly graphing library for Python. Previously, I’ve mostly used the matplotlib package for static visualization, and bokeh for interactive charts. In my view, plotly is now the best available free tool for creating interactive charts in Python.
The Plotly Express API makes it trivially easy to create and animate simple charts (like scatters and bars). If you need more detailed control over your figures, there is a lower-level graph object API which is what we will be using today.
To install Plotly, I recommend starting from the Anaconda Python 3 distribution.
Once you have a working Anaconda installation, from your command line, type
conda install plotly and you should be all set.
Check out the examples and tutorials available on the plotly Python reference page.
We will be using the
Mesh3d graph object today.
To familiarize yourself, check out the Mesh3d examples page.
Mesh3d trace takes a triangulated surface and renders it in 3D, complete with lighting effects and shading.
I’ll briefly cover the format plotly expects to see.
Mesh3d constructor takes several arguments, including the following geometry data:
Alternatively, you can provide a point cloud (x, y, z only) and plotly can try to construct a Delaunay triangulation of the object, and the plotly
Mesh3d example page provides an example of this. However, I don’t recommend this approach if you have CFD data since you already know the structure of the mesh.
Our lab’s workflow generates surface pressure distributions as .cgns files which we postprocess in Tecplot 360. It is highly capable software, but it’s also very expensive. We would like to be able to show interactive, volume-rendered CFD data to the general public without the need for a local Tecplot installation.
Data-Alter-Specify Equations. In the pop-up window, input
myvarnameis the parameter you want to plot. Select
New var locationto be
Node. Then click
File-Write Data. In the pop-up window, choose a file name, keeping the
.datfile extension and click
Save. In the next dialog, select
Variable(s)section (in that order). Choose the
Zone(s)you want to plot (one or more is OK). Choose
pointfor the format (important).
You should see a four-column output format like this:
If you have structured CFD data exported from Tecplot in the process described above, the following conversion process applies to you.
You can tell if your data is structured because the header of your
.dat file will read something like this:
I=7, J=7, K=1, ZONETYPE=Ordered
If you have unstructured data you can use this script as inspiration but you’ll have to write your own parser.
I wrote a Python script to convert a structured Tecplot
.dat file into the x, y, z, i, j, k, intensity format.
The main challenge is that structured surface mesh data usually consists of quadrilaterals, whereas plotly wants triangles.
Therefore we have to triangulate each quad, which is trivial (you just bisect it corner to corner).
I ensured that the triangle normal vectors are pointing in a consistent direction which helps plotly render correctly.
Note that Tecplot saves its output so that i changes fastest, then j, then k (though for surface data k should always be 1).
Now that we have CFD data in the proper format, we can plot it easily using plotly.
We use the
plotly.io API to generate output in HTML format.
We use the option
include_plotlyjs='cdn', which will automatically download
plotly.js from the internet instead of bundling it with the HTML file (which greatly increases its size).
If everything went well, we should have a working visualization open in the browser! You can now redistribute this HTML file to anybody with a modern browser and they should be able to open it.
There is an easy way to embed plotly results, and an elegant way.
The easy way is to simply use an
iframe element to directly embed the plotly HTML file in your site.
However, since the
plotly.js file is so huge (3 MB), this will slow down your page load.
First, open the HTML file from the previous step. You should see a line similar to this:
<div id="d58f9b77-df41-4618-b6d2-baa7fb02b0a6" class="plotly-graph-div" style="height:100%; width:100%;"></div>
The unique identifier, height, and width information will come in handy later.
Below this line you should see a big
<script> element with your plot data.
Save the interior of the
<script> element (without the actual
Make sure your site can serve it as a static file.
Next, we create a button in our web page and tag it with some CSS classes to style it.
I use Bootstrap 3 so the
btn-lg classes apply colors and some effects.
<button class="btn btn-lg">Click to load</button>
Now we need to add some HTML5 data to the button so we know some information about the visualization for this interaction. Let’s add the following attributes:
Let’s also tag it with a new CSS class called
The HTML code for our button now looks like this:
<button class="btn btn-lg btn-hidden-viz" data-plotly-src="/assets/viz/cfdexample.js" data-plotly-uid="d58f9b77-df41-4618-b6d2-baa7fb02b0a6" data-height="100%" data-width="100%"> Click to load </button>
Next, I want to create a click handler which loads
plotly.js from a CDN, then loads my visualization, and finally inserts it into the page and disappears.
I use jQuery’s click handler to apply the interaction to all buttons with the
I use jQuery
ajax to ensure that the
plotly.js file is loaded before the visualization is opened.
I also set a 10 second timeout in case the user is on a slow connection or has lost connection to the CDN.
Finally, let’s add a spinner effect while the visualization is loading.
I did this by adding a
<span> element with these classes to the button during the
glyphicon glyphicon-refresh glyphicon-refresh-animate
We include the following snippet (which I swiped from a CSS showcase somewhere) in our site’s CSS to get the animation to work properly:
And there you have it! The final product looks like this:
Plotly is the best way I have found so far to render CFD results interactively on the internet for free.
You can find the code I used for this example and a sample Tecplot
.dat file here.