function varargout = McCabeThieleGUI(varargin)
% MCCABETHIELEGUI M-file for McCabeThieleGUI.fig
%      MCCABETHIELEGUI, by itself, creates a new MCCABETHIELEGUI or raises the existing
%      singleton*.
%
%      H = MCCABETHIELEGUI returns the handle to a new MCCABETHIELEGUI or the handle to
%      the existing singleton*.
%
%      MCCABETHIELEGUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in MCCABETHIELEGUI.M with the given input arguments.
%
%      MCCABETHIELEGUI('Property','Value',...) creates a new MCCABETHIELEGUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before McCabeThieleGUI_OpeningFunction gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to McCabeThieleGUI_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Last Modified by GUIDE v2.5 06-Jul-2010 12:55:42

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @McCabeThieleGUI_OpeningFcn, ...
                   'gui_OutputFcn',  @McCabeThieleGUI_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before McCabeThieleGUI is made visible.
function McCabeThieleGUI_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to McCabeThieleGUI (see VARARGIN)

set(handles.mixturepanel_buttongroup,'SelectionChangeFcn',@mixturepanel_buttongroup_SelectionChangeFcn);

% Choose default command line output for McCabeThieleGUI
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes McCabeThieleGUI wait for user response (see UIRESUME)
% uiwait(handles.figure1);

% --- Outputs from this function are returned to the command line.
function varargout = McCabeThieleGUI_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;
%% Mixture Panel

function mixturepanel_buttongroup_SelectionChangeFcn(hObject, eventdata)

handles = guidata(hObject);

switch get(eventdata.NewValue,'Tag')   % Get Tag of selected object
    case 'methanolwater_radiobutton'
        %equilibrium data
        xMW = '[0    0.0200    0.0400    0.0600    0.0800    0.1000    0.1500    0.2000    0.3000    0.4000    0.5000    0.6000    0.7000    0.8000    0.9000    0.9500    1.0000]';
        yMW = '[0    0.1340    0.2300    0.3040    0.3650    0.4180    0.5170    0.5790    0.6650    0.7290    0.7790    0.8250    0.8700    0.9150    0.9580    0.9790    1.0000]';
        set(handles.userdefined_input,'Enable','Off')
        set(handles.userdefined_input2,'Enable','Off')
        set(handles.userdefined_input,'String',xMW)
        set(handles.userdefined_input2,'String',yMW)
        %hold off
        %methanol-water mixture
        %polynomial regression and plot of equilibrium data
        %p = polyfit(xMW,yMW,6);
        %x = 0:.1:100;
        %y = polyval(p,x);
        %plot(xMW,yMW)
        %hold on
        %axis([0 1 0 1])
        %plot(x,y)
        %plot(x,x)
        %xlabel('Liquid Mole Fraction of Methanol')
        %ylabel('Vapor Mole Fraction of Methanol')
        %title('McCabe-Thiele Diagram for Methanol-Water')

    case 'ethanolwater_radiobutton'
        %equilibrium data
        xEW = '[0    0.0190    0.0721    0.0966    0.1238    0.1661    0.2337    0.2608    0.3273    0.3965    0.5198    0.5732    0.6763    0.7472    0.8943    1.0000]';
        yEW = '[0    0.1700    0.3891    0.4375    0.4704    0.5089    0.5445    0.5580    0.5826    0.6122    0.6599    0.6841    0.7385    0.7815    0.8943    1.0000]';
        xeq = num2str(xEW);
        yeq = num2str(yEW);
        set(handles.userdefined_input,'Enable','Off')
        set(handles.userdefined_input2,'Enable','Off')
        set(handles.userdefined_input,'String',xeq)
        set(handles.userdefined_input2,'String',yeq)
        %hold off
        %ethanol-water mixture
        %polynomial regression and plot of equilibrium data
        %p = polyfit(xEW,yEW,8);
        %x = 0:.1:100;
        %y = polyval(p,x);
        %plot(x,y)
        %plot(xEW,yEW)
        %hold on
        %axis([0 1 0 1])
        %plot(x,x)
        %xlabel('Liquid Mole Fraction of Ethanol')
        %ylabel('Vapor Mole Fraction of Ethanol')
        %title('McCabe-Thiele Diagram for Ethanol-Water')

    case 'acetonethanol_radiobutton'
        %equilibrium data
        xAE = '[0    0.1000    0.1500    0.2000    0.2500    0.3000    0.3500    0.4000    0.5000    0.6000    0.7000    0.8000    0.9000    1.0000]';
        yAE = '[0    0.2620    0.3480    0.4170    0.4780    0.5240    0.5660    0.6050    0.6740    0.7390    0.8020    0.8650    0.9290    1.0000]';
        set(handles.userdefined_input,'Enable','Off')
        set(handles.userdefined_input2,'Enable','Off')
        set(handles.userdefined_input,'String',xAE)
        set(handles.userdefined_input2,'String',yAE)
        %hold off
        %acetone-ethanol mixture
        %polynomial regression and plot of equilibrium data
        %p = polyfit(xAE,yAE,6);
        %x = 0:.1:100;
        %y = polyval(p,x);
        %plot(xAE,yAE)
        %hold on
        %plot(x,y)
        %plot(x,x)
        %axis([0 1 0 1])
        %xlabel('Liquid Mole Fraction of Acetone')
        %ylabel('Vapor Mole Fraction of Acetone')
        %title('McCabe-Thiele Diagram for Acetone-Ethanol')

    case 'userdefined_radiobutton'
        hold off
       %User Defined Input
        choice = menu('Input Equilibrium Data as a Row Vector or as a Relative Volatility (alpha)','Vector','Alpha');
        switch choice
            case 1
                set(handles.userdefined_input,'Enable','On')
                set(handles.userdefined_input2,'Enable','On')
                set(handles.userdefined_input,'String','[Liquid Mole Fractions]')
                set(handles.userdefined_input2,'String','[Vapor Mole Fractions]')
                warndlg('Enlose your vectors with brackets and single quotes', 'Warning');
                %disp('You must enter your own equilibrium data in vector form ')
                %MVC = input('Enter the name of the more volatile component ','s');
                %LVC = input('Enter the name of the less volatile component ','s');
                %xU = input('Enter liquid mole fraction data as a row vector (use brackets) \n');
                %a = length(xU);
                %fprintf('You have entered %1.0f "x" data points, you must enter an equal number of y data points \n',a)
                %yU = input('Enter vapor phase mole fraction data as a row vector (use brackets) \n');
                %b = length(yU);
                %if a == b
                    %plot(xU,yU,'o')
                    %hold on
                    %p = polyfit(xU,yU,6);
                    %x = 0:.1:100;
                    %y = polyval(p,x);
                    %plot(x,y)
                    %plot(x,x)
                    %x_label = sprintf('Liquid Phase Mole Fraction of %s',MVC);
                    %y_label = sprintf('Vapor Phase Mole Fraction of %s',MVC);
                    %t_itle = sprintf('McCabe-Thiele Diagram for %s-%s',MVC,LVC);
                    %xlabel(x_label)
                    %ylabel(y_label)
                    %title(t_itle)
                %else
                    %disp('Equilibrium data does not match, vectors must be equal lengths')
                %end
            case 2
                set(handles.userdefined_input,'Enable','On')
                set(handles.userdefined_input2,'String','[]')
                set(handles.userdefined_input,'String','<Enter Relative Volatility>')
        end
end
%updates the handles structure
guidata(hObject, handles);
function userdefined_input_Callback(hObject, eventdata, handles)
% --- Executes during object creation, after setting all properties.
function userdefined_input_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
function userdefined_input2_Callback(hObject, eventdata, handles)
% --- Executes during object creation, after setting all properties.
function userdefined_input2_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%% Column Pressure Checkbox

%Column Pressure Input
function pressureinput_Callback(hObject, eventdata, handles)
% Hints: get(hObject,'String') returns contents of pressureinput as text
%        str2double(get(hObject,'String')) returns contents of pressureinput as a double

% --- Executes during object creation, after setting all properties.
function pressureinput_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function columnpressure_checkbox_Callback(hObject, eventdata, handles)

checkbox1_Status = get(handles.columnpressure_checkbox,'Value');
if checkbox1_Status == 0
    set(handles.pressureinput,'String',' ')
else
    set(handles.pressureinput,'Enable','On')
    set(handles.pressureinput,'String','<Enter Column Pressure>')
end

%% Feed
%% Feed Flow Rate
%Feed Flow Rate Input
function feedflowinput_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function feedflowinput_CreateFcn(hObject, eventdata, handles)

    if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
    end

%Feed Flow Rate Checkbox
function feedflowrate_checkbox_Callback(hObject, eventdata, handles)

checkbox2_Status = get(handles.feedflowrate_checkbox,'Value');

if checkbox2_Status == 0
    set(handles.feedflowinput,'Enable','Off')
    set(handles.feedflowinput,'String',' ');
else
    set(handles.feedflowinput,'Enable','On')
    set(handles.feedflowinput,'String','<Enter Feed Flow Rate>')
end

%% Feed Composition of the Volatile Component Input
function feedcompvolatile_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function feedcompvolatile_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Feed Composition of the Less Volatile Component Input
function feedcomplessvolatile_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function feedcomplessvolatile_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Feed Composition Checkbox
function feedcomposition_checkbox_Callback(hObject, eventdata, handles)

checkbox3_Status = get(handles.feedcomposition_checkbox,'Value');

if checkbox3_Status == 0
    set(handles.feedcompvolatile,'Enable','Off')
    set(handles.feedcomplessvolatile,'Enable','Off')
    set(handles.feedcompvolatile,'String',' ')
    set(handles.feedcomplessvolatile,'String',' ')
else
    set(handles.feedcompvolatile,'Enable','On')
    set(handles.feedcomplessvolatile,'Enable','On')
    set(handles.feedcompvolatile,'String','<Volatile>')
    set(handles.feedcomplessvolatile,'String','<Non-Volatile>')
end

%% Feed Enthalpy
%Feed Enthalpy Input
function feedenthalpyinput_Callback(hObject, eventdata, handles)
function feedenthalpyinput_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Feed Enthalpy Checkbox
function feedenthalpy_Callback(hObject, eventdata, handles)

checkbox4_Status = get(handles.feedenthalpy,'Value');

if checkbox4_Status == 0
    set(handles.feedenthalpyinput,'Enable','Off')
    set(handles.feedenthalpyinput,'String',' ')
else
    set(handles.feedenthalpyinput,'Enable','On')
    set(handles.feedenthalpyinput,'String','<Feed Enthalpy>')
end

%Reboiler Duty Input
function reboilerdutyinput_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function reboilerdutyinput_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% Reboiler Duty Checkbox
function reboilerdutycheckbox_Callback(hObject, eventdata, handles)

checkbox7_Status = get(handles.reboilerdutycheckbox,'Value');
if checkbox7_Status == 0
    set(handles.reboilerdutyinput,'Enable','Off')
    set(handles.reboilerdutyinput,'String',' ')
else
    set(handles.reboilerdutyinput,'Enable','On')
    set(handles.reboilerdutyinput,'String','<Reboiler Duty>')
end

%% Distillate composition

%Distillate Composition, Volatile Component Input
function distcompvolatile_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function distcompvolatile_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Distillate Composition of the less Volatile Component Input
function distcomplessvolatile_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function distcomplessvolatile_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Distillate composition checkbox
function distillatecomposition_checkbox_Callback(hObject, eventdata, handles)

checkbox9_Status = get(handles.distillatecomposition_checkbox,'Value');

if checkbox9_Status == 0
    set(handles.distcompvolatile,'Enable','Off')
    set(handles.distcomplessvolatile,'Enable','Off')
    set(handles.distcompvolatile,'String',' ')
    set(handles.distcomplessvolatile,'String',' ')
