2012-05-26 20:50:17 +02:00
function model_diagnostics ( M,options,oo)
% function model_diagnostics(M,options,oo)
2017-05-16 15:10:20 +02:00
% computes various diagnostics on the model
2009-03-26 10:34:40 +01:00
% INPUTS
2017-05-16 15:10:20 +02:00
% M [matlab structure] Definition of the model.
2012-05-26 20:50:17 +02:00
% options [matlab structure] Global options.
2017-05-16 15:10:20 +02:00
% oo [matlab structure] Results
%
2009-03-26 10:34:40 +01:00
% OUTPUTS
% none
2017-05-16 15:10:20 +02:00
%
2009-03-26 10:34:40 +01:00
% ALGORITHM
% ...
2017-05-16 15:10:20 +02:00
%
2009-03-26 10:34:40 +01:00
% SPECIAL REQUIREMENTS
% none.
2017-05-16 15:10:20 +02:00
%
2009-03-26 10:34:40 +01:00
2023-01-09 15:19:36 +01:00
% Copyright © 1996-2023 Dynare Team
2009-03-26 10:34:40 +01:00
%
% 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
2021-06-09 17:33:48 +02:00
% along with Dynare. If not, see <https://www.gnu.org/licenses/>.
2009-04-02 15:22:41 +02:00
2012-05-26 20:50:17 +02:00
endo_nbr = M . endo_nbr ;
endo_names = M . endo_names ;
lead_lag_incidence = M . lead_lag_incidence ;
2013-01-07 10:40:49 +01:00
maximum_endo_lag = M . maximum_endo_lag ;
2009-04-02 15:22:41 +02:00
2021-11-25 16:04:14 +01:00
if options . ramsey_policy
%test whether specification matches
inst_nbr = size ( options . instruments , 1 ) ;
if inst_nbr ~= 0
orig_endo_aux_nbr = M . orig_endo_nbr + min ( find ( [ M . aux_vars . type ] == 6 ) ) - 1 ;
implied_inst_nbr = orig_endo_aux_nbr - M . orig_eq_nbr ;
if inst_nbr > implied_inst_nbr
error ( ' You have specified more instruments than there are omitted equations' )
elseif inst_nbr < implied_inst_nbr
error ( ' You have specified fewer instruments than there are omitted equations' )
end
else
if options . steadystate_flag
error ( ' You have specified a steady state file, but not provided an instrument. Either delete the steady state file or provide an instrument' )
end
end
end
2014-02-10 18:21:20 +01:00
problem_dummy = 0 ;
2022-05-04 13:05:27 +02:00
%naming conflict in steady state file
if options . steadystate_flag == 1
if strmatch ( ' ys' , M . endo_names , ' exact' )
disp ( [ ' MODEL_DIAGNOSTICS: using the name ys for an endogenous variable will typically conflict with the internal naming in user-defined steady state files.' ] )
problem_dummy = 1 ;
end
if strmatch ( ' ys' , M . param_names , ' exact' )
disp ( [ ' MODEL_DIAGNOSTICS: using the name ys for a parameter will typically conflict with the internal naming in user-defined steady state files.' ] )
problem_dummy = 1 ;
end
if strmatch ( ' M_' , M . endo_names , ' exact' )
disp ( [ ' MODEL_DIAGNOSTICS: using the name M_ for an endogenous variable will typically conflict with the internal naming in user-defined steady state files.' ] )
problem_dummy = 1 ;
end
if strmatch ( ' M_' , M . param_names , ' exact' )
disp ( [ ' MODEL_DIAGNOSTICS: using the name M_ for a parameter will typically conflict with the internal naming in user-defined steady state files.' ] )
problem_dummy = 1 ;
end
end
2009-12-16 18:17:34 +01:00
%
% missing variables at the current period
%
2013-01-07 10:40:49 +01:00
k = find ( lead_lag_incidence ( maximum_endo_lag + 1 , : ) == 0 ) ;
2009-12-16 18:17:34 +01:00
if ~ isempty ( k )
2014-02-10 18:21:20 +01:00
problem_dummy = 1 ;
2014-03-28 14:52:29 +01:00
disp ( [ ' MODEL_DIAGNOSTICS: The following endogenous variables aren' ' t present at ' ...
2009-12-16 18:17:34 +01:00
' the current period in the model:' ] )
for i = 1 : length ( k )
2017-10-10 10:05:59 +02:00
disp ( endo_names { k ( i ) } )
2009-04-02 15:22:41 +02:00
end
2009-12-16 18:17:34 +01:00
end
%
% check steady state
%
info = 0 ;
2012-05-26 20:50:17 +02:00
if M . exo_nbr == 0
oo . exo_steady_state = [ ] ;
2009-12-16 18:17:34 +01:00
end
2014-05-07 10:49:50 +02:00
info = test_for_deep_parameters_calibration ( M ) ;
if info
problem_dummy = 1 ;
2017-05-16 12:42:01 +02:00
end
2014-05-07 10:49:50 +02:00
2009-12-16 18:17:34 +01:00
% check if ys is steady state
2022-08-11 09:43:30 +02:00
options . debug = true ; %locally set debug option to true
2021-09-28 09:35:27 +02:00
if options . logged_steady_state %if steady state was previously logged, undo this
oo . dr . ys = exp ( oo . dr . ys ) ;
oo . steady_state = exp ( oo . steady_state ) ;
options . logged_steady_state = 0 ;
end
2020-03-10 11:06:35 +01:00
[ dr . ys , M . params , check1 ] = evaluate_steady_state ( oo . steady_state , M , options , oo , options . steadystate . nocheck ) ;
2012-05-26 20:50:17 +02:00
2009-12-16 18:17:34 +01:00
% testing for problem
2013-08-22 09:49:29 +02:00
if check1 ( 1 )
2014-02-10 18:21:20 +01:00
problem_dummy = 1 ;
2014-03-28 14:52:29 +01:00
disp ( ' MODEL_DIAGNOSTICS: The steady state cannot be computed' )
2013-08-22 09:49:29 +02:00
if any ( isnan ( dr . ys ) )
2014-03-28 14:52:29 +01:00
disp ( [ ' MODEL_DIAGNOSTICS: Steady state contains NaNs' ] )
2013-08-22 09:49:29 +02:00
end
if any ( isinf ( dr . ys ) )
2014-03-28 14:52:29 +01:00
disp ( [ ' MODEL_DIAGNOSTICS: Steady state contains Inf' ] )
2013-08-22 09:49:29 +02:00
end
2017-05-16 12:42:01 +02:00
return
2009-12-16 18:17:34 +01:00
end
2009-04-02 15:22:41 +02:00
2009-12-16 18:17:34 +01:00
if ~ isreal ( dr . ys )
2014-02-10 18:21:20 +01:00
problem_dummy = 1 ;
2014-03-28 14:52:29 +01:00
disp ( [ ' MODEL_DIAGNOSTICS: Steady state contains complex ' ...
2009-12-16 18:17:34 +01:00
' numbers' ] )
return
end
2009-04-02 15:22:41 +02:00
2009-12-16 18:17:34 +01:00
%
% singular Jacobian of static model
%
2013-10-31 08:07:55 +01:00
singularity_problem = 0 ;
2012-11-16 17:39:03 +01:00
if ~ isfield ( M , ' block_structure_stat' )
2012-05-26 20:50:17 +02:00
nb = 1 ;
else
2012-11-16 17:39:03 +01:00
nb = length ( M . block_structure_stat . block ) ;
2012-05-26 20:50:17 +02:00
end
2009-12-16 18:17:34 +01:00
2012-05-26 20:50:17 +02:00
exo = [ oo . exo_steady_state ; oo . exo_det_steady_state ] ;
for b = 1 : nb
if options . bytecode
if nb == 1
2020-01-10 17:55:57 +01:00
[ res , jacob ] = bytecode ( dr . ys , exo , M . params , dr . ys , 1 , exo , ...
' evaluate' , ' static' ) ;
2012-05-26 20:50:17 +02:00
else
2020-01-10 17:55:57 +01:00
[ res , jacob ] = bytecode ( dr . ys , exo , M . params , dr . ys , 1 , exo , ...
2023-01-09 15:19:36 +01:00
' evaluate' , ' static' , ' block_decomposed' , [ ' block=' ...
2012-05-26 20:50:17 +02:00
int2str ( b ) ] ) ;
2009-12-16 18:17:34 +01:00
end
2012-05-26 20:50:17 +02:00
else
2018-06-27 17:02:13 +02:00
[ res , jacob ] = feval ( [ M . fname ' .static' ] , dr . ys , exo , M . params ) ;
2009-12-16 18:17:34 +01:00
end
2014-03-28 14:52:29 +01:00
if any ( any ( isinf ( jacob ) | isnan ( jacob ) ) )
problem_dummy = 1 ;
[ infrow , infcol ] = find ( isinf ( jacob ) | isnan ( jacob ) ) ;
fprintf ( ' \nMODEL_DIAGNOSTICS: The Jacobian of the static model contains Inf or NaN. The problem arises from: \n\n' )
display_problematic_vars_Jacobian ( infrow , infcol , M , dr . ys , ' static' , ' MODEL_DIAGNOSTICS: ' )
end
2014-09-14 19:34:00 +02:00
if any ( any ( ~ isreal ( jacob ) ) )
problem_dummy = 1 ;
[ imagrow , imagcol ] = find ( abs ( imag ( jacob ) ) > 1e-15 ) ;
fprintf ( ' \nMODEL_DIAGNOSTICS: The Jacobian of the static model contains imaginary parts. The problem arises from: \n\n' )
display_problematic_vars_Jacobian ( imagrow , imagcol , M , dr . ys , ' static' , ' MODEL_DIAGNOSTICS: ' )
end
2014-03-28 14:52:29 +01:00
try
2022-08-28 13:29:57 +02:00
if isoctave || matlab_ver_less_than ( ' 9.12' ) || isempty ( options . jacobian_tolerance )
2022-07-26 15:32:25 +02:00
rank_jacob = rank ( jacob ) ; %can sometimes fail
else
2022-08-28 13:29:57 +02:00
rank_jacob = rank ( jacob , options . jacobian_tolerance ) ; %can sometimes fail
2022-07-26 15:32:25 +02:00
end
2014-03-28 14:52:29 +01:00
catch
rank_jacob = size ( jacob , 1 ) ;
end
2012-05-26 20:50:17 +02:00
if rank_jacob < size ( jacob , 1 )
2014-02-10 18:21:20 +01:00
problem_dummy = 1 ;
2013-10-31 08:07:55 +01:00
singularity_problem = 1 ;
2014-03-28 14:52:29 +01:00
disp ( [ ' MODEL_DIAGNOSTICS: The Jacobian of the static model is ' ...
2012-05-26 20:50:17 +02:00
' singular' ] )
2014-03-28 14:52:29 +01:00
disp ( [ ' MODEL_DIAGNOSTICS: there is ' num2str ( endo_nbr - rank_jacob ) ...
2012-05-26 20:50:17 +02:00
' colinear relationships between the variables and the equations' ] )
2022-08-28 13:29:57 +02:00
if isoctave || matlab_ver_less_than ( ' 9.12' ) || isempty ( options . jacobian_tolerance )
2022-07-26 15:32:25 +02:00
ncol = null ( jacob ) ;
else
2022-08-28 13:29:57 +02:00
ncol = null ( jacob , options . jacobian_tolerance ) ; %can sometimes fail
2022-07-26 15:32:25 +02:00
end
2012-05-26 20:50:17 +02:00
n_rel = size ( ncol , 2 ) ;
for i = 1 : n_rel
if n_rel > 1
disp ( [ ' Relation ' int2str ( i ) ] )
end
disp ( ' Colinear variables:' )
for j = 1 : 10
k = find ( abs ( ncol ( : , i ) ) > 10 ^- j ) ;
if max ( abs ( jacob ( : , k ) * ncol ( k , i ) ) ) < 1e-6
break
end
end
2018-01-25 17:37:12 +01:00
fprintf ( ' %s\n' , endo_names { k } )
2009-12-16 18:17:34 +01:00
end
2022-08-28 13:29:57 +02:00
if isoctave || matlab_ver_less_than ( ' 9.12' ) || isempty ( options . jacobian_tolerance )
2022-07-26 15:32:25 +02:00
neq = null ( jacob ' ) ; %can sometimes fail
else
2022-08-28 13:29:57 +02:00
neq = null ( jacob ' , options . jacobian_tolerance ) ; %can sometimes fail
2022-07-26 15:32:25 +02:00
end
2012-05-26 20:50:17 +02:00
n_rel = size ( neq , 2 ) ;
for i = 1 : n_rel
if n_rel > 1
disp ( [ ' Relation ' int2str ( i ) ] )
end
disp ( ' Colinear equations' )
for j = 1 : 10
k = find ( abs ( neq ( : , i ) ) > 10 ^- j ) ;
if max ( abs ( jacob ( k , : ) ' * neq ( k , i ) ) ) < 1e-6
break
end
2009-04-02 15:22:41 +02:00
end
2012-05-26 20:50:17 +02:00
disp ( k ' )
2009-04-02 15:22:41 +02:00
end
end
2009-12-16 18:17:34 +01:00
end
2017-05-16 15:10:20 +02:00
if singularity_problem
2014-10-29 19:33:33 +01:00
try
options_check = options ;
options_check . noprint = 1 ;
[ eigenvalues_ ] = check ( M , options_check , oo ) ;
2014-12-03 13:35:06 +01:00
if any ( abs ( abs ( eigenvalues_ ) - 1 ) < 1e-6 )
2014-10-29 19:33:33 +01:00
fprintf ( ' MODEL_DIAGNOSTICS: The singularity seems to be (partly) caused by the presence of a unit root\n' )
fprintf ( ' MODEL_DIAGNOSTICS: as the absolute value of one eigenvalue is in the range of +-1e-6 to 1.\n' )
fprintf ( ' MODEL_DIAGNOSTICS: If the model is actually supposed to feature unit root behavior, such a warning is expected,\n' )
fprintf ( ' MODEL_DIAGNOSTICS: but you should nevertheless check whether there is an additional singularity problem.\n' )
end
catch
end
2014-03-28 14:52:29 +01:00
fprintf ( ' MODEL_DIAGNOSTICS: The presence of a singularity problem typically indicates that there is one\n' )
fprintf ( ' MODEL_DIAGNOSTICS: redundant equation entered in the model block, while another non-redundant equation\n' )
fprintf ( ' MODEL_DIAGNOSTICS: is missing. The problem often derives from Walras Law.\n' )
end
%%check dynamic Jacobian
klen = M . maximum_lag + M . maximum_lead + 1 ;
exo_simul = [ repmat ( oo . exo_steady_state ' , klen , 1 ) repmat ( oo . exo_det_steady_state ' , klen , 1 ) ] ;
iyv = M . lead_lag_incidence ' ;
iyv = iyv ( : ) ;
iyr0 = find ( iyv ) ;
it_ = M . maximum_lag + 1 ;
z = repmat ( dr . ys , 1 , klen ) ;
2016-12-09 20:17:19 +01:00
if ~ options . block
if options . order == 1
if ( options . bytecode )
2020-01-10 17:55:57 +01:00
[ ~ , loc_dr ] = bytecode ( ' dynamic' , ' evaluate' , z , exo_simul , ...
M . params , dr . ys , 1 ) ;
2016-12-09 20:17:19 +01:00
jacobia_ = [ loc_dr . g1 loc_dr . g1_x loc_dr . g1_xd ] ;
else
2018-11-13 17:58:42 +01:00
[ ~ , jacobia_ ] = feval ( [ M . fname ' .dynamic' ] , z ( iyr0 ) , exo_simul , ...
M . params , dr . ys , it_ ) ;
2017-05-16 12:42:01 +02:00
end
2016-12-09 20:17:19 +01:00
elseif options . order > = 2
if ( options . bytecode )
2020-01-10 17:55:57 +01:00
[ ~ , loc_dr ] = bytecode ( ' dynamic' , ' evaluate' , z , exo_simul , ...
M . params , dr . ys , 1 ) ;
2016-12-09 20:17:19 +01:00
jacobia_ = [ loc_dr . g1 loc_dr . g1_x ] ;
else
2018-11-13 17:58:42 +01:00
[ ~ , jacobia_ , hessian1 ] = feval ( [ M . fname ' .dynamic' ] , z ( iyr0 ) , ...
exo_simul , ...
M . params , dr . ys , it_ ) ;
2017-05-16 12:42:01 +02:00
end
2014-03-28 14:52:29 +01:00
end
2017-05-16 15:10:20 +02:00
2016-12-09 20:17:19 +01:00
if any ( any ( isinf ( jacobia_ ) | isnan ( jacobia_ ) ) )
problem_dummy = 1 ;
[ infrow , infcol ] = find ( isinf ( jacobia_ ) | isnan ( jacobia_ ) ) ;
fprintf ( ' \nMODEL_DIAGNOSTICS: The Jacobian of the dynamic model contains Inf or NaN. The problem arises from: \n\n' )
display_problematic_vars_Jacobian ( infrow , infcol , M , dr . ys , ' dynamic' , ' MODEL_DIAGNOSTICS: ' )
end
if any ( any ( ~ isreal ( jacobia_ ) ) )
[ imagrow , imagcol ] = find ( abs ( imag ( jacobia_ ) ) > 1e-15 ) ;
2021-05-20 11:23:48 +02:00
if ~ isempty ( imagrow )
problem_dummy = 1 ;
fprintf ( ' \nMODEL_DIAGNOSTICS: The Jacobian of the dynamic model contains imaginary parts. The problem arises from: \n\n' )
display_problematic_vars_Jacobian ( imagrow , imagcol , M , dr . ys , ' dynamic' , ' MODEL_DIAGNOSTICS: ' )
end
2014-04-01 14:39:19 +02:00
end
2016-12-09 20:17:19 +01:00
if exist ( ' hessian1' , ' var' )
if any ( any ( isinf ( hessian1 ) | isnan ( hessian1 ) ) )
problem_dummy = 1 ;
fprintf ( ' \nMODEL_DIAGNOSTICS: The Hessian of the dynamic model contains Inf or NaN.\n' )
end
2017-05-16 15:10:20 +02:00
end
2016-12-09 20:17:19 +01:00
else
fprintf ( ' \nMODEL_DIAGNOSTICS: This command currently does not support the block option for checking.\n' )
fprintf ( ' \nMODEL_DIAGNOSTICS: the dynamic model. You may want to disable it for doing model_diagnostics. Skipping this part.\n' )
2013-10-31 08:07:55 +01:00
end
2016-12-09 20:17:19 +01:00
2014-02-10 18:21:20 +01:00
if problem_dummy == 0
2014-03-28 14:52:29 +01:00
fprintf ( ' MODEL_DIAGNOSTICS: No obvious problems with this mod-file were detected.\n' )
2014-02-10 18:21:20 +01:00
end