From 915bea91a101ba009f30387d02cc3c1cbd0d9698 Mon Sep 17 00:00:00 2001
From: Houtan Bastani <houtan@dynare.org>
Date: Mon, 20 Feb 2017 12:18:11 +0100
Subject: [PATCH] preprocessor: output JSON after different steps, write
 static, dynamic, params derivs files in JSON. #1387

---
 ComputingTasks.cc            |  36 ++--
 DynamicModel.cc              | 302 +++++++++++++++++++++++++++++-
 DynamicModel.hh              |   6 +
 DynareMain.cc                |  29 ++-
 DynareMain2.cc               |  17 +-
 ExprNode.cc                  | 350 +++++++++++++++++++++++++++++++----
 ExprNode.hh                  |  52 ++++--
 ExtendedPreprocessorTypes.hh |   9 +
 ModFile.cc                   | 141 +++++++++++++-
 ModFile.hh                   |   5 +-
 ModelTree.cc                 | 179 +++++++++++++++---
 ModelTree.hh                 |   6 +-
 NumericalInitialization.cc   |  10 +-
 Shocks.cc                    |  10 +-
 StaticModel.cc               | 284 ++++++++++++++++++++++++++++
 StaticModel.hh               |   8 +-
 SymbolTable.cc               |   2 +-
 17 files changed, 1329 insertions(+), 117 deletions(-)

diff --git a/ComputingTasks.cc b/ComputingTasks.cc
index db2ac624..f750b9b6 100644
--- a/ComputingTasks.cc
+++ b/ComputingTasks.cc
@@ -509,7 +509,7 @@ RamseyConstraintsStatement::writeJsonOutput(ostream &output) const
 	  exit(1);
 	}
       output << " ";
-      it->expression->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->expression->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}" << endl;
     }
   output << "]" << endl;
@@ -1170,23 +1170,23 @@ EstimatedParamsStatement::writeJsonOutput(ostream &output) const
         }
 
       output << ", \"init_val\": \"";
-      it->init_val->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->init_val->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\", \"lower_bound\": \"";
-      it->low_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->low_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\", \"upper_bound\": \"";
-      it->up_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->up_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\", \"prior_distribution\": "
              << it->prior
              << ", \"mean\": \"";
-      it->mean->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->mean->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\", \"std\": \"";
-      it->std->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->std->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\", \"p3\": \"";
-      it->p3->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->p3->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\", \"p4\": \"";
-      it->p4->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->p4->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\", \"jscale\": \"";
-      it->jscale->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->jscale->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}" << endl;
     }
   output << "]"
@@ -1297,7 +1297,7 @@ EstimatedParamsInitStatement::writeJsonOutput(ostream &output) const
           break;
         }
       output << ", \"init_val\": \"";
-      it->init_val->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->init_val->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}";
     }
   output << "]"
@@ -1417,9 +1417,9 @@ EstimatedParamsBoundsStatement::writeJsonOutput(ostream &output) const
           break;
         }
       output << ", \"lower_bound\": ";
-      it->low_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->low_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << ", \"upper_bound\": ";
-      it->up_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->up_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "}";
     }
   output << "]"
@@ -1470,7 +1470,7 @@ ObservationTrendsStatement::writeJsonOutput(ostream &output) const
           if (printed)
             output << ", ";
           output << "\"" << it->first << "\": \"";
-          it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+          it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
           output << "\"" << endl;
           printed = true;
         }
@@ -1571,9 +1571,9 @@ OsrParamsBoundsStatement::writeJsonOutput(ostream &output) const
         output << ", ";
       output << "{\"parameter\": \"" << it->name << "\","
              << "\"bounds\": [\"";
-      it->low_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->low_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\", \"";
-      it->up_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->up_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"]"
              << "}";
     }
@@ -1699,7 +1699,7 @@ OptimWeightsStatement::writeJsonOutput(ostream &output) const
         output << ", ";
       output << "{\"name\": \"" << it->first << "\""
              << ", \"value\": \"";
-      it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}";
     }
 
@@ -1711,7 +1711,7 @@ OptimWeightsStatement::writeJsonOutput(ostream &output) const
       output << "{\"name1\": \"" << it->first.first << "\""
              << ", \"name2\": \"" << it->first.second << "\""
              << ", \"value\": \"";
-      it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}";
     }
   output << "]"
@@ -3504,7 +3504,7 @@ BasicPriorStatement::writeJsonPriorOutput(ostream &output) const
     {
       deriv_node_temp_terms_t tef_terms;
       output << ", \"variance\": \"";
-      variance->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      variance->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"";
     }
   if (options_list.getNumberOfOptions())
