diff --git a/CodeInterpreter.hh b/CodeInterpreter.hh
index 8a9ef76ffdb8888791946d716903df17851e9969..b8b65a5300050bb2391326ca1e0f2302189c2fcd 100644
--- a/CodeInterpreter.hh
+++ b/CodeInterpreter.hh
@@ -136,7 +136,8 @@ enum SymbolType
     eParameter = 4,                //!< Parameter
     eModelLocalVariable = 10,      //!< Local variable whose scope is model (pound expression)
     eModFileLocalVariable = 11,    //!< Local variable whose scope is mod file (model excluded)
-    eExternalFunction = 12         //!< External (user-defined) function
+    eExternalFunction = 12,        //!< External (user-defined) function
+    eTrend = 13                    //!< Trend variable
   };
 
 enum ExpressionType
diff --git a/DataTree.hh b/DataTree.hh
index 0bd3a813ab36bec9993629a27c7738c18f9a6aa8..648c62c7d4001f7534355db8e9244aa272d05fdf 100644
--- a/DataTree.hh
+++ b/DataTree.hh
@@ -213,6 +213,16 @@ public:
   {
   };
 
+  //! Raised when a trend is declared twice
+  class TrendException
+  {
+  public:
+    string name;
+    TrendException(const string &name_arg) : name(name_arg)
+    {
+    }
+  };
+
   //! Returns the derivation ID, or throws an exception if the derivation ID does not exist
   virtual int getDerivID(int symb_id, int lag) const throw (UnknownDerivIDException);
   //! Returns the column of the dynamic Jacobian associated to a derivation ID
diff --git a/DynamicModel.cc b/DynamicModel.cc
index ea4b544ed11e4ac66d0514e81a17f29d7d2fa0d9..e7ecc7751f17e3b39554162c2008b67289bca9d6 100644
--- a/DynamicModel.cc
+++ b/DynamicModel.cc
@@ -2411,6 +2411,13 @@ DynamicModel::collect_first_order_derivatives_endogenous()
   return endo_derivatives;
 }
 
+void
+DynamicModel::runTrendTest(const eval_context_t &eval_context)
+{
+  computeDerivIDs();
+  testTrendDerivativesEqualToZero(eval_context);
+}
+
 void
 DynamicModel::computingPass(bool jacobianExo, bool hessian, bool thirdDerivatives, bool paramsDerivatives,
                             const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll, bool bytecode)
@@ -2832,6 +2839,29 @@ DynamicModel::writeDynamicFile(const string &basename, bool block, bool bytecode
     writeDynamicMFile(t_basename);
 }
 
+void
+DynamicModel::cloneDynamic(DynamicModel &dynamic_model) const
+{
+  /* Ensure that we are using the same symbol table, because at many places we manipulate
+     symbol IDs rather than strings */
+  assert(&symbol_table == &dynamic_model.symbol_table);
+
+  // Convert model local variables (need to be done first)
+  for (map<int, expr_t>::const_iterator it = local_variables_table.begin();
+       it != local_variables_table.end(); it++)
+    dynamic_model.AddLocalVariable(it->first, it->second->cloneDynamic(dynamic_model));
+
+  // Convert equations
+  for (vector<BinaryOpNode *>::const_iterator it = equations.begin();
+       it != equations.end(); it++)
+    dynamic_model.addEquation((*it)->cloneDynamic(dynamic_model));
+
+  // Convert auxiliary equations
+  for (deque<BinaryOpNode *>::const_iterator it = aux_equations.begin();
+       it != aux_equations.end(); it++)
+    dynamic_model.addAuxEquation((*it)->cloneDynamic(dynamic_model));
+}
+
 void
 DynamicModel::toStatic(StaticModel &static_model) const
 {
@@ -2870,6 +2900,7 @@ DynamicModel::computeDerivIDs()
       equations[i]->collectVariables(eExogenous, dynvars);
       equations[i]->collectVariables(eExogenousDet, dynvars);
       equations[i]->collectVariables(eParameter, dynvars);
+      equations[i]->collectVariables(eTrend, dynvars);
     }
 
   for (set<pair<int, int> >::const_iterator it = dynvars.begin();
@@ -2982,7 +3013,8 @@ DynamicModel::computeDynJacobianCols(bool jacobianExo)
             dyn_jacobian_cols_table[deriv_id] = dynJacobianColsNbr + symbol_table.exo_nbr() + tsid;
           break;
         case eParameter:
-          // We don't assign a dynamic jacobian column to parameters
+        case eTrend:
+          // We don't assign a dynamic jacobian column to parameters or trend variables
           break;
         default:
           // Shut up GCC
@@ -3012,6 +3044,34 @@ DynamicModel::getDynJacobianCol(int deriv_id) const throw (UnknownDerivIDExcepti
     return it->second;
 }
 
+void
+DynamicModel::testTrendDerivativesEqualToZero(const eval_context_t &eval_context)
+{
+  for (deriv_id_table_t::const_iterator it = deriv_id_table.begin();
+       it != deriv_id_table.end(); it++)
+    if (symbol_table.getType(it->first.first) == eTrend)
+      for (int eq = 0; eq < (int) equations.size(); eq++)
+        {
+          expr_t testeq = AddLog(AddMinus(equations[eq]->get_arg1(), // F: a = b -> ln(a - b)
+                                          equations[eq]->get_arg2()));
+          assert(testeq != NULL);
+          testeq = testeq->getDerivative(it->second); // d F / d Trend
+          for (deriv_id_table_t::const_iterator endogit = deriv_id_table.begin();
+               endogit != deriv_id_table.end(); endogit++)
+            if (symbol_table.getType(endogit->first.first) == eEndogenous)
+              {
+                double nearZero = testeq->getDerivative(endogit->second)->eval(eval_context); // eval d F / d Trend d Endog
+                if (nearZero < -ZERO_BAND || nearZero > ZERO_BAND)
+                  {
+                    cerr << "ERROR: the second-order cross partial of equation " << eq + 1 << " w.r.t. trend variable "
+                         << symbol_table.getName(it->first.first) << " and endogenous variable "
+                         << symbol_table.getName(endogit->first.first) << " is not null. " << endl;
+                    exit(EXIT_FAILURE);
+                  }
+              }
+        }
+}
+
 void
 DynamicModel::computeParamsDerivatives()
 {
@@ -3467,6 +3527,37 @@ DynamicModel::transformPredeterminedVariables()
     }
 }
 
