dynare.m 11.6 KB
Newer Older
michel's avatar
michel committed
1
function dynare(fname, varargin)
2
3
%       This command runs dynare with specified model file in argument
%       Filename.
4
%       The name of model file begins with an alphabetic character,
5
6
7
%       and has a filename extension of .mod or .dyn.
%       When extension is omitted, a model file with .mod extension
%       is processed.
assia's avatar
assia committed
8
9
10
11
%
% INPUTS
%   fname:      file name
%   varargin:   list of arguments following fname
12
%
assia's avatar
assia committed
13
14
% OUTPUTS
%   none
15
%
assia's avatar
assia committed
16
17
% SPECIAL REQUIREMENTS
%   none
18

19
% Copyright (C) 2001-2021 Dynare Team
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
%
% 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 <http://www.gnu.org/licenses/>.
sebastien's avatar
sebastien committed
35

36
if ~nargin || strcmpi(fname,'help')
37
    skipline()
38
    disp(['This is Dynare version ' dynare_version() '.'])
39
    skipline()
40
    disp('USAGE: dynare FILENAME[.mod,.dyn] [OPTIONS]')
41
    skipline()
42
    disp('The dynare command executes instruction included in FILENAME.mod.')
43
    disp('See the reference manual for the available options.')
44
    skipline()
45
46
47
    return
end

48
49
50
% The following needs to come early, to avoid spurious warnings (especially under Octave)
warning_config;

51
52
53
54
% Handle nopathchange option
% Note that it is only handled if it appears on the command-line, and not at
% the top of the .mod file (since the treatment needs to take place very early,
% even before we make the various checks on the filename)
55
56
change_path_flag = true;
if nargin>1
57
58
    id = ismember(varargin, 'nopathchange');
    if any(id)
59
        change_path_flag = false;
60
        varargin(id) = [];
61
    end
62
63
64
65
end
check_matlab_path(change_path_flag);

% Detect if MEX files are present; if not, use alternative M-files
66
dynareroot = dynare_config();
67

68
if isoctave
69
70
71
    % The supported_octave_version.m file is not in git nor in the source
    % package, it is manually added in binary packages distributed on dynare.org
    if exist('supported_octave_version', 'file') && ~strcmp(supported_octave_version, version)
72
73
        skipline()
        warning(['This version of Octave is not supported. Consider installing ' ...
74
75
76
                 'version %s of Octave\n' ...
                 'from www.octave.org, otherwise m files will be used instead ' ...
                 'of precompiled mex files and some\nfeatures, like solution ' ...
77
78
                 'of models approximated at third order, will not be available.'], supported_octave_version())
        skipline()
79
    elseif octave_ver_less_than('6.2.0') % Should match the test in mex/build/octave/configure.ac, and also the one in matlab/modules/dseries/src/initialize_dseries_class.m
80
        skipline()
81
        warning(['This version of Dynare has only been tested on Octave 6.2.0 and above. Dynare may fail to run or give unexpected result. Consider upgrading your version of Octave.'])
82
        skipline()
83
84
    end
else
85
    if matlab_ver_less_than('8.3') % Should match the test in mex/build/matlab/configure.ac
86
                                   % and in m4/ax_mexopts.m4
87
        skipline()
88
        warning('This version of Dynare has only been tested on MATLAB 8.3 (R2014a) and above. Since your MATLAB version is older than that, Dynare may fail to run, or give unexpected results. Consider upgrading your MATLAB installation, or switch to Octave.');
89
        skipline()
90
    end
sebastien's avatar
v4:    
sebastien committed
91
92
93
end

% disable output paging (it is on by default on Octave)
94
95
96
more off

% sets default format for save() command
97
if isoctave
98
    save_default_options('-mat')
99
100
end

sebastien's avatar
sebastien committed
101
if nargin < 1
102
    error('Dynare: you must provide the name of the .mod file in argument')
michel's avatar
michel committed
103
end
sebastien's avatar
sebastien committed
104

sebastien's avatar
sebastien committed
105
if ~ischar(fname)
106
    error('Dynare: argument of dynare must be a text string')
sebastien's avatar
sebastien committed
107
end
sebastien's avatar
sebastien committed
108

Stéphane Adjemian's avatar
Stéphane Adjemian committed
109
% Testing if filename has more than one period (not allowed).
110
dot_location=strfind(fname,'.');
111
if length(dot_location)>1
112
    error('Dynare: Periods in filenames are only allowed for .mod or .dyn extensions')
113
114
115
end

if dot_location==length(fname)
116
    error('Dynare: Periods in filenames are only allowed for .mod or .dyn extensions')