else
    set(handles.distcompvolatile,'Enable','On')
    set(handles.distcomplessvolatile,'Enable','On')
    set(handles.distcompvolatile,'String','<Volatile>')
    set(handles.distcomplessvolatile,'String','<Non-Volatile>')
end

%% Reflux Ratio
%Reflux Ratio Input
function refluxratio_input_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function refluxratio_input_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function minimumrefluxinput_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function minimumrefluxinput_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Reflux Ratio Checkbox
function refluxratio_checkbox_Callback(hObject, eventdata, handles)

checkbox11_Status = get(handles.refluxratio_checkbox,'Value');

if checkbox11_Status == 0
    set(handles.refluxratio_input,'Enable','Off')
    set(handles.refluxratio_input,'String',' ')
    set(handles.minimumrefluxinput,'Enable','Off')
    set(handles.minimumrefluxinput,'String',' ')
elseif checkbox11_Status == 1
    choice = menu('Are you specifying minimum reflux or actual reflux','Actual','Minumum');
    switch choice
        case 1
            set(handles.refluxratio_input,'Enable','On')
            set(handles.refluxratio_input,'String','<Reflux Ratio>')
            set(handles.minimumrefluxinput,'Enable','Off')
            set(handles.minimumrefluxinput,'String',' ')
        case 2
            Rmin = str2double(get(handles.minimumrefluxinput,'String'));
            if isnan(Rmin) == 1
                set(handles.refluxratio_input,'Enable','On')
                set(handles.refluxratio_input,'String','<Operating Factor>')
                set(handles.minimumrefluxinput,'Enable','On')
                set(handles.minimumrefluxinput,'String','<Minumum Reflux>')
            elseif isnan(Rmin) == 0
                set(handles.refluxratio_input,'Enable','On')
                set(handles.refluxratio_input,'String','<Operating Factor>')
                set(handles.minimumrefluxinput,'Enable','Off')
            end
    end

end

%% Bottoms Composition
%Bottoms Composition of the Less Volatile Component Input
function botcomplessvolatile_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function botcomplessvolatile_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Bottoms Composition of the Volatile Component Input
function botcompvolatile_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function botcompvolatile_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Bottoms Composition Checkbox
function bottomscomposition_checkbox_Callback(hObject, eventdata, handles)

checkbox10_Status = get(handles.bottomscomposition_checkbox,'Value');

if checkbox10_Status == 0
    set(handles.botcomplessvolatile,'Enable','Off')
    set(handles.botcompvolatile,'Enable','Off')
    set(handles.botcomplessvolatile,'String',' ')
    set(handles.botcompvolatile,'String',' ')
elseif checkbox10_Status == 1
    set(handles.botcomplessvolatile,'Enable','On')
    set(handles.botcompvolatile,'Enable','On')
    set(handles.botcompvolatile,'String','<Volatile>')
    set(handles.botcomplessvolatile,'String','<Non-Volatile>')
end

%% Optimum Feed Plate
%Optimum Feed Plate Checkbox
function optimumfeedplate_Callback(hObject, eventdata, handles)

%% Distillate Flow Rate
%Distillate Flow Rate Input
function distillateflowrateinput_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function distillateflowrateinput_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Distillate Flow Rate Checkbox
function distillateflowrate_checkbox_Callback(hObject, eventdata, handles)
checkbox14_Status = get(handles.distillateflowrate_checkbox,'Value');

if checkbox14_Status == 0
    set(handles.distillateflowrateinput,'Enable','Off')
    set(handles.distillateflowrateinput,'String',' ')
else
    set(handles.distillateflowrateinput,'Enable','On')
    set(handles.distillateflowrateinput,'String','<Enter Distillate Flow Rate>')
end

%% Fractional Recoveries

%Fractional Recovery of the Volatile Component in the Distillate Input
function fracrecoveryvolatile_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function fracrecoveryvolatile_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Fractional Recovery of the Less Volatile Component in the Bottoms Input
function fracrecoverylessvolatile_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function fracrecoverylessvolatile_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Fractional Recoveries Checkbox
function fractionalrecoveries_checkbox_Callback(hObject, eventdata, handles)

checkbox12_Status = get(handles.fractionalrecoveries_checkbox,'Value');

if checkbox12_Status == 0
    set(handles.fracrecoveryvolatile,'Enable','Off')
    set(handles.fracrecoverylessvolatile,'Enable','Off')
    set(handles.fracrecoveryvolatile,'String','0')
    set(handles.fracrecoverylessvolatile,'String','0')
else
    set(handles.fracrecoveryvolatile,'Enable','On')
    set(handles.fracrecoverylessvolatile,'Enable','On')
    set(handles.fracrecoveryvolatile,'String','<Volatile>')
    set(handles.fracrecoverylessvolatile,'String','<Non-Volatile>')
end

%% Bottoms Flow Rate
function bottomsflowrateinput_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function bottomsflowrateinput_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Bottoms Flow Rate Checkbox
function bottomsflowrate_checkbox_Callback(hObject, eventdata, handles)
checkbox15_Status = get(handles.bottomsflowrate_checkbox,'Value');
if checkbox15_Status == 0
    set(handles.bottomsflowrateinput,'Enable','Off')
    set(handles.bottomsflowrateinput,'String',' ')
else
    set(handles.bottomsflowrateinput,'Enable','On')
    set(handles.bottomsflowrateinput,'String','<Enter Bottoms Flow Rate>')
end

%% Boilup Ratio Checkbox

%Boilup Ratio Input
function boilupratioinput_Callback(hObject, eventdata, handles)

function boilupratioinput_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function boilupratio_checkbox_Callback(hObject, eventdata, handles)

checkbox15_Status = get(handles.boilupratio_checkbox,'Value');

if checkbox15_Status == 0
    set(handles.boilupratioinput,'Enable','Off')
    set(handles.boilupratioinput,'String',' ')
elseif checkbox15_Status == 1
    set(handles.boilupratioinput,'Enable','On')
    set(handles.boilupratioinput,'String','<Enter Boilup Ratio>')
elseif checkbox15_Status == 0 && checkbox11_Status == 1 && checkbox6_Status == 1 && checkbox9_Status == 1
    set(handles.boilupratioinput,'Enable','Off')
    set(handles.boilupratioinput,'String',' ')
    xi = (-(Q-1)*(1-R/(R+1))*xd-zf)/((Q-1)*R/(R+1)-Q);
    yi = (zf+xd*Q/R)/(1+Q/R);
    xs = linspace(xb,xi);
    ys = linspace(xb,yi);
    plot(xs,ys)
    hold on
end

%% Feed Quality

%Feed Quality Input
function feedqualityinput_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function feedqualityinput_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Feed Quality Checkbox
function feedquality_checkbox_Callback(hObject, eventdata, handles)

checkbox6_Status = get(handles.feedquality_checkbox,'Value');

if checkbox6_Status == 0
    set(handles.feedqualityinput,'Enable','Off')
    set(handles.feedqualityinput,'String',' ')
else
    set(handles.feedqualityinput,'Enable','On')
    set(handles.feedqualityinput,'String','<Enter Feed Quality>')
end

%Condenser Duty Input
function condenserdutyinput_Callback(hObject, eventdata, handles)
function condenserdutyinput_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Condenser Duty Checkbox
function condenserdutycheckbox_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function condenserdutycheckbox_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

checkbox5_Status = get(handles.condenserdutycheckbox,'Value');
if checkbox5_Status == 0
    set(handles.condenserdutyinput,'Enable','Off')
    set(handles.condenserdutyinput,'String',' ')
else
    set(handles.condenserdutyinput,'Enable','On')
    set(handles.condenserdutyinput,'String','<Enter Condenser Duty>')
end

%Reflux Enthalpy Input
function refluxenthalpyinput_Callback(hObject, eventdata, handles)
% --- Executes during object creation, after setting all properties.
function refluxenthalpyinput_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
%Reflux Enthalpy Checkbox
function refluxenthalpy_Callback(hObject, eventdata, handles)

checkbox8_Status = get(handles.refluxenthalpy,'Value');
if checkbox8_Status == 0
    set(handles.refluxenthalpyinput,'Enable','Off')
    set(handles.refluxenthalpyinput,'String',' ')
else
    set(handles.refluxenthalpyinput,'Enable','On')
    set(handles.refluxenthalpyinput,'String','<Reflux Enthalpy>')
end

%Boilup Enthalpy Input
function boilupenthalpyinput_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function boilupenthalpyinput_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

%Boilup Enthalpy Checkbox
function boilupenthalpycheckbox_Callback(hObject, eventdata, handles)
checkbox20_Status = get(handles.boilupenthalpycheckbox,'Value');
if checkbox20_Status == 0
    set(handles.boilupenthalpyinput,'Enable','Off')
    set(handles.boilupenthalpyinput,'String',' ')
else
    set(handles.boilupenthalpyinput,'Enable','On')
    set(handles.boilupenthalpyinput,'String','<Boilup Enthalpy>')
end

%Distillate Enthalpy
function distillateenthalpyinput_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function distillateenthalpyinput_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in distillateenthalpycheckbox.
function distillateenthalpycheckbox_Callback(hObject, eventdata, handles)
checkbox21_Status = get(handles.distillateenthalpycheckbox,'Value');
if checkbox21_Status == 0
    set(handles.distillateenthalpyinput,'Enable','Off')
    set(handles.distillateenthalpyinput,'String',' ')
else
    set(handles.distillateenthalpyinput,'Enable','On')
    set(handles.distillateenthalpyinput,'String','<Distillate Enthalpy>')
end

%Bottoms enthalpy
function bottomsenthalpyinput_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function bottomsenthalpyinput_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in bottomsenthalpycheckbox.
function bottomsenthalpycheckbox_Callback(hObject, eventdata, handles)
checkbox22_Status = get(handles.bottomsenthalpycheckbox,'Value');
if checkbox22_Status == 0
    set(handles.bottomsenthalpyinput,'Enable','Off')
    set(handles.bottomsenthalpyinput,'String',' ')
else
    set(handles.bottomsenthalpyinput,'Enable','On')
    set(handles.bottomsenthalpyinput,'String','<Bottoms Enthalpy>')
end

% --- Executes on button press in startbutton.
function startbutton_Callback(hObject, eventdata, handles)

% Get Values

Alpha = str2double(get(handles.userdefined_input,'String'));

P = str2double(get(handles.pressureinput,'String'));
F = str2double(get(handles.feedflowinput,'String'));
zf = str2double(get(handles.feedcompvolatile,'String'));
zfnv = str2double(get(handles.feedcomplessvolatile,'String'));
xd = str2double(get(handles.distcompvolatile,'String'));
xdnv = str2double(get(handles.distcomplessvolatile,'String'));
xb = str2double(get(handles.botcompvolatile,'String'));
xbnv = str2double(get(handles.botcomplessvolatile,'String'));
D = str2double(get(handles.distillateflowrateinput,'String'));
fv = str2double(get(handles.fracrecoveryvolatile,'String'));
fnv = str2double(get(handles.fracrecoverylessvolatile,'String'));
B = str2double(get(handles.bottomsflowrateinput,'String'));
S = str2double(get(handles.boilupratioinput,'String'));
Q = str2double(get(handles.feedqualityinput,'String'));
R = str2double(get(handles.refluxratio_input,'String'));
Rmin = str2double(get(handles.minimumrefluxinput,'String'));
hf = str2double(get(handles.feedenthalpyinput,'String'));
hD = str2double(get(handles.refluxenthalpyinput,'String'));
hB = str2double(get(handles.boilupenthalpyinput,'String'));
Qc = str2double(get(handles.condenserdutyinput,'String'));
Qr = str2double(get(handles.reboilerdutyinput,'String'));
HD = str2double(get(handles.distillateenthalpyinput,'String'));
HB = str2double(get(handles.bottomsenthalpyinput,'String'));