diff --git a/DynamicModel.cc b/DynamicModel.cc
index 704592da..edcc5f3a 100644
--- a/DynamicModel.cc
+++ b/DynamicModel.cc
@@ -5341,5 +5341,305 @@ DynamicModel::writeCCOutput(ostream &output, const string &basename, bool block_
 void
 DynamicModel::writeJsonOutput(ostream &output) const
 {
-  writeJsonModelEquations(output);
+  writeJsonModelEquations(output, false);
+}
+
+void
+DynamicModel::writeJsonComputingPassOutput(ostream &output) const
+{
+  ostringstream model_local_vars_output;  // Used for storing model local vars
+  ostringstream model_output;             // Used for storing model temp vars and equations
+  ostringstream jacobian_output;          // Used for storing jacobian equations
+  ostringstream hessian_output;           // Used for storing Hessian equations
+  ostringstream third_derivatives_output; // Used for storing third order derivatives equations
+
+  deriv_node_temp_terms_t tef_terms;
+  temporary_terms_t temp_term_empty;
+  temporary_terms_t temp_term_union = temporary_terms_res;
+  temporary_terms_t temp_term_union_m_1;
+
+  string concat = "";
+  int hessianColsNbr = dynJacobianColsNbr * dynJacobianColsNbr;
+
+  writeJsonModelLocalVariables(model_local_vars_output, tef_terms);
+
+  writeJsonTemporaryTerms(temporary_terms_res, temp_term_union_m_1, model_output, tef_terms, concat);
+
+  writeJsonModelEquations(model_output, true);
+
+  // Writing Jacobian
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g1.begin(), temporary_terms_g1.end());
+  concat = "jacobian";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, jacobian_output, tef_terms, concat);
+  jacobian_output << ", \"jacobian\": {"
+                  << "  \"nrows\": " << equations.size()
+                  << ", \"ncols\": " << dynJacobianColsNbr
+                  << ", \"entries\": [";
+  for (first_derivatives_t::const_iterator it = first_derivatives.begin();
+       it != first_derivatives.end(); it++)
+    {
+      if (it != first_derivatives.begin())
+        jacobian_output << ", ";
+
+      int eq = it->first.first;
+      string var = symbol_table.getName(getSymbIDByDerivID(it->first.second));
+      int lag = getLagByDerivID(it->first.second);
+      expr_t d1 = it->second;
+
+      jacobian_output << "{\"eq\": " << eq
+                      << ", \"var\": \"" << var << "\""
+                      << ", \"lag\": " << lag
+                      << ", \"val\": \"";
+      d1->writeJsonOutput(jacobian_output, temp_term_union, tef_terms);
+      jacobian_output << "\"}" << endl;
+    }
+  jacobian_output << "]}";
+
+  // Writing Hessian
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g2.begin(), temporary_terms_g2.end());
+  concat = "hessian";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, hessian_output, tef_terms, concat);
+  hessian_output << ", \"hessian\": {"
+                 << "  \"nrows\": " << equations.size()
+                 << ", \"ncols\": " << hessianColsNbr
+                 << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = second_derivatives.begin();
+       it != second_derivatives.end(); it++)
+    {
+      if (it != second_derivatives.begin())
+        hessian_output << ", ";
+
+      int eq = it->first.first;
+      string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first));
+      int lag1 = getLagByDerivID(it->first.second.first);
+      string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second));
+      int lag2 = getLagByDerivID(it->first.second.second);
+      expr_t d2 = it->second;
+
+      hessian_output << "{\"eq\": " << eq
+                     << ", \"var1\": \"" << var1 << "\""
+                     << ", \"lag1\": " << lag1
+                     << ", \"var2\": \"" << var2 << "\""
+                     << ", \"lag2\": " << lag2
+                     << ", \"val\": \"";
+      d2->writeJsonOutput(hessian_output, temp_term_union, tef_terms);
+      hessian_output << "\"}" << endl;
+    }
+  hessian_output << "]}";
+
+  // Writing third derivatives
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g3.begin(), temporary_terms_g3.end());
+  concat = "third_derivatives";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, third_derivatives_output, tef_terms, concat);
+  third_derivatives_output << ", \"third_derivative\": {"
+                           << "  \"nrows\": " << equations.size()
+                           << ", \"ncols\": " << hessianColsNbr * dynJacobianColsNbr
+                           << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = third_derivatives.begin();
+       it != third_derivatives.end(); it++)
+    {
+      if (it != third_derivatives.begin())
+        third_derivatives_output << ", ";
+
+      int eq = it->first.first;
+      string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first));
+      int lag1 = getLagByDerivID(it->first.second.first);
+      string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first));
+      int lag2 = getLagByDerivID(it->first.second.second.first);
+      string var3 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second));
+      int lag3 = getLagByDerivID(it->first.second.second.second);
+      expr_t d3 = it->second;
+
+      third_derivatives_output << "{\"eq\": " << eq
+                               << ", \"var1\": \"" << var1 << "\""
+                               << ", \"lag1\": " << lag1
+                               << ", \"var2\": \"" << var2 << "\""
+                               << ", \"lag2\": " << lag2
+                               << ", \"var3\": \"" << var3 << "\""
+                               << ", \"lag3\": " << lag3
+                               << ", \"val\": \"";
+      d3->writeJsonOutput(third_derivatives_output, temp_term_union, tef_terms);
+      third_derivatives_output << "\"}" << endl;
+    }
+  third_derivatives_output << "]}";
+
+  output << "\"dynamic_model_derivatives\": {"
+         << model_local_vars_output.str()
+         << ", " << model_output.str()
+         << ", " << jacobian_output.str()
+         << ", " << hessian_output.str()
+         << ", " << third_derivatives_output.str()
+         << "}";
+}
+
+void
+DynamicModel::writeJsonParamsDerivativesFile(ostream &output) const
+{
+  if (!residuals_params_derivatives.size()
+      && !residuals_params_second_derivatives.size()
+      && !jacobian_params_derivatives.size()
+      && !jacobian_params_second_derivatives.size()
+      && !hessian_params_derivatives.size())
+    return;
+
+  ostringstream model_local_vars_output;   // Used for storing model local vars
+  ostringstream model_output;              // Used for storing model temp vars and equations
+  ostringstream jacobian_output;           // Used for storing jacobian equations
+  ostringstream hessian_output;            // Used for storing Hessian equations
+  ostringstream hessian1_output;           // Used for storing Hessian equations
+  ostringstream third_derivs_output;       // Used for storing third order derivatives equations
+  ostringstream third_derivs1_output;      // Used for storing third order derivatives equations
+
+  deriv_node_temp_terms_t tef_terms;
+  writeJsonModelLocalVariables(model_local_vars_output, tef_terms);
+
+  temporary_terms_t temp_terms_empty;
+  string concat = "all";
+  writeJsonTemporaryTerms(params_derivs_temporary_terms, temp_terms_empty, model_output, tef_terms, concat);
+  jacobian_output << "\"deriv_wrt_params\": {"
+                  << "  \"neqs\": " << equations.size()
+                  << ", \"nparamcols\": " << symbol_table.param_nbr()
+                  << ", \"entries\": [";
+  for (first_derivatives_t::const_iterator it = residuals_params_derivatives.begin();
+       it != residuals_params_derivatives.end(); it++)
+    {
+      if (it != residuals_params_derivatives.begin())
+        jacobian_output << ", ";
+
+      int eq = it->first.first;
+      string param = symbol_table.getName(getSymbIDByDerivID(it->first.second));
+      expr_t d1 = it->second;
+
+      jacobian_output << "{\"eq\": " << eq
+                      << ", \"param\": \"" << param << "\""
+                      << ", \"val\": \"";
+      d1->writeJsonOutput(jacobian_output, params_derivs_temporary_terms, tef_terms);
+      jacobian_output << "\"}" << endl;
+    }
+  jacobian_output << "]}";
+  hessian_output << "\"deriv_jacobian_wrt_params\": {"
+                 << "  \"neqs\": " << equations.size()
+                 << ", \"nvarcols\": " << dynJacobianColsNbr
+                 << ", \"nparamcols\": " << symbol_table.param_nbr()
+                 << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = jacobian_params_derivatives.begin();
+       it != jacobian_params_derivatives.end(); it++)
+    {
+      if (it != jacobian_params_derivatives.begin())
+        hessian_output << ", ";
+
+      int eq = it->first.first;
+      string var = symbol_table.getName(getSymbIDByDerivID(it->first.second.first));
+      int lag = getLagByDerivID(it->first.second.first);
+      string param = symbol_table.getName(getSymbIDByDerivID(it->first.second.second));
+      expr_t d2 = it->second;
+
+      hessian_output << "{\"eq\": " << eq
+                     << ", \"var\": \"" << var << "\""
+                     << ", \"lag\": " << lag
+                     << ", \"param\": \"" << param << "\""
+                     << ", \"val\": \"";
+      d2->writeJsonOutput(hessian_output, params_derivs_temporary_terms, tef_terms);
+      hessian_output << "\"}" << endl;
+    }
+  hessian_output << "]}";
+
+  hessian1_output << "\"second_deriv_residuals_wrt_params\": {"
+                  << "  \"nrows\": " << equations.size()
+                  << ", \"nparam1cols\": " << symbol_table.param_nbr()
+                  << ", \"nparam2cols\": " << symbol_table.param_nbr()
+                  << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = residuals_params_second_derivatives.begin();
+       it != residuals_params_second_derivatives.end(); ++it)
+    {
+      if (it != residuals_params_second_derivatives.begin())
+        hessian1_output << ", ";
+
+      int eq = it->first.first;
+      string param1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first));
+      string param2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second));
+      expr_t d2 = it->second;
+
+      hessian1_output << "{\"eq\": " << eq
+                     << ", \"param1\": \"" << param1 << "\""
+                     << ", \"param2\": \"" << param2 << "\""
+                     << ", \"val\": \"";
+      d2->writeJsonOutput(hessian1_output, params_derivs_temporary_terms, tef_terms);
+      hessian1_output << "\"}" << endl;
+    }
+  hessian1_output << "]}";
+  third_derivs_output << "\"second_deriv_jacobian_wrt_params\": {"
+                      << "  \"neqs\": " << equations.size()
+                      << ", \"nvarcols\": " << dynJacobianColsNbr
+                      << ", \"nparam1cols\": " << symbol_table.param_nbr()
+                      << ", \"nparam2cols\": " << symbol_table.param_nbr()
+                      << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = jacobian_params_second_derivatives.begin();
+       it != jacobian_params_second_derivatives.end(); ++it)
+    {
+      if (it != jacobian_params_second_derivatives.begin())
+        third_derivs_output << ", ";
+
+      int eq = it->first.first;
+      string var = symbol_table.getName(it->first.second.first);
+      int lag = getLagByDerivID(it->first.second.first);
+      string param1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first));
+      string param2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second));
+      expr_t d2 = it->second;
+
+      third_derivs_output << "{\"eq\": " << eq
+                          << ", \"var\": \"" << var << "\""
+                          << ", \"lag\": " << lag
+                          << ", \"param1\": \"" << param1 << "\""
+                          << ", \"param2\": \"" << param2 << "\""
+                          << ", \"val\": \"";
+      d2->writeJsonOutput(third_derivs_output, params_derivs_temporary_terms, tef_terms);
+      third_derivs_output << "\"}" << endl;
+    }
+  third_derivs_output << "]}" << endl;
+
+  third_derivs1_output << "\"derivative_hessian_wrt_params\": {"
+                       << "  \"neqs\": " << equations.size()
+                       << ", \"nvar1cols\": " << dynJacobianColsNbr
+                       << ", \"nvar2cols\": " << dynJacobianColsNbr
+                       << ", \"nparamcols\": " << symbol_table.param_nbr()
+                       << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = hessian_params_derivatives.begin();
+       it != hessian_params_derivatives.end(); ++it)
+    {
+      if (it != hessian_params_derivatives.begin())
+        third_derivs1_output << ", ";
+
+      int eq = it->first.first;
+      string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first));
+      int lag1 = getLagByDerivID(it->first.second.first);
+      string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first));
+      int lag2 = getLagByDerivID(it->first.second.second.first);
+      string param = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second));
+      expr_t d2 = it->second;
+
+      third_derivs1_output << "{\"eq\": " << eq
+                           << ", \"var1\": \"" << var1 << "\""
+                           << ", \"lag1\": " << lag1
+                           << ", \"var2\": \"" << var2 << "\""
+                           << ", \"lag2\": " << lag2
+                           << ", \"param1\": \"" << param << "\""
+                           << ", \"val\": \"";
+      d2->writeJsonOutput(third_derivs1_output, params_derivs_temporary_terms, tef_terms);
+      third_derivs1_output << "\"}" << endl;
+    }
+  third_derivs1_output << "]}" << endl;
+
+  output << "\"dynamic_model_params_derivatives\": {"
+         << model_local_vars_output.str()
+         << ", " << model_output.str()
+         << ", " << jacobian_output.str()
+         << ", " << hessian_output.str()
+         << ", " << hessian1_output.str()
+         << ", " << third_derivs_output.str()
+         << ", " << third_derivs1_output.str()
+         << "}";
 }
diff --git a/DynamicModel.hh b/DynamicModel.hh
index e79ac7f4..87e41e38 100644
--- a/DynamicModel.hh
+++ b/DynamicModel.hh
@@ -220,6 +220,12 @@ public:
   //! Write JSON Output
   void writeJsonOutput(ostream &output) const;
 
+  //! Write JSON Output representation of dynamic model after computing pass
+  void writeJsonComputingPassOutput(ostream &output) const;
+
+  //! Write JSON prams derivatives file
+  void writeJsonParamsDerivativesFile(ostream &output) const;
+
   //! Return true if the hessian is equal to zero
   inline bool checkHessianZero() const;
 
diff --git a/DynareMain.cc b/DynareMain.cc
index c5650926..cd62325c 100644
--- a/DynareMain.cc
+++ b/DynareMain.cc
@@ -45,7 +45,7 @@ void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool
 #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__)
            , bool cygwin, bool msvc, bool mingw
 #endif
-           , bool json, JsonFileOutputType json_output_mode
+           , JsonOutputPointType json, JsonFileOutputType json_output_mode
            );
 
 void main1(char *modfile, string &basename, bool debug, bool save_macro, string &save_macro_file,
@@ -62,7 +62,7 @@ usage()
 #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__)
        << " [cygwin] [msvc] [mingw]"
 #endif
-       << "[json] [jsonstdout]"
+       << "[json=parse|check|transform|compute] [jsonstdout]"
        << endl;
   exit(EXIT_FAILURE);
 }
@@ -115,7 +115,7 @@ main(int argc, char **argv)
   map<string, string> defines;
   vector<string> path;
   FileOutputType output_mode = none;
-  bool json = false;
+  JsonOutputPointType json = nojson;
   JsonFileOutputType json_output_mode = file;
   LanguageOutputType language = matlab;
 
@@ -297,8 +297,27 @@ main(int argc, char **argv)
         }
       else if (!strcmp(argv[arg], "jsonstdout"))
         json_output_mode = standardout;
