function varargout = MixSIR(varargin) % MIXSIR M-file for MixSIR.fig % MIXSIR, by itself, creates a new MIXSIR or raises the existing % singleton*. % % H = MIXSIR returns the handle to a new MIXSIR or the handle to % the existing singleton*. % % MIXSIR('CALLBACK',hObject,eventData,handles,...) calls the local % function named CALLBACK in MIXSIR.M with the given input arguments. % % MIXSIR('Property','Value',...) creates a new MIXSIR or raises the % existing singleton*. Starting from the left, property value pairs are % applied to the GUI before MixSIR_OpeningFunction gets called. An % unrecognized property name or invalid value makes property application % stop. All inputs are passed to MixSIR_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 MixSIR % Last Modified by GUIDE v2.5 30-Jul-2007 12:25:36 % Begin initialization code - DO NOT EDIT gui_Singleton = 1; gui_State = struct('gui_Name', mfilename, ... 'gui_Singleton', gui_Singleton, ... 'gui_OpeningFcn', @MixSIR_OpeningFcn, ... 'gui_OutputFcn', @MixSIR_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 MixSIR is made visible. function MixSIR_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 MixSIR (see VARARGIN) % Choose default command line output for MixSIR handles.output = hObject; priors = 0; % initialize priors (this specifies the uniformative case as default) save 'priors.mat' priors %saves prior placeholder to working directory handles.printresult=0; %sets default to not write results files % Update handles structure guidata(hObject, handles); % UIWAIT makes MixSIR wait for user response (see UIRESUME) % uiwait(handles.figure1); % --- Outputs from this function are returned to the command line. function varargout = MixSIR_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; % --- Executes on button press in "About MixSIR...". function about_Callback(hObject, eventdata, handles) % hObject handle to about (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) open about.txt; function iterations_Callback(hObject, eventdata, handles) % hObject handle to iterations (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 iterations as text handles.iters =str2double(get(hObject,'String'));% returns contents of iterations as a double guidata(hObject,handles); % --- Executes during object creation, after setting all properties. function iterations_CreateFcn(hObject, eventdata, handles) % hObject handle to iterations (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 % --- Executes on button press in runmodelbutton. function runmodelbutton_Callback(hObject, eventdata, handles) % hObject handle to runmodelbutton (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) %get the user defined number of model iterations to be used iterations_Callback(hObject, eventdata, handles); try if isnan(handles.iters) msgbox('You have not entered a valid number into the iterations field.','Oops...','error') return; elseif handles.iters<100 msgbox('Less than 100 iterations not allowed.','Oops...','error') return; end catch msgbox('You have not entered a valid number into the iterations field.','Oops...','error') return; end %READ THESE IN... %_________________________________________________________________________________________ load mean_source.txt; %creates matrix called mean_source load SD_source.txt; %creates matrix called SD_source load mix_data.txt; handles.mean_mix = mean(mix_data,1);%creates matrix called mean_mix load mean_frac.txt; %creates matrix called mean_frac load SD_frac.txt; %creates matrix called SD_frac %convert from SD to variance var_source = SD_source.^2; var_frac = SD_frac.^2; %_________________________________________________________________________________________ % Check that data are in the right format (at least in terms of matrix sizes) if (size(mean_source,1)-size(SD_source,1) + size(mean_source,2)-size(SD_source,2)) +... (size(mean_frac,1)-size(SD_frac,1) + size(mean_frac,2)-size(SD_frac,2))+... (size(mix_data,2)-size(SD_frac,2))+... (size(mean_source,2)-size(mean_frac,2) + (size(mean_source,1)-size(mean_frac,1))) ~= 0 msgbox('Dimensions of source data matrices do not agree!','Oops...','error'); return; end %MAKE THESE FOR WORK.... %_________________________________________________________________________________________ handles.source_num = size(mean_source,1); % how many sources contribute to the mixator spp of concern? handles.iso_num = size(mean_source,2); % how many isotopes are you using? %set the priors based on user specs load priors.mat; %load prior placeholder file if priors == 0; handles.A = ones(1,handles.source_num);%sets uninformative priors as default handles.B = ones(1,handles.source_num);%sets uninformative priors as default clear priors; else handles.A = priors(1,:); handles.B = priors(2,:); clear priors; end source = zeros(handles.source_num, handles.iso_num); % this used to store sampled iso vals for source mix = zeros(1,handles.iso_num); % this used to store sampled iso vals for mix contribution = zeros(1,handles.source_num)'; % this used to store sampled contribs handles.contrib_out = zeros(1,handles.source_num); % this used to store accepted contrib vectors (OUTPUT!) handles.mix_out = zeros(1,handles.iso_num); % this used to store accepted contrib vectors (OUTPUT!) out_ticker = 0; % keeps track of the # of SIR accepts fraction = zeros(handles.source_num,handles.iso_num); % this used to store sampled fractionation for each iso Total = 0; % this used to keep tally of likes for SIR accept MaxDup = 0; % keeps track of duplicate accepts. Used to evaluate threshold. likestor = 0; % this used to store best threshold guess ljump = 0; % keeps track of the # likes accepted handles.L =zeros(1,1); % this used to store all the accepted likes progressbar; %Initializes a GUI progress bar %_________________________________________________________________________________________ %IDENTIFY AN APPROPRIATE THRESHOLD..... %_________________________________________________________________________________________ for irep=1:(round(handles.iters*0.1))%uses 10% run size to get threshold progressbar(irep/(round(handles.iters*0.1)+handles.iters)); %begins updating progress bar % Generate random proportions that sum to one (one for each source) contribution= rand_props2(handles.source_num); %calls function randprops2 to make random proportions (1 column) %Below uses an analytic solution to the mean and var of pred (without frationation) based on combining source %means and vars. Note that I have implemented a vectorized version of this calc below, so beware of tricky matrix math! mproposal = (mean_source'*contribution)';%generates a row of proposed mean mixs (one for each iso) vproposal = ((var_source)'*(contribution.^2))'; %does same for var % Now use the same method as above to get proposed fractionation mfraction = (mean_frac'*contribution)';%generates a row of proposed fractionations (one for each iso) vfraction = ((var_frac)'*(contribution.^2))'; %does same for var %when adding distributions, both the mean and variance are additive. So %we simply add the fractionation mean and var to the mean and var of the %mix calculated above mproposal=mproposal+mfraction; vproposal=vproposal+vfraction; % EVALUATE THE NEGLOGLIKE FOR THE PROPOSED MIX BASED ON DATA neglog = 0; % clear to zero for each run for iso_i = 1:handles.iso_num neglog = neglog + normlike([mproposal(iso_i),vproposal(iso_i)],mix_data(:,iso_i)); %neglogs for consumer iso vals end % EVALUATE THE NEGLOGLIKE FOR source CONTRIBS BASED ON PRIORS neglog = neglog - sum(log(betapdf(contribution',handles.A,handles.B)+1e-100)); likelihood = exp(-(neglog)); %presto! The likelihood appears like magic if likelihood > likestor likestor = likelihood; %keeps the very best like found end end Threshold = likestor*2; % Define SIR accept. criteria %_________________________________________________________________________________________ %RUN THE SIR ALGORITHM.... %_________________________________________________________________________________________ % DO for each replicate for irep = 1:handles.iters progressbar((round(handles.iters*0.1)+irep)/(handles.iters+(round(handles.iters*0.1)))); %continues updating progress bar from where left off last % Generate random proportions that sum to one (one for each source) contribution= rand_props2(handles.source_num); %calls function randprops2 to make random proportions (1 column) %Below uses an analytic solution to the mean and var of pred (without frationation) based on combining source %means and vars. See "Behboodian 1970. On a mixture of normal distributions. Biometrika 57(1):215-217" %for details on the calculation. Note that I have implemented a %vectorized version of this calc below, so beware of tricky matrix math! mproposal = (mean_source'*contribution)';%generates a row of proposed mean mixs (one for each iso) vproposal = ((var_source)'*(contribution.^2))'; %does same for var % Now use the same method as above to get proposed fractionation mfraction = (mean_frac'*contribution)';%generates a row of proposed fractionations (one for each iso) vfraction = ((var_frac)'*(contribution.^2))'; %does same for var %when adding distributions, both the mean and variance are additive. So %we simply add the fractionation mean and var to the mean and var of the %mix calculated above mproposal=mproposal+mfraction; vproposal=vproposal+vfraction; % EVALUATE THE NEGLOGLIKE FOR THE PROPOSED MIX BASED ON DATA neglog = 0; % clear to zero for each run for iso_i = 1:handles.iso_num neglog = neglog + normlike([mproposal(iso_i),vproposal(iso_i)],mix_data(:,iso_i)); %neglogs for consumer iso vals end %INCORPORATE PRIORS FOR source CONTRIBS neglog = neglog - sum(log(betapdf(contribution',handles.A,handles.B)+1e-100)); likelihood = exp(-(neglog)); %presto! The likelihood appears like magic % HERE COMES THE SIR... % Check whether write out is needed - also keep track of duplicates Total = Total + likelihood; Dups = 0; while Total > Threshold Dups = Dups + 1; ljump = ljump + 1; handles.L(ljump,1) = likelihood; %records all accepted likelihoods if Dups > MaxDup MaxDup = Dups; %shows the draw that got duped most before dropping Total below treshold end %WRITE OUT ACCEPTED DRAWS out_ticker = out_ticker+1; handles.contrib_out(out_ticker,:) = contribution'; handles.mix_out(out_ticker,:) = mix; %Reduce the total and try again Total = Total - Threshold; end end %DEVELOP RESULTS OF MODEL RUN BELOW..... % --- Executes during object creation, after setting all properties. axes(handles.boxplotter) %identifies the correct parent axes to put the plot boxplot(handles.contrib_out); xlabel('Sources (Same Order As The Data Files)'); ylabel('Proportional Contribution Of Each Source To The Mix'); title('Posterior Source Contributions To The Mix') if handles.printresult==1 % write out results dlmwrite('contrib_out.txt', handles.contrib_out, '\t') dlmwrite('likelihoods.txt', handles.L, '\t') end handles.runique = length(unique(handles.contrib_out,'rows'));% # of unique parameter vectors in resample handles.Lmax = max(handles.L)/sum(handles.L); % best likelihood (% of total) printout(out_ticker,MaxDup,handles.contrib_out,handles.source_num, handles.runique,handles.Lmax); guidata(hObject, handles); % --- Executes on button press in box_plot_butt. function box_plot_butt_Callback(hObject, eventdata, handles) % hObject handle to box_plot_butt (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) if handles.boxprint == 1 figure; boxplot(handles.contrib_out); xlabel('Sources (Same Order As The Data Files)'); ylabel('Proportional Contribution Of Each Source To The Mix'); title('Posterior Source Contributions To The Mix') else axes(handles.boxplotter) %identifies the correct parent axes to put the plot boxplot(handles.contrib_out); xlabel('Sources (Same Order As The Data Files)'); ylabel('Proportional Contribution Of Each Source To The Mix'); title('Posterior Source Contributions To The Mix') end % --- Executes on button press in likelihood_distrib. function likelihood_distrib_Callback(hObject, eventdata, handles) % hObject handle to likelihood_distrib (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % all accepted likelihoods relative to max accepted like (MLE) if handles.likeprint == 1 figure; hist(handles.L/max(handles.L),20); h = findobj(gca,'Type','patch'); set(h,'FaceColor','y','EdgeColor','k') xlabel('Relative Likelihood') ylabel('Count') Title('Likelihoods for SIR Resample') else axes(handles.boxplotter) %identifies the correct parent axes to put the plot hist(handles.L/max(handles.L),20); h = findobj(gca,'Type','patch'); set(h,'FaceColor','y','EdgeColor','k') xlabel('Relative Likelihood') ylabel('Count') Title('Likelihoods for SIR Resample') end % --- Executes on button press in results_check. function results_check_Callback(hObject, eventdata, handles) % hObject handle to results_check (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.printresult =get(hObject,'Value');% returns toggle state of results_check guidata(hObject,handles); % --- Executes on button press in boxprint. function boxprint_Callback(hObject, eventdata, handles) % hObject handle to boxprint (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.boxprint =get(hObject,'Value');% returns toggle state of results_check guidata(hObject,handles); % --- Executes on button press in likeprint. function likeprint_Callback(hObject, eventdata, handles) % hObject handle to likeprint (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.likeprint =get(hObject,'Value');% returns toggle state of results_check guidata(hObject,handles); % -------------------------------------------------------------------- function priorpanel_SelectionChangeFcn(hObject, eventdata, handles) % hObject handle to priorpanel (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) switch get(hObject,'Tag') % Get Tag of selected object case 'uninformative' % code piece when radiobutton1 is selected goes here priors = 0; % 0 values set prior distrib to Beta(1,1) upon program execution save 'priors.mat' priors %saves prior placeholder to working directory case 'define' % code piece when radiobutton2 is selected goes here if exist('define.txt')==2 load define.txt; %brings in defined priors A and B (columns) for each source (rows) priors(1,:) = define(1,:); priors(2,:) = define(2,:); save 'priors.mat' priors%saves prior placeholder to working directory else msgbox('ERROR: The file define.txt does not exist in the program directory','File Missing...','error') end end %--- STATUS BAR BELOW function progressbar(fractiondone, position) % Description: % progressbar(fractiondone,position) provides an indication of the progress of % some task using graphics and text. Calling progressbar repeatedly will update % the figure and automatically estimate the amount of time remaining. % This implementation of progressbar is intended to be extremely simple to use % while providing a high quality user experience. % % Features: % - Can add progressbar to existing m-files with a single line of code. % - The figure closes automatically when the task is complete. % - Only one progressbar can exist so old figures don't clutter the desktop. % - Remaining time estimate is accurate even if the figure gets closed. % - Minimal execution time. Won't slow down code. % - Random color and position options. When a programmer gets bored.... % % Usage: % fractiondone specifies what fraction (0.0 - 1.0) of the task is complete. % Typically, the figure will be updated according to that value. However, if % fractiondone == 0.0, a new figure is created (an existing figure would be % closed first). If fractiondone == 1.0, the progressbar figure will close. % position determines where the progressbar figure appears on screen. This % argument only has an effect when a progress bar is first created or is reset % by calling with fractiondone = 0. The progress bar's position can be specifed % as follows: % [x, y] - Position of lower left corner in normalized units (0.0 - 1.0) % 0 - Centered (Default) % 1 - Upper right % 2 - Upper left % 3 - Lower left % 4 - Lower right % 5 - Random [x, y] position % The color of the progressbar is choosen randomly when it is created or % reset. Clicking inside the figure will cause a random color change. % For best results, call progressbar(0) (or just progressbar) before starting % a task. This sets the proper starting time to calculate time remaining. % % Example Function Calls: % progressbar(fractiondone,position) % progressbar % Initialize/reset % progressbar(0) % Initialize/reset % progressbar(0,4) % Initialize/reset and specify position % progressbar(0,[0.2 0.7]) % Initialize/reset and specify position % progressbar(0.5) % Update % progressbar(1) % Close % % Demo: % n = 1000; % progressbar % Create figure and set starting time % for i = 1:n % pause(0.01) % Do something important % progressbar(i/n) % Update figure % end % % Author: Steve Hoelzer % % Revisions: % 2002-Feb-27 Created function % 2002-Mar-19 Updated title text order % 2002-Apr-11 Use floor instead of round for percentdone % 2002-Jun-06 Updated for speed using patch (Thanks to waitbar.m) % 2002-Jun-19 Choose random patch color when a new figure is created % 2002-Jun-24 Click on bar or axes to choose new random color % 2002-Jun-27 Calc time left, reset progress bar when fractiondone == 0 % 2002-Jun-28 Remove extraText var, add position var % 2002-Jul-18 fractiondone input is optional % 2002-Jul-19 Allow position to specify screen coordinates % 2002-Jul-22 Clear vars used in color change callback routine % 2002-Jul-29 Position input is always specified in pixels % 2002-Sep-09 Change order of title bar text % 2003-Jun-13 Change 'min' to 'm' because of built in function 'min' % 2003-Sep-08 Use callback for changing color instead of string % 2003-Sep-10 Use persistent vars for speed, modify titlebarstr % 2003-Sep-25 Correct titlebarstr for 0% case % 2003-Nov-25 Clear all persistent vars when percentdone = 100 % 2004-Jan-22 Cleaner reset process, don't create figure if percentdone = 100 % 2004-Jan-27 Handle incorrect position input % 2004-Feb-16 Minimum time interval between updates % 2004-Apr-01 Cleaner process of enforcing minimum time interval % 2004-Oct-08 Seperate function for timeleftstr, expand to include days % 2004-Oct-20 Efficient if-else structure for sec2timestr % persistent progfig progpatch starttime lastupdate % Set defaults for variables not passed in if nargin < 1 fractiondone = 0; end if nargin < 2 position = 0; end try % Access progfig to see if it exists ('try' will fail if it doesn't) dummy = get(progfig,'UserData'); % If progress bar needs to be reset, close figure and set handle to empty if fractiondone == 0 delete(progfig) % Close progress bar progfig = []; % Set to empty so a new progress bar is created end catch progfig = []; % Set to empty so a new progress bar is created end % If task completed, close figure and clear vars, then exit percentdone = floor(100*fractiondone); if percentdone == 100 % Task completed delete(progfig) % Close progress bar clear progfig progpatch starttime lastupdate % Clear persistent vars return end % Create new progress bar if needed if isempty(progfig) % Calculate position of progress bar in normalized units scrsz = [0 0 1 1]; width = scrsz(3)/4; height = scrsz(4)/50; if (length(position) == 1) hpad = scrsz(3)/64; % Padding from left or right edge of screen vpad = scrsz(4)/24; % Padding from top or bottom edge of screen left = scrsz(3)/2 - width/2; % Default bottom = scrsz(4)/2 - height/2; % Default switch position case 0 % Center % Do nothing (default) case 1 % Top-right left = scrsz(3) - width - hpad; bottom = scrsz(4) - height - vpad; case 2 % Top-left left = hpad; bottom = scrsz(4) - height - vpad; case 3 % Bottom-left left = hpad; bottom = vpad; case 4 % Bottom-right left = scrsz(3) - width - hpad; bottom = vpad; case 5 % Random left = rand * (scrsz(3)-width); bottom = rand * (scrsz(4)-height); otherwise warning('position must be (0-5). Reset to 0.') end position = [left bottom]; elseif length(position) == 2 % Error checking on position if (position(1) < 0) | (scrsz(3)-width < position(1)) position(1) = max(min(position(1),scrsz(3)-width),0); warning('Horizontal position adjusted to fit on screen.') end if (position(2) < 0) | (scrsz(4)-height < position(2)) position(2) = max(min(position(2),scrsz(4)-height),0); warning('Vertical position adjusted to fit on screen.') end else error('position is not formatted correctly') end % Initialize progress bar progfig = figure(... 'Units', 'normalized',... 'Position', [position width height],... 'NumberTitle', 'off',... 'Resize', 'off',... 'MenuBar', 'none',... 'BackingStore', 'off' ); progaxes = axes(... 'Position', [0.02 0.15 0.96 0.70],... 'XLim', [0 1],... 'YLim', [0 1],... 'Box', 'on',... 'ytick', [],... 'xtick', [] ); progpatch = patch(... 'XData', [0 0 0 0],... 'YData', [0 0 1 1],... 'EraseMode', 'none' ); set(progfig, 'ButtonDownFcn',{@changecolor,progpatch}); set(progaxes, 'ButtonDownFcn',{@changecolor,progpatch}); set(progpatch,'ButtonDownFcn',{@changecolor,progpatch}); changecolor(0,0,progpatch) % Set time of last update to ensure a redraw lastupdate = clock - 1; % Task starting time reference if isempty(starttime) | (fractiondone == 0) starttime = clock; end end % Enforce a minimum time interval between updates if etime(clock,lastupdate) < 0.01 return end % Update progress patch set(progpatch,'XData',[0 fractiondone fractiondone 0]) % Update progress figure title bar if (fractiondone == 0) titlebarstr = ' 0%'; else runtime = etime(clock,starttime); timeleft = runtime/fractiondone - runtime; timeleftstr = sec2timestr(timeleft); titlebarstr = sprintf('%2d%% %s remaining',percentdone,timeleftstr); end set(progfig,'Name',titlebarstr) % Force redraw to show changes drawnow % Record time of this update lastupdate = clock; % ------------------------------------------------------------------------------ function changecolor(h,e,progpatch) % Change the color of the progress bar patch colorlim = 2.8; % Must be <= 3.0 - This keeps the color from being too light thiscolor = rand(1,3); while sum(thiscolor) > colorlim thiscolor = rand(1,3); end set(progpatch,'FaceColor',thiscolor); % ------------------------------------------------------------------------------ function timestr = sec2timestr(sec) % Convert a time measurement from seconds into a human readable string. % Convert seconds to other units d = floor(sec/86400); % Days sec = sec - d*86400; h = floor(sec/3600); % Hours sec = sec - h*3600; m = floor(sec/60); % Minutes sec = sec - m*60; s = floor(sec); % Seconds % Create time string if d > 0 if d > 9 timestr = sprintf('%d day',d); else timestr = sprintf('%d day, %d hr',d,h); end elseif h > 0 if h > 9 timestr = sprintf('%d hr',h); else timestr = sprintf('%d hr, %d min',h,m); end elseif m > 0 if m > 9 timestr = sprintf('%d min',m); else timestr = sprintf('%d min, %d sec',m,s); end else timestr = sprintf('%d sec',s); end % --- Executes on button press in about. function about_Callback(hObject, eventdata, handles) % hObject handle to about (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA)