function [rxnInLoops, N, loopInfo] = findMinNull(model, formulation, varargin)
% Find a minimal null-space for all internal cycles by solving a MILP,
% as proposed in Chan et al., 2017.
%
% USAGE:
%    [rxnInLoops, N, loopInfo] = findMinNull(model, formulation, parameters)
%
% INPUT:
%    model:               COBRA model structure
%
% OPTIONAL INPUTS:
%    formulation:         1: solve the MILP problem for a minimal null-space basis
%                            in an interlaced fashion by presolving some relaxed LPs to simultaneously
%                            determine the directions of reactions that participate in internal cycles
%                            (default, the quickest way as of 2017 Nov)
%                         2: directly solve the MILP. Then determine the directions
%                            of reactions that participate in internal cycles
%    parameters:          solver-specific parameter structure or name-value pair argument for solverCobraMILP
%
% OUTPUTS:
%    rxnInLoops:          #rxns-by-2 matrix. rxnInLoops(j, 1) = true => reverse direction of rxn j in loops
%                         rxnInLoops(j, 2) = true => forward direction of rxn j in loops
%    N:                   Minimal feasible null-space matrix for internal cycles
%    loopInfo:            structure containing the following parameters/information:
%                         *.M:          the bound for minimum/maximum flux
%                         *.minFlux:    minimum flux required for a reaction to be active
%                         *.ignoreRxns: rxns with small coefficients that are prechecked
%                                       before solving the MILP to avoid numerical issues
%                         *.nsTime:      wall time for finding the null-space
%                         *.nsCPU:      CPU time for finding the null-space
%                         *.loopPreprocessCPU:  CPU time for finding the directions of reactions participating in loops
%                         *.loopPreprocessTime: wall time for finding the directions of reactions participating in loops

if nargin < 2 || isempty(formulation)
	formulation = 1;
else
	if ~isscalar(formulation)
        % first varargin recognized as formulation
		varargin = [{formulation}; varargin(:)];
		formulation = 1;
	end
end

% filter out reactions with very small stoichiometric coefficents. They are
% usually not in loops. This can accelerate MILP solution time.
% (part of nullspace preprocessing)
cpu0 = cputime;
t = tic;

bigM = 100;
minFlux = 0.1;
rxnIn = sum(model.S ~= 0, 1) > 1;
rxnInIDs = find(rxnIn);
nR = sum(rxnIn);
metIn = any(model.S(:, rxnIn), 2);
nM = sum(metIn);
feasTol = getCobraSolverParams('LP', 'feasTol');

% rxnInLoops(j, 1) = true => reverse direction in loops
% rxnInLoops(j, 2) = true => forward direction in loops
rxnInLoops = false(numel(model.rxns), 2);

nsCPU = cputime - cpu0;
nsTime = toc(t);

