diff --git a/matlab/expand_group.m b/matlab/expand_group.m
new file mode 100644
index 000000000..388c93002
--- /dev/null
+++ b/matlab/expand_group.m
@@ -0,0 +1,47 @@
+function expand_group(use_shock_groups,var_list_, ic)
+% function expand_group(use_shock_groups,var_list_, ic)
+% Expands shocks contributions out of a group of shocks
+%
+% INPUTS
+% use_shock_groups: [char] name of the group
+% var_list_: [char] list of variables
+% ic: [int] group # to expand
+%
+% SPECIAL REQUIREMENTS
+% none
+
+% Copyright (C) 2016-2017 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 .
+
+M = evalin('base','M_');
+oo = evalin('base','oo_');
+options = evalin('base','options_');
+
+% define expanded group
+label=M.shock_groups.(use_shock_groups).(['group' int2str(ic)]).label;
+shocks=M.shock_groups.(use_shock_groups).(['group' int2str(ic)]).shocks;
+options.use_shock_groups = strrep(label,' ','_'); %[use_shock_groups_old int2str(ic)];
+for j=1:length(shocks)
+ M.shock_groups.(options.use_shock_groups).(['group' int2str(j)]).label=shocks{j};
+ M.shock_groups.(options.use_shock_groups).(['group' int2str(j)]).shocks=shocks(j);
+end
+
+options.shock_decomp.fig_names = [options.shock_decomp.fig_names '_expand'];
+options.shock_decomp.interactive=0;
+plot_shock_decomposition(M,oo,options,var_list_);
+
+
diff --git a/matlab/graph_decomp_detail.m b/matlab/graph_decomp_detail.m
new file mode 100644
index 000000000..ee5d82f9b
--- /dev/null
+++ b/matlab/graph_decomp_detail.m
@@ -0,0 +1,209 @@
+function []=graph_decomp_detail(z,shock_names,endo_names,i_var,initial_date,DynareModel,DynareOptions,opts_decomp)
+%function []=graph_decomp_detail(z,shock_names,endo_names,i_var,initial_date,DynareModel,DynareOptions)
+% Plots the results from the shock_decomposition command
+%
+% Inputs
+% z [n_var*(nshock+2)*nperiods] shock decomposition array, see shock_decomposition.m for details
+% shock_names [endo_nbr*string length] shock names from M_.exo_names
+% endo_names [exo_nbr*string length] variable names from M_.endo_names
+% i_var [n_var*1] vector indices of requested variables in M_.endo_names and z
+% initial_date [dseries object] first period of decomposition to plot
+% DynareModel [structure] Dynare model structure
+% DynareOptions [structure] Dynare options structure
+
+% Copyright (C) 2010-2016 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 .
+
+% interactive = 0;
+% fig_mode='';
+fig_mode1='';
+% fig_names='';
+% screen_shocks=0;
+use_shock_groups = DynareOptions.use_shock_groups;
+if use_shock_groups
+ shock_groups = DynareModel.shock_groups.(use_shock_groups);
+ shock_ind = fieldnames(shock_groups);
+end
+
+% number of components equals number of shocks + 1 (initial conditions)
+comp_nbr = size(z,2)-1;
+
+opts_decomp = DynareOptions.shock_decomp;
+
+interactive = opts_decomp.interactive;
+if ~isempty(opts_decomp.fig_mode)
+ fig_mode = opts_decomp.fig_mode;
+ fig_mode1 = ['_' fig_mode];
+ fig_mode = [fig_mode '_'];
+end
+if DynareOptions.use_shock_groups,
+ screen_shocks=0;
+elseif comp_nbr>18
+ screen_shocks = opts_decomp.screen_shocks;
+end
+fig_names = opts_decomp.fig_names;
+% fig_names = ['_' fig_names];
+fig_names1 = [fig_names];
+fig_names = [fig_names '_'];
+if screen_shocks
+ fig_names1 = [fig_names1 '_screen'];
+ fig_names = [fig_names 'screen_'];
+end
+
+
+gend = size(z,3);
+if isempty(initial_date)
+ x = 0:gend;
+ freq = 1;
+else
+ freq = initial_date.freq;
+ initial_period = initial_date.time(1) + (initial_date.time(2)-1)/freq;
+ x = initial_period-1/freq:(1/freq):initial_period+(gend-1)/freq;
+end
+
+ind_yrs = find(floor(x)==x);
+dind_tick = 1;
+if floor(length(ind_yrs)/3);
+ dind_tick = floor(length(ind_yrs)/3);
+ xind_tick = x(ind_yrs(1)):dind_tick:x(ind_yrs(end))+(length(ind_yrs)-(dind_tick*3+1));
+else
+ xind_tick = x(ind_yrs(1)):dind_tick:x(ind_yrs(end))+(length(ind_yrs)-(dind_tick+1));
+end
+% xind_tick = floor(x(1))-floor(dind_tick/2):dind_tick:ceil(x(end))+ceil(dind_tick/2);
+if abs(floor(x(1))-xind_tick(1))-abs(ceil(x(end))-xind_tick(end))>1
+ xind_tick = xind_tick-1;
+end
+if abs(floor(x(1))-xind_tick(1))-abs(ceil(x(end))-xind_tick(end))<-1
+ xind_tick = xind_tick+1;
+end
+% xind_tick = [x(ind_yrs(1))-floor(dind_tick/2):dind_tick:x(ind_yrs(end))+floor(dind_tick/2)]+1;
+% xind_tick = x(ind_yrs(1))-1:dind_tick:x(ind_yrs(end))+1;
+% xind_tick = x(ind_yrs(1))-1:dind_tick:x(ind_yrs(end))+dind_tick;
+
+nvar = length(i_var);
+
+%% write LaTeX-Header
+if DynareOptions.TeX && any(strcmp('eps',cellstr(DynareOptions.graph_format)))
+ fidTeX = fopen([DynareModel.fname '_shock_decomp' fig_mode1 fig_names1 '_detail.tex'],'w');
+ fprintf(fidTeX,'%% TeX eps-loader file generated by Dynare''s graph_decomp_detail.m.\n');
+ fprintf(fidTeX,['%% ' datestr(now,0) '\n']);
+ fprintf(fidTeX,' \n');
+end
+
+ncol=3;
+nrow=ceil(comp_nbr/ncol);
+ntotrow = nrow;
+nrow = min(ntotrow, 6);
+nfigs = ceil(ntotrow/nrow);
+labels = char(char(shock_names),'Initial values');
+if ~(screen_shocks && comp_nbr>18),
+ screen_shocks=0;
+end
+comp_nbr0=comp_nbr;
+%%plot decomposition
+for j=1:nvar
+ z1 = squeeze(z(i_var(j),:,:));
+ if screen_shocks,
+ [junk, isort] = sort(mean(abs(z1(1:end-2,:)')), 'descend');
+ labels = char(char(shock_names(isort(1:16),:)),'Others', 'Initial values');
+ zres = sum(z1(isort(17:end),:),1);
+ z1 = [z1(isort(1:16),:); zres; z1(comp_nbr0:end,:)];
+ comp_nbr=18;
+ nfigs=1;
+ end
+ xmin = x(1);
+ xmin = min(xmin, xind_tick(1));
+ xmax = x(end)+1/freq;
+ xmax = max(xmax, xind_tick(end));
+ ix = z1(1:comp_nbr,:) > 0;
+ ymax = max(sum(z1(1:comp_nbr,:).*ix))*1.1;
+ ix = z1(1:comp_nbr,:) < 0;
+ ymin = min(sum(z1(1:comp_nbr,:).*ix))*1.1;
+ if ymax-ymin < 1e-6
+ continue
+ end
+ for jf = 1:nfigs
+ fhandle = dyn_figure(DynareOptions,'Name',['Shock decomposition (detail): ' endo_names(i_var(j),:) fig_mode fig_names1],'position',[200 100 650 850], 'PaperPositionMode', 'auto','PaperOrientation','portrait','renderermode','auto');
+ a0=zeros(1,4);
+ a0(3)=inf;
+ a0(4)=-inf;
+ for ic=1+nrow*ncol*(jf-1):min(nrow*ncol*jf,comp_nbr),
+ i = ic-nrow*ncol*(jf-1);
+ zz = z1(ic,:);
+ zz(2,:)=z1(end,:)-zz;
+ ipos=zz>0;
+ ineg=zz<0;
+ hax = subplot(nrow,ncol,i); set(gca,'box','on')
+ hbar = bar(x(2:end),(zz.*ipos)','stacked');
+ colormap([0.15 0.15 0.15;0.85 0.85 0.85]),
+ set(hbar,'edgecolor','flat');
+ hold on,
+ hbar = bar(x(2:end),(zz.*ineg)','stacked');
+ colormap([0.15 0.15 0.15;0.85 0.85 0.85]),
+ set(hbar,'edgecolor','flat');
+ title(deblank(labels(ic,:)),'Interpreter','none'),
+ axis tight;
+ a=axis;
+ set(gca,'Xtick',xind_tick)
+ set(gca,'xlim',[xmin xmax])
+ a0(3)=min(a(3),a0(3));
+ a0(4)=max(a(4),a0(4));
+ set(gca,'ylim',a0(3:4))
+ hold on, h1=plot(x(2:end),z1(end,:),'k-','LineWidth',2);
+ if interactive & (~isoctave & use_shock_groups)
+ mydata.use_shock_groups = DynareOptions.use_shock_groups;
+ mydata.group_members = shock_groups.(shock_ind{ic}).shocks;
+ set(gca,'UserData',mydata);
+ if ~isempty(mydata.group_members{1})
+ c = uicontextmenu;
+ hax.UIContextMenu=c;
+ browse_menu = uimenu(c,'Label','Browse group');
+ expand_menu = uimenu(c,'Label','Expand group','Callback',['expand_group(''' mydata.use_shock_groups ''',''' deblank(endo_names(i_var(j),:)) ''',' int2str(ic) ')']);
+ for jmember = mydata.group_members
+ uimenu('parent',browse_menu,'Label',char(jmember))
+ end
+ end
+ end
+ end
+ for isub=1:i,
+ subplot(nrow,ncol,isub),
+ set(gca,'ylim',a0(3:4))
+ end
+ if nfigs>1,
+ suffix = ['detail_' int2str(jf)];
+ else
+ suffix = ['detail'];
+ end
+ dyn_saveas(fhandle,[DynareModel.fname,'_shock_decomposition_',fig_mode,deblank(endo_names(i_var(j),:)),fig_names suffix],DynareOptions);
+ if DynareOptions.TeX && any(strcmp('eps',cellstr(DynareOptions.graph_format)))
+ fprintf(fidTeX,'\\begin{figure}[H]\n');
+ fprintf(fidTeX,'\\centering \n');
+ fprintf(fidTeX,['\\includegraphics[width=0.8\\textwidth]{%s_shock_decomposition_%s}\n'],DynareModel.fname,[fig_mode deblank(endo_names(i_var(j),:)) fig_names suffix]);
+ fprintf(fidTeX,'\\label{Fig:shock_decomp:%s}\n',deblank(endo_names(i_var(j),:)));
+ fprintf(fidTeX,'\\caption{Historical shock decomposition: $ %s $}\n',deblank(DynareModel.endo_names_tex(i_var(j),:)));
+ fprintf(fidTeX,'\\end{figure}\n');
+ fprintf(fidTeX,' \n');
+ end
+ end
+end
+
+%% write LaTeX-Footer
+if DynareOptions.TeX && any(strcmp('eps',cellstr(DynareOptions.graph_format)))
+ fprintf(fidTeX,' \n');
+ fprintf(fidTeX,'%% End of TeX file.\n');
+ fclose(fidTeX);
+end
diff --git a/matlab/plot_shock_decomposition.m b/matlab/plot_shock_decomposition.m
new file mode 100644
index 000000000..8072842cc
--- /dev/null
+++ b/matlab/plot_shock_decomposition.m
@@ -0,0 +1,196 @@
+function plot_shock_decomposition(M_,oo_,options_,varlist)
+% function plot_shock_decomposition(M_,oo_,options_,varlist)
+% Computes shocks contribution to a simulated trajectory. The field set is
+% oo_.shock_decomposition. It is a n_var by nshock+2 by nperiods array. The
+% first nshock columns store the respective shock contributions, column n+1
+% stores the role of the initial conditions, while column n+2 stores the
+% value of the smoothed variables. Both the variables and shocks are stored
+% in the order of declaration, i.e. M_.endo_names and M_.exo_names, respectively.
+%
+% INPUTS
+% M_: [structure] Definition of the model
+% oo_: [structure] Storage of results
+% options_: [structure] Options
+% varlist: [char] List of variables
+%
+% SPECIAL REQUIREMENTS
+% none
+
+% Copyright (C) 2016-2017 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 .
+
+% indices of endogenous variables
+if size(varlist,1) == 0
+ varlist = M_.endo_names(1:M_.orig_endo_nbr,:);
+end
+
+[i_var,nvar] = varlist_indices(varlist,M_.endo_names);
+
+% number of variables
+endo_nbr = M_.endo_nbr;
+
+% number of shocks
+nshocks = M_.exo_nbr;
+% type = '';
+% fig_names='';
+% detail_plot=0;
+% realtime_=0; % 0 is standard; 1 is realtime (pool/vintage); 2 is conditional (pool/vintage); 3 is forecast (pool/vintage)
+% vintage_=0; % 0 pool realtime/conditional; int: forecast/conditional shock decompositions
+% forecast_=0;
+% steadystate=0;
+% write_xls=0;
+
+ if ~isempty(options_.shock_decomp.fig_names)
+ fig_names=['_' options_.shock_decomp.fig_names];
+ end
+ type=options_.shock_decomp.type;
+ detail_plot=options_.shock_decomp.detail_plot;
+ realtime_= options_.shock_decomp.realtime;
+ vintage_ = options_.shock_decomp.vintage;
+ forecast_ = options_.shock_decomp.forecast;
+ steadystate = options_.shock_decomp.steadystate;
+ write_xls = options_.shock_decomp.write_xls;
+
+initial_date = options_.initial_date;
+
+switch realtime_
+
+ case 0
+ z = oo_.shock_decomposition;
+
+ case 1 % realtime
+ if vintage_
+ z = oo_.realtime_shock_decomposition.(['time_' int2str(vintage_)]);
+ fig_names=[fig_names '_realtime_' char(initial_date+vintage_-1)];
+ else
+ z = oo_.realtime_shock_decomposition.pool;
+ fig_names=[fig_names '_realtime_pool'];
+ end
+
+ case 2 % conditional
+ if vintage_
+ z = oo_.conditional_shock_decomposition.(['time_' int2str(vintage_)]);
+ initial_date = options_.initial_date+vintage_-forecast_;
+ fig_names=[fig_names '_conditional_' int2str(forecast_) 'step_' char(initial_date)];
+ else
+ z = oo_.conditional_shock_decomposition.pool;
+ fig_names=[fig_names '_conditional_pool'];
+ end
+
+ case 3 % forecast
+ if vintage_
+ z = oo_.realtime_forecast_shock_decomposition.(['time_' int2str(vintage_)]);
+ initial_date = options_.initial_date+vintage_-1;
+ fig_names=[fig_names '_forecast_' int2str(forecast_) 'step_' char(initial_date)];
+ else
+ z = oo_.realtime_forecast_shock_decomposition.pool;
+ fig_names=[fig_names '_forecast_1step_pool'];
+ end
+end
+
+gend = size(z,3);
+if options_.use_shock_groups
+ shock_groups = M_.shock_groups.(options_.use_shock_groups);
+ shock_ind = fieldnames(shock_groups);
+ ngroups = length(shock_ind);
+ fig_names=[fig_names '_group_' options_.use_shock_groups];
+ shock_names = shock_ind;
+ for i=1:ngroups,
+ shock_names{i} = (shock_groups.(shock_ind{i}).label);
+ end
+ zz = zeros(endo_nbr,ngroups+2,gend);
+ kcum=[];
+ for i=1:ngroups
+ for j = shock_groups.(shock_ind{i}).shocks
+ k = find(strcmp(j,cellstr(M_.exo_names)));
+ zz(:,i,:) = zz(:,i,:) + z(:,k,:);
+ z(:,k,:) = 0;
+ kcum = [kcum k];
+ end
+ end
+ zothers = sum(z(:,1:nshocks,:),2);
+ shock_groups.(['group' int2str(ngroups+1)]).shocks = cellstr(M_.exo_names(find(~ismember([1:M_.exo_nbr],kcum)),:))';
+ M_.shock_groups.(options_.use_shock_groups)=shock_groups;
+ if any(any(zothers)),
+ shock_names = [shock_names; {'Others + Initial Values'}];
+ end
+ zz(:,ngroups+1,:) = sum(z(:,1:nshocks+1,:),2);
+ zz(:,ngroups+2,:) = z(:,nshocks+2,:);
+ z = zz;
+else
+ shock_names = M_.exo_names;
+end
+
+ func = @(x) colorspace('RGB->Lab',x);
+ MAP = distinguishable_colors(size(z,2)-1,'w',func);
+% MAP = [MAP; MAP(end,:)];
+ MAP(end,:) = [0.7 0.7 0.7];
+% MAP = [MAP; [0.7 0.7 0.7]; [0.3 0.3 0.3]];
+
+if isempty(options_.colormap),
+ options_.colormap = MAP;
+end
+steady_state = oo_.steady_state;
+fig_mode=type;
+
+switch type
+
+ case '' % default
+
+ case 'qoq'
+
+ case 'yoy'
+ z=z(:,:,1:end-3)+z(:,:,2:end-2)+z(:,:,3:end-1)+z(:,:,4:end);
+ if ~isempty(initial_date),
+ initial_date = initial_date+3;
+ else
+ initial_date = dates('0Q4');
+ end
+ fig_mode = type;
+ steady_state = 4*steady_state;
+
+ case 'aoa'
+
+ if isempty(initial_date),
+ initial_date = dates('1Y');
+ t0=4;
+ else
+ initial_date = dates([int2str(initial_date.time(1)) 'Y']);
+ t0=4-initial_date.time(2)+1;
+ end
+ z=z(:,:,t0:4:end);
+ fig_mode = 'AoA';
+
+ otherwise
+
+ error('plot_shock_decomposition:: Wrong type')
+
+end
+if steadystate
+ options_.shock_decomp.steady_state=steady_state;
+end
+options_.shock_decomp.fig_mode=fig_mode;
+options_.shock_decomp.fig_names=fig_names;
+if detail_plot,
+ graph_decomp_detail(z,shock_names,M_.endo_names,i_var,initial_date,M_,options_)
+else
+ graph_decomp(z,shock_names,M_.endo_names,i_var,initial_date,M_,options_,options_.shock_decomp);
+end
+
+if write_xls
+ WriteShockDecomp2Excel(z,shock_names,M_.endo_names,i_var,initial_date,M_,options_,options_.shock_decomp);
+end
\ No newline at end of file