function [A] = GridDef(lbmub,varargin)%,indin,opt)

% This functions defines a grid for sampling using three different
% approaches:
%  - Complete grids
%  - Latin Hypercube sampling with the function lhsdesign.m
%  - Orthogonal sampling with the function orthogonal_sample.m
%
% The input of this function is given by
%       lbmub:	3 x ntot matrix, with first row determining the minimum
%               value, the second row the reference value and the third row
%               the maximum value. This matrix includes all independent
%               variables, also the unvaried.
%
%       indin:  Indices ofthe lbmub matrix, which should be varied
%
%       opt:	Structure containing the options of the system, includes
%               .type:  String containing CG, LHS or OD
%               .Np:    CG:     Points per variable
%                       LHS:    Total number of points
%                       OD:     Number of points per subdivision
%                       RND:    Random numbers generated
%               .Ns     LHS:    Number of subdivision per variable


% Safety function to use all available input points and a complete grid in
% the case no inputs or grids are defined.
if nargin < 2
    indin = 1:size(lbmub);
    opt = 'CG';
elseif nargin < 3
    indin = varargin{1};
    opt = 'CG';
else
    indin = varargin{1};
    opt = varargin{2};
end

% Definition of the number of varied independent variables and the total
% number of variables
nvar = length(indin);
ntot = size(lbmub,2);

switch opt.type
    case 'CG'
        % Predefinition of the cell vector for the varied values
        vec = cell(1,ntot);
        
        for k = indin
            vec{k} = linspace(lbmub(1,k), lbmub(3,k),opt.Np);
        end
        
        grid_comb = cell(1,ntot);
        [grid_comb{indin}] = ndgrid(vec{indin});
        
        for k = indin
            grid_comb{k} = grid_comb{k}(:);
        end
        
        A.grid = cell2mat(grid_comb(indin));
        
        % Definition of the number of samples
        nsamp = size(A.grid,1);
        
    case 'RND'
        if opt.val == 'n'
            % Predefinition of the cell vector for the varied values
            vec = cell(1,ntot);

            for k = indin
                vec{k} = linspace(lbmub(1,k), lbmub(3,k),2);
            end

            grid_comb = cell(1,ntot);
            [grid_comb{indin}] = ndgrid(vec{indin});

            for k = indin
                grid_comb{k} = grid_comb{k}(:);
            end

            A.CG = cell2mat(grid_comb(indin));
        else
            A.CG = [];
        end

        % Definition of the number of samples
        nsamp = opt.Np;
            
        % Performing the LHS
        A.init = rand(nsamp,nvar);

        % Rescaling of the problem
        A.grid = [A.init.*(ones(nsamp,1)*diff(lbmub([1 3],indin)))+ones(nsamp,1)*lbmub(1,indin);...
                  A.CG];
        
        % Definition of the number of samples
        nsamp = size(A.grid,1);
        
    case 'LHS'
        if opt.val == 'n'
            % Predefinition of the cell vector for the varied values
            vec = cell(1,ntot);

            for k = indin
                vec{k} = linspace(lbmub(1,k), lbmub(3,k),2);
            end

            grid_comb = cell(1,ntot);
            [grid_comb{indin}] = ndgrid(vec{indin});

            for k = indin
                grid_comb{k} = grid_comb{k}(:);
            end

            A.CG = cell2mat(grid_comb(indin));
        else
            A.CG = [];
        end

        % Definition of the number of samples
        nsamp = opt.Np;
            
        % Performing the LHS
        A.init = lhsdesign(nsamp,nvar,'criterion','correlation');

        % Rescaling of the problem
        A.grid = [A.init.*(ones(nsamp,1)*diff(lbmub([1 3],indin)))+ones(nsamp,1)*lbmub(1,indin);...
                  A.CG];
        
        % Definition of the number of samples
        nsamp = size(A.grid,1);
        
    case 'OS'
        if opt.val == 'n'
            % Predefinition of the cell vector for the varied values
            vec = cell(1,ntot);

            for k = indin
                vec{k} = linspace(lbmub(1,k), lbmub(3,k),2);
            end

            grid_comb = cell(1,ntot);
            [grid_comb{indin}] = ndgrid(vec{indin});

            for k = indin
                grid_comb{k} = grid_comb{k}(:);
            end

            A.CG = cell2mat(grid_comb(indin));
        else
            A.CG = [];
        end
        
        % Performing the orthogonal sampling
        [A.init] = orthogonal_sample(nvar,opt.Ns,opt.Np);

        % Definition of the number of samples
        nsamp = length(A.init);
        
        % Rescaling of the problem
        A.grid = [((A.init-1)/(size(A.init,1)-1)).*...
                  (ones(nsamp,1)*diff(lbmub([1 3],indin)))+ones(nsamp,1)*lbmub(1,indin);...
                  A.CG];
              
        % Definition of the number of samples
        nsamp = size(A.grid,1);
    otherwise
                
end

% Definition of the vectors for the feed composition without any change
A.out = ones(nsamp,1)*lbmub(2,:);

% Definition of the adjusted matrix
A.out(:,indin) = A.grid;