Skip to content

Commit 33b8e49

Browse files
authored
Merge pull request #211 from kejacobson/geometry_access
Add a geometry base class to the MPhys variable convention
2 parents 4529b50 + 8e34654 commit 33b8e49

File tree

12 files changed

+359
-423
lines changed

12 files changed

+359
-423
lines changed

.flake8

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
[flake8]
2+
max-line-length = 120
3+
4+
extend-ignore =
5+
# black
6+
E203,
7+
# too many leading '#' for block comment
8+
E266,
9+
# expected 2 blank lines, found 1
10+
E302,
11+
# do not use mutable data structures for argument defaults (too many false positives)
12+
B006,
13+
# ===== TODO: to be fixed:
14+
# invalid escape sequence, necessary for sphinx directives in docstrings but should switch to raw string
15+
W605,
16+
# line length, exceeded by some docstrings
17+
E501,
18+
# Function definition does not bind loop variable, happens everywhere in our code
19+
B023,
20+
# pydocstyle
21+
D
22+
23+
# Only add patterns here that are not included by the defaults of flake8 or other plugins
24+
# extend-select =
25+
26+
# flake8-docstrings
27+
docstring-convention = numpy
28+
29+
# flake8-rst-docstrings
30+
rst-roles =
31+
class,
32+
func,
33+
ref,
34+
meth,
35+
36+
rst-directives =
37+
# Custom directives defined in the sphinx_mdolab_theme
38+
embed-compare,
39+
embed-bibtex,
40+
embed-code,
41+
embed-shell-cmd,
42+
embed-n2,
43+
44+
# mccabe complexity
45+
# max-complexity = 10
46+
47+
# ignored files/directories
48+
# we use exclude here and extend-exclude in repo-specific config files
49+
# so that we can pass both to flake8 directly without needing to merge them first
50+
exclude =
51+
# No need to traverse the git directory
52+
.git,
53+
# There's no value in checking cache directories
54+
__pycache__,
55+
# The conf file is mostly autogenerated, ignore it
56+
doc/conf.py,
57+
# No need for init and setup files
58+
__init__.py,
59+
setup.py,

.vscode/extensions.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3+
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4+
5+
// List of extensions which should be recommended for users of this workspace.
6+
"recommendations": [
7+
"ms-python.python",
8+
"ms-python.isort",
9+
"ms-python.flake8",
10+
"ms-python.black-formatter",
11+
],
12+
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
13+
"unwantedRecommendations": [
14+
15+
]
16+
}

.vscode/settings.json

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
{
2-
"python.formatting.provider": "black",
3-
"python.testing.unittestArgs": [
4-
"-v",
5-
"-s",
6-
"./tests/unit_tests",
7-
"-p",
8-
"test*.py"
9-
],
10-
"python.testing.pytestEnabled": false,
11-
"python.testing.nosetestsEnabled": false,
12-
"python.testing.unittestEnabled": true,
13-
"python.analysis.useImportHeuristic": true,
14-
"esbonio.server.enabled": true,
15-
"esbonio.sphinx.confDir": "${workspaceFolder}/docs"
2+
"[python]": {
3+
"editor.defaultFormatter": "ms-python.black-formatter",
4+
"editor.formatOnSave": true, // black on save
5+
"editor.codeActionsOnSave": {
6+
"source.organizeImports": "always" // isort on save
7+
}
8+
},
9+
"flake8.args": ["--config", ".flake8"]
1610
}

examples/aerostructural/supersonic_panel/as_opt_parallel.py

Lines changed: 85 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@
88
from structures_mphys import StructBuilder
99
from xfer_mphys import XferBuilder
1010

11-
from mphys import Multipoint, MultipointParallel
11+
from mphys import MPhysVariables, MultipointParallel
1212
from mphys.scenarios.aerostructural import ScenarioAeroStructural
1313

14-
# True=check objective/constraint derivatives, False=run optimization
15-
check_totals = False
16-
1714
# panel geometry
1815
panel_chord = 0.3
1916
panel_width = 0.01
@@ -23,7 +20,6 @@
2320
N_el_aero = 7
2421

2522

26-
# Mphys parallel multipoint scenarios
2723
class AerostructParallel(MultipointParallel):
2824
def initialize(self):
2925
self.options.declare("aero_builder")
@@ -108,8 +104,13 @@ def setup(self):
108104
)
109105

