function DBAddFigure(f,eid,name,comments,parameters,mfiles,varargin)

%DBAddFigure - Save figure in current database.
%
% Save figure as MATLAB fig and PNG image. Also save code used to generate it
% (although not required, installing export_fig will yield better PNG images).
%
%  USAGE
%
%    DBAddFigure(f,eid,name,comments,parameters,mfiles,<options>)
%
%    f              figure handle
%    eid            experiment ID (identifier string)
%    name           descriptive name
%    comments       comment string
%    parameters     figure parameters
%    mfiles         cell array of m-file names (used to generate the figure)
%    <options>      optional list of property-value pairs (see table below)
%
%    =========================================================================
%     Properties    Values
%    -------------------------------------------------------------------------
%     'onlyPNG'     skip fig and only store png capture (use this to avoid
%                   storing very large figures into the database,
%                   default = 'off')
%    =========================================================================
%
%  NOTE
%
%    The pair (eid,name) must uniquely define the figure (they are used as
%    primary keys in the database).
%
%  SEE
%
%    See also DBAddVariable, DBGetFigures, DBExportGallery.
%

% Copyright (C) 2007-2013 by Michaël Zugaro
%
% This program 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.

global dbUser;

% Make sure MyM is installed and functional
CheckMyM;

% Check number of parameters
if nargin < 6,
	error('Incorrect number of parameters (type ''help DBAddFigure'' for details).');
end

% Default values
onlyPNG = 'off';

% Check parameters
if ~ishandle(f),
	error('Incorrect figure handle (type ''help DBAddFigure'' for details).');
end
if ~ischar(eid),
	error('Incorrect EID string (type ''help DBAddFigure'' for details).');
end
if ~ischar(name),
	error('Incorrect figure name (type ''help DBAddFigure'' for details).');
end
if ~isempty(strfind(eid,'/')) || ~isempty(strfind(name,'/')),
	error('EIDs and names should not contain ''/'' (type ''help DBAddFigure'' for details).');
end
if ~ischar(comments),
	error('Incorrect comment string (type ''help DBAddFigure'' for details).');
end
if ~ischar(parameters),
	error('Incorrect figure parameters (type ''help DBAddFigure'' for details).');
end
if ~ischar(mfiles) && ~iscell(mfiles),
	error('Incorrect list of m-files (type ''help DBAddFigure'' for details).');
end
if ischar(mfiles),
	mfiles = {mfiles};
end

