Skip to content

Commit

Permalink
Exploded views demo in caps2tacs (smdogroup#285)
Browse files Browse the repository at this point in the history
* demonstrate exploded views

* remove autosave csm and merge
  • Loading branch information
sean-engelstad authored Dec 1, 2023
1 parent 0e99906 commit 53aad02
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 21 deletions.
4 changes: 3 additions & 1 deletion examples/caps_wing/1_steady_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

print(f"proc on rank {comm.rank}")

tacs_model = caps2tacs.TacsModel.build(csm_file="simple_naca_wing.csm", comm=comm, active_procs=[0])
tacs_model = caps2tacs.TacsModel.build(
csm_file="simple_naca_wing.csm", comm=comm, active_procs=[0]
)
tacs_model.mesh_aim.set_mesh(
edge_pt_min=15,
edge_pt_max=20,
Expand Down
4 changes: 3 additions & 1 deletion examples/caps_wing/4_sizing_and_shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
# Setup CAPS Problem
# --------------------------------------------------------------#
comm = MPI.COMM_WORLD
tacs_model = caps2tacs.TacsModel.build(csm_file="large_naca_wing.csm", comm=comm, active_procs=[0])
tacs_model = caps2tacs.TacsModel.build(
csm_file="large_naca_wing.csm", comm=comm, active_procs=[0]
)
tacs_model.mesh_aim.set_mesh( # need a refined-enough mesh for the derivative test to pass
edge_pt_min=15,
edge_pt_max=20,
Expand Down
6 changes: 4 additions & 2 deletions examples/caps_wing/7_multiproc_post_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
# Setup CAPS Problem
# --------------------------------------------------------------#
comm = MPI.COMM_WORLD
tacs_model = caps2tacs.TacsModel.build(csm_file="large_naca_wing.csm", comm=comm, active_procs=[0,1])
tacs_model = caps2tacs.TacsModel.build(
csm_file="large_naca_wing.csm", comm=comm, active_procs=[0, 1]
)
tacs_model.mesh_aim.set_mesh( # need a refined-enough mesh for the derivative test to pass
edge_pt_min=15,
edge_pt_max=20,
Expand Down Expand Up @@ -115,4 +117,4 @@
naims = len(tacs_model.active_procs)
if comm.rank == 0:
print(f"Elapsed time with {naims} procs is {mins_elapsed} mins using 4 shape vars.")
print(f"Also each post analysis took {post_analysis_time/60.0:.4f} min", flush=True)
print(f"Also each post analysis took {post_analysis_time/60.0:.4f} min", flush=True)
110 changes: 110 additions & 0 deletions examples/caps_wing/8_make_exploded_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""
Sean Engelstad, Febuary 2023
GT SMDO Lab, Dr. Graeme Kennedy
Caps to TACS example
December 1, 2023
Run this with conda-mpirun -n 3 python 8_make_exploded_view.py
Then process the f5 files which are moved to the exploded folder.
"""

from tacs import caps2tacs
from mpi4py import MPI
import os, shutil

# run a steady elastic structural analysis in TACS using the tacsAIM wrapper caps2tacs submodule
# -------------------------------------------------------------------------------------------------
# 1: build the tacs aim, egads aim wrapper classes

comm = MPI.COMM_WORLD

print(f"proc on rank {comm.rank}")

tacs_model = caps2tacs.TacsModel.build(
csm_file="large_naca_wing.csm",
comm=comm,
problem_name="capsExploded",
active_procs=[_ for _ in range(3)],
)
tacs_model.mesh_aim.set_mesh(
edge_pt_min=15,
edge_pt_max=20,
global_mesh_size=0.25,
max_surf_offset=0.01,
max_dihedral_angle=15,
).register_to(tacs_model)

# set the exploded views to 1,2,3 for each of the 3 separate procs
tacs_aim = tacs_model.tacs_aim
exploded_view = comm.rank + 1
tacs_aim.set_config_parameter("exploded", exploded_view)

aluminum = caps2tacs.Isotropic.aluminum().register_to(tacs_model)

# setup the thickness design variables + automatic shell properties
# choose pattern based dv1 values
nribs = int(tacs_model.get_config_parameter("nribs"))
nspars = int(tacs_model.get_config_parameter("nspars"))
nOML = nribs - 1

if exploded_view == 2: # only make these internal struct variables on proc 1 tacs model
for irib in range(1, nribs + 1):
caps2tacs.ThicknessVariable(
caps_group=f"rib{irib}", value=0.1 - 0.01 * irib, material=aluminum
).register_to(tacs_model)
for ispar in range(1, nspars + 1):
caps2tacs.ThicknessVariable(
caps_group=f"spar{ispar}", value=0.1 - 0.01 * irib, material=aluminum
).register_to(tacs_model)

if exploded_view in [
1,
3,
]: # only make these OML struct variables on procs 0,2 tacs model
for iOML in range(1, nOML + 1):
caps2tacs.ThicknessVariable(
caps_group=f"OML{iOML}", value=0.1 - 0.01 * iOML, material=aluminum
).register_to(tacs_model)

# add constraints and loads
caps2tacs.PinConstraint("root").register_to(tacs_model)
caps2tacs.GridForce("OML", direction=[0, 0, 1.0], magnitude=100).register_to(tacs_model)

# run the pre analysis to build tacs input files
# alternative is to call tacs_aim.setup_aim().pre_analysis() with tacs_aim = tacs_model.tacs_aim
tacs_model.setup()

comm.Barrier()

SPs = tacs_model.createTACSProbs(addFunctions=True)

# make a directory for the exploded views
exploded_dir = os.path.join(os.getcwd(), "exploded")
if not os.path.exists(exploded_dir) and comm.rank == 0:
os.mkdir(exploded_dir)

# create a mesh of each of the exploded views
names = ["upperOML", "int-struct", "lowerOML"]
for rank in range(3):
# create tacs problems in the tacs directory of this proc
SPs = tacs_model.createTACSProbs(root=rank)
# then write solution using all procs
for caseID in SPs:
SPs[caseID].writeSolution(
baseName=names[rank], outputDir=tacs_model.analysis_dir(proc=rank), number=0
)

# move the file to the exploded view directory
filename = names[rank] + "_000.f5"
src = os.path.join(tacs_model.analysis_dir(proc=rank), filename)
dest = os.path.join(exploded_dir, filename)

if comm.rank == 0:
shutil.copy(src, dest)

comm.Barrier()

print("Done creating exploded views for the large_naca_wing.csm..")
print(
"\tGoto the exploded/ folder and process the f5 files to create an exploded view visualization!"
)
36 changes: 30 additions & 6 deletions examples/caps_wing/large_naca_wing.csm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
# number of ribs and spars
cfgpmtr nribs 10
cfgpmtr nspars 2
cfgpmtr exploded 0 # 0 - non-exploded, 1 upperOML, 2 internalStruct, 3 - lowerOML

# root and tip chord
despmtr chord0 2.0
Expand Down Expand Up @@ -58,7 +59,7 @@ rotatex 90 0 0
translate xf -sspan zf

# loft the solid wing and store it
loft 0
rule

# attribute the solid wing
select face
Expand All @@ -67,14 +68,22 @@ attribute capsLoad $OML
attribute _color $blue

# make root and tip caps the ribs
select face 5
select face 4
attribute capsGroup $rib1
attribute tagComp $rib
attribute _color $green

select face 4
select face 5
attribute capsGroup !$rib+nribs
attribute tagComp $rib
attribute _color $green

select face 1
attribute tagComp $OMLtop

select face 2
attribute tagComp $OMLbot

store solidWing

### 2. Internal Structure ###
Expand All @@ -101,7 +110,7 @@ patbeg ispar nspars
# add caps attributes
select face
attribute capsGroup !$spar+ispar
attribute has_group $yes
attribute tagComp $spar
attribute _color $green
patend

Expand All @@ -121,7 +130,7 @@ patbeg index ninnerRibs
# add caps attributes
select face
attribute capsGroup !$rib+irib
attribute has_group $yes
attribute tagComp $rib
attribute _color $green

# union with previous ribs/spars
Expand Down Expand Up @@ -155,6 +164,9 @@ union
select face $capsGroup $rib1
attribute capsConstraint $root

select face $capsGroup $*
attribute has_group $yes

# add the constraint attribute to adjacent edges, nodes
# otherwise they can pop out of the mesh in the structural analysis
udprim editAttr filename <<
Expand All @@ -173,11 +185,23 @@ udprim editAttr filename <<
patend
>>

# extract only certain faces for the exploded view
ifthen exploded EQ 1
select face $tagComp $OMLtop
extract @sellist
elseif exploded EQ 2
select face $tagComp $rib
select add $tagComp $spar
extract @sellist
elseif exploded EQ 3
select face $tagComp $OMLbot
extract @sellist
endif

# add AIM attribute to specify the analyses to use
select body
attribute capsAIM $egadsTessAIM;tacsAIM

end
|||||
|||
||||||||||
2 changes: 1 addition & 1 deletion examples/caps_wing/simple_naca_wing.csm
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ rotatex 90 0 0
translate xf -sspan zf

# loft the solid wing and store it
loft 0
rule

# attribute the solid wing
select face
Expand Down
6 changes: 4 additions & 2 deletions tacs/caps2tacs/tacs_aim.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ def get_proc_with_shape_var(self, shape_var: ShapeVariable or str):
if shape_var.name == this_shape_var.name:
return rank
# if not found in for loop trigger error
raise AssertionError(f"failed to find shape var {shape_var} on rank {self.comm.rank}")
raise AssertionError(
f"failed to find shape var {shape_var} on rank {self.comm.rank}"
)

@property
def local_shape_vars(self) -> list:
Expand All @@ -130,7 +132,7 @@ def setup_aim(
self,
large_format: bool = True,
static: bool = True,
barrier:bool=True,
barrier: bool = True,
):
# make sure there is at least one material, property, constraint, etc.
assert len(self._materials) > 0
Expand Down
15 changes: 7 additions & 8 deletions tacs/caps2tacs/tacs_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def build(
active_procs: list = [0],
problem_name: str = "capsStruct",
mesh_morph: bool = False,
verbosity:int=0,
verbosity: int = 0,
):
"""
make a pyCAPS problem with the tacsAIM and egadsAIM on serial / root proc
Expand All @@ -79,7 +79,7 @@ def build(
tacs_project: str
project name for all ESP/CAPS work directory files (affects filenames)
active_procs: list
list of active procs for parallel tacsAIM instances. Ex: if you want to use 5
list of active procs for parallel tacsAIM instances. Ex: if you want to use 5
parallel tacsAIMs you can choose active_procs=[_ for _ in range(5)] or
equivalently active_procs=[0,1,2,3,4]
problem_name: str
Expand All @@ -93,7 +93,7 @@ def build(
assert 0 in active_procs
caps_problem = None
assert mesh in cls.MESH_AIMS
assert max(active_procs)+1 <= comm.Get_size()
assert max(active_procs) + 1 <= comm.Get_size()

for iproc in active_procs:
if comm.rank == iproc:
Expand Down Expand Up @@ -291,19 +291,18 @@ def update_design(self, input_dict: dict = None):

return changed_design

@property
def fea_solver(self) -> pyTACS:
def fea_solver(self, root=0) -> pyTACS:
"""
build pyTACS from nastran dat file on the root proc
"""
return pyTACS(self.tacs_aim.dat_file_path(self.root_proc_ind), self.comm)
return pyTACS(self.tacs_aim.dat_file_path(root), self.comm)

def createTACSProbs(self, addFunctions: bool = True):
def createTACSProbs(self, root=0, addFunctions: bool = True):
"""
creates TACS list of static, transient, or modal analysis TACS problems from the TacsAim class
most important call method from the tacsAim class: SPs = tacs_aim.createTACSProbs
"""
fea_solver = self.fea_solver
fea_solver = self.fea_solver(root)
fea_solver.initialize()
SPs = fea_solver.createTACSProbsFromBDF()
self.SPs = SPs # store the static problems as well
Expand Down

0 comments on commit 53aad02

Please sign in to comment.