FUN3D Analysis Interface Module (AIM)
FUN3D Analysis Interface Module (AIM)
FUN3D AIM Example

Table of Contents

This is a walkthrough for using FUN3D AIM to analyze a three-dimensional two-wing configuration.

Prerequisites

It is presumed that ESP and CAPS have been already installed, as well as FUN3D. In this example the open-source, tetrahedral mesh generator, TetGen, is coupled to the FUN3D AIM to provide a volumetric mesh.

Script files

Two scripts are used for this illustration:

  1. cfdMultiBody.csm: Creates geometry, as described in following section.
  2. fun3d_and_Tetgen_PyTest.py: pyCAPS script for performing analysis, as described in Performing analysis using pyCAPS.

Creating Geometry using ESP

In our example *.csm file setting up the CAPS fidelity is the first step. If multiple bodies exist in the *.csm file the tag, capsIntent, can be used to distinguish what type of analysis the body may be used for. In this example, the geometry model generated can be used for CFD analysis, as shown:

attribute capsIntent CFD

A typical geometry model can be created and interactively modified using design parameters. These design parameters are either design- or geometry- based. In this example, a two wing configuration is created using following design parameters.

despmtr series[1,1] 8412.00000
despmtr series2[1,1] 20.00000
despmtr area[1,1] 40.00000
despmtr aspect[1,1] 5.00000
despmtr taper[1,1] 0.50000
despmtr twist[1,1] 15.00000
despmtr lesweep[1,1] 30.00000
despmtr dihedral[1,1] 1.00000

Next, internal CAPS reference attributes are set.

# Set reference values
attribute capsReferenceArea area
attribute capsReferenceChord sqrt(area/aspect)
attribute capsReferenceSpan sqrt(area/aspect)*aspect

After our design parameters are defined they are used to setup other local variables (analytically) for the wing.

set cmean sqrt(area/aspect)
set span cmean*aspect
set sspan span/2
set croot 2*cmean/(1+taper)
set ctip croot*taper
set xtip sspan*tand(lesweep)
set ytip sspan*tand(dihedral)
set ybot -0.1*croot
set ytop +0.2*croot+ytip
set extend 0.02*cmean

Once all design and locale variables are defined, a half span, solid model is created by "ruling" together NACA series airfoils (following a series of scales, rotations, and translations).

mark
udprim naca Series series
scale croot
udprim naca Series series2
scale ctip
rotatez -twist 0 0
translate xtip ytip -sspan
rule 0

A full span model is then created by mirroring and joining the half-span model.

# Store half of wing
store HalfWing 0 0
# Restore the half wing
restore HalfWing 0
# Restore and mirror the half wing
restore HalfWing 0
mirror 0 0 1 0
# Combine halfs into a whole
join 0

Once the desired model obtained it needs to be rotated so that it is in the expected aero-coordinated system (y- out the right wing, x- in the flow direction, and +z- up).

# Get body into a typical aero-system
rotatex 90 0 0

Next, an attribute is then placed in the geometry so that the geometry components may be reference by the FUN3D AIM.

# Store the wing
store Wing 0 0
# Wing 1 - Restore
restore Wing 0
attribute capsGroup $Wing1

Following the completion of the first wing, a second wing is created and scaled using the store/restore operations.

# Wing 2 - Restore and scale, translate
restore Wing 0
attribute capsGroup $Wing2
scale 0.4
translate 10 0 0

Finally, for three-dimensional CFD analysis with the FUN3D AIM a "farfield" or "bounding box" boundary needs to be provided. In this example, a simple sphere is created and tagged as a farfield boundary using the capsGroup attribute.

sphere 0 0 0 80
attribute capsGroup $Farfield

Performing analysis using pyCAPS

The first step in the pyCAPS script is to import the required modules. For this example, the following modules are used,

from __future__ import print_function
try:
import os
except:
print ("Unable to import os module")
raise SystemError

In order to create a new capsProblem the pyCAPS module also needs to be imported; on Linux and OSX this is the pyCAPS.so file, while on Windows it is the pyCAPS.pyd file. For convenience, it is recommended that the path to this file is added to the environmental variable PYTHONPATH.

from pyCAPS import capsProblem

Similarly, local variables used throughout the script may be defined.

workDir = "FUN3DTetgenAnalysisTest"

Once the required modules have been loaded, a capsProblem can be instantiated.

myProblem = capsProblem()

Using the loadCAPS() function, the desired geometry file is then loaded into the problem.

myGeometry = myProblem.loadCAPS("./csmData/cfdMultiBody.csm")

