2020-01-28 16:39:15 +01:00
function aggregate ( ofile, dynopt, rootfolder, varargin)
2019-03-25 17:59:22 +01:00
% Agregates cherry-picked models.
2023-03-16 13:46:33 +01:00
% Copyright © 2019-2023 Dynare Team
2019-03-25 17:59:22 +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/>.
2019-03-25 17:59:22 +01:00
2019-04-02 07:11:32 +02:00
MAX_NUMBER_OF_ELEMENTS = 10000 ;
2019-03-25 17:59:22 +01:00
2023-03-17 18:19:03 +01:00
if ~ isoctave && matlab_ver_less_than ( ' 9.14' ) % Warning removed in R2023a
2023-03-17 16:03:37 +01:00
warning off MATLAB : subscripting : noSubscriptsSpecified
end
2019-03-25 17:59:22 +01:00
2019-10-01 12:53:17 +02:00
if ~ isempty ( dynopt )
% Should be a list of options for the preprocessor in a cell
% array.
firstline = ' // --+ options:' ;
if iscell ( dynopt )
for i = 1 : length ( dynopt )
firstline = sprintf ( ' %s %s' , firstline , dynopt { i } ) ;
end
firstline = sprintf ( ' %s %s' , firstline , ' +--' ) ;
else
error ( ' Second argument has to be a cell array (list of options for dynare preprocessor).' )
end
else
firstline = ' ' ;
end
2019-03-25 17:59:22 +01:00
% Get parameters.
for i = 1 : length ( varargin )
fid = fopen ( sprintf ( ' %s/parameters.inc' , varargin { i } ) ) ;
2019-04-27 18:08:19 +02:00
if fid < 0
% No parameters in the cherrypicked (sub)model, go to the
% next cherrypicked model.
continue
end
2019-03-25 17:59:22 +01:00
statement = fgetl ( fid ) ;
if exist ( ' plist' , ' var' )
plist = union ( plist , strsplit ( statement , { ' parameters' , ' ' , ' ;' } ) ) ;
else
plist = strsplit ( statement , { ' parameters' , ' ' , ' ;' } ) ;
end
plist ( cellfun ( @ ( x ) all ( isempty ( x ) ) , plist ) ) = [ ] ;
fclose ( fid ) ;
end
% Get equations
eqlist = cell ( MAX_NUMBER_OF_ELEMENTS , 4 ) ;
tagnum = 1 ;
eqnum = 0 ;
for i = 1 : length ( varargin )
2021-01-29 12:29:39 +01:00
% Store all non-empty lines of model.inc in the “model” cell-array
fid = fopen ( sprintf ( ' %s/model.inc' , varargin { i } ) ) ;
model = { } ;
while ~ feof ( fid )
line = fgetl ( fid ) ;
if ~ isempty ( line )
model { end + 1 } = line ;
end
end
fclose ( fid ) ;
2019-03-25 17:59:22 +01:00
eqtag = false ;
for j = 1 : length ( model )
if isequationtag ( model { j } )
if eqtag
error ( ' An equation tag must be followed by an equation.' )
end
2020-01-28 16:40:31 +01:00
% Ensure that the equation tag name matches the LHS variable.
eqtagname = regexp ( model { j } , ' name=' ' (\w*)' ' ' , ' match' ) ;
[ lhs , ~ ] = getequation ( model { j + 1 } ) ;
endovar = getendovar ( lhs ) ;
eqtagname_ = strcat ( ' name=' ' ' , endovar { 1 } , ' ' ' ' ) ;
2020-01-29 11:38:20 +01:00
if ~ isempty ( eqtagname )
if ~ isequal ( eqtagname { 1 } , eqtagname_ )
model { j } = strrep ( model { j } , eqtagname { 1 } , eqtagname_ ) ;
end
else
2021-11-25 16:16:42 +01:00
model { j } = strcat ( ' [' , eqtagname_ , ' ]' ) ;
2020-01-28 16:40:31 +01:00
end
2020-02-11 19:09:33 +01:00
% Add equation tag with block name.
if ~ isempty ( rootfolder )
model { j } = strcat ( ' [blockname=' ' ' , getblockname ( varargin { i } , rootfolder ) , ' ' ' ,' , model { j } ( 2 : end ) ) ;
end
2019-03-25 17:59:22 +01:00
eqlist { tagnum , 4 } = model { j } ;
eqtag = true ;
else
eqnum = eqnum + 1 ;
[ lhs , rhs ] = getequation ( model { j } ) ;
endovar = getendovar ( lhs ) ;
eqlist { eqnum , 1 } = endovar { 1 } ;
eqlist { eqnum , 2 } = lhs ;
eqlist { eqnum , 3 } = rhs ;
eqtag = false ;
tagnum = tagnum + 1 ;
end
end
end
eqlist = eqlist ( 1 : eqnum , : ) ;
2021-03-12 14:50:35 +01:00
[ ~ , idx ] = unique ( eqlist ( : , 1 ) , ' stable' ) ;
2020-01-28 16:38:15 +01:00
eqlist = eqlist ( idx , : ) ;
2020-01-29 11:38:20 +01:00
2019-03-25 17:59:22 +01:00
% Get endogenous variables.
elist = cell ( MAX_NUMBER_OF_ELEMENTS , 2 ) ;
enum = 0 ;
for i = 1 : length ( varargin )
fid = fopen ( sprintf ( ' %s/endogenous.inc' , varargin { i } ) ) ;
cline = fgetl ( fid ) ;
while ischar ( cline )
if ~ isequal ( cline , ' var' )
enum = enum + 1 ;
cline = regexprep ( cline , ' \t' , ' ' ) ;
cline = regexprep ( cline , ' ;' , ' ' ) ;
[ v , t ] = getvarandtag ( cline ) ;
elist ( enum , 1 ) = { v } ;
elist ( enum , 2 ) = { t } ;
end
cline = fgetl ( fid ) ;
end
fclose ( fid ) ;
end
elist = elist ( 1 : enum , : ) ;
2021-03-12 14:50:35 +01:00
[ ~ , idx ] = unique ( elist ( : , 1 ) , ' stable' ) ;
2020-01-28 16:38:15 +01:00
elist = elist ( idx , : ) ;
2019-03-25 17:59:22 +01:00
% Get exogenous variables.
xlist = cell ( MAX_NUMBER_OF_ELEMENTS , 2 ) ;
xnum = 0 ;
for i = 1 : length ( varargin )
fid = fopen ( sprintf ( ' %s/exogenous.inc' , varargin { i } ) ) ;
2019-04-27 18:08:19 +02:00
if fid < 0
% No exogenous variables in the cherrypicked (sub)model, go to the
% next cherrypicked model.
continue
end
2019-03-25 17:59:22 +01:00
cline = fgetl ( fid ) ;
while ischar ( cline )
if ~ isequal ( cline , ' varexo' )
xnum = xnum + 1 ;
cline = regexprep ( cline , ' \t' , ' ' ) ;
cline = regexprep ( cline , ' ;' , ' ' ) ;
[ v , t ] = getvarandtag ( cline ) ;
xlist ( xnum , 1 ) = { v } ;
xlist ( xnum , 2 ) = { t } ;
end
cline = fgetl ( fid ) ;
end
fclose ( fid ) ;
end
xlist = xlist ( 1 : xnum , : ) ;
2021-03-12 14:50:35 +01:00
[ ~ , idx ] = unique ( xlist ( : , 1 ) , ' stable' ) ;
2020-01-28 16:38:15 +01:00
xlist = xlist ( idx , : ) ;
2019-03-25 17:59:22 +01:00
2019-04-02 07:11:32 +02:00
% Get parameter values.
2022-04-28 12:56:21 +02:00
pArray = cell ( 0 , 3 ) ;
2019-04-02 07:11:32 +02:00
for i = 1 : length ( varargin )
fid = fopen ( sprintf ( ' %s/parameter-values.inc' , varargin { i } ) ) ;
2019-04-27 18:08:19 +02:00
if fid < 0
% No calibrations in the cherrypicked (sub)model, go to the
% next cherrypicked model.
continue
end
2019-04-02 07:11:32 +02:00
cline = fgetl ( fid ) ;
while ischar ( cline )
2023-09-27 12:05:57 +02:00
tmp = textscan ( cline , ' %s = %f' , ' Delimiter' , ' ;= ' ) ;
2022-04-28 12:56:21 +02:00
pArray ( end + 1 , 1 ) = tmp { 1 } ;
pArray { end , 2 } = tmp { 2 } ;
pArray { end , 3 } = varargin { i } ;
2019-04-02 07:11:32 +02:00
cline = fgetl ( fid ) ;
end
fclose ( fid ) ;
end
2022-04-28 12:56:21 +02:00
if rows ( pArray ) > 1
irow = 2 ;
while irow < = rows ( pArray )
ispreviouslydefined = strcmpi ( pArray { irow , 1 } , pArray ( 1 : irow - 1 , 1 ) ) ;
if any ( ispreviouslydefined )
if isnan ( pArray { ispreviouslydefined , 2 } )
if ~ isnan ( pArray { irow , 2 } )
% Remove first assignment (with NaN)
pArray ( ispreviouslydefined , : ) = [ ] ;
else
% Remove second assignment (both assigments are NaNs)
pArray ( irow , : ) = [ ] ;
end
elseif isnan ( pArray { irow , 2 } )
% New assigment is NaN but not the previous one.
pArray ( irow , : ) = [ ] ;
else
% Check that the values are identical in both assignments.
if abs ( pArray { ispreviouslydefined , 2 } - pArray { irow , 2 } ) > 1e-10
error ( ' More than one assigment for parameter %s with different values (see cherrypicked files in %s and %s).' , pArray { irow , 1 } , pArray { irow , 3 } , pArray { ispreviouslydefined , 3 } ) ;
else
% Remove last assignement (duplicate).
pArray ( irow , : ) = [ ] ;
end
end
else
irow = irow + 1 ;
end
end
end
2022-04-29 22:39:29 +02:00
if any ( isnan ( [ pArray { : , 2 } ] ) )
msg = ' ' ;
for i = 1 : rows ( pArray )
if isnan ( pArray { i , 2 } )
msg = sprintf ( ' %sParameter %s has no value.\n' , msg , pArray { i , 1 } ) ;
end
end
error ( msg )
end
2022-04-28 12:56:21 +02:00
calibration = ' ' ;
for i = 1 : rows ( pArray )
2022-06-17 16:44:51 +02:00
calibration = sprintf ( ' %s%s = %s;\n' , calibration , pArray { i , 1 } , num2str ( pArray { i , 2 } , 16 ) ) ;
2022-04-28 12:56:21 +02:00
end
2019-03-25 17:59:22 +01:00
% Move the endogenous variables which are not LHS of an equation
% into the set of exogenous variables.
[ ~ , i1 ] = intersect ( elist ( : , 1 ) , eqlist ( : , 1 ) ) ;
if ~ isequal ( length ( i1 ) , rows ( eqlist ) )
error ( ' Something is wrong with the endogenous variables.' )
end
i2 = setdiff ( 1 : rows ( elist ) , i1 ) ;
xlist = [ xlist ; elist ( i2 , : ) ] ;
2019-10-01 12:24:20 +02:00
[ ~ , idx ] = unique ( xlist ( : , 1 ) ) ; % Ensure that the exogenous variable names are unique.
xlist = [ xlist ( idx , 1 ) xlist ( idx , 2 ) ] ; % We do not test that the tags are the same.
2019-03-25 17:59:22 +01:00
elist = elist ( i1 , : ) ;
2019-07-17 17:52:16 +02:00
% Remove endogenous variables from list of exogenous variables (if any).
2019-10-01 12:24:20 +02:00
xlist1 = xlist ( : , 1 ) ;
xlist2 = xlist ( : , 2 ) ;
[ xlist1 , id ] = setdiff ( xlist1 , elist ( : , 1 ) ) ;
xlist2 = xlist2 ( id ) ;
xlist = [ xlist1 , xlist2 ] ;
2019-07-17 17:52:16 +02:00
2019-03-25 17:59:22 +01:00
% Print all cherry-picked models in one mod-file.
[ filepath , filename , fileext ] = fileparts ( ofile ) ;
if ~ isempty ( filepath ) && ~ exist ( filepath , ' dir' )
mkdir ( filepath ) ;
end
if isempty ( filepath )
fid = fopen ( sprintf ( ' %s%s' , filename , fileext ) , ' w' ) ;
else
fid = fopen ( sprintf ( ' %s%s%s%s' , filepath , filesep ( ) , filename , fileext ) , ' w' ) ;
end
2019-10-01 12:53:17 +02:00
if ~ isempty ( firstline )
fprintf ( fid , ' %s\n\n' , firstline ) ;
end
2023-03-16 13:46:33 +01:00
% Print list of endogenous variables.
2019-03-25 17:59:22 +01:00
fprintf ( fid , ' var\n' ) ;
for i = 1 : rows ( elist )
2019-07-19 16:51:16 +02:00
if size ( elist , 2 ) == 1 || isempty ( elist { i , 2 } )
2019-03-25 17:59:22 +01:00
fprintf ( fid , ' \t%s\n' , elist { i , 1 } ) ;
else
fprintf ( fid , ' \t%s %s\n' , elist { i , 1 } , elist { i , 2 } ) ;
end
end
2023-10-11 15:47:57 +02:00
fprintf ( fid , ' ;\n\n' ) ;
2023-09-28 09:39:18 +02:00
if exist ( ' plist' , ' var' ) && ~ isempty ( plist )
2023-03-16 13:46:33 +01:00
% Print list of parameters.
2019-05-04 08:52:51 +02:00
fprintf ( fid , ' parameters\n' ) ;
for i = 1 : length ( plist )
fprintf ( fid , ' \t%s\n' , plist { i } ) ;
end
fprintf ( fid , ' ;\n\n' ) ;
2023-03-16 13:46:33 +01:00
% Print calibration.
2019-05-04 08:52:51 +02:00
fprintf ( fid , calibration ) ;
end
2023-09-28 09:39:18 +02:00
if exist ( ' xlist' , ' var' ) && ~ isempty ( xlist )
2023-03-16 13:46:33 +01:00
% Print list of exogenous variables.
2019-05-04 08:52:51 +02:00
fprintf ( fid , ' \n\n' ) ;
fprintf ( fid , ' varexo\n' ) ;
for i = 1 : rows ( xlist )
2019-07-19 16:51:16 +02:00
if size ( xlist , 2 ) == 1 || isempty ( xlist { i , 2 } )
2019-05-04 08:52:51 +02:00
fprintf ( fid , ' \t%s\n' , xlist { i , 1 } ) ;
else
fprintf ( fid , ' \t%s %s\n' , xlist { i , 1 } , xlist { i , 2 } ) ;
end
2019-03-25 17:59:22 +01:00
end
2023-10-11 15:47:57 +02:00
fprintf ( fid , ' ;\n' ) ;
2019-03-25 17:59:22 +01:00
end
2023-03-16 13:46:33 +01:00
skipline ( 1 , fid )
% Provide an interface to flip endogenous and exogenous variables. Active if only macrovariable
% InvertModel is set to True. The calls to the change_type command must be provided in the file
% model-inversion-setup.inc (in the current folder).
fprintf ( fid , ' @#ifdef InvertModel\n' ) ;
fprintf ( fid , ' @#if InvertModel\n' ) ;
fprintf ( fid , ' @#include "model-inversion-setup.inc"\n' ) ;
fprintf ( fid , ' @#endif\n' ) ;
fprintf ( fid , ' @#endif\n' ) ;
skipline ( 1 , fid )
2019-03-25 17:59:22 +01:00
fprintf ( fid , ' model;\n\n' ) ;
for i = 1 : rows ( eqlist )
if isempty ( eqlist { i , 4 } )
fprintf ( fid , ' \t%s = %s;\n\n' , eqlist { i , 2 } , eqlist { i , 3 } ) ;
else
fprintf ( fid , ' \t%s\n' , eqlist { i , 4 } ) ;
fprintf ( fid , ' \t%s = %s;\n\n' , eqlist { i , 2 } , eqlist { i , 3 } ) ;
end
end
fprintf ( fid , ' end;' ) ;
fclose ( fid ) ;
2023-03-17 18:19:03 +01:00
if ~ isoctave && matlab_ver_less_than ( ' 9.14' )
2023-03-17 16:03:37 +01:00
warning on MATLAB : subscripting : noSubscriptsSpecified
end
2019-03-25 17:59:22 +01:00
function b = isequationtag ( str)
b = true ;
if isempty ( regexp ( str , ' \[.*\]' , ' once' ) )
b = false ;
end
function [lhs, rhs] = getequation ( str)
terms = strsplit ( str , { ' =' , ' ;' } ) ;
terms ( cellfun ( @ ( x ) all ( isempty ( x ) ) , terms ) ) = [ ] ;
terms ( 1 ) = { strrep ( terms { 1 } , ' ' , ' ' ) } ;
2019-10-02 19:39:27 +02:00
lhs = regexp ( terms { 1 } , ' ^(diff\([\-]*(log|diff)\([\-\+\*\/\w]*\)\)|(log|diff)\([\(\-\+\*\/\)\w]*\)|\w*)' , ' match' ) ;
2019-03-25 17:59:22 +01:00
if ~ isempty ( lhs )
lhs = lhs { 1 } ;
2019-09-30 22:38:40 +02:00
if isequal ( lhs , ' log' )
error ( ' Malformed equation: log of log or diff are not allowed.' )
end
2019-03-25 17:59:22 +01:00
rhs = terms { 2 } ;
else
error ( ' Malformed equation.' )
end
function v = getendovar ( lhs)
2019-09-30 22:38:40 +02:00
v = strsplit ( lhs , { ' diff' , ' log' , ' (' , ' )' , ' +' , ' -' , ' *' , ' /' } ) ;
2019-03-25 17:59:22 +01:00
v ( cellfun ( @ ( x ) all ( isempty ( x ) ) , v ) ) = [ ] ;
2019-09-30 22:38:40 +02:00
if length ( v ) > 1
error ( ' Malformed equation: no more than one endogenous variable can be used on the LHS.' )
end
2019-03-25 17:59:22 +01:00
function [v, t] = getvarandtag ( str)
tmp = regexp ( str , ' (?<name>\w+)\s*(?<tag>\(.*\))' , ' names' ) ;
if isempty ( tmp )
tmp = regexp ( str , ' (?<name>\w+)\s*' , ' names' ) ;
v = tmp . name ;
t = ' ' ;
else
v = tmp . name ;
t = tmp . tag ;
2020-01-28 16:39:15 +01:00
end
function blkname = getblockname ( str, ROOT_FOLDER)
2020-02-11 19:08:37 +01:00
str = strrep ( str , ' /' , filesep ( ) ) ;
2020-01-28 16:39:15 +01:00
str = strrep ( str , [ ROOT_FOLDER filesep ( ) ' blocks' filesep ( ) ] , ' ' ) ;
idx = strfind ( str , filesep ( ) ) ;
2021-01-15 14:45:25 +01:00
blkname = str ( 1 : idx ( 1 ) - 1 ) ;