if formulation == 1
    % Formulation 1: the procedure stated in SI Methods section 7 in Chan et al. (2017)
    % Determine reactions in loops and their feasible directions in loops
    % in an interlaced fashion

    % find maximum number of active reactions
    % (part of nullspace preprocessing)
    cpu0 = cputime;
    t = tic;

    MILP.A = [model.S(metIn, rxnIn),  sparse(nM, nR * 2); ... Sv = 0
             -speye(nR),             -bigM * speye(nR)    sparse(nR, nR); ...  -v - M z_pos <= -minFlux
              speye(nR),              sparse(nR, nR),    -bigM * speye(nR)];  % v - M z_neg <= -minFlux
    MILP.b = [zeros(nM, 1); -minFlux * ones(nR * 2, 1)];
    MILP.c = [zeros(nR, 1); ones(nR * 2, 1)];

    % Step 2 in SI Methods section 7.
    % Find all irreversible reactions that are in loops
    % fix z_pos = 1 if lb < 0, i.e., v may be negative
    % fix z_neg = 1 if ub > 0, i.e., v may be positive
    % (=> z_pos = z_neg = 1 for truly reversible reactions)
    MILP.lb = [-bigM * (model.lb(rxnIn) < 0); model.lb(rxnIn) < 0; model.ub(rxnIn) > 0];
    MILP.ub = [bigM * (model.ub(rxnIn) > 0); ones(nR * 2, 1)];
    MILP.osense = 1;
    MILP.csense = char(['E' * ones(1, nM), 'L' * ones(1, nR * 2)]);
    sol.irr = solveCobraLP(MILP, varargin{:});

    % Step 3 in SI Methods section 7.
    % Record identified reactions
    rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | sol.irr.full(1:nR) < -1e-3;
    rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | sol.irr.full(1:nR) > 1e-3;

    % Step 4 in SI Methods section 7.
    % Check reversible reactions whose forward direction not yet found to be in loops
    rxnCk = ~rxnInLoops(rxnIn, 2) & (model.lb(rxnIn) < 0 & model.ub(rxnIn) >0);
    % fix irreversible reactions known to be not in loops
    MILP.lb((model.lb(rxnIn) >= 0 | model.ub(rxnIn) <= 0) & ~any(rxnInLoops(rxnIn, :), 2)) = 0;
    MILP.ub((model.lb(rxnIn) >= 0 | model.ub(rxnIn) <= 0) & ~any(rxnInLoops(rxnIn, :), 2)) = 0;
    % fix z_pos = 1 for reactions not in rxnCk
    MILP.lb((nR + 1):end) = [~rxnCk; ones(nR, 1)];
    sol.rev1 = solveCobraLP(MILP, varargin{:});
    % Record identified reactions
    rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | sol.rev1.full(1:nR) < -1e-3;
    rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | sol.rev1.full(1:nR) > 1e-3;

    % Step 5 in SI Methods section 7.
    % Check reversible reactions whose reverse direction not yet found to be in loops
    rxnCk = ~rxnInLoops(rxnIn, 1) & (model.lb(rxnIn) < 0 & model.ub(rxnIn) >0);
    % fix z_neg = 1 for reactions not in rxnCk
    MILP.lb((nR + 1):end) = [ones(nR, 1); ~rxnCk];
    sol.rev2 = solveCobraLP(MILP, varargin{:});
    % Record identified reactions
    rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | sol.rev2.full(1:nR) < -1e-3;
    rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | sol.rev2.full(1:nR) > 1e-3;

    % This step is not mentioned in SI.
    % Filter reactions with small coefficients before solving MILP.
    % They are usually not in loops. This can accelerate MILP solution time.
    % reactions to be checked
    rxnCk = find(any(abs(model.S(:, rxnIn)) > 0 & abs(model.S(:, rxnIn)) < 1e-3, 1)' ...
        & model.lb(rxnIn) < 0 & model.ub(rxnIn) > 0 & ~any(rxnInLoops(rxnIn, :), 2));
    % fix all z_pos and z_neg
    MILP.lb((nR + 1):end) = 1;
    MILP.c(:) = 0;
    for j = 1:numel(rxnCk)
        % check feasibility in the forward direction
        if ~rxnInLoops(rxnInIDs(rxnCk(j)), 2) && MILP.ub(rxnCk(j)) > 0
            bd0 = MILP.lb(rxnCk(j));
            MILP.lb(rxnCk(j)) = minFlux / 10;
            solJ = solveCobraLP(MILP, varargin{:});
            if checkSolFeas(MILP, solJ) <= feasTol
                rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | solJ.full(1:nR) < -1e-3;
                rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | solJ.full(1:nR) > 1e-3;
            end
            MILP.lb(rxnCk(j)) = bd0;
        end
        % check feasibility in the reverse direction
        if ~rxnInLoops(rxnInIDs(rxnCk(j)), 1) && MILP.lb(rxnCk(j)) < 0
            bd0 = MILP.ub(rxnCk(j));
            MILP.ub(rxnCk(j)) = -minFlux / 10;
            solJ = solveCobraLP(MILP, varargin{:});
            if checkSolFeas(MILP, solJ) <= feasTol
                rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | solJ.full(1:nR) < -1e-3;
                rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | solJ.full(1:nR) > 1e-3;
            end
            MILP.ub(rxnCk(j)) = bd0;
        end
    end
    ignoreRxns = rxnCk(~any(rxnInLoops(rxnInIDs(rxnCk), :), 2));
    MILP.lb(ignoreRxns) = 0;
    MILP.ub(ignoreRxns) = 0;
    ignoreRxns = rxnInIDs(ignoreRxns);

    % Step 6 in SI Methods section 7.
    % Solve MILP for the forward directions
    rxnCk = ~rxnInLoops(rxnIn, 2) & (model.lb(rxnIn) < 0 & model.ub(rxnIn) >0);
    % fix z_pos for those not rxnCk. Fix all z_neg
    MILP.lb((nR + 1):end) = [~rxnCk; ones(nR, 1)];
    MILP.vartype = char(['C' * ones(1, nR), 'B' * ones(1, nR * 2)]);
    MILP.x0 = [];
    % minimize z_pos + z_neg
    MILP.c((nR + 1):end) = 1;
    sol.rev3 = solveCobraMILP(MILP, varargin{:});
    % Record identified reactions
    rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | sol.rev3.full(1:nR) < -1e-3;
    rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | sol.rev3.full(1:nR) > 1e-3;

    % end of the first part of null-space preprocessing
    nsCPU = nsCPU + (cputime - cpu0);
    nsTime = nsTime + toc(t);

    % Step 7 in SI Methods section 7.
    % Check whether the reactions with negative fluxes in sol.rev3.x can
    % actual have positive fluxes (part of looping reaction preprocessing)
    cpu0 = cputime;
    t = tic;

    rxnCk = find(sol.rev3.full(1:nR) < -1e-3 & rxnCk);
    if ~isempty(rxnCk)
        % fix all z when solving LP
        MILP.lb((nR + 1):end) = 1;
        MILP.c(:) = 0;
        for j = 1:numel(rxnCk)
            if ~rxnInLoops(rxnInIDs(rxnCk(j)), 2)
                bd0 = MILP.lb(rxnCk(j));
                MILP.lb(rxnCk(j)) = minFlux / 10;
                solJ = solveCobraLP(MILP, varargin{:});
                if checkSolFeas(MILP, solJ) <= feasTol
                    rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | solJ.full(1:nR) < -1e-3;
                    rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | solJ.full(1:nR) > 1e-3;
                end
                MILP.lb(rxnCk(j)) = bd0;
            end
        end
    end

    % end of the first part of loop preprocessing time
    loopPreprocessCPU = cputime - cpu0;
    loopPreprocessTime = toc(t);

    % Step 8 in SI Methods section 7.
    % Solve MILP for the reverse direction. (2nd part of nullspace preprocessing)
    cpu0 = cputime;
    t = tic;

    rxnCk = ~rxnInLoops(rxnIn, 1) & (model.lb(rxnIn) < 0 & model.ub(rxnIn) >0);
    % fix z_neg for those not rxnCk. Fix all z_pos
    MILP.lb((nR + 1):end) = [ones(nR, 1); ~rxnCk];
    MILP.c((nR + 1):end) = 1;
    sol.rev4 = solveCobraMILP(MILP, varargin{:});

    rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | sol.rev4.full(1:nR) < -1e-3;
    rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | sol.rev4.full(1:nR) > 1e-3;

    nsCPU = nsCPU + (cputime - cpu0);
    nsTime = nsTime + toc(t);

    % Step 9 in SI Methods section 7.
    % Check whether the reactions with positive fluxes in sol.rev4.cont can
    % actual have negative fluxes (part of looping reaction preprocessing)
    cpu0 = cputime;
    t = tic;

    rxnCk = find(sol.rev4.full(1:nR) > 1e-3 & rxnCk);
    if ~isempty(rxnCk)
        % fix all z when solving LP
        MILP.lb((nR + 1):end) = 1;
        MILP.c(:) = 0;
        for j = 1:numel(rxnCk)
            if ~rxnInLoops(rxnInIDs(rxnCk(j)), 1)
                bd0 = MILP.ub(rxnCk(j));
                MILP.ub(rxnCk(j)) = -minFlux / 10;
                solJ = solveCobraLP(MILP, varargin{:});
                if checkSolFeas(MILP, solJ) <= feasTol
                    rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | solJ.full(1:nR) < -1e-3;
                    rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | solJ.full(1:nR) > 1e-3;
                end
                MILP.ub(rxnCk(j)) = bd0;
            end
        end
    end
    loopPreprocessCPU = loopPreprocessCPU + (cputime - cpu0);
    loopPreprocessTime = loopPreprocessTime + toc(t);
