Skip to content

Commit

Permalink
Merge pull request #913 from swryan/work
Browse files Browse the repository at this point in the history
Problem recorder should record all outputs by default
  • Loading branch information
swryan committed Apr 18, 2019
2 parents ae107f5 + 3d4c6ef commit 156289a
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 26 deletions.
35 changes: 17 additions & 18 deletions openmdao/core/driver.py
Expand Up @@ -377,29 +377,28 @@ def _get_vars_to_record(self, recording_options):

filtered_vars_to_record['in'] = list(myinputs)

# system outputs (if the options being processed are for the driver itself)
if recording_options is self.recording_options:
myoutputs = set()
# system outputs
myoutputs = set()

if incl:
myoutputs = {n for n in model._outputs
if n in abs2prom and check_path(abs2prom[n], incl, excl)}
if incl:
myoutputs = {n for n in model._outputs
if n in abs2prom and check_path(abs2prom[n], incl, excl)}

if MPI:
# gather the variables from all ranks to rank 0
all_vars = model.comm.gather(myoutputs, root=0)
if MPI.COMM_WORLD.rank == 0:
myoutputs = all_vars[-1]
for d in all_vars[:-1]:
myoutputs.update(d)
if MPI:
# gather the variables from all ranks to rank 0
all_vars = model.comm.gather(myoutputs, root=0)
if MPI.COMM_WORLD.rank == 0:
myoutputs = all_vars[-1]
for d in all_vars[:-1]:
myoutputs.update(d)

# de-duplicate
myoutputs = myoutputs.difference(all_desvars, all_objectives, all_constraints)
# de-duplicate
myoutputs = myoutputs.difference(all_desvars, all_objectives, all_constraints)

if MPI:
myoutputs = [n for n in myoutputs if rrank == rowned[n]]
if MPI:
myoutputs = [n for n in myoutputs if rrank == rowned[n]]

filtered_vars_to_record['sys'] = list(myoutputs)
filtered_vars_to_record['sys'] = list(myoutputs)

return filtered_vars_to_record

Expand Down
12 changes: 9 additions & 3 deletions openmdao/core/problem.py
Expand Up @@ -656,16 +656,22 @@ def record_iteration(self, case_name):
obj_vars = {name: obj_vars[name] for name in filt['obj']}
con_vars = {name: con_vars[name] for name in filt['con']}

names = model._outputs._names
views = model._outputs._views
sys_vars = {name: views[name] for name in names if name in filt['sys']}

if MPI:
des_vars = model._gather_vars(model, des_vars)
obj_vars = model._gather_vars(model, obj_vars)
con_vars = model._gather_vars(model, con_vars)
des_vars = driver._gather_vars(model, des_vars)
obj_vars = driver._gather_vars(model, obj_vars)
con_vars = driver._gather_vars(model, con_vars)
sys_vars = driver._gather_vars(model, sys_vars)

outs = {}
if not MPI or model.comm.rank == 0:
outs.update(des_vars)
outs.update(obj_vars)
outs.update(con_vars)
outs.update(sys_vars)