% Parse options
for i = 1:2:length(varargin),
	if ~ischar(varargin{i}),
		error(['Parameter ' num2str(i+firstIndex) ' is not a property (type ''help DBAddFigure'' for details).']);
	end
	switch(lower(varargin{i})),
		case 'onlypng',
			onlyPNG = lower(varargin{i+1});
			if ~isstring_FMAT(onlyPNG,'on','off'),
				error('Incorrect value for property ''onlypng'' (type ''help DBAddFigure'' for details).');
			end
		otherwise,
			error(['Unknown property ''' num2str(varargin{i}) ''' (type ''help DBAddFigure'' for details).']);
	end
end

onlyPNG = strcmp(onlyPNG,'on');

basename = tempname;
figName = [basename '.fig'];
pngName = [basename '.png'];
if ~onlyPNG,
	try
		% Create temporary fig file
		saveas(f,figName);
	catch
		error('Could not create temporary file for fig figure.');
	end
end
try
	% Create temporary png file
	if ~isempty(which('export_fig')),
		export_fig(f,pngName,'-png','-a1');
	else
		saveas(f,pngName);
	end
catch
	error('Could not create temporary file for png figure.');
end

% M-Files
for i = 1:length(mfiles),
	mfileName = which(mfiles{i});
	if isempty(mfileName),
		error(['M-File for function ''' mfiles{i} ''' not found.']);
	end
	fid = fopen(mfileName);
	code{i} = fread(fid);
	fclose(fid);
end

% Date and md5
d = datestr(now);
md5 = CalcMD5(pngName);

% Execute SQL query command
if onlyPNG,
	h = mym(['insert into figures (eid,name,comments,parameters,mfiles,code,date,user,md5,png) values ("{S}","{S}","{S}","{S}","{M}","{M}","{S}","{S}","{Si}","{uF}")'],eid,name,comments,parameters,mfiles,code,d,dbUser,md5,pngName);
else
	h = mym(['insert into figures (eid,name,comments,parameters,mfiles,code,date,user,md5,fig,png) values ("{S}","{S}","{S}","{S}","{M}","{M}","{S}","{S}","{Si}","{F}","{uF}")'],eid,name,comments,parameters,mfiles,code,d,dbUser,md5,figName,pngName);
end

% Delete temporary files
if ~onlyPNG,
	delete(figName);
end
delete(pngName);


function []= mdp_silent()

% mdp_silent Ask for running resolution functions of the MDP Toolbox
% in silent mode

% MDPtoolbox: Markov Decision Processes Toolbox
% Copyright (C) 2009  INRA
% Redistribution and use in source and binary forms, with or without modification,
% are permitted provided that the following conditions are met:
%    * Redistributions of source code must retain the above copyright notice,
%      this list of conditions and the following disclaimer.
%    * Redistributions in binary form must reproduce the above copyright notice,
%      this list of conditions and the following disclaimer in the documentation
%      and/or other materials provided with the distribution.
%    * Neither the name of the <ORGANIZATION> nor the names of its contributors
%      may be used to endorse or promote products derived from this software
%      without specific prior written permission.
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
% ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
% WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
% IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
% INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
% DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
% LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
% OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
% OF THE POSSIBILITY OF SUCH DAMAGE.

global mdp_VERBOSE;

mdp_VERBOSE = 0;


% GUI Layout Toolbox
% Version 2.3.4 (R2018b) 31-January-2019
%
% Panels
%   uix.Panel          - arrange a single element inside a standard panel
%   uix.CardPanel      - show one element from a list
%   uix.BoxPanel       - arrange a single element inside a panel with a boxed title
%   uix.TabPanel       - arrange elements in a panel with tabs for selecting which is visible
%   uix.ScrollingPanel - arrange a single element inside a scrollable panel
%
% Boxes
%   uix.HBox           - arrange elements horizontally in a single row
%   uix.VBox           - arrange elements vertically in a single column
%   uix.HBoxFlex       - arrange elements horizontally with draggable dividers
%   uix.VBoxFlex       - arrange elements vertically with draggable dividers
%   uix.HButtonBox     - arrange buttons horizontally in a single row
%   uix.VButtonBox     - arrange buttons vertically in a single column
%
% Grids
%   uix.Grid           - arrange elements in a two-dimensional grid
%   uix.GridFlex       - arrange elements in a two-dimensional grid with draggable dividers
%
% Other
%   uix.Empty          - create an empty space
%   uix.tracking       - track anonymized usage data

%  Copyright 2009-2019 The MathWorks, Inc.
%  $Revision: 1774 $ $Date: 2018-12-06 06:03:23 +0000 (Thu, 06 Dec 2018) $


function frame = getnext(vr)
%FRAME=GETNEXT(VR)
%  This method is a shortcut for
%    if (next(vr))
%      frame = getframe(vr);
%    else
%      frame = [];
%    end
%
%  Although this method can be more convenient than calling NEXT and GETFRAME
%  separately, there is no way to distinguish between a zero-sized frame and
%  reading past the end of the stream.
%
%  Typical usage:
%    vr = videoReader('numbers.uncompressed.avi');
%    info = getinfo(vr);
%    for i=1:info.numFrames
%      img = getnext(vr);
%      imshow(img);
%      pause(1/info.fps);
%    end
%    vr = close(vr);
%
%SEE ALSO
%  videoReader
%  videoReader/getframe
%  videoReader/next
%
%Copyright (c) 2006 Gerald Dalley
%See "MIT.txt" in the installation directory for licensing details (especially
%when using this library on GNU/Linux).

if (next(vr))
  frame = getframe(vr);
else
  frame = [];
end


function save_model_path = mask_train(conf, imdb_train, roidb_train, varargin)
% save_model_path = fast_rcnn_train(conf, imdb_train, roidb_train, varargin)
% --------------------------------------------------------
% Fast R-CNN
% Reimplementation based on Python Fast R-CNN (https://github.com/rbgirshick/fast-rcnn)
% Copyright (c) 2015, Shaoqing Ren
% Licensed under The MIT License [see LICENSE for details]
% --------------------------------------------------------

%% inputs
    ip = inputParser;
    ip.addRequired('conf',                              @isstruct);
    ip.addRequired('imdb_train',                        @iscell);
    ip.addRequired('roidb_train',                       @iscell);
    ip.addParamValue('do_val',          false,          @isscalar);
    ip.addParamValue('imdb_val',        struct(),       @isstruct);
    ip.addParamValue('roidb_val',       struct(),       @isstruct);
    ip.addParamValue('val_iters',       100,            @isscalar);
    ip.addParamValue('val_interval',    400,           @isscalar);
    ip.addParamValue('snapshot_interval',...
                                        2000,          @isscalar);
    ip.addParamValue('solver_def_file', fullfile(pwd, 'models', 'mask_rcnn_prototxts/resnet_50layers_conv', 'solver_30k40k.prototxt'), ...
                                                        @isstr);
    ip.addParamValue('net_file',        fullfile(pwd, 'models', 'mask_rcnn_prototxts/resnet_50layers_conv', 'solver_30k40k.prototxt'), ...
                                                        @isstr);
    ip.addParamValue('cache_name',      'mask_RES50_VOC2007', ...
                                                        @isstr);

    ip.parse(conf, imdb_train, roidb_train, varargin{:});
    opts = ip.Results;

%% try to find trained model
    imdbs_name = cell2mat(cellfun(@(x) x.name, imdb_train, 'UniformOutput', false));
    cache_dir = fullfile(pwd, 'output', 'mask_rcnn_cachedir', opts.cache_name, imdbs_name);
    save_model_path = fullfile(cache_dir, 'final')
    if exist(save_model_path, 'file')
        fprintf('Found existing model\n');
        return;
    end
%% init
    % init caffe solver
    mkdir_if_missing(cache_dir);
    caffe_log_file_base = fullfile(cache_dir, 'caffe_log');
    caffe.init_log(caffe_log_file_base);
    caffe_solver = caffe.Solver(opts.solver_def_file);
    caffe_solver.net.copy_from(opts.net_file);
    % init log
    timestamp = datestr(datevec(now()), 'yyyymmdd_HHMMSS');
    mkdir_if_missing(fullfile(cache_dir, 'log'));
    log_file = fullfile(cache_dir, 'log', ['train_', timestamp, '.txt']);
    diary(log_file);

    % set random seed
    prev_rng = seed_rand(conf.rng_seed);
    caffe.set_random_seed(conf.rng_seed);

    % set gpu/cpu
    if conf.use_gpu
        caffe.set_mode_gpu();
    else
        caffe.set_mode_cpu();
    end
    %disp(conf);
    %disp(opts);
   fprintf('Preparing data\n');
%% making tran/val data
    [image_roidb_train, bbox_means, bbox_stds]...
                            = mask_prepare_image_roidb_voc(conf, opts.imdb_train, opts.roidb_train);

  if opts.do_val
        [image_roidb_val]...
                                = mask_prepare_image_roidb_voc(conf, opts.imdb_val, opts.roidb_val, bbox_means, bbox_stds);
        % fix validation data
        shuffled_inds_val = generate_random_minibatch([], image_roidb_val, conf.ims_per_batch);
        shuffled_inds_val = shuffled_inds_val(randperm(length(shuffled_inds_val), opts.val_iters));
    end
   fprintf('Done\n');
%%  try to train/val with images which have maximum size potentially, to validate whether the gpu memory is enough
    num_classes = size(image_roidb_train(1).overlap, 2);
    fprintf('Checking GPU Memory\n');
    check_gpu_memory(conf, caffe_solver, num_classes, opts.do_val);
    fprintf('Done\n');
%% training
    shuffled_inds = [];
    train_results = [];
    val_results = [];
    iter_ = caffe_solver.iter();
    max_iter = caffe_solver.max_iter();

    while (iter_ < max_iter)
        caffe_solver.net.set_phase('train');
        % generate minibatch training data
        [shuffled_inds, sub_db_inds] = generate_random_minibatch(shuffled_inds, image_roidb_train, conf.ims_per_batch);
        [im_blob, rois_blob, labels_blob, bbox_targets_blob, bbox_loss_weights_blob, mask_targets_blob] = ...
            mask_get_minibatch(conf, image_roidb_train(sub_db_inds));

        net_inputs = {im_blob, rois_blob, labels_blob, bbox_targets_blob, bbox_loss_weights_blob, mask_targets_blob};

        caffe_solver.net.reshape_as_input(net_inputs);

        % one iter SGD update
        caffe_solver.net.set_input_data(net_inputs);
        caffe_solver.step(1);
        rst = caffe_solver.net.get_output();
        train_results = parse_rst(train_results, rst);
        % do valdiation per val_interval iterations
        if ~mod(iter_, opts.val_interval)
            if opts.do_val
                caffe_solver.net.set_phase('test');
                for i = 1:length(shuffled_inds_val)
                    sub_db_inds = shuffled_inds_val{i};
                    [im_blob, rois_blob, labels_blob, bbox_targets_blob, bbox_loss_weights_blob, mask_targets_blob] = ...
                        mask_get_minibatch(conf, image_roidb_val(sub_db_inds));

                    % Reshape net's input blobs
                    net_inputs = {im_blob, rois_blob, labels_blob, bbox_targets_blob, bbox_loss_weights_blob, mask_targets_blob};
                    caffe_solver.net.reshape_as_input(net_inputs);

                    caffe_solver.net.forward(net_inputs);
                    rst = caffe_solver.net.get_output();
                    val_results = parse_rst(val_results, rst);
                end
            end
            show_state(iter_, train_results, val_results);
            train_results = [];
            val_results = [];
            diary; diary; % flush diary
        end

        % snapshot
        if ~mod(iter_, opts.snapshot_interval)
            snapshot(caffe_solver, bbox_means, bbox_stds, cache_dir, sprintf('iter_%d', iter_));
        end
        iter_ = caffe_solver.iter();
    end

    % final snapshot
    snapshot(caffe_solver, bbox_means, bbox_stds, cache_dir, sprintf('iter_%d', iter_));
    save_model_path = snapshot(caffe_solver, bbox_means, bbox_stds, cache_dir, 'final');

    diary off;
    caffe.reset_all();
    rng(prev_rng);
end

function [shuffled_inds, sub_inds] = generate_random_minibatch(shuffled_inds, image_roidb_train, ims_per_batch)

    % shuffle training data per batch
    if isempty(shuffled_inds)
        % make sure each minibatch, only has horizontal images or vertical
        % images, to save gpu memory

        hori_image_inds = arrayfun(@(x) x.im_size(2) >= x.im_size(1), image_roidb_train, 'UniformOutput', true);
        vert_image_inds = ~hori_image_inds;
        hori_image_inds = find(hori_image_inds);
        vert_image_inds = find(vert_image_inds);

        % random perm
        lim = floor(length(hori_image_inds) / ims_per_batch) * ims_per_batch;
        hori_image_inds = hori_image_inds(randperm(length(hori_image_inds), lim));
        lim = floor(length(vert_image_inds) / ims_per_batch) * ims_per_batch;
        vert_image_inds = vert_image_inds(randperm(length(vert_image_inds), lim));

        % combine sample for each ims_per_batch
        hori_image_inds = reshape(hori_image_inds, ims_per_batch, []);
        vert_image_inds = reshape(vert_image_inds, ims_per_batch, []);
        shuffled_inds = [hori_image_inds, vert_image_inds];
        shuffled_inds = shuffled_inds(:, randperm(size(shuffled_inds, 2)));

        shuffled_inds = num2cell(shuffled_inds, 1);
    end

    if nargout > 1
        % generate minibatch training data
        sub_inds = shuffled_inds{1};
        assert(length(sub_inds) == ims_per_batch);
        shuffled_inds(1) = [];
    end
end

function check_gpu_memory(conf, caffe_solver, num_classes, do_val)
%%  try to train/val with images which have maximum size potentially, to validate whether the gpu memory is enough
    % generate pseudo training data with max size
    im_blob = single(zeros(max(conf.scales), conf.max_size, 3, conf.ims_per_batch));
    rois_blob = single(repmat([0; 0; 0; max(conf.scales)-1; conf.max_size-1], 1, conf.batch_size));
    rois_blob = permute(rois_blob, [3, 4, 1, 2]);
    labels_blob = single(ones(conf.batch_size, 1));
    labels_blob = permute(labels_blob, [3, 4, 2, 1]);
    bbox_targets_blob = zeros(4 * (num_classes+1), conf.batch_size, 'single');
    bbox_targets_blob = single(permute(bbox_targets_blob, [3, 4, 1, 2]));
    bbox_loss_weights_blob = bbox_targets_blob;

    mask_targets_blob = zeros(conf.batch_size, num_classes+1, 28, 28, 'single');
    mask_targets_blob(:) = -1;
    mask_targets_blob = single(permute(mask_targets_blob, [4, 3, 2, 1]));

    net_inputs = {im_blob, rois_blob, labels_blob, bbox_targets_blob, bbox_loss_weights_blob, mask_targets_blob};
    % Reshape net's input blobs
    caffe_solver.net.reshape_as_input(net_inputs);
    % one iter SGD update
    caffe_solver.net.set_input_data(net_inputs);
    caffe_solver.step(1);
    if do_val
        % use the same net with train to save memory
        caffe_solver.net.set_phase('test');
        caffe_solver.net.forward(net_inputs);
        caffe_solver.net.set_phase('train');
    end
end

function model_path = snapshot(caffe_solver, bbox_means, bbox_stds, cache_dir, file_name)
    bbox_stds_flatten = reshape(bbox_stds', [], 1);
    bbox_means_flatten = reshape(bbox_means', [], 1);

    % merge bbox_means, bbox_stds into the model
    bbox_pred_layer_name = 'bbox_pred';
    weights = caffe_solver.net.params(bbox_pred_layer_name, 1).get_data();
    biase = caffe_solver.net.params(bbox_pred_layer_name, 2).get_data();
    weights_back = weights;
    biase_back = biase;

    weights = ...
        bsxfun(@times, weights, bbox_stds_flatten'); % weights = weights * stds;
    biase = ...
        biase .* bbox_stds_flatten + bbox_means_flatten; % bias = bias * stds + means;

    caffe_solver.net.set_params_data(bbox_pred_layer_name, 1, weights);
    caffe_solver.net.set_params_data(bbox_pred_layer_name, 2, biase);

    model_path = fullfile(cache_dir, file_name);
    caffe_solver.net.save(model_path);
    fprintf('Saved as %s\n', model_path);

    % restore net to original state
    caffe_solver.net.set_params_data(bbox_pred_layer_name, 1, weights_back);
    caffe_solver.net.set_params_data(bbox_pred_layer_name, 2, biase_back);
end

function show_state(iter, train_results, val_results)
    fprintf('\n------------------------- Iteration %d -------------------------\n', iter);
    fprintf('Training : error %.3g, loss (cls %.3g, reg %.3g, mask %.3g)\n', ...
        1 - mean(train_results.accuarcy.data), ...
        mean(train_results.loss_cls.data), ...
        mean(train_results.loss_bbox.data), ...
        mean(train_results.loss_mask.data));
    if exist('val_results', 'var') && ~isempty(val_results)
        fprintf('Testing  : error %.3g, loss (cls %.3g, reg %.3g, mask %.3g)\n', ...
            1 - mean(val_results.accuarcy.data), ...
            mean(val_results.loss_cls.data), ...
            mean(val_results.loss_bbox.data), ...
            mean(val_results.loss_mask.data));
    end
end


function test_example_bids_emg

% MEM 4gb
% WALLTIME 00:20:00

%% Converting an example EMG dataset for sharing in BIDS
%
% The [BIDS standard](https://bids.neuroimaging.io) does currently not specify how to represent EMG recordings. This example - and the support that is implemented in the **[data2bids](https://github.com/fieldtrip/fieldtrip/blob/release/data2bids.m)** function - should be considered as a preliminary proposal to help researchers with their existing data. This example may also serve to start a discussion on whether and how this data type should be added to the [BIDS specification](http://bids-specification.readthedocs.io/).
%
% EMG is often recorded along with other experiments, such as MEG or functional MRI recordings, but can also be recorded by itself. EMG can for example be used to check compliance with the task, to detect movements and compute reaction times, or to check the activation pattern of specific muscles in a task.
%
% EMG is not part as an individual data type in the BIDS specification. In the **[data2bids](https://github.com/fieldtrip/fieldtrip/blob/release/data2bids.m)** function we are mostly treating it similar to EEG data, with only some differences in the metadata. E.g., the |EEGPlacementScheme|, |CapManufacturer|, and |CapManufacturersModelName| do not apply.  Other than that, we have implemented it the same, with the same data formats and the same way to code events.
%
%% # Example
%
% The example data is available from our [FTP server](ftp://ftp.fieldtriptoolbox.org/pub/fieldtrip/example/bids_emg/)
%
% The example includes the original log files under the “original” directory. It also has a copy of the script to do the conversion under “code”. The reorganized data is under the “bids” directory. According to [the documentation](https://bids-specification.readthedocs.io/en/stable/02-common-principles.html#source-vs-raw-vs-derived-data) the original data can be added to the BIDS dataset under the “sourcedata” directory and code can be added to the “code” directory. This way no information is lost and the conversion/reorganization is fully reproducible.
%
% In general: if your original data is in a different format than the BIDS representation (e.g., DICOMs instead of NIfTI, or data from an EMG system in an unsupported format), you might want to keep the sourcedata, e.g., on a data acquisition collection on the Donders Repository. If it is in the same format (as here), you could simply delete the copy in sourcedata. Your own analyses and the sharing of the data would be based on the BIDS representation.
%
cfg = [];

cfg.InstitutionName             = 'Radboud University';
cfg.InstitutionalDepartmentName = 'Donders Institute for Brain, Cognition and Behaviour';
cfg.InstitutionAddress          = 'Kapittelweg 29, 6525 EN, Nijmegen, The Netherlands';

% required for dataset_description.json
cfg.dataset_description.Name                = 'EMG example';
cfg.dataset_description.BIDSVersion         = 'unofficial extension';

% optional for dataset_description.json
cfg.dataset_description.License             = 'n/a';
cfg.dataset_description.Authors             = 'n/a';
cfg.dataset_description.Acknowledgements    = 'n/a';
cfg.dataset_description.Funding             = 'n/a';
cfg.dataset_description.ReferencesAndLinks  = 'n/a';
cfg.dataset_description.DatasetDOI          = 'n/a';

cfg.method = 'copy'; % the original data is in a BIDS -compliant format and can simply be copied

cfg.bidsroot = fullfile(tempdir, 'bids');  % write to the some scratch directory
cfg.datatype = 'emg';
cfg.sub = 'NT05';

% these are general fields
cfg.Manufacturer           = 'BrainProducts';
cfg.ManufacturersModelName = 'BrainAmp MR plus';

% these are EMG specific fields
cfg.emg.EMGPlacementScheme = 'electrode pairs were placed over various muscles';
cfg.emg.EMGReference       = 'bipolar';
cfg.emg.EMGGround          = 'unclear where the ground electrode was placed on the body';
cfg.emg.EMGChannelCount    = 13; % it might actually be that some channels are recording something else

% there are two recordings of the EMG, during the RS scan and during the GABA scan
% in both EMG recordings the task for the subject was the same

cfg.TaskDescription = 'The subject was lying in the MRI scanner during a resting-state BOLD scan, while EMG was being recorded';
cfg.task = 'resting';
cfg.dataset = dccnpath('/home/common/matlab/fieldtrip/data/ftp/example/bids_emg/original/nt05_EMG_SESS1_RS_RAW.vhdr');
cfg.run = 1;

% write the first EMG recording as run-1
data2bids(cfg);

cfg.TaskDescription = 'The subject was lying in the MRI scanner during a GABA MRS scan, while EMG was being recorded';
cfg.task = 'resting';
cfg.dataset = dccnpath('/home/common/matlab/fieldtrip/data/ftp/example/bids_emg/original/nt05_EMG_SESS1_GABA_RAW.vhdr');
cfg.run = 2;

% write the first EMG recording as run-2
data2bids(cfg);


function z = colon( x, y )
if ~isa( x, 'cvxdual' ),
    z = x; x = y; y = z;
end
global cvx___
try
    duals = cvx___.problems( x.problem_ ).duals;
    q = builtin( 'subsref', duals, x.name_ );
catch
    cvx_throw( 'Internal CVX data corruption. Please CLEAR ALL and rebuild your model.' );
end
if isa( q, 'cvx' ),
    nm = cvx_subs2str( x.name_ );
    cvx_throw( 'Dual variable "%s" has already been assigned.', nm(2:end) );
end
try
    z = cvx_setdual( y, x.name_ );
catch
    cvx_throw( 'Cannot attach a dual variable to an object of type %s.', class( y ) );
end

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


classdef  VideoMaker_TopOpt_densityBridge < VideoMaker_TopOpt
  properties

  end

  methods (Access = public)

        function Make_video_design_variable(obj,output_video_name)
            post = Postprocess_TopOpt_density();
            field2print = post.density_name;
            componentfield = post.density_name_component;
            obj.Make_video_density_field(field2print,componentfield,output_video_name)
        end

        function Make_video_design_variable_reg(obj,output_video_name)
            post = Postprocess_TopOpt_density();
            field2print = post.density_name_reg;
            componentfield = post.density_name_component_reg;
            obj.Make_video_density_field(field2print,componentfield,output_video_name)
        end

  end

  methods (Access = private)
        function Make_video_density_field(obj,field2print,componentfield,output_video_name)
            file_tcl_name = 'tcl_gid.tcl';
            file_list = obj.create_file_list(obj.iterations_to_print,obj.file_name,obj.files_folder);
            [output_video_name] = obj.replace_special_character(output_video_name);
            [output_photo]=obj.replace_special_character(strcat(obj.files_folder,'\',obj.file_name,'.png'));
            [file_list] = obj.replace_special_character(file_list);

            file_tcl_name_with_path = fullfile(obj.files_folder,file_tcl_name);
            file_path_in = fullfile(pwd,'FEM','PostProcess','Make_Video_densityBridge.tcl');
            filepath = obj.replace_special_character(file_path_in);

            fid = fopen(file_tcl_name_with_path,'w+');

            fprintf(fid,'GiD_Process PostProcess \n');
            fprintf(fid,'%s\n',['set arg1 "',file_list,'"']);
            fprintf(fid,'%s\n',['set arg2 "',output_video_name,'"']);
            fprintf(fid,'%s\n',['set arg3 "',field2print,'"']);
            fprintf(fid,'%s\n',['set arg4 "',componentfield,'"']);
            fprintf(fid,'%s\n',['set arg5 "',output_photo,'"']);

            fprintf(fid,'%s\n',['source "',filepath,'"']);
            fprintf(fid,'%s\n',['Make_Video_density $arg1 $arg2 $arg3 $arg4 $arg5']);
            fprintf(fid,'%s\n',['GiD_Process Mescape Quit']);
            fclose(fid);
            obj.execute_tcl_files(obj.gidPath,file_tcl_name_with_path)
        end

    end
end


function db_insert(tablename, s)

% DB_INSERT inserts a structure into a database table. Each field of
% the structure should correspond with one of the fields in the table.
%
% Use as
%   db_insert(tablename, s)

% Copyright (C) 2007, Robert Oostenveld
%
% $Log: db_insert.m,v $
% Revision 1.2  2007/12/03 12:35:24  roboos
% fixed bug when input is double([])
%
% Revision 1.1  2007/11/07 10:50:46  roboos
% created helper functions for easy access to a MySQL database table using a structure for representing the data
%

if isempty(s)
  % the input consists of an empty structure. so nothing to do
  return
end

f  = fieldnames(s);
v = {};
t = {};
l = length(f);
for i=1:l
  v{i} = getfield(s, f{i});
  t{i} = class(v{i});
end

for j=1:numel(s)
  % loop over all elements of a structure array

  cmd = ['INSERT INTO ' tablename ' ( '];

  % these are the fieldnames
  for i=1:l
    cmd = [cmd f{i} ', '];
  end
  cmd = cmd(1:(end-2));  % remove the last ', '
  cmd = [cmd ' ) VALUES ( '];

  % these are the corresponding values
  for i=1:l
    switch t{i}
      case 'char'
        if isempty(v{i})
          cmd = [cmd '""' ];
        else
          cmd = [cmd '"' v{i} '"' ];
        end

      case {'int8', 'int16', 'int32', 'uint8', 'uint16', 'uint32', 'double'}
        if isempty(v{i})
          cmd = [cmd '""' ];
        else
          cmd = [cmd num2str(v{i})];
        end

      otherwise
        ft_error('unsuported data type in structure');
    end
    cmd = [cmd ', '];
  end

  cmd = cmd(1:(end-2));  % remove the last ', '
  cmd = [cmd ' ) ;'];

  % execute the query
  mysql(cmd);

end %for numel(s)


% pop_readegi() - load a EGI EEG file (pop out window if no arguments).
%
% Usage:
%   >> EEG = pop_readegi;             % a window pops up
%   >> EEG = pop_readegi( filename );
%   >> EEG = pop_readegi( filename, datachunks, forceversion, fileloc);
%
% Inputs:
%   filename       - EGI file name
%   datachunks     - desired frame numbers (see readegi() help)
%                    option available from the command line only
%   forceversion   - [integer] force reading a specfic file version
%   fileloc        - [string] channel location file name. Default is
%                    'auto' (autodetection)
%
% Outputs:
%   EEG            - EEGLAB data structure
%
% Author: Arnaud Delorme, CNL / Salk Institute, 12 Nov 2002
%
% See also: eeglab(), readegi(), readegihdr()

% Copyright (C) 12 Nov 2002 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This program 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 2 of the License, or
% (at your option) any later version.
%
% This program 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 program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function [EEG, command] = pop_readegi(filename, datachunks, forceversion, fileloc);

EEG = [];
command = '';
if nargin < 4, fileloc = 'auto'; end;
disp('Warning: This function can only import continuous files or');
disp('         epoch files with only one length for data epochs');

if nargin < 1
    % ask user
    [filename, filepath] = uigetfile('*.RAW;*.raw', ...
        'Choose an EGI RAW file -- pop_readegi()');
    drawnow;
    if filename == 0 return; end;
    filename = [filepath filename];

    fid = fopen(filename, 'rb', 'b');
    if fid == -1, error('Cannot open file'); end
    head = readegihdr(fid); % read EGI file header
    fclose(fid);
    if head.segments ~= 0
        fileloc = '';
        floc = { 'GSN-HydroCel-32.sfp' 'GSN65v2_0.sfp' 'GSN129.sfp' 'GSN-HydroCel-257.sfp'};
        switch head.nchan
            case { 32 33 }, fileloc = floc;
            case { 64 65 }, fileloc =  {floc{2} floc{3:4} floc{1}};
            case { 128 129 }, fileloc = {floc{3} floc{4} floc{1:2}};
            case { 256 257 }, fileloc = {floc{4} floc{1:3}};
        end;
        uilist = { { 'style' 'text' 'string' sprintf('Segment/frame number (default: 1:%d)', head.segments) } ...
                   { 'style' 'edit' 'string' '' } ...
                   { 'style' 'text' 'string' 'Channel location file (in eeglab/sample_locs)' } ...
                   { 'style' 'popupmenu' 'string' fileloc } ...
                   { } ...
                   { 'style' 'text' 'string' ...
                   [ 'Note: Choosing the correct electrode location file for your data is critical.' 10 ...
        'Note that in some cases none of the channel location files listed will correspond' 10 ...
        'to your montage as EGI has different versions of caps and is creating new ones' 10 ...
        'constantly. Remember to check your montage in the channel editor and import. Channel' 10 ...
        'location files are stored in the sample_locs sub-folder of the EEGLAB distribution.' ] } };
        uigeometry = { [2 1] [2 1] [1] [1] };
        uigeomvert = [1 1 1.5 3];
        result = inputgui('uilist', uilist, 'geometry', uigeometry, 'geomvert', uigeomvert);

%         promptstr    = { sprintf('Segment/frame number (default: 1:%d)', head.segments) 'Channel location file (in eeglab/sample_locs)' };
%         inistr       = { '' fileloc(res{2})};
%         result       = inputdlg2( promptstr, 'Import EGI file -- pop_readegi()', 1,  inistr, 'pop_readegi');
        if length(result) == 0 return; end;
        datachunks   = eval( [ '['  result{1} ']' ] );
        fileloc      = char(fileloc(result{2}));
    else
        datachunks   = [];
        disp('Only one segment, cannot read portion of the file');
    end;
end;

% load data
% ----------
EEG = eeg_emptyset;
if exist('datachunks') && exist('forceversion') && ~isempty(forceversion)
    [Head EEG.data Eventdata SegCatIndex] = readegi( filename, datachunks,forceversion);
elseif exist('forceversion') && ~isempty(forceversion)
    [Head EEG.data Eventdata SegCatIndex] = readegi( filename,[],forceversion);
elseif exist('datachunks')
    [Head EEG.data Eventdata SegCatIndex] = readegi( filename, datachunks);
    forceversion = [];
else
    [Head EEG.data Eventdata SegCatIndex] = readegi( filename);
    forceversion = [];
end
if ~isempty(Eventdata) & size(Eventdata,2) == size(EEG.data,2)
    EEG.data(end+1:end+size(Eventdata,1),:) = Eventdata;
end;
EEG.comments        = [ 'Original file: ' filename ];
EEG.setname 		= 'EGI file';
EEG.nbchan          = size(EEG.data,1);
EEG.srate           = Head.samp_rate;
EEG.trials          = Head.segments;
EEG.pnts            = Head.segsamps;
EEG.xmin            = 0;

% importing the events
% --------------------
EEG = eeg_checkset(EEG);
if ~isempty(Eventdata)
    orinbchans = EEG.nbchan;
    for index = size(Eventdata,1):-1:1
        EEG = pop_chanevent( EEG, orinbchans-size(Eventdata,1)+index, 'edge', 'leading', ...
            'delevent', 'off', 'typename', Head.eventcode(index,:), ...
            'nbtype', 1, 'delchan', 'on');
        Head.eventcode(end,:) = [];
    end;

    % renaming event codes
    % --------------------
    try,
        tmpevent = EEG.event;
        alltypes = { tmpevent.type };
        if isstr(alltypes{1})
            indepoc = strmatch('epoc', lower(alltypes), 'exact');
            indtim  = strmatch('tim0', lower(alltypes), 'exact');

            % if epoc but no tim0 then epoc represent pauses in recording
            if isempty(indtim) & ~isempty(indepoc)
                for index = indepoc
                    EEG.event(index).type = 'boundary';
                end;
            end;
            % other wise if both non-empty data epochs
            if ~isempty(indtim) & ~isempty(indepoc)
                if rem(size(EEG.data,2) / (length(indepoc)+1),1) == 0
                    EEG.event(index) = []; % remove epoch events
                    EEG.trials       = length(indepoc)+1;
                else
                    disp('Warning: data epochs detected but wrong data size');
                end;
            end;
        end;
    catch, disp('Warning: event renaming failed'); end;
end;

% adding segment category indices
% -------------------------------
if ~isempty(SegCatIndex) && EEG.trials > 1
    try
        if ~isempty(EEG.event)
            for index = 1:length(EEG.event)
                EEG.event(index).category = Head.catname{SegCatIndex(EEG.event(index).epoch)};
            end;
        else % create time-locking events
            for trial = 1:EEG.trials
                EEG.event(trial).epoch    = trial;
                EEG.event(trial).type     = 'TLE';
                EEG.event(trial).latency  = -EEG.xmin*EEG.srate+1+(trial-1)*EEG.pnts;
                EEG.event(trial).category = Head.catname{SegCatIndex(trial)};
            end;
        end;
    catch,
        disp('Warning: error while importing trial categories');
        EEG.event = rmfield(EEG.event, 'category');
    end;
end;
EEG = eeg_checkset(EEG, 'makeur');
EEG = eeg_checkset(EEG, 'eventconsistency');

% importing channel locations
% ---------------------------
if nargin < 1
    warndlg2( [ 'EEGLAB will now import a default electrode location file' 10 ...
        'for your data. Note that this might not correspond' 10 ...
        'to your montage as EGI has different versions of caps.' 10 ...
        'Check your montage in the channel editor and import' 10 ...
        'the correct location file if necessary.' ]);
end;
if all(EEG.data(end,1:10) == 0)
    disp('Deleting empty data reference channel (reference channel location is retained)');
    EEG.data(end,:)   = [];
    EEG.nbchan        = size(EEG.data,1);
    EEG = eeg_checkset(EEG);
end;
if ~isempty(fileloc)
    if strcmpi(fileloc, 'auto')
        EEG = readegilocs(EEG);
    else
        EEG = readegilocs(EEG, fileloc);
    end;
end;

if nargin < 1
    command = sprintf('EEG = pop_readegi(''%s'', %s);', filename, vararg2str({datachunks forceversion fileloc }) );
end;

return;


function [mNewCatalog] = bc_SelectMechanism_Start(mCatalog)

% Default return value
mNewCatalog = nan;

% Invoke the user interface
hDialog = bc_SelectMechanism_Dialog;

% Analyze Output
if ~ishandle(hDialog)
  answer = 0;
else
  handles = guidata(hDialog);
  answer = handles.answer;
  % OK pressed
  if answer == 1
    % Get the user options
    nType = get(handles.cboMechanism, 'Value');
    fAngle = str2double(get(handles.txtAngle, 'String'));
    % Remove figure from memory
    delete(hDialog);
    % Create the new catalog
    [mNewCatalog] = bc_SelectMechanism(mCatalog, nType, fAngle);
  else
    % Remove figure from memory
    delete(hDialog);
  end
end


function [celBodyData] = processINIBodyInfo(celBodyDataFromINI, varargin)
%processINIBodyInfo Summary of this function goes here
%   Detailed explanation goes here
    clear findRow

    if(length(varargin)>=1)
        showWaitbar = varargin{1};

        if(length(varargin)>=2)
            dataType = varargin{2};

            if(length(varargin) >= 3)
                hFig = varargin{3};
            else
                hFig = [];
            end
        else
            dataType = 'bodyInfo';
            hFig = [];
        end
    else
        showWaitbar = true;
        dataType = 'bodyInfo';
        hFig = [];
    end

    if(showWaitbar)
        if(not(isempty(hFig)))
            hWaitbar = uiprogressdlg(hFig,'Message','Loading bodies file, please wait...', 'Title','KSP Trajectory Optimizatoon Tool');
        else
            hWaitbar = waitbar(0,'Loading bodies file, please wait...');
        end
    end

    celBodyData = struct();
    for(i=1:size(celBodyDataFromINI,1)) %#ok<*NO4LP>
        row = celBodyDataFromINI(i,:);
        row{1} = lower(matlab.lang.makeValidName(row{1}));
        row{3} = lower(matlab.lang.makeValidName(row{3}));

        if(~isfield(celBodyData,row{1}))
%             celBodyData.(row{1}) = struct();
            celBodyData.(row{1}) = getNewObjForDataType(dataType);
        end

        if(strcmpi(row{3}, 'atmoPressAlts'))
            celBodyData = createCurveFitFromRows(celBodyDataFromINI, row{1}, 'atmoPressAlts', 'atmoPressPresses', 'atmoPressCurve', celBodyData);

        elseif(strcmpi(row{3}, 'atmoTempAlts'))
            celBodyData = createCurveFitFromRows(celBodyDataFromINI, row{1}, 'atmoTempAlts', 'atmoTempTemps', 'atmoTempCurve', celBodyData);

        elseif(strcmpi(row{3}, 'atmoTempSunMultAlts'))
            celBodyData = createCurveFitFromRows(celBodyDataFromINI, row{1}, 'atmoTempSunMultAlts', 'atmoTempSunMults', 'atmoTempSunMultCurve', celBodyData);

        elseif(strcmpi(row{3}, 'latTempBiasLats'))
            celBodyData = createCurveFitFromRows(celBodyDataFromINI, row{1}, 'latTempBiasLats', 'latTempBiases', 'latTempBiasCurve', celBodyData);

        elseif(strcmpi(row{3}, 'latTempSunMultLats'))
            celBodyData = createCurveFitFromRows(celBodyDataFromINI, row{1}, 'latTempSunMultLats', 'latTempSunMults', 'latTempSunMultCurve', celBodyData);

        elseif(strcmpi(row{3}, 'axialtemperaturesunbiasdeg'))
           celBodyData = createCurveFitFromRows(celBodyDataFromINI, row{1}, 'axialtemperaturesunbiasdeg', 'axialtemperaturesunbiases', 'axialTempSunBiasCurve', celBodyData);

        elseif(strcmpi(row{3}, 'axialtemperaturesunmultlats'))
            celBodyData = createCurveFitFromRows(celBodyDataFromINI, row{1}, 'axialtemperaturesunmultlats', 'axialtemperaturesunmults', 'axialTempSunMultCurve', celBodyData);

        elseif(strcmpi(row{3}, 'eccentricitytemperaturebiaspts'))
            celBodyData = createCurveFitFromRows(celBodyDataFromINI, row{1}, 'eccentricitytemperaturebiaspts', 'eccentricitytemperaturebiases', 'eccTempBiasCurve', celBodyData);

        elseif(any(strcmpi(row{3}, {'atmoPressPresses', 'atmoTempTemps', 'atmoTempSunMults', 'latTempBiases', 'latTempSunMults', 'axialtemperaturesunbiases', 'axialtemperaturesunmults', 'eccentricitytemperaturebiases'})))
            continue;
        else
            if(~checkStrIsNumeric(row{4}))
                entry = row{4};
            else
                entry = str2double(row{4});
            end

            if((strcmpi(row{3},'name') || strcmpi(row{3},'parent')) && ischar(entry))
                entry = matlab.lang.makeValidName(entry);
            end

            if(isfield(celBodyData,row{1}))
                celBodyData.(row{1}).(row{3}) = entry;
            else
                celBodyData.(row{1}) = struct();
                celBodyData.(row{1}) = getNewObjForDataType(dataType);
                celBodyData.(row{1}).(row{3}) = entry;
            end
        end

        if(showWaitbar)
            waitbarValue = i/size(celBodyDataFromINI,1);
            waitbarMsg = sprintf('Loading bodies file, please wait... [%u/%u]', i, size(celBodyDataFromINI,1));

            if(not(isempty(hFig)))
                hWaitbar.Value = waitbarValue;
                hWaitbar.Message = waitbarMsg;
            else
                waitbar(waitbarValue, hWaitbar, waitbarMsg);
            end
        end
    end

    if(strcmpi(dataType,'bodyInfo'))
        names = fieldnames(celBodyData);
        for(i=1:length(names))
            name = names{i};
            celBodyData.(name).celBodyData = celBodyData;
            [~] = celBodyData.(name).getParBodyInfo(celBodyData); %set that parent info now so that we don't have to handle it later
            [~] = celBodyData.(name).getChildrenBodyInfo(celBodyData);

            celBodyData.(name).setPropTypeEnum();
            celBodyData.(name).setBaseBodySurfaceTexture();
        end
    end

    if(showWaitbar)
        close(hWaitbar);
    end

    return;
end

function celBodyData = createCurveFitFromRows(celBodyDataFromINI, bodyName, indVarRow, depVarRow, celBodyFieldName, celBodyData)
    indRow = findRow(celBodyDataFromINI, bodyName, indVarRow);
    depRow = findRow(celBodyDataFromINI, bodyName, depVarRow);

    indVar = str2double(strsplit(indRow{4},','));
    indVar = reshape(indVar, length(indVar), 1);

    depVar = str2double(strsplit(depRow{4},','));
    depVar = reshape(depVar, length(depVar), 1);

    if(length(indVar) > 1 && length(depVar) > 1)
        fitobject = griddedInterpolant(indVar,depVar,'linear', 'nearest');
%         fitobject = fit(indVar,depVar,'smoothingspline');
%         fitobject = @(xi) interp1qr(indVar,depVar,xi);
    elseif(length(indVar) == 1 && length(depVar) == 1)
        fitobject = griddedInterpolant([indVar(1) indVar(1)+1]',[depVar(1) depVar(1)]','linear', 'nearest');
%         fitobject = fit([indVar(1) indVar(1)+1]',[depVar(1) depVar(1)]','smoothingspline');
%         fitobject = @(xi) interp1qr([indVar(1) indVar(1)+1]',[depVar(1) depVar(1)]',xi);
    else
        fitobject = griddedInterpolant([0 1]',[0 0]','linear', 'nearest');
%         fitobject = fit([0 1]',[0 0]','smoothingspline');
%         fitobject = @(xi) interp1qr([0 1]',[0 0]',xi);
    end

    celBodyData.(bodyName).(lower(celBodyFieldName)) = fitobject;
end

function row = findRow(celBodyDataFromINI, col1, col3)
    persistent celBodyDataFromINICol1
    if(isempty(celBodyDataFromINICol1) || size(celBodyDataFromINI,1) ~= length(celBodyDataFromINICol1))
        celBodyDataFromINICol1 = matlab.lang.makeValidName(celBodyDataFromINI(:,1));
    end

    row = celBodyDataFromINI(strcmpi(col1,celBodyDataFromINICol1) & strcmpi(col3,celBodyDataFromINI(:,3)), :);
end

function obj = getNewObjForDataType(dataType)
    switch dataType
        case 'bodyInfo'
            obj = KSPTOT_BodyInfo();
        case 'appOptions'
            obj = KSPTOT_AppOptions();
        otherwise
            error('Unknown data type %s in processINIBodyInfo().', dataType);
    end
end


function dispfrac(mode)
% DISPFRAC Display terms in laplacian format.
%          DISPFRAC displays the current terms in fraction format.

% Author: Craig Borghesani
% Date: 8/23/94
% Revised: 10/18/94
% Copyright (c) 1999, Prentice-Hall

% obtain handle information
f=gcf;
ui_data     = get(f,'userdata');
ui_han      = ui_data{1};
ui_obj      = ui_data{2};
%popup       = ui_han(1);
popup       = ui_obj.SysUI(5);
term_axis   = ui_han(10);
plant       = ui_han(30);
for_cont    = ui_han(31);
bac_cont    = ui_han(32);
set_to_one1 = ui_han(33);
set_to_one2 = ui_han(34);
cont_type   = ui_han(35);
num_den     = ui_han(36);
pid_1       = ui_han(37);
pid_2       = ui_han(38);
component   = ui_han(44);
open_loop   = ui_han(45);
closed_loop = ui_han(46);
factored    = ui_han(47);
coefficient = ui_han(48);
inverse     = ui_han(49);
neg_loc     = ui_han(68);
cur_sys     = get(ui_han(30),'userdata');
cur_page    = get(ui_han(31),'userdata');
sys_state   = get(ui_han(33),'userdata');
page_setup  = get(ui_han(34),'userdata');
stat_bar    = get(ui_han(43),'userdata');
lab_txt     = get(ui_han(44),'userdata');
ers = 'norm';
fontname = 'times';

% define various shades of grey
grey = get(0,'defaultuicontrolbackground');
ltgrey = [0.5,0.5,0.5]*1.5;
dkgrey = [0.5,0.5,0.5]*0.5;

if nargin == 0, mode = 0; end

% update checked properties of menu items
if mode,
 if any(abs(mode) == [1,2,3]), % switching systems

  if cur_sys == mode, return; end

  eraser1 = ui_obj.eraser1;
  tab_uis = ui_obj.SysTabs;

   %sel_dims = [-3,0,+6,+2];
   %unsel_dims = [3,0,-6,-2];

  sel_dims = [0,0,0,+2];
  unsel_dims = [0,0,0,-2];

  sel_tab = findobj(f,'tag','selected_tab1');
  cur_obj = tab_uis(abs(mode));
  if mode > 0 & sel_tab == cur_obj, return; end

  if length(sel_tab),
     tab_pos = get(sel_tab,'pos');
     set(sel_tab,'pos',tab_pos+unsel_dims,'tag','',...
                 'back',ltgrey);
  end

  cur_pos = get(cur_obj,'pos');
  set(cur_obj,'pos',cur_pos+sel_dims,'tag','selected_tab1',...
              'back',grey);
  eraser_pos = cur_pos+sel_dims;
  set(eraser1,'pos',[eraser_pos(1:3)+[2,0,-4],2]);

  set(ui_han(25+cur_sys),'checked','off');
  set(ui_han(25+abs(mode)),'checked','on');
  cur_sys = abs(mode);
  set(ui_han(30),'userdata',cur_sys);
  set(lab_txt(3),'callback',['dispfrac(',int2str(rem(cur_sys,3)+1),')'],...
                 'string',['System ',int2str(cur_sys),' Info']);

% restore settings for system
% Plant option
  if sys_state(1,cur_sys),
   popup_str = ['Gain|Integrator|Differentiator|Real Pole|Real Zero|',...
      'Complex Pole|Complex Zero|Lead/Lag|Num/Den|Delay Time|Design Point'];
   set(popup,'string',popup_str,'callback','termmang(0,1,1)');
   set(plant,'checked','on','enable','on');
   set(cont_type,'enable','off');
   set([for_cont,bac_cont],'checked','off');
   set(ui_obj.SysUI(1),'value',1);
   set(ui_obj.SysUI(2:3),'value',0);
   set(lab_txt(1),'callback','dispfrac(5)');
   loc_type = 1;

% set to one option
   set(set_to_one1,'label',['Set G(s) = 1']);
   set(set_to_one2,'label',['Set H(s) = 1']);
   if sys_state(4,cur_sys),
    set(set_to_one1,'checked','on');
    set(for_cont,'enable','off');
   else
    set(set_to_one1,'checked','off');
    set(for_cont,'enable','on');
   end
   if sys_state(5,cur_sys),
    set(set_to_one2,'checked','on');
    set(bac_cont,'enable','off');
   else
    set(set_to_one2,'checked','off');
    set(bac_cont,'enable','on');
   end
  end

% Forward Controller option
  if sys_state(2,cur_sys),
   set(for_cont,'checked','on','enable','on');
   set([plant,bac_cont],'checked','off');
   set(ui_obj.SysUI(2),'value',1);
   set(ui_obj.SysUI([1,3]),'value',0);
   set(cont_type,'enable','on');
   set(lab_txt(1),'callback','dispfrac(6)');

% set to one option
   set(set_to_one1,'label',['Set P(s) = 1']);
   set(set_to_one2,'label',['Set H(s) = 1']);
   if sys_state(4,cur_sys),
    set(set_to_one1,'checked','on');
    set(plant,'enable','off');
   else
    set(set_to_one1,'checked','off');
    set(plant,'enable','on');
   end
   if sys_state(5,cur_sys),
    set(set_to_one2,'checked','on');
    set(bac_cont,'enable','off');
   else
    set(set_to_one2,'checked','off');
    set(bac_cont,'enable','on');
   end

% what type of forward controller
   loc_type = find(sys_state(6:8,cur_sys)==1);
   set(ui_han(36:38),'checked','off');
   set(ui_han(35+loc_type),'checked','on');

   if loc_type == 1,
    popup_str = ['Gain|Integrator|Differentiator|Real Pole|Real Zero|',...
      'Complex Pole|Complex Zero|Lead/Lag|Num/Den|Delay Time|Design Point'];
    set(popup,'string',popup_str,'callback','termmang(0,1,1)');
   else
    popup_str = ['Proportional Gain|Integral Gain|Derivative Gain|Design Poin'];
    set(popup,'string',popup_str,'callback','pidmang(0,1)');
   end

  end

% Feedback Controller option
  if sys_state(3,cur_sys),
   set(bac_cont,'checked','on','enable','on');
   set([plant,for_cont],'checked','off');
   set(cont_type,'enable','on');
   set(ui_obj.SysUI(3),'value',1);
   set(ui_obj.SysUI(1:2),'value',0);
   set(lab_txt(1),'callback','dispfrac(6)');

% set to one option
   set(set_to_one1,'label',['Set P(s) = 1']);
   set(set_to_one2,'label',['Set G(s) = 1']);
   if sys_state(4,cur_sys),
    set(set_to_one1,'checked','on');
    set(plant,'enable','off');
   else
    set(set_to_one1,'checked','off');
    set(plant,'enable','on');
   end
   if sys_state(5,cur_sys),
    set(set_to_one2,'checked','on');
    set(for_cont,'enable','off');
   else
    set(set_to_one2,'checked','off');
    set(for_cont,'enable','on');
   end

% what type of feedback controller
   loc_type = find(sys_state(9:11,cur_sys)==1);
   set(ui_han(36:38),'checked','off');
   set(ui_han(35+loc_type),'checked','on');

   if loc_type == 1,
    popup_str = ['Gain|Integrator|Differentiator|Real Pole|Real Zero|',...
      'Complex Pole|Complex Zero|Lead/Lag|Num/Den|Delay Time|Design Point'];
    set(popup,'string',popup_str,'callback','termmang(0,1,1)');
   else
    popup_str = ['Proportional Gain|Integral Gain|Derivative Gain|Design Poin'];
    set(popup,'string',popup_str,'callback','pidmang(0,1)');
   end

  end

  if loc_type == 1,
   termmang(1,2,1);
  else
   pidmang(1,2)
  end

% clear root locus storage
  set(ui_han([37,69:75]),'userdata',[]);

  pageplot(0,13);

 elseif mode == 4, % switching to plant
  if strcmp(get(plant,'enable'),'off'),
   dispfrac(5);
   return
  end
  set(stat_bar,'string',['Switching to Plant ',int2str(cur_sys),' transfer function']);
  set(lab_txt(1),'callback','dispfrac(5)');
  set(plant,'checked','on');
  set([for_cont,bac_cont],'checked','off');
  set(ui_obj.SysUI(1),'value',1);
  set(ui_obj.SysUI(2:3),'value',0);

  set(set_to_one1,'label',['Set G(s) = 1']);
  set(set_to_one2,'label',['Set H(s) = 1']);

  if strcmp(get(for_cont,'enable'),'off'),
   set(set_to_one1,'checked','on');
   temp1 = get(ui_han(12+cur_sys*2-1),'userdata');
   temp2 = get(ui_han(12+cur_sys*2),'userdata');
   set(ui_han(12+cur_sys*2-1),'userdata',temp2);
   set(ui_han(12+cur_sys*2),'userdata',temp1);
  end

  if strcmp(get(bac_cont,'enable'),'off'),
   set(set_to_one2,'checked','on');
  end

  set(cont_type,'enable','off');
  popup_str = ['Gain|Integrator|Differentiator|Real Pole|Real Zero|',...
            'Complex Pole|Complex Zero|Lead/Lag|Num/Den|Delay Time|Design Point'];
  set(popup,'string',popup_str,'callback','termmang(0,1,1)');
  termmang(1,2,1)

% update sys_state matrix
  sys_state(2:3,cur_sys) = [0;0];
  sys_state(1,cur_sys) = 1;

% need to update gain plots because of transfer function change
  pageplot(4,[]);

 elseif mode == 5, % switching to forward controller
  if strcmp(get(for_cont,'enable'),'off'),
   dispfrac(6);
   return
  end
  set(stat_bar,'string',['Switching to Forward Controller ',int2str(cur_sys),' transfer function']);
  set(lab_txt(1),'callback','dispfrac(6)');
  set(for_cont,'checked','on');
  set([plant,bac_cont],'checked','off');
  set(ui_obj.SysUI(2),'value',1);
  set(ui_obj.SysUI([1,3]),'value',0);

  set(set_to_one1,'label',['Set P(s) = 1']);
  set(set_to_one2,'label',['Set H(s) = 1']);

  if strcmp(get(plant,'enable'),'off'),
   set(set_to_one1,'checked','on');
  end
  if strcmp(get(bac_cont,'enable'),'off'),
   set(set_to_one2,'checked','on');
  end

  set(cont_type,'enable','on');

% what type of forward controller
  loc_type = find(sys_state(6:8,cur_sys)==1);
  set(ui_han(36:38),'checked','off');
  set(ui_han(35+loc_type),'checked','on');

  if strcmp(get(num_den,'checked'),'on'),
   popup_str = ['Gain|Integrator|Differentiator|Real Pole|Real Zero|',...
     'Complex Pole|Complex Zero|Lead/Lag|Num/Den|Delay Time|Design Point'];
   set(popup,'string',popup_str,'callback','termmang(0,1,1)');
   termmang(1,2,1)
  else
   popup_str = ['Proportional Gain|Integral Gain|Derivative Gain|Design Point'];
   set(popup,'string',popup_str,'callback','pidmang(0,1)');
   pidmang(1,2)
  end

% update sys_state matrix
  sys_state([1,3],cur_sys) = [0;0];
  sys_state(2,cur_sys) = 1;

% need to update gain plots because of transfer function change
  pageplot(4,[]);

 elseif mode == 6, % switching to feedback controller
  if strcmp(get(bac_cont,'enable'),'off'),
   dispfrac(4);
   return
  end
  set(stat_bar,'string',['Switching to Feedback Controller ',int2str(cur_sys),' transfer function']);
  set(lab_txt(1),'callback','dispfrac(4)');
  set(bac_cont,'checked','on');
  set([plant,for_cont],'checked','off');
  set(ui_obj.SysUI(3),'value',1);
  set(ui_obj.SysUI(1:2),'value',0);

  set(set_to_one1,'label',['Set P(s) = 1']);
  set(set_to_one2,'label',['Set G(s) = 1']);

  if strcmp(get(plant,'enable'),'off'),
   set(set_to_one1,'checked','on');
  end
  if strcmp(get(for_cont,'enable'),'off'),
   set(set_to_one2,'checked','on');
   temp1 = get(ui_han(12+cur_sys*2-1),'userdata');
   temp2 = get(ui_han(12+cur_sys*2),'userdata');
   set(ui_han(12+cur_sys*2-1),'userdata',temp2);
   set(ui_han(12+cur_sys*2),'userdata',temp1);
  end

  set(cont_type,'enable','on');

% what type of feedback controller
  loc_type = find(sys_state(9:11,cur_sys)==1);
  set(ui_han(36:38),'checked','off');
  set(ui_han(35+loc_type),'checked','on');

  if strcmp(get(num_den,'checked'),'on'),
   popup_str = ['Gain|Integrator|Differentiator|Real Pole|Real Zero|',...
     'Complex Pole|Complex Zero|Lead/Lag|Num/Den|Delay Time|Design Point'];
   set(popup,'string',popup_str,'callback','termmang(0,1,1)');
   termmang(1,2,1)
  else
   popup_str = ['Proportional Gain|Integral Gain|Derivative Gain|Design Point'];
   set(popup,'string',popup_str,'callback','pidmang(0,1)');
   pidmang(1,2)
  end

% update sys_state matrix
  sys_state(1:2,cur_sys) = [0;0];
  sys_state(3,cur_sys) = 1;

% need to update gain plots because of transfer function change
  pageplot(4,[]);

 elseif mode == 7, % component
  set(stat_bar,'string','Displaying individual transfer function');
  set(ui_han([45:46]),'checked','off')
  set(component,'checked','on');

 elseif mode == 8, % open-loop
  set(stat_bar,'string','Displaying open-loop transfer function');
  set(ui_han([44,46]),'checked','off')
  set(open_loop,'checked','on');

 elseif mode == 9, % closed-loop
  set(stat_bar,'string','Displaying closed-loop transfer function');
  set(ui_han([44:45]),'checked','off');
  set(closed_loop,'checked','on');

 elseif mode == 10, % factored
  set(stat_bar,'string','Displaying pole-zero factored form');
  set(ui_han([48:49]),'checked','off');
  set(factored,'checked','on');

 elseif mode == 11, % coefficient
  set(stat_bar,'string','Displaying polynomial form');
  set(ui_han([47,49]),'checked','off');
  set(coefficient,'checked','on');

 elseif mode == 12, % inverse laplace transform
  set(stat_bar,'string','Displaying inverse Laplace form');
  set(ui_han([47:48]),'checked','off');
  set(inverse,'checked','on');

 end
 set(ui_han(33),'userdata',sys_state);

end

% determine states of display

% which component is displayed
if strcmp(get(plant,'checked'),'on'), mode1 = 1;
elseif strcmp(get(for_cont,'checked'),'on'), mode1 = 2;
else mode1 = 3; end

% what type of controller is displayed
if strcmp(get(num_den,'checked'),'on'), mode2 = 1;
elseif strcmp(get(pid_1,'checked'),'on'), mode2 = 2;
else mode2 = 3; end

% what configuration is desired
if strcmp(get(component,'checked'),'on'), mode3 = 1;
elseif strcmp(get(open_loop,'checked'),'on'), mode3 = 2;
else mode3 = 3; end

% what form is desired
if strcmp(get(factored,'checked'),'on'), mode4 = 1;
elseif strcmp(get(coefficient,'checked'),'on'), mode4 = 2;
else mode4 = 3; end

if mode1 == 1,
 set(lab_txt(1),'string',['Plant ',int2str(cur_sys),' Entry']);
elseif mode1 == 2,
 set(lab_txt(1),'string',['Forward ',int2str(cur_sys),' Entry']);
else
 set(lab_txt(1),'string',['Feedback ',int2str(cur_sys),' Entry']);
end

plant_mat = get(ui_han(3+cur_sys),'userdata');
for_mat = get(ui_han(6+cur_sys),'userdata');
bac_mat = get(ui_han(9+cur_sys),'userdata');

if mode3 == 1,

 if mode1 == 1,
  tf_str = ['P',int2str(cur_sys)];
  term_mat = plant_mat;
 elseif mode1 == 2,
  tf_str = ['G',int2str(cur_sys)];
  term_mat = for_mat;
 else
  tf_str = ['H',int2str(cur_sys)];
  term_mat = bac_mat;
 end

elseif mode3 == 2,

 tf_str = ['GPH',int2str(cur_sys)];
 term_mat = termjoin(plant_mat,for_mat,bac_mat);

else

 if any(mode == [4:6]), return; end
 tf_str = ['CL',int2str(cur_sys)];
 [nump,denp] = termextr(plant_mat);
 [numg,deng] = termextr(for_mat);
 [numh,denh] = termextr(bac_mat);
 neg_locus = strcmp(get(neg_loc,'checked'),'on');
 numcl = conv(conv(nump,numg),denh);
 num = conv(conv(nump,numg),numh);
 den = conv(conv(denp,deng),denh);
 ln = length(num); ld = length(den);
 num = [zeros(1,ld-ln),num];
 den = [zeros(1,ln-ld),den];
 dencl = den + num;
 term_mat = termpars(numcl,dencl);

end

if mode4 < 3 , tf_str = [tf_str,'(s)='];
else tf_str = [tf_str,'(t)=']; end

if mode1 > 1 & mode2 > 1 & mode3 == 1, % pid controller
 if mode4 > 1,
  if term_mat(4) == 40, term_mat = pid2pid(term_mat,1); end
  term_mat = termpars(term_mat([3,1,2]),[1,0]);
 end
end

% destroy present transfer function
axes(term_axis);
cla;

line_yloc = 0.5;
T = [];
txt = text(0,0.5,tf_str,'erase',ers,'horizontalalignment','left',...
        'verticalalignment','middle','fontname',fontname,'color','k');
tf_ext = get(txt,'extent');

% initial locations of text for the numerator and denominator
num_btm = line_yloc+0.01;
den_btm = line_yloc-tf_ext(4)-0.01;
txt_lft = sum(tf_ext([1,3]))+0.01;
term_val = [1:8];

% mode1 - transfer function
% mode2 - controller type
% mode3 - component, open-loop, closed-loop
% mode4 - factored, coefficient, inverse laplace

if mode4 == 1,
 if mode1 > 1 & mode2 == 2 & mode3 == 1, % pid form #1
  p_gain = num2str(term_mat(1));
  i_gain = num2str(term_mat(2));
  d_gain = num2str(term_mat(3));
  txt = text(txt_lft,0.5,[p_gain,' + '],'erase',ers,...
            'horizontalalignment','left','verticalalignment','middle',...
            'userdata',[1,0],'fontname',fontname,...
            'tag','0','color','k');
%            'buttondownfcn','pagemous(0)');
  txt_ext = get(txt,'extent');
  txt_lft = txt_lft+txt_ext(3);
  txt = text(txt_lft,num_btm,i_gain,'erase',ers,...
            'horizontalalignment','left','verticalalignment','bottom',...
            'userdata',[2,0],'fontname',fontname,...
            'tag','0','color','k');
%            'buttondownfcn','pagemous(0)');
  txt_ext = get(txt,'extent');
  new_lft = txt_lft+txt_ext(3);
  lin_lft = txt_lft; lin_rht = new_lft;
  lin = line([lin_lft,lin_rht],[line_yloc,line_yloc],'erase',ers,'color','k');
  txt_mid = txt_lft + (lin_rht-lin_lft)/2;
  txt = text(txt_mid,den_btm,'s','erase',ers,...
           'horizontalalignment','center','verticalalignment','bottom',...
           'userdata',[2,0],'fontname',fontname,...
           'tag','0','color','k');
%           'buttondownfcn','pagemous(0)');
  text(new_lft,0.5,[' + ',d_gain,'s'],'erase',ers,...
            'horizontalalignment','left','verticalalignment','middle',...
            'userdata',[3,0],'fontname',fontname,...
            'tag','0','color','k');
%            'buttondownfcn','pagemous(0)');

 elseif mode1 > 1 & mode2 == 3 & mode3 == 1, % pid form #2

  p_gain = num2str(term_mat(1));
  i_gain = num2str(abs(term_mat(2)));
  d_gain = num2str(abs(term_mat(3)));

  if term_mat(2) >= 0, p_gain = [p_gain,' + '];
  else p_gain = [p_gain,' - ']; end

  if term_mat(3) >= 0, d_gain = [' + ',d_gain];
  else d_gain = [' - ',d_gain]; end

  txt = text(txt_lft,0.5,['(1',d_gain,'s)'],'erase',ers,...
            'horizontalalignment','left','verticalalignment','middle',...
            'userdata',[3,0],'fontname',fontname,...
            'tag','0','color','k');
%            'buttondownfcn','pagemous(0)');
  txt_ext = get(txt,'extent');
  txt_lft = txt_lft+txt_ext(3);

  txt = text(txt_lft,0.5,['(',p_gain],'erase',ers,...
            'horizontalalignment','left','verticalalignment','middle',...
            'userdata',[1,0],'fontname',fontname,...
            'tag','0','color','k');
%            'buttondownfcn','pagemous(0)');
  txt_ext = get(txt,'extent');
  txt_lft = txt_lft+txt_ext(3);

  txt = text(txt_lft,num_btm,i_gain,'erase',ers,...
            'horizontalalignment','left','verticalalignment','bottom',...
            'userdata',[2,0],'fontname',fontname,...
            'tag','0','color','k');
%            'buttondownfcn','pagemous(0)');
  txt_ext = get(txt,'extent');
  new_lft = txt_lft+txt_ext(3);
  lin_lft = txt_lft; lin_rht = new_lft;
  lin = line([lin_lft,lin_rht],[line_yloc,line_yloc],'erase',ers,'color','k');
  txt_mid = txt_lft + (lin_rht-lin_lft)/2;
  txt = text(txt_mid,den_btm,'s','erase',ers,...
           'horizontalalignment','center','verticalalignment','bottom',...
           'userdata',[2,0],'fontname',fontname,...
           'tag','0','color','k');
%           'buttondownfcn','pagemous(0)');
  text(new_lft,0.5,')','erase',ers,...
            'horizontalalignment','left','verticalalignment','middle',...
            'userdata',[2,0],'fontname',fontname,...
            'tag','0','color','k');

 else
  for k = term_val,
   term_loc=find(k==term_mat(:,4));
   if length(term_loc),
    for h=1:length(term_loc),

     if k==1, % Gain

      gain = num2str(term_mat(1,1));
      txt = text(txt_lft,0.5,gain,'erase',ers,...
                 'horizontalalignment','left','verticalalignment','middle',...
                 'fontname',fontname,'color','k');
      txt_ext = get(txt,'extent');

      if mode3 == 1 & mode4 == 1,
       set(txt,'userdata',term_loc(h),'tag','0');
%       set(txt,'userdata',term_loc(h),'buttondownfcn','pagemous(0)');
      else
       set(txt,'tag','9');
      end

      txt_lft = txt_lft + txt_ext(3)+0.01;

     elseif k==2,

      integ = term_mat(term_loc(h),1);
      if integ~=0,
       if integ > 0,
        txt1_btm = den_btm; txt2_btm = num_btm;
       else
        txt1_btm = num_btm; txt2_btm = den_btm;
       end

       coeffs = [1,zeros(1,abs(integ))];
       [txt_han,new_lft] = coefdisp(txt_lft,txt1_btm,coeffs,0,term_loc(h));

       lin_lft = txt_lft; lin_rht = new_lft;
       lin = line([lin_lft,lin_rht],[line_yloc,line_yloc],'erase',ers,'color','k');
       txt_mid = txt_lft + (lin_rht-lin_lft)/2;
       txt = text(txt_mid,txt2_btm,'1','erase',ers,...
            'horizontalalignment','center','verticalalignment','bottom',...
            'fontname',fontname,'color','k');
       set(txt,'userdata',term_loc(h));
       set(lin,'userdata',[txt_han,txt]);

       if mode3 == 1 & mode4 == 1,
        set([txt,txt_han],'tag','0');
%        set([txt,txt_han],'buttondownfcn','pagemous(0)');
       else
        set([txt,txt_han],'tag','9');
       end

       txt_lft = new_lft + 0.01;
      end

     elseif any(k==[4,5]), % real pole/zero

      if k==4,
       txt1_btm = den_btm; txt2_btm = num_btm;
      else
       txt1_btm = num_btm; txt2_btm = den_btm;
      end

      coeffs = [1,term_mat(term_loc(h),1)];
      [txt_han,new_lft] = coefdisp(txt_lft,txt1_btm,coeffs,1,term_loc(h));

      lin_lft = txt_lft; lin_rht = new_lft;
      lin = line([lin_lft,lin_rht],[line_yloc,line_yloc],'erase',ers,'color','k');
      txt_mid = txt_lft + (lin_rht-lin_lft)/2;
      txt = text(txt_mid,txt2_btm,'1','erase',ers,...
              'horizontalalignment','center','verticalalignment','bottom',...
              'fontname',fontname,'color','k');
      set(txt,'userdata',term_loc(h));

      if mode3 == 1 & mode4 == 1,
       set([txt,txt_han],'tag','0');
%       set([txt,txt_han],'buttondownfcn','pagemous(0)');
      else
       set([txt,txt_han],'tag','9');
      end

      set(lin,'userdata',[txt_han,txt]);
      txt_lft = new_lft + 0.01;

     elseif any(k==[6,7]), % complex pole/zero

      if k==6,
       txt1_btm = den_btm; txt2_btm = num_btm;
      else
       txt1_btm = num_btm; txt2_btm = den_btm;
      end

      zeta = term_mat(term_loc(h),1);
      wn = term_mat(term_loc(h),2);
      coeffs = [1,2*zeta*wn,wn^2];
      [txt_han,new_lft] = coefdisp(txt_lft,txt1_btm,coeffs,1,term_loc(h));

      lin_lft = txt_lft; lin_rht = new_lft;
      lin = line([lin_lft,lin_rht],[line_yloc,line_yloc],'erase',ers,'color','k');
      txt_mid = txt_lft + (lin_rht-lin_lft)/2;
      txt = text(txt_mid,txt2_btm,'1','erase',ers,...
             'horizontalalignment','center','verticalalignment','bottom',...
             'fontname',fontname,'color','k');
      set(txt,'userdata',term_loc(h));

      if mode3 == 1 & mode4 == 1,
       set([txt,txt_han],'tag','0');
%       set([txt,txt_han],'buttondownfcn','pagemous(0)');
      else
       set([txt,txt_han],'tag','9');
      end

      set(lin,'userdata',[txt_han,txt]);
      txt_lft = new_lft + 0.01;

     elseif k==8, % lead/lag

      phase = term_mat(term_loc(h),1);
      freq = term_mat(term_loc(h),2);
      [jk,zero,pole]=leadlag(phase,freq,[],T);

      zero_str = num2str(zero);
      pole_str = num2str(pole);

      if zero > 0,
       lead = ['(s+',zero_str,')'];
      else
       lead = ['(s',zero_str,')'];
      end

      if pole > 0,
       lag = ['(s+',pole_str,')'];
      else
       lag = ['(s',pole_str,')'];
      end

      txt1 = text(txt_lft,num_btm,lead,'erase',ers,...
            'horizontalalignment','left','verticalalignment','bottom',...
            'fontname',fontname,'color','k');
      set(txt1,'userdata',term_loc(h));

      txt_ext = get(txt1,'extent');
      lin_lft = txt_lft; lin_rht = txt_lft+txt_ext(3);
      lin = line([lin_lft,lin_rht],[line_yloc,line_yloc],'erase',ers,'color','k');

      txt2 = text(txt_lft,den_btm,lag,'erase',ers,...
            'horizontalalignment','left','verticalalignment','bottom',...
            'fontname',fontname,'color','k');
      set(txt2,'userdata',term_loc(h));
      set(lin,'userdata',[txt1,txt2]);

      if mode3 == 1 & mode4 == 1,
       set([txt1,txt2],'tag','0');
%       set([txt1,txt2],'buttondownfcn','pagemous(0)');
      else
       set([txt1,txt2],'tag','9');
      end

      txt_lft = txt_lft + txt_ext(3) + 0.01;

     end % end else-ifs
    end % end for h = loop
   end % end of if length(term_loc)
  end % end of for k = loop

  if term_mat(1,2)~=0,
   e_str = 'e';
   txt1=text(txt_lft,line_yloc,e_str,'erase',ers,...
             'horizontalalignment','left','verticalalignment','middle',...
             'fontname',fontname,'color','k');
   ext_txt = get(txt1,'extent');
   txt_lft = txt_lft + ext_txt(3);
   if term_mat(1,2) > 0,
    delay_str = ['-',num2str(term_mat(1,2)),'s'];
   else
    delay_str = [num2str(-term_mat(1,2)),'s'];
   end
   txt2=text(txt_lft,line_yloc,delay_str,'erase',ers,...
             'horizontalalignment','left','verticalalignment','bottom',...
             'fontname',fontname,'color','k');
   if mode3 == 1 & mode4 == 1,
    set([txt1,txt2],'userdata',[0,1],'tag','0');
%       set([txt1,txt2],'buttondownfcn','pagemous(0)');
   else
    set([txt1,txt2],'tag','9');
   end
  end
 end

elseif mode4 == 2, % coefficient

 [num,den] = termextr(term_mat);
 num = num/term_mat(1,1);

 gain = num2str(term_mat(1,1));
 txt = text(txt_lft,0.5,gain,'erase',ers,...
            'horizontalalignment','left','verticalalignment','middle',...
            'fontname',fontname,'color','k');
 txt_ext = get(txt,'extent');
 set(txt,'userdata',1);
 txt_lft = txt_lft + txt_ext(3)+0.01;

 [txt_han1,new_lft1] = coefdisp(txt_lft,num_btm,num,0,[0,0]);
 [txt_han2,new_lft2] = coefdisp(txt_lft,den_btm,den,0,[0,0]);
 min_lft = min(new_lft1,new_lft2); max_lft = max(new_lft1,new_lft2);
 shft = (max_lft - min_lft)/2;
 if new_lft1 < new_lft2,
  for k = length(txt_han1):-1:1,
   txt_pos = get(txt_han1(k),'pos');
   set(txt_han1(k),'pos',txt_pos+[shft,0,0]);
  end
 elseif new_lft2 < new_lft1,
  for k = length(txt_han2):-1:1,
   txt_pos = get(txt_han2(k),'pos');
   set(txt_han2(k),'pos',txt_pos+[shft,0,0]);
  end
 end
 lin_lft = txt_lft; lin_rht = max_lft;
 lin = line([lin_lft,lin_rht],[line_yloc,line_yloc],'erase',ers,'color','k');
 set(lin,'userdata',[txt_han1,txt_han2]);
 set([txt_han1,txt_han2],'tag','9');

elseif mode4 == 3, % Inverse Laplace Transform

 residisp(term_mat,tf_ext);

end


function Model = readCbTmodel(modelName, Tmodel, varargin)
% Creates COBRA format of a specific model from `Tmodel`.
% (composite database).
% Called by `mergeModelsBorg`, `driveModelBorgifier`, calls `TmodelFields`, `orderModelFieldsBorg`, `organizeModelCool`, `buildRxnEquations`, `ismatlab`, `parseBoolean`.
%
% USAGE:
%
%    Model = readCbTmodel(modelName, Tmodel)
%
% INPUTS:
%    modelName:           Name of an available model (i.e. iAF1260). Available names
%                         can be found by looking in `Tmodel.Models`
%    Tmodel:              Otherwise `Tmodel` will be loaded from path below.
%
% OPTIONAL INPUTS:
%    emptyArrayChoice:    "y" or "n" to remove empty arrays or not
%    'Verbose':           Print progress stamps.
%
% OUTPUTS:
%    Model:         Model in COBRA format.
%
% Please cite:
% `Sauls, J. T., & Buescher, J. M. (2014). Assimilating genome-scale
% metabolic reconstructions with modelBorgifier. Bioinformatics
% (Oxford, England), 30(7), 1036?8`. http://doi.org/10.1093/bioinformatics/btt747
%
% ..
%    Edit the above text to modify the response to help addMetInfo
%    Last Modified by GUIDE v2.5 06-Dec-2013 14:19:28
%    This file is published under Creative Commons BY-NC-SA.
%
%    Correspondance:
%    johntsauls@gmail.com
%
%    Developed at:
%    BRAIN Aktiengesellschaft
%    Microbial Production Technologies Unit
%    Quantitative Biology and Sequencing Platform
%    Darmstaeter Str. 34-36
%    64673 Zwingenberg, Germany
%    www.brain-biotech.de

verbose = false ;  % Varaging.
emptyArrayChoice = [] ;
if ~isempty(varargin)
    if sum(strcmp('Verbose', varargin))
        verbose = true ;
    end
    if sum(strcmp('y', varargin))
        emptyArrayChoice = 'y' ;
    end
    if sum(strcmp('n', varargin))
        emptyArrayChoice = 'n' ;
    end
end

%% Declare variables.
% Check to see if model exists.
TmodelNames = fieldnames(Tmodel.Models) ;
modelCheck = 0 ;
while ~modelCheck
    modelCheck = sum(strcmp(modelName, TmodelNames)) ;
    if modelCheck
        if verbose ; fprintf('Extracting %s from Tmodel\n', modelName) ; end
        modelCheck = 1 ;
    else
        fprintf('ERROR: Model %s not found in Tmodel\n', modelName)
        % Print available model names and allow user to rechoose.
        fprintf('The available models are :\n')
        for iName = 1:length(TmodelNames)
            fprintf([TmodelNames{iName} '\n'])
        end
        modelName = input('Input desired model: ', 's') ;
    end
end

% Set name.
Model.description = modelName ;

otherModels = find(cellfun(@isempty, (strfind(TmodelNames, modelName)))) ;

% Get field names.
fields = TmodelFields ;
% Reaction related cell field names.
rxnFields = fields{1} ;
% Reaction related double Fields (which are kept model specific).
rNumFields = fields{2} ;
% Metabolite related cell field names.
metFields = fields{3} ;
% Metabolite related double field names.
mNumFields = fields{4} ;
% All fields that will end up in the Model.
allFields = fields{5} ;

% Identity arrays for desired model.
rxnLog = Tmodel.Models.(modelName).rxns ;
metLog = Tmodel.Models.(modelName).mets ;

%% Extract reaction information.
for iF = 1:length(rxnFields)
    Model.(rxnFields{iF}) = Tmodel.(rxnFields{iF})(rxnLog) ;
end
for iF = 1:length(rNumFields)
    Model.(rNumFields{iF}) = Tmodel.(rNumFields{iF}).(modelName)(rxnLog);
end

% Remove information from other models for grRules.
% Find where the rull starts for the model.
% searchStringStart = ['(?<=(^|\|)' modelName ':).*'] ;
grRulesStart = regexp(Model.grRules, modelName ) ; %searchStringStart) ;
fixGrRulesStart = @(startpos, shift) not(isempty(startpos)) * (startpos + shift) ;
grRulesStart = cellfun(@(startpos, shift)fixGrRulesStart(startpos, shift), ...
                        grRulesStart, repmat({length(modelName) + 1}, ...
                        size(grRulesStart)), 'Uniformoutput',false) ;
ruleIndexes = find(~cellfun(@isempty,grRulesStart)) ;
% Find where information for other models starts, if it is after the
% information for this model.
searchStringEnd = ['(?<=' modelName '.*).('] ;
for iMo = 1:length(otherModels)
    if iMo ~= 1
        searchStringEnd = [searchStringEnd '|'] ;
    end
    searchStringEnd = [searchStringEnd '\|'...
                        TmodelNames{otherModels(iMo)}] ;
end
searchStringEnd = [searchStringEnd '):'] ;
grRulesEnd = regexpi(Model.grRules,searchStringEnd, 'once') ;
% Clear gene rules and rebuild.
grRulesHold = Model.grRules ;
Model.grRules(:) = {''} ;
% Only include information from between the index where information starts
% and where it end.
for iRxn = 1:length(ruleIndexes)
    % if there was no ending index, set it as the length of the string.
    if isempty(grRulesEnd{ruleIndexes(iRxn)})
        grRulesEnd{ruleIndexes(iRxn)} = ...
            length(grRulesHold{ruleIndexes(iRxn)}) ;
    end
    Model.grRules{ruleIndexes(iRxn)} = ...
        grRulesHold{ruleIndexes(iRxn)} ...
            (grRulesStart{ruleIndexes(iRxn)}: ...
            grRulesEnd{ruleIndexes(iRxn)}) ;
end

% Clean up rxnID also. This is really key, beacause we need the original
% IDs to compare the removed model to the model before it was merged.
if ismatlab
    searchString = ['(?<=(^|\|)' modelName ':)[^\|]*'] ;
    IDs = regexpi(Model.rxnID, searchString, 'match') ;
else
    for ir = 1:length(Model.rxnID)
        nowID = Model.rxnID{ir} ;
        startpos = min(strfind(nowID, modelName) + length(modelName) + 1) ;
        endpos =   strfind(nowID, '|') -1 ;
        endpos = min(endpos(endpos > startpos)) ;
        IDs{ir} = nowID(startpos:endpos) ;
    end
end
IDIndexes = find(~cellfun(@isempty, IDs)) ;
for iRxn = 1:length(IDIndexes)
    Model.rxnID{IDIndexes(iRxn)} = char(IDs{iRxn}) ;
end

%% Extract metabolite information.
Model.mets = Tmodel.mets(metLog) ;
for iF = 1:length(metFields)
    Model.(metFields{iF}) = Tmodel.(metFields{iF})(metLog) ;
end
for iF = 1:length(mNumFields)
    Model.(mNumFields{iF}) = Tmodel.(mNumFields{iF})(metLog) ;
end

% Clean up metID
if ismatlab
    searchString = ['(?<=(^|\|)' modelName ':)[^\|]*'] ;
    IDs = regexpi(Model.metID, searchString, 'match') ;
else
    for ir = 1:length(Model.metID)
        nowID = Model.metID{ir} ;
        startpos = min(strfind(nowID, modelName) + length(modelName) + 1) ;
        endpos =   strfind(nowID, '|') -1 ;
        endpos = min(endpos(endpos > startpos)) ;
        IDs{ir} = nowID(startpos:endpos) ;
    end
end
IDIndexes = find(~cellfun(@isempty, IDs)) ;
for iMet = 1:length(IDIndexes)
    Model.metID{IDIndexes(iMet)} = char(IDs{iMet}) ;
end

%% Construct S Matrix.
Model.S = Tmodel.S(metLog, rxnLog) ;

%% Rebuild reaction equations (as bounds are different per Model)
Model = buildRxnEquations(Model) ;

%% Extract gene information.
if isfield(Tmodel.Models.(modelName), 'genes')

    nRxns = length(Model.rxns) ;

    allGenes = Tmodel.Models.(modelName).genes ;
    Model.genes = allGenes ; % put in model for saving.
    genesByRxn = cell(nRxns, 1) ;

    % Construct rules cell array
    rules = cell(nRxns, 1) ;
    rules(:) = {''} ;

    % Convert grRules to rules format and pull out genes per reaction.
    for iRxn = 1:nRxns
       [genesByRxn{iRxn}, rules{iRxn}] = parseBoolean(Model.grRules{iRxn});
    end

    % Construct gene to rxn mapping.
    rxnGeneMat = sparse(nRxns,length(allGenes)) ;

    % but only make the rules if there are grRules.
    if sum(rxnGeneMat) > 0
        fprintf('Building rxnGeneMat.\n');
        for i = 1:nRxns
            if iscell(genesByRxn{i})
                [~, geneInd] = ismember(genesByRxn{i}, allGenes);
            else
                [~, geneInd] = ismember(num2cell(genesByRxn{i}), allGenes);
            end

            if geneInd > 0
                rxnGeneMat(i, geneInd) = 1;
                for j = 1:length(geneInd)
                    rules{i} = strrep(rules{i}, ['x(' num2str(j) ')'], ...
                        ['x(' num2str(geneInd(j)) '_TMP_)']);
                end
                rules{i} = strrep(rules{i}, '_TMP_', '');
            else
                rules{i} = '' ;
            end
        end

        % Put things in the model.
        Model.rules = rules ;
        Model.rxnGeneMat = rxnGeneMat ;
    end
end

%% Remove all empty cell arrays.
if isempty(emptyArrayChoice)
    choice = input('Remove empty cell arrays? (y/n): ', 's') ;
else
    choice = emptyArrayChoice ;
end
if strcmpi(choice,'y') || strcmpi(choice, 'yes')
    if verbose ; fprintf('Removing empty cell arrays:\n') ; end
    for iF = 1:length(allFields)
        % Only remove the cell array fields.
        if isfield(Model, allFields{iF})
            if iscell(Model.(allFields{iF}))
                if cellfun(@isempty, Model.(allFields{iF}))
                    Model = rmfield(Model, allFields{iF}) ;
                    if verbose ; fprintf([allFields{iF} '\n']) ; end
                end
            end
        end
    end
end

%% Order model.
Model = orderModelFieldsBorg(Model) ;
Model = organizeModelCool(Model) ;


%Protein processing II process test case
%
% Author: Jared Jacobs, jmjacobs@stanford.edu
% Author: Jonathan Karr, jkarr@stanford.edu
% Affilitation: Covert Lab, Department of Bioengineering, Stanford University
% Last updated: 8/9/2010
classdef ProteinProcessingII_Test < edu.stanford.covert.cell.sim.ProcessTestCase
    methods
        function this = ProteinProcessingII_Test(methodName)
            this = this@edu.stanford.covert.cell.sim.ProcessTestCase(methodName);
        end

        function testOneMonomerRequiringNoProcessing(this)
            m = this.process;
            m.lipoproteinMonomerIndexs = [];
            m.secretedMonomerIndexs = [];
            m.unprocessedMonomerIndexs = 1;
            m.substrates(:) = 0;
            m.enzymes(:) = 0;
            m.unprocessedMonomers = 1;
            m.processedMonomers = 0;
            m.signalSequenceMonomers = 0;

            m.evolveState();
            assertEqual(0, m.unprocessedMonomers);
            assertEqual(1, m.processedMonomers);
            assertEqual(0, m.signalSequenceMonomers);
            assertEqual(zeros(size(m.substrates)), m.substrates);
        end

        function testOneSecretedMonomer(this)
            m = this.process;
            m.lipoproteinMonomerIndexs = [];
            m.secretedMonomerIndexs = 1;
            m.unprocessedMonomerIndexs = [];
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_water) = 1;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_signalPeptidase) = 1;
            m.unprocessedMonomers = 1;
            m.processedMonomers = 0;
            m.signalSequenceMonomers = 0;

            m.evolveState();
            assertEqual(0, m.unprocessedMonomers);
            assertEqual(1, m.processedMonomers);
            assertEqual(1, m.signalSequenceMonomers);
            assertEqual(zeros(size(m.substrates)), m.substrates);
            assertEqual(1, m.enzymes(m.enzymeIndexs_signalPeptidase));
        end

        function testOneLipoprotein(this)
            m = this.process;
            m.lipoproteinMonomerIndexs = 1;
            m.secretedMonomerIndexs = [];
            m.unprocessedMonomerIndexs = [];
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_water) = 1;
            m.substrates(m.substrateIndexs_PG160) = 1;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_signalPeptidase) = 1;
            m.enzymes(m.enzymeIndexs_diacylglycerylTransferase) = 99;
            m.unprocessedMonomers = 1;
            m.processedMonomers = 0;
            m.signalSequenceMonomers = 0;

            m.evolveState();
            assertEqual(0, m.unprocessedMonomers);
            assertEqual(1, m.processedMonomers);
            assertEqual(1, m.signalSequenceMonomers);
            assertEqual(0, m.substrates(m.substrateIndexs_water));
            assertEqual(0, m.substrates(m.substrateIndexs_PG160));
            assertEqual(1, m.substrates(m.substrateIndexs_hydrogen));
            assertEqual(1, m.substrates(m.substrateIndexs_SNGLYP));
            assertEqual(1, m.enzymes(m.enzymeIndexs_signalPeptidase));
            assertEqual(99, m.enzymes(m.enzymeIndexs_diacylglycerylTransferase));
        end

        function testNoProcessingWithoutWater(this)
            m = this.process;
            m.lipoproteinMonomerIndexs = 1;
            m.secretedMonomerIndexs = 2;
            m.unprocessedMonomerIndexs = [];
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_PG160) = 1e3;
            m.enzymes(:) = 1e3;
            m.unprocessedMonomers = [1; 1];
            m.processedMonomers = [0; 0];
            m.signalSequenceMonomers = [0; 0];

            m.evolveState();
            assertEqual([1 1], m.unprocessedMonomers');
            assertEqual([0 0], m.processedMonomers');
            assertEqual([0 0], m.signalSequenceMonomers');
            assertEqual(0, m.substrates(m.substrateIndexs_water));
            assertEqual(1e3, m.substrates(m.substrateIndexs_PG160));
        end

        function testNoProcessingWithoutSignalPeptidase(this)
            m = this.process;
            m.lipoproteinMonomerIndexs = 1;
            m.secretedMonomerIndexs = 2;
            m.unprocessedMonomerIndexs = [];
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.substrates(m.substrateIndexs_PG160) = 1e3;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_diacylglycerylTransferase) = 1e3;
            m.unprocessedMonomers = [1;1];
            m.processedMonomers = [0;0];
            m.signalSequenceMonomers = [0;0];

            m.evolveState();
            assertEqual([1 1], m.unprocessedMonomers');
            assertEqual([0 0], m.processedMonomers');
            assertEqual([0 0], m.signalSequenceMonomers');
            assertEqual(1e6, m.substrates(m.substrateIndexs_water));
            assertEqual(1e3, m.substrates(m.substrateIndexs_PG160));
        end

        function testNoLipoproteinProcessingWithoutDiacylglycerylTransferase(this)
            m = this.process;
            m.lipoproteinMonomerIndexs = 1;
            m.secretedMonomerIndexs = [];
            m.unprocessedMonomerIndexs = [];
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.substrates(m.substrateIndexs_PG160) = 1e3;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_signalPeptidase) = 1e3;
            m.unprocessedMonomers = 1;
            m.processedMonomers = 0;
            m.signalSequenceMonomers = 0;

            m.evolveState();
            assertEqual(1, m.unprocessedMonomers);
            assertEqual(0, m.processedMonomers);
            assertEqual(0, m.signalSequenceMonomers);
            assertEqual(1e6, m.substrates(m.substrateIndexs_water));
            assertEqual(1e3, m.substrates(m.substrateIndexs_PG160));
        end

        % Verifies that signal peptidase processes roughly as many monomers as
        % its rate will allow when it's the limiting factor, and that the
        % monomers chosen for processing are chosen without egregious bias.
        function testLimitedSignalPeptidase_secretedProteinsOnly(this)
            m = this.process;
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_signalPeptidase) = 3;
            m.unprocessedMonomers(:) = 0;
            m.unprocessedMonomers(m.secretedMonomerIndexs) = 10;
            m.processedMonomers(:) = 0;
            m.signalSequenceMonomers(:) = 0;

            m.evolveState();
            n = m.enzymes(m.enzymeIndexs_signalPeptidase) * ...
                m.lipoproteinSignalPeptidaseSpecificRate * m.stepSizeSec;
            i = m.secretedMonomerIndexs;
            assertVectorsAlmostEqual(...
                n, sum(m.processedMonomers(i)), 'relative', 0.10);
            assertTrue(10 > max(m.processedMonomers(i)));
            assertTrue(0 < min(m.processedMonomers(i)));
            assertEqual(...
                10 * ones(size(i)), ...
                m.processedMonomers(i) + m.unprocessedMonomers(i));
            assertEqual(m.processedMonomers, m.signalSequenceMonomers);
        end

        % Verifies that signal peptidase processes roughly as many monomers as
        % its rate will allow when it's the limiting factor and there is a mix
        % of lipoproteins and secreted proteins, and that the monomers chosen
        % for processing are chosen without egregious bias.
        function testLimitedSignalPeptidase_lipoproteinsAndSecretedProteins(this)
            m = this.process;
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.substrates(m.substrateIndexs_PG160) = 1e3;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_signalPeptidase) = 20;
            m.enzymes(m.enzymeIndexs_diacylglycerylTransferase) = 1e4;
            m.unprocessedMonomers(:) = 0;
            m.unprocessedMonomers(m.secretedMonomerIndexs) = 10;
            m.unprocessedMonomers(m.lipoproteinMonomerIndexs) = 10;
            m.processedMonomers(:) = 0;
            m.signalSequenceMonomers(:) = 0;

            m.evolveState();
            n = m.enzymes(m.enzymeIndexs_signalPeptidase) * ...
                m.lipoproteinSignalPeptidaseSpecificRate * m.stepSizeSec;
            i = [m.secretedMonomerIndexs;m.lipoproteinMonomerIndexs];
            assertVectorsAlmostEqual(...
                n, sum(m.processedMonomers(i)), 'relative', 0.05);
            assertTrue(10 > max(m.processedMonomers(i)));
            assertTrue(0 < min(m.processedMonomers(i)));
            assertEqual(...
                10 * ones(size(i)), ...
                m.processedMonomers(i) + m.unprocessedMonomers(i));
            assertEqual(m.processedMonomers, m.signalSequenceMonomers);
        end

        % Verifies that diacylglyceryl transferase processes roughly as many
        % lipoproteins as its rate will allow when it's the limiting factor.
        function testLimitedDiacylglycerylTransferase(this)
            m = this.process;
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.substrates(m.substrateIndexs_PG160) = 1e3;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_signalPeptidase) = 1e6;
            m.enzymes(m.enzymeIndexs_diacylglycerylTransferase) = 1e3;
            m.unprocessedMonomers(:) = 0;
            m.unprocessedMonomers(m.lipoproteinMonomerIndexs) = 10;
            m.processedMonomers(:) = 0;
            m.signalSequenceMonomers(:) = 0;

            m.evolveState();
            n = m.enzymes(m.enzymeIndexs_diacylglycerylTransferase) * ...
                m.lipoproteinDiacylglycerylTransferaseSpecificRate * m.stepSizeSec;
            i = m.lipoproteinMonomerIndexs;
            assertElementsAlmostEqual(n, sum(m.processedMonomers(i)), 'absolute', 3);
            assertTrue(10 > max(m.processedMonomers(i)));
            assertTrue(0 < min(m.processedMonomers(i)));
        end

        function testLimitedPG160(this)
            m = this.process;
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.substrates(m.substrateIndexs_PG160) = 100;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_signalPeptidase) = 1e5;
            m.enzymes(m.enzymeIndexs_diacylglycerylTransferase) = 1e5;
            m.unprocessedMonomers(:) = 0;
            m.unprocessedMonomers(m.lipoproteinMonomerIndexs) = 10;
            m.processedMonomers(:) = 0;
            m.signalSequenceMonomers(:) = 0;
            assertTrue(sum(m.unprocessedMonomers(m.lipoproteinMonomerIndexs)) > m.substrates(m.substrateIndexs_PG160));

            m.evolveState();
            i = m.lipoproteinMonomerIndexs;
            assertIn(nnz(m.unprocessedMonomers(m.lipoproteinMonomerIndexs)), [1 Inf]);
            assertEqual(100, sum(m.processedMonomers(i)));
        end

        function testLotsOfEverything(this)
            m = this.process;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.substrates(m.substrateIndexs_PG160) = 1e4;
            m.enzymes(m.enzymeIndexs_signalPeptidase) = 1e3;
            m.enzymes(m.enzymeIndexs_diacylglycerylTransferase) = 1e2;
            i = [m.secretedMonomerIndexs;m.lipoproteinMonomerIndexs];
            m.unprocessedMonomers(i) = randi(100, size(i));
            m.processedMonomers(:) = 0;
            m.signalSequenceMonomers(:) = 0;

            m.evolveState();
            bounds = sort(...
                [m.enzymes(m.enzymeIndexs_signalPeptidase) * ...
                    m.lipoproteinSignalPeptidaseSpecificRate * ...
                    m.stepSizeSec;
                 m.enzymes(m.enzymeIndexs_diacylglycerylTransferase) * ...
                    m.lipoproteinDiacylglycerylTransferaseSpecificRate * ...
                    m.stepSizeSec]);
            assertTrue(0.99 * bounds(1) < sum(m.processedMonomers(i)));
            assertTrue(1.01 * bounds(2) > sum(m.processedMonomers(i)));
        end

        function testGeneEssentiality(this)
            m = this.process;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.substrates(m.substrateIndexs_PG160) = 1e3;
            m.enzymes(m.enzymeIndexs_signalPeptidase) = 1e3;
            m.enzymes(m.enzymeIndexs_diacylglycerylTransferase) = 1e3;
            m.unprocessedMonomers(:) = 1;
            m.processedMonomers(:) = 0;
            this.helpTestGeneEssentiality({
                'MG_086';     %prolipoprotein diacylglyceryl transferase
                'MG_210'},... %prolipoprotein signal peptidase, signal peptidase II
                @(m, i) any(i.processedMonomers(m.unprocessedMonomerIndexs) < ...
                            m.processedMonomers(m.unprocessedMonomerIndexs)) && ...
                        any(i.processedMonomers(m.lipoproteinMonomerIndexs) < ...
                            m.processedMonomers(m.lipoproteinMonomerIndexs)) && ...
                        any(i.processedMonomers(m.secretedMonomerIndexs) < ...
                            m.processedMonomers(m.secretedMonomerIndexs)));
        end
    end
end