110106
# geometry
111-
builders = {"struct": struct_builder, "aero": aero_builder}
112-
geometry_builder = GeometryBuilder(builders)
107+
geometry_builder = GeometryBuilder()
108+
geometry_builder.add_discipline(
109+
struct_builder, MPhysVariables.Structures.Geometry
110+
)
111+
geometry_builder.add_discipline(
112+
aero_builder, MPhysVariables.Aerodynamics.Surface.Geometry
113+
)
113114

114115
# add parallel multipoint group
115116
self.add_subsystem(
@@ -125,38 +126,34 @@ def setup(self):
125126

126127
for i in range(len(self.scenario_names)):
127128

128-
# connect scalar inputs to the scenario
129129
for var in ["modulus", "yield_stress", "density", "dv_struct"]:
130130
self.connect(var, "multipoint." + self.scenario_names[i] + "." + var)
131131

132-
# connect vector inputs
133132
for var in ["mach", "qdyn", "aoa"]:
134133
self.connect(
135134
var,
136135
"multipoint." + self.scenario_names[i] + "." + var,
137136
src_indices=[i],
138137
)
139138

140-
# connect top-level geom parameter
141139
self.connect(
142140
"geometry_morph_param",
143141
"multipoint."
144142
+ self.scenario_names[i]
145143
+ ".geometry.geometry_morph_param",
146144
)
147145

148-
# add design vars
149146
self.add_design_var("geometry_morph_param", lower=0.1, upper=10.0)
150147
self.add_design_var("dv_struct", lower=1.0e-4, upper=1.0e-2, ref=1.0e-3)
151148
self.add_design_var("aoa", lower=-20.0, upper=20.0)
152149

153-
# add objective/constraints
154150
self.add_objective(f"multipoint.{self.scenario_names[0]}.mass", ref=0.01)
155151
self.add_constraint(
156152
f"multipoint.{self.scenario_names[0]}.func_struct",
157153
upper=1.0,
158154
parallel_deriv_color="struct_cons",
159155
) # run func_struct derivatives in parallel
156+
160157
self.add_constraint(
161158
f"multipoint.{self.scenario_names[1]}.func_struct",
162159
upper=1.0,
@@ -168,6 +165,7 @@ def setup(self):
168165
ref=0.1,
169166
parallel_deriv_color="lift_cons",
170167
) # run C_L derivatives in parallel
168+
171169
self.add_constraint(
172170
f"multipoint.{self.scenario_names[1]}.C_L",
173171
lower=0.45,
@@ -180,101 +178,92 @@ def get_model(scenario_names):
180178
return Model(scenario_names=scenario_names)
181179

182180

183-
# run model and check derivatives
184-
if __name__ == "__main__":
185-
186-
prob = om.Problem()
187-
prob.model = Model()
188-
189-
if check_totals:
190-
prob.setup(mode="rev")
191-
om.n2(prob, show_browser=False, outfile="n2.html")
192-
prob.run_model()
193-
prob.check_totals(
194-
step_calc="rel_avg",
195-
compact_print=True,
196-
directional=False,
197-
show_progress=True,
198-
out_stream=None if prob.model.comm.rank > 0 else _DEFAULT_OUT_STREAM,
199-
)
200-
201-
else:
202-
203-
# setup optimization driver
204-
prob.driver = om.ScipyOptimizeDriver(
205-
debug_print=["nl_cons", "objs", "desvars", "totals"]
206-
)
207-
prob.driver.options["optimizer"] = "SLSQP"
208-
prob.driver.options["tol"] = 1e-5
209-
prob.driver.options["disp"] = True
210-
prob.driver.options["maxiter"] = 300
211-
212-
# add optimization recorder
213-
prob.driver.recording_options["record_objectives"] = True
214-
prob.driver.recording_options["record_constraints"] = True
215-
prob.driver.recording_options["record_desvars"] = True
216-
prob.driver.recording_options["record_derivatives"] = True
217-
218-
recorder = om.SqliteRecorder("optimization_history.sql")
219-
prob.driver.add_recorder(recorder)
220-
221-
# run the optimization
222-
prob.setup(mode="rev")
223-
prob.run_driver()
224-
prob.cleanup()
225-
226-
if prob.model.comm.rank == 0: # write out data
227-
cr = om.CaseReader(f"{prob.get_outputs_dir()}/optimization_history.sql")
228-
driver_cases = cr.list_cases("driver")
229-
230-
case = cr.get_case(0)
231-
cons = case.get_constraints()
232-
dvs = case.get_design_vars()
233-
objs = case.get_objectives()
234-
235-
f = open("optimization_history.dat", "w+")
236-
181+
def run_check_totals(prob: om.Problem):
182+
prob.setup(mode="rev")
183+
om.n2(prob, show_browser=False, outfile="n2.html")
184+
prob.run_model()
185+
prob.check_totals(
186+
step_calc="rel_avg",
187+
compact_print=True,
188+
directional=False,
189+
show_progress=True,
190+
out_stream=None if prob.model.comm.rank > 0 else _DEFAULT_OUT_STREAM,
191+
)
192+
193+
194+
def run_optimization(prob: om.Problem):
195+
prob.driver = om.ScipyOptimizeDriver(
196+
debug_print=["nl_cons", "objs", "desvars", "totals"]
197+
)
198+
prob.driver.options["optimizer"] = "SLSQP"
199+
prob.driver.options["tol"] = 1e-5
200+
prob.driver.options["disp"] = True
201+
prob.driver.options["maxiter"] = 300
202+
203+
# add optimization recorder
204+
prob.driver.recording_options["record_objectives"] = True
205+
prob.driver.recording_options["record_constraints"] = True
206+
prob.driver.recording_options["record_desvars"] = True
207+
prob.driver.recording_options["record_derivatives"] = True
208+
209+
recorder = om.SqliteRecorder("optimization_history.sql")
210+
prob.driver.add_recorder(recorder)
211+
212+
# run the optimization
213+
prob.setup(mode="rev")
214+
prob.run_driver()
215+
prob.cleanup()
216+
217+
write_out_optimization_data(prob, "optimization_history.sql")
218+
219+
220+
def write_out_optimization_data(prob: om.Problem, sql_file: str):
221+
if prob.model.comm.rank == 0:
222+
cr = om.CaseReader(f"{prob.get_outputs_dir()}/{sql_file}")
223+
driver_cases = cr.list_cases("driver")
224+
225+
case = cr.get_case(0)
226+
cons = case.get_constraints()
227+
dvs = case.get_design_vars()
228+
objs = case.get_objectives()
229+
230+
with open("optimization_history.dat", "w+") as f:
237231
for i, k in enumerate(objs.keys()):
238232
f.write("objective: " + k + "\n")
239233
for j, case_id in enumerate(driver_cases):
240234
f.write(
241-
str(j)
242-
+ " "
243-
+ str(cr.get_case(case_id).get_objectives(scaled=False)[k][0])
244-
+ "\n"
235+
f"{j} {cr.get_case(case_id).get_objectives(scaled=False)[k][0]}\n"
245236
)
246-
f.write(" " + "\n")
237+
f.write("\n")
247238

248239
for i, k in enumerate(cons.keys()):
249240
f.write("constraint: " + k + "\n")
250241
for j, case_id in enumerate(driver_cases):
251-
f.write(
252-
str(j)
253-
+ " "
254-
+ " ".join(
255-
map(
256-
str,
257-
cr.get_case(case_id).get_constraints(scaled=False)[k],
258-
)
259-
)
260-
+ "\n"
261-
)
262-
f.write(" " + "\n")
242+
constraints = cr.get_case(case_id).get_constraints(scaled=False)[k]
243+
line = f"{j} {' '.join(map(str, constraints))}\n"
244+
f.write(line)
245+
f.write("\n")
263246

264247
for i, k in enumerate(dvs.keys()):
265248
f.write("DV: " + k + "\n")
266249
for j, case_id in enumerate(driver_cases):
267-
f.write(
268-
str(j)
269-
+ " "
270-
+ " ".join(
271-
map(
272-
str,
273-
cr.get_case(case_id).get_design_vars(scaled=False)[k],
274-
)
275-
)
276-
+ "\n"
277-
)
278-
f.write(" " + "\n")
250+
design_vars = cr.get_case(case_id).get_design_vars(scaled=False)[k]
251+
line = f"{j} {' '.join(map(str, design_vars))}\n"
252+
f.write(line)
253+
254+
255+
def main():
279256

280-
f.close()
257+
check_totals = False
258+
259+
prob = om.Problem()
260+
prob.model = Model()
261+
262+
if check_totals:
263+
run_check_totals(prob)
264+
else:
265+
run_optimization(prob)
266+
267+
268+
if __name__ == "__main__":
269+
main()

0 commit comments

Comments
 (0)