else
    % Formulation 2: directly solve the MILP and find the feasible reaction
    % direction participating in loops for each reaction

    % find maximum number of active reactions (nullspace preprocessing)
    cpu0 = cputime;
    t = tic;

    % filter reactions with small coefficients before solving MILP
    % reactions to be checked
    LP.A = model.S(metIn, rxnIn);
    LP.b = zeros(nM, 1);
    LP.c = zeros(nR, 1);
    LP.lb = -bigM * (model.lb(rxnIn) < 0);
    LP.ub = bigM * (model.ub(rxnIn) > 0);
    LP.csense = char('E' * ones(1, nM));
    [lb0, ub0] = deal(LP.lb, LP.ub);
    % reactions to be checked
    rxnCk = find(any(abs(model.S(:, rxnIn)) > 0 & abs(model.S(:, rxnIn)) < 1e-3, 1));
    for j = 1:numel(rxnCk)
        % check feasibility in the forward direction
        if LP.ub(rxnCk(j)) > 0
            LP.lb(rxnCk(j)) = minFlux / 10;
            solJ = solveCobraLP(LP, varargin{:});
            if checkSolFeas(LP, solJ) <= feasTol
                rxnInLoops(rxnInIDs(rxnCk(j)), 2) = true;
            end
            LP.lb(rxnCk(j)) = lb0(rxnCk(j));
        end
        % check feasibility in the reverse direction
        if ~rxnInLoops(rxnInIDs(rxnCk(j)), 2) && LP.lb(rxnCk(j)) < 0
            LP.ub(rxnCk(j)) = -minFlux / 10;
            solJ = solveCobraLP(LP, varargin{:});
            if checkSolFeas(LP, solJ) <= feasTol
                rxnInLoops(rxnInIDs(rxnCk(j)), 1) = true;
            end
            LP.ub(rxnCk(j)) = ub0(rxnCk(j));
        end
    end
    clear LP
    ignoreRxns = rxnInIDs(rxnCk(~any(rxnInLoops(rxnInIDs(rxnCk), :), 2)));
    rxnIn(ignoreRxns) = false;
    nR = sum(rxnIn);
    metIn = any(model.S(:, rxnIn), 2);
    nM = sum(metIn);
    rxnInIDs = find(rxnIn);

    % solve MILP
    MILP.A = [model.S(metIn, rxnIn),  sparse(nM, nR * 2); ... Sv = 0
             -speye(nR),             -bigM * speye(nR)    sparse(nR, nR); ...  -v - M z_pos <= -1
              speye(nR),              sparse(nR, nR),    -bigM * speye(nR); ...   % v - M z_neg <= -1
              sparse(nR, nR),         speye(nR),          speye(nR)];   % z_pos + z_neg >= 1
    MILP.b = [zeros(nM, 1); -minFlux * ones(nR * 2, 1); ones(nR, 1)];
    MILP.c = [zeros(nR, 1); ones(nR * 2, 1)];
    % fix z_pos = 1 for reactions with ub <= 0. Fix z_neg = 1 for reactions with lb >= 0
    MILP.lb = [-bigM * (model.lb(rxnIn) < 0); model.ub(rxnIn) <= 0; model.lb(rxnIn) >= 0];
    MILP.ub = [bigM * (model.ub(rxnIn) > 0); ones(nR * 2, 1)];
    MILP.osense = 1;
    MILP.csense = char(['E' * ones(1, nM), 'L' * ones(1, nR * 2), 'G' * ones(1, nR)]);
    MILP.vartype = char(['C' * ones(1, nR), 'B' * ones(1, nR * 2)]);
    % z_pos for reactions with lb >= 0 and z_neg for reactions with ub <= 0 can be treated as continuous
    MILP.vartype(nR + find(model.lb(rxnIn) >= 0)) = 'C';
	MILP.vartype(nR * 2 + find(model.ub(rxnIn) <= 0)) = 'C';
    MILP.x0 = [zeros(nR, 1); ones(nR * 2, 1)];
    sol = solveCobraMILP(MILP, varargin{:});
    if isempty(sol.full)
		varargin2 = [{'feasTol'; 1e-7}; varargin(:)];
		sol = solveCobraMILP(MILP, varargin2{:});
    end

    nsCPU = nsCPU + (cputime - cpu0);
    nsTime = nsTime + toc(t);

    cpu0 = cputime;
    t = tic;

    % Check whether the reversible reactions with nonzero fluxes in sol.cont can
    % have fluxes in the opposite sign (part of looping reaction preprocessing)

    rxnInLoops(rxnIn, 1) = sol.full(1:nR) < -1e-3;
    rxnInLoops(rxnIn, 2) = sol.full(1:nR) > 1e-3;

    rxnCk = find(sol.full(1:nR) < -1e-3 | sol.full(1:nR) > 1e-3 & model.lb(rxnIn) < 0 & model.ub(rxnIn) > 0);

    LP.A = model.S(metIn, rxnIn);
    LP.b = zeros(nM, 1);
    LP.c = zeros(nR, 1);
    LP.lb = MILP.lb(1:nR) .* any(rxnInLoops(rxnIn, :), 2);
    LP.ub = MILP.ub(1:nR) .* any(rxnInLoops(rxnIn, :), 2);
    LP.csense = MILP.csense(1:nM);
    clear MILP

    for j = 1:numel(rxnCk)
        if ~rxnInLoops(rxnInIDs(rxnCk(j)), 2)
			bd0 = LP.lb(rxnCk(j));
            LP.lb(rxnCk(j)) = minFlux / 10;
            solJ = solveCobraLP(LP, varargin{:});
            if checkSolFeas(LP, solJ) <= feasTol
                rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | solJ.full(1:nR) < -1e-3;
				rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | solJ.full(1:nR) > 1e-3;
            end
            LP.lb(rxnCk(j)) = bd0;
        end
        if ~rxnInLoops(rxnInIDs(rxnCk(j)), 1)
			bd0 = LP.ub(rxnCk(j));
            LP.ub(rxnCk(j)) = -minFlux / 10;
            solJ = solveCobraLP(LP, varargin{:});
            if checkSolFeas(LP, solJ) <= feasTol
                rxnInLoops(rxnIn, 1) = rxnInLoops(rxnIn, 1) | solJ.full(1:nR) < -1e-3;
				rxnInLoops(rxnIn, 2) = rxnInLoops(rxnIn, 2) | solJ.full(1:nR) > 1e-3;
            end
            LP.ub(rxnCk(j)) = bd0;
        end
    end

    loopPreprocessCPU = cputime - cpu0;
    loopPreprocessTime = toc(t);