+void
+DynamicModel::detrendEquations()
+{
+  for (trend_symbols_map_t::const_iterator it = nonstationary_symbols_map.begin();
+       it != nonstationary_symbols_map.end(); it++)
+    for (int i = 0; i < (int) equations.size(); i++)
+      {
+        BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]->detrend(it->first, it->second));
+        assert(substeq != NULL);
+        equations[i] = dynamic_cast<BinaryOpNode *>(substeq);
+      }
+
+  for (int i = 0; i < (int) equations.size(); i++)
+    {
+      BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]->removeTrendLeadLag(trend_symbols_map));
+      assert(substeq != NULL);
+      equations[i] = dynamic_cast<BinaryOpNode *>(substeq);
+    }
+}
+
+void
+DynamicModel::removeTrendVariableFromEquations()
+{
+  for (int i = 0; i < (int) equations.size(); i++)
+    {
+      BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]->replaceTrendVar());
+      assert(substeq != NULL);
+      equations[i] = dynamic_cast<BinaryOpNode *>(substeq);
+    }
+}
+
 void
 DynamicModel::fillEvalContext(eval_context_t &eval_context) const
 {
@@ -3503,4 +3594,10 @@ DynamicModel::fillEvalContext(eval_context_t &eval_context) const
           // Do nothing
         }
     }
+
+  //Third, trend variables
+  vector <int> trendVars = symbol_table.getTrendVarIds();
+  for (vector <int>::const_iterator it = trendVars.begin();
+       it != trendVars.end(); it++)
+    eval_context[*it] = 2; //not <= 0 bc of log, not 1 bc of powers
 }
diff --git a/DynamicModel.hh b/DynamicModel.hh
index 05189ff9c437235456d0d47453dd183a4811c25f..4d98a97d4e89099de98958861f4cc9c562d1be81 100644
--- a/DynamicModel.hh
+++ b/DynamicModel.hh
@@ -21,6 +21,7 @@
 #define _DYNAMICMODEL_HH
 
 using namespace std;
+#define ZERO_BAND 1e-8
 
 #include <fstream>
 
@@ -156,6 +157,8 @@ private:
   void computeDynJacobianCols(bool jacobianExo);
   //! Computes derivatives of the Jacobian w.r. to parameters
   void computeParamsDerivatives();
+  //! Computes derivatives of the Jacobian w.r. to trend vars and tests that they are equal to zero
+  void testTrendDerivativesEqualToZero(const eval_context_t &eval_context);
   //! Computes temporary terms for the file containing parameters derivatives
   void computeParamsDerivativesTemporaryTerms();
   //! Collect only the first derivatives
@@ -278,6 +281,10 @@ public:
   /*! It assumes that the static model given in argument has just been allocated */
   void toStatic(StaticModel &static_model) const;
 
+  //! Copies a dynamic model (only the equations)
+  /*! It assumes that the dynamic model given in argument has just been allocated */
+  void cloneDynamic(DynamicModel &dynamic_model) const;
+
   //! Writes LaTeX file with the equations of the dynamic model
   void writeLatexFile(const string &basename) const;
 
@@ -294,6 +301,9 @@ public:
     return true;
   };
 
+  //! Drive test of detrended equations
+  void runTrendTest(const eval_context_t &eval_context);
+
   //! Transforms the model by removing all leads greater or equal than 2 on endos
   /*! Note that this can create new lags on endos and exos */
   void substituteEndoLeadGreaterThanTwo(bool deterministic_model);
@@ -314,6 +324,12 @@ public:
   //! Transforms the model by decreasing the lead/lag of predetermined variables in model equations by one
   void transformPredeterminedVariables();
 
+  //! Transforms the model by removing trends specified by the user
+  void detrendEquations();
+
+  //! Transforms the model by replacing trend variables with a 1
+  void removeTrendVariableFromEquations();
+
   //! Fills eval context with values of model local variables and auxiliary variables
   void fillEvalContext(eval_context_t &eval_context) const;
 
diff --git a/DynareBison.yy b/DynareBison.yy
index 1cdeb212e09b15af353850cbfb348322596e116f..defb9cc9783d49c632d5d873fdc0f87685168407 100644
--- a/DynareBison.yy
+++ b/DynareBison.yy
@@ -154,7 +154,7 @@ class ParsingDriver;
 %token COMPUTE_MDD COMPUTE_PROBABILITIES PRINT_DRAWS N_DRAWS THINNING_FACTOR PROPOSAL_DRAWS MARKOV_FILE
 %token MHM_FILE OUTPUT_FILE_TAG DRAWS_NBR_BURN_IN_1 DRAWS_NBR_BURN_IN_2 DRAWS_NBR_MEAN_VAR_ESTIMATE
 %token DRAWS_NBR_MODIFIED_HARMONIC_MEAN DIRICHLET_SCALE
