function json = cherrypick(infile, outfold, eqtags, noresids, json) % Extract some equations in infile (mod file used for estimation) % and write them in outfile (mod file used for simulation). % % INPUTS % - infile [string] Name of the mod file where all the equations used for estimation are available. % - outfold [string] Name of the folder where the generated files are saveda subset of the equations is to be printed. % - eqtags [cell] Equation tags of the selected equations. % - noresids [logical] Removes estimation residuals (not to be used in simulation) if true. % - json [char] Content of a JSON file. % % OUTPUTS % - json [char] Content of a JSON file. % % SPECIAL REQUIREMENTS % It is expected that the file infile.mod has already been run, and % that the associated JSON output is available. % Copyright © 2019-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 . global M_ % Set default value if nargin<4 || isempty(noresids) noresids = true; end % Delete outfold subdirectory if it already exists if exist(outfold, 'dir') rmdir(outfold, 's'); end % Create the subdirectoty where the generated files will be saved. mkdir(outfold); % Check that infile.mod and the related JSON output exist. if ~exist(sprintf('%s.mod', infile), 'file') error('Cannot find %s.mod.', infile) end if ~exist(sprintf('%s/model/json', infile), 'dir') error('Cannot find %s/model/json folder. Did you run %s.mod with the json option?', infile, infile); end % Check if some variables have to be renamed. rename = M_.equations_tags(strcmp('rename',M_.equations_tags(:,2)),[1,3]); isrename = ~isempty(rename); if nargin<5 % Load json file (original mod file) json = loadjson_(sprintf('%s/model/json/modfile-original.json', M_.dname)); end % Create a new file. fid = fopen(sprintf('%s/model.inc', outfold), 'w'); plist = {}; elist = {}; xlist = {}; try for i=1:length(eqtags) rhs = []; lhs = []; % Get equation number. eqnum = get_equation_number_by_tag(eqtags{i}, M_); % Get the original equation. [LHS, RHS] = get_lhs_and_rhs(eqtags{i}, M_, true, json); % Get the parameters, endogenous and exogenous variables in the current equation. [pnames, enames, xnames] = get_variables_and_parameters_in_equation(LHS, RHS, M_); lhs_expression = LHS; LHS = get_variables_and_parameters_in_expression(LHS); enames = union(enames, LHS); if length(LHS)>1 error('Expressions with more than one variable on the LHS are not allowed.') end LHS = LHS{1}; if isrename [variable_has_to_be_renamed, id] = ismember(eqnum, [rename{:,1}]); if variable_has_to_be_renamed TMP = strsplit(rename{id,2}, ','); for j=1:length(TMP) tmp = strsplit(TMP{j}, '->'); lhs_expression = exactstrrep(lhs_expression, tmp{1}, tmp{2}); RHS = exactstrrep(RHS, tmp{1}, tmp{2}); rep = strcmp(tmp{1}, enames); if any(rep) enames(rep) = tmp(2); end rep = strcmp(tmp{1}, xnames); if any(rep) xnames(rep) = tmp(2); end end end end % Remove residual from equation if required. if noresids if isfield(M_, 'simulation_exo_names') exogenous_variables_to_be_removed = ~ismember(xnames, M_.simulation_exo_names); else exogenous_variables_to_be_removed = false(size(xnames)); end if any(exogenous_variables_to_be_removed) switch sum(exogenous_variables_to_be_removed) case 1 RHS = regexprep(RHS, sprintf('\\ *\\+\\ *%s', xnames{exogenous_variables_to_be_removed}), ''); RHS = regexprep(RHS, sprintf('%s', xnames{exogenous_variables_to_be_removed}), ''); case 0 % Nothing to do. otherwise error('Cannot remove more than one exogenous variable in an equation (%s).', eqtags{i}) end xnames = setdiff(xnames, xnames{exogenous_variables_to_be_removed}); end end % Unroll expectation terms if any. isvar = regexp(RHS, 'var_expectation\(model_name = (?\w+)\)', 'names'); ispac = regexp(RHS, 'pac_expectation\(model_name = (?\w+)\)', 'names'); istar = regexp(RHS, 'pac_target_nonstationary\(model_name = (?\w+)\)', 'names'); if ~isempty(isvar) rhs = write_expectations(isvar.name, 'var'); auxlhs = sprintf('%s_VE', eqtags{i}); RHS = strrep(RHS, sprintf('var_expectation(model_name = %s)', isvar.name), auxlhs); end if ~isempty(ispac) if isfield(M_.pac.(ispac.name), 'components') [rhs, growthneutralitycorrection] = write_expectations(ispac.name, 'pac', false, false); else [rhs, growthneutralitycorrection] = write_expectations(ispac.name, 'pac'); end if ~isempty(rhs) if iscell(rhs) % PAC expectations are decomposed. auxlhs = cell(size(rhs)); for k=1:length(M_.pac.(ispac.name).components) if isequal(k, 1) lhs = M_.lhs{M_.pac.(ispac.name).components(k).aux_id}; auxlhs{k} = lhs; if ~isempty(growthneutralitycorrection{k}) lhs = sprintf('%s+%s', lhs, growthneutralitycorrection{k}); end if ~isequal(M_.pac.(ispac.name).components(k).coeff_str, '1') if isempty(growthneutralitycorrection{k}) lhs = sprintf('%s*%s', M_.pac.(ispac.name).components(k).coeff_str, lhs); else lhs = sprintf('%s*(%s)', M_.pac.(ispac.name).components(k).coeff_str, lhs); end end else lhs_ = M_.lhs{M_.pac.(ispac.name).components(k).aux_id}; auxlhs{k} = lhs_; if ~isempty(growthneutralitycorrection{k}) lhs_ = sprintf('%s+%s', lhs_, growthneutralitycorrection{k}); end if ~isequal(M_.pac.(ispac.name).components(k).coeff_str, '1') if isempty(growthneutralitycorrection{k}) lhs_ = sprintf('%s*%s', M_.pac.(ispac.name).components(k).coeff_str, lhs_); else lhs_ = sprintf('%s*(%s)', M_.pac.(ispac.name).components(k).coeff_str, lhs_); end end lhs = sprintf('%s+%s', lhs, lhs_); end end RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), lhs); else auxlhs = M_.lhs{M_.pac.(ispac.name).aux_id}; if isempty(growthneutralitycorrection) RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), auxlhs); else RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), sprintf('%s+%s', auxlhs, growthneutralitycorrection)); end end else % MCE version of the PAC equation. [rhs, growthneutralitycorrection] = write_pac_mce_expectations(eqtags{i}, ispac.name); auxlhs = sprintf('%s_Z', eqtags{i}); if isempty(growthneutralitycorrection) RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), auxlhs); else RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), sprintf('%s+%s', auxlhs, growthneutralitycorrection)); end end end if ~isempty(istar) RHS = strrep(RHS, sprintf('pac_target_nonstationary(model_name = %s)', ispac.name), sprintf('%s(-1)', M_.endo_names{M_.pac.(ispac.name).ec.vars(M_.pac.(ispac.name).ec.istarget)})); end % Print equation for unrolled PAC/VAR-expectation and update % list of parameters and endogenous variables (if any). if ~isempty(rhs) % Note that the call to get_variables_and_parameters_in_equation() % will not return the lhs variable in expectation_enames since % the name is created on the fly and is not a member of M_.endo_names. expectation_pnames = get_variables_and_parameters_in_equation('', rhs, M_); expectation_enames = get_variables_and_parameters_in_expression(auxlhs); expectation_xnames = get_variables_and_parameters_in_expression(rhs); pnames = union(pnames, expectation_pnames); xnames = union(xnames, setdiff(expectation_xnames, expectation_pnames)); enames = union(enames, expectation_enames); if ischar(rhs) fprintf(fid, '[name=''%s'']\n', auxlhs); fprintf(fid, '%s = %s;\n\n', auxlhs, rhs); else for k=1:length(rhs) fprintf(fid, '[name=''%s'']\n', auxlhs{k}); fprintf(fid, '%s = %s;\n\n', auxlhs{k}, rhs{k}); end end if ~isempty(ispac) && isfield(M_.pac.(ispac.name), 'components') for k=1:length(M_.pac.(ispac.name).components) if ~isequal(M_.pac.(ispac.name).components(k).coeff_str, '1') params = get_variables_and_parameters_in_expression(M_.pac.(ispac.name).components(k).coeff_str); pnames = union(pnames, params); end end end else pRHS = get_variables_and_parameters_in_equation('', RHS, M_); xRHS = get_variables_and_parameters_in_expression(RHS); xnames = union(xnames, setdiff(xRHS, pRHS)); pnames = union(pnames, pRHS); end % Update pnames, enames and xnames if PAC with growth neutrality correction. if ~isempty(ispac) && ~isempty(growthneutralitycorrection) [growthneutralitycorrection_pnames, ... growthneutralitycorrection_enames, ... growthneutralitycorrection_xnames] = get_variables_and_parameters_in_equation('', growthneutralitycorrection, M_); if ~isempty(growthneutralitycorrection_pnames) pnames = union(pnames, growthneutralitycorrection_pnames); end if ~isempty(growthneutralitycorrection_enames) xnames = union(xnames, growthneutralitycorrection_enames); end if ~isempty(growthneutralitycorrection_xnames) xnames = union(xnames, growthneutralitycorrection_xnames); end end % Print tags if iscell(json.model) tfields = fieldnames(json.model{eqnum}.tags); tags = sprintf('%s=''%s''', tfields{1}, json.model{eqnum}.tags.(tfields{1})); for j=2:length(tfields) if ~isempty(json.model{eqnum}.tags.(tfields{j})) tags = sprintf('%s, %s=''%s''', tags, tfields{j}, json.model{eqnum}.tags.(tfields{j})); end end else tfields = fieldnames(json.model.tags); tags = sprintf('%s=''%s''', tfields{1}, json.model.tags.(tfields{1})); for j=2:length(tfields) if ~isempty(json.model.tags.(tfields{j})) tags = sprintf('%s, %s=''%s''', tags, tfields{j}, json.model.tags.(tfields{j})); end end end fprintf(fid, '[%s]\n', tags); % Print equation. fprintf(fid, '%s = %s;\n\n', lhs_expression, RHS); % Update lists of parameters, endogenous variables and exogenous variables. plist = union(plist, pnames); elist = union(elist, enames); xlist = union(xlist, xnames); end catch e fclose(fid); fprintf(2, '%s\n', e.message) fprintf(2, 'Delete ''%s'' file.\n', sprintf('%s/model.inc', outfold)) delete(sprintf('%s/model.inc', outfold)) return end fclose(fid); % Export parameters if ~isempty(plist) fid = fopen(sprintf('%s/parameters.inc', outfold), 'w'); fprintf(fid, 'parameters %s;', sprintf('%s ', plist{:})); fclose(fid); end % Export endogegnous variables fid = fopen(sprintf('%s/endogenous.inc', outfold), 'w'); printlistofvariables(fid, 'endo', elist, M_, elist); fclose(fid); % Export exogenous variables if ~isempty(xlist) fid = fopen(sprintf('%s/exogenous.inc', outfold), 'w'); printlistofvariables(fid, 'exo', xlist, M_, xlist); fclose(fid); end % Export parameter values if ~isempty(plist) fid = fopen(sprintf('%s/parameter-values.inc', outfold), 'w'); for i=1:length(plist) id = strcmp(plist{i}, M_.param_names); if any(id) if isnan(M_.params(id)) warning('Parameter %s has no value.', plist{i}) else fprintf(fid, '%s = %s;\n', plist{i}, num2str(M_.params(id), 16)); end end end fclose(fid); end function printlistofvariables(fid, kind, list, DynareModel, vappend) if isfield(DynareModel, sprintf('%s_partitions', kind)) % Some endogenous variables are tagged. switch kind case 'exo' tfields = fieldnames(DynareModel.exo_partitions); vlist = 'varexo'; vnames = DynareModel.exo_names; partitions = DynareModel.exo_partitions; case 'endo' tfields = fieldnames(DynareModel.endo_partitions); vlist = 'var'; vnames = DynareModel.endo_names(1:DynareModel.orig_endo_nbr); partitions = DynareModel.endo_partitions; otherwise error('Illegal value for second input argument.') end for i = 1:length(list) id = strmatch(list{i}, vnames, 'exact'); if ~isempty(id) tags = ''; for j=1:length(tfields) if ~isempty(partitions.(tfields{j}){id}) tags = sprintf('%s, %s=''%s''', tags, tfields{j}, partitions.(tfields{j}){id}); end end if ~isempty(tags) tags = sprintf('(%s)', tags(3:end)); end elseif ~isempty(strmatch(list{i}, vappend, 'exact')) % Nothing to do, this variable was renamed by cherrypick tags = ''; else if isequal(kind, 'endo') && (isequal(list{i}(end-2:end), '_PE') || isequal(list{i}(end-2:end), '_VE')) if isequal(list{i}(end-2:end), '_PE') tags = sprintf('(expectation_kind=''%s'')', 'pac'); else tags = sprintf('(expectation_kind=''%s'')', 'var'); end else error('Unknown variable.') end end if isempty(tags) vlist = sprintf('%s\n\t%s', vlist, list{i}); else vlist = sprintf('%s\n\t%s %s', vlist, list{i}, tags); end end fprintf(fid, '%s;', vlist); else switch kind case 'exo' vlist = 'varexo'; case 'endo' vlist = 'var'; otherwise error('Illegal value for second input argument.') end for i=1:length(list) vlist = sprintf('%s\n\t%s', vlist, list{i}); end fprintf(fid, '%s;', vlist); end