From 1ddf706c938cf5a945eb12fe4e67def4932945fb Mon Sep 17 00:00:00 2001 From: Danny Kilkenny Date: Tue, 11 Aug 2020 11:14:31 -0400 Subject: [PATCH 01/10] added test --- .../recorders/tests/test_sqlite_recorder.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/openmdao/recorders/tests/test_sqlite_recorder.py b/openmdao/recorders/tests/test_sqlite_recorder.py index 6edca95dd6..28cb54f40c 100644 --- a/openmdao/recorders/tests/test_sqlite_recorder.py +++ b/openmdao/recorders/tests/test_sqlite_recorder.py @@ -289,6 +289,42 @@ def test_simple_driver_recording_pyoptsparse(self): expected_data = ((coordinate, (t0, t1), expected_derivs),) assertDriverDerivDataRecorded(self, expected_data, self.eps) + def test_double_run_driver_option_overwrite(self): + prob = ParaboloidProblem() + + driver = prob.driver = om.ScipyOptimizeDriver(disp=False, tol=1e-9) + driver.recording_options['record_desvars'] = True + driver.recording_options['record_objectives'] = True + driver.recording_options['record_constraints'] = True + driver.recording_options['record_derivatives'] = True + driver.recording_options['includes'] = ['*'] + driver.add_recorder(self.recorder) + + prob.setup() + prob.set_solver_print(0) + prob.run_driver() + + cr = om.CaseReader(self.filename) + + driver_cases = cr.list_cases('driver') + driver_case = cr.get_case(driver_cases[0]) + objectives = driver_case.get_objectives() + constraints = driver_case.get_constraints() + + driver.recording_options['record_constraints'] = False + prob.setup() + prob.run_driver() + prob.cleanup() + + cr = om.CaseReader(self.filename) + + driver_cases = cr.list_cases('driver') + driver_case = cr.get_case(driver_cases[0]) + objectives = driver_case.get_objectives() + constraints = driver_case.get_constraints() + print(objectives) + print(constraints) + def test_simple_driver_recording_with_prefix(self): prob = ParaboloidProblem() From ed83841235d40d03fd3d6816dacb685443671df5 Mon Sep 17 00:00:00 2001 From: Danny Kilkenny Date: Tue, 11 Aug 2020 12:33:46 -0400 Subject: [PATCH 02/10] Fixed test to better capture issue --- openmdao/recorders/tests/test_sqlite_recorder.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/openmdao/recorders/tests/test_sqlite_recorder.py b/openmdao/recorders/tests/test_sqlite_recorder.py index 28cb54f40c..a5ee99b294 100644 --- a/openmdao/recorders/tests/test_sqlite_recorder.py +++ b/openmdao/recorders/tests/test_sqlite_recorder.py @@ -306,24 +306,16 @@ def test_double_run_driver_option_overwrite(self): cr = om.CaseReader(self.filename) - driver_cases = cr.list_cases('driver') - driver_case = cr.get_case(driver_cases[0]) - objectives = driver_case.get_objectives() - constraints = driver_case.get_constraints() + self.assertTrue(cr.system_options['root']['component_options']['assembled_jac_type'], 'csc') - driver.recording_options['record_constraints'] = False + # New option and re run of run_driver + prob.model.options['assembled_jac_type'] = 'dense' prob.setup() prob.run_driver() - prob.cleanup() cr = om.CaseReader(self.filename) + self.assertTrue(cr.system_options['root']['component_options']['assembled_jac_type'], 'dense') - driver_cases = cr.list_cases('driver') - driver_case = cr.get_case(driver_cases[0]) - objectives = driver_case.get_objectives() - constraints = driver_case.get_constraints() - print(objectives) - print(constraints) def test_simple_driver_recording_with_prefix(self): prob = ParaboloidProblem() From abc52c6516b34d12be77ff34d0cce25e1c4467b1 Mon Sep 17 00:00:00 2001 From: Danny Kilkenny Date: Thu, 13 Aug 2020 14:52:59 -0400 Subject: [PATCH 03/10] Added list_model_metadata to display the model's options --- openmdao/core/problem.py | 9 ++++++ openmdao/recorders/recording_manager.py | 2 +- openmdao/recorders/sqlite_reader.py | 29 +++++++++++++++++-- openmdao/recorders/sqlite_recorder.py | 13 +++++---- .../recorders/tests/test_sqlite_recorder.py | 10 +++++-- 5 files changed, 51 insertions(+), 12 deletions(-) diff --git a/openmdao/core/problem.py b/openmdao/core/problem.py index b7c906f08f..37d53d76d8 100644 --- a/openmdao/core/problem.py +++ b/openmdao/core/problem.py @@ -640,6 +640,10 @@ def run_driver(self, case_prefix=None, reset_iter_counts=True): self.driver.iter_count = 0 self.model._reset_iter_counts() + self._run_counter = 0 + if self._setup_already_called: + self._run_counter += 1 + self.final_setup() self.model._clear_iprint() return self.driver.run() @@ -877,6 +881,11 @@ def setup(self, check=False, logger=None, mode='auto', force_alloc_complex=False self._check = check self._logger = logger + if self._setup_status == 2: + self._setup_already_called = True + else: + self._setup_already_called = False + self._setup_status = 1 return self diff --git a/openmdao/recorders/recording_manager.py b/openmdao/recorders/recording_manager.py index 42eea34705..04362d89f3 100644 --- a/openmdao/recorders/recording_manager.py +++ b/openmdao/recorders/recording_manager.py @@ -270,4 +270,4 @@ def record_system_options(problem): for recorder in recorders: for sub in problem.model.system_iter(recurse=True, include_self=True): - recorder.record_metadata_system(sub) + recorder.record_metadata_system(sub, problem._run_counter) diff --git a/openmdao/recorders/sqlite_reader.py b/openmdao/recorders/sqlite_reader.py index cce90a4cd9..3ba7a06f5d 100644 --- a/openmdao/recorders/sqlite_reader.py +++ b/openmdao/recorders/sqlite_reader.py @@ -260,13 +260,14 @@ def _collect_system_metadata(self, cur): cur : sqlite3.Cursor Database cursor to use for reading the data. """ - cur.execute("SELECT id, scaling_factors, component_metadata FROM system_metadata") + cur.execute("SELECT id, run_num, scaling_factors, component_metadata FROM system_metadata") for row in cur: id = row[0] self.system_options[id] = {} - self.system_options[id]['scaling_factors'] = pickle.loads(row[1]) - self.system_options[id]['component_options'] = pickle.loads(row[2]) + self.system_options[id]['run_num'] = row[1] + self.system_options[id]['scaling_factors'] = pickle.loads(row[2]) + self.system_options[id]['component_options'] = pickle.loads(row[3]) def _collect_solver_metadata(self, cur): """ @@ -410,6 +411,28 @@ def list_source_vars(self, source, out_stream=_DEFAULT_OUT_STREAM): return dct + def list_model_metadata(self, run_number=None, out_stream=_DEFAULT_OUT_STREAM): + + if out_stream: + if out_stream is _DEFAULT_OUT_STREAM: + out_stream = sys.stdout + + for i in self.system_options: + subsys, num = i.rsplit('_', 1) + + # subs + + if (run_number is not None and run_number == int(num) and subsys == 'root') or \ + (subsys == 'root' and run_number is None): + out_stream.write( + 'Run Number: {}\n Subsystem: {}'.format( + self.system_options[i]['run_num'], subsys)) + + for j in self.system_options[i]['component_options']: + option = "{0} : {1}".format( + j, self.system_options[i]['component_options'][j]) + out_stream.write('\n {}\n'.format(option)) + def list_cases(self, source=None, recurse=True, flat=True, out_stream=_DEFAULT_OUT_STREAM): """ Iterate over Driver, Solver and System cases in order. diff --git a/openmdao/recorders/sqlite_recorder.py b/openmdao/recorders/sqlite_recorder.py index 0482eb98b6..52c62488b6 100644 --- a/openmdao/recorders/sqlite_recorder.py +++ b/openmdao/recorders/sqlite_recorder.py @@ -228,7 +228,7 @@ def _initialize_database(self): c.execute("CREATE TABLE driver_metadata(id TEXT PRIMARY KEY, " "model_viewer_data TEXT)") c.execute("CREATE TABLE system_metadata(id TEXT PRIMARY KEY, " - "scaling_factors BLOB, component_metadata BLOB)") + "run_num INT, scaling_factors BLOB, component_metadata BLOB)") c.execute("CREATE TABLE solver_metadata(id TEXT PRIMARY KEY, " "solver_options BLOB, solver_class TEXT)") @@ -622,7 +622,7 @@ def record_viewer_data(self, model_viewer_data, key='Driver'): except sqlite3.IntegrityError: print("Model viewer data has already has already been recorded for %s." % key) - def record_metadata_system(self, recording_requester): + def record_metadata_system(self, recording_requester, run_counter): """ Record system metadata. @@ -630,6 +630,8 @@ def record_metadata_system(self, recording_requester): ---------- recording_requester : System The System that would like to record its metadata. + run_counter : int + The number of times run_driver has been called. """ if self.connection: scaling_vecs, user_options = self._get_metadata_system(recording_requester) @@ -664,9 +666,10 @@ def record_metadata_system(self, recording_requester): # SQL errors for "UNIQUE constraint failed: system_metadata.id" # Future versions of OpenMDAO will handle this better. with self.connection as c: - c.execute("INSERT OR IGNORE INTO system_metadata" - "(id, scaling_factors, component_metadata) " - "VALUES(?,?,?)", (path, scaling_factors, pickled_metadata)) + c.execute("INSERT INTO system_metadata" + "(id, run_num, scaling_factors, component_metadata) " + "VALUES(?,?,?,?)", (path + '_' + str(run_counter), + run_counter, scaling_factors, pickled_metadata)) def record_metadata_solver(self, recording_requester): """ diff --git a/openmdao/recorders/tests/test_sqlite_recorder.py b/openmdao/recorders/tests/test_sqlite_recorder.py index a5ee99b294..ddb318b43c 100644 --- a/openmdao/recorders/tests/test_sqlite_recorder.py +++ b/openmdao/recorders/tests/test_sqlite_recorder.py @@ -306,16 +306,20 @@ def test_double_run_driver_option_overwrite(self): cr = om.CaseReader(self.filename) - self.assertTrue(cr.system_options['root']['component_options']['assembled_jac_type'], 'csc') + self.assertTrue(cr.system_options['root_0']['component_options']['assembled_jac_type'], 'csc') - # New option and re run of run_driver + # New option and re-run of run_driver prob.model.options['assembled_jac_type'] = 'dense' prob.setup() prob.run_driver() cr = om.CaseReader(self.filename) - self.assertTrue(cr.system_options['root']['component_options']['assembled_jac_type'], 'dense') + self.assertTrue(cr.system_options['root_1']['component_options']['assembled_jac_type'], 'dense') + # cr.list_metadata() + cr.list_model_metadata(run_number=1) + print('None') + cr.list_model_metadata() def test_simple_driver_recording_with_prefix(self): prob = ParaboloidProblem() From c75061edd9099f9745986a537b814ff33304f553 Mon Sep 17 00:00:00 2001 From: Danny Kilkenny Date: Tue, 18 Aug 2020 15:57:40 -0400 Subject: [PATCH 04/10] privatization of subsystem options --- openmdao/recorders/base_case_reader.py | 8 +- openmdao/recorders/recording_manager.py | 5 +- openmdao/recorders/sqlite_reader.py | 18 ++--- openmdao/recorders/sqlite_recorder.py | 15 ++-- .../recorders/tests/test_sqlite_reader.py | 10 +-- .../recorders/tests/test_sqlite_recorder.py | 73 ++++++++++--------- 6 files changed, 67 insertions(+), 62 deletions(-) diff --git a/openmdao/recorders/base_case_reader.py b/openmdao/recorders/base_case_reader.py index 64b608c9b4..1db2defd1d 100644 --- a/openmdao/recorders/base_case_reader.py +++ b/openmdao/recorders/base_case_reader.py @@ -17,7 +17,7 @@ class BaseCaseReader(object): Metadata about the problem, including the system hierachy and connections. solver_metadata : dict The solver options for each solver in the recorded model. - system_options : dict + _system_options : dict Metadata about each system in the recorded model, including options and scaling factors. """ @@ -35,7 +35,7 @@ def __init__(self, filename, pre_load=False): self._format_version = None self.problem_metadata = {} self.solver_metadata = {} - self.system_options = {} + self._system_options = {} @property def system_metadata(self): @@ -45,11 +45,11 @@ def system_metadata(self): Returns ------- dict - reference to the 'system_options' attribute. + reference to the '_system_options' attribute. """ warn_deprecation("The BaseCaseReader.system_metadata attribute is deprecated. " "Use the BaseCaseReader.system_option attribute instead.") - return self.system_options + return self._system_options def get_cases(self, source, recurse=True, flat=False): """ diff --git a/openmdao/recorders/recording_manager.py b/openmdao/recorders/recording_manager.py index 04362d89f3..b58a01ddb0 100644 --- a/openmdao/recorders/recording_manager.py +++ b/openmdao/recorders/recording_manager.py @@ -270,4 +270,7 @@ def record_system_options(problem): for recorder in recorders: for sub in problem.model.system_iter(recurse=True, include_self=True): - recorder.record_metadata_system(sub, problem._run_counter) + if hasattr(problem, "_run_counter"): + recorder.record_metadata_system(sub, problem._run_counter) + else: + recorder.record_metadata_system(sub) diff --git a/openmdao/recorders/sqlite_reader.py b/openmdao/recorders/sqlite_reader.py index 3ba7a06f5d..2136a17548 100644 --- a/openmdao/recorders/sqlite_reader.py +++ b/openmdao/recorders/sqlite_reader.py @@ -260,14 +260,13 @@ def _collect_system_metadata(self, cur): cur : sqlite3.Cursor Database cursor to use for reading the data. """ - cur.execute("SELECT id, run_num, scaling_factors, component_metadata FROM system_metadata") + cur.execute("SELECT id, scaling_factors, component_metadata FROM system_metadata") for row in cur: id = row[0] - self.system_options[id] = {} + self._system_options[id] = {} - self.system_options[id]['run_num'] = row[1] - self.system_options[id]['scaling_factors'] = pickle.loads(row[2]) - self.system_options[id]['component_options'] = pickle.loads(row[3]) + self._system_options[id]['scaling_factors'] = pickle.loads(row[1]) + self._system_options[id]['component_options'] = pickle.loads(row[2]) def _collect_solver_metadata(self, cur): """ @@ -417,7 +416,7 @@ def list_model_metadata(self, run_number=None, out_stream=_DEFAULT_OUT_STREAM): if out_stream is _DEFAULT_OUT_STREAM: out_stream = sys.stdout - for i in self.system_options: + for i in self._system_options: subsys, num = i.rsplit('_', 1) # subs @@ -425,12 +424,11 @@ def list_model_metadata(self, run_number=None, out_stream=_DEFAULT_OUT_STREAM): if (run_number is not None and run_number == int(num) and subsys == 'root') or \ (subsys == 'root' and run_number is None): out_stream.write( - 'Run Number: {}\n Subsystem: {}'.format( - self.system_options[i]['run_num'], subsys)) + 'Run Number: {}\n Subsystem: {}'.format(num, subsys)) - for j in self.system_options[i]['component_options']: + for j in self._system_options[i]['component_options']: option = "{0} : {1}".format( - j, self.system_options[i]['component_options'][j]) + j, self._system_options[i]['component_options'][j]) out_stream.write('\n {}\n'.format(option)) def list_cases(self, source=None, recurse=True, flat=True, out_stream=_DEFAULT_OUT_STREAM): diff --git a/openmdao/recorders/sqlite_recorder.py b/openmdao/recorders/sqlite_recorder.py index 52c62488b6..8af0c26aa8 100644 --- a/openmdao/recorders/sqlite_recorder.py +++ b/openmdao/recorders/sqlite_recorder.py @@ -228,7 +228,7 @@ def _initialize_database(self): c.execute("CREATE TABLE driver_metadata(id TEXT PRIMARY KEY, " "model_viewer_data TEXT)") c.execute("CREATE TABLE system_metadata(id TEXT PRIMARY KEY, " - "run_num INT, scaling_factors BLOB, component_metadata BLOB)") + "scaling_factors BLOB, component_metadata BLOB)") c.execute("CREATE TABLE solver_metadata(id TEXT PRIMARY KEY, " "solver_options BLOB, solver_class TEXT)") @@ -622,7 +622,7 @@ def record_viewer_data(self, model_viewer_data, key='Driver'): except sqlite3.IntegrityError: print("Model viewer data has already has already been recorded for %s." % key) - def record_metadata_system(self, recording_requester, run_counter): + def record_metadata_system(self, recording_requester, run_counter=None): """ Record system metadata. @@ -634,6 +634,9 @@ def record_metadata_system(self, recording_requester, run_counter): The number of times run_driver has been called. """ if self.connection: + if run_counter is None: + run_counter = self._counter + scaling_vecs, user_options = self._get_metadata_system(recording_requester) if scaling_vecs is None: @@ -666,10 +669,10 @@ def record_metadata_system(self, recording_requester, run_counter): # SQL errors for "UNIQUE constraint failed: system_metadata.id" # Future versions of OpenMDAO will handle this better. with self.connection as c: - c.execute("INSERT INTO system_metadata" - "(id, run_num, scaling_factors, component_metadata) " - "VALUES(?,?,?,?)", (path + '_' + str(run_counter), - run_counter, scaling_factors, pickled_metadata)) + c.execute("INSERT OR IGNORE INTO system_metadata" + "(id, scaling_factors, component_metadata) " + "VALUES(?,?,?)", (path + '_' + str(run_counter), scaling_factors, + pickled_metadata)) def record_metadata_solver(self, recording_requester): """ diff --git a/openmdao/recorders/tests/test_sqlite_reader.py b/openmdao/recorders/tests/test_sqlite_reader.py index 5d29c0c1ba..7239e8f119 100644 --- a/openmdao/recorders/tests/test_sqlite_reader.py +++ b/openmdao/recorders/tests/test_sqlite_reader.py @@ -2009,7 +2009,7 @@ def test_system_options_pickle_fail(self): prob.cleanup() cr = om.CaseReader(self.filename) - subs_options = cr.system_options['subs']['component_options'] + subs_options = cr._system_options['subs_0']['component_options'] # no options should have been recorded for d1 self.assertEqual(len(subs_options._dict), 0) @@ -2045,8 +2045,8 @@ def test_pre_load(self): self.assertEqual(cr._format_version, format_version) - self.assertEqual(set(cr.system_options.keys()), - set(['root'] + [sys.name for sys in prob.model._subsystems_allprocs])) + self.assertEqual(set(cr._system_options.keys()), + set(['root_0'] + [sys.name + '_0' for sys in prob.model._subsystems_allprocs])) self.assertEqual(set(cr.problem_metadata.keys()), { 'tree', 'sys_pathnames_list', 'connections_list', 'variables', 'abs2prom', @@ -2073,8 +2073,8 @@ def test_pre_load(self): self.assertEqual(cr._format_version, format_version) - self.assertEqual(set(cr.system_options.keys()), - set(['root'] + [sys.name for sys in prob.model._subsystems_allprocs])) + self.assertEqual(set(cr._system_options.keys()), + set(['root_0'] + [sys.name + '_0' for sys in prob.model._subsystems_allprocs])) self.assertEqual(set(cr.problem_metadata.keys()), { 'tree', 'sys_pathnames_list', 'connections_list', 'variables', 'abs2prom', diff --git a/openmdao/recorders/tests/test_sqlite_recorder.py b/openmdao/recorders/tests/test_sqlite_recorder.py index ddb318b43c..aab8288e83 100644 --- a/openmdao/recorders/tests/test_sqlite_recorder.py +++ b/openmdao/recorders/tests/test_sqlite_recorder.py @@ -306,7 +306,7 @@ def test_double_run_driver_option_overwrite(self): cr = om.CaseReader(self.filename) - self.assertTrue(cr.system_options['root_0']['component_options']['assembled_jac_type'], 'csc') + self.assertTrue(cr._system_options['root_0']['component_options']['assembled_jac_type'], 'csc') # New option and re-run of run_driver prob.model.options['assembled_jac_type'] = 'dense' @@ -314,7 +314,7 @@ def test_double_run_driver_option_overwrite(self): prob.run_driver() cr = om.CaseReader(self.filename) - self.assertTrue(cr.system_options['root_1']['component_options']['assembled_jac_type'], 'dense') + self.assertTrue(cr._system_options['root_1']['component_options']['assembled_jac_type'], 'dense') # cr.list_metadata() cr.list_model_metadata(run_number=1) @@ -489,18 +489,18 @@ def test_system_record_model_metadata(self): cr = om.CaseReader("cases.sql") # Quick check to see that keys and values were recorded - for key in ['root', '_auto_ivc', 'd1', 'd2', 'obj_cmp', 'con_cmp1', 'con_cmp2']: - self.assertTrue(key in cr.system_options.keys()) + for key in ['root_0', '_auto_ivc_0', 'd1_0', 'd2_0', 'obj_cmp_0', 'con_cmp1_0', 'con_cmp2_0']: + self.assertTrue(key in cr._system_options.keys()) - value = cr.system_options['root']['component_options']['assembled_jac_type'] + value = cr._system_options['root_0']['component_options']['assembled_jac_type'] self.assertEqual(value, 'csc') # quick check only. Too much to check exhaustively def test_record_system_options(self): # Regardless what object the case recorder is attached to, system options # should be recorded for all systems in the model - expected_system_options_keys = ['root', '_auto_ivc', 'd1', 'd2', 'obj_cmp', 'con_cmp1', - 'con_cmp2'] + expected_system_options_keys = ['root_0', '_auto_ivc_0', 'd1_0', 'd2_0', 'obj_cmp_0', 'con_cmp1_0', + 'con_cmp2_0'] # Recorder on Driver prob = om.Problem(model=SellarDerivatives()) @@ -513,8 +513,8 @@ def test_record_system_options(self): cr = om.CaseReader("cases_driver.sql") # Quick check to see that keys and values were recorded for key in expected_system_options_keys: - self.assertTrue(key in cr.system_options.keys()) - value = cr.system_options['root']['component_options']['assembled_jac_type'] + self.assertTrue(key in cr._system_options.keys()) + value = cr._system_options['root_0']['component_options']['assembled_jac_type'] self.assertEqual('csc', value) # quick check only. Too much to check exhaustively # Recorder on Problem @@ -528,8 +528,8 @@ def test_record_system_options(self): cr = om.CaseReader("cases_problem.sql") # Quick check to see that keys and values were recorded for key in expected_system_options_keys: - self.assertTrue(key in cr.system_options.keys()) - value = cr.system_options['root']['component_options']['assembled_jac_type'] + self.assertTrue(key in cr._system_options.keys()) + value = cr._system_options['root_0']['component_options']['assembled_jac_type'] self.assertEqual(value, 'csc') # quick check only. Too much to check exhaustively # Recorder on a subsystem @@ -543,8 +543,8 @@ def test_record_system_options(self): cr = om.CaseReader("cases_subsystem.sql") # Quick check to see that keys and values were recorded for key in expected_system_options_keys: - self.assertTrue(key in cr.system_options.keys()) - value = cr.system_options['root']['component_options']['assembled_jac_type'] + self.assertTrue(key in cr._system_options.keys()) + value = cr._system_options['root_0']['component_options']['assembled_jac_type'] self.assertEqual(value, 'csc') # quick check only. Too much to check exhaustively # Recorder on a solver @@ -558,11 +558,11 @@ def test_record_system_options(self): cr = om.CaseReader("cases_solver.sql") # Quick check to see that keys and values were recorded for key in expected_system_options_keys: - self.assertTrue(key in cr.system_options.keys()) - value = cr.system_options['root']['component_options']['assembled_jac_type'] + self.assertTrue(key in cr._system_options.keys()) + value = cr._system_options['root_0']['component_options']['assembled_jac_type'] self.assertEqual(value, 'csc') # quick check only. Too much to check exhaustively - def test_warning_system_options_overwriting(self): + def test_warning__system_options_overwriting(self): prob = ParaboloidProblem() prob.driver = om.ScipyOptimizeDriver(disp=False, tol=1e-9) @@ -1505,14 +1505,14 @@ def test_record_system_recursively(self): # Just make sure all Systems had some metadata recorded assertSystemMetadataIdsRecorded(self, [ - 'root', - '_auto_ivc', - 'mda', - 'mda.d1', - 'mda.d2', - 'obj_cmp', - 'con_cmp1', - 'con_cmp2' + 'root_0', + '_auto_ivc_0', + 'mda_0', + 'mda.d1_0', + 'mda.d2_0', + 'obj_cmp_0', + 'con_cmp1_0', + 'con_cmp2_0' ]) # Make sure all the Systems are recorded @@ -1541,14 +1541,14 @@ def test_record_system_with_prefix(self): # Just make sure all Systems had some metadata recorded assertSystemMetadataIdsRecorded(self, [ - 'root', - '_auto_ivc', - 'mda', - 'mda.d1', - 'mda.d2', - 'obj_cmp', - 'con_cmp1', - 'con_cmp2' + 'root_0', + '_auto_ivc_0', + 'mda_0', + 'mda.d1_0', + 'mda.d2_0', + 'obj_cmp_0', + 'con_cmp1_0', + 'con_cmp2_0' ]) # Make sure all the Systems are recorded at least once @@ -2508,14 +2508,15 @@ def test_feature_recording_system_options(self): cr = om.CaseReader("cases.sql") # metadata for all the systems in the model - metadata = cr.system_options + metadata = cr._system_options self.assertEqual(sorted(metadata.keys()), - sorted(['root', '_auto_ivc', 'd1', 'd2', 'obj_cmp', 'con_cmp1', 'con_cmp2'])) + sorted(['root_0', '_auto_ivc_0', 'd1_0', 'd2_0', 'obj_cmp_0', 'con_cmp1_0', + 'con_cmp2_0'])) # options for system 'd1', with second option excluded - self.assertEqual(metadata['d1']['component_options']['distributed'], False) - self.assertEqual(metadata['d1']['component_options']['options value 1'], 1) + self.assertEqual(metadata['d1_0']['component_options']['distributed'], False) + self.assertEqual(metadata['d1_0']['component_options']['options value 1'], 1) def test_feature_system_recording_options(self): import openmdao.api as om From 812d52bd1e921d8708c918e630fd42675e5dcb42 Mon Sep 17 00:00:00 2001 From: Danny Kilkenny Date: Tue, 18 Aug 2020 16:09:23 -0400 Subject: [PATCH 05/10] Cleaned up test --- .../recorders/tests/test_sqlite_recorder.py | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/openmdao/recorders/tests/test_sqlite_recorder.py b/openmdao/recorders/tests/test_sqlite_recorder.py index aab8288e83..f4a2c60a01 100644 --- a/openmdao/recorders/tests/test_sqlite_recorder.py +++ b/openmdao/recorders/tests/test_sqlite_recorder.py @@ -2,6 +2,7 @@ import errno import os import unittest +from io import StringIO import numpy as np import sqlite3 @@ -27,7 +28,7 @@ from openmdao.recorders.tests.recorder_test_utils import run_driver from openmdao.utils.assert_utils import assert_near_equal, assert_warning, assert_equal_arrays -from openmdao.utils.general_utils import determine_adder_scaler +from openmdao.utils.general_utils import determine_adder_scaler, remove_whitespace from openmdao.utils.testing_utils import use_tempdirs # check that pyoptsparse is installed. if it is, try to use SLSQP. @@ -316,10 +317,41 @@ def test_double_run_driver_option_overwrite(self): cr = om.CaseReader(self.filename) self.assertTrue(cr._system_options['root_1']['component_options']['assembled_jac_type'], 'dense') - # cr.list_metadata() - cr.list_model_metadata(run_number=1) - print('None') - cr.list_model_metadata() + stream = StringIO() + + cr.list_model_metadata(out_stream=stream) + + text = stream.getvalue().split('\n') + + expected = [ + "Run Number: 0", + " Subsystem: root", + " assembled_jac_type : csc", + "Run Number: 1", + " Subsystem: root", + " assembled_jac_type : dense" + ] + + for i, line in enumerate(expected): + if line and not line.startswith('-'): + self.assertEqual(remove_whitespace(text[i]), remove_whitespace(line)) + + stream = StringIO() + + cr.list_model_metadata(run_number=1, out_stream=stream) + + text = stream.getvalue().split('\n') + + expected = [ + "Run Number: 1", + " Subsystem: root", + " assembled_jac_type : dense" + ] + + for i, line in enumerate(expected): + if line and not line.startswith('-'): + self.assertEqual(remove_whitespace(text[i]), remove_whitespace(line)) + def test_simple_driver_recording_with_prefix(self): prob = ParaboloidProblem() From bb94e37aa5091c31fd2cf2b6307defa5e625751a Mon Sep 17 00:00:00 2001 From: Danny Kilkenny Date: Tue, 18 Aug 2020 17:06:15 -0400 Subject: [PATCH 06/10] Added dict return --- openmdao/recorders/sqlite_reader.py | 30 ++++++++++++++++--- openmdao/recorders/sqlite_recorder.py | 2 +- .../recorders/tests/test_sqlite_recorder.py | 11 ++----- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/openmdao/recorders/sqlite_reader.py b/openmdao/recorders/sqlite_reader.py index 2136a17548..eefa349229 100644 --- a/openmdao/recorders/sqlite_reader.py +++ b/openmdao/recorders/sqlite_reader.py @@ -410,19 +410,36 @@ def list_source_vars(self, source, out_stream=_DEFAULT_OUT_STREAM): return dct - def list_model_metadata(self, run_number=None, out_stream=_DEFAULT_OUT_STREAM): + def list_model_metadata(self, run_counter=None, out_stream=_DEFAULT_OUT_STREAM): + """ + List of all model options. + + Parameters + ---------- + run_counter : int or None + Run_driver iteration to inspect + out_stream : file-like object + Where to send human readable output. Default is sys.stdout. + Set to None to suppress. + Returns + ------- + dict + {'root':{key val}} + """ if out_stream: if out_stream is _DEFAULT_OUT_STREAM: out_stream = sys.stdout + dct = {} + for i in self._system_options: subsys, num = i.rsplit('_', 1) - # subs + if (run_counter is not None and run_counter == int(num) and subsys == 'root') or \ + (subsys == 'root' and run_counter is None): + print("yes") - if (run_number is not None and run_number == int(num) and subsys == 'root') or \ - (subsys == 'root' and run_number is None): out_stream.write( 'Run Number: {}\n Subsystem: {}'.format(num, subsys)) @@ -431,6 +448,11 @@ def list_model_metadata(self, run_number=None, out_stream=_DEFAULT_OUT_STREAM): j, self._system_options[i]['component_options'][j]) out_stream.write('\n {}\n'.format(option)) + dct[subsys] = {} + dct[subsys][j] = self._system_options[i]['component_options'][j] + + return dct + def list_cases(self, source=None, recurse=True, flat=True, out_stream=_DEFAULT_OUT_STREAM): """ Iterate over Driver, Solver and System cases in order. diff --git a/openmdao/recorders/sqlite_recorder.py b/openmdao/recorders/sqlite_recorder.py index 8af0c26aa8..fd67e133de 100644 --- a/openmdao/recorders/sqlite_recorder.py +++ b/openmdao/recorders/sqlite_recorder.py @@ -672,7 +672,7 @@ def record_metadata_system(self, recording_requester, run_counter=None): c.execute("INSERT OR IGNORE INTO system_metadata" "(id, scaling_factors, component_metadata) " "VALUES(?,?,?)", (path + '_' + str(run_counter), scaling_factors, - pickled_metadata)) + pickled_metadata)) def record_metadata_solver(self, recording_requester): """ diff --git a/openmdao/recorders/tests/test_sqlite_recorder.py b/openmdao/recorders/tests/test_sqlite_recorder.py index f4a2c60a01..75d917799c 100644 --- a/openmdao/recorders/tests/test_sqlite_recorder.py +++ b/openmdao/recorders/tests/test_sqlite_recorder.py @@ -294,12 +294,8 @@ def test_double_run_driver_option_overwrite(self): prob = ParaboloidProblem() driver = prob.driver = om.ScipyOptimizeDriver(disp=False, tol=1e-9) - driver.recording_options['record_desvars'] = True - driver.recording_options['record_objectives'] = True - driver.recording_options['record_constraints'] = True - driver.recording_options['record_derivatives'] = True - driver.recording_options['includes'] = ['*'] - driver.add_recorder(self.recorder) + + prob.model.add_recorder(self.recorder) prob.setup() prob.set_solver_print(0) @@ -338,7 +334,7 @@ def test_double_run_driver_option_overwrite(self): stream = StringIO() - cr.list_model_metadata(run_number=1, out_stream=stream) + cr.list_model_metadata(run_counter=1, out_stream=stream) text = stream.getvalue().split('\n') @@ -352,7 +348,6 @@ def test_double_run_driver_option_overwrite(self): if line and not line.startswith('-'): self.assertEqual(remove_whitespace(text[i]), remove_whitespace(line)) - def test_simple_driver_recording_with_prefix(self): prob = ParaboloidProblem() From 4381d9bb0fce295b948b4eddfddc887c1ebb44a9 Mon Sep 17 00:00:00 2001 From: Danny Kilkenny Date: Wed, 19 Aug 2020 11:15:14 -0400 Subject: [PATCH 07/10] cleanup --- openmdao/core/problem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmdao/core/problem.py b/openmdao/core/problem.py index 2d184b7341..2b9828dff3 100644 --- a/openmdao/core/problem.py +++ b/openmdao/core/problem.py @@ -838,7 +838,7 @@ def setup(self, check=False, logger=None, mode='auto', force_alloc_complex=False self._setup_already_called = False if hasattr(self, '_metadata') and self._metadata is not None: - if self._metadata['setup_status'] == _SetupStatus.POST_FINAL_SETUP: #3 + if self._metadata['setup_status'] == _SetupStatus.POST_FINAL_SETUP: self._setup_already_called = True # PETScVector is required for MPI @@ -891,7 +891,7 @@ def setup(self, check=False, logger=None, mode='auto', force_alloc_complex=False self._check = check self._logger = logger - self._metadata['setup_status'] = _SetupStatus.POST_SETUP # 2 + self._metadata['setup_status'] = _SetupStatus.POST_SETUP return self From c570fbda2545bb46fc5da237afb3977042c5323c Mon Sep 17 00:00:00 2001 From: Danny Kilkenny Date: Wed, 19 Aug 2020 11:26:03 -0400 Subject: [PATCH 08/10] added test to cover run_model as well --- openmdao/core/problem.py | 5 +- openmdao/recorders/sqlite_reader.py | 2 +- openmdao/recorders/sqlite_recorder.py | 4 +- .../recorders/tests/test_sqlite_recorder.py | 62 ++++++++++++++++++- 4 files changed, 67 insertions(+), 6 deletions(-) diff --git a/openmdao/core/problem.py b/openmdao/core/problem.py index 2b9828dff3..b016c2cdd5 100644 --- a/openmdao/core/problem.py +++ b/openmdao/core/problem.py @@ -169,6 +169,7 @@ def __init__(self, model=None, driver=None, comm=None, name=None, **options): self._initial_condition_cache = {} self._metadata = None + self._run_counter = 0 self._system_options_recorded = False self._rec_mgr = RecordingManager() @@ -597,6 +598,9 @@ def run_model(self, case_prefix=None, reset_iter_counts=True): self.driver.iter_count = 0 self.model._reset_iter_counts() + if self._setup_already_called: + self._run_counter += 1 + self.final_setup() self.model._clear_iprint() self.model.run_solve_nonlinear() @@ -633,7 +637,6 @@ def run_driver(self, case_prefix=None, reset_iter_counts=True): self.driver.iter_count = 0 self.model._reset_iter_counts() - self._run_counter = 0 if self._setup_already_called: self._run_counter += 1 diff --git a/openmdao/recorders/sqlite_reader.py b/openmdao/recorders/sqlite_reader.py index f7181f56e7..9f06b45ed9 100644 --- a/openmdao/recorders/sqlite_reader.py +++ b/openmdao/recorders/sqlite_reader.py @@ -409,7 +409,7 @@ def list_source_vars(self, source, out_stream=_DEFAULT_OUT_STREAM): return dct - def list_model_metadata(self, run_counter=None, out_stream=_DEFAULT_OUT_STREAM): + def list_model_options(self, run_counter=None, out_stream=_DEFAULT_OUT_STREAM): """ List of all model options. diff --git a/openmdao/recorders/sqlite_recorder.py b/openmdao/recorders/sqlite_recorder.py index fd67e133de..8e0752726c 100644 --- a/openmdao/recorders/sqlite_recorder.py +++ b/openmdao/recorders/sqlite_recorder.py @@ -630,7 +630,7 @@ def record_metadata_system(self, recording_requester, run_counter=None): ---------- recording_requester : System The System that would like to record its metadata. - run_counter : int + run_counter : int or None The number of times run_driver has been called. """ if self.connection: @@ -671,7 +671,7 @@ def record_metadata_system(self, recording_requester, run_counter=None): with self.connection as c: c.execute("INSERT OR IGNORE INTO system_metadata" "(id, scaling_factors, component_metadata) " - "VALUES(?,?,?)", (path + '_' + str(run_counter), scaling_factors, + "VALUES(?,?,?)", ("{}_{}".format(path, str(run_counter)), scaling_factors, pickled_metadata)) def record_metadata_solver(self, recording_requester): diff --git a/openmdao/recorders/tests/test_sqlite_recorder.py b/openmdao/recorders/tests/test_sqlite_recorder.py index f4d0587b57..ea15ef9259 100644 --- a/openmdao/recorders/tests/test_sqlite_recorder.py +++ b/openmdao/recorders/tests/test_sqlite_recorder.py @@ -315,7 +315,7 @@ def test_double_run_driver_option_overwrite(self): stream = StringIO() - cr.list_model_metadata(out_stream=stream) + cr.list_model_options(out_stream=stream) text = stream.getvalue().split('\n') @@ -334,7 +334,65 @@ def test_double_run_driver_option_overwrite(self): stream = StringIO() - cr.list_model_metadata(run_counter=1, out_stream=stream) + cr.list_model_options(run_counter=1, out_stream=stream) + + text = stream.getvalue().split('\n') + + expected = [ + "Run Number: 1", + " Subsystem: root", + " assembled_jac_type : dense" + ] + + for i, line in enumerate(expected): + if line and not line.startswith('-'): + self.assertEqual(remove_whitespace(text[i]), remove_whitespace(line)) + + def test_double_run_model_option_overwrite(self): + prob = ParaboloidProblem() + + driver = prob.driver = om.ScipyOptimizeDriver(disp=False, tol=1e-9) + + prob.model.add_recorder(self.recorder) + + prob.setup() + prob.set_solver_print(0) + prob.run_model() + + cr = om.CaseReader(self.filename) + + self.assertTrue(cr._system_options['root_0']['component_options']['assembled_jac_type'], 'csc') + + # New option and re-run of run_driver + prob.model.options['assembled_jac_type'] = 'dense' + prob.setup() + prob.run_model() + + cr = om.CaseReader(self.filename) + self.assertTrue(cr._system_options['root_1']['component_options']['assembled_jac_type'], 'dense') + + stream = StringIO() + + cr.list_model_options(out_stream=stream) + + text = stream.getvalue().split('\n') + + expected = [ + "Run Number: 0", + " Subsystem: root", + " assembled_jac_type : csc", + "Run Number: 1", + " Subsystem: root", + " assembled_jac_type : dense" + ] + + for i, line in enumerate(expected): + if line and not line.startswith('-'): + self.assertEqual(remove_whitespace(text[i]), remove_whitespace(line)) + + stream = StringIO() + + cr.list_model_options(run_counter=1, out_stream=stream) text = stream.getvalue().split('\n') From d332376d9e8ddc2946d6eee22272e91352ab4cb1 Mon Sep 17 00:00:00 2001 From: Danny Kilkenny Date: Wed, 19 Aug 2020 12:16:01 -0400 Subject: [PATCH 09/10] PEP and other cleanup --- openmdao/core/problem.py | 2 ++ openmdao/recorders/sqlite_reader.py | 2 +- openmdao/recorders/sqlite_recorder.py | 2 +- openmdao/recorders/tests/test_sqlite_recorder.py | 7 +------ 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/openmdao/core/problem.py b/openmdao/core/problem.py index b016c2cdd5..7b5368bb81 100644 --- a/openmdao/core/problem.py +++ b/openmdao/core/problem.py @@ -116,6 +116,8 @@ class Problem(object): A flag to indicate whether the system options for all the systems have been recorded _metadata : dict Problem level metadata. + _run_counter : int + The number of times run_driver or run_model has been called. """ def __init__(self, model=None, driver=None, comm=None, name=None, **options): diff --git a/openmdao/recorders/sqlite_reader.py b/openmdao/recorders/sqlite_reader.py index 9f06b45ed9..822467028a 100644 --- a/openmdao/recorders/sqlite_reader.py +++ b/openmdao/recorders/sqlite_reader.py @@ -416,7 +416,7 @@ def list_model_options(self, run_counter=None, out_stream=_DEFAULT_OUT_STREAM): Parameters ---------- run_counter : int or None - Run_driver iteration to inspect + Run_driver or run_model iteration to inspect out_stream : file-like object Where to send human readable output. Default is sys.stdout. Set to None to suppress. diff --git a/openmdao/recorders/sqlite_recorder.py b/openmdao/recorders/sqlite_recorder.py index 8e0752726c..91e0cb8348 100644 --- a/openmdao/recorders/sqlite_recorder.py +++ b/openmdao/recorders/sqlite_recorder.py @@ -631,7 +631,7 @@ def record_metadata_system(self, recording_requester, run_counter=None): recording_requester : System The System that would like to record its metadata. run_counter : int or None - The number of times run_driver has been called. + The number of times run_driver or run_model has been called. """ if self.connection: if run_counter is None: diff --git a/openmdao/recorders/tests/test_sqlite_recorder.py b/openmdao/recorders/tests/test_sqlite_recorder.py index ea15ef9259..ee48be01e7 100644 --- a/openmdao/recorders/tests/test_sqlite_recorder.py +++ b/openmdao/recorders/tests/test_sqlite_recorder.py @@ -410,12 +410,7 @@ def test_simple_driver_recording_with_prefix(self): prob = ParaboloidProblem() driver = prob.driver = om.ScipyOptimizeDriver(disp=False, tol=1e-9) - driver.recording_options['record_desvars'] = True - driver.recording_options['record_objectives'] = True - driver.recording_options['record_constraints'] = True - driver.recording_options['record_derivatives'] = True - driver.recording_options['includes'] = ['*'] - driver.add_recorder(self.recorder) + prob.model.add_recorder(self.recorder) prob.setup() prob.set_solver_print(0) From 6a794f1e336ad77470a3fb129a71bb9b2f4b790b Mon Sep 17 00:00:00 2001 From: Danny Kilkenny Date: Wed, 19 Aug 2020 15:32:02 -0400 Subject: [PATCH 10/10] Reset mistaken test deletion --- openmdao/recorders/tests/test_sqlite_recorder.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openmdao/recorders/tests/test_sqlite_recorder.py b/openmdao/recorders/tests/test_sqlite_recorder.py index ee48be01e7..ecc3c508ca 100644 --- a/openmdao/recorders/tests/test_sqlite_recorder.py +++ b/openmdao/recorders/tests/test_sqlite_recorder.py @@ -410,6 +410,12 @@ def test_simple_driver_recording_with_prefix(self): prob = ParaboloidProblem() driver = prob.driver = om.ScipyOptimizeDriver(disp=False, tol=1e-9) + driver.recording_options['record_desvars'] = True + driver.recording_options['record_objectives'] = True + driver.recording_options['record_constraints'] = True + driver.recording_options['record_derivatives'] = True + driver.recording_options['includes'] = ['*'] + driver.add_recorder(self.recorder) prob.model.add_recorder(self.recorder) prob.setup()