Skip to content

Commit

Permalink
Added complex step version of check partials for f2f and tacs
Browse files Browse the repository at this point in the history
  • Loading branch information
kejacobson committed Apr 14, 2019
1 parent ae363d1 commit 9295e92
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 72 deletions.
84 changes: 46 additions & 38 deletions examples/funtofem_and_tacs/assemble_dummy_aero.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,77 +24,71 @@ class FsiComps(object):
solver components
"""
def __init__(self):
# Flow data to keep track of
self.flow = None

def __init__(self,tacs_setup,meld_setup):
self.flow = {'nnodes':2}
# Structural data to keep track of
self.tacs_setup = tacs_setup
self.struct_comm = None
self.tacs = None
self.struct_ndv = 0
self.struct_ndof = 0
self.struct_nprocs = 0

# Transfer data to keep track of
self.meld_setup = meld_setup
self.xfer_ndof = 3
self.meld = None
def get_aero_surface_size(self):
return self.flow['nnodes']*3

def add_fsi_subsystems(self,model,setup,prefix='',reuse_solvers=True):
self.tacs_setup = setup['tacs']
self.meld_setup = setup['meld']
self.flow_setup = setup['flow']
def add_fsi_subsystems(self,model,aero,aero_nnodes,prefix='',reuse_solvers=True):
self.aero_nnodes = aero_nnodes

# Structural data to keep track of
self.struct_nprocs = self.tacs_setup['nprocs']

# Initialize the disciplinary meshes
aero_mesh, struct_mesh = self._initialize_meshes(reuse_solvers)

# Initialize the disciplinary solvers
aero, struct, disp_xfer, load_xfer = self._initialize_solvers()
struct, disp_xfer, load_xfer = self._initialize_solvers()

# Initialize the coupling group
fsi_solver = FsiSolver(aero=aero,
struct=struct,
disp_xfer=disp_xfer,
load_xfer=load_xfer,
struct_nprocs=self.struct_nprocs,
get_vector_size=self.get_vector_size)
fsi_solver = FsiSolver(aero=aero,struct=struct,disp_xfer=disp_xfer,load_xfer=load_xfer,struct_nprocs=self.struct_nprocs,get_vector_size=self.get_aero_surface_size)

# Initialize the function evaluators
struct_funcs = self._initialize_function_evaluators()
model.add_subsystem(prefix+'fsi_solver',fsi_solver)

model.add_subsystem(prefix+'aero_mesh',aero_mesh,promotes=['x_a0'])
model.add_subsystem(prefix+'struct_mesh',struct_mesh,promotes=['x_s0'],max_procs=self.struct_nprocs)
def create_fsi_connections(self,model,struct_mesh='struct_mesh',aero_mesh='aero_mesh',fsi_solver='fsi_solver',
nonlinear_xfer=False):

model.add_subsystem(prefix+'fsi_solver',fsi_solver,promotes=['dv_aero','dv_struct','x_a0','x_s0','x_g','q','u_s'])
model.connect(fsi_solver+'.struct.u_s',[fsi_solver+'.disp_xfer.u_s'])
if nonlinear_xfer:
model.connect(fsi_solver+'.struct.u_s',[fsi_solver+'.load_xfer.u_s'])

model.add_subsystem(prefix+'struct_funcs',struct_funcs,promotes=['*'],max_procs=self.struct_nprocs)
model.connect(fsi_solver+'.disp_xfer.u_a',fsi_solver+'.geo_disps.u_a')
model.connect(fsi_solver+'.geo_disps.x_a',fsi_solver+'.aero.deformer.x_a')
model.connect(fsi_solver+'.aero.deformer.x_g',[fsi_solver+'.aero.solver.x_g',
fsi_solver+'.aero.forces.x_g'])
model.connect(fsi_solver+'.aero.solver.q',[fsi_solver+'.aero.forces.q'])
model.connect(fsi_solver+'.aero.forces.f_a',[fsi_solver+'.load_xfer.f_a'])
model.connect(fsi_solver+'.load_xfer.f_s',fsi_solver+'.struct.f_s')

def _initialize_meshes(self,reuse_solvers):
def _initialize_mesh(self,reuse_solvers):
"""
Initialize the disciplinary meshes
Initialize the different discipline meshes
"""
aero_mesh = AeroMesh(aero_mesh_setup=self.aero_mesh_setup)
tacs_mesh = TacsMesh(tacs_mesh_setup=self.tacs_mesh_setup)

return aero_mesh, tacs_mesh
return tacs_mesh

def _initialize_solvers(self):
"""
Initialize the disciplinary solvers
Initialize the different disciplinary solvers
"""
deformer = AeroDeformer(aero_deformer_setup=self.aero_deformer_setup)
aero_solver = AeroSolver(aero_solver_setup=self.aero_solver_setup)
aero_force = AeroForceIntegrator(aero_force_integrator_setup=self.aero_force_integrator_setup)
aero_group = AeroSolverGroup(deformer=deformer,solver=aero_solver,force=aero_force)

tacs_solver = TacsSolver(tacs_solver_setup=self.tacs_solver_setup)
# Initialize the structural solver
struct = TacsSolver(tacs_solver_setup=self.tacs_solver_setup)

# Initialize the transfers
disp_xfer = FuntofemDisplacementTransfer(disp_xfer_setup=self.disp_xfer_setup)
load_xfer = FuntofemLoadTransfer(load_xfer_setup=self.load_xfer_setup)

return aero_group, tacs_solver, disp_xfer, load_xfer
return struct, disp_xfer, load_xfer

def _initialize_function_evaluators(self):
"""
Expand All @@ -103,6 +97,16 @@ def _initialize_function_evaluators(self):
tacs_funcs = TacsFunctions(tacs_func_setup=self.tacs_func_setup)
return tacs_funcs