-%token SBVAR MS_SBVAR
+%token SBVAR MS_SBVAR TREND_VAR DEFLATOR GROWTH_FACTOR
 %token SVAR_IDENTIFICATION EQUATION EXCLUSION LAG UPPER_CHOLESKY LOWER_CHOLESKY
 %token MARKOV_SWITCHING CHAIN STATE DURATION NUMBER_OF_STATES
 %token SVAR COEFFICIENTS VARIANCES CONSTANTS EQUATIONS
@@ -241,6 +241,7 @@ statement : parameters
           | svar
           | external_function
           | steady_state_model
+          | trend_var
           ;
 
 dsample : DSAMPLE INT_NUMBER ';'
@@ -251,7 +252,42 @@ dsample : DSAMPLE INT_NUMBER ';'
 
 rplot : RPLOT symbol_list ';' { driver.rplot(); };
 
-var : VAR var_list ';';
+trend_var : TREND_VAR '(' GROWTH_FACTOR EQUAL { driver.begin_trend(); } hand_side ')' trend_var_list ';'
+            { driver.end_trend_var($6); }
+          ;
+
+trend_var_list : trend_var_list symbol
+                 { driver.declare_trend_var($2); }
+               | trend_var_list COMMA symbol
+                 { driver.declare_trend_var($3); }
+               | symbol
+                 { driver.declare_trend_var($1); }
+               | trend_var_list symbol TEX_NAME
+                 { driver.declare_trend_var($2, $3); }
+               | trend_var_list COMMA symbol TEX_NAME
+                 { driver.declare_trend_var($3, $4); }
+               | symbol TEX_NAME
+                 { driver.declare_trend_var($1, $2); }
+               ;
+
+var : VAR var_list ';'
+    | VAR '(' DEFLATOR EQUAL { driver.begin_trend(); } hand_side ')' nonstationary_var_list ';'
+      { driver.end_nonstationary_var($6); }
+    ;
+
+nonstationary_var_list : nonstationary_var_list symbol
+                         { driver.declare_nonstationary_var($2); }
+                       | nonstationary_var_list COMMA symbol
+                         { driver.declare_nonstationary_var($3); }
+                       | symbol
+                         { driver.declare_nonstationary_var($1); }
+                       | nonstationary_var_list symbol TEX_NAME
+                         { driver.declare_nonstationary_var($2, $3); }
+                       | nonstationary_var_list COMMA symbol TEX_NAME
+                         { driver.declare_nonstationary_var($3, $4); }
+                       | symbol TEX_NAME
+                         { driver.declare_nonstationary_var($1, $2); }
+                       ;
 
 varexo : VAREXO varexo_list ';';
 
@@ -702,7 +738,6 @@ period_list : period_list COMMA INT_NUMBER
               { driver.add_period($1); }
             ;
 
-
 sigma_e : SIGMA_E EQUAL '[' triangular_matrix ']' ';' { driver.do_sigma_e(); };
 
 value_list
diff --git a/DynareFlex.ll b/DynareFlex.ll
index f2b1b7b97072dd3944f18e6687d01891b304bab6..388f07fd28280091361c016c4d19599a0633f5df 100644
--- a/DynareFlex.ll
+++ b/DynareFlex.ll
@@ -102,6 +102,7 @@ string eofbuff;
 <INITIAL>var {BEGIN DYNARE_STATEMENT; return token::VAR;}
 <INITIAL>varexo {BEGIN DYNARE_STATEMENT; return token::VAREXO;}
 <INITIAL>varexo_det {BEGIN DYNARE_STATEMENT; return token::VAREXO_DET;}
+<INITIAL>trend_var {BEGIN DYNARE_STATEMENT; return token::TREND_VAR;}
 <INITIAL>predetermined_variables {BEGIN DYNARE_STATEMENT; return token::PREDETERMINED_VARIABLES;}
 <INITIAL>parameters {BEGIN DYNARE_STATEMENT; return token::PARAMETERS;}
 <INITIAL>periods 	{BEGIN DYNARE_STATEMENT; return token::PERIODS;}
@@ -360,7 +361,9 @@ string eofbuff;
 <DYNARE_STATEMENT>filter_covariance {return token::FILTER_COVARIANCE; }
 <DYNARE_STATEMENT>filter_decomposition {return token::FILTER_DECOMPOSITION; }
 <DYNARE_STATEMENT>selected_variables_only {return token::SELECTED_VARIABLES_ONLY; }
-<DYNARE_STATEMENT>pruning {return token::PRUNING; };
+<DYNARE_STATEMENT>pruning {return token::PRUNING; }
+<DYNARE_STATEMENT>deflator {return token::DEFLATOR;}
+<DYNARE_STATEMENT>growth_factor {return token::GROWTH_FACTOR;}
 
 <DYNARE_STATEMENT>[\$][^$]*[\$] {
   strtok(yytext+1, "$");
diff --git a/ExprNode.cc b/ExprNode.cc
index 40c1cd2a2cb61f7f257e52482c61c52aeb43e924..f652a98cee84cca28cdad3e525d0489930fdda8e 100644
--- a/ExprNode.cc
+++ b/ExprNode.cc
@@ -329,6 +329,12 @@ NumConstNode::toStatic(DataTree &static_datatree) const
   return static_datatree.AddNumConstant(datatree.num_constants.get(id));
 }
 
