function varargout = Hot_Spot_Simulator(varargin)
% HOT_SPOT_SIMULATOR M-file for Hot_Spot_Simulator.fig

% Author: Bart Desoete
% Copyright: AMI Semiconductor

% version 1.0: first release of the tool (June 2006)


% --- Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @Hot_Spot_Simulator_OpeningFcn, ...
                   'gui_OutputFcn',  @Hot_Spot_Simulator_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 Hot_Spot_Simulator is made visible.
function Hot_Spot_Simulator_OpeningFcn(hObject, eventdata, handles, varargin)

set (hObject, 'Name', 'Hot Spot Simulator');

handles.output = hObject;

set (handles.listbox_sources, 'String', '');
set (handles.listbox_sources, 'Value', []);
handles.index_sources = 0;

handles.init_source_struct.source_name = '';
handles.init_source_struct.source_x1 = '';
handles.init_source_struct.source_y1 = '';
handles.init_source_struct.source_x2 = '';
handles.init_source_struct.source_y2 = '';
handles.init_source_struct.source_power_low = '';
handles.init_source_struct.source_power_high = '';
handles.init_source_struct.source_delay = '';
handles.init_source_struct.source_pulse_width = '';
handles.init_source_struct.source_rise_time = '';
handles.init_source_struct.source_fall_time = '';
handles.init_source_struct.source_period = '';
handles.init_source_struct.source_time_vector = '';
handles.init_source_struct.source_power_vector = '';
handles.init_source_struct.source_filename = '';
handles.init_source_struct.radiobutton_tag = 'radiobutton_pulse';
handles.source_struct(1) = handles.init_source_struct;

set (handles.listbox_sensors, 'String', '');
set (handles.listbox_sensors, 'Value', []);
handles.index_sensors = 0;

handles.init_sensor_struct.sensor_name = get (handles.sensor_name, 'String');
handles.init_sensor_struct.sensor_x = get (handles.sensor_x, 'String');
handles.init_sensor_struct.sensor_y = get (handles.sensor_y, 'String');
handles.sensor_struct(1) = handles.init_sensor_struct;

guidata(hObject, handles);


% --- Outputs from this function are returned to the command line.
function varargout = Hot_Spot_Simulator_OutputFcn(hObject, eventdata, handles) 

% Get default command line output from handles structure
varargout{1} = handles.output;


% ------------------------------------------------------------------------
% Callbacks linked to power source definitions.
% ------------------------------------------------------------------------

% --- Executes on selection change in listbox_sources.
function listbox_sources_Callback(hObject, eventdata, handles)

index = get (handles.listbox_sources, 'Value');
if isempty (index) || index == 0
    set (handles.source_name, 'String', '');
    set (handles.source_x1, 'String', '');
    set (handles.source_y1, 'String', '');
    set (handles.source_x2, 'String', '');
    set (handles.source_y2, 'String', '');
    set (handles.source_power_low, 'String', '');
    set (handles.source_power_high, 'String', '');
    set (handles.source_delay, 'String', '');
    set (handles.source_pulse_width, 'String', '');
    set (handles.source_rise_time, 'String', '');
    set (handles.source_fall_time, 'String', '');
    set (handles.source_period, 'String', '');
    set (handles.source_time_vector, 'String', '');
    set (handles.source_power_vector, 'String', '');
    set (handles.source_filename, 'String', '');
    set (handles.uipanel_waveform, 'SelectedObject', ...
         findobj (handles.uipanel_waveform, 'Tag', 'radiobutton_pulse'));
else
    source_struct = handles.source_struct(index);
    set (handles.source_name, 'String', source_struct.source_name);
    set (handles.source_x1, 'String', source_struct.source_x1);
    set (handles.source_y1, 'String', source_struct.source_y1);
    set (handles.source_x2, 'String', source_struct.source_x2);
    set (handles.source_y2, 'String', source_struct.source_y2);
    set (handles.source_power_low, 'String', source_struct.source_power_low);
    set (handles.source_power_high, 'String', source_struct.source_power_high);
    set (handles.source_delay, 'String', source_struct.source_delay);
    set (handles.source_pulse_width, 'String', source_struct.source_pulse_width);
    set (handles.source_rise_time, 'String', source_struct.source_rise_time);
    set (handles.source_fall_time, 'String', source_struct.source_fall_time);
    set (handles.source_period, 'String', source_struct.source_period);
    set (handles.source_time_vector, 'String', source_struct.source_time_vector);
    set (handles.source_power_vector, 'String', source_struct.source_power_vector);
    set (handles.source_filename, 'String', source_struct.source_filename);
    set (handles.uipanel_waveform, 'SelectedObject', ...
         findobj (handles.uipanel_waveform, 'Tag', source_struct.radiobutton_tag));
end;
uipanel_waveform_SelectionChangeFcn(hObject, eventdata, handles);

guidata (hObject, handles);


% --- Executes on button press in pushbutton_new_source.
function pushbutton_new_source_Callback(hObject, eventdata, handles)

names_sources = get (handles.listbox_sources, 'String');
number_sources = size (names_sources, 1);
number_sources = number_sources + 1;
index_sources = handles.index_sources + 1;
name_source = ['source' int2str(index_sources)];
names_sources{number_sources,1} = name_source;
set (handles.listbox_sources, 'String', names_sources, ...
                              'Value', number_sources);
set (handles.source_name, 'String', name_source);
handles.index_sources = index_sources;
if number_sources == 1
    handles.source_struct = handles.init_source_struct;
    handles.source_struct.source_name = name_source;
else
    handles.source_struct(number_sources) = handles.init_source_struct;
    handles.source_struct(number_sources).source_name = name_source;
end;
listbox_sources_Callback (hObject, eventdata, handles);

guidata (hObject, handles);


% --- Executes on button press in pushbutton_copy_source.
function pushbutton_copy_source_Callback(hObject, eventdata, handles)

index = get (handles.listbox_sources, 'Value');
names_sources = get (handles.listbox_sources, 'String');
number_sources = size (names_sources, 1);
if number_sources == 0
    errordlg ('No sources to copy !', 'Error Dialog', 'modal');
else
    number_sources = number_sources + 1;
    index_sources = handles.index_sources + 1;
    name_source = ['source' int2str(index_sources)];
    names_sources{number_sources,1} = name_source;
    set (handles.listbox_sources, 'String', names_sources, ...
                                  'Value', number_sources);
    set (handles.source_name, 'String', name_source);
    handles.index_sources = index_sources;
    handles.source_struct(number_sources) = handles.source_struct(index);
    handles.source_struct(number_sources).source_name = name_source;
    listbox_sources_Callback (hObject, eventdata, handles);
end;

guidata (hObject, handles);


% --- Executes on button press in pushbutton_remove_source.
function pushbutton_remove_source_Callback(hObject, eventdata, handles)

index = get (handles.listbox_sources, 'Value');
names_sources = get (handles.listbox_sources, 'String');
number_sources = size (names_sources, 1);
if number_sources == 0
    errordlg ('No sources to remove !', 'Error Dialog', 'modal');
elseif number_sources == 1
    names_sources = {};
    handles.source_struct = [];
    set (handles.listbox_sources, 'String', names_sources, ...
                                  'Value', 0);
    name_source = '';
    set (handles.source_name, 'String', name_source);
    handles.source_struct(index).source_name = name_source;
    listbox_sources_Callback (hObject, eventdata, handles);
elseif index == number_sources
    names_sources(index) = [];
    handles.source_struct(index) = [];
    set (handles.listbox_sources, 'String', names_sources, ...
                                  'Value', index-1);
    name_source = names_sources{index-1};
    set (handles.source_name, 'String', name_source);
    handles.source_struct(index).source_name = name_source;
    listbox_sources_Callback (hObject, eventdata, handles);
else
    names_sources(index) = [];
    handles.source_struct(index) = [];
    set (handles.listbox_sources, 'String', names_sources, ...
                                  'Value', index);
    name_source = names_sources{index};
    set (handles.source_name, 'String', name_source);
    handles.source_struct(index).source_name = name_source;
    listbox_sources_Callback (hObject, eventdata, handles);
end;

guidata (hObject, handles);


% --- Executes after change of source_name.
function source_name_Callback(hObject, eventdata, handles)

