diff --git a/FunctionsMatlab.prj b/FunctionsMatlab.prj deleted file mode 100644 index 92c6696..0000000 --- a/FunctionsMatlab.prj +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/beamtime/FileList.mat b/beamtime/FileList.mat deleted file mode 100644 index a3cfae1..0000000 Binary files a/beamtime/FileList.mat and /dev/null differ diff --git a/beamtime/IBWread.m b/beamtime/IBWread.m deleted file mode 100644 index c45b66f..0000000 --- a/beamtime/IBWread.m +++ /dev/null @@ -1,188 +0,0 @@ -function D = IBWread(FN); -% IBWread - read Igor wave from IBW file -% D = IBWread('Foo.ibw') reads Igor file Foo.ibw into struct D. - -if exist('fullfilename', 'file'), FFN = fullfilename(FN, cd, '.ibw'); -else, FFN = FN; -end - -% read headers -[D.binHeader, D.waveHeader, FFN] = readIBWheaders(FN); -fid = fopen(FFN,'r'); -fid = fopen(FFN,'r'); -% For numeric waves, the type field is interpreted bitwise. One of the following bits, as represented by symbols defined in IgorBin.h, will be set: -% -% % #define NT_CMPLX 1 % Complex numbers. -% % #define NT_FP32 2 % 32 bit fp numbers. -% % #define NT_FP64 4 % 64 bit fp numbers. -% % #define NT_I8 8 % 8 bit signed integer. Requires Igor Pro 2.0 or later. -% % #define NT_I16 0x10 % 16 bit integer numbers. Requires Igor Pro 2.0 or later. -% % #define NT_I32 0x20 % 32 bit integer numbers. Requires Igor Pro 2.0 or later. -% % #define NT_UNSIGNED 0x40 % Makes above signed integers unsigned. Requires Igor Pro 3.0 or later. -% NT_FP64 64-bit floating point (double) -% NT_FP32 32-bit floating point (float) -% NT_I32 32 bit integer (long) -% NT_16 16 bit integer (short) -% NT_I8 8 bit integer (char) -datatype = D.waveHeader.type; -CMPLX = rem(datatype,2); -if CMPLX, datatype = datatype-1; end -switch datatype, - case 0, prec = '*char'; - case 2, prec = 'single'; - case 4, prec = 'double'; - case 8, prec = 'int8'; - case 16, prec = 'int16'; - case 32, prec = 'int32'; - case 64+8, prec = 'uint8'; - case 64+16, prec = 'uint16'; - case 64+32, prec = 'uint32'; - otherwise, error('Invalid numerical datatype.'); -end - -D.bname = D.waveHeader.bname; -% The date/time is store as seconds since midnight, January 1, 1904. -D.creationDate = local_igorTime2vec(D.waveHeader.creationDate); -D.modDate = local_igorTime2vec(D.waveHeader.creationDate); -switch D.binHeader.version, - case 2, - % The version 2 file has the following general layout. - % BinHeader2 structure: 16 bytes - % WaveHeader2 structure excluding wData field; 110 bytes - % Wave data: Variable size - D.Nsam = D.waveHeader.npnts; - D.Ndim = 1; - % X value for point p = hsA*p + hsB - D.dx = D.waveHeader.hsA; - D.x0 = D.waveHeader.hsB; - D.x1 = D.x0+D.Nsam*D.dx; - fseek(fid, 16+110, 'bof'); - NN = D.Nsam*(1+double(CMPLX)); % if complex, read twice as many numbers - D.y = fread(fid, NN, prec); - if CMPLX, D.y = D.y(1:2:end) + i*D.y(2:2:end); end; % Re & Im values are interleaved - case 5, - % The version 5 file has the following general layout. - % BinHeader5 structure 64 bytes - % WaveHeader5 structure excluding wData field 320 bytes - % Wave data Variable size - % Optional wave dependency formula Variable size - % Optional wave note data Variable size - D.Nsam = D.waveHeader.npnts; - D.Ndim = sum(D.waveHeader.nDim>0); - % X offset & spacing (documentation is obscure) - D.dx = D.waveHeader.sfA(1:D.Ndim); - D.x0 = D.waveHeader.sfB(1:D.Ndim); - D.x1 = nan; % D.x0+D.Nsam*D.dx; - fseek(fid, 64+320, 'bof'); - NN = D.Nsam*(1+double(CMPLX)); % if complex, read twice as many numbers - if isequal(0,datatype), % text data - % Number of bytes of wave data = wfmSize - (sizeof(WaveHeader5) - 4) - NN = D.binHeader.wfmSize-320; - D.y = fread(fid, NN, prec)'; - else, % numerical data - D.y = fread(fid, NN, prec); - end - if CMPLX, D.y = D.y(1:2:end) + i*D.y(2:2:end); end; % Re & Im values are interleaved - if ~isempty(D.y) && D.Ndim>1, - D.y = reshape(D.y, D.waveHeader.nDim(1:D.Ndim)); - end -end -D.WaveNotes = local_readNotes(fid, D.binHeader); -if isequal(0,datatype), % partition text data into lines using string indices stored @ eof - D = local_partition_text(fid, D); -end -fseek(fid,0,'eof'); -D.fileSize = ftell(fid); -fclose(fid); - - -%=============================== -function DV=local_igorTime2vec(it); -% igor time -> date vector a la Matlab -% The date/time is store as seconds since midnight, January 1, 1904. -Nsec_4year = 126230400; -idate_1988 = 21*uint32(Nsec_4year); % # seconds between 1-jan-1904 & 1-jan-1988 -it = double(it-idate_1988); % smaller numbers-> use ordinary numbers ("doubles") -M4 = floor(it/Nsec_4year); -YR = double(1988+4*M4); -it = double(it-M4*Nsec_4year); -last_it = it; -while 1, % subtract years as long as they fit - s = etime([YR+1 1 1 0 0 0], [YR 1 1 0 0 0]); - if it - end - - - - end - end - % import Photon Energy (cols) - try %general try to ensure that script does not stop upon errors. - try - TmpXrayEkin = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/scan 1/energy'); % X-ray excitation energy; Photon energy in eV - TmpXrayEkin(TmpXrayEkin==0)=[]; - catch - TmpXrayEkin = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/entry/instrument/NDAttributes/PhotonEnergy'); % X-ray excitation energy; Photon energy in eV - TmpXrayEkin(TmpXrayEkin==0)=[]; - end - % Make unique - [TmpFileList{2}(ii).xRayEkin_eV, ind] = unique(TmpXrayEkin); - TmpFileList{2}(ii).image = TmpImage(:,ind); - % NEXAFS pass energy - try - tmp = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/scan 1/attrs/PassEnergy'); % in eV - TmpFileList{2}(ii).scientaPassEnergy_eV = str2double(tmp(1)); - catch - tmp = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/entry/instrument/NDAttributes/PassEnergy'); % in eV - TmpFileList{2}(ii).scientaPassEnergy_eV = str2double(tmp(1)); - end - % Acquisition mode - try - TmpFileList{2}(ii).scientaAcquisitionMode = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/scan 1/attrs/AcquisitionMode'); - catch - TmpFileList{2}(ii).scientaAcquisitionMode = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/entry/instrument/NDAttributes/AcquireMode'); - end - if strcmp(TmpFileList{2}(ii).scientaAcquisitionMode,'Fixed') - % NEXAFS kinetic energy window - fixed mode - try - tmp = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/scan 1/attrs/ScientaCenterEnergy'); % in eV - catch - tmp = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/entry/instrument/NDAttributes/CenterEnergy'); % in eV - end - TmpFileList{2}(ii).scientaEkinRange_eV = [tmp(1)-TmpFileList{2}(ii).scientaPassEnergy_eV/20 tmp(1)+TmpFileList{2}(ii).scientaPassEnergy_eV/20]; - TmpFileList{2}(ii).scientaEkinStep_eV = NaN; - TmpFileList{2}(ii).scientaEkin_eV = linspace(TmpFileList{2}(ii).scientaEkinRange_eV(:,1)... - ,TmpFileList{2}(ii).scientaEkinRange_eV(:,2),size(TmpFileList{2}(ii).image,1))'; - else - % NEXAFS kinetic energy window - scan mode - try - tmp = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/scan 1/attrs/ScientaLowEnergy'); % in eV - tmp2 = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/scan 1/attrs/ScientaHighEnergy'); - catch - tmp = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/entry/instrument/NDAttributes/LowEnergy'); % in eV - tmp2 = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/entry/instrument/NDAttributes/HighEnergy'); - end - TmpFileList{2}(ii).scientaEkinRange_eV = [tmp(1) tmp2(1)]; - try - TmpFileList{2}(ii).scientaEkinStep_eV = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/scan 1/attrs/StepSize'); - catch - TmpFileList{2}(ii).scientaEkinStep_eV = h5read([TmpFileList{2}(ii).folder filesep TmpFileList{2}(ii).name],'/entry/instrument/NDAttributes/StepSize'); - end - TmpFileList{2}(ii).scientaEkin_eV = [TmpFileList{2}(ii).scientaEkinRange_eV(:,1):TmpFileList{2}(ii).scientaEkinStep_eV(1):TmpFileList{2}(ii).scientaEkinRange_eV(:,2)]'; - end - catch - end -end -%% Merge lists into one -% - -% get index of non-empty structures -tf =~cellfun(@isempty,TmpFileList); - -% merge the non-empty list structures into one structure -ListFiles = cat(1,TmpFileList{tf}); - -% remove lines with empty images -for ii = 1:size(ListFiles,1) - tmpLogic(ii) = isempty(ListFiles(ii).image); - noncells = tmpLogic; -end -ListFiles(noncells) = []; - -clearvars -except ListFiles DataTable - - -%% - - - -%% Sort by date -% rename date fields and delete those fields not needed -[ListFiles.lastModifiedDatestr] = ListFiles.date; -[ListFiles.lastModifiedDatenum] = ListFiles.datenum; - -% First, we need to convert into a table, because structures can not be sorted: -ListFiles = struct2table(ListFiles,'AsArray',true); -% Then, we sort the table based on the time (6th column, datenum) -ListFiles = sortrows(ListFiles,6); -% Then, remove un-needed columns -ListFiles = removevars(ListFiles,{'bytes','isdir','date','datenum'}); - -% merge tables (append imported data to previous table) -if exist("DataTable",'var') - ListFiles = outerjoinRowToTable(ListFiles,DataTable); -end -% Then, we sort the table based on the time (datenum) -ListFiles = sortrows(ListFiles,'lastModifiedDatenum'); -end \ No newline at end of file diff --git a/beamtime/WriteH5.m b/beamtime/WriteH5.m deleted file mode 100644 index 5132e64..0000000 --- a/beamtime/WriteH5.m +++ /dev/null @@ -1,134 +0,0 @@ -%% Develpment of hdf export and import -% -% from table to our instrument hdf structure -%% Todo -% -% * ensure logging of processing in NEXAFS and XPS to select data, make it -% usfull for string operations (no cells) -% * How to include units and definitions -% * Next, make this work for averageded files -%% -clc -% % add some SES data -%tmpFileImport = load('../beamtimes/20220828BeamTimeIceNappIss/FileList.mat'); -% FileList = outerjoinRowToTable(FileList, tmpFileImport.FileList); -clearvars tmp* -% select only data that has been used, -[tmpn1, ~] = cellfun(@size,FileList.spectrum_counts); % spectra have been generated -[tmpn2, ~] = cellfun(@size,FileList.spectrum_countsNorm); -[tmpn3, ~] = cellfun(@size,FileList.spectrum_countsPerSecond); -tmpDataSelection = contains(FileList.sample,lettersPattern) ... % we have added sample notes, so this is data - & ~contains(FileList.sample, '(bad data)') & ~contains(FileList.sample, '(no notes)') ... - & (tmpn1 > 1 | tmpn2 > 1 | tmpn3 > 1); % has actually been proceesed. - - - -tmpUserName = 'ThorstenBR'; -tmpFileList = FileList(tmpDataSelection,:); -% get table variables that are data -tmpMissingVariable = ~ismember(tmpFileList.Properties.VariableNames,... - [{'image'}; {'spectrum_counts'}; {'spectrum_countsPerSecond'}; {'spectrum_countsNorm'}; {'xRayEkin_eV'}; {'scientaEkin_eV'}; {'imageRoh'}; {'spectrum_countsPerSecondRoh'};{'beamlineInt'}]); -tmpVariablesToBeAdded = tmpFileList.Properties.VariableNames(tmpMissingVariable); - -for ij = 1:size(tmpFileList,1) - % get file name and "instruement" name - tmpPathParts = split(tmpFileList(ij,:).folder,"/"); - tmpFileName = [tmpPathParts{end-1} tmpUserName '.h5']; - tmpTopGroupName = tmpPathParts{end}; - % write data - h5create(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/image'],... - size(tmpFileList(ij,:).image{:})); - h5write(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/image'],... - tmpFileList(ij,:).image{:}) - if %XPS - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/image'],'label','electron emission intensity'); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/image'],'units','XPS (y,x): counts per second vs. electron volt; NEXAFS (y,x,z): counts vs. X-ray photon kinetic energy vs. electron kinetic energy'); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/image'],'definition','X-ray excited electron emission'); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/image'],'comment','XPS: intensity vs. electron kinetic energy for each sequence iteration; NEXAFS: intensity vs. x-ray photon kinetic energy (non-linear scaling) vs. electron kinetic energy'); - else %NEXAFS - - end - - try - h5create(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_counts'],... - size(tmpFileList(ij,:).spectrum_counts{:})); - h5write(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_counts'],... - tmpFileList(ij,:).spectrum_counts{:}) - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_counts'],'label','electron emission intensity'); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_counts'],'units','arb. unit'); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_counts'],'definition','X-ray excited electron emission'); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_counts'],'comment',' '); - catch - end - try - h5create(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsPerSecond'],... - size(tmpFileList(ij,:).spectrum_countsPerSecond{:})); - h5write(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsPerSecond'],... - tmpFileList(ij,:).spectrum_countsPerSecond{:}) - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsPerSecond'],'label',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsPerSecond'],'units',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsPerSecond'],'definition',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsPerSecond'],'comment',' '); - catch - end - try - h5create(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsNorm'],... - size(tmpFileList(ij,:).spectrum_countsNorm{:})); - h5write(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsNorm'],... - tmpFileList(ij,:).spectrum_countsNorm{:}) - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsNorm'],'label',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsNorm'],'units',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsNorm'],'definition',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/spectrum_countsNorm'],'comment',' '); - catch - end - try - h5create(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/beamlineInt'],... - size(tmpFileList(ij,:).beamlineInt{:})); - h5write(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/beamlineInt'],... - tmpFileList(ij,:).beamlineInt{:}) - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/beamlineInt'],'label',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/beamlineInt'],'units',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/beamlineInt'],'definition',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/beamlineInt'],'comment',' '); - catch - end - h5create(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/xRayEkin_eV'],... - size(tmpFileList(ij,:).xRayEkin_eV{:})); - h5write(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/xRayEkin_eV'],... - tmpFileList(ij,:).xRayEkin_eV{:}) - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/xRayEkin_eV'],'label',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/xRayEkin_eV'],'units',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/xRayEkin_eV'],'definition',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/xRayEkin_eV'],'comment',' '); - - h5create(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/scientaEkin_eV'],... - size(tmpFileList(ij,:).scientaEkin_eV{:})); - h5write(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/scientaEkin_eV'],... - tmpFileList(ij,:).scientaEkin_eV{:}) - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/scientaEkin_eV'],'label',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/scientaEkin_eV'],'units',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/scientaEkin_eV'],'definition',' '); - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:} '/scientaEkin_eV'],'comment',' '); - % add attributes - tmpCells= []; % create empty array - for ii = 1:size(tmpVariablesToBeAdded,2) - - if matches(class(tmpFileList.(tmpVariablesToBeAdded{ii})),'cell') - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:}],tmpVariablesToBeAdded{ii},tmpFileList(ij,:).(tmpVariablesToBeAdded{ii}){:}); - tmpCells = [tmpCells,', ' tmpVariablesToBeAdded{ii}]; - else - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:}],tmpVariablesToBeAdded{ii},tmpFileList(ij,:).(tmpVariablesToBeAdded{ii})); - end - % write variables that were cells to a list; so upon import the - % variable type can be set again. - h5writeatt(tmpFileName,['/' tmpTopGroupName '/' tmpFileList(ij,:).name{:}],'matlabVariablesThatAreCells',tmpCells); - - end - clearvars tmpCells - - -end -disp('*************************************************') -disp('* Voila: HDF file(s) written *') -disp('*************************************************') diff --git a/beamtime/brewermap.m b/beamtime/brewermap.m deleted file mode 100644 index f5797a1..0000000 --- a/beamtime/brewermap.m +++ /dev/null @@ -1,473 +0,0 @@ -function [map,num,typ,scheme] = brewermap(N,scheme) -% The complete selection of ColorBrewer colorschemes/palettes (RGB colormaps). -% -% Returns an RGB colormap from Cynthia Brewer's ColorBrewer 2.0 palettes, -% intended for mapping and plots with attractive, distinguishable colors. -% -%%% Basic Syntax %%% -% -% brewermap() % print summary -% map = brewermap(N,scheme) -% -%%% Preset Syntax %%% -% -% old = brewermap(scheme) -% map = brewermap() -% map = brewermap(N) -% -% [...,num,typ] = brewermap(...) -% -%% Colorschemes %% -% -% This product includes color specifications and designs developed by Cynthia Brewer. -% See the ColorBrewer website for further information about each colorscheme, -% colour-blind suitability, licensing, and citations: http://colorbrewer.org/ -% Each colorscheme is defined by a set of hand-picked RGB values (nodes). -% -% To reverse the colormap sequence prefix the colorscheme name with '-'. -% -% Diverging | Qualitative | Sequential -% ----------|-------------|------------------ -% BrBG | Accent | Blues PuBuGn -% PiYG | Dark2 | BuGn PuRd -% PRGn | Paired | BuPu Purples -% PuOr | Pastel1 | GnBu RdPu -% RdBu | Pastel2 | Greens Reds -% RdGy | Set1 | Greys YlGn -% RdYlBu | Set2 | OrRd YlGnBu -% RdYlGn | Set3 | Oranges YlOrBr -% Spectral | | PuBu YlOrRd -% -% If is greater than the requested colorscheme's defining nodes then: -% - Diverging and Sequential colorschemes are interpolated. -% - Qualitative colorschemes repeat the nodes (i.e. just like LINES does). -% Else: -% - Exact values from the ColorBrewer colorschemes are returned. -% -%% Examples %% -% -%%% New colors for the COLORMAP example %%% -% -% >> S = load('spine'); -% >> image(S.X) -% >> colormap(brewermap([],"YlGnBu")) -% -%%% New colors for the SURF example %%% -% -% >> [X,Y,Z] = peaks(30); -% >> surfc(X,Y,Z) -% >> colormap(brewermap([],'RdYlGn')) -% >> axis([-3,3,-3,3,-10,5]) -% -%%% Plot a colorscheme's RGB values %%% -% -% >> rgbplot(brewermap(NaN, '+Blues')) % standard -% >> rgbplot(brewermap(NaN, '-Blues')) % reversed -% -%%% View information about a colorscheme %%% -% -% >> [~,num,typ] = brewermap(NaN,'Paired') -% num = 12 -% typ = 'Qualitative' -% -%%% Multi-line plot using matrices %%% -% -% >> N = 6; -% >> axes('ColorOrder',brewermap(N,'Pastel2'),'NextPlot','replacechildren') -% >> X = linspace(0,pi*3,1000); -% >> Y = bsxfun(@(x,n)n*sin(x+2*n*pi/N), X(:), 1:N); -% >> plot(X,Y, 'linewidth',4) -% -%%% Multi-line plot in a loop %%% -% -% set(0,'DefaultAxesColorOrder',brewermap(NaN,'Accent')) -% N = 6; -% X = linspace(0,pi*3,1000); -% Y = bsxfun(@(x,n)n*sin(x+2*n*pi/N), X(:), 1:N); -% for n = 1:N -% plot(X(:),Y(:,n), 'linewidth',4); -% hold all -% end -% -%% Input Arguments (**=default) %% -% -% N = NumericScalar, N>=0, an integer to specify the colormap length. -% = []**, map has the same length as MATLAB's inbuilt colormap functions. -% = NaN, map is exactly the defining RGB nodes (useful for line ColorOrder). -% scheme = CharRowVector or StringScalar, a ColorBrewer colorscheme name. -% -%% Output Arguments %% -% -% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. -% num = NumericVector, the number of nodes defining the ColorBrewer colorscheme. -% typ = CharRowVector, the colorscheme type: 'Diverging'/'Qualitative'/'Sequential'. -% -%% Dependencies %% -% -% * MATLAB R2009a or later. -% -% See also BREWERMAP_NODES BREWERMAP_VIEW PRESET_COLORMAP CUBEHELIX MAXDISTCOLOR -% LBMAP PARULA LINES RGBPLOT COLORMAP COLORBAR PLOT PLOT3 AXES SET CONTOURF -persistent bmc scm txt -% -if isempty(bmc) - bmc = bmStruct(); -end -% -%% Input Wrangling %% -% -if nargin==0 - N = []; -end -% -err = 'First input must be a real positive scalar numeric or [] or NaN.'; -% -if nargout==0 && nargin==0 - hdr = { 'Type'; 'Scheme'; 'Nodes'}; - tsn = [{bmc.typ};{bmc.str};{bmc.num}]; - fprintf('%-12s %-9s %s\n',hdr{:}); - fprintf('%-12s %-9s %u\n',tsn{:}); - return -elseif isnumeric(N) - if isequal(N,[]) - % Default N is the same as MATLAB colormaps: - N = cmDefaultN(); - else - assert(isscalar(N),... - 'SC:brewermap:N:NotScalarNumeric',err) - assert(isnan(N) || isreal(N)&&isfinite(N)&&fix(N)==N&&N>=0,... - 'SC:brewermap:N:NotWholeRealNotNaN',err) - N = double(N); - end - if nargin<2 - assert(~isempty(scm),... - 'SC:colorbrewer:scheme:NotPreset',... - 'Colorscheme must be preset before this call: BREWERMAP(SCHEME)') - scheme = scm; - else - scheme = bm1s2c(scheme); - assert(ischar(scheme)&&ndims(scheme)==2&&size(scheme,1)==1,... - 'SC:brewermap:scheme:NotText',... - 'Input must be a character vector or a string scalar.') %#ok - end -else % preset - assert(nargin<2,... - 'SC:brewermap:WrongArgumentNumber',... - 'If calling with two inputs then the 1st input must be numeric.') - scheme = bm1s2c(N); - assert(ischar(scheme)&&ndims(scheme)==2&&size(scheme,1)==1,... - 'SC:brewermap:N:NotText',... - 'To preset: the scheme must be a character vector or a string scalar.') %#ok - if strcmpi(scheme,'list') - map = {bmc.str}; - num = [bmc.num]; - typ = {bmc.typ}; - return - end -end -% -isr = strncmp(scheme,'-',1) || strncmp(scheme,'*',1); -isd = strncmp(scheme,'+',1) || isr; % direction -ids = strcmpi(scheme(1+isd:end),{bmc.str}); -assert(any(ids),... - 'SC:brewermap:scheme:UnknownColorscheme',... - 'Unknown colorscheme name: "%s"',scheme) -% -num = bmc(ids).num; -typ = bmc(ids).typ; -% -if ~isnumeric(N) % preset - map = txt; - txt = N; - scm = scheme; - return -elseif N==0 - map = nan(0,3); - return -elseif isnan(N) - N = num; -end -% -% Downsample: -[idx,itp] = bmIndex(N,num,typ); -% -map = bmc(ids).rgb(idx,:)/255; -% -% Interpolate: -if itp - % - % Extrapolate a small amount beyond the end nodes: - %ido = linspace(0,num+1,N+2); - %ido = ido(2:end-1); - % Interpolation completely within the end nodes: - ido = linspace(1,num,N); - % - switch typ - case 'Diverging' - mid = ceil(num/2); - idl = 1:mid; - idr = mid:num; - map = [... - interp1(idl,map(idl,:),ido(ido<=mid),'pchip');... - interp1(idr,map(idr,:),ido(ido>mid),'pchip')]; - case 'Sequential' - map = interp1(1:num,map,ido,'pchip'); - otherwise - error('SC:brewermap:Interp:UnknownType','Unknown colorscheme type.') - end - % -end -% -% Limit output range: -map = max(0,min(1,map)); -% -% Reverse row order: -if isr - map = map(end:-1:1,:); -end -% -end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%brewermap -function N = cmDefaultN() -% Get the colormap size from the current figure or default colormap. -try - F = get(groot,'CurrentFigure'); -catch %#ok pre HG2 - N = size(get(gcf,'colormap'),1); - return -end -if isempty(F) - N = size(get(groot,'DefaultFigureColormap'),1); -else - N = size(F.Colormap,1); -end -end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%cmDefaultN -function arr = bm1s2c(arr) -% If scalar string then extract the character vector, otherwise data is unchanged. -if isa(arr,'string') && isscalar(arr) - arr = arr{1}; -end -end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bm1s2c -function [idx,itp] = bmIndex(N,num,typ) -% Ensure exactly the same colors as the online ColorBrewer colorschemes. -% -switch typ - case 'Qualitative' - itp = false; - idx = 1+mod(0:N-1,num); - case 'Diverging' - itp = N>num; - switch N - case 1 % extrapolated - idx = 8; - case 2 % extrapolated - idx = [4,12]; - case 3 - idx = [5,8,11]; - case 4 - idx = [3,6,10,13]; - case 5 - idx = [3,6,8,10,13]; - case 6 - idx = [2,5,7,9,11,14]; - case 7 - idx = [2,5,7,8,9,11,14]; - case 8 - idx = [2,4,6,7,9,10,12,14]; - case 9 - idx = [2,4,6,7,8,9,10,12,14]; - case 10 - idx = [1,2,4,6,7,9,10,12,14,15]; - otherwise - idx = [1,2,4,6,7,8,9,10,12,14,15]; - end - case 'Sequential' - itp = N>num; - switch N - case 1 % extrapolated - idx = 6; - case 2 % extrapolated - idx = [4,8]; - case 3 - idx = [3,6,9]; - case 4 - idx = [2,5,7,10]; - case 5 - idx = [2,5,7,9,11]; - case 6 - idx = [2,4,6,7,9,11]; - case 7 - idx = [2,4,6,7,8,10,12]; - case 8 - idx = [1,3,4,6,7,8,10,12]; - otherwise - idx = [1,3,4,6,7,8,10,11,13]; - end - otherwise - error('SC:brewermap:Index:UnknownType','Unknown colorscheme type.') -end -% -end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bmIndex -function bmc = bmStruct() -% Return a structure of all colorschemes: name, scheme type, RGB values, number of nodes. -% Order: sorted first by , then case-insensitive sorted by . -bmc(35).str = 'YlOrRd'; -bmc(35).typ = 'Sequential'; -bmc(35).rgb = [255,255,204;255,255,178;255,237,160;254,217,118;254,204,92;254,178,76;253,141,60;252,78,42;240,59,32;227,26,28;189,0,38;177,0,38;128,0,38]; -bmc(34).str = 'YlOrBr'; -bmc(34).typ = 'Sequential'; -bmc(34).rgb = [255,255,229;255,255,212;255,247,188;254,227,145;254,217,142;254,196,79;254,153,41;236,112,20;217,95,14;204,76,2;153,52,4;140,45,4;102,37,6]; -bmc(33).str = 'YlGnBu'; -bmc(33).typ = 'Sequential'; -bmc(33).rgb = [255,255,217;255,255,204;237,248,177;199,233,180;161,218,180;127,205,187;65,182,196;29,145,192;44,127,184;34,94,168;37,52,148;12,44,132;8,29,88]; -bmc(32).str = 'YlGn'; -bmc(32).typ = 'Sequential'; -bmc(32).rgb = [255,255,229;255,255,204;247,252,185;217,240,163;194,230,153;173,221,142;120,198,121;65,171,93;49,163,84;35,132,67;0,104,55;0,90,50;0,69,41]; -bmc(31).str = 'Reds'; -bmc(31).typ = 'Sequential'; -bmc(31).rgb = [255,245,240;254,229,217;254,224,210;252,187,161;252,174,145;252,146,114;251,106,74;239,59,44;222,45,38;203,24,29;165,15,21;153,0,13;103,0,13]; -bmc(30).str = 'RdPu'; -bmc(30).typ = 'Sequential'; -bmc(30).rgb = [255,247,243;254,235,226;253,224,221;252,197,192;251,180,185;250,159,181;247,104,161;221,52,151;197,27,138;174,1,126;122,1,119;122,1,119;73,0,106]; -bmc(29).str = 'Purples'; -bmc(29).typ = 'Sequential'; -bmc(29).rgb = [252,251,253;242,240,247;239,237,245;218,218,235;203,201,226;188,189,220;158,154,200;128,125,186;117,107,177;106,81,163;84,39,143;74,20,134;63,0,125]; -bmc(28).str = 'PuRd'; -bmc(28).typ = 'Sequential'; -bmc(28).rgb = [247,244,249;241,238,246;231,225,239;212,185,218;215,181,216;201,148,199;223,101,176;231,41,138;221,28,119;206,18,86;152,0,67;145,0,63;103,0,31]; -bmc(27).str = 'PuBuGn'; -bmc(27).typ = 'Sequential'; -bmc(27).rgb = [255,247,251;246,239,247;236,226,240;208,209,230;189,201,225;166,189,219;103,169,207;54,144,192;28,144,153;2,129,138;1,108,89;1,100,80;1,70,54]; -bmc(26).str = 'PuBu'; -bmc(26).typ = 'Sequential'; -bmc(26).rgb = [255,247,251;241,238,246;236,231,242;208,209,230;189,201,225;166,189,219;116,169,207;54,144,192;43,140,190;5,112,176;4,90,141;3,78,123;2,56,88]; -bmc(25).str = 'Oranges'; -bmc(25).typ = 'Sequential'; -bmc(25).rgb = [255,245,235;254,237,222;254,230,206;253,208,162;253,190,133;253,174,107;253,141,60;241,105,19;230,85,13;217,72,1;166,54,3;140,45,4;127,39,4]; -bmc(24).str = 'OrRd'; -bmc(24).typ = 'Sequential'; -bmc(24).rgb = [255,247,236;254,240,217;254,232,200;253,212,158;253,204,138;253,187,132;252,141,89;239,101,72;227,74,51;215,48,31;179,0,0;153,0,0;127,0,0]; -bmc(23).str = 'Greys'; -bmc(23).typ = 'Sequential'; -bmc(23).rgb = [255,255,255;247,247,247;240,240,240;217,217,217;204,204,204;189,189,189;150,150,150;115,115,115;99,99,99;82,82,82;37,37,37;37,37,37;0,0,0]; -bmc(22).str = 'Greens'; -bmc(22).typ = 'Sequential'; -bmc(22).rgb = [247,252,245;237,248,233;229,245,224;199,233,192;186,228,179;161,217,155;116,196,118;65,171,93;49,163,84;35,139,69;0,109,44;0,90,50;0,68,27]; -bmc(21).str = 'GnBu'; -bmc(21).typ = 'Sequential'; -bmc(21).rgb = [247,252,240;240,249,232;224,243,219;204,235,197;186,228,188;168,221,181;123,204,196;78,179,211;67,162,202;43,140,190;8,104,172;8,88,158;8,64,129]; -bmc(20).str = 'BuPu'; -bmc(20).typ = 'Sequential'; -bmc(20).rgb = [247,252,253;237,248,251;224,236,244;191,211,230;179,205,227;158,188,218;140,150,198;140,107,177;136,86,167;136,65,157;129,15,124;110,1,107;77,0,75]; -bmc(19).str = 'BuGn'; -bmc(19).typ = 'Sequential'; -bmc(19).rgb = [247,252,253;237,248,251;229,245,249;204,236,230;178,226,226;153,216,201;102,194,164;65,174,118;44,162,95;35,139,69;0,109,44;0,88,36;0,68,27]; -bmc(18).str = 'Blues'; -bmc(18).typ = 'Sequential'; -bmc(18).rgb = [247,251,255;239,243,255;222,235,247;198,219,239;189,215,231;158,202,225;107,174,214;66,146,198;49,130,189;33,113,181;8,81,156;8,69,148;8,48,107]; -bmc(17).str = 'Set3'; -bmc(17).typ = 'Qualitative'; -bmc(17).rgb = [141,211,199;255,255,179;190,186,218;251,128,114;128,177,211;253,180,98;179,222,105;252,205,229;217,217,217;188,128,189;204,235,197;255,237,111]; -bmc(16).str = 'Set2'; -bmc(16).typ = 'Qualitative'; -bmc(16).rgb = [102,194,165;252,141,98;141,160,203;231,138,195;166,216,84;255,217,47;229,196,148;179,179,179]; -bmc(15).str = 'Set1'; -bmc(15).typ = 'Qualitative'; -bmc(15).rgb = [228,26,28;55,126,184;77,175,74;152,78,163;255,127,0;255,255,51;166,86,40;247,129,191;153,153,153]; -bmc(14).str = 'Pastel2'; -bmc(14).typ = 'Qualitative'; -bmc(14).rgb = [179,226,205;253,205,172;203,213,232;244,202,228;230,245,201;255,242,174;241,226,204;204,204,204]; -bmc(13).str = 'Pastel1'; -bmc(13).typ = 'Qualitative'; -bmc(13).rgb = [251,180,174;179,205,227;204,235,197;222,203,228;254,217,166;255,255,204;229,216,189;253,218,236;242,242,242]; -bmc(12).str = 'Paired'; -bmc(12).typ = 'Qualitative'; -bmc(12).rgb = [166,206,227;31,120,180;178,223,138;51,160,44;251,154,153;227,26,28;253,191,111;255,127,0;202,178,214;106,61,154;255,255,153;177,89,40]; -bmc(11).str = 'Dark2'; -bmc(11).typ = 'Qualitative'; -bmc(11).rgb = [27,158,119;217,95,2;117,112,179;231,41,138;102,166,30;230,171,2;166,118,29;102,102,102]; -bmc(10).str = 'Accent'; -bmc(10).typ = 'Qualitative'; -bmc(10).rgb = [127,201,127;190,174,212;253,192,134;255,255,153;56,108,176;240,2,127;191,91,23;102,102,102]; -bmc(09).str = 'Spectral'; -bmc(09).typ = 'Diverging'; -bmc(09).rgb = [158,1,66;213,62,79;215,25,28;244,109,67;252,141,89;253,174,97;254,224,139;255,255,191;230,245,152;171,221,164;153,213,148;102,194,165;43,131,186;50,136,189;94,79,162]; -bmc(08).str = 'RdYlGn'; -bmc(08).typ = 'Diverging'; -bmc(08).rgb = [165,0,38;215,48,39;215,25,28;244,109,67;252,141,89;253,174,97;254,224,139;255,255,191;217,239,139;166,217,106;145,207,96;102,189,99;26,150,65;26,152,80;0,104,55]; -bmc(07).str = 'RdYlBu'; -bmc(07).typ = 'Diverging'; -bmc(07).rgb = [165,0,38;215,48,39;215,25,28;244,109,67;252,141,89;253,174,97;254,224,144;255,255,191;224,243,248;171,217,233;145,191,219;116,173,209;44,123,182;69,117,180;49,54,149]; -bmc(06).str = 'RdGy'; -bmc(06).typ = 'Diverging'; -bmc(06).rgb = [103,0,31;178,24,43;202,0,32;214,96,77;239,138,98;244,165,130;253,219,199;255,255,255;224,224,224;186,186,186;153,153,153;135,135,135;64,64,64;77,77,77;26,26,26]; -bmc(05).str = 'RdBu'; -bmc(05).typ = 'Diverging'; -bmc(05).rgb = [103,0,31;178,24,43;202,0,32;214,96,77;239,138,98;244,165,130;253,219,199;247,247,247;209,229,240;146,197,222;103,169,207;67,147,195;5,113,176;33,102,172;5,48,97]; -bmc(04).str = 'PuOr'; -bmc(04).typ = 'Diverging'; -bmc(04).rgb = [127,59,8;179,88,6;230,97,1;224,130,20;241,163,64;253,184,99;254,224,182;247,247,247;216,218,235;178,171,210;153,142,195;128,115,172;94,60,153;84,39,136;45,0,75]; -bmc(03).str = 'PRGn'; -bmc(03).typ = 'Diverging'; -bmc(03).rgb = [64,0,75;118,42,131;123,50,148;153,112,171;175,141,195;194,165,207;231,212,232;247,247,247;217,240,211;166,219,160;127,191,123;90,174,97;0,136,55;27,120,55;0,68,27]; -bmc(02).str = 'PiYG'; -bmc(02).typ = 'Diverging'; -bmc(02).rgb = [142,1,82;197,27,125;208,28,139;222,119,174;233,163,201;241,182,218;253,224,239;247,247,247;230,245,208;184,225,134;161,215,106;127,188,65;77,172,38;77,146,33;39,100,25]; -bmc(01).str = 'BrBG'; -bmc(01).typ = 'Diverging'; -bmc(01).rgb = [84,48,5;140,81,10;166,97,26;191,129,45;216,179,101;223,194,125;246,232,195;245,245,245;199,234,229;128,205,193;90,180,172;53,151,143;1,133,113;1,102,94;0,60,48]; -% Number of nodes: -for k = 1:numel(bmc) - switch bmc(k).typ - case 'Diverging' - bmc(k).num = 11; - case 'Qualitative' - bmc(k).num = size(bmc(k).rgb,1); - case 'Sequential' - bmc(k).num = 9; - otherwise - error('SC:brewermap:Struct:UnknownType','Unknown colorscheme type.') - end -end -% -end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bmStruct -% -% Code and Implementation: -% Copyright (c) 2014-2025 Stephen Cobeldick -% Color Values Only: -% Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University. -% -% Licensed under the Apache License, Version 2.0 (the "License"); -% you may not use this file except in compliance with the License. -% You may obtain a copy of the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, -% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -% See the License for the specific language governing permissions and limitations under the License. -% -% Redistribution and use in source and binary forms, with or without -% modification, are permitted provided that the following conditions are met: -% -% 1. Redistributions as source code must retain the above copyright notice, this -% list of conditions and the following disclaimer. -% -% 2. The end-user documentation included with the redistribution, if any, must -% include the following acknowledgment: "This product includes color -% specifications and designs developed by Cynthia Brewer -% (http://colorbrewer.org/)." Alternately, this acknowledgment may appear in the -% software itself, if and wherever such third-party acknowledgments normally appear. -% -% 4. The name "ColorBrewer" must not be used to endorse or promote products -% derived from this software without prior written permission. For written -% permission, please contact Cynthia Brewer at cbrewer@psu.edu. -% -% 5. Products derived from this software may not be called "ColorBrewer", nor -% may "ColorBrewer" appear in their name, without prior written permission of Cynthia Brewer. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%license \ No newline at end of file diff --git a/beamtime/brewermap_nodes.m b/beamtime/brewermap_nodes.m deleted file mode 100644 index 61a6708..0000000 --- a/beamtime/brewermap_nodes.m +++ /dev/null @@ -1,63 +0,0 @@ -function brewermap_nodes() -% Create a figure showing all ColorBrewer 2.0 colorschemes' defining nodes. -% -% (c) 2014-2025 Stephen Cobeldick -% -% View Cynthia Brewer's ColorBrewer 2.0 colorschemes/palettes in a figure: -% -% * Each row of the figure shows the defining nodes for one colorscheme. -% * Text with all colorschemes' names. -% * Text with all colorschemes' types (Diverging/Qualitative/Sequential). -% -%%% Syntax %%% -% -% brewermap_nodes() -% -%% Dependencies %% -% -% * MATLAB R2009a or later. -% * brewermap.m -% -% See also BREWERMAP BREWERMAP_VIEW CUBEHELIX MAXDISTCOLOR -% LBMAP PARULA LINES RGBPLOT COLORMAP COLORBAR PLOT PLOT3 AXES SET -persistent cbh axh -% -[mcs,nmn,pyt] = brewermap('list'); -% -xmx = max(nmn); -ymx = numel(pyt); -% -if ishghandle(cbh) - figure(cbh); - delete(axh); -else - cbh = figure('HandleVisibility','callback', 'IntegerHandle','off',... - 'NumberTitle','off', 'Name',mfilename,... - 'MenuBar','figure', 'Toolbar','none', 'Tag',mfilename); - set(cbh,'Units','pixels') - pos = get(cbh,'Position'); - pos(1:2) = pos(1:2) - 123; - pos(3:4) = max(pos(3:4),[842,532]); - set(cbh,'Position',pos) -end -% -axh = axes('Parent',cbh, 'Color','none',... - 'XTick',0:xmx, 'YTick',0.5:ymx, 'YTickLabel',mcs, 'YDir','reverse'); -title(axh,'ColorBrewer Color Schemes (brewermap.m)', 'Interpreter','none') -xlabel(axh,'Scheme Nodes') -ylabel(axh,'Scheme Name') -axf = get(axh,'FontName'); -% -for y = 1:ymx - N = nmn(y); - M = brewermap(N,mcs{y}); - for x = 1:N - patch([x-1,x-1,x,x],[y-1,y,y,y-1],1, 'FaceColor',M(x,:), 'Parent',axh) - end - text(xmx+0.1,y-0.5,pyt{y}, 'Parent',axh, 'FontName',axf) -end -% -drawnow() -% -end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%brewermap_nodes \ No newline at end of file diff --git a/beamtime/brewermap_view.m b/beamtime/brewermap_view.m deleted file mode 100644 index e7ec245..0000000 --- a/beamtime/brewermap_view.m +++ /dev/null @@ -1,408 +0,0 @@ -function [map,num,typ,scheme] = brewermap_view(N,scheme,isco) -% Create an interactive figure for viewing ColorBrewer colormaps. With demo! -% -% (c) 2014-2025 Stephen Cobeldick -% -% View Cynthia Brewer's ColorBrewer 2.0 colorschemes/palettes in a figure: -% -% * Two colorbars give the colorscheme in color and grayscale. -% * A button toggles between 3D-cube and 2D-lineplot of the RGB values. -% * A button toggles an endless demo cycle through the colorschemes. -% * A button reverses the colormap. -% * Thirty-five buttons select any ColorBrewer colorscheme. -% * Text with the colorscheme's type (Diverging/Qualitative/Sequential). -% * Text with the colorscheme's number of nodes (i.e. defining colors). -% -%%% Syntax %%% -% -% brewermap_view -% brewermap_view(N) -% brewermap_view(N,scheme) -% brewermap_view(N,scheme,isco) -% brewermap_view([],...) -% brewermap_view(axes/figure handle array,...) % see "Adjust Colormaps" -% [map,num,typ] = brewermap_view(...) -% -% Calling the function with an output argument blocks MATLAB execution until -% the figure is deleted: the final colormap and parameters are then returned. -% -%% Adjust Colormaps or Colororders of Figures or Axes %% -% -% For R2014b or later: provide axes or figure handles as the first input -% and their COLORMAP will be updated in real-time by BREWERMAP_VIEW. -% For R2019b or later: set the 3rd input to TRUE to update COLORORDER. -% -% >> S = load('spine'); -% >> image(S.X) -% >> brewermap_view(gca) % colormap -% -% >> plot(rand(5,7)) -% >> brewermap_view(gca,[],true) % colororder -% -%% Input Arguments (**=default) %% -% -% N = NumericScalar, an integer to define the colormap length. -% = []**, colormap length of two hundred and fifty-six (256). -% = NaN, same length as the defining RGB nodes (useful for Line ColorOrder). -% = Array of axes or figure handles. R2014b or later only. -% scheme = CharRowVector or StringScalar, a ColorBrewer colorscheme name. -% = []** randomly selects a colorscheme. -% isco = LogicalScalar, true/false** updates the colororder/colormap of -% the provided axes or figure handles. R2019b or later only. -% -%% Output Arguments (block code execution until figure is closed) %% -% -% map = NumericMatrix, the colormap defined when the figure is closed. -% num = NumericVector, the number of nodes defining the ColorBrewer colorscheme. -% typ = CharRowVector, the colorscheme type: 'Diverging'/'Qualitative'/'Sequential'. -% -%% Dependencies %% -% -% * MATLAB R2009a or later. -% * brewermap.m -% -% See also BREWERMAP BREWERMAP_NODES CUBEHELIX PRESET_COLORMAP MAXDISTCOLOR -% RGBPLOT COLORMAP COLORMAPEDITOR COLORBAR UICONTROL ADDLISTENER -persistent ax2D ln2D ax3D pt3D txtH is2D cbAx cbIm pTxt pSld bEig bGrp bRev scm isr -% -new = isempty(ax2D)||~ishghandle(ax2D); -dfn = 256; -upd = false; -upb = false; -hgv = []; -nmr = dfn; -% -%% Input Wrangling %% -% -if nargin>2 && isco - % >R2019a only! - fnh = @colororder; -else % default - fnh = @colormap; -end -% -err = 'First input must be a real positive scalar numeric or [] or NaN.'; -if nargin==0 || isnumeric(N)&&isequal(N,[]) - N = dfn; -elseif isnumeric(N) - assert(isscalar(N),'SC:brewermap_view:N:NotScalarNumeric',err) - assert(isreal(N)&&isfinite(N)&&fix(N)==N&&N>0||isnan(N),... - 'SC:brewermap_view:N:NotRealPositiveIntegerNorNaN',err) - N = double(N); -elseif all(ishghandle(N(:))) % R2014b or later - assert(all(isgraphics(N(:),'axes')|isgraphics(N(:),'figure')),... - 'SC:brewermap_view:N:NotAxesNorFigureHandles',... - 'First input may be an array of figure or axes handles.') - hgv = N(:); - nmr = arrayfun(@(h)size(fnh(h),1),hgv); - N = nmr(1); -else - error('SC:brewermap_view:N:UnsupportedInput',err) -end -% -[mcs,nmn,pyt] = brewermap('list'); -% -% Check BREWERMAP output: -tmp = find([any(diff(double(char(pyt)),1),2);1]); -assert(isequal(tmp,[9;17;35]),'SC:brewermap_view:BREWERMAP:OutputOrder',... - 'The BREWERMAP function returned an unexpected colorscheme sequence.') -% -if nargin<2 || isnumeric(scheme)&&isequal(scheme,[]) - % Default pseudo-random colorscheme: - isr = rand(1)>0.5; - scm = mcs{1+mod(round(now*1e7),numel(mcs))}; %#ok -else - % Parse input colorscheme: - scheme = bmv1s2c(scheme); - assert(ischar(scheme) && ndims(scheme)==2 && size(scheme,1)==1,... - 'SC:brewermap_view:scheme:NotCharacterVector',... - 'Second input must be a 1xN char vector.') %#ok - % Check if a reversed colormap was requested: - isr = strncmp(scheme,'-',1) || strncmp(scheme,'*',1); - isd = strncmp(scheme,'+',1) || isr; - scm = scheme(1+isd:end); -end -% -if isnan(N) - N = nmn(strcmpi(scm,mcs)); -end -% -%% Ensure Figure Exists %% -% -% LHS and RHS slider bounds/limits, and slider step sizes: -lbd = 1; -rbd = dfn; -stp = [1,10]; % [minor,major] -% -% Define the 3D cube axis order: -xyz = 'RGB'; % specify the order here. -[~,xyz] = ismember(xyz,'RGB'); -% -if new % Create a new figure. - % - % Figure parameters: - M = 9; % buttons per column - gap = 0.01; % gaps - bth = 0.04; % demo button height - btw = 0.10; % demo button width - bgh = 0.40; % button group height - cbw = 0.23; % colorbar width (both together) - cbh = 1-3*gap-bth; % colorbar height - axh = 1-bgh-2*gap; % axes height - axw = 1-cbw-2*gap; % axes width - bgw = axw-btw-gap; % button group width - % - figH = figure('HandleVisibility','callback',... - 'IntegerHandle','off', 'NumberTitle','off', 'Units','normalized',... - 'Name','ColorBrewer Interactive ColorScheme Selector',... - 'MenuBar','figure', 'Toolbar','none', 'Tag',mfilename); - % - % Add 2D lineplot: - ax2D = axes('Parent',figH, 'Position',[gap,bgh+gap,axw,axh], 'Box','on',... - 'ColorOrder',[1,0,0; 0,1,0; 0,0,1; 0.6,0.6,0.6], 'HitTest','off',... - 'Visible','off', 'XLim',[0,1], 'YLim',[0,1], 'XTick',[], 'YTick',[]); - ln2D = line([0,0,0,0;1,1,1,1],[0,0,0,0;1,1,1,1], 'Parent',ax2D,... - 'Visible','off', 'Linestyle','-', 'Marker','.'); - % - % Add 3D scatterplot: - ax3D = axes('Parent',figH, 'OuterPosition',[0,bgh,axw+2*gap,1-bgh],... - 'Visible','on', 'XLim',[0,1], 'YLim',[0,1], 'ZLim',[0,1], 'HitTest','on'); - pt3D = patch('Parent',ax3D, 'XData',[0;1], 'YData',[0;1], 'ZData',[0;1],... - 'Visible','on', 'LineStyle','none', 'FaceColor','none', 'MarkerEdgeColor','none',... - 'Marker','o', 'MarkerFaceColor','flat', 'MarkerSize',10, 'FaceVertexCData',[1,1,0;1,0,1]); - view(ax3D,3); - grid(ax3D,'on') - lbl = {'Red','Green','Blue'}; - xlabel(ax3D,lbl{xyz(1)}) - ylabel(ax3D,lbl{xyz(2)}) - zlabel(ax3D,lbl{xyz(3)}) - % - % Add warning text: - txtH = text('Parent',ax2D, 'Units','normalized', 'Position',[1,1],... - 'HorizontalAlignment','right', 'VerticalAlignment','top'); - % - % Add demo button: - demo = uicontrol(figH, 'Style','togglebutton', 'Units','normalized',... - 'Position',[1-cbw/2,1-bth-gap,cbw/2-gap,bth], 'String','Demo',... - 'Max',1, 'Min',0, 'Callback',@bmvDemo); %#ok - % Add 2D/3D button: - is2D = uicontrol(figH, 'Style','togglebutton', 'Units','normalized',... - 'Position',[1-cbw/1,1-bth-gap,cbw/2-gap,bth], 'String','2D / 3D',... - 'Max',1, 'Min',0, 'Callback',@bmv2D3D); - % Add reverse button: - bRev = uicontrol(figH, 'Style','togglebutton', 'Units','normalized',... - 'Position',[bgw+2*gap,bgh-bth,btw,bth], 'String','Reverse',... - 'Max',1, 'Min',0, 'Callback',@bmvRevM); - % - % Add colorbars: - C(1,1,:) = [1,1,1]; - cbAx(2) = axes('Parent',figH, 'Visible','off', 'Units','normalized',... - 'Position',[1-cbw/2,gap,cbw/2-gap,cbh], 'YLim',[0.5,1.5],... - 'YDir','normal', 'HitTest','off'); - cbAx(1) = axes('Parent',figH, 'Visible','off', 'Units','normalized',... - 'Position',[1-cbw/1,gap,cbw/2-gap,cbh], 'YLim',[0.5,1.5],... - 'YDir','normal', 'HitTest','off'); - cbIm(2) = image('Parent',cbAx(2), 'CData',C); - cbIm(1) = image('Parent',cbAx(1), 'CData',C); - % - % Add parameter sliders, listeners, and corresponding text: - sv = mean([lbd,rbd],2); - pTxt = uicontrol(figH,'Style','text', 'Units','normalized',... - 'Position',[bgw+2*gap,bgh-2*bth-gap,btw,bth], 'String','X'); - pSld = uicontrol(figH,'Style','slider', 'Units','normalized',... - 'Position',[bgw+2*gap,gap,btw,bgh-2*bth-gap], 'Min',lbd(1), 'Max',rbd(1),... - 'SliderStep',stp(1,:)/(rbd(1)-lbd(1)), 'Value',sv(1)); - addlistener(pSld, 'Value', 'PostSet',@bmvSldr); - % - % Add colorscheme button group: - bGrp = uibuttongroup('Parent',figH, 'BorderType','none', ... - 'Units','normalized', 'Position',[gap,gap,bgw,bgh-gap]); - % Determine button locations: - Z = 1:numel(mcs); - Z = Z+(Z>17); - C = (ceil(Z/M)-1)/4; - R = (M-1-mod(Z-1,M))/M; - % Add colorscheme buttons to group: - for jj = numel(mcs):-1:1 - bEig(jj) = uicontrol('Parent',bGrp, 'Style','Toggle', 'String',mcs{jj},... - 'Unit','normalized', 'Position',[C(jj),R(jj),1/4,1/M]); - end - set(bGrp,'SelectionChangeFcn',@bmvChgS); - % -end -% -%% Nested Functions %% -% - function str = bmvName() - % Generate the colorscheme name. - pfx = '+-'; - ids = strcmpi(scm,mcs); - if any(ids) - str = [pfx(1+isr),mcs{ids}]; - else % will throw an error in BREWERMAP: - str = scm; - end - end -% - function bmvUpDt() - % Update all graphics objects in the figure. - % - % Get ColorBrewer colormap and grayscale equivalent: - [map,num,typ] = brewermap(N,bmvName()); - mag = map*[0.298936;0.587043;0.114021]; - % - % Update colorbar values: - set(cbAx, 'YLim',[0,abs(N)+(N==0)]+0.5); - set(cbIm(1), 'CData',reshape(map,[],1,3)) - set(cbIm(2), 'CData', repmat(mag,[1,1,3])) - % - % Update 2D line / 3D patch values: - if get(is2D, 'Value') - set(ln2D, 'XData',linspace(0,1,abs(N))); - set(ln2D,{'YData'},num2cell([map,mag],1).'); - else % 3D - set(pt3D,... - 'XData',map(:,xyz(1)),... - 'YData',map(:,xyz(2)),... - 'ZData',map(:,xyz(3)),... - 'FaceVertexCData',map) - end - % - % Update reverse button: - set(bRev, 'Value',isr) - % - % Update warning text: - str = {[bmvName(),' '];[typ,' '];sprintf('%d Nodes ',num)}; - set(txtH,'String',str); - % - % Update parameter value text: - set(pTxt(1), 'String',sprintf('N = %.0f',N)); - % - % Update external axes/figure colormaps/colororders: - nmr(1) = N; - for k = 1:numel(hgv) - fnh(hgv(k),brewermap(nmr(k),bmvName())); - end - % - drawnow() - end -% - function bmv2D3D(h,~) - % Switch between 2D-line and 3D-cube representation. - % - if get(h,'Value') % 2D - set(ax3D, 'HitTest','off', 'Visible','off') - set(ax2D, 'HitTest','on', 'Visible','on') - set(pt3D, 'Visible','off') - set(ln2D, 'Visible','on') - else % 3D - set(ax2D, 'HitTest','off', 'Visible','off') - set(ax3D, 'HitTest','on', 'Visible','on') - set(ln2D, 'Visible','off') - set(pt3D, 'Visible','on') - end - % - bmvUpDt(); - end -% - function bmvChgS(~,e) - % Change the colorscheme. - % - scm = get(e.NewValue,'String'); - % - bmvUpDt() - end -% - function bmvRevM(h,~) - % Reverse the colormap. - % - isr = logical(get(h,'Value')); - % - bmvUpDt() - end -% - function bmvSldr(~,~) - % Update the slider position. - % - if ~upd - return - end - % - N = round(get(pSld,'Value')); - % - bmvUpDt() - end -% - function bmvDemo(h,~) - % Display all ColorBrewer colorschemes sequentially. - % - cnt = 0; - while ishghandle(h)&&get(h,'Value') - cnt = mod(cnt+1,pow2(53)); - % - if mod(cnt,23)<1 - ids = 1+mod(find(strcmpi(scm,mcs)),numel(mcs)); - scm = mcs{ids}; - try %#ok - set(bGrp, 'SelectedObject',bEig(ids)); - end - end - % - if mod(cnt,69)<1 - isr = ~isr; - end - % - upb = (upb || N<=1) && N - set(pSld, 'Value',N) - bmvUpDt() - end - upd = true; - % - % Faster/slower: - pause(0.1); - end - % - end -% -%% Initialize the Figure %% -% -set(bGrp,'SelectedObject',bEig(strcmpi(scm,mcs))); -set(pSld,'Value',max(lbd,min(rbd,N))); -upd = true; -bmvUpDt() -% -if nargout - waitfor(ax2D); - scheme = bmvName(); -else - clear map -end -% -end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%brewermap_view -function arr = bmv1s2c(arr) -% If scalar string then extract the character vector, otherwise data is unchanged. -if isa(arr,'string') && isscalar(arr) - arr = arr{1}; -end -end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bmv1s2c -% -% Copyright (c) 2014-2025 Stephen Cobeldick -% -% Licensed under the Apache License, Version 2.0 (the "License"); -% you may not use this file except in compliance with the License. -% You may obtain a copy of the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, -% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -% See the License for the specific language governing permissions and limitations under the License. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%license \ No newline at end of file diff --git a/beamtime/clean_file.py b/beamtime/clean_file.py new file mode 100644 index 0000000..5c9bb6d --- /dev/null +++ b/beamtime/clean_file.py @@ -0,0 +1,20 @@ + +import sys + +input_path = '/Users/bartels-rausch/Documents/GitLab/functionsMatlab/beamtime/nappFileList.m' +output_path = '/Users/bartels-rausch/Documents/GitLab/functionsMatlab/beamtime/nappFileList_clean.m' + +try: + with open(input_path, 'rb') as f: + content = f.read() + + # Try decoding as utf-8, replace errors + text = content.decode('utf-8', errors='replace') + + with open(output_path, 'w', encoding='utf-8') as f: + f.write(text) + + print(f"Successfully cleaned file to {output_path}") + +except Exception as e: + print(f"Error: {e}") diff --git a/beamtime/distFig.m b/beamtime/distFig.m deleted file mode 100644 index 0876817..0000000 --- a/beamtime/distFig.m +++ /dev/null @@ -1,831 +0,0 @@ -function distFig(varargin) -% ===== Syntax ============================================================ -% distFig(...,'Screen',Value) -% distFig(...,'Position',Value) -% -% distFig(...,'Rows',Value) -% distFig(...,'Columns',Value) -% -% distFig(...,'Not',Value) -% distFig(...,'Only',Value) -% distFig(...,'Offset',Value) -% -% distFig(...,'Adjust',Value) -% distFig(...,'Extra',Value) -% distFig(...,'Menu',Value) -% distFig(...,'Transpose',Value) -% distFig(...,'Simulink',Value) -% distFig(...,'Tight',Value) -% distFig(...,'Scale',Value) -% distFig(...,'ScaleOrigin',Value) -% distFig(...,'FreezeSize',Value) -% distFig(...,'Order',Value) -% -% ===== Description ======================================================= -% distFig(...,'Screen',Value) assigns where the figures will be -% distributed. -% Synonyms for 'Screen' are 'Scr' and 'S'. Value can be: -% 'C' / 'Center' (Default) -% 'W' / 'West' / 'L' / 'Left' -% 'E' / 'East' / 'R' / 'Right' -% 'N' / 'North' / 'T' / 'Top' -% 'S' / 'South' / 'B' / 'Bottom' -% 'Main' / 'Primary' -% 'Ext' / 'External' / 'Secondary' -% -% distFig(...,'Position',Value) assigns in which part of the screen the -% figures will be distributed. -% Synonyms for 'Position' are 'Pos' and 'P'. Value can be: -% 'C' / 'Center' (Default) -% 'W' / 'West' / 'L' / 'Left' -% 'E' / 'East' / 'R' / 'Right' -% 'N' / 'North' / 'T' / 'Top' -% 'S' / 'South' / 'B' / 'Bottom' -% 'NW' -% 'NE' -% 'SW' -% 'SE' -% -% distFig(...,'Rows',Value) assigns how many rows the figures will be -% distributed on. -% Synonyms for 'Rows' are 'R'. Value can be: -% 1...n -% 'Auto' / -1 -% 'Auto' indicates that it automatically calculates the number of required -% rows. -% -% distFig(...,'Columns',Value) assigns how many rows the figures will be -% distributed on. -% Synonyms for 'Columns' are 'Cols' and 'C'. Value can be: -% 1...n -% 'Auto' / -1 -% 'Auto' indicates that it automatically calculates the number of required -% columns. -% -% distFig(...,'Not',Value) excludes specified figures from the distribution -% list. Value must be an array with the excluded figure numbers. The -% default value is []. The input argument 'gcf' (get current figure) can be -% used as well. -% -% distFig(...,'Only',Value) does only distribute specified figures. Value -% must be an array with the figure which will be distributed. The -% default value is []. The input argument 'gcf' (get current figure) can be -% used as well. -% -% distFig(...,'Offset',Value) can be used to shift all figures on the -% distribution list. Synonyms for 'Offset' is 'O'. Value must be an integer -% larger or equal to zero. The default offset value is 0. -% -% distFig(...,'Adjust',Value) can be used to adjust all figure positions. -% For instance, if all figures should be moved 20 pixels to the right, -% which is not possible with the other features, Value should be [20,0]. -% If Value is below 1, the scalars indicate the relative adjustment to the -% screen. If the selected monitor is [1920,1080] pixels, a Values of -% [0.25,-0.5] moves all figures with [480,540] pixels. -% Synonyms for 'Ajust' is 'A'. Value can be: -% [Integer,Integer] (In order to adjust by a specific ammount) -% [Scalar,Scalar]( < 1) (To adjust a relative ammount of the monitor size) -% The default value is [0,0]. -% -% distFig(...,'Extra',Value) is used to handle the extra figures, which -% might not fit into 'Rows' * 'Cols'. For instance, 5 figure are to be -% distributed on a 2x2 = 4 area. The fifth figure is then places on top of -% the first figure if 'Extra' is 'restart'. It can be ignored by setting -% 'Extra' to 'ignore', in which the fifth figure will not be distributed. -% -% distFig(...,'Menu',Value) can be used to modify the menu bar. -% Value can be: -% 'figure' -% 'none' -% -% distFig(...,'Transpose',Value) can be used to tranpose the order of -% distributing. The values must be logical and the default value is false. -% -% distFig(...,'Simulink',Value) can be used to handle simulink figures. -% Value can be: -% 'include' (Default) -% 'exclude' -% 'only' -% If value is true, simulink figures will be distributed along with the -% other figures. If value if 'exclude' simulink figures will be -% excluded from the distribution list. If value is 'only', only the -% simulink figures will be distributed and not the ordinary figures. -% -% distFig(...,'Tight',Value) can be used to stretch the figure to the -% border of the figure, so no unnecessary "whitespace" is present. -% Value must be logical and the default value if false. -% -% distFig(...,'Scale',Value) can be used to scale the figure matrix. Both -% horizontal and vertical scaling can be applied, but also similar scaling. -% Value is a single scalar for similar scaling, but is a 2x1 matrix for -% specific scaling in each direction. For instance, distFig('Scale',0.5) -% scales all figures by 50% relative to the upper left corner of the -% distribution area (Default Scale-origin). distFig('Scale',[0.8,0.4]) -% scales the figures by 80% and 40% in the horizontal and vertical -% directions respectivly relative to the default scale-origin. -% -% distFig(...,'ScaleOrigin',Value) can be used in combination with the -% 'Scale' option. Value is a 2x1 matrix with the origin. If these values -% are between 0 and 1 the relative monitor size is used, whereas larger -% values should be rounded indicating pixel values. For instance, -% distFig('Scale',0.5,'ScaleOrigin',[0.5,1]) scales the figures relative -% to the midpoint on the right hand side of the selected monitor. For a -% monitor with resolution 1920x1080, this would be equal to -% distFig('Scale',0.5,'ScaleOrigin',[1920,960]). -% The default scale origin is in the upper left corner of the distribution -% area. -% Synonyms for 'ScaleOrigin' are 'Origin', 'Orig' and 'Scaleorig'. -% -% distFig(...,'FreezeSize',Value) can be used to freeze the sizes of the -% figures before distribution. Currently, this function anchors the figures -% to the upper left corner of the original position, yet keeping the -% original size - it does not calculate new positions, so the figures may -% overlap. -% Synonym for 'FreezeSize' is 'Freeze'. -% -% distFig(...,'Order',Value) can be used to control the plotting order. For -% instance, distFig('Only',[5,6,7,8],'Order',[2,1,4,3]) will plot figure -% 5,6,7 and 8 in the order of 6,5,8 and 7. The ordering argument is thus -% related to the input of 'Only'. -% -% ===== Examples ========================================================== -% distFig(); -% This will distribute all open figures on the primary screen in two rows. -% -% distFig('Screen','Left','Position','Right','Only',[1,2,4]) -% This will only distribute figure 1, 2 and 4 on the right part of the left -% screen. -% -% distFig('Offset',2,'Not',[1,2]) -% This will distribute all figure but figure 1 and 2 in the same pattern as -% distFig(), but figure 1 and 2 will not be distributed, but instead there will -% be blank spots where they would have been distributed. -% -% ===== Note ============================================================== -% If you find any errors or bugs with this version please contact me on -% AndersSSimonsen@GMail.com or write a comment on file exchange - then I'll -% take a look at it. :) -% -% This function will only work in MATLAB 2014b and onwards due to the -% massive overhaul in the figure handle system - I will not support -% previous versions. - -% ========================================================================= -% ===== Version =========================================================== -% ========================================================================= - -% Anders Schou Simonsen, AndersSSimonsen@GMail.com -% Version 5.5 -% 31/03-2015 - -% ========================================================================= -% ===== Default values ==================================================== -% ========================================================================= - -Rows = -1; -Cols = -1; -Scr = 'C'; -Pos = 'C'; -Tight = false; -Menu = ''; -Transpose = false; -Extra = 'restart'; -Offset = 0; -Not = []; -Only = []; -Simulink = 'include'; -Adjust = [0,0]; -Scale = 1; -Scale_Orig = []; -FreezeSize = false; -Order = []; - -% ========================================================================= -% ===== Get inputs ======================================================== -% ========================================================================= - -if (mod(nargin,2) ~= 0) - error('Uneven number of inputs! Returning...'); -end - -for i = 1:2:nargin - if (ischar(varargin{i+1})) - varargin{i+1} = lower(varargin{i+1}); - end - switch lower(varargin{i}) - case {'scr','screen','s'} - % ============================================================= - Allow = { - 'C' 'c' 'center' 'main' 'primary' - 'W' 'w' 'west' 'l' 'left' - 'E' 'e' 'east' 'r' 'right' - 'N' 'n' 'north' 't' 'top' - 'S' 's' 'south' 'b' 'bottom' - 'Ext' 'ext' 'external' 'secondary' NaN - }; - Trigger = any(strcmp(Allow,varargin{i+1}),2); - if (~any(Trigger)) - warning('Input ''%s'' not recognized for ''%s''!',varargin{i+1},varargin{i}); - else - Scr = Allow{Trigger,1}; - end - case {'pos','position','p'} - % ============================================================= - Allow = { - 'C' 'c' 'center' NaN NaN - 'W' 'w' 'west' 'l' 'left' - 'E' 'e' 'east' 'r' 'right' - 'N' 'n' 'north' 't' 'top' - 'S' 's' 'south' 'b' 'bottom' - 'NW' 'nw' NaN NaN NaN - 'NE' 'ne' NaN NaN NaN - 'SW' 'sw' NaN NaN NaN - 'SE' 'se' NaN NaN NaN - }; - Trigger = any(strcmp(Allow,varargin{i+1}),2); - if (~any(Trigger)) - warning('Input ''%s'' not recognized for ''%s''!',varargin{i+1},varargin{i}); - else - Pos = Allow{Trigger,1}; - end - case {'rows','r'} - % ============================================================= - if (strcmp(varargin{i+1},'auto')) - Rows = -1; - else - if ~((isnumeric(varargin{i+1})) && (mod(varargin{i+1},1) == 0)) - warning('Input to ''%s'' must be a round numeric value!',varargin{i}); - else - Rows = varargin{i+1}; - end - end - case {'cols','columns','c'} - % ============================================================= - if (strcmp(varargin{i+1},'auto')) - Cols = -1; - else - if ~((isnumeric(varargin{i+1})) && (mod(varargin{i+1},1) == 0)) - warning('Input to ''%s'' must be a round numeric value!',varargin{i}); - else - Cols = varargin{i+1}; - end - end - case {'ext','extra'} - % ============================================================= - Allow = { - 'ignore' - 'restart' - }; - Trigger = any(strcmp(Allow,varargin{i+1}),2); - if (~any(Trigger)) - warning('Input ''%s'' not recognized for ''%s''!',varargin{i+1},varargin{i}); - else - Extra = Allow{Trigger,1}; - end - case {'menu','bar'} - % ============================================================= - Allow = { - 'figure' - 'none' - }; - Trigger = any(strcmp(Allow,varargin{i+1}),2); - if (~any(Trigger)) - warning('Input ''%s'' not recognized for ''%s''!',varargin{i+1},varargin{i}); - else - Menu = Allow{Trigger,1}; - end - case {'transpose'} - % ============================================================= - if (~islogical(varargin{i+1})) - warning('Input to ''%s'' must be logical!',varargin{i}); - else - Transpose = varargin{i+1}; - end - case {'offset','o'} - % ============================================================= - if ~((isnumeric(varargin{i+1})) && (mod(varargin{i+1},1) == 0)) - warning('Input to ''%s'' must be a round numeric value!',varargin{i}); - else - Offset = varargin{i+1}; - end - case {'adjust','a'} - % ============================================================= - if ~(isnumeric(varargin{i+1})) - warning('Input to ''%s'' must be numeric!',varargin{i}); - elseif (numel(varargin{i+1}) ~= 2) - warning('Input to ''%s'' must be a (1 x 2) matrix with integers or scalars less than one!',varargin{i}); - elseif (all(mod(varargin{i+1},1) == 0)) - Adjust = varargin{i+1}; - else - if (any(varargin{i+1} > 1)) - warning('Input to ''%s'' must be either integers or scalars less than one!',varargin{i}); - else - Adjust = varargin{i+1}; - end - end - case {'not'} - % ============================================================= - if ~((isnumeric(varargin{i+1}) && all(mod(varargin{i+1},1) == 0)) || isobject(varargin{i+1})) - warning('Input to ''%s'' must be round numeric values!',varargin{i}); - else - if (isobject(varargin{i+1})) - Not = get(varargin{i+1},'Number'); - if (iscell(Not)) - Not = cell2mat(Not); - end - else - Not = varargin{i+1}; - end - end - case {'only'} - % ============================================================= - if ~((isnumeric(varargin{i+1}) && all(mod(varargin{i+1},1) == 0)) || isobject(varargin{i+1})) - warning('Input to ''%s'' must be round numeric values!',varargin{i}); - else - if (isobject(varargin{i+1})) - Only = get(varargin{i+1},'Number'); - if (iscell(Only)) - Only = cell2mat(Only); - end - else - Only = varargin{i+1}; - end - end - case {'simu','simulink'} - % ============================================================= - Allow = { - 'include' NaN - 'exclude' 'ignore' - 'only' NaN - }; - Trigger = any(strcmp(Allow,varargin{i+1}),2); - if (~any(Trigger)) - warning('Input ''%s'' not recognized for ''%s''!',varargin{i+1},varargin{i}); - else - Simulink = Allow{Trigger,1}; - end - case {'tight'} - % ============================================================= - if (~islogical(varargin{i+1})) - warning('Input to ''%s'' must be logical!',varargin{i}); - else - Tight = varargin{i+1}; - end - case {'scale'} - % ============================================================= - if (~isnumeric(varargin{i+1}) || (numel(varargin{i+1}) > 2)) - warning('Input to ''%s'' must be one or two numeric values (x and y scale)!',varargin{i}); - else - Scale = varargin{i+1}; - end - case {'origin','orig','scaleorig','scaleorigin'} - % ============================================================= - if (~isnumeric(varargin{i+1}) || (numel(varargin{i+1}) ~= 2)) - warning('Input to ''%s'' must be two numeric values (x0 and y0)!',varargin{i}); - else - Scale_Orig = varargin{i+1}; - end - case {'freezesize','freeze'} - % ============================================================= - if (~islogical(varargin{i+1})) - warning('Input to ''%s'' must be logical!',varargin{i}); - else - FreezeSize = varargin{i+1}; - end - case {'order'} - % ============================================================= - if ~(isnumeric(varargin{i+1}) && all(mod(varargin{i+1},1) == 0)) - warning('Input to ''%s'' must be round numeric values!',varargin{i}); - else - Order = varargin{i+1}; - end - otherwise - % ============================================================= - fprintf('Input ''%s'' not recognized!',varargin{i}); - end -end - -% ========================================================================= -% ===== Constants ========================================================= -% ========================================================================= - -% ===== Limits ============================================================ -Limits = {... - 'C' [0,1] [0,1] - 'W' [0,0.5] [0,1] - 'E' [0.5,1] [0,1] - 'N' [0,1] [0.5,1] - 'NW' [0,0.5] [0.5,1] - 'NE' [0.5,1] [0.5,1] - 'S' [0,1] [0,0.5] - 'SW' [0,0.5] [0,0.5] - 'SE' [0.5,1] [0,0.5] - }; - -% ===== Screen angles ===================================================== -Screens = {... - (-pi * 1 / 4) (+pi * 1 / 4) 'E' - (-pi * 3 / 4) (-pi * 1 / 4) 'S' - (+pi * 1 / 4) (+pi * 3 / 4) 'N' - (+pi * 3 / 4) Inf 'W' - -Inf (-pi * 3 / 4) 'W' - }; - -% ===== Taskbar height ==================================================== -Taskbar_Height = 40; - -% ========================================================================= -% ===== Figure list ======================================================= -% ========================================================================= - -% ===== All figures ======================================================= -Fig_Object = findall(0,'type','figure'); -if (isempty(Fig_Object)) - fprintf('distFig: No figures to distribute!\n'); - return; -end - -% ===== Remove not visible figures ======================================== -Visible = arrayfun(@(n) (strcmp(get(Fig_Object(n),'Visible'),'on')),1:numel(Fig_Object)); -Fig_Object = Fig_Object(Visible); - -% ===== Include simulink figures ========================================== -Fig_Number = {Fig_Object.Number}; -Empty = arrayfun(@(n) (isempty(Fig_Number{n})),1:numel(Fig_Number)); -Fig_Number(Empty) = {0}; -Fig_Number = cell2mat(Fig_Number); -[~,Index] = sort(get(Fig_Object(Fig_Number == 0),'Name')); -Temp = find(Fig_Number == 0); -Fig_Number(Temp(Index)) = -(numel(Index):(-1):1); - -% ===== Logical distribution array ======================================== -Fig_Dist = true(1,numel(Fig_Object)); - -% ===== Simulink figures ================================================== -if strcmp(Simulink,'exclude') - Fig_Dist = (Fig_Number > 0); -end -if strcmp(Simulink,'only') - Fig_Dist = (Fig_Number < 0); -end - -% ===== Not =============================================================== -Fig_Dist(ismember(Fig_Number,Not)) = false; - -% ===== Only ============================================================== -if (~isempty(Only)) - Fig_Dist(~ismember(Fig_Number,Only)) = false; -end - -% ===== Number of figures ================================================= -nFig_Dist = sum(Fig_Dist); - -% ===== Return ============================================================ -if (nFig_Dist == 0) - return; -end - -% ========================================================================= -% ===== Monitor =========================================================== -% ========================================================================= - -% ===== Get monitor positions ============================================= -Monitors = get(0,'MonitorPositions'); -Monitors_Center = Monitors(:,1:2) + Monitors(:,3:4) / 2; -Monitors_Label = cell(size(Monitors,1),1); - -% ===== Center monitor ==================================================== -Temp = sum(abs(Monitors(:,1:2) - 1),2); -Trigger_C = find(Temp == min(Temp)); -Monitors_Label{Trigger_C} = 'C'; - -% ===== External monitors ================================================= -Dir = Monitors_Center - repmat(Monitors_Center(Trigger_C,:),size(Monitors_Center,1),1); -Theta = atan2(Dir(:,2),Dir(:,1)); -for i = 1:numel(Theta) - if (i ~= Trigger_C) - Monitors_Label{i} = Screens{(Theta(i) > [Screens{:,1}]) & (Theta(i) <= [Screens{:,2}]),3}; - end -end - -% ===== Select monitor ==================================================== -Monitor = Monitors(strcmp(Monitors_Label,Scr),:); -if (isempty(Monitor)) - if (strcmp(Scr,'Ext')) - if (size(Monitors,1) == 1) - warning('No external monitor could be found!'); - Monitor = Monitors(1,:); - else - Monitor = Monitors(find(~strcmp(Monitors_Label,'C'),1,'first'),:); - end - else - warning(['Screen ''%s'' could not be found! (Using ''C'' instead)\nThe following monitors were identified: %s.\n'... - 'If the function cannot find the monitor try and restart MATLAB - this will reset the monitor-matrix, which is being used by the function.'],... - Scr,sprintf('%s\b\b\b\b\b',sprintf('''%s'' and ',Monitors_Label{:}))); - Monitor = Monitors(strcmp(Monitors_Label,'C'),:); - if (isempty(Monitor)) - warning(['distFig cannot find matching monitors - using the first one!',... - '\nPlease report this problem to AndersSSimonsen@GMail.com, where you include this matrix:'],0); - disp(Monitors); - Monitor = Monitors(1,:); - end - end -end - -% ========================================================================= -% ===== Rows and columns ================================================== -% ========================================================================= - -Limit = Limits(strcmp(Limits(:,1),Pos),:); -if ((Rows == (-1)) && (Cols == (-1))) - AR_Ideal = 1.2; - AR_Mean = Inf; - for i = 1:50 - % ===== Exception ================================================= - if ((nFig_Dist + Offset) == 4) - Rows = 2; - Cols = 2; - break; - end - - % ===== Temporary rows and columns ================================ - Rows = i; - Cols = ceil((nFig_Dist + Offset) / Rows); - - % ===== Sizes ===================================================== - x = round(linspace(Limit{2}(1),Limit{2}(2),Cols + 1) * Monitor(3)) + 1; - y = round(linspace(Limit{3}(1),Limit{3}(2),Rows + 1) * (Monitor(4) - Taskbar_Height)) + Taskbar_Height + 1; - clear Size; - [Size(:,:,1),Size(:,:,2)] = meshgrid(diff(x),diff(y)); - - % ===== Output ==================================================== - AR_Mean_Prev = AR_Mean; - AR_Mean = mean(mean(Size(:,:,1) ./ Size(:,:,2))); - if (AR_Mean > AR_Ideal) - AR_Error = abs([AR_Ideal - AR_Mean_Prev,AR_Ideal - AR_Mean]); - if (AR_Error(1) < AR_Error(2)) - Rows = i - 1; - end - Cols = ceil((nFig_Dist + Offset) / Rows); - clear Size; - break; - end - end -elseif (Rows == (-1)) - Rows = ceil((nFig_Dist + Offset) / Cols); -elseif (Cols == (-1)) - Cols = ceil((nFig_Dist + Offset) / Rows); -end - -% ========================================================================= -% ===== Location matrix =================================================== -% ========================================================================= - -Sets = ceil(nFig_Dist / (Rows * Cols) + Offset); -Mat = nan(Rows,Cols,Sets); -if (Transpose) - Mat = permute(Mat,[2,1,3]); -end -if (isempty(Order)) - Order = (1:sum(Fig_Dist)); -end -Temp = sort(Fig_Number(Fig_Dist)); -if (max(Order) > numel(Temp)) - error('The ordering command is related to the input - not the actual figure numbers! Returning...'); -end -Mat((1:nFig_Dist) + Offset) = Temp(Order); -if (Transpose) - Mat = permute(Mat,[2,1,3]); -end -if (strcmp(Extra,'ignore')) - Sets = 1; -end - -% ========================================================================= -% ===== Position and size ================================================= -% ========================================================================= - -% ===== Grid ============================================================== -x = round(linspace(Limit{2}(1),Limit{2}(2),Cols + 1) * Monitor(3)) + 1; -y = round(linspace(Limit{3}(1),Limit{3}(2),Rows + 1) * (Monitor(4) - Taskbar_Height)) + Taskbar_Height + 1; - -% ===== Scale ============================================================= -if (isempty(Scale_Orig)) - Scale_Orig = [x(1),y(end)]; -end -if ((all(mod(Scale_Orig,1) == 0)) && (any(Scale_Orig > 1))) - ScaleOrig_Pixel = Scale_Orig; -else - ScaleOrig_Pixel = Monitor(3:4) .* Scale_Orig; -end -if (numel(Scale) == 1) - Scale(2) = Scale(1); -end -x = (x - ScaleOrig_Pixel(1)) * Scale(1) + ScaleOrig_Pixel(1); -y = (y - ScaleOrig_Pixel(2)) * Scale(2) + ScaleOrig_Pixel(2); - -% ===== Positon =========================================================== -[FPos(:,:,1),FPos(:,:,2)] = meshgrid(x(1:end-1),y(1:end-1)); -FPos(:,:,2) = flipud(FPos(:,:,2)); -FPos(:,:,1) = FPos(:,:,1) + Monitor(1) - 1; -FPos(:,:,2) = FPos(:,:,2) + Monitor(2) - 1; - -% ===== Size ============================================================== -[Size(:,:,1),Size(:,:,2)] = meshgrid(diff(x),diff(y)); - -% ===== Adjust ============================================================ -if (any(Adjust ~= 0)) - if (all(mod(Adjust,1) == 0)) - Adjust_Pixels = Adjust; - else - Adjust_Pixels = round(Adjust .* (Monitor(3:4) + [0,-Taskbar_Height])); - end -else - Adjust_Pixels = [0,0]; -end - -% ========================================================================= -% ===== Distribute figures ================================================ -% ========================================================================= - -for s = 1:Sets - for i = 1:size(Mat,1) - for j = 1:size(Mat,2) - if (~isnan(Mat(i,j,s))) - % ===== Position and figure =============================== - Pos_Temp = [squeeze(FPos(i,j,:))' + Adjust_Pixels,squeeze(Size(i,j,:))']; - gcf_Temp = Fig_Object(Fig_Number == Mat(i,j,s)); - gca_Temp = get(gcf_Temp,'CurrentAxes'); - - % ===== Freeze size ======================================= - if (FreezeSize) - Pos_Orig = get(gcf_Temp,'Position'); - Pos_Temp(2) = Pos_Temp(2) + Pos_Temp(4) - Pos_Orig(4); - Pos_Temp(3:4) = Pos_Orig(3:4); - end - - % ===== Focus figures to bring to front =================== - figure(gcf_Temp); - - % ===== Set units ========================================= - if (~isempty(Menu)) - set(gcf_Temp,'MenuBar',Menu); - end - if (Mat(i,j,s) < 0) - drawnow; - end - gca_Units_Prev = get(gca_Temp,'Units'); - gcf_Units_Prev = get(gcf_Temp,'Units'); - - % ===== Distribute figure ================================= - set(gca_Temp,'Units','normalized'); - set(gcf_Temp,'Units','pixels','OuterPosition',Pos_Temp); - set(gcf_Temp,'Units',gcf_Units_Prev); - - % ===== Apply tight ======================================= - if ((Tight) && (Mat(i,j,s) > 0)) - drawnow; - set(gca_Temp,'Position',[get(gca_Temp,'TightInset') * eye(4,2),1 - get(gca_Temp,'TightInset') * [1,0,1,0;0,1,0,1]']); - end - set(gca_Temp,'Units',gca_Units_Prev); - end - end - end -end - -% ========================================================================= -% ===== Check for new updates ============================================= -% ========================================================================= - -% This feature check for a new version of distFig. It is only an attempt, -% so it might not work without bugs. It can be disables by setting the -% variable below called "Update" to "false" or by deleting this whole -% section - this won't affect the rest of the function. -% -% It generates a .txt file called "distFig_Update.txt" located in the same -% folder as distFig.m, which holds the date for the last time the function -% checked for updates. In order to not check for updates all the time, the -% function only does this ONCE every 7 days (variable "Check_Interval"), -% and at max once for every started MATLAB session. Also, it uses appdata, -% so if you're using this as well, it might display messages multiple times -% within a session, if an update is available, if appdata is deleted. -% -% The update feature works by scanning the file exchange page for distFig -% for a string value called "datePublished", and compares it to the date of -% the current version (variable "Date_Current"). If these are not the same, -% a hyperlink will be shown to the function page on file exchange page. It -% thus depends on a very specific format, which might differ(?) from -% different languages - I'm not aware whether this is true, so please -% contact me on AndersSSimonsen@GMail.com if you find this to be true, so I -% can fix the feature. :) - -% ===== DISABLE THE UPDATE FEATURE BY SETTING THIS VALUE TO false ========= -Update = true; -% ===== DISABLE THE UPDATE FEATURE BY SETTING THIS VALUE TO false ========= - -if (Update) - try - % ===== Initialize ================================================ - Date_Current = [2015,03,31]; - Check_Interval = 7; - Check = false; - - % ===== Path of update file ======================================= - Path = mfilename('fullpath'); - Path = sprintf('%s\\distFig_Update.txt',Path(1:end-numel('\distFig'))); - - if (isempty(getappdata(0,'distFig_Update'))) - % ===== Set appdata =========================================== - setappdata(0,'distFig_Update',1); - - % ===== Read update file ====================================== - File_ID = fopen(Path,'r'); - Clock = clock; - Date_Today = Clock(1:3); - if (File_ID == (-1)) - % ===== Generate update file ============================== - File_ID = fopen(Path,'w'); - fprintf(File_ID,'%d %d %d',Date_Today(1),Date_Today(2),Date_Today(3)); - fclose(File_ID); - Check = true; - else - % ===== Read last date ==================================== - Data = textscan(File_ID,'%s','delimiter',''); - if (strcmp(Data{1},'DISABLE')) - Check = false; - else - Date_Last_Checked = cell2mat(textscan(Data{1}{1},'%f %f %f')); - - % ===== Write new date ================================ - File_ID = fopen(Path,'w'); - fprintf(File_ID,'%d %d %d',Date_Today(1),Date_Today(2),Date_Today(3)); - fclose(File_ID); - - % ===== Check for new updates? ======================== - Days_Elapsed = etime([Date_Today,zeros(1,3)],[Date_Last_Checked,zeros(1,3)]) / (60^2 * 24); - if (Days_Elapsed > Check_Interval) - Check = true; - end - end - end - - % ===== Check for updates ===================================== - if (Check) - % ===== Read File Exchange date =========================== - Data = urlread('http://se.mathworks.com/matlabcentral/fileexchange/37176-distribute-figures'); - Temp = Data((-1:100) + regexp(Data,'datePublished')); - Date_Online = cell2mat(textscan(Temp(26:end),'%f-%f-%f')); - - % ===== New update available? ============================= - if (~all(Date_Current == Date_Online)) - setappdata(0,'distFig_Update',2); - setappdata(0,'distFig_Online_Date',Date_Online); - end - end - end - - % ===== Message =================================================== - if (getappdata(0,'distFig_Update') == 2) - try - % ===== New version ======================================= - Date_Online = getappdata(0,'distFig_Online_Date'); - fprintf('New update available for distFig! '); - disp('Download here') - fprintf('\tCurrent version date:\t%02.0f-%02.0f-%02.0f\n',Date_Current(1),Date_Current(2),Date_Current(3)); - fprintf('\tOnline version date:\t%02.0f-%02.0f-%02.0f\n',Date_Online(1),Date_Online(2),Date_Online(3)); - - % ===== Postpone ========================================== - fprintf('Click here to postpone this message for %d days: ',Check_Interval); - Command = sprintf([... - 'setappdata(0,''distFig_Update'',1);',... - 'fprintf(''distFig update message postponed for %d days!\\n'');' - ],Check_Interval); - disp(sprintf('Postpone update message',Command)); %#ok - - % ===== Disable =========================================== - fprintf('Click here to disable the update feature forever: '); - Command = sprintf([... - 'File_ID = fopen(''%s'',''w'');',... - 'fprintf(File_ID,''DISABLE'');',... - 'fclose(File_ID);',... - 'setappdata(0,''distFig_Update'',1);',... - 'fprintf(''distFig update feature disabled!\\n'');' - ],Path); - disp(sprintf('Disable update feature',Command)); %#ok - catch - setappdata(0,'distFig_Update',1); - end - end - catch Error %#ok - % ===== Error handling ============================================ - try - Path_Error = [Path(1:end-numel([filesep 'distFig_Update.txt'])), [filesep 'distFig_Error.mat']]; - fprintf([ - 'There was an error in distFig when checking for updates.',... - '\nPlease report this to AndersSSimonsen@GMail.com by sending the error-file "distFig_Error.mat" located in %s. :)\n\n'],Path_Error); - AppData = getappdata(0); %#ok - save(Path_Error); - catch - end - end -end \ No newline at end of file diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley.html b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley.html new file mode 100644 index 0000000..4be049f --- /dev/null +++ b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley.html @@ -0,0 +1,5268 @@ + + + + + +Test script to fit some SLS data + + + + + + + +
+

Test script to fit some SLS data

+ +

This calls all models in all varieties from the nappFitGaussXps.m function. Basically, to test that it is working. The data is random, so fitting is meaningless.

+ +

Contents

+
+ +
+

Random data for 2 peaks

+
clc
+clearvars
+close all
+
+% create data table consistent with ISS data
+FitList = table;
+FitList.sample = 'O1s, 120eV, m30, cps, 092022';
+FitList.name = {'random.ibw'};
+tmpDataSelection = matches(FitList.sample,'O1s, 120eV, m30, cps, 092022'); % This filters one specific spectrum by "sample name".
+
+% add random data on kinetic energy scale
+x = linspace(105, 120, 100)';
+true_params = [99900 2 113; 29000 0.9 110.5];
+y = zeros(size(x));
+fwhm_to_sigma = @(fwhm) fwhm / (2*sqrt(2*log(2)));
+for i = 1:size(true_params,1)
+    A = true_params(i,1);
+    sigma = fwhm_to_sigma(true_params(i,2));
+    pos = true_params(i,3);
+    y = y + A * exp(-((x - pos).^2) / (2*sigma^2));
+end
+y = y + (-195.*x+32980);
+y = y + 1000 * randn(size(x));  % add noise
+figure;
+plot(x, y, 'k.');
+xlabel('Kinetic Energy');
+ylabel('Intensity');
+title('Raw Data without Shirley Tail');
+if ~ismember('scientaEkin_eV', FitList.Properties.VariableNames)
+    FitList.scientaEkin_eV = cell(size(FitList,1),1);
+end
+if ~ismember('spectrum_countsNorm', FitList.Properties.VariableNames)
+    FitList.spectrum_countsNorm = cell(size(FitList,1),1);
+end
+FitList(tmpDataSelection,:).scientaEkin_eV{:} = x;
+FitList(tmpDataSelection,:).spectrum_countsNorm{:} = y;
+index= find(FitList(tmpDataSelection,:).scientaEkin_eV{:}>113,1);
+FitList(tmpDataSelection,:).spectrum_countsNorm{:}(1:index) = FitList(tmpDataSelection,:).spectrum_countsNorm{:}(1:index) + 1000;
+
+% add random data on binding energy scale
+x = linspace(42, 30, 1000)';
+true_params = [800 0.4 36.2; 500 0.3 38.0];
+y = zeros(size(x));
+fwhm_to_sigma = @(fwhm) fwhm / (2*sqrt(2*log(2)));
+for i = 1:size(true_params,1)
+    A = true_params(i,1);
+    sigma = fwhm_to_sigma(true_params(i,2));
+    pos = true_params(i,3);
+    y = y + A * exp(-((x - pos).^2) / (2*sigma^2));
+end
+% Simulate realistic Shirley-style background using smooth tanh transition
+center = 36.5; width = 3;
+shirley_step = 75 + 45 * (1 + tanh((x - center)/width))/2;
+y = y + shirley_step;
+y = y + 5 * randn(size(x));  % add mild noise
+figure;
+plot(x, y, 'k.');
+xlabel('Binding Energy');
+ylabel('Intensity');
+title('Raw Data with Shirley Tail');
+set(gca, 'XDir', 'reverse'); grid on;
+if ~ismember('bindingEnergy_eV', FitList.Properties.VariableNames)
+    FitList.bindingEnergy_eV = cell(size(FitList,1),1);
+end
+if ~ismember('spectrum_counts', FitList.Properties.VariableNames)
+    FitList.spectrum_counts = cell(size(FitList,1),1);
+end
+FitList(tmpDataSelection,:).bindingEnergy_eV{:} = x;
+FitList(tmpDataSelection,:).spectrum_counts{:} = y;
+
+% plot
+nappPlot(FitList,tmpDataSelection,'tableVariable','spectrum_countsNorm','energyScale','kinetic');
+nappPlot(FitList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','binding');
+
+

TEST 1.1: Unconstrained kinetic Gauss linear

+

Gaussian + Linear, individual area/width/position per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea                   = [5e5 100]; % <- 2 values => 2 peaks
+tmpFitParameters.peakWidth                  = [1.6 0.6];
+tmpFitParameters.peakPos                    = [113 110];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound         =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound         =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound        =  [1.0 0.6];
+tmpFitParameters.peakWidthUpperBound        =  [2.0 1.2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound          =  [112 109];
+tmpFitParameters.peakPosUpperBound          =  [114  111];
+tmpFitParameters.backgroundRange            = [12 6]; % <- selects fit range around peak1
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','unconstrained','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name           peakPosition  
+    ______________    ________________
+
+    {'random.ibw'}    112.99     110.5
+
+         name                 peakArea        
+    ______________    ________________________
+
+    {'random.ibw'}    2.1226e+05         27727
+
+         name           peakFWHM  
+    ______________    ____________
+
+    {'random.ibw'}    2    0.88526
+
+         name           peakBackground  
+    ______________    __________________
+
+    {'random.ibw'}    -332.34      49032
+
+
+

TEST 1.2: Unconstrained kinetic PV linear

+

Pseudo-Voigt + Linear, individual area/width/eta/position per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea                   = [5e5 100];
+tmpFitParameters.peakWidth                  = [1.6 0.6];
+tmpFitParameters.peakPos                    = [113 110];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound         =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound         =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound        =  [1.0 0.6];
+tmpFitParameters.peakWidthUpperBound        =  [2.0 1.2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound          =  [112 109];
+tmpFitParameters.peakPosUpperBound          =  [114  111];
+tmpFitParameters.backgroundRange            = [12 6];
+% PSEUDO-VOIGT:
+ tmpFitParameters.peakEta                   = [1 1];   % <- Gauss - Lorentzian ratio
+ tmpFitParameters.peakEtaLowerBound         = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound         = [1.0, 1.0];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','unconstrained','backgroundMode','linear','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+

TEST 1.3: Unconstrained kinetic Gauss Shirley

+

Gaussian + Shirley, individual area/width/position per peak, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth             = [1.6 0.6];
+tmpFitParameters.peakPos         = [113 110];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [1.0 0.6];
+tmpFitParameters.peakWidthUpperBound     =  [2.0 1.2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [112 109];
+tmpFitParameters.peakPosUpperBound       =  [114  111];
+tmpFitParameters.backgroundRange        = [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.001, 0.001];  % <- K controls Shirley step magnitude
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [10, 10];
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','unconstrained','backgroundMode','shirley','showFigures','off'); % <- background is now Shirley
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name           peakPosition              peakArea              peakFWHM      peakBackground
+    ______________    ________________    ________________________    ____________    ______________
+
+    {'random.ibw'}    113.01    110.51    2.1191e+05         26111    2    0.85481      0    10088  
+
+         name          peakEta          peakShirleyK    
+    ______________    __________    ____________________
+
+    {'random.ibw'}    NaN    NaN    0.014409    0.010989
+
+
+

TEST 1.4: Unconstrained kinetic PV Shirley

+

Pseudo-Voigt + Shirley, individual area/width/eta/position per peak, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth             = [1.6 0.6];
+tmpFitParameters.peakPos         = [113 110];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [1.0 0.6];
+tmpFitParameters.peakWidthUpperBound     =  [2.0 1.2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [112 109];
+tmpFitParameters.peakPosUpperBound       =  [114  111];
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT:
+ tmpFitParameters.peakEta                = [1 1];       % <- Gauss - Lorentzian ratio
+ tmpFitParameters.peakEtaLowerBound      = [0.0 0.0];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.001, 0.001];   % <- K controls Shirley step magnitude
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [10, 10];
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','unconstrained','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name           peakPosition              peakArea              peakFWHM      peakBackground
+    ______________    ________________    ________________________    ____________    ______________
+
+    {'random.ibw'}    113.01    110.51    2.1524e+05         25896    2    0.85069      0    9897   
+
+         name              peakEta              peakShirleyK    
+    ______________    __________________    ____________________
+
+    {'random.ibw'}    0.96301          1    0.013671    0.019616
+
+
+

TEST 1.5: Unconstrained binding Gauss linear

+

Gaussian + Linear, individual area/width/position per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea                   = [1e5 100];
+tmpFitParameters.peakWidth                  = [1.6 1.6 ];
+tmpFitParameters.peakPos                    = [38 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound         =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound         =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound        =  [0.2 0.2];
+tmpFitParameters.peakWidthUpperBound        =  [2.0 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound          =  [37 35];
+tmpFitParameters.peakPosUpperBound          =  [39 37];
+
+tmpFitParameters.backgroundRange            = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...    % <- process binding energy
+    'mode','unconstrained','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name         peakPosition
+    ______________    ____________
+
+    {'random.ibw'}     38    36.2 
+
+         name             peakArea    
+    ______________    ________________
+
+    {'random.ibw'}    161.41    339.54
+
+         name              peakFWHM     
+    ______________    __________________
+
+    {'random.ibw'}    0.30274    0.39891
+
+         name          peakBackground 
+    ______________    ________________
+
+    {'random.ibw'}    4.499    -66.192
+
+
+

TEST 1.5.2: Unconstrained binding Gauss linear

+

Gaussian + Linear, individual area/width/position per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea                   = [1e5 1e4 100]; % <- 3 peaks
+tmpFitParameters.peakWidth                  = [1.6 1.6 1.6];
+tmpFitParameters.peakPos                    = [38 37 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound         =  [1e2 1e2 1e2];
+tmpFitParameters.peakAreaUpperBound         =  [Inf Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound        =  [0.2 0.2 0.2];
+tmpFitParameters.peakWidthUpperBound        =  [2.0 2 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound          =  [37 37 35];
+tmpFitParameters.peakPosUpperBound          =  [39 37.5 37];
+
+tmpFitParameters.backgroundRange            = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','unconstrained','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 3
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 3 valid peaks (non-NaN)
+         name                peakPosition       
+    ______________    __________________________
+
+    {'random.ibw'}    38.002      37.5    36.198
+
+         name                  peakArea         
+    ______________    __________________________
+
+    {'random.ibw'}    141.14       100    331.37
+
+         name                   peakFWHM           
+    ______________    _____________________________
+
+    {'random.ibw'}    0.27818          2    0.39199
+
+         name          peakBackground  
+    ______________    _________________
+
+    {'random.ibw'}    3.7559    -45.397
+
+
+

TEST 1.6: Unconstrained binding PV linear

+

Pseudo-Voigt + Linear, individual area/width/eta/position per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea                   = [1e5 100]; % <- back to 2 peaks
+tmpFitParameters.peakWidth                  = [1.6 1.6 ];
+tmpFitParameters.peakPos                    = [38 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound         =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound         =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound        =  [0.2 0.2];
+tmpFitParameters.peakWidthUpperBound        =  [2.0 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound          =  [37 35];
+tmpFitParameters.peakPosUpperBound          =  [39 37];
+tmpFitParameters.backgroundRange            = [12 6];
+% PSEUDO-VOIGT + LINEAR variant:
+ tmpFitParameters.peakEta                   = [1 1];
+ tmpFitParameters.peakEtaLowerBound         = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound         = [1.0, 1.0];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','unconstrained','backgroundMode','linear','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name            peakPosition                peakArea                       peakFWHM                peakBackground  
+    ______________    __________________    __________________________    _____________________________    _________________
+
+    {'random.ibw'}    38    36.2     NaN    166.69    339.68       NaN    0.29956      0.399        NaN    4.4343    -64.288
+
+         name                    peakEta                 peakShirleyK   
+    ______________    _____________________________    _________________
+
+    {'random.ibw'}    0.89096          1        NaN    NaN    NaN    NaN
+
+
+

TEST 1.7: Unconstrained binding Gauss Shirley

+

Gaussian + Shirley, individual area/width/position per peak, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea                   = [1e5 100];
+tmpFitParameters.peakWidth                  = [1.6 1.6 ];
+tmpFitParameters.peakPos                    = [38 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound         =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound         =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound        =  [0.2 0.2];
+tmpFitParameters.peakWidthUpperBound        =  [2.0 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound          =  [37 35];
+tmpFitParameters.peakPosUpperBound          =  [39 37];
+tmpFitParameters.backgroundRange            = [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK             = [0.01, 0.01];  % <- K controls Shirley step magnitude
+  tmpFitParameters.peakShirleyKLowerBound   = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound   = [100, 100];
+  tmpFitParameters.peakShirleyOffset        = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','unconstrained','backgroundMode','shirley','showFigures','off');
+
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+2 out of 3 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.997    36.197       NaN    158.68    344.57       NaN    0.29936    0.40291        NaN     0    80.681  
+
+         name              peakEta                   peakShirleyK          
+    ______________    _________________    ________________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.090928    0.060519         NaN
+
+
+

TEST 1.8: Unconstrained binding PV Shirley

+

Pseudo-Voigt + Shirley, individual area/width/eta/position per peak, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea                   = [1e5 100];
+tmpFitParameters.peakWidth                  = [1.6 1.6 ];
+tmpFitParameters.peakPos                    = [38 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound         =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound         =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound        =  [0.2 0.2];
+tmpFitParameters.peakWidthUpperBound        =  [2.0 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound          =  [37 35];
+tmpFitParameters.peakPosUpperBound          =  [39 37];
+tmpFitParameters.backgroundRange            = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                   = [1 1];
+ tmpFitParameters.peakEtaLowerBound         = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound         = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK             = [0.01, 0.01];  % <- K controls Shirley step magnitude
+  tmpFitParameters.peakShirleyKLowerBound   = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound   = [100, 100];
+  tmpFitParameters.peakShirleyOffset        = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','unconstrained','backgroundMode','shirley','showFigures','off');
+
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.997    36.198       NaN    159.35    357.04       NaN    0.30019    0.39955        NaN     0    79.747  
+
+         name                 peakEta                     peakShirleyK          
+    ______________    _______________________    _______________________________
+
+    {'random.ibw'}    1    0.89055        NaN    0.10961    0.052005         NaN
+
+
+

TEST 2.1: Position-Constrained kinetic Gaussian Linear

+

Gaussian + Linear, first peak position free, other peaks offset fixed

+
clc
+clearvars tmpFitParameters;
+tmpFitParameters.peakArea                   = [1e5 1e5]; % <- 2 peaks
+tmpFitParameters.peakWidth                  = [2 1];
+tmpFitParameters.peakPos                    = [113 -2.32]; % <- pos peak #2 is relative to peak #1
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound         =  [1E4 1E4];
+tmpFitParameters.peakAreaUpperBound         =  [1E6 1E6];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound        =  [1.5 0.6];
+tmpFitParameters.peakWidthUpperBound        =  [2.5 1.5];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound          =  112.5; % <- only pos 1 is fitted
+tmpFitParameters.peakPosUpperBound          =  113.5;
+tmpFitParameters.backgroundRange            = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','position','backgroundMode','linear','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                             peakFWHM                peakBackground  
+    ______________    __________________________    ______________________________________    ____________________________    __________________
+
+    {'random.ibw'}    112.98    110.66       NaN    2.0893e+05         27722           NaN    1.9636    0.96037        NaN    -323.76      48305
+
+         name              peakEta           peakShirleyK   
+    ______________    _________________    _________________
+
+    {'random.ibw'}    NaN    NaN    NaN    NaN    NaN    NaN
+
+
+

TEST 2.2: Position-Constrained kinetic PV Linear

+

Pseudo-Voigt + Linear, first peak position free, other peaks offset fixed

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 1e5];
+tmpFitParameters.peakWidth              = [2 1];
+tmpFitParameters.peakPos                = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1E4 1E4];
+tmpFitParameters.peakAreaUpperBound      =  [1E6 1E6];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [1.5 0.6];
+tmpFitParameters.peakWidthUpperBound     =  [2.5 1.5];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  112.5;
+tmpFitParameters.peakPosUpperBound       =  113.5;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','position','backgroundMode','linear','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                             peakFWHM                peakBackground  
+    ______________    __________________________    ______________________________________    ____________________________    __________________
+
+    {'random.ibw'}    112.98    110.66       NaN    2.0881e+05         28143           NaN    1.9628    0.95856        NaN    -321.99      48089
+
+         name                 peakEta              peakShirleyK   
+    ______________    _______________________    _________________
+
+    {'random.ibw'}    1    0.95559        NaN    NaN    NaN    NaN
+
+
+

TEST 2.3: Position-Constrained kinetic Gauss Shirley

+

Gaussian + Shirley, first peak position free, other peaks offset fixed, Shirley K per peak

+
clearvars tmpFitParameters;
+tmpFitParameters.peakArea               = [1e5 1e5];
+tmpFitParameters.peakWidth              = [2 1];
+tmpFitParameters.peakPos                = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1E4 1E4];
+tmpFitParameters.peakAreaUpperBound      =  [1E6 1E6];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [1.5 0.6];
+tmpFitParameters.peakWidthUpperBound     =  [2.5 1.5];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  112.5;
+tmpFitParameters.peakPosUpperBound       =  113.5;
+tmpFitParameters.backgroundRange        = [12 6];
+ % SHIRLEY:
+  tmpFitParameters.peakShirleyK           = [0.01, 0.001];
+  tmpFitParameters.peakShirleyKLowerBound = [0.0, 0.0];
+  tmpFitParameters.peakShirleyKUpperBound = [Inf, Inf];
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','position','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM              peakBackground
+    ______________    __________________________    ______________________________________    ___________________________    ______________
+
+    {'random.ibw'}    112.98    110.66       NaN    2.1721e+05         27055           NaN    2.012    0.91594        NaN     0    9838.1  
+
+         name              peakEta                      peakShirleyK             
+    ______________    _________________    ______________________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    1.1215e-17       0.15213           NaN
+
+
+

TEST 2.4: Position-Constrained kinetic PV Shirley

+

Pseudo-Voigt + Shirley, first peak position free, other peaks offset fixed, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 1e5];
+tmpFitParameters.peakWidth              = [2 1];
+tmpFitParameters.peakPos                = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1E4 1E4];
+tmpFitParameters.peakAreaUpperBound      =  [1E6 1E6];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [1.5 0.6];
+tmpFitParameters.peakWidthUpperBound     =  [2.5 1.5];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  112.5;
+tmpFitParameters.peakPosUpperBound       =  113.5;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+ % SHIRLEY:
+  tmpFitParameters.peakShirleyK           = [0.01, 0.001];
+  tmpFitParameters.peakShirleyKLowerBound = [0.0, 0.0];
+  tmpFitParameters.peakShirleyKUpperBound = [Inf, Inf];
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','position','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM             peakBackground
+    ______________    __________________________    ______________________________________    __________________________    ______________
+
+    {'random.ibw'}    112.97    110.65       NaN    2.2521e+05         26167           NaN    2.01    0.89985        NaN     0    9379.8  
+
+         name                    peakEta                            peakShirleyK             
+    ______________    _____________________________    ______________________________________
+
+    {'random.ibw'}    0.90898          1        NaN    1.1167e-17       0.16586           NaN
+
+
+

TEST 2.5: Position binding Gauss linear

+

Gaussian + Linear, first peak position free, other peaks offset fixed

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = [1.6 1.6 ];
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [0.2 0.2];
+tmpFitParameters.peakWidthUpperBound     =  [2.0 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','position','backgroundMode','linear','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name            peakPosition                peakArea                       peakFWHM                peakBackground 
+    ______________    __________________    __________________________    _____________________________    ________________
+
+    {'random.ibw'}    38    36.2     NaN    161.41    339.54       NaN    0.30274    0.39891        NaN    4.499    -66.193
+
+         name              peakEta           peakShirleyK   
+    ______________    _________________    _________________
+
+    {'random.ibw'}    NaN    NaN    NaN    NaN    NaN    NaN
+
+
+

TEST 2.6: Position binding PV linear

+

Pseudo-Voigt + Linear, first peak position free, other peaks offset fixed

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = [1.6 1.6 ];
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [0.2 0.2];
+tmpFitParameters.peakWidthUpperBound     =  [2.0 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT + LINEAR variant:
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','position','backgroundMode','linear','showFigures','on');
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name            peakPosition   
+    ______________    __________________
+
+    {'random.ibw'}    38    36.2     NaN
+
+         name                 peakArea         
+    ______________    _________________________
+
+    {'random.ibw'}    166.7    339.68       NaN
+
+         name                   peakFWHM           
+    ______________    _____________________________
+
+    {'random.ibw'}    0.29956    0.39901        NaN
+
+         name          peakBackground  
+    ______________    _________________
+
+    {'random.ibw'}    4.4342    -64.285
+
+         name                    peakEta           
+    ______________    _____________________________
+
+    {'random.ibw'}    0.89075          1        NaN
+
+
+

TEST 2.7: Position binding Gauss Shirley

+

Gaussian + Shirley, first peak position free, other peaks offset fixed, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = [1.6 1.6 ];
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [0.2 0.2];
+tmpFitParameters.peakWidthUpperBound     =  [2.0 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.01, 0.01];
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [100, 100];
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','position','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.997    36.197       NaN    158.68    344.56       NaN    0.29935     0.4029        NaN     0    80.679  
+
+         name              peakEta                   peakShirleyK          
+    ______________    _________________    ________________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.090755    0.060597         NaN
+
+
+

TEST 2.8: Position binding PV Shirley

+

Pseudo-Voigt + Shirley, first peak position free, other peaks offset fixed, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = [1.6 1.6 ];
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [0.2 0.2];
+tmpFitParameters.peakWidthUpperBound     =  [2.0 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.01, 0.01];  % <- 1 K for each peak
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [100, 100];
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','position','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 4 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.997    36.197       NaN    159.22    356.34       NaN    0.30002    0.39958        NaN     0    79.756  
+
+         name                 peakEta                     peakShirleyK         
+    ______________    _______________________    ______________________________
+
+    {'random.ibw'}    1    0.89508        NaN    0.1062    0.053513         NaN
+
+
+

TEST 2.9: Position kinetic PV Shirley shared

+

Pseudo-Voigt + Shirley, first peak position free, other peaks offset fixed, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea                   = [1e5 1e5];
+tmpFitParameters.peakWidth                  = [2 1];
+tmpFitParameters.peakPos                    = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound         =  [1E4 1E4];
+tmpFitParameters.peakAreaUpperBound         =  [1E6 1E6];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound        =  [1.5 0.6];
+tmpFitParameters.peakWidthUpperBound        =  [2.5 1.5];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound          =  112.5;
+tmpFitParameters.peakPosUpperBound          =  113.5;
+tmpFitParameters.backgroundRange            = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                   = [1 1];
+ tmpFitParameters.peakEtaLowerBound         = [0 0];
+ tmpFitParameters.peakEtaUpperBound         = [1.0, 1.0];
+ % SHIRLEY:
+  tmpFitParameters.peakShirleyK             = 0.01;  % <- same K for all peaks
+  tmpFitParameters.peakShirleyKLowerBound   = 0.0;
+  tmpFitParameters.peakShirleyKUpperBound   = Inf;
+  tmpFitParameters.peakShirleyOffset        = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','positionShirley','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM             peakBackground
+    ______________    __________________________    ______________________________________    __________________________    ______________
+
+    {'random.ibw'}    112.99    110.67       NaN    2.0881e+05         26346           NaN    1.9658    0.9424       NaN      0    10519  
+
+         name             peakEta                peakShirleyK         
+    ______________    _______________    _____________________________
+
+    {'random.ibw'}    1      1    NaN    0.01253    0.01253        NaN
+
+
+

TEST 2.10: Position kinetic Gauss Shirley Shared

+

Gaussian + Shirley, first peak position free, other peaks offset fixed, shared Shirley K

+
clearvars tmpFitParameters;
+tmpFitParameters.peakArea               = [1e5 1e5];
+tmpFitParameters.peakWidth              = [2 1];
+tmpFitParameters.peakPos                = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1E4 1E4];
+tmpFitParameters.peakAreaUpperBound      =  [1E6 1E6];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [1.5 0.6];
+tmpFitParameters.peakWidthUpperBound     =  [2.5 1.5];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  112.5;
+tmpFitParameters.peakPosUpperBound       =  113.5;
+tmpFitParameters.backgroundRange        = [12 6];
+ % SHIRLEY:
+  tmpFitParameters.peakShirleyK           = 0.01;
+  tmpFitParameters.peakShirleyKLowerBound = 0.0;
+  tmpFitParameters.peakShirleyKUpperBound = Inf;
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','positionShirley','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM             peakBackground
+    ______________    __________________________    ______________________________________    __________________________    ______________
+
+    {'random.ibw'}    112.99    110.67       NaN    2.0881e+05         26346           NaN    1.9658    0.9424       NaN      0    10519  
+
+         name              peakEta                 peakShirleyK         
+    ______________    _________________    _____________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.01253    0.01253        NaN
+
+
+

TEST 2.11: Position binding Gauss Shirley Shared

+

Gaussian + Shirley, first peak position free, other peaks offset fixed, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = [1.6 1.6 ];
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [0.2 0.2];
+tmpFitParameters.peakWidthUpperBound     =  [2.0 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.01;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 100;
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','positionShirley','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 4 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.997    36.197       NaN    158.03    343.26       NaN    0.29852     0.4019        NaN     0    80.547  
+
+         name              peakEta                   peakShirleyK          
+    ______________    _________________    ________________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.069475    0.069475         NaN
+
+
+

TEST 2.12: Position binding PV Shirley Shared

+

Pseudo-Voigt + Shirley, first peak position free, other peaks offset fixed, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = [1.6 1.6 ];
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [0.2 0.2];
+tmpFitParameters.peakWidthUpperBound     =  [2.0 2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.01;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 100;
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','positionShirley','backgroundMode','shirley','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 4 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition       
+    ______________    __________________________
+
+    {'random.ibw'}    37.997    36.197       NaN
+
+         name                  peakArea         
+    ______________    __________________________
+
+    {'random.ibw'}    158.05    348.71       NaN
+
+         name                   peakFWHM           
+    ______________    _____________________________
+
+    {'random.ibw'}    0.29854    0.39983        NaN
+
+         name         peakBackground
+    ______________    ______________
+
+    {'random.ibw'}     0    80.022  
+
+         name                 peakEta        
+    ______________    _______________________
+
+    {'random.ibw'}    1    0.94589        NaN
+
+         name                   peakShirleyK          
+    ______________    ________________________________
+
+    {'random.ibw'}    0.069109    0.069109         NaN
+
+
+

TEST 3.1: widthPosition kinetic Gauss linear

+

Gaussian + Linear, shared width, first peak position free, other peaks offset fixed

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea                   = [5e5 100]; % <- 2 peaks
+tmpFitParameters.peakWidth                  = 1.6; % <- one width for all peaks
+tmpFitParameters.peakPos                    = [113 -2.32]; % <- positions relative to peak1
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound         =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound         =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound        =  1.0;
+tmpFitParameters.peakWidthUpperBound        =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound          =  112;
+tmpFitParameters.peakPosUpperBound          =  114;
+tmpFitParameters.backgroundRange            = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthPosition','backgroundMode','linear','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                          peakFWHM              peakBackground  
+    ______________    __________________________    ______________________________________    _______________________    __________________
+
+    {'random.ibw'}    113.04    110.72       NaN    2.0058e+05         41563           NaN    1.867    1.867      NaN    -269.69      41861
+
+         name              peakEta           peakShirleyK   
+    ______________    _________________    _________________
+
+    {'random.ibw'}    NaN    NaN    NaN    NaN    NaN    NaN
+
+
+

TEST 3.2: widthPosition kinetic PV linear

+

Pseudo-Voigt + Linear, shared width, first peak position free, other peaks offset fixed

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  112;
+tmpFitParameters.peakPosUpperBound       =  114;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT:
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthPosition','backgroundMode','linear','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM               peakBackground  
+    ______________    __________________________    ______________________________________    __________________________    __________________
+
+    {'random.ibw'}    113.04    110.72       NaN    1.9879e+05         53903           NaN    1.8688    1.8688       NaN    -224.69      36273
+
+         name                 peakEta              peakShirleyK   
+    ______________    _______________________    _________________
+
+    {'random.ibw'}    1    0.40299        NaN    NaN    NaN    NaN
+
+
+

TEST 3.3: widthPosition kinetic Gauss Shirley

+

Gaussian + Shirley, shared width, first peak position free, other peaks offset fixed, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  112;
+tmpFitParameters.peakPosUpperBound       =  114;
+tmpFitParameters.backgroundRange        = [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [10, 10];
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthPosition','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM             peakBackground
+    ______________    __________________________    ______________________________________    __________________________    ______________
+
+    {'random.ibw'}    113.04    110.72       NaN    2.0367e+05         41896           NaN    1.8806    1.8806       NaN      0    10361  
+
+         name              peakEta                peakShirleyK        
+    ______________    _________________    ___________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.001    0.05436        NaN
+
+
+

TEST 3.4: widthPosition kinetic PV Shirley

+

Pseudo-Voigt + Shirley, shared width, first peak position free, other peaks offset fixed, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  112;
+tmpFitParameters.peakPosUpperBound       =  114;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT:
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0.0 0.0];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [10, 10];
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthPosition','backgroundMode','shirley','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition       
+    ______________    __________________________
+
+    {'random.ibw'}    113.04    110.72       NaN
+
+         name                        peakArea               
+    ______________    ______________________________________
+
+    {'random.ibw'}    2.0064e+05         55404           NaN
+
+         name                  peakFWHM         
+    ______________    __________________________
+
+    {'random.ibw'}    1.8783    1.8783       NaN
+
+         name         peakBackground
+    ______________    ______________
+
+    {'random.ibw'}     0    9972.6  
+
+         name                 peakEta        
+    ______________    _______________________
+
+    {'random.ibw'}    1    0.35861        NaN
+
+         name                 peakShirleyK         
+    ______________    _____________________________
+
+    {'random.ibw'}    0.001    0.034913         NaN
+
+
+

TEST 3.5: widthPosition binding Gauss linear

+

Gaussian + Linear, shared width, first peak position free, other peaks offset fixed

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','widthPosition','backgroundMode','linear','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name            peakPosition                peakArea                       peakFWHM                peakBackground  
+    ______________    __________________    __________________________    _____________________________    _________________
+
+    {'random.ibw'}    38    36.2     NaN    178.45    329.79       NaN    0.37613    0.37613        NaN    4.2762    -58.777
+
+         name              peakEta           peakShirleyK   
+    ______________    _________________    _________________
+
+    {'random.ibw'}    NaN    NaN    NaN    NaN    NaN    NaN
+
+
+

TEST 3.6: widthPosition binding PV linear

+

Pseudo-Voigt + Linear, shared width, first peak position free, other peaks offset fixed

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT + LINEAR variant:
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','widthPosition','backgroundMode','linear','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+1 out of 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name            peakPosition                peakArea                       peakFWHM                peakBackground  
+    ______________    __________________    __________________________    _____________________________    _________________
+
+    {'random.ibw'}    38    36.2     NaN    177.35    347.05       NaN    0.36994    0.36994        NaN    4.2705    -59.821
+
+         name                 peakEta              peakShirleyK   
+    ______________    _______________________    _________________
+
+    {'random.ibw'}    1    0.82672        NaN    NaN    NaN    NaN
+
+
+

TEST 3.7: widthPosition binding Gauss Shirley

+

Gaussian + Shirley, shared width, first peak position free, other peaks offset fixed, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.01, 0.01];
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [100, 100];
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','widthPosition','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 11 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.998    36.198       NaN    177.53    334.34       NaN    0.37884    0.37884        NaN     0    81.607  
+
+         name              peakEta                   peakShirleyK          
+    ______________    _________________    ________________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.083602    0.051366         NaN
+
+
+

TEST 3.8: widthPosition binding PV Shirley

+

Pseudo-Voigt + Shirley, shared width, first peak position free, other peaks offset fixed, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.01, 0.01];
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [100, 100];
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','widthPosition','backgroundMode','shirley','showFigures','off');
+
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.998    36.198       NaN    176.87    376.53       NaN    0.36743    0.36743        NaN      0    78.42  
+
+         name                 peakEta                     peakShirleyK          
+    ______________    _______________________    _______________________________
+
+    {'random.ibw'}    1    0.63825        NaN    0.13562    0.028569         NaN
+
+
+

TEST 3.9: widthPosition kinetic Gauss Shirley Shared

+

Gaussian + Shirley, shared width, first peak position free, other peaks offset fixed, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  112;
+tmpFitParameters.peakPosUpperBound       =  114;
+tmpFitParameters.backgroundRange        = [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.001;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 10;
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthPositionShirley','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM             peakBackground
+    ______________    __________________________    ______________________________________    __________________________    ______________
+
+    {'random.ibw'}    113.04    110.72       NaN    2.0056e+05         40339           NaN    1.8695    1.8695       NaN      0    10531  
+
+         name              peakEta                    peakShirleyK            
+    ______________    _________________    ___________________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.0091774    0.0091774          NaN
+
+
+

TEST 3.10: widthPosition kinetic PV Shirley Shared

+

Pseudo-Voigt + Shirley, shared width, first peak position free, other peaks offset fixed, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  112;
+tmpFitParameters.peakPosUpperBound       =  114;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT:
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0.0 0.0];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.1;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 10;
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthPositionShirley','backgroundMode','shirley','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition       
+    ______________    __________________________
+
+    {'random.ibw'}    113.04    110.72       NaN
+
+         name                        peakArea               
+    ______________    ______________________________________
+
+    {'random.ibw'}    1.9813e+05         56900           NaN
+
+         name                  peakFWHM         
+    ______________    __________________________
+
+    {'random.ibw'}    1.8704    1.8704       NaN
+
+         name         peakBackground
+    ______________    ______________
+
+    {'random.ibw'}      0    10166  
+
+         name                 peakEta        
+    ______________    _______________________
+
+    {'random.ibw'}    1    0.26558        NaN
+
+         name                    peakShirleyK            
+    ______________    ___________________________________
+
+    {'random.ibw'}    0.0060439    0.0060439          NaN
+
+
+

TEST 3.11: widthPosition binding Gauss Shirley Shared

+

Gaussian + Shirley, shared width, first peak position free, other peaks offset fixed, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.01, 0.01];   % <- Too many parameters,
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001]; % Will run anyway
+  tmpFitParameters.peakShirleyKUpperBound = [100, 100];     % but show a warning.
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','widthPositionShirley','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+24 out of 25 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.998    36.198       NaN    176.65    332.86       NaN    0.37769    0.37769        NaN     0    81.436  
+
+         name              peakEta                   peakShirleyK          
+    ______________    _________________    ________________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.061951    0.061951         NaN
+
+
+

TEST 3.12: widthPosition binding PV Shirley Shared

+

Pseudo-Voigt + Shirley, shared width, first peak position free, other peaks offset fixed, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.01;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 100;
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','widthPositionShirley','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.998    36.198       NaN    174.65    360.94       NaN    0.36721    0.36721        NaN     0    78.743  
+
+         name                 peakEta                      peakShirleyK          
+    ______________    _______________________    ________________________________
+
+    {'random.ibw'}    1    0.72536        NaN    0.061437    0.061437         NaN
+
+
+

TEST 3.13: widthPosition kinetic PV Shirley & Eta Shared

+

Pseudo-Voigt + Shirley, shared width, first peak position free, other peaks offset fixed, shared Shirley K, shared PV eta

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 -2.32];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  112;
+tmpFitParameters.peakPosUpperBound       =  114;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT:
+ tmpFitParameters.peakEta                = 1;
+ tmpFitParameters.peakEtaLowerBound      = 0.0;
+ tmpFitParameters.peakEtaUpperBound      = 1.0;
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.1;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 10;
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthPositionShirleyEta','backgroundMode','shirley','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition       
+    ______________    __________________________
+
+    {'random.ibw'}    113.04    110.72       NaN
+
+         name                        peakArea               
+    ______________    ______________________________________
+
+    {'random.ibw'}    2.0056e+05         40339           NaN
+
+         name                  peakFWHM         
+    ______________    __________________________
+
+    {'random.ibw'}    1.8695    1.8695       NaN
+
+         name         peakBackground
+    ______________    ______________
+
+    {'random.ibw'}      0    10531  
+
+         name             peakEta    
+    ______________    _______________
+
+    {'random.ibw'}    1      1    NaN
+
+         name                    peakShirleyK            
+    ______________    ___________________________________
+
+    {'random.ibw'}    0.0091774    0.0091774          NaN
+
+
+

TEST 3.14: widthPosition binding PV Shirley & Eta Shared

+

Pseudo-Voigt + Shirley, shared width, first peak position free, other peaks offset fixed, shared Shirley K and PV eta

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 -1.8];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  37;
+tmpFitParameters.peakPosUpperBound       =  39;
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = 1;
+ tmpFitParameters.peakEtaLowerBound      = 0;
+ tmpFitParameters.peakEtaUpperBound      = 1.0;
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.01;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 100;
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','widthPositionShirleyEta','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.998    36.198       NaN    181.63    341.72       NaN    0.37433    0.37433        NaN     0    80.449  
+
+         name                    peakEta                         peakShirleyK          
+    ______________    _____________________________    ________________________________
+
+    {'random.ibw'}    0.90968    0.90968        NaN    0.059933    0.059933         NaN
+
+
+

TEST 4.1: Width kinetic Gauss linear

+

Gaussian + Linear, shared width, individual areas and positions

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              =  1.6;
+tmpFitParameters.peakPos                = [113 110];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [112 109];
+tmpFitParameters.peakPosUpperBound       =  [114  111];
+tmpFitParameters.backgroundRange        = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','width','backgroundMode','linear','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM               peakBackground  
+    ______________    __________________________    ______________________________________    __________________________    __________________
+
+    {'random.ibw'}    113.03    110.63       NaN    2.0228e+05         41618           NaN    1.8803    1.8803       NaN    -259.91      40642
+
+         name              peakEta           peakShirleyK   
+    ______________    _________________    _________________
+
+    {'random.ibw'}    NaN    NaN    NaN    NaN    NaN    NaN
+
+
+

TEST 4.2: Width kinetic PV linear

+

Pseudo-Voigt + Linear, shared width, individual areas, positions, and etas

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 110];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [112 109];
+tmpFitParameters.peakPosUpperBound       =  [114  111];
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT:
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','width','backgroundMode','linear','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM              peakBackground 
+    ______________    __________________________    ______________________________________    __________________________    ________________
+
+    {'random.ibw'}    113.04    110.61       NaN    1.9965e+05         64093           NaN    1.8879    1.8879       NaN    -172.1     29768
+
+         name                 peakEta              peakShirleyK   
+    ______________    _______________________    _________________
+
+    {'random.ibw'}    1    0.08888        NaN    NaN    NaN    NaN
+
+
+

TEST 4.3: Width kinetic Gauss Shirley

+

Gaussian + Shirley, shared width, individual areas and positions, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 110];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [112 109];
+tmpFitParameters.peakPosUpperBound       =  [114  111];
+tmpFitParameters.backgroundRange        =  [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [10, 10];
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','width','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM             peakBackground
+    ______________    __________________________    ______________________________________    __________________________    ______________
+
+    {'random.ibw'}    113.03    110.65       NaN    2.0463e+05         42032           NaN    1.8892    1.8892       NaN      0    10381  
+
+         name              peakEta                 peakShirleyK         
+    ______________    _________________    _____________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.001    0.049002         NaN
+
+
+

TEST 4.4: Width kinetic PV Shirley

+

Pseudo-Voigt + Shirley, shared width, individual areas, positions, and etas, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 110];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [112 109];
+tmpFitParameters.peakPosUpperBound       =  [114  111];
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT:
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0.0 0.0];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [10, 10];
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','width','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                          peakFWHM            peakBackground
+    ______________    __________________________    ______________________________________    _______________________    ______________
+
+    {'random.ibw'}    113.04     110.6       NaN    2.0006e+05         67979           NaN    1.893    1.893      NaN     0    9671.6  
+
+         name                    peakEta                       peakShirleyK         
+    ______________    _____________________________    _____________________________
+
+    {'random.ibw'}    1    1.7875e-12           NaN    0.001    0.016524         NaN
+
+
+

TEST 4.5: Width binding Gauss linear

+

Gaussian + Linear, shared width, individual areas and positions

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              =  1.6;
+tmpFitParameters.peakPos                = [38 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [37 35];
+tmpFitParameters.peakPosUpperBound       =  [39 37];
+tmpFitParameters.backgroundRange        = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','width','backgroundMode','linear','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name            peakPosition                peakArea                       peakFWHM                peakBackground  
+    ______________    __________________    __________________________    _____________________________    _________________
+
+    {'random.ibw'}    38    36.2     NaN    178.45    329.79       NaN    0.37613    0.37613        NaN    4.2763    -58.783
+
+         name              peakEta           peakShirleyK   
+    ______________    _________________    _________________
+
+    {'random.ibw'}    NaN    NaN    NaN    NaN    NaN    NaN
+
+
+

TEST 4.6: Width binding PV linear

+

Pseudo-Voigt + Linear, shared width, individual areas, positions, and etas

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [37 35];
+tmpFitParameters.peakPosUpperBound       =  [39 37];
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT + LINEAR variant:
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','width','backgroundMode','linear','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 17 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name            peakPosition                peakArea                       peakFWHM                peakBackground  
+    ______________    __________________    __________________________    _____________________________    _________________
+
+    {'random.ibw'}    38    36.2     NaN    177.35    347.04       NaN    0.36994    0.36994        NaN    4.2706    -59.824
+
+         name                 peakEta              peakShirleyK   
+    ______________    _______________________    _________________
+
+    {'random.ibw'}    1    0.82681        NaN    NaN    NaN    NaN
+
+
+

TEST 4.7: Width binding Gauss Shirley

+

Gaussian + Shirley, shared width, individual areas and positions, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [37 35];
+tmpFitParameters.peakPosUpperBound       =  [39 37];
+tmpFitParameters.backgroundRange        = [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.01, 0.01];
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [100, 100];
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','width','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.997    36.198       NaN    177.64    334.52       NaN    0.37898    0.37898        NaN     0    81.633  
+
+         name              peakEta                   peakShirleyK          
+    ______________    _________________    ________________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.086202    0.050048         NaN
+
+
+

TEST 4.8: Width binding PV Shirley

+

Pseudo-Voigt + Shirley, shared width, individual areas, positions, and etas, Shirley K per peak

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [37 35];
+tmpFitParameters.peakPosUpperBound       =  [39 37];
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = [0.01, 0.01];
+  tmpFitParameters.peakShirleyKLowerBound = [0.001, 0.001];
+  tmpFitParameters.peakShirleyKUpperBound = [100, 100];
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','width','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 7 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.995      36.2       NaN    177.27    379.09       NaN    0.36755    0.36755        NaN     0    78.411  
+
+         name                peakEta                    peakShirleyK          
+    ______________    _____________________    _______________________________
+
+    {'random.ibw'}    1    0.6252       NaN    0.14837    0.022886         NaN
+
+
+

TEST 4.9: Width kinetic Gauss Shirley Shared

+

Gaussian + Shirley, shared width, individual areas and positions, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 110];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [112 109];
+tmpFitParameters.peakPosUpperBound       =  [114  111];
+tmpFitParameters.backgroundRange        =  [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.001;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 10;
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthShirley','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM             peakBackground
+    ______________    __________________________    ______________________________________    __________________________    ______________
+
+    {'random.ibw'}    113.04    110.64       NaN    2.0225e+05         40491           NaN    1.8825    1.8825       NaN      0    10468  
+
+         name              peakEta                    peakShirleyK            
+    ______________    _________________    ___________________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.0086228    0.0086228          NaN
+
+
+

TEST 4.10: Width kinetic PV Shirley Shared

+

Pseudo-Voigt + Shirley, shared width, individual areas, positions, and etas, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [113 110];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [1e3 1e3];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [112 109];
+tmpFitParameters.peakPosUpperBound       =  [114  111];
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT:
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0.0 0.0];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.001;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 10;
+  tmpFitParameters.peakShirleyOffset      = 1E4;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthShirley','backgroundMode','shirley','showFigures','off');
+quickPlotKinetic(FitList,tmpDataSelection)
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                          peakArea                            peakFWHM             peakBackground
+    ______________    __________________________    ______________________________________    __________________________    ______________
+
+    {'random.ibw'}    113.04     110.6       NaN    1.9912e+05         67333           NaN    1.8892    1.8892       NaN     0    9850.2  
+
+         name                    peakEta                          peakShirleyK            
+    ______________    _____________________________    ___________________________________
+
+    {'random.ibw'}    1    2.7303e-14           NaN    0.0035491    0.0035491          NaN
+
+
+

TEST 4.11: Width binding Gauss Shirley Shared

+

Gaussian + Shirley, shared width, individual areas and positions, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [37 35];
+tmpFitParameters.peakPosUpperBound       =  [39 37];
+tmpFitParameters.backgroundRange        = [12 6];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.01;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 100;
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','widthShirley','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 12 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.998    36.197       NaN    176.65    332.86       NaN    0.37769    0.37769        NaN     0    81.434  
+
+         name              peakEta                 peakShirleyK         
+    ______________    _________________    _____________________________
+
+    {'random.ibw'}    NaN    NaN    NaN    0.06196    0.06196        NaN
+
+
+

TEST 4.12: Width binding PV Shirley Shared

+

Pseudo-Voigt + Shirley, shared width, individual areas and positions, shared Shirley K

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [1e5 100];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [38 36];
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0.01 0.01];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.2;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [37 35];
+tmpFitParameters.peakPosUpperBound       =  [39 37];
+tmpFitParameters.backgroundRange        = [12 6];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = [1 1];
+ tmpFitParameters.peakEtaLowerBound      = [0 0 ];
+ tmpFitParameters.peakEtaUpperBound      = [1.0, 1.0];
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.01;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 100;
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','widthShirley','backgroundMode','shirley','showFigures','off');
+quickPlotBinding(FitList,tmpDataSelection)
+xlim([34,39])
+
+
Validating FitParameter structure...
+  Number of peaks detected: 2
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 14 local solver runs converged with a positive local solver exit flag.
+Found 2 valid peaks (non-NaN)
+         name                peakPosition                    peakArea                       peakFWHM               peakBackground
+    ______________    __________________________    __________________________    _____________________________    ______________
+
+    {'random.ibw'}    37.998    36.198       NaN    174.65    360.96       NaN    0.36721    0.36721        NaN     0    78.737  
+
+         name                 peakEta                      peakShirleyK          
+    ______________    _______________________    ________________________________
+
+    {'random.ibw'}    1    0.72518        NaN    0.061454    0.061454         NaN
+
+
+

Random data for 5 peaks

+
clc
+close all
+% binding
+x = linspace(50, 30, 1000)';
+true_params = [800 1.6 36.2; 500 1.6 38.0;1000 0.3 39.0;800 1.6 40;500 1.6 40.5];
+y = zeros(size(x));
+fwhm_to_sigma = @(fwhm) fwhm / (2*sqrt(2*log(2)));
+for i = 1:size(true_params,1)
+    A = true_params(i,1);
+    sigma = fwhm_to_sigma(true_params(i,2));
+    pos = true_params(i,3);
+    y = y + A * exp(-((x - pos).^2) / (2*sigma^2));
+end
+% Simulate realistic Shirley-style background using smooth tanh transition
+center = 36.2; width = 3;
+shirley_step = 75 + 45 * (1 + tanh((x - center)/width))/2;
+y = y + shirley_step;
+
+center = 38; width = 3;
+shirley_step = 75 + 45 * (1 + tanh((x - center)/width))/2;
+y = y + shirley_step;
+
+center = 40; width = 3;
+shirley_step = 75 + 45 * (1 + tanh((x - center)/width))/2;
+y = y + shirley_step;
+
+center = 40.5; width = 3;
+shirley_step = 75 + 45 * (1 + tanh((x - center)/width))/2;
+y = y + shirley_step;
+
+
+y = y + 5 * randn(size(x));  % add mild noise
+figure;
+plot(x, y, 'k.');
+xlabel('Binding Energy');
+ylabel('Intensity');
+title('Raw Data with Shirley Tail');
+set(gca, 'XDir', 'reverse'); grid on;
+hold on;
+if ~ismember('bindingEnergy_eV', FitList.Properties.VariableNames)
+    FitList.bindingEnergy_eV = cell(size(FitList,1),1);
+end
+if ~ismember('spectrum_counts', FitList.Properties.VariableNames)
+    FitList.spectrum_counts = cell(size(FitList,1),1);
+end
+FitList(tmpDataSelection,:).bindingEnergy_eV{:} = x;
+FitList(tmpDataSelection,:).spectrum_counts{:} = y;
+
+nappPlot(FitList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','binding');
+
+
+% kinetic
+x = linspace(30, 45, 1000)';
+true_params = [800 1.6 36.2; 500 1.6 38.0;1000 0.3 39.0;800 1.6 40;500 1.6 40.5];
+y = zeros(size(x));
+fwhm_to_sigma = @(fwhm) fwhm / (2*sqrt(2*log(2)));
+for i = 1:size(true_params,1)
+    A = true_params(i,1);
+    sigma = fwhm_to_sigma(true_params(i,2));
+    pos = true_params(i,3);
+    y = y + A * exp(-((x - pos).^2) / (2*sigma^2));
+end
+y = y + 5 * randn(size(x));  % add mild noise
+figure;
+plot(x, y, 'k.');
+xlabel('Kinetic Energy');
+ylabel('Intensity');
+title('Raw Data without Shirley Tail');
+grid on;
+hold on;
+
+FitList(tmpDataSelection,:).scientaEkin_eV{:} = x;
+FitList(tmpDataSelection,:).spectrum_countsNorm{:} = y;
+
+nappPlot(FitList,tmpDataSelection,'tableVariable','spectrum_countsNorm','energyScale','kinetic');
+
+

Test 5.0 Custom ModelunconstrainedAndWidthPosition, kinetic, linear

+

Custom: Gaussian + Linear, shared width for 2 peaks, individual area/position for 5 peaks (peak count must match hardcoded equation: 5 peaks)

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 5e5 5e5 5e5 5e5];
+tmpFitParameters.peakWidth              = [1.6 0.6];
+tmpFitParameters.peakPos                = [-1.8 38 39 41 41] ;
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0 0 0 0 0];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf Inf Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [1.0 0.1];
+tmpFitParameters.peakWidthUpperBound     =  [2.0 1.2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [-1.8 38 39 41 41]-1;
+tmpFitParameters.peakPosUpperBound       =  [-1.8 38 39 41 41]+1;
+tmpFitParameters.backgroundRange        = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','unconstrainedAndWidthPosition','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 5
+Found 5 valid peaks (non-NaN)
+         name                         peakPosition                
+    ______________    ____________________________________________
+
+    {'random.ibw'}    36.2    37.997        39        40    40.507
+
+         name                            peakArea                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1359.5     853.1     321.4    1373.6    840.22
+
+         name                              peakFWHM                     
+    ______________    __________________________________________________
+
+    {'random.ibw'}    1.5961     1.5961    0.30004     1.5961     1.5961
+
+         name             peakBackground    
+    ______________    ______________________
+
+    {'random.ibw'}    -0.031208        1.246
+
+
+

Test 5.1 Custom ModelunconstrainedAndWidthPosition, binding, linear

+

Custom: Gaussian + Linear, shared width for 2 peaks, individual area/position for 5 peaks (peak count must match hardcoded equation: 5 peaks)

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 5e5 5e5 5e5 5e5];
+tmpFitParameters.peakWidth              = [1.6 0.6];
+tmpFitParameters.peakPos                = [-1.8 38 39 41 41] ;
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0 0 0 0 0];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf Inf Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [1.0 0.1];
+tmpFitParameters.peakWidthUpperBound     =  [2.0 1.2];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [-1.8 38 39 41 41]-1;
+tmpFitParameters.peakPosUpperBound       =  [-1.8 38 39 41 41]+1;
+tmpFitParameters.backgroundRange        = [12 12];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','unconstrainedAndWidthPosition','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 5
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+27 out of 30 local solver runs converged with a positive local solver exit flag.
+Found 5 valid peaks (non-NaN)
+         name                          peakPosition                 
+    ______________    ______________________________________________
+
+    {'random.ibw'}    36.218    38.036    39.001    40.146    41.171
+
+         name                            peakArea                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1333.6    853.51    329.61    2055.8    219.92
+
+         name                              peakFWHM                     
+    ______________    __________________________________________________
+
+    {'random.ibw'}    1.5999     1.5999    0.30481     1.5999     1.5999
+
+         name          peakBackground  
+    ______________    _________________
+
+    {'random.ibw'}    11.364    -54.982
+
+
+

Test 5.3 Custom widthPositionAmineAreaRatio, kinetic, linear

+

Custom: Gaussian + Linear, shared width, constrained area ratios, 5 peaks with position/area constraints (peak count must match hardcoded equation: 5 peaks)

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 5e5 1 5e5 5e5];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [36 1.8 2.8 3.8 5.5 6] ;
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0 0 0 0 0];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf Inf Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  34;
+tmpFitParameters.peakPosUpperBound       =  36;
+tmpFitParameters.backgroundRange        = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthPositionAmineAreaRatio','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 5
+Found 5 valid peaks (non-NaN)
+         name                    peakPosition           
+    ______________    __________________________________
+
+    {'random.ibw'}    36    37.8    38.8    39.8    41.5
+
+         name                            peakArea                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1716.2    592.77    592.77    2423.3    905.56
+
+         name               peakFWHM       
+    ______________    _____________________
+
+    {'random.ibw'}    2    2    2    2    2
+
+         name           peakBackground  
+    ______________    __________________
+
+    {'random.ibw'}    -21.402     667.62
+
+
+