+expr_t
+NumConstNode::cloneDynamic(DataTree &dynamic_datatree) const
+{
+  return dynamic_datatree.AddNumConstant(datatree.num_constants.get(id));
+}
+
 int
 NumConstNode::maxEndoLead() const
 {
@@ -424,6 +430,24 @@ NumConstNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int la
   return false;
 }
 
+expr_t
+NumConstNode::replaceTrendVar() const
+{
+  return const_cast<NumConstNode *>(this);
+}
+
+expr_t
+NumConstNode::detrend(int symb_id, expr_t trend) const
+{
+  return const_cast<NumConstNode *>(this);
+}
+
+expr_t
+NumConstNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const
+{
+  return const_cast<NumConstNode *>(this);
+}
+
 void
 VariableNode::prepareForDerivation()
 {
@@ -439,6 +463,7 @@ VariableNode::prepareForDerivation()
     case eExogenous:
     case eExogenousDet:
     case eParameter:
+    case eTrend:
       // For a variable or a parameter, the only non-null derivative is with respect to itself
       non_null_derivatives.insert(datatree.getDerivID(symb_id, lag));
       break;
@@ -465,6 +490,7 @@ VariableNode::computeDerivative(int deriv_id)
     case eExogenous:
     case eExogenousDet:
     case eParameter:
+    case eTrend:
       if (deriv_id == datatree.getDerivID(symb_id, lag))
         return datatree.One;
       else
@@ -514,7 +540,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
         output << "\\bar{";
       output << datatree.symbol_table.getTeXName(symb_id);
       if (output_type == oLatexDynamicModel
-          && (type == eEndogenous || type == eExogenous || type == eExogenousDet || type == eModelLocalVariable))
+          && (type == eEndogenous || type == eExogenous || type == eExogenousDet || type == eModelLocalVariable || type == eTrend))
         {
           output << "_{t";
           if (lag != 0)
@@ -677,6 +703,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
       break;
 
     case eExternalFunction:
+    case eTrend:
       cerr << "Impossible case" << endl;
       exit(EXIT_FAILURE);
     }
@@ -812,6 +839,7 @@ VariableNode::getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recur
     case eExogenous:
     case eExogenousDet:
     case eParameter:
+    case eTrend:
       if (deriv_id == datatree.getDerivID(symb_id, lag))
         return datatree.One;
       else
@@ -856,6 +884,12 @@ VariableNode::toStatic(DataTree &static_datatree) const
   return static_datatree.AddVariable(symb_id);
 }
 
+expr_t
+VariableNode::cloneDynamic(DataTree &dynamic_datatree) const
+{
+  return dynamic_datatree.AddVariable(symb_id, lag);
+}
+
 int
 VariableNode::maxEndoLead() const
 {
@@ -920,6 +954,7 @@ VariableNode::decreaseLeadsLags(int n) const
     case eEndogenous:
     case eExogenous:
     case eExogenousDet:
+    case eTrend:
       return datatree.AddVariable(symb_id, lag-n);
     case eModelLocalVariable:
       return datatree.local_variables_table[symb_id]->decreaseLeadsLags(n);
@@ -1104,6 +1139,51 @@ VariableNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int la
     return false;
 }
 
+expr_t
+VariableNode::replaceTrendVar() const
+{
+  if (get_type() == eTrend)
+    return datatree.One;
+  else
+    return const_cast<VariableNode *>(this);
+}
+
+expr_t
+VariableNode::detrend(int symb_id, expr_t trend) const
+{
+  if (get_symb_id() != symb_id)
+    return const_cast<VariableNode *>(this);
+
+  if (get_lag() == 0)
+    return datatree.AddTimes(const_cast<VariableNode *>(this), trend);
+  else
+    return datatree.AddTimes(const_cast<VariableNode *>(this), trend->decreaseLeadsLags(-1*get_lag()));
+}
+
+expr_t
+VariableNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const
+{
+  if (get_type() != eTrend || get_lag() == 0)
+    return const_cast<VariableNode *>(this);
+
+  map<int, expr_t>::const_iterator it = trend_symbols_map.find(symb_id);
+  expr_t noTrendLeadLagNode = new VariableNode(datatree, it->first, 0);
+  if (get_lag() > 0)
+    {
+      expr_t growthFactorSequence = it->second->decreaseLeadsLags(-1);
+      for (int i=1; i<get_lag(); i++)
+        growthFactorSequence = datatree.AddTimes(growthFactorSequence, it->second->decreaseLeadsLags(-1*(i+1)));
+      return datatree.AddTimes(noTrendLeadLagNode, growthFactorSequence);
+    }
+  else //get_lag < 0
+    {
+      expr_t growthFactorSequence = it->second;
+      for (int i=1; i<abs(get_lag()); i++)
+        growthFactorSequence = datatree.AddTimes(growthFactorSequence, it->second->decreaseLeadsLags(i));
+      return datatree.AddDivide(noTrendLeadLagNode, growthFactorSequence);
+    }
+}
+
 UnaryOpNode::UnaryOpNode(DataTree &datatree_arg, UnaryOpcode op_code_arg, const expr_t arg_arg, const int expectation_information_set_arg, const string &expectation_information_set_name_arg) :
   ExprNode(datatree_arg),
   arg(arg_arg),
@@ -1779,6 +1859,13 @@ UnaryOpNode::toStatic(DataTree &static_datatree) const
   return buildSimilarUnaryOpNode(sarg, static_datatree);
 }
 
+expr_t
+UnaryOpNode::cloneDynamic(DataTree &dynamic_datatree) const
+{
+  expr_t substarg = arg->cloneDynamic(dynamic_datatree);
+  return buildSimilarUnaryOpNode(substarg, dynamic_datatree);
+}
+
 int
 UnaryOpNode::maxEndoLead() const
 {
@@ -1948,6 +2035,27 @@ UnaryOpNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag
   return false;
 }
 
