%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% RUN THIS SCRIPT TO REMOVE LOCAL PATHS ADDED WHEN RUNNING THE
% CONTROLLER.
%
% In the Simulink model, this script is run every time the user presses
% the 'terminate' button.

%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
rmpath(genpath('./src/'))

% Create a folder for collecting data
if Config.SAVE_WORKSPACE

    if (~exist(['experiments',date],'dir'))

        mkdir(['experiments',date]);
    end

   matFileList = dir(['./experiments',date,'/*.mat']);
   c           = clock;

   save(['./experiments',date,'/exp_',num2str(c(4)),'-',num2str(c(5)),'.mat'])
end

% Compare the Yarp time with the Simulink time to catch if the required
% integration time step is respected during the simulation
if Config.CHECK_INTEGRATION_TIME && exist('yarp_time','var')

    sim_time   = yarp_time.time;

    % normalize the yarp time over the first value (at t_sim = 0)
    yarp_time0 = yarp_time.signals.values - yarp_time.signals.values(1);

    % fast check of yarp time vs. Simulink time
    if Config.PLOT_INTEGRATION_TIME

        figure
        hold on
        plot(yarp_time0,0:length(yarp_time0)-1,'o')
        plot(sim_time,0:length(sim_time)-1,'o-')
        xlabel('Time [s]')
        ylabel('Iterations')
        grid on
        legend('Yarp Time','Simulink Time')
        title('Yarp time vs. Simulink time')
    end

    % number of times the real time step was bigger than twice the
    % desired time step value
    numOfTimeStepViolations = sum(diff(yarp_time0) > 2*Config.Ts);

    if numOfTimeStepViolations > 1 && numOfTimeStepViolations <= 50

        warning(['The time step tolerance of ', num2str(Config.Ts), '[s] has been violated at least once.'])

    elseif numOfTimeStepViolations > 50

        warning(['The time step tolerance of ', num2str(Config.Ts), '[s] has been violated  more than 50 times.'])
    end
end


%% gaborFilter
% Below is a demonstration of the features of the |gaborFilter| function

%%
clear; close all; clc;

%% Syntax
% |GB=gaborFilter(Vr,S,f,tagShift,d,siz,p);|

%% Description
% UNDOCUMENTED
%% Examples
%
%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


EEGDATA.buffer(:,1+mod(EEGDATA.smax:EEGDATA.smax+size(EEGDATA_chunk,2)-1,EEGDATA.buffer_len)) = EEGDATA_chunk;
EEGDATA.smax = EEGDATA.smax + size(EEGDATA_chunk,2);


function isExist = file_exist(filename)
% FILE_EXIST: Test the existence of an absolute file path on the disk.
%             Replacement for the Matlab call "exist(..., 'file')" that gives unexpected results
%             when the file is somewhere in the Matlab path.

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c)2000-2020 University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Author: Francois Tadel, 2011-2013

% Empty variable
if isempty(filename)
    isExist = 0;