Test 5.4 Custom gasAndTwoAcidBasePairs, kinetic, linear

+

Custom: Gaussian + Linear, 2 shared widths, constrained to acid-base pair model, 5 peaks (peak count must match hardcoded equation: 5 peaks)

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 5e5 5e5 5e5 5e5];
+tmpFitParameters.peakWidth              = [1 0.3];
+tmpFitParameters.peakPos                = [-1 36 39 -1 41] ;
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [100 100 100 100 100];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf Inf Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [1 0.1];
+tmpFitParameters.peakWidthUpperBound     =  [1.6 1];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [-1 37 39 -1 41]-1 ;
+tmpFitParameters.peakPosUpperBound       =  [-1 37 39 -1 41]+1 ;
+tmpFitParameters.backgroundRange        = [12 12];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','gasAndTwoAcidBasePairs','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 5
+Found 5 valid peaks (non-NaN)
+         name                         peakPosition                
+    ______________    ____________________________________________
+
+    {'random.ibw'}    36.2    37.997        39    39.997    40.504
+
+         name                            peakArea                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1359.3    852.88    321.29    1360.3    853.74
+
+         name                              peakFWHM                     
+    ______________    __________________________________________________
+
+    {'random.ibw'}    1.5959     1.5959    0.29999     1.5959     1.5959
+
+         name            peakBackground   
+    ______________    ____________________
+
+    {'random.ibw'}    -0.02561      1.0647
+
+
+