117
118
end

Stéphane Adjemian's avatar
Stéphane Adjemian committed
119
% Add dyn or mod extension to the file name if not already provided.
120
if isempty(dot_location)
121
    fnamelength = length(fname);
122
123
124
125
126
127
    fname1 = [fname '.dyn'];
    d = dir(fname1);
    if length(d) == 0
        fname1 = [fname '.mod'];
    end
    fname = fname1;
michel's avatar
michel committed
128
else
Stéphane Adjemian's avatar
Stéphane Adjemian committed
129
    % Check provided file extension.
130
    if ~strcmpi(fname(dot_location+1:end), 'mod') && ~strcmpi(fname(dot_location+1:end), 'dyn')
131
        error('Dynare: argument must be a filename with .mod or .dyn extensions')
132
    end
133
    fnamelength = length(fname) - 4;
134
end
135

136
if fnamelength + length('.set_auxiliary_variables') > namelengthmax()
137
    error('Dynare: the name of your .mod file is too long, please shorten it')
138
139
end

140
if ~isempty(strfind(fname,filesep))
141
    fprintf('\nIt seems you are trying to call a .mod file not located in the "Current Folder". This is not possible (the %s symbol is not allowed in the name of the .mod file).\n', filesep)
Houtan Bastani's avatar
Houtan Bastani committed
142
    [pathtomodfile,basename] = fileparts(fname);
143
144
145
146
147
    if exist(pathtomodfile,'dir')
        filesindirectory = dir(pathtomodfile);
        filesindirectory = struct2cell(filesindirectory);
        filesindirectory = filesindirectory(1,:);
        if ~isempty(strmatch([basename '.mod'],filesindirectory)) || ~isempty(strmatch([basename '.dyn'],filesindirectory))
148
            fprintf('Please set your "Current Folder" to the folder where the .mod file is located using the following command:\n')
149
150
151
152
153
            fprintf('\n  >> cd %s\n\n',pathtomodfile)
        else
            fprintf('The file %s[.mod,.dyn] could not be located!\n\n',basename)
        end
    end
154
    error(['Dynare: can''t open ' fname, '.'])
155
156
157
end

if ~exist(fname,'file') || isequal(fname,'dir')
158
159
    fprintf('\nThe file %s could not be located in the "Current Folder". Check whether you typed in the correct filename\n',fname)
    fprintf('and whether the file is really located in the "Current Folder".\n')
160
161
    try
        list_of_mod_files = ls('*.mod');
162
        fprintf('\nCurrent folder is %s, and contains the following .mod files:\n\n',pwd)
163
164
        disp(list_of_mod_files)
    catch
165
        fprintf('\nCurrent folder is %s, and does not contain any .mod files.\n\n',pwd)
166
    end
167
    error(['Dynare: can''t open ' fname])
168
end
169

170
if ~isvarname(fname(1:end-4))
171
    error('Dynare: argument of dynare must conform to MATLAB''s convention for naming functions, i.e. start with a letter and not contain special characters. Please rename your .mod file.')
172
173
end

174
% pre-dynare-preprocessor-hook
175
176
if exist(fname(1:end-4),'dir') && exist([fname(1:end-4) filesep 'hooks'],'dir') && exist([fname(1:end-4) filesep 'hooks/priorprocessing.m'],'file')
    run([fname(1:end-4) filesep 'hooks/priorprocessing'])
177
178
end

179
180
181
182
183
184
185
186
% Parse some options, either for the command-line or from the top of the .mod file
file_opts = parse_options_line(fname);
preprocessoroutput = ~ismember('nopreprocessoroutput', varargin) && ...
                     ~ismember('nopreprocessoroutput', file_opts);
nolog = ismember('nolog', varargin) || ismember('nolog', file_opts);
onlymacro = ismember('onlymacro', varargin) || ismember('onlymacro', file_opts);
onlyjson = ismember('onlyjson', varargin) || ismember('onlyjson', file_opts);

187
188
189
190
191
192
193
194
195
196
% Start journal
diary off
if ~nolog
    logfile = [ fname(1:end-4) '.log' ];
    if exist(logfile, 'file')
        delete(logfile)
    end
    diary(logfile)
end

197
if preprocessoroutput
198
    fprintf(['Starting Dynare (version ' dynare_version() ').\n']);
199
    fprintf('Calling Dynare with arguments: ');
200
201
    if isempty(varargin)
        disp('none')
202
    else
203
204
205
206
        disp(strjoin(varargin, ' '));
    end
end