-      else if (!strcmp(argv[arg], "json"))
-        json = true;
+      else if (strlen(argv[arg]) >= 4 && !strncmp(argv[arg], "json", 4))
+        {
+	  if (strlen(argv[arg]) <= 5 || argv[arg][4] != '=')
+	    {
+	      cerr << "Incorrect syntax for json option" << endl;
+	      usage();
+	    }
+	  if (strlen(argv[arg]) == 10 && !strncmp(argv[arg] + 5, "parse", 5))
+	    json = parsing;
+	  else if (strlen(argv[arg]) ==  10 && !strncmp(argv[arg] + 5, "check", 5))
+	    json = checkpass;
+	  else if (strlen(argv[arg]) == 14 && !strncmp(argv[arg] + 5, "transform", 9))
+	    json = transformpass;
+	  else if (strlen(argv[arg]) == 12 && !strncmp(argv[arg] + 5, "compute", 7))
+	    json = computingpass;
+	  else
+	    {
+	      cerr << "Incorrect syntax for json option" << endl;
+	      usage();
+            }
+        }
       else
         {
           cerr << "Unknown option: " << argv[arg] << endl;
diff --git a/DynareMain2.cc b/DynareMain2.cc
index 3bbc4b4f..bc2d34ff 100644
--- a/DynareMain2.cc
+++ b/DynareMain2.cc
@@ -34,32 +34,33 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool clear
 #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__)
       , bool cygwin, bool msvc, bool mingw
 #endif
-      , bool json, JsonFileOutputType json_output_mode
+      , JsonOutputPointType json, JsonFileOutputType json_output_mode
       )
 {
   ParsingDriver p(warnings, nostrict);
 
   // Do parsing and construct internal representation of mod file
   ModFile *mod_file = p.parse(in, debug);
-  if (json)
-    {
-      mod_file->symbol_table.freeze();
-      mod_file->writeJsonOutput(basename, json_output_mode);
-      mod_file->symbol_table.unfreeze();
-      cout << "JSON file written after Parsing step." << endl;
-    }
+  if (json == parsing)
+    mod_file->writeJsonOutput(basename, json, json_output_mode);
 
   // Run checking pass
   mod_file->checkPass(nostrict);
+  if (json == checkpass)
+    mod_file->writeJsonOutput(basename, json, json_output_mode);
 
   // Perform transformations on the model (creation of auxiliary vars and equations)
   mod_file->transformPass(nostrict);
+  if (json == transformpass)
+    mod_file->writeJsonOutput(basename, json, json_output_mode);
 
   // Evaluate parameters initialization, initval, endval and pounds
   mod_file->evalAllExpressions(warn_uninit);
 
   // Do computations
   mod_file->computingPass(no_tmp_terms, output_mode, compute_xrefs, params_derivs_order);
+  if (json == computingpass)
+    mod_file->writeJsonOutput(basename, json, json_output_mode);
 
   // Write outputs
   if (output_mode != none)
diff --git a/ExprNode.cc b/ExprNode.cc
index ccba75c2..b5b9d4dd 100644
--- a/ExprNode.cc
+++ b/ExprNode.cc
@@ -73,6 +73,13 @@ ExprNode::precedence(ExprNodeOutputType output_type, const temporary_terms_t &te
   return 100;
 }
 
+int
+ExprNode::precedenceJson(const temporary_terms_t &temporary_terms) const
+{
+  // For a constant, a variable, or a unary op, the precedence is maximal
+  return 100;
+}
+
 int
 ExprNode::cost(int cost, bool is_matlab) const
 {
@@ -185,6 +192,14 @@ ExprNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output
   // Nothing to do
 }
 
+void
+ExprNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                          const temporary_terms_t &temporary_terms,
+                                          deriv_node_temp_terms_t &tef_terms) const
+{
+  // Nothing to do
+}
+
 void
 ExprNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                         bool lhs_rhs, const temporary_terms_t &temporary_terms,
@@ -323,7 +338,7 @@ NumConstNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
 }
 
 void
-NumConstNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
+NumConstNode::writeJsonOutput(ostream &output,
                               const temporary_terms_t &temporary_terms,
                               deriv_node_temp_terms_t &tef_terms) const
 {
@@ -624,10 +639,17 @@ VariableNode::containsExternalFunction() const
 }
 
 void
-VariableNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
+VariableNode::writeJsonOutput(ostream &output,
                               const temporary_terms_t &temporary_terms,
                               deriv_node_temp_terms_t &tef_terms) const
 {
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<VariableNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
   output << datatree.symbol_table.getName(symb_id);
   if (lag != 0)
     output << "(" << lag << ")";
@@ -1869,13 +1891,20 @@ UnaryOpNode::containsExternalFunction() const
 }
 
 void
-UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
+UnaryOpNode::writeJsonOutput(ostream &output,
                              const temporary_terms_t &temporary_terms,
                              deriv_node_temp_terms_t &tef_terms) const
 {
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<UnaryOpNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
   // Always put parenthesis around uminus nodes
   if (op_code == oUminus)
-    output << LEFT_PAR(output_type);
+    output << "(";
 
   switch (op_code)
     {
@@ -1938,7 +1967,7 @@ UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
       break;
     case oSteadyState:
       output << "(";
-      arg->writeJsonOutput(output, output_type, temporary_terms, tef_terms);
+      arg->writeJsonOutput(output, temporary_terms, tef_terms);
       output << ")";
       return;
     case oSteadyStateParamDeriv:
@@ -1949,7 +1978,6 @@ UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
         assert(datatree.symbol_table.getType(param1_symb_id) == eParameter);
         int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id);
         int tsid_param = datatree.symbol_table.getTypeSpecificID(param1_symb_id);
-        assert(IS_MATLAB(output_type));
         output << "ss_param_deriv(" << tsid_endo+1 << "," << tsid_param+1 << ")";
       }
       return;
@@ -1963,7 +1991,6 @@ UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
         int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id);
         int tsid_param1 = datatree.symbol_table.getTypeSpecificID(param1_symb_id);
         int tsid_param2 = datatree.symbol_table.getTypeSpecificID(param2_symb_id);
-        assert(IS_MATLAB(output_type));
         output << "ss_param_2nd_deriv(" << tsid_endo+1 << "," << tsid_param1+1
                << "," << tsid_param2+1 << ")";
       }
@@ -1984,23 +2011,21 @@ UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
   */
   if (op_code != oUminus
       || (op_code == oUminus
-          && arg->precedence(output_type, temporary_terms) < precedence(output_type, temporary_terms)))
+          && arg->precedenceJson(temporary_terms) < precedenceJson(temporary_terms)))
     {
-      output << LEFT_PAR(output_type);
-      if (op_code == oSign && (output_type == oCDynamicModel || output_type == oCStaticModel))
-        output << "1.0,";
+      output << "(";
       close_parenthesis = true;
     }
 
   // Write argument
-  arg->writeJsonOutput(output, output_type, temporary_terms, tef_terms);
+  arg->writeJsonOutput(output, temporary_terms, tef_terms);
 
   if (close_parenthesis)
-    output << RIGHT_PAR(output_type);
+    output << ")";
 
   // Close parenthesis for uminus
   if (op_code == oUminus)
-    output << RIGHT_PAR(output_type);
+    output << ")";
 }
 
 void
@@ -2197,6 +2222,14 @@ UnaryOpNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType out
   arg->writeExternalFunctionOutput(output, output_type, temporary_terms, tef_terms);
 }
 
+void
+UnaryOpNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                             const temporary_terms_t &temporary_terms,
+                                             deriv_node_temp_terms_t &tef_terms) const
+{
+  arg->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+}
+
 void
 UnaryOpNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                            bool lhs_rhs, const temporary_terms_t &temporary_terms,
@@ -2963,6 +2996,43 @@ BinaryOpNode::precedence(ExprNodeOutputType output_type, const temporary_terms_t
   exit(EXIT_FAILURE);
 }
 
+int
+BinaryOpNode::precedenceJson(const temporary_terms_t &temporary_terms) const
+{
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<BinaryOpNode *>(this));
+  // A temporary term behaves as a variable
+  if (it != temporary_terms.end())
+    return 100;
+
+  switch (op_code)
+    {
+    case oEqual:
+      return 0;
+    case oEqualEqual:
+    case oDifferent:
+      return 1;
+    case oLessEqual:
+    case oGreaterEqual:
+    case oLess:
+    case oGreater:
+      return 2;
+    case oPlus:
+    case oMinus:
+      return 3;
+    case oTimes:
+    case oDivide:
+      return 4;
+    case oPower:
+    case oPowerDeriv:
+      return 5;
+    case oMin:
+    case oMax:
+      return 100;
+    }
+  // Suppress GCC warning
+  exit(EXIT_FAILURE);
+}
+
 int
 BinaryOpNode::cost(const map<NodeTreeReference, temporary_terms_t> &temp_terms_map, bool is_matlab) const
 {
@@ -3226,10 +3296,18 @@ BinaryOpNode::containsExternalFunction() const
 }
 
 void
-BinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
+BinaryOpNode::writeJsonOutput(ostream &output,
                               const temporary_terms_t &temporary_terms,
                               deriv_node_temp_terms_t &tef_terms) const
 {
+  // If current node is a temporary term
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<BinaryOpNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
   if (op_code == oMax || op_code == oMin)
     {
       switch (op_code)
@@ -3243,32 +3321,32 @@ BinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
         default:
           ;
         }
-      arg1->writeJsonOutput(output, output_type, temporary_terms, tef_terms);
+      arg1->writeJsonOutput(output, temporary_terms, tef_terms);
       output << ",";
-      arg2->writeJsonOutput(output, output_type, temporary_terms, tef_terms);
+      arg2->writeJsonOutput(output, temporary_terms, tef_terms);
       output << ")";
       return;
     }
 
-  int prec = precedence(output_type, temporary_terms);
+  int prec = precedenceJson(temporary_terms);
 
   bool close_parenthesis = false;
 
   // If left argument has a lower precedence, or if current and left argument are both power operators,
   // add parenthesis around left argument
   BinaryOpNode *barg1 = dynamic_cast<BinaryOpNode *>(arg1);
