diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 478e9df8d818dd24443624276df0f5c89ac18553..247bbad092dc801126fcfe84268e18b1331fd39e 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -4245,7 +4245,7 @@ DynamicModel::computingPass(bool jacobianExo, int derivsOrder, int paramsDerivsO { auto contemporaneous_jacobian = evaluateAndReduceJacobian(eval_context); - computeNonSingularNormalization(contemporaneous_jacobian); + computeNonSingularNormalization(contemporaneous_jacobian, true); auto [prologue, epilogue] = computePrologueAndEpilogue(); diff --git a/src/ModelTree.cc b/src/ModelTree.cc index 37319bacd3b24c580ef6aa7a69148c7ed1ee5d86..a78a57b767cc87449aadf284d65a7676377a3be3 100644 --- a/src/ModelTree.cc +++ b/src/ModelTree.cc @@ -201,7 +201,7 @@ ModelTree::operator=(const ModelTree &m) } bool -ModelTree::computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool verbose) +ModelTree::computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool dynamic, bool verbose) { const int n = equations.size(); @@ -241,7 +241,7 @@ ModelTree::computeNormalization(const jacob_map_t &contemporaneous_jacobian, boo it != mate_map.begin() + n) { if (verbose) - cerr << "ERROR: Could not normalize the model. Variable " + cerr << "ERROR: Could not normalize the " << (dynamic ? "dynamic" : "static") << " model. Variable " << symbol_table.getName(symbol_table.getID(SymbolType::endogenous, it - mate_map.begin())) << " is not in the maximum cardinality matching." << endl; check = false; @@ -250,9 +250,9 @@ ModelTree::computeNormalization(const jacob_map_t &contemporaneous_jacobian, boo } void -ModelTree::computeNonSingularNormalization(const jacob_map_t &contemporaneous_jacobian) +ModelTree::computeNonSingularNormalization(const jacob_map_t &contemporaneous_jacobian, bool dynamic) { - cout << "Normalizing the model..." << endl; + cout << "Normalizing the " << (dynamic ? "dynamic" : "static") << " model..." << endl; int n = equations.size(); @@ -284,14 +284,14 @@ ModelTree::computeNonSingularNormalization(const jacob_map_t &contemporaneous_ja suppressed++; if (suppressed != last_suppressed) - found_normalization = computeNormalization(normalized_contemporaneous_jacobian_above_cutoff, false); + found_normalization = computeNormalization(normalized_contemporaneous_jacobian_above_cutoff, dynamic, false); last_suppressed = suppressed; if (!found_normalization) { current_cutoff /= 2; // In this last case try to normalize with the complete jacobian if (current_cutoff <= cutoff_lower_limit) - found_normalization = computeNormalization(normalized_contemporaneous_jacobian, false); + found_normalization = computeNormalization(normalized_contemporaneous_jacobian, dynamic, false); } } @@ -302,12 +302,19 @@ ModelTree::computeNonSingularNormalization(const jacob_map_t &contemporaneous_ja normalization even with a potential singularity. TODO: Explain why symbolic_jacobian is not contemporaneous. */ auto symbolic_jacobian = computeSymbolicJacobian(); - found_normalization = computeNormalization(symbolic_jacobian, true); + found_normalization = computeNormalization(symbolic_jacobian, dynamic, true); } if (!found_normalization) { - cerr << "No normalization could be computed. Aborting." << endl; + /* Some models don’t have a steady state, and this can cause the + normalization to fail (e.g. if some variable only appears in a diff(), + it will disappear from the static model). Suggest the “no_static” + option as a possible solution. */ + if (!dynamic) + cerr << "If your model does not have a steady state, you may want to try the 'no_static' option of the 'model' block." << endl; + /* The last call to computeNormalization(), which was verbose, already + printed an error message, so we can immediately exit. */ exit(EXIT_FAILURE); } } diff --git a/src/ModelTree.hh b/src/ModelTree.hh index 4c5b18102478e6373efc72b1dc06b2567532819d..c7f17aeaeae05563bdf8e7daeaac8104d105c1cc 100644 --- a/src/ModelTree.hh +++ b/src/ModelTree.hh @@ -283,7 +283,7 @@ protected: \param contemporaneous_jacobian Jacobian used as an incidence matrix: all elements declared in the map (even if they are zero), are used as vertices of the incidence matrix \return True if a complete normalization has been achieved */ - bool computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool verbose); + bool computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool dynamic, bool verbose); //! Try to compute the matching between endogenous and variable using a decreasing cutoff /*! @@ -292,7 +292,7 @@ protected: If no matching is found with a zero cutoff, an error message is printed. The resulting normalization is stored in endo2eq. */ - void computeNonSingularNormalization(const jacob_map_t &contemporaneous_jacobian); + void computeNonSingularNormalization(const jacob_map_t &contemporaneous_jacobian, bool dynamic); //! Evaluate the jacobian (w.r.t. endogenous) and suppress all the elements below the cutoff /*! Returns the contemporaneous_jacobian. Elements below the cutoff are discarded. External functions are evaluated to 1. */ diff --git a/src/StaticModel.cc b/src/StaticModel.cc index 906bdca0d7ec919f152bd8be5cadf16940f83214..3123b088bfe0dd06cdd590bd59f9ab94d6509cda 100644 --- a/src/StaticModel.cc +++ b/src/StaticModel.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2021 Dynare Team + * Copyright © 2003-2022 Dynare Team * * This file is part of Dynare. * @@ -1040,7 +1040,7 @@ StaticModel::computingPass(int derivsOrder, int paramsDerivsOrder, const eval_co { auto contemporaneous_jacobian = evaluateAndReduceJacobian(eval_context); - computeNonSingularNormalization(contemporaneous_jacobian); + computeNonSingularNormalization(contemporaneous_jacobian, false); auto [prologue, epilogue] = computePrologueAndEpilogue();