end

% get the nullspace matrix (part of nullspace preprocessing)
cpu0 = cputime;
t = tic;

rxnCyc = any(rxnInLoops, 2);
N = sparseNull(model.S(any(model.S(:, rxnCyc), 2), rxnCyc));
[row, col, entry] = find(N);
rxnCyc = find(rxnCyc);
row = rxnCyc(row);
N = sparse(row, col, entry, size(model.S, 2), size(N, 2));

nsCPU = nsCPU + (cputime - cpu0);
nsTime = nsTime + toc(t);

loopInfo.M = bigM;
loopInfo.minFlux = minFlux;
loopInfo.nsCPU = nsCPU;
loopInfo.nsTime = nsTime;
loopInfo.loopPreprocessCPU = loopPreprocessCPU;
loopInfo.loopPreprocessTime = loopPreprocessTime;
loopInfo.ignoreRxns = model.rxns(ignoreRxns);
end


%%
 %  Copyright (c) 2014, Facebook, Inc.
 %  All rights reserved.
 %
 %  This source code is licensed under the BSD-style license found in the
 %  LICENSE file in the root directory of this source tree. An additional grant
 %  of patent rights can be found in the PATENTS file in the same directory.
 %
 %%
function [ap,level2_scores] = test_level2_cnn(level2_model,test_labels,test_features,test_gfeatures, config)
%test level2 cnn

is_score = (size(test_features{1}.features,2) == 1);
level2_features_test = generate_level2_features_cnn(test_features,test_gfeatures,config);
clear test_features;
for attr_id = 1:size(test_labels,2)
    %%%test%%%
    %ignore those whith labels = 0
    idx  = find(test_labels(:,attr_id) ~= 0);

    if is_score
        level2_scores{attr_id} = level2_model{attr_id}.svm_weights'*level2_features_test';
    else
        level2_scores{attr_id} = level2_model{attr_id}.svm_weights(1:end-1)*level2_features_test'+...
            level2_model{attr_id}.svm_weights(end);
    end
    ap(attr_id)= get_precision_recall(level2_scores{attr_id}(idx),test_labels(idx,attr_id));
end

for attr_id=1:length(ap)
   fprintf('%4.2f & ',ap(attr_id)*100);
end
fprintf(' mean AP=%4.3f\n',mean(ap)*100);

end


