function aboxes_out = post_process_candidate_detections_all_imgs(...
    aboxes_in, nms_iou_thrs, thresh_val, varargin)
% post_process_candidate_detections_all_imgs performs the post-processing
% step of non-maximum-suppression and optionally of box voting on the
% candidate bounding box detections of a set of images.
%
% INPUTS:
% 1) aboxes_in: contains the candidate bounding box detections of each image.
% It can be of two forms:
%   a) (the flag is_per_class must being set to false) a NI x 1 cell array
%   where NI is the number of images. The aboxes_in{i} element contains
%   the candidate bounding box detection of the i-th image in the form of a
%   NB_i x (4 + C) array where C is the number of categories and NB_i
%   is the number of candidate detection boxes of the i-th image. The first
%   4 columns of this array contain the bounding box coordinates in the
%   form of [x0,y0,x1,y1] (where the (x0,y0) and (x1,y1) are the top-left
%   and bottom-right corners) and the rest C columns contain the confidence
%   score of the bounding boxes for each of the C categories.
%   b) (the flag is_per_class must being set to true) a C x 1 cell array
%   where C is the number of categories. The aboxes_in{j} element in this case
%   is NI x 1 cell array, where NI is the number of images, with the candidate
%   bounding box detections of the j-th category for each image. The
%   element aboxes_in{j}{i} is a NB_{i,j} x 5 array, where NB_{i,j} is the
%   number candidate bounding box detections of the i-th image for the j-th
%   category. The first 4 columns of this array are the bounding box
%   coordinates in the form of [x0,y0,x1,y1] (where the (x0,y0) and (x1,y1)
%   are the top-left and bottom-right corners) and the 5-th column contains
%   the confidence score of each bounding box with respect to the j-th category.
% 2) nms_iou_thrs: scalar value with the IoU threshold that will be used
% during the non-max-suppression step.
% 3) thresh_val: is a C x 1 array, where C is the number of categories.
% It must contains the threshold per category that will be used for
% removing candidate boxes with low confidence prior to applying the
% non-max-suppression step.
% OPTIONAL INPUT:
% 4) is_per_class: boolean value that if set to false, then the 1.a) form
% of the aboxes_in input parameter will be expected; otherwise, if set to
% true then the 1.b) form of the aboxes_in input parameter will be expected
% 5) max_per_image: scalar value with the maximum number of detection per
% image and per category. Default value: 200.
% 6) do_bbox_voting: boolean value that if is set to True then the box voting
% step is applied. Default value: false
% 7) box_ave_iou_thresh: scalar value with the minimum IoU threshold that
% is used in order to define the neighbors of bounding box during the box
% voting step. Default value: 0.5
% 8) add_val: scalar value that is added to the confidence score of bounding
% boxes in order to compute the box weight during the box voting step.
% Default value: 1.5
% 9) use_not_static_thr: boolean value that if set to true, then the threshold
% (param thresh_val) that is applied on the candidate bounding box
% detections will be modified (decreased from its input value) such that
% the average number of detections per image and per category to be
% ave_per_image. Default value: true
% 10) ave_per_image: scalar value with the desired average number of
% detections per image and per category. Used only when the use_not_static_thr
% input parameter is set to true. default value: 5
%
%
% OUTPUT:
% 1) aboxes_out: is a C x 1 array where C is the number of
% categories. The aboxes_out{j} element is a NI x 1 cell array, where NI is
% the number of images, with the bounding box detections of the j-th
% category for each image. The element aboxes_out{j}{i} is a ND_{i,j} x 5 array,
% where ND_{i,j} is the number bounding box detections for the i-th image
% and the j-th category. The first 4 columns of this array contain the
% bounding box coordinates in the form of [x0,y0,x1,y1] (where the (x0,y0)
% and (x1,y1) are the top-left and bottom-right corners) and the 5-th
% column contains the confidence score of each bounding box with respect to
% the j-th category.
%
% This file is part of the code that implements the following ICCV2015 accepted paper:
% title: "Object detection via a multi-region & semantic segmentation-aware CNN model"
% authors: Spyros Gidaris, Nikos Komodakis
% institution: Universite Paris Est, Ecole des Ponts ParisTech
% Technical report: http://arxiv.org/abs/1505.01749
% code: https://github.com/gidariss/mrcnn-object-detection
%
% Part of the code in this file comes from the R-CNN code:
% https://github.com/rbgirshick/rcnn
%
% AUTORIGHTS
% --------------------------------------------------------
% Copyright (c) 2015 Spyros Gidaris
%
% "Object detection via a multi-region & semantic segmentation-aware CNN model"
% Technical report: http://arxiv.org/abs/1505.01749
% Licensed under The MIT License [see LICENSE for details]
% ---------------------------------------------------------
% Copyright (c) 2014, Ross Girshick
%
% This file is part of the R-CNN code and is available
% under the terms of the Simplified BSD License provided in
% LICENSE. Please retain this notice and LICENSE if you use
% this file (or any portion of it) in your project.
% ---------------------------------------------------------

ip = inputParser;
ip.addParamValue('is_per_class',      false, @islogical);
ip.addParamValue('do_bbox_voting',    false, @islogical);
ip.addParamValue('box_ave_thresh',      0.5, @isnumeric);
ip.addParamValue('use_not_static_thr', true, @islogical);
ip.addParamValue('ave_per_image',         5, @isnumeric);
ip.addParamValue('max_per_image',       200, @isnumeric);
ip.addParamValue('add_val',             1.5, @isnumeric);

ip.parse(varargin{:});
opts = ip.Results;

is_per_class       = opts.is_per_class;
do_bbox_voting     = opts.do_bbox_voting;
box_ave_thresh     = opts.box_ave_thresh;
use_not_static_thr = opts.use_not_static_thr;
max_per_image      = opts.max_per_image;
ave_per_image      = opts.ave_per_image;
add_val            = opts.add_val;

if ~is_per_class
    num_imgs    = length(aboxes_in);
    num_classes = size(aboxes_in{1},2) - 4;
else
    num_classes = length(aboxes_in);
    num_imgs    = length(aboxes_in{1});
end

max_per_set   = ceil(ave_per_image * num_imgs);
aboxes_out    = cell(num_classes, 1);
for i = 1:num_classes, aboxes_out{i} = cell(num_imgs, 1); end

thresh_val_all = ones(num_classes,1,'single') * thresh_val;

for i = 1:num_imgs
    % get the candidate bounding box detection of one image
    if ~is_per_class
        assert(size(aboxes_in{i},2) == (4 + num_classes));
        bbox_cand_dets = aboxes_in{i};
    else
        bbox_cand_dets = cell(num_classes,1);
        for j = 1:num_classes
            assert(size(aboxes_in{j}{i},2) == 5);
            bbox_cand_dets{j} = aboxes_in{j}{i};
        end
    end

    % post-process the candidate bounding box detection of one image
    bbox_detections_per_class = post_process_candidate_detections( ...
        bbox_cand_dets, thresh_val_all, nms_iou_thrs, max_per_image, ...
        do_bbox_voting, box_ave_thresh, add_val );

    for j = 1:num_classes
        aboxes_out{j}{i} = bbox_detections_per_class{j};
    end

    if (mod(i, 1000) == 0) && use_not_static_thr
        for j = 1:num_classes
            [aboxes_out{j}, thresh_val_all(j)] = keep_top_k(aboxes_out{j}, i, max_per_set, thresh_val_all(j));
        end
    end
end