+expr_t
+UnaryOpNode::replaceTrendVar() const
+{
+  expr_t argsubst = arg->replaceTrendVar();
+  return buildSimilarUnaryOpNode(argsubst, datatree);
+}
+
+expr_t
+UnaryOpNode::detrend(int symb_id, expr_t trend) const
+{
+  expr_t argsubst = arg->detrend(symb_id, trend);
+  return buildSimilarUnaryOpNode(argsubst, datatree);
+}
+
+expr_t
+UnaryOpNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const
+{
+  expr_t argsubst = arg->removeTrendLeadLag(trend_symbols_map);
+  return buildSimilarUnaryOpNode(argsubst, datatree);
+}
+
 BinaryOpNode::BinaryOpNode(DataTree &datatree_arg, const expr_t arg1_arg,
                            BinaryOpcode op_code_arg, const expr_t arg2_arg) :
   ExprNode(datatree_arg),
@@ -2817,6 +2925,14 @@ BinaryOpNode::toStatic(DataTree &static_datatree) const
   return buildSimilarBinaryOpNode(sarg1, sarg2, static_datatree);
 }
 
+expr_t
+BinaryOpNode::cloneDynamic(DataTree &dynamic_datatree) const
+{
+  expr_t substarg1 = arg1->cloneDynamic(dynamic_datatree);
+  expr_t substarg2 = arg2->cloneDynamic(dynamic_datatree);
+  return buildSimilarBinaryOpNode(substarg1, substarg2, dynamic_datatree);
+}
+
 int
 BinaryOpNode::maxEndoLead() const
 {
@@ -2899,7 +3015,6 @@ BinaryOpNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vecto
           return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
         }
     }
-
 }
 
 expr_t
@@ -2982,6 +3097,30 @@ BinaryOpNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int la
   return false;
 }
 
+expr_t
+BinaryOpNode::replaceTrendVar() const
+{
+  expr_t arg1subst = arg1->replaceTrendVar();
+  expr_t arg2subst = arg2->replaceTrendVar();
+  return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree);
+}
+
+expr_t
+BinaryOpNode::detrend(int symb_id, expr_t trend) const
+{
+  expr_t arg1subst = arg1->detrend(symb_id, trend);
+  expr_t arg2subst = arg2->detrend(symb_id, trend);
+  return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree);
+}
+
+expr_t
+BinaryOpNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const
+{
+  expr_t arg1subst = arg1->removeTrendLeadLag(trend_symbols_map);
+  expr_t arg2subst = arg2->removeTrendLeadLag(trend_symbols_map);
+  return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree);
+}
+
 TrinaryOpNode::TrinaryOpNode(DataTree &datatree_arg, const expr_t arg1_arg,
                              TrinaryOpcode op_code_arg, const expr_t arg2_arg, const expr_t arg3_arg) :
   ExprNode(datatree_arg),
@@ -3403,6 +3542,15 @@ TrinaryOpNode::toStatic(DataTree &static_datatree) const
   return buildSimilarTrinaryOpNode(sarg1, sarg2, sarg3, static_datatree);
 }
 
+expr_t
+TrinaryOpNode::cloneDynamic(DataTree &dynamic_datatree) const
+{
+  expr_t substarg1 = arg1->cloneDynamic(dynamic_datatree);
+  expr_t substarg2 = arg2->cloneDynamic(dynamic_datatree);
+  expr_t substarg3 = arg3->cloneDynamic(dynamic_datatree);
+  return buildSimilarTrinaryOpNode(substarg1, substarg2, substarg3, dynamic_datatree);
+}
+
 int
 TrinaryOpNode::maxEndoLead() const
 {
@@ -3516,6 +3664,33 @@ TrinaryOpNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int l
   return false;
 }
 
+expr_t
+TrinaryOpNode::replaceTrendVar() const
+{
+  expr_t arg1subst = arg1->replaceTrendVar();
+  expr_t arg2subst = arg2->replaceTrendVar();
+  expr_t arg3subst = arg3->replaceTrendVar();
+  return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree);
+}
+
+expr_t
+TrinaryOpNode::detrend(int symb_id, expr_t trend) const
+{
+  expr_t arg1subst = arg1->detrend(symb_id, trend);
+  expr_t arg2subst = arg2->detrend(symb_id, trend);
+  expr_t arg3subst = arg3->detrend(symb_id, trend);
+  return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree);
+}
+
+expr_t
+TrinaryOpNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const
+{
+  expr_t arg1subst = arg1->removeTrendLeadLag(trend_symbols_map);
+  expr_t arg2subst = arg2->removeTrendLeadLag(trend_symbols_map);
+  expr_t arg3subst = arg3->removeTrendLeadLag(trend_symbols_map);
+  return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree);
+}
+
 ExternalFunctionNode::ExternalFunctionNode(DataTree &datatree_arg,
                                          int symb_id_arg,
                                          const vector<expr_t> &arguments_arg) :
@@ -3797,6 +3972,16 @@ ExternalFunctionNode::toStatic(DataTree &static_datatree) const
   return static_datatree.AddExternalFunction(symb_id, static_arguments);
 }
 
