Skip to content

Commit 60e70cb

Browse files
authored
Merge pull request #173 from Asthelen/network_remote_dvs
Tweaks for remote components
2 parents 29cf851 + 83bcd2d commit 60e70cb

18 files changed

+539
-256
lines changed

docs/basics/remote_components.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Troubleshooting
6868
---------------
6969
The :code:`dump_json` option for :code:`RemoteZeroMQComp` will make the component write input and output JSON files, which contain all data sent to and received from the server.
7070
An exception is the :code:`wall_time` entry (given in seconds) in the output JSON file, which is added on the client-side after the server has completed the design evaluation.
71+
Similarly, the :code:`down_time` entry keeps track of the elapsed time between the end of the previous design evaluation and the beginning of the current one.
7172
Another entry that is only provided for informational purposes is :code:`design_counter`, which keeps track of how many different designs have been evaluated on the current server.
7273
If :code:`dump_separate_json` is set to True, then separate files will be written for each design evaluation.
7374
On the server side, an n2 file titled :code:`n2_inner_analysis_<component name>.html` will be written after each evaluation.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Summary of top-level codes:
2+
3+
run.py: most basic code that demonstrates a single scenario, doing a derivative check at the starting design
4+
run_parallel.py: code that demonstrates two scenarios (differing by Mach and dynamic pressure), evaluated in parallel with MultipointParallel, doing a derivative check at the starting design
5+
as_opt_parallel.py: runs an optimization of the previous code's two scenarios (mass minimization subject to lift and stress constraints at the two flight conditions)
6+
as_opt_remote_serial.py: runs the same optimization using one remote component that evaluates the MultipointParallel group in as_opt_parallel.py
7+
as_opt_remote_parallel.py: runs the same optimization using two parallel remote components, which each evaluates the Multipoint analysis in run.py
8+
9+
The optimizations should complete with the following metrics (with C_L being lift coefficient and func_struct being an aggregated von Mises stress).
10+
Note that objective and constraint names can vary slightly based on the optimization script.
11+
12+
Design Vars
13+
{'aoa': array([10.52590682, 18.2314054 ]),
14+
'dv_struct': array([0.0001 , 0.0001 , 0.0001 , 0.0001 , 0.0001 ,
15+
0.0001 , 0.0001 , 0.0001 , 0.0001 , 0.00010421,
16+
0.00010883, 0.00011221, 0.00011371, 0.00011452, 0.0001133 ,
17+
0.00010892, 0.00010359, 0.0001 , 0.0001 , 0.0001 ]),
18+
'geometry_morph_param': array([0.1])}
19+
20+
Nonlinear constraints
21+
{'multipoint.aerostructural1.C_L': array([0.15]),
22+
'multipoint.aerostructural1.func_struct': array([1.00000023]),
23+
'multipoint.aerostructural2.C_L': array([0.45]),
24+
'multipoint.aerostructural2.func_struct': array([1.00000051])}
25+
26+
Objectives
27+
{'multipoint.aerostructural1.mass': array([8.73298752e-05])}
28+
29+
Optimization terminated successfully (Exit mode 0)
30+
Current function value: 0.008732987524877025
31+
Iterations: 22
32+
Function evaluations: 24
33+
Gradient evaluations: 22
34+
35+
Note that the remote scripts, which both use mphys_server.py to launch the HPC job used for the analyses, are set up to use the K4 queue of NASA Langley's K cluster.
36+
To run this script on an HPC not supported by pbs4py, you will likely have to write your own pbs4py Launcher constructor.
37+
Further details on remote components may be found on the document page on remote components: https://openmdao.github.io/mphys/basics/remote_components.html

examples/aerostructural/supersonic_panel/aerodynamics_mphys.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def initialize(self):
1212
self.options.declare("x_aero0")
1313

