35
35
pass
36
36
37
37
38
- class FUNtoFEMmodal (FUNtoFEMDriver ):
38
+ class FUNtoFEMmodalDriver (FUNtoFEMDriver ):
39
39
def __init__ (
40
40
self ,
41
41
solvers ,
@@ -46,8 +46,8 @@ def __init__(
46
46
reload_funtofem_states = False ,
47
47
):
48
48
"""
49
- Driver that is based on FUNtoFEMnlbgs, but uses an IDF
50
- implementation to solve the coupled problem and a modal
49
+ Driver that is based on FUNtoFEMnlbgs, but uses an IDF
50
+ implementation to solve the coupled problem and a modal
51
51
reconstruction of the structural deformation.
52
52
53
53
Parameters
@@ -64,7 +64,7 @@ def __init__(
64
64
whether to save and reload funtofem states
65
65
"""
66
66
67
- super (FUNtoFEMmodal , self ).__init__ (
67
+ super (FUNtoFEMmodalDriver , self ).__init__ (
68
68
solvers ,
69
69
comm_manager = comm_manager ,
70
70
transfer_settings = transfer_settings ,
@@ -88,7 +88,7 @@ def manager(self, hot_start: bool = False, write_designs: bool = True):
88
88
89
89
def _initialize_adjoint_variables (self , scenario , bodies ):
90
90
"""
91
- Initialize the adjoint variables
91
+ Initialize the adjoint variables stored in the body.
92
92
93
93
Parameters
94
94
----------
@@ -105,8 +105,9 @@ def _initialize_adjoint_variables(self, scenario, bodies):
105
105
106
106
def _solve_steady_forward (self , scenario , steps = None ):
107
107
"""
108
- Solve the aerothermoelastic forward analysis using the nonlinear block Gauss-Seidel algorithm.
109
- Aitken under-relaxation is used here for stabilty.
108
+ Evaluate the aerothermoelastic forward analysis. Does *not* solve
109
+ the coupled problem.
110
+ Evaluation path for e.g., aeroelastic is D->A->L->S.
110
111
111
112
Parameters
112
113
----------
@@ -119,127 +120,53 @@ def _solve_steady_forward(self, scenario, steps=None):
119
120
assert scenario .steady
120
121
fail = 0
121
122
122
- # # Determine if we're using the scenario's number of steps or the argument
123
- # if steps is None:
124
- # steps = scenario.steps
123
+ # Transfer modal displacements and temperatures from structure to aerodynamic mesh
124
+ for body in self .model .bodies :
125
+ # Get the modal coordinates on the structure mesh and compute the product
126
+ # to get effective disps.
127
+ body .convert_modal_disps (scenario )
128
+ body .convert_modal_temps (scenario )
129
+ # At this stage, we've recreated u_s and T_s
130
+
131
+ body .transfer_disps (scenario )
132
+ body .transfer_temps (scenario )
125
133
126
- # flow uncoupled steps (mainly for aerothermal and aerothermoelastic analysis)
127
- for step in range (1 , scenario .uncoupled_steps + 1 ):
128
- # Take a step in the flow solver for (just aerodynamic iteration)
129
- fail = self .solvers .flow .uncoupled_iterate (
130
- scenario , self .model .bodies , step
131
- )
134
+ # Solve the flow problem
135
+ for step in range (1 , scenario .steps + 1 ):
136
+ fail = self .solvers .flow .iterate (scenario , self .model .bodies , step )
132
137
133
- # exit with failure if the flow iteration failed
134
138
fail = self .comm .allreduce (fail )
135
139
if fail != 0 :
136
140
if self .comm .Get_rank () == 0 :
137
- print ("Flow solver returned fail flag" )
141
+ print ("Flow solver returned fail flag. " )
138
142
return fail
139
143
140
- # Loop over the NLBGS steps in a loose coupling phase then tight coupling phase
141
- for i , nlbgs_steps in enumerate (
142
- [scenario .steps , scenario .post_tight_forward_steps ]
143
- ):
144
- if i == 1 :
145
- self .solvers .flow .initialize_forward_tight_coupling (scenario )
146
-
147
- for step in range (1 , nlbgs_steps + 1 ):
148
- # Transfer displacements and temperatures
149
- for body in self .model .bodies :
150
- body .transfer_disps (scenario )
151
- body .transfer_temps (scenario )
152
-
153
- # Take a step in the flow solver
154
- fail = self .solvers .flow .iterate (scenario , self .model .bodies , step )
155
-
156
- fail = self .comm .allreduce (fail )
157
- if fail != 0 :
158
- if self .comm .Get_rank () == 0 :
159
- print ("Flow solver returned fail flag" )
160
- return fail
161
-
162
- # Transfer the loads and heat flux
163
- for body in self .model .bodies :
164
- body .transfer_loads (scenario )
165
- body .transfer_heat_flux (scenario )
166
-
167
- if self ._debug :
168
- struct_loads = body .get_struct_loads (scenario )
169
- aero_loads = body .get_aero_loads (scenario )
170
- print (f"========================================" )
171
- print (f"Inside nlbgs driver, step: { step } " )
172
- if struct_loads is not None :
173
- print (
174
- f"norm of real struct_loads: { real_norm (struct_loads )} "
175
- )
176
- print (
177
- f"norm of imaginary struct_loads: { imag_norm (struct_loads )} "
178
- )
179
- print (f"aero_loads: { aero_loads } " )
180
- if aero_loads is not None :
181
- print (f"norm of real aero_loads: { real_norm (aero_loads )} " )
182
- print (
183
- f"norm of imaginary aero_loads: { imag_norm (aero_loads )} "
184
- )
185
- print (f"========================================\n " , flush = True )
186
-
187
- # Take a step in the FEM model
188
- fail = self .solvers .structural .iterate (
189
- scenario , self .model .bodies , step
190
- )
191
-
192
- fail = self .comm .allreduce (fail )
193
- if fail != 0 :
194
- if self .comm .Get_rank () == 0 :
195
- print ("Structural solver returned fail flag" )
196
- return fail
144
+ # Transfer forces and heat fluxes from aerodynamic to structure mesh
145
+ for body in self .model .bodies :
146
+ body .transfer_loads (scenario )
147
+ body .transfer_heat_flux (scenario )
197
148
198
- # Under-relaxation for solver stability
199
- for body in self .model .bodies :
200
- body .aitken_relax (self .comm , scenario )
149
+ # Solve the structure problem
150
+ fail = self .solvers .structural .iterate (scenario , self .model .bodies , step )
201
151
202
- # check for early stopping criterion, exit if meets criterion
203
- exit_early = False
204
- # only exit early in the loose coupling phase
205
- if (
206
- scenario .early_stopping
207
- and step > scenario .min_forward_steps
208
- and i == 0
209
- ):
210
- all_converged = True
211
- for solver in self .solvers .solver_list :
212
- forward_resid = abs (solver .get_forward_residual (step = step ))
213
- if forward_resid != 0.0 :
214
- if self .comm .rank == 0 :
215
- print (
216
- f"f2f scenario { scenario .name } , forward resid = { forward_resid } " ,
217
- flush = True ,
218
- )
219
- forward_tol = solver .forward_tolerance
220
- if forward_resid > forward_tol :
221
- all_converged = False
222
- break
152
+ fail = self .comm .allreduce (fail )
153
+ if fail != 0 :
154
+ if self .comm .Get_rank () == 0 :
155
+ print ("Structural solver returned fail flag." )
156
+ return fail
223
157
224
- if all_converged :
225
- exit_early = True
226
- if exit_early and self .comm .rank == 0 :
227
- print (
228
- f"F2F Steady Forward analysis of scenario { scenario .name } exited early"
229
- )
230
- print (
231
- f"\t at step { step } with tolerance { forward_resid } < { forward_tol } " ,
232
- flush = True ,
233
- )
234
- if exit_early :
235
- break
158
+ # Additional computation to transpose modal coordinate matrix
159
+ for body in self .model .bodies :
160
+ body .convert_modal_disps_transpose (scenario )
161
+ body .convert_modal_temps_transpose (scenario )
236
162
237
163
return fail
238
164
239
165
def _solve_steady_adjoint (self , scenario ):
240
166
"""
241
- Solve the aeroelastic adjoint analysis using the linear block Gauss-Seidel algorithm.
242
- Aitken under-relaxation for stabilty.
167
+ Evaluate the aerothermoelastic adjoint analysis. Does *not* solve
168
+ the coupled problem.
169
+ Evaluation path for e.g., aeroelastic is S^bar->L^bar->A^bar->D^bar.
243
170
244
171
Parameters
245
172
----------
@@ -255,9 +182,34 @@ def _solve_steady_adjoint(self, scenario):
255
182
body .transfer_disps (scenario )
256
183
body .transfer_loads (scenario )
257
184
185
+ body .transfer_temps (scenario )
186
+ body .transfer_heat_flux (scenario )
187
+
258
188
# Initialize the adjoint variables
259
189
self ._initialize_adjoint_variables (scenario , self .model .bodies )
260
190
191
+ # Take a step in the structural adjoint
192
+ fail = self .solvers .structural .iterate_adjoint (
193
+ scenario , self .model .bodies , step = 0
194
+ )
195
+
196
+ # Solve the flow adjoint
197
+ for step in range (1 , scenario .adjoint_steps + 1 ):
198
+ # Get force and heat flux terms for flow solver
199
+ for body in self .model .bodies :
200
+ body .transfer_loads_adjoint (scenario )
201
+ body .transfer_heat_flux_adjoint (scenario )
202
+
203
+ fail = self .solvers .flow .iterate_adjoint (scenario , self .model .bodies , step )
204
+
205
+ fail = self .comm .allreduce (fail )
206
+ if fail != 0 :
207
+ if self .comm .Get_rank () == 0 :
208
+ print ("Flow solver returned fail flag." )
209
+ return fail
210
+
211
+ ###
212
+
261
213
# loop over the adjoint NLBGS solver in a loose coupling phase
262
214
for i , nlbgs_steps in enumerate (
263
215
[scenario .adjoint_steps , scenario .post_tight_adjoint_steps ]
@@ -365,68 +317,7 @@ def _solve_unsteady_forward(self, scenario, steps=None):
365
317
366
318
"""
367
319
368
- assert not scenario .steady
369
- fail = 0
370
-
371
- if not steps :
372
- if not self .fakemodel :
373
- steps = scenario .steps
374
- else :
375
- if self .comm .Get_rank () == 0 :
376
- print (
377
- "No number of steps given for the coupled problem. Using default (1000)"
378
- )
379
- steps = 1000
380
-
381
- for time_index in range (1 , steps + 1 ):
382
- # Transfer displacements and temperatures
383
- for body in self .model .bodies :
384
- body .transfer_disps (scenario , time_index )
385
- body .transfer_temps (scenario , time_index )
386
-
387
- # Take a step in the flow solver
388
- fail = self .solvers .flow .iterate (scenario , self .model .bodies , time_index )
389
-
390
- fail = self .comm .allreduce (fail )
391
- if fail != 0 :
392
- if self .comm .Get_rank () == 0 :
393
- print ("Flow solver returned fail flag" )
394
- return fail
395
-
396
- # Transfer the loads and heat flux
397
- for body in self .model .bodies :
398
- body .transfer_loads (scenario , time_index )
399
- body .transfer_heat_flux (scenario , time_index )
400
-
401
- if self ._debug :
402
- struct_loads = body .get_struct_loads (
403
- scenario , time_index = time_index
404
- )
405
- aero_loads = body .get_aero_loads (scenario , time_index = time_index )
406
- print (f"========================================" )
407
- print (f"Inside nlbgs driver, step: { time_index } " )
408
- if struct_loads is not None :
409
- print (f"norm of real struct_loads: { real_norm (struct_loads )} " )
410
- print (
411
- f"norm of imaginary struct_loads: { imag_norm (struct_loads )} "
412
- )
413
- if aero_loads is not None :
414
- print (f"norm of real aero_loads: { real_norm (aero_loads )} " )
415
- print (f"norm of imaginary aero_loads: { imag_norm (aero_loads )} " )
416
- print (f"========================================\n " , flush = True )
417
-
418
- # Take a step in the FEM model
419
- fail = self .solvers .structural .iterate (
420
- scenario , self .model .bodies , time_index
421
- )
422
-
423
- fail = self .comm .allreduce (fail )
424
- if fail != 0 :
425
- if self .comm .Get_rank () == 0 :
426
- print ("Structural solver returned fail flag" )
427
- return fail
428
-
429
- return fail
320
+ pass
430
321
431
322
def _solve_unsteady_adjoint (self , scenario ):
432
323
"""
@@ -446,78 +337,4 @@ def _solve_unsteady_adjoint(self, scenario):
446
337
447
338
"""
448
339
449
- assert not scenario .steady
450
- fail = 0
451
-
452
- # how many steps to take
453
- steps = scenario .steps
454
-
455
- # Initialize the adjoint variables
456
- self ._initialize_adjoint_variables (scenario , self .model .bodies )
457
-
458
- # Loop over each time step in the reverse order
459
- for rstep in range (1 , steps + 1 ):
460
- step = steps - rstep + 1
461
-
462
- # load current state, affects MELD jacobians in the adjoint matrix (esp. load transfer)
463
- for body in self .model .bodies :
464
- body .transfer_disps (scenario , time_index = step )
465
- body .transfer_temps (scenario , time_index = step )
466
-
467
- self .solvers .flow .set_states (scenario , self .model .bodies , step )
468
- # Due to the staggering, we linearize the transfer about t_s^(n-1)
469
- self .solvers .structural .set_states (scenario , self .model .bodies , step - 1 )
470
-
471
- # take a step in the structural adjoint
472
- fail = self .solvers .structural .iterate_adjoint (
473
- scenario , self .model .bodies , step
474
- )
475
-
476
- fail = self .comm .allreduce (fail )
477
- if fail != 0 :
478
- if self .comm .Get_rank () == 0 :
479
- print ("Structural solver returned fail flag" )
480
- return fail
481
-
482
- for body in self .model .bodies :
483
- body .transfer_loads_adjoint (scenario )
484
- body .transfer_heat_flux_adjoint (scenario )
485
-
486
- fail = self .solvers .flow .iterate_adjoint (scenario , self .model .bodies , step )
487
-
488
- fail = self .comm .allreduce (fail )
489
- if fail != 0 :
490
- if self .comm .Get_rank () == 0 :
491
- print ("Flow solver returned fail flag" )
492
- return fail
493
-
494
- for body in self .model .bodies :
495
- body .transfer_disps_adjoint (scenario )
496
- body .transfer_temps_adjoint (scenario )
497
-
498
- # extract and accumulate coordinate derivative every step
499
- self ._extract_coordinate_derivatives (scenario , self .model .bodies , step )
500
-
501
- # end of solve loop
502
-
503
- # evaluate the initial conditions
504
- fail = self .solvers .flow .iterate_adjoint (scenario , self .model .bodies , step = 0 )
505
- fail = self .comm .allreduce (fail )
506
- if fail != 0 :
507
- if self .comm .Get_rank () == 0 :
508
- print ("Flow solver returned fail flag" )
509
- return fail
510
-
511
- fail = self .solvers .structural .iterate_adjoint (
512
- scenario , self .model .bodies , step = 0
513
- )
514
- fail = self .comm .allreduce (fail )
515
- if fail != 0 :
516
- if self .comm .Get_rank () == 0 :
517
- print ("Structural solver returned fail flag" )
518
- return fail
519
-
520
- # extract coordinate derivative term from initial condition
521
- self ._extract_coordinate_derivatives (scenario , self .model .bodies , step = 0 )
522
-
523
- return 0
340
+ pass
0 commit comments