+expr_t
+ExternalFunctionNode::cloneDynamic(DataTree &dynamic_datatree) const
+{
+  vector<expr_t> dynamic_arguments;
+  for (vector<expr_t>::const_iterator it = arguments.begin();
+       it != arguments.end(); it++)
+    dynamic_arguments.push_back((*it)->cloneDynamic(dynamic_datatree));
+  return dynamic_datatree.AddExternalFunction(symb_id, dynamic_arguments);
+}
+
 int
 ExternalFunctionNode::maxEndoLead() const
 {
@@ -3936,6 +4121,33 @@ ExternalFunctionNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id
   return false;
 }
 
+expr_t
+ExternalFunctionNode::replaceTrendVar() const
+{
+  vector<expr_t> arguments_subst;
+  for (vector<expr_t>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
+    arguments_subst.push_back((*it)->replaceTrendVar());
+  return buildSimilarExternalFunctionNode(arguments_subst, datatree);
+}
+
+expr_t
+ExternalFunctionNode::detrend(int symb_id, expr_t trend) const
+{
+  vector<expr_t> arguments_subst;
+  for (vector<expr_t>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
+    arguments_subst.push_back((*it)->detrend(symb_id, trend));
+  return buildSimilarExternalFunctionNode(arguments_subst, datatree);
+}
+
+expr_t
+ExternalFunctionNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const
+{
+  vector<expr_t> arguments_subst;
+  for (vector<expr_t>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
+    arguments_subst.push_back((*it)->removeTrendLeadLag(trend_symbols_map));
+  return buildSimilarExternalFunctionNode(arguments_subst, datatree);
+}
+
 FirstDerivExternalFunctionNode::FirstDerivExternalFunctionNode(DataTree &datatree_arg,
                                                                int top_level_symb_id_arg,
                                                                const vector<expr_t> &arguments_arg,
diff --git a/ExprNode.hh b/ExprNode.hh
index 9a4df0e2066af5f83a3c21691330f5cd8fb306dd..de71231eacb932f11ddc0ded7cdc5726ce961b3c 100644
--- a/ExprNode.hh
+++ b/ExprNode.hh
@@ -356,6 +356,22 @@ public:
     */
   virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const = 0;
 
+  //! Replaces the Trend var with datatree.One
+  virtual expr_t replaceTrendVar() const = 0;
+
+  //! Constructs a new expression where the variable indicated by symb_id has been detrended
+  /*!
+    \param[in] symb_id indicating the variable to be detrended
+    \param[in] expr_t indicating the trend
+    \param[out] expr_t the new binary op pointing to a detrended variable
+  */
+  virtual expr_t detrend(int symb_id, expr_t trend) const = 0;
+
+  //! Add ExprNodes to the provided datatree
+  virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const = 0;
+
+  //! Move a trend variable with lag/lead to time t by dividing/multiplying by its growth factor
+  virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const = 0;
 };
 
 //! Object used to compare two nodes (using their indexes)
@@ -405,6 +421,10 @@ public:
   virtual expr_t decreaseLeadsLagsPredeterminedVariables() const;
   virtual bool isNumConstNodeEqualTo(double value) const;
   virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const;
+  virtual expr_t replaceTrendVar() const;
+  virtual expr_t detrend(int symb_id, expr_t trend) const;
+  virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const;
+  virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const;
 };
 
 //! Symbol or variable node
@@ -458,6 +478,10 @@ public:
   virtual expr_t decreaseLeadsLagsPredeterminedVariables() const;
   virtual bool isNumConstNodeEqualTo(double value) const;
   virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const;
+  virtual expr_t replaceTrendVar() const;
+  virtual expr_t detrend(int symb_id, expr_t trend) const;
+  virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const;
+  virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const;
 };
 
 //! Unary operator node
@@ -523,6 +547,10 @@ public:
   virtual expr_t decreaseLeadsLagsPredeterminedVariables() const;
   virtual bool isNumConstNodeEqualTo(double value) const;
   virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const;
+  virtual expr_t replaceTrendVar() const;
+  virtual expr_t detrend(int symb_id, expr_t trend) const;
+  virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const;
+  virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const;
 };
 
 //! Binary operator node
@@ -593,6 +621,10 @@ public:
   virtual expr_t decreaseLeadsLagsPredeterminedVariables() const;
   virtual bool isNumConstNodeEqualTo(double value) const;
   virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const;
+  virtual expr_t replaceTrendVar() const;
+  virtual expr_t detrend(int symb_id, expr_t trend) const;
+  virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const;
+  virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const;
 };
 
 //! Trinary operator node
@@ -645,6 +677,10 @@ public:
   virtual expr_t decreaseLeadsLagsPredeterminedVariables() const;
   virtual bool isNumConstNodeEqualTo(double value) const;
   virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const;
+  virtual expr_t replaceTrendVar() const;
+  virtual expr_t detrend(int symb_id, expr_t trend) const;
+  virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const;
+  virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const;
 };
 
 //! External function node
@@ -703,6 +739,10 @@ public:
   virtual bool isNumConstNodeEqualTo(double value) const;
   virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const;
   virtual void writePrhs(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms, const string &ending) const;
+  virtual expr_t replaceTrendVar() const;
+  virtual expr_t detrend(int symb_id, expr_t trend) const;
+  virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const;
+  virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const;
 };
 
 class FirstDerivExternalFunctionNode : public ExternalFunctionNode
diff --git a/ModFile.cc b/ModFile.cc
index f2da960cf81eaf80722229c6af7881cad2ec1f12..e97f5ff51c8fe9e78bd9475beaecb45c176adcbe 100644
--- a/ModFile.cc
+++ b/ModFile.cc
@@ -25,10 +25,11 @@
 
 ModFile::ModFile() : expressions_tree(symbol_table, num_constants, external_functions_table),
                      dynamic_model(symbol_table, num_constants, external_functions_table),
