From 8698b4c540f2f9881f2201a30b6d08344b23068f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Tue, 5 Feb 2019 17:14:59 +0100
Subject: [PATCH] Dynare++: fix computation of IRFs

Since the introduction of the --burn option (in Dynare++ shipped with Dynare
4.3.0), the IRFs reported by Dynare++ were wrong.

The IRFs are computed using a generalized IRF method: the result is
the (average) difference between a simulation with shock and a simulation
without shock. The problem was that the two simulations were not using the same
starting point.

Closes #1634
---
 dynare++/kord/decision_rule.cc | 14 ++++++++------
 dynare++/kord/decision_rule.hh | 12 ++++++++++--
 2 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/dynare++/kord/decision_rule.cc b/dynare++/kord/decision_rule.cc
index fc5dbce2e..7afc2b97a 100644
--- a/dynare++/kord/decision_rule.cc
+++ b/dynare++/kord/decision_rule.cc
@@ -106,7 +106,7 @@ SimResults::simulate(int num_sim, const DecisionRule &dr, const Vector &start,
    and shocks are thrown away. */
 
 bool
-SimResults::addDataSet(TwoDMatrix *d, ExplicitShockRealization *sr)
+SimResults::addDataSet(TwoDMatrix *d, ExplicitShockRealization *sr, const ConstVector &st)
 {
   KORD_RAISE_IF(d->nrows() != num_y,
                 "Incompatible number of rows for SimResults::addDataSets");
@@ -118,6 +118,10 @@ SimResults::addDataSet(TwoDMatrix *d, ExplicitShockRealization *sr)
       data.push_back(new TwoDMatrix((const TwoDMatrix &) (*d), num_burn, num_per));
       shocks.push_back(new ExplicitShockRealization(
                                                     ConstTwoDMatrix(sr->getShocks(), num_burn, num_per)));
+      if (num_burn == 0)
+        start.emplace_back(st);
+      else
+        start.emplace_back(d->getCol(num_burn-1));
       ret = true;
     }
 
@@ -486,7 +490,7 @@ SimulationWorker::operator()(std::mutex &mut)
   TwoDMatrix *m = dr.simulate(em, np, st, *esr);
   {
     std::unique_lock<std::mutex> lk{mut};
-    res.addDataSet(m, esr);
+    res.addDataSet(m, esr, st);
   }
 }
 
@@ -499,13 +503,11 @@ SimulationIRFWorker::operator()(std::mutex &mut)
   auto *esr
     = new ExplicitShockRealization(res.control.getShocks(idata));
   esr->addToShock(ishock, 0, imp);
-  const TwoDMatrix &data = res.control.getData(idata);
-  Vector st{data.getCol(res.control.getNumBurn())};
-  TwoDMatrix *m = dr.simulate(em, np, st, *esr);
+  TwoDMatrix *m = dr.simulate(em, np, res.control.getStart(idata), *esr);
   m->add(-1.0, res.control.getData(idata));
   {
     std::unique_lock<std::mutex> lk{mut};
-    res.addDataSet(m, esr);
+    res.addDataSet(m, esr, res.control.getStart(idata));
   }
 }
 
diff --git a/dynare++/kord/decision_rule.hh b/dynare++/kord/decision_rule.hh
index ef7210354..532c5ec22 100644
--- a/dynare++/kord/decision_rule.hh
+++ b/dynare++/kord/decision_rule.hh
@@ -718,7 +718,8 @@ DRFixPoint<t>::calcFixPoint(emethod em, Vector &out)
 
 /* This is a basically a number of matrices of the same dimensions,
    which can be obtained as simulation results from a given decision rule
-   and shock realizations. We also store the realizations of shocks. */
+   and shock realizations. We also store the realizations of shocks and the
+   starting point of each simulation. */
 
 class ExplicitShockRealization;
 class SimResults
@@ -729,6 +730,7 @@ protected:
   int num_burn;
   vector<TwoDMatrix *> data;
   vector<ExplicitShockRealization *> shocks;
+  vector<ConstVector> start;
 public:
   SimResults(int ny, int nper, int nburn = 0)
     : num_y(ny), num_per(nper), num_burn(nburn)
@@ -765,7 +767,13 @@ public:
   {
     return *(shocks[i]);
   }
-  bool addDataSet(TwoDMatrix *d, ExplicitShockRealization *sr);
+  const ConstVector &
+  getStart(int i) const
+  {
+    return start[i];
+  }
+
+  bool addDataSet(TwoDMatrix *d, ExplicitShockRealization *sr, const ConstVector &st);
   void writeMat(const char *base, const char *lname) const;
   void writeMat(mat_t *fd, const char *lname) const;
 };
-- 
GitLab