function [data_len, winlen, winstep] = mrcg_extract( audio_dir, varargin )

    %UNTITLED2 이 함수의 요약 설명 위치
    %   자세한 설명 위치
    [noisy_speech, audio_sr] = audioread(audio_dir);

    if isempty(varargin)
        y_label = zeros(length(noisy_speech), 1);
    else
        label_dir = varargin{1};
        load(label_dir);
    end

    mkdir './sample_data'
    mkdir './sample_data/Labels'

    save_dir = './sample_data';
    name_mrcg = [save_dir, '/mrcg'];
    name_label = [save_dir, '/Labels/label'];

%     noisy_speech = noisy_speech(1:1000000,:);
%     y_label = y_label(1:1000000,:);

    mrcg_mat = MRCG_features(noisy_speech, audio_sr)';
    winlen             = ceil(audio_sr*25*0.001);	%window length (default : 25 ms)
    winstep            = ceil(audio_sr*10*0.001);	%window step (default : 10 ms)
    train_mean = mean(mrcg_mat,1);
    train_std = std(mrcg_mat,1,1);

    %% Read label

    framed_label = Truelabel2Trueframe( y_label, winlen, winstep );
    num = 0;

    if (length(mrcg_mat) > length(framed_label))
        binary_saver( name_mrcg, mrcg_mat(1:length(framed_label), :), num );
        binary_saver( name_label, framed_label, num );
        data_len = length(framed_label);
    else
        binary_saver( name_mrcg, mrcg_mat, num );
        binary_saver( name_label, framed_label(1:length(mrcg_mat), 1), num );
        data_len = length(mrcg_mat);
    end

    %% Save global normalization factor

    save([save_dir, '/normalize_factor'], 'train_mean', 'train_std');

    disp('MRCG extraction is successifully done.')

end


% [tInc,tIncCh] = hmrR_MotionArtifactByChannel(data, probe, mlActMan, mlActAuto, tIncMan, tMotion, tMask, STDEVthresh, AMPthresh)
%
% UI NAME:
% Motion_Artifacts_By_Channel
%
%
% Identifies motion artifacts in an input data matrix d. If any active
% data channel exhibits a signal change greater than std_thresh or
% amp_thresh, then a segment of data around that time point is marked as a
% motion artifact. The channel-wise motion artifacts are recorded in the
% output matrix tIncCh. If any channel has a motion artifact, it is
% indicated by the vector tInc.
%
%
% INPUTS:
% data: SNIRF data structure data, containing time course data
% probe:   SNIRF data structure probe, containing probe source/detector geometry
% tIncMan: Cell array of vectors corresponding to the number of time bases in data.
%          tIncMan has been manually excluded. 0-excluded. 1-included. Vector same length as d.
% mlActMan: Cell array of vectors, one for each time base in data, specifying
%        active/inactive channels with 1 meaning active, 0 meaning inactive
% mlActAuto: Cell array of vectors, one for each time base in data, specifying
%        active/inactive channels with 1 meaning active, 0 meaning inactive
% tMotion: Check for signal change indicative of a motion artifact over
%     time range tMotion. Units of seconds.
% tMask: Mark data over +/- tMask seconds around the identified motion
%     artifact as a motion artifact. Units of seconds.
% STDEVthresh: If the signal d for any given active channel changes by more
%     that stdev_thresh * stdev(d) over the time interval tMotion, then
%     this time point is marked as a motion artifact. The standard deviation is
%     determined for each channel independently.
% AMPthresh: If the signal d for any given active channel changes by more
%     that amp_thresh over the time interval tMotion, then this time point
%     is marked as a motion artifact.
%
%
% OUTPUTS:
% tInc: a vector of length time points with 1's indicating data included
%       and 0's indicate motion artifact
% tIncCh: a matrix with #time points x #channels, with 1's indicating data
%       included and 0's indicating motion artifacts on a channel by
%       channel basis
%
% USAGE OPTIONS:
% Motion_Artifacts_By_Channel:  [tIncAuto, tIncAutoCh] = hmrR_MotionArtifactByChannel(dod, probe, mlActMan, mlActAuto, tIncMan, tMotion, tMask, STDEVthresh, AMPthresh)
%
% PARAMETERS:
% tMotion: 0.5
% tMask: 1.0
% STDEVthresh: 50.0
% AMPthresh: 5.00
%
% PREREQUISITES:
% Intensity_to_Delta_OD: dod = hmrR_Intensity2OD( intensity )
%
% LOG:
% K. Perdue
% kperdue@nmr.mgh.harvard.edu
% Sept. 23, 2010
% Modified by DAB 3/17/2011 to not act on a single channel by default
% DAB 4/20/2011 added tMotion and tMask and hard coded stdev option.
% DAB 8/4/2011 added amp_thresh to work at same time as std_thresh
%
% TO DO:
% Consider tIncMan

function [tInc, tIncCh] = hmrR_MotionArtifactByChannel(data, probe, mlActMan, mlActAuto, tIncMan, tMotion, tMask, std_thresh, amp_thresh)

tInc   = cell(length(data), 1);
tIncCh = cell(length(data), 1);

% Input processing.  Check required inputs, throw errors if necessary.
if nargin<3
    error('First and second inputs must be data and probe SNIRF objects of type DataClass and ProbeClass.')
end
if ~isa(data, 'DataClass')
    error('First input must be data SNIRF objects of type DataClass.')