if use_not_static_thr
    disp(thresh_val_all(:)');
    for i = 1:num_classes
        % go back through and prune out detections below the found threshold
        aboxes_out{i} = prune_detections(aboxes_out{i}, thresh_val_all(i));
    end
end

total_num_bboxes = zeros(num_classes, 1);
for j = 1:num_classes
    total_num_bboxes(j) = sum(cellfun(@(x) size(x,1), aboxes_out{j}, 'UniformOutput', true));
end

fprintf('Average number of bounding boxes per class\n');
disp(total_num_bboxes(:)' / num_imgs);
fprintf('Average number of bounding boxes in total\n');
disp(sum(total_num_bboxes) / num_imgs);
end

function [boxes, thresh] = keep_top_k(boxes, end_at, top_k, thresh)
% keep top K detections
X = cat(1, boxes{1:end_at});
if isempty(X), return; end

scores = sort(X(:,end), 'descend');
thresh = scores(min(length(scores), top_k));
for image_index = 1:end_at
    bbox = boxes{image_index};
    keep = find(bbox(:,end) >= thresh);
    boxes{image_index} = bbox(keep,:);
end

end

function bbox_dets = prune_detections(bbox_dets, thresh)
for j = 1:length(bbox_dets)
    if ~isempty(bbox_dets{j})
        bbox_dets{j}(bbox_dets{j}(:,end) < thresh ,:) = [];
    end
end
end


function [o, others] = slover(params, others, varargin)
% class constructor for slice overlay (slover) object
% FORMAT [o, others] = slover(params, others, varargin)
%
% Inputs
% params    - either:
%             - action string implementing class methods (see below)
%             - array of image names / vol structs to display
%             - structure with some fields for object (see below)
% others    - structure, containing extra fields for object (or children)
% varargin  - maybe some other parameters for action calls (see below)
%
% Outputs
% o       - slover object
% others  - any unrecognized fields from params, others
%
% Object fields are:
%  - img - array of structs with information for images to display
%        - img structs contain fields
%             type - one of {'truecolour' 'split', 'contour'};
%                   truecolour - displays transparent (see prop) image
%                      overlaid with any previous
%                   split - in defined area, replaces image present (SPM
%                      type activation display)
%                   contour - contour map of image overlaid.  See help
%                      for contours function in matlab
%             vol - vol struct info (see spm_vol)
%                   can also be vol containing image as 3d matrix
%                   set with add_blobs method
%             cmap - colormap for this image
%             nancol - color for NaN. If scalar, this is an index into
%                    the image cmap.  If 1x3 vector, it's a colour
%             prop - proportion of intensity for this cmap/img
%             func - function to apply to image before scaling to cmap
%                    (and therefore before min/max thresholding. E.g. a func of
%                    'i1(i1==0)=NaN' would convert zeros to NaNs
%             range - 2x1 vector of values for image to distribute colormap across
%                    the first row of the colormap applies to the first
%                    value in 'range', and the last value to the second
%                    value in 'range'
%             outofrange - behavior for image values to the left and
%                    right of image limits in 'range'.  Left means
%                    colormap values < 1, i.e for image values <
%                    range(1), if (range(1)<range(2)), and image values >
%                    range(1) where (range(1)>range(2)). If missing,
%                    display min (for Left) and max (for Right) value from colormap.
%                    Otherwise should be a 2 element cell array, where
%                    the first element is the colour value for image values
%                    left of 'range', and the second is for image values
%                    right of 'range'.  Scalar values for
%                    colour index the colormap, 3x1 vectors are colour
%                    values.  An empty array attracts default settings
%                    appropriate to the mode - i.e. transparent colour (where
%                    img(n).type is truecolour), or split colour.  Empty cells
%                    default to 0. 0 specifies that voxels with this
%                    colour do not influence the image (split =
%                    background, true = black)
%            hold  - resampling order for image (see spm_sample_vol) -
%                    default 1
%            background - value when resampling outside image - default
%                    NaN
%            linespec - string, applies only to contour map,
%                    e.g. 'w-' for white continuous lines
%            contours - vector, applies to contour map only, defines
%                    values in image for which to show contours
%                    (see help contours)
%            linewidth - scalar, width in points of contour lines
%
% - transform - either - 4x4 transformation to apply to image slice position,
%             relative to mm given by slicedef, before display
%               or     - text string, one of axial, coronal, sagittal
%                        These orientations assume the image is currently
%                        (after its mat file has been applied) axially
%                        oriented
% - slicedef - 2x3 array specifying dimensions for slice images in mm
%             where rows are x,and y of slice image, and cols are neg max dim,
%             slice separation and pos max dim
% - slices   - vector of slice positions in mm in z (of transformed image)
% - figure    - figure handle for slice display figure
%               The object used for the display is attached as 'UserData'
%               to this figure
% - figure_struct - stored figure parameters (in case figure dies and
%               needs to be recreated)
% - refreshf  - flag - if set or empty, refresh axis info for figure
%             else assume this is OK
% - clf       - flag, non zero -> clear figure before display.  Redundant
%               if refreshf == 0
% - resurrectf - if not zero, and figure (above) does not exist, will
%               attempt to recreate figure with same area properties.
%               Otherwise painting will give an error.
% - userdata  - flag, non zero -> attaches object to figure when ploting,
%               for use by callbacks (default is 1)
% - area      - struct with fields
%                  position - bottom left, x size y size 1x4 vector of
%                      area in which to display slices
%                  units    - one of
%                    inches,centimeters,normalized,points,{pixels}
%                  halign - one of left,{center},right
%                  valign - one of top,{middle},bottom
% - xslices  - no of slices to display across figure (defaults to an optimum)
% - cbar      - if empty, missing, no colourbar.  If an array of integers, then
%             indexes img array, and makes colourbar for each cmap for
%             that img.  Cbars specified in order of appearance L->R
% - labels - struct can be:
%                  - empty (-> default numerical labels)
%                  - 'none' (string) (no labels)
%                  - or contain fields:
%                  colour - colour for label text
%                  size - font size in units normalized to slice axes
%                  format - if = cell array of strings =
%                  labels for each slice in Z.  If is string, specifies
%                  sprintf format string for labelling in distance of the
%                  origin (Xmm=0, Ymm=0) of each slice from plane containing
%                  the AC, in mm, in the space of the transformed image
% - callback - callback string for button down on image panels. THe
%              following examples assume that you have the 'userdata'
%              field set to 1, giving you access to underlying object
%              To print to the matlab window the equivalent position in
%              mm of the position of a mouse click on one of the image
%              slices, set callback to:
%                   'get_pos(get(gcf, ''UserData''))'
%              To print the intensity values of the images at the clicked point:
%                   ['so_obj = get(gcf, ''UserData''); ' ...
%                    'point_vals(so_obj, get_pos(so_obj))']
% - printstr - string for printing slice overlay figure window, e.g.
%              'print -dpsc -painters -noui' (the default)
% - printfile - name of file to print output to; default 'slices.ps'
%
% Action string formats:
% FORMAT [cmap warnstr] = slover('getcmap', cmapname)
% Gets colormap named in cmapname string
%
% FORMAT [mx mn] = slover('volmaxmin', vol)
% Returns maximum and minimum finite values from vol struct 'vol'
%
% FORMAT vol = slover('blobs2vol', XYZ, vals, mat)
% returns (pseudo) vol struct for 3d blob volume specified
% in matrices as above
%
% FORMAT vol = slover('matrix2vol', mat3d, mat)
% returns (pseudo) vol struct for 3d matrix
% input matrices as above
%
% FORMAT obj = slover('basic_ui' [,dispf])
% Runs basic UI to fetch some parameters, does display, returns object
% If optional dispf parameter = 0, supresses display
%__________________________________________________________________________

% Matthew Brett
% $Id: slover.m 6623 2015-12-03 18:38:08Z guillaume $

myclass = 'slover';

% Default object structure
defstruct = struct('img', [], ...
    'transform', 'axial', ...
    'slicedef', [], ...
    'slices', [], ...
    'figure', [], ...
    'figure_struct', [], ...
    'refreshf', 1, ...
    'clf', 1, ...
    'resurrectf', 1, ...
    'userdata', 1, ...
    'area', [], ...
    'xslices', [], ...
    'cbar', [], ...
    'labels', [], ...
    'callback', ';', ...
    'printstr', 'print -dpsc -painters -noui', ...
    'printfile', 'slices.ps');

if nargin < 1
    o = class(defstruct, myclass);
    others = [];
    return
end
if nargin < 2
    others = [];
end

% parse out string action calls (class functions)
if ischar(params)
    switch params
        case 'getcmap'
            if nargin < 2
                error('Need colormap name');
            end
            o = pr_getcmap(others);
            return
        case 'volmaxmin'
            if nargin < 2
                error('Need volume to calculate max/min');
            end
            [o,others] = pr_volmaxmin(others);
            return
        case 'blobs2vol'
            if nargin < 4
                error('Need XYZ, vals, mat');
            end
            o = pr_blobs2vol(others, varargin{:});
            return
        case 'matrix2vol'
            if nargin < 3
                error('Need matrix and mat');
            end
            o = pr_matrix2vol(others, varargin{:});
            return
        case 'basic_ui'
            o = pr_basic_ui(others, varargin{:});
            if ~isempty(o), o = paint(o); end
            return
    end

    % if not action string, must be filename(s)
    params = spm_vol(params);
end

% Could these just be image vol structs?
if isfield(params, 'fname')
    for i = 1:numel(params)
        obj.img(i).vol = params(i);
    end
    params = obj;
end

% Deal with passed objects of this (or child) class
if isa(params, myclass)
    o = params;
    % Check for simple form of call
    if isempty(others), return, end

    % Otherwise, we are being asked to set fields of object
    [p,others] = mars_struct('split', others, defstruct);
    o = mars_struct('ffillmerge', o, p);
    return
end

% fill params with defaults, parse into fields for this object, children
params = mars_struct('fillafromb', params, others);
[params, others] = mars_struct('ffillsplit', defstruct, params);

% set the slover object
o  = class(params, myclass);

% refill with defaults
o = fill_defaults(o);


%Transcription
%
% Author: Jonathan Karr, jkarr@stanford.edu
% Affilitation: Covert Lab, Department of Bioengineering, Stanford University
% Last updated: 8/6/2011
classdef Transcription
    %plotting
    methods (Static = true)
        function plotRNA_Polymerase_States(sim, axesHandle, time, ~)
            import edu.stanford.covert.util.ConstantUtil;

            rnaPol = sim.state('RNAPolymerase');

            maxState = max(rnaPol.transcripts.transcriptionUnitLengths);
            if ndims(rnaPol.states) == 3
                colors = zeros([size(rnaPol.states) 3]);
            else
                colors = zeros([size(rnaPol.states) 1 3]);
            end
            for i = 1:size(rnaPol.states, 1)
                for k = 1:size(rnaPol.states, 3)
                    switch rnaPol.states(i, 1, k)
                        case rnaPol.notExistValue
                            colors(i,1,k,:) = [1 0 0];
                        case rnaPol.freeValue
                            colors(i,1,k,:) = [0 1 0];
                        case rnaPol.nonSpecificallyBoundValue
                            colors(i,1,k,:) = [0 0 1];
                        otherwise
                            colors(i,1,k,:) = repmat(max(0, rnaPol.states(i,1,k)) / maxState, 1, 3);
                    end
                end
            end

            colors = reshape(colors, [], size(rnaPol.states, 3), 3);
            image(colors, 'Parent', axesHandle);

            xlabel(axesHandle, 'Time (h)', 'fontSize', 8);
            ylabel(axesHandle, 'RNA Polymerase', 'fontSize', 8);

            xTick = get(axesHandle, 'XTick');
            xTickLabel = round((xTick - 0.5) * max(time) / ConstantUtil.secondsPerHour / max(xTick));
            set(axesHandle, 'XTickLabel', xTickLabel);
        end

        function plotRNA_Polymerase_State_Occupancies(sim, axesHandle, time, ~)
            rnaPol = sim.state('RNAPolymerase');

            labels = cell(4,1);
            labels{rnaPol.activelyTranscribingIndex} = 'Actively Transcribing';
            labels{rnaPol.specificallyBoundIndex} = 'Specifically Bound';
            labels{rnaPol.nonSpecificallyBoundIndex} = 'Non-specifically Bound';
            labels{rnaPol.freeIndex} = 'Free';

            plotHandles = plot(axesHandle, time / 3600, permute(rnaPol.stateOccupancies, [3 1 2]));
            legend(plotHandles, labels);
            xlabel(axesHandle, 'Time (h)', 'fontSize', 8);
            ylabel(axesHandle, 'Occupancy', 'fontSize', 8);
            xlim(axesHandle, [0 max(1, time(end))] / 3600);
        end

        function plotRNA_Polymerases(sim, axesHandle, time, ~)
            rnaPol = sim.state('RNAPolymerase');

            rnaPolymeraseGeneStates = rnaPol.states;
            rnaPolymeraseGenomeStates = zeros(size(rnaPolymeraseGeneStates));
            for i = 1:size(rnaPolymeraseGeneStates,1)
                for k = 1:size(rnaPolymeraseGeneStates,3)
                    switch rnaPolymeraseGeneStates(i, 1, k)
                        case rnaPol.specificallyBoundValue
                            rnaPolymeraseGenomeStates(i, 1, k) = rnaPol.transcripts.transcriptionUnitFivePrimeCoordinates(rnaPol.transcripts.boundTranscriptionUnits(i,1,k));
                        case rnaPol.activelyTranscribingValue
                            rnaPolymeraseGenomeStates(i, 1, k) = rnaPol.transcripts.transcriptionUnitFivePrimeCoordinates(rnaPol.transcripts.boundTranscriptionUnits(i,1,k))+...
                                (2*rnaPol.transcripts.transcriptionUnitDirections(rnaPol.transcripts.boundTranscriptionUnits(i,1,k))-1)*(rnaPolymeraseGeneStates(i,1,k)-1);
                    end
                end
            end

            plot(axesHandle, time/3600, permute(rnaPolymeraseGenomeStates, [3 1 2]), '.');
            xlabel(axesHandle, 'Time (h)', 'fontSize', 8);
            ylabel(axesHandle, 'Genome Coordinate', 'fontSize', 8);
            xlim(axesHandle, [0 max(1, time(end))] / 3600);
            ylim(axesHandle, [rnaPol.freeValue-1 rnaPol.transcripts.genomeLength+1]);
        end

        function plotRNA_Polymerase_Bound_Transcription_Units(sim, axesHandle, time, ~)
            rnaPol = sim.state('RNAPolymerase');

            numTimePoints = size(rnaPol.states,3);

            polymeraseTUs = rnaPol.transcripts.boundTranscriptionUnits;
            boundTUs = zeros(length(rnaPol.transcripts.transcriptionUnitLengths), 1, numTimePoints);
            for i = 1:size(polymeraseTUs,1)
                for k = 1:size(polymeraseTUs,3)
                    if polymeraseTUs(i,1,k) > 0
                        boundTUs(polymeraseTUs(i,1,k),1,k) = ...
                            boundTUs(polymeraseTUs(i,1,k),1,k) + 1;
                    end
                end
            end

            boundTUs = permute(boundTUs, [1 3 2]);
            colors = repmat(boundTUs/(max(max(boundTUs))),[1 1 3]);

            image(colors,'Parent',axesHandle);
            xlabel(axesHandle,'Time (h)','fontSize',8);
            ylabel(axesHandle,'Transcription Unit','fontSize',8);

            xTick = get(axesHandle,'XTick');
            xTickLabel = round((xTick-0.5)*max(time)/3600/max(xTick));
            set(axesHandle,'XTickLabel',xTickLabel);
        end

        function plotNTPs(sim, axesHandle, time, ~)
            p = sim.process('Transcription');

            plotHandles = plot(axesHandle, time / 3600, permute(p.substrates(p.substrateIndexs_ntp, :, :), [3 1 2]));
            legend(plotHandles, p.substrateWholeCellModelIDs(p.substrateIndexs_ntp));
            xlabel(axesHandle, 'Time (h)', 'fontSize', 8);
            ylabel(axesHandle, 'NTPs', 'fontSize', 8);
            xlim(axesHandle, [0 max(1, time(end))] / 3600);
        end

        function plotNMPs(sim, axesHandle, time, ~)
            p = sim.process('Transcription');

            plotHandles = plot(axesHandle, time / 3600, permute(p.substrates(p.substrateIndexs_nmp, :, :), [3 1 2]));
            legend(plotHandles, p.substrateWholeCellModelIDs(p.substrateIndexs_nmp));
            xlabel(axesHandle,'Time (h)', 'fontSize', 8);
            ylabel(axesHandle,'NMPs', 'fontSize', 8);
            xlim(axesHandle, [0 max(1, time(end))] / 3600);
        end

        %plot translation limits
        function plotTranscription_Limits(sim, axesHandle, time, ~)
            p = sim.process('Transcription');

            plotHandles = plot(axesHandle, time / 3600, permute(p.substrates(p.substrateIndexs_ntp), [3 1 2]));
            legend(plotHandles, p.substrateWholeCellModelIDs(p.substrateIndexs_ntp));
            xlabel(axesHandle, 'Time (h)', 'fontSize', 8);
            ylabel(axesHandle, 'NTP', 'fontSize', 8);
            xlim(axesHandle, [0 max(1, time(end))] / 3600);
        end

        function plotBound_Transcription_Factors(sim, axesHandle, time, ~)
            p = sim.process('Transcription');

            transcriptionFactors      = p.enzymes(p.enzymeIndexs_transcriptionFactors, :, :);
            boundTranscriptionFactors = p.boundEnzymes(p.enzymeIndexs_transcriptionFactors, :, :);

            plotHandles = plot(axesHandle, time / 3600, permute(boundTranscriptionFactors./(transcriptionFactors+boundTranscriptionFactors), [3 1 2]));
            legend(plotHandles, p.enzymeNames(p.enzymeIndexs_transcriptionFactors));
            xlabel(axesHandle, 'Time (h)', 'fontSize', 8);
            ylabel(axesHandle, 'Fraction Bound', 'fontSize', 8);
            xlim(axesHandle, [0 max(1, time(end))] / 3600);
            ylim(axesHandle, [0 1]);
        end
    end
end


function obj = eq_pnp_func_new(in1,in2,in3,in4,in5)
coef_f0_q_sym1 = in1(:,1);
coef_f0_q_sym2 = in1(:,2);
coef_f1_q_sym1 = in2(:,1);
coef_f0_q_sym3 = in1(:,3);
coef_f1_q_sym2 = in2(:,2);
coef_f2_q_sym1 = in3(:,1);
coef_f0_q_sym4 = in1(:,4);
coef_f1_q_sym3 = in2(:,3);
coef_f2_q_sym2 = in3(:,2);
coef_f3_q_sym1 = in4(:,1);
coef_f0_q_sym5 = in1(:,5);
coef_f1_q_sym4 = in2(:,4);
coef_f2_q_sym3 = in3(:,3);
coef_f3_q_sym2 = in4(:,2);
coef_f0_q_sym6 = in1(:,6);
coef_f1_q_sym5 = in2(:,5);
coef_f2_q_sym4 = in3(:,4);
coef_f3_q_sym3 = in4(:,3);
coef_f0_q_sym7 = in1(:,7);
coef_f1_q_sym6 = in2(:,6);
coef_f2_q_sym5 = in3(:,5);
coef_f3_q_sym4 = in4(:,4);
coef_f0_q_sym8 = in1(:,8);
coef_f1_q_sym7 = in2(:,7);
coef_f2_q_sym6 = in3(:,6);
coef_f3_q_sym5 = in4(:,5);
coef_f0_q_sym9 = in1(:,9);
coef_f1_q_sym8 = in2(:,8);
coef_f2_q_sym7 = in3(:,7);
coef_f3_q_sym6 = in4(:,6);
coef_f1_q_sym9 = in2(:,9);
coef_f2_q_sym8 = in3(:,8);
coef_f3_q_sym7 = in4(:,7);
coef_f2_q_sym9 = in3(:,9);
coef_f3_q_sym8 = in4(:,8);
coef_f3_q_sym9 = in4(:,9);
coef_f0_q_sym10 = in1(:,10);
coef_f0_q_sym11 = in1(:,11);
coef_f0_q_sym20 = in1(:,20);
coef_f1_q_sym10 = in2(:,10);
coef_f0_q_sym12 = in1(:,12);
coef_f0_q_sym21 = in1(:,21);
coef_f1_q_sym11 = in2(:,11);
coef_f1_q_sym20 = in2(:,20);
coef_f2_q_sym10 = in3(:,10);
coef_f0_q_sym13 = in1(:,13);
coef_f0_q_sym22 = in1(:,22);
coef_f1_q_sym12 = in2(:,12);
coef_f1_q_sym21 = in2(:,21);
coef_f2_q_sym11 = in3(:,11);
coef_f2_q_sym20 = in3(:,20);
coef_f3_q_sym10 = in4(:,10);
coef_f0_q_sym14 = in1(:,14);
coef_f0_q_sym23 = in1(:,23);
coef_f1_q_sym13 = in2(:,13);
coef_f1_q_sym22 = in2(:,22);
coef_f2_q_sym12 = in3(:,12);
coef_f2_q_sym21 = in3(:,21);
coef_f3_q_sym11 = in4(:,11);
coef_f3_q_sym20 = in4(:,20);
coef_f0_q_sym15 = in1(:,15);
coef_f0_q_sym24 = in1(:,24);
coef_f1_q_sym14 = in2(:,14);
coef_f1_q_sym23 = in2(:,23);
coef_f2_q_sym13 = in3(:,13);
coef_f2_q_sym22 = in3(:,22);
coef_f3_q_sym12 = in4(:,12);
coef_f3_q_sym21 = in4(:,21);
coef_f0_q_sym16 = in1(:,16);
coef_f1_q_sym15 = in2(:,15);
coef_f1_q_sym24 = in2(:,24);
coef_f2_q_sym14 = in3(:,14);
coef_f2_q_sym23 = in3(:,23);
coef_f3_q_sym13 = in4(:,13);
coef_f3_q_sym22 = in4(:,22);
coef_f0_q_sym17 = in1(:,17);
coef_f1_q_sym16 = in2(:,16);
coef_f2_q_sym15 = in3(:,15);
coef_f2_q_sym24 = in3(:,24);
coef_f3_q_sym14 = in4(:,14);
coef_f3_q_sym23 = in4(:,23);
coef_f0_q_sym18 = in1(:,18);
coef_f1_q_sym17 = in2(:,17);
coef_f2_q_sym16 = in3(:,16);
coef_f3_q_sym15 = in4(:,15);
coef_f3_q_sym24 = in4(:,24);
coef_f0_q_sym19 = in1(:,19);
coef_f1_q_sym18 = in2(:,18);
coef_f2_q_sym17 = in3(:,17);
coef_f3_q_sym16 = in4(:,16);
coef_f1_q_sym19 = in2(:,19);
coef_f2_q_sym18 = in3(:,18);
coef_f3_q_sym17 = in4(:,17);
coef_f2_q_sym19 = in3(:,19);
coef_f3_q_sym18 = in4(:,18);
coef_f3_q_sym19 = in4(:,19);
q0 = in5(1,:);
q1 = in5(2,:);
q2 = in5(3,:);
q3 = in5(4,:);
t92 = q0.^2;
t93 = q1.^2;
t94 = q2.^2;
t95 = q3.^2;
t96 = t92.^2;
obj = [-coef_f1_q_sym11.*t92+coef_f0_q_sym18.*t93-coef_f1_q_sym1.*t96+coef_f0_q_sym12.*t93.^2+coef_f0_q_sym11.*q0.*q1-coef_f1_q_sym18.*q0.*q1-coef_f1_q_sym22.*q0.*q2+coef_f0_q_sym22.*q1.*q2-coef_f1_q_sym24.*q0.*q3+coef_f0_q_sym24.*q1.*q3+coef_f0_q_sym2.*t92.*t93-coef_f1_q_sym5.*t92.*t93-coef_f1_q_sym8.*t92.*t94-coef_f1_q_sym10.*t92.*t95+coef_f0_q_sym15.*t93.*t94+coef_f0_q_sym17.*t93.*t95+coef_f0_q_sym1.*q0.*q1.*t92-coef_f1_q_sym2.*q0.*q1.*t92+coef_f0_q_sym5.*q0.*q1.*t93-coef_f1_q_sym12.*q0.*q1.*t93+coef_f0_q_sym8.*q0.*q1.*t94-coef_f1_q_sym15.*q0.*q1.*t94+coef_f0_q_sym10.*q0.*q1.*t95-coef_f1_q_sym17.*q0.*q1.*t95-coef_f1_q_sym3.*q0.*q2.*t92+coef_f0_q_sym6.*q0.*q2.*t93-coef_f1_q_sym13.*q0.*q2.*t93-coef_f1_q_sym19.*q0.*q2.*t94-coef_f1_q_sym21.*q0.*q2.*t95+coef_f0_q_sym3.*q1.*q2.*t92-coef_f1_q_sym4.*q0.*q3.*t92-coef_f1_q_sym6.*q1.*q2.*t92+coef_f0_q_sym7.*q0.*q3.*t93+coef_f0_q_sym13.*q1.*q2.*t93-coef_f1_q_sym14.*q0.*q3.*t93-coef_f1_q_sym20.*q0.*q3.*t94+coef_f0_q_sym19.*q1.*q2.*t94+coef_f0_q_sym21.*q1.*q2.*t95-coef_f1_q_sym23.*q0.*q3.*t95+coef_f0_q_sym4.*q1.*q3.*t92-coef_f1_q_sym7.*q1.*q3.*t92+coef_f0_q_sym14.*q1.*q3.*t93+coef_f0_q_sym20.*q1.*q3.*t94+coef_f0_q_sym23.*q1.*q3.*t95-coef_f1_q_sym9.*q2.*q3.*t92+coef_f0_q_sym16.*q2.*q3.*t93+coef_f0_q_sym9.*q0.*q1.*q2.*q3-coef_f1_q_sym16.*q0.*q1.*q2.*q3;-coef_f2_q_sym11.*t92+coef_f0_q_sym22.*t94-coef_f2_q_sym1.*t96+coef_f0_q_sym19.*t94.^2-coef_f2_q_sym18.*q0.*q1+coef_f0_q_sym11.*q0.*q2-coef_f2_q_sym22.*q0.*q2-coef_f2_q_sym24.*q0.*q3+coef_f0_q_sym18.*q1.*q2+coef_f0_q_sym24.*q2.*q3-coef_f2_q_sym5.*t92.*t93+coef_f0_q_sym3.*t92.*t94-coef_f2_q_sym8.*t92.*t94-coef_f2_q_sym10.*t92.*t95+coef_f0_q_sym13.*t93.*t94+coef_f0_q_sym21.*t94.*t95-coef_f2_q_sym2.*q0.*q1.*t92-coef_f2_q_sym12.*q0.*q1.*t93+coef_f0_q_sym6.*q0.*q1.*t94-coef_f2_q_sym15.*q0.*q1.*t94-coef_f2_q_sym17.*q0.*q1.*t95+coef_f0_q_sym1.*q0.*q2.*t92-coef_f2_q_sym3.*q0.*q2.*t92+coef_f0_q_sym5.*q0.*q2.*t93-coef_f2_q_sym13.*q0.*q2.*t93+coef_f0_q_sym8.*q0.*q2.*t94-coef_f2_q_sym19.*q0.*q2.*t94+coef_f0_q_sym10.*q0.*q2.*t95-coef_f2_q_sym21.*q0.*q2.*t95+coef_f0_q_sym2.*q1.*q2.*t92-coef_f2_q_sym4.*q0.*q3.*t92-coef_f2_q_sym6.*q1.*q2.*t92+coef_f0_q_sym12.*q1.*q2.*t93-coef_f2_q_sym14.*q0.*q3.*t93+coef_f0_q_sym9.*q0.*q3.*t94-coef_f2_q_sym20.*q0.*q3.*t94+coef_f0_q_sym15.*q1.*q2.*t94-coef_f2_q_sym23.*q0.*q3.*t95+coef_f0_q_sym17.*q1.*q2.*t95-coef_f2_q_sym7.*q1.*q3.*t92+coef_f0_q_sym16.*q1.*q3.*t94+coef_f0_q_sym4.*q2.*q3.*t92-coef_f2_q_sym9.*q2.*q3.*t92+coef_f0_q_sym14.*q2.*q3.*t93+coef_f0_q_sym20.*q2.*q3.*t94+coef_f0_q_sym23.*q2.*q3.*t95+coef_f0_q_sym7.*q0.*q1.*q2.*q3-coef_f2_q_sym16.*q0.*q1.*q2.*q3;-coef_f3_q_sym11.*t92+coef_f0_q_sym24.*t95-coef_f3_q_sym1.*t96+coef_f0_q_sym23.*t95.^2-coef_f3_q_sym18.*q0.*q1-coef_f3_q_sym22.*q0.*q2+coef_f0_q_sym11.*q0.*q3-coef_f3_q_sym24.*q0.*q3+coef_f0_q_sym18.*q1.*q3+coef_f0_q_sym22.*q2.*q3-coef_f3_q_sym5.*t92.*t93-coef_f3_q_sym8.*t92.*t94+coef_f0_q_sym4.*t92.*t95-coef_f3_q_sym10.*t92.*t95+coef_f0_q_sym14.*t93.*t95+coef_f0_q_sym20.*t94.*t95-coef_f3_q_sym2.*q0.*q1.*t92-coef_f3_q_sym12.*q0.*q1.*t93-coef_f3_q_sym15.*q0.*q1.*t94+coef_f0_q_sym7.*q0.*q1.*t95-coef_f3_q_sym17.*q0.*q1.*t95-coef_f3_q_sym3.*q0.*q2.*t92-coef_f3_q_sym13.*q0.*q2.*t93-coef_f3_q_sym19.*q0.*q2.*t94+coef_f0_q_sym9.*q0.*q2.*t95-coef_f3_q_sym21.*q0.*q2.*t95+coef_f0_q_sym1.*q0.*q3.*t92-coef_f3_q_sym4.*q0.*q3.*t92-coef_f3_q_sym6.*q1.*q2.*t92+coef_f0_q_sym5.*q0.*q3.*t93-coef_f3_q_sym14.*q0.*q3.*t93+coef_f0_q_sym8.*q0.*q3.*t94-coef_f3_q_sym20.*q0.*q3.*t94+coef_f0_q_sym10.*q0.*q3.*t95+coef_f0_q_sym16.*q1.*q2.*t95-coef_f3_q_sym23.*q0.*q3.*t95+coef_f0_q_sym2.*q1.*q3.*t92-coef_f3_q_sym7.*q1.*q3.*t92+coef_f0_q_sym12.*q1.*q3.*t93+coef_f0_q_sym15.*q1.*q3.*t94+coef_f0_q_sym17.*q1.*q3.*t95+coef_f0_q_sym3.*q2.*q3.*t92-coef_f3_q_sym9.*q2.*q3.*t92+coef_f0_q_sym13.*q2.*q3.*t93+coef_f0_q_sym19.*q2.*q3.*t94+coef_f0_q_sym21.*q2.*q3.*t95+coef_f0_q_sym6.*q0.*q1.*q2.*q3-coef_f3_q_sym16.*q0.*q1.*q2.*q3;t92+t93+t94+t95-1.0];


function d2img = draw_2Dskeleton_MSRA(tline,frameId,folderId,modelId,coord_pixel)

    db_path = '/home/gyeongsikmoon/workspace/Data/Hand_pose_estimation/MSRA/cvpr15_MSRAHandGestureDB/';
    jointNum =  21;
    cubicSz = 200;
    imgWidth = 320;
    imgHeight = 240;
    folder_list = ["1","2","3","4","5","6","7","8","9","I","IP","L","MP","RP","T","TIP","Y"];

    coord_pixel = squeeze(coord_pixel);
    rgb_img = ones(imgHeight,imgWidth,3);
    refDepths = zeros(1,jointNum);
    line_width = 4;

    bin_name = strcat(db_path,'P',num2str(modelId),'/',folder_list(folderId),'/',sprintf('%06d',frameId-1),'_depth.bin');
    splitted = strsplit(tline);

    for jid = 1:jointNum
        refDepths(1,jid) = -str2num(splitted{(jid-1)*3+3});
    end
    refDepth = (min(refDepths(:)) + max(refDepths(:)))/2;

    fp_bin = fopen(bin_name,'r');
    img_info = fread(fp_bin,6,'int');
    left = img_info(3);
    top = img_info(4);
    right = img_info(5)-1;
    bottom = img_info(6)-1;

    img = fread(fp_bin,[right-left+1 bottom-top+1],'float');
    img = permute(img,[2,1]);
    img(img==0) = refDepth+cubicSz/2;
    fclose(fp_bin);

    img = img - refDepth;
    img = img/(cubicSz/2);
    img(img>1) = 1;
    img(img<-1) = -1;

    img = img + 1;
    img = img/2;

    rgb_img(:,:,1) = 255/255;
    rgb_img(:,:,2) = 240/255;
    rgb_img(:,:,3) = 204/255;

    rgb_img(top:bottom,left:right,1) = img*255/255;
    rgb_img(top:bottom,left:right,2) = img*240/255;
    rgb_img(top:bottom,left:right,3) = img*204/255;

    f = figure;
    set(f, 'visible', 'off');
    imshow(rgb_img);
    hold on;

    plot([coord_pixel(1,1),coord_pixel(1,18)],[coord_pixel(2,1),coord_pixel(2,18)],'Color',[255/255,153/255,153/255],'LineWidth',line_width) %wrist to thumb mcp
    plot([coord_pixel(1,18),coord_pixel(1,19)],[coord_pixel(2,18),coord_pixel(2,19)],'Color',[255/255,102/255,102/255],'LineWidth',line_width) %thumb mcp to thumb pip
    plot([coord_pixel(1,19),coord_pixel(1,20)],[coord_pixel(2,19),coord_pixel(2,20)],'Color',[255/255,51/255,51/255],'LineWidth',line_width) %thumb pip to thumb dip
    plot([coord_pixel(1,20),coord_pixel(1,21)],[coord_pixel(2,20),coord_pixel(2,21)],'Color',[255/255,0/255,0/255],'LineWidth',line_width) %thumb dip to thumb tip

    plot([coord_pixel(1,1),coord_pixel(1,2)],[coord_pixel(2,1),coord_pixel(2,2)],'Color',[153/255,255/255,153/255],'LineWidth',line_width) %wrist to index mcp
    plot([coord_pixel(1,2),coord_pixel(1,3)],[coord_pixel(2,2),coord_pixel(2,3)],'Color',[102/255,255/255,102/255],'LineWidth',line_width) %index mcp to index pip
    plot([coord_pixel(1,3),coord_pixel(1,4)],[coord_pixel(2,3),coord_pixel(2,4)],'Color',[51/255,255/255,51/255],'LineWidth',line_width) %index pip to index dip
    plot([coord_pixel(1,4),coord_pixel(1,5)],[coord_pixel(2,4),coord_pixel(2,5)],'Color',[0/255,255/255,0/255],'LineWidth',line_width) %index dip to index tip

    plot([coord_pixel(1,1),coord_pixel(1,6)],[coord_pixel(2,1),coord_pixel(2,6)],'Color',[255/255,204/255,153/255],'LineWidth',line_width) %wrist to middle mcp
    plot([coord_pixel(1,6),coord_pixel(1,7)],[coord_pixel(2,6),coord_pixel(2,7)],'Color',[255/255,178/255,102/255],'LineWidth',line_width) %middle mcp to middle pip
    plot([coord_pixel(1,7),coord_pixel(1,8)],[coord_pixel(2,7),coord_pixel(2,8)],'Color',[255/255,153/255,51/255],'LineWidth',line_width) %middle pip to middle dip
    plot([coord_pixel(1,8),coord_pixel(1,9)],[coord_pixel(2,8),coord_pixel(2,9)],'Color',[255/255,128/255,0/255],'LineWidth',line_width) %middle dip to middle tip

    plot([coord_pixel(1,1),coord_pixel(1,10)],[coord_pixel(2,1),coord_pixel(2,10)],'Color',[153/255,204/255,255/255],'LineWidth',line_width) %wrist to ring mcp
    plot([coord_pixel(1,10),coord_pixel(1,11)],[coord_pixel(2,10),coord_pixel(2,11)],'Color',[102/255,178/255,255/255],'LineWidth',line_width) %ring mcp to ring pip
    plot([coord_pixel(1,11),coord_pixel(1,12)],[coord_pixel(2,11),coord_pixel(2,12)],'Color',[51/255,153/255,255/255],'LineWidth',line_width) %ring pip to ring dip
    plot([coord_pixel(1,12),coord_pixel(1,13)],[coord_pixel(2,12),coord_pixel(2,13)],'Color',[0/255,128/255,255/255],'LineWidth',line_width) %ring dip to ring tip

    plot([coord_pixel(1,1),coord_pixel(1,14)],[coord_pixel(2,1),coord_pixel(2,14)],'Color',[255/255,153/255,255/255],'LineWidth',line_width) %wrist to little mcp
    plot([coord_pixel(1,14),coord_pixel(1,15)],[coord_pixel(2,14),coord_pixel(2,15)],'Color',[255/255,102/255,255/255],'LineWidth',line_width) %little mcp to little pip
    plot([coord_pixel(1,15),coord_pixel(1,16)],[coord_pixel(2,15),coord_pixel(2,16)],'Color',[255/255,51/255,255/255],'LineWidth',line_width) %little pip to little dip
    plot([coord_pixel(1,16),coord_pixel(1,17)],[coord_pixel(2,16),coord_pixel(2,17)],'Color',[255/255,0/255,255/255],'LineWidth',line_width) %little dip to little tip

    colorList = [
    230/255 230/255 0/255;

    153/255 255/255 153/255;
    102/255 255/255 102/255;
    51/255 255/255 51/255;
    0/255 255/255 0/255;

    255/255 204/255 153/255;
    255/255 178/255 102/255;
    255/255 153/255 51/255;
    255/255 128/255 0/255;

    153/255 204/255 255/255;
    102/255 178/255 255/255;
    51/255 153/255 255/255;
    0/255 128/255 255/255;

    255/255 153/255 255/255;
    255/255 102/255 255/255;
    255/255 51/255 255/255;
    255/255 0/255 255/255;

    255/255 153/255 153/255;
    255/255 102/255 102/255;
    255/255 51/255 51/255;
    255/255 0/255 0/255;
    ];

    scatter(coord_pixel(1,:),coord_pixel(2,:),100,colorList,'filled');

    set(gca,'Units','normalized','Position',[0 0 1 1]);  %# Modify axes size
    set(gcf,'Units','pixels','Position',[200 200 2*imgWidth 2*imgHeight]);  %# Modify figure size

    frame = getframe(gcf);
    framedata = frame.cdata;

    xmin = min(coord_pixel(1,:));
    xmax = max(coord_pixel(1,:));
    ymin = min(coord_pixel(2,:));
    ymax = max(coord_pixel(2,:));

    len = max(xmax-xmin+1,ymax-ymin+1) + 70;
    xcenter = (xmin + xmax)/2;
    ycenter = (ymin + ymax)/2;

    xmin = max(round(xcenter - len/2),1);
    xmax = min(round(xmin + len),imgWidth);
    ymin = max(round(ycenter - len/2),1);
    ymax = min(round(ymin + len),imgHeight);

    framedata = framedata(2*ymin:2*ymax,2*xmin:2*xmax,:);

    hold off;
    close(f);

    d2img = framedata;

end


function plot_overlap_recall_curve(iou_files, methods, num_candidates, fh, ...
  names_in_plot, legend_location, use_long_labels, custom_legend)

  if nargin < 7
    use_long_labels = false;
  end
  if nargin < 8
    custom_legend = [];
  end

  [~,method_order] = sort([methods.sort_key]);
  methods = methods(method_order);
  iou_files = iou_files(method_order);
  if ~isempty(custom_legend)
    custom_legend = custom_legend(method_order);
  end

  labels = {methods.short_name};
  long_labels = {methods.name};
  assert(numel(iou_files) == numel(labels));
  n = numel(iou_files);

  num_pos = zeros(n, 1);

  figure(fh);
  for i = 1:n
    data = load(iou_files{i});
    thresh_idx = find( ...
      [data.best_candidates.candidates_threshold] <= num_candidates, 1, 'last');
    experiment = data.best_candidates(thresh_idx);
    [overlaps, recall, auc] = compute_average_recall(experiment.best_candidates.iou);

    display_auc = auc * 100;
    % round to first decimal
    display_auc = round(display_auc * 10) / 10;
    display_num_candidates = mean([experiment.image_statistics.num_candidates]);
    display_num_candidates = round(display_num_candidates * 10) / 10;
    number_str = sprintf('%g (%g)', display_auc, display_num_candidates);
    if names_in_plot
      labels{i} = sprintf('%s %s', labels{i}, number_str);
      long_labels{i} = sprintf('%s %s', long_labels{i}, number_str);
    else
      labels{i} = number_str;
      long_labels{i} = number_str;
    end
    num_pos(i) = numel(overlaps);
    line_style = '-';
    if methods(i).is_baseline
      line_style = '--';
    end
    if ~isempty(methods(i).line_style)
      line_style = methods(i).line_style;
    end
    plot(overlaps, recall, 'Color', methods(i).color, 'LineWidth', 1.5, 'LineStyle', line_style);
    hold on;
  end
  grid on;
  xlabel('IoU overlap threshold');
  ylabel('recall');
  xlim([0.5, 1]);
  ylim([0, 1]);
  if ~strcmp(legend_location, 'none')
    if ~isempty(custom_legend)
      lgnd = legend(custom_legend, 'Location', legend_location);
    elseif use_long_labels
      lgnd = legend(long_labels, 'Location', legend_location);
    else
      lgnd = legend(labels, 'Location', legend_location);
    end
  %   set(lgnd, 'color','none');
  %   legendshrink(0.5);
    legend boxoff;
  end
end


function imStack=analyze2mrLoadRet3TSeries(inFileRoot,outFileRoot,nVols,firstVolIndex,doRotate,scaleFact,flipFlag)
% function imStack=analyze2mrLoadRet3TSeries(inFileRoot,outFileRoot,nVols,firstVolIndex,doRotate,scaleFact,flipFlag)
% Converts from analyze functional image data to mrLoadRet TSeries format
% Analyze functional data are stored as N individual volumes, each with S slices
% mrLoadRet has S individual files with N acquisitions in each.
% the doRotate param allows to you roate the functional data by doRotate*90 degrees
% Try to read the the first volume to see if it's there and get the dimensions of all the rest

% TODO: 1:  Rotate these so that they are in the same orientation as the anatomicals
% (Maybe make this a flag)
% 2: Why can't we see the anatomicals? Claims not to be able to read from /Raw/Anatomy/Inplane
% 3: Why can't we load in the corAnal? We do this by hand perfectly well but it won't do it from mrLoadRet
% 4: Do we want to resample the functional data? Or is this the moment to go to mrLoadRet3?
%
%
% ARW 032703 : Now saves out data in mrLoadRet3.0 format (.mat as opposed to .dat files)

if (~exist('firstVolIndex','var'))
    firstVolIndex=1;
end

if (~exist('scaleFact','var'))
    scaleFact=[1 1]; % No interpolation. (Scaling=1)
end

if (length(scaleFact)~=2) % If we just get a scalar for the scale factor, assume that it applies in both dimensions
    scaleFact=repmat(scaleFact(1),2);
end

if (~exist('doRotate','var'))
    doRotate=1; % This is on by default. Rotates 1*90 degrees
end

if (~exist('flipFlag','var'))
    flipFlag=1; % This is on by default. Flips up/down after rotation
end
suffix=sprintf('%04d',firstVolIndex);

fileName=[inFileRoot,suffix,'.hdr'];

V=spm_vol(fileName);
im=spm_read_vols(V);

[y,x,nSlices]=size(im);
fprintf('Read in a volume of size %d, %d, %d',y,x,nSlices);

% Pre-allocate memory: This is a monster and will fail on many machines.
fprintf('\nTrying to allocate an array with %d elements...\n',y*x*nSlices*nVols);

if (mod(doRotate,2)) % When we rotate by 180 degrees the x and y dimensions remain unchanged
    funcVol=zeros(y,x,nSlices,nVols);
else
    funcVol=zeros(x,y,nSlices,nVols);
end
 fprintf('Rotating by %d x 90, flipFlag=%d',doRotate,flipFlag);

for t=0:(nVols-1)
    thisImIndex=t+firstVolIndex;
    suffix=sprintf('%04d',thisImIndex);
    fileName=[inFileRoot,suffix];
    V=spm_vol(fileName);
    im=spm_read_vols(V);

    % Do the rotation and scaling

    if (mod(doRotate,2)) % When we rotate by 180 degrees the x and y dimensions remain unchanged
        im2=zeros(y,x,nSlices);
    else
        im2=zeros(x,y,nSlices);
    end
    fprintf('\nVol=%d',thisImIndex);

    for thisSlice=1:nSlices
        imSlice=squeeze(im(:,:,thisSlice));
    %s    imSlice=imresize(imSlice,[scaleFact(1)*y,scaleFact(2)*x],'nearest');

        im2(:,:,thisSlice)=rot90(imSlice,doRotate);
        if (flipFlag)

            im2(:,:,thisSlice)=flipud(im2(:,:,thisSlice));
        end

    end % next imSlice

    funcVol(:,:,:,t+1)=im2;
    %fprintf('.');

end
size(funcVol);
[y x nSlices nVols]=size(funcVol);

% Now write them out in a different format
fprintf('\nDone reading data: Writing now...\n');
for t=1:nSlices
    suffix=int2str(t);
    tSeries=squeeze(funcVol(:,:,t,:));
    [a,b,c]=size(tSeries);
    fprintf('\nSize before: %d by %d by %d vols ',a,b,c);

    tSeries=squeeze(shiftdim(tSeries,2));

    [a,b,c]=size(tSeries);
    fprintf('\nSize after:%d samples by %d by %d',a,b*scaleFact(1),c*scaleFact(2));

    % Reshape tSeries here
    tSeries=reshape(tSeries,a,(b*c));

    if ~exist(outFileRoot,'dir')
      mkdir(outFileRoot);
    end

    pathStr = fullfile(outFileRoot,['tSeries',num2str(t)]);
%disp(['Saving: ',pathStr]);
    save(pathStr,'tSeries');

    fprintf('_');
end
fprintf('\nDone\n');
imStack='pathStr';


function out = spm_run_reorient(varargin)
% SPM job execution function
% takes a harvested job data structure and call SPM functions to perform
% computations on the data.
% Input:
% job    - harvested job data structure (see matlabbatch help)
% Output:
% out    - computation results, usually a struct variable.
%__________________________________________________________________________
% Copyright (C) 2006-2014 Wellcome Trust Centre for Neuroimaging

% Volkmar Glauche
% $Id: spm_run_reorient.m 6078 2014-06-30 18:10:33Z guillaume $

job = varargin{1};
if isfield(job.transform,'transprm')
    job.transform.transM = spm_matrix(job.transform.transprm);
elseif isfield(job.transform,'transF')
    load(char(job.transform.transF), 'M');
    job.transform.transM = M;
end

K = numel(job.srcfiles);
spm_progress_bar('Init', K, 'Reorient', 'Images completed');
if isempty(job.prefix)

    % read and write separately, so duplicates get harmlessly overwritten
    MM = zeros(4, 4, K);
    for k = 1:K
        MM(:, :, k) = spm_get_space(job.srcfiles{k});
    end
    for k = 1:K
        spm_get_space(job.srcfiles{k}, job.transform.transM * MM(:, :, k));
        spm_progress_bar('Set',k);
    end
    out.files = job.srcfiles;

else

    out.files = cell(size(job.srcfiles));
    for k = 1:K
        V       = spm_vol(job.srcfiles{k});
        X       = spm_read_vols(V);
        V.mat   = job.transform.transM * V.mat;
        V.fname = spm_file(V.fname, 'prefix',job.prefix);
        spm_write_vol(V,X);
        out.files{k} = [V.fname ',' num2str(V.n(1))];
        spm_progress_bar('Set',k);
    end

end
spm_progress_bar('Clear');


% Formatting_step1_cleanup

clear all;close all;clc

code_dir = 'C:\Users\Xiu\Dropbox\Github\FishExplorer';
addpath(genpath(code_dir));

%% Set Manaully!
% file directories
M_dir = GetFishDirectories();
M_tcutoff = {3500,[],[],3500,3600,4000,1800,[],... % Fish 1-8
    [],5000,[] }; % FIsh 9-11

fpsec = 1.97; % Hz

% also check manual frame-correction section below

%%
poolobj=parpool(8);
%%
range_fish = 15;

for i_fish = range_fish,
    tic
    disp(['i_fish = ', num2str(i_fish)]);

    %% load data
    disp(['load data: fish ' num2str(i_fish)]);
    data_dir = M_dir{i_fish};
    if exist(fullfile(data_dir,'cell_resp_dim_lowcut.mat'), 'file'),
        load(fullfile(data_dir,'cell_resp_dim_lowcut.mat'));
    elseif exist(fullfile(data_dir,'cell_resp_dim.mat'), 'file'),
        load(fullfile(data_dir,'cell_resp_dim.mat'));
    else
        errordlg('find data to load!');
    end

    load(fullfile(data_dir,'cell_info.mat'));
    if exist(fullfile(data_dir,'cell_resp_lowcut.stackf'), 'file'),
        cell_resp_full = read_LSstack_fast_float(fullfile(data_dir,'cell_resp_lowcut.stackf'),cell_resp_dim);
    elseif exist(fullfile(data_dir,'cell_resp.stackf'), 'file'),
        cell_resp_full = read_LSstack_fast_float(fullfile(data_dir,'cell_resp.stackf'),cell_resp_dim);
    else
        errordlg('find data to load!');
    end

    load(fullfile(data_dir,'frame_turn.mat'));
    frame_keys = frame_turn;

    %% load anatomy
    tiffname = fullfile(data_dir,'ave.tif');
    info = imfinfo(tiffname,'tiff');
    nPlanes = length(info);
    s1 = info(1).Height;
    s2 = info(1).Width;
    ave_stack = zeros(s1,s2,nPlanes);
    for i=1:nPlanes,
        ave_stack(:,:,i) = imread(tiffname,i);
    end

    %% fix the left-right flip in the anatomy stack and subsequent cell_info
    anat_stack = fliplr(ave_stack);

    [s1,s2,~] = size(ave_stack);
    for i_cell = 1:length(cell_info),
        % fix '.center'
        cell_info(i_cell).center(2) = s2-cell_info(i_cell).center(2)+1; %#ok<*SAGROW>
    end

    %% reformat coordinates
    numcell_full = cell_resp_dim(1);
    temp = [cell_info(:).center];
    XY = reshape(temp',[],numcell_full)';
    Z = [cell_info.slice]';
    CellXYZ = horzcat(XY,Z);

    %% Manual occasional frame corrections: ONLY RUN ONCE!!!!!!!!!

    if true,
        % add 1 frame at start: ------------- for which fish again? all till F11?
        cell_resp_full = horzcat(cell_resp_full(:,1),cell_resp_full);
        frame_keys = vertcat(frame_keys(1,:),frame_keys);
    end

    % correction of an error in Fish #1
    if i_fish == 1,
        cell_resp_full = horzcat(cell_resp_full(:,1:20),cell_resp_full);
    end

    %% Crop end of experiment (when cell-segmentation drift > ~1um, manually determined)
    if ~isempty(M_tcutoff{i_fish}),
        cell_resp_full = cell_resp_full(:,1:M_tcutoff{i_fish});
        frame_keys = frame_keys(1:M_tcutoff{i_fish},:);
    end

    %% detrend
    CR_dtr = zeros(size(cell_resp_full));
    tmax=size(cell_resp_full,2);
    numcell_full=size(cell_resp_full,1);

    parfor i=1:numcell_full,
        cr = cell_resp_full(i,:);
        crd = 0*cr;
        for j=1:100:tmax,
            if j<=150,
                tlim1 = 1;
                tlim2 = 300;
            elseif j>tmax-150,
                tlim1 = tmax-300;
                tlim2 = tmax;
            else
                tlim1 = j-150;
                tlim2 = j+150;
            end
            crr = cr(tlim1:tlim2);
            crd(max(1,j-50):min(tmax,j+50)) = prctile(crr,15);
        end
%         if mod(i,100)==0,
%             disp(num2str(i));
%         end
        CR_dtr(i,:) = cr-crd;
    end

    TimeSeries = single(CR_dtr);

    %% Place holder for registered coordinates from morphing to ZBrain
    CellXYZ_norm = CellXYZ;

    %% Save files

    % directory to save data formatted for distribution:
    save_masterdir = GetNestedDataDir();
    save_dir = fullfile(save_masterdir,['subject_' num2str(i_fish)]);
    if ~exist(save_dir, 'dir')
        mkdir(save_dir);
    end

    % save time-series
    h5create(fullfile(save_dir,'TimeSeries.h5'),'/TimeSeries',size(TimeSeries),'Datatype','single','ChunkSize',[1000 100]);
    h5write(fullfile(save_dir,'TimeSeries.h5'),'/TimeSeries',TimeSeries);

    % save .mat files
    filename = fullfile(save_dir,'CoreInfo.mat');
    varList = {'CellXYZ','anat_stack','fpsec'};
    save(filename,varList{:});

    filename = fullfile(save_dir,'OptionalInfo.mat');
    varList = {'numcell_full','CellXYZ_norm'};
    save(filename,varList{:});

    filename = fullfile(save_dir,'AdditionalInfo.mat');
    save(filename,'frame_keys');

    %%
    toc
end

%%
% delete(poolobj);


function [varargout]= fileutil_concatBV(file_list, varargin)
% FILEUTIL_CONCATBV - concatenate files which are stored in BrainVision format
%
% Synopsis:
%   [DAT, MRK, MNT]= fileutil_concatBV(FILE_LIST, 'Property, 'Value', ...)
%
% Arguments:
%   FILE_LIST: list of file names (no extension)
%
% Returns:
%   DAT: structure of continuous or epoched signals
%   MRK: marker structure
%   MNT: electrode montage structure
%
% Properties:
%   are passed to file_loadBV
%
% Description:
%   This function is called by file_loadBV in case the file name argument
%   is a cell array of file names. Typically there is no need to call this
%   function directly.
%
%

if ~iscell(file_list),
  file_list= {file_list};
end

T= zeros(1, length(file_list));
dataOffset = 0;
for ii= 1:length(file_list),
  [cnt, mrk, hdr]= file_loadBV(file_list{ii}, varargin{:});
  T(ii)= size(cnt.x,1);
  if ii==1,
    ccnt= cnt;
    curmrk= mrk;
  else
    if ~isequal(cnt.clab, ccnt.clab),
      warning(['inconsistent clab structure will be repaired ' ...
               'by using the intersection']);
      commonclab= intersect(cnt.clab, ccnt.clab);
      cnt= proc_selectChannels(cnt, commonclab{:});
      ccnt= proc_selectChannels(ccnt, commonclab{:});
    end
    if ~isequal(cnt.fs, ccnt.fs)
        error('inconsistent sampling rate');
    end
    ccnt.x= cat(1, ccnt.x, cnt.x);

    mrk.time= mrk.time + dataOffset*1000/cnt.fs;

%     % find markers in the loaded interval
%     inival= find(curmrk.time > skip*1000/cnt.fs & ...
%         curmrk.time <= (skip+maxlen)*1000/cnt.fs);
%     curmrk= mrk_selectEvents(curmrk, inival);
%     %let the markers start at zero
%     curmrk.time= curmrk.time - skip*1000/cnt.fs;

    curmrk = mrk_mergeMarkers(curmrk, mrk);

  end
  dataOffset = dataOffset + T(ii);

end

ccnt.T= T;
if length(file_list)>1,
  ccnt.title= [ccnt.title ' et al.'];
  ccnt.file= strcat(fileparts(ccnt.file), file_list);
end

varargout= cell(1, nargout);
varargout{1}= ccnt;
if nargout>1,
  varargout{2}= curmrk;
  if nargout>2,
    varargout{3}= hdr;
  end
end


function calcFeatureImportanceRF_Aerts(pathRF,nPerms,seed)

startpath = pwd;
cd(pathRF), load('testingVariableImportance') % 'variableImportance' gets out of there

[percentAUCdecrease,varNames] = calcFeatureImportanceRF_HN(pathRF,nPerms,'DeathSign','CT',seed);
variableImportance.DeathSign.CT.percentAUCdecrease = percentAUCdecrease;
variableImportance.DeathSign.CT.varNames = varNames;
cd(pathRF), save('testingVariableImportance','variableImportance')

cd(startpath)
end


function calcAllAertsFeatures_batchHN_temp(pathData,pathText,namePT,nameCT,nameROI,outcomes,featType,nBatch,matlabPATH)
% -------------------------------------------------------------------------
% function calcAllSeparateTextures_batchHN(pathData,pathText,namePT,nameCT,nameROI,outcomes,featType,scale_mat,Ng_mat,nBatch,matlabPATH)
% -------------------------------------------------------------------------
% DESCRIPTION:
% This function computes SEPARATE texture features for all patients, for
% all different combinations of the following texture extraction parameters:
% - Scale: Resolution at which the ROI is isotropically resampled.
% - Ng: Number of gray-levels in the quantization process.
%
% Different extraction parameters are passed as arrays or cells in the
% function in order to test all possible combinations. This function is
% used for SEPARATE scans specifically. See Ref. [1,2] and 'prepareVolume.m'
% for more details.
%
% Texture features are computed for all head and neck (HN) DICOM imaging
% data downloaded from The Cancer Imaging Archive (TCIA) website at:
% <http://dx.doi.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>, and first organized
% in a 'DATA' directory using the function readAllDICOM_HN.m.  Results are
% then saved in a folder 'TEXTURES' in the HN WORKSPACE.
% -------------------------------------------------------------------------
% REFERENCES:
% [1] Vallieres, M. et al. (2015). FDG-PET/CT radiomics models for the
%     early prediction of different tumour outcomes in head and neck cancer.
%     The Journal of Nuclear Medicine, aa(bb), xxx-yyy.
%     doi:
% [2] Vallieres, M. et al. (2015). A radiomics model from joint FDG-PET and
%     MRI texture features for the prediction of lung metastases in soft-tissue
%     sarcomas of the extremities. Physics in Medicine and Biology, 60(14),
%     5471-5496. doi:10.1088/0031-9155/60/14/5471
% -------------------------------------------------------------------------
% INPUTS:
% 1. pathData: Full path to the HN sData files directory.
%              --> Ex: '/myProject/WORKSPACE/DATA'
% 2. pathText: Full path to the HN non texture features directory.
%              --> Ex: '/myProject/WORKSPACE/FEATURES/TEXTURES'
% 3. namePT: Cell of strings of all PET sData files to read
%            --> Ex: {'HGJ_001_PT.PTscan.mat';'HGJ_022_PT.PTscan.mat'}
% 4. namePT: Cell of strings of all CT sData files to read
%            --> Ex: {'HGJ_001_CT.CTscan.mat';'HGJ_022_CT.CTscan.mat'}
% 5. nameROI: Cell of strings specifying the ROI names to analyze for the
%             patients defined by "namePT" and "nameCT"
%             --> Ex: {'GTV';'GTV-P'}
% 6. outcomes: Structure specifying the status (1 or 0) for different
%              outcomes in HN cancer. Contains: outcomes.Failure,
%              outcomes.Locoregional, outcomes.Distant. See ref.[1] for
%              more details.
% 7. featType: Either 'GTVp' for primary GTV, or 'GTVtot' for primaty GTV +
%              nodal GTVs
%              --> Ex: 'GTVp'
% 8. scale_mat: Array vector specifying the different 'Scale' values to test.
%               --> Ex: [1,2,3,4,5]
% 9. Ng_mat: Array vector specifying the different 'Ng' values to test.
%            --> Ex: [8,16,32,64]
% 10. nBatch: Number of parallel batch.
%             --> Ex: 8
% 11.  matlabPATH: Full path to the MATLAB excutable on the system.
%      --> Ex: 'matlab' (symbolic link)
% -------------------------------------------------------------------------
% AUTHOR(S): Martin Vallieres <mart.vallieres@gmail.com>
% -------------------------------------------------------------------------
% HISTORY:
% - Creation: March 2016
%--------------------------------------------------------------------------
% STATEMENT:
% This file is part of <https://github.com/mvallieres/radiomics/>,
% a package providing MATLAB programming tools for radiomics analysis.
% --> Copyright (C) 2015  Martin Vallieres
%
%    This package 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.
%
%    This package 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 this package.  If not, see <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

startpath = pwd;
ind = strfind(namePT{1},'_'); cohortID = namePT{1}(1:ind-1);
cd(pathText), mkdir(['batchLog_',cohortID,'_',featType,'_AertsFeatures']), cd(['batchLog_',cohortID,'_',featType,'_AertsFeatures']), pathBatch = pwd;
time = 60; % Number of seconds to wait before checking if parallel computations are done
nameOutcomes = fieldnames(outcomes); nOutcomes = numel(nameOutcomes);
scans = {'PT','CT'}; nScans = numel(scans);

% PRODUCE BATCH COMPUTATIONS
nPatient = numel(namePT); valid = ones(nPatient,1);
for i = 1:nPatient
    if isempty(nameROI{i})
        valid(i) = 0;
    end
end
indValid = find(valid); nPatient = numel(indValid);
if nPatient < nBatch
    nBatch = nPatient;
end
[patients] = batchPatients(nPatient,nBatch);
save('workspace','pathData','pathText','namePT','nameCT','nameROI','patients','indValid','featType'), pause(5);
for i = 1:nBatch
    nameScript = ['batch',num2str(i),'_script.m'];
    fid = fopen(nameScript,'w');
    fprintf(fid,'load(''workspace'')\n');
    fprintf(fid,['calcAllAertsFeatures_HN(pathData,pathText,namePT(indValid(patients{',num2str(i),'})),nameCT(indValid(patients{',num2str(i),'})),nameROI(indValid(patients{',num2str(i),'})),featType)\n']);
    fprintf(fid,['system(''touch batch',num2str(i),'_end'');\n']);
    fprintf(fid,'clear all');
    fclose(fid);
    system([matlabPATH,' -nojvm -nodisplay -nodesktop -nosplash < ',nameScript,' >& ',nameScript(1:end-1),'log &']);
end

% WAITING LOOP
waitBatch(pathBatch,time,nBatch)
delete('workspace.mat')

% % GROUPING RESULTS FROM ALL BATCH
% nPatient = numel(namePT);
% names = {namePT,nameCT};
% for scan = 1:nScans
%     cd(pathText)
%     sign = struct;
%     signTemp = zeros(nPatient,4); % 4-feature signature
%     tempText = cell(1,nPatient); % Cell used to load patient textures only once
%     for p = 1:nPatient
%         ind = strfind(names{scan}{p},'.'); namePatientScan = names{scan}{p}(1:ind(1)-1);
%         if exist([namePatientScan,'_',featType,'_sign.mat'],'file')
%             load([namePatientScan,'_',featType,'_sign']) % Variable 'signature' is now in MATLAB workspace
%         else
%             load([namePatientScan,'_','GTVp','_sign']) % Variable 'signature' is now in MATLAB workspace
%         end
%         tempText{p} = signature;
%     end
%     for p = 1:nPatient
%         signTemp(p,:) = tempText{p};
%     end
%     sign.Data = signTemp;
%     for o = 1:nOutcomes
%         [sign.Spearman.(nameOutcomes{o}).rs,sign.Spearman.(nameOutcomes{o}).p] = corr(sign.Data,outcomes.(nameOutcomes{o}),'type','Spearman','rows','pairwise');
%     end
%     cd .., save(['AertsSign_',cohortID,'_',scans{scan},'_',featType],'sign')
% end

cd(startpath)
end


function [f0,irms,df,amp]=f0track5(f0v,vrv,dfv,pwt,pwh,aav,shiftm,imgi)

%	F0 trajectory tracker
%	[f0,irms,df,amp]=f0track2(f0v,vrv,dfv,shiftm,imgi)
%		f0	: extracted F0 (Hz)
%		irms	: relative interfering energy in rms
%
%	f0v	: fixed point frequency vector
%	vrv	: relative interfering energy vector
%	dfv	: fixed point slope vector
%	pwt	: total power
%	pwh	: power in higher frequency range
%	aav	: amplitude list for fixed points
%	shiftm	: frame update period (ms)
%	imgi	: display indicator, 1: display on (default), 0: off
%
%	This is a very primitive and conventional algorithm.

%	coded by Hideki Kawahara
%	copyright(c) Wakayama University/CREST/ATR
%	10/April/1999 first version
%	17/May/1999 relative fq jump thresholding
%	01/August/1999 parameter tweeking
%   07/Dec./2002 waitbar was added
%   13/Jan./2005 bug fix on lines 58, 97 (Thanx Ishikasa-san)
%	30/April/2005 modification for Matlab v7.0 compatibility
%	10/Aug./2005 modified  by Takahashi on waitbar
%	10/Sept./2005 modified by Kawahara on waitbar

if nargin==7; imgi=1; end; %10/Sept./2005
vrv=sqrt(vrv);
[~,mm]=size(vrv);
mm=min(mm,length(pwt));

f0=zeros(1,mm);
irms=ones(1,mm);
df=ones(1,mm);
amp=zeros(1,mm);
von=0;
[mxvr,ixx]=min(vrv);
hth=0.12;	% highly confident voiced threshould (updated on 01/August/1999)
lth=0.9;	% threshold to loose confidence
bklm=100;	% back track length for voicing decision
lalm=10;	% look ahead length for silence decision
bkls=bklm/shiftm;
lals=lalm/shiftm;
htr=10*log10(pwh./pwt);

thf0j=0.04*sqrt(shiftm); %  4 % of F0 is the limit of jump
ii=1;
f0ref=0;
htrth=-2.0; % was -3 mod 2002.6.3
if imgi==1; hpg=waitbar(0,'F0 tracking'); end; % 07/Dec./2002 by H.K.%10/Aug./2005
while ii < mm+1
	if (von == 0) && (mxvr(ii)<hth) && (htr(ii)<htrth)
		von = 1;
		f0ref=f0v(ixx(ii),ii); % start value for search
		for jj=ii:-1:max(1,ii-bkls)
			[gomi,jxx]=min(abs((f0v(:,jj)-f0ref)/f0ref));
			gomi=gomi+(f0ref>10000)+(f0v(jxx,jj)>10000);
			if (((gomi>thf0j) || (vrv(jxx,jj)>lth) || (htr(jj)>htrth))&&(f0v(jxx,jj)<1000)) && htr(jj)>-18
%				disp(['break pt1 at ' num2str(jj)])
				break
			end;
			if (gomi>thf0j)
%				disp(['break pt2 at ' num2str(jj)])
				break
			end;

			f0(jj)=f0v(jxx,jj);
			irms(jj)=vrv(jxx,jj);
			df(jj)=dfv(jxx,jj);
			amp(jj)=aav(jxx,jj);
			f0ref=f0(jj);
		end;
		f0ref=f0v(ixx(ii),ii);
	end;
	if (f0ref>0) && (f0ref<10000)
		[gomi,jxx]=min(abs((f0v(:,ii)-f0ref)/f0ref));
	else
		gomi=10;
	end;
	if (von ==1) && (mxvr(ii)>hth)
		for jj=ii:min(mm,ii+lals)
			ii=jj;
			[gomi,jxx]=min(abs((f0v(:,ii)-f0ref)/f0ref));
			gomi=gomi+(f0ref>10000)+(f0v(jxx,ii)>10000);
			if (gomi< thf0j) && ((htr(ii)<htrth)||(f0v(jxx,ii)>=1000))
				f0(ii)=f0v(jxx,ii);
				irms(ii)=vrv(jxx,ii);
				df(ii)=dfv(jxx,ii);
				amp(ii)=aav(jxx,ii);
				f0ref=f0(ii);
			end;
			if (gomi>thf0j) || (vrv(jxx,ii)>lth) || ((htr(ii)>htrth)&&(f0v(jxx,ii)<1000))
				von = 0;f0ref=0;
				break
			end;
		end;
	elseif (von==1) && (gomi < thf0j)  && ((htr(ii)<htrth)||(f0v(jxx,ii)>=1000))
		f0(ii)=f0v(jxx,ii);
		irms(ii)=vrv(jxx,ii);
		df(ii)=dfv(jxx,ii);
		amp(ii)=aav(jxx,ii);
		f0ref=f0(ii);
	else
		von=0;
	end;
    if imgi==1; waitbar(ii/mm); end; %,hpg); % 07/Dec./2002 by H.K.%10/Aug./2005
	ii=ii+1;
end;
if imgi==1; close(hpg); end;%10/Aug./2005


function [massImbalance, imBalancedMass, imBalancedCharge, imBalancedRxnBool, elements, missingFormulaeBool, balancedMetBool] = checkMassChargeBalance(model, printLevel, modelName)
% Tests for a list of reactions if these reactions are
% mass-balanced by adding all elements on left hand side and comparing them
% with the sums of elements on the right hand side of the reaction.
% A reaction is considered elementally imbalanced if any of the molecular
% species involved is missing a chemical formula.
%
% USAGE:
%
%    [massImbalance, imBalancedMass, imBalancedCharge, imBalancedRxnBool, elements, missingFormulaeBool, balancedMetBool] = checkMassChargeBalance(model, printLevel, modelName)
%
% INPUT:
%    model:                  COBRA model structure:
%
%                              * .S - `m` x `n` stoichiometric matrix
%                              * .metForumlas - `m` x 1 cell array of metabolite formulas
%                              * .metCharges - `m` x 1 double array of charges
%                              * model.SIntRxnBool - Boolean of reactions heuristically though to be mass balanced. (optional)
%
% OPTIONAL INPUTS:
%    printLevel:             {-1, (0), 1} where:
%
%                            -1 = print out diagnostics on problem reactions to a file,
%                            0 = silent,
%                            1 = print elements as they are checked (display progress),
%                            2 = also print out diagnostics on problem reactions to screen
%    modelName:               name of the file
%
% OUTPUTS:
%    massImbalance:          `nRxn` x `nElement` matrix with mass imbalance
%                            for each element checked. 0 if balanced.
%    imBalancedMass:         `nRxn` x 1 cell with mass imbalance
%                            e.g. -3 H means three hydrogens disappear in the reaction.
%    imBalancedCharge:       `nRxn` x 1 vector with charge imbalance, empty if no imbalanced reactions
%    imBalancedRxnBool:      boolean vector indicating imbalanced reactions (including exchange reactions!)
%    elements:               `nElement` x 1 cell array of element abbreviations checked
%    missingFormulaeBool:    `nMet` x 1 boolean vector indicating metabolites without formulae
%    balancedMetBool:        boolean vector indicating metabolites exclusively involved in balanced reactions
%
%
% OPTIONAL OUTPUT FILES:
% modelName_mass_imbalanced_reactions.txt  provides a human readable summary
% for each mass imbalanced reaction.
%
% For each reaction it contains:
% j             the index of the column of the stoichiometric matrix corresponding to the reaction
% rxns{j}       the abbreviation of the reaction
% imbalance     the number of each element that is unbalanced
% equation      the reaction equation
%
% For each metabolite involved in a reaction it contains
% i               the index of the row of the stoichiometric matrix corresponding to the metabolite
% mets{i}         the abbreviation of the reaction
% S(i,j)          the stoichiometric coefficient
% metFormulas{i}  the chemical formula of the metabolite
%
% Example
% #Rxn;rxnAbbr;imbalance;equation
% 32;2AMACSULT;3 O, 1 S;2amac[c] + nadph[c] + paps[c]  -> nadp[c] + Lcyst[c] + pap[c]
%    58	       2amac[c]	-1	C3H5NO2
%    60	       nadph[c]	-1	C21H26N7O17P3
%    61	        nadp[c]	1	C21H25N7O17P3
%    62	        paps[c]	-1	C10H11N5O10P2
%    63	       Lcyst[c]	1	C3H6NO5S
%    64	         pap[c]	1	C10H11N5O10P2
%
% .. Authors:
%       - Ines Thiele 12/09
%       - IT, 06/10, Corrected some bugs and improved speed.
%       - RF, 09/09/10, Support for very large models and printing to file.
%       - RF, 18/12/14, Default is now to check balancing of all reactions.

[nMet, nRxn]=size(model.S);

if ~exist('printLevel', 'var')
    printLevel=0;
end

if ~isfield(model,'SIntRxnBool')
    model.SIntRxnBool=true(nRxn,1);%assume all reactions are supposed to be internal if no other info provided
end

if ~exist('modelName','var')
    modelName='';
end
if ~isfield(model,'rxns')
    for i=1:nRxn
        model.rxns{i,1}=['rxn' int2str(i)];
    end
end
% List of elements
elements = {'H','C', 'O', 'P', 'S', 'N', 'Mg','X','Fe','Zn','Co','Ca','Y','I','Na','Cl','K','R','FULLR'};

E=sparse(nMet, length(elements));
massImbalance=zeros(nRxn, length(elements));
missingFormulaeBool=cellfun(@isempty, model.metFormulas);
for j = 1 : length(elements)
    if j==1
        [dE, E_el, missingFormulaeBool]=checkBalance(model, elements{j}, printLevel,[],missingFormulaeBool);
        massImbalance(:, j)=dE;
        E(:, j)=E_el;
        if printLevel>0
            fprintf('%s\n', ['Checked element ' elements{j}]);
        end
    else
        %no need to print out for each element which metabolites have no
        %formula
        [massImbalance(:, j), E(:, j)]=checkBalance(model, elements{j}, 0);
        if printLevel>0
            fprintf('%s\n', ['Checking element ' elements{j}]);
        end
    end
end

%ignore mass imbalance of exchange reactions if the internal reactions have
%been identified at the input
if any(~model.SIntRxnBool)
    massImbalance(~model.SIntRxnBool,:)=1;
end

E=full(E);

% A reaction is considered elementally imbalanced if any of the molecular
% species involved is missing a chemical formula.
imBalancedRxnBool=any(massImbalance, 2) | any(model.S(missingFormulaeBool, :),1)';

imBalancedMass=cell(nRxn, 1);
for i = 1 : nRxn
    imBalancedMass{i, 1}='';
    if imBalancedRxnBool(i)
        for j = 1 : length(elements)
            if massImbalance(i, j) ~= 0
                if ~strcmp(imBalancedMass{i, 1}, '')
                    imBalancedMass{i, 1} = [imBalancedMass{i, 1} ', ' int2str(massImbalance(i, j)) ' ' elements{j}];
                else
                    imBalancedMass{i, 1} = [int2str(massImbalance(i, j)) ' ' elements{j}];
                end
            end
        end
        if strfind(imBalancedMass{i, 1}, 'NaN')
            imBalancedMass{i, 1}='NaN';
        end
    end
    if mod(i, 1000)==0
        fprintf('%n\t%s\n', i, ['reactions checked for ' elements{j} ' balance']);
    end
end
if printLevel==-1
    firstMissing=0;
    for p=1:nRxn
        %only print out for reactions supposed to be mass balanced
        if model.SIntRxnBool(p) && ~strcmp(imBalancedMass{p,1},'')
            %at the moment, ignore reactions with a metabolite that have
            %no formula
            if ~strcmp(imBalancedMass{p, 1}, 'NaN')
                if ~firstMissing
                    fid=fopen([modelName 'mass_imbalanced_reactions.txt'],'w');
                    fprintf(fid, '%s;%s;%s;%s\n', 'j', 'rxns{j}', 'imbalance', 'equation');
                    fprintf(fid, '%s;%s;%s;%s\n\n', 'i', 'mets{i}', 'S(i,j)', 'metFormulas{i}');
                    fprintf('%s\n',['There are mass imbalanced reactions, see ' modelName 'mass_imbalanced_reactions.txt'])
                    firstMissing=1;
                end
                equation=printRxnFormula(model, model.rxns(p), 0);
                fprintf(fid, '%s;%s;%s;%s\n', int2str(p), model.rxns{p}, imBalancedMass{p, 1}, equation{1});
                for m=1:size(model.S, 1)
                    if model.S(m, p) ~= 0
                        fprintf(fid,'%5u\t%15s\t%g\t%s\n',m,model.mets{m},full(model.S(m,p)),model.metFormulas{m});
                    end
                end
            end
        end
    end
    if firstMissing
        fclose(fid);
    end
end
if printLevel==2
    for p=1:nRxn
        %only print out for reactions supposed to be mass balanced
        if model.SIntRxnBool(p) && ~strcmp(imBalancedMass{p,1},'')
            %at the moment, ignore reactions with a metabolite that have
            %no formula
            if ~strcmp(imBalancedMass{p, 1}, 'NaN')
                equation=printRxnFormula(model, model.rxns(p), 0);
                fprintf('%6s\t%30s\t%10s\t%s\n', int2str(p), model.rxns{p}, imBalancedMass{p, 1}, equation{1});
                % for m=1:size(model.S, 1)
                %     if model.S(m, p) ~= 0
                %         fprintf('%5u\t%15s\t%g\t%s\n',m,model.mets{m},full(model.S(m,p)),model.metFormulas{m});
                %     end
                % end

            end
        end
    end
end

%
if nnz(strcmp('', imBalancedMass))==nRxn
    imBalancedMass=[];
end

% Check for charge balance (initialize with NaN, if the fields are not set
% this will make it clear.
imBalancedCharge = NaN * ones(nRxn, 1);
firstMissing=0;
if isfield(model, 'metCharges')
    for m=1:nMet
        if isnan(model.metCharges(m)) && ~isempty(model.metFormulas{m})
            if printLevel==2
                fprintf('%s\t%s\n', int2str(m), [model.mets{m} ' has no charge but has formula.'])
                if ~firstMissing
                    warning('model structure must contain model.metCharges field for each metabolite');
                end
                firstMissing=1;
            end
            if printLevel==-1
                if ~firstMissing
                    fid=fopen([modelName 'metabolites_without_charge.txt'],'w');
                end
                firstMissing=1;
                fprintf(fid, '%s\t%s\n', int2str(m), model.mets{m});
            end
        end
    end

    imBalancedCharge = model.S' * double(model.metCharges); % Matlab does not support this operation on two int values - one needs to be converted to double. The smaller matrix is selected.
end

if printLevel==-1 && isfield(model,'SIntRxnBool')
    firstMissing=0;
    if any(imBalancedCharge)
        for q=1:nRxn
            if model.SIntRxnBool(q) && strcmp(imBalancedMass{q, 1}, '') && imBalancedCharge(q) ~= 0
                if ~firstMissing
                    fid=fopen([modelName 'mass_balanced_charge_imbalanced_reactions.txt'],'w');
                    fprintf('%s\n',['There are mass balanced, but charge imbalanced reactions, see ' modelName 'charge_imbalanced_reactions.txt'])
                    firstMissing=1;
                end
                equation=printRxnFormula(model, model.rxns(q), 0);
                fprintf(fid, '%s\t%s\t%s\n', int2str(q), model.rxns{q}, equation{1});
                % for m=1:size(model.S, 1)
                %     if model.S(m, q) ~= 0
                %         fprintf(fid,'%5u\t%15s\t%g\t%g\t%s\n',m,model.mets{m},full(model.S(m,q)),model.metCharges(m),model.metFormulas{m});
                %     end
                % end
            end
        end
        if firstMissing
            fclose(fid);
        end
    end
end

if printLevel==2 && isfield(model,'SIntRxnBool')
    if any(imBalancedCharge)
        fprintf('%s\n', 'Mass balanced, but charged imbalanced reactions:')
        for q=1:nRxn
            if model.SIntRxnBool(q) && strcmp(imBalancedMass{p, 1}, '') && imBalancedCharge(q) ~= 0
                equation=printRxnFormula(model, model.rxns(q), 0);
                fprintf('%s\t%s\t%s\n', int2str(q), model.rxns{q}, equation{1});
                for m=1:size(model.S, 1)
                    if model.S(m, q) ~= 0
                        fprintf('%5u\t%15s\t%g\t%g\t%s\n',m,model.mets{m},full(model.S(m,q)),model.metCharges(m),model.metFormulas{m});
                    end
                end
            end
        end
    end
end

%If the field is set we should assume, that all values are defined.
if isfield(model, 'metCharges')
    imBalancedRxnBool = imBalancedRxnBool | imBalancedCharge ~= 0;
end

if isfield(model,'SIntRxnBool')
    imBalancedRxnBool = imBalancedRxnBool | ~model.SIntRxnBool;
end

%nonzero rows corresponding to completely mass balanced reactions
balancedMetBool = getCorrespondingRows(model.S,true(nMet,1),~imBalancedRxnBool,'exclusive');
massImbalance = sparse(massImbalance);


classdef prtRv < prtAction
    % prtRv Base class for all prt random variables
    %
    %   This is an abstract class from which all prt random variables
    %   inherit. It can not be instantiated. prtRv contains the following
    %   properties:
    %
    %   name           - Name of the random variable.
    %   userData       - Structure for holding additional related to the
    %                    random variable.
    %   nDimensions    - Number of dimensions of the vector space
    %                    represented by the random variable.
    %
    %   The prtRv class has the following methods
    %
    %   plotPdf - Plot the pdf of the random variable
    %   plotCdf - Plot the cdf of the random variable
    %
    %   The prtRv class has the following methods, most of which are
    %   overloaded. If a method is not overloaded, it is because it is not
    %   possible to implement the functionality.
    %
    %   pdf - Output the pdf of the random variable evaluated at the points
    %         specified
    %
    %   logPdf - Output the log-pdf of the random variable evaluated at the
    %            points specified (for many distributions, this can be
    %            calculated more easily than simply log(pdf(R,X))
    %
    %   cdf - Output the cdf of the random variable evaluated at the
    %         points specified
    %
    %   draw - Draw samples from the random variable
    %
    %   mle - Perform maximum likelihood estimation of the objects parameters
    %         using the specified data
    %
    %   See also: prtRvMvn, prtRvGmm, prtRvMultinomial, prtRvUniform,
    %   prtRvUniformImproper, prtRvVq

    properties
        plotOptions  = prtRv.initializePlotOptions()
    end
    properties (Abstract = true, Hidden = true, Dependent = true)
        nDimensions % The number of dimensions
    end
    methods (Abstract, Hidden=true)
        [bool, reasonStr] = isValid(R)
    end
    methods
        % These functions are default "error" functions incase a
        % subclass has not specified these standard methods.
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        function vals = pdf(R,X) %#ok
            % PDF Output the pdf of the random variable evaluated at the points specified
            %
            % pdf = RV.pdf(X) returns the value of the pdf of the prtRv
            % object evaluated at X. X must be an N x nDims matrix, where N
            % is the number of locations to evaluate the pdf, and nDims is
            % the same as the number of dimensions, nDimensions, of the
            % prtRv object RV.
            missingMethodError(R,'pdf');
        end

        function vals = logPdf(R,X)
            % LOGPDF Output the log pdf of the random variable evaluated at the points specified
            %
            % logpdf = RV.logpdf(X) returns the logarithm of value of the
            % pdf of the prtRv object evaluated at X. X must be an N x
            % nDims matrix, where N is the number of locations to evaluate
            % the pdf, and nDims is the same as the number of dimensions,
            % nDimensions, of the prtRv object RV.
            vals = log(R.pdf(X));
        end

        function vals = cdf(R,X) %#ok
            % CDF Output the cdf of the random variable evaluated at the points specified
            %
            % cdf = RV.cdf(X) returns the value of the cdf of the prtRv
            % object evaluated at X. X must be an N x nDims matrix, where
            % N is the number of locations to evaluate the pdf, and nDims
            % is the same as the number of dimensions, nDimensions, of the
            % prtRv object RV.

            missingMethodError(R,'cdf');
        end

        function vals = draw(R,N) %#ok
            % DRAW  Draw random samples from the distribution described by the prtRv object
            %
            % VAL = RV.draw(N) generates N random samples drawn from the
            % distribution described by the prtRv object RV. VAL will be a
            % N x nDimensions vector, where nDimensions is the number of
            % dimensions of RV.

            missingMethodError(R,'draw');
        end

        function vals = mle(R,X) %#ok
            % MLE Compute the maximum likelihood estimate
            %
            % RV = RV.mle(X) computes the maximum likelihood estimate based
            % the data X. X should be nObservations x nDimensions.
            missingMethodError(R,'mle');
        end
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        % These functions are default plotting functions
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        function varargout = plotPdf(R,varargin)
            % PLOTPDF  Plot the pdf of the prtRv
            %
            % R.plotPdf()
            % R.plotPdf([xMin yMin (zMin) xMax yMax (zMax)]);

            varargout = {};
            [isValid, reasonStr] = R.isValid;
            if R.isPlottable

                if nargin > 1 % Calculate appropriate limits from covariance
                    plotLims = varargin{1};
                else
                    plotLims = plotLimits(R);
                end
                [linGrid, gridSize] = prtPlotUtilGenerateGrid(plotLims(1:2:end), plotLims(2:2:end), R.plotOptions.nSamplesPerDim);

                imageHandle = prtPlotUtilPlotGriddedEvaledFunction(R.pdf(linGrid), linGrid, gridSize, R.plotOptions.colorMapFunction(R.plotOptions.nColorMapSamples),varargin{2:end});

                if nargout
                    varargout = {imageHandle};
                end
            else
                if isValid
                    error('prt:prtRv:plot','This RV object cannont be plotted because it has too many dimensions.')
                else
                    error('prt:prtRv:plot','This RV object cannot be plotted. This RV is not yet valid %s.',reasonStr);
                end
            end
        end
        function varargout = plotLogPdf(R,varargin)
            % plotLogPdf  Plot the pdf of the prtRv
            %
            % R.plotLogPdf()
            % R.plotLogPdf([xMin yMin (zMin) xMax yMax (zMax)]);

            varargout = {};
            [isValid, reasonStr] = R.isValid;
            if R.isPlottable

                if nargin > 1 % Calculate appropriate limits from covariance
                    plotLims = varargin{1};
                else
                    plotLims = plotLimits(R);
                end

                [linGrid, gridSize] = prtPlotUtilGenerateGrid(plotLims(1:2:end), plotLims(2:2:end), R.plotOptions.nSamplesPerDim);

                imageHandle = prtPlotUtilPlotGriddedEvaledFunction(R.logPdf(linGrid), linGrid, gridSize, R.plotOptions.colorMapFunction(R.plotOptions.nColorMapSamples),varargin{2:end});

                if nargout
                    varargout = {imageHandle};
                end
            else
                if isValid
                    error('prt:prtRv:plot','This RV object cannont be plotted because it has too many dimensions.')
                else
                    error('prt:prtRv:plot','This RV object cannot be plotted. This RV is not yet valid %s.',reasonStr);
                end
            end
        end

        function varargout = plotCdf(R,varargin)
            %PLOTCDF Plot the cdf of the prtRv
            % R.plotCdf()
            % R.plotCdf([xMin yMin (zMin) xMax yMax (zMax)]);

            varargout = {};
            [isValid, reasonStr] = R.isValid;
            if R.isPlottable

                if nargin > 1 % Calculate appropriate limits from covariance
                    plotLims = varargin{1};
                else
                    plotLims = plotLimits(R);
                end

                [linGrid,gridSize] = prtPlotUtilGenerateGrid(plotLims(1:2:end), plotLims(2:2:end), R.plotOptions.nSamplesPerDim);

                imageHandle = prtPlotUtilPlotGriddedEvaledFunction(R.cdf(linGrid), linGrid, gridSize, R.plotOptions.colorMapFunction(R.plotOptions.nColorMapSamples));

                if nargout
                    varargout = {imageHandle};
                end
            else
                if isValid
                    error('prt:prtRv:plot','This RV object cannont be plotted because it has too many dimensions for plotting.')
                else
                    error('prt:prtRv:plot','This RV object cannot be plotted. This RV is not yet valid %s.',reasonStr);
                end
            end
        end
    end

    methods (Hidden = true)
        % As a default we just use the monte carlo limits.
        % If a sub-class implements plotLimits ezPdfPlot or ezCdfPlot
        % should use that.
        function limits = plotLimits(R)
            limits = monteCarloPlotLimits(R);
        end

        function val = isPlottable(R)
            val = ~isempty(R.nDimensions) && R.nDimensions < 4 && R.isValid;
        end
    end

    methods (Access = protected, Hidden = true)
        function Obj = trainAction(Obj, DataSet)
            Obj = Obj.mle(DataSet);
        end

        function DataSet = runAction(Obj, DataSet)
            DataSet = DataSet.setObservations(Obj.logPdf(DataSet));
        end

        function xOut = runActionFast(Obj, xIn, ds) %#ok<INUSD>
            xOut = Obj.logPdf(xIn);
        end
    end

    methods (Access = 'private', Hidden = true)
        function missingMethodError(R,methodName) %#ok<MANU>
            error('The method %s is not defined for this prtRv object',methodName);
        end
    end
    methods (Access = 'private',Hidden = true,Static = true)
        function plotOptions = initializePlotOptions()
            if ~isdeployed
                plotOptions = prtOptionsGet('prtOptionsRvPlot');
            else
                plotOptions = prtOptions.prtOptionsRvPlot;
            end
        end
    end

    methods (Access = 'protected', Hidden = true)
        function X = dataInputParse(R,X) %#ok<MANU>
            % dataInputParse - Parse inputs for RVs that only require the
            % data. Since most RVs need only the observations (X). This
            % function allows RVs to operate on prtDataSetStandard()s and
            % a data matrix.

            if isnumeric(X) || islogical(X)
                % Quick exit from this ifelse so we don't call isa
                % which can be slow
            elseif isa(X,'prtDataSetStandard')
                X = X.getObservations();
            else
                error('prt:prtRv','Input to mle() must be a matrix of data or a prtDataSet.');
            end

        end

        function R = constructorInputParse(R,varargin)

            nIn = length(varargin);

            % Quick Exit for the zero input constructor
            if nIn == 0
                return
            elseif mod(nIn,2)
                error('prt:prtRv:constructorInputParse','Inputs must be supplied by as string/value pairs');
            end

            R = prtUtilAssignStringValuePairs(R,varargin{:});

        end

        function val = monteCarloCovariance(R,nSamples)
            % Calculates the sample covariance of drawn data
            if nargin < 2 || isempty(nSamples)
                nSamples = 1e3;
            end
            val = cov(draw(R,nSamples));
        end

        function val = monteCarloMean(R,nSamples)
            % Calculates the sample mean of drawn data
            if nargin < 2 || isempty(nSamples)
                nSamples = 1e3;
            end
            val = mean(draw(R,nSamples));
        end

        function limits = monteCarloPlotLimits(R,nStds,nSamples)
            % Calculate plotting limits
            if nargin < 2 || isempty(nStds)
                nStds = 2;
            end
            if nargin < 3 || isempty(nSamples)
                nSamples = []; % Let the defaults from monteCarloMean and
                               % monteCarloCovariance decide.
            end

            mu = monteCarloMean(R,nSamples);
            C = monteCarloCovariance(R,nSamples);

            minX = min(mu, [], 1)' - nStds*sqrt(diag(C));
            maxX = max(mu, [], 1)' + nStds*sqrt(diag(C));

            limits = zeros(1,2*length(minX));
            limits(1:2:end) = minX;
            limits(2:2:end) = maxX;
        end
    end
    methods (Hidden = true)
        function S = toStructure(obj)
            % toStructure(obj)
            % This default prtRv method adds all properties defined in
            % the class of obj into the structure, that are:
            %   GetAccess: public
            %   Hidden: false
            % other prtRvs (that are properties, contained in cells,
            %   or fields of structures) are also converted to structures.

            MetaInfo = meta.class.fromName(class(obj));

            propNames = {};
            for iProperty = 1:length(MetaInfo.Properties)
                if isequal(MetaInfo.Properties{iProperty}.DefiningClass,MetaInfo) && strcmpi(MetaInfo.Properties{iProperty}.GetAccess,'public') && ~MetaInfo.Properties{iProperty}.Hidden
                    propNames{end+1} = MetaInfo.Properties{iProperty}.Name; %#ok<AGROW>
                end
            end

            S.class = 'prtRv';
            S.prtRvType = class(obj);
            for iProp = 1:length(propNames)
                cProp = obj.(propNames{iProp});
                for icProp = 1:length(cProp) % Allow for arrays of objects
                    cOut = prtUtilFindPrtActionsAndConvertToStructures(cProp(icProp));
                    if icProp == 1
                        cVal = repmat(cOut,size(cProp));
                    else
                        cVal(icProp) = cOut;
                    end
                end
                S.(propNames{iProp}) = cVal;
            end
            S.userData = obj.userData;
        end
    end
end