1function smoother2histval(opts)
2% This function takes values from oo_.SmoothedVariables (and possibly
3% oo_.SmoothedShocks) and copies them into M_.histval.
4%
5% Optional fields in 'opts' structure:
6%    infile:      An optional *_results MAT file created by Dynare.
7%                 If present, oo_.Smoothed{Variables,Shocks} are read from
8%                 there. Otherwise, they are read from the global workspace.
9%    invars:      An optional char or cell array listing variables to read in
10%                 oo_.SmoothedVariables. If absent, all the endogenous
11%                 variables present in oo_.SmoothedVariables are used.
12%    period:      An optional period number to use as the starting point
13%                 for subsequent simulations. It should be between 1 and
14%                 the number of observations that were used to produce the
15%                 smoothed values. If absent, the last observation is used.
16%    outfile:     An optional MAT file in which to save the histval structure.
17%                 If absent, the output will be written in M_.endo_histval
18%    outvars:     An optional char or cell array listing variables to be written in
19%                 outfile or M_.endo_histval. This cell must be of same
20%                 length than invars, and there is a mapping between the input
21%                 variable at the i-th position in invars, and the output
22%                 variable at the i-th position in outvars. If absent, then
23%                 taken as equal to invars.
24%
25% The function also uses the value of option_.parameter_set
26
27% Copyright (C) 2014-2018 Dynare Team
28%
29% This file is part of Dynare.
30%
31% Dynare is free software: you can redistribute it and/or modify
32% it under the terms of the GNU General Public License as published by
33% the Free Software Foundation, either version 3 of the License, or
34% (at your option) any later version.
35%
36% Dynare is distributed in the hope that it will be useful,
37% but WITHOUT ANY WARRANTY; without even the implied warranty of
38% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39% GNU General Public License for more details.
40%
41% You should have received a copy of the GNU General Public License
42% along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
43
44global M_ options_ oo_
45
46if ~isfield(opts, 'infile')
47    if ~isfield(oo_, 'SmoothedVariables')
48        error('Could not find smoothed variables; did you set the "smoother" option?')
49    end
50    smoothedvars = oo_.SmoothedVariables;
51    smoothedshocks = oo_.SmoothedShocks;
52    steady_state = oo_.steady_state;
53else
54    S = load(opts.infile);
55    if ~isfield(S, 'oo_') || ~isfield(S.oo_, 'SmoothedVariables')
56        error('Could not find smoothed variables in file; is this a Dynare results file, and did you set the "smoother" option when producing it?')
57    end
58    smoothedvars = S.oo_.SmoothedVariables;
59    smoothedshocks = S.oo_.SmoothedShocks;
60    steady_state = S.oo_.steady_state;
61end
62
63% Hack to determine if oo_.SmoothedVariables was computed after a Metropolis
64tmp = fieldnames(smoothedvars);
65if isstruct(smoothedvars.(tmp{1}))
66    post_metropolis = 1;
67    if ~ isstruct(smoothedvars.(tmp{end}))
68        % point and metropolis results are simultaneously present
69        post_metropolis = 2;
70    end
71
72elseif isstruct(smoothedvars.(tmp{end}))
73    % point and metropolis results are simultaneously present
74    post_metropolis = 2;
75else
76    post_metropolis = 0;
77end
78
79if post_metropolis
80    tmp = fieldnames(smoothedvars.Mean);
81    tmpexo = fieldnames(smoothedshocks.Mean);
82else
83    tmp = fieldnames(smoothedvars);
84    tmpexo = fieldnames(smoothedshocks);
85end
86
87% If post-Metropolis, select the parameter set
88if isempty(options_.parameter_set)
89    if post_metropolis
90        smoothedvars = smoothedvars.Mean;
91        smoothedshocks = smoothedshocks.Mean;
92        steady_state = zeros(size(steady_state));
93    end
94else
95    switch options_.parameter_set
96      case 'calibration'
97        if post_metropolis == 1
98            error('Option parameter_set=calibration is not consistent with computed smoothed values.')
99        end
100      case 'posterior_mode'
101        if post_metropolis == 1
102            error('Option parameter_set=posterior_mode is not consistent with computed smoothed values.')
103        end
104      case 'posterior_mean'
105        if ~post_metropolis
106            error('Option parameter_set=posterior_mean is not consistent with computed smoothed values.')
107        end
108        smoothedvars = smoothedvars.Mean;
109        smoothedshocks = smoothedshocks.Mean;
110        steady_state = zeros(size(steady_state));
111      case 'posterior_median'
112        if ~post_metropolis
113            error('Option parameter_set=posterior_median is not consistent with computed smoothed values.')
114        end
115        smoothedvars = smoothedvars.Median;
116        smoothedshocks = smoothedshocks.Median;
117        steady_state = zeros(size(steady_state));
118      otherwise
119        error([ 'Option parameter_set=' options_.parameter_set ' unsupported.' ])
120    end
121end
122
123% Determine number of periods
124n = size(smoothedvars.(tmp{1}));
125
126if n < M_.maximum_endo_lag
127    error('Not enough observations to create initial conditions')
128end
129
130if isfield(opts, 'invars')
131    invars = opts.invars;
132    if ischar(invars)
133        invars = cellstr(invars);
134    end
135else
136    invars = [tmp; tmpexo];
137end
138
139if isfield(opts, 'period')
140    period = opts.period;
141    if period > n
142        error('The period that you indicated is beyond the data sample')
143    end
144    if period < M_.maximum_endo_lag
145        error('The period that you indicated is too small to construct initial conditions')
146    end
147else
148    period = n;
149end
150
151if isfield(opts, 'outvars')
152    outvars = opts.outvars;
153    if ischar(outvars)
154        outvars = cellstr(outvars);
155    end
156    if length(invars) ~= length(outvars)
157        error('The number of input and output variables is not the same')
158    end
159else
160    outvars = invars;
161end
162
163% Initialize outputs
164if ~isfield(opts, 'outfile')
165    % Output to M_.endo_histval
166    M_.endo_histval = repmat(oo_.steady_state, 1, M_.maximum_endo_lag);
167else
168    % Output to a file
169    o = struct();
170end
171
172% Handle all endogenous variables to be copied
173for i = 1:length(invars)
174    if isempty(strmatch(invars{i}, M_.endo_names, 'exact'))
175        % Skip exogenous
176        continue
177    end
178    s = smoothedvars.(invars{i});
179    j = strmatch(invars{i}, M_.endo_names, 'exact');
180    v = s((period-M_.maximum_endo_lag+1):period);% + steady_state(j);
181    if ~isfield(opts, 'outfile')
182        j = strmatch(outvars{i}, M_.endo_names, 'exact');
183        if isempty(j)
184            error(['smoother2histval: output variable ' outvars{i} ' does not exist.'])
185        else
186            M_.endo_histval(j, :) = v;
187        end
188    else
189        % When saving to a file, x(-1) is in the variable called "x_"
190        o.([ outvars{i} '_' ]) = v;
191    end
192end
193
194% Handle auxiliary variables for lags (both on endogenous and exogenous)
195for i = 1:length(M_.aux_vars)
196    if ~ ismember(M_.endo_names{M_.aux_vars(i).endo_index},invars)
197        if M_.aux_vars(i).type ~= 1 && M_.aux_vars(i).type ~= 3
198            continue
199        end
200        if M_.aux_vars(i).type == 1
201            % Endogenous
202            orig_var = M_.endo_names{M_.aux_vars(i).orig_index};
203        else
204            % Exogenous
205            orig_var = M_.exo_names{M_.aux_vars(i).orig_index};
206        end
207        [m, k] = ismember(orig_var, outvars);
208        if m
209            if ~isempty(strmatch(invars{k}, M_.endo_names))
210                s = smoothedvars.(invars{k});
211            else
212                s = smoothedshocks.(invars{k});
213            end
214            l = M_.aux_vars(i).orig_lead_lag;
215            if period-M_.maximum_endo_lag+1+l < 1
216                error('The period that you indicated is too small to construct initial conditions')
217            end
218            j = M_.aux_vars(i).endo_index;
219            v = s((period-M_.maximum_endo_lag+1+l):(period+l)); %+steady_state(j);
220            if ~isfield(opts, 'outfile')
221                M_.endo_histval(j, :) = v;
222            else
223                % When saving to a file, x(-2) is in the variable called "x_l2"
224                lead_lag = num2str(l);
225                lead_lag = regexprep(lead_lag, '-', 'l');
226                o.([ orig_var '_' lead_lag ]) = v;
227            end
228        end
229    end
230end
231
232% Finalize output
233if isfield(opts, 'outfile')
234    save(opts.outfile, '-struct', 'o')
235end
236
237end
238