%xie = 1/2*(-Q+zf*Alpha+Q*Alpha-zf-Alpha+(2*Q*Alpha^2*zf+Q^2-2*Q*zf+2*zf*Alpha-2*zf^2*Alpha+zf^2*Alpha^2-2*zf*Alpha^2+zf^2+2*Q*Alpha-2*Q^2*Alpha+Alpha^2+Q^2*Alpha^2-2*Q*Alpha^2)^(1/2))/Q/(-1+Alpha);
%yie = xie*Alpha/(1-xie+xie*Alpha);
xi = (-(Q-1)*(1-R/(R+1))*xd-zf)/((Q-1)*R/(R+1)-Q);
yi = (zf+xd*Q/R)/(1+Q/R);

%Error Tests

%Feed Quality & Feed Line
checkbox6_Status = get(handles.feedquality_checkbox,'Value');
if checkbox6_Status == 0
    errordlg('Feed quality must be specified')
    return
elseif checkbox6_Status == 1 && isnan(Q) == 1
    errordlg('Feed quality must be specified')
    return
elseif checkbox6_Status == 1 && isnan(Q) == 0
    ye = 0:.001:1;
    if Q > -inf && Q <1
            xf = 0:.001:1;
    elseif Q > 1
            xf = zf:.001:1;
    end
    if Q ~= 1
        yf = yfeed(xf,Q,zf);
    elseif Q == 1
        yf = 0:.001:1;
        xf = zf*ones(length(yf));
    end
end

%Equilibrium Data
if any(isnan(Alpha)) == 1
    xeq = str2num(get(handles.userdefined_input,'String'));
    yeq = str2num(get(handles.userdefined_input2,'String'));
    %Error Test on Equilibrium Vector Length
    if length(yeq) ~= length(xeq) && isempty(yeq) == 1 && length(xeq) > 1
        errordlg('Equilibrium data does not match')
        return
    elseif length(yeq) == length(xeq) && length(xeq) < 10
        errordlg('Too few data points will give a poor equilibrium curve')
    else
        k = 1; %k is a constant, metric for stepping off equilibrium stages
    end
elseif isnan(Alpha) == 0 && length(Alpha) == 1
    yeq = [];
    if Alpha <= 1
        errordlg('Relative volatility must be greater than 1')
        return
    elseif Alpha > 1
        k = 2;
    end
end
if k == 1
    xx = 0:.001:1;
    yy = spline(xeq,yeq,xx);
    if Q == 0
        xx = .001:.001:1.001;
        yy = spline(xeq,yeq,xx);
        diffe = abs(yy-zf);
        [a b] = min(diffe) ;
        xie = xx(b);
        yie = zf;
    elseif Q == 1
        yie = spline(xeq,yeq,zf);
        xie = zf;
    elseif Q~=0 && Q~=1
        diffe = abs(yy-yf);
        [a b] = min(diffe);
        xie = xx(b);
        yie = yy(b);
    end
elseif k == 2
    xie = 1/2*(-Q+zf*Alpha+Q*Alpha-zf-Alpha+(2*Q*Alpha^2*zf+Q^2-2*Q*zf+2*zf*Alpha-2*zf^2*Alpha+zf^2*Alpha^2-2*zf*Alpha^2+zf^2+2*Q*Alpha-2*Q^2*Alpha+Alpha^2+Q^2*Alpha^2-2*Q*Alpha^2)^(1/2))/Q/(-1+Alpha);
    yie = xie*Alpha/(1-xie+xie*Alpha);
end

%Overall Mass Balance
checkbox2_Status = get(handles.feedflowrate_checkbox,'Value');
checkbox17_Status = get(handles.distillateflowrate_checkbox,'Value');
checkbox18_Status = get(handles.bottomsflowrate_checkbox,'Value');
l = [checkbox2_Status checkbox17_Status checkbox18_Status]; %l is a status vector for mass flow streams
if any([F D B]< 0)
    errordlg('Mass flow rates must be greater than zero')
    return
elseif sum(l) == 3 && D + B ~= F
    errordlg('The mass balance is incorrect')
    return
elseif sum(l) == 2
    if isnan(F) == 0
        if isnan(B) == 0
            D = F - B;
            Ds = num2str(D);
            set(handles.distillateflowrateinput,'String',Ds)
        elseif isnan(D) == 0
            B = F - D;
            Bs = num2str(B);
            set(handles.bottomsflowrateinput,'String',Bs)
        end
    elseif isnan(F) == 1
        F = B + D;
        Fs = num2str(F);
        set(handles.feedflowinput,'String',Fs)
    end
end

%Feed Composition
checkbox3_Status = get(handles.feedcomposition_checkbox,'Value');
if checkbox3_Status == 1
    if isnan(zf) == 1 && isnan(zfnv) == 1
        errordlg('Feed composition must be a real number')
        return
    elseif isnan(zf) == 0 && isnan(zfnv) == 1
        zfnv = 1 - zf;
        zfnv = num2str(zfnv);
        set(handles.feedcomplessvolatile,'String',zfnv)
    elseif isnan(zf) == 1 && isnan(zfnv) == 0
        zf = 1 - zfnv;
        zf = num2str(zf);
        set(handles.feedcompvolatile,'String',zf)
    elseif isnan(zf) == 0 && isnan(zfnv) == 0
        if zf + zfnv ~= 1
            errordlg('Mole fractions must add up to 1')
            return
        elseif zf < 0 || zf > 1 || zfnv < 0 || zfnv > 1
            errordlg('Mole fractions must be between 0 and 1')
            return
        end
    end
end

%Distillate Composition
checkbox9_Status = get(handles.distillatecomposition_checkbox,'Value');
if checkbox9_Status == 1
    if isnan(xd) && isnan(xdnv)
        errordlg('Distillate composition must be a real number')
        return
    elseif isnan(xd) == 0 && isnan(xdnv) == 1
        xdnv = 1 - xd;
        xdnvs = num2str(xdnv);
        set(handles.distcomplessvolatile,'String',xdnvs)
    elseif isnan(xd) == 1 && isnan(xdnv) == 0
        xd = 1 - xdnv;
        xds = num2str(xd);
        set(handles.distcompvolatile,'String',xds)
    elseif isnan(xd) == 0 && isnan(xdnv) == 0
        if xd + xdnv ~= 1
            errordlg('Mole fractions must add up to 1')
            return
        elseif xd < 0 || xd > 1 || xdnv < 0 || xdnv > 1
            errordlg('Mole fractions must be between 0 and 1')
            return
        end
    end
end

%Bottoms Composition
checkbox10_Status = get(handles.bottomscomposition_checkbox,'Value');
if checkbox10_Status == 1
    if isnan(xb) == 1 && isnan(xbnv) == 1
        errordlg('Bottoms composition must be a real number')
        return
    elseif isnan(xb) == 0 && isnan(xbnv) == 1
        xbnv = 1 - xb;
        xbnvs = num2str(xbnv);
        set(handles.botcomplessvolatile,'String',xbnvs)
    elseif isnan(xb) == 1 && isnan(xbnv) == 0
        xb = 1 - xbnv;
        xbs = num2str(xb);
        set(handles.botcompvolatile,'String',xbs)
    elseif isnan(xb) == 0 && isnan(xbnv) == 0
        if xb + xbnv ~= 1
            errordlg('Mole fractions must add up to 1')
            return
        elseif xb < 0 || xb > 1 || xbnv < 0 || xbnv > 1
            errordlg('Mole fractions must be between 0 and 1')
            return
        end
    end
end

%Test to see if the mass balance has converged
%lk is a status vector for feed stream compositions
lk = [checkbox3_Status checkbox9_Status checkbox10_Status];
if sum(lk) == 3
    if sum(l) == 1
        if isnan(F) == 0
            if isnan(D) == 1 && isnan(B) == 1
                D = F*(zf-xb)/(xd-xb);
                Ds = num2str(D);
                set(handles.distillateflowrateinput,'String',Ds)
                B = F - D;
                Bs = num2str(B);
                set(handles.bottomsflowrateinput,'String',Bs)
                fv = D*xd/F/zf;
                fvs = num2str(fv);
                set(handles.fracrecoveryvolatile,'String',fvs)
                fnv = B*(1-xb)/F/(1-zf);
                fnvs = num2str(fnv);
                set(handles.fracrecoverylessvolatile,'String',fnvs)
            end
        end
    elseif sum(l) == 2
        if isnan(F) == 0
            if isnan(D) == 0
                Dk = F*(zf-xb)/(xd-xb);
                Bk = F - Dk;
                if D ~= Dk
                    Ds = num2str(Dk);
                    set(handles.distillateflowrateinput,'String',Ds)
                    Bk = F-Dk;
                    Bs = num2str(Bk);
                    set(handles.bottomsflowrateinput,'String',Bs)
                    fv = D*xd/F/zf;
                    fvs = num2str(fv);
                    set(handles.fracrecoveryvolatile,'String',fvs)
                    fnv = B*(1-xb)/F/(1-zf);
                    fnvs = num2str(fnv);
                    set(handles.fracrecoverylessvolatile,'String',fnvs)
                end
                if B ~= Bk
                    Bs = num2str(Bk);
                    set(handles.bottomsflowrateinput,'String',Bs)
                    Dk = F-Bk;
                    Ds = num2str(Dk);
                    set(handles.distillateflowrateinput,'String',Ds)
                    fv = D*xd/F/zf;
                    fvs = num2str(fv);
                    set(handles.fracrecoveryvolatile,'String',fvs)
                    fnv = B*(1-xb)/F/(1-zf);
                    fnvs = num2str(fnv);
                    set(handles.fracrecoverylessvolatile,'String',fnvs)
                end
            end
        end
    end
elseif sum(lk) == 1 && isnan(zf) == 0
checkbox12_Status = get(handles.fractionalrecoveries_checkbox,'Value');
    if sum(l) == 2 || sum(l) == 3
        %Fractional Recoveries
        if  checkbox12_Status == 1
            if any(isnan([fv fnv])) == 1
                errordlg('Fractional recovery must be a real number')
                return
            elseif any([fv fnv]>=1) || any([fv fnv]<0)
                errordlg('Fractional recovery must be between 0 and 1')
                return
            elseif any([fv fnv]==1)
                errordlg('100 percent recovery is physically impossible, try a different value')
                return
            else
                xd = fv/D*F*zf;
                xds = num2str(xd);
                set(handles.distcompvolatile,'String',xds)
                xb = 1-fnv/(F-D)*F*(1-zf);
                xbs = num2str(xb);
                set(handles.botcompvolatile,'String',xbs)
            end
        end
    elseif checkbox12_Status == 0
        errordlg('The system is underspecified')
        return
    end
end

%Fractional Recoveries
checkbox12_Status = get(handles.fractionalrecoveries_checkbox,'Value');
if checkbox12_Status == 0
    if all(isnan([F D B zf xd xb])) == 0
        fv = D*xd/F/zf;
        fvs = num2str(fv);
        set(handles.fracrecoveryvolatile,'String',fvs)
        fnv = B*(1-xb)/F/(1-zf);
        fnvs = num2str(fnv);
        set(handles.fracrecoverylessvolatile,'String',fnvs)
    end
end

%Feed Enthalpy
checkbox4_Status = get(handles.feedenthalpy,'Value');
if checkbox4_Status == 1 && isnan(hf) == 1
    errordlg('Feed enthalpy must be a real number')
    return
end

%Condenser Duty
checkbox5_Status = get(handles.condenserdutycheckbox,'Value');
if checkbox5_Status == 1 && isnan(Qc) == 1
    errordlg('Condenser duty must be a real number')
    return
end

%Reboiler Duty
checkbox7_Status = get(handles.reboilerdutycheckbox,'Value');
if checkbox7_Status == 1 && isnan(Qr) == 1
    errordlg('Reboiler duty must be a real number')
    return
end

%Reflux Enthalpy
checkbox8_Status = get(handles.refluxenthalpy,'Value');
if checkbox8_Status == 1 && isnan(hD) == 1
    errordlg('Reflux enthalpy must be a real number')
    return
end

