@@ -257,6 +257,86 @@ def prime_loads(
257
257
timing_file = timing_file ,
258
258
)
259
259
260
+ @classmethod
261
+ def prime_loads_from_unsteady_files (
262
+ cls ,
263
+ files : list ,
264
+ solvers ,
265
+ model ,
266
+ nprocs ,
267
+ transfer_settings ,
268
+ external_shape = False ,
269
+ init_transfer = False ,
270
+ timing_file = None ,
271
+ ):
272
+ """
273
+ Used to prime aero loads for optimization over tacs analysis with shape change and tacs aim
274
+ Built from an aero loads file of a previous CFD analysis in FuntofemNlbgs driver (TODO : make uncoupled fluid solver features)
275
+ The loads file is written from the FUNtoFEM model after a forward analysis of a flow solver
276
+
277
+ Parameters
278
+ ----------
279
+ filename : str or path to aero loads file
280
+ the filepath of the aerodynamic loads file from a previous CFD analysis (written from FUNtoFEM model)
281
+ solvers: :class:`~interface.SolverManager`
282
+ Solver Interface for CFD such as Fun3dInterface, Su2Interface, or test aero solver
283
+ model : :class:`~model.FUNtoFEMmodel
284
+ nprocs: int
285
+ Number of processes that TACS is running on.
286
+ transfer_settings: :class:`~transfer_settings.TransferSettings`
287
+ Settings for transfer of state variables across aero and struct meshes
288
+ struct_aim: `caps2tacs.TacsAim`
289
+ Interface object from TACS to ESP/CAPS, wraps the tacsAIM object.
290
+ external_shape: bool
291
+ whether the tacs aim shape analysis is performed outside this class
292
+ timing_file: str or path
293
+ path to funtofem timing file statistics
294
+ """
295
+ comm = solvers .comm
296
+ world_rank = comm .Get_rank ()
297
+ if world_rank < nprocs :
298
+ color = 1
299
+ else :
300
+ color = MPI .UNDEFINED
301
+ tacs_comm = comm .Split (color , world_rank )
302
+
303
+ # initialize transfer settings
304
+ comm_manager = solvers .comm_manager
305
+
306
+ for itime , file in enumerate (files ):
307
+ # read in the loads from the file for each time step
308
+ loads_data = model ._read_aero_loads (comm , file )
309
+
310
+ # initialize the transfer scheme then distribute aero loads
311
+ for body in model .bodies :
312
+ if (
313
+ itime == 0
314
+ ): # only initialize transfer and scenario data on the first time step after the aero mesh is loaded
315
+ body .initialize_transfer (
316
+ comm = comm ,
317
+ struct_comm = tacs_comm ,
318
+ struct_root = comm_manager .struct_root ,
319
+ aero_comm = comm_manager .aero_comm ,
320
+ aero_root = comm_manager .aero_root ,
321
+ transfer_settings = transfer_settings ,
322
+ )
323
+ for scenario in model .scenarios :
324
+ assert not scenario .steady
325
+ body .initialize_variables (scenario )
326
+
327
+ body ._distribute_aero_loads (loads_data , steady = False , itime = itime )
328
+
329
+ tacs_driver = cls (
330
+ solvers ,
331
+ model ,
332
+ nprocs = nprocs ,
333
+ external_shape = external_shape ,
334
+ timing_file = timing_file ,
335
+ )
336
+ if init_transfer :
337
+ tacs_driver ._transfer_fixed_aero_loads ()
338
+ return tacs_driver
339
+
260
340
@classmethod
261
341
def prime_loads_from_file (
262
342
cls ,
@@ -304,7 +384,7 @@ def prime_loads_from_file(
304
384
comm_manager = solvers .comm_manager
305
385
306
386
# read in the loads from the file
307
- loads_data = model .read_aero_loads (comm , filename )
387
+ loads_data = model ._read_aero_loads (comm , filename )
308
388
309
389
# initialize the transfer scheme then distribute aero loads
310
390
for body in model .bodies :
@@ -318,7 +398,8 @@ def prime_loads_from_file(
318
398
)
319
399
for scenario in model .scenarios :
320
400
body .initialize_variables (scenario )
321
- body ._distribute_aero_loads (loads_data )
401
+ assert scenario .steady
402
+ body ._distribute_aero_loads (loads_data , steady = True )
322
403
323
404
tacs_driver = cls (
324
405
solvers ,
@@ -418,16 +499,36 @@ def _transfer_fixed_aero_loads(self):
418
499
)
419
500
420
501
# initialize new elastic struct vectors
421
- if body .transfer is not None :
422
- body .struct_loads [scenario .id ] = np .zeros (3 * ns , dtype = dtype )
423
- body .struct_disps [scenario .id ] = np .zeros (3 * ns , dtype = dtype )
424
-
425
- # initialize new struct heat flux
426
- if body .thermal_transfer is not None :
427
- body .struct_heat_flux [scenario .id ] = np .zeros (ns , dtype = dtype )
428
- body .struct_temps [scenario .id ] = (
429
- np .ones (ns , dtype = dtype ) * scenario .T_ref
430
- )
502
+ if scenario .steady :
503
+ if body .transfer is not None :
504
+ body .struct_loads [scenario .id ] = np .zeros (3 * ns , dtype = dtype )
505
+ body .struct_disps [scenario .id ] = np .zeros (3 * ns , dtype = dtype )
506
+
507
+ # initialize new struct heat flux
508
+ if body .thermal_transfer is not None :
509
+ body .struct_heat_flux [scenario .id ] = np .zeros (ns , dtype = dtype )
510
+ body .struct_temps [scenario .id ] = (
511
+ np .ones (ns , dtype = dtype ) * scenario .T_ref
512
+ )
513
+
514
+ else : # unsteady
515
+ if body .transfer is not None :
516
+ body .struct_loads [scenario .id ] = [
517
+ np .zeros (3 * ns , dtype = dtype ) for _ in range (scenario .steps )
518
+ ]
519
+ body .struct_disps [scenario .id ] = [
520
+ np .zeros (3 * ns , dtype = dtype ) for _ in range (scenario .steps )
521
+ ]
522
+
523
+ # initialize new struct heat flux
524
+ if body .thermal_transfer is not None :
525
+ body .struct_heat_flux [scenario .id ] = [
526
+ np .zeros (ns , dtype = dtype ) for _ in range (scenario .steps )
527
+ ]
528
+ body .struct_temps [scenario .id ] = [
529
+ (np .ones (ns , dtype = dtype ) * scenario .T_ref )
530
+ for _ in range (scenario .steps )
531
+ ]
431
532
432
533
# transfer disps to prevent seg fault if coming from OnewayAeroDriver
433
534
body .transfer_disps (scenario )
0 commit comments