def add_tacs_mesh(self,model,prefix='',reuse_solvers=True):
# Initialize the disciplinary meshes
tacs_mesh = TacsMesh(tacs_mesh_setup=self.tacs_mesh_setup)
model.add_subsystem('struct_mesh',tacs_mesh)

def add_tacs_functions(self,model,prefix='',reuse_solvers=True):
# Initialize the function evaluators
struct_funcs = self._initialize_function_evaluators()
model.add_subsystem('struct_funcs',struct_funcs)

def tacs_mesh_setup(self,comm):
"""
Setup callback function for TACS intial setup: reading the mesh and
Expand All @@ -125,9 +129,13 @@ def tacs_solver_setup(self,comm):
"""
Setup callback function for TACS solver setup.
"""

mat = self.tacs.createFEMat()
pc = TACS.Pc(mat)

self.mat = mat
self.pc = pc

subspace = 100
restarts = 2
gmres = TACS.KSM(mat, pc, subspace, restarts)
Expand All @@ -152,7 +160,7 @@ def tacs_func_setup(self,comm):
elif func.lower() == 'mass':
func_list.append(functions.StructuralMass(self.tacs))

return func_list, self.tacs, self.struct_ndv
return func_list, self.tacs, self.struct_ndv, self.mat, self.pc

def aero_mesh_setup(self,comm):
"""
Expand Down
1 change: 1 addition & 0 deletions examples/funtofem_and_tacs/debug.bdf
11 changes: 6 additions & 5 deletions examples/funtofem_and_tacs/dummy_aero_fixed.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def setup(self):
flow = self.options['aero_deformer_setup'](self.comm)
nnodes = flow['nnodes']

print('KEJ deformer print',nnodes*3)
self.add_input('x_a0',shape=nnodes*3, desc='dummy aero jig shape surface coordinates')
self.add_input('x_a',shape=nnodes*3, desc='dummy aero deformed surface coordinates')
self.add_output('x_g',shape=nnodes*3, desc='dummy aero volume grid')
Expand All @@ -48,13 +49,13 @@ def solve_nonlinear(self, inputs, outputs):

def solve_linear(self, d_outputs,d_residuals,mode):
if mode == 'fwd':
raise ValueError('forward mode requested but not implemented')
pass
if mode == 'rev':
d_residuals['x_g'] += d_outputs['x_g']

def apply_linear(self,inputs,outputs,d_inputs,d_outputs,d_residuals,mode):
if mode == 'fwd':
raise ValueError('forward mode requested but not implemented')
pass
if mode == 'rev':
if 'x_g' in d_residuals:
if 'x_g' in d_outputs:
Expand Down Expand Up @@ -90,13 +91,13 @@ def solve_nonlinear(self, inputs, outputs):

def solve_linear(self, d_outputs,d_residuals,mode):
if mode == 'fwd':
raise ValueError('forward mode requested but not implemented')
pass
if mode == 'rev':
d_residuals['q'] += d_outputs['q']

def apply_linear(self,inputs,outputs,d_inputs,d_outputs,d_residuals,mode):
if mode == 'fwd':
raise ValueError('forward mode requested but not implemented')
pass
if mode == 'rev':
if 'q' in d_residuals:
if 'q' in d_outputs:
Expand Down Expand Up @@ -126,7 +127,7 @@ def compute(self, inputs, outputs):

def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode):
if mode == 'fwd':
raise ValueError('forward mode requested but not implemented')
pass
if mode == 'rev':
if 'f_a' in d_outputs:
if 'q' in d_inputs:
Expand Down
71 changes: 43 additions & 28 deletions examples/funtofem_and_tacs/openmdao_fixed_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from tacs import elements, constitutive
from assemble_dummy_aero import FsiComps
from dummy_aero_fixed import *