data = {
'out': outs,
Expand Down
48 changes: 48 additions & 0 deletions openmdao/recorders/tests/sqlite_recorder_test_utils.py
Expand Up @@ -54,6 +54,54 @@ def get_format_version_abs2meta(db_cur):

return f_version, abs2meta

def assertProblemDataRecorded(test, expected, tolerance):
"""
Expected can be from multiple cases.
"""
with database_cursor(test.filename) as db_cur:
f_version, abs2meta = get_format_version_abs2meta(db_cur)

# iterate through the cases
for case, (t0, t1), outputs_expected in expected:
# from the database, get the actual data recorded
db_cur.execute("SELECT * FROM problem_cases WHERE case_name=:case_name",
{"case_name": case})
row_actual = db_cur.fetchone()

test.assertTrue(row_actual, 'Problem table does not contain the requested '
'case name: "{}"'.format(case))

counter, global_counter, case_name, timestamp, success, msg, outputs_text = row_actual

if f_version >= 3:
outputs_actual = json_to_np_array(outputs_text, abs2meta)
elif f_version in (1, 2):
outputs_actual = blob_to_array(outputs_text)

test.assertEqual(success, 1)
test.assertEqual(msg, '')

for vartype, actual, expected in (
('outputs', outputs_actual, outputs_expected),
):

if expected is None:
if f_version >= 3:
test.assertIsNone(actual)
if f_version in (1, 2):
test.assertEqual(actual, np.array(None, dtype=object))
else:
actual = actual[0]
# Check to see if the number of values in actual and expected match
test.assertEqual(len(actual), len(expected))
for key, value in iteritems(expected):
# Check to see if the keys in the actual and expected match
test.assertTrue(key in actual.dtype.names,
'{} variable not found in actual data'
' from recorder'.format(key))
# Check to see if the values in actual and expected match
assert_rel_error(test, actual[key], expected[key], tolerance)


def assertDriverIterDataRecorded(test, expected, tolerance, prefix=None):
"""
Expand Down
18 changes: 14 additions & 4 deletions openmdao/recorders/tests/test_distrib_sqlite_recorder.py
@@ -1,6 +1,7 @@
import errno
import os
import unittest
from time import time
from shutil import rmtree
from tempfile import mkdtemp

Expand All @@ -12,7 +13,8 @@
from openmdao.api import ExecComp, ExplicitComponent, Problem, \
Group, ParallelGroup, IndepVarComp, SqliteRecorder, ScipyOptimizeDriver
from openmdao.utils.array_utils import evenly_distrib_idxs
from openmdao.recorders.tests.sqlite_recorder_test_utils import assertDriverIterDataRecorded
from openmdao.recorders.tests.sqlite_recorder_test_utils import \
assertDriverIterDataRecorded, assertProblemDataRecorded
from openmdao.recorders.tests.recorder_test_utils import run_driver

if MPI:
Expand Down Expand Up @@ -204,17 +206,22 @@ def test_recording_remote_voi(self):

# Create problem and run driver
prob = Problem(model, driver)
prob.add_recorder(self.recorder)
prob.setup()

t0, t1 = run_driver(prob)
prob.record_iteration('final')
t2 = time()

prob.cleanup()

# Since the test will compare the last case recorded, just check the
# current values in the problem. This next section is about getting those values

# These involve collective gathers so all ranks need to run this
expected_outputs = prob.driver.get_design_var_values()
expected_outputs.update(prob.driver.get_objective_values())
expected_outputs.update(prob.driver.get_constraint_values())
expected_outputs = driver.get_design_var_values()
expected_outputs.update(driver.get_objective_values())
expected_outputs.update(driver.get_constraint_values())

# includes for outputs are specified as promoted names but we need absolute names
prom2abs = model._var_allprocs_prom2abs_list['output']
Expand Down Expand Up @@ -253,6 +260,9 @@ def test_recording_remote_voi(self):
expected_data = ((coordinate, (t0, t1), expected_outputs, None),)
assertDriverIterDataRecorded(self, expected_data, self.eps)

expected_data = (('final', (t1, t2), expected_outputs),)
assertProblemDataRecorded(self, expected_data, self.eps)


if __name__ == "__main__":
from openmdao.utils.mpi import mpirun_tests
Expand Down
75 changes: 74 additions & 1 deletion openmdao/recorders/tests/test_sqlite_recorder.py
Expand Up @@ -1577,6 +1577,37 @@ def assert_closed(self, recorder):
self.assertFalse(system._rec_mgr.has_recorders())
self.assertFalse(solver._rec_mgr.has_recorders())

def test_problem_record_no_voi(self):
prob = Problem(model=SellarDerivatives())

prob.add_recorder(SqliteRecorder("cases.sql"))

prob.setup()
prob.run_driver()

prob.record_iteration('final')
prob.cleanup()

cr = CaseReader("cases.sql")

problem_cases = cr.list_cases('problem')
self.assertEqual(len(problem_cases), 1)

final_case = cr.get_case('final')

# we didn't declare any VOIs
desvars = final_case.get_design_vars()
objectives = final_case.get_objectives()
constraints = final_case.get_constraints()

self.assertEqual(len(desvars), 0)
self.assertEqual(len(objectives), 0)
self.assertEqual(len(constraints), 0)

# by default we should get all outputs
self.assertEqual(set(final_case.outputs.keys()),
{'con1', 'con2', 'obj', 'x', 'y1', 'y2', 'z'})

def test_problem_record_with_options(self):
prob = Problem(model=SellarDerivatives())

Expand All @@ -1590,7 +1621,6 @@ def test_problem_record_with_options(self):

prob.add_recorder(SqliteRecorder("cases.sql"))

prob.recording_options['includes'] = []
prob.recording_options['record_objectives'] = False
prob.recording_options['record_constraints'] = False
prob.recording_options['record_desvars'] = False
Expand All @@ -1616,6 +1646,49 @@ def test_problem_record_with_options(self):
self.assertEqual(len(objectives), 0)
self.assertEqual(len(constraints), 0)

# includes all outputs (default) minus the VOIs, which we have excluded
self.assertEqual(set(final_case.outputs.keys()), {'y1', 'y2'})

def test_problem_record_options_includes(self):
prob = Problem(model=SellarDerivatives())

model = prob.model
model.add_design_var('z', lower=np.array([-10.0, 0.0]),
upper=np.array([10.0, 10.0]))
model.add_design_var('x', lower=0.0, upper=10.0)
model.add_objective('obj')
model.add_constraint('con1', upper=0.0)
model.add_constraint('con2', upper=0.0)

prob.add_recorder(SqliteRecorder("cases.sql"))

prob.recording_options['includes'] = []

prob.setup()
prob.run_driver()

prob.record_iteration('final')
prob.cleanup()

cr = CaseReader("cases.sql")

problem_cases = cr.list_cases('problem')
self.assertEqual(len(problem_cases), 1)

final_case = cr.get_case('final')

desvars = final_case.get_design_vars()
objectives = final_case.get_objectives()
constraints = final_case.get_constraints()

self.assertEqual(len(desvars), 2)
self.assertEqual(len(objectives), 1)
self.assertEqual(len(constraints), 2)

# includes no outputs except the the VOIs that are recorded by default
self.assertEqual(set(final_case.outputs.keys()),
{'con1', 'con2', 'obj', 'x', 'z'})

def test_simple_paraboloid_scaled_desvars(self):
prob = Problem()
model = prob.model
Expand Down

0 comments on commit 156289a

Please sign in to comment.