%Reflux Ratio
checkbox11_Status = get(handles.refluxratio_checkbox,'Value');
if checkbox11_Status == 1
    if isnan(R) == 1 && isnan(Rmin) == 1
        errordlg('Reflux ratio must be a real number')
        return
    elseif R < 0
        errordlg('Reflux ratio must be greater than 0')
        return
    elseif Rmin < 0
        errordlg('Minumum reflux must be greater than 0')
        return
    elseif isnan(Rmin) == 0 && isnan(R) == 1
        errordlg('You must specify an operating factor')
        return
    end
elseif checkbox11_Status == 0
    if isnan(xd) == 1 && isnan(Q) == 1
        errordlg('You must specify feed quality and distillate composition')
        return
    elseif isnan(xd) == 0 && isnan(Q) == 1
        errordlg('You must specify feed quality')
        return
    elseif isnan(xd) == 1 && isnan(Q) == 0
        errordlg('You must specify distillate composition')
        return
    elseif isnan(Rmin) == 1 && isnan(Q) == 0 && isnan(xd) == 0
        if isnan(Alpha) == 0
            if isnan(R) == 1
                Emin = (xd-yie)/(xd-xie);
                Rmin = Emin/(1-Emin);
                Rmins = num2str(Rmin);
                set(handles.minimumrefluxinput,'String',Rmins)
                errordlg('Minimum reflux has been calculated and returned but you must specify an operating factor')
                return
            elseif isnan(R) == 0
                Emin = (xd-yie)/(xd-xie);
                Rmin = Emin/(1-Emin);
                Rmins = num2str(Rmin);
                R = R*Rmin;
                Rs = num2str(R);
                set(handles.minimumrefluxinput,'String',Rmins)
                set(handles.refluxratio_input,'String',Rs)
            elseif isnan(Rmin) == 0 && isnan(R) == 1
                errordlg('You must specify an operating factor')
                return
            end
        elseif isnan(Alpha) == 1 && k ==1
            if isnan(R) == 1
                Emin = (xd-yie)/(xd-xie);
                Rmin = Emin/(1-Emin);
                Rmins = num2str(Rmin);
                set(handles.minimumrefluxinput,'String',Rmins)
                errordlg('Minimum reflux has been calculated and returned but you must specify an operating factor')
                return
            elseif isnan(R) == 0
                Emin = (xd-yie)/(xd-xie);
                Rmin = Emin/(1-Emin);
                Rmins = num2str(Rmin);
                R = R*Rmin;
                Rs = num2str(R);
                set(handles.minimumrefluxinput,'String',Rmins)
                set(handles.refluxratio_input,'String',Rs)
            elseif isnan(Rmin) == 0 && isnan(R) == 1
                errordlg('You must specify an operating factor')
                return
            end
        end
    end
end

%Optimum Feed Plate
checkbox12_Status = get(handles.optimumfeedplate,'Value');
if checkbox12_Status == 0
    errordlg('This version does not support non-optimum feed plate')
    return
end

%Boilup Ratio
if S < 0
    errordlg('Boilup ratio must be greater than 0')
    return
end

%Boilup Enthalpy
checkbox20_Status = get(handles.boilupenthalpycheckbox,'Value');
if checkbox20_Status == 1 && isnan(hB) == 1
    errordlg('Boilup enthalpy must be a real number')
    return
end

%Pressure
if P < 0
    errordlg('Pressure must be greater than 0')
end

%Energy Balance
%checkbox4_Status = get(handles.feedenthalpy,'Value');
%checkbox5_Status = get(handles.condenserdutycheckbox,'Value');
%checkbox7_Status = get(handles.reboilerdutycheckbox,'Value');
%checkbox8_Status = get(handles.refluxenthalpy,'Value');
%checkbox20_Status = get(handles.boilupenthalpycheckbox,'Value');
%checkbox21_Status = get(handles.distillateenthalpycheckbox,'Value');
%checkbox22_Status = get(handles.bottomsenthalpycheckbox,'Value');
%jkl = [checkbox4_Status checkbox5_Status checkbox7_Status checkbox8_Status checkbox20_Status checkbox21_Status checkbox22_Status]; %Status vector
%Condenser Energy Balance
if isnan(Qc) == 0
    if isnan(hD) == 1
        hD = Qc/D/(R+1)*3600;
        hDs = num2str(hD);
        set(handles.refluxenthalpyinput,'String',hDs)
    end
elseif isnan(hD) == 0
    if isnan(Qc) == 1
        Qc = hB*D*(R+1)/3600;
        Qcs = num2str(Qc);
        set(handles.condenserdutyinput,'String',Qcs)
    end
end
%Reboiler Energy Balance
if isnan(Qr) == 0
    if isnan(hB) == 1
        hB = Qr/B/S*3600;
        hBs = num2str(hB);
        set(handles.boilupenthalpyinput,'String',hBs)
    end
elseif isnan(hB) == 0
    if isnan(Qr) == 1
        Qr = B*S*hB/3600;
        Qrs = num2str(Qr);
        set(handles.reboilerdutyinput,'String',Qrs)
    end
end
%jklm = [isnan(F) isnan(hf) isnan(Qc) isnan(Qr) isnan(B) isnan(HB) isnan(D) isnan(HD)];
%if sum(jklm) == 0
%    if F*hf + Qc + Qr - B*HB - D*HD >= 100
%        errordlg('The energy balance is not correct')
%        return
%    end
%end

%Equilibrium Curves
if k ==1 %Vector
    xx = 0:.001:1;
    yy = spline(xeq,yeq,xx);
    hold off
    plot(xx,yy)
    axis([0 1 0 1])
    hold on
    plot(xx,xx)
elseif k == 2 %Alpha
    ye = 0:.001:1;
    xe = equilib(ye,Alpha);
    hold off
    plot(xe,ye)
    axis([0 1 0 1])
    hold on
    plot(ye,ye)
end

%Plotting the Operating Lines
ytopop = ytop(ye,R,xd);
ybotop = ybot(ye,S,xb);
plot(xf,yf);
plot(ye,ytopop)
plot(ye,ybotop)
plot(ye,ye)
plot(xb,xb,'o')
text(xb+.025,xb-.025,'x_B')
plot(xd,xd,'o')
text(xd+.025,xd-.025,'x_D')
plot(zf,zf,'o')

% Computing the intersection of feed line and operating lines
plot(xi,yi,'o')
text(xi-.1,yi+.025,'Feed Line')
text(xb-.025,xb+.05,'Stripping Line')
text(xd-.25,xd-.05,'Enriching Line')
xlabel('Liquid Phase Mole Fraction, x')
ylabel('Vapor Phase Mole Fraction, y')
title('McCabe-Thiele Diagram for Binary Column Distillation')
if k == 2
    yi2 = interp1 (xe,ye,xi);
    if yi > yi2
        errordlg ('The distillation is not possible. Try a different operating condition.')
        return
    end
elseif k == 1
    yi2 = interp1(xx,yy,xi);
    if yi > yi2
        errordlg('The distillation is not possible. Try a different operating condition.')
        return
    end
end

% Rectifying section
if k == 2 %user defined systems
    i = 1;
    xp(1) = xd;
    yp(1) = xd;
    y = xd;
    while xp (i) > xi
        xp(i+1)= equilib(y,Alpha);
        yp(i+1)= R/(R+1)*xp (i+1)+xd/(R+1);
        y = yp (i+1);
        a = linspace(xp(i),xp(i+1));
        b = yp(i)*ones(length(a));
        plot(a,b)
        text ((xp(i+1)-.025),(yp(i)+.025),num2str (i))
        if xp (i+1) > xi
            c = linspace(yp(i),yp(i+1));
            d = xp(i+1)*ones(length(c));
            plot(d,c)
        end
        i = i+1;
    end
    % Stripping section
    xs = linspace(xb,xi);
    ys = linspace(xb,yi);
    plot(xs,ys)
    ss = (yi-xb)/(xi-xb);
    S = 1/(ss-1);
    S = num2str(S);
    set(handles.boilupratioinput,'String',S)
    yp(i) = ss*(xp(i)-xb)+xb;
    y = yp(i);
    a = linspace(yp(i-1),yp(i));
    b = xp(i)*ones(length(a));
    plot(b,a)
    while xp (i) > xb
        xp(i+1) = equilib(y,Alpha);
        yp(i+1) = ss*(xp(i+1)-xb)+xb;
        y = yp(i+1);
        a = linspace(xp(i),xp(i+1));
        b = yp(i)*ones(length(a));
        plot(a,b)
        text ((xp(i+1)-.025),(yp(i)+.025),num2str (i))
        if xp (i+1) > xb
            a = linspace(yp(i),yp(i+1));
            b = xp(i+1)*ones(length(a));
            plot(b,a)
        end
        i = i+1;
    end

elseif k ==1 %predefined equilibrium systems
    i = 1;
    xp(1) = xd;
    yp(1) = xd;
    y = xd;
    while xp(i) > xi
        xp(i+1)= predefeq(xeq,yeq,y);
        yp(i+1)= R/(R+1)*xp(i+1)+xd/(R+1);
        y = yp(i+1);
        a = linspace(xp(i),xp(i+1));
        b = yp(i)*ones(length(a));
        plot(a,b)
        text ((xp(i+1)-.025),(yp(i)+.025),num2str (i))
        if xp (i+1) > xi
            c = linspace(yp(i),yp(i+1));
            d = xp(i+1)*ones(length(c));
            plot(d,c)
        end
        i = i+1;
    end
    % Stripping section
    xs = linspace(xb,xi);
    ys = linspace(xb,yi);
    plot(xs,ys)
    ss = (yi-xb)/(xi-xb);
    S = 1/(ss-1);
    S = num2str(S);
    set(handles.boilupratioinput,'String',S)
    yp(i) = ss*(xp(i)-xb)+xb;
    y = yp(i);
    a = linspace(yp(i-1),yp(i));
    b = xp(i)*ones(length(a));
    plot(b,a)
    while xp (i) > xb
        xp(i+1) = predefeq(xeq,yeq,y);
        yp(i+1) = ss*(xp(i+1)-xb)+xb;
        y = yp(i+1);
        a = linspace(xp(i),xp(i+1));
        b = yp(i)*ones(length(a));
        plot(a,b)
        text ((xp(i+1)-.025),(yp(i)+.025),num2str (i))
        if xp (i+1) > xb
            a = linspace(yp(i),yp(i+1));
            b = xp(i+1)*ones(length(a));
            plot(b,a)
        end
        i = i+1;
    end
end

% Functions called with start button: operating & equilibrium lines
function yf = yfeed(xf,Q,zf)
yf = Q/(Q-1)*xf+zf/(1-Q);

function xa = equilib(ya,Alpha)
xa = ya./(Alpha-ya*(Alpha-1));

function ybotop = ybot(x,S,xb)
ybotop = (S+1)/S*x-xb/S;

function ytopop = ytop(x,R,xd)
ytopop = R/(R+1)*x+xd/(R+1);

function backl = predefeq(xeq,yeq,val)
xx = 0:.001:1;
yy = spline(xeq,yeq,xx);
ym = val*ones(1,length(xx));
diffe = abs(yy-ym);
[a b] = min(diffe);
xk = xx(b);
backl = xk;

%System of Nonlinear Equations -- Will be functional in a later version

%User Input Vector
%L = R*D;
%V = D*(R+1);
%Vbar = S*B;
%Lbar = B*(S+1);
%Input_Vector = [F,zf,zfnv,xd,xdnv,xb,xbnv,D,fv,fnv,B,S,Q,R,Rmin,hf,hD,hB,Qc,Qr,L,V,Lbar,Vbar,xie,yie,xi,yi];
%for k = 1:20
%    if isnan(Input_Vector(k)) == 0
%        v(k) = Input_Vector(k);
%    end
%end

