dynare/matlab/backward/shock_decomposition_backward.m

122 lines
5.3 KiB
Matlab
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

function decomposition = shock_decomposition_backward(simulations, initialconditions, shocklist, endograph, use_shock_groups)
% Computes and possibly plots the shock decomposition of a backward (possibly nonlinear)
% model simulation.
%
% Inputs:
% - simulations dseries object as returned by simul_backward_model
% - initialconditions dseries object as passed to simul_backward_model
% - shocklist a cell array listing the (names of the) shocks whose contribution should be
% computed. The order matters: the contribution of a shock appearing at index
% i is computed as the difference between the simulation where all shocks ≥i+1
% are zero and the simulation where all shocks ≥i are zero. It is also
% possible to put in this list shock groups, as defined in a shock_groups
% block
% - endograph an optional cell array listing the (names of the) endogenous variables for
% which a shock decomposition graph should be created
% - use_shock_groups an optional string giving the name of the shock_groups block to be used to
% resolve shock groups listed in shocklist. If not given, 'default' is used.
%
% Output:
% - decomposition a 3D array of size endo_nbr×nshocks×nperiods where nshocks=length(shocklist)
% and nperiods is the number of simulation periods (i.e. excluding the initial
% conditions)
% Copyright © 2020-2021 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <https://www.gnu.org/licenses/>.
global M_ options_
narginchk(3, 5);
if nargin < 4
endograph = {};
end
if nargin < 5
use_shock_groups = 'default';
end
% Extract matrix of innovations from the whole simulation paths
simdates = simulations.dates(initialconditions.nobs+1:end);
innovations = simulations{M_.exo_names{:}}(simdates);
% Number of simulation periods
nperiods = simulations.nobs - initialconditions.nobs;
decomposition = NaN(M_.endo_nbr, length(shocklist), nperiods);
% Add auxiliary variables to simulation paths
if exist(sprintf('+%s/dynamic_set_auxiliary_series.m', M_.fname), 'file')
simulations = feval(sprintf('%s.dynamic_set_auxiliary_series', M_.fname), simulations, M_.params);
end
for i = length(shocklist):-1:1
% Zero the innovation(s) corresponding to this shock or shock group
if ismember(shocklist{i}, M_.exo_names)
innovations{shocklist{i}}(simdates) = zeros(nperiods, 1);
else % This is a shock group
if ~ismember(use_shock_groups, fieldnames(M_.shock_groups))
error(['Unknown shock_groups block: ' use_shock_groups])
end
groups = fieldnames(M_.shock_groups.(use_shock_groups));
shocks_in_group = [];
for j = 1:length(groups)
if strcmp(shocklist{i}, M_.shock_groups.(use_shock_groups).(groups{j}).label)
shocks_in_group = M_.shock_groups.(use_shock_groups).(groups{j}).shocks;
break
end
end
if isempty(shocks_in_group)
error(['Unknown shock group: ' shocklist{i}])
end
for j = 1:length(shocks_in_group)
innovations{shocks_in_group{j}}(simdates) = zeros(nperiods, 1);
end
end
% Compute simulation with the current shock or shock group removed
simulations_new = simul_backward_model(initialconditions, nperiods, innovations);
if exist(sprintf('+%s/dynamic_set_auxiliary_series.m', M_.fname), 'file')
simulations_new = feval(sprintf('%s.dynamic_set_auxiliary_series', M_.fname), simulations_new, M_.params);
end
% Compute the contribution of the current shock or shock group
if ~isoctave && matlab_ver_less_than('9.7')
% Workaround for MATLAB bug described in dseries#45
% The solution is to avoid using the "end" keyword
myend = nobs(simulations);
contribution = simulations{M_.endo_names{:}}.data(initialconditions.nobs+1:myend, :) ...
- simulations_new{M_.endo_names{:}}.data(initialconditions.nobs+1:myend, :);
else
contribution = simulations{M_.endo_names{:}}.data(initialconditions.nobs+1:end, :) ...
- simulations_new{M_.endo_names{:}}.data(initialconditions.nobs+1:end, :);
end
decomposition(:, i, :) = contribution';
simulations = simulations_new;
end
% Plot the decomposition
for i = 1:length(endograph)
h = dyn_figure(options_.plot_shock_decomp.nodisplay, 'Name', [ 'Shock decomposition for ' endograph{i}]);
endoidx = find(strcmp(endograph{i}, M_.endo_names));
bar(double(simdates), squeeze(decomposition(endoidx, :, :))', 'stacked')
legend(shocklist)
end
end