-  if (arg1->precedence(output_type, temporary_terms) < prec
+  if (arg1->precedenceJson(temporary_terms) < prec
       || (op_code == oPower && barg1 != NULL && barg1->op_code == oPower))
     {
-      output << LEFT_PAR(output_type);
+      output << "(";
       close_parenthesis = true;
     }
 
   // Write left argument
-  arg1->writeJsonOutput(output, output_type, temporary_terms, tef_terms);
+  arg1->writeJsonOutput(output, temporary_terms, tef_terms);
 
   if (close_parenthesis)
-    output << RIGHT_PAR(output_type);
+    output << ")";
 
   // Write current operator symbol
   switch (op_code)
@@ -3321,21 +3399,21 @@ BinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
      - it is a minus operator with same precedence than current operator
      - it is a divide operator with same precedence than current operator */
   BinaryOpNode *barg2 = dynamic_cast<BinaryOpNode *>(arg2);
-  int arg2_prec = arg2->precedence(output_type, temporary_terms);
+  int arg2_prec = arg2->precedenceJson(temporary_terms);
   if (arg2_prec < prec
-      || (op_code == oPower && barg2 != NULL && barg2->op_code == oPower && !IS_LATEX(output_type))
+      || (op_code == oPower && barg2 != NULL && barg2->op_code == oPower)
       || (op_code == oMinus && arg2_prec == prec)
-      || (op_code == oDivide && arg2_prec == prec && !IS_LATEX(output_type)))
+      || (op_code == oDivide && arg2_prec == prec))
     {
-      output << LEFT_PAR(output_type);
+      output << "(";
       close_parenthesis = true;
     }
 
   // Write right argument
-  arg2->writeJsonOutput(output, output_type, temporary_terms, tef_terms);
+  arg2->writeJsonOutput(output, temporary_terms, tef_terms);
 
   if (close_parenthesis)
-    output << RIGHT_PAR(output_type);
+    output << ")";
 }
 
 void
@@ -3527,6 +3605,15 @@ BinaryOpNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType ou
   arg2->writeExternalFunctionOutput(output, output_type, temporary_terms, tef_terms);
 }
 
+void
+BinaryOpNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                              const temporary_terms_t &temporary_terms,
+                                              deriv_node_temp_terms_t &tef_terms) const
+{
+  arg1->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+  arg2->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+}
+
 void
 BinaryOpNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                             bool lhs_rhs, const temporary_terms_t &temporary_terms,
@@ -4478,10 +4565,18 @@ TrinaryOpNode::containsExternalFunction() const
 }
 
 void
-TrinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
+TrinaryOpNode::writeJsonOutput(ostream &output,
                                const temporary_terms_t &temporary_terms,
                                deriv_node_temp_terms_t &tef_terms) const
 {
+  // If current node is a temporary term
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<TrinaryOpNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
   switch (op_code)
     {
     case oNormcdf:
@@ -4492,11 +4587,11 @@ TrinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
       break;
     }
 
-  arg1->writeJsonOutput(output, output_type, temporary_terms, tef_terms);
+  arg1->writeJsonOutput(output, temporary_terms, tef_terms);
   output << ",";
-  arg2->writeJsonOutput(output, output_type, temporary_terms, tef_terms);
+  arg2->writeJsonOutput(output, temporary_terms, tef_terms);
   output << ",";
-  arg3->writeJsonOutput(output, output_type, temporary_terms, tef_terms);
+  arg3->writeJsonOutput(output, temporary_terms, tef_terms);
   output << ")";
 }
 
@@ -4576,6 +4671,16 @@ TrinaryOpNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType o
   arg3->writeExternalFunctionOutput(output, output_type, temporary_terms, tef_terms);
 }
 
+void
+TrinaryOpNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const
+{
+  arg1->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+  arg2->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+  arg3->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+}
+
 void
 TrinaryOpNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
@@ -5181,7 +5286,7 @@ AbstractExternalFunctionNode::writeExternalFunctionArguments(ostream &output, Ex
 }
 
 void
-AbstractExternalFunctionNode::writeJsonExternalFunctionArguments(ostream &output, ExprNodeOutputType output_type,
+AbstractExternalFunctionNode::writeJsonExternalFunctionArguments(ostream &output,
                                                                  const temporary_terms_t &temporary_terms,
                                                                  deriv_node_temp_terms_t &tef_terms) const
 {
@@ -5191,7 +5296,7 @@ AbstractExternalFunctionNode::writeJsonExternalFunctionArguments(ostream &output
       if (it != arguments.begin())
         output << ",";
 
-      (*it)->writeJsonOutput(output, output_type, temporary_terms, tef_terms);
+      (*it)->writeJsonOutput(output, temporary_terms, tef_terms);
     }
 }
 
@@ -5359,12 +5464,19 @@ ExternalFunctionNode::compileExternalFunctionOutput(ostream &CompileCode, unsign
 }
 
 void
-ExternalFunctionNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
+ExternalFunctionNode::writeJsonOutput(ostream &output,
                                       const temporary_terms_t &temporary_terms,
                                       deriv_node_temp_terms_t &tef_terms) const
 {
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<ExternalFunctionNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
   output << datatree.symbol_table.getName(symb_id) << "(";
-  writeJsonExternalFunctionArguments(output, output_type, temporary_terms, tef_terms);
+  writeJsonExternalFunctionArguments(output, temporary_terms, tef_terms);
   output << ")";
 }
 
@@ -5477,6 +5589,42 @@ ExternalFunctionNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutpu
     }
 }
 