################################################################################
# Tacs solver pieces
Expand All @@ -27,7 +28,7 @@ def add_elements(mesh):
max_thickness = 1.00

num_components = mesh.getNumComponents()
for i in xrange(num_components):
for i in range(num_components):
descript = mesh.getElementDescript(i)
stiff = constitutive.isoFSDT(rho, E, nu, kcorr, ys, t, i,
min_thickness, max_thickness)
Expand All @@ -44,7 +45,7 @@ def add_elements(mesh):
func_list = ['ks_failure','mass']
tacs_setup = {'add_elements': add_elements,
'nprocs' : 4,
'mesh_file' : 'CRM_box_2nd.bdf',
'mesh_file' : 'debug.bdf',
'func_list' : func_list}
meld_setup = {'isym': 1,
'n': 200,
Expand All @@ -53,7 +54,6 @@ def add_elements(mesh):

setup = {'tacs': tacs_setup, 'meld': meld_setup, 'flow': flow_setup}

fsi_comps = FsiComps()

################################################################################
# OpenMDAO setup
Expand All @@ -62,30 +62,45 @@ def add_elements(mesh):
model = prob.model

indeps = IndepVarComp()
indeps.add_output('dv_struct',np.array(240*[0.0031]))
indeps.add_output('dv_struct',np.array([0.1]))
indeps.add_output('dv_aero',1.0)
model.add_subsystem('indeps',indeps,promotes=['dv_struct','dv_aero'])

fsi_comps.add_fsi_subsystems(model,setup)

prob.driver = ScipyOptimizeDriver(debug_print=['objs','nl_cons'],maxiter=1000)
prob.driver.options['optimizer'] = 'SLSQP'

#recorder = SqliteRecorder('crm.sql')
#prob.driver.add_recorder(recorder)
#prob.driver.recording_options['includes'] = ['*']

model.add_design_var('dv_struct',lower=0.001,upper=0.075,scaler=1.0/1.0)

model.add_objective('mass',scaler=1.0/100000.0)
model.add_constraint('f_struct',lower = 0.0, upper = 2.0/3.0,scaler=100.0/100.0)

prob.setup()

#prob.run_model()
model.add_subsystem('dv',indeps)

fsi_comps = FsiComps(tacs_setup,meld_setup)
fsi_comps.add_tacs_mesh(model)
aero_mesh = AeroMesh(aero_mesh_setup=fsi_comps.aero_mesh_setup)
aero_deform = AeroDeformer(aero_deformer_setup=fsi_comps.aero_deformer_setup)
aero_solver = AeroSolver(aero_solver_setup=fsi_comps.aero_solver_setup)
aero_forces = AeroForceIntegrator(aero_force_integrator_setup=fsi_comps.aero_force_integrator_setup)

model.add_subsystem('aero_mesh',aero_mesh)
aero_group = Group()
aero_group.add_subsystem('deformer',aero_deform)
aero_group.add_subsystem('solver',aero_solver)
aero_group.add_subsystem('forces',aero_forces)
aero_group.nonlinear_solver = NonlinearRunOnce()
aero_group.linear_solver = LinearRunOnce()

fsi_comps.add_fsi_subsystems(model,aero_group,aero_nnodes=2)
fsi_comps.add_tacs_functions(model)

model.connect('aero_mesh.x_a0',['fsi_solver.disp_xfer.x_a0',
'fsi_solver.geo_disps.x_a0',
'fsi_solver.load_xfer.x_a0'])
model.connect('struct_mesh.x_s0',['fsi_solver.disp_xfer.x_s0',
'fsi_solver.load_xfer.x_s0',
'fsi_solver.struct.x_s0',
'struct_funcs.x_s0'])
model.connect('dv.dv_struct',['fsi_solver.struct.dv_struct',
'struct_funcs.dv_struct'])
model.connect('dv.dv_aero',['fsi_solver.aero.solver.dv_aero'])


model.connect('fsi_solver.struct.u_s','struct_funcs.u_s')
fsi_comps.create_fsi_connections(model,nonlinear_xfer=True)

prob.setup(force_alloc_complex=True)

prob.run_model()
#prob.check_partials()

prob.run_driver()

for i in range(240):
print('final dvs',i,prob['dv_struct'][i])
prob.check_partials(step=1e-30,compact_print=False,method='cs')
1 change: 1 addition & 0 deletions examples/tacs_only/debug.bdf
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def load_function(x_s,ndof):
f_s[2::ndof] = 100.0
return f_s

func_list = ['compliance']
func_list = ['mass','compliance']
tacs_setup = {'add_elements': add_elements,
'nprocs' : 4,
'mesh_file' : 'debug.bdf',
Expand Down

0 comments on commit 9295e92

Please sign in to comment.