Test 5.5 Custom gasAndTwoAcidBasePairs, binding, linear

+

Custom: Gaussian + Linear, 2 shared widths, constrained to acid-base pair model, 5 peaks (peak count must match hardcoded equation: 5 peaks)

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 5e5 5e5 5e5 5e5];
+tmpFitParameters.peakWidth              = [1 0.3];
+tmpFitParameters.peakPos                = [-1 36 39 -1 41] ;
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [100 100 100 100 100];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf Inf Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  [1 0.1];
+tmpFitParameters.peakWidthUpperBound     =  [1.6 1];
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [-1 37 39 -1 41]-1 ;
+tmpFitParameters.peakPosUpperBound       =  [-1 37 39 -1 41]+1 ;
+tmpFitParameters.backgroundRange        = [12 12];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','gasAndTwoAcidBasePairs','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 5
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 5 valid peaks (non-NaN)
+         name                         peakPosition                 
+    ______________    _____________________________________________
+
+    {'random.ibw'}    36.21        38        39    40.068    40.791
+
+         name                            peakArea                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1311.7     840.6     330.9    1780.9    478.83
+
+         name                              peakFWHM                     
+    ______________    __________________________________________________
+
+    {'random.ibw'}    1.5726     1.5726    0.30548     1.5726     1.5726
+
+         name          peakBackground  
+    ______________    _________________
+
+    {'random.ibw'}    12.414    -90.617
+
+
+