1414
def setup(self):
15-
self.x_aero0_name = MPhysVariables.Aerodynamics.Surface.COORDINATES_INITIAL
15+
self.x_aero0_name = MPhysVariables.Aerodynamics.Surface.Mesh.COORDINATES
1616
self.add_output(
1717
self.x_aero0_name,
1818
val=self.options["x_aero0"],

examples/aerostructural/supersonic_panel/as_opt_parallel.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@
1111
from mphys import Multipoint, MultipointParallel
1212
from mphys.scenarios.aerostructural import ScenarioAeroStructural
1313

14-
check_totals = (
15-
False # True=check objective/constraint derivatives, False=run optimization
16-
)
14+
# True=check objective/constraint derivatives, False=run optimization
15+
check_totals = False
1716

1817
# panel geometry
1918
panel_chord = 0.3
@@ -23,6 +22,7 @@
2322
N_el_struct = 20
2423
N_el_aero = 7
2524

25+
2626
# Mphys parallel multipoint scenarios
2727
class AerostructParallel(MultipointParallel):
2828
def initialize(self):
@@ -224,7 +224,7 @@ def get_model(scenario_names):
224224
prob.cleanup()
225225

226226
if prob.model.comm.rank == 0: # write out data
227-
cr = om.CaseReader("optimization_history.sql")
227+
cr = om.CaseReader(f"{prob.get_outputs_dir()}/optimization_history.sql")
228228
driver_cases = cr.list_cases("driver")
229229

230230
case = cr.get_case(0)

examples/aerostructural/supersonic_panel/as_opt_remote_parallel.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
from mphys.network.zmq_pbs import RemoteZeroMQComp
66

7-
check_totals = (
8-
False # True=check objective/constraint derivatives, False=run optimization
9-
)
7+
# True=check objective/constraint derivatives, False=run optimization
8+
check_totals = False
9+
1010

1111
# for running scenarios on different servers in parallel
1212
class ParallelRemoteGroup(om.ParallelGroup):
@@ -58,9 +58,6 @@ def setup(self):
5858

5959
class TopLevelGroup(om.Group):
6060
def setup(self):
61-
if self.comm.size != 2:
62-
raise SystemError("Please launch with 2 processors")
63-
6461
# IVCs that feed into both parallel groups
6562
self.add_subsystem("ivc", om.IndepVarComp(), promotes=["*"])
6663

@@ -140,7 +137,9 @@ def setup(self):
140137

141138
# write out data
142139
if prob.model.comm.rank == 0:
143-
cr = om.CaseReader("optimization_history_parallel.sql")
140+
cr = om.CaseReader(
141+
f"{prob.get_outputs_dir()}/optimization_history_parallel.sql"
142+
)
144143
driver_cases = cr.list_cases("driver")
145144

146145
case = cr.get_case(0)
@@ -193,5 +192,6 @@ def setup(self):
193192
)
194193
f.write(" " + "\n")
195194

196-
# shutdown each rank's server
197-
eval(f"prob.model.multipoint.remote_scenario{prob.model.comm.rank}.stop_server()")
195+
# shutdown the servers
196+
prob.model.multipoint.remote_scenario0.stop_server()
197+
prob.model.multipoint.remote_scenario1.stop_server()

examples/aerostructural/supersonic_panel/as_opt_remote_serial.py

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33

44
from mphys.network.zmq_pbs import RemoteZeroMQComp
55

6-
check_totals = (
7-
False # True=check objective/constraint derivatives, False=run optimization
8-
)
6+
# True=check objective/constraint derivatives, False=run optimization
7+
check_totals = False
98

109
# initialize pbs4py
1110
pbs = PBS.k4(time=1)
@@ -60,59 +59,66 @@
6059
prob.cleanup()
6160

