This is a walkthrough for using Masstran AIM to analyze a three-dimensional wing with internal ribs and spars.
Prerequisites
It is presumed that ESP and CAPS have been already installed, as well as Masstran.
Script files
Two scripts are used for this illustration:
- feaWingBEM.csm: Creates geometry, as described in the next section (Creating Geometry using ESP ).
- masstran_PyTest.py: pyCAPS script for performing analysis, as described in Performing analysis using pyCAPS .
Creating Geometry using ESP
The CSM script generates Bodies which are designed to be used by specific AIMs. The AIMs that the Body is designed for is communicated to the CAPS framework via the "capsAIM" string attribute. This is a semicolon-separated string with the list of AIM names. Thus, the CSM author can give a clear indication to which AIMs should use the Body. In this example, the list contains the structural finite element analysis tools that can analyze the body:
attribute capsAIM $nastranAIM;astrosAIM;mystranAIM;masstranAIM;egadsTessAIM
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 wing configuration is created using following design parameters.
# Design Parameters for OML
despmtr thick 0.12 frac of local chord
despmtr camber 0.04 frac of loacl chord
despmtr area 10.0
despmtr aspect 6.00
despmtr taper 0.60
despmtr sweep 20.0 deg (of c/4)
despmtr washout 5.00 deg (down at tip)
despmtr dihedral 4.00 deg
# Design Parameters for BEM
despmtr nrib 11 number of ribs
despmtr spar1 0.20 frac of local chord
despmtr spar2 0.75 frac of local chord
After our design parameters are defined they are used to setup other local variables (analytically) for the outer model line (OML).
# OML
set span sqrt(aspect*area)
set croot 2*area/span/(1+taper)
set ctip croot*taper
set dxtip (croot-ctip)/4+span/2*tand(sweep)
set dytip span/2*tand(dihedral)
In a similar manner, local variables are defined for the ribs and spars.
# wing ribs
set Nrib nint(nrib)
# wing spars
set eps 0.01*span
Once all design and local variables are defined, a full span, solid model is created by "ruling" together NACA series airfoils (following a series of scales, rotations, and translations).
mark
# Right tip
udprim naca Thickness thick Camber camber
scale ctip
rotatez washout ctip/4 0
translate dxtip dytip -span/2
# root
udprim naca Thickness thick Camber camber
scale croot
# left tip
udprim naca Thickness thick Camber camber
scale ctip
rotatez washout ctip/4 0
translate dxtip dytip +span/2
rule
attribute OML 1
Once complete, the wing is stored for later use under the name OML.
Next, the inner layout of the ribs and spars are created using the waffle udprim.
udprim waffle Depth +6*thick*croot Filename <<
patbeg i Nrib
point A at (span/2)*(2*i-Nrib-1)/Nrib -0.01*croot
point B at (span/2)*(2*i-Nrib-1)/Nrib max(croot,dxtip+ctip)
line AB A B tagComponent=rib tagIndex=!val2str(i,0)
patend
point A at -span/2-eps spar1*ctip+dxtip
point B at 0 spar1*croot
line AB A B tagComponent=spar tagIndex=1 tagPosition=left
point A at span/2+eps spar1*ctip+dxtip
point B at 0 spar1*croot
line AB A B tagComponent=spar tagIndex=1 tagPosition=right
point A at -span/2-eps spar2*ctip+dxtip
point B at 0 spar2*croot
line AB A B tagComponent=spar tagIndex=2 tagPosition=left
point A at span/2+eps spar2*ctip+dxtip
point B at 0 spar2*croot
line AB A B tagComponent=spar tagIndex=2 tagPosition=right
>>
An attribute is then placed on ribs and spars so that the geometry components may be reference by the Masstran AIM.
attribute capsGroup $Ribs_and_Spars
Following a series of rotations and translations the ribs and spars are stored for later use.
translate 0 0 -3*thick*croot
rotatey 90 0 0
rotatez -90 0 0
store layoutRibSpar
Next, the layout of the ribs and spars are intersected the outer mold line of wing, which results in only keeping the part of layout that is inside the OML.
restore layoutRibSpar
restore OML
intersect
Finally, select faces (airfoil sections at the root) are tagged, so that a constraint may be applied later.
udprim editAttr filename <<
edge adj2face tagComponent=spar tagPosition=right
and adj2face tagComponent=spar tagPosition=left
set capsConstraint=Rib_Constraint
node adj2face tagComponent=spar tagPosition=right
and adj2face tagComponent=spar tagPosition=left
set capsConstraint=Rib_Constraint
>>
ifthen nint(mod(Nrib,2)) ne 0
set midRib Nrib/2
select face $tagComponent $rib $tagIndex val2str(midRib,0)
attribute tagPosition $root
udprim editAttr filename <<
face has tagComponent=rib tagPosition=root
set capsConstraint=Rib_Constraint
edge adj2face tagComponent=rib tagPosition=root
set capsConstraint=Rib_Constraint
node adj2face tagComponent=rib tagPosition=root
set capsConstraint=Rib_Constraint
>>
endif
The above *.csm file results in the follow geometry model:
Wing built up element model
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
import os
import argparse
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
Once the required modules have been loaded, a capsProblem can be instantiated.
myProblem = capsProblem()
Next, using the loadCAPS() function, the desired geometry file is then loaded into the problem.
myProblem.loadCAPS("../csmData/feaWingBEM.csm", verbosity=args.verbosity)
After the geometry is loaded, a structural mesh is generated using the egadsTessAIM.
myProblem.loadAIM( aim = "egadsTessAIM",
altName = "tess" )
myProblem.analysis["tess"].setAnalysisVal("Mesh_Elements", "Quad")
myProblem.analysis["tess"].setAnalysisVal("Tess_Params", [.05,.5,15])
myProblem.analysis["tess"].preAnalysis()
myProblem.analysis["tess"].postAnalysis()
Next, the Masstran AIM is instantiated with the surface mesh as a parent.
masstranAIM = myProblem.loadAIM(aim = "masstranAIM",
altName = "masstran",
parents = ["tess"] )
Once loaded analysis parameters specific to Masstran need to be set (see AIM Inputs). These parameters are automatically converted into Masstran specific format and transferred into the Masstran 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.
myProblem.analysis["masstran"].setAnalysisVal("Edge_Point_Min", 2)
myProblem.analysis["masstran"].setAnalysisVal("Edge_Point_Max", 3)
myProblem.analysis["masstran"].setAnalysisVal("Quad_Mesh", True)
Along the same lines of setting the input values above the "Material" (see FEA Material) and "Property" (see FEA Property) tuples are used to set more complex information. The user is encouraged to read the additional documentation on these inputs for further explanations. Once provided this information is converted into Masstran specific syntax and set in the Masstran configuration file.
unobtainium = {"youngModulus" : 2.2E11 ,
"poissonRatio" : .33,
"density" : 7850}
madeupium = {"materialType" : "isotropic",
"youngModulus" : 1.2E9 ,
"poissonRatio" : .5,
"density" : 7850}
masstranAIM.setAnalysisVal("Material", [("Unobtainium", unobtainium),
("Madeupium", madeupium)])
shell = {"propertyType" : "Shell",
"membraneThickness" : 0.2,
"bendingInertiaRatio" : 1.0,
"shearMembraneRatio" : 5.0/6.0}
masstranAIM.setAnalysisVal("Property", ("Ribs_and_Spars", shell))
After all desired options are set aimPreAnalysis needs to be executed by calling the pre/post-Analysis. The MasstrainAIM will compute all mass properties in memory without writing files.
masstranAIM.preAnalysis()
masstranAIM.postAnalysis()
Finally, available AIM outputs (see AIM Outputs) may be retrieved, for example:
print ("\nGetting results mass properties.....\n")
Area = masstranAIM.getAnalysisOutVal("Area")
Mass = masstranAIM.getAnalysisOutVal("Mass")
Centroid = masstranAIM.getAnalysisOutVal("Centroid")
CG = masstranAIM.getAnalysisOutVal("CG")
Ixx = masstranAIM.getAnalysisOutVal("Ixx")
Iyy = masstranAIM.getAnalysisOutVal("Iyy")
Izz = masstranAIM.getAnalysisOutVal("Izz")
Ixy = masstranAIM.getAnalysisOutVal("Ixy")
Ixz = masstranAIM.getAnalysisOutVal("Ixz")
Iyz = masstranAIM.getAnalysisOutVal("Iyz")
I = masstranAIM.getAnalysisOutVal("I_Vector")
II = masstranAIM.getAnalysisOutVal("I_Tensor")
print("Area ", Area)
print("Mass ", Mass)
print("Centroid ", Centroid)
print("CG ", CG)
print("Ixx ", Ixx)
print("Iyy ", Iyy)
print("Izz ", Izz)
print("Ixy ", Ixy)
print("Ixz ", Ixz)
print("Iyz ", Iyz)
print("I ", I)
print("II ", II)
results in,
Area 3.28946557
Mass 5164.46094491
Centroid [1.2409841844368583, 0.16359702451265337, 4.0874212239589455e-09]
CG [1.2409841844368585, 0.16359702451265348, 4.087420991763218e-09]
Ixx 21325.300951
Iyy 22558.0731769
Izz 1292.98036179
Ixy 153.720903861
Ixz 2.06373216532e-06
Iyz 2.36311990987e-06
I [21325.300951015903, 22558.07317691867, 1292.9803617927173, 153.72090386142395, 2.063732165317917e-06, 2.363119909871653e-06]
II [[21325.300951015903, -153.72090386142395, -2.063732165317917e-06], [-153.72090386142395, 22558.07317691867, -2.363119909871653e-06], [-2.063732165317917e-06, -2.363119909871653e-06, 1292.9803617927173]]
When finally finished with the script, the open CAPS problem should be closed.
Executing pyCAPS script
Issuing the following command executes the script:
python masstran_PyTest.py