name_source = get (handles.source_name, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    names_sources = get (handles.listbox_sources, 'String');
    names_sources{index} = name_source;
    set (handles.listbox_sources, 'String', names_sources);
    handles.source_struct(index).source_name = name_source;
end;
listbox_sources_Callback (hObject, eventdata, handles);

guidata (hObject, handles);


% --- Executes after change of source_x1.
function source_x1_Callback(hObject, eventdata, handles)

source_x1_string = get (handles.source_x1, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_x1 = source_x1_string;
    source_x1 = str2num (source_x1_string);
    if (~isscalar (source_x1) || ~isreal (source_x1) || source_x1 < 0) && ...
        ~isempty (source_x1_string)
        errordlg ('Source coordinate x1 should be a positive real number !', ...
                  'Error Dialog', 'modal');
    end;
end;
    
guidata (hObject, handles);


% --- Executes after change of source_y1.
function source_y1_Callback(hObject, eventdata, handles)

source_y1_string = get (handles.source_y1, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_y1 = source_y1_string;
    source_y1 = str2num (source_y1_string);
    if (~isscalar (source_y1) || ~isreal (source_y1) || source_y1 < 0) && ...
        ~isempty (source_y1_string)
        errordlg ('Source coordinate y1 should be a positive real number !', ...
                  'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_x2.
function source_x2_Callback(hObject, eventdata, handles)

source_x2_string = get (handles.source_x2, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_x2 = source_x2_string;
    source_x2 = str2num (source_x2_string);
    if (~isscalar (source_x2) || ~isreal (source_x2) || source_x2 < 0) && ...
        ~isempty (source_x2_string)
        errordlg ('Source coordinate x2 should be a positive real number !', ...
                  'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_y2.
function source_y2_Callback(hObject, eventdata, handles)

source_y2_string = get (handles.source_y2, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_y2 = source_y2_string;
    source_y2 = str2num (source_y2_string);
    if (~isscalar (source_y2) || ~isreal (source_y2) || source_y2 < 0) && ...
        ~isempty (source_y2_string)
        errordlg ('Source coordinate y2 should be a positive real number !', ...
                  'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of waveform type.
function uipanel_waveform_SelectionChangeFcn(hObject, eventdata, handles)

radiobutton_tag = get (get (handles.uipanel_waveform, 'SelectedObject'), 'Tag');
grey = [0.8314 0.8157 0.7843];
switch radiobutton_tag
    case 'radiobutton_pulse'
        set (handles.source_power_low, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.source_power_high, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.source_delay, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.source_pulse_width, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.source_rise_time, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.source_fall_time, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.source_period, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.text_power_low, 'Enable', 'on');
        set (handles.text_power_high, 'Enable', 'on');
        set (handles.text_delay, 'Enable', 'on');
        set (handles.text_pulse_width, 'Enable', 'on');
        set (handles.text_rise_time, 'Enable', 'on');
        set (handles.text_fall_time, 'Enable', 'on');
        set (handles.text_period, 'Enable', 'on');
        set (handles.source_time_vector, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_power_vector, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.text_time_vector, 'Enable', 'off');
        set (handles.text_power_vector, 'Enable', 'off');
        set (handles.source_filename, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.pushbutton_load_data, 'Enable', 'off');
    case 'radiobutton_pwl'
        set (handles.source_power_low, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_power_high, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_delay, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_pulse_width, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_rise_time, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_fall_time, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_period, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.text_power_low, 'Enable', 'off');
        set (handles.text_power_high, 'Enable', 'off');
        set (handles.text_delay, 'Enable', 'off');
        set (handles.text_pulse_width, 'Enable', 'off');
        set (handles.text_rise_time, 'Enable', 'off');
        set (handles.text_fall_time, 'Enable', 'off');
        set (handles.text_period, 'Enable', 'off');
        set (handles.source_time_vector, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.source_power_vector, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.text_time_vector, 'Enable', 'on');
        set (handles.text_power_vector, 'Enable', 'on');
        set (handles.source_filename, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.pushbutton_load_data, 'Enable', 'off');
    case 'radiobutton_datafile'
        set (handles.source_power_low, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_power_high, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_delay, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_pulse_width, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_rise_time, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_fall_time, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_period, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.text_power_low, 'Enable', 'off');
        set (handles.text_power_high, 'Enable', 'off');
        set (handles.text_delay, 'Enable', 'off');
        set (handles.text_pulse_width, 'Enable', 'off');
        set (handles.text_rise_time, 'Enable', 'off');
        set (handles.text_fall_time, 'Enable', 'off');
        set (handles.text_period, 'Enable', 'off');
        set (handles.source_time_vector, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.source_power_vector, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.text_time_vector, 'Enable', 'off');
        set (handles.text_power_vector, 'Enable', 'off');
        set (handles.source_filename, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.pushbutton_load_data, 'Enable', 'on');
end;

index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).radiobutton_tag = radiobutton_tag;
end;

guidata (hObject, handles);


% --- Executes after change of source_power_low.
function source_power_low_Callback(hObject, eventdata, handles)

source_power_low_string = get (handles.source_power_low, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_power_low = source_power_low_string;
    source_power_low = str2num (source_power_low_string);
    if (~isscalar (source_power_low) || ~isreal (source_power_low) || source_power_low < 0) && ...
        ~isempty (source_power_low_string)
        errordlg ('Low power level should be a positive real number !', 'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_power_high.
function source_power_high_Callback(hObject, eventdata, handles)

source_power_high_string = get (handles.source_power_high, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_power_high = source_power_high_string;
    source_power_high = str2num (source_power_high_string);
    if (~isscalar (source_power_high) || ~isreal (source_power_high) || source_power_high <= 0) && ...
        ~isempty (source_power_high_string)
        errordlg ('High power level should be a strictly positive real number !', 'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_delay.
function source_delay_Callback(hObject, eventdata, handles)

source_delay_string = get (handles.source_delay, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_delay = source_delay_string;
    source_delay = str2num (source_delay_string);
    if (~isscalar (source_delay) || ~isreal (source_delay) || source_delay < 0) && ...
        ~isempty (source_delay_string)
        errordlg ('Delay should be a positive real number !', 'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_pulse_width.
function source_pulse_width_Callback(hObject, eventdata, handles)

source_pulse_width_string = get (handles.source_pulse_width, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_pulse_width = source_pulse_width_string;
    source_pulse_width = str2num (source_pulse_width_string);
    if (~isscalar (source_pulse_width) || ~isreal (source_pulse_width) || source_pulse_width < 0) && ...
        ~isempty (source_pulse_width_string)
        errordlg ('Pulse width should be a positive real number !', 'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_rise_time.
function source_rise_time_Callback(hObject, eventdata, handles)

source_rise_time_string = get (handles.source_rise_time, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_rise_time = source_rise_time_string;
    source_rise_time = str2num (source_rise_time_string);
    if (~isscalar (source_rise_time) || ~isreal (source_rise_time) || source_rise_time < 0) && ...
        ~isempty (source_rise_time_string)
        errordlg ('Rise time should be a positive real number !', 'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_fall_time.
function source_fall_time_Callback(hObject, eventdata, handles)

source_fall_time_string = get (handles.source_fall_time, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_fall_time = source_fall_time_string;
    source_fall_time = str2num (source_fall_time_string);
    if (~isscalar (source_fall_time) || ~isreal (source_fall_time) || source_fall_time < 0) && ...
        ~isempty (source_fall_time_string)
        errordlg ('Fall time should be a positive real number !', 'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_period.
function source_period_Callback(hObject, eventdata, handles)

source_period_string = get (handles.source_period, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_period = source_period_string;
    source_period = str2num (source_period_string);
    if (~isscalar (source_period) || ~isreal (source_period) || source_period <= 0) && ...
        ~isempty (source_period_string)
        errordlg ('Period should be a strictly positive real number !', 'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_time_vector.
function source_time_vector_Callback(hObject, eventdata, handles)

source_time_vector_string = get (handles.source_time_vector, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_time_vector = source_time_vector_string;
    source_time_vector = str2num (source_time_vector_string);
    if (~isvector (source_time_vector) || any (source_time_vector < 0)) && ...
        ~isempty (source_time_vector_string)
        errordlg ('Time vector should be a list of positive real numbers !', 'Error Dialog', 'modal');
    elseif ~all (source_time_vector == sort (source_time_vector, 'ascend'))
        errordlg ('Time vector should be in ascending order !', 'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_power_vector.
function source_power_vector_Callback(hObject, eventdata, handles)

source_power_vector_string = get (handles.source_power_vector, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_power_vector = source_power_vector_string;
    source_power_vector = str2num (source_power_vector_string);
    if (~isvector (source_power_vector) || any (source_power_vector < 0)) && ...
        ~isempty (source_power_vector_string)
        errordlg ('Power vector should be a list of positive real numbers !', 'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% --- Executes after change of source_filename.
function source_filename_Callback(hObject, eventdata, handles)

source_filename = get (handles.source_filename, 'String');
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_filename = source_filename;
end;

guidata (hObject, handles);


% --- Executes on button press in pushbutton_load_data.
function pushbutton_load_data_Callback(hObject, eventdata, handles)

[file, path] = uigetfile ('*.*', 'Load two-column data file (time and power vector)');
source_filename = [path file];
if file ~= 0
    set (handles.source_filename, 'String', source_filename);
end;
index = get (handles.listbox_sources, 'Value');
if ~isempty (index) && index > 0
    handles.source_struct(index).source_filename = source_filename;
end;

guidata (hObject, handles);


% ------------------------------------------------------------------------
% Callbacks linked to sensor definitions.
% ------------------------------------------------------------------------

% --- Executes on selection change in listbox_sensors.
function listbox_sensors_Callback(hObject, eventdata, handles)

index = get (handles.listbox_sensors, 'Value');
if isempty (index) || index == 0
    set (handles.sensor_name, 'String', '');
    set (handles.sensor_x, 'String', '');
    set (handles.sensor_y, 'String', '');
else
    sensor_struct = handles.sensor_struct(index);
    set (handles.sensor_name, 'String', sensor_struct.sensor_name);
    set (handles.sensor_x, 'String', sensor_struct.sensor_x);
    set (handles.sensor_y, 'String', sensor_struct.sensor_y);
end;

guidata (hObject, handles);


% --- Executes on button press in pushbutton_new_sensor.
function pushbutton_new_sensor_Callback(hObject, eventdata, handles)

names_sensors = get (handles.listbox_sensors, 'String');
number_sensors = size (names_sensors, 1);
number_sensors = number_sensors + 1;
index_sensors = handles.index_sensors + 1;
name_sensor = ['sensor' int2str(index_sensors)];
names_sensors{number_sensors,1} = name_sensor;
set (handles.listbox_sensors, 'String', names_sensors, ...
                              'Value', number_sensors);
set (handles.sensor_name, 'String', name_sensor);
handles.index_sensors = index_sensors;
if number_sensors == 1
    handles.sensor_struct = handles.init_sensor_struct;
    handles.sensor_struct.sensor_name = name_sensor;
else
    handles.sensor_struct(number_sensors) = handles.init_sensor_struct;
    handles.sensor_struct(number_sensors).sensor_name = name_sensor;
end;
listbox_sensors_Callback (hObject, eventdata, handles);

guidata (hObject, handles);


% --- Executes on button press in pushbutton_copy_sensor.
function pushbutton_copy_sensor_Callback(hObject, eventdata, handles)

index = get (handles.listbox_sensors, 'Value');
names_sensors = get (handles.listbox_sensors, 'String');
number_sensors = size (names_sensors, 1);
if number_sensors == 0
    errordlg ('No sensors to copy !', 'Error Dialog', 'modal');
else
    number_sensors = number_sensors + 1;
    index_sensors = handles.index_sensors + 1;
    name_sensor = ['sensor' int2str(index_sensors)];
    names_sensors{number_sensors,1} = name_sensor;
    set (handles.listbox_sensors, 'String', names_sensors, ...
                                  'Value', number_sensors);
    set (handles.sensor_name, 'String', name_sensor);
    handles.index_sensors = index_sensors;
    handles.sensor_struct(number_sensors) = handles.sensor_struct(index);
    handles.sensor_struct(number_sensors).sensor_name = name_sensor;
    listbox_sensors_Callback (hObject, eventdata, handles);
end;

guidata (hObject, handles);


% --- Executes on button press in pushbutton_remove_sensor.
function pushbutton_remove_sensor_Callback(hObject, eventdata, handles)

index = get (handles.listbox_sensors, 'Value');
names_sensors = get (handles.listbox_sensors, 'String');
number_sensors = size (names_sensors, 1);
if number_sensors == 0
    errordlg ('No sensors to remove !', 'Error Dialog', 'modal');
elseif number_sensors == 1
    names_sensors = {};
    handles.sensor_struct = [];
    set (handles.listbox_sensors, 'String', names_sensors, ...
                                  'Value', 0);
    name_sensor = '';
    set (handles.sensor_name, 'String', name_sensor);
    handles.sensor_struct(index).sensor_name = name_sensor;
    listbox_sensors_Callback (hObject, eventdata, handles);
elseif index == number_sensors
    names_sensors(index) = [];
    handles.sensor_struct(index) = [];
    set (handles.listbox_sensors, 'String', names_sensors, ...
                                  'Value', index-1);
    name_sensor = names_sensors{index-1};
    set (handles.sensor_name, 'String', name_sensor);
    handles.sensor_struct(index).sensor_name = name_sensor;
    listbox_sensors_Callback (hObject, eventdata, handles);
else
    names_sensors(index) = [];
    handles.sensor_struct(index) = [];
    set (handles.listbox_sensors, 'String', names_sensors, ...
                                  'Value', index);
    name_sensor = names_sensors{index};
    set (handles.sensor_name, 'String', name_sensor);
    handles.sensor_struct(index).sensor_name = name_sensor;
    listbox_sensors_Callback (hObject, eventdata, handles);
end;

guidata (hObject, handles);


% --- Executes after change of sensor_name.
function sensor_name_Callback(hObject, eventdata, handles)

name_sensor = get (handles.sensor_name, 'String');
index = get (handles.listbox_sensors, 'Value');
if ~isempty (index) && index > 0
    names_sensors = get (handles.listbox_sensors, 'String');
    names_sensors{index} = name_sensor;
    set (handles.listbox_sensors, 'String', names_sensors);
    handles.sensor_struct(index).sensor_name = name_sensor;
end;
listbox_sensors_Callback (hObject, eventdata, handles);

guidata (hObject, handles);


% --- Executes after change of sensor_x.
function sensor_x_Callback(hObject, eventdata, handles)

sensor_x_string = get (handles.sensor_x, 'String');
index = get (handles.listbox_sensors, 'Value');
if ~isempty (index) && index > 0
    handles.sensor_struct(index).sensor_x = sensor_x_string;
    sensor_x = str2num (sensor_x_string);
    if (~isscalar (sensor_x) || ~isreal (sensor_x) || sensor_x < 0) && ...
        ~isempty (sensor_x_string)
        errordlg ('Sensor coordinate x should be a positive real number !', ...
                  'Error Dialog', 'modal');
    end;
end;
    
guidata (hObject, handles);


% --- Executes after change of sensor_y.
function sensor_y_Callback(hObject, eventdata, handles)

sensor_y_string = get (handles.sensor_y, 'String');
index = get (handles.listbox_sensors, 'Value');
if ~isempty (index) && index > 0
    handles.sensor_struct(index).sensor_y = sensor_y_string;
    sensor_y = str2num (sensor_y_string);
    if (~isscalar (sensor_y) || ~isreal (sensor_y) || sensor_y < 0) && ...
        ~isempty (sensor_y_string)
        errordlg ('Sensor coordinate y should be a positive real number !', ...
                  'Error Dialog', 'modal');
    end;
end;

guidata (hObject, handles);


% ------------------------------------------------------------------------
% Callbacks linked to die size definitions.
% ------------------------------------------------------------------------

% --- Executes after change of die_x2.
function die_x2_Callback(hObject, eventdata, handles)

die_x2_string = get (handles.die_x2, 'String');
die_x2 = str2num (die_x2_string);
if (~isscalar (die_x2) || ~isreal (die_x2) || die_x2 <= 0) && ...
    ~isempty (die_x2_string)
    errordlg ('Die coordinate x2 should be a strictly positive real number !', ...
              'Error Dialog', 'modal');
else
    set (handles.sim_x2, 'String', die_x2_string);
end;

guidata (hObject, handles);


% --- Executes after change of die_y2.
function die_y2_Callback(hObject, eventdata, handles)

die_y2_string = get (handles.die_y2, 'String');
die_y2 = str2num (die_y2_string);
if (~isscalar (die_y2) || ~isreal (die_y2) || die_y2 <= 0) && ...
    ~isempty (die_y2_string)
    errordlg ('Die coordinate y2 should be a strictly positive real number !', ...
              'Error Dialog', 'modal');
else
    set (handles.sim_y2, 'String', die_y2_string);
end;

guidata (hObject, handles);


% ------------------------------------------------------------------------
% Callbacks linked to simulation setup.
% ------------------------------------------------------------------------

% --- Executes after change of waveform type.
function uipanel_simulation_SelectionChangeFcn(hObject, eventdata, handles)

radiobutton_tag = get (get (handles.uipanel_simulation, 'SelectedObject'), 'Tag');
grey = [0.8314 0.8157 0.7843];
switch radiobutton_tag
    case 'radiobutton_distribution'
        set (handles.distribution_time_vector, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.gridcells_x, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.gridcells_y, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.sim_x1, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.sim_y1, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.sim_x2, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.sim_y2, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.text_distribution_time_vector, 'Enable', 'on');
        set (handles.text_x_axis, 'Enable', 'on');
        set (handles.text_y_axis, 'Enable', 'on');
        set (handles.text_grid_cells, 'Enable', 'on');
        set (handles.text_sim_x1, 'Enable', 'on');
        set (handles.text_sim_y1, 'Enable', 'on');
        set (handles.text_sim_x2, 'Enable', 'on');
        set (handles.text_sim_y2, 'Enable', 'on');
        set (handles.evolution_time_vector, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.text_evolution_time_vector, 'Enable', 'off');
    case 'radiobutton_evolution'
        set (handles.distribution_time_vector, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.gridcells_x, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.gridcells_y, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.sim_x1, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.sim_y1, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.sim_x2, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.sim_y2, 'Enable', 'off', 'BackgroundColor', grey);
        set (handles.text_distribution_time_vector, 'Enable', 'off');
        set (handles.text_x_axis, 'Enable', 'off');
        set (handles.text_y_axis, 'Enable', 'off');
        set (handles.text_grid_cells, 'Enable', 'off');
        set (handles.text_sim_x1, 'Enable', 'off');
        set (handles.text_sim_y1, 'Enable', 'off');
        set (handles.text_sim_x2, 'Enable', 'off');
        set (handles.text_sim_y2, 'Enable', 'off');
        set (handles.evolution_time_vector, 'Enable', 'on', 'BackgroundColor', 'White');
        set (handles.text_evolution_time_vector, 'Enable', 'on');
end;


% --- Executes after change of distribution_time_vector.
function distribution_time_vector_Callback(hObject, eventdata, handles)

distribution_time_vector_string = get (handles.distribution_time_vector, 'String');
distribution_time_vector = str2num (distribution_time_vector_string);
if (~isvector (distribution_time_vector) || any (distribution_time_vector <= 0)) && ...
    ~isempty (distribution_time_vector_string)
    errordlg ('Simulation time vector should be a list of strictly positive real numbers !', 'Error Dialog', 'modal');
elseif max (distribution_time_vector) > 1
    warndlg ('Above around 1 second simulations may deviate from reality due to package effects, which are not taken into account !', ...
             'Warning Dialog', 'modal');
end;

guidata (hObject, handles);


% --- Executes after change of gridcells_x.
function gridcells_x_Callback(hObject, eventdata, handles)

gridcells_x_string = get (handles.gridcells_x, 'String');
gridcells_x = str2num (gridcells_x_string);
if (~isscalar (gridcells_x) || gridcells_x ~= floor(gridcells_x) || gridcells_x <= 0) && ...
    ~isempty (gridcells_x_string)
    errordlg ('Number of grid cells in x-direction should be a strictly positive integer number !', 'Error Dialog', 'modal');
end;

guidata (hObject, handles);


% --- Executes after change of gridcells_y.
function gridcells_y_Callback(hObject, eventdata, handles)

gridcells_y_string = get (handles.gridcells_y, 'String');
gridcells_y = str2num (gridcells_y_string);
if (~isscalar (gridcells_y) || gridcells_y ~= floor(gridcells_y) || gridcells_y <= 0) && ...
    ~isempty (gridcells_y_string)
    errordlg ('Number of grid cells in y-direction should be a strictly positive integer number !', 'Error Dialog', 'modal');
end;

guidata (hObject, handles);


% --- Executes after change of sim_x1.
function sim_x1_Callback(hObject, eventdata, handles)

sim_x1_string = get (handles.sim_x1, 'String');
sim_x1 = str2num (sim_x1_string);
if (~isscalar (sim_x1) || ~isreal (sim_x1) || sim_x1 < 0) && ...
    ~isempty (sim_x1_string)
    errordlg ('Grid coordinate x1 should be a positive real number !', ...
              'Error Dialog', 'modal');
end;

guidata (hObject, handles);


% --- Executes after change of sim_y1.
function sim_y1_Callback(hObject, eventdata, handles)

sim_y1_string = get (handles.sim_y1, 'String');
sim_y1 = str2num (sim_y1_string);
if (~isscalar (sim_y1) || ~isreal (sim_y1) || sim_y1 < 0) && ...
    ~isempty (sim_y1_string)
    errordlg ('Grid coordinate y1 should be a positive real number !', ...
              'Error Dialog', 'modal');
end;

guidata (hObject, handles);


% --- Executes after change of sim_x2.
function sim_x2_Callback(hObject, eventdata, handles)

sim_x2_string = get (handles.sim_x2, 'String');
sim_x2 = str2num (sim_x2_string);
if (~isscalar (sim_x2) || ~isreal (sim_x2) || sim_x2 < 0) && ...
    ~isempty (sim_x2_string)
    errordlg ('Grid coordinate x2 should be a positive real number !', ...
              'Error Dialog', 'modal');
end;

guidata (hObject, handles);


% --- Executes after change of sim_y2.
function sim_y2_Callback(hObject, eventdata, handles)

sim_y2_string = get (handles.sim_y2, 'String');
sim_y2 = str2num (sim_y2_string);
if (~isscalar (sim_y2) || ~isreal (sim_y2) || sim_y2 < 0) && ...
    ~isempty (sim_y2_string)
    errordlg ('Grid coordinate y2 should be a positive real number !', ...
              'Error Dialog', 'modal');
end;

guidata (hObject, handles);


% --- Executes after change of evolution_time_vector.
function evolution_time_vector_Callback(hObject, eventdata, handles)

evolution_time_vector_string = get (handles.evolution_time_vector, 'String');
evolution_time_vector = str2num (evolution_time_vector_string);
if (~isvector (evolution_time_vector) || any (evolution_time_vector < 0)) && ...
    ~isempty (evolution_time_vector_string)
    errordlg ('Simulation time vector should be a list of positive real numbers !', 'Error Dialog', 'modal');
elseif ~all (evolution_time_vector == sort (evolution_time_vector, 'ascend'))
    errordlg ('Simulation time vector should be in ascending order !', 'Error Dialog', 'modal');
elseif max (evolution_time_vector) > 1
    warndlg ('Above around 1 second simulations may deviate from reality due to package effects, which are not taken into account !', ...
             'Warning Dialog', 'modal');
end;

guidata (hObject, handles);


% ------------------------------------------------------------------------
% Callbacks linked to menu.
% ------------------------------------------------------------------------

% --- Executes when selecting menu item File.
function menu_file_Callback(hObject, eventdata, handles)


% --- Executes when selecting menu item File->Load state.
function menu_load_state_Callback(hObject, eventdata, handles)

[file, path] = uigetfile ('*.mat', 'Load state');
state_gui_filename = [path file];
if file ~= 0
    if all (state_gui_filename (end-3:end) == '.mat')
        state_fig_filename = [state_gui_filename(1:end-4) '.fig'];
    else
        errordlg ('File extension should be .mat !', 'Error Dialog', 'modal');
        return;
    end;
    try
        file_content = load (state_gui_filename, 'state');
    catch
        errordlg ('Invalid state file !', 'File Type Error', 'modal');
        return;
    end;
    if ~isfield (file_content, 'state')
        errordlg ('Invalid state file !', 'File Type Error', 'modal');
        return;
    end;
else
    return;
end;

set (get (get (hObject, 'Parent'), 'Parent'), 'Name', ...
     ['Hot Spot Simulator  -  ' file(1:end-4)]);

state = file_content.state;

set (handles.die_x2, 'String', state.die_x2);
set (handles.die_y2, 'String', state.die_y2);

handles.source_struct = state.source_struct;
handles.index_sources = state.index_sources;

index = state.index_listbox_sources;
if isempty (index) || index == 0
    set (handles.listbox_sources, 'String', '', 'Value', []);
    set (handles.source_name, 'String', '');
    set (handles.source_x1, 'String', '');
    set (handles.source_y1, 'String', '');
    set (handles.source_x2, 'String', '');
    set (handles.source_y2, 'String', '');
    set (handles.source_power_low, 'String', '');
    set (handles.source_power_high, 'String', '');
    set (handles.source_delay, 'String', '');
    set (handles.source_pulse_width, 'String', '');
    set (handles.source_rise_time, 'String', '');
    set (handles.source_fall_time, 'String', '');
    set (handles.source_period, 'String', '');
    set (handles.source_time_vector, 'String', '');
    set (handles.source_power_vector, 'String', '');
    set (handles.source_filename, 'String', '');
    set (handles.uipanel_waveform, 'SelectedObject', ...
         findobj (handles.uipanel_waveform, 'Tag', 'radiobutton_pulse'));
else
    for i = 1 : length(handles.source_struct)
        source_names {i,1} = handles.source_struct(i).source_name;
    end;
    set (handles.listbox_sources, 'String', source_names, ...
                                  'Value', index);
    source_struct = handles.source_struct(index);
    set (handles.source_name, 'String', source_struct.source_name);
    set (handles.source_x1, 'String', source_struct.source_x1);
    set (handles.source_y1, 'String', source_struct.source_y1);
    set (handles.source_x2, 'String', source_struct.source_x2);
    set (handles.source_y2, 'String', source_struct.source_y2);
    set (handles.source_power_low, 'String', source_struct.source_power_low);
    set (handles.source_power_high, 'String', source_struct.source_power_high);
    set (handles.source_delay, 'String', source_struct.source_delay);
    set (handles.source_pulse_width, 'String', source_struct.source_pulse_width);
    set (handles.source_rise_time, 'String', source_struct.source_rise_time);
    set (handles.source_fall_time, 'String', source_struct.source_fall_time);
    set (handles.source_period, 'String', source_struct.source_period);
    set (handles.source_time_vector, 'String', source_struct.source_time_vector);
    set (handles.source_power_vector, 'String', source_struct.source_power_vector);
    set (handles.source_filename, 'String', source_struct.source_filename);
    set (handles.uipanel_waveform, 'SelectedObject', ...
         findobj (handles.uipanel_waveform, 'Tag', source_struct.radiobutton_tag));
end;
uipanel_waveform_SelectionChangeFcn (hObject, eventdata, handles);

handles.sensor_struct = state.sensor_struct;
handles.index_sensors = state.index_sensors;

index = state.index_listbox_sensors;
if isempty (index) || index == 0
    set (handles.listbox_sensors, 'String', '', 'Value', []);
    set (handles.sensor_name, 'String', '');
    set (handles.sensor_x, 'String', '');
    set (handles.sensor_y, 'String', '');
else
    for i = 1 : length(handles.sensor_struct)
        sensor_names {i,1} = handles.sensor_struct(i).sensor_name;
    end;
    set (handles.listbox_sensors, 'String', sensor_names, ...
                                  'Value', index);
    sensor_struct = handles.sensor_struct(index);
    set (handles.sensor_name, 'String', sensor_struct.sensor_name);
    set (handles.sensor_x, 'String', sensor_struct.sensor_x);
    set (handles.sensor_y, 'String', sensor_struct.sensor_y);
end;

set (handles.distribution_time_vector, 'String', state.distribution_time_vector);
set (handles.gridcells_x, 'String', state.gridcells_x);
set (handles.gridcells_y, 'String', state.gridcells_y);
set (handles.sim_x1, 'String', state.sim_x1);
set (handles.sim_y1, 'String', state.sim_y1);
set (handles.sim_x2, 'String', state.sim_x2);
set (handles.sim_y2, 'String', state.sim_y2);
set (handles.evolution_time_vector, 'String', state.evolution_time_vector);
set (handles.uipanel_simulation, 'SelectedObject', ...
     findobj (handles.uipanel_simulation, 'Tag', state.simulation_radiobutton_tag));
uipanel_simulation_SelectionChangeFcn (hObject, eventdata, handles);

guidata (hObject, handles);

try
    figure_handles = findobj ('Tag', 'hotspotsim');
    close (figure_handles);
    if exist (state_fig_filename, 'file') == 2
        hgload (state_fig_filename);
    end;
catch
    errordlg (lasterr, 'File Load Error', 'modal');
    return;
end;


% --- Executes when selecting menu item File->Save state.
function menu_save_state_Callback(hObject, eventdata, handles)

state.die_x2 = get (handles.die_x2, 'String');
state.die_y2 = get (handles.die_y2, 'String');

state.source_struct = handles.source_struct;
state.index_sources = handles.index_sources;
state.index_listbox_sources = get (handles.listbox_sources, 'Value');

state.sensor_struct = handles.sensor_struct;
state.index_sensors = handles.index_sensors;
state.index_listbox_sensors = get (handles.listbox_sensors, 'Value');

state.distribution_time_vector = get (handles.distribution_time_vector, 'String');
state.gridcells_x = get (handles.gridcells_x, 'String');
state.gridcells_y = get (handles.gridcells_y, 'String');
state.sim_x1 = get (handles.sim_x1, 'String');
state.sim_y1 = get (handles.sim_y1, 'String');
state.sim_x2 = get (handles.sim_x2, 'String');
state.sim_y2 = get (handles.sim_y2, 'String');
state.evolution_time_vector = get (handles.evolution_time_vector, 'String');
state.simulation_radiobutton_tag = get (get (handles.uipanel_simulation, 'SelectedObject'), 'Tag');

figure_handles = findobj ('Tag', 'hotspotsim');

[file, path] = uiputfile ('*.mat', 'Save state');
state_gui_filename = [path file];
if file ~= 0
    if all (state_gui_filename (end-3:end) == '.mat')
        state_fig_filename = [state_gui_filename(1:end-4) '.fig'];
    else
        errordlg ('File extension should be .mat !', 'Error Dialog', 'modal');
        return;
    end;
    try
        save (state_gui_filename, 'state');
        if ~isempty (figure_handles)
            hgsave (figure_handles, state_fig_filename);
        end;
    catch
        errordlg (lasterr, 'File Save Error', 'modal');
        return;
    end;
end;


% --- Executes when selecting menu item Help.
function menu_help_Callback(hObject, eventdata, handles)


% --- Executes when selecting menu item Help->User manual.
function menu_manual_Callback(hObject, eventdata, handles)

manual_file = 'Hot_Spot_Simulator_manual.pdf';
try
    open (manual_file);
catch
    errordlg (['Unable to open user manual: ' lasterr], 'File Error', 'modal');
    return;
end;


% --- Executes when selecting menu item Help->Engineering Forum paper.
function menu_paper_Callback(hObject, eventdata, handles)

paper_file = 'Hot_Spot_Simulator_paper.pdf';
try
    open (paper_file);
catch
    errordlg (['Unable to open Engineering Forum paper: ' lasterr], 'File Error', 'modal');
    return;
end;


% --- Executes when selecting menu item Help->About.
function menu_about_Callback(hObject, eventdata, handles)

msgbox ({'Hot Spot Simulator'; ...
         ''; ...
         'Release version : 1.0'; ...
         'Date : June 2006'; ...
         'Author : Bart Desoete'; ...
         'Copyright : AMI Semiconductor'}, ...
         'About ...', ...
         'modal');


% ------------------------------------------------------------------------
% Callbacks linked to simulation execution.
% ------------------------------------------------------------------------

% --- Executes on button press in pushbutton_simulate.
function pushbutton_simulate_Callback(hObject, eventdata, handles)

die_coords = get_die_coords (hObject, eventdata, handles);
if die_coords == zeros(1,4), return, end;

errorflag = true;
source_names = get_source_names (hObject, eventdata, handles, errorflag);
number_sources = size (source_names, 1);
if number_sources == 0, return, end;
source_coords = get_source_coords (hObject, eventdata, handles);
if size (source_coords, 1) < number_sources, return, end;
source_params = get_source_params (hObject, eventdata, handles);
if size (source_params, 1) < number_sources, return, end;

radiobutton_tag = get (get (handles.uipanel_simulation, 'SelectedObject'), 'Tag');

errorflag = true;
sensor_names = get_sensor_names (hObject, eventdata, handles, errorflag);
number_sensors = size (sensor_names, 1);
if strcmp (radiobutton_tag, 'radiobutton_evolution') && number_sensors == 0, return, end;
sensor_coords = get_sensor_coords (hObject, eventdata, handles);
if size (sensor_coords, 1) < number_sensors, return, end;

switch radiobutton_tag
    case 'radiobutton_distribution'
        distribution_time_vector = get_distribution_time_vector (hObject, eventdata, handles);
        if isempty (distribution_time_vector), return, end;
        [gridvector_x, gridvector_y] = get_gridvectors (hObject, eventdata, handles);
        if isempty (gridvector_x) || isempty (gridvector_y), return, end;
        [gridmatrix_x, gridmatrix_y] = meshgrid (gridvector_x, gridvector_y);
        x_vector = reshape (gridmatrix_x, length(gridvector_x) * length(gridvector_y), 1);
        y_vector = reshape (gridmatrix_y, length(gridvector_x) * length(gridvector_y), 1);
        temp_distribution = [];
        handle_waitbar = waitbar (0, ...
            {'Please wait ...' ; 'Press Cancel to abort simulation ...'}, ...
            'WindowStyle', 'modal', 'CreateCancelBtn', 'delete(gcf)');
        for i = 1 : length (distribution_time_vector)
            temp_distribution (:,i) = temp_calculation (x_vector, y_vector, ...
                distribution_time_vector, i, ...
                die_coords, source_coords, source_params, ...
                handle_waitbar);
        end;
        temp_distribution = reshape (temp_distribution, ...
            [length(gridvector_y) length(gridvector_x) length(distribution_time_vector)]);
        temp_evolution = [];
        if number_sensors > 0
            x_vector = sensor_coords (:, 1);
            y_vector = sensor_coords (:, 2);
            for i = 1 : length (distribution_time_vector)
                abort_flag = false;
                [temp_evolution(:,i), abort_flag] = temp_calculation (x_vector, y_vector, ...
                    distribution_time_vector, i, ...
                    die_coords, source_coords, source_params, ...
                    handle_waitbar);
                if abort_flag, return, end;
            end;
        end;
        if ishandle (handle_waitbar)
            close (handle_waitbar);
        end;
        plot_distributions (gridmatrix_x, gridmatrix_y, distribution_time_vector, ...
            temp_distribution, temp_evolution, ...
            source_coords, sensor_names, sensor_coords);
    case 'radiobutton_evolution'
        evolution_time_vector = get_evolution_time_vector (hObject, eventdata, handles);
        if isempty (evolution_time_vector), return, end;
        x_vector = sensor_coords (:, 1);
        y_vector = sensor_coords (:, 2);
        temp_evolution = [];
        handle_waitbar = waitbar (0, ...
            {'Please wait ...' ; 'Press Cancel to abort simulation ...'}, ...
            'WindowStyle', 'modal', 'CreateCancelBtn', 'delete(gcf)');
        for i = 1 : length (evolution_time_vector)
            abort_flag = false;
            [temp_evolution(:,i), abort_flag] = temp_calculation (x_vector, y_vector, ...
                evolution_time_vector, i, ...
                die_coords, source_coords, source_params, ...
                handle_waitbar);
            if abort_flag, return, end;
        end;
        if ishandle (handle_waitbar)
            close (handle_waitbar);
        end;
        plot_evolutions (evolution_time_vector, temp_evolution, sensor_names);
end;

guidata (hObject, handles);


% --- Executes on button press in pushbutton_plot_power.
function pushbutton_plot_power_Callback(hObject, eventdata, handles)

errorflag = true;
source_names = get_source_names (hObject, eventdata, handles, errorflag);
number_sources = size (source_names, 1);
if number_sources == 0, return, end;
source_params = get_source_params (hObject, eventdata, handles);
if size (source_params, 1) < number_sources, return, end;

radiobutton_tag = get (get (handles.uipanel_simulation, 'SelectedObject'), 'Tag');
switch radiobutton_tag
    case 'radiobutton_distribution'
        distribution_time_vector = get_distribution_time_vector (hObject, eventdata, handles);
        if isempty (distribution_time_vector), return, end;
        t_max = max (distribution_time_vector);
    case 'radiobutton_evolution'
        evolution_time_vector = get_evolution_time_vector (hObject, eventdata, handles);
        if isempty (evolution_time_vector), return, end;
        t_max = max (evolution_time_vector);
end;

plot_power_waveforms (source_names, source_params, t_max);


% --- Executes on button press in pushbutton_draw_floorplan.
function pushbutton_draw_floorplan_Callback(hObject, eventdata, handles)

die_coords = get_die_coords (hObject, eventdata, handles);
if die_coords == zeros(1,4), return, end;

errorflag = false;
source_names = get_source_names (hObject, eventdata, handles, errorflag);
number_sources = size (source_names, 1);
source_coords = get_source_coords (hObject, eventdata, handles);
if size (source_coords, 1) < number_sources, return, end;

errorflag = false;
sensor_names = get_sensor_names (hObject, eventdata, handles, errorflag);
number_sensors = size (sensor_names, 1);
sensor_coords = get_sensor_coords (hObject, eventdata, handles);
if size (sensor_coords, 1) < number_sensors, return, end;

draw_floorplan (die_coords, source_names, source_coords, sensor_names, sensor_coords);


% --- Retrieval of die coordinates from GUI.
function die_coords = get_die_coords (hObject, eventdata, handles)

die_coords = zeros(1,4);

die_x2_string = get (handles.die_x2, 'String');
die_x2 = str2num (die_x2_string);
if ~isscalar (die_x2) || ~isreal (die_x2) || die_x2 <= 0
    errordlg ('Die coordinate x2 should be a strictly positive real number !', ...
              'Error Dialog', 'modal');
    return;
end;

die_y2_string = get (handles.die_y2, 'String');
die_y2 = str2num (die_y2_string);
if ~isscalar (die_y2) || ~isreal (die_y2) || die_y2 <= 0
    errordlg ('Die coordinate y2 should be a strictly positive real number !', ...
              'Error Dialog', 'modal');
    return;
end;

die_coords = [0 0 die_x2 die_y2];


% --- Retrieval of source names from GUI.
function source_names = get_source_names (hObject, eventdata, handles, errorflag)

source_names = get (handles.listbox_sources, 'String');
if size (source_names, 1) == 0 && errorflag
    errordlg ('No power sources defined !', 'Error Dialog', 'modal');
    return;
end;


% --- Retrieval of source coordinates from GUI.
function source_coords = get_source_coords (hObject, eventdata, handles)

source_coords = [];

source_names = get (handles.listbox_sources, 'String');
number_sources = size (source_names, 1);
for i = 1 : number_sources
    source_x1 = str2num (handles.source_struct(i).source_x1);
    source_y1 = str2num (handles.source_struct(i).source_y1);
    source_x2 = str2num (handles.source_struct(i).source_x2);
    source_y2 = str2num (handles.source_struct(i).source_y2);
    die_x2 = str2num (get (handles.die_x2, 'String'));
    die_y2 = str2num (get (handles.die_y2, 'String'));
    if ~isscalar (source_x1) || ~isreal (source_x1) || source_x1 < 0
        errordlg (['Power source ''' source_names{i} ...
                  ''' : coordinate x1 should be a positive real number !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    if ~isscalar (source_y1) || ~isreal (source_y1) || source_y1 < 0
        errordlg (['Power source ''' source_names{i} ...
                  ''' : coordinate y1 should be a positive real number !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    if ~isscalar (source_x2) || ~isreal (source_x2) || source_x2 < 0
        errordlg (['Power source ''' source_names{i} ...
                  ''' : coordinate x2 should be a positive real number !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    if ~isscalar (source_y2) || ~isreal (source_y2) || source_y2 < 0
        errordlg (['Power source ''' source_names{i} ...
                  ''' : coordinate y2 should be a positive real number !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    if source_x1 >= source_x2
        errordlg (['Power source ''' source_names{i} ...
                  ''' : coordinate x2 should be larger than x1 !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    if source_y1 >= source_y2
        errordlg (['Power source ''' source_names{i} ...
                  ''' : coordinate y2 should be larger than y1 !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    if source_x2 > die_x2
        errordlg (['Power source ''' source_names{i} ...
                  ''' : coordinate x2 exceeds die coordinate x2 !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    if source_y2 > die_y2
        errordlg (['Power source ''' source_names{i} ...
                  ''' : coordinate y2 exceeds die coordinate y2 !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    source_coords (i,:) = [source_x1 source_y1 source_x2 source_y2];
end;


% --- Retrieval of source parameters from GUI.
function source_params = get_source_params (hObject, eventdata, handles)

source_params = [];

source_names = get (handles.listbox_sources, 'String');
number_sources = size (source_names, 1);
for i = 1 : number_sources
    radiobutton_tag = handles.source_struct(i).radiobutton_tag;
    switch radiobutton_tag
        case 'radiobutton_pulse'
            source_power_low = str2num (handles.source_struct(i).source_power_low);
            source_power_high = str2num (handles.source_struct(i).source_power_high);
            source_delay = str2num (handles.source_struct(i).source_delay);
            source_pulse_width = str2num (handles.source_struct(i).source_pulse_width);
            source_rise_time = str2num (handles.source_struct(i).source_rise_time);
            source_fall_time = str2num (handles.source_struct(i).source_fall_time);
            source_period = str2num (handles.source_struct(i).source_period);
            if ~isscalar (source_power_low) || ~isreal (source_power_low) || source_power_low < 0
                errordlg (['Power source ''' source_names{i} ...
                          ''' : low power level should be a positive real number !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if ~isscalar (source_power_high) || ~isreal (source_power_high) || source_power_high <= 0
                errordlg (['Power source ''' source_names{i} ...
                          ''' : high power level should be a strictly positive real number !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if ~isscalar (source_delay) || ~isreal (source_delay) || source_delay < 0
                errordlg (['Power source ''' source_names{i} ...
                          ''' : delay should be a positive real number !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if ~isscalar (source_pulse_width) || ~isreal (source_pulse_width) || source_pulse_width < 0
                errordlg (['Power source ''' source_names{i} ...
                          ''' : pulse width should be a positive real number !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if ~isscalar (source_rise_time) || ~isreal (source_rise_time) || source_rise_time < 0
                errordlg (['Power source ''' source_names{i} ...
                          ''' : rise time should be a positive real number !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if ~isscalar (source_fall_time) || ~isreal (source_fall_time) || source_fall_time < 0
                errordlg (['Power source ''' source_names{i} ...
                          ''' : fall time should be a positive real number !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if ~isscalar (source_period) || ~isreal (source_period) || source_period <= 0
                errordlg (['Power source ''' source_names{i} ...
                          ''' : period should be a strictly positive real number !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if source_power_low >= source_power_high
                errordlg (['Power source ''' source_names{i} ...
                          ''' : high power level should be higher than low power level !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if source_pulse_width + source_rise_time + source_fall_time > source_period
                errordlg (['Power source ''' source_names{i} ...
                          ''' : pulse width + rise time + fall time should not be larger than period !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            source_params {i,1} = {@pulse source_power_low source_power_high source_delay ...
                source_pulse_width source_rise_time source_fall_time source_period};
        case 'radiobutton_pwl'
            source_time_vector = str2num (handles.source_struct(i).source_time_vector)';
            source_power_vector = str2num (handles.source_struct(i).source_power_vector)';
            if ~isvector (source_time_vector) || any (source_time_vector < 0)
                errordlg (['Power source ''' source_names{i} ...
                          ''' : time vector should be a list of positive real numbers !'], ...
                          'Error Dialog', 'modal');
                return;
            elseif ~all (source_time_vector == sort (source_time_vector, 'ascend'))
                errordlg (['Power source ''' source_names{i} ...
                          ''' : time vector should be in ascending order !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if ~isvector (source_power_vector) || any (source_power_vector < 0)
                errordlg (['Power source ''' source_names{i} ...
                          ''' : power vector should be a list of positive real numbers !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if length (source_time_vector) ~= length (source_power_vector)
                errordlg (['Power source ''' source_names{i} ...
                          ''' : time vector and power vector should have the same number of elements !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            source_params {i,1} = {@pwl source_time_vector source_power_vector};
        case 'radiobutton_datafile'
            source_filename = handles.source_struct(i).source_filename;
            try
                file_content = load ('-ascii', source_filename);
            catch
                errordlg (['Power source ''' source_names{i} ''' : ' lasterr], ...
                          'File Type Error', 'modal');
                return;
            end;
            if size (file_content,2) ~= 2
                errordlg (['Power source ''' source_names{i} ...
                          ''' : file should contain 2 columns of numeric data ' ...
                          '(time vector and power vector) !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            source_time_vector = file_content (:,1);
            source_power_vector = file_content (:,2);
            if ~isvector (source_time_vector) || any (source_time_vector < 0)
                errordlg (['Power source ''' source_names{i} ...
                          ''' : time vector should be a list of positive real numbers !'], ...
                          'Error Dialog', 'modal');
                return;
            elseif ~all (source_time_vector == sort (source_time_vector, 'ascend'))
                errordlg (['Power source ''' source_names{i} ...
                          ''' : time vector should be in ascending order !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            if ~isvector (source_power_vector) || any (source_power_vector < 0)
                errordlg (['Power source ''' source_names{i} ...
                          ''' : power vector should be a list of positive real numbers !'], ...
                          'Error Dialog', 'modal');
                return;
            end;
            source_params {i,1} = {@pwl source_time_vector source_power_vector};
    end;
end;


% --- Retrieval of sensor names from GUI.
function sensor_names = get_sensor_names (hObject, eventdata, handles, errorflag)

sensor_names = get (handles.listbox_sensors, 'String');
radiobutton_tag = get (get (handles.uipanel_simulation, 'SelectedObject'), 'Tag');
if size (sensor_names, 1) == 0 && strcmp (radiobutton_tag, 'radiobutton_evolution') && errorflag
    errordlg ('No sensors defined !', 'Error Dialog', 'modal');
    return;
end;


% --- Retrieval of sensor coordinates from GUI.
function sensor_coords = get_sensor_coords (hObject, eventdata, handles)

sensor_coords = [];

sensor_names = get (handles.listbox_sensors, 'String');
number_sensors = size (sensor_names, 1);
for i = 1 : number_sensors
    sensor_x = str2num (handles.sensor_struct(i).sensor_x);
    sensor_y = str2num (handles.sensor_struct(i).sensor_y);
    die_x2 = str2num (get (handles.die_x2, 'String'));
    die_y2 = str2num (get (handles.die_y2, 'String'));
    if ~isscalar (sensor_x) || ~isreal (sensor_x) || sensor_x < 0
        errordlg (['Sensor ''' sensor_names{i} ...
                  ''' : coordinate x should be a positive real number !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    if ~isscalar (sensor_y) || ~isreal (sensor_y) || sensor_y < 0
        errordlg (['Sensor ''' sensor_names{i} ...
                  ''' : coordinate y should be a positive real number !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    if sensor_x > die_x2
        errordlg (['Sensor ''' sensor_names{i} ...
                  ''' : coordinate x exceeds die coordinate x2 !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    if sensor_y > die_y2
        errordlg (['Sensor ''' sensor_names{i} ...
                  ''' : coordinate y exceeds die coordinate y2 !'], ...
                  'Error Dialog', 'modal');
        return;
    end;
    sensor_coords (i,:) = [sensor_x sensor_y];
end;


% --- Retrieval of distribution time vector from GUI.
function distribution_time_vector = get_distribution_time_vector (hObject, eventdata, handles)

distribution_time_vector_string = get (handles.distribution_time_vector, 'String');
distribution_time_vector = str2num (distribution_time_vector_string);
if ~isvector (distribution_time_vector) || any (distribution_time_vector <= 0)
    errordlg ('Simulation time vector should be a list of strictly positive real numbers !', ...
              'Error Dialog', 'modal');
    distribution_time_vector = [];
    return;
elseif max (distribution_time_vector) > 1
    warndlg ('Above around 1 second simulations may deviate from reality due to package effects, which are not taken into account !', ...
             'Warning Dialog', 'modal');
end;


% --- Retrieval of evolution time vector from GUI.
function evolution_time_vector = get_evolution_time_vector (hObject, eventdata, handles)

evolution_time_vector_string = get (handles.evolution_time_vector, 'String');
evolution_time_vector = str2num (evolution_time_vector_string);
if ~isvector (evolution_time_vector) || any (evolution_time_vector < 0)
    errordlg ('Simulation time vector should be a list of positive real numbers !', ...
              'Error Dialog', 'modal');
    evolution_time_vector = [];
    return;
elseif ~all (evolution_time_vector == sort (evolution_time_vector, 'ascend'))
    errordlg ('Simulation time vector should be in ascending order !', ...
              'Error Dialog', 'modal');
    evolution_time_vector = [];
    return;
elseif max (evolution_time_vector) > 1
    warndlg ('Above around 1 second simulations may deviate from reality due to package effects, which are not taken into account !', ...
             'Warning Dialog', 'modal');
end;


% --- Retrieval of gridvectors from GUI.
function [gridvector_x, gridvector_y] = get_gridvectors (hObject, eventdata, handles)

gridvector_x = [];
gridvector_y = [];

gridcells_x = str2num (get (handles.gridcells_x, 'String'));
gridcells_y = str2num (get (handles.gridcells_y, 'String'));
sim_x1 = str2num (get (handles.sim_x1, 'String'));
sim_y1 = str2num (get (handles.sim_y1, 'String'));
sim_x2 = str2num (get (handles.sim_x2, 'String'));
sim_y2 = str2num (get (handles.sim_y2, 'String'));
die_x2 = str2num (get (handles.die_x2, 'String'));
die_y2 = str2num (get (handles.die_y2, 'String'));
if ~isscalar (gridcells_x) || gridcells_x ~= floor(gridcells_x) || gridcells_x <= 0
    errordlg ('Number of grid cells in x-direction should be a strictly positive integer number !', ...
              'Error Dialog', 'modal');
    return;
end;
if ~isscalar (gridcells_y) || gridcells_y ~= floor(gridcells_y) || gridcells_y <= 0
    errordlg ('Number of grid cells in y-direction should be a strictly positive integer number !', ...
              'Error Dialog', 'modal');
    return;
end;
if ~isscalar (sim_x1) || ~isreal (sim_x1) || sim_x1 < 0
    errordlg ('Grid coordinate x1 should be a positive real number !', ...
              'Error Dialog', 'modal');
    return;
end;
if ~isscalar (sim_y1) || ~isreal (sim_y1) || sim_y1 < 0
    errordlg ('Grid coordinate y1 should be a positive real number !', ...
              'Error Dialog', 'modal');
    return;
end;
if ~isscalar (sim_x2) || ~isreal (sim_x2) || sim_x2 < 0
    errordlg ('Grid coordinate x2 should be a positive real number !', ...
              'Error Dialog', 'modal');
    return;
end;
if ~isscalar (sim_y2) || ~isreal (sim_y2) || sim_y2 < 0
    errordlg ('Grid coordinate y2 should be a positive real number !', ...
              'Error Dialog', 'modal');
    return;
end;
if sim_x1 >= sim_x2
    errordlg ('Grid coordinate x2 should be larger than grid coordinate x1 !', ...
              'Error Dialog', 'modal');
    return;
end;
if sim_y1 >= sim_y2
    errordlg ('Grid coordinate y2 should be larger than grid coordinate y1 !', ...
              'Error Dialog', 'modal');
    return;
end;
if sim_x2 > die_x2
    errordlg ('Grid coordinate x2 exceeds die coordinate x2 !', ...
              'Error Dialog', 'modal');
    return;
end;
if sim_y2 > die_y2
    errordlg ('Grid coordinate y2 exceeds die coordinate y2 !', ...
              'Error Dialog', 'modal');
    return;
end;

gridvector_x = linspace (sim_x1, sim_x2, gridcells_x+1);
gridvector_y = linspace (sim_y1, sim_y2, gridcells_y+1);


% ------------------------------------------------------------------------
% Functions for temperature calculation.
% ------------------------------------------------------------------------

% --- Calculation of temperature rise for single time and multiple coordinates.
function [temp, abort_flag] = temp_calculation (x_vector, y_vector, ...
    time_vector, index_time, ...
    die_coords, source_coords, source_params, handle_waitbar)

% from um to cm
x_vector = 1e-4 * x_vector;
y_vector = 1e-4 * y_vector;
die_coords = 1e-4 * die_coords;
source_coords = 1e-4 * source_coords;

die_x2 = die_coords (3);
die_y2 = die_coords (4);

number_sources = size (source_coords, 1);

alfa = 0.5;

t = time_vector (index_time);
number_times = length (time_vector);
n_threshold = 1;
dist_threshold = n_threshold * sqrt (4 * pi * alfa * t);

temp = zeros (size (x_vector));

abort_flag = false;

for source = 1 : number_sources
    eps = 1e-20;
    if t < eps, break, end;
    
    coord_source = source_coords (source, :);
    param_source = source_params {source, :};
    coord_mirrors = [];
    
    for tour = 1 : 1000
        coord_cells = [];
        
        i_cell = -tour;
        for j_cell = -tour : tour
            coord_cells = [coord_cells; i_cell j_cell];
        end;
        
        i_cell = tour;
        for j_cell = -tour : tour
            coord_cells = [coord_cells; i_cell j_cell];
        end;
        
        j_cell = -tour;
        for i_cell = -tour + 1 : tour - 1
            coord_cells = [coord_cells; i_cell j_cell];
        end;
        
        j_cell = tour;
        for i_cell = -tour + 1 : tour - 1
            coord_cells = [coord_cells; i_cell j_cell];
        end;
        
        number_extra_mirrors = 0;
        for cell = 1 : size (coord_cells, 1)
            i_cell = coord_cells (cell, 1);
            j_cell = coord_cells (cell, 2);
            
            if (-1) ^ i_cell > 0
                coord_mirror (1, 1) = 2 * floor ((i_cell + 1) / 2) * die_x2 + coord_source (1, 1);
                coord_mirror (1, 3) = 2 * floor ((i_cell + 1) / 2) * die_x2 + coord_source (1, 3);
            else
                coord_mirror (1, 1) = 2 * floor ((i_cell + 1) / 2) * die_x2 - coord_source (1, 3);
                coord_mirror (1, 3) = 2 * floor ((i_cell + 1) / 2) * die_x2 - coord_source (1, 1);
            end;
            if (-1) ^ j_cell > 0
                coord_mirror (1, 2) = 2 * floor ((j_cell + 1) / 2) * die_y2 + coord_source (1, 2);
                coord_mirror (1, 4) = 2 * floor ((j_cell + 1) / 2) * die_y2 + coord_source (1, 4);
            else
                coord_mirror (1, 2) = 2 * floor ((j_cell + 1) / 2) * die_y2 - coord_source (1, 4);
                coord_mirror (1, 4) = 2 * floor ((j_cell + 1) / 2) * die_y2 - coord_source (1, 2);
            end;
            
            if i_cell < 0
                min_dist_x = -coord_mirror (1, 3);
            elseif i_cell > 0
                min_dist_x = coord_mirror (1, 1) - die_x2;
            else
                min_dist_x = 0;
            end;
            
            if j_cell < 0
                min_dist_y = -coord_mirror (1, 4);
            elseif j_cell > 0
                min_dist_y = coord_mirror (1, 2) - die_y2;
            else
                min_dist_y = 0;
            end;
            
            min_dist = sqrt (min_dist_x ^ 2 + min_dist_y ^ 2);
            if min_dist < dist_threshold
                coord_mirrors = [coord_mirrors; coord_mirror];
                number_extra_mirrors = number_extra_mirrors + 1;
            end;
        end;
        
        if number_extra_mirrors == 0
            break
        end;
    end;
    
    coord_source_and_mirrors = [coord_source; coord_mirrors];
    number_source_and_mirrors = size (coord_source_and_mirrors, 1);
    
    for i_source = 1 : number_source_and_mirrors
        W_source = coord_source_and_mirrors (i_source, 3) - coord_source_and_mirrors (i_source, 1);
        L_source = coord_source_and_mirrors (i_source, 4) - coord_source_and_mirrors (i_source, 2);
        x_center = (coord_source_and_mirrors (i_source, 1) + coord_source_and_mirrors (i_source, 3)) / 2;
        y_center = (coord_source_and_mirrors (i_source, 2) + coord_source_and_mirrors (i_source, 4)) / 2;
        number_x_y = size (x_vector, 1);
        for i = 1 : number_x_y
            x = x_vector (i);
            y = y_vector (i);
            temp (i, 1) = temp (i, 1) + ...
                temp_green_function (t, x - x_center, y - y_center, W_source, L_source, param_source);
            if ishandle (handle_waitbar)
                x_waitbar = (((i / number_x_y + i_source - 1) / ...
                            number_source_and_mirrors + source - 1) / ...
                            number_sources + index_time - 1) / ...
                            number_times;
                waitbar (x_waitbar, handle_waitbar);
            else
                abort_flag = true;
                return;
            end;
        end;
    end;
    
end;


% --- Calculation of temperature rise based on Green's function.
function temp = temp_green_function (t, x, y, W, L, params)

%   This function calculates the temperature rise in a 3-D infinite region
%   (with an adiabatic boundary at z=0) due to a time-dependent power source,
%   uniformly generated in a 2-D region with rectangular boundaries.
%   
%   x, y, z: coordinates of point where to evaluate temperature rise [cm]
%   t: time after start of heat pulse [s]
%   W: width of heat source (in x-direction) [cm]
%   L: length of heat source (in y-direction) [cm]
%   params: time-dependent power dissipation [W]
%       1st element of cell array: function handle
%       other elements of cell array: function parameters
%   D: depth of heat source (in z-direction) [cm]
%   k: thermal conductivity [W/cmK] (optional)
%   alfa: thermal diffusivity [cm^2/s] (optional)
%   
%   Source: N. Rinaldi, "On the modeling of the transient thermal behavior
%   of semiconductor devices," IEEE Trans. Electron Devices, vol. 48, no.
%   12, pp. 2796-2802, Dec. 2001.
%

z = 0;
D = 0;
k = 1;
alfa = 0.5;

eps = 1e-20;                     % to avoid division by zero in integral

u_f = sqrt (4 * alfa * t);
integral = quadl (@green_function_integrand, eps, u_f + eps, [], [], ...
                  x, y, z, t, W, L, params, D, alfa);

sqrt_pi = 1.77245385090552;
temp = (1 / (8 * k * sqrt_pi * W * L)) * integral;


% --- Integrand of temperature formula based on Green's function.
function f = green_function_integrand (u, x, y, z, t, W, L, params, D, alfa)

f = feval (params {1}, t - u.^2./(4*alfa), params {2 : end}) .* ...
    (erf ((W./2+x)./u) + erf ((W./2-x)./u)) .* ...
    (erf ((L./2+y)./u) + erf ((L./2-y)./u)) .* ...
    (exp (-(z-D).^2./u.^2) + exp (-(z+D).^2./u.^2));


% ------------------------------------------------------------------------
% Generic functions for construction of power waveforms.
% ------------------------------------------------------------------------

% --- Pulse waveform.
function f = pulse (t, val0, val1, delay, width, rise, fall, period)

ts = t - delay;
tm = rem (ts, period);

t0 = [0     rise  rise+width  rise+width+fall  period];
P0 = [val0  val1  val1        val0             val0];

f = pwl (tm, t0, P0);


% --- Piecewise linear waveform.
function f = pwl (t, t0, P0)

size_t = size (t);
t = t (:);
t0 = t0 (:);
P0 = P0 (:);

[n, k] = histc (t, t0);
f = zeros (size (t));
f (k==0 & t<t0(1)) = P0(1);
f ((k==0 & t>t0(end)) | k==length(t0)) = P0(end);

k0 = (k~=0 & k~=length(t0));
kk = k(k0);
f (k0) = P0(kk) + (P0(kk+1) - P0(kk)) .* (t(k0) - t0(kk)) ./ (t0(kk+1) - t0(kk));

f = reshape (f, size_t);


% ------------------------------------------------------------------------
% Functions for plotting.
% ------------------------------------------------------------------------

% --- Plotting temperature distributions.
function plot_distributions (gridmatrix_x, gridmatrix_y, distribution_time_vector, ...
            temp_distribution, temp_evolution, ...
            source_coords, sensor_names, sensor_coords)

number_times = length (distribution_time_vector);

for i = 1 : number_times
    t = distribution_time_vector (i);
    
    figure ('Tag', 'hotspotsim');
    surfc (gridmatrix_x, gridmatrix_y, temp_distribution(:,:,i));
    xlim ([gridmatrix_x(1,1) gridmatrix_x(1,end)]);
    ylim ([gridmatrix_y(1,1) gridmatrix_y(end,1)]);
    zlimits = zlim;
    zlim ([0 zlimits(2)]);
    dar = get (gca, 'DataAspectRatio');
    dar_min = min (dar(1), dar(2));
    set (gca, 'DataAspectRatio', [dar_min dar_min dar(3)]);
    title (['t = ' num2str(t) ' s']);
    xlabel ('x [\mum]');
    ylabel ('y [\mum]');
    zlabel ('\DeltaT [K]');
    set (gcf, 'PaperPosition', [1.7 3.6 5.5 4.1]);
    
    figure ('Tag', 'hotspotsim');
    [C, h] = contour (gridmatrix_x, gridmatrix_y, temp_distribution(:,:,i));
    h_labels = clabel (C, h);
    set (h_labels, 'FontSize', 7);
    hold on;
    plot_rectangles ([], source_coords);
    number_sensors = size (sensor_names, 1);
    if number_sensors > 0
        symbols = '*d^v><s+phxo';
        for j = 1 : number_sensors
            symbol = symbols (mod (j-1, length(symbols)) + 1);
            h(j) = plot (sensor_coords(j,1), sensor_coords(j,2), [symbol 'k']);
            temp_sensor = temp_evolution (j,i);
            legend_matrix {j,1} = [sensor_names{j,1} ' : ' num2str(temp_sensor,4) ' K'];
        end;
        legend (h, legend_matrix, 'Location', 'EastOutside', 'Interpreter', 'none');
    end;
    axis equal;
    xlim ([gridmatrix_x(1,1) gridmatrix_x(1,end)]);
    ylim ([gridmatrix_y(1,1) gridmatrix_y(end,1)]);
    title (['t = ' num2str(t) ' s']);
    xlabel ('x [\mum]');
    ylabel ('y [\mum]');
    set (gcf, 'PaperPosition', [1.7 3.6 5.5 4.1]);
end;

temp_distribution_vector = reshape (temp_distribution, [], number_times);
gridmatrix_x_vector = gridmatrix_x (:);
gridmatrix_y_vector = gridmatrix_y (:);
[temp_max, index_max] = max (temp_distribution_vector, [], 1);
x_at_max = gridmatrix_x_vector (index_max);
y_at_max = gridmatrix_y_vector (index_max);
for i = 1 : number_times
    t = distribution_time_vector (i);
    message_matrix {i,1} = ['t = ' num2str(t) ' s  :  \DeltaT\_max = ' ...
        num2str(temp_max(i),4) ' K  at  (x,y) = (' ...
        num2str(x_at_max(i),4) ',' num2str(y_at_max(i),4) ')'];
end;
handle_msgbox = msgbox (message_matrix, 'Maximum temperatures', 'help');
set (handle_msgbox, 'Tag', 'hotspotsim');
set (findobj (handle_msgbox, 'Type', 'text'), 'Interpreter', 'tex');


% --- Plotting temperature evolutions.
function plot_evolutions (evolution_time_vector, temp_evolution, sensor_names)

figure ('Tag', 'hotspotsim');
hold on;
colours = 'kbrgmcy';
styles = {'-' '--' ':' '-.'};

number_sensors = size (sensor_names, 1);
for i = 1 : number_sensors
    colour = colours (mod (i-1, length(colours)) + 1);
    style = styles {mod (fix ((i-1) / length(colours)), length(styles)) + 1};
    h(i) = plot (evolution_time_vector, temp_evolution (i,:), [colour style]);
    legend_matrix {i,1} = sensor_names {i,1};
end;

xlim ([0 evolution_time_vector(end)]);
ylimits = ylim;
ylim ([0 ylimits(2)]);
xlabel ('t [s]');
ylabel ('\DeltaT [K]');
legend (h, legend_matrix, 'Location', 'EastOutside', 'Interpreter', 'none');
grid on;
set (gcf, 'PaperPosition', [1.7 3.6 5.5 4.1]);

[temp_max, index_max] = max (temp_evolution, [], 2);
time_at_max = evolution_time_vector (index_max);
for i = 1 : number_sensors
    message_matrix {i,1} = [sensor_names{i,1} ' :  \DeltaT\_max = ' ...
        num2str(temp_max(i),4) 'K  at  t = ' num2str(time_at_max(i)) ' s'];
end;
handle_msgbox = msgbox (message_matrix, 'Maximum temperatures', 'help');
set (handle_msgbox, 'Tag', 'hotspotsim');
set (findobj (handle_msgbox, 'Type', 'text'), 'Interpreter', 'tex');


% --- Plotting power waveforms.
function plot_power_waveforms (source_names, source_params, t_max)

figure ('Tag', 'hotspotsim');
hold on;
colours = 'kbrgmcy';
styles = {'-' '--' ':' '-.'};

number_sources = size (source_names, 1);
for i = 1 : number_sources
    source_param = source_params {i,1};
    function_handle = source_param {1};
    switch func2str (function_handle)
        case 'pulse'
            [val0 val1 delay width rise fall period] = source_param {2:end};
            t0 = [0 ; rise ; rise+width ; rise+width+fall];
            P0 = [val0 ; val1 ; val1 ; val0];
            number_periods = fix (max (t_max - delay, 0) / period);
            t0 = repmat (t0, 1, number_periods + 1);
            t0 = t0 + repmat (period * (0:number_periods), 4, 1);
            t0 = t0 (:) + delay;
            P0 = repmat (P0, 1, number_periods + 1);
            P0 = P0 (:);
        case 'pwl'
            [time_vector power_vector] = source_param {2:end};
            t0 = time_vector (:);
            P0 = power_vector (:);
    end;
    if t0(1) > 0
        t0 = [0 ; t0];
        P0 = [P0(1) ; P0];
    end;
    if t0(end) < t_max
        t0 = [t0 ; t_max];
        P0 = [P0 ; P0(end)];
    end;
    colour = colours (mod (i-1, length(colours)) + 1);
    style = styles {mod (fix ((i-1) / length(colours)), length(styles)) + 1};
    h(i) = plot (t0, P0, [colour style]);
    legend_matrix {i,1} = source_names{i,1};
end;

legend (h, legend_matrix, 'Location', 'EastOutside', 'Interpreter', 'none');
xlim ([0 t_max]);
ylimits = ylim;
ylim ([0 ylimits(2)]);
xlabel ('t [s]');
ylabel ('P [W]');
set (gcf, 'PaperPosition', [1.7 3.6 5.5 4.1]);


% --- Plotting floorplan.
function draw_floorplan (die_coords, source_names, source_coords, sensor_names, sensor_coords)

figure ('Tag', 'hotspotsim');
hold on;
plot_rectangles (source_names, source_coords);
number_sensors = size (sensor_names, 1);
if number_sensors > 0
    symbols = '*d^v><s+phxo';
    for j = 1 : number_sensors
        symbol = symbols (mod (j-1, length(symbols)) + 1);
        h(j) = plot (sensor_coords(j,1), sensor_coords(j,2), [symbol 'k']);
        legend_matrix {j,1} = sensor_names{j,1};
    end;
    legend (h, legend_matrix, 'Location', 'EastOutside', 'Interpreter', 'none');
end;
axis equal;
set (gca, 'Box', 'on');
xlim ([0 die_coords(3)]);
ylim ([0 die_coords(4)]);
xlabel ('x [\mum]');
ylabel ('y [\mum]');
set (gcf, 'PaperPosition', [1.7 3.6 5.5 4.1]);


% --- Plotting rectangles on floorplan and contour plot.
function plot_rectangles (source_names, source_coords)

number_sources = size (source_coords, 1);

for source = 1 : number_sources
    x1 = source_coords (source, 1);
    y1 = source_coords (source, 2);
    x2 = source_coords (source, 3);
    y2 = source_coords (source, 4);
    x_rectangle = [x1 x2 x2 x1 x1];
    y_rectangle = [y1 y1 y2 y2 y1];
    plot (x_rectangle, y_rectangle, '--k');
    if ~isempty (source_names)
        text ((x1+x2)/2, (y1+y2)/2, source_names {source,1}, ...
            'HorizontalAlignment', 'Center');
    end;
end;