Any design parameters available in *.csm file are also available within the pyCAPS script. The following snippet changes the despmtr "area" which will force a rebuild of the geometry that FUN3D will now use.

myGeometry.setGeometryVal("area", 50)

When loading each analysis tools the desired capsIntent needs to be specified. Optionally, this may be set at the problem level as follows to avoid redundancy.

myProblem.capsIntent = "CFD"

A typical high-fidelity CFD analysis requires meshing AIMs to be coupled to the analysis AIM (unless a mesh already exists).For surface meshing, the face tessellation from the ESP geometry can be directly used as the surface mesh. If the face tessellation is not satisfactory, a surface meshing AIM may be coupled to the volume meshing AIM. In this example, the face tessellation is used as the surface mesh and TetGen for volumetric mesh generation. The TetGen AIM in loaded using the following

meshAIM = myProblem.loadAIM(aim = "tetgenAIM",
analysisDir = workDir)

Once loaded, the appropriate inputs to the mesh generator required to generate mesh with adequate mesh quality are set. Refer TetGen AIM documentation for the list of all the available options.

# Set new EGADS body tessellation parameters
meshAIM.setAnalysisVal("Tess_Params", [.05, 0.01, 20.0])
# Preserve surface mesh while meshing
meshAIM.setAnalysisVal("Preserve_Surf_Mesh", True)

After options are set aimPreAnalysis needs to be executed. For example,

meshAIM.aimPreAnalysis()

In the case of the TetGen AIM, TetGen was already ran during preAnalysis. To make the volumetric mesh available to other AIMs, aimPostAnalysis just needs to be additionally implemented.

meshAIM.aimPostAnalysis()

Next the FUN3D AIM needs to be loaded. In this example, the previously loaded TetGen AIM is linked as a parent. This allows the volume mesh generated by the TetGen AIM to be inherited (see AIM Shareable Data) by the FUN3D AIM, in which case FUN3D will write out the mesh in its preferred, native format.

# Load FUN3D aim - child of Tetgen AIM
fun3dAIM = myProblem.loadAIM(aim = "fun3dAIM",
altName = "fun3d",
analysisDir = workDir, parents = meshAIM.aimName)

Once loaded analysis parameters specific to FUN3D need to be set (see AIM Inputs). These parameters are automatically converted into FUN3D specific format and transferred into the FUN3D configuration file. One will note in the following snippet the instance of the AIM is referenced in two different manners: 1. Using the returned object from load call and 2. Using the "altName" name reference in the analysis dictionary. While syntactically different, these two forms are essentially identical.

# Set project name
fun3dAIM.setAnalysisVal("Proj_Name", "fun3dTetgenTest")
fun3dAIM.setAnalysisVal("Mesh_ASCII_Flag", False)
# Set AoA number
myProblem.analysis["fun3d"].setAnalysisVal("Alpha", 1.0)
# Set Mach number
myProblem.analysis["fun3d"].setAnalysisVal("Mach", 0.5901)
# Set equation type
fun3dAIM.setAnalysisVal("Equation_Type","compressible")
# Set Viscous term
myProblem.analysis["fun3d"].setAnalysisVal("Viscous", "inviscid")
# Set number of iterations
myProblem.analysis["fun3d"].setAnalysisVal("Num_Iter",10)
# Set CFL number schedule
myProblem.analysis["fun3d"].setAnalysisVal("CFL_Schedule",[0.5, 3.0])
# Set read restart option
fun3dAIM.setAnalysisVal("Restart_Read","off")
# Set CFL number iteration schedule
myProblem.analysis["fun3d"].setAnalysisVal("CFL_Schedule_Iter", [1, 40])
# Set overwrite fun3d.nml if not linking to Python library
myProblem.analysis["fun3d"].setAnalysisVal("Overwrite_NML", True)

Along the same lines of setting the other input values the "Boundary_Condition" tuple is used to set the boundary conditions (CFD Boundary Conditions). These boundary tags (which reference capsGroup attributes in the *.csm file) and associated boundary conditions are converted into FUN3D specific boundary conditions and set in the FUN3D configuration file.

inviscidBC1 = {"bcType" : "Inviscid", "wallTemperature" : 1}
inviscidBC2 = {"bcType" : "Inviscid", "wallTemperature" : 1.2}
fun3dAIM.setAnalysisVal("Boundary_Condition", [("Wing1", inviscidBC1),
("Wing2", inviscidBC2),
("Farfield","farfield")])

Again, after all desired options are set aimPreAnalysis needs to be executed.