207
command = ['"' dynareroot '..' filesep 'preprocessor' filesep 'dynare-preprocessor" ' fname] ;
208
209
210
211
212
213
214
215
216
217
218
command = [ command ' mexext=' mexext ' "matlabroot=' matlabroot '"'];
% Properly quote arguments before passing them to the shell
if ~isempty(varargin)
    varargincopy = varargin;
    % Escape backslashes and double-quotes
    varargincopy = strrep(varargincopy, '\', '\\');
    varargincopy = strrep(varargincopy, '"', '\"');
    if ~ispc
        % On GNU/Linux and macOS, also escape dollars and backquotes
        varargincopy = strrep(varargincopy, '$', '\$');
        varargincopy = strrep(varargincopy, '`', '\`');
219
    end
220
221
222
    % Finally, enclose arguments within double quotes
    dynare_varargin = ['"' strjoin(varargincopy, '" "') '"'];
    command = [command ' ' dynare_varargin];
223
end
224

225
226
227
228
229
230
231
232
233
234
% On MATLAB+Windows, the +folder may be locked by MATLAB, preventing its
% removal by the preprocessor.
% Trying to delete it here will actually fail, but surprisingly this allows
% the preprocessor to actually remove the folder (see ModFile::writeOutputFiles())
% For an instance of this bug, see:
% https://forum.dynare.org/t/issue-with-dynare-preprocessor-4-6-1/15448/1
if ispc && ~isoctave && exist(['+',fname(1:end-4)],'dir')
    [~,~]=rmdir(['+', fname(1:end-4)],'s');
end

235
236
237
% Under Windows, make sure the MEX file is unloaded (in the use_dll case),
% otherwise the preprocessor can't recompile it
if isoctave
238
    clear([fname(1:end-4) '.static'], [fname(1:end-4) '.dynamic'])
239
else
240
    clear(['+' fname(1:end-4) '/static'], ['+' fname(1:end-4) '/dynamic'])
241
242
end

michel's avatar
michel committed
243
[status, result] = system(command);
244
245
246
if status ~= 0 || preprocessoroutput
    disp(result)
end
247
if onlymacro
248
    if preprocessoroutput
Sébastien Villemot's avatar
Sébastien Villemot committed
249
        disp('Preprocessor stopped after macroprocessing step because of ''onlymacro'' option.');
250
    end
251
    return
252
end
253

254
if onlyjson
255
    if preprocessoroutput
Sébastien Villemot's avatar
Sébastien Villemot committed
256
        disp('Preprocessor stopped after preprocessing step because of ''onlyjson'' option.');
257
    end
258
259
260
    return;
end

261
% post-dynare-prerocessor-hook
262
263
if exist(fname(1:end-4),'dir') && exist([fname(1:end-4) filesep 'hooks'],'dir') && exist([fname(1:end-4) filesep 'hooks/postprocessing.m'],'file')
    run([fname(1:end-4) filesep 'hooks/postprocessing'])
264
265
end

michel's avatar
michel committed
266
if status
267
    diary off
268
    % Should not use "error(result)" since message will be truncated if too long
269
    error('Dynare: preprocessing failed')
michel's avatar
michel committed
270
271
272
end

if ~ isempty(find(abs(fname) == 46))
273
    fname = fname(:,1:find(abs(fname) == 46)-1) ;
michel's avatar
michel committed
274
end
275
276
277
278
279

% We need to clear the driver (and only the driver, because the "clear all"
% within the driver will clean the rest)
clear(['+' fname '/driver'])

280
281
282
283
284
285
286
287
try
    evalin('base',[fname '.driver']) ;
catch ME
    diary off
    rethrow(ME)
end

diary off
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322

end

% Looks for an options list in the first non-empty line of the .mod file
% Should be kept in sync with the function of the same name in preprocessor/src/DynareMain.cc
%
% Note that separating options with commas is accepted, but is deprecated (and undocumented)
%
% Also, the parser does not handle correctly some corner cases: for example, it
% will fail on something like -Dfoo="a b,c" (will split at whitespace and comma)
function opts = parse_options_line(fname)
    opts = {};
    fid = fopen(fname, 'r');
    while true
        firstline = fgetl(fid);
        if firstline == -1
            fclose(fid);
            return
        end
        if ~isempty(firstline)
            break
        end
    end
    fclose(fid);
    t = regexp(firstline, '^\s*//\s*--\+\s*options:([^\+]*)\+--', 'tokens');
    if isempty(t)
        return
    end

    opts = regexp(t{1}{1}, '[^,\s]+', 'match');

    if ismember(opts, 'nopathchange')
        warning('The ''nopathchange'' option is not taken into account when it appears at the top of ''.mod'' file. You should rather pass it on the command-line.')
    end
end