diff --git a/matlab/+occbin/forecast.m b/matlab/+occbin/forecast.m index 3cc855223..480fc2067 100644 --- a/matlab/+occbin/forecast.m +++ b/matlab/+occbin/forecast.m @@ -1,143 +1,169 @@ -function [oo_, error_flag] = forecast(options_,M_,oo_,forecast) %,hist_period) -%function oo_ = forecast(options_,M_,oo_,forecast) -% forecast +function [forecast, error_flag] = forecast(options_,M_,dr,endo_steady_state,exo_steady_state,exo_det_steady_state,forecast_horizon) +% [forecast, error_flag] = forecast(options_,M_,dr,endo_steady_state,exo_steady_state,exo_det_steady_state,forecast_horizon) +% Occbin forecasts +% +% INPUTS +% - options_ [structure] Matlab's structure describing the current options +% - M_ [structure] Matlab's structure describing the model +% - dr_in [structure] model information structure +% - endo_steady_state [double] steady state value for endogenous variables +% - exo_steady_state [double] steady state value for exogenous variables +% - exo_det_steady_state [double] steady state value for exogenous deterministic variables +% - forecast_horizon [integer] forecast horizon +% +% OUTPUTS +% - forecast [structure] forecast results +% - error_flag [integer] error code +% +% SPECIAL REQUIREMENTS +% none. + +% Copyright © 2022-2023 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 . opts = options_.occbin.forecast; options_.occbin.simul.maxit = opts.maxit; options_.occbin.simul.check_ahead_periods = opts.check_ahead_periods; -options_.occbin.simul.periods = forecast; -SHOCKS0 = opts.SHOCKS0; -if ~isempty(SHOCKS0) - if iscell(SHOCKS0) - for j=1:length(SHOCKS0) - sname = SHOCKS0{j}{1}; - inds(j)=strmatch(sname,M_.exo_names); - SHOCKS1(j,:)=SHOCKS0{j}{2}; +options_.occbin.simul.periods = forecast_horizon; +shocks_input = opts.SHOCKS0; + +if ~isempty(shocks_input) + n_shocks=size(shocks_input,1); + if iscell(shocks_input) + inds=NaN(n_shocks,1); + periods=length(shocks_input{1}{2}); + shock_mat=NaN(n_shocks,periods); + for j=1:n_shocks + exo_pos=strmatch(shocks_input{j}{1},M_.exo_names,'exact'); + if isempty(exo_pos) + error('occbin.forecast: unknown exogenous shock %s',shocks_input{j}{1}) + else + inds(j)=exo_pos; + end + if length(shocks_input{j}{2})~=periods + error('occbin.forecast: unknown exogenous shock %s',shocks_input{j}{1}) + else + shock_mat(j,:)=shocks_input{j}{2}; + end end - elseif isreal(SHOCKS0) - SHOCKS1=SHOCKS0; - inds = 1:M_.exo_nbr; + elseif isreal(shocks_input) + shock_mat=shocks_input; + inds = (1:M_.exo_nbr)'; end end +options_.occbin.simul.endo_init = M_.endo_histval(:,1)-endo_steady_state; %initial condition +options_.occbin.simul.init_regime = opts.frcst_regimes; +options_.occbin.simul.init_binding_indicator = []; + +shocks_base = zeros(forecast_horizon,M_.exo_nbr); +if ~isempty(shocks_input) + for j=1:n_shocks + shocks_base(:,inds(j))=shock_mat(j,:); + end +end if opts.replic h = dyn_waitbar(0,'Please wait occbin forecast replic ...'); ishock = find(sqrt(diag((M_.Sigma_e)))); + options_.occbin.simul.exo_pos=ishock; effective_exo_nbr= length(ishock); - effective_exo_names = M_.exo_names(ishock); - effective_Sigma_e = M_.Sigma_e(ishock,ishock); + effective_Sigma_e = M_.Sigma_e(ishock,ishock); % does not take heteroskedastic shocks into account [U,S] = svd(effective_Sigma_e); + % draw random shocks if opts.qmc opts.replic =2^(round(log2(opts.replic+1)))-1; - SHOCKS_ant = qmc_sequence(forecast*effective_exo_nbr, int64(1), 1, opts.replic)'; + SHOCKS_add = qmc_sequence(forecast_horizon*effective_exo_nbr, int64(1), 1, opts.replic); else - SHOCKS_ant = randn(forecast*effective_exo_nbr,opts.replic)'; + SHOCKS_add = randn(forecast_horizon*effective_exo_nbr,opts.replic); end - zlin0=zeros(forecast,M_.endo_nbr,opts.replic); - zpiece0=zeros(forecast,M_.endo_nbr,opts.replic); + SHOCKS_add=reshape(SHOCKS_add,effective_exo_nbr,forecast_horizon,opts.replic); + z.linear=NaN(forecast_horizon,M_.endo_nbr,opts.replic); + z.piecewise=NaN(forecast_horizon,M_.endo_nbr,opts.replic); + error_flag=true(opts.replic,1); + simul_SHOCKS=NaN(forecast_horizon,M_.exo_nbr,opts.replic); for iter=1:opts.replic - - if ~isempty(SHOCKS0) - for j=1:length(SHOCKS0) - SHOCKS(:,inds(j))=SHOCKS1(j,:); - end - end - - error_flagx=1; - % while error_flagx, - % SHOCKS=transpose(sqrt(diag(diag(effective_Sigma_e)))*(reshape(SHOCKS_ant(iter,:),forecast,effective_exo_nbr))'); - SHOCKS=transpose(U*sqrt(S)*(reshape(SHOCKS_ant(iter,:),forecast,effective_exo_nbr))'); - % SHOCKS=transpose(U*sqrt(S)*randn(forecast,M_.exo_nbr)'); %realized shocks - options_.occbin.simul.endo_init = M_.endo_histval(:,1)-oo_.steady_state; - options_.occbin.simul.init_regime = opts.frcst_regimes; - options_.occbin.simul.init_binding_indicator = []; - options_.occbin.simul.exo_pos=ishock; - options_.occbin.simul.SHOCKS = SHOCKS; + options_.occbin.simul.SHOCKS = shocks_base+transpose(U*sqrt(S)*SHOCKS_add(:,:,iter)); options_.occbin.simul.waitbar=0; - [~, out] = occbin.solver(M_,options_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state); - zlin0(:,:,iter)=out.linear; - zpiece0(:,:,iter)=out.piecewise; - ys=out.ys; - frcst_regime_history(iter,:)=out.regime_history; + [~, out] = occbin.solver(M_,options_,dr,endo_steady_state,exo_steady_state,exo_det_steady_state); error_flag(iter)=out.error_flag; - error_flagx = error_flag(iter); - % end - simul_SHOCKS(:,:,iter) = SHOCKS; - - if error_flag(iter) && debug_flag - % display('no solution') - -% keyboard; - save no_solution SHOCKS zlin0 zpiece0 iter frcst_regime_history + if ~error_flag(iter) + z.linear(:,:,iter)=out.linear; + z.piecewise(:,:,iter)=out.piecewise; + frcst_regime_history(iter,:)=out.regime_history; + error_flag(iter)=out.error_flag; + simul_SHOCKS(:,:,iter) = shocks_base; + else + if options_.debug + save('Occbin_forecast_debug','simul_SHOCKS','z','iter','frcst_regime_history','error_flag','out','shocks_base') + end end dyn_waitbar(iter/opts.replic,h,['OccBin MC forecast replic ',int2str(iter),'/',int2str(opts.replic)]) end dyn_waitbar_close(h); - save temp zlin0 zpiece0 simul_SHOCKS error_flag + if options_.debug + save('Occbin_forecast_debug','simul_SHOCKS','z','iter','frcst_regime_history','error_flag') + end inx=find(error_flag==0); - zlin0=zlin0(:,:,inx); - zpiece0=zpiece0(:,:,inx); - zlin = mean(zlin0,3); - zpiece = mean(zpiece0,3); - zpiecemin = min(zpiece0,[],3); - zpiecemax = max(zpiece0,[],3); - zlinmin = min(zlin0,[],3); - zlinmax = max(zlin0,[],3); - - for i=1:M_.endo_nbr - for j=1:forecast - [post_mean(j,1), post_median(j,1), post_var(j,1), hpd_interval(j,:), post_deciles(j,:)] = posterior_moments(squeeze(zlin0(j,i,:)),options_.forecasts.conf_sig); + z.linear=z.linear(:,:,inx); + z.piecewise=z.piecewise(:,:,inx); + z.min.piecewise = min(z.piecewise,[],3); + z.max.piecewise = max(z.piecewise,[],3); + z.min.linear = min(z.linear,[],3); + z.max.linear = max(z.linear,[],3); + + field_names={'linear','piecewise'}; + post_mean=NaN(forecast_horizon,1); + post_median=NaN(forecast_horizon,1); + post_var=NaN(forecast_horizon,1); + hpd_interval=NaN(forecast_horizon,2); + post_deciles=NaN(forecast_horizon,9); + for field_iter=1:2 + for i=1:M_.endo_nbr + for j=1:forecast_horizon + [post_mean(j,1), post_median(j,1), post_var(j,1), hpd_interval(j,:), post_deciles(j,:)] = posterior_moments(squeeze(z.(field_names{field_iter})(j,i,:)),options_.forecasts.conf_sig); + end + forecast.(field_names{field_iter}).Mean.(M_.endo_names{i})=post_mean; + forecast.(field_names{field_iter}).Median.(M_.endo_names{i})=post_median; + forecast.(field_names{field_iter}).Var.(M_.endo_names{i})=post_var; + forecast.(field_names{field_iter}).HPDinf.(M_.endo_names{i})=hpd_interval(:,1); + forecast.(field_names{field_iter}).HPDsup.(M_.endo_names{i})=hpd_interval(:,2); + forecast.(field_names{field_iter}).Deciles.(M_.endo_names{i})=post_deciles; + forecast.(field_names{field_iter}).Min.(M_.endo_names{i})=z.min.(field_names{field_iter})(:,i); + forecast.(field_names{field_iter}).Max.(M_.endo_names{i})=z.max.(field_names{field_iter})(:,i); end - oo_.occbin.linear_forecast.Mean.(M_.endo_names{i})=post_mean; - oo_.occbin.linear_forecast.Median.(M_.endo_names{i})=post_median; - oo_.occbin.linear_forecast.Var.(M_.endo_names{i})=post_var; - oo_.occbin.linear_forecast.HPDinf.(M_.endo_names{i})=hpd_interval(:,1); - oo_.occbin.linear_forecast.HPDsup.(M_.endo_names{i})=hpd_interval(:,2); - oo_.occbin.linear_forecast.Deciles.(M_.endo_names{i})=post_deciles; - oo_.occbin.linear_forecast.Min.(M_.endo_names{i})=zlinmin(:,i); - oo_.occbin.linear_forecast.Max.(M_.endo_names{i})=zlinmax(:,i); - for j=1:forecast - [post_mean(j,1), post_median(j,1), post_var(j,1), hpd_interval(j,:), post_deciles(j,:)] = posterior_moments(squeeze(zpiece0(j,i,:)),options_.forecasts.conf_sig); - end - oo_.occbin.forecast.Mean.(M_.endo_names{i})=post_mean; - oo_.occbin.forecast.Median.(M_.endo_names{i})=post_median; - oo_.occbin.forecast.Var.(M_.endo_names{i})=post_var; - oo_.occbin.forecast.HPDinf.(M_.endo_names{i})=hpd_interval(:,1); - oo_.occbin.forecast.HPDsup.(M_.endo_names{i})=hpd_interval(:,2); - oo_.occbin.forecast.Deciles.(M_.endo_names{i})=post_deciles; - oo_.occbin.forecast.Min.(M_.endo_names{i})=zpiecemin(:,i); - oo_.occbin.forecast.Max.(M_.endo_names{i})=zpiecemax(:,i); - % eval([M_.endo_names{i},'_ss=zdatass(i);']); end - else - SHOCKS = zeros(forecast,M_.exo_nbr); - if ~isempty(SHOCKS0) - for j=1:length(SHOCKS0) - SHOCKS(:,inds(j))=SHOCKS1(j,:); - end - end - options_.occbin.simul.endo_init = M_.endo_histval(:,1)-oo_.steady_state; - options_.occbin.simul.init_regime = opts.frcst_regimes; - options_.occbin.simul.init_violvecbool = []; options_.occbin.simul.irfshock = M_.exo_names; - options_.occbin.simul.SHOCKS = SHOCKS; - [~, out] = occbin.solver(M_,options_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state); + options_.occbin.simul.SHOCKS = shocks_base; + [~, out] = occbin.solver(M_,options_,dr,endo_steady_state,exo_steady_state,exo_det_steady_state); + error_flag=out.error_flag; + if out.error_flag + fprintf('occbin.forecast: forecast simulation failed.') + return; + end - zlin=out.linear; - zpiece=out.piecewise; frcst_regime_history=out.regime_history; error_flag=out.error_flag; for i=1:M_.endo_nbr - oo_.occbin.linear_forecast.Mean.(M_.endo_names{i})= zlin(:,i); - oo_.occbin.forecast.Mean.(M_.endo_names{i})= zpiece(:,i); - oo_.occbin.forecast.HPDinf.(M_.endo_names{i})= nan; - oo_.occbin.forecast.HPDsup.(M_.endo_names{i})= nan; + forecast.linear.Mean.(M_.endo_names{i})= out.linear(:,i); + forecast.piecewise.Mean.(M_.endo_names{i})= out.piecewise(:,i); end - end -oo_.occbin.forecast.regimes=frcst_regime_history; - +forecast.regimes=frcst_regime_history; \ No newline at end of file diff --git a/matlab/+occbin/irf.m b/matlab/+occbin/irf.m index a94b42b9d..6266f1b69 100644 --- a/matlab/+occbin/irf.m +++ b/matlab/+occbin/irf.m @@ -1,140 +1,124 @@ -function [oo_] = irf(M_,oo_,options_) +function irfs = irf(M_,oo_,options_) +% irfs = irf(M_,oo_,options_) +% Calls a minimizer +% +% INPUTS +% - M_ [structure] Matlab's structure describing the model +% - oo_ [structure] Matlab's structure containing the results +% - options_ [structure] Matlab's structure describing the current options +% +% OUTPUTS +% - irfs [structure] IRF results +% +% SPECIAL REQUIREMENTS +% none. +% +% +% Copyright © 2022-2023 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 . shocknames = options_.occbin.irf.exo_names; -shocksigns = options_.occbin.irf.shocksigns; +shocksigns = options_.occbin.irf.shocksigns; %'pos','neg' shocksize = options_.occbin.irf.shocksize; -t0 = options_.occbin.irf.t0; +t_0 = options_.occbin.irf.t0; + +%% set simulation options based on IRF options options_.occbin.simul.init_regime = options_.occbin.irf.init_regime; options_.occbin.simul.check_ahead_periods = options_.occbin.irf.check_ahead_periods; options_.occbin.simul.maxit = options_.occbin.irf.maxit; options_.occbin.simul.periods = options_.irf; -% Run inital conditions + other shocks -if t0 == 0 - shocks0= zeros(options_.occbin.simul.periods+1,M_.exo_nbr); +%% Run initial conditions + other shocks +if t_0 == 0 + shocks_base = zeros(options_.occbin.simul.periods+1,M_.exo_nbr); options_.occbin.simul.endo_init = []; else - % girf conditional to smoothed states in t0 and shocks in t0+1 - shocks0= [oo_.occbin.smoother.etahat(:,t0+1)'; zeros(options_.occbin.simul.periods,M_.exo_nbr)]; - options_.occbin.simul.SHOCKS=shocks0; - options_.occbin.simul.endo_init = oo_.occbin.smoother.alphahat(oo_.dr.inv_order_var,t0); + if ~isfield(oo_.occbin,'smoother') + error('occbin.irfs: smoother must be run before requesting GIRFs based on smoothed results') + end + % GIRF conditional on smoothed states in t_0 and shocks in t_0+1 + shocks_base= [oo_.occbin.smoother.etahat(:,t_0+1)'; zeros(options_.occbin.simul.periods,M_.exo_nbr)]; + options_.occbin.simul.SHOCKS=shocks_base; + options_.occbin.simul.endo_init = oo_.occbin.smoother.alphahat(oo_.dr.inv_order_var,t_0); end -options_.occbin.simul.SHOCKS=shocks0; -[~, out0] = occbin.solver(M_,options_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state); -zlin0 = out0.linear; -zpiece0 = out0.piecewise; +options_.occbin.simul.SHOCKS=shocks_base; -% Select shocks of interest -jexo_all =zeros(size(shocknames,1),1); +[~, out_base] = occbin.solver(M_,options_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state); +if out_base.error_flag + error('occbin.irfs: could not compute the solution') +end +irfs.linear = struct(); +irfs.piecewise = struct(); + +% Get indices of shocks of interest +exo_index =zeros(size(shocknames,1),1); for i=1:length(shocknames) - jexo_all(i) = strmatch(shocknames{i},M_.exo_names,'exact'); + exo_index(i) = strmatch(shocknames{i},M_.exo_names,'exact'); end -oo_.occbin.linear_irfs = struct(); -oo_.occbin.irfs = struct(); +% cs=get_lower_cholesky_covariance(M_.Sigma_e,options_.add_tiny_number_to_cholesky); +% irf_shocks_indx = getIrfShocksIndx(M_, options_); + % Set shock size if isempty(shocksize) - % if isfield(oo_.posterior_mode.shocks_std,M_.exo_names{jexo}) - shocksize = sqrt(diag(M_.Sigma_e(jexo_all,jexo_all))); %oo_.posterior_mode.shocks_std.(M_.exo_names{jexo}); + shocksize = sqrt(diag(M_.Sigma_e(exo_index,exo_index))); if any(shocksize < 1.e-9) shocksize(shocksize < 1.e-9) = 0.01; end end + if numel(shocksize)==1 shocksize=repmat(shocksize,[length(shocknames),1]); end % Run IRFs -for counter = 1:length(jexo_all) - - jexo = jexo_all(counter); - - if ~options_.noprint - fprintf('Producing GIRFs for shock %s. Simulation %d out of %d. \n',M_.exo_names{jexo},counter,size(jexo_all,1)); - end - - if ismember('pos',shocksigns) - % (+) shock - shocks1=shocks0; - shocks1(1,jexo)=shocks0(1,jexo)+shocksize(counter); - if t0 == 0 - options_.occbin.simul.SHOCKS=shocks1; +for sign_iter=1:length(shocksigns) + for IRF_counter = 1:length(exo_index) + jexo = exo_index(IRF_counter); + if ~options_.noprint && options_.debug + fprintf('occbin.irf: Producing GIRFs for shock %s. Simulation %d out of %d. \n',M_.exo_names{jexo},IRF_counter,size(exo_index,1)); + end + shocks1=shocks_base; + if ismember('pos',shocksigns{sign_iter}) + shocks1(1,jexo)=shocks_base(1,jexo)+shocksize(IRF_counter); + elseif ismember('neg',shocksigns{sign_iter}) + shocks1(1,jexo)=shocks_base(1,jexo)-shocksize(IRF_counter); + end + options_.occbin.simul.SHOCKS=shocks1; + if t_0 == 0 options_.occbin.simul.endo_init = []; - [~, out_pos] = occbin.solver(M_,options_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state); else - options_.occbin.simul.SHOCKS=shocks1; - options_.occbin.simul.endo_init = oo_.occbin.smoother.alphahat(oo_.dr.inv_order_var,t0); - [~, out_pos] = occbin.solver(M_,options_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state); + options_.occbin.simul.endo_init = oo_.occbin.smoother.alphahat(oo_.dr.inv_order_var,t_0); end - if out_pos.error_flag - warning('Occbin error.') - return + [~, out_sim] = occbin.solver(M_,options_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state); + if out_sim.error_flag + warning('occbin.irfs: simulation failed') + skip end - zlin_pos = out_pos.linear; - zpiece_pos = out_pos.piecewise; % Substract inital conditions + other shocks - zlin_pos_diff = zlin_pos-zlin0; - zpiece_pos_diff = zpiece_pos-zpiece0; - end - - if ismember('neg',shocksigns) - % (-) shock - shocks_1=shocks0; - shocks_1(1,jexo)=shocks0(1,jexo)-shocksize(counter); - if t0 == 0 - options_.occbin.simul.SHOCKS=shocks_1; - options_.occbin.simul.endo_init = []; - [~, out_neg] = occbin.solver(M_,options_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state); - else - options_.occbin.simul.SHOCKS=shocks_1; - options_.occbin.simul.endo_init = oo_.occbin.smoother.alphahat(oo_.dr.inv_order_var,t0); - [~, out_neg] = occbin.solver(M_,options_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state); + zdiff.linear.(shocksigns{sign_iter}) = out_sim.linear-out_base.linear; + zdiff.piecewise.(shocksigns{sign_iter}) = out_sim.piecewise-out_base.piecewise; + + for j_endo=1:M_.endo_nbr + if ismember('pos',shocksigns) + irfs.piecewise.([M_.endo_names{j_endo} '_' M_.exo_names{jexo} '_' shocksigns{sign_iter}]) = zdiff.piecewise.(shocksigns{sign_iter})(:,j_endo); + irfs.linear.([M_.endo_names{j_endo} '_' M_.exo_names{jexo} '_' shocksigns{sign_iter}]) = zdiff.linear.(shocksigns{sign_iter})(:,j_endo); + end end - if out_neg.error_flag - warning('Occbin error.') - return - end - zlin_neg = out_neg.linear; - zpiece_neg = out_neg.piecewise; - zlin_neg_diff = zlin_neg-zlin0; - zpiece_neg_diff = zpiece_neg-zpiece0; end - - % Save - if ~isfield(oo_.occbin,'linear_irfs') - oo_.occbin.linear_irfs = struct(); - end - if ~isfield(oo_.occbin,'irfs') - oo_.occbin.irfs = struct(); - end - - for jendo=1:M_.endo_nbr -% oo_.occbin.irfs.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '1']) = zpiece_pos (:,jendo); -% oo_.occbin.irfs.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '_1']) = zpiece_neg (:,jendo); -% oo_.occbin.linear_irfs.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '1']) = zlin_pos (:,jendo); -% oo_.occbin.linear_irfs.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '_1']) = zlin_neg(:,jendo); - - if ismember('pos',shocksigns) - oo_.occbin.irfs.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '_pos']) = zpiece_pos_diff (:,jendo); - oo_.occbin.linear_irfs.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '_pos']) = zlin_pos_diff (:,jendo); - end - - if ismember('neg',shocksigns) - oo_.occbin.irfs.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '_neg']) = zpiece_neg_diff (:,jendo); - oo_.occbin.linear_irfs.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '_neg']) = zlin_neg_diff (:,jendo); - end - -% % -% oo_.occbin.irfs0.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '1']) = zpiece0(:,jendo); -% oo_.occbin.linear_irfs0.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '1']) = zlin0(:,jendo); -% oo_.occbin.irfs0.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '_1']) = zpiece0(:,jendo); -% oo_.occbin.linear_irfs0.([M_.endo_names{jendo} '_' M_.exo_names{jexo} '_1']) = zlin0(:,jendo); - - end -end - - - -end - +end \ No newline at end of file diff --git a/matlab/+occbin/plot_irfs.m b/matlab/+occbin/plot_irfs.m index efe928547..29c9c63c3 100644 --- a/matlab/+occbin/plot_irfs.m +++ b/matlab/+occbin/plot_irfs.m @@ -1,34 +1,74 @@ -function plot_irfs(M_,oo_,options_,irf3,irf4) +function plot_irfs(M_,irfs,options_,var_list) +% plot_irfs(M_,irfs,options_,var_list) +% +% INPUTS +% - M_ [structure] Matlab's structure describing the model +% - irfs [structure] IRF results +% - options_ [structure] Matlab's structure describing the current options +% - var_list [character array] list of endogenous variables specified +% +% OUTPUTS +% none +% +% SPECIAL REQUIREMENTS +% none. -shocknames = options_.occbin.plot_irf.exo_names; -simulname = options_.occbin.plot_irf.simulname; -if isempty(simulname) - simulname_ = simulname; -else - simulname_ = [ simulname '_' ]; +% Copyright © 2022-2023 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 . + +if (isfield(options_,'irf_shocks')==0) + shock_names = M_.exo_names; +else + shock_names = options_.irf_shocks; end -vars_irf = options_.occbin.plot_irf.endo_names; -endo_names_long = options_.occbin.plot_irf.endo_names_long; + +simul_name = options_.occbin.plot_irf.simulname; +if isempty(simul_name) + save_name = simul_name; +else + save_name = [ simul_name '_' ]; +end + +if isempty(var_list) + var_list = M_.endo_names(1:M_.orig_endo_nbr); +end + +[i_var, ~, index_uniques] = varlist_indices(var_list, M_.endo_names); +vars_irf=var_list(index_uniques); + endo_scaling_factor = options_.occbin.plot_irf.endo_scaling_factor; -length_irf = options_.occbin.plot_irf.tplot; -if isempty(length_irf) - length_irf = options_.irf; -end +length_irf = options_.irf; -irflocation_lin = oo_.occbin.linear_irfs; -irflocation_piece = oo_.occbin.irfs; - - -steps_irf = 1; -warning('off','all') +steps_irf = 1; DirectoryName = CheckPath('graphs',M_.dname); +latexFolder = CheckPath('latex',M_.dname); +if options_.TeX && any(strcmp('eps',cellstr(options_.graph_format))) + fidTeX = fopen([latexFolder '/' M_.fname '_occbin_irfs.tex'],'w'); + fprintf(fidTeX,'%% TeX eps-loader file generated by occbin.plot_irfs.m (Dynare).\n'); + fprintf(fidTeX,['%% ' datestr(now,0) '\n']); + fprintf(fidTeX,' \n'); +end iexo=[]; -for i=1:size(shocknames,1) - itemp = strmatch(shocknames{i},M_.exo_names,'exact'); +for var_iter=1:size(shock_names,1) + itemp = strmatch(shock_names{var_iter},M_.exo_names,'exact'); if isempty(itemp) - error(['Shock ',shocknames{i},' is not defined!']) + error(['Shock ',shock_names{var_iter},' is not defined!']) else iexo=[iexo, itemp]; end @@ -38,104 +78,102 @@ ncols = options_.occbin.plot_irf.ncols; nrows = options_.occbin.plot_irf.nrows; npan = ncols*nrows; -plot_grid = options_.occbin.plot_irf.grid; -shocksigns = options_.occbin.plot_irf.shocksigns; -threshold = options_.occbin.plot_irf.threshold; - -% Add steady_state -if options_.occbin.plot_irf.add_steadystate - add_stst = options_.occbin.plot_irf.add_steadystate; -else - add_stst = 0; -end -for sss = 1:numel(shocksigns) - - shocksign = shocksigns{sss}; - - for j=1:size(shocknames,1) - %shocknames = M_.exo_names{j}; +shocksigns = options_.occbin.plot_irf.shocksigns; +threshold = options_.impulse_responses.plot_threshold; +for shock_sign_iter = 1:numel(shocksigns) + shocksign = shocksigns{shock_sign_iter}; + if strcmp(shocksign,'pos') + plot_title_sign='positive'; + elseif strcmp(shocksign,'neg') + plot_title_sign='negative'; + else + error('Unknown shock sign %s',shocksign); + end + + for shock_iter=1:size(shock_names,1) j1 = 0; isub = 0; ifig = 0; - % Variables - % ---------------------- - for i = 1:length(vars_irf) - + for var_iter = 1:length(vars_irf) j1=j1+1; if mod(j1,npan)==1 - % vector corresponds to [left bottom width height]. 680 and 678 for the left and bottom elements correspond to the default values used by MATLAB while creating a figure and width, . - hfig = dyn_figure(options_.nodisplay,'name',['OccbinIRFs ' shocknames{j} ' ' simulname ' ' shocksign],'PaperPositionMode', 'auto','PaperType','A4','PaperOrientation','portrait','renderermode','auto','position',[10 10 950 650]); + % vector corresponds to [left bottom width height]. 680 and 678 for the left and bottom elements correspond to the default values used by MATLAB while creating a figure and width, . + screensize = get( groot, 'Screensize' ); + hfig = dyn_figure(options_.nodisplay,'name',['OccBin IRFs to ' plot_title_sign ' ' shock_names{shock_iter} ' shock ' simul_name],'OuterPosition' ,[50 50 min(1000,screensize(3)-50) min(750,screensize(4)-50)]); ifig=ifig+1; isub=0; end - isub=isub+1; - + isub=isub+1; if isempty(endo_scaling_factor) exofactor = 1; - else - exofactor = endo_scaling_factor{i}; - end - - subplot(nrows,ncols,isub) - irf_field = strcat(vars_irf{i,1},'_',shocknames{j},'_',shocksign); - - irfvalues = irflocation_lin.(irf_field); - if add_stst - irfvalues = irfvalues + get_mean(vars_irf{i,1}); - end - - irfvalues(abs(irfvalues) 10 - irfvalues = irf3.(irf_field) ; - irfvalues(abs(irfvalues) 11 - irfvalues = irf4.(irf_field) ; - irfvalues(abs(irfvalues) . nperiods = size(regimes,2); nconstr = length(fieldnames(regimes(1)))/2; @@ -13,9 +35,15 @@ else end GraphDirectoryName = CheckPath('graphs',M_.dname); +fhandle = dyn_figure(options_.nodisplay,'Name',[M_.fname ': OccBin regimes']); -fhandle = dyn_figure(options_.nodisplay,'Name',[M_.fname ' occbin regimes']); - +latexFolder = CheckPath('latex',M_.dname); +if options_.TeX && any(strcmp('eps',cellstr(options_.graph_format))) + fidTeX = fopen([latexFolder '/' M_.fname '_occbin_regimes.tex'],'w'); + fprintf(fidTeX,'%% TeX eps-loader file generated by occbin.plot_regimes.m (Dynare).\n'); + fprintf(fidTeX,['%% ' datestr(now,0) '\n']); + fprintf(fidTeX,' \n'); +end for k=1:nconstr subplot(nconstr,1,k) @@ -36,12 +64,23 @@ for k=1:nconstr end end end - title(['regime ' int2str(k)]) - xlabel('historic period') - ylabel('regime expected start') + xlim([1 nperiods]) + title(['Regime ' int2str(k)]) + xlabel('Historic period') + ylabel('Regime: expected start') end -annotation('textbox',[.25,0,.15,.05],'String','Unbinding','Color','blue'); -annotation('textbox',[.65,0,.15,.05],'String','Binding','Color','red'); - +annotation('textbox',[.25,0,.15,.05],'String','Slack','Color','blue'); +annotation('textbox',[.65,0,.2,.05],'String','Binding','Color','red'); dyn_saveas(fhandle,[GraphDirectoryName, filesep, M_.fname '_occbin_regimes'],options_.nodisplay,options_.graph_format); + +if options_.TeX && any(strcmp('eps',cellstr(options_.graph_format))) + fprintf(fidTeX,'\\begin{figure}[H]\n'); + fprintf(fidTeX,'\\centering \n'); + fprintf(fidTeX,'\\includegraphics[width=%2.2f\\textwidth]{%s_occbin_regimes}\n',options_.figures.textwidth,[GraphDirectoryName '/' M_.fname]); + fprintf(fidTeX,'\\caption{OccBin: regime evolution over time.}\n'); + fprintf(fidTeX,'\\label{Fig:occbin_regimes}\n'); + fprintf(fidTeX,'\\end{figure}\n'); + fprintf(fidTeX,'\n'); + fclose(fidTeX); +end diff --git a/matlab/+occbin/set_default_options.m b/matlab/+occbin/set_default_options.m index 99a1e2e1f..b720160c5 100644 --- a/matlab/+occbin/set_default_options.m +++ b/matlab/+occbin/set_default_options.m @@ -55,9 +55,7 @@ if ismember(flag,{'forecast','all'}) options_occbin_.forecast.maxit=30; options_occbin_.forecast.qmc=0; options_occbin_.forecast.replic=0; - options_occbin_.forecast.sepath=0; options_occbin_.forecast.SHOCKS0=[]; - options_occbin_.forecast.treepath=1; % number of branches end if ismember(flag,{'irf','all'}) @@ -98,17 +96,12 @@ end if ismember(flag,{'plot_irf','all'}) options_occbin_.plot_irf.add_steadystate = 0; - options_occbin_.plot_irf.exo_names = []; - options_occbin_.plot_irf.endo_names = M_.endo_names; - options_occbin_.plot_irf.endo_names_long = []; options_occbin_.plot_irf.endo_scaling_factor = []; options_occbin_.plot_irf.grid = true; options_occbin_.plot_irf.ncols = 3; options_occbin_.plot_irf.nrows = 3; options_occbin_.plot_irf.shocksigns = {'pos','neg'}; options_occbin_.plot_irf.simulname=''; - options_occbin_.plot_irf.threshold = 10^-6; - options_occbin_.plot_irf.tplot = []; end if ismember(flag,{'plot_shock_decomp','all'}) diff --git a/tests/occbin/filter/NKM.mod b/tests/occbin/filter/NKM.mod index 325e77402..1b552290f 100644 --- a/tests/occbin/filter/NKM.mod +++ b/tests/occbin/filter/NKM.mod @@ -13,66 +13,66 @@ // ----------------- Defintions -----------------------------------------// var - c //1 Consumption - n //2 Labor - y //5 Output - yf //6 Final goods - yg //11 Output growth gap - w //12 Real wage rate - wf //13 Flexible real wage - pigap //15 Inflation rate -> pi(t)/pibar = pigap - inom ${i^{nom}}$ //16 Nominal interest rate - inomnot //17 Notional interest rate - mc //19 Real marginal cost - lam ${\lambda}$ //20 Inverse marginal utility of wealth - g //21 Growth shock - s //22 Risk premium shock - mp //23 Monetary policy shock - pi ${\pi}$ //24 Observed inflation + c $c$ (long_name='Consumption') + n (long_name='Labor') + y $y$ (long_name='Output') + yf (long_name='Final goods') + yg (long_name='Output growth gap') + w (long_name='Real wage rate') + wf (long_name='Flexible real wage') + pigap (long_name='Inflation rate -> pi(t)/pibar = pigap') + inom ${i^{nom}}$ (long_name='Nominal interest rate') + inomnot (long_name='Notional interest rate') + mc (long_name='Real marginal cost') + lam ${\lambda}$ (long_name='Inverse marginal utility of wealth') + g (long_name='Growth shock') + s (long_name='Risk premium shock') + mp (long_name='Monetary policy shock') + pi ${\pi}$ (long_name='Observed inflation') @#if !(small_model) - x //3 Investment - k //4 Capital - u //7 Utilization cost - ups //8 Utilization choice - wg //9 Real wage growth gap - xg //10 Investment growth - rk //14 Real rental rate - q //18 Tobins q + x (long_name='Investment') + k (long_name='Capital') + u (long_name='Utilization cost') + ups (long_name='Utilization choice') + wg (long_name='Real wage growth gap') + xg (long_name='Investment growth') + rk (long_name='Real rental rate') + q (long_name='Tobins q') @#endif ; varexo - epsg ${\varepsilon_g}$ // Productivity growth shock - epsi // Notional interest rate shock - epss // Risk premium shock + epsg ${\varepsilon_g}$ (long_name='Productivity growth shock') + epsi (long_name='Notional interest rate shock') + epss (long_name='Risk premium shock') ; parameters // Calibrated Parameters - beta $\beta$ // Discount factor - chi // Labor disutility scale - thetap // Elasticity of subs. between intermediate goods - thetaw // Elasticity of subs. between labor types - nbar // Steady state labor - eta // Inverse frish elasticity of labor supply - delta // Depreciation - alpha // Capital share - gbar // Mean growth rate - pibar // Inflation target - inombar // Steady gross nom interest rate - inomlb // Effective lower bound on gross nominal interest rate - sbar // Average risk premium + beta $\beta$ (long_name='Discount factor') + chi (long_name='Labor disutility scale') + thetap (long_name='Elasticity of subs. between intermediate goods') + thetaw (long_name='Elasticity of subs. between labor types') + nbar (long_name='Steady state labor') + eta (long_name='Inverse frish elasticity of labor supply') + delta (long_name='Depreciation') + alpha (long_name='Capital share') + gbar (long_name='Mean growth rate') + pibar (long_name='Inflation target') + inombar (long_name='Steady gross nom interest rate') + inomlb (long_name='Effective lower bound on gross nominal interest rate') + sbar (long_name='Average risk premium') // Parameters for DGP and Estimated parameters - varphip // Rotemberg price adjustment cost - varphiw // Rotemberg wage adjustment cost - h // Habit persistence - rhos // Persistence - rhoi // Persistence - sigz // Standard deviation technology - sigs // Standard deviation risk premia - sigi // Standard deviation mon pol - phipi // Inflation responsiveness - phiy // Output responsiveness - nu // Investment adjustment cost - sigups // Utilization + varphip (long_name='Rotemberg price adjustment cost') + varphiw (long_name='Rotemberg wage adjustment cost') + h (long_name='Habit persistence') + rhos (long_name='Persistence') + rhoi (long_name='Persistence') + sigz (long_name='Standard deviation technology') + sigs (long_name='Standard deviation risk premia') + sigi (long_name='Standard deviation mon pol') + phipi (long_name='Inflation responsiveness') + phiy (long_name='Output responsiveness') + nu (long_name='Investment adjustment cost') + sigups (long_name='Utilization') ; @@ -316,36 +316,34 @@ varobs yg inom pi; // forecast starting from period 42, zero shocks (default) smoother2histval(period=42); - [oo, error_flag] = occbin.forecast(options_,M_,oo_,8); + [forecast, error_flag] = occbin.forecast(options_,M_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state,8); // forecast with stochastic shocks options_.occbin.forecast.qmc=true; options_.occbin.forecast.replic=127; - [oo1, error_flag] = occbin.forecast(options_,M_,oo_,8); + [forecast1, error_flag] = occbin.forecast(options_,M_,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state,8); + + figure('Name','OccBin: Forecasts') + subplot(2,1,1) + plot(1:8,forecast.piecewise.Mean.inom,'b-',1:8,forecast1.piecewise.Mean.inom,'r--') + subplot(2,1,2) + plot(1:8,forecast.piecewise.Mean.y,'b-',1:8,forecast1.piecewise.Mean.y,'r--') // GIRF given states in 42 and shocks in 43 t0=42; options_.occbin.irf.exo_names=M_.exo_names; options_.occbin.irf.t0=t0; - oo_ = occbin.irf(M_,oo_,options_); + oo_.occbin.irfs = occbin.irf(M_,oo_,options_); - vars_irf = { - 'c', 'consumption' - 'n', 'labor' - 'y', 'output' - 'pigap', 'inflation rate' - 'inom', 'interest rate' - 'inomnot', 'shadow rate' - }; + var_list_ = {'c','n','y','pigap','inom','inomnot'}; - options_.occbin.plot_irf.exo_names = M_.exo_names; - options_.occbin.plot_irf.endo_names = vars_irf(:,1); - options_.occbin.plot_irf.endo_names_long = vars_irf(:,2); // if you want to scale ... // options_occbin_.plot_irf.endo_scaling_factor = vars_irf(:,3); options_.occbin.plot_irf.simulname = ['t0_' int2str(t0)]; - options_.occbin.plot_irf.tplot = min(40,options_.irf); - occbin.plot_irfs(M_,oo_,options_); - + options_.irf=40; + occbin.plot_irfs(M_,oo_.occbin.irfs,options_,var_list_); + var_list_={}; + options_.occbin.plot_irf.simulname = ['t0_' int2str(t0) '_full']; + occbin.plot_irfs(M_,oo_.occbin.irfs,options_,var_list_); oo0=oo_; // use smoother_redux estimation( @@ -374,7 +372,7 @@ varobs yg inom pi; consider_all_endogenous,heteroskedastic_filter,filter_step_ahead=[1],smoothed_state_uncertainty); // show initial condition effect of IF - figure, + figure('Name','OccBin: Smoothed shocks') subplot(221) plot([oo0.SmoothedShocks.epsg oo_.SmoothedShocks.epsg]), title('epsg') subplot(222) @@ -382,7 +380,7 @@ varobs yg inom pi; subplot(223) plot([oo0.SmoothedShocks.epss oo_.SmoothedShocks.epss]), title('epss') legend('PKF','IF') - figure, + figure('Name','OccBin: Smoothed Variables') subplot(221) plot([oo0.SmoothedVariables.inom oo_.SmoothedVariables.inom]), title('inom') subplot(222)