+                     trend_dynamic_model(symbol_table, num_constants, external_functions_table),
                      static_model(symbol_table, num_constants, external_functions_table),
                      steady_state_model(symbol_table, num_constants, external_functions_table, static_model),
                      linear(false), block(false), byte_code(false),
-                     use_dll(false), no_static(false)
+                     use_dll(false), no_static(false), nonstationary_variables(false)
 {
 }
 
@@ -212,6 +213,13 @@ ModFile::transformPass()
   if (symbol_table.predeterminedNbr() > 0)
     dynamic_model.transformPredeterminedVariables();
 
+  if (nonstationary_variables)
+    {
+      dynamic_model.detrendEquations();
+      dynamic_model.cloneDynamic(trend_dynamic_model);
+      dynamic_model.removeTrendVariableFromEquations();
+    }
+
   // Create auxiliary vars for Expectation operator
   dynamic_model.substituteExpectation(mod_file_struct.partial_information);
 
@@ -295,6 +303,9 @@ ModFile::computingPass(bool no_tmp_terms)
     || mod_file_struct.ramsey_policy_present || mod_file_struct.identification_present;
   if (dynamic_model.equation_number() > 0)
     {
+      if (nonstationary_variables)
+        trend_dynamic_model.runTrendTest(global_eval_context);
+
       // Compute static model and its derivatives
       dynamic_model.toStatic(static_model);
       if(!no_static)
diff --git a/ModFile.hh b/ModFile.hh
index b2d650dae18e7e6b02286351d203b0252ba5e8c6..a9f354dbfd98936a02e6e06c656dc249f62b4552 100644
--- a/ModFile.hh
+++ b/ModFile.hh
@@ -50,6 +50,8 @@ public:
   DataTree expressions_tree;
   //! Dynamic model, as declared in the "model" block
   DynamicModel dynamic_model;
+  //! A copy of Dynamic model, for testing trends declared by user
+  DynamicModel trend_dynamic_model;
   //! Static model, as derived from the "model" block when leads and lags have been removed
   StaticModel static_model;
   //! Static model, as declared in the "steady_state_model" block if present
@@ -69,6 +71,9 @@ public:
   //! Is the static model have to computed (no_static=false) or not (no_static=true). Option of 'model'
   bool no_static;
 
+  //! Are nonstationary variables present ?
+  bool nonstationary_variables;
+
   //! Global evaluation context
   /*! Filled using initval blocks and parameters initializations */
   eval_context_t global_eval_context;
diff --git a/ModelTree.cc b/ModelTree.cc
index e4beba9d61f0309697ff35d59710aa5ab656e7da..c51f2ae2778620b616ba4bedde533ac5236abae6 100644
--- a/ModelTree.cc
+++ b/ModelTree.cc
@@ -1362,3 +1362,29 @@ ModelTree::addAuxEquation(expr_t eq)
 
   aux_equations.push_back(beq);
 }
+
+void
+ModelTree::addTrendVariables(vector<int> trend_vars, expr_t growth_factor) throw (TrendException)
+{
+  while (!trend_vars.empty())
+    if (trend_symbols_map.find(trend_vars.back()) != trend_symbols_map.end())
+      throw TrendException(symbol_table.getName(trend_vars.back()));
+    else
+      {
+        trend_symbols_map[trend_vars.back()] = growth_factor;
+        trend_vars.pop_back();
+      }
+}
+
+void
+ModelTree::addNonstationaryVariables(vector<int> nonstationary_vars, expr_t deflator) throw (TrendException)
+{
+  while (!nonstationary_vars.empty())
+    if (nonstationary_symbols_map.find(nonstationary_vars.back()) != nonstationary_symbols_map.end())
+      throw TrendException(symbol_table.getName(nonstationary_vars.back()));
+    else
+      {
+        nonstationary_symbols_map[nonstationary_vars.back()] = deflator;
+        nonstationary_vars.pop_back();
+      }
+}
diff --git a/ModelTree.hh b/ModelTree.hh
index 47ad302d799db63fee4f49351f36859ee95f8a15..11ac9bf7cb71f619ed9b561e834f606eed14c909 100644
--- a/ModelTree.hh
+++ b/ModelTree.hh
@@ -45,12 +45,14 @@ typedef vector< pair<pair<int, int>, pair< int, expr_t > > > block_derivatives_e
 //! for all blocks derivatives description
 typedef vector<block_derivatives_equation_variable_laglead_nodeid_t> blocks_derivatives_t;
 
+//! for all trends
+typedef map<int, expr_t> trend_symbols_map_t;
+
 //! Shared code for static and dynamic models
 class ModelTree : public DataTree
 {
   friend class DynamicModel;
   friend class StaticModel;
-
 protected:
   //! Stores declared and generated auxiliary equations
   vector<BinaryOpNode *> equations;
@@ -92,6 +94,10 @@ protected:
 
   //! Temporary terms (those which will be noted Txxxx)
   temporary_terms_t temporary_terms;
+  //! Trend variables and their growth factors
+  trend_symbols_map_t trend_symbols_map;
+  //! Nonstationary variables and their deflators
+  trend_symbols_map_t nonstationary_symbols_map;
 
   //! Computes 1st derivatives
   /*! \param vars the derivation IDs w.r. to which compute the derivatives */
@@ -233,6 +239,10 @@ public:
   void addAuxEquation(expr_t eq);
   //! Returns the number of equations in the model
   int equation_number() const;
+  //! Adds a trend variable with its growth factor
+  void addTrendVariables(vector<int> trend_vars, expr_t growth_factor) throw (TrendException);
+  //! Adds a nonstationary variable with its deflator
+  void addNonstationaryVariables(vector<int> nonstationary_vars, expr_t deflator) throw (TrendException);
 
   inline static std::string
   c_Equation_Type(int type)
diff --git a/ParsingDriver.cc b/ParsingDriver.cc
index 6f17788b7d0052aecd9eec2f4d41a885abd703de..f0652bebb57cef3f5dd751fee397591f21f70651 100644
--- a/ParsingDriver.cc
+++ b/ParsingDriver.cc
@@ -164,6 +164,37 @@ ParsingDriver::declare_parameter(string *name, string *tex_name)
     delete tex_name;
 }
 