+void
+ExternalFunctionNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                                      const temporary_terms_t &temporary_terms,
+                                                      deriv_node_temp_terms_t &tef_terms) const
+{
+  int first_deriv_symb_id = datatree.external_functions_table.getFirstDerivSymbID(symb_id);
+  assert(first_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+  for (vector<expr_t>::const_iterator it = arguments.begin();
+       it != arguments.end(); it++)
+    (*it)->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+
+  if (!alreadyWrittenAsTefTerm(symb_id, tef_terms))
+    {
+      tef_terms[make_pair(symb_id, arguments)] = (int) tef_terms.size();
+      int indx = getIndxInTefTerms(symb_id, tef_terms);
+      int second_deriv_symb_id = datatree.external_functions_table.getSecondDerivSymbID(symb_id);
+      assert(second_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+      stringstream ef;
+      ef << "{\"external_function\": {"
+         << "\"output\": \"TEF_" << indx << "\"";
+
+      if (symb_id == first_deriv_symb_id)
+        ef << ", \"output_d\": \"TEFD_" << indx << "\"";
+
+      if (symb_id == second_deriv_symb_id)
+        ef << ", \"output_dd\": \"TEFDD_" << indx << "\"";
+
+      ef << ", \"function\": \"" << datatree.symbol_table.getName(symb_id) << "(";
+      writeJsonExternalFunctionArguments(ef, temporary_terms, tef_terms);
+      ef << ")\"}}";
+      efout.push_back(ef.str());
+    }
+}
+
 expr_t
 ExternalFunctionNode::toStatic(DataTree &static_datatree) const
 {
@@ -5559,10 +5707,31 @@ FirstDerivExternalFunctionNode::composeDerivatives(const vector<expr_t> &dargs)
 }
 
 void
-FirstDerivExternalFunctionNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
+FirstDerivExternalFunctionNode::writeJsonOutput(ostream &output,
                                                 const temporary_terms_t &temporary_terms,
                                                 deriv_node_temp_terms_t &tef_terms) const
 {
+  // If current node is a temporary term
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<FirstDerivExternalFunctionNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
+  const int first_deriv_symb_id = datatree.external_functions_table.getFirstDerivSymbID(symb_id);
+  assert(first_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+  const int tmpIndx = inputIndex - 1;
+
+  if (first_deriv_symb_id == symb_id)
+    output << "TEFD_" << getIndxInTefTerms(symb_id, tef_terms)
+           << "[" << tmpIndx << "]";
+  else if (first_deriv_symb_id == eExtFunNotSet)
+    output << "TEFD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex;
+  else
+    output << "TEFD_def_" << getIndxInTefTerms(first_deriv_symb_id, tef_terms)
+           << "[" << tmpIndx << "]";
 }
 
 void
@@ -5752,6 +5921,47 @@ FirstDerivExternalFunctionNode::writeExternalFunctionOutput(ostream &output, Exp
     }
 }
 
+void
+FirstDerivExternalFunctionNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                                                const temporary_terms_t &temporary_terms,
+                                                                deriv_node_temp_terms_t &tef_terms) const
+{
+  int first_deriv_symb_id = datatree.external_functions_table.getFirstDerivSymbID(symb_id);
+  assert(first_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+  /* For a node with derivs provided by the user function, call the method
+     on the non-derived node */
+  if (first_deriv_symb_id == symb_id)
+    {
+      expr_t parent = datatree.AddExternalFunction(symb_id, arguments);
+      parent->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+      return;
+    }
+
+  if (alreadyWrittenAsTefTerm(first_deriv_symb_id, tef_terms))
+    return;
+
+  stringstream ef;
+  if (first_deriv_symb_id == eExtFunNotSet)
+    ef << "{\"first_deriv_external_function\": {"
+       << "\"output\": \"TEFD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex << "\""
+       << ", \"analytic_derivative\": false"
+       << ", \"wrt\": " << inputIndex
+       << ", \"function\": \"" << datatree.symbol_table.getName(symb_id) << "(";
+  else
+    {
+      tef_terms[make_pair(first_deriv_symb_id, arguments)] = (int) tef_terms.size();
+      ef << "{\"first_deriv_external_function\": {"
+         << "\"output\": \"TEFD_def_" << getIndxInTefTerms(first_deriv_symb_id, tef_terms)
+         << ", \"analytic_derivative\": true"
+         << ", \"function\": \"" << datatree.symbol_table.getName(first_deriv_symb_id) << "(";
+    }
+
+  writeJsonExternalFunctionArguments(ef, temporary_terms, tef_terms);
+  ef << ")\"}}";
+  efout.push_back(ef.str());
+}
+
 void
 FirstDerivExternalFunctionNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                                               bool lhs_rhs, const temporary_terms_t &temporary_terms,
@@ -5878,10 +6088,32 @@ SecondDerivExternalFunctionNode::composeDerivatives(const vector<expr_t> &dargs)
 }
 
 void
-SecondDerivExternalFunctionNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type,
+SecondDerivExternalFunctionNode::writeJsonOutput(ostream &output,
                                                  const temporary_terms_t &temporary_terms,
                                                  deriv_node_temp_terms_t &tef_terms) const
 {
+  // If current node is a temporary term
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<SecondDerivExternalFunctionNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
+  const int second_deriv_symb_id = datatree.external_functions_table.getSecondDerivSymbID(symb_id);
+  assert(second_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+  const int tmpIndex1 = inputIndex1 - 1;
+  const int tmpIndex2 = inputIndex2 - 1;
+
+  if (second_deriv_symb_id == symb_id)
+    output << "TEFDD_" << getIndxInTefTerms(symb_id, tef_terms)
+           << "[" << tmpIndex1 << "," << tmpIndex2 << "]";
+  else if (second_deriv_symb_id == eExtFunNotSet)
+    output << "TEFDD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex1 << "_" << inputIndex2;
+  else
+    output << "TEFDD_def_" << getIndxInTefTerms(second_deriv_symb_id, tef_terms)
+           << "[" << tmpIndex1 << "," << tmpIndex2 << "]";
 }
 
 void
@@ -6048,6 +6280,48 @@ SecondDerivExternalFunctionNode::writeExternalFunctionOutput(ostream &output, Ex
     }
 }
 
+void
+SecondDerivExternalFunctionNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                                                 const temporary_terms_t &temporary_terms,
+                                                                 deriv_node_temp_terms_t &tef_terms) const
+{
+  int second_deriv_symb_id = datatree.external_functions_table.getSecondDerivSymbID(symb_id);
+  assert(second_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+  /* For a node with derivs provided by the user function, call the method
+     on the non-derived node */
+  if (second_deriv_symb_id == symb_id)
+    {
+      expr_t parent = datatree.AddExternalFunction(symb_id, arguments);
+      parent->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+      return;
+    }
+
+  if (alreadyWrittenAsTefTerm(second_deriv_symb_id, tef_terms))
+    return;
+
+  stringstream ef;
+  if (second_deriv_symb_id == eExtFunNotSet)
+    ef << "{\"second_deriv_external_function\": {"
+       << "\"output\": \"TEFDD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex1 << "_" << inputIndex2 << "\""
+       << ", \"analytic_derivative\": false"
+       << ", \"wrt1\": " << inputIndex1
+       << ", \"wrt2\": " << inputIndex2
+       << ", \"function\": \"" << datatree.symbol_table.getName(symb_id) << "(";
+  else
+    {
+      tef_terms[make_pair(second_deriv_symb_id, arguments)] = (int) tef_terms.size();
+      ef << "{\"second_deriv_external_function\": {"
+         << "\"output\": \"TEFDD_def_" << getIndxInTefTerms(second_deriv_symb_id, tef_terms)
+         << ", \"analytic_derivative\": true"
+         << ", \"function\": \"" << datatree.symbol_table.getName(second_deriv_symb_id) << "(";
+    }
+
+  writeJsonExternalFunctionArguments(ef, temporary_terms, tef_terms);
+  ef << ")\"}}" << endl;
+  efout.push_back(ef.str());
+}
+
 expr_t
 SecondDerivExternalFunctionNode::cloneDynamic(DataTree &dynamic_datatree) const
 {
diff --git a/ExprNode.hh b/ExprNode.hh
index 32654071..e4e5d9bc 100644
--- a/ExprNode.hh
+++ b/ExprNode.hh
@@ -222,13 +222,21 @@ public:
   void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const;
 
   //! Writes output of node in JSON syntax
-  virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0;
+
+  virtual int precedenceJson(const temporary_terms_t &temporary_terms) const;
 
   //! Writes the output for an external function, ensuring that the external function is called as few times as possible using temporary terms
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
 
+  //! Write the JSON output of an external function in a string vector
+  //! Allows the insertion of commas if necessary
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
+
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -481,7 +489,7 @@ public:
   };
   virtual void prepareForDerivation();
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
-  virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual bool containsExternalFunction() const;
   virtual void collectDynamicVariables(SymbolType type_arg, set<pair<int, int> > &result) const;
   virtual void collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const;
@@ -531,7 +539,7 @@ public:
   VariableNode(DataTree &datatree_arg, int symb_id_arg, int lag_arg);
   virtual void prepareForDerivation();
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
-  virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual bool containsExternalFunction() const;
   virtual void collectDynamicVariables(SymbolType type_arg, set<pair<int, int> > &result) const;
   virtual void computeTemporaryTerms(map<expr_t, int > &reference_count,
@@ -607,11 +615,14 @@ public:
                                      map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
                                      bool is_matlab, NodeTreeReference tr) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
-  virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual bool containsExternalFunction() const;
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -690,16 +701,20 @@ public:
   BinaryOpNode(DataTree &datatree_arg, const expr_t arg1_arg,
                BinaryOpcode op_code_arg, const expr_t arg2_arg, int powerDerivOrder);
   virtual void prepareForDerivation();
+  virtual int precedenceJson(const temporary_terms_t &temporary_terms) const;
   virtual int precedence(ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const;
   virtual void computeTemporaryTerms(map<expr_t, pair<int, NodeTreeReference> > &reference_count,
                                      map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
                                      bool is_matlab, NodeTreeReference tr) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
-  virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual bool containsExternalFunction() const;
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -801,11 +816,14 @@ public:
                                      map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
                                      bool is_matlab, NodeTreeReference tr) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
-  virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual bool containsExternalFunction() const;
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -872,7 +890,7 @@ protected:
   int getIndxInTefTerms(int the_symb_id, deriv_node_temp_terms_t &tef_terms) const throw (UnknownFunctionNameAndArgs);
   //! Helper function to write output arguments of any given external function
   void writeExternalFunctionArguments(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
-  void writeJsonExternalFunctionArguments(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  void writeJsonExternalFunctionArguments(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
 public:
   AbstractExternalFunctionNode(DataTree &datatree_arg, int symb_id_arg,
                                const vector<expr_t> &arguments_arg);
@@ -881,11 +899,14 @@ public:
                                      map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
                                      bool is_matlab, NodeTreeReference tr) const = 0;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0;
-  virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0;
   virtual bool containsExternalFunction() const;
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const = 0;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const = 0;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -948,10 +969,13 @@ public:
                                      map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
                                      bool is_matlab, NodeTreeReference tr) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
-  virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -989,7 +1013,7 @@ public:
                                      vector< vector<temporary_terms_t> > &v_temporary_terms,
                                      int equation) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
-  virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual void compile(ostream &CompileCode, unsigned int &instruction_number,
                        bool lhs_rhs, const temporary_terms_t &temporary_terms,
                        const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -997,6 +1021,9 @@ public:
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -1029,7 +1056,7 @@ public:
                                      vector< vector<temporary_terms_t> > &v_temporary_terms,
                                      int equation) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
-  virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual void compile(ostream &CompileCode, unsigned int &instruction_number,
                        bool lhs_rhs, const temporary_terms_t &temporary_terms,
                        const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -1037,6 +1064,9 @@ public:
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
diff --git a/ExtendedPreprocessorTypes.hh b/ExtendedPreprocessorTypes.hh
index 1388cafc..26c8ac19 100644
--- a/ExtendedPreprocessorTypes.hh
+++ b/ExtendedPreprocessorTypes.hh
@@ -44,4 +44,13 @@ enum JsonFileOutputType
     file,                             // output JSON files to file
     standardout,                      // output JSON files to stdout
   };
+
+enum JsonOutputPointType
+  {
+    nojson,                            // don't output JSON
+    parsing,                           // output JSON after the parsing step
+    checkpass,                         // output JSON after the check pass
+    transformpass,                     // output JSON after the transform pass
+    computingpass                      // output JSON after the computing pass
+  };
 #endif
diff --git a/ModFile.cc b/ModFile.cc
index 78ae952a..4cf0ba1b 100644
--- a/ModFile.cc
+++ b/ModFile.cc
@@ -1248,7 +1248,44 @@ ModFile::writeExternalFilesJulia(const string &basename, FileOutputType output)
 }
 
 void
-ModFile::writeJsonOutput(const string &basename, JsonFileOutputType json_output_mode) const
+ModFile::writeJsonOutput(const string &basename, JsonOutputPointType json, JsonFileOutputType json_output_mode)
+{
+  if (json == nojson)
+    return;
+
+  if (json == parsing || json == checkpass)
+    symbol_table.freeze();
+
+  writeJsonOutputParsingCheck(basename, json_output_mode);
+
+  if (json == parsing || json == checkpass)
+    symbol_table.unfreeze();
+
+  if (json == computingpass)
+    writeJsonComputingPassOutput(basename, json_output_mode);
+
+  switch (json)
+    {
+    case parsing:
+      cout << "JSON written after Parsing step." << endl;
+      break;
+    case checkpass:
+      cout << "JSON written after Check step." << endl;
+      break;
+    case transformpass:
+      cout << "JSON written after Transform step." << endl;
+      break;
+    case computingpass:
+      cout << "JSON written after Computing step." << endl;
+      break;
+    case nojson:
+      cerr << "ModFile::writeJsonOutput: should not arrive here." << endl;
+      exit(EXIT_FAILURE);
+    }
+}
+
+void
+ModFile::writeJsonOutputParsingCheck(const string &basename, JsonFileOutputType json_output_mode) const
 {
   ostringstream output;
   output << "{" << endl;
@@ -1298,3 +1335,105 @@ ModFile::writeJsonOutput(const string &basename, JsonFileOutputType json_output_
       jsonOutputFile.close();
     }
 }