end
if ~isa(probe, 'ProbeClass')
    error('Second input must be probe SNIRF objects of type ProbeClass.')
end
if isempty(tIncMan)
    tIncMan = cell(length(data),1);
end
if isempty(mlActMan)
    mlActMan = cell(length(data),1);
end
if isempty(mlActAuto)
    mlActAuto = cell(length(data),1);
end

for iBlk = 1:length(data)

    d           = data(iBlk).GetDataTimeSeries();
    fs          = data(iBlk).GetTime();
    MeasList    = data(iBlk).GetMeasList();

    if length(fs)~=1
        fs = 1/(fs(2)-fs(1));
    end

    if isempty(tIncMan{iBlk})
        tIncMan{iBlk} = ones(size(d,1),1);
    end
    tInc{iBlk}   = ones(size(d,1),1);
    tIncCh{iBlk} = tIncCh_Initialize(tIncCh{iBlk}, d, MeasList);

    % get list of active channels
    mlActMan{iBlk} = mlAct_Initialize(mlActMan{iBlk}, MeasList);
    mlActAuto{iBlk} = mlAct_Initialize(mlActAuto{iBlk}, MeasList);
    lstAct1 = mlAct_Matrix2IndexList(mlActAuto{iBlk}, MeasList);
    lstAct2 = mlAct_Matrix2IndexList(mlActMan{iBlk}, MeasList);
    lstAct = unique([lstAct1(:)', lstAct2(:)']);

    % set artifact buffer for tMask seconds on each side of spike
    art_buffer = round(tMask*fs); % time in seconds times sample rate

    % LOOP OVER CHANNELS
    for iCh = 1:length(lstAct)

        lstActTmp = find(MeasList(:,1)==MeasList(lstAct(iCh),1) & ...
                         MeasList(:,2)==MeasList(lstAct(iCh),2) );

        % calculate std_diff for each channel
        std_diff = std( d(2:end, lstActTmp) - d(1:end-1, lstActTmp), 0, 1);

        % calculate max_diff across channels for different time delays
        max_diff = zeros(size(d,1)-1, length(lstActTmp));
        for ii = 1:round(tMotion*fs)
            max_diff=max([abs(d((ii+1):end,lstActTmp)-d(1:(end-ii),lstActTmp)); zeros(ii-1,length(lstActTmp))], max_diff);
        end

        % find indices with motion artifacts based on std_thresh or amp_thresh
        bad_inds = zeros(size(max_diff));
        mc_thresh = std_diff*std_thresh;
        for ii = 1:length(lstActTmp)
            bad_inds(:,ii) = max( [ max_diff(:,ii)>mc_thresh(ii), max_diff(:,ii)>amp_thresh ], [], 2);
        end
        bad_inds = find(max(bad_inds,[],2)==1);

        % Eliminate time points before or after motion artifacts
        if ~isempty(bad_inds)
            bad_inds = repmat(bad_inds, 1, 2*art_buffer+1) + repmat(-art_buffer:art_buffer, length(bad_inds), 1);
            bad_inds = bad_inds((bad_inds>0) & (bad_inds<=(size(d, 1)-1)));

            % exclude points that were manually excluded
            bad_inds(find(tIncMan{iBlk}(bad_inds)==0)) = [];

            % Set t and diff of data to 0 at the bad inds
            tInc{iBlk}(1+bad_inds) = 0; % bad inds calculated on diff so add 1
            tIncCh{iBlk}(1+bad_inds, lstAct(iCh)) = 0;
        end

    end % loop over channels

end


classdef GenericQuatInterpSteeringModel < AbstractSteeringModel
    %GenericQuatInterpSteeringModel Summary of this class goes here
    %   Detailed explanation goes here

    properties
        t0(1,1) double = 0;
        tDur(1,1) double = 0;

        alpha0(1,1) double = 0;
        beta0(1,1) double = 0;
        gamma0(1,1) double = 0;

        alpha1(1,1) double = 0;
        beta1(1,1) double = 0;
        gamma1(1,1) double = 0;

        initQuat(1,4) double = [1,0,0,0];
        finalQuat(1,4) double = [1,0,0,0];

        angleContinuity(1,1) double = false;

        refFrame AbstractReferenceFrame
        controlFrame AbstractControlFrame
    end

    methods
        function dcm = getBody2InertialDcmAtTime(obj, ut, rVect, vVect, bodyInfo)
            if(obj.tDur > 0)
                if(ut < obj.t0)
                    f = 0;
                elseif(ut > (obj.t0 + obj.tDur))
                    f = 1;
                else
                    f = ((ut - obj.t0)/(obj.tDur));

                    if(f > 1)
                        f = 1;
                    elseif(f < 0)
                        f = 0;
                    end
                end

                q = quatinterp(obj.initQuat, obj.finalQuat, f);
            else
                q = obj.initQuat;
            end

