function [G All] = ObjectiveValue(m, con, obj, opts)
%OBJECTIVEVALUE Evaluate an objective function
%
%   Mathematically: G = sum(dG/dx(t) * x(t), t)
%   
%   [G All] = ObjectiveValue(m, con, obj, opts)
%   
%   Inputs:
%       m    - The KroneckerBio model that will be simulated
%       con  - A vector of experimental conditions under which the model
%              will be simulated
%       obj  - A matrix length of con by any number of objective functions
%              that will be evaluated
%       opts - Optional function options
%           UseModelICs - Logical scalar indicating that the model's
%                         initial conditions should be used instead of
%                         those of the experimental conditions.
%                         Default = true
%           ObjWeights  - A matrix of size(obj) indicating a post-
%                         evaluation weight on each objective function in
%                         terms of how much it will contribute to the final
%                         value. Default = ones(size(obj))
%           RelTol      - Numerical scalar for the relative tolerance of 
%                         the integration. Default = 1e-6
%           AbsTol      - Cell vector of vectors, numerical scalar, or 
%                         numerical vector for the absolute tolerance of
%                         the integration. Default = 1e-9 
%           Verbose     - Numerical scalar for how much progress 
%                         information should be displayed. Default = 0
%
%   Outputs:
%       G   - The sum of all objective function values
%       All - A matrix size(obj) for the values for each objective function

% (c) 2010 David R Hagen & Bruce Tidor
% This work is released under the MIT license.

%% Work-up
% Clean up inputs
if nargin < 4
    opts = [];
end

assert(isscalar(m), 'KroneckerBio:ObjectiveValue:MoreThanOneModel', 'The model structure must be scalar')

% Options
defaultOpts.UseModelICs = true;
defaultOpts.ObjWeights  = ones(size(obj));
defaultOpts.RelTol      = NaN;
defaultOpts.AbsTol      = NaN;
defaultOpts.Verbose     = 0;

opts = mergestruct(defaultOpts, opts);

% Constants
nX = m.nX;
nCon = numel(con);

% Add missing fields to structure
con = pastestruct(Uzero(m), con);
obj = pastestruct(Gzero(m), obj);

% Fix integration type
[opts.continuous, opts.complex, opts.tGet] = fixIntegrationType(obj);

%% Tolerances
% RelTol
if isempty(opts.RelTol) || isnan(opts.RelTol)
    opts.RelTol = 1e-6;
end

% Fix AbsTol to be a cell array of vectors appropriate to the problem
opts.AbsTol = fixAbsTol(opts.AbsTol, 1, opts.continuous, nX, nCon);

%% Run appropriate objective evaluation
if nargout <= 1
    G = computeObj(m, con, obj, opts);
else
    [G All] = computeObjAll(m, con, obj, opts);
end
