function varargout = gradient_field_GUI(varargin)
% GRADIENT_FIELD_GUI M-file for gradient_field_GUI.fig
%      GRADIENT_FIELD_GUI, by itself, creates a new GRADIENT_FIELD_GUI or raises the existing
%      singleton*.
%
%      H = GRADIENT_FIELD_GUI returns the handle to a new GRADIENT_FIELD_GUI or the handle to
%      the existing singleton*.
%
%      GRADIENT_FIELD_GUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in GRADIENT_FIELD_GUI.M with the given input arguments.
%
%      GRADIENT_FIELD_GUI('Property','Value',...) creates a new GRADIENT_FIELD_GUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before gradient_field_GUI_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to gradient_field_GUI_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

% Edit the above text to modify the response to help gradient_field_GUI

% Last Modified by GUIDE v2.5 11-Sep-2012 12:13:24

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @gradient_field_GUI_OpeningFcn, ...
                   'gui_OutputFcn',  @gradient_field_GUI_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
% End initialization code - DO NOT EDIT


% --- Executes just before gradient_field_GUI is made visible.
function gradient_field_GUI_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 gradient_field_GUI (see VARARGIN)

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

% Update handles structure
guidata(hObject, handles);

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

% P R E S E T S

global RHS
global f
global x_min 
global x_max 
global y_min 
global y_max 
global h
global delta
global x0
global y0

% Define the RHSfunc of the first order ODE : y' = RHSfunc(x,y).
RHS =  @(x,y) y;
set(handles.RHSfunc,'string','y');
% Define the analytic solution
f = @(x) exp(x);
set(handles.analsol,'string','exp(x)');
% Preset h
h = 0.3;
set(handles.stepsizeFE,'string','0.3');

% Preset delta (for field lines)
delta = 0.1; %This decides how dense the field lines are going to be.
set(handles.edit8,'string','0.1');
% Limit axes
x_min = 0;
x_max = 2;
y_min = 1;
y_max = 8;
set(handles.xinf,'string','0');
set(handles.xsup,'string','2');
set(handles.yinf,'string','1');
set(handles.ysup,'string','8');

%Initial conditions
x0 = 0;
y0 = 1;
set(handles.xin,'string','0');
set(handles.yin,'string','1');
end

% --- Outputs from this function are returned to the command line.
function varargout = gradient_field_GUI_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;
end