%             elemSet = CartesianElementSet(ut, rVect(:), vVect(:), bodyInfo.getBodyCenteredInertialFrame());
%             if(not(isempty(obj.refFrame.getOriginBody())))
%                 elemSet = elemSet.convertToFrame(obj.refFrame);
%             end

            [alphaAng, betaAng, gammaAng] = quat2angle(q, 'ZYX');

            dcm = obj.controlFrame.computeDcmToInertialFrame(ut, rVect, vVect, bodyInfo, gammaAng, betaAng, alphaAng, obj.refFrame);
            dcm = real(dcm);
        end

        function t0 = getT0(obj)
            t0 = obj.t0;
        end

        function setT0(obj, newT0)
            obj.t0 = newT0;
        end

        function angleCont = getContinuityTerms(obj)
            angleCont = obj.angleContinuity;
        end

        function setContinuityTerms(obj, angleContinuity)
            obj.angleContinuity = angleContinuity;
        end

        function tDur = getDuration(obj)
            tDur = obj.tDur;
        end

        function setDuration(obj, tDur)
            obj.tDur = tDur;
        end

        function [gamma0, beta0, alpha0] = getInitAngles(obj)
            gamma0 = obj.gamma0;
            beta0 = obj.beta0;
            alpha0 = obj.alpha0;
        end

        function [gamma1, beta1, alpha1] = getFinalAngles(obj)
            gamma1 = obj.gamma1;
            beta1 = obj.beta1;
            alpha1 = obj.alpha1;
        end

        function setInitAngles(obj, gamma0, beta0, alpha0)
            obj.gamma0 = gamma0;
            obj.beta0 = beta0;
            obj.alpha0 = alpha0;
        end

        function setFinalAngles(obj, gamma1, beta1, alpha1)
            obj.gamma1 = gamma1;
            obj.beta1 = beta1;
            obj.alpha1 = alpha1;
        end

        function setConstsFromDcmAndContinuitySettings(obj, dcm, ut, rVect, vVect, bodyInfo)
            if(obj.angleContinuity)
                elemSet = CartesianElementSet(ut, rVect(:), vVect(:), bodyInfo.getBodyCenteredInertialFrame());

%                 if(not(isempty(obj.refFrame.getOriginBody())))
%                     elemSet = elemSet.convertToFrame(obj.refFrame);
%                 end

                [gammaAngle, betaAngle, alphaAngle] = obj.controlFrame.getAnglesFromInertialBodyAxes(LaunchVehicleAttitudeState(dcm), elemSet.time, elemSet.rVect(:), elemSet.vVect(:), elemSet.frame.getOriginBody(), obj.refFrame);

                obj.alpha0 = alphaAngle;
                obj.beta0 = betaAngle;
                obj.gamma0 = gammaAngle;
            end

            obj.setQuatsByAngles(); %need this here because I need to initialize the quaternions correctly from the angles at action init
        end

        function setInitialAttitudeFromState(obj, stateLogEntry, tOffsetDelta)
            %nothing
        end

        function [angle1Name, angle2Name, angle3Name] = getAngleNames(obj)
%             angle1Name = 'Gamma';
%             angle2Name = 'Beta';
%             angle3Name = 'Alpha';

            angleNames = obj.controlFrame.getControlFrameEnum().angleNames;
            angle1Name = angleNames{1};
            angle2Name = angleNames{2};
            angle3Name = angleNames{3};
        end

        function newSteeringModel = deepCopy(obj)
            newSteeringModel = GenericQuatInterpSteeringModel(obj.t0, obj.tDur, obj.alpha0, obj.beta0, obj.gamma0, obj.alpha1, obj.beta1, obj.gamma1);

            newSteeringModel.angleContinuity = obj.angleContinuity;

            newSteeringModel.refFrame = obj.refFrame;
            newSteeringModel.controlFrame = obj.controlFrame;
        end

        function optVar = getNewOptVar(obj)
            optVar = SetGenericQuatInterpSteeringModelActionOptimVar(obj);
        end

        function optVar = getExistingOptVar(obj)
            optVar = obj.optVar;
        end

        function tf = usesRefFrame(~)
            tf = true;
        end

        function refFrame = getRefFrame(obj)
            refFrame = obj.refFrame;
        end

        function setRefFrame(obj, refFrame)
            obj.refFrame = refFrame;
        end

        function tf = usesControlFrame(~)
            tf = true;
        end

        function cFrame = getControlFrame(obj)
            cFrame = obj.controlFrame;
        end

        function setControlFrame(obj, cFrame)
            obj.controlFrame = cFrame;
        end

        function tf = requiresReInitAfterSoIChange(obj)
            tf = false;
        end

        function enum = getSteeringModelTypeEnum(~)
            enum = SteerModelTypeEnum.QuaterionInterp;
        end

        function [addActionTf, steeringModel] = openEditSteeringModelUI(obj, lv, useContinuity)
            output = AppDesignerGUIOutput({false, obj});
            lvd_EditActionSetQuatInterpSteeringModelGUI_App(obj, lv, useContinuity, output);
            addActionTf = output.output{1};
            steeringModel = output.output{2};
        end
    end

    methods(Access=private)
        function obj = GenericQuatInterpSteeringModel(t0, tDur, alpha0, beta0, gamma0, alpha1, beta1, gamma1)
            obj.t0 = t0;
            obj.tDur = tDur;

            obj.alpha0 = alpha0;
            obj.beta0 = beta0;
            obj.gamma0 = gamma0;

            obj.alpha1 = alpha1;
            obj.beta1 = beta1;
            obj.gamma1 = gamma1;

            obj.setQuatsByAngles();
        end

        function setQuatsByAngles(obj)
            obj.initQuat = angle2quat(obj.alpha0, obj.beta0, obj.gamma0, 'ZYX');
            obj.finalQuat = angle2quat(obj.alpha1, obj.beta1, obj.gamma1, 'ZYX');
        end
    end

    methods(Static)
        function model = getDefaultSteeringModel()
            t0 = 0;
            tDur = 1;

            alpha0 = 0;
            beta0 = 0;
            gamma0 = 0;

            alpha1 = 0;
            beta1 = 0;
            gamma1 = 0;

            model = GenericQuatInterpSteeringModel(t0, tDur, alpha0, beta0, gamma0, alpha1, beta1, gamma1);
        end

        function typeStr = getTypeNameStr()
            typeStr = SteeringModelEnum.GenericQuatInterp.nameStr;
        end
    end