+
+void
+ModFile::writeJsonComputingPassOutput(const string &basename, JsonFileOutputType json_output_mode) const
+{
+  ostringstream static_output;
+  static_output << "{";
+  static_model.writeJsonComputingPassOutput(static_output);
+  static_output << "}" << endl;
+
+  ostringstream dynamic_output;
+  dynamic_output << "{";
+  dynamic_model.writeJsonComputingPassOutput(dynamic_output);
+  dynamic_output << "}" << endl;
+
+  ostringstream tmp_out, static_paramsd_output;
+  tmp_out << "";
+  static_paramsd_output << "";
+  static_model.writeJsonParamsDerivativesFile(tmp_out);
+  if (!tmp_out.str().empty())
+    static_paramsd_output << "{" << tmp_out.str() << "}" << endl;
+
+  ostringstream tmp1_out, dynamic_paramsd_output;
+  tmp1_out << "";
+  dynamic_paramsd_output << "";
+  dynamic_model.writeJsonParamsDerivativesFile(tmp1_out);
+  if (!tmp1_out.str().empty())
+    dynamic_paramsd_output << "{" << tmp1_out.str() << "}" << endl;
+
+  if (json_output_mode == standardout)
+    {
+      cout << static_output.str() << endl;
+      cout << dynamic_output.str() << endl;
+      if (!dynamic_paramsd_output.str().empty())
+        cout << dynamic_paramsd_output.str() << endl;
+      if (!static_paramsd_output.str().empty())
+        cout << static_paramsd_output.str() << endl;
+    }
+  else
+    {
+      if (basename.empty())
+        {
+          cerr << "ERROR: Missing file name" << endl;
+          exit(EXIT_FAILURE);
+        }
+
+      string fname_static, fname_dynamic;
+      fname_static = basename + "_static.json";
+      fname_dynamic = basename + "_dynamic.json";
+
+      ofstream jsonOutputFileStatic, jsonOutputFileDynamic;
+      jsonOutputFileStatic.open(fname_static.c_str(), ios::out | ios::binary);
+      if (!jsonOutputFileStatic.is_open())
+        {
+          cerr << "ERROR: Can't open file " << fname_static << " for writing" << endl;
+          exit(EXIT_FAILURE);
+        }
+
+      jsonOutputFileDynamic.open(fname_dynamic.c_str(), ios::out | ios::binary);
+      if (!jsonOutputFileDynamic.is_open())
+        {
+          cerr << "ERROR: Can't open file " << fname_dynamic << " for writing" << endl;
+          exit(EXIT_FAILURE);
+        }
+
+      jsonOutputFileStatic << static_output.str();
+      jsonOutputFileStatic.close();
+      jsonOutputFileDynamic << dynamic_output.str();
+      jsonOutputFileDynamic.close();
+
+      if (!static_paramsd_output.str().empty())
+        {
+          string fname_static_params;
+          fname_static_params = basename + "_static_params_derivs.json";
+          ofstream jsonOutputFileStaticParamsDerivs;
+          jsonOutputFileStaticParamsDerivs.open(fname_static_params.c_str(), ios::out | ios::binary);
+          if (!jsonOutputFileStaticParamsDerivs.is_open())
+            {
+              cerr << "ERROR: Can't open file " << fname_static_params << " for writing" << endl;
+              exit(EXIT_FAILURE);
+            }
+
+          jsonOutputFileStaticParamsDerivs << static_paramsd_output.str();
+          jsonOutputFileStaticParamsDerivs.close();
+        }
+
+      if (!dynamic_paramsd_output.str().empty())
+        {
+          string fname_dynamic_params;
+          fname_dynamic_params = basename + "_params_derivs.json";
+          ofstream jsonOutputFileDynamicParamsDerivs;
+          jsonOutputFileDynamicParamsDerivs.open(fname_dynamic_params.c_str(), ios::out | ios::binary);
+          if (!jsonOutputFileDynamicParamsDerivs.is_open())
+            {
+              cerr << "ERROR: Can't open file " << fname_dynamic_params << " for writing" << endl;
+              exit(EXIT_FAILURE);
+            }
+
+          jsonOutputFileDynamicParamsDerivs << dynamic_paramsd_output.str();
+          jsonOutputFileDynamicParamsDerivs.close();
+        }
+    }
+}
diff --git a/ModFile.hh b/ModFile.hh
index b83f984d..684d592e 100644
--- a/ModFile.hh
+++ b/ModFile.hh
@@ -117,6 +117,9 @@ private:
   ModFileStructure mod_file_struct;
   //! Warnings Encountered
   WarningConsolidation &warnings;
+  //! Functions used in writing of JSON outut. See writeJsonOutput
+  void writeJsonOutputParsingCheck(const string &basename, JsonFileOutputType json_output_mode) const;
+  void writeJsonComputingPassOutput(const string &basename, JsonFileOutputType json_output_mode) const;
 
 public:
   //! Add a statement
@@ -171,7 +174,7 @@ public:
   //! Initially created to enable Julia to work with .mod files
   //! Potentially outputs ModFile after the various parts of processing (parsing, checkPass, transformPass, computingPass)
   //! Allows user of other host language platforms (python, fortran, etc) to provide support for dynare .mod files
-  void writeJsonOutput(const string &basename, JsonFileOutputType json_output_mode) const;
+  void writeJsonOutput(const string &basename, JsonOutputPointType json, JsonFileOutputType json_output_mode);
 };
 
 #endif // ! MOD_FILE_HH
diff --git a/ModelTree.cc b/ModelTree.cc
index 444aec2b..3e2b7395 100644
--- a/ModelTree.cc
+++ b/ModelTree.cc
@@ -1292,6 +1292,59 @@ ModelTree::writeTemporaryTerms(const temporary_terms_t &tt, const temporary_term
       }
 }
 
+void
+ModelTree::writeJsonTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, ostream &output,
+                                   deriv_node_temp_terms_t &tef_terms, string &concat) const
+{
+  // Local var used to keep track of temp nodes already written
+  bool wrote_term = false;
+  temporary_terms_t tt2 = ttm1;
+
+  output << "\"external_functions_temporary_terms_" << concat << "\": [";
+  for (temporary_terms_t::const_iterator it = tt.begin();
+       it != tt.end(); it++)
+    if (ttm1.find(*it) == ttm1.end())
+      {
+        if (dynamic_cast<AbstractExternalFunctionNode *>(*it) != NULL)
+          {
+            if (wrote_term)
+              output << ", ";
+            vector<string> efout;
+            (*it)->writeJsonExternalFunctionOutput(efout, tt2, tef_terms);
+            for (vector<string>::const_iterator it1 = efout.begin(); it1 != efout.end(); it1++)
+              {
+                if (it1 != efout.begin())
+                  output << ", ";
+                output << *it1;
+              }
+            wrote_term = true;
+          }
+        tt2.insert(*it);
+      }
+
+  tt2 = ttm1;
+  wrote_term = false;
+  output << "]"
+         << ", \"temporary_terms_" << concat << "\": [";
+  for (temporary_terms_t::const_iterator it = tt.begin();
+       it != tt.end(); it++)
+    if (ttm1.find(*it) == ttm1.end())
+      {
+        if (wrote_term)
+          output << ", ";
+        output << "{\"temporary_term\": \"";
+        (*it)->writeJsonOutput(output, tt, tef_terms);
+        output << " = ";
+        (*it)->writeJsonOutput(output, tt2, tef_terms);
+        output << "\"}" << endl;
+        wrote_term = true;
+
+        // Insert current node into tt2
+        tt2.insert(*it);
+      }
+  output << "]";
+}
+
 void
 ModelTree::fixNestedParenthesis(ostringstream &output, map<string, string> &tmp_paren_vars, bool &message_printed) const
 {
@@ -1481,6 +1534,51 @@ ModelTree::writeModelLocalVariables(ostream &output, ExprNodeOutputType output_t
     }
 }
 
+void
+ModelTree::writeJsonModelLocalVariables(ostream &output, deriv_node_temp_terms_t &tef_terms) const
+{
+  /* Collect all model local variables appearing in equations, and print only
+     them. Printing unused model local variables can lead to a crash (see
+     ticket #101). */
+  set<int> used_local_vars;
+
+  // Use an empty set for the temporary terms
+  const temporary_terms_t tt;
+
+  for (size_t i = 0; i < equations.size(); i++)
+    equations[i]->collectVariables(eModelLocalVariable, used_local_vars);
+
+  output << "\"external_functions_model_local_variables\": [";
+  for (set<int>::const_iterator it = used_local_vars.begin();
+       it != used_local_vars.end(); ++it)
+    {
+      vector<string> efout;
+      expr_t value = local_variables_table.find(*it)->second;
+      value->writeJsonExternalFunctionOutput(efout, tt, tef_terms);
+      for (vector<string>::const_iterator it1 = efout.begin(); it1 != efout.end(); it1++)
+        {
+          if (it1 != efout.begin())
+            output << ", ";
+          output << *it1;
+        }
+    }
+  output << "]"
+         << ", \"model_local_variables\": [";
+  for (set<int>::const_iterator it = used_local_vars.begin();
+       it != used_local_vars.end(); ++it)
+    {
+      int id = *it;
+      expr_t value = local_variables_table.find(id)->second;
+
+      /* We append underscores to avoid name clashes with "g1" or "oo_" (see
+         also VariableNode::writeOutput) */
+      output << "{\"" << symbol_table.getName(id) << "__ = ";
+      value->writeJsonOutput(output, tt, tef_terms);
+      output << "\"}" << endl;
+    }
+  output << "]";
+}
+
 void
 ModelTree::writeModelEquations(ostream &output, ExprNodeOutputType output_type) const
 {
@@ -1920,37 +2018,76 @@ bool ModelTree::isNonstationary(int symb_id) const
 }
 
 void
