Unable to sample NACA 0012 symmetrical airfoil

Hi,
I am trying to simulate flow across NACA 0012 airfoil. The formula for the shape of NACA 0012 is -
yt = 5t(0.2969*sqrt(x) - 0.1260*x - 0.3516*x^2 +0.2843*x^3 - 0.1036*x^4) ,
where,
x is the position along the cord(0 to 1)
yt is the half thickness at a given value of x
t is the maximum thickness as a fraction of the chord, here t = 12% or 0.12

The coordinates for upper and lower surface of the airfoil are (xu,yu) and (xl,yl), where,
xu = xl = x, yu = yt and yl = -yt

Can someone please help me with the custom geometry class required to sample the airfoil? I am attaching an image of NACA 0012 for your reference.

Thanks in advance

You may have solved this issue already, but the way I solved this problem was by producing the NACA wing as a list of points, and then I plugged the points into the modulus.geometry.primative_2d.Polygon object. A word of caution, however, while this produces the Wing, producing the Polygon object takes a considerable amount of CPU time. I did this all with Modulus 22.07.

Here’s a sample of my code to hopefully help get started:

import numpy as np
from modulus.geometry.primitives_2d import Polygon
import matplotlib.plot as plt

# First, compute the p, m, t values from NACA Number
cord = 1
p = (0) * (cord / 10)
m = (0) * (cord / 100)
t = (12) * (cord / 100)

# 10 points is computable, but 100> makes the wing 'smooth'
x = np.linspace(0, cord, 10)

# the mask allows us to handle airfoils with camber
mask = x < p
yc = (m / ((1 - p)**2)) * (1-(2*p) + (2*p*x) - x**2)
if mask.any():
  yc[mask] = (m / (p**2)) * ((2*p*x[mask]) - (x[mask]**2))

dyc_dx = (2*m / ((1-p)**2)) * (p - x)
if mask.any():
  dyc_dx[mask] = (2*m / (p**2)) * (p-x[mask])

yt = 5*t*(.2969*np.sqrt(x) - .126*x - .3516*(x**2) + .2843*(x**3) - .1036*(x**4))

# These will solve correctly, even with NACA 00XX foils
theta = np.arctan(dyc_dx)
Xu = x - yt * np.sin(theta)
Yu = yc + yt * np.cos(theta)

Xl = x + yt * np.sin(theta)
Yl = yc - yt * np.cos(theta)

Xt = np.concatenate((Xu[::-1], Xl[1:]))
Yt = np.concatenate((Yu[::1], Yl[1:]))

# You can plot this in matplotlib if you want to.
# plt.plot(Xt, Yt)
# plt.show()

# Convert for Polygon
points = []
for X, Y in zip(Xt, Yt):
  points.append((X, Y))

# Produce the shape: Warning, this is the most time consuming part
wing = Polygon(points)

Hope this helps.

1 Like

Hi mrunal.nasery, I tried in the old SimNet before but it was not easy using symbolic programming and I gave up. Wonder if it’s easier in Modulus now.

Hi Markjonestx, you are creating a wing, right? So I guess there’s many pts. I guess it should be much faster if it’s just a 2D airfoil. I will take your code and give it a try. Thanks!

Hi @tsltaywb

In the current Modulus version a polygon geometry class has been added to our CSG module to make things like 2D airfoils easier to work with. For 3D wings I would probably suggest making a discrete set of STL files and using our tessellated geometry functionality for these more complex cases.

Hi ngeneva,

Thanks for the tips. I’ll give it a try!

Hello tsltaywb! As ngeneva has suggested, STL will likely be a better solution for 3D airfoils. If you’re working with 2D airfoils though, I have been attempting to explore better solutions than what I posted above. My latest attempt was to take a 2D cross-section of a NACA wing and load it as an STL file, but I suspect the classmethod that parses STL files was not written with 2D objects in mind. I’m exploring other solutions though.

1 Like

Hi @tsltaywb

Did the suggested approach work for you? Would you be interested in speaking to the modulus team to share more details on the use case and we can try to share more insights on how to apply Modulus for you problem. You can reach out to us directly at modulus-team@exchange.nvidia.com.

Thanks
Ram

Hi markjonestx,

Sure. I’ll talk to them. Thanks for the info!

Hi ramc,

I tried to email you ppl but the email bounced back:

Recipient address rejected: Access denied. AS(201806281)

Is this the correct email?

Thanks.

Sorry about that - yes there seems to be an issue with the email alias and we are trying to address it. In the mean time, you can reach out to ramc@nvidia.com or anshumanb@nvidia.com.

Hi,

I have successfully used the py file ( script at /examples/geometry/naca_airfoil.py) to construct a problem for flow past naca0012 airfoil. I have gotten some results. In the code:

x = [x for x in np.linspace(0, 0.2, airfoil_fore_pts)] + [x for x in np.linspace(0.2, 1.0, airfoil_aft_pts)][

We can specify how many pieces of lines can be used to form the polygon airfoil. I realised that when I specify 50 for both airfoil_fore_pts and airfoil_aft_pts, it took a long time to set up, before the actual training starts, like 20 - 30mins. When I use 100, it took like around 1+ to 2 hrs on a V100.

Is this normal? Am I using excessively a lot of points? Of course, I still need to do some convergent test but the initialization took really long. I wonder if I do things correctly.

Hi @tsltaywb

As the number of elements increase in the CSG module the sample time does rapidly increase since interior points are sampled based on the analytical SDF’s of each element (so each element in the polynomial has its own SDF). Thus you are likely using too many elements in your polynomial for fast sampling. We have some improvements for the geometry module road-mapped.

In the past with really complex geometry that takes a long time we have manually sampled points and saved them to file. Then we would load them into a dictionary in our training script and manually create a DictPointwiseDataset which can then be fed into a basic Constraint. The alternative would be to mesh your geometry then use PySDF for sampling.

Hi @ngeneva

Thanks for the info. Will take note to reduce the no. of polygon elements.
Btw, is there an example with regard to the DictPointwiseDataset mtd? Seems like a good alternative.

Kind of. This DictPointwiseDataset is used in quite a few spots under the hood. But probably the most convenient location of it being used is in the .from_numpy() class function of the PointwiseConstraint which is essentially an automated method of what I just described.

A couple of examples use this: The anti-derivative example with DeepONet, wave inverse problem, etc. Typically shows up with problems involving some data or specific discretization.

Hi,

Now I need to add discrete pts to create an airfoil. There’s no formula to generate the airfoil. I believe I can still use the prev mtd which involves using polygon.

I just saw this post:
https://forums.developer.nvidia.com/t/add-grid-points-manually/241039

Will it be faster than using polygon?

Using the above 2 approaches, is it also possible to do parameterization?

Supposed I have a set of airfoil pts. I have a parameter t. I will multiply it with the y component of the airfoil pts to enable thickness parameterization. Is this workable?

Thanks.