end


report_this_filefun(mfilename('fullpath'));

BV = [];
BV3 = [];
mag = [];
me = [];
av2=[];
Nmin = 50;
def = {'10','5'};
tit ='b with depth input parameters';
prompt={ 'Depth range sampled in km',...
    'move window in km',...
    };

ni2 = inputdlg(prompt,tit,1,def);
l = ni2{1};
drkm = str2double(l);
l = ni2{2};
mokm = str2double(l);

ButtonName=questdlg('Mc determination?', ...
    ' Question', ...
    'Automatic','Fixed Mc=Mmin','Money');

think
[s,is] = sort(newt2.Depth);
newt1 = newt2(is(:,1),:) ;
watchon;

for t = min(newt2.Depth):mokm:max(newt2.Depth)
    % calculate b-value based an weighted LS
    l = newt2.Depth >= t & newt2.Depth < t+drkm;
    b = newt2(l,:);

    switch ButtonName
        case 'Automatic'
            % mcperc_ca3;
            %if isnan(Mc95) == 0
            %    magco = Mc95;
            %elseif isnan(Mc90) == 0
            %    magco = Mc90;
            %else
            [bv magco stan av me mer me2,  pr] =  bvalca3(b,1,1);
            %end
        case 'Fixed Mc=Mmin'
            magco = min(newt1(:,6))
    end

    l = b(:,6) >= magco-0.05;
    if length(b(l,:)) >= Nmin
        %[bv magco0 stan av me mer me2,  pr] =  bvalca3(b(l,:),2,2);
        [mea bv stan,  av] =  bmemag(b(l,:));
    else
        bv = nan; bv2 = nan, magco = nan; av = nan; av2 = nan;
    end
    BV = [BV ; bv min(b(:,7)) ; bv max(b(:,7)) ; inf inf];
    BV3 = [BV3 ; bv mean(b(:,7)) stan ];
    %mag = [mag ; av newt1(t+round(ni/2),7)];

    % calculate b-value based on maximum likelihood
    %av2 = [av2 ;   av  newt1(t+round(ni/2),7) stan bv];

end

watchoff

% Find out of figure already exists
%
[existFlag,figNumber]=figure_exists('b-value with depth',1);
newdepWindowFlag=~existFlag;
bdep= figNumber;

% Set up the Cumulative Number window

if newdepWindowFlag
    bdep = figure_w_normalized_uicontrolunits( ...
        'Name','b-value with depth',...
        'NumberTitle','off', ...
        'MenuBar','none', ...
        'NextPlot','add', ...
        'backingstore','on',...
        'Visible','on', ...
        'Position',[ 150 150 (ZmapGlobal.Data.map_len - [50 20]) ]);

    uicontrol('Units','normal',...
        'Position',[.0 .85 .08 .06],'String','Info ',...
         'Callback','infoz(1)');

    matdraw
end

figure_w_normalized_uicontrolunits(bdep)
delete(gca)
delete(gca)
delete(gca)
delete(gca)
hold off

axis off
hold on
orient tall
%rect = [0.15 0.65 0.7 0.25];
rect = [0.25 0.15 0.5 0.75];
axes('position',rect)
ple = errorbar(BV3(:,2),BV3(:,1),BV3(:,3),BV3(:,3),'k')
set(ple(1),'color',[0.5 0.5 0.5]);

hold on
pl = plot(BV(:,2),BV(:,1),'color',[0.5 0.5 0.5]);

pl = plot(BV3(:,2),BV3(:,1),'sk')

set(pl,'LineWidth',1.0,'MarkerSize',4,...
    'MarkerFaceColor','w','MarkerEdgeColor','k','Marker','s');

set(gca,'box','on',...
    'SortMethod','childorder','TickDir','out','FontWeight',...
    'bold','FontSize',ZmapGlobal.Data.fontsz.m,'Linewidth',1.,'Ticklength',[ 0.02 0.02])

bax = gca;
strib = [name ', ni = ' num2str(ni), ', Mmin = ' num2str(min(newt2.Magnitude)) ];
ylabel('b-value')
xlabel('Depth [km]')
title2(strib,'FontWeight','bold',...
    'FontSize',ZmapGlobal.Data.fontsz.m,...
    'Color','k')

xl = get(gca,'Xlim');
view([90 90])


filename='BridgeCool_Quadrilateral_Bilinear_Structured';
 ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'full';
cost = {'compliance','perimeter'};
weights = [1 0.1];
constraint = {'volume'};
optimizer = 'MMA'; incrementFactor = 1;
filterType = 'P1';
constraint_case = 'INEQUALITY';
line_search_initiator = 'STANDARD';

nsteps = 15;
Vfrac_final = 0.2;
Perimeter_target = 1;
optimality_final = 1e-3;
constr_final =1e-3;

Vfrac_initial = 1;
optimality_initial = 1e-3;
constr_initial = 1e-3;
TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;
TOL.nu_plus = 1/3;
TOL.nu_minus = 1/3;