Test 5.6 Custom widthPositionAreaRatio, kinetic, linear

+

Custom: Gaussian + Linear, shared width, fixed area ratios from first peak, 5 peaks (peak count must match hardcoded equation: 5 peaks)

+
+% pos 2-5 of area bounds and position bounds are not used for fitting, but
+% function requires during input validation that these vectors are non NaN
+% and have same length as peakArea. Therefore we need a workaround: set
+% values to 0.
+clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 1 1 1 1]; % <- area ratio rel to peak #1
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [36 2 3 4 5] ; % <- position relative to peak #1
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0 0 0 0 0]; % <- workaround
+tmpFitParameters.peakAreaUpperBound      =  [Inf 0 0 0 0];% <- workaround
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.5;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [34 0 0 0 0];% <- workaround
+tmpFitParameters.peakPosUpperBound       =  [36 0 0 0 0];% <- workaround
+tmpFitParameters.backgroundRange        = [12 12];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','widthPositionAreaRatio','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 5
+Found 5 valid peaks (non-NaN)
+         name                peakPosition       
+    ______________    __________________________
+
+    {'random.ibw'}    36    38    39    40    41
+
+         name                            peakArea                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    975.33    975.33    975.33    975.33    975.33
+
+         name                            peakFWHM                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1.6527    1.6527    1.6527    1.6527    1.6527
+
+         name           peakBackground  
+    ______________    __________________
+
+    {'random.ibw'}    -4.4239      157.4
+
+
+

