function a = iscomplex(X)
a = ~isreal(X);
end


classdef PTKLobesFromFissurePlaneOblique < PTKPlugin
    % PTKLobesFromFissurePlaneOblique. Plugin which is part of the lobar segmentation.
    %
    %     This is a plugin for the Pulmonary Toolkit. Plugins can be run using
    %     the gui, or through the interfaces provided by the Pulmonary Toolkit.
    %     See PTKPlugin.m for more information on how to run plugins.
    %
    %     Plugins should not be run directly from your code.
    %
    %     PTKLobesFromFissurePlaneOblique is an intermediate stage in segmenting the
    %     lobes.
    %
    %     For more information, see
    %     [Doel et al., Pulmonary lobe segmentation from CT images using
    %     fissureness, airways, vessels and multilevel B-splines, 2012]
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        ButtonText = 'Lobes Oblique'
        ToolTip = ''
        Category = 'Lobes'

        AllowResultsToBeCached = true
        AlwaysRunPlugin = false
        PluginType = 'ReplaceOverlay'
        HidePluginInDisplay = false
        FlattenPreviewImage = true
        PTKVersion = '1'
        ButtonWidth = 6
        ButtonHeight = 2
        GeneratePreview = true
        Visibility = 'Developer'
    end

    methods (Static)
        function results = RunPlugin(application, reporting)

            left_and_right_lungs = application.GetResult('PTKLeftAndRightLungs');
            fissure_plane = application.GetResult('PTKFissurePlaneOblique');
            lung_mask = application.GetResult('PTKLeftAndRightLungs');
            left_lung_template = application.GetTemplateImage(PTKContext.LeftLung).BlankCopy;
            right_lung_template = application.GetTemplateImage(PTKContext.RightLung).BlankCopy;
            results_left = PTKLobesFromFissurePlaneOblique.GetLeftLungResults(left_lung_template, lung_mask.Copy, fissure_plane.Copy, reporting);
            results_right = PTKLobesFromFissurePlaneOblique.GetRightLungResults(right_lung_template, lung_mask, fissure_plane, reporting);

            results = PTKCombineLeftAndRightImages(application.GetTemplateImage(PTKContext.LungROI), results_left, results_right, left_and_right_lungs);
            results.ImageType = PTKImageType.Colormap;
        end

        function results = GenerateImageFromResults(results, ~, ~)
        end
    end

    methods (Static, Access = private)
        function left_results = GetLeftLungResults(lung_template, lung_mask, fissure_plane, reporting)

            lung_mask.ChangeRawImage(uint8(lung_mask.RawImage == 2));

            lung_mask.ResizeToMatch(lung_template);

            fissure_plane.ResizeToMatch(lung_template);
            fissure_plane = find(fissure_plane.RawImage(:) == 4);

            left_results = PTKDivideVolumeUsingScatteredPoints(lung_mask, fissure_plane, 5, reporting);
            left_results.ChangeColourIndex(1, 5);
            left_results.ChangeColourIndex(2, 6);
        end

        function results_right = GetRightLungResults(lung_template, lung_mask, fissure_plane, reporting)
            lung_mask.ChangeRawImage(uint8(lung_mask.RawImage == 1));

            lung_mask.ResizeToMatch(lung_template);
            fissure_plane.ResizeToMatch(lung_template);
            fissure_plane_o = find(fissure_plane.RawImage(:) == 3);

            results_right = PTKDivideVolumeUsingScatteredPoints(lung_mask, fissure_plane_o, 5, reporting);
            results_right.ChangeColourIndex(2, 4);
        end
    end
end


function sel = filtertable( table, filter )

fnames = fieldnames(filter);
sel = true(size(table, 1), 1);

for fi = 1:numel(fnames)
  fname = fnames{fi};
  fvalue = filter.(fname);
  sel = sel & ismember(table.(fname), fvalue);
end

end


function count=get_lines_executed_count(obj)
% get a mask indicating which lines have been executed
%
% count=get_lines_executed_count(obj)
%
% Input:
%   obj                 MOcovMFile instance
%
% Output:
%   count               Nx1 numeric vector, with count(k)=c indicating
%                       that the k-th line has been executed k times. Lines
%                       that are marked as non-executable have a value of
%                       zero.

    count=obj.executed_count;
    count(~get_lines_executable(obj))=0;


