diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index e22bd2cc4c106e8f84fd4302b77e914cfa11388f..9a10ad93fb7cc2b3e7de2aacf4f0e890db276ff5 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -198,238 +198,6 @@ DynamicModel::additionalBlockTemporaryTerms(int blk, d->computeBlockTemporaryTerms(blk, blocks[blk].size, blocks_temporary_terms, reference_count); } -void -DynamicModel::writeDynamicPerBlockHelper(int blk, ostream &output, ExprNodeOutputType output_type, temporary_terms_t &temporary_terms, int nze_stochastic, int nze_deterministic, int nze_exo, int nze_exo_det, int nze_other_endo) const -{ - BlockSimulationType simulation_type = blocks[blk].simulation_type; - int block_size = blocks[blk].size; - int block_mfs_size = blocks[blk].mfs_size; - int block_recursive_size = blocks[blk].getRecursiveSize(); - - deriv_node_temp_terms_t tef_terms; - - auto write_eq_tt = [&](int eq) - { - for (auto it : blocks_temporary_terms[blk][eq]) - { - if (dynamic_cast<AbstractExternalFunctionNode *>(it)) - it->writeExternalFunctionOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs, tef_terms); - - output << " "; - it->writeOutput(output, output_type, blocks_temporary_terms[blk][eq], blocks_temporary_terms_idxs, tef_terms); - output << '='; - it->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs, tef_terms); - temporary_terms.insert(it); - output << ';' << endl; - } - }; - - // The equations - for (int eq = 0; eq < block_size; eq++) - { - write_eq_tt(eq); - - EquationType equ_type = getBlockEquationType(blk, eq); - BinaryOpNode *e = getBlockEquationExpr(blk, eq); - expr_t lhs = e->arg1, rhs = e->arg2; - switch (simulation_type) - { - case BlockSimulationType::evaluateBackward: - case BlockSimulationType::evaluateForward: - evaluation: - if (equ_type == EquationType::evaluateRenormalized) - { - e = getBlockEquationRenormalizedExpr(blk, eq); - lhs = e->arg1; - rhs = e->arg2; - } - else if (equ_type != EquationType::evaluate) - { - cerr << "Type mismatch for equation " << getBlockEquationID(blk, eq)+1 << endl; - exit(EXIT_FAILURE); - } - output << " "; - lhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); - output << '='; - rhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); - output << ';' << endl; - break; - case BlockSimulationType::solveBackwardSimple: - case BlockSimulationType::solveForwardSimple: - case BlockSimulationType::solveBackwardComplete: - case BlockSimulationType::solveForwardComplete: - case BlockSimulationType::solveTwoBoundariesComplete: - case BlockSimulationType::solveTwoBoundariesSimple: - if (eq < block_recursive_size) - goto evaluation; - output << " residual" << LEFT_ARRAY_SUBSCRIPT(output_type) - << eq-block_recursive_size+ARRAY_SUBSCRIPT_OFFSET(output_type) - << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=("; - goto end; - default: - end: - lhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); - output << ")-("; - rhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); - output << ");" << endl; - } - } - - // The Jacobian if we have to solve the block - - // Write temporary terms for derivatives - write_eq_tt(blocks[blk].size); - - if (isCOutput(output_type)) - output << " if (stochastic_mode) {" << endl; - else - output << " if stochastic_mode" << endl; - - ostringstream i_output, j_output, v_output; - int line_counter = ARRAY_SUBSCRIPT_OFFSET(output_type); - for (const auto &[indices, d] : blocks_derivatives[blk]) - { - auto [eq, var, lag] = indices; - int jacob_col = blocks_jacob_cols_endo[blk].at({ var, lag }); - i_output << " g1_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << eq+1 << ';' << endl; - j_output << " g1_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << jacob_col+1 << ';' << endl; - v_output << " g1_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; - d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); - v_output << ';' << endl; - line_counter++; - } - assert(line_counter == nze_stochastic+ARRAY_SUBSCRIPT_OFFSET(output_type)); - output << i_output.str() << j_output.str() << v_output.str(); - - i_output.str(""); - j_output.str(""); - v_output.str(""); - line_counter = ARRAY_SUBSCRIPT_OFFSET(output_type); - for (const auto &[indices, d] : blocks_derivatives_exo[blk]) - { - auto [eq, var, lag] = indices; - int jacob_col = blocks_jacob_cols_exo[blk].at({ var, lag }); - i_output << " g1_x_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << eq+1 << ';' << endl; - j_output << " g1_x_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << jacob_col+1 << ';' << endl; - v_output << " g1_x_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; - d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); - v_output << ';' << endl; - line_counter++; - } - assert(line_counter == nze_exo+ARRAY_SUBSCRIPT_OFFSET(output_type)); - output << i_output.str() << j_output.str() << v_output.str(); - - i_output.str(""); - j_output.str(""); - v_output.str(""); - line_counter = ARRAY_SUBSCRIPT_OFFSET(output_type); - for (const auto &[indices, d] : blocks_derivatives_exo_det[blk]) - { - auto [eq, var, lag] = indices; - int jacob_col = blocks_jacob_cols_exo_det[blk].at({ var, lag }); - i_output << " g1_xd_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << eq+1 << ';' << endl; - j_output << " g1_xd_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << jacob_col+1 << ';' << endl; - v_output << " g1_xd_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; - d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); - v_output << ';' << endl; - line_counter++; - } - assert(line_counter == nze_exo_det+ARRAY_SUBSCRIPT_OFFSET(output_type)); - output << i_output.str() << j_output.str() << v_output.str(); - - i_output.str(""); - j_output.str(""); - v_output.str(""); - line_counter = ARRAY_SUBSCRIPT_OFFSET(output_type); - for (const auto &[indices, d] : blocks_derivatives_other_endo[blk]) - { - auto [eq, var, lag] = indices; - int jacob_col = blocks_jacob_cols_other_endo[blk].at({ var, lag }); - i_output << " g1_o_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << eq+1 << ';' << endl; - j_output << " g1_o_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << jacob_col+1 << ';' << endl; - v_output << " g1_o_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; - d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); - v_output << ';' << endl; - line_counter++; - } - assert(line_counter == nze_other_endo+ARRAY_SUBSCRIPT_OFFSET(output_type)); - output << i_output.str() << j_output.str() << v_output.str(); - - // Deterministic mode - if (simulation_type != BlockSimulationType::evaluateForward - && simulation_type != BlockSimulationType::evaluateBackward) - { - if (isCOutput(output_type)) - output << " } else {" << endl; - else - output << " else" << endl; - i_output.str(""); - j_output.str(""); - v_output.str(""); - line_counter = ARRAY_SUBSCRIPT_OFFSET(output_type); - if (simulation_type == BlockSimulationType::solveBackwardSimple - || simulation_type == BlockSimulationType::solveForwardSimple - || simulation_type == BlockSimulationType::solveBackwardComplete - || simulation_type == BlockSimulationType::solveForwardComplete) - for (const auto &[indices, d] : blocks_derivatives[blk]) - { - auto [eq, var, lag] = indices; - if (lag == 0 && eq >= block_recursive_size && var >= block_recursive_size) - { - i_output << " g1_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' - << eq+1-block_recursive_size << ';' << endl; - j_output << " g1_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' - << var+1-block_recursive_size << ';' << endl; - v_output << " g1_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; - d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); - v_output << ';' << endl; - line_counter++; - } - } - else // solveTwoBoundariesSimple || solveTwoBoundariesComplete - for (const auto &[indices, d] : blocks_derivatives[blk]) - { - auto [eq, var, lag] = indices; - assert(lag >= -1 && lag <= 1); - if (eq >= block_recursive_size && var >= block_recursive_size) - { - i_output << " g1_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' - << eq+1-block_recursive_size << ';' << endl; - j_output << " g1_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' - << var+1-block_recursive_size+block_mfs_size*(lag+1) << ';' << endl; - v_output << " g1_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; - d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); - v_output << ';' << endl; - line_counter++; - } - } - assert(line_counter == nze_deterministic+ARRAY_SUBSCRIPT_OFFSET(output_type)); - output << i_output.str() << j_output.str() << v_output.str(); - } - if (isCOutput(output_type)) - output << " }" << endl; - else - output << " end" << endl; -} - int DynamicModel::nzeDeterministicJacobianForBlock(int blk) const { @@ -527,7 +295,7 @@ DynamicModel::writeDynamicPerBlockMFiles(const string &basename) const output << " end" << endl << endl; - writeDynamicPerBlockHelper(blk, output, ExprNodeOutputType::matlabDynamicModel, temporary_terms, + writeDynamicPerBlockHelper<ExprNodeOutputType::matlabDynamicModel>(blk, output, temporary_terms, nze_stochastic, nze_deterministic, nze_exo, nze_exo_det, nze_other_endo); output << endl @@ -611,7 +379,7 @@ DynamicModel::writeDynamicPerBlockCFiles(const string &basename) const output << "void dynamic_" << blk+1 << "(double *restrict y, const double *restrict x, int nb_row_x, const double *restrict params, const double *restrict steady_state, double *restrict T, int it_, bool stochastic_mode, double *restrict residual, double *restrict g1_i, double *restrict g1_j, double *restrict g1_v, double *restrict g1_x_i, double *restrict g1_x_j, double *restrict g1_x_v, double *restrict g1_xd_i, double *restrict g1_xd_j, double *restrict g1_xd_v, double *restrict g1_o_i, double *restrict g1_o_j, double *restrict g1_o_v)" << endl; output << '{' << endl; - writeDynamicPerBlockHelper(blk, output, ExprNodeOutputType::CDynamicModel, temporary_terms, + writeDynamicPerBlockHelper<ExprNodeOutputType::CDynamicModel>(blk, output, temporary_terms, nze_stochastic, nze_deterministic, nze_exo, nze_exo_det, nze_other_endo); output << '}' << endl @@ -5369,18 +5137,18 @@ DynamicModel::isChecksumMatching(const string &basename) const // Write equation tags equation_tags.writeCheckSumInfo(buffer); - ExprNodeOutputType buffer_type = ExprNodeOutputType::CDynamicModel; + constexpr ExprNodeOutputType buffer_type{ExprNodeOutputType::CDynamicModel}; deriv_node_temp_terms_t tef_terms; temporary_terms_t temp_term_union; - writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_idxs, - buffer, buffer_type, tef_terms); + writeModelLocalVariableTemporaryTerms<buffer_type>(temp_term_union, temporary_terms_idxs, + buffer, tef_terms); - writeTemporaryTerms(temporary_terms_derivatives[0], - temp_term_union, temporary_terms_idxs, - buffer, buffer_type, tef_terms); + writeTemporaryTerms<buffer_type>(temporary_terms_derivatives[0], + temp_term_union, temporary_terms_idxs, + buffer, tef_terms); - writeModelEquations(buffer, buffer_type, temp_term_union); + writeModelEquations<buffer_type>(buffer, temp_term_union); size_t result = hash<string>{}(buffer.str()); diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index 15adc46bc8517d6e138406608bb299be5a7eee53..ce051ec493024cdead844c7d2f30e276a292265f 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -132,7 +132,8 @@ private: block-decomposed model */ int nzeDeterministicJacobianForBlock(int blk) const; //! Helper for writing the per-block dynamic files of block decomposed models - void writeDynamicPerBlockHelper(int blk, ostream &output, ExprNodeOutputType output_type, temporary_terms_t &temporary_terms, int nze_stochastic, int nze_deterministic, int nze_exo, int nze_exo_det, int nze_other_endo) const; + template<ExprNodeOutputType output_type> + void writeDynamicPerBlockHelper(int blk, ostream &output, temporary_terms_t &temporary_terms, int nze_stochastic, int nze_deterministic, int nze_exo, int nze_exo_det, int nze_other_endo) const; //! Writes the per-block dynamic files of block decomposed model (MATLAB version) void writeDynamicPerBlockMFiles(const string &basename) const; //! Writes the per-block dynamic files of block decomposed model (C version) @@ -659,6 +660,241 @@ public: set<int> findPacExpectationEquationNumbers() const; }; +template<ExprNodeOutputType output_type> +void +DynamicModel::writeDynamicPerBlockHelper(int blk, ostream &output, temporary_terms_t &temporary_terms, + int nze_stochastic, int nze_deterministic, int nze_exo, + int nze_exo_det, int nze_other_endo) const +{ + BlockSimulationType simulation_type { blocks[blk].simulation_type }; + int block_size { blocks[blk].size }; + int block_mfs_size { blocks[blk].mfs_size }; + int block_recursive_size { blocks[blk].getRecursiveSize() }; + + deriv_node_temp_terms_t tef_terms; + + auto write_eq_tt = [&](int eq) + { + for (auto it : blocks_temporary_terms[blk][eq]) + { + if (dynamic_cast<AbstractExternalFunctionNode *>(it)) + it->writeExternalFunctionOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs, tef_terms); + + output << " "; + it->writeOutput(output, output_type, blocks_temporary_terms[blk][eq], blocks_temporary_terms_idxs, tef_terms); + output << '='; + it->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs, tef_terms); + temporary_terms.insert(it); + output << ';' << endl; + } + }; + + // The equations + for (int eq {0}; eq < block_size; eq++) + { + write_eq_tt(eq); + + EquationType equ_type { getBlockEquationType(blk, eq) }; + BinaryOpNode *e { getBlockEquationExpr(blk, eq) }; + expr_t lhs { e->arg1 }, rhs { e->arg2 }; + switch (simulation_type) + { + case BlockSimulationType::evaluateBackward: + case BlockSimulationType::evaluateForward: + evaluation: + if (equ_type == EquationType::evaluateRenormalized) + { + e = getBlockEquationRenormalizedExpr(blk, eq); + lhs = e->arg1; + rhs = e->arg2; + } + else if (equ_type != EquationType::evaluate) + { + cerr << "Type mismatch for equation " << getBlockEquationID(blk, eq)+1 << endl; + exit(EXIT_FAILURE); + } + output << " "; + lhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); + output << '='; + rhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); + output << ';' << endl; + break; + case BlockSimulationType::solveBackwardSimple: + case BlockSimulationType::solveForwardSimple: + case BlockSimulationType::solveBackwardComplete: + case BlockSimulationType::solveForwardComplete: + case BlockSimulationType::solveTwoBoundariesComplete: + case BlockSimulationType::solveTwoBoundariesSimple: + if (eq < block_recursive_size) + goto evaluation; + output << " residual" << LEFT_ARRAY_SUBSCRIPT(output_type) + << eq-block_recursive_size+ARRAY_SUBSCRIPT_OFFSET(output_type) + << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=("; + goto end; + default: + end: + lhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); + output << ")-("; + rhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); + output << ");" << endl; + } + } + + // The Jacobian if we have to solve the block + + // Write temporary terms for derivatives + write_eq_tt(blocks[blk].size); + + if constexpr(isCOutput(output_type)) + output << " if (stochastic_mode) {" << endl; + else + output << " if stochastic_mode" << endl; + + ostringstream i_output, j_output, v_output; + int line_counter { ARRAY_SUBSCRIPT_OFFSET(output_type) }; + for (const auto &[indices, d] : blocks_derivatives[blk]) + { + const auto &[eq, var, lag] {indices}; + int jacob_col { blocks_jacob_cols_endo[blk].at({ var, lag }) }; + i_output << " g1_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << eq+1 << ';' << endl; + j_output << " g1_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << jacob_col+1 << ';' << endl; + v_output << " g1_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; + d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); + v_output << ';' << endl; + line_counter++; + } + assert(line_counter == nze_stochastic+ARRAY_SUBSCRIPT_OFFSET(output_type)); + output << i_output.str() << j_output.str() << v_output.str(); + + i_output.str(""); + j_output.str(""); + v_output.str(""); + line_counter = ARRAY_SUBSCRIPT_OFFSET(output_type); + for (const auto &[indices, d] : blocks_derivatives_exo[blk]) + { + const auto &[eq, var, lag] {indices}; + int jacob_col { blocks_jacob_cols_exo[blk].at({ var, lag }) }; + i_output << " g1_x_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << eq+1 << ';' << endl; + j_output << " g1_x_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << jacob_col+1 << ';' << endl; + v_output << " g1_x_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; + d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); + v_output << ';' << endl; + line_counter++; + } + assert(line_counter == nze_exo+ARRAY_SUBSCRIPT_OFFSET(output_type)); + output << i_output.str() << j_output.str() << v_output.str(); + + i_output.str(""); + j_output.str(""); + v_output.str(""); + line_counter = ARRAY_SUBSCRIPT_OFFSET(output_type); + for (const auto &[indices, d] : blocks_derivatives_exo_det[blk]) + { + const auto &[eq, var, lag] {indices}; + int jacob_col { blocks_jacob_cols_exo_det[blk].at({ var, lag }) }; + i_output << " g1_xd_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << eq+1 << ';' << endl; + j_output << " g1_xd_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << jacob_col+1 << ';' << endl; + v_output << " g1_xd_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; + d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); + v_output << ';' << endl; + line_counter++; + } + assert(line_counter == nze_exo_det+ARRAY_SUBSCRIPT_OFFSET(output_type)); + output << i_output.str() << j_output.str() << v_output.str(); + + i_output.str(""); + j_output.str(""); + v_output.str(""); + line_counter = ARRAY_SUBSCRIPT_OFFSET(output_type); + for (const auto &[indices, d] : blocks_derivatives_other_endo[blk]) + { + const auto &[eq, var, lag] {indices}; + int jacob_col { blocks_jacob_cols_other_endo[blk].at({ var, lag }) }; + i_output << " g1_o_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << eq+1 << ';' << endl; + j_output << " g1_o_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << jacob_col+1 << ';' << endl; + v_output << " g1_o_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; + d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); + v_output << ';' << endl; + line_counter++; + } + assert(line_counter == nze_other_endo+ARRAY_SUBSCRIPT_OFFSET(output_type)); + output << i_output.str() << j_output.str() << v_output.str(); + + // Deterministic mode + if (simulation_type != BlockSimulationType::evaluateForward + && simulation_type != BlockSimulationType::evaluateBackward) + { + if constexpr(isCOutput(output_type)) + output << " } else {" << endl; + else + output << " else" << endl; + i_output.str(""); + j_output.str(""); + v_output.str(""); + line_counter = ARRAY_SUBSCRIPT_OFFSET(output_type); + if (simulation_type == BlockSimulationType::solveBackwardSimple + || simulation_type == BlockSimulationType::solveForwardSimple + || simulation_type == BlockSimulationType::solveBackwardComplete + || simulation_type == BlockSimulationType::solveForwardComplete) + for (const auto &[indices, d] : blocks_derivatives[blk]) + { + const auto &[eq, var, lag] {indices}; + if (lag == 0 && eq >= block_recursive_size && var >= block_recursive_size) + { + i_output << " g1_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' + << eq+1-block_recursive_size << ';' << endl; + j_output << " g1_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' + << var+1-block_recursive_size << ';' << endl; + v_output << " g1_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; + d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); + v_output << ';' << endl; + line_counter++; + } + } + else // solveTwoBoundariesSimple || solveTwoBoundariesComplete + for (const auto &[indices, d] : blocks_derivatives[blk]) + { + const auto &[eq, var, lag] {indices}; + assert(lag >= -1 && lag <= 1); + if (eq >= block_recursive_size && var >= block_recursive_size) + { + i_output << " g1_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' + << eq+1-block_recursive_size << ';' << endl; + j_output << " g1_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' + << var+1-block_recursive_size+block_mfs_size*(lag+1) << ';' << endl; + v_output << " g1_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; + d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); + v_output << ';' << endl; + line_counter++; + } + } + assert(line_counter == nze_deterministic+ARRAY_SUBSCRIPT_OFFSET(output_type)); + output << i_output.str() << j_output.str() << v_output.str(); + } + if constexpr(isCOutput(output_type)) + output << " }" << endl; + else + output << " end" << endl; +} + template<bool julia> void DynamicModel::writeParamsDerivativesFile(const string &basename) const diff --git a/src/ModelTree.cc b/src/ModelTree.cc index 43483486c9403301d213f62e620abb4495b603e7..f96efb26429b8c67eaa27094e5fc4be17fc90a03 100644 --- a/src/ModelTree.cc +++ b/src/ModelTree.cc @@ -1019,61 +1019,6 @@ ModelTree::additionalBlockTemporaryTerms([[maybe_unused]] int blk, { } -void -ModelTree::writeModelLocalVariableTemporaryTerms(temporary_terms_t &temp_term_union, - const temporary_terms_idxs_t &tt_idxs, - ostream &output, ExprNodeOutputType output_type, - deriv_node_temp_terms_t &tef_terms) const -{ - temporary_terms_t tto; - for (auto [mlv, value] : temporary_terms_mlv) - tto.insert(mlv); - - for (auto [mlv, value] : temporary_terms_mlv) - { - value->writeExternalFunctionOutput(output, output_type, temp_term_union, tt_idxs, tef_terms); - - if (isJuliaOutput(output_type)) - output << " const "; - - mlv->writeOutput(output, output_type, tto, tt_idxs, tef_terms); - output << " = "; - value->writeOutput(output, output_type, temp_term_union, tt_idxs, tef_terms); - - if (isCOutput(output_type) || isMatlabOutput(output_type)) - output << ";"; - output << endl; - - /* We put in temp_term_union the VariableNode corresponding to the MLV, - not its definition, so that when equations use the MLV, - T(XXX) is printed instead of the MLV name */ - temp_term_union.insert(mlv); - } -} - -void -ModelTree::writeTemporaryTerms(const temporary_terms_t &tt, - temporary_terms_t &temp_term_union, - const temporary_terms_idxs_t &tt_idxs, - ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const -{ - for (auto it : tt) - { - if (dynamic_cast<AbstractExternalFunctionNode *>(it)) - it->writeExternalFunctionOutput(output, output_type, temp_term_union, tt_idxs, tef_terms); - - it->writeOutput(output, output_type, tt, tt_idxs, tef_terms); - output << " = "; - it->writeOutput(output, output_type, temp_term_union, tt_idxs, tef_terms); - - if (isCOutput(output_type) || isMatlabOutput(output_type)) - output << ";"; - output << endl; - - temp_term_union.insert(it); - } -} - void ModelTree::writeJsonTemporaryTerms(const temporary_terms_t &tt, temporary_terms_t &temp_term_union, @@ -1311,62 +1256,6 @@ ModelTree::writeJsonModelLocalVariables(ostream &output, bool write_tef_terms, d output << "]"; } -void -ModelTree::writeModelEquations(ostream &output, ExprNodeOutputType output_type, - const temporary_terms_t &temporary_terms) const -{ - for (int eq = 0; eq < static_cast<int>(equations.size()); eq++) - { - BinaryOpNode *eq_node = equations[eq]; - expr_t lhs = eq_node->arg1, rhs = eq_node->arg2; - - // Test if the right hand side of the equation is empty. - double vrhs = 1.0; - try - { - vrhs = rhs->eval({}); - } - catch (ExprNode::EvalException &e) - { - } - - if (vrhs != 0) // The right hand side of the equation is not empty ==> residual=lhs-rhs; - if (isJuliaOutput(output_type)) - { - output << " residual" << LEFT_ARRAY_SUBSCRIPT(output_type) - << eq + ARRAY_SUBSCRIPT_OFFSET(output_type) - << RIGHT_ARRAY_SUBSCRIPT(output_type) - << " = ("; - lhs->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); - output << ") - ("; - rhs->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); - output << ")" << endl; - } - else - { - output << "lhs = "; - lhs->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); - output << ";" << endl - << "rhs = "; - rhs->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); - output << ";" << endl - << "residual" << LEFT_ARRAY_SUBSCRIPT(output_type) - << eq + ARRAY_SUBSCRIPT_OFFSET(output_type) - << RIGHT_ARRAY_SUBSCRIPT(output_type) - << " = lhs - rhs;" << endl; - } - else // The right hand side of the equation is empty ==> residual=lhs; - { - output << "residual" << LEFT_ARRAY_SUBSCRIPT(output_type) - << eq + ARRAY_SUBSCRIPT_OFFSET(output_type) - << RIGHT_ARRAY_SUBSCRIPT(output_type) - << " = "; - lhs->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); - output << ";" << endl; - } - } -} - void ModelTree::writeBytecodeModelEquations(BytecodeWriter &code_file, ExprNodeBytecodeOutputType output_type, const temporary_terms_t &temporary_terms_union, const temporary_terms_idxs_t &temporary_terms_idxs, const deriv_node_temp_terms_t &tef_terms) const { diff --git a/src/ModelTree.hh b/src/ModelTree.hh index 9ca733c4048ce5013dfcddd2b96f204b430cae35..7061eb6d5f49a8745f41df9d9a4c532d047e4f07 100644 --- a/src/ModelTree.hh +++ b/src/ModelTree.hh @@ -238,7 +238,8 @@ protected: //! Computes temporary terms for the file containing parameters derivatives void computeParamsDerivativesTemporaryTerms(); //! Writes temporary terms - void writeTemporaryTerms(const temporary_terms_t &tt, temporary_terms_t &temp_term_union, const temporary_terms_idxs_t &tt_idxs, ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const; + template<ExprNodeOutputType output_type> + void writeTemporaryTerms(const temporary_terms_t &tt, temporary_terms_t &temp_term_union, const temporary_terms_idxs_t &tt_idxs, ostream &output, deriv_node_temp_terms_t &tef_terms) const; void writeJsonTemporaryTerms(const temporary_terms_t &tt, temporary_terms_t &temp_term_union, ostream &output, deriv_node_temp_terms_t &tef_terms, const string &concat) const; //! Writes temporary terms in bytecode void writeBytecodeTemporaryTerms(BytecodeWriter &code_file, ExprNodeBytecodeOutputType output_type, temporary_terms_t &temporary_terms_union, const temporary_terms_idxs_t &temporary_terms_idxs, deriv_node_temp_terms_t &tef_terms) const; @@ -248,13 +249,14 @@ protected: void fixNestedParenthesis(ostringstream &output, map<string, string> &tmp_paren_vars, bool &message_printed) const; //! Tests if string contains more than 32 nested parens, Issue #1201 bool testNestedParenthesis(const string &str) const; + + template<ExprNodeOutputType output_type> void writeModelLocalVariableTemporaryTerms(temporary_terms_t &temp_term_union, const temporary_terms_idxs_t &tt_idxs, - ostream &output, ExprNodeOutputType output_type, - deriv_node_temp_terms_t &tef_terms) const; + ostream &output, deriv_node_temp_terms_t &tef_terms) const; //! Writes model equations - void writeModelEquations(ostream &output, ExprNodeOutputType output_type, - const temporary_terms_t &temporary_terms) const; + template<ExprNodeOutputType output_type> + void writeModelEquations(ostream &output, const temporary_terms_t &temporary_terms) const; // Returns outputs for derivatives and temporary terms at each derivation order template<ExprNodeOutputType output_type> @@ -518,6 +520,118 @@ public: } }; +template<ExprNodeOutputType output_type> +void +ModelTree::writeTemporaryTerms(const temporary_terms_t &tt, + temporary_terms_t &temp_term_union, + const temporary_terms_idxs_t &tt_idxs, + ostream &output, deriv_node_temp_terms_t &tef_terms) const +{ + for (auto it : tt) + { + if (dynamic_cast<AbstractExternalFunctionNode *>(it)) + it->writeExternalFunctionOutput(output, output_type, temp_term_union, tt_idxs, tef_terms); + + it->writeOutput(output, output_type, tt, tt_idxs, tef_terms); + output << " = "; + it->writeOutput(output, output_type, temp_term_union, tt_idxs, tef_terms); + + if constexpr(isCOutput(output_type) || isMatlabOutput(output_type)) + output << ";"; + output << endl; + + temp_term_union.insert(it); + } +} + +template<ExprNodeOutputType output_type> +void +ModelTree::writeModelLocalVariableTemporaryTerms(temporary_terms_t &temp_term_union, + const temporary_terms_idxs_t &tt_idxs, + ostream &output, deriv_node_temp_terms_t &tef_terms) const +{ + temporary_terms_t tto; + for (const auto &[mlv, value] : temporary_terms_mlv) + tto.insert(mlv); + + for (const auto &[mlv, value] : temporary_terms_mlv) + { + value->writeExternalFunctionOutput(output, output_type, temp_term_union, tt_idxs, tef_terms); + + if constexpr(isJuliaOutput(output_type)) + output << " const "; + + mlv->writeOutput(output, output_type, tto, tt_idxs, tef_terms); + output << " = "; + value->writeOutput(output, output_type, temp_term_union, tt_idxs, tef_terms); + + if constexpr(isCOutput(output_type) || isMatlabOutput(output_type)) + output << ";"; + output << endl; + + /* We put in temp_term_union the VariableNode corresponding to the MLV, + not its definition, so that when equations use the MLV, + T(XXX) is printed instead of the MLV name */ + temp_term_union.insert(mlv); + } +} + +template<ExprNodeOutputType output_type> +void +ModelTree::writeModelEquations(ostream &output, const temporary_terms_t &temporary_terms) const +{ + for (int eq {0}; eq < static_cast<int>(equations.size()); eq++) + { + BinaryOpNode *eq_node { equations[eq] }; + expr_t lhs { eq_node->arg1 }, rhs { eq_node->arg2 }; + + // Test if the right hand side of the equation is empty. + double vrhs {1.0}; + try + { + vrhs = rhs->eval({}); + } + catch (ExprNode::EvalException &e) + { + } + + if (vrhs != 0) // The right hand side of the equation is not empty ==> residual=lhs-rhs; + if constexpr(isJuliaOutput(output_type)) + { + output << " residual" << LEFT_ARRAY_SUBSCRIPT(output_type) + << eq + ARRAY_SUBSCRIPT_OFFSET(output_type) + << RIGHT_ARRAY_SUBSCRIPT(output_type) + << " = ("; + lhs->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); + output << ") - ("; + rhs->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); + output << ")" << endl; + } + else + { + output << "lhs = "; + lhs->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); + output << ";" << endl + << "rhs = "; + rhs->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); + output << ";" << endl + << "residual" << LEFT_ARRAY_SUBSCRIPT(output_type) + << eq + ARRAY_SUBSCRIPT_OFFSET(output_type) + << RIGHT_ARRAY_SUBSCRIPT(output_type) + << " = lhs - rhs;" << endl; + } + else // The right hand side of the equation is empty ==> residual=lhs; + { + output << "residual" << LEFT_ARRAY_SUBSCRIPT(output_type) + << eq + ARRAY_SUBSCRIPT_OFFSET(output_type) + << RIGHT_ARRAY_SUBSCRIPT(output_type) + << " = "; + lhs->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs); + output << ";" << endl; + } + } +} + template<ExprNodeOutputType output_type> pair<vector<ostringstream>, vector<ostringstream>> ModelTree::writeModelFileHelper() const @@ -528,23 +642,19 @@ ModelTree::writeModelFileHelper() const deriv_node_temp_terms_t tef_terms; temporary_terms_t temp_term_union; - writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_idxs, - tt_output[0], output_type, tef_terms); + writeModelLocalVariableTemporaryTerms<output_type>(temp_term_union, temporary_terms_idxs, + tt_output[0], tef_terms); - writeTemporaryTerms(temporary_terms_derivatives[0], - temp_term_union, - temporary_terms_idxs, - tt_output[0], output_type, tef_terms); + writeTemporaryTerms<output_type>(temporary_terms_derivatives[0], temp_term_union, + temporary_terms_idxs, tt_output[0], tef_terms); - writeModelEquations(d_output[0], output_type, temp_term_union); + writeModelEquations<output_type>(d_output[0], temp_term_union); // Writing Jacobian if (!derivatives[1].empty()) { - writeTemporaryTerms(temporary_terms_derivatives[1], - temp_term_union, - temporary_terms_idxs, - tt_output[1], output_type, tef_terms); + writeTemporaryTerms<output_type>(temporary_terms_derivatives[1], temp_term_union, + temporary_terms_idxs, tt_output[1], tef_terms); for (const auto &[indices, d1] : derivatives[1]) { @@ -566,10 +676,8 @@ ModelTree::writeModelFileHelper() const for (size_t i = 2; i < derivatives.size(); i++) if (!derivatives[i].empty()) { - writeTemporaryTerms(temporary_terms_derivatives[i], - temp_term_union, - temporary_terms_idxs, - tt_output[i], output_type, tef_terms); + writeTemporaryTerms<output_type>(temporary_terms_derivatives[i], temp_term_union, + temporary_terms_idxs, tt_output[i], tef_terms); /* When creating the sparse matrix (in MATLAB or C mode), since storage is in column-major order, output the first column, then the second, @@ -680,9 +788,12 @@ ModelTree::writeParamsDerivativesFileHelper() const temporary_terms_t temp_term_union; deriv_node_temp_terms_t tef_terms; - writeModelLocalVariableTemporaryTerms(temp_term_union, params_derivs_temporary_terms_idxs, tt_output, output_type, tef_terms); + writeModelLocalVariableTemporaryTerms<output_type>(temp_term_union, + params_derivs_temporary_terms_idxs, + tt_output, tef_terms); for (const auto &[order, tts] : params_derivs_temporary_terms) - writeTemporaryTerms(tts, temp_term_union, params_derivs_temporary_terms_idxs, tt_output, output_type, tef_terms); + writeTemporaryTerms<output_type>(tts, temp_term_union, params_derivs_temporary_terms_idxs, + tt_output, tef_terms); for (const auto &[indices, d1] : params_derivatives.find({ 0, 1 })->second) { diff --git a/src/StaticModel.cc b/src/StaticModel.cc index 0a276ad200a11cdf3cd254c13576b849d6f2e1fd..6dc463b7b1e20b6706d09eb07d6893ba66b605e2 100644 --- a/src/StaticModel.cc +++ b/src/StaticModel.cc @@ -114,107 +114,6 @@ StaticModel::writeBytecodeChainRuleDerivative(BytecodeWriter &code_file, int blk code_file << FLDZ_{}; } -void -StaticModel::writeStaticPerBlockHelper(int blk, ostream &output, ExprNodeOutputType output_type, temporary_terms_t &temporary_terms) const -{ - BlockSimulationType simulation_type = blocks[blk].simulation_type; - int block_recursive_size = blocks[blk].getRecursiveSize(); - - // The equations - deriv_node_temp_terms_t tef_terms; - - auto write_eq_tt = [&](int eq) - { - for (auto it : blocks_temporary_terms[blk][eq]) - { - if (dynamic_cast<AbstractExternalFunctionNode *>(it)) - it->writeExternalFunctionOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs, tef_terms); - - output << " "; - it->writeOutput(output, output_type, blocks_temporary_terms[blk][eq], blocks_temporary_terms_idxs, tef_terms); - output << '='; - it->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs, tef_terms); - temporary_terms.insert(it); - output << ';' << endl; - } - }; - - for (int eq = 0; eq < blocks[blk].size; eq++) - { - write_eq_tt(eq); - - EquationType equ_type = getBlockEquationType(blk, eq); - BinaryOpNode *e = getBlockEquationExpr(blk, eq); - expr_t lhs = e->arg1, rhs = e->arg2; - switch (simulation_type) - { - case BlockSimulationType::evaluateBackward: - case BlockSimulationType::evaluateForward: - evaluation: - if (equ_type == EquationType::evaluateRenormalized) - { - e = getBlockEquationRenormalizedExpr(blk, eq); - lhs = e->arg1; - rhs = e->arg2; - } - else if (equ_type != EquationType::evaluate) - { - cerr << "Type mismatch for equation " << getBlockEquationID(blk, eq)+1 << endl; - exit(EXIT_FAILURE); - } - output << " "; - lhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); - output << '='; - rhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); - output << ';' << endl; - break; - case BlockSimulationType::solveBackwardSimple: - case BlockSimulationType::solveForwardSimple: - case BlockSimulationType::solveBackwardComplete: - case BlockSimulationType::solveForwardComplete: - if (eq < block_recursive_size) - goto evaluation; - output << " residual" << LEFT_ARRAY_SUBSCRIPT(output_type) - << eq-block_recursive_size+ARRAY_SUBSCRIPT_OFFSET(output_type) - << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=("; - lhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); - output << ")-("; - rhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); - output << ");" << endl; - break; - default: - cerr << "Incorrect type for block " << blk+1 << endl; - exit(EXIT_FAILURE); - } - } - // The Jacobian if we have to solve the block - if (simulation_type != BlockSimulationType::evaluateBackward - && simulation_type != BlockSimulationType::evaluateForward) - { - // Write temporary terms for derivatives - write_eq_tt(blocks[blk].size); - - ostringstream i_output, j_output, v_output; - for (int line_counter{ARRAY_SUBSCRIPT_OFFSET(output_type)}; - const auto &[indices, d] : blocks_derivatives[blk]) - { - auto [eq, var, ignore] = indices; - i_output << " g1_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << eq+1-block_recursive_size - << ';' << endl; - j_output << " g1_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << var+1-block_recursive_size - << ';' << endl; - v_output << " g1_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter - << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; - d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); - v_output << ';' << endl; - line_counter++; - } - output << i_output.str() << j_output.str() << v_output.str(); - } -} - void StaticModel::writeStaticPerBlockMFiles(const string &basename) const { @@ -258,7 +157,7 @@ StaticModel::writeStaticPerBlockMFiles(const string &basename) const << " g1_v=zeros(" << blocks_derivatives[blk].size() << ",1);" << endl << endl; - writeStaticPerBlockHelper(blk, output, ExprNodeOutputType::matlabStaticModel, temporary_terms); + writeStaticPerBlockHelper<ExprNodeOutputType::matlabStaticModel>(blk, output, temporary_terms); if (simulation_type != BlockSimulationType::evaluateBackward && simulation_type != BlockSimulationType::evaluateForward) @@ -306,7 +205,7 @@ StaticModel::writeStaticPerBlockCFiles(const string &basename) const output << "void static_" << blk+1 << "(double *restrict y, const double *restrict x, const double *restrict params, double *restrict T, double *restrict residual, double *restrict g1_i, double *restrict g1_j, double *restrict g1_v)" << endl; output << '{' << endl; - writeStaticPerBlockHelper(blk, output, ExprNodeOutputType::CStaticModel, temporary_terms); + writeStaticPerBlockHelper<ExprNodeOutputType::CStaticModel>(blk, output, temporary_terms); output << '}' << endl << endl; diff --git a/src/StaticModel.hh b/src/StaticModel.hh index d781d0a35d532e2987681ead6cc9edbc751dcdfe..fa412814b5872f6a0c6982ffe00927721ccb3ca3 100644 --- a/src/StaticModel.hh +++ b/src/StaticModel.hh @@ -50,7 +50,8 @@ private: void writeStaticBlockCFile(const string &basename) const; //! Helper for writing a per-block static file of block decomposed model - void writeStaticPerBlockHelper(int blk, ostream &output, ExprNodeOutputType output_type, temporary_terms_t &temporary_terms) const; + template<ExprNodeOutputType output_type> + void writeStaticPerBlockHelper(int blk, ostream &output, temporary_terms_t &temporary_terms) const; //! Writes the per-block static files of block decomposed model (MATLAB version) void writeStaticPerBlockMFiles(const string &basename) const; @@ -172,6 +173,108 @@ public: void addAllParamDerivId(set<int> &deriv_id_set) override; }; +template<ExprNodeOutputType output_type> +void +StaticModel::writeStaticPerBlockHelper(int blk, ostream &output, temporary_terms_t &temporary_terms) const +{ + BlockSimulationType simulation_type { blocks[blk].simulation_type }; + int block_recursive_size { blocks[blk].getRecursiveSize() }; + + // The equations + deriv_node_temp_terms_t tef_terms; + + auto write_eq_tt = [&](int eq) + { + for (auto it : blocks_temporary_terms[blk][eq]) + { + if (dynamic_cast<AbstractExternalFunctionNode *>(it)) + it->writeExternalFunctionOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs, tef_terms); + + output << " "; + it->writeOutput(output, output_type, blocks_temporary_terms[blk][eq], blocks_temporary_terms_idxs, tef_terms); + output << '='; + it->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs, tef_terms); + temporary_terms.insert(it); + output << ';' << endl; + } + }; + + for (int eq {0}; eq < blocks[blk].size; eq++) + { + write_eq_tt(eq); + + EquationType equ_type { getBlockEquationType(blk, eq) }; + BinaryOpNode *e { getBlockEquationExpr(blk, eq) }; + expr_t lhs { e->arg1 }, rhs { e->arg2 }; + switch (simulation_type) + { + case BlockSimulationType::evaluateBackward: + case BlockSimulationType::evaluateForward: + evaluation: + if (equ_type == EquationType::evaluateRenormalized) + { + e = getBlockEquationRenormalizedExpr(blk, eq); + lhs = e->arg1; + rhs = e->arg2; + } + else if (equ_type != EquationType::evaluate) + { + cerr << "Type mismatch for equation " << getBlockEquationID(blk, eq)+1 << endl; + exit(EXIT_FAILURE); + } + output << " "; + lhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); + output << '='; + rhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); + output << ';' << endl; + break; + case BlockSimulationType::solveBackwardSimple: + case BlockSimulationType::solveForwardSimple: + case BlockSimulationType::solveBackwardComplete: + case BlockSimulationType::solveForwardComplete: + if (eq < block_recursive_size) + goto evaluation; + output << " residual" << LEFT_ARRAY_SUBSCRIPT(output_type) + << eq-block_recursive_size+ARRAY_SUBSCRIPT_OFFSET(output_type) + << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=("; + lhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); + output << ")-("; + rhs->writeOutput(output, output_type, temporary_terms, blocks_temporary_terms_idxs); + output << ");" << endl; + break; + default: + cerr << "Incorrect type for block " << blk+1 << endl; + exit(EXIT_FAILURE); + } + } + // The Jacobian if we have to solve the block + if (simulation_type != BlockSimulationType::evaluateBackward + && simulation_type != BlockSimulationType::evaluateForward) + { + // Write temporary terms for derivatives + write_eq_tt(blocks[blk].size); + + ostringstream i_output, j_output, v_output; + for (int line_counter { ARRAY_SUBSCRIPT_OFFSET(output_type) }; + const auto &[indices, d] : blocks_derivatives[blk]) + { + const auto &[eq, var, ignore] {indices}; + i_output << " g1_i" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << eq+1-block_recursive_size + << ';' << endl; + j_output << " g1_j" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '=' << var+1-block_recursive_size + << ';' << endl; + v_output << " g1_v" << LEFT_ARRAY_SUBSCRIPT(output_type) << line_counter + << RIGHT_ARRAY_SUBSCRIPT(output_type) << '='; + d->writeOutput(v_output, output_type, temporary_terms, blocks_temporary_terms_idxs); + v_output << ';' << endl; + line_counter++; + } + output << i_output.str() << j_output.str() << v_output.str(); + } +} + template<bool julia> void StaticModel::writeParamsDerivativesFile(const string &basename) const