% File is a root folder: let's consider it exists
% elseif strcmp(filename, bst_fileparts(filename))
elseif isequal(filename, '/') || isequal(filename, '\')
    isExist = 1;
% File does not exist: no ambiguity
elseif isempty(dir(filename))
    isExist = 0;
% File exists: we have to make sure it is NOT relatively to the current path
else
    % Check the file relative to the current Matlab folder
    pwdPath = pwd;
    pwdFile = [pwdPath '/' filename];
    % If it does NOT exist: no ambiguity, file exists
    if isempty(dir(pwdFile))
        isExist = 1;
    % Else: we consider that the file exists only in the current folder is a root folder
    % (=> folder = folder's parent)
    elseif strcmp(pwdPath, bst_fileparts(pwdPath, 1))
        isExist = 1;
    else
        isExist = 0;
    end
end


% VL_IHASHFIND  Find labels in an integer hash table
%   SEL = VL_IHASHFIND(ID, NEXT, K, X) returns a vector SEL of the
%   entires in the hash table ID,NEXT,K corresponding to the labels
%   stored as columns of X.
%
%   The format is the same as for the functino VL_IHASHSUM().
%
%   See also: VL_IHASHSUM().

% Author: Andrea Vedaldi

% Copyright (C) 2008-12 Andrea Vedaldi.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).


function ui = mrViewLoad(ui, pth, type, format, varargin);
% Load a new MR data file / ROI / other data into a mrViewer UI.
%
%   ui = mrViewLoad([ui, pth, type, format, [options]]);
%
% ui: mrViewer UI struct. Finds the most current one if
% omitted.
%
% pth: path to the MR file/s to load. (see mrLoad.)
%
% type: flag for what type of data to load:
%       0 [default]: load the newMR object as the new 'base' newMR object
%                    (stored in the ui.newMR field); the spaces,
%                    as well as any overlays/ROIs/ will need to be
%                    redefined in terms of this new space.
%       1:          load as a map in the ui.maps cell array, to be used
%                   for overlays.
%       2:          load ROI.
%       3:          load space transformation information. Right now,
%                   this means loading a mrSESSION.alignment field. May
%                   become more general in the future.
%       4:          load stimulus files / parfiles.
%       5:          segmentation.
%       6:          mesh.
%       7:          mesh settings file.
% type can also be a string out of:
%   'base', 'map', 'roi', 'space', 'stim', 'segmentation', 'mesh'.
%   'meshsettings'.
%
% format: file format (see mrLoad). Usually, this can be omitted
% and will be inferred from the filename.
%
% For some data types, the code will accept optional additional arguments.
% For instance, when loading a map, the 5th argument can specify which
% sub-volume to load in a map. (E.g., if a map comprises multiple 3-D
% scans, the argument can specify which of these scans to keep, discarding
% the others.)
%
% ras 07/05.
if ~exist('ui','var') | isempty(ui), ui = mrViewGet;            end
if ishandle(ui),                     ui = get(ui,'UserData');   end
if ~exist('type','var') | isempty(type), type = 0;     end
if ~exist('pth', 'var'),		pth = '';						end
if ~exist('format', 'var'),		format = '';					end

typesList = {'base', 'map', 'roi', 'space', 'stim', 'segmentation', ...
	'mesh' 'meshsettings'};

if isnumeric(type), 	type = typesList{type+1};			end

if ~ismember(lower(type), typesList), error('Invalid data type.'); end

% ras 03/07: converted SWITCH statement into a set of sub-functions, to
% make 'em easier to get to.
subfun = sprintf('mrViewLoad%s%s', upper(type(1)), lower(type(2:end)));
if isempty(varargin)
	% evaluate the sub-function without additional options
	ui = feval(subfun, ui, pth, format);
else
	% also pass along the options
	ui = feval(subfun, ui, pth, format, varargin);
end

% update the UI figure
if ishandle(ui.fig)
	set(ui.fig,'UserData',ui);
end

return
% /-----------------------------------------------------------------/ %

% /-----------------------------------------------------------------/ %
function ui = mrViewLoadBase(ui, pth, format, varargin);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% load as a base object:
% adjust spaces accordingly. When overlays
% and ROIs are added, will need to adjust these as
% well.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if notDefined('pth')
	ui.mr = mrLoad;
elseif notDefined('format')
	ui.mr = mrParse(pth); % also allow struct
else
	ui.mr = mrLoad(pth, format);
end
ui.spaces = ui.mr.spaces;

return
% /-----------------------------------------------------------------/ %

% /-----------------------------------------------------------------/ %
function ui = mrViewLoadMap(ui, pth, format, varargin);
%%%%%%%%%%%%%%%%%
% load as a map %
%%%%%%%%%%%%%%%%%
if notDefined('pth')
	pth = mrLoad;
elseif ~exist(pth, 'file')
	% check: if the path is a string to a file that can't be
	% found, see if it's relative to a mrVista data directory:
	if ischar(pth) | ~exist(pth, 'file')
		mrGlobals2;
		test = fullfile(dataDir(INPLANE{1}), [pth '.mat']);
		if exist(test, 'file'), pth = test; end
	end
end

if notDefined('format')
	newMR = mrParse(pth);
else
	newMR = mrLoad(pth, format);
end

%%%%%special case: old corAnal files
if isequal(newMR.name,'Coherence') & isequal(newMR.format,'1.0corAnal')
	[co amp ph] = mrReadOldCorAnal(newMR.path);
	ui = mrViewAddMap(ui,co);
	ui = mrViewAddMap(ui,amp);
	ui = mrViewAddMap(ui,ph);
	return
end

% varargin may specify a set of scans from which to take the map
if ~isempty(varargin)
	varargin = unNestCell(varargin);
	scans = varargin{1};
	try
		% find the indices I which correspond to the requested scans
		[scansWithData, I] = intersect(newMR.info.scans, scans);
		if length(scansWithData) < length(scans)
			% can't load all the specified scans? error.
% 			error('Can''t load all selected scans.')
		end

		% sub-select the scan data
		newMR.data = newMR.data(:,:,:,I);
		newMR.dims = size(newMR.data);
		newMR.info.scans = newMR.info.scans(I);
		if prefsVerboseCheck >= 1
			fprintf('[%s]: Loading map data from scans %s.\n', ...
					mfilename, num2str(scans));
		end
	catch
		if prefsVerboseCheck >= 1
			fprintf('[%s]: Couldn''t sub-select scans; loading all scans.\n', ...
					mfilename);
		end
	end
end

% finally, add the new MR data as a map to the UI:
ui = mrViewAddMap(ui, newMR);

return
% /-----------------------------------------------------------------/ %

% /-----------------------------------------------------------------/ %
function ui = mrViewLoadRoi(ui, pth, format, varargin);
%%%%%%%%%%%%
% Load ROI %
%%%%%%%%%%%%
if ~iscell(pth), pth = {pth}; end

for i = 1:length(pth)
	% check: if the path is a string to a file that can't be
	% found, see if it's relative to a mrVista ROI directory:
	if ~check4File(pth{i}, '.mat')
		mrGlobals2;
		test = fullfile(roiDir(INPLANE{1}), [pth{i} '.mat']);
		if exist(test, 'file'), pth{i} = test; end
	end

	if ~check4File(pth{i}, '.mat')
		% still not found? Don't crash, just warn about it.
		warning( sprintf('%s not found.', pth{i}) );
		return
	end

	roi = roiCheckCoords(pth{i}, ui.mr);  % this will load the ROI file
	roi.lineHandles = []; % for drawing ROIs
	roi.prevCoords = []; % for undo
	if isequal(ui.mr.name, 'Inplane')
		roi.viewType = 'Inplane';
		roi.reference = ui.mr.path;
		roi.voxelSize = ui.mr.voxelSize;
	else
		roi.viewType = 'Volume';
		roi.reference = getVAnatomyPath;
		hdr = mrLoadHeader(roi.reference);
		roi.voxelSize = hdr.voxelSize;
	end

	ui = mrViewSet(ui, 'AddROI', roi);
end

return
% /-----------------------------------------------------------------/ %

% /-----------------------------------------------------------------/ %
function ui = mrViewLoadSpace(ui, pth, format, varargin);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Load Space Transformation / Alignment %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if isequal(lower(pth), 'dialog')
	% get path with a dialog
	txt = 'Select a mrSESSSION.mat file with the desired alignment';
	pth = mrSelectDataFile('stayput', 'r', '*.mat', txt);
end

[p f ext] = fileparts(pth);
if ~isequal(lower(f), 'mrsession')
	error('Can only load a mrSESSION alignment right now.');
end
load(pth, 'mrSESSION');

% create the new space -- this only works if the base MR object
% is the vAnatomy to which the inplanes were aligned:
ip = mrSESSION.inplanes;
ui.spaces(end+1).name = sprintf('%s Inplanes', mrSESSION.sessionCode);
ui.spaces(end).xform = inv(mrSESSION.alignment);
try
	ifileDir = fullfile(p, 'Raw', 'Anatomy', 'Inplane');
	w = dir(fullfile(ifileDir, 'I*'));
	ifile = fullfile(ifileDir, w(1).name);
	ui.spaces(end).dirLabels = mrIfileDirections(ifile);
catch
	ui.spaces(end).dirLabels = {'Rows' 'Cols' 'Slices'};
end
ui.spaces(end).sliceLabels = {'Rows' 'Cols' 'Slices'};
ui.spaces(end).units = 'Inplane Voxels';
ui.spaces(end).bounds = [1 1 1; ip.cropSize ip.nSlices]';

% add an option for this space in the 'Coordinates' menu
N = length(ui.spaces);
cb = sprintf('mrViewSet([],''Space'',%i); mrViewRefresh;', N);
h = uimenu(ui.menus.space, 'Label',ui.spaces(N).name, ...
	'Checked','off', 'Callback',cb);
ui.spaces(N).menuHandle = h;

return
% /-----------------------------------------------------------------/ %

% /-----------------------------------------------------------------/ %
function ui = mrViewLoadStim(ui, pth, format, varargin);
ui = mrViewAttachStim(ui, pth);
return
% /-----------------------------------------------------------------/ %

% /-----------------------------------------------------------------/ %
function ui = mrViewLoadSegmentation(ui, pth, format, varargin);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Load Segmentation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if ~isempty(pth) & exist(pth, 'file')
	%% load from a saved segmentation file...
	load(pth, 'seg');
	saveFlag = 0;

else
	%% create a segmentation, based on .class and .gray files
	saveFlag = 1; % will offer to save this info below...
	classFilters = {'*lass' 'mrGray Classification File'; ...
					'*nii*' 'NIFTI-format Classification File'; ...
					'*.*' 'All Files'};
	grayFilters = {'*ray' 'mrGray Gray Graph'; ...
				   '*.*' 'All Files'};
	classPath = mrvSelectFile('r', classFilters, 'Select Class File');
	grayPath = mrvSelectFile('r', grayFilters, 'Select Gray Graph');
	[ignore def] = fileparts(fileparts(classPath));
	name = inputdlg('Name of Segmentation?', mfilename, 1, {def});
	if isempty(name), return; else, name = name{1}; end
	seg = segCreate(name, classPath, grayPath);
end

ui = mrViewSet(ui, 'AddSegmentation', seg);

if saveFlag==1
	resp = questdlg(['Do you want to save a small segmentation ' ...
		'file, remembering the paths and name you ' ...
		'selected?'], 'Yes', 'No');
	if isequal(resp, 'Yes')
		seg = ui.segmentation(end);
		segPath = fullfile(fileparts(seg.class), 'segmentation.mat');
		save(segPath, 'seg');
		fprintf('Saved segmentation info in %s.\n', segPath);
	end
end

return
% /-----------------------------------------------------------------/ %

% /-----------------------------------------------------------------/ %
function ui = mrViewLoadMesh(ui, pth, format, varargin);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Load Mesh
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if ~isfield(ui.settings, 'segmentation') | ~isfield(ui, 'segmentation')
	resp = questdlg('No Segmentation installed. Install one now?');
	if isequal(resp, 'Yes')
		ui = mrViewLoad(ui, [], 'segmentation')
	else
		disp('mrViewLoad mesh aborted.'); return
	end
end

s = ui.settings.segmentation;
if isequal(lower(pth), 'firstmesh')
	% special: take the first mesh in the mesh dir
	startDir = ui.segmentation(s).params.meshDir;
	w = what(startDir);
	w.mat = setdiff(w.mat, {'MeshAngles.mat' 'MeshSettings.mat'});
	if isempty(w.mat)
		error( sprintf('No meshes found in %s.', startDir) );
	end
	pth = fullfile(startDir, w.mat{1});
elseif ~exist('pth', 'var') | ~exist(pth, 'file')
	startDir = ui.segmentation(s).params.meshDir;
	pth = mrvSelectFile('r', 'mat', 'Select Mesh File', startDir);
end
if ~exist(pth, 'file'), return; end % user canceled

ui = mrViewAddMesh(ui, mrmReadMeshFile(pth));

return
% /-----------------------------------------------------------------/ %

% /-----------------------------------------------------------------/ %
function ui = mrViewLoadMeshsettings(ui, pth, format, varargin);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Load Mesh Settings
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if notDefined('pth')      % pth is mesh dir in this case
	pth = mrViewGet(ui, 'CurMeshDir');
	if ~exist(pth, 'dir')
		[f pth] = uigetfile('*.mat', 'Select a Mesh Settings File');
	end
end

settingsFile = fullfile(pth, 'MeshSettings.mat');
if exist(settingsFile, 'file')
	load(settingsFile, 'settings');
	names = {settings.name};
	settingsList = findobj('Parent', ui.panels.mesh, 'Style', 'listbox');

	% check that the selected setting is within the range of the new set of
	% settings names
	n = get(settingsList, 'Value');
	if n > length(names), n = length(names); end

	set(settingsList, 'String', names, 'Value', n);
else
	warning( sprintf('Couldn''t find mesh settings file %s.', settingsFile) );
end
return


function om = opf_setup(mpc, mpopt)
%OPF  Constructs an OPF model object from a MATPOWER case struct.
%   OM = OPF_SETUP(MPC, MPOPT)
%
%   Assumes that MPC is a MATPOWER case struct with internal indexing,
%   all equipment in-service, etc.
%
%   See also OPF, EXT2INT, OPF_EXECUTE.

%   MATPOWER
%   Copyright (c) 1996-2016, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%   and Carlos E. Murillo-Sanchez, PSERC Cornell & Universidad Nacional de Colombia
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

%% options
dc  = strcmp(upper(mpopt.model), 'DC');
alg = upper(mpopt.opf.ac.solver);
use_vg = mpopt.opf.use_vg;
vcart = ~dc && mpopt.opf.v_cartesian;

%% define named indices into data matrices
[PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
    VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
[GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
    MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
    QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
[F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
    TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
    ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
[PW_LINEAR, POLYNOMIAL, MODEL, STARTUP, SHUTDOWN, NCOST, COST] = idx_cost;

%% define flag to indicate whether we are tied to legacy formulation
%% implemented by legacy MINOS and PDIPM solvers (e.g. with hard-coded
%% costs and constrain
if strcmp(alg, 'MINOPF') || strcmp(alg, 'PDIPM') || ...
        strcmp(alg, 'TRALM') || strcmp(alg, 'SDPOPF')
    legacy_formulation = 1;
    if vcart
        error('Option ''opf.v_cartesian'' = 1 is not compatible with ''opf.solver.ac''=''%s''.', alg);
    end
    if mpopt.opf.current_balance
        error('Option ''opf.current_balance'' = 1 is not compatible with ''opf.solver.ac''=''%s''.', alg);
    end
else
    legacy_formulation = 0;
end
if ~dc && ( ~isempty(mpopt.exp.sys_wide_zip_loads.pw) && ...
                    ~isequal(mpopt.exp.sys_wide_zip_loads.pw, [1 0 0]) || ...
            ~isempty(mpopt.exp.sys_wide_zip_loads.qw) && ...
                    ~isequal(mpopt.exp.sys_wide_zip_loads.qw, [1 0 0]) )
    if vcart
        warning('Voltage dependent loads are not supported with option ''opf.v_cartesian'' = 1. Reverting to constant power load model.');
    end
    if mpopt.opf.current_balance
        warning('Voltage dependent loads are not supported with option ''opf.current_balance'' = 1. Reverting to constant power load model.');
    end
end

%% data dimensions
nb   = size(mpc.bus, 1);    %% number of buses
nl   = size(mpc.branch, 1); %% number of branches
ng   = size(mpc.gen, 1);    %% number of dispatchable injections
nnle = 0;                   %% number of nonlinear user-defined equality cons
nnli = 0;                   %% number of nonlinear user-defined inequality cons
if isfield(mpc, 'A')
  nlin = size(mpc.A, 1);    %% number of linear user constraints
else
  nlin = 0;
end
if isfield(mpc, 'N')
  nw = size(mpc.N, 1);      %% number of general cost vars, w
else
  nw = 0;
end

if dc
  %% ignore reactive costs for DC
  mpc.gencost = pqcost(mpc.gencost, ng);

  %% reduce A and/or N from AC dimensions to DC dimensions, if needed
  if nlin || nw
    acc = [nb+(1:nb) 2*nb+ng+(1:ng)];   %% Vm and Qg columns
    if nlin && size(mpc.A, 2) >= 2*nb + 2*ng
      %% make sure there aren't any constraints on Vm or Qg
      if any(any(mpc.A(:, acc)))
        error('opf_setup: attempting to solve DC OPF with user constraints on Vm or Qg');
      end
      mpc.A(:, acc) = [];               %% delete Vm and Qg columns
    end
    if nw && size(mpc.N, 2) >= 2*nb + 2*ng
      %% make sure there aren't any costs on Vm or Qg
      if any(any(mpc.N(:, acc)))
        [ii, jj] = find(mpc.N(:, acc));
        ii = unique(ii);    %% indices of w with potential non-zero cost terms from Vm or Qg
        if any(mpc.Cw(ii)) || (isfield(mpc, 'H') && ~isempty(mpc.H) && ...
                any(any(mpc.H(:, ii))))
          error('opf_setup: attempting to solve DC OPF with user costs on Vm or Qg');
        end
      end
      mpc.N(:, acc) = [];               %% delete Vm and Qg columns
    end
  end
else    %% AC
  if use_vg     %% adjust bus voltage limits based on generator Vg setpoint
    %% gen connection matrix, element i, j is 1 if, generator j at bus i is ON
    Cg = sparse(mpc.gen(:, GEN_BUS), (1:ng)', mpc.gen(:, GEN_STATUS) > 0, nb, ng);
    Vbg = Cg * sparse(1:ng, 1:ng, mpc.gen(:, VG), ng, ng);
    Vmax = max(Vbg, [], 2); %% zero for non-gen buses, else max Vg of gens @ bus
    ib = find(Vmax);                %% buses with online gens
    Vmin = max(2*Cg - Vbg, [], 2);  %% same as Vmax, except min Vg of gens @ bus
    Vmin(ib) = 2 - Vmin(ib);

    if use_vg == 1      %% use Vg setpoint directly
        mpc.bus(ib, VMAX) = Vmax(ib);   %% max set by max Vg @ bus
        mpc.bus(ib, VMIN) = Vmin(ib);   %% min set by min Vg @ bus
        mpc.bus(ib, VM) = mpc.bus(ib, VMAX);
    elseif use_vg > 0 && use_vg < 1     %% fractional value
        %% use weighted avg between original Vmin/Vmax limits and Vg
        mpc.bus(ib, VMAX) = (1-use_vg) * mpc.bus(ib, VMAX) + use_vg * Vmax(ib);
        mpc.bus(ib, VMIN) = (1-use_vg) * mpc.bus(ib, VMIN) + use_vg * Vmin(ib);
    else
        error('opf_setup: option ''opf.use_vg'' (= %g) cannot be negative or greater than 1', use_vg);
    end
  end
  if isfield(mpc, 'user_constraints')
    if isfield(mpc.user_constraints, 'nle')
      for k = 1:length(mpc.user_constraints.nle)
        nnle = nnle + mpc.user_constraints.nle{k}{2};
      end
    end
    if isfield(mpc.user_constraints, 'nli')
      for k = 1:length(mpc.user_constraints.nli)
        nnli = nnli + mpc.user_constraints.nli{k}{2};
      end
    end
  end
end

%% convert single-block piecewise-linear costs into linear polynomial cost
pwl1 = find(mpc.gencost(:, MODEL) == PW_LINEAR & mpc.gencost(:, NCOST) == 2);
% p1 = [];
if ~isempty(pwl1)
  x0 = mpc.gencost(pwl1, COST);
  y0 = mpc.gencost(pwl1, COST+1);
  x1 = mpc.gencost(pwl1, COST+2);
  y1 = mpc.gencost(pwl1, COST+3);
  m = (y1 - y0) ./ (x1 - x0);
  b = y0 - m .* x0;
  mpc.gencost(pwl1, MODEL) = POLYNOMIAL;
  mpc.gencost(pwl1, NCOST) = 2;
  mpc.gencost(pwl1, COST:COST+1) = [m b];
end

%% create (read-only) copies of individual fields for convenience
[baseMVA, bus, gen, branch, gencost, Au, lbu, ubu, mpopt, ...
    N, fparm, H, Cw, z0, zl, zu, userfcn] = opf_args(mpc, mpopt);

%% warn if there is more than one reference bus
refs = find(bus(:, BUS_TYPE) == REF);
if length(refs) > 1 && mpopt.verbose > 0
  errstr = ['\nopf_setup: Warning: Multiple reference buses.\n', ...
              '           For a system with islands, a reference bus in each island\n', ...
              '           may help convergence, but in a fully connected system such\n', ...
              '           a situation is probably not reasonable.\n\n' ];
  fprintf(errstr);
end

%% set up initial variables and bounds
Va   = bus(:, VA) * (pi/180);
Vau = Inf(nb, 1);       %% voltage angle limits
Val = -Vau;
Vau(refs) = Va(refs);   %% voltage angle reference constraints
Val(refs) = Va(refs);
Pg   = gen(:, PG) / baseMVA;
Pmin = gen(:, PMIN) / baseMVA;
Pmax = gen(:, PMAX) / baseMVA;
if ~dc
  Vm   = bus(:, VM);
  Qg   = gen(:, QG) / baseMVA;
  Qmin = gen(:, QMIN) / baseMVA;
  Qmax = gen(:, QMAX) / baseMVA;
  if vcart
    V = Vm .* exp(1j*Va);
    Vr = real(V);
    Vi = imag(V);
  end
end

%% find/prepare polynomial generator costs
cpg = [];
cqg = [];
%% reduce order where highest order has zero coefficient
gc = mpc.gencost;
while 1
    ii = find(  gc(:, MODEL) == POLYNOMIAL & ...
                gc(:, NCOST) > 2 & ...
                gc(:, COST) == 0    );
    if isempty(ii), break; end  %% exit loop if there are none
    gc(ii, NCOST) = gc(ii, NCOST) - 1;          %% reduce order
    gc(ii, COST:end-1) = gc(ii, COST+1:end);    %% shift coefficients
    gc(ii, end) = 0;
end
[pcost qcost] = pqcost(gc, ng);
ip0 = find(pcost(:, MODEL) == POLYNOMIAL & pcost(:, NCOST) == 1);   %% constant
ip1 = find(pcost(:, MODEL) == POLYNOMIAL & pcost(:, NCOST) == 2);   %% linear
ip2 = find(pcost(:, MODEL) == POLYNOMIAL & pcost(:, NCOST) == 3);   %% quadratic
ip3 = find(pcost(:, MODEL) == POLYNOMIAL & pcost(:, NCOST) > 3);    %% cubic or greater
if ~isempty(ip2) || ~isempty(ip1) || ~isempty(ip0)
    kpg = zeros(ng, 1);
    cpg = zeros(ng, 1);
    if ~isempty(ip2)
        Qpg = zeros(ng, 1);
        Qpg(ip2) = 2 * pcost(ip2, COST) * baseMVA^2;
        cpg(ip2) = cpg(ip2) + pcost(ip2, COST+1) * baseMVA;
        kpg(ip2) = kpg(ip2) + pcost(ip2, COST+2);
    else
        Qpg = [];   %% no quadratic terms
    end
    if ~isempty(ip1)
        cpg(ip1) = cpg(ip1) + pcost(ip1, COST) * baseMVA;
        kpg(ip1) = kpg(ip1) + pcost(ip1, COST+1);
    end
    if ~isempty(ip0)
        kpg(ip0) = kpg(ip0) + pcost(ip0, COST);
    end
end
if ~isempty(qcost)
    iq0 = find(qcost(:, MODEL) == POLYNOMIAL & qcost(:, NCOST) == 1);   %% constant
    iq1 = find(qcost(:, MODEL) == POLYNOMIAL & qcost(:, NCOST) == 2);   %% linear
    iq2 = find(qcost(:, MODEL) == POLYNOMIAL & qcost(:, NCOST) == 3);   %% quadratic
    iq3 = find(qcost(:, MODEL) == POLYNOMIAL & qcost(:, NCOST) > 3);    %% cubic or greater
    if ~isempty(iq2) || ~isempty(iq1) || ~isempty(iq0)
        kqg = zeros(ng, 1);
        cqg = zeros(ng, 1);
        if ~isempty(iq2)
            Qqg = zeros(ng, 1);
            Qqg(iq2) = 2 * qcost(iq2, COST) * baseMVA^2;
            cqg(iq2) = cqg(iq2) + qcost(iq2, COST+1) * baseMVA;
            kqg(iq2) = kqg(iq2) + qcost(iq2, COST+2);
        else
            Qqg = [];   %% no quadratic terms
        end
        if ~isempty(iq1)
            cqg(iq1) = cqg(iq1) + qcost(iq1, COST) * baseMVA;
            kqg(iq1) = kqg(iq1) + qcost(iq1, COST+1);
        end
        if ~isempty(iq0)
            kqg(iq0) = kqg(iq0) + qcost(iq0, COST);
        end
    end
end

%% branch voltage angle difference limits
[Aang, lang, uang, iang]  = makeAang(baseMVA, branch, nb, mpopt);
nang = length(iang);

if dc               %% DC model
  %% check generator costs
  if ~isempty(ip3)
    error('opf_setup: DC OPF cannot handle polynomial costs with higher than quadratic order.');
  end

  %% more problem dimensions
  nv    = 0;            %% number of voltage magnitude vars
  nq    = 0;            %% number of Qg vars
  q1    = [];           %% index of 1st Qg column in Ay

  %% power mismatch constraints
  [B, Bf, Pbusinj, Pfinj] = makeBdc(baseMVA, bus, branch);
  neg_Cg = sparse(gen(:, GEN_BUS), 1:ng, -1, nb, ng);   %% Pbus w.r.t. Pg
  Amis = [B neg_Cg];
  bmis = -(bus(:, PD) + bus(:, GS)) / baseMVA - Pbusinj;

  %% branch flow constraints
  il = find(branch(:, RATE_A) ~= 0 & branch(:, RATE_A) < 1e10);
  nl2 = length(il);         %% number of constrained lines
  if nl2
    upf = branch(il, RATE_A) / baseMVA - Pfinj(il);
    upt = branch(il, RATE_A) / baseMVA + Pfinj(il);
  else
    upf = [];
    upt = [];
  end

  user_vars = {'Va', 'Pg'};
  ycon_vars = {'Pg', 'y'};
else                %% AC model
  %% more problem dimensions
  nv    = nb;           %% number of voltage magnitude vars
  nq    = ng;           %% number of Qg vars
  q1    = 1+ng;         %% index of 1st Qg column in Ay

  %% find branches with flow limits
  il = find(branch(:, RATE_A) ~= 0 & branch(:, RATE_A) < 1e10);
  nl2 = length(il);         %% number of constrained lines

  %% build admittance matrices
  [Ybus, Yf, Yt] = makeYbus(baseMVA, bus, branch);

  %% dispatchable load, constant power factor constraints
  [Avl, lvl, uvl]  = makeAvl(mpc);

  %% generator PQ capability curve constraints
  [Apqh, ubpqh, Apql, ubpql, Apqdata] = makeApq(baseMVA, gen);

  if vcart
      user_vars = {'Vr', 'Vi', 'Pg', 'Qg'};
      nodal_balance_vars = {'Vr', 'Vi', 'Pg', 'Qg'};
      flow_lim_vars = {'Vr', 'Vi'};
  else
      user_vars = {'Va', 'Vm', 'Pg', 'Qg'};
      nodal_balance_vars = {'Va', 'Vm', 'Pg', 'Qg'};
      flow_lim_vars = {'Va', 'Vm'};
  end
  ycon_vars = {'Pg', 'Qg', 'y'};

  %% nonlinear constraint functions
  if mpopt.opf.current_balance
    mis_cons = {'rImis', 'iImis'};
    fcn_mis = @(x)opf_current_balance_fcn(x, mpc, Ybus, mpopt);
    hess_mis = @(x, lam)opf_current_balance_hess(x, lam, mpc, Ybus, mpopt);
  else
    mis_cons = {'Pmis', 'Qmis'};
    fcn_mis = @(x)opf_power_balance_fcn(x, mpc, Ybus, mpopt);
    hess_mis = @(x, lam)opf_power_balance_hess(x, lam, mpc, Ybus, mpopt);
  end
  fcn_flow = @(x)opf_branch_flow_fcn(x, mpc, Yf(il, :), Yt(il, :), il, mpopt);
  hess_flow = @(x, lam)opf_branch_flow_hess(x, lam, mpc, Yf(il, :), Yt(il, :), il, mpopt);
  if vcart
    fcn_vref = @(x)opf_vref_fcn(x, mpc, refs, mpopt);
    hess_vref = @(x, lam)opf_vref_hess(x, lam, mpc, refs, mpopt);
    veq = find(mpc.bus(:, VMIN) == mpc.bus(:, VMAX));
    viq = find(mpc.bus(:, VMIN) ~= mpc.bus(:, VMAX));
    nveq = length(veq);
    nvlims = length(viq);
    if nveq
      fcn_veq = @(x)opf_veq_fcn(x, mpc, veq, mpopt);
      hess_veq = @(x, lam)opf_veq_hess(x, lam, mpc, veq, mpopt);
    end
    fcn_vlim = @(x)opf_vlim_fcn(x, mpc, viq, mpopt);
    hess_vlim = @(x, lam)opf_vlim_hess(x, lam, mpc, viq, mpopt);
    fcn_ang = @(x)opf_branch_ang_fcn(x, Aang, lang, uang);
    hess_ang = @(x, lam)opf_branch_ang_hess(x, lam, Aang, lang, uang);
  end

  %% nonlinear cost functions
  if ~isempty(ip3)
    cost_Pg = @(x)opf_gen_cost_fcn(x, baseMVA, pcost, ip3);
  end
  if ~isempty(qcost) && ~isempty(iq3)
    cost_Qg = @(x)opf_gen_cost_fcn(x, baseMVA, qcost, iq3);
  end
end

%% basin constraints for piece-wise linear gen cost variables
if (strcmp(alg, 'PDIPM') && mpopt.pdipm.step_control) || strcmp(alg, 'TRALM')
  %% SC-PDIPM or TRALM, no CCV cost vars
  ny = 0;
  Ay = sparse(0, ng+nq);
  by =[];
else
  ipwl = find(gencost(:, MODEL) == PW_LINEAR);  %% piece-wise linear costs
  ny = size(ipwl, 1);   %% number of piece-wise linear cost vars
  [Ay, by] = makeAy(baseMVA, ng, gencost, 1, q1, 1+ng+nq);
end
if any(gencost(:, MODEL) ~= POLYNOMIAL & gencost(:, MODEL) ~= PW_LINEAR)
    error('opf_setup: some generator cost rows have invalid MODEL value');
end

%% more problem dimensions
nx    = nb+nv + ng+nq;  %% number of standard OPF control variables
if nlin
  nz = size(mpc.A, 2) - nx; %% number of user z variables
  if nz < 0
    error('opf_setup: user supplied A matrix must have at least %d columns.', nx);
  end
else
  nz = 0;               %% number of user z variables
  if nw                 %% still need to check number of columns of N
    if size(mpc.N, 2) ~= nx;
      error('opf_setup: user supplied N matrix must have %d columns.', nx);
    end
  end
end

%% construct OPF model object
om = opf_model(mpc);
if ~isempty(pwl1)
  om.userdata.pwl1 = pwl1;
end
om.userdata.iang = iang;
if dc
  %% user data
  om.userdata.Bf = Bf;
  om.userdata.Pfinj = Pfinj;

  %% optimization variables
  om.add_var('Va', nb, Va, Val, Vau);
  om.add_var('Pg', ng, Pg, Pmin, Pmax);

  %% linear constraints
  om.add_lin_constraint('Pmis', Amis, bmis, bmis, {'Va', 'Pg'});    %% nb
  om.add_lin_constraint('Pf',  Bf(il,:), -upt, upf, {'Va'});        %% nl2
  om.add_lin_constraint('ang', Aang, lang, uang, {'Va'});           %% nang

  %% quadratic generator costs
  if ~isempty(cpg)
    om.add_quad_cost('polPg', Qpg, cpg, kpg, {'Pg'});
  end
else
  %% user data
  om.userdata.Apqdata = Apqdata;

  %% optimization variables
  if vcart
      Vclim = 1.1 * bus(:, VMAX);
      om.add_var('Vr', nb, Vr, -Vclim, Vclim);
      om.add_var('Vi', nb, Vi, -Vclim, Vclim);
  else
      om.add_var('Va', nb, Va, Val, Vau);
      om.add_var('Vm', nb, Vm, bus(:, VMIN), bus(:, VMAX));
  end
  om.add_var('Pg', ng, Pg, Pmin, Pmax);
  om.add_var('Qg', ng, Qg, Qmin, Qmax);

  %% nonlinear constraints
  om.add_nln_constraint(mis_cons, [nb;nb], 1, fcn_mis, hess_mis, nodal_balance_vars);
  if legacy_formulation
    om.add_nln_constraint({'Sf', 'St'}, [nl;nl], 0, fcn_flow, hess_flow, flow_lim_vars);
  else
    om.add_nln_constraint({'Sf', 'St'}, [nl2;nl2], 0, fcn_flow, hess_flow, flow_lim_vars);
  end
  if vcart
    om.userdata.veq = veq;  %% buses with voltage magnitude equality constraints
    om.userdata.viq = viq;  %% buses with voltage magnitude limits
    om.add_nln_constraint('Vref', length(refs), 1, fcn_vref, hess_vref, {'Vr', 'Vi'});
    if nveq
      om.add_nln_constraint('Veq', nveq, 1, fcn_veq, hess_veq, {'Vr', 'Vi'});
    end
    om.add_nln_constraint({'Vmin', 'Vmax'}, [nvlims;nvlims], 0, fcn_vlim, hess_vlim, {'Vr', 'Vi'});
    om.add_nln_constraint({'angL', 'angU'}, [nang;nang], 0, fcn_ang, hess_ang, {'Vr', 'Vi'});
  end

  %% linear constraints
  om.add_lin_constraint('PQh', Apqh, [], ubpqh, {'Pg', 'Qg'});      %% npqh
  om.add_lin_constraint('PQl', Apql, [], ubpql, {'Pg', 'Qg'});      %% npql
  om.add_lin_constraint('vl',  Avl, lvl, uvl,   {'Pg', 'Qg'});      %% nvl
  if ~vcart
    om.add_lin_constraint('ang', Aang, lang, uang, {'Va'});         %% nang
  end

  %% polynomial generator costs
  if ~legacy_formulation
    %% quadratic/linear generator costs
    if ~isempty(cpg)
      om.add_quad_cost('polPg', Qpg, cpg, kpg, {'Pg'});
    end
    if ~isempty(cqg)
      om.add_quad_cost('polQg', Qqg, cqg, kqg, {'Qg'});
    end

    %% higher order polynomial generator costs
    if ~isempty(ip3)
      om.add_nln_cost('polPg', 1, cost_Pg, {'Pg'});
    end
    if ~isempty(qcost) && ~isempty(iq3)
      om.add_nln_cost('polQg', 1, cost_Qg, {'Qg'});
    end
  end
end

%% y vars, constraints for piece-wise linear gen costs
if ny > 0
  om.add_var('y', ny);
  om.add_lin_constraint('ycon', Ay, [], by, ycon_vars);             %% ncony
  if dc || ~legacy_formulation
    om.add_quad_cost('pwl', [], ones(ny, 1), 0, {'y'});
  end
end

%% add user vars, constraints and costs (as specified via A, ..., N, ...)
if nz > 0
  om.add_var('z', nz, z0, zl, zu);
  user_vars{end+1} = 'z';
end
if nlin
  om.add_lin_constraint('usr', mpc.A, lbu, ubu, user_vars);         %% nlin
end
if nnle
  for k = 1:length(mpc.user_constraints.nle)
    nlc = mpc.user_constraints.nle{k};
    fcn  = eval(['@(x)' nlc{3} '(x, nlc{6}{:})']);
    hess = eval(['@(x, lam)' nlc{4} '(x, lam, nlc{6}{:})']);
    om.add_nln_constraint(nlc{1:2}, 1, fcn, hess, nlc{5});
  end
end
if nnli
  for k = 1:length(mpc.user_constraints.nli)
    nlc = mpc.user_constraints.nli{k};
    fcn  = eval(['@(x)' nlc{3} '(x, nlc{6}{:})']);
    hess = eval(['@(x, lam)' nlc{4} '(x, lam, nlc{6}{:})']);
    om.add_nln_constraint(nlc{1:2}, 0, fcn, hess, nlc{5});
  end
end
if nw
  user_cost.N = mpc.N;
  user_cost.Cw = Cw;
  if ~isempty(fparm)
    user_cost.dd = fparm(:, 1);
    user_cost.rh = fparm(:, 2);
    user_cost.kk = fparm(:, 3);
    user_cost.mm = fparm(:, 4);
  end
  if ~isempty(H)
    user_cost.H = H;
  end
  om.add_legacy_cost('usr', user_cost, user_vars);
end

%% execute userfcn callbacks for 'formulation' stage
om = run_userfcn(userfcn, 'formulation', om, mpopt);

%% implement legacy user costs using quadratic or general non-linear costs
cp = om.params_legacy_cost();   %% construct/fetch the parameters
[N, H, Cw, rh, mm] = deal(cp.N, cp.H, cp.Cw, cp.rh, cp.mm);
[nw, nx] = size(N);
if nw
    if any(cp.dd ~= 1) || any(cp.kk)    %% not simple quadratic form
        if dc                           %% (includes "dead zone" or
            if any(cp.dd ~= 1)          %%  quadratic "penalty")
                error('opf_setup: DC OPF can only handle legacy user-defined costs with d = 1');
            end
            if any(cp.kk)
                error('opf_setup: DC OPF can only handle legacy user-defined costs with no "dead zone", i.e. k = 0');
            end
        elseif ~legacy_formulation
            %% use general nonlinear cost to implement legacy user cost
            legacy_cost_fcn = @(x)opf_legacy_user_cost_fcn(x, cp);
            om.add_nln_cost('usr', 1, legacy_cost_fcn);
        end
    else                                %% simple quadratic form
        %% use a quadratic cost to implement legacy user cost
        if dc || ~legacy_formulation
            %% f = 1/2 * w'*H*w + Cw'*w, where w = diag(mm)*(N*x - rh)
            %% Let: MN = diag(mm)*N
            %%      MR = M * rh
            %%      HMR  = H  * MR;
            %%      HtMR = H' * MR;
            %%  =>   w = MN*x - MR
            %% f = 1/2 * (MN*x - MR)'*H*(MN*x - MR) + Cw'*(MN*x - MR)
            %%   = 1/2 * x'*MN'*H*MN*x +
            %%          (Cw'*MN - 1/2 * MR'*(H+H')*MN)*x +
            %%          1/2 * MR'*H*MR - Cw'*MR
            %%   = 1/2 * x'*Q*w + c'*x + k

            M    = sparse(1:nw, 1:nw, mm, nw, nw);
            MN   = M * N;
            MR   = M * rh;
            HMR  = H  * MR;
            HtMR = H' * MR;
            Q = MN' * H * MN;
            c = full(MN' * (Cw - 1/2*(HMR+HtMR)));
            k = (1/2 * HtMR - Cw)' * MR;
            om.add_quad_cost('usr', Q, c, k);
        end
    end
end


% Average European Diet defintion. For details, please see https://www.vmh.life/#nutrition
% Ines Thiele 2016-2019

Diet = {%'Exchange reactions'	'Total in mmol/(human*day)'
%'reaction'	'fluxValue'
'EX_10fthf(e)'	'0.000125752'
'EX_5mthf(e)'	'0.000129311'
'EX_adpcbl(e)'	'3.61E-06'
'EX_ala_L(e)'	'37.20856362'
'EX_arach(e)'	'1.033055397'
'EX_arachd(e)'	'0.536810751'
'EX_arg_L(e)'	'20.3518771'
'EX_ascb_L(e)'	'0.583441166'
'EX_asp_L(e)'	'47.08674913'
'EX_avite1(e)'	'0.03685808'
'EX_btn(e)'	'0.000178666'
'EX_but(e)'	'26.33425644'
'EX_ca2(e)'	'18.5490793'
'EX_caro(e)'	'0.003585581'
'EX_CE2510(e)'	'1.086665034'
'EX_CE4843(e)'	'0.114865263'
'EX_cellul(e)'	'0.052346876'
'EX_chsterol(e)'	'1.23218851'
'EX_cl(e)'	'187.7787493'
'EX_clpnd(e)'	'0.048376886'
'EX_crvnc(e)'	'0.16630008'
'EX_cu2(e)'	'0.035674944'
'EX_cys_L(e)'	'7.511831638'
'EX_dca(e)'	'10.74842619'
'EX_ddca(e)'	'13.45904717'
'EX_doco13ac(e)'	'0.560730443'
'EX_docosac(e)'	'0.454096231'
'EX_etoh(e)'	'234.4340155'
'EX_fe2(e)'	'0.109248814'
'EX_fe3(e)'	'0.109248814'
'EX_fol(e)'	'0.000134614'
'EX_fru(e)'	'106.5058652'
'EX_gal(e)'	'0.029974039'
'EX_glc_D(e)'	'135.5803501'
'EX_glu_L(e)'	'103.1222005'
'EX_gly(e)'	'36.76468629'

'EX_h2o(e)'	'165892.3425'
'EX_hdca(e)'	'92.78506719'
'EX_hdcea(e)'	'7.120473022'
'EX_his_L(e)'	'14.02407663'
'EX_hpdca(e)'	'1.779524923'
'EX_i(e)'	'0.00201238'
'EX_ile_L(e)'	'28.92167513'
'EX_k(e)'	'83.43380658'
'EX_lcts(e)'	'4.126714705'
'EX_leu_L(e)'	'46.88780991'
'EX_lgnc(e)'	'0.222615856'
'EX_lnlc(e)'	'54.98546187'
'EX_lnlnca(e)'	'4.163336898'
'EX_lys_L(e)'	'33.31154825'
'EX_malt(e)'	'8.413758248'
'EX_met_L(e)'	'10.72740469'
'EX_mg2(e)'	'14.52993211'
'EX_mn2(e)'	'0.074702331'
'EX_mnl(e)'	'0.170169038'
'EX_na1(e)'	'172.4462717'
'EX_nac(e)'	'0.308616192'
'EX_ncam(e)'	'0.1455276'
'EX_ocdca(e)'	'35.85086639'
'EX_ocdcea(e)'	'101.5927326'
'EX_octa(e)'	'6.845572908'
'EX_phe_L(e)'	'20.71498664'
'EX_phyQ(e)'	'0.000136877'
'EX_pi(e)'	'14.22660928'
'EX_pnto_R(e)'	'0.025569705'
'EX_pro_L(e)'	'53.81527918'
'EX_ptdca(e)'	'2.89407663'
'EX_pydam(e)'	'0.00317177'
'EX_pydx(e)'	'0.003210459'
'EX_pydxn(e)'	'0.003172205'
'EX_retinol(e)'	'3.002252387'
'EX_ribflv(e)'	'0.003693234'
'EX_sbt_D(e)'	'0.032935943'
'EX_ser_L(e)'	'37.37922556'
'EX_strch1(e)'	'33.03699973'
'EX_strdnc(e)'	'0'
'EX_sucr(e)'	'202.3830217'
'EX_thf(e)'	'0.000133696'
'EX_thm(e)'	'5.407858013'
'EX_thr_L(e)'	'25.88105024'
'EX_trp_L(e)'	'4.554824772'
'EX_ttdca(e)'	'30.21138004'
'EX_ttdcea(e)'	'3.783984795'
'EX_tyr_L(e)'	'15.64685397'
'EX_urate(e)'	'2.919392803'
'EX_val_L(e)'	'37.78437731'
'EX_vitd3(e)'	'8.76E-06'
'EX_xylt(e)'	'0.141969085'
'EX_zn2(e)'	'0.150963597'
'EX_adrn(e)'	'0'

% add bile acids
'EX_gchola(e)'	'10'
'EX_tdchola(e)'	'10'
'EX_tchola(e)'	'10'
'EX_dgchol(e)'	'10'
'EX_M01989(e)'	'10'
'EX_M01989(e)'	'10'

    };
Diet = regexprep(Diet,'EX_','Diet_EX_');
Diet = regexprep(Diet,'\(e\)','\[d\]');


function [files, metadata] = experiment_unsupervised(tracker, sequence, directory, parameters, scan)

    files = {};
    metadata.completed = true;
	cache = get_global_variable('experiment_cache', true);
	silent = get_global_variable('experiment_silent', false);

    defaults = struct('repetitions', 15);
    context = struct_merge(parameters, defaults);
    metadata.deterministic = false;

    time_file = fullfile(directory, sprintf('%s_time.txt', sequence.name));

    times = zeros(sequence.length, context.repetitions);

    if ~scan && cache && exist(time_file, 'file')
        times = csvread(time_file);
    end;

	r = context.repetitions;

	if isfield(tracker, 'metadata') && isfield(tracker.metadata, 'deterministic') && tracker.metadata.deterministic
		r = 1;
	end

	check_deterministic = ~(scan && nargout < 2); % Ensure faster execution when we only want a list of files by ommiting determinisim check.

    for i = 1:r

        result_file = fullfile(directory, sprintf('%s_%03d.txt', sequence.name, i));

        if cache && exist(result_file, 'file')
            files{end+1} = result_file; %#ok<AGROW>
            values = dir(fullfile(directory, sprintf('%s_%03d_*.value', sequence.name, i)));
            files(end+1:end+length(values)) = cellfun(@(x) fullfile(directory, x.name), num2cell(values), 'UniformOutput', false);
            continue;
        end;

        if check_deterministic && i == 4 && is_deterministic(sequence, 3, directory)
            if ~silent
                print_debug('Detected a deterministic tracker, skipping remaining trials.');
            end;
            metadata.deterministic = true;
            break;
        end;

        if scan
            metadata.completed = false;
            continue;
        end;

        print_indent(1);

        print_text('Repetition %d', i);

        context.repetition = i;

		data.sequence = sequence;
		data.index = 1;
		data.context = context;
		data.result = repmat({0}, sequence.length, 1);
		data.timing = nan(sequence.length, 1);
        data.properties = properties_create(sequence);
        data.channels = {};

		data = tracker_run(tracker, @callback, data);

	    times(:, i) = data.timing;
	    write_trajectory(result_file, data.result);
		csvwrite(time_file, times);

        properties_save(directory, sprintf('%s_%03d', sequence.name, i), data.properties);

        files{end+1} = result_file; %#ok<AGROW>
        values = dir(fullfile(directory, sprintf('%s_%03d_*.value', sequence.name, i)));
        files(end+1:end+length(values)) = cellfun(@(x) fullfile(directory, x.name), num2cell(values), 'UniformOutput', false);

        print_indent(-1);
    end;

    if exist(time_file, 'file')
        files{end+1} = time_file;
    else
        metadata.completed = false;
    end;

end

function [image, region, properties, data] = callback(state, data)

	region = [];
	image = [];
    properties = struct();

    if isempty(data.channels)
        if ~all(ismember(state.channels, fieldnames(data.sequence.channels)));
            error('Sequence does not contain all channels required by the tracker.');
        end;
        data.channels = state.channels;
    end;

	% Handle initial frame (initialize for the first time)
	if isempty(state.region)
		region = data.sequence.initialize(data.sequence, data.index, data.context);
		image = sequence_get_image(data.sequence, data.index, data.channels);
		return;
	end;

	% Store initialization
	if data.index == 1
		data.result{data.index} = 1;
	else
		data.result{data.index} = state.region;
	end;
	data.timing(data.index) = state.time;

    data.properties = properties_set(data.properties, data.index, state.properties);

	data.index = data.index + 1;

	% End of sequence
	if data.index > data.sequence.length
		return;
	end

    image = sequence_get_image(data.sequence, data.index, data.channels);

end


function DATA = read_edat_output_2008(fname, varargin)
% Function that creates a structure DATA containing columns
% of the edat file output (saved in text tab delimited "excel" format)
%
% :Usage:
% ::
%
%     DATA = read_edat_output_2008(fname, varargin)
%
% For this code to work on a Mac, you must: 1) export .edat2 file as an Excel file,
% then 2) open this file in Excel on a Mac and save as a .csv, 3) read that
% .csv file
%
% :Examples:
% ::
%
%    fname = 'myfile.txt';
%    DATA = read_edat_output_2008(fname)
%
% :Defaults:
% These are the default formats this function expects:
% tab delimited, 1 header row, then row of column names, then data
%
% You can override some of them by using the following --
% E.g., for zero header rows and comma delimited data:
% ::
%
%    DATA = read_edat_output_2008(fname, 'nheaderrows', 0, 'mydelimiter', ',')
%
% You can force the number of columns to be a certain value by doing the
% following:
%% ::
%
%    DATA = read_edat_output_2008(fname, 'nheaderrows', 1, 'numc', 103);
%
% This could be useful if your last row contains empty cells at the end,
% which will mess up the automatic calculation of number of columns.
%
% ..
%    Tor Wager, Oct 2008
% ..

% ..
%    read the database initially to get all column names, etc.
% ..
DATA = [];

% assume you have one header row
nheaderrows = 1;
mydelimiter = '\t';
numc = [];

for i = 1:length(varargin)
        if ischar(varargin{i})
            switch varargin{i}
                % reserved keywords
                case 'nheaderrows', nheaderrows = varargin{i+1};
                case 'mydelimiter', mydelimiter = varargin{i+1};

                case 'numc', numc = varargin{i+1};

                otherwise, warning(['Unknown input string option:' varargin{i}]);
            end
        end
end

col1 = textread(fname, '%s%*[^\n]', 'delimiter', mydelimiter, 'headerlines', nheaderrows, 'bufsize', 10000000);

nrows = length(col1);

%numc = 148;
[d] = textread(fname,'%s','headerlines', nheaderrows, 'delimiter', mydelimiter, 'bufsize', 10000000);

for i = 1:length(d), if isempty(d{i}), d{i} = 'NaN'; end, end

if isempty(numc)
    % determine from data
    numc = length(d) ./ nrows;
else
    % force numc to be input value
    disp(['Forcing number of columns to be ' num2str(numc)])
    totalel = nrows * numc;
    if length(d) < totalel
        numtoadd = totalel - length(d);
        for i = 1:numtoadd
            d{end+1} = 'NaN';
        end
    else
        d = d(1:totalel);
    end
end

% % if strcmp(d{1},'This file contained edited data.'),
% %     % add an extra input row!
% %     disp('edited data: extra row.')
% %     addone = 1;
% %     [d] = textread(fname,'%s','headerlines',2,'delimiter','\t');
% % end

if mod(length(d), nrows) == 0
    fprintf('This data matrix appears to be OK, with %3.0f rows (including col. names) x %3.0f cols\n', nrows, numc)
else
    fprintf('This data matrix IS NOT OK\n')
    fprintf('i think it has %3.0f header rows, %3.2f data rows (including col. names) and %3.2f cols\n', nheaderrows, nrows, numc)

    disp('Here are the first 10 rows of the first column: ')
    disp(char(col1{1:10}))

    disp('One potential cause is if you have empty spaces in the last row in your file.')
    disp('then matlab will think it''s reached the end of the file and you will have too few rows.')
    disp('Try entering ''numc'' as an input with the number of columns, or delete the last row.')

    return
end

names = d(1:numc)'; disp(['Last name column read is ' names{end}])

disp(' ')
disp('Your column names:')
fprintf('%s ', names{:});
disp(' ')

% ------------------------------------------------------------------------
% replace illegal characters that will cause Matlab problems
% ------------------------------------------------------------------------

for i = 1:length(names), names{i}(findstr('.',names{i})) = '_'; end
for i = 1:length(names), names{i}(findstr('[',names{i})) = ''; end
for i = 1:length(names), names{i}(findstr(']',names{i})) = ''; end
for i = 1:length(names), names{i}(findstr(':',names{i})) = ''; end
for i = 1:length(names), names{i}(findstr('=',names{i})) = ''; end

% ------------------------------------------------------------------------
% Get data matrix in appropriate format
% ------------------------------------------------------------------------

% This only works if there are no blanks
%dmat = reshape(d, numc, nrows)';

% The code below works with blanks

% dmat(1, :) = [];  % get rid of names

% adjust for header rows
nrows = nrows - 1;

fmtstring = '%s%*[^\n]';

for i = 1:numc
    %mycol = dmat(:, i);

    % read in the nth column, skipping header rows and column names
    mycol = textread(fname, fmtstring, 'delimiter', mydelimiter, 'headerlines', nheaderrows + 1, 'bufsize', 100000);

    fmtstring = ['%*s' fmtstring];  % add this so we skip this col next time

    % Get the first non-empty entry and determine if it's numeric or text
    isvalidnumber(i) = 0;
    for j = 1:length(mycol)
        empt = isempty(mycol{j});

        if ~empt
            isvalidnumber(i) = ~isempty(str2num(mycol{j}));
            break
        end
    end

    if isvalidnumber(i)
        % This column has numbers
        for j = 1:nrows
            try
                mynum = str2num(mycol{j});  % sometimes, with 17:40:12 notation, returns more than 1 number
                if isempty(mynum), mynum = NaN; end

            catch
                disp('We seem to be mixing up text and numbers in columns.  Are your rows and cols correct?')
                disp('Here''s the current column (1st 15 rows)')
                mycol(1:15)

                disp('Here''s the first 10 rows and cols:')
                dmat(1:10, 1:10)

                keyboard
            end

            DATA.(names{i})(j, 1) = mynum(1);
        end
    else
        % This column is text
        DATA.(names{i}) = mycol;
    end

end

end

% %
% %
% %
% % % ------------------------------------------------------------------------
% % % create formatting string with number of columns and output var names
% % % ------------------------------------------------------------------------
% %
% % fmt = repmat('%s',1,numc);
% % fmt = [fmt '%*[^\n]'];
% %
% % outs = ['[' names{1}];
% % for i = 2:numc, outs = [outs ',' names{i}]; end
% % outs = [outs ']'];
% %
% % % works, but requires an extra step
% % %outs = ['[out{1}'];
% % %for i = 2:numc, outs = [outs ',out{' num2str(i) '}'];, end
% % %outs = [outs ']'];
% %
% % % ------------------------------------------------------------------------
% % % read the database again with proper formatting and output names
% % % ------------------------------------------------------------------------
% %
% % if addone
% %     str = [outs ' = textread(''' fname ''',fmt,''headerlines'',3,''delimiter'',''\t'');'];
% % else
% %     str = [outs ' = textread(''' fname ''',fmt,''headerlines'',2,''delimiter'',''\t'');'];
% % end
% %
% % eval(str)
% %
% % warning off
% % ww = whos('*RT*'); ww = ww(end).name; eval(['ww = isempty(str2num(' ww '{1}));'])
% % warning on
% % if ww,
% %     str = [outs ' = textread(''' fname ''',fmt,''headerlines'',3,''delimiter'',''\t'');'];
% %     eval(str)
% % end
% %
% % % not necessary if all filenames are OK
% % %for i = 1:length(outs),
% % %    eval([names{i} ' = out{i};'])
% % %end
% %
% %
% % % ------------------------------------------------------------------------
% % % convert blanks to NaN's, to avoid losing placeholders, and
% % % convert columns with numeric information to numeric vectors
% % % ------------------------------------------------------------------------
% % for i = 1:numc
% %
% %     % The replacing blanks part
% %     eval(['wh = strmatch('' '',str2mat(' names{i} '{:}));'])
% %     eval([names{i} '(wh) = {''NaN''};'])
% %
% %     % the conversion to numbers part
% %     eval(['a = str2num(str2mat(' names{i} '{:}));'])
% %     if isempty(a) | sum(isnan(a)) == length(a)
% %         % leave it alone; it's text
% %     else
% %         eval([names{i} ' = a;']),
% %     end
% % end


function [major, minor, numCommits, sha] = parseVersion(ver)
    if ~isempty(strfind(lower(ver), 'fatal'))
        error('BNT:arg', 'Incorrect argument ''ver'' (type ''help helpers.parseVersion'' for details).');
    end
    hyphenInd = strfind(ver, '-'); % should be two
    if isempty(hyphenInd)
        nums = regexpi(ver, '\d+', 'match'); % check that we have some numbers (should be two of them)
        if isempty(nums)
            error('BNT:arg', 'Incorrect argument ''ver'' (type ''help helpers.parseVersion'' for details).');
        end
        major = str2double(nums{1});
        minor = str2double(nums{2});
        numCommits = '';
        sha = '';
    else
        if length(hyphenInd) ~= 2
            error('BNT:arg', 'Incorrect argument ''ver'' (type ''help helpers.parseVersion'' for details).');
        end
        verId = ver(1:hyphenInd(1)-1);
        numCommits = ver(hyphenInd(1)+1:hyphenInd(2)-1);
        sha = ver(hyphenInd(2)+2:end); % remove 'g' character
        nums = regexp(verId, '\d*', 'match');
        major = str2double(nums{1});
        minor = str2double(nums{2});
    end
end


%kMarker 'Marker Object Menuform'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros Marker.pane file
%
% Parameters:
% Integer: graphicsMarkerScale 'Marker Scale', default: 1: 'marker scale'
%
% Example: kMarker( {'graphicsMarkerScale',1})
%
% Khoros helpfile follows below:
% .begin tagged
%
% .item "The Marker Visual Object"
% A marker visual object supports the display of a marker annotation.
% The (x, y) location of the marker may be specified in device coordinates
% or world coordinates, as determined by the application.  The menuform,
% however, displays the world coordinate location of the marker,
% regardless of whether the application used world or device coordinates to
% specify that location.  Attributes of the marker object that can be
% interactively specified include its type, scale, and color, as well as its
% world coordinate location.
%
% .item "Marker Type"
% The indicator may use a variety of marker types, including Arc, Bow Tie, Box,
% Caret, Circle, Cross, Dagger, Diamond, Dot, Hexagon, Point, Square, Triangle,
% V, and X.
%
% .item "Marker Scale"
% Markers can be scaled so that they are displayed in a larger size.  The scale
% is an integer value;  for a scale of 2, the marker will appear twice its
% normal size, for a scale of 3, the marker will appear three times its normal
% size, and so on.
%
% .item "Marker Color"
% This stringlist selection lets you set the foreground color
% of the marker object, using the color name.
%
% .item "X Placement, Y Placement"
% This pair of double values specifies the (x, y) location of the marker object
% on its parent in world coordinates.  The world coordinate range of the marker
% is specified by the application, and thus varies depending on context.
%
% .end tagged

function varargout = kMarker(varargin)
Inputs={};
if nargin ==0
  arglist={'',''};
elseif nargin ==1
  arglist=varargin{1};
else error('Usage: [out1,..] = kMarker(arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'graphicsMarkerScale', 1};
maxval={100};
minval={1};
istoggle=[0];
was_set=istoggle * 0;
paramtype={'Integer'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=0; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(0);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
callKhoros([w 'Marker" '],Inputs,narglist);


function [solver,diagnostic] = setupBNB(solver,ProblemClass,options,solvers,socp_are_really_qc,F,h,logdetStruct,parametric,evaluation_based,F_vars,exponential_cone,allsolvers)

diagnostic = [];

temp_options = options;
temp_options.solver = options.bnb.solver;
tempProblemClass = ProblemClass;
tempProblemClass.constraint.binary  = 0;
tempProblemClass.constraint.integer = 0;
tempProblemClass.constraint.semicont = 0;
localsolver = selectsolver(temp_options,tempProblemClass,solvers,socp_are_really_qc,allsolvers);
if isempty(localsolver) | strcmpi(localsolver.tag,'bnb')
    if isempty(temp_options.bnb.solver)
        diagnostic.solvertime = 0;
        diagnostic.info = yalmiperror(-2,'YALMIP');
        diagnostic.problem = -2;
    else
        % User has specified a lower-bound solver, but we failed to use
        % this. Could be that it doesn't exist, or that it is not
        % applicable
        for i = 1:length(solvers)
            if strcmpi(solvers(i).tag,temp_options.bnb.solver)
                % Solver exist, hence it is not applicable
                diagnostic.solvertime = 0;
                diagnostic.info = yalmiperror(-4,temp_options.bnb.solver);
                diagnostic.problem = -4;
                return
            end
        end
        % Solver was not found in list of available solvers, hance user
        % has specified a solver which doesn't exist
        diagnostic.solvertime = 0;
        diagnostic.info = yalmiperror(-3,temp_options.bnb.solver);
        diagnostic.problem = -3;
        return
    end
    return
elseif strcmpi(localsolver.tag,'bmibnb')
    [localsolver,diagnostics] = setupBMIBNB(localsolver,tempProblemClass,options,solvers,socp_are_really_qc,F,h,logdetStruct,parametric,evaluation_based,F_vars,[],allsolvers);
end
solver.lower = localsolver;


function [cum_ret, cumprod_ret, daily_ret, daily_portfolio] ...
    = up(fid, data, varargins, opts)
% This file is an entry for the up strategy.
%
% function [cum_ret, cumprod_ret, daily_ret, daily_portfolio] ...
%           = up_start(fid, data, varargins, opts)
% cum_ret: cumulative wealth achived at the end of a period.
% cumprod_ret: cumulative wealth achieved till the end each period.
% daily_ret: daily return achieved by a strategy.
% daily_portfolio: daily portfolios
%
% data: market sequence vectors
% fid: handle for write log file
% varargins: variable parameters
% opts: option parameter for behvaioral control
%
% Example: [cum_ret, cumprod_ret, daily_ret, daily_portfolio] ...
%          = up_start(fid, data, {0}, opts);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This file is part of OLPS: http://OLPS.stevenhoi.org/
% Original authors: Bin LI, Steven C.H. Hoi
% Contributors:
% Change log:
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Extract the parameters
tc = varargins{1};      % transaction cost fee rate

% Run the greedy algorithm
[cum_ret, cumprod_ret, daily_ret, daily_portfolio] ...
    = up_run(fid, data, tc, opts);

end


function [document, scores] = report_ar_rank(context, experiment, trackers, sequences, varargin)
% report_ar_rank Generate a report based on A-R ranking
%
% Performs A-R ranking analysis and generates a report based on the results.
%
% Input:
% - context (structure): Report context structure.
% - experiment (struct): An experiment structure.
% - trackers (cell): An array of tracker structures.
% - sequences (cell): An array of sequence structures.
% - varargin[UsePractical] (boolean): Use practical difference.
% - varargin[UseTags] (boolean): Rank according to tags (otherwise rank according to sequences).
% - varargin[Average] (string): How to compute average rank.
%     - weighted_mean: Average ranks, average values by taking into account length
%     - mean: Average ranks, average values
%     - pooled: gather all frames and compute ranking on a single combined sequence
% - varargin[Alpha] (double): Statistical significance parameter.
% - varargin[Adaptation] (string): Statistical significance parameter.
% - varargin[HideLegend] (boolean): Hide legend in plots.
%
% Output:
% - document (structure): Resulting document structure.
% - scores (struct): Averaged ranks for entire set.
%

usetags = get_global_variable('report_tags', true);
usepractical = get_global_variable('report_ar_practical', true);
orderingplot = get_global_variable('report_ar_ordering', true);
hidelegend = get_global_variable('report_legend_hide', false);
arplot = get_global_variable('report_ar_arplot', true);
average = get_global_variable('report_ar_average', 'weighted_mean');
adaptation = get_global_variable('report_ar_adaptation', 'mean');
sensitivity = get_global_variable('report_ar_sensitivity', 30);
alpha = get_global_variable('report_ar_alpha', 0.05);
table_format = get_global_variable('report_ar_table_format', 'accrob'); % joined, rankscores, accrob, fragmented
table_orientation = get_global_variable('report_ar_table_orientation', 'trackers'); % trackers, selectors, trackerscores, selectorscores

for i = 1:2:length(varargin)
    switch lower(varargin{i})
        case 'usepractical'
            usepractical = varargin{i+1};
        case 'usetags'
            usetags = varargin{i+1};
        case 'average'
            average = varargin{i+1};
        case 'alpha'
            alpha = varargin{i+1};
        case 'adaptation'
            adaptation = varargin{i+1};
        case 'hidelegend'
            hidelegend = varargin{i+1};
        otherwise
            error(['Unknown switch ', varargin{i}, '!']) ;
    end
end

if ~strcmp(experiment.type, 'supervised')
   error('A-R Ranking analysis only suitable for supervised experiments!');
end

if numel(trackers) < 2
    error('Ranking analysis requires two or more trackers.');
end;

if ~any(strcmp(average, {'mean', 'weighted_mean', 'pooled'}))
   error('Unknown averaging technique "%s"!', average);
end
document = document_create(context, 'ar_rank', 'title', 'AR ranking');

trackers_hash = md5hash(strjoin((cellfun(@(x) x.identifier, trackers, 'UniformOutput', false)), '-'), 'Char', 'hex');
parameters_hash = md5hash(sprintf('%f-%d-%d-%s', alpha, usetags, usepractical, adaptation));

tags = {};

if usetags && isfield(experiment, 'tags')
    tags = union(experiment.tags, {'all'});
    sequences_hash = md5hash(strjoin(tags, '-'), 'Char', 'hex');
else
    sequences_hash = md5hash(strjoin((cellfun(@(x) x.name, sequences, 'UniformOutput', false)), '-'), 'Char', 'hex');
end;

cache_identifier = sprintf('ranking_%s_%s_%s_%s', experiment.name, trackers_hash, sequences_hash, parameters_hash);

result = document_cache(context, cache_identifier, @analyze_accuracy_robustness, experiment, trackers, ...
    sequences, 'tags', tags, 'usepractical', usepractical, ...
    'alpha', alpha, 'adaptation', adaptation);

if usetags
    % When using tags we have inserted a separate one for this
    mask = strcmp('tag_all', result.tags);

    result.accuracy.pooled_values = result.accuracy.values(mask, :);
    result.robustness.pooled_values = result.robustness.values(mask, :);
    result.robustness.pooled_normalized = result.robustness.normalized(mask, :);
    result.accuracy.pooled_ranks = result.accuracy.ranks(mask, :);
    result.robustness.pooled_ranks = result.robustness.ranks(mask, :);

    % Now remove the 'all' tag from results
    result.accuracy.values = result.accuracy.values(~mask, :);
    result.accuracy.ranks = result.accuracy.ranks(~mask, :);
    result.robustness.values = result.robustness.values(~mask, :);
    result.robustness.normalized = result.robustness.normalized(~mask, :);
    result.robustness.ranks = result.robustness.ranks(~mask, :);
    result.lengths = result.lengths(~mask);
    result.tags = result.tags(~mask);

end

result.accuracy.weighted_mean_ranks = nanmean(result.accuracy.ranks, 1);
result.robustness.weighted_mean_ranks = nanmean(result.robustness.ranks, 1);

useable = result.lengths > 0;
result.accuracy.weighted_mean_values = sum(result.accuracy.values(useable, :) ...
    .* repmat(result.lengths(useable), 1, length(trackers)), 1) ./ sum(result.lengths(useable));
result.robustness.weighted_mean_values = sum(result.robustness.values(useable, :) ...
    .* repmat(result.lengths(useable), 1, length(trackers)), 1) ./ sum(result.lengths(useable));
result.robustness.weighted_mean_normalized = sum(result.robustness.normalized(useable, :) ...
    .* repmat(result.lengths(useable), 1, length(trackers)), 1) ./ sum(result.lengths(useable));

result.accuracy.mean_ranks = nanmean(result.accuracy.ranks, 1);
result.robustness.mean_ranks = nanmean(result.robustness.ranks, 1);

result.accuracy.mean_values = nanmean(result.accuracy.values, 1);
result.robustness.mean_values = nanmean(result.robustness.values, 1);
result.robustness.mean_normalized = nanmean(result.robustness.normalized, 1);

switch average

    case 'weighted_mean'

        values = cat(2, result.accuracy.weighted_mean_ranks', ...
            result.robustness.weighted_mean_ranks', ...
            result.accuracy.weighted_mean_values', ...
            result.robustness.weighted_mean_values');

    case 'mean'

        values = cat(2, result.accuracy.mean_ranks', ...
            result.robustness.mean_ranks', ...
            result.accuracy.mean_values', ...
            result.robustness.mean_values');

    case 'pool'

        if usetags
            values = cat(2, result.accuracy.pooled_ranks', ...
                result.robustness.pooled_ranks', ...
                result.accuracy.pooled_values', ...
                result.robustness.pooled_values');
        else
            values = cat(2, result.accuracy.weighted_mean_ranks', ...
                result.robustness.weighted_mean_ranks', ...
                result.accuracy.weighted_mean_values', ...
                result.robustness.weighted_mean_values');
        end
end

scores.name = 'A-R rank';
scores.values = values;
scores.ids = {'arank', 'rrank', 'overlap', 'failures'};
scores.names = {'A-Rank', 'R-Rank', 'Overlap', 'Failures'};
scores.order = {'ascending', 'ascending', 'descending', 'ascending'};

tracker_labels = cellfun(@(x) iff(isfield(x.metadata, 'verified') && x.metadata.verified, [x.label, '*'], x.label), trackers, 'UniformOutput', 0);

print_text('Writing ranking table ...');

document.section('Experiment %s', experiment.name);

if arplot

    ar_and_rank_plot(document, sprintf('%s_mean', experiment.name), ...
        sprintf('experiment %s (mean)', experiment.name), ...
        trackers, result.accuracy.mean_ranks, ...
        result.robustness.mean_ranks, ...
        result.accuracy.mean_values, ...
        result.robustness.mean_normalized, sensitivity, hidelegend);

    ar_and_rank_plot(document, sprintf('%s_weighted_mean', experiment.name), ...
        sprintf('experiment %s (weighted_mean)', experiment.name), ...
        trackers, result.accuracy.weighted_mean_ranks, ...
        result.robustness.weighted_mean_ranks, ...
        result.accuracy.weighted_mean_values, ...
        result.robustness.weighted_mean_normalized, sensitivity, hidelegend);

    if usetags

        ar_and_rank_plot(document, sprintf('%s_pooled', experiment.name), ...
        sprintf('experiment %s (pooled)', experiment.name), ...
        trackers, result.accuracy.pooled_ranks, ...
        result.robustness.pooled_ranks, ...
        result.accuracy.pooled_values, ...
        result.robustness.pooled_normalized, sensitivity, hidelegend);

    end

end;

selector_tags = result.tags;

score_tags = {'A-Rank', 'R-Rank', 'Overlap', 'Failures'};
score_sorting = {'ascending', 'ascending', 'descending', 'ascending'};
raw_scores = cat(3, result.accuracy.ranks', ...
    result.robustness.ranks', ...
    result.accuracy.values', ...
    result.robustness.values');
raw_scores = cat(2, raw_scores, cat(3, result.accuracy.mean_ranks', ...
    result.robustness.mean_ranks', ...
    result.accuracy.mean_values', ...
    result.robustness.mean_values'));
raw_scores = cat(2, raw_scores, cat(3, result.accuracy.weighted_mean_ranks', ...
    result.robustness.weighted_mean_ranks', ...
    result.accuracy.weighted_mean_values', ...
    result.robustness.weighted_mean_values'));

table_selector_tags = selector_tags;
table_selector_tags{end+1} = create_table_cell('Mean', 'class', 'average');
table_selector_tags{end+1} = create_table_cell('Weighted mean', 'class', 'average');

if usetags
    raw_scores = cat(2, raw_scores, cat(3, result.accuracy.pooled_ranks', ...
        result.robustness.pooled_ranks', ...
        result.accuracy.pooled_values', ...
        result.robustness.pooled_values'));
    table_selector_tags{end+1} = create_table_cell('Pooled', 'class', 'average');
end

switch table_format
    case 'joined'
        print_scores_table(document, raw_scores, score_sorting, score_tags, tracker_labels, table_selector_tags, table_orientation, 'Ranks and raw scores');
    case 'rankscores'
        print_scores_table(document, raw_scores(:, :, 1:2), score_sorting(1:2), score_tags(1:2), tracker_labels, table_selector_tags, table_orientation, 'Ranks');
        print_scores_table(document, raw_scores(:, :, 3:4), score_sorting(3:4), score_tags(3:4), tracker_labels, table_selector_tags, table_orientation, 'Raw scores');
    case 'accrob'
        print_scores_table(document, raw_scores(:, :, [1,3]), score_sorting([1,3]), score_tags([1,3]), tracker_labels, table_selector_tags, table_orientation, 'Accuracy');
        print_scores_table(document, raw_scores(:, :, [2,4]), score_sorting([2,4]), score_tags([2,4]), tracker_labels, table_selector_tags, table_orientation, 'Robustness');
    case 'fragmented'
        for t = 1:numel(score_tags)
            print_scores_table(document, raw_scores(:, :, t), score_sorting(t), score_tags(t), tracker_labels, table_selector_tags, table_orientation, score_tags{t});
        end;
end

document.subsection('Detailed plots');

if orderingplot

    h = plot_ordering(trackers, result.accuracy.ranks, selector_tags, ...
        'flip', 1, 'legend', ~hidelegend);
    document.figure(h, sprintf('ordering_accuracy_%s', experiment.name), ...
        'Ranking orderings for accuracy rank');

    close(h);

    h = plot_ordering(trackers, result.accuracy.values, selector_tags, ...
        'scope', [0, 1], 'type', 'Overall overlap', 'legend', ~hidelegend);
    document.figure(h, sprintf('ordering_overlap_%s', experiment.name), ...
        'Orderings for overall overlap');

    close(h);

    h = plot_ordering(trackers, result.robustness.ranks, selector_tags, ...
        'flip', 1, 'legend', ~hidelegend);
    document.figure(h, sprintf('ordering_robustness_%s', experiment.name), ...
        'Ranking orderings for robustness rank');

    close(h);

    robustness = result.robustness.normalized .* sensitivity;

    h = plot_ordering(trackers, robustness, selector_tags, ...
        'scope', [0, max(robustness(:))+eps], 'type', ...
        'Failures', 'legend', ~hidelegend);

    document.figure(h, sprintf('ordering_failures_%s', experiment.name), ...
        'Orderings for failures');

    close(h);

end;

if arplot

    for l = 1:length(selector_tags)

        plot_title = sprintf('Ranking plot for tag %s in experiment %s', ...
            selector_tags{l}, experiment.name);
        plot_id = sprintf('rankingplot_%s_%s', ...
            experiment.name, selector_tags{l});

        hf = plot_ranking(trackers, result.accuracy.ranks(l, :)', ...
            result.robustness.ranks(l, :)', ...
            'title', plot_title, 'limit', numel(trackers), 'legend', ~hidelegend);

        document.figure(hf, plot_id, plot_title);

        close(hf);

        plot_title = sprintf('AR plot for tag %s in experiment %s', ...
            selector_tags{l}, experiment.name);
        plot_id = sprintf('arplot_%s_%s', experiment.name, selector_tags{l});

        hf = plot_ar(trackers, result.accuracy.values(l, :), ...
            result.robustness.normalized(l, :), ...
            'title', plot_title, 'sensitivity', sensitivity, 'legend', ~hidelegend);

        document.figure(hf, plot_id, plot_title);

        close(hf);

    end;

end;

document.write();

end

% --------------------------------------------------------------------- %

function print_scores_table(document, scores, score_sorting, score_tags, tracker_labels, selector_tags, orientation, title)

    % Scores - selectors x trackers x scores

    score_count = numel(score_tags);
    selector_count = numel(selector_tags);
    tracker_count = numel(tracker_labels);

    switch orientation
        case 'trackers'
            row_tags = tracker_labels;
            column_labels = selector_tags;
            row_scores = false;
            sort_columns = false;
        case 'selectors'
            row_tags = selector_tags;
            column_labels = tracker_labels;
            row_scores = false;
            sort_columns = true;
        case 'trackerscores'
            row_tags = tracker_labels;
            column_labels = selector_tags;
            row_scores = true;
            sort_columns = true;
        case 'selectorscores'
            row_tags = selector_tags;
            column_labels = tracker_labels;
            row_scores = true;
            sort_columns = false;
        otherwise
            error('Unknown format %s', orientation);
    end

    column_labels = column_labels(:)';
    row_tags = row_tags(:);

    row_count = numel(row_tags);
    column_count = numel(column_labels);

    if sort_columns
        table_data = cell(tracker_count * score_count, selector_count);

        for s = 1:score_count
            score_table_data = highlight_best_rows(num2cell(scores(:, :, s)), ...
                repmat(score_sorting(s), 1, numel(selector_tags)));
            table_data(s:score_count:end, :) = score_table_data;
        end

        if ~row_scores
            table_data = table_data';
        end
    else
        table_data = cell(tracker_count, selector_count * score_count);

        for s = 1:score_count
            score_table_data = highlight_best_rows(num2cell(scores(:, :, s)), ...
                repmat(score_sorting(s), 1, numel(selector_tags)));
            table_data(:, s:score_count:end) = score_table_data;
        end

        if row_scores
            table_data = table_data';
        end
    end

    if row_scores

        if score_count > 1
            row_tags_exp = cell(score_count * row_count, 2);
            row_tags_exp(:, 1) = repmat({struct()}, 1, row_count * score_count);
            row_tags_exp(1:score_count:end, 1) = cellfun(@(x) create_table_cell(x, 'rows', score_count), row_tags, 'UniformOutput', false);
            row_tags_exp(:, 2) = score_tags(repmat(1:score_count, 1, row_count));
            row_tags = row_tags_exp;
        end

    else

        if score_count > 1
            column_labels_exp = cell(2, score_count * column_count);
            column_labels_exp(1, :) = repmat({struct()}, 1, column_count * score_count);
            column_labels_exp(1, 1:score_count:end) = cellfun(@(x) create_table_cell(x, 'columns', score_count), column_labels, 'UniformOutput', false);
            column_labels_exp(2, :) = score_tags(repmat(1:score_count, 1, column_count));
            column_labels = column_labels_exp;
        end

    end;

    document.table(table_data, 'columnLabels', column_labels, 'rowLabels', row_tags, 'title', title);

end

function ar_and_rank_plot(document, identifier, title, trackers, ...
    accuracy_ranks, robustness_ranks, accuracy_values, ...
    robustness_values, sensitivity, hidelegend)

    plot_title = sprintf('Ranking plot for %s', title);
    plot_id = sprintf('rankingplot_%s', identifier);

    hf = plot_ranking(trackers, accuracy_ranks, ...
        robustness_ranks, ...
        'title', plot_title, 'limit', numel(trackers), 'legend', ~hidelegend);

    document.figure(hf, plot_id, plot_title);

    close(hf);

    plot_title = sprintf('AR plot for %s', title);
    plot_id = sprintf('arplot_%s', identifier);

    hf = plot_ar(trackers, accuracy_values, ...
        robustness_values, ...
        'title', plot_title, 'sensitivity', sensitivity, 'legend', ~hidelegend);

    document.figure(hf, plot_id, plot_title);

    close(hf);

end


classdef nme_load_acc_nln < mp.nme_load_acc & mp.nme_wrapper_ac_nln

%   MATPOWER
%   Copyright (c) 2019-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

    properties
        nme_class = @mp.nme_load_acc;
    end

    methods
        function obj = nme_load_acc_nln()
            obj@mp.nme_load_acc();
            obj.nme_wrapper_ac_nln_init();
        end

        function build_params(obj, nm, dm)
            build_params@mp.nme_load_acc(obj, nm, dm);
            obj.build_nln_params(nm, dm);
        end

        function nk = count(obj, dm)
            obj.nme.count(dm);
            nk = count@mp.nme_load_acc(obj, dm);
        end
    end     %% methods
end         %% classdef


%  FILE:   cnn_widerface.m
%
%    This function serves as the main function for evaluating a model. It loads
%    detection and ground truth and evaluates at all three difficulty levels at
%    once.
%
%    Note that this evaluation script consistently produces slightly lower
%    numbers (mAPs) comparing to the official evaluation script. I implement my
%    own version because it runs faster and it is more customizable, in terms of
%    adding visualization etc.
%
%  INPUT:  configuration (see code for details)
%
%  OUTPUT: none

function cnn_widerface_eval(varargin)

%
opts.noUpsampling = false;
opts.noOrgres = false;
opts.noDownsampling = false;
opts.testMultires = false;
opts.testTag = '';
opts.inputSize = [500, 500];
[opts, varargin] = vl_argparse(opts, varargin);

%
opts.evalWithReg = true;
opts.tag = '';
opts.bboxReg = true;
opts.skipLRMult = [1, 0.001, 0.0001, 0.00001];
opts.penalizeDuplicate = true;
opts.nmsThresh = 0.3;
opts.probThresh = 0.8;
opts.draw = false;
opts.minOverlap = [0.3:0.2:0.7];
opts.testEpoch = 0;
opts.testIter = 0;
opts.testSet = 'val';
opts.resDir = 'results/';
opts.testName = '';
opts.clusterNum = 25;
opts.clusterName = '';
opts.sampleSize = 256;
opts.posFraction = 0.5;
opts.posThresh = 0.7;
opts.negThresh = 0.3;
opts.pretrainModelPath = 'matconvnet/pascal-fcn8s-tvg-dag.mat';
opts.dataDir = fullfile('data','widerface') ;
opts.modelType = 'pascal-fcn8s-tvg-dag' ;
opts.networkType = 'dagnn' ;
opts.batchNormalization = true ;
opts.weightInitMethod = 'gaussian' ;
[opts, varargin] = vl_argparse(opts, varargin) ;

%
opts.minClusterSize = [2, 2];
opts.maxClusterSize = opts.inputSize;
[opts, varargin] = vl_argparse(opts, varargin) ;

%
sfx = opts.modelType ;
sfx = [sfx '-' 'sample' num2str(opts.sampleSize)] ;
sfx = [sfx '-' 'posfrac' num2str(opts.posFraction)] ;
sfx = [sfx '-' 'N' num2str(opts.clusterNum)];

if opts.bboxReg, sfx = [sfx '-' 'bboxreg']; end

if any(opts.inputSize~=500),
    sz = opts.inputSize;
    sfx = [sfx '-input' num2str(sz(1)) 'x' num2str(sz(2))];
end
if ~isempty(opts.clusterName)
    sfx = [sfx '-' 'cluster-' opts.clusterName];
end

%
opts.expDir = fullfile('models', ['widerface-' sfx]);
if ~isempty(opts.tag)
    opts.expDir = [opts.expDir '-' opts.tag];
end
[opts, varargin] = vl_argparse(opts, varargin) ;

% imdb
opts.imdbPath = fullfile(opts.dataDir, 'imdb.mat');
[opts, varargin] = vl_argparse(opts, varargin) ;

%

if exist(opts.imdbPath)
    imdb = load(opts.imdbPath) ;
else
    imdb = cnn_setup_imdb('dataDir', opts.dataDir);
    if ~exist(opts.expDir), mkdir(opts.expDir) ; end
    save(opts.imdbPath, '-struct', 'imdb') ;
end

%
if opts.testEpoch == 0
    testEpoch = findLastCheckpoint(opts.expDir);
    if testEpoch==0
        error('No available model for evaluation.');
    end
else
    testEpoch = opts.testEpoch;
end
testSet = opts.testSet;

if isempty(opts.testName)
    testName = strrep(opts.expDir, 'models/', '');
    testName = sprintf('%s-epoch%d-%s', testName, testEpoch, testSet);
    testName = [testName '-probthresh' num2str(opts.probThresh)];
    testName = [testName '-nmsthresh' num2str(opts.nmsThresh)];
    if opts.testMultires, testName = [testName '-multires']; end
    if opts.noOrgres, testName = [testName '-noorgres']; end
    if opts.noUpsampling, testName = [testName '-noupsampling']; end
    if opts.noDownsampling, testName = [testName '-nodownsampling']; end
    if opts.evalWithReg, testName = [testName '-evalWithReg']; end
else
    testName = opts.testName;
end

if ~isempty(opts.testTag),
    testName = [testName '-' opts.testTag];
end

if strcmp(opts.resDir, 'results/')
    resDir = fullfile(opts.resDir, testName);
    if numel(resDir) > 255, resDir = strrep(resDir, '-nmsthresh0.3', ''); end
    if numel(resDir) > 255, resDir = strrep(resDir, 'widerface-resnet-50-',''); end
    if numel(resDir) > 255, resDir = strrep(resDir, 'bboxreg-logistic-cluster-',''); end
else
    resDir = opts.resDir;
end

% load ground truth info
%fprintf('Loading ground truth annotation for %s.\n', opts.testSet);
switch opts.testSet
  case 'val'
    test = find(imdb.images.set == 2);
  case 'test'
    error('Evaluting on test set - you must be kidding me...\n')
end

hard_info = load('eval_tools/ground_truth/wider_hard_val.mat');
med_info = load('eval_tools/ground_truth/wider_medium_val.mat');
easy_info = load('eval_tools/ground_truth/wider_easy_val.mat');

% thresholds
minOverlap = opts.minOverlap;
nt = numel(opts.minOverlap);

%
img_idx_map = containers.Map();
for i = 1:numel(hard_info.file_list)
    for j = 1:numel(hard_info.file_list{i})
        img_idx_map(hard_info.file_list{i}{j}) = j;
    end
end

% number of files
easy_npos = 0 ;
med_npos = 0 ;
hard_npos = 0 ;

gt(numel(test)) = struct('BB', [], 'det', []);
easy_gt(numel(test)) = struct('BB', [], 'det', []);
med_gt(numel(test)) = struct('BB', [], 'det', []);
hard_gt(numel(test)) = struct('BB', [], 'det', []);
for i = 1:numel(test)
    eventId = imdb.labels.eventid(test(i));

    gtrects = imdb.labels.rects{test(i)};
    gt(i).BB = gtrects';
    easy_gt(i).det = false(size(gtrects,1), nt);
    med_gt(i).det = false(size(gtrects,1), nt);
    hard_gt(i).det = false(size(gtrects,1), nt);

    gt_h = gtrects(:,4)-gtrects(:,2)+1;
    gt_w = gtrects(:,3)-gtrects(:,1)+1;

    % NOTE: using released evaluation tools
    img_size = imdb.images.size(test(i),:);
    [~, img_name, ~] = fileparts(imdb.images.name{test(i)});
    img_idx = img_idx_map(img_name);

    easy_gt(i).ign = ones(size(gtrects, 1), 1);
    med_gt(i).ign = ones(size(gtrects, 1), 1);
    hard_gt(i).ign = ones(size(gtrects, 1), 1);

    % easy_gt(i).ign(easy_info.ignore_list{eventId}{img_idx}) = 0;
    % med_gt(i).ign(med_info.ignore_list{eventId}{img_idx}) = 0;
    % hard_gt(i).ign(hard_info.ignore_list{eventId}{img_idx}) = 0;
    easy_gt(i).ign(easy_info.gt_list{eventId}{img_idx}) = 0;
    med_gt(i).ign(med_info.gt_list{eventId}{img_idx}) = 0;
    hard_gt(i).ign(hard_info.gt_list{eventId}{img_idx}) = 0;

    easy_npos = easy_npos + sum(easy_gt(i).ign == 0);
    med_npos = med_npos + sum(med_gt(i).ign == 0);
    hard_npos = hard_npos + sum(hard_gt(i).ign == 0);
end

% collect all predictions
detrespath = fullfile(resDir, sprintf('detections.txt'));
if ~exist(detrespath) || 1
    fout = fopen(detrespath, 'w');
    for i = 1:numel(test)
        eventId = imdb.labels.eventid(test(i));

        event = imdb.events.name{eventId};
        [~,imname,~] = fileparts(imdb.images.name{test(i)});
        resfile = fullfile(resDir, event, [imname '.txt']);
        if ~exist(resfile), continue; end
        o = fopen(resfile);
        C = textscan(o,'%d %d %d %d %f','HeaderLines', 2);
        % if this is an older result
        if any(cellfun(@(x)(any(isnan(x))), C))
            fclose(o);
            o = fopen(resfile);
            C = textscan(o,'%d %d %d %d %d %f','HeaderLines', 2);
        end
        x1 = C{1}; y1 = C{2}; w = C{3}; h = C{4};
        x2 = x1 + (w-1); y2 = y1 + (h-1);
        confidence = C{end};

        fclose(o);
        for j = 1:numel(confidence)
            fprintf(fout, '%d %f %d %d %d %d\n',i,confidence(j), ...
                    x1(j),y1(j),x2(j),y2(j));
        end
    end
    fclose(fout);
end

%
[ids,confidence,b1,b2,b3,b4] = textread(detrespath, '%d %f %d %d %d %d');
BB = [b1 b2 b3 b4]';

%
bh = b4 - b2 + 1;
bw = b3 - b1 + 1;

% sort detections by decreasing confidence
[sc,si]=sort(-confidence);
ids=ids(si);
BB=BB(:,si);
%tids = tids(si);

% assign detections to ground truth objects
nd=length(confidence);

easy_tp=zeros(nd,nt);
easy_fp=zeros(nd,nt);
med_tp=zeros(nd,nt);
med_fp=zeros(nd,nt);
hard_tp=zeros(nd,nt);
hard_fp=zeros(nd,nt);

ovmaxs=zeros(nd,1);
tic;
for d=1:nd
    % display progress
    if toc>1
        %fprintf('face: pr: compute: %d/%d\n',d,nd);
        drawnow;
        tic;
   end

    % find ground truth image
    i=ids(d);

    % assign detection to ground truth object if any
    bb=BB(:,d);
    ovmax=-inf;
    jmax = 0 ;

    for j=1:size(gt(i).BB,2)
        bbgt=gt(i).BB(:,j);
        bi=[max(bb(1),bbgt(1)) ; max(bb(2),bbgt(2)) ; min(bb(3),bbgt(3)) ; min(bb(4),bbgt(4))];
        iw=bi(3)-bi(1)+1;
        ih=bi(4)-bi(2)+1;
        if iw>0 & ih>0
            % compute overlap as area of intersection / area of union
            ua=(bb(3)-bb(1)+1)*(bb(4)-bb(2)+1)+...
               (bbgt(3)-bbgt(1)+1)*(bbgt(4)-bbgt(2)+1)-...
               iw*ih;
            ov=iw*ih/ua;
            if ov>ovmax
                ovmax=ov;
                jmax=j;
            end
        end
    end

    % assign detection as true positive/don't care/false positive
    for k=1:nt
        if ovmax>=opts.minOverlap(k)
            %if ~easy_gt(i).ign(j)
            if ~easy_gt(i).ign(jmax)
                if ~easy_gt(i).det(jmax,k) || ~opts.penalizeDuplicate
                    easy_tp(d,k)=1;            % true positive
                    easy_gt(i).det(jmax,k)=true;
                else
                    easy_fp(d,k)=1;            % false positive (multiple detection)
                end
            end
            %if ~med_gt(i).ign(j)
            if ~med_gt(i).ign(jmax)
                if ~med_gt(i).det(jmax,k) || ~opts.penalizeDuplicate
                    med_tp(d,k)=1;            % true positive
                    med_gt(i).det(jmax,k)=true;
                else
                    med_fp(d,k)=1;            % false positive (multiple detection)
                end
            end
            %if ~hard_gt(i).ign(j)
            if ~hard_gt(i).ign(jmax)
                if ~hard_gt(i).det(jmax,k) || ~opts.penalizeDuplicate
                    hard_tp(d,k)=1;            % true positive
                    hard_gt(i).det(jmax,k)=true;
                else
                    hard_fp(d,k)=1;            % false positive (multiple detection)
                end
            end
        else
            easy_fp(d,k)=1;                    % false positive
            med_fp(d,k)=1;                    % false positive
            hard_fp(d,k)=1;                    % false positive
        end
    end
    ovmaxs(d)=ovmax;
end

% compute precision/recall
easy_fp_ = easy_fp;
easy_tp_ = easy_tp;

easy_fp=cumsum(easy_fp,1);
easy_tp=cumsum(easy_tp,1);
easy_rec=easy_tp/easy_npos;
easy_prec=easy_tp./(easy_fp+easy_tp);

easy_aps = zeros(1, nt);
for k = 1:nt
    easy_aps(k)=VOCap(easy_rec(:,k),easy_prec(:,k));
    fprintf('class: face, epoch: %d, subset: %s (easy), minOverlap=%.2f, AP = %.3f\n', ...
            testEpoch, testSet, opts.minOverlap(k), easy_aps(k))
end

med_fp_ = med_fp;
med_tp_ = med_tp;

med_fp=cumsum(med_fp,1);
med_tp=cumsum(med_tp,1);
med_rec=med_tp/med_npos;
med_prec=med_tp./(med_fp+med_tp);

med_aps = zeros(1, nt);
for k = 1:nt
    med_aps(k)=VOCap(med_rec(:,k),med_prec(:,k));
    fprintf('class: face, epoch: %d, subset: %s (medium), minOverlap=%.2f, AP = %.3f\n', ...
            testEpoch, testSet, opts.minOverlap(k), med_aps(k))
end

hard_fp_ = hard_fp;
hard_tp_ = hard_tp;

hard_fp=cumsum(hard_fp,1);
hard_tp=cumsum(hard_tp,1);
hard_rec=hard_tp/hard_npos;
hard_prec=hard_tp./(hard_fp+hard_tp);

hard_aps = zeros(1, nt);
for k = 1:nt
    hard_aps(k)=VOCap(hard_rec(:,k),hard_prec(:,k));
    fprintf('class: face, epoch: %d, subset: %s (hard), minOverlap=%.2f, AP = %.3f\n', ...
            testEpoch, testSet, opts.minOverlap(k), hard_aps(k))
end

if opts.draw
    close all;
    for i = 1:3
        switch i
          case 1
            rec = easy_rec;
            prec = easy_prec;
            aps = easy_aps;
            diffLevel = 'easy';
          case 2
            rec = med_rec;
            prec = med_prec;
            aps = med_aps;
            diffLevel = 'medium';
          case 3
            rec = hard_rec;
            prec = hard_prec;
            aps = hard_aps;
            diffLevel = 'hard';
        end

        figure(i);
        %% plot our precision/recall
        hold on;
        for k = 1:nt
            plot(rec(:,k),prec(:,k),'-','linewidth',3);
            [~,ii] = max(rec(:,k).*prec(:,k));
        end

        hold off;
        grid;
        xlabel 'recall'
        ylabel 'precision'
        %title(sprintf('class: face, subset: %s, AP = %.3f',testSet,ap));
        title(sprintf('class face, epoch %d, subset %s(%s), AP(0.5) %.3f', ...
                      testEpoch, testSet, diffLevel, aps(opts.minOverlap==0.5)));
        xlim([0,1]);
        ylim([0,1]);
        print('-dpng', fullfile(resDir, ['wider_' diffLevel '.png']));
    end
end

% -------------------------------------------------------------------------
function [epoch, iter] = findLastCheckpoint(modelDir)
% -------------------------------------------------------------------------
list = dir(fullfile(modelDir, 'net-epoch-*.mat')) ;

epoch = 0;

tokens = regexp({list.name}, 'net-epoch-([\d]+).mat', 'tokens') ;
% find latest epoch
for i = 1:numel(tokens)
  token = tokens{i}{1};
  ep = str2num(token{1});
  if ep >= epoch
    epoch = ep;
  end
end


classdef xt_reserves < mp.extension

%   MATPOWER
%   Copyright (c) 2022, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

%     properties
%     end     %% properties

    methods
        function dmc_elements = dmc_element_classes(obj, dmc_class, fmt, mpopt)
            switch fmt
                case 'mpc2'
                    dmc_elements = { @mp.dmce_reserve_gen_mpc2, ...
                                     @mp.dmce_reserve_zone_mpc2 };
                otherwise
                    dmc_elements = {};      %% no modifications
            end
        end

        function dm_elements = dm_element_classes(obj, dm_class, task_tag, mpopt)
            switch task_tag
                case 'OPF'
                    dm_elements = { @mp.dme_reserve_gen, ...
                                    @mp.dme_reserve_zone };
                otherwise
                    dm_elements = {};       %% no modifications
            end
        end

        function mm_elements = mm_element_classes(obj, mm_class, task_tag, mpopt)
            switch task_tag
                case {'OPF'}
                    mm_elements = { @mp.mme_reserve_gen, ...
                                    @mp.mme_reserve_zone };
                otherwise
                    mm_elements = {};       %% no modifications
            end
        end
    end     %% methods
end         %% classdef


function newParameters = load(filepath)
% load   Load GPT-2
%
%   parameters = load(filepath) will load a GPT-2 model from the directory
%   specified by filepath.

% Load the parameters
s = load(filepath);

% First, assign the hyperparameters and then remove them from the loaded
% structure.
newParameters = struct;
newParameters.Hyperparameters = s.hyperparameters;
s = rmfield(s, 'hyperparameters');

% Next, assign the weights
newParameters.Weights = struct;

originalWeightNames = fieldnames(s);
newWeightNames = erase(originalWeightNames, 'model_');

% Permute all of the weights to match the MATLAB format
for i = 1:numel(originalWeightNames)
    if startsWith(newWeightNames{i},'h')
        nameSplit = split(newWeightNames{i}, '_');
        newParameters.Weights.(char(nameSplit(1))).(char(join(nameSplit(2:end),'_'))) = ...
            s.(originalWeightNames{i});
    else
        newParameters.Weights.(char(newWeightNames{i})) = s.(originalWeightNames{i});
    end
end

newParameters.Weights = iStructRecurseFun(@dlarray, newParameters.Weights);

end

function s = iStructRecurseFun(F, s, varargin)
if ~isstruct(s)
    s = F(s, varargin{:});
else
    fn = fieldnames(s);
    for i = 1:numel(fn)
        others = cellfun(@(o)o.(fn{i}), varargin, 'UniformOutput', false);
        s.(fn{i}) = iStructRecurseFun(F, s.(fn{i}), others{:});
    end
end
end