-ModelTree::writeJsonModelEquations(ostream &output) const
+ModelTree::writeJsonModelEquations(ostream &output, bool residuals) const
 {
   deriv_node_temp_terms_t tef_terms;
   vector<pair<string,string> > eqtags;
-  output << endl << ",\"model\":[" << endl;
+  temporary_terms_t tt_empty;
+  if (residuals)
+    output << endl << ",\"residuals\":[" << endl;
+  else
+    output << endl << ",\"model\":[" << endl;
   for (int eq = 0; eq < (int) equations.size(); eq++)
     {
-      output << "{ \"equation\": \"";
-      equations[eq]->writeJsonOutput(output, oMatlabDynamicModel, temporary_terms, tef_terms);
-      output << "\", \"line\": " << equations_lineno[eq];
-      for (vector<pair<int, pair<string, string> > >::const_iterator it = equation_tags.begin();
-           it != equation_tags.end(); it++)
-        if (it->first == eq)
-          eqtags.push_back(it->second);
-
-      if (!eqtags.empty())
+      if (eq > 0)
+        output << ", ";
+
+      if (residuals)
         {
-          output << ", \"tags\": {";
-          int i = 0;
-          for (vector<pair<string, string> >:: const_iterator it = eqtags.begin(); it != eqtags.end(); it++, i++)
+          BinaryOpNode *eq_node = equations[eq];
+          expr_t lhs = eq_node->get_arg1();
+          expr_t rhs = eq_node->get_arg2();
+
+          output << "{\"residual\": {"
+                 << "\"lhs\": \"";
+          lhs->writeJsonOutput(output, temporary_terms, tef_terms);
+          output << "\"";
+
+          output << ", \"rhs\": \"";
+          rhs->writeJsonOutput(output, temporary_terms, tef_terms);
+          output << "\"";
+          try
+            {
+              // Test if the right hand side of the equation is empty.
+              if (rhs->eval(eval_context_t()) != 0)
+                {
+                  output << ", \"rhs\": \"";
+                  rhs->writeJsonOutput(output, temporary_terms, tef_terms);
+                  output << "\"";
+                }
+            }
+          catch (ExprNode::EvalException &e)
             {
-              if (i != 0)
-                output << ", ";
-              output << "\"" << it->first << "\": \"" << it->second << "\"";
             }
           output << "}";
-          eqtags.clear();
         }
-      output << "}";
-      if (eq < (int) equations.size() - 1)
-        output << "," << endl;
+      else
+        {
+          output << "{\"equation\": \"";
+          equations[eq]->writeJsonOutput(output, tt_empty, tef_terms);
+          output << "\""
+                 << ", \"line\": " << equations_lineno[eq];
+
+          for (vector<pair<int, pair<string, string> > >::const_iterator it = equation_tags.begin();
+               it != equation_tags.end(); it++)
+            if (it->first == eq)
+              eqtags.push_back(it->second);
+
+          if (!eqtags.empty())
+            {
+              output << ", \"tags\": {";
+              int i = 0;
+              for (vector<pair<string, string> >:: const_iterator it = eqtags.begin(); it != eqtags.end(); it++, i++)
+                {
+                  if (i != 0)
+                    output << ", ";
+                  output << "\"" << it->first << "\": \"" << it->second << "\"";
+                }
+              output << "}";
+              eqtags.clear();
+            }
+        }
+      output << "}" << endl;
     }
   output << endl << "]" << endl;
 }
diff --git a/ModelTree.hh b/ModelTree.hh
index d74598d8..ac6bfca8 100644
--- a/ModelTree.hh
+++ b/ModelTree.hh
@@ -186,6 +186,7 @@ protected:
   void computeParamsDerivativesTemporaryTerms();
 //! Writes temporary terms
   void writeTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const;
+  void writeJsonTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, ostream &output, deriv_node_temp_terms_t &tef_terms, string &concat) const;
   //! Compiles temporary terms
   void compileTemporaryTerms(ostream &code_file, unsigned int &instruction_number, const temporary_terms_t &tt, map_idx_t map_idx, bool dynamic, bool steady_dynamic) const;
   //! Adds informations for simulation in a binary file
@@ -200,7 +201,10 @@ protected:
   //! Writes model equations
   void writeModelEquations(ostream &output, ExprNodeOutputType output_type) const;
   //! Writes JSON model equations
-  void writeJsonModelEquations(ostream &output) const;
+  //! if residuals = true, we are writing the dynamic/static model.
+  //! Otherwise, just the model equations (with line numbers, no tmp terms)
+  void writeJsonModelEquations(ostream &output, bool residuals) const;
+  void writeJsonModelLocalVariables(ostream &output, deriv_node_temp_terms_t &tef_terms) const;
   //! Compiles model equations
   void compileModelEquations(ostream &code_file, unsigned int &instruction_number, const temporary_terms_t &tt, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic) const;
 
diff --git a/NumericalInitialization.cc b/NumericalInitialization.cc
index 22c013b3..59ef96ad 100644
--- a/NumericalInitialization.cc
+++ b/NumericalInitialization.cc
@@ -68,7 +68,7 @@ InitParamStatement::writeJsonOutput(ostream &output) const
 {
   deriv_node_temp_terms_t tef_terms;
   output << "{\"statementName\": \"param_init\", \"name\": \"" << symbol_table.getName(symb_id) << "\", " << "\"value\": \"";
-  param_value->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+  param_value->writeJsonOutput(output, temporary_terms_t(), tef_terms);
   output << "\"}";
 }
 
@@ -184,7 +184,7 @@ InitOrEndValStatement::writeJsonInitValues(ostream &output) const
       if (it != init_values.begin())
         output << ", ";
       output << "{\"name\": \"" << symbol_table.getName(it->first) << "\", " << "\"value\": \"";
-      it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}";
     }
 }
@@ -428,7 +428,7 @@ HistValStatement::writeJsonOutput(ostream &output) const
       output << "{ \"name\": \"" << symbol_table.getName(it->first.first) << "\""
              << ", \"lag\": " << it->first.second
              << ", \"value\": \"";
-      it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}";
     }
   output << "]}";
@@ -526,11 +526,11 @@ HomotopyStatement::writeJsonOutput(ostream &output) const
       output << "{\"name\": \"" << symbol_table.getName(it->first) << "\""
              << ", \"initial_value\": \"";
       if (it->second.first != NULL)
-        it->second.first->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+        it->second.first->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       else
         output << "NaN";
       output << "\", \"final_value\": \"";
-      it->second.second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->second.second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}";
     }
   output << "]"
diff --git a/Shocks.cc b/Shocks.cc
index 95391092..4835b370 100644
--- a/Shocks.cc
+++ b/Shocks.cc
@@ -87,7 +87,7 @@ AbstractShocksStatement::writeJsonDetShocks(ostream &output) const
             output << "{\"period1\": " << it1->period1 << ", "
                    << "\"period2\": " << it1->period2 << ", "
                    << "\"value\": \"";
-            it1->value->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+            it1->value->writeJsonOutput(output, temporary_terms_t(), tef_terms);
             output << "\"}";
           }
       output << "]}";
@@ -174,7 +174,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const
         output << ", ";
       output << "{\"name\": \"" << symbol_table.getName(it->first) << "\", "
              << "\"variance\": \"";
-      it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}";
     }
   output << "]"
@@ -185,7 +185,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const
         output << ", ";
       output << "{\"name\": \"" << symbol_table.getName(it->first) << "\", "
              << "\"stderr\": \"";
-      it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}";
     }
   output << "]"
@@ -198,7 +198,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const
              << "\"name\": \"" << symbol_table.getName(it->first.first) << "\", "
              << "\"name2\": \"" << symbol_table.getName(it->first.second) << "\", "
              << "\"covariance\": \"";
-      it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}";
     }
   output << "]"
@@ -211,7 +211,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const
              << "\"name\": \"" << symbol_table.getName(it->first.first) << "\", "
              << "\"name2\": \"" << symbol_table.getName(it->first.second) << "\", "
              << "\"correlation\": \"";
-      it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms);
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
       output << "\"}";
     }
   output << "]"
diff --git a/StaticModel.cc b/StaticModel.cc
index a7652f9b..4516a886 100644
--- a/StaticModel.cc
+++ b/StaticModel.cc
@@ -2414,3 +2414,287 @@ StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) cons
 
   paramsDerivsFile.close();
 }
