function d = lognormal(this,d,varargin)
% lognormal  Characteristics of log-normal distributions returned by filter of forecast.
%
% Syntax
% =======
%
%     d = lognormal(m,d,...)
%
% Input arguments
% ================
%
% * `m` [ model ] - Model on which the `filter` or `forecast` function has
% been run.
%
% * `d` [ struct ] - Output structure from the `filter` or `forecast`
% functions.
%
% Output arguments
% =================
%
% * `d` [ struct ] - Output structure with new databases.
%
% Options
% ========
%
% * `'fresh='` [ `true` | *`false`* ] - Output structure will include only the
% newly computed databases.
%
% * `'mean='` [ *`true`* | `false` ] - Compute the mean of the log-normal
% distributions.
%
% * `'median='` [ *`true`* | `false` ] - Compute the median of the log-normal
% distributions.
%
% * `'mode='` [ *`true`* | `false` ] - Compute the mode of the log-normal
% distributions.
%
% * `'pctile='` [ numeric | *[5,95]* ] - Compute the selected percentiles of
% the log-normal distributions.
%
% * `'prefix='` [ char | *'lognormal'* ] - Prefix used in the names of the
% newly created databases.
%
% * `'std='` [ *`true`* | `false` ] - Compute the std deviations of the
% log-normal distributions.
%
% Description
% ============
% -IRIS Toolbox.
% -Copyright (c) 2007-2012 Jaromir Benes.

P = inputParser();
P.addRequired('this',@ismodel);
P.addRequired('data',@(x) ...
    isstruct(x) && isfield(x,'mean_') && isfield(x,'var_') ...
    && iscell(x.mean_) && iscell(x.mse_));
P.parse(this,d);

options = passvalopt('model.lognormal',varargin{:});

%**************************************************************************

% Keep only log-linearised variables, nan linearised measurement variables.
for i = 1 : 3
    if isempty(d.mean_{i}) || isempty(d.var_{i})
        continue
    end
    realid = real(this.solutionid{i});
    index = this.log(realid);
    d.mean_{i}(~index,:,:) = NaN;
    d.var_{i}(~index,:,:) = NaN;
end

list = {};
range = d.mean_{4};
if options.mode
    do_mode();
end
if options.median
    do_median();
end
if options.mean || options.std
    do_mean_std();
end
if ~isempty(options.pctile)
    pct = round(options.pctile(:).');
    do_pct();
end

if options.fresh
    d = rmfield(d,fieldnames(d)-list);
end

% Nested functions.

%**************************************************************************
    function do_median()
        medianDpk = cell(1,4);
        for ii = 1 : 3
            medianDpk{ii} = exp(d.mean_{ii});
        end
        medianDpk{4} = range;
        % Do not delogarithmised the mode values inside dp2db.
        list{end+1} = sprintf('%smedian',options.prefix);
        d.(list{end}) = dp2db(this,medianDpk,false);
    end
% do_median().

%**************************************************************************
    function do_mode()
        modeDpk = cell(1,4);
        for ii = 1 : 3
            modeDpk{ii} = exp(d.mean_{ii} - d.var_{ii});
        end
        modeDpk{4} = range;
        % Do not delogarithmised the mode values inside dp2db.
        list{end+1} = sprintf('%smode',options.prefix);
        d.(list{end}) = dp2db(this,modeDpk,false);
    end
% do_mode().

%**************************************************************************
    function do_mean_std()
        meanDpk = cell(1,4);
        stdDpk = cell(1,4);
        for ii = 1 : 3
            meanDpk{ii} = exp(d.mean_{ii} + 0.5*d.var_{ii});
            stdDpk{ii} = meanDpk{ii} .* sqrt(exp(d.var_{ii})-1);
        end
        % Do not delogarithmised the mean and std values inside dp2db.
        if options.mean
            meanDpk{4} = range;
            list{end+1} = sprintf('%smean',options.prefix);
            d.(list{end}) = dp2db(this,meanDpk,false);
        end
        if options.std
            stdDpk{4} = range;
            list{end+1} = sprintf('%sstd',options.prefix);
            d.(list{end}) = dp2db(this,stdDpk,false);
        end
    end
% do_mean_std().

%**************************************************************************
    function do_pct()
        pctDpk = cell(1,4);
        for ii = 1 : 3
            npct = length(pct);
            % Put percentiles along 4th dimension.
            pctDpk{ii} = nan(size(d.mean_{ii},1), ...
                size(d.mean_{ii},2), ...
                size(d.mean_{ii},3), ...
                npct);
            if isstats
                for j = 1 : npct
                    pctDpk{ii}(:,:,:,j) = ...
                        logninv(pct(j)/100,d.mean_{ii},sqrt(d.var_{ii}));
                end
            end
        end
        pctDpk{4} = range;
        % Do not delogarithmised the mean and std values inside dp2db.
        list{end+1} = sprintf('%spct',options.prefix);
        d.(list{end}) = dp2db(this,pctDpk,false);
    end
% do_mean_std().

end