%v(1) = F;
%v(2) = zf;
%v(3) = zfnv;
%v(4) = xd;
%v(5) = xdnv;
%v(6) = xb;
%v(7) = xbnv;
%v(8) = D;
%v(9) = fv;
%v(10) = fnv;
%v(11) = B;
%v(12) = S;
%v(13) = Q;
%v(14) = R;
%v(15) = Rmin;
%v(16) = hf;
%v(17) = hD;
%v(18) = hB;
%v(19) = Qc;
%v(20) = Qr;
%v(21) = L;
%v(22) = V;
%v(23) = Lbar;
%v(24) = Vbar;
%v(25) = xie;
%v(26) = yie;
%v(27) = xi;
%v(28) = yi;

%F = @(v) [v(10)-v(11).*v(7)./v(1)./v(3); v(9)-v(8).*v(4)./v(1)./v(2); v(11)+v(24)-v(23);
%    v(21)+v(8)-v(22); v(23)./v(24)-1./v(12)+1; v(22)./v(21)-1./v(14)-1; v(11)+v(8)-v(1);
%    v(11).*v(6)+v(8).*v(4)-v(1).*v(2); v(2)+v(3)-1; v(6)+v(7)-1; v(4)+v(5)-1;
%    v(1).*v(16)+v(19)+v(20)-v(8).*v(17)-v(11).*v(18); v(15)./(1+v(15))-(v(4)-v(26))./(v(4)-v(25));
%    v(12)-1./(((v(28)-v(6))./(v(27)-v(6)))-1); v(14)./(1+v(14))-(v(4)-v(28))./(v(4)-v(27))];

%InitialGuess = [50;.5;.5;.5;.5;.5;.5;25;.75;.75;25;2;.5;3;1.5;1;1;1;1;1;1;1;1;1;.5;.5;.5;.5];
%Options = optimset('Display','iter');
%XY = fsolve(F, InitialGuess, Options);

%fnv - B*xbnv/F/zfnv
%fv - D*xd/F/zf;
%B + Vbar - Lbar;
%L + D - V;
%Lbar/Vbar - 1/S + 1;
%V/L - 1/R - 1;
%B + D - F;
%B*xb + D*xd - F*zf;
%zf + zfnv - 1;
%xb + xbnv - 1;
%xd + xdnv - 1;
%F*hf + Qc + Qr - D*hD - B*hB;
%Rmin/(1+Rmin) - (xd-yie)/(xd-xie);
%S - 1/((yi-xb)/(xi-xb)-1);
%R/(1+R)-(xd-yi)/(xd-xi);