Test 5.7 Custom widthPositionAreaRatio, binding, linear

+

Custom: Gaussian + Linear, shared width, fixed area ratios from first peak, 5 peaks (peak count must match hardcoded equation: 5 peaks)

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 1 1 1 1];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [36 2 3 4 5] ;
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0 0 0 0 0]; % <- workaround
+tmpFitParameters.peakAreaUpperBound      =  [Inf 0 0 0 0];% <- workaround
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  0.5;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [34 0 0 0 0];% <- workaround
+tmpFitParameters.peakPosUpperBound       =  [36 0 0 0 0];% <- workaround
+tmpFitParameters.backgroundRange        = [12 12];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','widthPositionAreaRatio','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 5
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 5 local solver runs converged with a positive local solver exit flag.
+Found 5 valid peaks (non-NaN)
+         name                peakPosition       
+    ______________    __________________________
+
+    {'random.ibw'}    36    38    39    40    41
+
+         name                            peakArea                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    961.76    961.76    961.76    961.76    961.76
+
+         name                            peakFWHM                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1.6351    1.6351    1.6351    1.6351    1.6351
+
+         name          peakBackground  
+    ______________    _________________
+
+    {'random.ibw'}    10.816    -31.968
+
+
+

Random data for 4 peaks

+
clc
+close all
+% binding
+x = linspace(50, 30, 1000)';
+true_params = [800 1.6 36; 400 1.6 37.0;800 1.6 40;500 1.6 41];
+y = zeros(size(x));
+fwhm_to_sigma = @(fwhm) fwhm / (2*sqrt(2*log(2)));
+for i = 1:size(true_params,1)
+    A = true_params(i,1);
+    sigma = fwhm_to_sigma(true_params(i,2));
+    pos = true_params(i,3);
+    y = y + A * exp(-((x - pos).^2) / (2*sigma^2));
+end
+% Simulate realistic Shirley-style background using smooth tanh transition
+center = 36; width = 3;
+shirley_step = 75 + 45 * (1 + tanh((x - center)/width))/2;
+y = y + shirley_step;
+
+center = 37; width = 3;
+shirley_step = 75 + 45 * (1 + tanh((x - center)/width))/2;
+y = y + shirley_step;
+
+center = 40; width = 3;
+shirley_step = 75 + 45 * (1 + tanh((x - center)/width))/2;
+y = y + shirley_step;
+
+center = 401; width = 3;
+shirley_step = 75 + 45 * (1 + tanh((x - center)/width))/2;
+y = y + shirley_step;
+
+
+y = y + 5 * randn(size(x));  % add mild noise
+figure;
+plot(x, y, 'k.');
+xlabel('Binding Energy');
+ylabel('Intensity');
+title('Raw Data with Shirley Tail');
+set(gca, 'XDir', 'reverse'); grid on;
+hold on;
+if ~ismember('bindingEnergy_eV', FitList.Properties.VariableNames)
+    FitList.bindingEnergy_eV = cell(size(FitList,1),1);
+end
+if ~ismember('spectrum_counts', FitList.Properties.VariableNames)
+    FitList.spectrum_counts = cell(size(FitList,1),1);
+end
+FitList(tmpDataSelection,:).bindingEnergy_eV{:} = x;
+FitList(tmpDataSelection,:).spectrum_counts{:} = y;
+
+nappPlot(FitList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','binding');
+
+
+% kinetic
+x = linspace(30, 45, 1000)';
+true_params = [800 1.6 36; 400 1.6 37.0;800 1.6 40;400 1.6 41];
+y = zeros(size(x));
+fwhm_to_sigma = @(fwhm) fwhm / (2*sqrt(2*log(2)));
+for i = 1:size(true_params,1)
+    A = true_params(i,1);
+    sigma = fwhm_to_sigma(true_params(i,2));
+    pos = true_params(i,3);
+    y = y + A * exp(-((x - pos).^2) / (2*sigma^2));
+end
+y = y + 5 * randn(size(x));  % add mild noise
+figure;
+plot(x, y, 'k.');
+xlabel('Kinetic Energy');
+ylabel('Intensity');
+title('Raw Data without Shirley Tail');
+grid on;
+hold on;
+
+FitList(tmpDataSelection,:).scientaEkin_eV{:} = x;
+FitList(tmpDataSelection,:).spectrum_countsNorm{:} = y;
+
+nappPlot(FitList,tmpDataSelection,'tableVariable','spectrum_countsNorm','energyScale','kinetic');
+
+

Test 6.0 Custom TwoSpinOrbitDoublet, kinetic, linear

+

Custom: Gaussian + Linear, shared width, positions are relative, spin-orbit doublet pair model with intensity ratios, 4 peaks (peak count must match hardcoded equation: 4 peaks)

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 0.5 5e5 0.5];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [36 1 4] ;
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0 0 0  0];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [34 NaN 3];
+tmpFitParameters.peakPosUpperBound       =  [36 NaN 5];
+tmpFitParameters.backgroundRange        = [12 6];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','TwoSpinOrbitDoublet','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 4
+Found 4 valid peaks (non-NaN)
+         name                        peakPosition               
+    ______________    __________________________________________
+
+    {'random.ibw'}    36        37    40.001    41.001       NaN
+
+         name                            peakArea                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1364.3    682.16    1365.7    682.87       NaN
+
+         name                            peakFWHM                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1.6027    1.6027    1.6027    1.6027       NaN
+
+         name            peakBackground   
+    ______________    ____________________
+
+    {'random.ibw'}    -0.12453      3.7123
+
+
+

Test 6.1 Custom TwoSpinOrbitDoublet, binding, linear

+

Custom: Gaussian + Linear, spin-orbit doublet pair model with intensity ratios, 4 peaks (peak count must match hardcoded equation: 4 peaks)

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 0.5 5e5 0.5];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [36 1 4] ;
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0 0 0  0];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [34 NaN 3];
+tmpFitParameters.peakPosUpperBound       =  [36 NaN 5];
+tmpFitParameters.backgroundRange        = [12 12];
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','TwoSpinOrbitDoublet','backgroundMode','linear','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 4
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 4 valid peaks (non-NaN)
+         name                        peakPosition               
+    ______________    __________________________________________
+
+    {'random.ibw'}    36        37    40.062    41.062       NaN
+
+         name                            peakArea                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1380.1    690.03    1528.5    764.25       NaN
+
+         name                         peakFWHM                 
+    ______________    _________________________________________
+
+    {'random.ibw'}    1.661    1.661    1.661    1.661      NaN
+
+         name          peakBackground  
+    ______________    _________________
+
+    {'random.ibw'}    9.5173    0.47017
+
+
+

Test 6.2 Custom TwoSpinOrbitDoublet, kinetic, Shirley

+

Custom: Pseudo-Voigt + Shirley, spin-orbit doublet pair model with intensity ratios, shared Shirley K, 4 peaks (peak count must match hardcoded equation: 4 peaks)

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 0.5 5e5 0.5];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [36 1 4] ;
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0 0 0  0];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [34 NaN 3];
+tmpFitParameters.peakPosUpperBound       =  [36 NaN 5];
+tmpFitParameters.backgroundRange        = [12 12];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = 1;
+ tmpFitParameters.peakEtaLowerBound      = 0;
+ tmpFitParameters.peakEtaUpperBound      = 1.0;
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.0001;
+  tmpFitParameters.peakShirleyKLowerBound = 0;
+  tmpFitParameters.peakShirleyKUpperBound = 0.0001;
+  tmpFitParameters.peakShirleyOffset      = 0;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_countsNorm','energyScale','kinetic',...
+    'mode','TwoSpinOrbitDoubletPseudoVoigtShirley','backgroundMode','shirley','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 4
+Found 4 valid peaks (non-NaN)
+         name                        peakPosition               
+    ______________    __________________________________________
+
+    {'random.ibw'}    36        37    40.001    41.001       NaN
+
+         name                           peakArea                  
+    ______________    ____________________________________________
+
+    {'random.ibw'}    1362    681.01    1362.5    681.25       NaN
+
+         name                            peakFWHM                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1.6001    1.6001    1.6001    1.6001       NaN
+
+         name         peakBackground 
+    ______________    _______________
+
+    {'random.ibw'}    0    1.9145e-08
+
+         name                    peakEta           
+    ______________    _____________________________
+
+    {'random.ibw'}    1      1      1      1    NaN
+
+         name                                 peakShirleyK                         
+    ______________    _____________________________________________________________
+
+    {'random.ibw'}    6.422e-13    6.422e-13    6.422e-13    6.422e-13          NaN
+
+
+

Test 6.3 Custom TwoSpinOrbitDoubletPseudoVoigtShirley, binding, Shirley

+

Custom: Pseudo-Voigt + Shirley, spin-orbit doublet pair model with intensity ratios, shared Shirley K, 4 peaks (peak count must match hardcoded equation: 4 peaks)

+
clearvars tmpFitParameters;
+clc
+tmpFitParameters.peakArea               = [5e5 0.5 5e5 0.5];
+tmpFitParameters.peakWidth              = 1.6;
+tmpFitParameters.peakPos                = [36 1 4] ;
+% Bounds for areas (lower and upper)
+tmpFitParameters.peakAreaLowerBound      =  [0 0 0  0];
+tmpFitParameters.peakAreaUpperBound      =  [Inf Inf Inf Inf];
+% Bounds for widths
+tmpFitParameters.peakWidthLowerBound     =  1.0;
+tmpFitParameters.peakWidthUpperBound     =  2.0;
+% Bounds for positions
+tmpFitParameters.peakPosLowerBound       =  [34 NaN 3];
+tmpFitParameters.peakPosUpperBound       =  [36 NaN 5];
+tmpFitParameters.backgroundRange        = [12 12];
+% PSEUDO-VOIGT
+ tmpFitParameters.peakEta                = 1;
+ tmpFitParameters.peakEtaLowerBound      = 0;
+ tmpFitParameters.peakEtaUpperBound      = 1.0;
+% SHIRLEY variant:
+  tmpFitParameters.peakShirleyK           = 0.1;
+  tmpFitParameters.peakShirleyKLowerBound = 0.001;
+  tmpFitParameters.peakShirleyKUpperBound = 100;
+  tmpFitParameters.peakShirleyOffset      = 80;
+
+FitList = nappFitGaussXps(FitList,tmpFitParameters,tmpDataSelection,...
+    'tableVariable','spectrum_counts','energyScale','binding',...
+    'mode','TwoSpinOrbitDoubletPseudoVoigtShirley','backgroundMode','shirley','showFigures','on');
+
+
Validating FitParameter structure...
+  Number of peaks detected: 4
+
+GlobalSearch stopped because it analyzed all the trial points.
+
+All 2 local solver runs converged with a positive local solver exit flag.
+Found 4 valid peaks (non-NaN)
+         name                         peakPosition                 
+    ______________    _____________________________________________
+
+    {'random.ibw'}    35.99     36.99    40.037    41.037       NaN
+
+         name                            peakArea                   
+    ______________    ______________________________________________
+
+    {'random.ibw'}    1397.3    698.64    1495.5    747.77       NaN
+
+         name                         peakFWHM                 
+    ______________    _________________________________________
+
+    {'random.ibw'}    1.651    1.651    1.651    1.651      NaN
+
+         name         peakBackground
+    ______________    ______________
+
+    {'random.ibw'}     0    305.54  
+
+         name                    peakEta           
+    ______________    _____________________________
+
+    {'random.ibw'}    1      1      1      1    NaN
+
+         name                               peakShirleyK                      
+    ______________    ________________________________________________________
+
+    {'random.ibw'}    0.029178    0.029178    0.029178    0.029178         NaN
+
+
+

Helper Functions