function xinf_Callback(hObject, eventdata, handles)
% hObject    handle to xinf (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of xinf as text
%        str2double(get(hObject,'String')) returns contents of xinf as a double
getUserInput(handles);
end

% --- Executes during object creation, after setting all properties.
function xinf_CreateFcn(hObject, eventdata, handles)
% hObject    handle to xinf (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
end


function xsup_Callback(hObject, eventdata, handles)
% hObject    handle to xsup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of xsup as text
%        str2double(get(hObject,'String')) returns contents of xsup as a double
getUserInput(handles);
end

% --- Executes during object creation, after setting all properties.
function xsup_CreateFcn(hObject, eventdata, handles)
% hObject    handle to xsup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
end


function yinf_Callback(hObject, eventdata, handles)
% hObject    handle to yinf (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of yinf as text
%        str2double(get(hObject,'String')) returns contents of yinf as a double
getUserInput(handles);
end

% --- Executes during object creation, after setting all properties.
function yinf_CreateFcn(hObject, eventdata, handles)
% hObject    handle to yinf (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
end


function ysup_Callback(hObject, eventdata, handles)
% hObject    handle to ysup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of ysup as text
%        str2double(get(hObject,'String')) returns contents of ysup as a double
getUserInput(handles);
end

% --- Executes during object creation, after setting all properties.
function ysup_CreateFcn(hObject, eventdata, handles)
% hObject    handle to ysup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
end


function RHSfunc_Callback(hObject, eventdata, handles)
% hObject    handle to RHSfunc (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of RHSfunc as text
%        str2double(get(hObject,'String')) returns contents of RHSfunc as a double
getUserInput(handles);
end

% --- Executes during object creation, after setting all properties.
function RHSfunc_CreateFcn(hObject, eventdata, handles)
% hObject    handle to RHSfunc (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
end


function analsol_Callback(hObject, eventdata, handles)
% hObject    handle to analsol (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of analsol as text
%        str2double(get(hObject,'String')) returns contents of analsol as a double
getUserInput(handles);
end

% --- Executes during object creation, after setting all properties.
function analsol_CreateFcn(hObject, eventdata, handles)
% hObject    handle to analsol (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
end

% --- Executes on button press in pushbuttonfieldlines.
function pushbuttonfieldlines_Callback(hObject, eventdata, handles)
% hObject    handle to pushbuttonfieldlines (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global gradlines
cla
axes(handles.axes1)
plotgradlines
gradlines = 1;
end
 
% --- Executes on button press in pushbuttonanimation.
function pushbuttonanimation_Callback(hObject, eventdata, handles)
% hObject    handle to pushbuttonanimation (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global gradlines
global stopper
h = get(hObject,'string');

switch h
    case 'Start animation'
        stopper = 'go';
        set(hObject,'string','Stop animation')
        axes(handles.axes1)
        cla
        if gradlines == 1
            plotgradlines
        end
        plotgraphs(handles)        
    case 'Stop animation'
        set(hObject,'string','Start animation')
        stopper = 'stop';
end
end

function plotgradlines
global RHS
global x_min 
global x_max 
global y_min 
global y_max 
global delta

% Define # points.
N = (x_max - x_min)/delta;
M = (y_max - y_min)/delta;

% Construct matrix of RHSfunc(x,y) 
for i = 1:N + 1
   for j = 1:M + 1
      A(i,j) = RHS(x_min + (i-1)*delta, y_min + (j-1)*delta);
   end
end

% Create axes
axis([x_min x_max y_min y_max]);
axis square

% Plot gradient lines at each point
r = delta; % length of the lines
hold on
for i = 1:N + 1
   for j = 1:M + 1
      x = x_min + (i-1)*delta; 
      y = y_min + (j-1)*delta;
      x_down = x + r/sqrt(1 + A(i,j)^2); 
      x_up = x - r/sqrt(1 + A(i,j)^2);
      y_down = y - A(i,j)*(x - x_down); 
      y_up = y - A(i,j)*(x - x_up);
   	  plot([x_down x x_up],[y_down y y_up],'color',[0.7 0.7 0.7],'linewidth',1.4)   
   end
end
end

function plotgraphs(handles)
global RHS
global f
global x_min 
global x_max 
global y_min 
global y_max 
global h
global stopper
global x0
global y0
% Use Forward Euler

% Compute # of steps between x_min and x_max
N_steps = ceil((x_max - x_min)/h);

% Initial conditions
x(1) = x0;
y(1) = y0;

for i = 1:N_steps
    x(i+1) = x(1) + h*i;
    y(i+1) = y(i) + h*RHS(x(i),y(i));
end

% Create axes
axis([x_min x_max y_min y_max]);
axis square

%Plot analytic function and FE approximation
hold on
for i = 1: N_steps
    if strcmp(stopper,'stop')
        break
    elseif strcmp(stopper,'go')
        a(1) = plot([x(i) x(i+1)] ,[f(x(i)) f(x(i+1))] ,'r -','linewidth',1.3);
        a(2) = plot([x(i) x(i+1)] ,[y(i) y(i+1)],'b -','linewidth',1.2);
        legend(a,'Analytic solution','Forward Euler',2);
        drawnow
    end
end

set(handles.pushbuttonanimation,'string','Start animation')
end



function stepsizeFE_Callback(hObject, eventdata, handles)
% hObject    handle to stepsizeFE (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of stepsizeFE as text
%        str2double(get(hObject,'String')) returns contents of stepsizeFE as a double
getUserInput(handles);
end

% --- Executes during object creation, after setting all properties.
function stepsizeFE_CreateFcn(hObject, eventdata, handles)
% hObject    handle to stepsizeFE (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
end


function edit8_Callback(hObject, eventdata, handles)
% hObject    handle to edit8 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of edit8 as text
%        str2double(get(hObject,'String')) returns contents of edit8 as a double
getUserInput(handles);
end

% --- Executes during object creation, after setting all properties.
function edit8_CreateFcn(hObject, eventdata, handles)
% hObject    handle to edit8 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
end


% --- Executes during object creation, after setting all properties.
function axes1_CreateFcn(hObject, eventdata, handles)
% hObject    handle to axes1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: place code in OpeningFcn to populate axes1
end



function xin_Callback(hObject, eventdata, handles)
% hObject    handle to xin (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of xin as text
%        str2double(get(hObject,'String')) returns contents of xin as a double
getUserInput(handles);
end
% --- Executes during object creation, after setting all properties.
function xin_CreateFcn(hObject, eventdata, handles)
% hObject    handle to xin (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
end


function yin_Callback(hObject, eventdata, handles)
% hObject    handle to yin (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of yin as text
%        str2double(get(hObject,'String')) returns contents of yin as a double
getUserInput(handles);
end
% --- Executes during object creation, after setting all properties.
function yin_CreateFcn(hObject, eventdata, handles)
% hObject    handle to yin (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
end


% --- Executes on button press in closebutton.
function closebutton_Callback(hObject, eventdata, handles)
% hObject    handle to closebutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
close(handles.figure1)
end

function getUserInput(handles)
global x_min
global x_max
global y_min
global y_max
global x0
global y0
global RHS
global gradlines
global delta
global f
global h
try

    x_min = str2double(get(handles.xinf,'String'));
    assert(~isnan(x_min) && isreal(x_min) && ~isinf(x_min),...
        'Invalid minimum x value!');

    x_max = str2double(get(handles.xsup,'String'));
    assert(~isnan(x_max) && isreal(x_max) && ~isinf(x_max),...
        'Invalid maximum x value!');

    assert(x_min<x_max,'Invalid x range!');


    y_min = str2double(get(handles.yinf,'String'));
    assert(~isnan(y_min) && isreal(y_min) && ~isinf(y_min),...
        'Invalid minimum y value!');

    y_max = str2double(get(handles.ysup,'String'));
    assert(~isnan(y_max) && isreal(y_max) && ~isinf(y_max),...
        'Invalid maximum x value!');

    assert(x_min<x_max,'Invalid y range!');


    x0 = str2double(get(handles.xin,'string'));
    assert(~isnan(x0) && isreal(x0) && ~isinf(x0),...
        'Invalid initial x value!');

    y0 = str2double(get(handles.yin,'string'));
    assert(~isnan(y0) && isreal(y0) && ~isinf(y0),...
        'Invalid intial y value!');



    RHS = inline(get(handles.RHSfunc,'String'),'x','y');
    RHS(x0,y0); % Throw error if invalid
    gradlines = 0;

    
    delta = str2double(get(handles.edit8,'String'));
    assert(~isnan(delta) && isreal(delta) && ~isinf(delta)&& ...
        delta>0 && delta < min(x_max-x_min,y_max-y_min), ...
        'Invalid gradient field spacing!');


    f = inline(get(handles.analsol,'String'),'x');
    f(x0); % throw error if invalid


    h = str2double(get(handles.stepsizeFE,'String'));
        assert(~isnan(h) && isreal(h) && ~isinf(h)&& ...
        h>0 && h <(x_max-x_min), ...
        'Invalid step size (may be bigger than plot)!');

    set(handles.pushbuttonanimation,'Enable','on');
    set(handles.pushbuttonfieldlines,'Enable','on');
    
catch err
    waitfor(msgbox(err.message,'Error','error','modal'));
    set(handles.pushbuttonanimation,'Enable','off');
    set(handles.pushbuttonfieldlines,'Enable','off');
end
    
end