%kksinc 'Output = sin(Input)/Input'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros ksinc.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'Input data object'
% OutputFile: o 'Output', required: 'Resulting output data object'
%
% Example: o = kksinc(i, {'i','';'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% ksinc - Output = sin(Input)/Input
%
%  DESCRIPTION
% The "Sinc" operator calculates the sinc function (sin(x)/x) of each data
% point in the input data object, \fBInput".
%
% Executing "Sinc" runs the program \fIkarith1\fP with the -sinc flag.
%
%  "\fBData Type"" 5
% .cI $DATAMANIP/repos/shared/man/sections/value_type_1input
%
%  "\fBMap Data"" 5
% .cI $DATAMANIP/repos/shared/man/sections/map_1input
%
%  "\fBValidity Mask"" 5
% .cI $DATAMANIP/repos/shared/man/sections/mask_1input
%
%  "\fBExplicit Location and Time Data"" 5
% .cI $DATAMANIP/repos/shared/man/sections/loc_and_time_1input
%
%  "\fBFailure Modes""
% .cI $DATAMANIP/repos/shared/man/sections/fail_1input
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
% DATAMANIP::karith1
%
%  RESTRICTIONS
% Operations on complex data are not supported at this time.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kksinc(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kksinc(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'o', '__output'};
maxval={0,0};
minval={0,0};
istoggle=[0,0];
was_set=istoggle * 0;
paramtype={'InputFile','OutputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; 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(1,1);
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
[varargout{:}]=callKhoros([w 'karith1"  -sinc'],Inputs,narglist);


% test_all_emission.m

list = {
	'eml_curvature test'
	'eml_osem_example'
	'eml_em_test'
	'eml_osem_test'
	'eml_sps_os_test'
	'eml_psca_test'
	'eql_os_emdp_test'
	'eql_sps_os_test'
	'hole_example1'
	'psf_mismatch_example1'
	'psf_mismatch_example2'
};

run_mfile_local(list)
%run_mfile_local(list, 'pause', 1)


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   PARAMETERS Returns a data structure containing the parameters of the
%    EPSON C8.
%
% The author of this script is:
%		  Silvia Moreno Serrano
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Copyright (C) 2012, by Arturo Gil Aparicio
%
% This file is part of ARTE (A Robotics Toolbox for Education).
%
% ARTE is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% ARTE 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with ARTE.  If not, see <http://www.gnu.org/licenses/>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function robot = parameters()

robot.name= '6AXIS_C8';

%Path where everything is stored for this robot
robot.path = 'robots/EPSON/6AXIS_C8';

robot.DH.theta='[q(1)+pi/2 q(2)+pi/2 q(3) q(4) q(5) q(6)]';
robot.DH.d='[0.472 0 0 0.310 0 0.080]';
robot.DH.a='[0.100 0.300 0.03 0 0 0]';
robot.DH.alpha='[pi/2 0 pi/2 -pi/2 pi/2 0]';

robot.J=[];

robot.inversekinematic_fn = 'inversekinematic_C8(robot, T)';
robot.directkinematic_fn = 'directkinematic(robot, q)';

%number of degrees of freedom
robot.DOF = 6;

%rotational: 0, translational: 1
robot.kind=['R' 'R' 'R' 'R' 'R' 'R'];

%minimum and maximum rotation angle in rad
robot.maxangle =[deg2rad(-240) deg2rad(240); %Axis 1, minimum, maximum
                deg2rad(-158) deg2rad(65); %Axis 2, minimum, maximum
                deg2rad(-61) deg2rad(202); %Axis 3
                deg2rad(-200) deg2rad(200); %Axis 4: Unlimited (400? default)
                deg2rad(-135) deg2rad(135); %Axis 5
                deg2rad(-360) deg2rad(360)]; %Axis 6: Really Unlimited to (800? default)

%maximum absolute speed of each joint rad/s or m/s
robot.velmax = [deg2rad(331); %Axis 1, rad/s
                deg2rad(332); %Axis 2, rad/s
                deg2rad(450); %Axis 3, rad/s
                deg2rad(450); %Axis 4, rad/s
                deg2rad(450); %Axis 5, rad/s
                deg2rad(720)];%Axis 6, rad/s

robot.accelmax=robot.velmax/0.1; % 0.1 is here an acceleration time

% end effectors maximum velocity
robot.linear_velmax = 1; %m/s

%base reference system
robot.T0 = [1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1]; %%cambiar para dar la vuelta?

%INITIALIZATION OF VARIABLES REQUIRED FOR THE SIMULATION
%position, velocity and acceleration
robot=init_sim_variables(robot);
robot.path = pwd;

% GRAPHICS
robot.graphical.has_graphics=1;
robot.graphical.color = [255 102 51]./255;
%for transparency
robot.graphical.draw_transparent=1;
%draw DH systems
robot.graphical.draw_axes=1;
%DH system length and Font size, standard is 1/10. Select 2/20, 3/30 for
%bigger robots
robot.graphical.axes_scale=1;
%adjust for a default view of the robot
robot.axis=[-0.5 1 -0.5 1 0 1];
%read graphics files
robot = read_graphics(robot);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DYNAMIC PARAMETERS
%   WARNING! These parameters do not correspond to the actual IRB 140
%   robot. They have been introduced to demonstrate the necessity of
%   simulating the robot and should be used only for educational purposes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
robot.has_dynamics=1;

%consider friction in the computations
robot.dynamics.friction=0;

%link masses (kg)
robot.dynamics.masses=[22 13 6 5 2 1];

%COM of each link with respect to own reference system
robot.dynamics.r_com=[0       0          0; %(rx, ry, rz) link 1
                     -0.05	 0.006	 0.1; %(rx, ry, rz) link 2
                    -0.0203	-0.0141	 0.070;  %(rx, ry, rz) link 3
                     0       0.019       0;%(rx, ry, rz) link 4
                     0       0           0;%(rx, ry, rz) link 5
                     0       0         0.032];%(rx, ry, rz) link 6

%Inertia matrices of each link with respect to its D-H reference system.
% Ixx	Iyy	Izz	Ixy	Iyz	Ixz, for each row
robot.dynamics.Inertia=[0      0.35	0   	0	0	0;
    .13     .524	.539	0	0	0;
    .066	.086	.0125	0	0	0;
    1.8e-3	1.3e-3	1.8e-3	0	0	0;
    .3e-3	.4e-3	.3e-3	0	0	0;
    .15e-3	.15e-3	.04e-3	0	0	0];

robot.motors=load_motors([5 5 5 4 4 4]);
%Speed reductor at each joint
robot.motors.G=[300 300 300 300 300 300];


function res = ge(a,b)
%GE           Implements  a >= b  for slopes, compares only a.r and b.r
%

% written  12/06/98     S.M. Rump
% modified 09/28/01     S.M. Rump  matrices and multi-dimensional arrays
% modified 04/04/04     S.M. Rump  set round to nearest for safety
% modified 04/06/05     S.M. Rump  rounding unchanged
%

  if ~isa(a,'slope')
    asize = size(a);
    bsize = b.size;
    res = ( a(:)>=b.r(:,1) );
  elseif ~isa(b,'slope')
    asize = a.size;
    bsize = size(b);
    res = ( a.r(:,1)>=b(:) );
  else
    asize = a.size;
    bsize = b.size;
    res = ( a.r(:,1)>=b.r(:,1) );
  end

  if ~isequal(asize,bsize) & ( prod(asize)~=1 ) & ( prod(bsize)~=1 )
    error('incompatible size for slope >= ')
  end

  if prod(asize)==1
    res = reshape(res,bsize);
  else
    res = reshape(res,asize);
  end


function prob = sedumi2opti(prob)
%SEDUMI2OPTI  Converts a SEDUMI Problem (At, b, C, K) to OPTI Format
% prob = sedumi2opti(prob)

%   Copyright (C) 2013 Jonathan Currie (I2C2)

if(~isfield(prob,'sdcone') || isempty(prob.sdcone) || ~isstruct(prob.sdcone))
    error('This function expects a prob.sdcone to contain a structure');
end
sdcone = prob.sdcone;
if((~isfield(sdcone,'A') && ~isfield(sdcone,'At')) || ~isfield(sdcone,'b') || (~isfield(sdcone,'C') && ~isfield(sdcone,'c')) || ~isfield(sdcone,'K'))
    error('This function expects prob.sdcone to contain the fields At (or A), b, C and K');
end
if(~isstruct(sdcone.K))
    error('SeDuMi prob.sdcone.K must be a structure!');
end
if(~isfield(sdcone.K,'s') && ~isfield(sdcone.K,'l'))
    error('SeDuMi prob.sdcone.K must contain the fields l or s (or both)');
end
if(isfield(sdcone.K,'f')), error('SeDuMi free variables are not supported in this interface - use SeDuMi directly to solve!'); end
if(isfield(sdcone.K,'q')), error('SeDuMi SOCP constraints are not supported in this interface - use SeDuMi directly to solve!'); end
if(isfield(sdcone.K,'r')), error('SeDuMi rotated cone constraints are not supported in this interface - use SeDuMi directly to solve!'); end
if(isfield(sdcone.K,'scomplex') || isfield(sdcone.K,'ycomplex') || isfield(sdcone.K,'xcomplex'))
    error('Complex variables are not supported in this interface - use SeDuMi to solve!');
end

%Read SeDuMi problem, convert to OPTI standard primal form
% MINIMIZE   dot(f,x) SUCH THAT  SUM A_i*x_i - C >= 0.
top = 1; dims = 0;
haveSDP = false; haveLP = false;
K = sdcone.K;
if(isfield(sdcone,'C'))
    c = sdcone.C;
else
    c = sdcone.c;
end
if(isfield(sdcone,'A'))
    A = sdcone.A;
else
    A = sdcone.At;
end
b = full(sdcone.b);

%Check c, b is a vector
if(size(c,2) > 1 && size(c,1) > 1)
    error('SeDuMi c field must be a column vector!');
end
if(size(b,2) > 1 && size(b,1) > 1)
    error('SeDuMi b field must be a column vector!');
end

%Flip A based on b dimensions
if(size(A,2) ~= length(sdcone.b))
    if(size(A,1) == length(sdcone.b))
        A = A';
    else
        error('SeDuMi A (At) appears to  have incorrect dimensions.\nExpected one dimension of A to be the same as length as %s.','b');
    end
end
if(size(c,2) > size(c,1))
    c = c';
end
%Check length of C against A
if(length(c) ~= size(A,1))
    error('SeDuMi c does not have the same number of elements as rows in A (At)');
end
%Check dims entered in K
if(isfield(K,'s') && ~isempty(K.s) && K.s(1) > 0)
    haveSDP = true;
    dims = dims + sum(K.s.^2);
end
if(isfield(K,'l') && ~isempty(K.l) && K.l(1) > 0)
    if(length(K.l) > 1)
        error('The SeDuMi K.l field must contain a scalar, the number of linear constraints');
    end
    haveLP = true;
    dims = dims + K.l;
end
%Check dims against rows
if(dims ~= size(A,1))
    error('SeDuMi A (At) does not have correct dimensions as per the specifications in K. Expected %d rows.',dims);
end

%Extract Objective
prob.f = full(-b);

%Extract Linear Constraints
if(haveLP)
    n = K.l;
    if(isfield(prob,'A') && ~isempty(prob.A)) %concatenate
        prob.A = [prob.A; A(top:top+n-1,:)];
        prob.b = full([prob.b; prob.c(top:top+n-1,:)]);
    else
        prob.A = A(top:top+n-1,:);
        prob.b = full(c(top:top+n-1,:));
    end
    top = top+n;
end
%Extract Semidefinite Constraints
if (haveSDP)
    prob.sdcone = cell(length(K.s),1);
    for i = 1:length(K.s)
        n = K.s(i);
        prob.sdcone{i} = [-c(top:top+n^2-1,:) -A(top:top+n^2-1,:)];
        top = top+n^2;
    end
else
    prob.sdcone = [];
end


function H= stimutil_drawArrow(direction, varargin)
%STIMUTIL_DRAWARROW - Draw a thick arrow
%
%Synopsis:
% H= stimutil_drawArrow(DIRECTION, 'Prop1', VALUE1, ...)
%
%Arguments:
% DIRECTION: Derection of the arrow. Format is either a scalar
%   corresponding to a clock (3, 6, 9, 12), or a string ('right',
%   'down', 'left', 'up').
% Optional Properties:
%  'arrow_size': Size of the arrow in the units of the axis
%  'arrow_width': Width of the arrow's line, relative to arrow_size.
%  'arrow_blunt': Width of the arrow's blunt edges, relative to arrow_size.
%     Use 0 for sharp edges. Default: 0 if 'cross'=0, else 0.1.
%  'arrow_color': Default: 0.8*[1 1 1]
%  'arrow_edgecolor': Default 'none'.
%  'cross': Switch to superimpose a fiaxtion cross; Default: 0
%  'cross_size': Size of the cross, relative to arrow_size
%  'cross_width': Width of the cross' line, relative to arrow_size
%  'cross_color': Default: Color of the figure.
%  'cross_edgecolor': Default: 'none'.
%
%Returns
% H: Struct of handles of the graphical objects

% 11-2007 Benjamin Blankertz

props= {'arrow_size'        0.3           '!DOUBLE[1]'
        'arrow_width'       0.2           '!DOUBLE[1]'
        'arrow_blunt'       0             '!DOUBLE[1]'
        'arrow_tip_blunt'   0             '!DOUBLE[1]'
        'arrow_color'       0.8*[1 1 1]   '!DOUBLE[1 3]'
        'arrow_edgecolor'   'none'        'CHAR'
        'cross'             0             'BOOL'
        'cross_size'        0.2           '!DOUBLE[1]'
        'cross_width'       0.03          '!DOUBLE[1]'
        'cross_color'       0*[1 1 1]     '!DOUBLE[1 3]'
        'cross_edgecolor'   'none'        'CHAR'
       };

if nargin==0,
  H= props; return;
end

opt= opt_proplistToStruct(varargin{:});
opt= opt_setDefaults(opt, props, 1);

x= opt.arrow_size;
w= x*opt.arrow_width;
b= x*opt.arrow_blunt;
t= x*opt.arrow_tip_blunt;

%xpr= [0 x 0 0 -x+w -x+w 0];
%ypr= [x 0 -x -w -w w w];
xpr= [b x x b -b -b -x+w -x+w -b -b];
ypr= [x t -t -x -x -w -w w w x];
switch(direction),
 case {'up','tongue',0,12},
  xp= ypr;
  yp= xpr;
 case {'right',3},
  xp= xpr;
  yp= ypr;
 case {'down','foot',6},
  xp= -ypr;
  yp= -xpr;
 case {'left',9},
  xp= -xpr;
  yp= -ypr;
 otherwise,
  error('invalid direction: use 3, 6, 9, 12; or ''right'', ''down'', ...');
end

H.arrow= patch(xp, yp, opt.arrow_color);
set(H.arrow, 'EdgeColor', opt.arrow_edgecolor);

if opt.cross,
  c= x*opt.cross_size;
  v= x*opt.cross_width;
  H.cross= patch([v v c c v v -v -v -c -c -v -v], ...
                 [c v v -v -v -c -c -v -v v v c], opt.cross_color);
  set(H.cross, 'EdgeColor', opt.cross_edgecolor);
end


function extractSTPerframeFtrs(outdir,ftrs,stationary,flowname,params)

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

ff = fields(ftrs);

% Initialize the struct for features of all the frames
for fnum = 1:numel(ff)
  curf = ff{fnum};
  if strcmp(curf,'hogftrs')
    pfname = 'hf';
  elseif strcmp(curf,'flowftrs') && stationary
    pfname = [flowname 's'];
  elseif strcmp(curf,'flowftrs') && ~stationary
    pfname = flowname;
  else
    error('Unknown feature type');
  end
  ny = size(ftrs.(curf){1},1);
  nx = size(ftrs.(curf){1},2);
  nb = size(ftrs.(curf){1},3);
  psz = params.psize;
  for yy = 1:ny
    for xx = 1:nx
      for oo = 1:nb
        perframe = struct;
        perframe.units.num = {};
        perframe.units.den = {'s'};
        for fly = 1:numel(ftrs.(ff{fnum}))
          tt = ftrs.(ff{fnum}){fly}(yy,xx,oo,:);
          perframe.data{fly} = tt(:);
        end
        perframe_name = sprintf('st_%s_%02d_%02d_%d_ny%d_nx%d_ns%d',pfname,yy,xx,oo,ny,nx,psz);
        perframe.params = params;
        outfilename = fullfile(outdir,perframe_name);
        save(outfilename,'-struct','perframe','-v7.3');
      end
    end
  end
end


function imdb = setup_imdb_generic(datasetDir, varargin)

opts.seed = 0 ;             % random seed generator
opts.ratio = [0.7 0.3];     % train:val ratio
opts.ext = '.jpg';          % extension of target files
opts.per_class_limit = inf; % inf indicates no limit
opts = vl_argparse(opts, varargin);

opts.ratio = opts.ratio(1:2)/sum(opts.ratio(1:2));
rng(opts.seed);
imdb.imageDir = datasetDir;

% meta
fprintf('Scanning for classes ... ');
contents = dir(imdb.imageDir);
contents_name = {contents.name};
imdb.meta.classes = setdiff(contents_name(cell2mat({contents.isdir})),{'.','..'});
imdb.meta.sets = {'train', 'val', 'test'};
fprintf('%d classes found! \n', numel(imdb.meta.classes));

% images
imdb.images.name    = {};
imdb.images.class   = [];
imdb.images.set     = [];
fprintf('Scanning for images: \n');
for c = imdb.meta.classes,
  c = c{1};
  fprintf('\t%s ...', c);
  contents = dir(fullfile(imdb.imageDir,c,['*' opts.ext]));
  curr_name = cellfun(@(s) fullfile(c,s),{contents.name},'UniformOutput',false);
  curr_name = curr_name(1:min(numel(curr_name),opts.per_class_limit));
  imdb.images.name = [imdb.images.name curr_name];
  imdb.images.class = [imdb.images.class ones(1,numel(curr_name))*find(strcmp(imdb.meta.classes,c))];
  curr_set = ones(1,floor(opts.ratio(1)*numel(curr_name)));
  curr_set = [curr_set 2*ones(1,numel(curr_name)-numel(curr_set))];
  imdb.images.set = [imdb.images.set curr_set(randperm(numel(curr_set)))];
  fprintf(' done!\n');
end

% id
imdb.images.id = 1:length(imdb.images.name);


function [scr_dev_pav,scr_eval_pav] = pav_calibrate_scores_dev_eval(scr_dev,scr_eval,key_dev,ndx_eval,prior,score_offset,addzeros)
% A function to calibrate a set of scores (eval) using another set
% as reference (dev).  The function requires a key for the dev
% scores (supervised) and an ndx for the eval scores
% (unsupervised).  It trains a PAV transformation and then applies
% the transformation to both sets of scores.  Comparing the act_dcf
% and min_dcf values at the operating point gives an indication of
% the success of the calibration (assuming the score distribution
% is the same in the two sets --- if not, don't bother calibrating).
% Inputs:
%   scr_dev: The development scores.
%   scr_eval: The eval scores.
%   key_dev: The Key for the development scores i.e. must have
%     'tar' and 'non' fields.
%   ndx_eval: The Ndx for the eval scores i.e. must have a
%     'trialmask' field.
%   prior: The effective target prior.
%   score_offset: This is used to make the transform monotonically
%     increasing by tilting each flat portion of the PAV output.
%     The tilt is controlled by this value, and making it zero
%     results in no tilt.
%   addzeros: If true, missing scores (required by key but not
%     present in scr) are added (with value zero).
% Outputs:
%   scr_dev_pav: The calibrated development scores.
%   scr_eval_pav: The calibrated eval scores.

assert(nargin==7)
assert(isa(scr_dev,'Scores'))
assert(isa(scr_eval,'Scores'))
assert(isa(key_dev,'Key'))
assert(isa(ndx_eval,'Ndx'))
assert(scr_dev.validate())
assert(scr_eval.validate())
assert(key_dev.validate())
assert(ndx_eval.validate())

[tar,non] = scr_dev.get_tar_non(key_dev);
logprint(Logger.Info,'training calibration\n')
pav_trans = pav_calibration(tar,non,score_offset);

logprint(Logger.Info,'calibrating scores\n')
scr_dev_pav = scr_dev.align_with_ndx(key_dev);
scr_eval_pav = scr_eval.align_with_ndx(ndx_eval);

scr_dev_pav = scr_dev_pav.transform(pav_trans);
scr_eval_pav = scr_eval_pav.transform(pav_trans);

logprint(Logger.Info,'displaying calibration results\n')
res = Results(scr_dev_pav,key_dev);
logprint(Logger.Info,'norm_act_dcf = %g, norm_min_dcf = %g, prbep = %g\n',res.get_norm_act_dcf(prior),res.get_norm_min_dcf(prior),res.get_prbep());

if addzeros
    scr_dev_pav = scr_dev_pav.set_missing_to_value(key_dev,0.0);
    scr_eval_pav = scr_eval_pav.set_missing_to_value(ndx_eval,0.0);
end

assert(scr_dev_pav.validate())
assert(scr_eval_pav.validate())

end


function [tdiff, ac]  = timediff(clus_idx, look_ahead_time, clus, eqtimes)
    % TIMEDIFF calculates the time difference between the ith and jth event
    % works with variable eqtime from function CLUSTIME
    % gives the indices ac of the eqs not already related to cluster k1
    % eqtimes should be sorted!
    %
    % clus_idx : ith cluster (ci)
    % look_ahead : look-ahead time (tau)
    % clus: clusters (length of catalog)
    % eqtimes: datetimes for event catalog, in days  [did not use duration because of overhead]
    %
    % tdiff: is time between jth event and eqtimes(clus_idx)
    % ac: index of each event within the cluster

    comparetime = eqtimes(clus_idx);

    first_event = clus_idx + 1; % in cluster
    last_event = numel(eqtimes);
    max_elapsed = comparetime + look_ahead_time;

    if eqtimes(end) >= max_elapsed
        last_event = find(eqtimes(first_event : last_event) < max_elapsed, 1, 'last') + clus_idx;
    end

    tdiff = eqtimes(first_event : last_event) - comparetime;

    if first_event == last_event
        % no additional events were found.
        ac = [];
    else

        this_clusternum = clus(clus_idx);

        if this_clusternum == 0
            ac = first_event:last_event;
        else
            % indices of eqs not already related to this cluster
            ac = (find(clus(first_event : last_event) ~= this_clusternum)) + clus_idx;
        end
    end
    ac = ac(:);
end


function [attnInfo] = attnLayerForward(h_t, params, model, attnData, maskInfo)
%
% Attentional Layer: from lstm hidden state to softmax hidden state.
% Input:
%   attnData: require attnData.srcHidVecsOrig and attnData.srcLens
%
% Thang Luong @ 2015, <lmthang@stanford.edu>
%
  assert(params.attnFunc>0); % we should have enabled attention.

  attnInfo = [];
  if params.attnGlobal % global
    srcHidVecs = attnData.srcHidVecsOrig;
    attnInfo.srcMaskedIds = find(attnData.srcMask(:, 1:params.numSrcHidVecs)'==0); % numSrcHidVecs * curBatchSize
  else % local
    % positions
    if params.attnLocalPred % predictive alignments
      [mu, attnInfo] = regressPositions(model, h_t, attnData.srcLens, params);
      srcPositions = floor(mu);
    else % monotonic alignments
      srcPositions = attnData.tgtPos*ones(1, params.curBatchSize);
      flags = srcPositions>(attnData.srcLens-1);
      srcPositions(flags) = attnData.srcLens(flags)-1;
    end

    % assert
    if params.assert
      assert(isempty(find(srcPositions<1,1)));
      assert(isempty(find(attnData.tgtLens<=1,1)));
      assert(isempty(find(srcPositions(maskInfo.unmaskedIds)>(attnData.srcLens(maskInfo.unmaskedIds)-1),1)));
    end

    % reverse
    if params.isReverse
      srcPositions = params.srcMaxLen - srcPositions;
    end

    % build context vectors
    [srcHidVecs, attnInfo] = buildSrcVecs(attnData.srcHidVecsOrig, srcPositions, maskInfo, attnData.srcLens, params.srcMaxLen, params, attnInfo);

    attnInfo.srcMaskedIds = find(attnInfo.alignMask==0);
  end % end else if attnGlobal

  % compute alignScores: numAttnPositions * curBatchSize
  % TODO: precompute for attnOpt2 and attnOpt3 (we can premultiply srcHidVecs with W_a (attnOpt2) or W_a_src (attnOpt3)
  if params.attnOpt==1 || params.attnOpt==2 % dot product or general dot product
    if params.attnOpt==1 % dot product
      [alignScores] = srcCompareLayerForward(srcHidVecs, h_t, params);
    elseif params.attnOpt==2 % general dot product
      attnInfo.transform_ht = model.W_a * h_t; % TODO: shift the multiplication to srcHidVecs
      [alignScores] = srcCompareLayerForward(srcHidVecs, attnInfo.transform_ht, params);
    end
  elseif params.attnOpt==3 % Bengio's style
    % f(H_src + W_a*h_t): lstmSize * (curBatchSize * numAttnPositions))
    attnInfo.src_ht_hid = reshape(params.nonlinear_f(bsxfun(@plus, srcHidVecs, model.W_a*h_t)), params.lstmSize, []);

    % v_a * src_ht_hid
    alignScores = linearLayerForward(model.v_a, attnInfo.src_ht_hid); % 1 * (curBatchSize * numAttnPositions)
    alignScores = reshape(alignScores, params.curBatchSize, params.numAttnPositions)'; % numAttnPositions * curBatchSize
  end

  if params.attnLocalPred && params.normLocalAttn % new approach for local attention after EMNLP'15
    [attnInfo.distWeights, attnInfo.scaleX] = distLayerForward(mu, attnInfo, params); % numAttnPositions*curBatchSize
    attnInfo.unNormAlignWeights =  alignScores .* attnInfo.distWeights; % weighted by distances
    attnInfo.alignWeights = normLayerForward(attnInfo.unNormAlignWeights, attnInfo.srcMaskedIds);
    attnInfo.alignScores = alignScores;
  else
    % normalize -> alignWeights
    attnInfo.alignWeights = normLayerForward(alignScores, attnInfo.srcMaskedIds);

    % local, regression, multiply with distWeights
    if params.attnLocalPred
      [attnInfo.distWeights, attnInfo.scaleX] = distLayerForward(mu, attnInfo, params); % numAttnPositions*curBatchSize
      attnInfo.preAlignWeights = attnInfo.alignWeights;
      attnInfo.alignWeights = attnInfo.preAlignWeights.* attnInfo.distWeights; % weighted by distances
    end
  end

  % assert
  if params.assert
    assert(computeSum(attnInfo.alignWeights(attnInfo.srcMaskedIds), params.isGPU)==0);
  end

  attnInfo.alignWeights(:, maskInfo.maskedIds) = 0;
  % alignWeights, srcHidVecs -> contextVecs
  [contextVecs] = contextLayerForward(attnInfo.alignWeights, srcHidVecs, maskInfo.unmaskedIds, params);

  % f(W_h*[context_t; h_t])
  attnInfo.input = [contextVecs; h_t];
  attnInfo.h_t = h_t;
  softmax_h = hiddenLayerForward(model.W_h, attnInfo.input, params.nonlinear_f);
  attnInfo.softmax_h = softmax_h; % attentional vectors

  % assert
  if params.assert
    assert(isequal(size(attnInfo.alignWeights), [params.numAttnPositions, params.curBatchSize]));
    assert(isequal(size(h_t), size(contextVecs))); % lstmSize * curBatchSize
  end
end

function [mu, h2sInfo] = regressPositions(model, h_t, srcLens, params)
  % h_t -> scales=sigmoid(v_pos*f(W_pos*h_t)) in [0, 1]
  [h2sInfo.scales, h2sInfo.posForwData] = scaleLayerForward(model.W_pos, model.v_pos, h_t, params);

  % scales -> srcPositions
  mu = h2sInfo.scales.*(srcLens-1) + 1;
end


%% How to load the data
clear all;
DataFolder = '\\feevault\data0-shared\shared\EmilyShijieShared\CaExtraction\IsolatePreTut\6991';
cnmfeFilePath = fullfile('\\feevault\data0-shared\shared\EmilyShijieShared\CaExtraction\IsolatePreTut\6991', 'CNMFE_BatchVer.mat');
load(fullfile(DataFolder, 'singinginfo.mat'))
load(cnmfeFilePath)
%% compile
L = 1; % units of seconds
SONGfs = 1/diff(singinginfo(1).SpecTime(1:2));
VIDEOfs = singinginfo(1).VIDEOfs;
GCDfs = gcd(SONGfs,VIDEOfs); % for alignment
Lsong = L*SONGfs;
Lneural = L*VIDEOfs;
% for each file
% drop long gaps from spectrogram and neural
% concatenate song and neural, and keep track of new seg times
% do extraction

Fnums = 1:length(singinginfo);
compSONG = [];
compNEURO = [];

for fi = 1:length(Fnums)
    filei = Fnums(fi);
    RawSong = singinginfo(filei).SongSpec;
    RawNeural =  neuron_batch(filei).DeconvSpiketrain(:,:);
    RawNeural(isnan(RawNeural)) = 0; % deconv sometimes makes nans

    [N,T] = size(RawNeural);

    if length(singinginfo(filei).segs)>0
        % take out long gaps, only truncating at GCDfs (so alignment
        % consistent)
        bouts = SegsToBouts(singinginfo(filei).segs,.05*singinginfo(filei).SOUNDfs);
        onsetTimes = ceil(bouts(:,1)*GCDfs/singinginfo(filei).SOUNDfs);
        offsetTimes = floor(bouts(:,2)*GCDfs/singinginfo(filei).SOUNDfs);

        % take out long gaps in neural
        NEURAL1 = [];
        for segi = 1:length(onsetTimes)
            onsetTime =onsetTimes(segi)*VIDEOfs/GCDfs+1;
            offsetTime =offsetTimes(segi)*VIDEOfs/GCDfs;
            % expand spectrogram at syll onset
            NEURAL1 = [NEURAL1 RawNeural(:,onsetTime:offsetTime)];
        end
        NEURAL = NEURAL1;
%         FirstOfFileNeuro(fi) = size(compNEURO,2)+1;
        compNEURO = [compNEURO NEURAL];

        % take out long gaps in song
        SONG1 = [];
        for segi = 1:length(onsetTimes)
            onsetTime = onsetTimes(segi)*SONGfs/GCDfs+1;
            offsetTime = offsetTimes(segi)*SONGfs/GCDfs;
            % expand spectrogram at syll onset
            SONG1 = [SONG1  RawSong(:,onsetTime:offsetTime)];
        end
        SONG = SONG1;
%         FirstOfFileSong(fi) = size(compSONG,2)+1;
        compSONG = [compSONG SONG];
        figure(5); imagesc(compSONG); drawnow; shg
    end
end
NEURAL = compNEURO;
SONG = compSONG;
%
NEURAL = NEURAL./(prctile(NEURAL,100,2)+prctile(NEURAL(:),95));
SONG = compSONG;
SONG = SONG-prctile(SONG(:),70); SONG(SONG<0)=0;
SONG = SONG/max(SONG(:));

%%
save('C:\Users\emackev\Documents\MATLAB\seqnmf\MackeviciusData.mat', ...
    'NEURAL', 'SONG', 'SONGfs', 'VIDEOfs')


function [F,mptmissing] = filter_enumeration(F_xw,Zmodel,x,w,ops,uncertaintyTypes,separatedZmodel,VariableType)

mptmissing = 0;
if length(F_xw) == 0
    F = [];
    return;
else

    if any(Zmodel.K.q) | any(Zmodel.K.s)
        error('Only polytope uncertainty supported in duality based robustification');
    else
        if isempty(intersect(depends(F_xw),getvariables(w)))
            F = F_xw;
        elseif length(uncertaintyTypes)==1 & isequal(uncertaintyTypes{1},'inf-norm')

            if any(isinf((separatedZmodel{1}.lb))) | any(isinf(separatedZmodel{1}.ub))
                error('You have unbounded uncertain variables')
            else
                n = length(separatedZmodel{1}.lb);
                vertices = [];
                lb = separatedZmodel{1}.lb(:)';
                ub = separatedZmodel{1}.ub(:)';
                E = dec2bin(0:2^n-1,n)';
                E = double(E(:))-48;
                E = reshape(E,n,2^n);
                vertices = (repmat(lb(:),1,2^n) + E.*(repmat(ub(:),1,2^n)-repmat(lb(:),1,2^n)))';
                %for i = 0:2^n-1
                %    vertices = [vertices;lb+dec2decbin(i,n).*(ub-lb)];
                %end
                if ops.verbose
                    disp([' - Enumerated ' num2str(2^n) ' vertices'])
                end
                vertices = unique(vertices,'rows');
                if ops.verbose & 2^n > size(vertices,1)
                    disp([' - Reduced to ' num2str( size(vertices,1)) ' unique vertices'])
                end
                F = replaceVertices(F_xw,w,vertices',VariableType,ops);
            end

        elseif length(uncertaintyTypes)==1 & isequal(uncertaintyTypes{1},'simplex')

            k = abs(Zmodel.F_struc(1,1));
            n = length(w);

            vertices = zeros(n,1);
            for i = 1:n
                v = zeros(n,1);
                v(i) = k;
                vertices = [vertices v];
            end
            if ops.verbose
                disp([' - Enumerated ' num2str(n) ' vertices'])
            end
            vertices = pruneequalities(vertices,Zmodel);
            F = replaceVertices(F_xw,w,vertices,VariableType,ops);

        else
            % FIX : Assumes all uncertainty in all constraints
            K = Zmodel.K;
            A = -Zmodel.F_struc((1+K.f):(K.f + K.l),2:end);
            b =  Zmodel.F_struc((1+K.f):(K.f + K.l),1);

            % Some preprocessing to extract bounds from equality
            % constraints in order to make the uncertainty polytope
            % bounded (required since we are going to run vertex
            % enumeration)
            % We might have x>=0, sum(x)=1, and this code simply extracts
            % the implied bounds x<=1
            [lo,up] = find_lp_bounds(Zmodel.F_struc(1:K.f + K.l,:),K);
            Zmodel.lb = lo;Zmodel.ub = up;
            Zmodel = propagate_bounds_from_equalities(Zmodel);
            up = Zmodel.ub;
            lo = Zmodel.lb;
            upfi = find(~isinf(up));
            lofi = find(~isinf(lo));
            aux = Zmodel;
            aux.F_struc = [aux.F_struc;-lo(lofi) sparse(1:length(lofi),lofi,1,length(lofi),size(A,2))];
            aux.F_struc = [aux.F_struc;up(upfi) -sparse(1:length(upfi),upfi,1,length(upfi),size(A,2))] ;
            aux.K.l = aux.K.l + length(lofi) + length(upfi);
            K = aux.K;
            A = -aux.F_struc((1+K.f):(K.f + K.l),2:end);
            b =  aux.F_struc((1+K.f):(K.f + K.l),1);

            % Extract equalities Ex == f and project
            % Bunch of try-catch definsive as this assumes MPT
            % If fails we try internal crappy enumerator
            P = [];
            if any(K.f)
                f = aux.F_struc(1:K.f,1);
                E = -full(aux.F_struc(1:K.f,2:end));
                En = null(E);
                x0 = (E\f);
                % x = null(E)*z + x0, A*(null(E)*z + x0) <= b
                b = full(b-A*x0);
                A = full(A*En);
                try
                    P = polytope(A,b);
                catch
                end
            else
                x0 = zeros(size(A,2),1);
                En = eye(size(A,2));
                try
                    P = polytope(full(A),full(b));
                catch
                end
            end
            if ~isempty(P)
                try
                    vertices = extreme(P)';
                catch
                    error('The uncertainty space is unbounded (could be an artefact of YALMIPs modelling of nonolinear oeprators).')
                end
            else
                if ~all(b>0)
                    % Crappy enumeration requires feasible point
                    [x_c,R] = chebyball(A*sdpvar(size(A,2),1) <= b);
                else
                    x_c = zeros(size(A,2),1);
                end
                vertices = vertexenumerate(A,b,x_c);
                % This simply gives "nicer" models sometimes
                % First step in cleaning below too
                really_integer = abs(vertices(:)-round(vertices(:)))<eps;
                vertices(really_integer) = round(vertices(really_integer));
            end
            % Map back to original variables
            vertices = repmat(x0,1,size(vertices,2)) + En*vertices;

            % The vertex enumeration was done without any equality constraints.
            % We know check all vertices so see if they satisfy equalities.
            vertices = pruneequalities(vertices,Zmodel);
            if ops.verbose
                disp([' - Enumerated ' num2str(size(vertices,2)) ' vertices'])
            end
            F = replaceVertices(F_xw,w,vertices,VariableType,ops);
        end
    end
end

function F = replaceVertices(F_xw,w,vertices,VariableType,ops)
% Doing LP constraints in a vectorized manner saves a lot of time

F_xw_lp = F_xw(find(is(F_xw,'elementwise')));
F_xw_socp_sdp = F_xw -  F_xw_lp;
F = ([]);

x_Flp = depends(F_xw_lp);
uncAux = yalmip('auxvariablesW');
uncAux = recover(intersect(x_Flp,VariableType.aux_with_w_dependence));
if isequal(ops.robust.auxreduce,'none')
    uncAux = [];
end

if length(F_xw_lp)>0
    rLP = [];
    if ~isempty(uncAux)
        z = sdpvar(repmat(length(uncAux),1,size(vertices,2)),repmat(1,1,size(vertices,2)),'full');
    end
    for i = 1:size(vertices,2)
        temp = replace(sdpvar(F_xw_lp),w,vertices(:,i),0);
        if ~isempty(uncAux)
            temp = replace(temp,uncAux,z{i});
        end
        rLP = [rLP;temp];
    end

    % FIXME: More general detection of silly constraints
    if isa(rLP,'double') & all(rLP>=-eps^0.75)
        F = ([]);
    else
        % Easily generates redundant constraints
        [aux,index] = uniquesafe(getbase(rLP),'rows');
        try
            F = (rLP(index(randperm(length(index)))) >= 0);
        catch
            1
        end
    end
end

% Remaining conic stuff
for j = 1:length(F_xw_socp_sdp)
    for i = 1:size(vertices,2)
        temp = replace(F_xw_socp_sdp(j),w,vertices(:,i),0);
        if ~isempty(uncAux)
            temp = replace(temp,uncAux,z{i});
        end
        F = F + lmi(temp);
    end
end

function vertices = pruneequalities(vertices,Zmodel)
K = Zmodel.K;
% The vertex enumeration was done without any equality constraints.
% We know check all vertices so see if they satisfy equalities.
if any(K.f)
    Aeq = -Zmodel.F_struc(1:K.f,2:end);
    beq =  Zmodel.F_struc(1:K.f,1);
    feasible = sum(abs(Aeq*vertices - repmat(beq,1,size(vertices,2))),1) < 1e-6;
    vertices = vertices(:,feasible);
    if isempty(feasible)
        error('The uncertainty space is infeasible.')
    end
end


function c=xcorr(c,varargin)

% C = XCORR(C)
% This function calculates and fills in the correlation and lag fields in a
% correlation object. The input is a correlation object, presumeably with
% empty correlation and lag fields. c.C is a matrix of maximum correlation
% values normalized so that autocorrelations are 1. c.L is the lag time in
% between the two waveforms required for maximum correlation. To acheive
% maximum alignment, the value in position (i,j) should be added to the
% trigger time of trace j, or subtracted from trigger i. Traces can be
% aligned with the routine ADJUSTTRIG.
%
% By default, peak cross correlation values and lag times are NOT
% interpolated for sub-sample lag time because this requires a 30-40%
% increase in CPU time. For some uses, such as relative earthquake
% locations and coda wave interferometry, such precision is necessary. In
% these cases, consider the INTERP option below.
%
% C = XCORR(C,[PRETRIG POSTTRIG]);
% Perform cross correlation on a cropped portion of the data only. This is
% useful when you wish to keep the entire waveform but align the traces based on
% the correlation of a particular wavelet. PRETRIG and POSTTRIG are the
% time in seconds relative to the trigger time. Note that PRETRIG is
% negative for times before the trigger.
%
% C = XCORR(C,...,'1xr') Use single trace against one row algorithm
% (default).
%
% C = XCORR(C,...,'interp') Perform 2nd-order polynomial fitting to
% estimate sub-sample lag time. Sub-sample alignment requires an addition
% 30-40% CPU time but results in highest precision lag times possible.
%
% C = XCORR(C,...,'row',INDEX) Run correlation only on the traces specified
% by INDEX. Each trace of INDEX is correlated against the entire set of
% waveforms. This is useful if a small number of traces has been added to a
% large correlation matrix. Insead of recomputing the entire correlation
% and lag matrices, the routine allows only the "added" lines to be filled
% in. The syntax is a bit clunky. This routine requires the 'row' algorithm
% and the INDEX list. The two must be used together. Polynomial
% interpolation of lag values is always used with this algorithm.
%
%
% -- DEPRICATED ALGORITHMS ---------------------------------------------
% Because these algorithms seem to have little or no advantages over the
% '1xr' algorithm they will likely not be updated or improved.
%
% C = XCORR(C,...,'dec') Same as 1xr but decomposes complex numbers for
% calculation. Mathworks suggests this approach may be faster in some
% circumstances. However, initial testing found it slower that the 1xr
% algorithm.
%
% C = XCORR(C,...,'1x1') Use single trace against single trace algorithm.
% Conceivably faster when memory is very limited. In practice I have yet to
% encounter a situation where this algorithm benchmarks faster than the
% 1xr.

% Author: Michael West, Geophysical Institute, Univ. of Alaska Fairbanks
% $Date$
% $Revision$

% GET INPUT PARAMETERS
if ~isa(c,'correlation')
    disp('First input parameter must be a correlation object');
end
algorithm = '1xr';
c1 = correlation;
c1 = set(c1,'WAVEFORM', get(c,'WAVEFORM') );
c1 = set(c1,'TRIG', get(c,'TRIG') );

% CHECK FOR TRACE SUBSET
if length(varargin)>1
    if isa(varargin{end},'double')
        index = varargin{end};
        varargin = varargin(1:end-1);
    end;
end;

    % CHECK ALGORITHM
if ~isempty(varargin)
    if ischar(varargin{end})
        algorithm = lower(varargin{end});
        varargin = varargin(1:end-1);
    end;
end;

    % APPLY CROPPING
if ~isempty(varargin)
    if length(varargin{end})==2       % check for cropping values
        pretrig =  varargin{1}(1);
        posttrig = varargin{1}(2);
        c1 = crop(c,pretrig,posttrig);
    end
end;

% CREATE MATRIX OF DATA FROM WAVEFORM ARRAY
% The correlation object is modified here into a Matlab structure that
% shares similar fields to the object except that the the trace data is
% stored in a matrix instead of in a waveform object. This structure is
% passed to the correlation subroutines as 'd'. The matrix structure
% improves computation speed because fft and other routines are optomized
% for matrices. This structure is based on the correlation object version
% 0.
d.start = get(c1.W,'START_MATLAB');
d.Fs    = get(c1.W(1),'Fs');
d.trig  = c1.trig;
d.w = double(c1.W);
% d.w     = [];
% for i = 1:length(c1.W)
%     d.w(:,i) = get(c1.W(i),'DATA');
% end;
clear c1

% EXECUTE CROSS CORRELATION
if exist('pretrig','var') && exist('posttrig','var')
    disp(['using ' algorithm ' algorithm on the time interval [' num2str(pretrig) ' ' num2str(posttrig) '] ...' ]);
else
    %disp(['using ' algorithm ' algorithm ...']);
end
if strcmp(algorithm,'1x1')==1
	d = xcorr1x1(d);
  elseif strcmp(algorithm,'1xr')
  	d = xcorr1xr(d,0);
  elseif strncmpi(algorithm,'int',3)
  	d = xcorr1xr(d,1);
  elseif strcmp(algorithm,'dec')
  	d = xcorrdec(d);
  elseif strcmp(algorithm,'row')
  	d = xcorrrow(d,c,index);
else
    error('Correlation algorithm not recognized');
end;

% ASSIGN CORRELATION PARAMETERS TO ORIGINAL DATA
c = set( c , 'CORR' , d.C );
c = set( c , 'LAG'  , d.L  );
clear d