+
+function quickPlotKinetic(FitList,tmpDataSelection)
+% Plot Data
+close all
+nappPlot(FitList,tmpDataSelection,'tableVariable','spectrum_countsNorm','energyScale','kinetic');
+ax = gca;
+lines = findobj(ax, '-regexp', 'Type', 'line');
+set(lines, 'LineStyle', 'none', 'Marker', 'o', 'MarkerSize', 5);
+nappAddFitToPlot(FitList,tmpDataSelection,'energyScale','kinetic')
+try
+    disp(FitList(tmpDataSelection,["name","peakPosition","peakArea","peakFWHM","peakBackground"]))
+
+    disp(FitList(tmpDataSelection,["name","peakEta","peakShirleyK"]))
+catch
+    disp(FitList(tmpDataSelection,["sample","name","peakPosition","peakArea","peakFWHM"]))
+end
+end
+
+function quickPlotBinding(FitList,tmpDataSelection)
+% Plot Data
+close all
+nappPlot(FitList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','binding');
+ax = gca;
+lines = findobj(ax, '-regexp', 'Type', 'line');
+set(lines, 'LineStyle', 'none', 'Marker', 'o', 'MarkerSize', 5);
+nappAddFitToPlot(FitList,tmpDataSelection,'energyScale','binding')
+try
+    disp(FitList(tmpDataSelection,["name","peakPosition","peakArea","peakFWHM","peakBackground"]))
+
+    disp(FitList(tmpDataSelection,["name","peakEta","peakShirleyK"]))
+catch
+    disp(FitList(tmpDataSelection,["sample","name","peakPosition","peakArea","peakFWHM"]))
+end
+end
+
+
Found 2 valid peaks (non-NaN)
+         name         peakPosition            peakArea              peakFWHM        peakBackground  
+    ______________    ____________    ________________________    ____________    __________________
+
+    {'random.ibw'}    113    110.5    2.1207e+05         29330    2    0.87332    -325.54      48185
+
+         name           peakEta      peakShirleyK
+    ______________    ___________    ____________
+
+    {'random.ibw'}    1    0.8266     NaN    NaN 
+
+
+ +
+ + + diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley.png new file mode 100644 index 0000000..91e70bb Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_01.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_01.png new file mode 100644 index 0000000..8ffd5ed Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_01.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_02.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_02.png new file mode 100644 index 0000000..3fd89b8 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_02.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_03.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_03.png new file mode 100644 index 0000000..7c22cda Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_03.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_04.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_04.png new file mode 100644 index 0000000..a80fb45 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_04.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_05.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_05.png new file mode 100644 index 0000000..a697c55 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_05.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_06.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_06.png new file mode 100644 index 0000000..6db1156 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_06.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_07.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_07.png new file mode 100644 index 0000000..99fe46d Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_07.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_08.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_08.png new file mode 100644 index 0000000..348cf34 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_08.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_09.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_09.png new file mode 100644 index 0000000..57f9d25 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_09.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_10.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_10.png new file mode 100644 index 0000000..15b1038 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_10.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_11.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_11.png new file mode 100644 index 0000000..95fecd3 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_11.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_12.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_12.png new file mode 100644 index 0000000..b843fde Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_12.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_13.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_13.png new file mode 100644 index 0000000..c2621c5 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_13.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_14.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_14.png new file mode 100644 index 0000000..ca4baeb Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_14.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_15.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_15.png new file mode 100644 index 0000000..b31f2f0 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_15.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_16.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_16.png new file mode 100644 index 0000000..4e7bbaa Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_16.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_17.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_17.png new file mode 100644 index 0000000..a7fb42e Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_17.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_18.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_18.png new file mode 100644 index 0000000..8e75170 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_18.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_19.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_19.png new file mode 100644 index 0000000..ff1ca74 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_19.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_20.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_20.png new file mode 100644 index 0000000..5b570c8 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_20.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_21.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_21.png new file mode 100644 index 0000000..5587d83 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_21.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_22.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_22.png new file mode 100644 index 0000000..ec0fa2c Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_22.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_23.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_23.png new file mode 100644 index 0000000..b4e29b3 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_23.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_24.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_24.png new file mode 100644 index 0000000..e984d20 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_24.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_25.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_25.png new file mode 100644 index 0000000..5e1607b Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_25.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_26.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_26.png new file mode 100644 index 0000000..4fef30f Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_26.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_27.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_27.png new file mode 100644 index 0000000..8c278a2 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_27.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_28.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_28.png new file mode 100644 index 0000000..f1d2f6c Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_28.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_29.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_29.png new file mode 100644 index 0000000..a828a76 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_29.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_30.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_30.png new file mode 100644 index 0000000..0c1bec9 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_30.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_31.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_31.png new file mode 100644 index 0000000..e37e1ce Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_31.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_32.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_32.png new file mode 100644 index 0000000..eab4b8d Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_32.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_33.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_33.png new file mode 100644 index 0000000..0868761 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_33.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_34.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_34.png new file mode 100644 index 0000000..f77f65f Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_34.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_35.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_35.png new file mode 100644 index 0000000..c687902 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_35.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_36.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_36.png new file mode 100644 index 0000000..e69345e Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_36.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_37.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_37.png new file mode 100644 index 0000000..395e51d Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_37.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_38.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_38.png new file mode 100644 index 0000000..bdf9341 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_38.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_39.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_39.png new file mode 100644 index 0000000..d0e5660 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_39.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_40.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_40.png new file mode 100644 index 0000000..1f6a001 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_40.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_41.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_41.png new file mode 100644 index 0000000..6d394fc Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_41.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_42.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_42.png new file mode 100644 index 0000000..0c6b12c Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_42.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_43.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_43.png new file mode 100644 index 0000000..461f3f1 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_43.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_44.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_44.png new file mode 100644 index 0000000..9340d5a Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_44.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_45.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_45.png new file mode 100644 index 0000000..6fe4fd7 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_45.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_46.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_46.png new file mode 100644 index 0000000..e469cd0 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_46.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_47.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_47.png new file mode 100644 index 0000000..049fca4 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_47.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_48.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_48.png new file mode 100644 index 0000000..8d21a16 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_48.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_49.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_49.png new file mode 100644 index 0000000..90ee1b1 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_49.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_50.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_50.png new file mode 100644 index 0000000..0734916 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_50.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_51.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_51.png new file mode 100644 index 0000000..63bfcdf Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_51.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_52.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_52.png new file mode 100644 index 0000000..381105e Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_52.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_53.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_53.png new file mode 100644 index 0000000..9a499f2 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_53.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_54.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_54.png new file mode 100644 index 0000000..ee274d5 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_54.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_55.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_55.png new file mode 100644 index 0000000..652deb3 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_55.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_56.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_56.png new file mode 100644 index 0000000..59d91c6 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_56.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_57.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_57.png new file mode 100644 index 0000000..1469406 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_57.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_58.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_58.png new file mode 100644 index 0000000..41b850e Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_58.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_59.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_59.png new file mode 100644 index 0000000..2e7e581 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_59.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_60.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_60.png new file mode 100644 index 0000000..b6ab35f Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_60.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_61.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_61.png new file mode 100644 index 0000000..1992548 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_61.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_62.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_62.png new file mode 100644 index 0000000..24af3d9 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_62.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_63.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_63.png new file mode 100644 index 0000000..154f2ff Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_63.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_64.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_64.png new file mode 100644 index 0000000..559fbbf Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_64.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_65.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_65.png new file mode 100644 index 0000000..7f4944c Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_65.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_66.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_66.png new file mode 100644 index 0000000..5a8268e Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_66.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_67.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_67.png new file mode 100644 index 0000000..0411e7b Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_67.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_68.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_68.png new file mode 100644 index 0000000..efced97 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_68.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_69.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_69.png new file mode 100644 index 0000000..ab27894 Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_69.png differ diff --git a/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_70.png b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_70.png new file mode 100644 index 0000000..f199a1c Binary files /dev/null and b/beamtime/documentedExampleScripts/html/TestAndDevelopShirley_70.png differ diff --git a/beamtime/getPsiColors.m b/beamtime/getPsiColors.m deleted file mode 100644 index c23bc81..0000000 --- a/beamtime/getPsiColors.m +++ /dev/null @@ -1,24 +0,0 @@ -function PsiFarbe = getPsiColors() -% Returns a struct with PSI corporate identity colors. - -% define PSI cooperate identity colours -PsiFarbe.hellgrau = [226 226 226]/255; -PsiFarbe.mittelgrau = [184 184 184]/255; -PsiFarbe.dunkelgrau = [78 78 77]/255; -PsiFarbe.blaugrau = [236 236 243]/255; % This is actually not a PSI colour -PsiFarbe.gelb = [239 200 37]/255; -PsiFarbe.hellorange = [227 164 31]/255; -PsiFarbe.dunkelorange = [207 92 22]/255; -PsiFarbe.hellrot = [164 36 23]/255; -PsiFarbe.dunkelbraun = [114 85 65]/255; -PsiFarbe.hellbraun = [127 119 47]/255; -PsiFarbe.mittelgruen = [135 150 59]/255; -PsiFarbe.hellgruen = [195 214 47]/255; -PsiFarbe.dunkelgruen = [72 130 33]/255; -PsiFarbe.dunkelrot = [104 47 86]/255; -PsiFarbe.dunkelblau = [37 65 108]/255; -PsiFarbe.mittelgruenblau = [61 164 168]/255; -PsiFarbe.hellblau = [58 162 190]/255; -PsiFarbe.mittelblau = [50 118 158]/255; - -end \ No newline at end of file diff --git a/beamtime/importLabViewIssfile.m b/beamtime/importLabViewIssfile.m deleted file mode 100644 index e5a1645..0000000 --- a/beamtime/importLabViewIssfile.m +++ /dev/null @@ -1,107 +0,0 @@ -function TableLabViewIss = importLabViewIssfile(filenameOrFolder, dataLines) -%IMPORTFILE Import data from a text file or folder -% TableLabViewIss = IMPORTFILE(FILENAME) reads data from text -% file FILENAME and returns the data as a table. -% -% TableLabViewIss = IMPORTFILE(FOLDER) reads all .txt files from -% FOLDER, merges them into a single table (sorted by datetime). -% -% TableLabViewIss = IMPORTFILE(FILE, DATALINES) reads data -% for the specified row interval(s) of text file FILENAME. -% -% Example (single file): -% TableLabViewIss = importLabViewIssfile("/Users/bartels-rausch/Desktop/17-12-2025_09-14datafile.txt", [2, Inf]); -% -% Example (folder): -% TableLabViewIss = importLabViewIssfile("/Users/bartels-rausch/Desktop/DataFolder"); -% -% See also READTABLE. - -%% Input handling - -% If dataLines is not specified, define defaults -if nargin < 2 - dataLines = [2, Inf]; -end - -%% Check if input is a file or folder -if isfolder(filenameOrFolder) - % Process all .txt files in the folder - folderPath = filenameOrFolder; - fileList = dir(fullfile(folderPath, '*.txt')); - - if isempty(fileList) - error('No .txt files found in folder: %s', folderPath); - end - - fprintf('Found %d .txt files in folder. Processing...\n', length(fileList)); - - % Initialize empty table - TableLabViewIss = table(); - - % Loop through each file - for i = 1:length(fileList) - filepath = fullfile(folderPath, fileList(i).name); - fprintf(' [%d/%d] Processing: %s\n', i, length(fileList), fileList(i).name); - - % Import this file - tbl_temp = importSingleFile(filepath, dataLines); - - % Append to main table - if isempty(TableLabViewIss) - TableLabViewIss = tbl_temp; - else - TableLabViewIss = [TableLabViewIss; tbl_temp]; - end - end - - % Sort by datetime - [~, sortIdx] = sort(TableLabViewIss.datetime); - TableLabViewIss = TableLabViewIss(sortIdx, :); - - fprintf('Merged %d files into single table with %d rows.\n', length(fileList), height(TableLabViewIss)); - -else - % Process single file - TableLabViewIss = importSingleFile(filenameOrFolder, dataLines); -end - -end - -%% Helper function to import a single file -function tbl = importSingleFile(filename, dataLines) -% Import options setup -opts = delimitedTextImportOptions("NumVariables", 10); - -% Specify range and delimiter -opts.DataLines = dataLines; -opts.Delimiter = "\t"; - -% Specify column names and types -opts.VariableNames = ["date_DD_MM_JJJJ_", "time_hh_mm_ss_", "pressure_cell_hPa_", "temperature__C_", "x_mm_", "y_mm_", "z_mm_", "Tsealing__C_", "flowCryo_l_min_", "pOut_hPa_"]; -opts.VariableTypes = ["datetime", "duration", "double", "double", "double", "double", "double", "double", "double", "double"]; - -% Specify file level properties -opts.ExtraColumnsRule = "ignore"; -opts.EmptyLineRule = "read"; - -% Specify variable properties -opts = setvaropts(opts, "date_DD_MM_JJJJ_", "InputFormat", "dd.MM.yyyy"); -opts = setvaropts(opts, "time_hh_mm_ss_", "InputFormat", "hh:mm:ss.S"); - -% Import the data as regular table -tbl = readtable(filename, opts); - -% Merge date + time into a single datetime column -tbl.datetime = tbl.date_DD_MM_JJJJ_ + tbl.time_hh_mm_ss_; - -% Set the datetime display format to show date and time -tbl.datetime.Format = 'dd.MM.yyyy HH:mm:ss.SSS'; - -% Remove the original date and time columns -tbl(:, ["date_DD_MM_JJJJ_", "time_hh_mm_ss_"]) = []; - -% Move datetime to be the first column -tbl = movevars(tbl, "datetime", "Before", 1); - -end diff --git a/beamtime/outerjoinRowToTable.m b/beamtime/outerjoinRowToTable.m deleted file mode 100644 index 74d9e8a..0000000 --- a/beamtime/outerjoinRowToTable.m +++ /dev/null @@ -1,85 +0,0 @@ -function Table = outerjoinRowToTable(Table,TableRowToBeAdded) -%outerjoinRowToTable Adds one row to a table. Variables that are missing in -%either the table or the row are added with empty values {' '} for cells -%and NaN for doubles. Works with tables that contain both cells and -%doubles. -% -% * Strings in the table are not yet supported. -% * The row that is added needs to be formatted as table -% * Update 2024: Adds several rows, that is tables -% * Update 2026: Handles peakfitting columns with different size. -% -% T = outerjoinRowToTable(TableToAddTo,RowToBeAdded) -% -% tmpTableToBeAdded = table({tmpCombined(:,1)},{tmpCombined(:,2)},{'660eV, m50, 092022'},{'#288,#289,#290.ibw'}, ... -% 'VariableNames',["bindingEnergy_eV","spectrum_countsNorm","sample","name"]); -% SpectrumList = outerjoinRowToTable(SpectrumList,tmpTableToBeAdded); -% -% Thorsten, December 2023 - -% Original Table has more variables -if ~all(ismember(Table.Properties.VariableNames,TableRowToBeAdded.Properties.VariableNames)) - tmpMissingVariable = ~ismember(Table.Properties.VariableNames,TableRowToBeAdded.Properties.VariableNames); - tmpVariablesToBeAdded = Table.Properties.VariableNames(tmpMissingVariable); - for ii = 1:size(tmpVariablesToBeAdded,2) - if matches(class(Table.(tmpVariablesToBeAdded{ii})),'double') || matches(class(Table.(tmpVariablesToBeAdded{ii})),'int32') - tmpContentToBeAdded = NaN(size(TableRowToBeAdded,1),size(Table.(tmpVariablesToBeAdded{ii}),2)); - TableRowToBeAdded = addvars(TableRowToBeAdded,tmpContentToBeAdded,'NewVariableNames',tmpVariablesToBeAdded{ii}); - elseif matches(class(Table.(tmpVariablesToBeAdded{ii})),'cell') - tmpContentToBeAdded = repmat({' '},size(TableRowToBeAdded,1),size(Table.(tmpVariablesToBeAdded{ii}),2)); - TableRowToBeAdded = addvars(TableRowToBeAdded,tmpContentToBeAdded,'NewVariableNames',tmpVariablesToBeAdded{ii}); - elseif matches(class(Table.(tmpVariablesToBeAdded{ii})),'string') - tmpContentToBeAdded = repmat({" "},size(TableRowToBeAdded,1),size(Table.(tmpVariablesToBeAdded{ii}),2)); - TableRowToBeAdded = addvars(TableRowToBeAdded,tmpContentToBeAdded,'NewVariableNames',tmpVariablesToBeAdded{ii}); - end - end -end -% Table to be added has more variables -if ~all(ismember(TableRowToBeAdded.Properties.VariableNames,Table.Properties.VariableNames)) - tmpMissingVariable = ~ismember(TableRowToBeAdded.Properties.VariableNames,Table.Properties.VariableNames); - tmpVariablesToBeAdded = TableRowToBeAdded.Properties.VariableNames(tmpMissingVariable); - for ii = 1:size(tmpVariablesToBeAdded,2) - if matches(class(TableRowToBeAdded.(tmpVariablesToBeAdded{ii})),'double') || matches(class(TableRowToBeAdded.(tmpVariablesToBeAdded{ii})),'int32') - tmpContentToBeAdded = NaN(size(Table,1),size(TableRowToBeAdded.(tmpVariablesToBeAdded{ii}),2)); - Table = addvars(Table,tmpContentToBeAdded,'NewVariableNames',tmpVariablesToBeAdded{ii}); - elseif matches(class(TableRowToBeAdded.(tmpVariablesToBeAdded{ii})),'cell') - tmpContentToBeAdded = repmat({' '},size(Table,1),size(TableRowToBeAdded.(tmpVariablesToBeAdded{ii}),2)); - Table = addvars(Table,tmpContentToBeAdded,'NewVariableNames',tmpVariablesToBeAdded{ii}); - elseif matches(class(TableRowToBeAdded.(tmpVariablesToBeAdded{ii})),'string') - tmpContentToBeAdded = repmat({" "},size(Table,1),size(TableRowToBeAdded.(tmpVariablesToBeAdded{ii}),2)); - Table = addvars(Table,tmpContentToBeAdded,'NewVariableNames',tmpVariablesToBeAdded{ii}); - end - end -end -% Reconcile column widths for peak-fit columns. -% These numeric columns can have variable width (one entry per peak), -% so a width mismatch is expected when spectra have different numbers -% of peaks. Pad the narrower side with NaN. -variableWidthColumns = {'peakArea', 'peakPosition', 'peakFWHM', ... - 'peakBackground', 'peakEta', 'peakShirleyK'}; - -for ii = 1:numel(variableWidthColumns) - varName = variableWidthColumns{ii}; - - if ~ismember(varName, Table.Properties.VariableNames) || ... - ~ismember(varName, TableRowToBeAdded.Properties.VariableNames) - continue - end - - widthT = size(Table.(varName), 2); - widthR = size(TableRowToBeAdded.(varName), 2); - - if widthT < widthR - Table.(varName) = [Table.(varName), ... - NaN(height(Table), widthR - widthT)]; - elseif widthR < widthT - TableRowToBeAdded.(varName) = [TableRowToBeAdded.(varName), ... - NaN(height(TableRowToBeAdded), widthT - widthR)]; - end -end - -% Ensure matching column order before concatenation -TableRowToBeAdded = TableRowToBeAdded(:, Table.Properties.VariableNames); -% Add row to table -Table = [Table;TableRowToBeAdded]; -end \ No newline at end of file diff --git a/beamtime/plotExportedData.m b/beamtime/plotExportedData.m deleted file mode 100644 index 7826b3d..0000000 --- a/beamtime/plotExportedData.m +++ /dev/null @@ -1,151 +0,0 @@ -function plotExportedData(dataDirectory) -%plotExportedData Plot all exported ASCII data files in one figure -% -% This function reads all .txt files from the exported data (created by -% exportFigureData) and plots them in a single figure for visual comparison. -% File names are parsed to extract axis labels and legend entries. -% -% SYNTAX: -% plotExportedData() % Uses current working directory -% plotExportedData(dataDirectory) % Uses specified directory path -% -% INPUTS: -% dataDirectory : char or string (optional) -% Path to directory containing exported .txt files. -% If omitted, uses current working directory (pwd). -% -% OUTPUT: -% A new figure with all data plotted as lines. Axis labels and legend -% entries are reconstructed from the file names. -% -% NOTES: -% - Reads all .txt files in the specified directory -% - File name format expected: _[_]_vs__.txt -% - Plots are created with underscores converted back to spaces for display -% - X and Y axis labels are set based on parsed filename -% - Legend shows line labels from filenames -% - All data is plotted in a single axes for direct visual comparison -% -% EXAMPLE: -% % After running exportFigureData(): -% plotExportedData() -% % or -% plotExportedData('../exported_data/') - -% Handle input: use current directory if none provided -if nargin == 0 || isempty(dataDirectory) - dataDirectory = pwd; -end - -% Get all .txt files in the directory -fileStruct = dir(fullfile(dataDirectory, '*.txt')); -if isempty(fileStruct) - warning('plotExportedData:NoFiles', 'No .txt files found in %s', dataDirectory); - return; -end - -% Create a new figure -fig = figure('Name', 'Exported Data Comparison', 'NumberTitle', 'off'); -ax = axes(fig); -hold(ax, 'on'); -grid(ax, 'on'); - -% Storage for axis labels (to ensure consistency) -xLabelStr = ''; -yLabelStr = ''; -legendEntries = {}; - -% Loop over all .txt files -for ii = 1:length(fileStruct) - fileName = fileStruct(ii).name; - filePath = fullfile(dataDirectory, fileName); - - % Read the data - try - data = readmatrix(filePath); - catch ME - warning('plotExportedData:ReadFailed', 'Could not read file: %s\n%s', fileName, ME.message); - continue; - end - - % Check if data has at least 2 columns - if size(data, 2) < 2 || size(data, 1) < 1 - warning('plotExportedData:InvalidData', 'File %s does not have valid X,Y columns', fileName); - continue; - end - - xData = data(:, 1); - yData = data(:, 2); - - % Parse filename to extract labels - % Expected format: _[_]_vs__.txt - - % Remove .txt extension - nameNoExt = fileName(1:end-4); - - % Split by '_vs_' to separate y-axis label from the rest - parts = strsplit(nameNoExt, '_vs_'); - - if length(parts) >= 2 - % Extract line label (after _vs__) - rightPart = parts{2}; % _ - - % Find the last underscore to separate XLabel from LineLabel - underscores = find(rightPart == '_'); - if ~isempty(underscores) - lastUnderscore = underscores(end); - xLabelExtracted = rightPart(1:lastUnderscore-1); - lineLabel = rightPart(lastUnderscore+1:end); - else - xLabelExtracted = rightPart; - lineLabel = 'data'; - end - - % Extract y-axis label (before _vs_) - yLabelExtracted = parts{1}; - - % Remove figure title (first part before first underscore) - % This is tricky, so we'll keep what we have and note it's approximate - - % Convert underscores back to spaces for display - xLabelDisplay = strrep(xLabelExtracted, '_', ' '); - yLabelDisplay = strrep(yLabelExtracted, '_', ' '); - lineLabel = strrep(lineLabel, '_', ' '); - - % Store axis labels (use the first valid ones found) - if isempty(xLabelStr) - xLabelStr = xLabelDisplay; - end - if isempty(yLabelStr) - yLabelStr = yLabelDisplay; - end - - else - % Fallback if filename parsing fails - lineLabel = nameNoExt; - end - - % Plot the data - plot(ax, xData, yData, 'DisplayName', lineLabel, 'LineWidth', 1.5, 'Marker', 'o', 'MarkerSize', 4); - - % Store legend entry - legendEntries{end+1} = lineLabel; -end - -% Set axis labels -xlabel(ax, xLabelStr, 'Interpreter', 'none'); -ylabel(ax, yLabelStr, 'Interpreter', 'none'); -title(ax, 'Exported Data Comparison', 'Interpreter', 'none'); - -% Add legend -if ~isempty(legendEntries) - legend(ax, legendEntries, 'Interpreter', 'none', 'Location', 'best'); -end - -% Optimize figure appearance -grid(ax, 'on'); -hold(ax, 'off'); - -fprintf('Plotted %d data files from: %s\n', length(fileStruct), dataDirectory); - -end diff --git a/beamtime/preset_colormap.m b/beamtime/preset_colormap.m deleted file mode 100644 index b2197bd..0000000 --- a/beamtime/preset_colormap.m +++ /dev/null @@ -1,75 +0,0 @@ -function map = preset_colormap(N,varargin) -% Wrapper for any COLORMAP function, to provide preset parameter values. -% -% (c) 2020-2025 Stephen Cobeldick -% -%%% Syntax %%% -% -% preset_colormap(@fun,p1,p2,...,pN) % store function with any parameters -% map = preset_colormap(N) % generate colormap -% map = preset_colormap % generate colormap -% -%% Examples %% -% -% >> preset_colormap(@cubehelix,0.25,-0.67,1.5,1) -% >> colormap(preset_colormap) -% -% >> preset_colormap(5) -% ans = -% 0 0 0 -% 0.1055 0.2788 0.4895 -% 0.1660 0.6705 0.4961 -% 0.6463 0.8479 0.5076 -% 1.0000 1.0000 1.0000 -% -% >> preset_colormap(@brewermap,'PuOr') -% >> load topo -% >> load coast -% >> figure -% >> worldmap(topo, topolegend) -% >> contourfm(topo, topolegend); -% >> contourcmap('preset_colormap', 'Colorbar','on', 'Location','horizontal','TitleString','Contour Intervals in Meters'); -% >> plotm(lat, long, 'k') -% -%% Dependencies %% -% -% * MATLAB R2009a or later. -% -% See also BREWERMAP CUBEHELIX CMOCEAN LBMAP COLORMAP CONTOURCMAP -persistent fnh arg -% -if nargin==0 % Default N same as MATLAB colormaps. - N = cmDefaultN(); -elseif nargin==1 && isnumeric(N) - assert(isscalar(N) && isreal(N) && fix(N)==N,... - 'SC:preset_colormap:N:NotRealScalarNumeric',... - 'First input must be a real scalar numeric of the colormap size.') - N = double(N); -else % Store function handle and parameter values. - assert(isa(N,'function_handle'),... - 'SC:preset_colormap:N:NotFunctionHandle',... - 'First input must be a function handle to a colormap function.') - fnh = N; - arg = varargin; - return -end -% -map = fnh(N,arg{:}); -% -end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%preset_colormap -function N = cmDefaultN() -% Get the colormap size from the current figure or default colormap. -try - F = get(groot,'CurrentFigure'); -catch %#ok pre HG2 - N = size(get(gcf,'colormap'),1); - return -end -if isempty(F) - N = size(get(groot,'DefaultFigureColormap'),1); -else - N = size(F.Colormap,1); -end -end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%cmDefaultN \ No newline at end of file diff --git a/beamtime/readIBWbinheader.m b/beamtime/readIBWbinheader.m deleted file mode 100644 index 2654772..0000000 --- a/beamtime/readIBWbinheader.m +++ /dev/null @@ -1,52 +0,0 @@ -function H = readIBWbinheader(FFN); -% readIBWbinheader - read BinHeader segment of Igor IBW file -% H = readIBWbinheader('foo') reads BinHeader of file Foo.ibw -% IBW version 2,5 only -MAXDIMS = 4; - -fid = fopen(FFN,'r'); -H.version = fread(fid,1,'int16'); -switch H.version, - case 2, % typedef struct BinHeader2 { - H.wfmSize = fread(fid,1,'uint32'); % long wfmSize; // The size of the WaveHeader2 data structure plus the wave data plus 16 bytes of padding. - H.noteSize = fread(fid,1,'uint32'); % long noteSize; // The size of the note text. - H.pictSize = fread(fid,1,'uint32'); % long pictSize; // Reserved. Write zero. Ignore on read. - H.checksum = fread(fid,1,'int16'); % short checksum; // Checksum over this header and the wave header. - case 5, - H.checksum = fread(fid,1,'short'); - H.wfmSize = fread(fid,1,'long'); % The size of the WaveHeader5 data structure plus the wave data. - H.formulaSize = fread(fid,1,'long'); % The size of the dependency formula, if any. - H.noteSize = fread(fid,1,'long'); % The size of the note text. - H.dataEUnitsSize = fread(fid,1,'long'); % The size of optional extended data units. - H.dimEUnitsSize = fread(fid,MAXDIMS,'long'); % The size of optional extended dimension units. - H.dimLabelsSize = fread(fid,MAXDIMS,'long'); % The size of optional dimension labels. - H.sIndicesSize = fread(fid,1,'long'); ; % The size of string indicies if this is a text wave. - H.optionsSize1 = fread(fid,1,'long'); ; % Reserved. Write zero. Ignore on read. - H.optionsSize2 = fread(fid,1,'long'); ; % Reserved. Write zero. Ignore on read. - otherwise, -end % switch H.Version -fclose(fid); - -if ~ismember(H.version,[2 5]), - error(['Cannot read version ' num2str(H.version) ' IBW files - only versions 2,5 are okay.']); -end -%==FROM IgorBin.h ===================== -% #define MAXDIMS 4 -% -% typedef struct BinHeader5 { -% short version; // Version number for backwards compatibility. -% short checksum; // Checksum over this header and the wave header. -% long wfmSize; // The size of the WaveHeader5 data structure plus the wave data. -% long formulaSize; // The size of the dependency formula, if any. -% long noteSize; // The size of the note text. -% long dataEUnitsSize; // The size of optional extended data units. -% long dimEUnitsSize[MAXDIMS]; // The size of optional extended dimension units. -% long dimLabelsSize[MAXDIMS]; // The size of optional dimension labels. -% long sIndicesSize; // The size of string indicies if this is a text wave. -% long optionsSize1; // Reserved. Write zero. Ignore on read. -% long optionsSize2; // Reserved. Write zero. Ignore on read. -% } BinHeader5; - - - - diff --git a/beamtime/readIBWheaders.m b/beamtime/readIBWheaders.m deleted file mode 100644 index 75f10df..0000000 --- a/beamtime/readIBWheaders.m +++ /dev/null @@ -1,250 +0,0 @@ -function [BH, H, FFN] = readIBWheaders(FFN); -% readIBWheaders - read BinHeader & WaveHeader segments of Igor IBW file -% [BH, WH, FFN] = readIBWheaders('foo') reads BinHeader & WaveHeader of -% file Foo.ibw - Versions 2 and 5 only. FFN is full filename. - -% % 1 byte char -% % 2 bytes short -% % 4 bytes int, long, float, Handle, any kind of pointer -% % 8 bytes double -MAXDIMS = 4; -MAX_WAVE_NAME2 = 18; % Maximum length of wave name in version 1 and 2 files. Does not include the trailing null. -MAX_WAVE_NAME5 = 31; % Maximum length of wave name in version 5 files. Does not include the trailing null. -MAX_UNIT_CHARS = 3; - - -BH = readIBWbinheader(FFN); -fid = fopen(FFN,'r'); -switch BH.version - case 2, - % The version 2 file has the following general layout. - % BinHeader2 structure: 16 bytes - % WaveHeader2 structure excluding wData field; 110 bytes - % Wave data: Variable size - fseek(fid,16,'bof'); % start of wave header of IBW vs 2; % struct WaveHeader2 { - H.type = fread(fid,1, 'uint16'); % short type; % See types (e.g. NT_FP64) above. Zero for text waves. - H.WaveHeader2 = fread(fid,1, 'uint32'); % struct WaveHeader2 **next; // Used in memory only. Write zero. Ignore on read. - H.bname = local_char(fread(fid, MAX_WAVE_NAME2+2, 'char')); % char bname[MAX_WAVE_NAME2+2]; // Name of wave plus trailing null. - H.whVersion = fread(fid,1, 'uint16'); % short whVersion; // Write 0. Ignore on read. - H.srcFldr = fread(fid,1, 'uint16'); % short srcFldr; // Used in memory only. Write zero. Ignore on read. - H.fileName = fread(fid,1, 'uint32'); % Handle fileName; // Used in memory only. Write zero. Ignore on read. - % - H.dataUnits = local_char(fread(fid, MAX_UNIT_CHARS+1, 'char')); % char dataUnits[MAX_UNIT_CHARS+1]; // Natural data units go here - null if none. - H.xUnits = local_char(fread(fid, MAX_UNIT_CHARS+1, 'char')); % char xUnits[MAX_UNIT_CHARS+1]; // Natural x-axis units go here - null if none. - % - H.npnts = fread(fid,1, 'uint32'); % long npnts; // Number of data points in wave. - % - H.aModified = fread(fid,1, 'uint16'); % short aModified; // Used in memory only. Write zero. Ignore on read. - H.hsA = fread(fid,1, 'double'); % double hsA,hsB; // X value for point p = hsA*p + hsB - H.hsB = fread(fid,1, 'double'); % double hsA,hsB; // X value for point p = hsA*p + hsB - % - H.wModified = fread(fid,1, 'uint16'); % short wModified; // Used in memory only. Write zero. Ignore on read. - H.swModified = fread(fid,1, 'uint16'); % short swModified; // Used in memory only. Write zero. Ignore on read. - H.fsValid = fread(fid,1, 'uint16'); % short fsValid; // True if full scale values have meaning. - H.topFullScale = fread(fid,1, 'double'); % double topFullScale,botFullScale; // The min full scale value for wave. - H.botFullScale = fread(fid,1, 'double'); % double topFullScale,botFullScale; // The min full scale value for wave. - % - H.useBits = fread(fid,1, 'char'); % char useBits; // Used in memory only. Write zero. Ignore on read. - H.kindBits = fread(fid,1, 'char'); % char kindBits; // Reserved. Write zero. Ignore on read. - H.formula = fread(fid,1, 'uint32'); % void **formula; // Used in memory only. Write zero. Ignore on read. - H.depID = fread(fid,1, 'uint32'); % long depID; // Used in memory only. Write zero. Ignore on read. - H.creationDate = fread(fid,1, '*uint32'); % unsigned long creationDate; // DateTime of creation. Not used in version 1 files. - H.platform = fread(fid,1, 'uint8'); % unsigned char platform; // 0=unspecified, 1=Macintosh, 2=Windows; Added for Igor Pro 5.5. -% dummy = fread(fid,1, 'uint8'); % align - H.wUnused = fread(fid,1, 'uint8'); % char wUnused[1]; // Reserved. Write zero. Ignore on read. - % - H.modDate = fread(fid,1, '*uint32'); % unsigned long modDate; // DateTime of last modification. - H.waveNoteH = fread(fid,1, 'uint32'); % Handle waveNoteH; // Used in memory only. Write zero. Ignore on read. - % - H.wData = fread(fid,4, 'single').'; % float wData[4]; // The start of the array of waveform data. - case 5, - % The version 5 file has the following general layout. - % BinHeader5 structure: 64 bytes - % WaveHeader5 structure excluding wData field: 320 bytes - % Wave data: Variable size - fseek(fid,64,'bof'); % start of wave header of IBW vs 5 - % - H.next = fread(fid,1, 'int32'); % link to next wave in linked list. - % - H.creationDate = fread(fid,1, 'uint32'); % DateTime of creation. - H.modDate = fread(fid,1, 'uint32'); % DateTime of creation. - % - H.npnts = fread(fid,1, 'int32'); % Total number of points (multiply dimensions up to first zero). - H.type = fread(fid,1, 'uint16'); % See types (e.g. NT_FP64) above. Zero for text waves. - H.dLock = fread(fid, 1, 'int16'); % Reserved. Write zero. Ignore on read. - % - H.whpad1 = fread(fid, 6, 'char').'; % Reserved. Write zero. Ignore on read. - H.whVersion = fread(fid, 1, 'int16'); % Write 1. Ignore on read. - H.bname = local_char(fread(fid, MAX_WAVE_NAME5+1, 'char')); % Name of wave plus trailing null. - H.whpad2 = fread(fid, 1, 'int32'); % long Reserved. Write zero. Ignore on read. - H.dFolder = fread(fid, 1, 'int32'); % ptr Used in memory only. Write zero. Ignore on read. - - % % Dimensioning info. [0] == rows, [1] == cols etc - H.nDim = fread(fid, MAXDIMS, 'int32').'; % long nDim[MAXDIMS] Number of of items in a dimension -- 0 means no data. - H.sfA = fread(fid, MAXDIMS, 'double').'; % double sfA[MAXDIMS]; Index value for element e of dimension d = sfA[d]*e + sfB[d]. - H.sfB = fread(fid, MAXDIMS, 'double').'; % double sfB[MAXDIMS];% double sfB[MAXDIMS]; - % % - % % % SI units - H.dataUnits = local_char(fread(fid, MAX_UNIT_CHARS+1, 'char')); % char dataUnits[MAX_UNIT_CHARS+1]; % Natural data units go here - null if none. - H.dimUnits = fread(fid, MAXDIMS*(MAX_UNIT_CHARS+1), '*char').'; % % char dimUnits[MAXDIMS][MAX_UNIT_CHARS+1]; % Natural dimension units go here - null if none. - % % - H.fsValid = fread(fid, 1, 'uint16'); % % short fsValid; % TRUE if full scale values have meaning. - H.whpad3 = fread(fid, 1, 'int16'); % % short whpad3; % Reserved. Write zero. Ignore on read. - H.topFullScale = fread(fid, 1, 'double'); - H.botFullScale = fread(fid, 1, 'double'); % % double topFullScale,botFullScale; % The max and max full scale value for wave. - % % - H.dataEUnits = fread(fid, 1, 'int32'); % % Handle dataEUnits; % Used in memory only. Write zero. Ignore on read. - H.dimEUnits = fread(fid, MAXDIMS, 'int32').'; % % Handle dimEUnits[MAXDIMS]; % Used in memory only. Write zero. Ignore on read. - H.dimLabels = fread(fid, MAXDIMS, 'int32').'; % % Handle dimLabels[MAXDIMS]; % Used in memory only. Write zero. Ignore on read. - % % - H.waveNoteH = fread(fid, 1, 'int32'); % % Handle waveNoteH; % Used in memory only. Write zero. Ignore on read. - % % - H.platform = fread(fid, 1, 'uint8'); % % unsigned char platform; % 0=unspecified, 1=Macintosh, 2=Windows; Added for Igor Pro 5. - H.skip_junk________ = fread(fid,80,'char').'; - % H. = fread(fid, 1, ''); - % % unsigned char spare[3]; - % H. = fread(fid, 1, ''); - % % - % H. = fread(fid, 1, ''); - % % long whUnused[13]; % Reserved. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % - % H. = fread(fid, 1, ''); - % % long vRefNum, dirID; % Used in memory only. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % - % H. = fread(fid, 1, ''); - % % % The following stuff is considered private to Igor. - % H. = fread(fid, 1, ''); - % % - % H. = fread(fid, 1, ''); - % % short aModified; % Used in memory only. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % short wModified; % Used in memory only. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % short swModified; % Used in memory only. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % - % H. = fread(fid, 1, ''); - % % char useBits; % Used in memory only. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % char kindBits; % Reserved. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % void **formula; % Used in memory only. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % long depID; % Used in memory only. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % - % H. = fread(fid, 1, ''); - % % short whpad4; % Reserved. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % short srcFldr; % Used in memory only. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % Handle fileName; % Used in memory only. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % - % H. = fread(fid, 1, ''); - % % long **sIndices; % Used in memory only. Write zero. Ignore on read. - % H. = fread(fid, 1, ''); - % % - H.wData = fread(fid, 1, 'single'); - % % float wData[1]; % The start of the array of data. Must be 64 bit aligned. - % H. = fread(fid, 1, ''); - % }; -end % switch BH.version -H.EOH_pos = ftell(fid); - - - - -fclose(fid); - -%==FROM IgorBin.h ===================== -% #define MAXDIMS 4 - -% % #define MAX_WAVE_NAME5 31 // Maximum length of wave name in version 5 files. Does not include the trailing null. -% % #define MAX_UNIT_CHARS 3 - -% % #define NT_CMPLX 1 % Complex numbers. -% % #define NT_FP32 2 % 32 bit fp numbers. -% % #define NT_FP64 4 % 64 bit fp numbers. -% % #define NT_I8 8 % 8 bit signed integer. Requires Igor Pro 2.0 or later. -% % #define NT_I16 0x10 % 16 bit integer numbers. Requires Igor Pro 2.0 or later. -% % #define NT_I32 0x20 % 32 bit integer numbers. Requires Igor Pro 2.0 or later. -% % #define NT_UNSIGNED 0x40 % Makes above signed integers unsigned. Requires Igor Pro 3.0 or later. -% -% struct WaveHeader5 { -% struct WaveHeader5 **next; % link to next wave in linked list. -% -% unsigned long creationDate; % DateTime of creation. -% unsigned long modDate; % DateTime of last modification. -% -% long npnts; % Total number of points (multiply dimensions up to first zero). -% short type; % See types (e.g. NT_FP64) above. Zero for text waves. -% short dLock; % Reserved. Write zero. Ignore on read. -% -% char whpad1[6]; % Reserved. Write zero. Ignore on read. -% short whVersion; % Write 1. Ignore on read. -% char bname[MAX_WAVE_NAME5+1]; % Name of wave plus trailing null. -% long whpad2; % Reserved. Write zero. Ignore on read. -% struct DataFolder **dFolder; % Used in memory only. Write zero. Ignore on read. -% -% % Dimensioning info. [0] == rows, [1] == cols etc -% long nDim[MAXDIMS]; % Number of of items in a dimension -- 0 means no data. -% double sfA[MAXDIMS]; % Index value for element e of dimension d = sfA[d]*e + sfB[d]. -% double sfB[MAXDIMS]; -% -% % SI units -% char dataUnits[MAX_UNIT_CHARS+1]; % Natural data units go here - null if none. -% char dimUnits[MAXDIMS][MAX_UNIT_CHARS+1]; % Natural dimension units go here - null if none. -% -% short fsValid; % TRUE if full scale values have meaning. -% short whpad3; % Reserved. Write zero. Ignore on read. -% double topFullScale,botFullScale; % The max and max full scale value for wave. -% -% Handle dataEUnits; % Used in memory only. Write zero. Ignore on read. -% Handle dimEUnits[MAXDIMS]; % Used in memory only. Write zero. Ignore on read. -% Handle dimLabels[MAXDIMS]; % Used in memory only. Write zero. Ignore on read. -% -% Handle waveNoteH; % Used in memory only. Write zero. Ignore on read. -% -% unsigned char platform; % 0=unspecified, 1=Macintosh, 2=Windows; Added for Igor Pro 5.5. -% unsigned char spare[3]; -% -% long whUnused[13]; % Reserved. Write zero. Ignore on read. -% -% long vRefNum, dirID; % Used in memory only. Write zero. Ignore on read. -% -% % The following stuff is considered private to Igor. -% -% short aModified; % Used in memory only. Write zero. Ignore on read. -% short wModified; % Used in memory only. Write zero. Ignore on read. -% short swModified; % Used in memory only. Write zero. Ignore on read. -% -% char useBits; % Used in memory only. Write zero. Ignore on read. -% char kindBits; % Reserved. Write zero. Ignore on read. -% void **formula; % Used in memory only. Write zero. Ignore on read. -% long depID; % Used in memory only. Write zero. Ignore on read. -% -% short whpad4; % Reserved. Write zero. Ignore on read. -% short srcFldr; % Used in memory only. Write zero. Ignore on read. -% Handle fileName; % Used in memory only. Write zero. Ignore on read. -% -% long **sIndices; % Used in memory only. Write zero. Ignore on read. -% -% float wData[1]; % The start of the array of data. Must be 64 bit aligned. -% }; - -function s=local_char(S); -% null-terminated string -> char string -S = S(:).'; -S = S(S~=0); -s=char(S); - - - - - - - - diff --git a/beamtime/read_hdf5_as_table.m b/beamtime/read_hdf5_as_table.m deleted file mode 100644 index e2c622f..0000000 --- a/beamtime/read_hdf5_as_table.m +++ /dev/null @@ -1,130 +0,0 @@ -function output_table = read_hdf5_as_table(filename,exclude_var_set) -% receives a h5 file written with function table2h5. -% reduced_var_set (cell of character_vectors), not usable yet. - - -% Last update: 14.08.2023 -% By: Juan F. Florez Ospina -% Email: juan.florez-ospina@psi.ch - -if ~iscellstr(exclude_var_set) - disp("exclude_var_set needs to be a cell of character vectors, e.g, {'var1','var2'} to be excluded.") - disp("To proceed, exclude_var_set was set to {}. So vars will be excluded.") - exclude_var_set = {}; -end - -INFO = h5info(filename); -num_rows = length(INFO.Groups); - - -num_attr1 = length(INFO.Groups(1).Datasets); -num_attr2 = length(INFO.Groups(1).Attributes); -num_cols = num_attr1 + num_attr2; -sz = [num_rows,num_cols]; - -% Extract group level attributes, they align for all -% groups (here denoting measurements/or rows) of the table in filename .h5 -group_columns = {INFO.Groups(1).Attributes.Name}; - -if num_attr1 == 1 && isempty(INFO.Groups(1).Datasets(num_attr1).Attributes) - dataset_columns = {}; - num_attr1 = 0; - num_cols = num_cols - 1; -else - for j = 1 : num_attr1 - dataset_columns{j} = INFO.Groups(1).Datasets(j).Attributes.Value; - end -end -%TODO: Implement feature to exclude varibales/columns as well as rows at -%reading time. This requires propagating modifications -% % % Select group and dataset columns to be loaded from hdf5 file, which are -% % % those not in the exclude_var_set. -% % if ~isempty(exclude_var_set) -% % for j = 1 : length(exclude_var_set) -% % % keep all vars except exclude_var_set{j} -% % var_filter = ~strcmp(exclude_var_set{j},group_columns); -% % group_columns = group_columns(var_filter); -% % if sum(var_filter) > 0 -% % exclude_var_set(j) = []; -% % end -% % end -% % -% % for j = 1 : length(exclude_var_set) -% % % keep all vars except exclude_var_set{j} -% % var_filter = ~strcmp(exclude_var_set{j},dataset_columns); -% % dataset_columns = dataset_columns(var_filter); -% % if sum(var_filter) > 0 -% % exclude_var_set(j) = []; -% % end -% % end -% % end - - -% Construct cell array with table data, where each row denotes a group, and -% the columns are either datasets or attributes in the given group. -tmp = cell(num_rows,num_cols); % {}; -idx = []; -group_columns = {}; -for i = 1 : num_rows - disp(['Begin construction of row:',INFO.Groups(i).Name]) - - for j = 1 : num_cols - if j <= num_attr1 - ds_name = [INFO.Groups(i).Name '/' INFO.Groups(i).Datasets(j).Name]; - - %disp(ds_name) - tmp{i,j} = h5read(filename,ds_name); - if i < 2 - column_idx = str2double(INFO.Groups(i).Datasets(j).Name(3:end)); - idx = [idx,column_idx]; - end - end - if j > num_attr1 - Name = INFO.Groups(i).Attributes(j-num_attr1).Name; - Datatype = INFO.Groups(i).Attributes(j-num_attr1).Datatype.Class; - - % Detect string attributes and convert them to characters. - % TODO: extend to other necessary data types. - if strcmp(Datatype,'H5T_STRING') - convert_func = @(x) convertStringsToChars(x); - else % no data type conversion is performed - convert_func = @(x) x; - end - - tmp{i,j} = convert_func(h5readatt(filename,INFO.Groups(i).Name, Name)); - if i < 2 - - disp(Name) - % Split attribute name into column_tag (containing original - % column idx) and column_name - - delimiter_idx = find(INFO.Groups(i).Attributes(j-num_attr1).Name=='_'); - % Left most '_' determines the split location - delimiter_idx = delimiter_idx(1); - - column_idx = str2double(Name(5:delimiter_idx-1)); - group_columns = [group_columns,{Name(delimiter_idx+1:end)}]; - %disp([Name(5:delimiter_idx-1),'-',column_name]) - idx = [idx,column_idx]; - end - - end - - end - disp(['Ends construction of row:',INFO.Groups(i).Name]) - -end - -% Find original ordering of columns by sorting idx in ascending order -[~, idx_perm] = sort(idx,'ascend'); - -varNames = [dataset_columns,group_columns]; - -% Create output_table from cell array using cell2table. This as opposed to -% array2table extract the content of its cells, which facilitates filtering -% operations based on table columns/vars. - -%output_table = array2table(tmp(:,idx_perm), 'VariableNames', varNames(idx_perm)); -output_table = cell2table(tmp(:,idx_perm), 'VariableNames', varNames(idx_perm)); - - diff --git a/beamtime/rgaImportData.m b/beamtime/rgaImportData.m deleted file mode 100644 index eeead46..0000000 --- a/beamtime/rgaImportData.m +++ /dev/null @@ -1,97 +0,0 @@ -function tbl = rgaImportData(fullFileName) -%RGAIMPORTDATA Import an SRS RGA "Pressure vs Time" scan (.txt) into a table. -% -% tbl = rgaImportData(fullFileName) reads an RGA ASCII log and returns a -% table ready for plotRgaData, with: -% datetime - absolute time (start time + Time(s)) -% time_s - elapsed scan time in seconds -% one column per active channel, named _m (e.g. Water_m18), -% holding the partial pressure in the file's units (usually Torr). -% -% The scan units and channel metadata are stored in -% tbl.Properties.VariableUnits and tbl.Properties.UserData. -% -% Two quirks of this file format are handled: -% * multi-word species names in the channel table (e.g. "Carbn dio") -% * adjacent negative values in the data run together with no space -% (e.g. "-2.8663e-010-2.3529e-010"); values are recovered by matching -% scientific-notation tokens rather than by splitting on whitespace. -% -% EXAMPLE -% tbl = rgaImportData('rga1_Jul_01_2026_08-23-06_AM.txt'); -% ax = plotRgaData(tbl); -% -% See also PLOTRGADATA, PLOTCRYODATA - - lines = readlines(fullFileName); % string array, keeps blanks - - %--- Locate the data block header "Time(s) Channel#1 ..." --- - iData = find(startsWith(strip(lines),'Time(s)'), 1); - if isempty(iData) - error('rgaImportData:noData','Could not find the "Time(s)" data header.'); - end - header = lines(1:iData-1); % metadata + channel table - - %--- Start time (absolute) --- - iStart = find(startsWith(strip(header),'Start time,'), 1); - if isempty(iStart) - startStr = strip(header(1)); % fall back to first line - else - startStr = strip(extractAfter(header(iStart),',')); - end - startStr = regexprep(startStr,'\s+',' '); % collapse the double space - startTime = datetime(startStr, ... - 'InputFormat','MMM d, yyyy h:mm:ss a', 'Locale','en_US'); - - %--- Units --- - units = 'a.u.'; - iu = find(startsWith(strip(header),'Units,'), 1); - if ~isempty(iu) - p = strip(split(header(iu),',')); - units = char(p(end)); - end - - %--- Channel definitions (e.g. "1 28.00 Nitrogen 1.00 3 OFF") --- - chanPat = '^\s*(\d+)\s+([\d.]+)\s+(.+?)\s+[\d.]+\s+\d+\s+\w+\s*$'; - tok = regexp(header, chanPat, 'tokens', 'once'); - tok = tok(~cellfun(@isempty, tok)); - nCh = numel(tok); - if nCh == 0 - error('rgaImportData:noChannels','No channel definitions found.'); - end - chMass = zeros(nCh,1); chName = strings(nCh,1); - for k = 1:nCh - chMass(k) = str2double(tok{k}{2}); - chName(k) = strip(string(tok{k}{3})); - end - - %--- Data: time before the comma + N scientific-notation values --- - dataLines = lines(iData+1:end); - dataLines = dataLines(strlength(strip(dataLines)) > 0); - n = numel(dataLines); - - time_s = str2double(extractBefore(dataLines, ',')); - matches = regexp(dataLines, '[-+]?\d+\.\d+[eE][-+]?\d+', 'match'); - - vals = nan(n, nCh); - for r = 1:n - v = str2double(matches{r}); - nn = min(numel(v), nCh); - vals(r,1:nn) = v(1:nn); - end - - %--- Assemble table --- - dt = startTime + seconds(time_s); - varNames = arrayfun(@(k) matlab.lang.makeValidName( ... - sprintf('%s_m%d', chName(k), round(chMass(k)))), 1:nCh, 'UniformOutput', false); - - tbl = table(dt, time_s, 'VariableNames', {'datetime','time_s'}); - for k = 1:nCh - tbl.(varNames{k}) = vals(:,k); - end - - tbl.Properties.VariableUnits = [{'', 's'}, repmat({char(units)}, 1, nCh)]; - tbl.Properties.UserData = struct( ... - 'units', char(units), 'startTime', startTime, ... - 'channelName', chName, 'channelMass', chMass); -end diff --git a/beamtime/save_table_as_hdf5.m b/beamtime/save_table_as_hdf5.m deleted file mode 100644 index 5391e72..0000000 --- a/beamtime/save_table_as_hdf5.m +++ /dev/null @@ -1,155 +0,0 @@ -function success = save_table_as_hdf5(input_table, filename) - -% This function takes input_table (of table type), structured with -% Thorsten's FileTable format, and stores it as .h5 file with name -% filename. Each row is treated as a group, where columns can be attributes -% of the group or datasets inside the group. - -% Last update: 11.08.2023 -% By: Juan F. Florez Ospina -% Email: juan.florez-ospina@psi.ch - -if istable(input_table) - - string_columns = input_table(:,vartype("string")).Properties.VariableNames; - input_table = convertvars(input_table,string_columns,'cellstr'); - % split multicolumn variables - input_table = splitvars(input_table); - column_names = input_table.Properties.VariableNames; -else - success = 0; - return -end - -% Create array with indices of column_names -column_names_idx = 1 : length(column_names); - -% Divide input_table into tables with numeric and cellstr variables/columns -numeric_table = input_table(:,vartype('numeric')); % group attributes of a timestamped measurement -cellstr_table = input_table(:,vartype('cellstr')); % group datasets of a timestamped measurement - -% Record columns/vars original index in reference table -numeric_columns = numeric_table.Properties.VariableNames; -numeric_columns_idx = argwhere_var_in_varset(numeric_columns,column_names); - -str_columns = cellstr_table.Properties.VariableNames; -str_columns_idx = argwhere_var_in_varset(str_columns,column_names); - -% Based on homogeneous columns/cell arrays, we identify the remaining columns -% with possibly heterogeneous entries. Ideally, these should store numeric -% n-dimensional arrays/datasets. - -rest_columns = {}; -cntr = 1; -for i = 1 : length(input_table.Properties.VariableNames) - variable = input_table.Properties.VariableNames{i}; - - is_str = sum(strcmp(variable,str_columns))>0; - is_num = sum(strcmp(variable,numeric_columns))>0; - if ~(is_num || is_str) - rest_columns{cntr} = variable; - disp(variable) - cntr = cntr + 1; - end -end - -rest_columns_idx = argwhere_var_in_varset(rest_columns,column_names); - -% Create an hdf5 file, where rows are seen as measurements/groups with -% attributes given by numeric and str variables and datasets given by the -% remaining variables as long as they are numeric n-dimensional arrays. - -cell_table = input_table(:,rest_columns); -[rows, cols] = size(input_table); - -for i = 1 : rows - group_name = strcat("/MEAS_",string(i),"/"); - if ~isempty(rest_columns) - for j = 1 : length(rest_columns) - dataset_name = strcat("DS",string(rest_columns_idx(j))); - - % Some table entries do not provide direct access to the object - % of interest, but may contain either {object} or {{object}}. - % The following loop solves that problem. TODO: is this generic enough? - - data = cell_table{i,column_names{rest_columns_idx(j)}}{1}; % <=> data = cell_table{i,rest_columns{j}}{1}; - - while iscell(data) - data = data{1}; - end - % when there is no data, we still need to provide a valid size - if ~isempty(data) - sz = size(data); - else - sz = [1,1]; - end - %%%% - % Group's dataset: Create dataset of size sz in a certain group - h5create(filename, strcat(group_name,dataset_name),sz); - % Dataset's attribute: Add attribute with dataset_name equal to column_name - attr = "column_name"; - attr_value = column_names{rest_columns_idx(j)}; % <=> rest_columns{j}; - h5writeatt(filename,strcat(group_name,dataset_name),attr,attr_value) - - %attr = "column_name_idx"; - %attr_value = rest_columns_idx(j); % <=> rest_columns{j}; - %h5writeatt(filename,strcat(group_name,dataset_name),attr,attr_value) - - % Assign 'data' to the dataset. 'data' has to be of admissible type. - try - h5write(filename,strcat(group_name,dataset_name),data) - catch exception - disp(exception) - %h5write(filename,strcat(group_name,dataset_name),cell_table{i,rest_columns{j}}) - end - end - else - dataset_name = "DS_EMPTY"; - sz = [1,1]; - h5create(filename, strcat(group_name,dataset_name),sz); - end - - % Group's attribute: Assign group attributes - for attr_idx = 1 : length(numeric_columns) - attr = column_names{numeric_columns_idx(attr_idx)};% <=> attr = numeric_columns{attr_idx}; - attr_value = numeric_table{i,attr}; - - column_idx_tag = ['ATTR',num2str(numeric_columns_idx(attr_idx)),'_']; - h5writeatt(filename,group_name,[column_idx_tag,attr],attr_value) - - %attr = "column_name_idx"; - %attr_value = numeric_columns_idx(attr_idx); % <=> rest_columns{j}; - - %h5writeatt(filename,group_name,attr,attr_value) - end - - for attr_idx = 1 : length(str_columns) - - attr = column_names{str_columns_idx(attr_idx)}; % <=> attr = str_columns{attr_idx} - attr_value = cellstr_table{i,attr}; - - column_idx_tag = ['ATTR',num2str(str_columns_idx(attr_idx)),'_']; - h5writeatt(filename,group_name,[column_idx_tag,attr],attr_value) - - %attr = "column_name_idx"; - %attr_value = str_columns_idx(attr_idx); % <=> rest_columns{j}; - - %h5writeatt(filename,group_name,attr,attr_value) - end - %h5create(filename,"/g2/DS2",[20 Inf],"Chunksize",[5 5]); -end - -success = 1; - -function idx = argwhere_var_in_varset(var,varset) - ref_idx = 1 : length(varset); - if iscellstr(var) - idx = []; - for i = 1 : length(var) - logical_idx = strcmp(var{i},varset); - idx = [idx,ref_idx(logical_idx)]; - end - else - logical_idx = strcmp(var,varset); - idx = ref_idx(logical_idx); - end diff --git a/beamtime/LabView_importData.m b/import/LabView_importData.m similarity index 100% rename from beamtime/LabView_importData.m rename to import/LabView_importData.m diff --git a/beamtime/exportFigureData.m b/import/exportFigureData.m similarity index 100% rename from beamtime/exportFigureData.m rename to import/exportFigureData.m diff --git a/beamtime/issFlowImportData.m b/import/issFlowImportData.m similarity index 100% rename from beamtime/issFlowImportData.m rename to import/issFlowImportData.m diff --git a/beamtime/nappSaveDataTable.m b/import/nappSaveDataTable.m similarity index 100% rename from beamtime/nappSaveDataTable.m rename to import/nappSaveDataTable.m diff --git a/lopap/3.Skripte/.DS_Store b/lopap/3.Skripte/.DS_Store index 3390f63..63b3378 100644 Binary files a/lopap/3.Skripte/.DS_Store and b/lopap/3.Skripte/.DS_Store differ diff --git a/beamtime/nappImage.m b/oldVersions/nappImage.m similarity index 100% rename from beamtime/nappImage.m rename to oldVersions/nappImage.m diff --git a/nappNorm.m b/oldVersions/nappNorm.m similarity index 100% rename from nappNorm.m rename to oldVersions/nappNorm.m diff --git a/beamtime/createBeamtimeFolder.m b/utils/createBeamtimeFolder.m similarity index 100% rename from beamtime/createBeamtimeFolder.m rename to utils/createBeamtimeFolder.m diff --git a/utils/distFig_Error.mat b/utils/distFig_Error.mat index 1f39a8a..ec48824 100644 Binary files a/utils/distFig_Error.mat and b/utils/distFig_Error.mat differ