Skip to content

Commit 5ed057e

Browse files
black reformat + throw error if FUN3D 13.6 uses coupling frequency
1 parent db82db3 commit 5ed057e

File tree

6 files changed

+112
-44
lines changed

6 files changed

+112
-44
lines changed

funtofem/driver/funtofem_nlbgs_driver.py

+16-9
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ def _solve_steady_forward(self, scenario, steps=None):
201201
if forward_resid > forward_tol:
202202
all_converged = False
203203
break
204-
205-
if all_converged:
204+
205+
if all_converged:
206206
if self.comm.rank == 0:
207207
print(
208208
f"F2F Steady Forward analysis of scenario {scenario.name} exited early"
@@ -283,19 +283,26 @@ def _solve_steady_adjoint(self, scenario):
283283

284284
# check for early stopping criterion, exit if meets criterion
285285
exit_early = False
286-
print(f"scenario min adjoint steps = {scenario.min_adjoint_steps}", flush=True)
286+
print(
287+
f"scenario min adjoint steps = {scenario.min_adjoint_steps}", flush=True
288+
)
287289
if scenario.early_stopping and step > scenario.min_adjoint_steps:
288-
all_converged = True # assume all converged until proven otherwise (then when one isn't exit for loop)
289-
for isolver,solver in enumerate(self.solvers.solver_list):
290+
all_converged = True # assume all converged until proven otherwise (then when one isn't exit for loop)
291+
for isolver, solver in enumerate(self.solvers.solver_list):
290292
adjoint_resid = abs(solver.get_adjoint_residual(step=step))
291293
adjoint_tol = solver.adjoint_tolerance
292294
if isolver == 0:
293-
adjoint_resids = solver.get_adjoint_residual(step=step, all=True)
295+
adjoint_resids = solver.get_adjoint_residual(
296+
step=step, all=True
297+
)
294298
print(f"adjoint residuals = {adjoint_resids}", flush=True)
295-
print(f"adjoint step {step} solver {isolver} resid = {adjoint_resid}, tol = {adjoint_tol}", flush=True)
299+
print(
300+
f"adjoint step {step} solver {isolver} resid = {adjoint_resid}, tol = {adjoint_tol}",
301+
flush=True,
302+
)
296303
if adjoint_resid > adjoint_tol:
297304
all_converged = False
298-
305+
299306
if all_converged:
300307
if self.comm.rank == 0:
301308
print(
@@ -307,7 +314,7 @@ def _solve_steady_adjoint(self, scenario):
307314
)
308315
exit_early = True
309316
break
310-
317+
311318
if exit_early:
312319
break
313320

funtofem/interface/fun3d_14_interface.py

+20-8
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,9 @@ def set_functions(self, scenario, bodies):
315315
start = 1
316316
stop = 1
317317
if ct == 1 and scenario.early_stopping:
318-
raise AssertionError("Need to register an aerodynamic function first otherwise the Adjoint early stopping criterion fails")
318+
raise AssertionError(
319+
"Need to register an aerodynamic function first otherwise the Adjoint early stopping criterion fails"
320+
)
319321
else:
320322
start = 1 if function.start is None else function.start
321323
if unsteady:
@@ -674,7 +676,10 @@ def post(self, scenario, bodies):
674676

675677
scalar_resid = abs(np.linalg.norm(resid).real)
676678
if self.comm.rank == 0:
677-
print(f"scalar forward resid in post scenario {scenario.name} = {scalar_resid}", flush=True)
679+
print(
680+
f"scalar forward resid in post scenario {scenario.name} = {scalar_resid}",
681+
flush=True,
682+
)
678683

679684
# throw a runtime error if adjoint didn't converge sufficiently
680685
if scalar_resid > self.forward_tolerance:
@@ -850,7 +855,7 @@ def iterate_adjoint(self, scenario, bodies, step):
850855
rstep = step
851856

852857
# update the last successful adjoint step in case FUN3D exits early
853-
#self._last_adjoint_step = step
858+
# self._last_adjoint_step = step
854859

855860
nfuncs = scenario.count_adjoint_functions()
856861
for ibody, body in enumerate(bodies, 1):
@@ -1001,8 +1006,8 @@ def iterate_adjoint(self, scenario, bodies, step):
10011006
# in FUN3D)
10021007
if self.comm.rank == 0:
10031008
print(f"iterate fun3d adjoint step {rstep}", flush=True)
1004-
for i_coupled in range(1, scenario.coupling_frequency+1):
1005-
adj_step = scenario.coupling_frequency * (rstep-1) + i_coupled
1009+
for i_coupled in range(1, scenario.coupling_frequency + 1):
1010+
adj_step = scenario.coupling_frequency * (rstep - 1) + i_coupled
10061011
self.fun3d_adjoint.iterate(adj_step)
10071012
self._last_adjoint_step = adj_step
10081013

@@ -1094,7 +1099,9 @@ def post_adjoint(self, scenario, bodies):
10941099
"""
10951100

10961101
# report warning if flow residual too large
1097-
resid = self.get_adjoint_residual(step=self._last_adjoint_step, outer=False, all=True)
1102+
resid = self.get_adjoint_residual(
1103+
step=self._last_adjoint_step, outer=False, all=True
1104+
)
10981105
if self.comm.rank == 0:
10991106
print(f"Adjoint residuals = {resid}")
11001107
self._adjoint_done = True
@@ -1106,7 +1113,10 @@ def post_adjoint(self, scenario, bodies):
11061113

11071114
scalar_resid = abs(np.linalg.norm(resid).real)
11081115
if self.comm.rank == 0:
1109-
print(f"scalar resid in adjoint post scenario {scenario.name} = {scalar_resid}",flush = True)
1116+
print(
1117+
f"scalar resid in adjoint post scenario {scenario.name} = {scalar_resid}",
1118+
flush=True,
1119+
)
11101120

11111121
# throw a runtime error if adjoint didn't converge sufficiently
11121122
if abs(np.linalg.norm(resid).real) > self.adjoint_tolerance:
@@ -1150,7 +1160,9 @@ def get_adjoint_residual(self, step=0, outer=True, all=False):
11501160
all: bool
11511161
whether to return a list of all residuals or a scalar
11521162
"""
1153-
if outer: # just overwrite to the saved last adjoint step since we don't have the scenario data
1163+
if (
1164+
outer
1165+
): # just overwrite to the saved last adjoint step since we don't have the scenario data
11541166
step = self._last_adjoint_step
11551167

11561168
if not self._adjoint_done:

funtofem/interface/fun3d_interface.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,14 @@ def initialize_adjoint(self, scenario, bodies):
760760
if self.model.flow is not None:
761761
self.fun3d_adjoint.set_mesh_morph(self.model.flow.mesh_morph)
762762

763+
# set the funtofem coupling frequency
764+
# would need to be implemented in FUN3D adjoint
765+
# self.fun3d_adjoint.set_coupling_frequency(scenario.coupling_frequency)
766+
if scenario.coupling_frequency != 1:
767+
raise AssertionError(
768+
"Funtofem has not implemented funtofem coupling in FUN3D 13.6"
769+
)
770+
763771
# Deform the aero mesh before finishing FUN3D initialization
764772
for ibody, body in enumerate(bodies, 1):
765773
aero_disps = body.get_aero_disps(
@@ -945,9 +953,9 @@ def iterate_adjoint(self, scenario, bodies, step):
945953

946954
# Update the aerodynamic and grid adjoint variables (Note: step starts at 1
947955
# in FUN3D)
948-
for i_coupled in range(1,scenario.coupling_frequency+1):
949-
adj_step = scenario.coupling_frequency * (rstep-1) + i_coupled
950-
self.fun3d_adjoint.iterate(adj_step)
956+
for i_coupled in range(1, scenario.coupling_frequency + 1):
957+
adj_step = scenario.coupling_frequency * (rstep - 1) + i_coupled
958+
self.fun3d_adjoint.iterate(adj_step)
951959

952960
for ibody, body in enumerate(bodies, 1):
953961
# Extract aero_disps_ajp = dG/du_A^T psi_G from FUN3D

funtofem/model/scenario.py

+16-8
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,9 @@ def __init__(
153153

154154
# early stopping criterion
155155
self.min_forward_steps = (
156-
min_forward_steps if min_forward_steps is not None else uncoupled_steps+self.UNCOUPLED_STEP_BUFFER
156+
min_forward_steps
157+
if min_forward_steps is not None
158+
else uncoupled_steps + self.UNCOUPLED_STEP_BUFFER
157159
)
158160
self.min_adjoint_steps = (
159161
min_adjoint_steps if min_adjoint_steps is not None else 0
@@ -180,7 +182,13 @@ def __init__(
180182
self.add_variable("aerodynamic", zrate)
181183

182184
@classmethod
183-
def steady(cls, name: str, steps: int, coupling_frequency:int=1, uncoupled_steps: int = 0):
185+
def steady(
186+
cls,
187+
name: str,
188+
steps: int,
189+
coupling_frequency: int = 1,
190+
uncoupled_steps: int = 0,
191+
):
184192
return cls(
185193
name=name,
186194
steady=True,
@@ -206,20 +214,20 @@ def unsteady(
206214
)
207215

208216
@property
209-
def adjoint_steps(self) -> int:
217+
def adjoint_steps(self) -> int:
210218
"""
211-
in the steady case it's best to choose the
219+
in the steady case it's best to choose the
212220
adjoint steps based on the funtofem coupling frequency
213221
"""
214222
if self._adjoint_steps is not None and self.steady:
215223
return self._adjoint_steps
216224
elif not self.steady:
217-
return None # defaults to number of steps in unsteady case
218-
else: # choose it based on funtofem coupling frequency in steady case
219-
return int(np.ceil(self.steps/self.coupling_frequency))
225+
return None # defaults to number of steps in unsteady case
226+
else: # choose it based on funtofem coupling frequency in steady case
227+
return int(np.ceil(self.steps / self.coupling_frequency))
220228

221229
@adjoint_steps.setter
222-
def adjoint_steps(self, new_steps:int):
230+
def adjoint_steps(self, new_steps: int):
223231
assert self.steady
224232
self._adjoint_steps = new_steps
225233

tests/fun3d_tests/fully_coupled_disc_deriv/turb_AE/test_adjoint_speed.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Unittest for FUN3D 14.0.2 finite-difference test
33
"""
4+
45
import numpy as np, unittest, importlib, os
56
from mpi4py import MPI
67
import time
@@ -39,15 +40,17 @@ class TestFun3dTacs(unittest.TestCase):
3940
FILEPATH = os.path.join(results_folder, FILENAME)
4041

4142
def test_alpha_turbulent_aeroelastic(self):
42-
start_time = time.time()
43+
start_time = time.time()
4344

4445
# build the funtofem model with one body and scenario
4546
model = FUNtoFEMmodel("plate")
4647
plate = Body.aeroelastic("plate", boundary=2)
4748
plate.register_to(model)
4849

4950
# build the scenario
50-
test_scenario = Scenario.steady("turbulent_beta", steps=500, coupling_frequency=20, uncoupled_steps=10)
51+
test_scenario = Scenario.steady(
52+
"turbulent_beta", steps=500, coupling_frequency=20, uncoupled_steps=10
53+
)
5154
test_scenario.set_stop_criterion(early_stopping=True, min_forward_steps=50)
5255
test_scenario.set_temperature(T_ref=300.0, T_inf=300.0)
5356
Function.lift().register_to(test_scenario)
@@ -60,7 +63,13 @@ def test_alpha_turbulent_aeroelastic(self):
6063

6164
# build the solvers and coupled driver
6265
solvers = SolverManager(comm)
63-
solvers.flow = Fun3d14Interface(comm, model, fun3d_dir="meshes", forward_tolerance=1e-11, adjoint_tolerance=1e-9)
66+
solvers.flow = Fun3d14Interface(
67+
comm,
68+
model,
69+
fun3d_dir="meshes",
70+
forward_tolerance=1e-11,
71+
adjoint_tolerance=1e-9,
72+
)
6473

6574
solvers.structural = TacsSteadyInterface.create_from_bdf(
6675
model, comm, nprocs=1, bdf_file=bdf_filename, prefix=output_dir
@@ -78,25 +87,26 @@ def test_alpha_turbulent_aeroelastic(self):
7887

7988
# run the complex step test on the model and driver
8089
# max_rel_error = TestResult.complex_step(
81-
#max_rel_error = TestResult.finite_difference(
90+
# max_rel_error = TestResult.finite_difference(
8291
# "fun3d+tacs-turbulent-aeroelastic-flow",
8392
# model,
8493
# driver,
8594
# TestFun3dTacs.FILEPATH,
86-
#)
87-
#self.assertTrue(max_rel_error < 1e-7)
88-
95+
# )
96+
# self.assertTrue(max_rel_error < 1e-7)
97+
8998
driver.solve_forward()
9099
time2 = time.time()
91100
driver.solve_adjoint()
92101

93102
_end_time = time.time()
94103
dt_full = _end_time - start_time
95104
dt_adjoint = _end_time - time2
96-
105+
97106
print(f"full time = {dt_full} sec", flush=True)
98107
print(f"adjoint time = {dt_adjoint} sec", flush=True)
99108

109+
100110
if __name__ == "__main__":
101111
# open and close the file to reset it
102112
if comm.rank == 0:

tests/fun3d_tests/fully_coupled_disc_deriv/turb_AE/test_early_stop_FD.py

+31-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Unittest for FUN3D 14.0.2 finite-difference test
33
"""
4+
45
import numpy as np, unittest, importlib, os
56
from mpi4py import MPI
67
import time
@@ -39,21 +40,26 @@
3940
forward_tol = 1e-11
4041
adjoint_tol = 1e-9
4142

43+
4244
class TestFun3dTacs(unittest.TestCase):
4345
FILENAME = "fun3d-tacs-driver.txt"
4446
FILEPATH = os.path.join(results_folder, FILENAME)
4547

4648
def test_alpha_turbulent_aeroelastic(self):
47-
start_time = time.time()
49+
start_time = time.time()
4850

4951
# build the funtofem model with one body and scenario
5052
model = FUNtoFEMmodel("plate")
5153
plate = Body.aeroelastic("plate", boundary=2)
5254
plate.register_to(model)
5355

5456
# build the scenario
55-
test_scenario = Scenario.steady("turbulent_beta", steps=500, coupling_frequency=20, uncoupled_steps=10)
56-
test_scenario.set_stop_criterion(early_stopping=early_stopping, min_forward_steps=50)
57+
test_scenario = Scenario.steady(
58+
"turbulent_beta", steps=500, coupling_frequency=20, uncoupled_steps=10
59+
)
60+
test_scenario.set_stop_criterion(
61+
early_stopping=early_stopping, min_forward_steps=50
62+
)
5763
test_scenario.set_temperature(T_ref=300.0, T_inf=300.0)
5864
Function.lift().register_to(test_scenario)
5965
Function.ksfailure(ks_weight=10.0).register_to(test_scenario)
@@ -65,7 +71,13 @@ def test_alpha_turbulent_aeroelastic(self):
6571

6672
# build the solvers and coupled driver
6773
solvers = SolverManager(comm)
68-
solvers.flow = Fun3d14Interface(comm, model, fun3d_dir="meshes", forward_tolerance=forward_tol, adjoint_tolerance=adjoint_tol)
74+
solvers.flow = Fun3d14Interface(
75+
comm,
76+
model,
77+
fun3d_dir="meshes",
78+
forward_tolerance=forward_tol,
79+
adjoint_tolerance=adjoint_tol,
80+
)
6981

7082
solvers.structural = TacsSteadyInterface.create_from_bdf(
7183
model, comm, nprocs=1, bdf_file=bdf_filename, prefix=output_dir
@@ -102,18 +114,28 @@ def test_thick_turbulent_aeroelastic(self):
102114
plate.register_to(model)
103115

104116
# build the scenario
105-
test_scenario = Scenario.steady("turbulent_beta", steps=500, coupling_frequency=20, uncoupled_steps=10)
106-
test_scenario.set_stop_criterion(early_stopping=early_stopping, min_forward_steps=50)
117+
test_scenario = Scenario.steady(
118+
"turbulent_beta", steps=500, coupling_frequency=20, uncoupled_steps=10
119+
)
120+
test_scenario.set_stop_criterion(
121+
early_stopping=early_stopping, min_forward_steps=50
122+
)
107123
test_scenario.set_temperature(T_ref=300.0, T_inf=300.0)
108-
Function.lift().register_to(test_scenario)
124+
Function.lift().register_to(test_scenario)
109125
Function.ksfailure(ks_weight=10.0).register_to(test_scenario)
110126
Function.drag().register_to(test_scenario)
111127
test_scenario.set_flow_ref_vals(qinf=1.05e5)
112128
test_scenario.register_to(model)
113129

114130
# build the solvers and coupled driver
115131
solvers = SolverManager(comm)
116-
solvers.flow = Fun3d14Interface(comm, model, fun3d_dir="meshes", forward_tolerance=forward_tol, adjoint_tolerance=adjoint_tol)
132+
solvers.flow = Fun3d14Interface(
133+
comm,
134+
model,
135+
fun3d_dir="meshes",
136+
forward_tolerance=forward_tol,
137+
adjoint_tolerance=adjoint_tol,
138+
)
117139

118140
solvers.structural = TacsSteadyInterface.create_from_bdf(
119141
model, comm, nprocs=1, bdf_file=bdf_filename, prefix=output_dir
@@ -139,6 +161,7 @@ def test_thick_turbulent_aeroelastic(self):
139161
)
140162
self.assertTrue(max_rel_error < 2e-3)
141163

164+
142165
if __name__ == "__main__":
143166
# open and close the file to reset it
144167
if comm.rank == 0:

0 commit comments

Comments
 (0)