+void
+ParsingDriver::begin_trend()
+{
+  set_current_data_tree(&mod_file->dynamic_model);
+}
+
+void
+ParsingDriver::declare_trend_var(string *name, string *tex_name)
+{
+  declare_symbol(name, eTrend, tex_name);
+  declared_trend_vars.push_back(mod_file->symbol_table.getID(*name));
+  delete name;
+  if (tex_name != NULL)
+    delete tex_name;
+}
+
+void
+ParsingDriver::end_trend_var(expr_t growth_factor)
+{
+  try
+    {
+      dynamic_model->addTrendVariables(declared_trend_vars, growth_factor);
+    }
+  catch (DataTree::TrendException &e)
+    {
+      error("Trend variable " + e.name + " was declared twice.");
+    }
+  declared_trend_vars.clear();
+  reset_data_tree();
+}
+
 void
 ParsingDriver::add_predetermined_variable(string *name)
 {
@@ -260,6 +291,32 @@ ParsingDriver::add_expression_variable(string *name)
   return id;
 }
 
+void
+ParsingDriver::declare_nonstationary_var(string *name, string *tex_name)
+{
+  declare_endogenous(new string(*name), tex_name);
+  declared_nonstationary_vars.push_back(mod_file->symbol_table.getID(*name));
+  mod_file->nonstationary_variables = true;
+  delete name;
+  if (tex_name != NULL)
+    delete tex_name;
+}
+
+void
+ParsingDriver::end_nonstationary_var(expr_t deflator)
+{
+  try
+    {
+      dynamic_model->addNonstationaryVariables(declared_nonstationary_vars, deflator);
+    }
+  catch (DataTree::TrendException &e)
+    {
+      error("Variable " + e.name + " was listed more than once as following a trend.");
+    }
+  declared_nonstationary_vars.clear();
+  reset_data_tree();
+}
+
 void
 ParsingDriver::periods(string *periods)
 {
diff --git a/ParsingDriver.hh b/ParsingDriver.hh
index 597c735490323f3e6b66a88154e010e54be0db3c..32147ee21a5b37ab779e94f580f7d332ea50128e 100644
--- a/ParsingDriver.hh
+++ b/ParsingDriver.hh
@@ -163,6 +163,10 @@ private:
   int current_external_function_id;
   //! Temporary storage for option list provided to external_function()
   ExternalFunctionsTable::external_function_options current_external_function_options;
+  //! Temporary storage for declaring trend variables
+  vector<int> declared_trend_vars;
+  //! Temporary storage for declaring nonstationary variables
+  vector<int> declared_nonstationary_vars;
   //! reset the values for temporary storage
   void reset_current_external_function_options();
   //! Adds a model lagged variable to ModelTree and VariableTable
@@ -502,6 +506,16 @@ public:
   void begin_steady_state_model();
   //! Add an assignment equation in steady_state_model block
   void add_steady_state_model_equal(string *varname, expr_t expr);
+  //! Switches datatree
+  void begin_trend();
+  //! Declares a trend variable with its growth factor
+  void declare_trend_var(string *name, string *tex_name = NULL);
+  //! Ends declaration of trend variable
+  void end_trend_var(expr_t growth_factor);
+  //! Declares a nonstationary variable with its deflator
+  void declare_nonstationary_var(string *name, string *tex_name = NULL);
+  //! Ends declaration of nonstationary variable
+  void end_nonstationary_var(expr_t deflator);
 };
 
 #endif // ! PARSING_DRIVER_HH
diff --git a/SymbolTable.cc b/SymbolTable.cc
index a1e0d0b1f46d31173554367a18f97ce0504ab29d..071db40d90d52fc98c75200e61bbf37092655713 100644
--- a/SymbolTable.cc
+++ b/SymbolTable.cc
@@ -433,3 +433,14 @@ SymbolTable::getObservedVariableIndex(int symb_id) const
   assert(it != varobs.end());
   return (int) (it - varobs.begin());
 }
+
+vector <int>
+SymbolTable::getTrendVarIds() const
+{
+  vector <int> trendVars;
+  for (symbol_table_type::const_iterator it = symbol_table.begin();
+       it != symbol_table.end(); it++)
+    if (getType(it->second) == eTrend)
+      trendVars.push_back(it->second);
+  return trendVars;
+}
diff --git a/SymbolTable.hh b/SymbolTable.hh
index 43bdf87ff8ac2fa06b83d5348f8bd89f3f60fe40..ad0579cdd686d39257f04e707b27b964a92a8408 100644
--- a/SymbolTable.hh
+++ b/SymbolTable.hh
@@ -261,6 +261,7 @@ public:
   bool isObservedVariable(int symb_id) const;
   //! Return the index of a given observed variable in the vector of all observed variables
   int getObservedVariableIndex(int symb_id) const;
+  vector <int> getTrendVarIds() const;
 };
 
 inline bool