From 3e9b43cdcdfdc053c0d98bb4e577449e2bb69a37 Mon Sep 17 00:00:00 2001 From: dallan-keylogic <88728506+dallan-keylogic@users.noreply.github.com> Date: Thu, 7 Dec 2023 15:25:52 -0500 Subject: [PATCH] Fix methods in SVD Toolbox (#1288) * fix model diagnostics * fix tests and black * Make lists private --------- Co-authored-by: Andrew Lee --- idaes/core/util/model_diagnostics.py | 57 ++++++++----------- .../core/util/tests/test_model_diagnostics.py | 8 +-- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/idaes/core/util/model_diagnostics.py b/idaes/core/util/model_diagnostics.py index 5194ee0064..4baade5ef0 100644 --- a/idaes/core/util/model_diagnostics.py +++ b/idaes/core/util/model_diagnostics.py @@ -1450,6 +1450,10 @@ def __init__(self, model: _BlockData, **kwargs): self._model, scaled=False, equality_constraints_only=True ) + # Get list of equality constraint and variable names + self._eq_con_list = self.nlp.get_pyomo_equality_constraints() + self._var_list = self.nlp.get_pyomo_variables() + if self.jacobian.shape[0] < 2: raise ValueError( "Model needs at least 2 equality constraints to perform svd_analysis." @@ -1562,10 +1566,6 @@ def display_underdetermined_variables_and_constraints( tol = self.config.size_cutoff_in_singular_vector - # Get list of equality constraint and variable names - eq_con_list = self.nlp.get_pyomo_equality_constraints() - var_list = self.nlp.get_pyomo_variables() - if singular_values is None: singular_values = range(1, len(self.s) + 1) @@ -1588,11 +1588,11 @@ def display_underdetermined_variables_and_constraints( stream.write(f"{TAB}Smallest Singular Value {e}:\n\n") stream.write(f"{2 * TAB}Variables:\n\n") for v in np.where(abs(self.v[:, e - 1]) > tol)[0]: - stream.write(f"{3 * TAB}{var_list[v].name}\n") + stream.write(f"{3 * TAB}{self._var_list[v].name}\n") stream.write(f"\n{2 * TAB}Constraints:\n\n") for c in np.where(abs(self.u[:, e - 1]) > tol)[0]: - stream.write(f"{3 * TAB}{eq_con_list[c].name}\n") + stream.write(f"{3 * TAB}{self._eq_con_list[c].name}\n") stream.write("\n") stream.write("=" * MAX_STR_LENGTH + "\n") @@ -1620,23 +1620,19 @@ def display_constraints_including_variable(self, variable, stream=None): f"object (got {variable})." ) - # Get list of equality constraint and variable names - eq_con_list = self.nlp.get_pyomo_equality_constraints() - var_list = self.nlp.get_pyomo_variables() - # Get index of variable in Jacobian try: - var_idx = var_list.index(variable) - except (ValueError, PyomoException): + var_idx = self.nlp.get_primal_indices([variable])[0] + except (KeyError, PyomoException): raise AttributeError(f"Could not find {variable.name} in model.") - nonzeroes = self.jacobian[:, var_idx].nonzero() + nonzeros = self.jacobian.getcol(var_idx).nonzero() # Build a list of all constraints that include var cons_w_var = [] - for i, r in enumerate(nonzeroes[0]): + for r in nonzeros[0]: cons_w_var.append( - f"{eq_con_list[r].name}: {self.jacobian[(r, nonzeroes[1][i])]}" + f"{self._eq_con_list[r].name}: {self.jacobian[(r, var_idx)]:.3e}" ) # Write the output @@ -1671,23 +1667,20 @@ def display_variables_in_constraint(self, constraint, stream=None): f"object (got {constraint})." ) - # Get list of equality constraint and variable names - eq_con_list = self.nlp.get_pyomo_equality_constraints() - var_list = self.nlp.get_pyomo_variables() - # Get index of variable in Jacobian try: - con_idx = eq_con_list.index(constraint) - except ValueError: + con_idx = self.nlp.get_constraint_indices([constraint])[0] + except KeyError: raise AttributeError(f"Could not find {constraint.name} in model.") - nonzeroes = self.jacobian[con_idx, :].nonzero() + nonzeros = self.jacobian[con_idx, :].nonzero() # Build a list of all vars in constraint vars_in_cons = [] - for i, r in enumerate(nonzeroes[0]): - c = nonzeroes[1][i] - vars_in_cons.append(f"{var_list[c].name}: {self.jacobian[(r, c)]}") + for c in nonzeros[1]: + vars_in_cons.append( + f"{self._var_list[c].name}: {self.jacobian[(con_idx, c)]:.3e}" + ) # Write the output _write_report_section( @@ -2281,8 +2274,8 @@ def __init__(self, block_or_jac, solver=None): self.jac_eq = get_jacobian(self.block, equality_constraints_only=True)[0] # Create a list of equality constraint names - self.eq_con_list = self.nlp.get_pyomo_equality_constraints() - self.var_list = self.nlp.get_pyomo_variables() + self._eq_con_list = self.nlp.get_pyomo_equality_constraints() + self._var_list = self.nlp.get_pyomo_variables() self.candidate_eqns = None @@ -2293,7 +2286,7 @@ def __init__(self, block_or_jac, solver=None): # # TODO: Need to refactor, document, and test support for Jacobian # self.jac_eq = block_or_jac - # self.eq_con_list = None + # self._eq_con_list = None else: raise TypeError("Check the type for 'block_or_jac'") @@ -2813,11 +2806,11 @@ def underdetermined_variables_and_constraints(self, n_calc=1, tol=0.1, dense=Fal ) print("Column: Variable") for i in np.where(abs(self.v[:, n_calc - 1]) > tol)[0]: - print(str(i) + ": " + self.var_list[i].name) + print(str(i) + ": " + self._var_list[i].name) print("") print("Row: Constraint") for i in np.where(abs(self.u[:, n_calc - 1]) > tol)[0]: - print(str(i) + ": " + self.eq_con_list[i].name) + print(str(i) + ": " + self._eq_con_list[i].name) def find_candidate_equations(self, verbose=True, tee=False): """ @@ -2842,7 +2835,7 @@ def find_candidate_equations(self, verbose=True, tee=False): if verbose: print("Solving MILP model...") ce, ds = self._find_candidate_eqs( - self.candidates_milp, self.solver, self.eq_con_list, tee + self.candidates_milp, self.solver, self._eq_con_list, tee ) if ce is not None: @@ -2883,7 +2876,7 @@ def find_irreducible_degenerate_sets(self, verbose=True, tee=False): # Check if equation 'c' is a major element of an IDS ids_ = self._check_candidate_ids( - self.dh_milp, self.solver, c, self.eq_con_list, tee + self.dh_milp, self.solver, c, self._eq_con_list, tee ) if ids_ is not None: diff --git a/idaes/core/util/tests/test_model_diagnostics.py b/idaes/core/util/tests/test_model_diagnostics.py index 7990171982..3ea6c2e339 100644 --- a/idaes/core/util/tests/test_model_diagnostics.py +++ b/idaes/core/util/tests/test_model_diagnostics.py @@ -1598,8 +1598,8 @@ def test_display_constraints_including_variable(self): expected = """==================================================================================== The following constraints involve v[1]: - c1: 1.0 - c4: 8.0 + c1: 1.000e+00 + c4: 8.000e+00 ==================================================================================== """ @@ -1663,8 +1663,8 @@ def test_display_variables_in_constraint(self): expected = """==================================================================================== The following variables are involved in c1: - v[1]: 1.0 - v[2]: 2.0 + v[1]: 1.000e+00 + v[2]: 2.000e+00 ==================================================================================== """