At this point the required files necessary run FUN3D should have be created and placed in the specified analysis working directory. Next FUN3D needs to executed either through its Python interface module (not shown) or an OS system call such as,

print ("\n\nRunning FUN3D......")
currentDirectory = os.getcwd() # Get our current working directory
os.chdir(fun3dAIM.analysisDir) # Move into test directory
os.system("nodet_mpi --animation_freq -1 --write_aero_loads_to_file> Info.out"); # Run fun3d via system call
os.chdir(currentDirectory) # Move back to top directory

After FUN3D is finished running aimPostAnalysis needs to be executed.

fun3dAIM.aimPostAnalysis()

Finally, available AIM outputs (see AIM Outputs) may be retrieved, for example:

print ("Total Force - Pressure + Viscous")
# Get Lift and Drag coefficients
print ("Cl = " , fun3dAIM.getAnalysisOutVal("CLtot"),
"Cd = " , fun3dAIM.getAnalysisOutVal("CDtot"))
# Get Cmx, Cmy, and Cmz coefficients
print ("Cmx = " , fun3dAIM.getAnalysisOutVal("CMXtot"),
"Cmy = " , fun3dAIM.getAnalysisOutVal("CMYtot"),
"Cmz = " , fun3dAIM.getAnalysisOutVal("CMZtot"))
# Get Cx, Cy, Cz coefficients
print ("Cx = " , fun3dAIM.getAnalysisOutVal("CXtot"),
"Cy = " , fun3dAIM.getAnalysisOutVal("CYtot"),
"Cz = " , fun3dAIM.getAnalysisOutVal("CZtot"))
print ("Pressure Contribution")
# Get Lift and Drag coefficients
print ("Cl_p = " , fun3dAIM.getAnalysisOutVal("CLtot_p"),
"Cd_p = " , fun3dAIM.getAnalysisOutVal("CDtot_p"))
# Get Cmx, Cmy, and Cmz coefficients
print ("Cmx_p = " , fun3dAIM.getAnalysisOutVal("CMXtot_p"),
"Cmy_p = " , fun3dAIM.getAnalysisOutVal("CMYtot_p"),
"Cmz_p = " , fun3dAIM.getAnalysisOutVal("CMZtot_p"))
# Get Cx, Cy, and Cz, coefficients
print ("Cx_p = " , fun3dAIM.getAnalysisOutVal("CXtot_p"),
"Cy_p = " , fun3dAIM.getAnalysisOutVal("CYtot_p"),
"Cz_p = " , fun3dAIM.getAnalysisOutVal("CZtot_p"))
print ("Viscous Contribution")
# Get Lift and Drag coefficients
print ("Cl_v = " , fun3dAIM.getAnalysisOutVal("CLtot_v"),
"Cd_v = " , fun3dAIM.getAnalysisOutVal("CDtot_v"))
# Get Cmx, Cmy, and Cmz coefficients
print ("Cmx_v = " , fun3dAIM.getAnalysisOutVal("CMXtot_v"),
"Cmy_v = " , fun3dAIM.getAnalysisOutVal("CMYtot_v"),
"Cmz_v = " , fun3dAIM.getAnalysisOutVal("CMZtot_v"))
# Get Cx, Cy, and Cz, coefficients
print ("Cx_v = " , fun3dAIM.getAnalysisOutVal("CXtot_v"),
"Cy_v = " , fun3dAIM.getAnalysisOutVal("CYtot_v"),
"Cz_v = " , fun3dAIM.getAnalysisOutVal("CZtot_v"))

results in,

Total Force - Pressure + Viscous
Cl = 0.671595 Cd = 0.517818
Cmx = -0.002830832 Cmy = -1.342669 Cmz = -0.0020397
Cx = 0.5060182 Cy = -0.004986118 Cz = 0.6805299
Pressure Contribution
Cl_p = 0.671595 Cd_p = 0.517818
Cmx_p = -0.002830832 Cmy_p = -1.342669 Cmz_p = -0.0020397
Cx_p = 0.5060182 Cy_p = -0.004986118 Cz_p = 0.6805299
Viscous Contribution
Cl_v = 0.0 Cd_v = 0.0
Cmx_v = 0.0 Cmy_v = 0.0 Cmz_v = 0.0
Cx_v = 0.0 Cy_v = 0.0 Cz_v = 0.0

When finally finished with the script, the open CAPS problem should be closed.

myProblem.closeCAPS()

Executing pyCAPS script

Issuing the following command executes the script:

python fun3d_and_Tetgen_PyTest.py

Below are representative result images generated by the above script:

FUN3D_Ex1.png
FUN3D coupled to TetGen example