Commit 6e0ef026 authored by MichelJuillard's avatar MichelJuillard
Browse files

write C++ version of model functions without temporary terms

parent 71824b3d
......@@ -2089,8 +2089,7 @@ DynamicModel::writeDynamicModel(ostream &DynamicOutput, bool use_dll) const
ExprNodeOutputType output_type = (use_dll ? oCDynamicModel : oMatlabDynamicModel);
deriv_node_temp_terms_t tef_terms;
writeModelLocalVariables(model_output, output_type, tef_terms);
writeTemporaryTerms(temporary_terms, model_output, output_type, tef_terms);
writeModelEquations(model_output, output_type);
......@@ -4419,3 +4418,356 @@ DynamicModel::dynamicOnlyEquationsNbr() const
return eqs.size();
}
void
DynamicModel::writeFirstDerivativesCC(const string &basename, bool cuda) const
{
string filename = basename + "_first_derivatives.cc";
ofstream mDynamicModelFile, mDynamicMexFile;
mDynamicModelFile.open(filename.c_str(), ios::out | ios::binary);
if (!mDynamicModelFile.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
exit(EXIT_FAILURE);
}
mDynamicModelFile << "/*" << endl
<< " * " << filename << " : Computes first order derivatives of the model for Dynare" << endl
<< " *" << endl
<< " * Warning : this file is generated automatically by Dynare" << endl
<< " * from model " << basename << "(.mod)" << endl
<< " */" << endl
<< "#include <math.h>" << endl;
mDynamicModelFile << "#include <stdlib.h>" << endl;
mDynamicModelFile << "#define max(a, b) (((a) > (b)) ? (a) : (b))" << endl
<< "#define min(a, b) (((a) > (b)) ? (b) : (a))" << endl;
// Write function definition if oPowerDeriv is used
writePowerDerivCHeader(mDynamicModelFile);
mDynamicModelFile << "void FirstDerivatives(const double *y, double *x, int nb_row_x, double *params, double *steady_state, int it_, double *residual, double *g1, double *v2, double *v3)" << endl
<< "{" << endl;
// this is always empty here, but needed by d1->writeOutput
deriv_node_temp_terms_t tef_terms;
// Writing Jacobian
for (first_derivatives_t::const_iterator it = first_derivatives.begin();
it != first_derivatives.end(); it++)
{
int eq = it->first.first;
int var = it->first.second;
expr_t d1 = it->second;
jacobianHelper(mDynamicModelFile, eq, getDynJacobianCol(var), oCDynamicModel);
mDynamicModelFile << "=";
// oCstaticModel makes reference to the static variables
d1->writeOutput(mDynamicModelFile, oCStaticModel, temporary_terms, tef_terms);
mDynamicModelFile << ";" << endl;
}
mDynamicModelFile << "}" << endl;
writePowerDeriv(mDynamicModelFile, true);
mDynamicModelFile.close();
}
// using compressed sparse row format (CSR)
void
DynamicModel::writeSecondDerivativesCC_csr(const string &basename, bool cuda) const
{
string filename = basename + "_second_derivatives.cc";
ofstream mDynamicModelFile, mDynamicMexFile;
mDynamicModelFile.open(filename.c_str(), ios::out | ios::binary);
if (!mDynamicModelFile.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
exit(EXIT_FAILURE);
}
mDynamicModelFile << "/*" << endl
<< " * " << filename << " : Computes second order derivatives of the model for Dynare" << endl
<< " *" << endl
<< " * Warning : this file is generated automatically by Dynare" << endl
<< " * from model " << basename << "(.mod)" << endl
<< " */" << endl
<< "#include <math.h>" << endl;
mDynamicModelFile << "#include <stdlib.h>" << endl;
mDynamicModelFile << "#define max(a, b) (((a) > (b)) ? (a) : (b))" << endl
<< "#define min(a, b) (((a) > (b)) ? (b) : (a))" << endl;
// write function definition if oPowerDeriv is used
writePowerDerivCHeader(mDynamicModelFile);
mDynamicModelFile << "void SecondDerivatives(const double *y, double *x, int nb_row_x, double *params, double *steady_state, int it_, double *residual, int *row_ptr, int *col_ptr, double *value)" << endl
<< "{" << endl;
// this is always empty here, but needed by d1->writeOutput
deriv_node_temp_terms_t tef_terms;
// Indexing derivatives in column order
vector<int> d_order(NNZDerivatives[1]);
OrderByLinearAddress obla(NNZDerivatives[1]);
int counter = 0;
int dynHessianColsNbr = dynJacobianColsNbr*dynJacobianColsNbr;
for (second_derivatives_t::const_iterator it = second_derivatives.begin();
it != second_derivatives.end(); it++)
{
int eq = it->first.first;
int var1 = it->first.second.first;
int var2 = it->first.second.second;
int id1 = getDynJacobianCol(var1);
int id2 = getDynJacobianCol(var2);
int col_nb = id1 * dynJacobianColsNbr + id2;
int col_nb_sym = id2 * dynJacobianColsNbr + id1;
obla.linear_address[counter] = col_nb + eq*dynHessianColsNbr;
d_order[counter] = counter;
++counter;
if (id1 != id2)
{
obla.linear_address[counter] = col_nb_sym + eq*dynHessianColsNbr;
d_order[counter] = counter;
++counter;
}
}
sort(d_order.begin(), d_order.end(), obla);
// Writing Hessian
vector<int> row_ptr(equations.size());
fill(row_ptr.begin(),row_ptr.end(),0.0);
int k = 0; // Keep the order of a 2nd derivative
for (second_derivatives_t::const_iterator it = second_derivatives.begin();
it != second_derivatives.end(); it++)
{
int eq = it->first.first;
int var1 = it->first.second.first;
int var2 = it->first.second.second;
expr_t d2 = it->second;
int id1 = getDynJacobianCol(var1);
int id2 = getDynJacobianCol(var2);
int col_nb = id1 * dynJacobianColsNbr + id2;
int col_nb_sym = id2 * dynJacobianColsNbr + id1;
row_ptr[eq]++;
mDynamicModelFile << "col_ptr[" << d_order[k] << "] "
<< "=" << col_nb << ";" << endl;
mDynamicModelFile << "value[" << d_order[k] << "] = ";
// oCstaticModel makes reference to the static variables
d2->writeOutput(mDynamicModelFile, oCStaticModel, temporary_terms, tef_terms);
mDynamicModelFile << ";" << endl;
k++;
// Treating symetric elements
if (id1 != id2)
{
row_ptr[eq]++;
mDynamicModelFile << "col_ptr[" << d_order[k] << "] "
<< "=" << col_nb_sym << ";" << endl;
mDynamicModelFile << "value[" << d_order[k] << "] = ";
// oCstaticModel makes reference to the static variables
d2->writeOutput(mDynamicModelFile, oCStaticModel, temporary_terms, tef_terms);
mDynamicModelFile << ";" << endl;
k++;
}
}
// row_ptr must point to the relative address of the first element of the row
int cumsum = 0;
mDynamicModelFile << "row_ptr = [ 0";
for (vector<int>::iterator it=row_ptr.begin(); it != row_ptr.end(); ++it)
{
cumsum += *it;
mDynamicModelFile << ", " << cumsum;
}
mDynamicModelFile << "];" << endl;
mDynamicModelFile << "}" << endl;
writePowerDeriv(mDynamicModelFile, true);
mDynamicModelFile.close();
}
void
DynamicModel::writeThirdDerivativesCC_csr(const string &basename, bool cuda) const
{
string filename = basename + "_third_derivatives.cc";
ofstream mDynamicModelFile, mDynamicMexFile;
mDynamicModelFile.open(filename.c_str(), ios::out | ios::binary);
if (!mDynamicModelFile.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
exit(EXIT_FAILURE);
}
mDynamicModelFile << "/*" << endl
<< " * " << filename << " : Computes third order derivatives of the model for Dynare" << endl
<< " *" << endl
<< " * Warning : this file is generated automatically by Dynare" << endl
<< " * from model " << basename << "(.mod)" << endl
<< " */" << endl
<< "#include <math.h>" << endl;
mDynamicModelFile << "#include <stdlib.h>" << endl;
mDynamicModelFile << "#define max(a, b) (((a) > (b)) ? (a) : (b))" << endl
<< "#define min(a, b) (((a) > (b)) ? (b) : (a))" << endl;
// Write function definition if oPowerDeriv is used
writePowerDerivCHeader(mDynamicModelFile);
mDynamicModelFile << "void ThirdDerivatives(const double *y, double *x, int nb_row_x, double *params, double *steady_state, int it_, double *residual, double *g1, double *v2, double *v3)" << endl
<< "{" << endl;
// this is always empty here, but needed by d1->writeOutput
deriv_node_temp_terms_t tef_terms;
// Indexing derivatives in column order
vector<int> d_order(NNZDerivatives[1]);
OrderByLinearAddress obla(NNZDerivatives[1]);
int counter = 0;
int dynHessianColsNbr = dynJacobianColsNbr*dynJacobianColsNbr;
for (third_derivatives_t::const_iterator it = third_derivatives.begin();
it != third_derivatives.end(); it++)
{
int eq = it->first.first;
int var1 = it->first.second.first;
int var2 = it->first.second.second.first;
int var3 = it->first.second.second.second;
expr_t d3 = it->second;
int id1 = getDynJacobianCol(var1);
int id2 = getDynJacobianCol(var2);
int id3 = getDynJacobianCol(var3);
// Reference column number for the g3 matrix
int ref_col = id1 * hessianColsNbr + id2 * dynJacobianColsNbr + id3;
sparseHelper(3, mDynamicModelFile, k, 0, oCDynamicModel);
mDynamicModelFile << "=" << eq + 1 << ";" << endl;
sparseHelper(3, mDynamicModelFile, k, 1, oCDynamicModel);
mDynamicModelFile << "=" << ref_col + 1 << ";" << endl;
sparseHelper(3, mDynamicModelFile, k, 2, oCDynamicModel);
mDynamicModelFile << "=";
// oCstaticModel makes reference to the static variables
d3->writeOutput(mDynamicModelFile, oCStaticModel, temporary_terms, tef_terms);
mDynamicModelFile << ";" << endl;
// Compute the column numbers for the 5 other permutations of (id1,id2,id3) and store them in a set (to avoid duplicates if two indexes are equal)
set<int> cols;
cols.insert(id1 * hessianColsNbr + id3 * dynJacobianColsNbr + id2);
cols.insert(id2 * hessianColsNbr + id1 * dynJacobianColsNbr + id3);
cols.insert(id2 * hessianColsNbr + id3 * dynJacobianColsNbr + id1);
cols.insert(id3 * hessianColsNbr + id1 * dynJacobianColsNbr + id2);
cols.insert(id3 * hessianColsNbr + id2 * dynJacobianColsNbr + id1);
int k2 = 1; // Keeps the offset of the permutation relative to k
for (set<int>::iterator it2 = cols.begin(); it2 != cols.end(); it2++)
if (*it2 != ref_col)
{
sparseHelper(3, mDynamicModelFile, k+k2, 0, oCDynamicModel);
mDynamicModelFile << "=" << eq + 1 << ";" << endl;
sparseHelper(3, mDynamicModelFile, k+k2, 1, oCDynamicModel);
mDynamicModelFile << "=" << *it2 + 1 << ";" << endl;
sparseHelper(3, mDynamicModelFile, k+k2, 2, oCDynamicModel);
mDynamicModelFile << "=";
sparseHelper(3, mDynamicModelFile, k, 2, oCDynamicModel);
mDynamicModelFile << ";" << endl;
k2++;
}
k += k2;
}
// Writing third derivatives
int hessianColsNbr = dynJacobianColsNbr * dynJacobianColsNbr;
int k = 0; // Keep the line of a 3rd derivative in v3
for (third_derivatives_t::const_iterator it = third_derivatives.begin();
it != third_derivatives.end(); it++)
{
int eq = it->first.first;
int var1 = it->first.second.first;
int var2 = it->first.second.second.first;
int var3 = it->first.second.second.second;
expr_t d3 = it->second;
int id1 = getDynJacobianCol(var1);
int id2 = getDynJacobianCol(var2);
int id3 = getDynJacobianCol(var3);
// Reference column number for the g3 matrix
int ref_col = id1 * hessianColsNbr + id2 * dynJacobianColsNbr + id3;
sparseHelper(3, mDynamicModelFile, k, 0, oCDynamicModel);
mDynamicModelFile << "=" << eq + 1 << ";" << endl;
sparseHelper(3, mDynamicModelFile, k, 1, oCDynamicModel);
mDynamicModelFile << "=" << ref_col + 1 << ";" << endl;
sparseHelper(3, mDynamicModelFile, k, 2, oCDynamicModel);
mDynamicModelFile << "=";
// oCstaticModel makes reference to the static variables
d3->writeOutput(mDynamicModelFile, oCStaticModel, temporary_terms, tef_terms);
mDynamicModelFile << ";" << endl;
// Compute the column numbers for the 5 other permutations of (id1,id2,id3) and store them in a set (to avoid duplicates if two indexes are equal)
set<int> cols;
cols.insert(id1 * hessianColsNbr + id3 * dynJacobianColsNbr + id2);
cols.insert(id2 * hessianColsNbr + id1 * dynJacobianColsNbr + id3);
cols.insert(id2 * hessianColsNbr + id3 * dynJacobianColsNbr + id1);
cols.insert(id3 * hessianColsNbr + id1 * dynJacobianColsNbr + id2);
cols.insert(id3 * hessianColsNbr + id2 * dynJacobianColsNbr + id1);
int k2 = 1; // Keeps the offset of the permutation relative to k
for (set<int>::iterator it2 = cols.begin(); it2 != cols.end(); it2++)
if (*it2 != ref_col)
{
sparseHelper(3, mDynamicModelFile, k+k2, 0, oCDynamicModel);
mDynamicModelFile << "=" << eq + 1 << ";" << endl;
sparseHelper(3, mDynamicModelFile, k+k2, 1, oCDynamicModel);
mDynamicModelFile << "=" << *it2 + 1 << ";" << endl;
sparseHelper(3, mDynamicModelFile, k+k2, 2, oCDynamicModel);
mDynamicModelFile << "=";
sparseHelper(3, mDynamicModelFile, k, 2, oCDynamicModel);
mDynamicModelFile << ";" << endl;
k2++;
}
k += k2;
}
mDynamicModelFile << "}" << endl;
writePowerDeriv(mDynamicModelFile, true);
mDynamicModelFile.close();
}
OrderByLinearAddress::OrderByLinearAddress(int size)
{
linear_address.resize(size);
}
bool OrderByLinearAddress::operator()(const int i1, const int i2) const
{
return linear_address[i1] < linear_address[i2];
}
......@@ -223,6 +223,12 @@ public:
void writeDynamicFile(const string &basename, bool block, bool bytecode, bool use_dll, int order) const;
//! Writes file containing parameters derivatives
void writeParamsDerivativesFile(const string &basename) const;
//! Writes CC file containing first order derivatives of model evaluated at steady state
void writeFirstDerivativesCC(const string &basename, bool cuda) const;
//! Writes CC file containing second order derivatives of model evaluated at steady state (compressed sparse column)
void writeSecondDerivativesCC_csr(const string &basename, bool cuda) const;
//! Writes CC file containing third order derivatives of model evaluated at steady state (compressed sparse column)
void writeThirdDerivativesCC_csr(const string &basename, bool cuda) const;
//! Converts to static model (only the equations)
/*! It assumes that the static model given in argument has just been allocated */
void toStatic(StaticModel &static_model) const;
......@@ -467,4 +473,14 @@ public:
bool isModelLocalVariableUsed() const;
};
//! Class to re-order derivatives for various sparse storage formats
class OrderByLinearAddress
{
public:
//! vector of linear addresses in derivatives matrices
vector<long unsigned int> linear_address;
OrderByLinearAddress(int size);
//! Order by linear address in a matrix
bool operator()(const int i1, const int i2) const;
};
#endif
......@@ -199,13 +199,15 @@ main(int argc, char **argv)
cerr << "Incorrect syntax for ouput option" << endl;
usage();
}
// we don't want temp terms in CC functions
no_tmp_terms = true;
if (strlen(argv[arg]) == 14 && !strncmp(argv[arg] + 7, "dynamic", 7))
output_mode = dynamic;
else if (strlen(argv[arg]) == 12 && !strncmp(argv[arg] + 7, "first", 5))
else if (strlen(argv[arg]) == 12 && !strncmp(argv[arg] + 7, "first", 5))
output_mode = first;
else if (strlen(argv[arg]) == 13 && !strncmp(argv[arg] + 7, "second", 6))
else if (strlen(argv[arg]) == 13 && !strncmp(argv[arg] + 7, "second", 6))
output_mode = second;
else if (strlen(argv[arg]) == 12 && !strncmp(argv[arg] + 7, "third", 5))
else if (strlen(argv[arg]) == 12 && !strncmp(argv[arg] + 7, "third", 5))
output_mode = third;
else
{
......
......@@ -54,7 +54,7 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tm
mod_file->evalAllExpressions(warn_uninit);
// Do computations
mod_file->computingPass(no_tmp_terms);
mod_file->computingPass(no_tmp_terms, output_mode);
// Write outputs
if (output_mode != none)
......
......@@ -673,6 +673,9 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
case oSteadyStateFile:
output << "ys_(" << tsid + 1 << ")";
break;
case oCSteadyStateFile:
output << "ys_[" << tsid << "]";
break;
default:
cerr << "VariableNode::writeOutput: should not reach this point" << endl;
exit(EXIT_FAILURE);
......@@ -715,6 +718,9 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
case oSteadyStateFile:
output << "exo_(" << i << ")";
break;
case oCSteadyStateFile:
output << "exo_[" << i - 1 << "]";
break;
default:
cerr << "VariableNode::writeOutput: should not reach this point" << endl;
exit(EXIT_FAILURE);
......@@ -757,6 +763,9 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
case oSteadyStateFile:
output << "exo_(" << i << ")";
break;
case oCSteadyStateFile:
output << "exo_[" << i - 1 << "]";
break;
default:
cerr << "VariableNode::writeOutput: should not reach this point" << endl;
exit(EXIT_FAILURE);
......@@ -4376,7 +4385,7 @@ ExternalFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_typ
const temporary_terms_t &temporary_terms,
deriv_node_temp_terms_t &tef_terms) const
{
if (output_type == oMatlabOutsideModel || output_type == oSteadyStateFile)
if (output_type == oMatlabOutsideModel || output_type == oSteadyStateFile || output_type == oCSteadyStateFile)
{
output << datatree.symbol_table.getName(symb_id) << "(";
writeExternalFunctionArguments(output, output_type, temporary_terms, tef_terms);
......
......@@ -73,7 +73,8 @@ enum ExprNodeOutputType
oMatlabDynamicSteadyStateOperator, //!< Matlab code, dynamic model, inside a steady state operator
oMatlabDynamicSparseSteadyStateOperator, //!< Matlab code, dynamic block decomposed model, inside a steady state operator
oCDynamicSteadyStateOperator, //!< C code, dynamic model, inside a steady state operator
oSteadyStateFile //!< Matlab code, in the generated steady state file
oSteadyStateFile, //!< Matlab code, in the generated steady state file
oCSteadyStateFile //!< C code, in the generated steady state file
};
#define IS_MATLAB(output_type) ((output_type) == oMatlabStaticModel \
......
......@@ -30,7 +30,9 @@ using namespace std;
class ExternalFiles
{
public:
void eraseFiles(const string &basename);
void writeHeaders(const string &basename, bool cuda);
void writeModelCC(const string &basename, bool cuda);
};
......
......@@ -447,7 +447,7 @@ ModFile::transformPass(bool nostrict)
}
void
ModFile::computingPass(bool no_tmp_terms)
ModFile::computingPass(bool no_tmp_terms, OutputType output)
{
// Mod file may have no equation (for example in a standalone BVAR estimation)
if (dynamic_model.equation_number() > 0)
......@@ -493,8 +493,14 @@ ModFile::computingPass(bool no_tmp_terms)
cerr << "ERROR: Incorrect order option..." << endl;
exit(EXIT_FAILURE);
}
bool hessian = mod_file_struct.order_option >= 2 || mod_file_struct.identification_present || mod_file_struct.estimation_analytic_derivation;
bool thirdDerivatives = mod_file_struct.order_option == 3 || mod_file_struct.estimation_analytic_derivation;
bool hessian = mod_file_struct.order_option >= 2
|| mod_file_struct.identification_present
|| mod_file_struct.estimation_analytic_derivation
|| output == second
|| output == third;
bool thirdDerivatives = mod_file_struct.order_option == 3
|| mod_file_struct.estimation_analytic_derivation
|| output == third;
bool paramsDerivatives = mod_file_struct.identification_present || mod_file_struct.estimation_analytic_derivation;
dynamic_model.computingPass(true, hessian, thirdDerivatives, paramsDerivatives, global_eval_context, no_tmp_terms, block, use_dll, byte_code);
}
......@@ -799,29 +805,9 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all, bool no_log, b
}
void
ModFile::writeCOutputFiles(const string &basename) const
ModFile::writeModelCC(const string &basename, bool cuda) const
{
// Erase possible remnants of previous runs
string dynfile = basename + "_dynamic.m";
unlink(dynfile.c_str());
dynfile = basename + "_dynamic.c";
unlink(dynfile.c_str());
dynfile = basename + "_dynamic_mex.c";
unlink(dynfile.c_str());
string statfile = basename + "_static.m";
unlink(statfile.c_str());
statfile = basename + "_static.c";
unlink(statfile.c_str());
statfile = basename + "_static_mex.c";
unlink(statfile.c_str());
string filename = "preprocessorOutput.cc";
unlink(filename.c_str());
string filename = basename + ".cc";
ofstream mDriverCFile;
mDriverCFile.open(filename.c_str(), ios::out | ios::binary);
......@@ -847,8 +833,6 @@ ModFile::writeCOutputFiles(const string &basename) const
// Write basic info
symbol_table.writeCOutput(mDriverCFile);
dynamic_model.writeCOutput(mDriverCFile, basename, false, false, true, mod_file_struct.order_option, mod_file_struct.estimation_present);
mDriverCFile << "/*" << endl
<< " * Writing statements" << endl
<< " */" << endl
......@@ -875,11 +859,6 @@ ModFile::writeCOutputFiles(const string &basename) const
mDriverCFile << "}" << endl;
mDriverCFile.close();
dynamic_model.writeDynamicFile(basename, false, false, true, mod_file_struct.order_option);
if (!no_static)
static_model.writeStaticFile(basename, false, false, true);
// Write informational m file
ofstream mOutputFile;
......@@ -914,22 +893,28 @@ ModFile::writeCOutputFiles(const string &basename) const
void
ModFile::writeExternalFiles(const string &basename, OutputType output, bool cuda) const
{
ExternalFiles::writeHeaders(basename, cuda);
ExternalFiles::writeModelCC(cuda);
writeModelCC(basename, cuda);
steady_state_model.writeSteadyStateFileCC(basename, mod_file_struct.ramsey_policy_present, cuda);
static_model.writeStaticFile(basename, block, byte_code, use_dll);
static_model.writeParamsDerivativesFile(basename);
static_model.writeAuxVarInitvalCC(mOutputFile, oMatlabOutsideModel);
dynamic_model.writeResiduals(basename, cuda);
dynamic_model.writeParamsDerivativesFile(basename, cuda);
dynamic_model.writeFirstDerivatives(basename, cuda);
dynamic_model.writeDynamicFile(basename, block, byte_code, use_dll, mod_file_struct.order_option);
if (!no_static)
static_model.writeStaticFile(basename, false, false, true);
// static_model.writeStaticCFile(basename, block, byte_code, use_dll);
// static_model.writeParamsDerivativesFileCC(basename, cuda);
// static_model.writeAuxVarInitvalCC(mOutputFile, oMatlabOutsideModel, cuda);
// dynamic_model.writeResidualsCC(basename, cuda);
// dynamic_model.writeParamsDerivativesFileCC(basename, cuda);
dynamic_model.writeFirstDerivativesCC(basename, cuda);
if (output == second)
dynamic_model.writeSecondDerivatives(basename, cuda);
dynamic_model.writeSecondDerivativesCC_csr(basename, cuda);
else if (output == third)
{
dynamic_model.writeSecondDerivatives(basename, cuda);
dynamic_model.writeThirdDerivatives(basename, cuda);
dynamic_model.writeSecondDerivativesCC_csr(basename, cuda);
dynamic_model.writeThirdDerivativesCC_csr(basename, cuda);
}
}
......@@ -123,7 +123,7 @@ public:
void transformPass(bool nostrict);