diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 7fcd831466fc7ac46241fe1d359a9d135dac21b0..a6d8f2fe04b7a4de4bb45862dc19f4fc5d2731f9 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -3297,6 +3297,8 @@ DynamicModel::writeDynamicFile(const string &basename, bool block, bool use_dll, create_directories(sparsefolder / "private"); if (block_decomposed) create_directories(sparsefolder / "+block"); + + create_directories(plusfolder / "+debug"); } create_directories(model_dir / "bytecode"); @@ -3341,6 +3343,10 @@ DynamicModel::writeDynamicFile(const string &basename, bool block, bool use_dll, writeSparseModelMFiles<true>(basename); writeSetAuxiliaryVariables(basename, julia); + + // Support for model debugging + if (!julia) + writeDebugModelMFiles<true>(basename); } void diff --git a/src/ModelTree.hh b/src/ModelTree.hh index aced1279eb1f2314b990272bf367761ade292d5f..8b08051338b761e0c7354a511823f72b1abe0d3f 100644 --- a/src/ModelTree.hh +++ b/src/ModelTree.hh @@ -391,6 +391,15 @@ protected: //! Writes LaTeX model file void writeLatexModelFile(const string &mod_basename, const string &latex_basename, ExprNodeOutputType output_type, bool write_equation_tags) const; + /* Write files for helping a user to debug their model (MATLAB/Octave, + sparse representation). + Creates a dynamic/static files which evaluates separately the LHS and RHS + of each equation. + They are not optimized for performance (hence in particular the absence of + a C version, or the non-reuse of temporary terms). */ + template<bool dynamic> + void writeDebugModelMFiles(const string &basename) const; + private: //! Sparse matrix of double to store the values of the static Jacobian /*! First index is equation number, second index is endogenous type specific ID */ @@ -2939,3 +2948,49 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext, } } } + +template<bool dynamic> +void +ModelTree::writeDebugModelMFiles(const string &basename) const +{ + constexpr ExprNodeOutputType output_type {dynamic ? ExprNodeOutputType::matlabSparseDynamicModel : ExprNodeOutputType::matlabSparseStaticModel}; + + const filesystem::path m_dir {packageDir(basename) / "+debug"}; + // TODO: when C++20 support is complete, mark the following strings constexpr + const string prefix { dynamic ? "dynamic_" : "static_" }; + const string ss_arg { dynamic ? ", steady_state" : "" }; + + const filesystem::path resid_filename {m_dir / (prefix + "resid.m")}; + ofstream output {resid_filename, ios::out | ios::binary}; + if (!output.is_open()) + { + cerr << "ERROR: Can't open file " << resid_filename.string() << " for writing" << endl; + exit(EXIT_FAILURE); + } + + output << "function [lhs, rhs] = " << prefix << "resid(y, x, params" << ss_arg << ")" << endl + << "T = NaN(" << temporary_terms_derivatives[0].size() << ", 1);" << endl + << "lhs = NaN(" << equations.size() << ", 1);" << endl + << "rhs = NaN(" << equations.size() << ", 1);" << endl; + deriv_node_temp_terms_t tef_terms; + temporary_terms_t temporary_terms; + writeTemporaryTerms<output_type>(temporary_terms_derivatives[0], temporary_terms, + temporary_terms_idxs, output, tef_terms); + for (size_t eq {0}; eq < equations.size(); eq++) + { + output << "lhs" << LEFT_ARRAY_SUBSCRIPT(output_type) + << eq + ARRAY_SUBSCRIPT_OFFSET(output_type) + << RIGHT_ARRAY_SUBSCRIPT(output_type) << " = "; + equations[eq]->arg1->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); + output << ";" << endl + << "rhs" << LEFT_ARRAY_SUBSCRIPT(output_type) + << eq + ARRAY_SUBSCRIPT_OFFSET(output_type) + << RIGHT_ARRAY_SUBSCRIPT(output_type) << " = "; + equations[eq]->arg2->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); + output << ";" << endl; + } + + output << "end" << endl; + + output.close(); +} diff --git a/src/StaticModel.cc b/src/StaticModel.cc index e3adc0b3e650162054bdae14d99e937e626dd25f..192b06dcaa4a8713f2f99cbda89e04ec37754de6 100644 --- a/src/StaticModel.cc +++ b/src/StaticModel.cc @@ -639,6 +639,8 @@ StaticModel::writeStaticFile(const string &basename, bool block, bool use_dll, c create_directories(sparsefolder / "private"); if (block_decomposed) create_directories(sparsefolder / "+block"); + + create_directories(plusfolder / "+debug"); } create_directories(model_dir / "bytecode"); @@ -683,6 +685,10 @@ StaticModel::writeStaticFile(const string &basename, bool block, bool use_dll, c writeSparseModelMFiles<false>(basename); writeSetAuxiliaryVariables(basename, julia); + + // Support for model debugging + if (!julia) + writeDebugModelMFiles<false>(basename); } bool