function [db, info] = solvemodelforresiduals(modelname, db, cleanup)

% Solves a model for the residuals (given paths for the endogenous
% variables and observed exogenous variables), and check the
% consistency of the model and the database.
%
% INPUTS
% - modelname     [char]      1×n  Name of a mod file (with extension).
% - db            [dseries]   database containing at least all the endogenous variables.
% - cleanup       [logical]   scalar, removes generated files if true (default)
%
% OUTPUTS
% - db            [dseries]   updated database with the residuals (and Dynare's auxiliary variables).

global M_

[filepath, basename, ext] = fileparts(modelname);

if ~isempty(ext) && ~ismember(ext, {'.mod','.dyn'})
    error('File %s is not a Dynare file.', modelname)
end

if ~isempty(ext)
    if ~exist(modelname, 'file')
        error('File %s not found.', modelname)
    end
else
    if ~exist(sprintf('%s.mod', modelname), 'file')
        error('Dynare file extension was not provided and %s.mod cannot be found.', modelname)
    end
end

if nargin<3
    cleanup = true;
end

% Set path
if ~isempty(filepath)
    origPath = pwd();
    cd(filepath)
end

% Call dynare.
dynare(basename, 'nopreprocessoroutput', 'notime', 'stochastic', 'json=compute')

% Set list of endogenous variables.
listendo = M_.endo_names;

% Set list of exogenous variables.
listexo = M_.exo_names;

% Set list of residuals.
listres = listexo(~cellfun(@isempty, regexp(listexo, sprintf('\\<%s', 'res_'))));

% Set list of observed exogenous variables.
listexoo = setdiff(listexo, listres);

% Set list of observed variables.
listobserved = [listendo; listexoo];

% Ensure that the residuals are not in the database.
db{listres{:}} = [];

% Check database and append auxiliary variables.
[db, info] = checkdatabaseforinversion(db, M_);

% Remove any unused variable from the database.
db = db{listobserved{:}};

% Consider the largest possible subsample.
db = db(db.firstobservedperiod():db.lastobservedperiod());

% Solve for the residuals.
residuals = calibrateresiduals(db, info, M_);

% Update the database with the residuals.
db = merge(db, residuals);

% Cleanup
if cleanup
    rmdir(sprintf('+%s', basename), 's');
    rmdir(sprintf('%s', basename), 's');
    delete(sprintf('%s.log', basename));
    delete(sprintf('%s_results.mat', basename));
end

%(re)Set path.
if ~isempty(filepath)
    cd(origPath)
end