+
+void
+StaticModel::writeJsonComputingPassOutput(ostream &output) const
+{
+  ostringstream model_local_vars_output;   // Used for storing model local vars
+  ostringstream model_output;              // Used for storing model
+  ostringstream jacobian_output;           // Used for storing jacobian equations
+  ostringstream hessian_output;            // Used for storing Hessian equations
+  ostringstream third_derivatives_output;  // Used for storing third order derivatives equations
+
+  deriv_node_temp_terms_t tef_terms;
+  temporary_terms_t temp_term_empty;
+  temporary_terms_t temp_term_union = temporary_terms_res;
+  temporary_terms_t temp_term_union_m_1;
+
+  string concat = "";
+
+  writeJsonModelLocalVariables(model_local_vars_output, tef_terms);
+
+  writeJsonTemporaryTerms(temporary_terms_res, temp_term_union_m_1, model_output, tef_terms, concat);
+
+  writeJsonModelEquations(model_output, true);
+
+  int nrows = equations.size();
+  int JacobianColsNbr = symbol_table.endo_nbr();
+  int hessianColsNbr = JacobianColsNbr*JacobianColsNbr;
+
+  // Write Jacobian w.r. to endogenous only
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g1.begin(), temporary_terms_g1.end());
+  concat = "jacobian";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, jacobian_output, tef_terms, concat);
+  jacobian_output << ", \"jacobian\": {"
+                  << "  \"nrows\": " << nrows
+                  << ", \"ncols\": " << JacobianColsNbr
+                  << ", \"entries\": [";
+  for (first_derivatives_t::const_iterator it = first_derivatives.begin();
+       it != first_derivatives.end(); it++)
+    {
+      if (it != first_derivatives.begin())
+        jacobian_output << ", ";
+
+      int eq = it->first.first;
+      string var = symbol_table.getName(getSymbIDByDerivID(it->first.second));
+      expr_t d1 = it->second;
+
+      jacobian_output << "{\"eq\": " << eq
+                      << ", \"var\": \"" << var << "\""
+                      << ", \"val\": \"";
+      d1->writeJsonOutput(jacobian_output, temp_term_union, tef_terms);
+      jacobian_output << "\"}" << endl;
+    }
+  jacobian_output << "]}";
+
+  int g2ncols = symbol_table.endo_nbr() * symbol_table.endo_nbr();
+  // Write Hessian w.r. to endogenous only (only if 2nd order derivatives have been computed)
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g2.begin(), temporary_terms_g2.end());
+  concat = "hessian";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, hessian_output, tef_terms, concat);
+  hessian_output << ", \"hessian\": {"
+                 << "  \"nrows\": " << equations.size()
+                 << ", \"ncols\": " << g2ncols
+                 << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = second_derivatives.begin();
+       it != second_derivatives.end(); it++)
+    {
+      if (it != second_derivatives.begin())
+        hessian_output << ", ";
+
+      int eq = it->first.first;
+      string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first));
+      string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second));
+      expr_t d2 = it->second;
+
+      hessian_output << "{\"eq\": " << eq
+                     << ", \"var1\": \"" << var1 << "\""
+                     << ", \"var2\": \"" << var2 << "\""
+                     << ", \"val\": \"";
+      d2->writeJsonOutput(hessian_output, temp_term_union, tef_terms);
+      hessian_output << "\"}" << endl;
+    }
+  hessian_output << "]}";
+
+  // Writing third derivatives
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g3.begin(), temporary_terms_g3.end());
+  concat = "third_derivatives";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, third_derivatives_output, tef_terms, concat);
+  third_derivatives_output << ", \"third_derivative\": {"
+                           << "  \"nrows\": " << equations.size()
+                           << ", \"ncols\": " << hessianColsNbr * JacobianColsNbr
+                           << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = third_derivatives.begin();
+       it != third_derivatives.end(); it++)
+    {
+      if (it != third_derivatives.begin())
+        third_derivatives_output << ", ";
+
+      int eq = it->first.first;
+      string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first));
+      string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first));
+      string var3 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second));
+      expr_t d3 = it->second;
+
+      third_derivatives_output << "{\"eq\": " << eq
+                               << ", \"var1\": \"" << var1 << "\""
+                               << ", \"var2\": \"" << var2 << "\""
+                               << ", \"var3\": \"" << var3 << "\""
+                               << ", \"val\": \"";
+      d3->writeJsonOutput(third_derivatives_output, temp_term_union, tef_terms);
+      third_derivatives_output << "\"}" << endl;
+    }
+  third_derivatives_output << "]}";
+
+  output << "\"static_model_derivatives\": {"
+         << model_local_vars_output.str()
+         << ", " << model_output.str()
+         << ", " << jacobian_output.str()
+         << ", " << hessian_output.str()
+         << ", " << third_derivatives_output.str()
+         << "}";
+}
+
+void
+StaticModel::writeJsonParamsDerivativesFile(ostream &output) const
+{
+  if (!residuals_params_derivatives.size()
+      && !residuals_params_second_derivatives.size()
+      && !jacobian_params_derivatives.size()
+      && !jacobian_params_second_derivatives.size()
+      && !hessian_params_derivatives.size())
+    return;
+
+  ostringstream model_local_vars_output;   // Used for storing model local vars
+  ostringstream model_output;              // Used for storing model temp vars and equations
+  ostringstream jacobian_output;           // Used for storing jacobian equations
+  ostringstream hessian_output;            // Used for storing Hessian equations
+  ostringstream hessian1_output;           // Used for storing Hessian equations
+  ostringstream third_derivs_output;       // Used for storing third order derivatives equations
+  ostringstream third_derivs1_output;      // Used for storing third order derivatives equations
+
+  deriv_node_temp_terms_t tef_terms;
+  writeJsonModelLocalVariables(model_local_vars_output, tef_terms);
+
+  temporary_terms_t temp_terms_empty;
+  string concat = "all";
+  writeJsonTemporaryTerms(params_derivs_temporary_terms, temp_terms_empty, model_output, tef_terms, concat);
+  jacobian_output << "\"deriv_wrt_params\": {"
+                  << "  \"neqs\": " << equations.size()
+                  << ", \"nparamcols\": " << symbol_table.param_nbr()
+                  << ", \"entries\": [";
+  for (first_derivatives_t::const_iterator it = residuals_params_derivatives.begin();
+       it != residuals_params_derivatives.end(); it++)
+    {
+      if (it != residuals_params_derivatives.begin())
+        jacobian_output << ", ";
+
+      int eq = it->first.first;
+      string param = symbol_table.getName(getSymbIDByDerivID(it->first.second));
+      expr_t d1 = it->second;
+
+      jacobian_output << "{\"eq\": " << eq
+                      << ", \"param\": \"" << param << "\""
+                      << ", \"val\": \"";
+      d1->writeJsonOutput(jacobian_output, params_derivs_temporary_terms, tef_terms);
+      jacobian_output << "\"}" << endl;
+    }
+  jacobian_output << "]}";
+  hessian_output << "\"deriv_jacobian_wrt_params\": {"
+                 << "  \"neqs\": " << equations.size()
+                 << ", \"nvarcols\": " << symbol_table.endo_nbr()
+                 << ", \"nparamcols\": " << symbol_table.param_nbr()
+                 << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = jacobian_params_derivatives.begin();
+       it != jacobian_params_derivatives.end(); it++)
+    {
+      if (it != jacobian_params_derivatives.begin())
+        hessian_output << ", ";
+
+      int eq = it->first.first;
+      string var = symbol_table.getName(getSymbIDByDerivID(it->first.second.first));
+      string param = symbol_table.getName(getSymbIDByDerivID(it->first.second.second));
+      expr_t d2 = it->second;
+
+      hessian_output << "{\"eq\": " << eq
+                     << ", \"var\": \"" << var << "\""
+                     << ", \"param\": \"" << param << "\""
+                     << ", \"val\": \"";
+      d2->writeJsonOutput(hessian_output, params_derivs_temporary_terms, tef_terms);
+      hessian_output << "\"}" << endl;
+    }
+  hessian_output << "]}";
+
+  hessian1_output << "\"second_deriv_residuals_wrt_params\": {"
+                  << "  \"nrows\": " << equations.size()
+                  << ", \"nparam1cols\": " << symbol_table.param_nbr()
+                  << ", \"nparam2cols\": " << symbol_table.param_nbr()
+                  << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = residuals_params_second_derivatives.begin();
+       it != residuals_params_second_derivatives.end(); ++it)
+    {
+      if (it != residuals_params_second_derivatives.begin())
+        hessian1_output << ", ";
+
+      int eq = it->first.first;
+      string param1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first));
+      string param2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second));
+      expr_t d2 = it->second;
+
+      hessian1_output << "{\"eq\": " << eq
+                     << ", \"param1\": \"" << param1 << "\""
+                     << ", \"param2\": \"" << param2 << "\""
+                     << ", \"val\": \"";
+      d2->writeJsonOutput(hessian1_output, params_derivs_temporary_terms, tef_terms);
+      hessian1_output << "\"}" << endl;
+    }
+  hessian1_output << "]}";
+  third_derivs_output << "\"second_deriv_jacobian_wrt_params\": {"
+                      << "  \"neqs\": " << equations.size()
+                      << ", \"nvarcols\": " << symbol_table.endo_nbr()
+                      << ", \"nparam1cols\": " << symbol_table.param_nbr()
+                      << ", \"nparam2cols\": " << symbol_table.param_nbr()
+                      << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = jacobian_params_second_derivatives.begin();
+       it != jacobian_params_second_derivatives.end(); ++it)
+    {
+      if (it != jacobian_params_second_derivatives.begin())
+        third_derivs_output << ", ";
+
+      int eq = it->first.first;
+      string var = symbol_table.getName(it->first.second.first);
+      string param1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first));
+      string param2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second));
+      expr_t d2 = it->second;
+
+      third_derivs_output << "{\"eq\": " << eq
+                          << ", \"var\": \"" << var << "\""
+                          << ", \"param1\": \"" << param1 << "\""
+                          << ", \"param2\": \"" << param2 << "\""
+                          << ", \"val\": \"";
+      d2->writeJsonOutput(third_derivs_output, params_derivs_temporary_terms, tef_terms);
+      third_derivs_output << "\"}" << endl;
+    }
+  third_derivs_output << "]}" << endl;
+
+  third_derivs1_output << "\"derivative_hessian_wrt_params\": {"
+                       << "  \"neqs\": " << equations.size()
+                       << ", \"nvar1cols\": " << symbol_table.endo_nbr()
+                       << ", \"nvar2cols\": " << symbol_table.endo_nbr()
+                       << ", \"nparamcols\": " << symbol_table.param_nbr()
+                       << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = hessian_params_derivatives.begin();
+       it != hessian_params_derivatives.end(); ++it)
+    {
+      if (it != hessian_params_derivatives.begin())
+        third_derivs1_output << ", ";
+
+      int eq = it->first.first;
+      string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first));
+      string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first));
+      string param = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second));
+      expr_t d2 = it->second;
+
+      third_derivs1_output << "{\"eq\": " << eq
+                           << ", \"var1\": \"" << var1 << "\""
+                           << ", \"var2\": \"" << var2 << "\""
+                           << ", \"param1\": \"" << param << "\""
+                           << ", \"val\": \"";
+      d2->writeJsonOutput(third_derivs1_output, params_derivs_temporary_terms, tef_terms);
+      third_derivs1_output << "\"}" << endl;
+    }
+  third_derivs1_output << "]}" << endl;
+
+  output << "\"static_model_params_derivatives\": {"
+         << model_local_vars_output.str()
+         << ", " << model_output.str()
+         << ", " << jacobian_output.str()
+         << ", " << hessian_output.str()
+         << ", " << hessian1_output.str()
+         << ", " << third_derivs_output.str()
+         << ", " << third_derivs1_output.str()
+         << "}";
+}
diff --git a/StaticModel.hh b/StaticModel.hh
index bf6cad6f..04d41e14 100644
--- a/StaticModel.hh
+++ b/StaticModel.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003-2016 Dynare Team
+ * Copyright (C) 2003-2017 Dynare Team
  *
  * This file is part of Dynare.
  *
@@ -173,6 +173,12 @@ public:
   //! Writes static model file
   void writeStaticFile(const string &basename, bool block, bool bytecode, bool use_dll, bool julia) const;
 
+  //! Write JSON representation of static model
+  void writeJsonComputingPassOutput(ostream &output) const;
+
+  //! Writes file containing static parameters derivatives
+  void writeJsonParamsDerivativesFile(ostream &output) const;
+
   //! Writes file containing static parameters derivatives
   void writeParamsDerivativesFile(const string &basename, bool julia) const;
 
diff --git a/SymbolTable.cc b/SymbolTable.cc
index 04b46de0..d6150183 100644
--- a/SymbolTable.cc
+++ b/SymbolTable.cc
@@ -1022,7 +1022,7 @@ void
 SymbolTable::writeJsonVarVector(ostream &output, const vector<int> &varvec) const
 {
   output << "[";
-  for (int i = 0; i < varvec.size(); i++)
+  for (size_t i = 0; i < varvec.size(); i++)
     {
       output << endl << "{"
              << "\"name\":\"" << getName(varvec[i]) << "\", "
-- 
GitLab