6261
# write out data
63-
cr = om.CaseReader("optimization_history.sql")
64-
driver_cases = cr.list_cases("driver")
65-
66-
case = cr.get_case(0)
67-
cons = case.get_constraints()
68-
dvs = case.get_design_vars()
69-
objs = case.get_objectives()
70-
71-
with open("optimization_history.dat", "w+") as f:
72-
73-
for i, k in enumerate(objs.keys()):
74-
f.write("objective: " + k + "\n")
75-
for j, case_id in enumerate(driver_cases):
76-
f.write(
77-
str(j)
78-
+ " "
79-
+ str(cr.get_case(case_id).get_objectives(scaled=False)[k][0])
80-
+ "\n"
81-
)
82-
f.write(" " + "\n")
83-
84-
for i, k in enumerate(cons.keys()):
85-
f.write("constraint: " + k + "\n")
86-
for j, case_id in enumerate(driver_cases):
87-
f.write(
88-
str(j)
89-
+ " "
90-
+ " ".join(
91-
map(str, cr.get_case(case_id).get_constraints(scaled=False)[k])
62+
if prob.model.comm.rank == 0:
63+
cr = om.CaseReader(f"{prob.get_outputs_dir()}/optimization_history.sql")
64+
driver_cases = cr.list_cases("driver")
65+
66+
case = cr.get_case(0)
67+
cons = case.get_constraints()
68+
dvs = case.get_design_vars()
69+
objs = case.get_objectives()
70+
71+
with open("optimization_history.dat", "w+") as f:
72+
73+
for i, k in enumerate(objs.keys()):
74+
f.write("objective: " + k + "\n")
75+
for j, case_id in enumerate(driver_cases):
76+
f.write(
77+
str(j)
78+
+ " "
79+
+ str(cr.get_case(case_id).get_objectives(scaled=False)[k][0])
80+
+ "\n"
9281
)
93-
+ "\n"
94-
)
95-
f.write(" " + "\n")
96-
97-
for i, k in enumerate(dvs.keys()):
98-
f.write("DV: " + k + "\n")
99-
for j, case_id in enumerate(driver_cases):
100-
f.write(
101-
str(j)
102-
+ " "
103-
+ " ".join(
104-
map(str, cr.get_case(case_id).get_design_vars(scaled=False)[k])
82+
f.write(" " + "\n")
83+
84+
for i, k in enumerate(cons.keys()):
85+
f.write("constraint: " + k + "\n")
86+
for j, case_id in enumerate(driver_cases):
87+
f.write(
88+
str(j)
89+
+ " "
90+
+ " ".join(
91+
map(
92+
str,
93+
cr.get_case(case_id).get_constraints(scaled=False)[k],
94+
)
95+
)
96+
+ "\n"
10597
)
106-
+ "\n"
107-
)
108-
f.write(" " + "\n")
98+
f.write(" " + "\n")
99+
100+
for i, k in enumerate(dvs.keys()):
101+
f.write("DV: " + k + "\n")
102+
for j, case_id in enumerate(driver_cases):
103+
f.write(
104+
str(j)
105+
+ " "
106+
+ " ".join(
107+
map(
108+
str,
109+
cr.get_case(case_id).get_design_vars(scaled=False)[k],
110+
)
111+
)
112+
+ "\n"
113+
)
114+
f.write(" " + "\n")
109115

110-
f.write("run times, function\n")
111-
for i in range(len(prob.model.remote.times_function)):
112-
f.write(f"{prob.model.remote.times_function[i]}\n")
113-
f.write(" " + "\n")
116+
f.write("run times, function\n")
117+
for i in range(len(prob.model.remote.times_function)):
118+
f.write(f"{prob.model.remote.times_function[i]}\n")
119+
f.write(" " + "\n")
114120

115-
f.write("run times, gradient\n")
116-
for i in range(len(prob.model.remote.times_gradient)):
117-
f.write(f"{prob.model.remote.times_gradient[i]}\n")
118-
f.write(" " + "\n")
121+
f.write("run times, gradient\n")
122+
for i in range(len(prob.model.remote.times_gradient)):
123+
f.write(f"{prob.model.remote.times_gradient[i]}\n")
124+
f.write(" " + "\n")

examples/aerostructural/supersonic_panel/geometry_morph.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import openmdao.api as om
33
from mpi4py import MPI
44

5-
from mphys import Builder
5+
from mphys import Builder, MPhysVariables
66

77

88
# EC which morphs the geometry
@@ -14,34 +14,54 @@ def initialize(self):
1414
def setup(self):
1515
self.add_input("geometry_morph_param")
1616

17+
self.x_names = {}
1718
for name, n_nodes in zip(self.options["names"], self.options["n_nodes"]):
18-
self.add_input(f"x_{name}_in", distributed=True, shape_by_conn=True)
19+
if name == "aero":
20+
self.x_names[name] = {
21+
"input": MPhysVariables.Aerodynamics.Surface.Geometry.COORDINATES_INPUT,
22+
"output": MPhysVariables.Aerodynamics.Surface.Geometry.COORDINATES_OUTPUT,
23+
}
24+
elif name == "struct":
25+
self.x_names[name] = {
26+
"input": MPhysVariables.Structures.Geometry.COORDINATES_INPUT,
27+
"output": MPhysVariables.Structures.Geometry.COORDINATES_OUTPUT,
28+
}
29+
self.add_input(
30+
self.x_names[name]["input"],
31+
distributed=True,
32+
shape_by_conn=True,
33+
tags=["mphys_coordinates"],
34+
)
1935
self.add_output(
20-
f"x_{name}0",
36+
self.x_names[name]["output"],
2137
shape=n_nodes * 3,
2238
distributed=True,
2339
tags=["mphys_coordinates"],
2440
)
2541

2642
def compute(self, inputs, outputs):
2743
for name in self.options["names"]:
28-
outputs[f"x_{name}0"] = (
29-
inputs["geometry_morph_param"] * inputs[f"x_{name}_in"]
44+
outputs[self.x_names[name]["output"]] = (
45+
inputs["geometry_morph_param"] * inputs[self.x_names[name]["input"]]
3046
)
3147

3248
def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode):
3349
if mode == "rev":
3450
for name in self.options["names"]:
35-
if f"x_{name}0" in d_outputs:
51+
if self.x_names[name]["output"] in d_outputs:
3652
if "geometry_morph_param" in d_inputs:
3753
d_inputs["geometry_morph_param"] += self.comm.allreduce(
38-
np.sum(d_outputs[f"x_{name}0"] * inputs[f"x_{name}_in"]),
54+
np.sum(
55+
d_outputs[self.x_names[name]["output"]]
56+
* inputs[self.x_names[name]["input"]]
57+
),
3958
op=MPI.SUM,
4059
)
4160

42-
if f"x_{name}_in" in d_inputs:
43-
d_inputs[f"x_{name}_in"] += (
44-
d_outputs[f"x_{name}0"] * inputs["geometry_morph_param"]
61+
if self.x_names[name]["input"] in d_inputs:
62+
d_inputs[self.x_names[name]["input"]] += (
63+
d_outputs[self.x_names[name]["output"]]
64+
* inputs["geometry_morph_param"]
4565
)
4666

4767

examples/aerostructural/supersonic_panel/run.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from structures_mphys import StructBuilder
99
from xfer_mphys import XferBuilder
1010

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

1414
comm = MPI.COMM_WORLD
@@ -22,6 +22,7 @@
2222
N_el_struct = 20
2323
N_el_aero = 7
2424

25+
2526
# Mphys
2627
class Model(Multipoint):
2728
def initialize(self):
@@ -82,9 +83,6 @@ def setup(self):
8283
"geometry", geometry_builder.get_mesh_coordinate_subsystem(), promotes=["*"]
8384
)
8485

85-
self.connect("struct_mesh.x_struct0", "x_struct_in")
86-
self.connect("aero_mesh.x_aero0", "x_aero_in")
87-
8886
# create the run directory
8987
if self.comm.rank == 0:
9088
if not os.path.isdir(self.scenario_name):
@@ -118,11 +116,27 @@ def setup(self):
118116
"qdyn",
119117
"aoa",
120118
"dv_struct",
121-
"x_struct0",
122-
"x_aero0",
123119
]:
124120
self.connect(var, self.scenario_name + "." + var)
125121

122+
self.connect(
123+
f"aero_mesh.{MPhysVariables.Aerodynamics.Surface.Mesh.COORDINATES}",
124+
MPhysVariables.Aerodynamics.Surface.Geometry.COORDINATES_INPUT,
125+
)
126+
self.connect(
127+
MPhysVariables.Aerodynamics.Surface.Geometry.COORDINATES_OUTPUT,
128+
f"{self.scenario_name}.{MPhysVariables.Aerodynamics.Surface.COORDINATES_INITIAL}",
129+
)
130+
131+
self.connect(
132+
f"struct_mesh.{MPhysVariables.Structures.Mesh.COORDINATES}",
133+
MPhysVariables.Structures.Geometry.COORDINATES_INPUT,
134+
)
135+
self.connect(
136+
MPhysVariables.Structures.Geometry.COORDINATES_OUTPUT,
137+
f"{self.scenario_name}.{MPhysVariables.Structures.COORDINATES}",
138+
)
139+
126140
# add design variables, to simplify remote setup
127141
self.add_design_var("geometry_morph_param", lower=0.1, upper=10.0)
128142
self.add_design_var("dv_struct", lower=1.0e-4, upper=1.0e-2, ref=1.0e-3)

examples/aerostructural/supersonic_panel/run_parallel.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
N_el_struct = 20
2121
N_el_aero = 7
2222

23+
2324
# Mphys parallel multipoint scenarios
2425
class AerostructParallel(MultipointParallel):
2526
# class AerostructParallel(Multipoint):

0 commit comments

Comments
 (0)