classdef Translation_Test < edu.stanford.covert.cell.sim.ProcessTestCase
    methods
        function this = Translation_Test(name)
            this = this@edu.stanford.covert.cell.sim.ProcessTestCase(name);
        end

        function testSimpleFixture(this)
            m = this.process;

            %% initial conditions: one mRNA, components of one ribosome
            m.stimuli(:) = 0;
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_gtp) = 1e6;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.boundEnzymes(:) = 0;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_translationFactors) = 1;
            m.enzymes(m.enzymeIndexs_initiationFactor3) = 0;
            m.enzymes(m.enzymeIndexs_elongationGFactor) = 2;
            m.enzymes(m.enzymeIndexs_ribosome30SIF3) = 1;
            m.enzymes(m.enzymeIndexs_ribosome50S) = 1;
            m.ribosome.states = [];
            m.ribosome.boundMRNAs = [];
            m.ribosome.mRNAPositions = [];
            m.ribosome.tmRNAPositions = [];
            m.polypeptide.boundMRNAs = [];
            m.polypeptide.nascentMonomerLengths = [];
            m.polypeptide.proteolysisTagLengths = [];

            m.polypeptide.monomerAASequences = {'MKKKKKKKKKKKKKKKKK'};
            m.polypeptide.monomerTRNASequences = {[10 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20]'};
            m.polypeptide.monomerLengths = 18;
            m.monomers = 0;

            m.mRNAs = 1;
            m.aminoacylatedTRNAs = repmat(20, size(m.rna.matureTRNAIndexs));
            m.aminoacylatedTMRNA = 0;

            %% initiation
            m.evolveState();
            assertEqual(m.ribosome.activeValue, m.ribosome.states(1));
            assertEqual(0, m.polypeptide.nascentMonomerLengths(1));
            assertEqual(0, m.polypeptide.proteolysisTagLengths(1));
            assertEqual(1, m.polypeptide.boundMRNAs(1));
            assertEqual(1, m.ribosome.boundMRNAs(1));
            assertEqual(0, m.monomers(1));
            assertEqual(zeros(20,1), m.substrates(m.substrateIndexs_aminoAcids));
            assertEqual(1e6-1, m.substrates(m.substrateIndexs_gtp));
            assertEqual(1, m.substrates(m.substrateIndexs_gdp));
            assertEqual(1, m.substrates(m.substrateIndexs_phosphate));
            assertEqual(1e6-1, m.substrates(m.substrateIndexs_water));
            assertEqual(1, m.substrates(m.substrateIndexs_hydrogen));
            assertEqual(1, m.enzymes(m.enzymeIndexs_initiationFactor1));
            assertEqual(1, m.enzymes(m.enzymeIndexs_initiationFactor2));
            assertEqual(1, m.enzymes(m.enzymeIndexs_initiationFactor3));
            assertEqual([2;1;1;1], m.enzymes(m.enzymeIndexs_elongationFactors));
            assertEqual(1, m.enzymes(m.enzymeIndexs_terminationFactor));
            assertEqual(1, m.enzymes(m.enzymeIndexs_recyclingFactor));
            assertEqual(repmat(20, size(m.rna.matureTRNAIndexs)), m.aminoacylatedTRNAs);
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome30S));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome30SIF3));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome50S));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome70S));
            assertEqual(1, m.boundEnzymes(m.enzymeIndexs_ribosome70S));

            %% elongation
            m.evolveState();
            assertEqual(m.ribosome.activeValue, m.ribosome.states(1));
            assertEqual(16, m.polypeptide.nascentMonomerLengths(1));
            assertEqual(0, m.polypeptide.proteolysisTagLengths(1));
            assertEqual(1, m.polypeptide.boundMRNAs(1));
            assertEqual(1, m.ribosome.boundMRNAs(1));
            assertEqual(0, m.monomers(1));
            assertEqual(zeros(20,1), m.substrates(m.substrateIndexs_aminoAcids));
            assertEqual(1e6-33, m.substrates(m.substrateIndexs_gtp));
            assertEqual(33, m.substrates(m.substrateIndexs_gdp));
            assertEqual(33, m.substrates(m.substrateIndexs_phosphate));
            assertEqual(1e6-34, m.substrates(m.substrateIndexs_water));
            assertEqual(49, m.substrates(m.substrateIndexs_hydrogen));
            assertEqual(1, m.enzymes(m.enzymeIndexs_initiationFactor1));
            assertEqual(1, m.enzymes(m.enzymeIndexs_initiationFactor2));
            assertEqual(1, m.enzymes(m.enzymeIndexs_initiationFactor3));
            assertEqual([1;0;0;0], m.enzymes(m.enzymeIndexs_elongationFactors));
            assertEqual([1;1;1;1], m.boundEnzymes(m.enzymeIndexs_elongationFactors));
            assertEqual(1, m.enzymes(m.enzymeIndexs_terminationFactor));
            assertEqual(1, m.enzymes(m.enzymeIndexs_recyclingFactor));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome30S));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome30SIF3));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome50S));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome70S));
            assertEqual(1, m.boundEnzymes(m.enzymeIndexs_ribosome70S));
            assertEqual([19 20 20 20 20 20 20 20 20 20 5]', m.aminoacylatedTRNAs(10:20));

            %% elongation + termination
            m.evolveState();
            assertEqual(m.ribosome.notExistValue, m.ribosome.states(1));
            assertEqual(0, m.polypeptide.nascentMonomerLengths(1));
            assertEqual(0, m.polypeptide.proteolysisTagLengths(1));
            assertEqual(0, m.polypeptide.boundMRNAs(1));
            assertEqual(0, m.ribosome.boundMRNAs(1));
            assertEqual(1, m.monomers(1));
            assertEqual(zeros(20,1), m.substrates(m.substrateIndexs_aminoAcids));
            assertEqual(1e6-39, m.substrates(m.substrateIndexs_gtp));
            assertEqual(39, m.substrates(m.substrateIndexs_gdp));
            assertEqual(39, m.substrates(m.substrateIndexs_phosphate));
            assertEqual(1e6-40, m.substrates(m.substrateIndexs_water));
            assertEqual(57, m.substrates(m.substrateIndexs_hydrogen));
            assertEqual(1, m.enzymes(m.enzymeIndexs_initiationFactor1));
            assertEqual(1, m.enzymes(m.enzymeIndexs_initiationFactor2));
            assertEqual(1, m.enzymes(m.enzymeIndexs_initiationFactor3));
            assertEqual([1;0;0;0], m.enzymes(m.enzymeIndexs_elongationFactors));
            assertEqual([1;1;1;1], m.boundEnzymes(m.enzymeIndexs_elongationFactors));
            assertEqual(1, m.enzymes(m.enzymeIndexs_ribosome30S));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome30SIF3));
            assertEqual(1, m.enzymes(m.enzymeIndexs_ribosome50S));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome70S));
            assertEqual(0, m.boundEnzymes(m.enzymeIndexs_ribosome70S));
            assertEqual([19 20 20 20 20 20 20 20 20 20 3]', m.aminoacylatedTRNAs(10:20));

            %% freeing the elongation factors
            m.evolveState();
            assertEqual([2;1;1;1], m.enzymes(m.enzymeIndexs_elongationFactors));
            assertEqual([0;0;0;0], m.boundEnzymes(m.enzymeIndexs_elongationFactors));
        end

        function testInitiationFromUncomplexedRibosome30SAndIF3(this)
            m = this.process;
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_gtp) = 1;
            m.substrates(m.substrateIndexs_water) = 1;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_initiationFactors) = 1;
            m.enzymes(m.enzymeIndexs_ribosome30S) = 1;
            m.enzymes(m.enzymeIndexs_ribosome50S) = 1;
            m.boundEnzymes(:) = 0;
            m.mRNAs(:) = 1;
            m.ribosome.states(:) = m.ribosome.notExistValue;
            m.evolveState();
            assertTrue(any(m.ribosome.states==m.ribosome.activeValue),...
                'initiation failed');
        end

        function testInitiation(this)
            this.initializeProcessForSuccessfulInitiation();
            m = this.process;

            m.evolveState();
            assertTrue(any(m.ribosome.states==m.ribosome.activeValue),...
                'initiation failed');
        end

        function testNoInitiationWithoutAvailableEnergy(this)
            this.initializeProcessForSuccessfulInitiation();
            m = this.process;
            m.substrates(m.substrateIndexs_gtp) = 0;

            m.evolveState();
            assertTrue(~any(m.ribosome.states == m.ribosome.activeValue),...
                'initiation happened');
        end

        function testNoInitiationWithoutMRNAs(this)
            this.initializeProcessForSuccessfulInitiation();
            m = this.process;
            m.mRNAs(:) = 0;

            m.evolveState();
            assertTrue(~any(m.ribosome.states==m.ribosome.activeValue),...
                'initiation happened');
        end

        function testNoInitiationWithOneEnzymeMissing(this)
            m = this.process;
            essential_enzyme_indexs = [...
                m.enzymeIndexs_initiationFactor1,...
                m.enzymeIndexs_initiationFactor2,...
                m.enzymeIndexs_ribosome50S];
            for i=1:numel(essential_enzyme_indexs)
                this.initializeProcessForSuccessfulInitiation();
                m.enzymes(essential_enzyme_indexs(i)) = 0;

                m.evolveState();
                assertTrue(...
                    ~any(m.ribosome.states==m.ribosome.activeValue),...
                    ['initiation happened, i=' num2str(i)]);
            end

            % Ribosome 30S has two forms
            this.initializeProcessForSuccessfulInitiation();
            m.enzymes(m.enzymeIndexs_ribosome30S) = 0;
            m.enzymes(m.enzymeIndexs_ribosome30SIF3) = 0;

            m.evolveState();
            assertTrue(...
                ~any(m.ribosome.states == m.ribosome.activeValue),...
                'initiation happened');
        end

        function testElongation(this)
            this.initializeProcessForSuccessfulElongation(3);
            m = this.process;

            m.evolveState();
            assertEqual(3, m.polypeptide.nascentMonomerLengths);
            assertEqual(1, m.polypeptide.boundMRNAs);
            assertEqual(1, m.ribosome.boundMRNAs);
            assertEqual(0, m.monomers(1));
            assertTrue(~any(m.enzymes(m.enzymeIndexs_elongationFactors)));
            assertTrue(all(m.boundEnzymes(m.enzymeIndexs_elongationFactors)));
        end

        function testNoElongationWithoutEnoughEnergy(this)
            this.initializeProcessForSuccessfulElongation(3);
            m = this.process;
            m.substrates(m.substrateIndexs_gtp) = 1;  % 2 GTP required per AA

            m.evolveState();
            assertEqual(0, m.polypeptide.nascentMonomerLengths);
            assertEqual(1, m.polypeptide.boundMRNAs);
            assertEqual(1, m.ribosome.boundMRNAs);
            assertEqual(0, m.monomers(1));
            assertTrue(all(m.enzymes(m.enzymeIndexs_elongationFactors)));
            assertTrue(~any(m.boundEnzymes(m.enzymeIndexs_elongationFactors)));
        end

        function testNoElongationWithoutWater(this)
            this.initializeProcessForSuccessfulElongation(3);
            m = this.process;
            m.substrates(:) = 1e6;
            m.substrates(m.substrateIndexs_water) = 0;

            m.evolveState();
            assertEqual(0, m.polypeptide.nascentMonomerLengths);
            assertEqual(1, m.polypeptide.boundMRNAs);
            assertEqual(1, m.ribosome.boundMRNAs);
            assertEqual(0, m.monomers(1));
            assertTrue(all(m.enzymes(m.enzymeIndexs_elongationFactors)));
            assertTrue(~any(m.boundEnzymes(m.enzymeIndexs_elongationFactors)));
            assertEqual(0, m.substrates(m.substrateIndexs_water));
        end

        function testNoSubstrates(this)
            this.initializeProcessForSuccessfulElongation(3);

            m = this.process;
            m.substrates(:) = 0;

            initial_substrates = m.substrates;
            initial_enzymes = m.enzymes;
            initial_boundEnzymes = m.boundEnzymes;
            initial_aminoacylatedTRNAs = m.aminoacylatedTRNAs;
            initial_ribosomeStates = m.ribosome.states;
            initial_boundMRNAs = m.ribosome.boundMRNAs;
            initial_monomers = m.monomers;
            initial_monomerLengths = m.polypeptide.monomerLengths;

            m.evolveState();

            %no substrate used
            assertEqual(initial_substrates, m.substrates);
            assertEqual(initial_aminoacylatedTRNAs, m.aminoacylatedTRNAs);

            %all active ribosomes remain active and don't advance
            assertEqual(...
                initial_ribosomeStates(initial_ribosomeStates == m.ribosome.activeValue),...
                m.ribosome.states(initial_ribosomeStates == m.ribosome.activeValue));
            assertEqual(...
                initial_boundMRNAs(initial_ribosomeStates == m.ribosome.activeValue),...
                m.ribosome.boundMRNAs(initial_ribosomeStates == m.ribosome.activeValue));
            assertEqual(...
                initial_boundMRNAs(initial_ribosomeStates == m.ribosome.activeValue),...
                m.polypeptide.boundMRNAs(initial_ribosomeStates == m.ribosome.activeValue));

            %no enzyme gain or loss or binding
            initial_enzymes(m.enzymeIndexs_ribosome30SIF3) = 0;
            initial_enzymes(m.enzymeIndexs_ribosome30S) = 0;
            initial_enzymes(m.enzymeIndexs_initiationFactor3) = 0;

            assertEqual(initial_enzymes', m.enzymes');
            assertEqual(initial_boundEnzymes', m.boundEnzymes');

            %no additional monomers or nascent monomer elongation
            assertEqual(initial_monomers, m.monomers);
            assertEqual(initial_monomerLengths, m.polypeptide.monomerLengths);
        end

        function testManyTranscripts(this)
            m = this.process;

            %% initial conditions: three mRNAs, components of three ribosomes
            m.stimuli(:) = 0;
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_gtp) = 1e6;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.boundEnzymes(:) = 0;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_translationFactors) = 6;
            m.enzymes(m.enzymeIndexs_elongationGFactor) = 12;
            m.enzymes(m.enzymeIndexs_ribosome30S) = 6;
            m.enzymes(m.enzymeIndexs_ribosome50S) = 6;
            m.ribosome.states = zeros(0, 1);
            m.ribosome.boundMRNAs = zeros(0, 1);
            m.ribosome.mRNAPositions = zeros(0, 1);
            m.ribosome.tmRNAPositions = zeros(0, 1);
            m.polypeptide.boundMRNAs = zeros(0, 1);
            m.polypeptide.nascentMonomerLengths = zeros(0, 1);
            m.polypeptide.proteolysisTagLengths = zeros(0, 1);

            m.polypeptide.monomerAASequences = {
                'MMKRTYQPSKLKRAKTH';
                'MGFMARMATAQGRKVLR';
                'MQRRFKNRAQLTVSSER'};
            m.polypeptide.monomerTRNASequences = {
                [10 7 20 17 28 22 21 6 3 20 19 27 13 1 20 4 33]';
                [10 14 12 7 1 15 7 1 4 1 21 18 13 20 29 19 15]';
                [10 21 36 13 12 20 32 13 1 21 34 30 29 24 3 31 13]'};

            m.polypeptide.monomerLengths = [17 17 17]';
            m.monomers = [0 0 0]';

            m.mRNAs = [1 1 1]';
            m.aminoacylatedTRNAs = repmat(100, size(m.rna.matureTRNAIndexs));
            m.aminoacylatedTMRNA = 0;

            % 3 initiated, 3 idle
            m.evolveState();
            assertEqual(3, numel(find(m.ribosome.states==m.ribosome.activeValue)));
            assertTrue(~any(m.polypeptide.nascentMonomerLengths));
            assertEqual(0, sum(m.monomers));

            % 3 elongating, 3 initiated
            m.evolveState();
            assertEqual(6, numel(find(m.ribosome.states==m.ribosome.activeValue)));
            assertEqual([16 16 16 0 0 0]', m.polypeptide.nascentMonomerLengths);
            assertEqual(0, sum(m.monomers));

            % 3 terminated, 3 elongating
            m.evolveState();
            assertEqual(3, numel(find(m.ribosome.states==m.ribosome.activeValue)));
            assertEqual([0 0 0 16 16 16]', m.polypeptide.nascentMonomerLengths);
            assertEqual(3, sum(m.monomers));

            % 3 initiated, 3 terminated
            m.evolveState();
            assertEqual(3, numel(find(m.ribosome.states==m.ribosome.activeValue)));
            assertEqual([0 0 0 0 0 0]', m.polypeptide.nascentMonomerLengths);
            assertEqual(6, sum(m.monomers));

            % 3 elongating, 3 initiated
            m.evolveState();
            assertEqual(6, numel(find(m.ribosome.states==m.ribosome.activeValue)));
            assertEqual([16 16 16 0 0 0]', m.polypeptide.nascentMonomerLengths);
            assertEqual(6, sum(m.monomers));

            assertEqual(6, numel(find(m.ribosome.boundMRNAs)));
            assertEqual(6, numel(find(m.polypeptide.boundMRNAs)));
            assertEqual(100 * numel(m.rna.matureTRNAIndexs) - 150, sum(m.aminoacylatedTRNAs));

            % substrate usage = initiation + elongation + termination
            assertEqual(1e6-(12 + 2 * 150 + 2 * 6), m.substrates(m.substrateIndexs_gtp));
            assertEqual(12 + 2 * 150 + 2 * 6, m.substrates(m.substrateIndexs_gdp));
            assertEqual(12 + 2 * 150 + 2 * 6, m.substrates(m.substrateIndexs_phosphate));
            assertEqual(1e6-(12 + 2*150 + 3 * 6 + 3), m.substrates(m.substrateIndexs_water));
            assertEqual(12 + 3 * 150 + 2 * 6, m.substrates(m.substrateIndexs_hydrogen));

            assertEqual([6;6;6], m.enzymes(m.enzymeIndexs_initiationFactors));
            assertEqual([9;3;3;3], m.enzymes(m.enzymeIndexs_elongationFactors));
            assertEqual([3;3;3;3], m.boundEnzymes(m.enzymeIndexs_elongationFactors));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome30S));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome30SIF3));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome50S));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome70S));
            assertEqual(6, m.boundEnzymes(m.enzymeIndexs_ribosome70S));
        end

        function testBindingProbabilities(this)
            m = this.process;

            %plentiful substrate and enzyme and a small number of ribosomes
            numRibosomes = 50;
            m.substrates(:) = 1e6;
            m.enzymes(:) = 1e6;
            m.enzymes(m.enzymeIndexs_ribosome30S) = 0;
            m.enzymes(m.enzymeIndexs_ribosome30SIF3) = numRibosomes;
            m.enzymes(m.enzymeIndexs_ribosome50S) = numRibosomes;
            m.enzymes(m.enzymeIndexs_ribosome70S) = 0;

            %no bound ribosomes
            m.boundEnzymes(:) = 0;
            m.ribosome.states = repmat(m.ribosome.notExistValue, numRibosomes, 1);
            m.ribosome.boundMRNAs = zeros(numRibosomes, 1);
            m.polypeptide.boundMRNAs = zeros(numRibosomes, 1);
            m.polypeptide.nascentMonomerLengths = zeros(numRibosomes, 1);
            m.polypeptide.proteolysisTagLengths = zeros(numRibosomes, 1);
            m.ribosome.mRNAPositions = m.polypeptide.nascentMonomerLengths;
            m.ribosome.tmRNAPositions = m.polypeptide.proteolysisTagLengths;

            %binding probabilities
            m.mRNAs(1:numRibosomes) = 1;
            m.mRNAs(numRibosomes+1:end) = 0;

            m.evolveState();
            assertTrue(all(m.ribosome.states == m.ribosome.activeValue), 'not all ribosomes bound');
            assertEqual(1:numRibosomes, unique(m.ribosome.boundMRNAs)', 'not all mRNAs bound');
            assertEqual(1:numRibosomes, unique(m.polypeptide.boundMRNAs)', 'not all mRNAs bound');
        end

        function testRibosomeStalling(this)
            m = this.process;

            %% initial conditions: one ribosome bound to one mRNA
            m.stimuli(:) = 0;
            m.substrates(:) = 0;
            m.substrates(m.substrateIndexs_gtp) = 1e6;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_translationFactors) = 1;
            m.enzymes(m.enzymeIndexs_elongationGFactor) = 2;
            m.enzymes(m.enzymeIndexs_tmRNABindingProtein) = 1;
            m.enzymes(m.enzymeIndexs_peptidylTRNAHydrolase) = 1;
            m.boundEnzymes(:) = 0;
            m.boundEnzymes(m.enzymeIndexs_ribosome70S) = 1;
            m.boundTMRNA = 0;

            m.polypeptide.monomerAASequences = {'MKKKKKVVVVV'};
            m.polypeptide.monomerTRNASequences = {[10 20 20 20 20 20 29 29 29 29 29]'};
            m.polypeptide.monomerLengths = 11;
            m.monomers = 0;

            m.mRNAs = 1;
            m.ribosome.boundMRNAs = 1;
            m.polypeptide.boundMRNAs = 1;
            m.ribosome.states = m.ribosome.activeValue;
            m.ribosome.mRNAPositions = 0;
            m.ribosome.tmRNAPositions = 0;
            m.polypeptide.nascentMonomerLengths = 0;
            m.polypeptide.proteolysisTagLengths = 0;
            m.aminoacylatedTRNAs = repmat(20, size(m.rna.matureTRNAIndexs));
            m.aminoacylatedTRNAs(29) = 0;  % withhold valine
            m.aminoacylatedTMRNA = 1;
            m.tmRNABindingProbability = 1;

            %% elongation
            m.evolveState();
            assertEqual(m.ribosome.activeValue, m.ribosome.states(1));
            assertEqual(6, m.polypeptide.nascentMonomerLengths(1));
            assertEqual(0, m.polypeptide.proteolysisTagLengths(1));
            assertEqual(1, m.polypeptide.boundMRNAs(1));
            assertEqual(1, m.ribosome.boundMRNAs(1));
            assertEqual(0, m.monomers(1));

            %% stalling
            m.evolveState();
            assertEqual(m.ribosome.stalledValue, m.ribosome.states(1));
            assertEqual(6, m.polypeptide.nascentMonomerLengths(1));
            assertEqual(1, m.polypeptide.proteolysisTagLengths(1));
            assertEqual(1, m.polypeptide.boundMRNAs(1));
            assertEqual(1, m.ribosome.boundMRNAs(1));
            assertEqual(0, m.monomers(1));
            assertEqual(0, m.aminoacylatedTMRNA);
            assertEqual(0, m.enzymes(m.enzymeIndexs_tmRNA));
            assertEqual(1, m.boundTMRNA);
            assertEqual(zeros(20,1), m.substrates(m.substrateIndexs_aminoAcids));
            assertEqual(1e6 - 12, m.substrates(m.substrateIndexs_gtp));
            assertEqual(12, m.substrates(m.substrateIndexs_gdp));
            assertEqual(12, m.substrates(m.substrateIndexs_phosphate));
            assertEqual(1e6 - 12 + 6 -6 -1, m.substrates(m.substrateIndexs_water));
            assertEqual(12+6, m.substrates(m.substrateIndexs_hydrogen));

            %% elongation and termination of proteolysis tag
            m.aminoacylatedTRNAs(29) = 20;  % provide valine again
            m.evolveState();
            m.evolveState();
            assertEqual(1, numel(m.polypeptide.abortedSequences));
            assertEqual([1;0;0;0], m.enzymes(m.enzymeIndexs_elongationFactors));
            assertEqual([1;1;1;1], m.boundEnzymes(m.enzymeIndexs_elongationFactors));
            assertEqual(1, m.enzymes(m.enzymeIndexs_ribosome30S));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome30SIF3));
            assertEqual(1, m.enzymes(m.enzymeIndexs_ribosome50S));
            assertEqual(0, m.enzymes(m.enzymeIndexs_ribosome70S));
            assertEqual(0, m.boundEnzymes(m.enzymeIndexs_ribosome70S));
            assertEqual([19 18 18 20 20 20 20 20 20 20 14], m.aminoacylatedTRNAs(10:20)');

            %% freeing the elongation factors
            m.evolveState();
            assertEqual([2;1;1;1], m.enzymes(m.enzymeIndexs_elongationFactors));
            assertEqual([0;0;0;0], m.boundEnzymes(m.enzymeIndexs_elongationFactors));
        end

        function testDetailedMassBalance(this)
            m = this.process;

            m.mRNAs(:) = 0;
            m.mRNAs(1) = 1;

            m.enzymes = m.enzymes + m.boundEnzymes;
            m.boundEnzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_ribosome30S) = 1;
            m.enzymes(m.enzymeIndexs_ribosome30SIF3) = 0;
            m.enzymes(m.enzymeIndexs_ribosome50S) = 1;
            m.enzymes(m.enzymeIndexs_ribosome70S) = 0;

            m.ribosome.boundMRNAs = 0;
            m.polypeptide.boundMRNAs = 0;
            m.ribosome.states = m.ribosome.notExistValue;
            m.ribosome.mRNAPositions = 0;
            m.ribosome.tmRNAPositions = 0;
            m.polypeptide.nascentMonomerLengths = 0;
            m.polypeptide.proteolysisTagLengths = 0;

            m.substrates(:) = 1e6;
            m.aminoacylatedTRNAs(:) = 1e6;

            initSubstrates = m.substrates;

            for i = 1:200;
                m.evolveState();
                if m.monomers(1) == 1
                    break;
                end
            end

            finalSubstrates = initSubstrates;
            gtpCost = 3 + 2 * m.monomer.lengths(1);
            finalSubstrates(m.substrateIndexs_gtp) = finalSubstrates(m.substrateIndexs_gtp) - gtpCost;
            finalSubstrates(m.substrateIndexs_gdp) = finalSubstrates(m.substrateIndexs_gdp) + gtpCost;
            finalSubstrates(m.substrateIndexs_phosphate) = finalSubstrates(m.substrateIndexs_phosphate) + gtpCost;
            finalSubstrates(m.substrateIndexs_hydrogen) = finalSubstrates(m.substrateIndexs_hydrogen) ...
                + gtpCost ...           %energy
                + m.monomer.lengths(1); %peptidyl-tRNA bond
            finalSubstrates(m.substrateIndexs_water) = finalSubstrates(m.substrateIndexs_water) ...
                - gtpCost ...               %energy
                - m.monomer.lengths(1) ...  %peptidyl-tRNA bond
                + (m.monomer.lengths(1)-1); %peptide bond

            assertEqual(1, m.monomers(1));
            assertEqual(0, m.ribosome.boundMRNAs);
            assertEqual(finalSubstrates(setdiff(1:end, m.substrateIndexs_aminoAcids))', ...
                m.substrates(setdiff(1:end, m.substrateIndexs_aminoAcids))');
            assertEqual(finalSubstrates, m.substrates);
        end

        function testNoBiasedPausing(this)
            m = this.process;
            rib = m.ribosome;
            pol = m.polypeptide;

            %replace tRNA sequences with codons corresponding to limiting
            %tRNA
            pol.monomerTRNASequences = cellfun(@(seq) ones(1, 200), pol.monomerTRNASequences, 'UniformOutput', false);

            %all ribosomes
            %- active
            %- translating first mRNA at first codon which we've set to
            %  correspond to the limiting tRNA
            nRibs = 10;
            rib.states = repmat(rib.activeValue, [nRibs 1]);
            rib.boundMRNAs = ones(nRibs, 1);
            rib.mRNAPositions = zeros(nRibs, 1);
            rib.tmRNAPositions = zeros(nRibs, 1);

            %synchronize polypepide and ribosome states
            pol.boundMRNAs = rib.boundMRNAs;
            pol.nascentMonomerLengths = rib.mRNAPositions;
            pol.proteolysisTagLengths = rib.tmRNAPositions;
            pol.abortedPolypeptides = zeros(0, 3);

            %synchronize ribosome and protein complex states
            m.enzymes(:) = 0;
            m.boundEnzymes(:) = 0;
            m.boundEnzymes(m.enzymeIndexs_ribosome70S) = nRibs;
            m.enzymes(m.enzymeIndexs_translationFactors) = 100;
            m.boundEnzymes(m.enzymeIndexs_translationFactors) = 100;

            %simulate
            iterMax = 100;
            for i = 1:iterMax
                %lot of tRNA, but 1 tRNA limiting
                m.aminoacylatedTRNAs(:) = 100;
                m.aminoacylatedTRNAs(1) = 1;
                m.freeTRNAs(:) = 0;

                %simulate
                m.evolveState();
            end

            %assert that all ribosomes move
            assertEqual(nRibs, nnz(rib.mRNAPositions));
            assertIn(range(rib.mRNAPositions), [0 20]);
        end

        function testGeneEssentiality(this)
            m = this.process;

            m.substrates(:) = 1e6;
            m.enzymes(:) = 1e6;
            numRibosomes = 10;
            m.enzymes(m.enzymeIndexs_ribosome30SIF3) = 0;
            m.enzymes(m.enzymeIndexs_ribosome30S) = numRibosomes;
            m.enzymes(m.enzymeIndexs_ribosome50S) = numRibosomes;
            m.enzymes(m.enzymeIndexs_ribosome70S) = 0;
            m.boundEnzymes(m.enzymeIndexs_ribosome70S) = 0;
            m.aminoacylatedTRNAs = repmat(1e6, size(m.rna.matureTRNAIndexs));
            m.aminoacylatedTMRNA = 1e6;
            m.mRNAs(:) = 1;
            m.monomers(:) = 0;

            m.ribosome.states = zeros(0, 1);
            m.ribosome.boundMRNAs = zeros(0, 1);
            m.ribosome.mRNAPositions = zeros(0, 1);
            m.ribosome.tmRNAPositions = zeros(0, 1);
            m.polypeptide.boundMRNAs = zeros(0, 1);
            m.polypeptide.nascentMonomerLengths = zeros(0, 1);
            m.polypeptide.proteolysisTagLengths = zeros(0, 1);

            this.helpTestGeneEssentiality({
                'MG_173';   %translation initiation factor IF-1
                'MG_142';   %translation initiation factor IF-2
                'MG_196';   %translation initiation factor IF-3
                'MG_089';   %translation elongation factor G
                'MG_026';   %translation elongation factor P
                'MG_451';   %translation elongation factor Tu
                'MG_433';   %translation elongation factor Ts
                'MG_435';   %ribosome recycling factor
                'MG_473';   %ribosomal protein L33 type 2
                'MG_070';   %ribosomal protein S2
                'MG_081';   %ribosomal protein L11
                'MG_082';   %ribosomal protein L1
                'MG_087';   %ribosomal protein S12
                'MG_088';   %ribosomal protein S7
                'MG_090';   %ribosomal protein S6
                'MG_092';   %ribosomal protein S18
                'MG_093';   %ribosomal protein L9
                'MGrrnA5S';   %5S ribosomal rRNA
                'MGrrnA16S';  %16S ribosomal rRNA
                'MGrrnA23S';  %23S ribosomal rRNA
                'MG_150';   %ribosomal protein S10
                'MG_151';   %ribosomal protein L3
                'MG_152';   %ribosomal protein L4/L1 family
                'MG_153';   %ribosomal protein L23
                'MG_154';   %ribosomal protein L2
                'MG_155';   %ribosomal protein S19
                'MG_156';   %ribosomal protein L22
                'MG_157';   %ribosomal protein S3
                'MG_158';   %ribosomal protein L16
                'MG_159';   %ribosomal protein L29
                'MG_160';   %ribosomal protein S17
                'MG_161';   %ribosomal protein L14
                'MG_162';   %ribosomal protein L24
                'MG_163';   %ribosomal protein L5
                'MG_164';   %ribosomal protein S14
                'MG_165';   %ribosomal protein S8
                'MG_166';   %ribosomal protein L6
                'MG_167';   %ribosomal protein L18
                'MG_168';   %ribosomal protein S5
                'MG_169';   %ribosomal protein L15
                'MG_174';   %ribosomal protein L36
                'MG_175';   %ribosomal protein S13
                'MG_176';   %ribosomal protein S11
                'MG_178';   %ribosomal protein L17
                'MG_197';   %ribosomal protein L35
                'MG_198';   %ribosomal protein L20
                'MG_481';   %30S ribosomal protein S21
                'MG_232';   %ribosomal protein L21
                'MG_234';   %ribosomal protein L27
                'MG_257';   %ribosomal protein L31
                'MG_258';   %peptide chain release factor 1
                'MG_311';   %ribosomal protein S4
                'MG_325';   %ribosomal protein L33
                'MG_361';   %ribosomal protein L10
                'MG_362';   %ribosomal protein L7/L12
                'MG_363';   %ribosomal protein L32
                'MG_522';   %ribosomal protein S20
                'MG_417';   %ribosomal protein S9
                'MG_418';   %ribosomal protein L13
                'MG_424';   %ribosomal protein S15
                'MG_426';   %ribosomal protein L28
                'MG_444';   %ribosomal protein L19
                'MG_446';   %ribosomal protein S16
                'MG_466';   %ribosomal protein L34
                },...
                @(m,i) any(m.monomers > i.monomers),...
                struct('lengthSec', 75));
        end
    end

    methods
        function initializeProcessForSuccessfulInitiation(this)
            m = this.process;
            m.substrates(m.substrateIndexs_gtp) = 1e6;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.enzymes(:) = 10;
            m.boundEnzymes(:) = 0;
            m.aminoacylatedTRNAs = repmat(20, size(m.rna.matureTRNAIndexs));
            m.mRNAs(:) = 1;
            m.ribosome.states(:) = m.ribosome.notExistValue;
        end

        function initializeProcessForSuccessfulElongation(this, numAAs)
            m = this.process;
            m.substrates(m.substrateIndexs_gtp) = 2 * numAAs;
            m.substrates(m.substrateIndexs_water) = 1e6;
            m.mRNAs(:) = 1;
            m.enzymes(:) = 0;
            m.enzymes(m.enzymeIndexs_elongationFactors) = 1;
            m.boundEnzymes(:) = 0;
            m.boundEnzymes(m.enzymeIndexs_ribosome70S) = 1;
            m.ribosome.boundMRNAs = 1;
            m.polypeptide.boundMRNAs = 1;
            m.ribosome.states = m.ribosome.activeValue;
            m.ribosome.mRNAPositions = 0;
            m.ribosome.tmRNAPositions = 0;
            m.polypeptide.nascentMonomerLengths = 0;
            m.polypeptide.proteolysisTagLengths = 0;
            m.aminoacylatedTRNAs(:) = numAAs;
        end
    end
end


function [approach,action] = gui_configapproach(approach,dosave)
% bring up a modal configuration dialog for the given approach
% [Approach,Action] = gui_configapproach(Approach)
%
% In:
%   Approach : an approach; struct with fields 'paradigm' and 'parameters' (and optionally 'description' and 'name')
%              or cell array {paradigm, parameter1, parameter2, ...}
%
%   DoSave: Whether to bring up a save approach gui, after clicking okay (default: false)
%
% Out:
%   Result : a (re-)configured version of the Approach, or the unmodified input Approach (though possibly reformatted) if the user pressed 'Cancel'
%   Action : either 'OK' or 'Cancel'
%
%                           Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                           2010-10-25

if ~exist('approach','var') || isempty(approach)
    approach = gui_chooseapproach();
    if isempty(approach)
        return; end
end

if ~exist('dosave','var') || isempty(dosave)
    dosave = false; end

if iscell(approach)
    approach = struct('paradigm',approach{1}, 'parameters', {approach(2:end)}); end

calibrate_func = approach.paradigm;
if ischar(calibrate_func)
    instance = eval(calibrate_func); %#ok<NASGU>
    calibrate_func = eval('@instance.calibrate');
end

% bring up the GUI
result = arg_guidialog(calibrate_func,'params',approach.parameters,'title','BCILAB: Configure approach','Invoke',false);
if ~isempty(result)
    approach.parameters = {result};
    % get rid of hidden references...
    approach = utl_prune_handles(approach);
    if dosave
        gui_saveapproach(approach); end
    action = 'OK';
else
    action = 'Cancel';
end


function writeMesh(fileName, vertices, faces, varargin)
%WRITEMESH Write 3D mesh data by inferring format from file name.
%
%   writeMesh(FNAME, V, F)
%
%   writeMesh(FNAME, MESH)
%
%   Example
%   writeMesh
%
%   See also
%     meshes3d, readMesh, writeMesh_off, writeMesh_ply, writeMesh_stl
%

% ------
% Author: David Legland
% E-mail: david.legland@inrae.fr
% Created: 2020-11-20, using Matlab 9.8.0.1323502 (R2020a)
% Copyright 2020-2022 INRAE - BIA Research Unit - BIBS Platform (Nantes)

% check inputs
if ~ischar(fileName)
    error('First argument must contain the name of the file');
end

% optionnaly parses data
if isstruct(vertices)
    if nargin > 2
        varargin = [{faces} varargin{:}];
    end
    faces = vertices.faces;
    vertices = vertices.vertices;
end

[~, ~, ext] = fileparts(fileName);
switch lower(ext)
    case '.off'
        writeMesh_off(fileName, vertices, faces);
    case '.ply'
        writeMesh_ply(fileName, vertices, faces, varargin{:});
    case '.stl'
        writeMesh_stl(fileName, vertices, faces, varargin{:});
    otherwise
        error('Unrecognized file format for rezading mesh: %s', ext);
end


function [networks, rxnNumGenes] = GPR2models(metabolic_model, selected_rxns, separate_transcript, numWorkers, printLevel)
% Each GPR rule is converted into a network where the reaction and genes
% involved are interconnected.
%
% USAGE:
%
%    [networks, rxnNumGenes] = GPR2models(metabolic_model, selected_rxns, separate_transcript, numWorkers, printLevel)
%
% INPUTS:
%    metabolic_model:        Metabolic model structure (COBRA Toolbox format)
%    selected_rxns:          Index array which indicates selected reactions to
%                            calculate the network.
%    separate_transcript:    Character used to discriminate
%                            different isoforms of a gene. Default ''.
%
% OPTIONAL INPUTS:
%    numWorkers:        Maximum number of workers
%                       * 0 - maximum provided by the system (automatic)
%                       (default). If parallel pool is active, numWorkers
%                       is defined by the system, otherwise is 1.
%                       * 1 - sequential
%                       * 2+ - parallel
%    printLevel:        show the reactions created in models.
%                       * 0 - shows nothing
%                       * 1 - shows progress by reactions (default)
%                       * 2+ - shows everything (reaction and network generation)
%
% OUTPUT:
%    networks:          Cell array which contains all the networks.
%    rxnNumGenes:       Array with the number of genes present in each GPR
%                       rule for each reaction.
%
% .. Authors:
%       - Inigo Apaolaza, Aug 2017, University of Navarra, TECNUN School of Engineering.
%       - Luis V. Valcarcel, Aug 2017, University of Navarra, TECNUN School of Engineering.
%       - Francisco J. Planes, Aug 2017, University of Navarra, TECNUN School of Engineering.
%       - Inigo Apaolaza, April 2018, University of Navarra, TECNUN School of Engineering.

p = inputParser;
% check required arguments
addRequired(p, 'metabolic_model');
addOptional(p, 'selected_rxns', [], @isnumeric);
addOptional(p, 'separate_transcript', '', @(x)ischar(x)); % default is empty
addOptional(p, 'numWorkers', 0, @(x)isnumeric(x)&&isscalar(x)); % Default is gpc('nocreate')
addOptional(p, 'printLevel', 1, @(x)isnumeric(x)&&isscalar(x));
% extract variables from parser
parse(p, metabolic_model, selected_rxns, separate_transcript, numWorkers, printLevel);
metabolic_model = p.Results.metabolic_model;
selected_rxns = p.Results.selected_rxns;
separate_transcript = p.Results.separate_transcript;
numWorkers = p.Results.numWorkers;
printLevel = p.Results.printLevel;

% fill with all reactions
if (isempty(selected_rxns))
    selected_rxns = 1:length(metabolic_model.rxns);
end

% Step 1: check the fields of the input metabolic model
if ~isfield(metabolic_model,'genes')
    error('The genes of the model are not defined');
end
if ~isfield(metabolic_model,'rxns')
    error('The reactions of the model are not defined');
end
if ~isfield(metabolic_model,'grRules') || ~isfield(metabolic_model,'rules') ||~isfield(metabolic_model,'rxnGeneMat')
    error('The GPR rules of the model are not defined');
end

%rxnGeneMat is a required field for this function, so if it does not exist,
%build it.
if ~isfield(metabolic_model,'rxnGeneMat')
    metabolic_model = buildRxnGeneMat(metabolic_model);
end

% Generate a cell array to store the resulting models
networks = cell(size(selected_rxns));

% Examine if there is an existing pool
p = gcp('nocreate'); % If no pool, do not create new one.
if isempty(p)
    poolsize = 0;               % Single core
elseif numWorkers == 0
    poolsize = p.NumWorkers;    % Multi core, all cores in the PC
elseif numWorkers == 1
    poolsize = 0;               % Single core
else
    p = parpool(numWorkers);
    poolsize = p.NumWorkers;    % Multi core, limited by user
end

% Step 2: Create models
if printLevel > 0 && length(selected_rxns)>1
    disp('Calculating Networks for GPR rules...');
end
parfor (i=1:length(selected_rxns),poolsize)
    if printLevel > 0
%         clc
        disp([num2str(i),' of ', num2str(length(selected_rxns)) ,' rxns']);
    end
    RXN = metabolic_model.rxns{selected_rxns(i)};
    % Create empty model
    model = createModel();
    % include metabolic reaction as objective metabolite
    model.mets{1} = RXN;
    % Add objective function
    model.rxns{1} = RXN;
    model.S(1,1) = -1;

    % Check if there is any gene related to this reaction and add them
    genes = metabolic_model.genes(metabolic_model.rxnGeneMat(selected_rxns(i),:)>0);
    if length(genes)>1
        model.mets = vertcat(RXN, genes); % Include genes in the model
%         model = addMetabolite(model,genes);
        model.genes = genes;
        fp = FormulaParser();
        head = fp.parseFormula(metabolic_model.rules{selected_rxns(i)});
        model = modelParser(model,metabolic_model.genes,head,[RXN,'_N_1'],RXN, printLevel);
        model = reduceModel(model);
    elseif length(genes)==1
        model.mets = vertcat(RXN, genes); % Include genes in the model
        model.genes = genes;
        model.rxns(2) = genes;
        model.S(1:2,2) = [+1 -1];
    else
        model.rxns{2} = 'NO_GENES';
        model.S(1,1:2) = [-1 +1];
    end

    % Include Exchange reactions
    [~, gene_idx] = ismember(genes, model.mets);
    demand_idx = (1:length(genes)) + length(model.rxns);
    % compulsitory fields
    model.rxns(demand_idx) = strcat('DM_',genes);
    model.rxns = model.rxns';
    model.S(gene_idx,demand_idx) = eye(length(genes));

    % converge isoforms (if neccesary)
    if ~isempty(separate_transcript) && length(genes)>1
        model = convergeTranscripts2Gene(model, separate_transcript);
    end

    % Generate rest of fields
    idx_rxns = (1:length(model.rxns))';
    idx_mets = (1:length(model.mets))';
    model.b(idx_mets) = 0;
    model.csense(idx_mets) = 'E';
    model.c(idx_rxns) = 0;
    model.c(1) = 1;
    model.lb(idx_rxns) = 0;
    model.ub(idx_rxns) = inf;
    model.ub(1) = 1000;
    model.rules(demand_idx) = {''};
    model.b = model.b';
    model.c = model.c';
    model.lb = model.lb';
    model.ub = model.ub';
    model.rules = model.rules';

    % Store the model
    networks{i} = model;
end

% Calculate the number of genes per GPR rule
rxnNumGenes = zeros(size(selected_rxns));
for i = 1:length(selected_rxns)
    rxn = selected_rxns(i);
    idx_genes = find(metabolic_model.rxnGeneMat(rxn,:));
    rxn_isoforms = metabolic_model.genes(idx_genes);
    rxn_genes = unique(strtok(rxn_isoforms,separate_transcript));
    rxnNumGenes(i) = length(rxn_genes);
end

end

function model = modelParser(model,genes,head,node_parent,parent,printLevel)
% This function look into the GPRparser and builds auxiliary nodes for each
% layer of the GPR rules.
% For example:
%     g1 & g2 & g3 is one layer in the model,   RXN = g1 + g2 + g3
%     (g1 | g2) & g3 is a two layer model:      RXN = (g1 | g2) + g3
%                                               (g1 | g2) = g1
%                                               (g1 | g2) = g2

%  Name nodes according to position and layer inside the GPR rule
node = strcat({[node_parent,'_']},cellfun(@num2str,num2cell(1:length(head.children)),'UniformOutput', false));

% model = addMetabolite(model, node);
model.mets = vertcat(model.mets,node');
[~, idx_new_mets] = ismember(node, model.mets);

idx_parent_mets = find(strcmp(parent, model.mets));

%  Expand model with every node, using OR/AND rules
if isa(head,'OrNode')
    idx_new_rxn = length(model.rxns) + (1:length(head.children));
    model.rxns(idx_new_rxn) = node;
    model.S(idx_new_mets,idx_new_rxn) = -eye(length(head.children));
    model.S(idx_parent_mets,idx_new_rxn) = +1;
else
    idx_new_rxn = length(model.rxns)+1;
    model.rxns{idx_new_rxn} = ['AND_' parent];
    model.S(idx_new_mets,idx_new_rxn) = -1;
    model.S(idx_parent_mets,idx_new_rxn) = +1;
end

for i=1:length(head.children)
    child = head.children(i);
    % check if the child is final layer
    if isa(child,'LiteralNode')
        gen = genes(str2double(child.id));
        idx_new_rxn = length(model.rxns)+1;
        idx_met_gen = strcmp(gen,model.mets);
        idx_met_node = strcmp(node(i),model.mets);
        model.rxns{idx_new_rxn} = [gen{1},'_',node{i}];
        model.S(idx_met_node,idx_new_rxn) = +1;
        model.S(idx_met_gen,idx_new_rxn) = -1;
    else
        model = modelParser(model,genes,child,node{i},node{i},printLevel);
    end
end

end

function modelOut = reduceModel(model)
% As the algorithm generates redundant nodes, this function is used to
% remove these nodes:
% Ej:       gen -> node -> rule  == gen -> rule

% This is done for every gene of the model
genes = model.genes;
for gen=1:length(genes)
    gen_idx = strcmp(model.mets,genes{gen}); % find idx of gene
    rxn_gen_out = find(model.S(gen_idx,:)<0);   % find reactions that consume gene
    % for each reaction, find consumption node
    [node_idx,~] = find(model.S(:,rxn_gen_out)>0);
    for i = 1:length(node_idx)
        % for each reaction, find consumption node
        node_name = model.mets(node_idx(i));
        % find reactions out of this node
        [~, rxn_idx] = find((model.S(node_idx(i),:)<0));
        rxn_name = model.rxns(rxn_idx);
        % in this reaction, change (node -> rule) for (gene -> rule)
        model = changeRxnMets(model, node_name, genes(gen), rxn_name);
    end
    % remove stoichimetri of intermediate nodes
    model.S(node_idx,:)=0;
    % remove output of genes to intermediate nodes
    model.S(:,rxn_gen_out)=0;
end

% remove unused reactions and unused metabolites
idx_rxns = sum(model.S~=0,1)>0;
idx_mets = sum(model.S~=0,2)>0;
modelOut.S = model.S(idx_mets,idx_rxns);
modelOut.rxns = model.rxns(idx_rxns);
modelOut.mets = model.mets(idx_mets);

end

function model = convergeTranscripts2Gene(model, separate_transcripts)
% Some COBRA models have transcripts instead of genes. Most of the
% transcripts have the same functionallity, so we can converge them as the
% same gene.
% Ej:       gene 10005.1
%           gene 10005.2        ==>     gene 10005
%           gene 10005.3
%
% This is done for every gene of the model at exchange reaction level

% seach demand reactions
idx_DM_rxns = startsWith(model.rxns,'DM_');
DM_rxns = model.rxns(idx_DM_rxns);
% obtain isoforms and genes
transcripts = regexprep(DM_rxns,'DM_','');
genes = strtok(transcripts,separate_transcripts);

% Remove all the previously existing exchange reactions
model.S = model.S(:,~idx_DM_rxns);
model.rxns = model.rxns(~idx_DM_rxns);

% Divide into genes with one transcript and two or more transcripts
x = tabulate(genes);
genes_unique = x(:,1);
genes_one_transcrits = x(cell2mat(x(:,2))==1,1);
genes_more_transcripts = x(cell2mat(x(:,2))>1,1);

% For genes with one transcript, just change the name
[~,idx_genes_one_transcript] = ismember(genes_one_transcrits, strtok( model.mets,separate_transcripts));
model.mets(idx_genes_one_transcript) = genes_one_transcrits;

% For genes with more than one transcript, converge them into one
% metabolite
% Generate new metabolites
model = addMetabolite(model, genes_more_transcripts);
% Converge genes
for i = 1:length(genes_more_transcripts)
    gen_idx = find(strcmp(genes_more_transcripts{i}, model.mets));
    transcripts_idx = find(strcmp(genes_more_transcripts{i}, strtok( model.mets,separate_transcripts)));
    transcripts_idx = setdiff(transcripts_idx,gen_idx);
    % new reactions to converge genes
    idx_new_rxns = length(model.rxns)+1 : length(model.rxns) + length(transcripts_idx);
    model.S(transcripts_idx,idx_new_rxns) = +eye(length(transcripts_idx)); % produce transcript
    model.S(gen_idx,idx_new_rxns) = -1; % consume gene
    model.rxns(idx_new_rxns) = strcat('Con_',genes_more_transcripts{i},'_',model.mets(transcripts_idx));
end

% Generate new demand reactions for all genes
[~, gene_idx] = ismember(genes_unique, model.mets);
demand_idx = (1:length(genes_unique)) + length(model.rxns);
model.rxns(demand_idx) = strcat('DM_',genes_unique);
model.S(gene_idx,demand_idx) = eye(length(genes_unique));

end


function [im,header,timestamp,bb,mu] = mmf_read_frame(header,framei)

fp = header.fid;

% read from the current location if no frame input
if nargin < 2,
  loc = ftell(fp);
  framei = find(header.frame2file==loc,1);
  if isempty(framei),
    error('Could not find file location %d in frame index',loc);
  end
else
  fseek(fp,header.frame2file(framei),'bof');
end

[mu,header] = mmf_read_mean(header,'framei',framei);

im = mu;
im_idcode = fread(fp,1,'ulong'); %#ok<NASGU>
im_headersize = fread(fp,1,'int');
%im_depth = fread(fp,1,'int');
%im_nchannels = fread(fp,1,'int');
fseek(fp,8,'cof');
im_numblocks = fread(fp,1,'int');

% seek to the end of the header
fseek(fp,header.frame2file(framei)+im_headersize,'bof');

bb = nan(im_numblocks,4);
%for j = 1:im_numblocks,
  block_rect = fread(fp,4,'int');
  j=1;
while numel(block_rect) == 4 && block_rect(1)>=0
  %if block_rect(1)<0
      %disp(['skipping blocks ',num2str(framei),' ',mat2str(block_rect),sprintf(' block %d / %d',j,im_numblocks)])
      %break;
  %end
  bb(j,[2,1,4,3]) = block_rect;
  if block_rect(3)>header.height || block_rect(4) > header.width || any(block_rect<=0),
    break;
  end

  % then interlaced row ordered image data
  block_data = fread(fp,block_rect(3)*block_rect(4),'*uint8');
  block_data = reshape(block_data,[block_rect(3),block_rect(4)]);
  im(block_rect(1)+1:block_rect(1)+block_rect(3),block_rect(2)+1:block_rect(2)+block_rect(4)) = block_data;
  [block_rect,count] = fread(fp,4,'int');
  if count < 4,
    break;
  end
  j=j+1;
end
%disp([num2str(framei),' ',mat2str(block_rect),sprintf(' block %d / %d',j-1,im_numblocks)])
timestamp = nan;


function doZeroRange(solver,varargin)

zrm = getClass(varargin,'zeroRangeMethod');

if isempty(zrm), zrm = zeroRangeMethod(solver.pf,varargin{:}); end

isZero = zrm.checkZeroRange(solver.S3G);

solver.S3G = subGrid(solver.S3G,~isZero);

end


function [x_star_all, varx_star_all, mini] = ...
    vargplvmPredictLatent(model, Yts, testInd, batchMode, iters, displayTestOpt, mini, initQx, parallel)

% VARGPLVMPREDICTLATENT Given output observation(s) compute the approximate
% posterior
% DESC Given an output observed test point y* (or set of test points Y*)
% compute the approximate posterior p(X* | Y*) for the corresponding latent
% points.
%
% ARG model: The trained vargplvm model
% ARG Yts: The set of outputs observations
% ARG testInd: The indices of Yts to do inference for (default: all)
% ARG batchMode: If set to true, then if N* points are given in Yts, only
% one optimisation will be done in the N*-dimensional space. Otherwise, N*
% 1-dimensional optimisations will be performed. Batch mode is faster but
% possibly less accurate.
% ARG iters: the number of test iterations for the optimisation(s)
% ARG displayTestOpt: If set to true, then the test iterations will be
% displayed
% ARG mini: The indices of the points in the test set for which the test
% latent points are initialised with, ie x*(i,:) will be initialised with
% Xtrain(mini(i), :). If this vector is not given then this vector is
% computed here in the default way.
% ARG initQx: Direct initialisation (instead of mini). Has to contain
% .means and .covars
%
% SEEALSO:
%
% COPYRIGHT : Andreas C. Damianou, 2013
%
% VARGPLVM

if nargin < 2 || isempty(model) || isempty(Yts), error('At least 2 arguments needed!'); end
if nargin < 3 || isempty(testInd), testInd = 1:size(Yts,1); end
if nargin < 4 || isempty(batchMode), batchMode = false; end
if nargin < 5 || isempty(iters), iters = model.globalOpt.reconstrIters; end
if nargin < 6 || isempty(displayTestOpt), displayTestOpt = false; end
if nargin < 7, mini = []; end
if nargin < 8, initQx = []; end
if nargin < 9, parallel = []; end

try
    pool_open = matlabpool('size')>0;
catch e
    pool_open = 0;
end
if pool_open && ~isempty(parallel) && size(Yts,1) > 3 && ~batchMode
    parallel = parallel;
    warning('Parallel predictions!')
else
    parallel = false;
end

miniGiven = ~isempty(mini);
initQxGiven = ~isempty(initQx);

if initQxGiven && miniGiven
    error('Both initial training indices AND initial X was given!')
end

if batchMode
    y_star = Yts(testInd,:);
    if ~initQxGiven
        if ~miniGiven
            mini = NaN(1,length(testInd));
            for i=1:length(testInd)
                dst = dist2(y_star(i,:), model.y);
                [~, mini(i)] = min(dst);
            end
        end
        model.mini = mini;
        vardistx = vardistCreate(model.vardist.means(mini, :), model.q, 'gaussian');
        vardistx.covars = model.vardist.covars(mini, :);
    else
        vardistx = vardistCreate(initQx.means, model.q, 'gaussian');
        vardistx.covars = initQx.covars;
    end
    model.vardistx = vardistx;
    [x_star_all, varx_star_all] = vargplvmOptimisePoint(model, vardistx, y_star, true, iters);
else
    if parallel
        x_star_allCell = cell(length(testInd), 1);
        varx_star_allCell = cell(length(testInd), 1);
        if ~initQxGiven &&  ~miniGiven
            mini = NaN(1,length(testInd));
        end
        for i=1:length(testInd)
             curInd = testInd(i);
             YYts{i} = Yts(curInd,:);
             if initQxGiven
                initQxMeans{i} = initQx.means(i,:);
                initQxCovars{i} = initQx.covars(i,:);
             else
                 initQxMeans{i} = [];
                 initQxCovars{i} = [];
             end
             miniCell{i} = mini(i);
        end
         Ytr = model.y;
        pb = myProgressBar(length(testInd), min(length(testInd),20));
        for i=1:length(testInd)
            pbb{i} = pb;
        end
        parfor i=1:length(testInd)
            pbb{i} = myProgressBar(pbb{i},i);
            y_star =YYts{i};
            if ~initQxGiven
                if ~miniGiven
                    dst = dist2(y_star, Ytr);
                    [~, miniCur] = min(dst);
                    miniCell{i} = miniCur;
                else
                    miniCur = miniCell{i};
                end
                modelCur = model;
                modelCur.mini = miniCur;
                vardistx = vardistCreate(modelCur.vardist.means(miniCur,:), modelCur.q, 'gaussian');
                vardistx.covars = modelCur.vardist.covars(miniCur,:);
            else
                vardistx = vardistCreate(initQxMeans{i}, modelCur.q, 'gaussian');
                vardistx.covars = initQxCovars{i};
            end
            modelCur.vardistx = vardistx;

            % Find p(X_* | Y_*) which is approximated by q(X_*)
            [x_star, varx_star] = vargplvmOptimisePoint(modelCur, vardistx, y_star, displayTestOpt, iters);
            x_star_allCell{i} = x_star;
            varx_star_allCell{i} = varx_star;
        end
        for i=1:length(testInd)
            x_star_all(i,:) = x_star_allCell{i};
            varx_star_all(i,:) = varx_star_allCell{i};
            mini(i) = miniCell{i};
        end
        fprintf(1, '\n');
%         %.. TODO
%         x_star_all = zeros(length(testInd), model.q);
%         varx_star_all = zeros(length(testInd), model.q);
%         if ~initQxGiven &&  ~miniGiven
%             mini = NaN(1,length(testInd));
%         end
%         pb = myProgressBar(length(testInd), min(length(testInd),20));
%         YYts = cell(length(testInd),1);
%         initQxMeans = cell(length(testInd),1);
%         initQxCovars = cell(length(testInd),1);
%         for i=1:length(testInd)
%             curInd = testInd(i);
%             YYts{i} = Yts(curInd,:);
%             initQxMeans{i} = initQx.means(i,:);
%             initQxCovars{i} = initQx.covars(i,:);
%         end
%         parfor i=1:length(testInd)
%             pb = myProgressBar(pb,i);
%             %curInd = testInd(i);
%             y_star = YYts{i};
%             modelTmp = model;
%             if ~initQxGiven
%                 if ~miniGiven
%                     dst = dist2(y_star, model.y);
%                     [~, mini(i)] = min(dst);
%                 end
%                 modelTmp.mini = mini(i);
%                 vardistx = vardistCreate(modelTmp.vardist.means(mini(i),:), modelTmp.q, 'gaussian');
%                 vardistx.covars = modelTmp.vardist.covars(mini(i),:);
%             else
%                 vardistx = vardistCreate(initQxMeans{i}, modelTmp.q, 'gaussian');
%                 vardistx.covars = initQxCovars{i};
%             end
%             modelTmp.vardistx = vardistx;
%
%             % Find p(X_* | Y_*) which is approximated by q(X_*)
%             [x_star, varx_star] = vargplvmOptimisePoint(modelTmp, vardistx, y_star, displayTestOpt, iters);
%             x_star_all(i,:) = x_star;
%             varx_star_all(i,:) = varx_star;
%         end
%         fprintf(1, '\n');
    else
        x_star_all = zeros(length(testInd), model.q);
        varx_star_all = zeros(length(testInd), model.q);
        if ~initQxGiven &&  ~miniGiven
            mini = NaN(1,length(testInd));
        end
        pb = myProgressBar(length(testInd), min(length(testInd),20));
        for i=1:length(testInd)
            pb = myProgressBar(pb,i);
            curInd = testInd(i);
            y_star = Yts(curInd,:);
            if ~initQxGiven
                if ~miniGiven
                    dst = dist2(y_star, model.y);
                    [~, mini(i)] = min(dst);
                end
                model.mini = mini(i);
                vardistx = vardistCreate(model.vardist.means(mini(i),:), model.q, 'gaussian');
                vardistx.covars = model.vardist.covars(mini(i),:);
            else
                vardistx = vardistCreate(initQx.means(i,:), model.q, 'gaussian');
                vardistx.covars = initQx.covars(i,:);
            end
            model.vardistx = vardistx;

            % Find p(X_* | Y_*) which is approximated by q(X_*)
            [x_star, varx_star] = vargplvmOptimisePoint(model, vardistx, y_star, displayTestOpt, iters);
            x_star_all(i,:) = x_star;
            varx_star_all(i,:) = varx_star;
        end
        fprintf(1, '\n');
    end
end


function i4vec_write ( output_filename, n, x )

%*****************************************************************************80
%
%% I4VEC_WRITE writes an I4VEC file.
%
%  Discussion:
%
%    An I4VEC is a vector of I4's.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 July 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string OUTPUT_FILENAME, the output filename.
%
%    Input, integer N, the number of points.
%
%    Input, integer X(N), the vector.
%

%
%  Open the file.
%
  output_unit = fopen ( output_filename, 'wt' );

  if ( output_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'I4VEC_WRITE - Error!\n' );
    fprintf ( 1, '  Could not open the output file.\n' );
    error ( 'I4VEC_WRITE - Error!' );
  end

  for j = 1 : n
    fprintf ( output_unit, '%d\n', x(j) );
  end
%
%  Close the file.
%
  fclose ( output_unit );

  return
end


%--- help for generic/report ---
%
%  Assigns the elements of interest to a rise_report.report object
%
%    - display the default inputs::
%
%         report(rise.empty(0))
%
%    - assign the reported elements in rep_items to destination_root::
%
%         report(obj,destination_root,rep_items)
%
%    - assign varargin to obj before doing the rest::
%
%         report(obj,destination_root,rep_items,varargin)
%
%  Args:
%
%     obj (rise | dsge):
%     destination_root (rise_report.report): handle for the actual report
%     rep_items (char | cellstr): list of desired items to report. This list
%        can only include
%
%        - endogenous
%        - exogenous
%        - observables
%        - parameters
%        - solution
%        - estimation
%        - estimation_statistics
%        - equations
%        - code
%
%  Returns:
%     :
%
%     - none (Update the report in place)
%
%


hydro = struct();

hydro = readWAMIT(hydro,'rm3.out',[]);
hydro = radiationIRF(hydro,20,[],[],[],[]);
hydro = radiationIRFSS(hydro,[],[]);
hydro = excitationIRF(hydro,20,[],[],[],[]);
writeBEMIOH5(hydro)
plotBEMIO(hydro)


function [HDR] = sclose(HDR)
% SCLOSE closes the file with the handle HDR
% [HDR] = sclose(HDR)
%    HDR.FILE.status = -1 if file could not be closed.
%    HDR.FILE.status = 0 indicates the file has been closed.
%
% see also: SOPEN, SREAD, SSEEK, STELL, SCLOSE, SWRITE

% 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.

%	$Id$
%	(C) 1997-2005,2006,2008 by Alois Schloegl <a.schloegl@ieee.org>
%    	This is part of the BIOSIG-toolbox http://biosig.sf.net/

if (HDR.FILE.FID<0) || ~HDR.FILE.OPEN,
        HDR.FILE.status = -1;
        %fprintf(HDR.FILE.stderr,'Warning SCLOSE (%s): invalid handle\n',HDR.FileName);
end;

if HDR.FILE.OPEN >= 2,          % write-open of files
	% check file length - simple test for file integrity
        EndPos = ftell(HDR.FILE.FID);          % get file length
        % force file pointer to the end, otherwise Matlab 6.5 R13 on PCWIN
        status = fseek(HDR.FILE.FID,0,'eof');

        if strcmp(HDR.TYPE,'BKR');
                if HDR.NS<1,
                        fprintf(HDR.FILE.stderr,'Error SCLOSE BKR: number of channels (HDR.NS) must be larger than zero.\n');
                        return;
                end;
                if HDR.NRec<1,
                        fprintf(HDR.FILE.stderr,'Error SCLOSE BKR: number of blocks (HDR.NRec) must be larger than zero.\n');
                        return;
                end;
                % check file length and write Headerinfo.
                HDR.SPR = (EndPos-HDR.HeadLen)/(HDR.NRec*HDR.NS*2);
                if isnan(HDR.SPR), HDR.SPR=0; end;
                if HDR.FILE.OPEN==3;
                        if any(isnan([HDR.NRec,HDR.NS,HDR.SPR,HDR.DigMax,HDR.PhysMax,HDR.SampleRate])), 	% if any unknown, ...
                                fprintf(HDR.FILE.stderr,'Error SCLOSE BKR: some important header information is still undefined (i.e. NaN).\n');
                                fprintf(HDR.FILE.stderr,'\t HDR.NRec,HDR.NS,HDR.SPR,HDR.DigMax,HDR.PhysMax,HDR.SampleRate must be defined.\n');
                                fprintf(HDR.FILE.stderr,'\t Try again.\n');
                        end;

                        fclose(HDR.FILE.FID);
                        HDR.FILE.FID = fopen(HDR.FileName,'r+');

                        count=fwrite(HDR.FILE.FID,HDR.VERSION,'int16');	        % version number of header
                        count=fwrite(HDR.FILE.FID,HDR.NS,'int16');	        % number of channels
                        count=fwrite(HDR.FILE.FID,HDR.SampleRate,'int16');      % sampling rate
                        count=fwrite(HDR.FILE.FID,HDR.NRec,'int32');            % number of trials: 1 for untriggered data
                        count=fwrite(HDR.FILE.FID,HDR.SPR,'uint32');            % samples/trial/channel
                        count=fwrite(HDR.FILE.FID,HDR.PhysMax,'int16');		% Kalibrierspannung
                        count=fwrite(HDR.FILE.FID,HDR.DigMax, 'int16');		% Kalibrierwert
                        count=fwrite(HDR.FILE.FID,zeros(4,1),'uint8');
                        count=fwrite(HDR.FILE.FID,[HDR.Filter.LowPass,HDR.Filter.HighPass],'float');

                        fseek(HDR.FILE.FID,32,'bof');
                        HDR.FLAG.TRIGGERED   = HDR.NRec>1;	% Trigger Flag
                        count = fwrite(HDR.FILE.FID,HDR.FLAG.TRIGGERED,'int16');           % FLAG TRIGGERED
                end;

	elseif strcmp(HDR.TYPE,'EDF') || strcmp(HDR.TYPE,'BDF') || strcmp(HDR.TYPE,'GDF'),
         	tmp = floor((EndPos - HDR.HeadLen) / HDR.AS.bpb);  % calculate number of records
                if isnan(tmp)
                	tmp = 0;
                end;

                if (HDR.NRec~=tmp)
                       if ~any(HDR.FILE.PERMISSION=='z')
                               HDR.NRec=tmp;
                               fseek(HDR.FILE.FID,236,'bof');
                               if strcmp(HDR.TYPE,'GDF')
                                        c=fwrite(HDR.FILE.FID,[HDR.NRec,0],'int32');
                               else
                                        fprintf(HDR.FILE.FID,'%-8i',HDR.NRec);
                                end;
                        else    %% due to a limitation in zlib
                                fprintf(HDR.FILE.stderr,'ERROR SCLOSE: number-of-records-field (HDR.NRec) could not be updated in file %s.\n',HDR.FileName);
                        end;
                end;

                if strcmp(HDR.TYPE,'GDF') && isfield(HDR,'EVENT'),
                	if ~all([HDR.NS, HDR.NRec, HDR.AS.bpb]>0)
                		HDR.AS.EVENTTABLEPOS = HDR.HeadLen;
                	else
	                        HDR.AS.EVENTTABLEPOS = HDR.HeadLen+HDR.AS.bpb*HDR.NRec;
	                end;
                        if isfield(HDR.EVENT,'VAL')
                                % handling of sparse (non-equidistant) sampling values
                                if isempty(HDR.EVENT.DUR)
                                        HDR.EVENT.DUR = zeros(size(HDR.EVENT.TYP));
                                end;
                                if (HDR.VERSION<1.90)
                                        fprintf(2,'Warning SCLOSE: GDF v2.0 or higher required for storing sparse samples but version is only %4.2f.\n',HDR.VERSION);
                                        %ix0 = ~isnan(HDR.EVENT.VAL);
                                        %HDR.EVENT.POS = HDR.EVENT.POS(~ix0);
                                        %HDR.EVENT.TYP = HDR.EVENT.TYP(~ix0);
                                        %HDR.EVENT.CHN = HDR.EVENT.CHN(~ix0);
                                        %HDR.EVENT.DUR = HDR.EVENT.DUR(~ix0);
                                        %HDR.EVENT = rmfield(HDR.EVENT,'VAL');
                                end;
	                end;
                        if isfield(HDR.EVENT,'VAL')
                                ix  = find(~isnan(HDR.EVENT.VAL));
                                tmp = unique(HDR.EVENT.CHN(ix));

                                flag.invalid = 0;
                                if (~all(HDR.EVENT.CHN(ix) > 0))
                                        flag.invalid = 1;
                                        fprintf(2,'Warning SCLOSE: Sparse sampling values without valid channel. Samples are not stored.\n');
                                        tmp = tmp(tmp > 0);
                                end;
                                if any(HDR.GDFTYP(tmp) > 6)
                                        fprintf(2,'Warning SCLOSE: Sparse sampling values must be of type integer using no more than 32 bits. Data is converted to uint32.\n');
                                end;

                                if any(HDR.AS.SPR(tmp)) || flag.invalid,
                                        fprintf(2,'Warning SCLOSE: Sparse sampling value for non-sparse channels not allowed. The following channel(s) is(are) affected: ');
                                        fprintf(2,'%i', tmp(HDR.AS.SPR(tmp)>0) );
                                        fprintf(2,'.  Samples are not stored.\n')
                                        ix0 = ~isnan(HDR.EVENT.VAL) & ~(HDR.EVENT.CHN>0); % initialize index with logical(0)
                                        for k = 1:length(tmp),
                                                if (HDR.AS.SPR(tmp(k))>0),
                                                        ix0 = ix0 | (HDR.EVENT.CHN==tmp(k));
                                                end;
                                        end;
                                        HDR.EVENT.POS = HDR.EVENT.POS(~ix0);
                                        HDR.EVENT.TYP = HDR.EVENT.TYP(~ix0);
                                        HDR.EVENT.CHN = HDR.EVENT.CHN(~ix0);
                                        HDR.EVENT.DUR = HDR.EVENT.DUR(~ix0);
                                        HDR.EVENT.VAL = HDR.EVENT.VAL(~ix0);
                                        ix = ~isnan(HDR.EVENT.VAL);
                                end;

                                % prepare for storing
                                HDR.EVENT.TYP(ix) = hex2dec('7fff');
                                HDR.EVENT.DUR(ix) = HDR.EVENT.VAL(ix);
                        end;

                        len = [length(HDR.EVENT.POS),length(HDR.EVENT.TYP)];
                        EVENT.Version = 1;
                        if isfield(HDR.EVENT,'CHN') && isfield(HDR.EVENT,'DUR'),
                                if any(HDR.EVENT.CHN) || any(HDR.EVENT.DUR),
                                        EVENT.Version = 3;
					len = [len,length(HDR.EVENT.CHN),length(HDR.EVENT.DUR)];
                                end;
                        end;

                        if any(len~=len(1))
                                fprintf(HDR.FILE.stderr,'Error SCLOSE-GDF: cannot write Event table, file %s not closed.\n',HDR.FileName);
				return;
                        else
                                status  = fseek(HDR.FILE.FID,HDR.HeadLen+HDR.AS.bpb*HDR.NRec,'bof');
                                %status = fseek(HDR.FILE.FID,0,'eof');
                                if ftell(HDR.FILE.FID)~=HDR.AS.EVENTTABLEPOS,
                                        fprintf(HDR.FILE.stderr,'Warning SCLOSE-GDF: inconsistent GDF file\n');
                                end
				if ~isfield(HDR.EVENT,'SampleRate'),
					HDR.EVENT.SampleRate = HDR.SampleRate;
				end;

				% write eventtable info: Version, SampleRate & length
				if (HDR.VERSION<1.94)
					tmp = HDR.EVENT.SampleRate;
					tmp = [EVENT.Version,mod(tmp,256),floor(mod(tmp,65536)/256),floor(tmp/65536)];
	                                fwrite(HDR.FILE.FID,tmp,'uint8');
	                                fwrite(HDR.FILE.FID,length(HDR.EVENT.POS),'uint32');
				else
					tmp = length(HDR.EVENT.POS);
					tmp = [EVENT.Version,mod(tmp,256),floor(mod(tmp,65536)/256),floor(tmp/65536)];
	                                fwrite(HDR.FILE.FID,tmp,'uint8');
	                                fwrite(HDR.FILE.FID,HDR.EVENT.SampleRate,'float32');
				end;

				% write table
                                c1 = fwrite(HDR.FILE.FID,HDR.EVENT.POS,'uint32');
                                c2 = fwrite(HDR.FILE.FID,HDR.EVENT.TYP,'uint16');
                                c3 = length(HDR.EVENT.POS); c4 = c3;
                                if EVENT.Version==3;
                                        c3 = fwrite(HDR.FILE.FID,HDR.EVENT.CHN,'uint16');
                                        c4 = fwrite(HDR.FILE.FID,HDR.EVENT.DUR,'uint32');
                                end;
                                if any([c1,c2,c3,c4]~=length(HDR.EVENT.POS))
                                        fprintf(2,'\nError SCLOSE: writing of EVENTTABLE failed. File %s not closed.\n', HDR.FileName);
                                        return;
                                end
                        end;
                end;

        elseif strcmp(HDR.TYPE,'CFWB');
                tmp = (EndPos-HDR.HeadLen)/HDR.AS.bpb;
                if isnan(tmp), tmp=0; end;
                if (tmp~=HDR.NRec);
                        if ~any(HDR.FILE.PERMISSION=='z')
                                HDR.NRec = tmp;
                                fseek(HDR.FILE.FID,14*4,-1);
                                count = fwrite(HDR.FILE.FID,HDR.NRec,'int32');           % channels
                        else
                                fprintf(HDR.FILE.stderr,'ERROR SCLOSE (CFWB): number-of-samples-field (HDR.SPR) could not be updated in file %s.\n',HDR.FileName);
                        end;
                end;

        elseif strcmp(HDR.TYPE,'SND');
                tmp = (EndPos-HDR.HeadLen)/HDR.AS.bpb;
                if isnan(tmp), tmp=0; end;
                if (HDR.FILE.OPEN==3) && (tmp~=HDR.SPR);
                        if ~any(HDR.FILE.PERMISSION=='z')
                                HDR.SPR = tmp;
                                fseek(HDR.FILE.FID,8,'bof');
                                count = fwrite(HDR.FILE.FID,HDR.SPR*HDR.AS.bpb,'uint32');           % bytes
                                fseek(HDR.FILE.FID,20,-1);
                                count = fwrite(HDR.FILE.FID,HDR.NS,'uint32');           % channels
                        else
                                fprintf(HDR.FILE.stderr,'ERROR SCLOSE (SND): fields HDR.SPR and HDR.NS could not be updated in file %s.\n',HDR.FileName);
                        end;
		end;

        elseif strcmp(HDR.TYPE,'AIF');
                if HDR.FILE.OPEN==3;
                        fseek(HDR.FILE.FID,4,-1);
                        count = fwrite(HDR.FILE.FID,EndPos-8,'uint32');           % bytes
                        fseek(HDR.FILE.FID,HDR.WAV.posis(2),-1);
                        count = fwrite(HDR.FILE.FID,EndPos-4-HDR.WAV.posis(2),'uint32');           % channels
                end;

        elseif strcmp(HDR.TYPE,'FLT') ;
		% warning FLT/header might have changed in needs to be rewritten
        elseif strcmp(HDR.TYPE,'WAV') ;
                if HDR.FILE.OPEN==3;
                        fseek(HDR.FILE.FID,4,-1);
                        count = fwrite(HDR.FILE.FID,EndPos-16,'uint32');           % bytes
                        fseek(HDR.FILE.FID,HDR.WAV.posis(2),-1);
                        count = fwrite(HDR.FILE.FID,EndPos-4-HDR.WAV.posis(2),'uint32');           % channels
                end;
        end;
end;

if 0,
elseif strcmp(HDR.TYPE,'ZIP')
        [SUCCESS,MESSAGE,MESSAGEID] = rmdir(HDR.ZIP.TEMPDIR,'s');

elseif strcmp(HDR.TYPE,'FIF') && HDR.FILE.OPEN;
        global FLAG_NUMBER_OF_OPEN_FIF_FILES
        rawdata('close');
        HDR.FILE.OPEN = 0;
        HDR.FILE.status = 0;
        FLAG_NUMBER_OF_OPEN_FIF_FILES = FLAG_NUMBER_OF_OPEN_FIF_FILES-1;

elseif strmatch(HDR.TYPE,{'ADI','GTEC','LABVIEW','MAT','MAT4','MAT5','native','XML','XML-FDA','SierraECG'}),
        HDR.FILE.OPEN = 0;

elseif HDR.FILE.OPEN,
        HDR.FILE.OPEN = 0;
        HDR.FILE.status = fclose(HDR.FILE.FID);
end;


function [ns_RESULT, nsNeuralInfo] = ns_GetNeuralInfo(hFile, EntityID);

%ns_GetNeuralInfo   Retrieves information for neural event entities
%
%   Usage:
%      [ns_RESULT, nsNeuralInfo] = ns_GetNeuralInfo(hFile, EntityID)
%
%   Description:
%       Retrieves information on Neural Event entity EntityID from the
%       file referenced by hFile.  The information is returned in the
%       nsNeuralInfo.
%
%   Parameters:
%       hFile	    Handle/Indentification number to an open file.
%       EntityID	Identification number of the entity in the data file.
%
%   Return Values:
%       nsNeuralInfo    ns_NEURALINFO structure to receive the Neural
%                       Event information.
%       ns_RESULT   This function returns ns_OK if the file is successfully
%                   opened. Otherwise one of the following error codes is
%                   generated:
%
%                       ns_BADFILE	    Invalid file handle passed to
%                                       function
%                       ns_BADENTITY	Invalid or inappropriate entity
%                                       identifier specified
%                       ns_FILEERROR	File access or read error
%
%   Copyright (C) 2003 Neuroshare Project
%   Author: Almut Branner
%   Last modification: 10/24/2003

[ns_RESULT, nsNeuralInfo] = mexprog(12, hFile, EntityID - 1);

SourceEntityID = [nsNeuralInfo.SourceEntityID] + 1;
SourceUnitID = [nsNeuralInfo.SourceUnitID];

ind = find(SourceUnitID == 1);
SourceUnitID(ind) = 255;

ind = find((SourceUnitID > 1) & (SourceUnitID < 255));
SourceUnitID(ind) = log2(SourceUnitID(ind));

for i = 1:length(nsNeuralInfo)
    nsNeuralInfo(i).SourceEntityID = SourceEntityID(i);
    nsNeuralInfo(i).SourceUnitID = SourceUnitID(i);
end


function results = testModelsAlgorithmically(solvers,matFolder,modelNames,printLevel)
%test a set of models for the feasibility of a nonzero objective(>1e-4)
%by default, do not run this script with testAll
%
%OPTIONAL INPUT
% solvers       z x 1 cell array of solvers to test e.g. {'gurobi5','quadMinos'}
% matFolder     absolute path to the folder where k model .mat files are
% modelNames    k x 2 cell array of {Species, modelFilename} setting order
%               of results structure when returned
%               e.g. modelNames={...
%                    'Lactococcus lactis','LLACTIS';
%                    'Mus musculus','iMM302'};
%
%printLevel    {(0),1} choose the amount to be printed to screen
%
%OUTPUT
% results      k x (2 + z) cell array of results

% 39 Jan 2016 Ronan M.T. Fleming

global CBT_LP_SOLVER
if 1
    %%parameters

    %select solver to use
    if ~exist('solvers','var')
        if ~isunix || ismac
            solvers={CBT_LP_SOLVER};
        else
            [status,cmdout]=system('which minos');
            if isempty(cmdout)
                [status,cmdout]=system('echo $PATH');
                disp(cmdout);
                warning('Minos not installed or not on system path.');
            else
                solvers={CBT_LP_SOLVER,'dqqMinos'};
            end
        end

        %gurobi (http://www.gurobi.com/) gurboi versions 5 and 6 are supported
        %solvers={'gurobi'};
        %optionally also test with quadMinos (a quadruple precision solver by Michael Saunders, Stanford Systems Optimization Laboratory)
        %solvers={'gurobi','dqqMinos'};
        solvers={'dqqMinos'};
    end

    pth=which('initCobraToolbox.m');
    global CBTDIR
    CBTDIR = pth(1:end-(length('initCobraToolbox.m')+1));

    if ~exist('matFolder','var')
        matFolder=pwd;
        % set the folder within the folder 'testModels' where the .xml files are located
        %matFolder=[CBTDIR '/testing/testModels/m_model_collection_mat']; %selection of mat files already parsed from https://github.com/opencobra/m_model_collection.git'
        %matFolder=['/usr/local/bin/cobratoolbox_master' '/testing/testModels/m_model_collection_mat'];
        %matFolder=[CBTDIR '/testing/testModels/testedModels'];
        %matFolder=[CBTDIR '/testing/testModels/testBiGG'];
        %matFolder='~/Dropbox/modelling/natureComm/source/BiGG_Models/mat';
        matFolder='~/Dropbox/modelling/natureComm/source/MSP_ME';
        matFolder='~/Dropbox/modelling/natureComm/source/MSP_ReconX/';
    end

    %modelNameStructure='MSP_ReconX';
    if ~exist('modelNames','var')
        modelNames=[];
    else
        if ~isempty(modelNames)
        if ~isstruct(modelNames)

        %choose the ordering of the table of results, the second column contains a
        %unique abbreviation for each model
        switch modelNames
            case ''
                %use the filenames
                modelNames=[];
            case 'MSP_ME'
                modelNames={...
                    'E. coli ME (Thiele et al)','ME_matrix_GlcAer_WT'};
            case 'MSP_ReconX'
                modelNames={...
                    'Homo sapiens','121114_Recon2betaModel';
                    'Homo sapiens','Recon2.v04'};
            case 'mongoose'
                modelNames={...
                    'Lactococcus lactis','LLACTIS';
                    'Halobacterium salinarum','';
                    'Mus musculus','';
                    'Streptomyces coelicolor','S_coilicolor';
                    'Mus musculus ','';
                    'Thermotoga maritima','T_Maritima';
                    'Clostridium acetobutylicum ','';
                    'Clostridium acetobutylicum ','';
                    'Corynebacterium glutamicum ','';
                    'Corynebacterium glutamicum ','';
                    'Geobacter metallireducens ','';
                    'Geobacter sulfurreducens ','';
                    'Mus musculus','mus_musculus';
                    'Lactobacillus plantarum','';
                    'Mannheimia succiniciproducens','';
                    'Mannheimia succiniciproducens','';
                    'Neisseria meningitidis','';
                    'Rhodoferax ferrireducens','';
                    'Staphylococcus aureus','';
                    'Streptococcus thermophilus','';
                    'Streptomyces coelicolor','';
                    'Natronomonas pharaonis','Natronomonas_pharaonis';
                    'Synechocystis sp. PCC6803 ','';
                    'Plasmodium falciparum','PlasmoNet';
                    'Acinetobacter baumannii','AbyMBEL891';
                    'Aspergillus oryzae','AORYZAE_COBRA';
                    'Arabidopsis thaliana','AraGEM';
                    'Mycobacterium tuberculosis','GSMN-TB';
                    'Acinetobacter baylyi','iAbaylyiV4';
                    'Acinetobacter baylyi','iAbaylyiV4';
                    'Acinetobacter baylyi','iAbaylyiV4';
                    'Acinetobacter baylyi ','iAbaylyiV4';
                    'Leishmania major','iAC560';
                    'Escherichia coli ','iAF1260';
                    'Methanosarcina barkeri','iAF692';
                    'Dehalococcoides ethenogenes','iAI549';
                    'Yersinia pestis','iAN818m';
                    'Bacillus subtilis','iBsu1103';
                    'Escherichia coli','iCA1273';
                    'Clostridium beijerinckii','iCB925';
                    'Helicobacter pylori','iCS291';
                    'Haemophilus influenzae','iCS400';
                    'Saccharomyces cerevisiae','iFF708';
                    'Buchnera aphidicola','iGT196';
                    'Aspergillus nidulans','iHD666 ';
                    'Saccharomyces cerevisiae','iIN800';
                    'Helicobacter pylori','iIT341';
                    'Synechocystis sp. PCC6803','iJN678';
                    'Escherichia coli','iJO1366';
                    'Pseudomonas putida','iJP815';
                    'Escherichia coli','iJR904';
                    'Burkholderia cenocepacia','iKF1028';
                    'Pichia pastoris','iLC915';
                    'Saccharomyces cerevisiae','iLL672';
                    'Aspergillus niger','iMA871';
                    'Salmonella typhimurium','iMA945';
                    'Methanosarcina acetivorans','iMB745';
                    'Staphylococcus aureus','iMH551';
                    'Saccharomyces cerevisiae','iMH805/775';
                    'Mus musculus','iMM1415';
                    'Saccharomyces cerevisiae','iMM904';
                    'Pseudomonas aeruginosa','iMO1056';
                    'Saccharomyces cerevisiae','iND750';
                    'Mycobacterium tuberculosis','iNJ661';
                    'Mycobacterium tuberculosis','iNJ661m';
                    'Pseudomonas putida','iNJ746';
                    'Cryptosporidium hominis','iNV213';
                    'Chromohalobacter salexigens','iOA584';
                    'Rhizobium etli','iOR363';
                    'Pichia pastoris','iPP668';
                    'Mycoplasma genitalium','iPS189';
                    'Chlamydomonas reinhardtii','iRC1080';
                    'Salmonella typhimurium','iRR1083';
                    'Zea mays','iRS1563';
                    'Arabidopsis thaliana','iRS1597';
                    'Francisella tularensis','iRS605';
                    'Rhodobacter sphaeroides','iRsp1095';
                    'Staphylococcus aureus','iSB619';
                    'Shewanella oneidensis','iSO783';
                    'Clostridium thermocellum','iSR432';
                    'Pichia stipitis','iSS884';
                    'Synechocystis sp. PCC6803','iSyn669';
                    'Plasmodium falciparum','iTH366';
                    'Scheffersomyces stipitis','iTL885';
                    'Porphyromonas gingivalis','iVM679';
                    'Methanosarcina acetivorans','iVS941';
                    'Ketogulonicigenium vulgare','iWZ663';
                    'Klebsiella pneumoniae','iYL1228';
                    'Zymomonas mobilis','iZM363';
                    'Bacillus subtilis ','model_v3';
                    'Pichia pastoris','PpaMBEL1254 ';
                    'Pseudomonas putida','PpuMBEL1071';
                    'Homo sapiens','121114_Recon2betaModel';
                    'Saccharomyces pombe','SpoMBEL1693';
                    'Salmonella typhimurium','STM_v1.0';
                    'Escherichia coli','textbook';
                    'Vibrio vulnificus','VvuMBEL943';
                    'Zymomonas mobilis','ZmobMBEL601'};
        end
        end
        end
    end
    %optionally convert the batch of .xml files into .mat files
    if 0
        %the folder where the SBML .xml files are located
        xmlFolder='m_model_collection';

        %folder where he .mat files are to be located
        matFolder=[pathContainingOpencobra 'cobratoolbox_master/testing/testModels/m_model_collection_mat'];

        %parsing via cobra toolbox and sbml toolbox and libsbml with matlab bindings
        sbmlTestModelToMat(xmlFolder,matFolder);
    end

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

    %%

    %The remainder of this code should run uninterupted,
    if any(strcmp(solvers,'quadMinos')) && isunix
        %quadMinos
        %addpath(pathContainingQuadMinos)
        %try to find the minos solver
        [status,cmdout]=system('which minos');
        if isempty(cmdout)
            [status,cmdout]=system('echo $PATH');
            disp(cmdout);
            warning('Minos not installed or not on system path.');
        end
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % batch of mat files models the matFolder directory
    cd(matFolder)

    %batch of models in .mat format in a directory
    %assumes that each .mat file is a model
    matFiles=dir(matFolder);
    nModels=length(matFiles)-2;

    modelResults=cell(nModels,2+length(solvers));
    j=1;
    for k=3:length(matFiles) %loop through the mat files in the directory
        if strcmp(matFiles(k).name(end-2:end),'mat')

            if printLevel>0
                %disp(j)
                disp(matFiles(k).name)
            end

            %get the id of the model from the filename
            whosFile=whos('-file',matFiles(k).name);
            modelID=matFiles(k).name(1:end-4);
            modelResults{j,1}=modelID;
            if printLevel>-1
                fprintf('%20s\n',modelID);
            end
            load(matFiles(k).name);
            model=eval(whosFile.name);
            %stamp the model with the ID of the file
            model.modelID=modelID;
            model.description=modelID;

            %find the exchange reactions
            [m,n]=size(model.S);
            try
                if length(find(model.c~=0))~=1 % if more than one objective vector are defined in the model, only the one of the them is chosen for the testing.
                    ind=find(model.c~=0);
                    if isempty(ind); % if no objective vector is defined, set the first reaction as the objective for the testing.
                        warning('all zero entries in model.c')
                        model.c(1)=1;
                    else
                        warning('multiple nonzero entries in model.c')
                        model.c(ind)=0;
                        model.c(ind(1))=1; % by default, the first objective vector is used for the testing
                    end
                end
                model=findSExRxnInd(model,m,printLevel-1);
            catch
                disp('good');
            end

            if 0
                %check if stoichiometrically consistent
                [inform,m,model]=checkStoichiometricConsistency(model,printLevel-1);
            end

            %record the reaction to be optimized
            if any(model.c~=0) && isfield(model,'rxns')
                modelResults{j,2}=model.rxns{model.c~=0};
            else
                modelResults{j,2}='?';
            end

            %test with different solvers
            [out,solutions{j}]=testDifferentLPSolvers(model,solvers,printLevel);
            %save results
            for z=1:length(solvers)
                modelResults{j,2+z}=solutions{j}{z}.obj;
            end
            j=j+1;%used below
        end
    end

    %depending how the data is to be ordered, results structure is
    %different
    if isempty(modelNames)
        %create results structure
        results=cell(j,2+length(solvers));
        %add results in the order given by modelNames
        for k=1:j-1
            %Abbreviation of model
            results{k+1,1}=modelResults{k,1};
            results{k+1,2}=modelResults{k,2};
            %Abbreviation of reaction optimised'
            %solver objectives
            for z=1:length(solvers)
                results{k+1,2+z}=modelResults{k,2+z};
            end
        end
        %add headings to the results structure
        results{1,1}='Model';
        results{1,2}='Rxn maximised';
        for z=1:length(solvers)
            results{1,2+z}=solvers{z};
        end
    else
        %create results structure
        results=cell(size(modelNames,1)+1,3+length(solvers));
        %add results in the order given by modelNames
        for k=1:size(modelNames,1)
            %Abbreviation of model
            results{k+1,1}=modelNames{k,1};
            results{k+1,2}=modelNames{k,2};
            bool=strcmp(modelNames{k,2},modelResults(:,1));
            if any(bool)
                %Abbreviation of reaction optimised'
                results{k+1,3}=modelResults{bool,2};
                %solver objectives
                for z=1:length(solvers)
                    results{k+1,3+z}=modelResults{bool,2+z};
                end
            end
        end
        %add headings to the results structure
        results{1,1}='Species';
        results{1,2}='Model';
        results{1,3}='Rxn maximised';
        for z=1:length(solvers)
            results{1,3+z}=solvers{z};
        end
    end
end


function planC = updatePlanIVH(planD)
% updatePlanIVH
%
% Updates the CERR planC with IVH (intensity volume histogram) field.
%
% Usuage
% planC = updatePlanIVH(planC);
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

planC = initializeCERR;
indexS = planD{end};
fields = fieldnames(indexS);
indexSNew = planC{end};

for i = 1:length(fields)
    field = fields{i};
    if ~strcmpi(field,'indexS')
        try
            planC{indexSNew.(field)} = planD{indexS.(field)};
        catch
            warning(['Unknown field "' field '"in CERR plan. Rejecting this field']);
            continue
        end
    end
end
planC{end}=indexSNew;
clear planD