%% How to analyse ISS XPS and NEXAFS data using Matlab % %% Introduction: Concept % % NEXAFS and XPS data from beam times is imported into a MATLAB table. The % table allows to add meta data such as sample temperature, cell pressure, % or Scienta settings (pass energy, etc). Further, data from several % beam times can be imported and then filtered - for example to process all % gas-phase CO2 PE from the last 5 years; or all ice NEXAFS at -10° to % -12°C. Functions and the table are organised such that one can always go % back to raw data to re-do the analysis or continue with processed data. % % The basic idea is that a set of MATLAB functions that import the data of % different format and from various sources and that can be used to perform % basic XPS and NEXAFS data processing are used, shared, and developed by % all group members. This requires common data formats and naming. The % scripts/live scripts/functions that are used to call the common MATLAB % functions are written, stored, named individually by each user. % % % % % %% Introduction: Function calls % % Most functions need the MATLAB data table as input. The output can be % stored in the same data table adding data to the original data table, or % in a new one - thus creating a copy. Some functions such as those used % for plotting do not write data. %% % % InputTable = nappFunctionAbc(InputTable); % %% % This command runs the function nappFunctionAbc on the data table % _InputTable_ and writes the results into the same table (with the name % _InputTable_. % % The _InputTable_ may hold different data types such as XPS data, NEXAFS, % and pictures. Mostly, the functions require one and the same data type as % input. *The _InputTable_ needs to be filtered when passed to a function* % (see below). Exceptions from this are the |nappGenerateSpectra| and % |nappPlot| functions that can be called with some limitations with % mixed data as input (including pictures, that are ignored). % %% % % OutputTable = nappFunctionAbc(InputTable); % %% % % This command runs the same function on the data in the table _InputTable and % writes the results into the data table _OutputTable_ which is a full copy % of _InputTable_ plus the results of the function nappFunctionAbc. % % % Most functions allow to set a number of optional input parameters, some % require additional mandatory input. Please check the documentation of % each function for further help: % %% % % help nappFunctionAbc % %% % % The mandatory input comes first in each function call. In the following % example the data of the _InputTable_ is passed to the function as well as % the variables _x_ and _y_. The optional function input is given just like % in any MATLAB function using parameter descriptions: 'option',setting. % Setting can be a text string in quotes, or a variable (array, logical, % table, date number, etc). Most common are: % %% % % OutputTable = nappFunctionAbc(InputTable,x,y,'tableSelection',tmpDataSelection,'... % 'tableVariable','TableVariable', energyScale','kinetic','mode','mean'); % %% % * 'tableSelection': allows to filter the table and run the function only % on selected table lines. tmpDataSelection is a logical array, see section % Work with data: Filter table in this document. % * 'tableVariable': allows to choose the data of the data table that the % function should work with. See Introduction: Data structure section in % this document. % * 'energyScale': allows to use kinetic or binding energy scale to plot or % perform calculation. % * 'mode': allows to select options for functions such as using mean or % sum for calculations, etc. % * 'showFigures': allows to view or view not figures and function output. % % Please consult the help files of each function for a complete list of % options. % %% Introduction: Data structure % % It starts with importing the multi-dimensional IgorPro files that the SES % software saves or with the h5 file structure that is saved for the NEXAFS % data. % % * Upon import of the SES data, region iterations are averaged and % counts are normalised to 1 s. % * NEXAFS data... % % The data are then saved in a data table, each file in one row and the % data in columns. Columns are called table variables in MATLAB and in the % nappFunctions. The data columns are: % % * *image*: PE data: Intensity in counts-per-second vs. kinetic energy and sequence % iteration. Functions that work with image data, overwrite this column. % * *imageRoh*: a copy of image at the time of data import. % * *spectrum_countsPerSecond* and *spectrum_counts*: Hold the spectra that % are computed from the image. These data columns are modified by % nappFunctions that work with spectrum data. % * *spectrumRoh_countsPerSecond* and *spectrumRoh_counts*: a copy of the % spectrum data at time of generation. % % In other words, the data in the columns spectrum_countsPerSecond, % spectrum_counts, image always hold the processed data and are modified by % each function call. The Roh data allows to go back and re-do the % processing. Next to this the data table stores analyser settings such as % scientaEkin and sample parameters such as temperature and pressure. View % the data table in the data viewer or command window of MATLAB to see all % columns. This data structure allows to process all data and then still plot % images, unprocessed data, or processed data of selected experiments. %% ToDo % % * add code for intensity vs. time plotting % * add code for average and plot iterations. % * get rid of peakfind and replace by gauss fitting % * use gauss fitting function within functions? % * Tidy html output, and get Yanisha's feedback % * Add section on how to modify figures after plotting % * add section on how to access data in table % * add section on how to merge data tables % * Work on code and add section how to remove XPS from NEXAFS % * Work on code and add section on I0 including 2nd order light % * Add code to add combined spectra to data table as row. % * Update help files for NEXAFS functions and NEXAFS options in general % functions. % * Set-up folders for Yanisha %% Prepare: Initialise MATLAB % % You need to have access to the folder holding the functions and helper % files. These are shared via switch drive. % % *Add the paths to the initializeMatlab function at the end of this % script* This function needs to be added to the end of each of your % scripts or live scripts. Below is an example. % %% % % function [myColorMap, PsiFarbe] = initializeMatlab % %initializeMatlab Sets NappIce specific settings % % Adds Napp files to path and defines file locations for mac, windows, % % and Matlab online (which runs on unix) % % % change working directory % path = matlab.desktop.editor.getActiveFilename; % [filepath,~,~] = fileparts(path); % cd(filepath); % % % The fitting routines writes quite a lot of feedback and warnings. I shut them off. % warning('off','all') % warning off backtrace % warning off verbose % % % Functions and helper files path: % if ismac % % add Napp files to path % addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/Add-Ons'); % addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/nappIce'); % elseif ispc % % add Napp files to path % addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/Add-Ons'); % addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/nappIce'); % elseif isunix % % add Napp files to path % addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/Add-Ons'); % addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/nappIce'); % end % % % Color maps % myColorMap.red = colormap(autumn(7)); % myColorMap.blue = colormap(winter(7)); % % % 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 %% % The path might be different % on your computer depending how you have set up SwitchDrive: % %% % % addpath('C:\Users\bletry_c\switchdrive\PSI_Matlab\nappIce'); % addpath('C:\Users\bletry_c\switchdrive\PSI_Matlab\Add-Ons'); % %% % then run the initialiseMatlab function: %% % clearvars % [myColorMap, PsiFarbe] = initializeMatlab; % close all % clc %% Prepare: ISS data structure and path to local copy of ISS data % % Data needs to be organised in beam time folders that can be located on the % Napp drive or locally on your computer. The data folder naming and % structure within the beam time folder (orange on figure) is strict and % there must not be any subfolders in the data folders: % % % % %% % * NEXAFS holds *.h5 XAS data % * Photos holds *.bmp pictures % * Pressure holds the *.dat LabView files % * SES holds the *.ibw PE data. % * To run the scripts, there *needs to be at % least ONE *.ibw file in the SES folder* % % % % *beam time folder location* % % * The beam time folder can be a subfolder of any number of folders. % * The beam time folder needs to have the same name, same subfolders, and % folders above (path) locally and on the NAPP drive. This can be set by % the user when calling the import function. As standard, we use % "year:YYYY_MM__monthIssIceNapp" % * on Napp drive: the beam time folder (and folders above) needs to be % within the "SC Data" folder % * locally: the beam time folder (and folders above) needs to be within % your "MATLAB home folder:NAPP:SC Data" folder % % % The see all import options (few examples given below) check out the % nappFileList.m help (this works for all nappIce functions): %% % % help nappFileList.m % %% Helper functions % % * Napp_p_ice(T_current) states and plots the vapour pressure of ice between 200-270 K % * Napp_p_RH(T_current,RH) calculates the partial pressure of water for a given % temperature and relative humidity. % * Napp_RH_p(T_current,partial_pressure_water) calculates the relative humidity for a given % temperature and water pressure. %% Import ISS data: Complete beam time folder % %% % % FileList = nappFileList('2022/2022_02__FebIssIceNapp'); % %% % This will create a new data table "FileList" overwriting any previous % versions of this list with data imported from the local copy of the beam % time folder with the name "2022_02__FebIssIceNapp" being a subfolder of % the folder "2022". %% clearvars %% [myColorMap, PsiFarbe] = initializeMatlab; close all clc %% if isfile('nappIceHowToData.mat') load('nappIceHowToData.mat') disp('data read from mat file') else FileList = nappFileList('2022/2022_02__FebIssIceNapp'); % add photon energy to table FileList = addPhotonEnergy(FileList,[1,8:12,26],1000,2,2022); FileList = addPhotonEnergy(FileList,[2:3,5,7,13:14,16:18,20:25,27:31,33:35,37:38,40,42,44,46,47,49:51,54:56,60:62,65:66,68,70,73,74,76,77,82],900,2,2022); FileList = addPhotonEnergy(FileList,[4,6,15,19,58,59,64,67,72,80,81],650,2,2022); FileList = addPhotonEnergy(FileList,[32,36,39,41,43,45,48,57,63,69,71,75,78,83],1150,2,2022); FileList = addPhotonEnergy(FileList,79,NaN,2,2022); % add sample description FileList = addSampleNotes(FileList,[1,8:11],'Sample holder',2,2022); FileList = addSampleNotes(FileList,[2:7,35:36,56:60],'Ice with N2',2,2022); FileList = addSampleNotes(FileList,[12:34,54:55],'Ice',2,2022); FileList = addSampleNotes(FileList,[16,20],'Ice (bad data)',2,2022); FileList = addSampleNotes(FileList,[37:51,61:72],'Ice with N2 and phenol in Ar',2,2022); FileList = addSampleNotes(FileList,44,'Ice with N2 and phenol in Ar (bad data)',2,2022); FileList = addSampleNotes(FileList,73:76,'H2O gas-phase',2,2022); FileList = addSampleNotes(FileList,73,'H2O gas-phase (bad data)',2,2022); FileList = addSampleNotes(FileList,77:83,'CO2 gas-phase',2,2022); FileList = addSampleNotes(FileList,79,'CO2 gas-phase (bad data)',2,2022); % import data and add to data table FileList = nappFileList('2021/2021_10__OctIssIceNapp',FileList); FileList = nappFileList('2021/2021_08__AugIssIceNapp',FileList); % add photon energy to table FileList = addPhotonEnergy(FileList,1:10,1000,8,2021); FileList = addPhotonEnergy(FileList,36:42,1000,8,2021); FileList = addPhotonEnergy(FileList,51:72,1000,8,2021); FileList = addPhotonEnergy(FileList,78:120,1000,8,2021); FileList = addPhotonEnergy(FileList,1:6,1000,10,2021); FileList = addPhotonEnergy(FileList,8,500,10,2021); FileList = addPhotonEnergy(FileList,10,750,10,2021); FileList = addPhotonEnergy(FileList,13,500,10,2021); FileList = addPhotonEnergy(FileList,16,500,10,2021); FileList = addPhotonEnergy(FileList,17,750,10,2021); FileList = addPhotonEnergy(FileList,18:20,500,10,2021); FileList = addPhotonEnergy(FileList,21,750,10,2021); FileList = addPhotonEnergy(FileList,23,500,10,2021); FileList = addPhotonEnergy(FileList,26,600,10,2021); FileList = addPhotonEnergy(FileList,27,850,10,2021); FileList = addPhotonEnergy(FileList,28:31,600,10,2021); FileList = addPhotonEnergy(FileList,32:51,1000,10,2021); FileList = addPhotonEnergy(FileList,53:68,1000,10,2021); FileList = addPhotonEnergy(FileList,[74,76:85,87:91,93:94],1000,10,2021); % add sample description FileList = addSampleNotes(FileList,1:10,'MgO in N2',8,2021); FileList = addSampleNotes(FileList,36:39,'MgO in H2O',8,2021); FileList = addSampleNotes(FileList,40:44,'MgO in N2',8,2021); FileList = addSampleNotes(FileList,45:49,'MgO in Ar',8,2021); FileList = addSampleNotes(FileList,[51,53:55],'MgO in UHV',8,2021); FileList = addSampleNotes(FileList,56:60,'MgO ice (bad data)',8,2021); FileList = addSampleNotes(FileList,[61,66:72],'MgO ice in Ar HONO',8,2021); FileList = addSampleNotes(FileList,61,'MgO ice in Ar HONO (bad data)',8,2021); FileList = addSampleNotes(FileList,[68,69,70, 72],'MgO ice in Ar HONO on(bad data)',8,2021); FileList = addSampleNotes(FileList,78:80,'MgO in UHV',8,2021); FileList = addSampleNotes(FileList,81:82,'MgO in H2O',8,2021); FileList = addSampleNotes(FileList,83:85,'MgO ice',8,2021); FileList = addSampleNotes(FileList,86:94,'MgO ice AA in Ar',8,2021); FileList = addSampleNotes(FileList,[86 88],'MgO ice AA in Ar (bad data)',8,2021); % temporarily, Ar very dominating FileList = addSampleNotes(FileList,89,'MgO ice AA in Ar (bad data)',8,2021); FileList = addSampleNotes(FileList,98,'Ar',8,2021); FileList = addSampleNotes(FileList,99,'SiO2 in H2O',8,2021); FileList = addSampleNotes(FileList,100:103,'SiO2 ice',8,2021); FileList = addSampleNotes(FileList,104:110,'SiO2 ice AA in Ar',8,2021); FileList = addSampleNotes(FileList,111:112,'SiO2 ice',8,2021); FileList = addSampleNotes(FileList,113:118,'SiO2 ice AA in Ar',8,2021); FileList = addSampleNotes(FileList,119:120,'CO2',8,2021); FileList = addSampleNotes(FileList,1,'MgO in N2',10,2021); FileList = addSampleNotes(FileList,2,'MgO in N2, PE 50, Slits 1/1/1',10,2021); FileList = addSampleNotes(FileList,3,'MgO in N2, PE 50, Slits 1/1/1',10,2021); FileList = addSampleNotes(FileList,5,'MgO in N2, PE 50, Slits 1/0.5/0.5',10,2021); FileList = addSampleNotes(FileList,6,'MgO in N2, PE 50, Slits 1/1/1',10,2021); FileList = addSampleNotes(FileList,8,'MgO in N2, PE 20, Slits 1/1/1',10,2021); FileList = addSampleNotes(FileList,10,'MgO in N2, PE 20, Slits 1/1/1',10,2021); FileList = addSampleNotes(FileList,13,'MgO in N2, PE 20, Slits 1/1/1',10,2021); FileList = addSampleNotes(FileList,16,'MgO in N2, PE 20, Slits 1/0.8/0.8',10,2021); FileList = addSampleNotes(FileList,18,'MgO in N2, PE 20, Slits 1/0.8/0.8',10,2021); FileList = addSampleNotes(FileList,19,'MgO in N2, PE 20, Slits 0.5/1/1',10,2021); FileList = addSampleNotes(FileList,20,'MgO in N2, PE 20, Slits 0.5/1/1',10,2021); FileList = addSampleNotes(FileList,21,'MgO in N2, PE 20, Slits 0.5/1/1',10,2021); FileList = addSampleNotes(FileList,23,'MgO in N2, PE 20, Slits 0.5/1/1',10,2021); FileList = addSampleNotes(FileList,26,'MgO in N2, PE 50, Slits 0.5/1/1',10,2021); FileList = addSampleNotes(FileList,27,'MgO in N2, PE 20, Slits 0.5/1/1',10,2021); FileList = addSampleNotes(FileList,28,'MgO in N2, PE 50, Slits 0.5/0.5/0.5',10,2021); FileList = addSampleNotes(FileList,29,'MgO in N2, PE 50, Slits 1/1/1',10,2021); FileList = addSampleNotes(FileList,31,'MgO in N2, PE 20, Slits 1/1/1',10,2021); FileList = addSampleNotes(FileList,32:33,'MgO in N2',10,2021); FileList = addSampleNotes(FileList,34:36,'MgO ice',10,2021); FileList = addSampleNotes(FileList,37:41,'MgO in H2O',10,2021); FileList = addSampleNotes(FileList,42:51,'MgO ice',10,2021); FileList = addSampleNotes(FileList,45,'MgO ice (bad data)',10,2021); FileList = addSampleNotes(FileList,[53:68,70:71],'MgO ice AA in N2' ,10,2021); FileList = addSampleNotes(FileList,54,'MgO ice AA in N2 (bad data)' ,10,2021); FileList = addSampleNotes(FileList,68,'MgO ice AA in N2 (bad data)' ,10,2021); FileList = addSampleNotes(FileList,63,'MgO ice AA in N2 (bad data)' ,10,2021); FileList = addSampleNotes(FileList, [72,74],'MgO in H2O' ,10,2021); FileList = addSampleNotes(FileList, [76,78:80],'MgO in N2 AA plus H2O' ,10,2021); FileList = addSampleNotes(FileList,81:82,'SiO2 in N2',10,2021); FileList = addSampleNotes(FileList,83:85,'SiO2 ice',10,2021); FileList = addSampleNotes(FileList,87:90,'SiO2 in H2O',10,2021); FileList = addSampleNotes(FileList,91,'SiO2 AA in N2',10,2021); FileList = addSampleNotes(FileList,93:94,'SiO2 in H2O AA',10,2021); % import FileList = nappFileList('2020/202008AugustISS',FileList); FileList = addSampleNotes(FileList,3,'diode upstream',8,2020); FileList = addSampleNotes(FileList,4,'diode in-cell',8,2020); FileList = addSampleNotes(FileList,8,'diode upstream',8,2020); FileList = addSampleNotes(FileList,9,'diode in-cell',8,2020); FileList = addSampleNotes(FileList,10,'diode in-cell',8,2020); FileList = addSampleNotes(FileList,11,'diode upstream',8,2020); FileList = addSampleNotes(FileList,13:23,'O_K-edge ice',8,2020); FileList = addSampleNotes(FileList,13:18,'O_K-edge ice (bad S/N)',8,2020); FileList = addSampleNotes(FileList,[15,19,20],'O_K-edge ice (no notes)',8,2020); %ListNexafs = addSampleNotes(ListNexafs,21:23,'O_K-edge ice (ice unstable)',8,2020); FileList = addSampleNotes(FileList,24,'diode (no notes)',8,2020); FileList = addSampleNotes(FileList,25,'diode upstream',8,2020); FileList = addSampleNotes(FileList,[26,28,30],'O_K-edge gold',8,2020); FileList = addSampleNotes(FileList,[27,29,31],'O_K-edge gold (no notes)',8,2020); FileList = addSampleNotes(FileList,[32,33],'(no notes)',8,2020); FileList = addSampleNotes(FileList,[34,35,37,38],'diode in-cell',8,2020); FileList = addSampleNotes(FileList,[36,39:42],'diode upstream',8,2020); FileList = addSampleNotes(FileList,43:45,'O_K-edge gold',8,2020); FileList = addSampleNotes(FileList,[48,50],'diode upstream',8,2020); FileList = addSampleNotes(FileList,[49,51,54],'(no notes)',8,2020); FileList = addSampleNotes(FileList,[43:45,52,53,55:59],'O_K-edge gold',8,2020); FileList = addSampleNotes(FileList,53,'O_K-edge gas-phase (interference)',8,2020); FileList = addSampleNotes(FileList,54,'O_K-edge (no data)',8,2020); FileList = addSampleNotes(FileList,55,'O_K-edge gas-phase',8,2020); FileList = addSampleNotes(FileList,60,'diode upstream',8,2020); FileList = addSampleNotes(FileList,[61,63],'O_K-edge ice',8,2020); % ListNexafs = addSampleNotes(ListNexafs,61,'O_K-edge ice (ice unstable)',8,2020); FileList = addSampleNotes(FileList,62,'O_K-edge ice (no notes)',8,2020); FileList = addSampleNotes(FileList,64,'diode upstream',8,2020); FileList = addSampleNotes(FileList,65,'diode in-cell',8,2020); FileList = addSampleNotes(FileList,66,'diode in-cell',8,2020); save('nappIceHowToData.mat','FileList'); end %% Import ISS data: Error messages % % If you get a message like this in the command window % % There appears to be no file in the SES folder. Add at least one file first. % I quit now % %% % and MATLAB quits running the script, please check that there is at least % a *.ibw file in the SES folder %% % If you instead get a message like this % % There is something wrong with the path. Check for typo and that the drives are mounted % I quit now % %% % and MATLAB quits running the script, please check % % * that there are no typos in the path names % * that the drives are mounted. %% Import ISS data: Add data to existing data table % % This will import data from the beam time folder % "2021/2021_08__AugIssIceNapp" on the NAPP drive adding the data to the data table % "FileList" in the MATLAB workspace %% % FileList = nappFileList('2021/2021_08__AugIssIceNapp',FileList,'mode','nappDrive'); %% Import ISS data: Add new SES or NEXAFS files from local beam time folder % % Using the mode 'localNew' the content of the beam time folder will be % compared to that of the FileList in the workspace and only those files % not yet imported will be processed. This is a little faster and preserves % any changes to the FileList. *To prevent data failure of running SES % measurements, this only works on the local copy of the beam time folder* %% % % FileList = nappFileList('2022/2022_02__FebIssIceNapp',FileList,'mode','localNew'); % %% Import ISS data: Choose files manually % % This will open a windows file explorer window where you can choose as % many data files to be imported as you want. In this example, a new % FileList is written, overwriting any previous versions in the workspace. %% % % FileList = nappFileList('2022/2022_02__FebIssIceNapp','mode','nappDrivePick'); % % % % % %% Work with data: Excel % % The nappFileList.m function also writes a csv file to the beam time % folder. Open it as xlsx and use Excels formatting and filtering tools to % work with your data set. So, the xlsx file is edited manually and might % contain additional information that you have added such as slit settings, % comments, type of sample, scope of the measurement, etc. The csv file it % automatically generated and might thus be frequently be over-written. Use % copy/paste to update the xlsx file with new data, formatting will be % automatically applied to new data then. %% % % % % % %% Work with data: Add photon energy to table (XPS) % % ISS beamline does not log settings of SES data. Photon energy, which is % needed to calculate the binding energy later, needs to be added manually. % This will read the FileList table and add the photon energy "1000" to the % SES data with file numbers 1,8 to 12, and 26 acquired in February (month % "2") of the year "2022"). Note, this is only adding to XPS data, NEXAFS % data are not touched: %% % % FileList = addPhotonEnergy(FileList,[1,8:12,26],1000,2,2022); % %% Work with data: Add sample description % % Sample description to label figures and for filtering data can be added. % It does not make sense to use temperature or pressure, as these data are % written to the table anyway. It does make sense to use standard phrases % to enable filtering all beam time data. This code example follow the same % input structure as the addPhotonEnergy function. This function works on % both NEXAFS and XPS data. One may limit and select either one % specifically by adding either 'NEXAFS' or 'XPS' strings as last input % parameter. This is optional, if not specified function runs on both data % types: %% % % FileList = addSampleNotes(FileList,[1,8:11],'Sample holder',2,2022,'XPS'); % FileList = addSampleNotes(FileList,[1,8:11],'Sample holder',2,2022,'NEXAFS'); % FileList = addSampleNotes(FileList,[2:7,35:36,56:60],'Ice with N2',2,2022); % FileList = addSampleNotes(FileList,73:76,'H2O gas-phase',2,2022); % FileList = addSampleNotes(FileList,73,'H2O gas-phase (bad data)',2,2022); %% Work with data: Filter table % % An advantage of the data table is filtering. This works with standard % MATLAB functions using logical operations. Main motivation of filtering % is to work with selected subset of data which for example can be % processed with the same settings, fitted with the same constrains, or % shall be plotted in one graph for comparison. % % Further, the _InputTable_ may hold different data types such as XPS data, % NEXAFS, and pictures. Mostly, the functions require one and the same data % type as input. Therefore, *the _InputTable_ needs to be filtered when % passed to most functions*. Exceptions from this are the % |nappGenerateSpectra| and |nappPlot| functions that can be called with % some limitations in the settings with mixed data as input (including % pictures, that are ignored). % % The first example filter CO2 gas-phase C1s PE data that is not "(bad % data)" and has a pass energy of 50 eV. In the second example, we pick a % C1s or O1s PE data from the SES file #77 from February 2022. Any table % column can be used for filtering. "&" means AND "|" is OR. % %% % tmpDataSelection1 = matches(FileList.sample,'CO2 gas-phase') ... % & ~contains(FileList.sample,'(bad data)')... % & contains(FileList.name,'C1s')... % & FileList.scientaPassEnergy_eV == 50 ; % % tmpDataSelection2 = (contains(FileList.name,'077_C1s') | contains(FileList.name,'077_O1s')) ... % (month(FileList.lastModifiedDatenum) == 2) &... % (year(FileList.lastModifiedDatenum) == 2022); %% tmpDataSelection1 = matches(FileList.sample,'CO2 gas-phase') ... & ~contains(FileList.sample,'(bad data)')... & contains(FileList.name,'C1s')... & FileList.scientaPassEnergy_eV == 50 ; tmpDataSelection2 = (contains(FileList.name,'077_C1s') | contains(FileList.name,'077_O1s'))& ... (month(FileList.lastModifiedDatenum) == 2) &... (year(FileList.lastModifiedDatenum) == 2022); %% Work with data: Display filtered table and selected columns % % MATLAB tables allow to address the columns by name. To display only the % rows that match the filter criteria and only specific columns, code like % the examples below can be used: %% % disp(FileList(tmpDataSelection1,{'name','sample','xRayEkin_eV','scientaPassEnergy_eV','lastModifiedDatestr','sampleTemp_dC',... % 'cellPressure_mbar' })) % disp(FileList(tmpDataSelection2,{'name','scientaLensMode','xRayEkinRange_eV','scientaPassEnergy_eV'})) %% disp(FileList(tmpDataSelection1,{'name','sample','xRayEkin_eV','scientaPassEnergy_eV','lastModifiedDatestr','sampleTemp_dC',... 'cellPressure_mbar' })) disp(FileList(tmpDataSelection2,{'name','scientaLensMode','xRayEkinRange_eV','scientaPassEnergy_eV'})) clearvars tmp* %% % %% Work with data: Modify data in table % % There might be bad sweeps (sequence iterations) either with too low % signal to noise or because some setting was changed during the run. These % can be removed by directly addressing the data in the images. Same % procedure, first the data (table row) is filtered, then the image % modified for the selected data. % % *remove one sweep* %% % % tmpDataSelection = contains(FileList.name,'077_C1s')& ... % (month(FileList.lastModifiedDatenum) == 2) &... % (year(FileList.lastModifiedDatenum) == 2022); % FileList(tmpDataSelection,:).image{:}(:,3)=[]; % % tmpDataSelection = contains(FileList.name,'077_O1s')& ... % (month(FileList.lastModifiedDatenum) == 2) &... % (year(FileList.lastModifiedDatenum) == 2022); % FileList(tmpDataSelection,:).image{:}(:,3)=[]; % %% % *remove several sweeps* % %% % % tmpDataSelection = contains(FileList.name,'059_C1s')& ... % (month(FileList.lastModifiedDatenum) == 10) &... % (year(FileList.lastModifiedDatenum) == 2021); % FileList(tmpDataSelection,:).image{:}(:,5:15)=[]; %% % *remove all data (complete table rows) outside a specific time window* % %% % tmpTime.start = datenum('30-Apr-2019 02:00:00'); % tmpTime.end = datenum('30-Apr-2019 05:00:00'); % toDelete = Table_FileList.datenum <= tmpTime.start; % Table_FileList(toDelete,:) = []; % toDelete = Table_FileList.datenum >= tmpTime.end; % Table_FileList(toDelete,:) = []; %% % *Correct beam line-offset in data* % % This will correct 1.6 from the X-ray energies, of particular importance % for NEXAFS data. One can also do this on selected data. %% % beamlineOffset = 1.6; % FileList.xRayEkin_eV = cellfun(@(x) x+beamlineOffset,FileList.xRayEkin_eV,'UniformOutput',false); %% Add data (columns) to table % % Calculation results for each row can be added to data tables using % standard Matlab functions. This example illustrates the use of % anonymous functions, their call for each row using |cellfun|, and % the generation of additional columns to which (selection of) the data are % written. %% % % fun1 =@(c) interp1(IzeroAugInCell(:,1),IzeroAugInCell(:,2), c); % fun2 =@(c) interp1(IzeroAugInCell(:,1),IzeroAugInCell(:,3), c); % tmpMatch = (month(ListNexafs.lastModifiedDatenum) == 8) &... % (year(ListNexafs.lastModifiedDatenum) == 2020) |... % (startsWith(ListNexafs.name, 'sum_Aug')); % ListNexafs.uhvI0(tmpMatch) = cellfun(fun1, ListNexafs.xRayEkin_eV(tmpMatch) ,'uni' , 0); % ListNexafs.uhvI0std(tmpMatch) = cellfun(fun2, ListNexafs.xRayEkin_eV(tmpMatch) ,'uni' , 0); % clearvars tmp* fun* %% Plot data: XPS images % % We use the nappPlot function to plot the images. For this, we specify % the column of the data table that should be plotted: % 'tableVarialbe','image' plots the image for all data in FileList that are % selected by the logical array tmpDataSelection (See _Filtering table_ % above). %% % % nappPlot(FileList,tmpDataSelection,'tableVariable','image'); % %% close all tmpDataSelection = contains(FileList.name,'035_O1s') & FileList.xRayEkinRange_eV(:,1) == 900 ... & FileList.scientaPassEnergy_eV == 50 ... & (month(FileList.lastModifiedDatenum) == 2) ... & (year(FileList.lastModifiedDatenum) == 2022) ... & (day(FileList.lastModifiedDatenum) >= 27); nappPlot(FileList,tmpDataSelection,'tableVariable','image'); %% Plot data: XPS and NEXAFS images % % This example filters for a XPS file name and a NEXAFS file name and shows % two things. First, that the XPS file name is not unique and filtering % thus needs to be combined with extra parameters such as date and second % how NEXAS and XPS data can be simultaneously passed to the |nappPlot| % function %% % tmpDataSelection = matches(FileList.name,'0067067_O1s_1000eV.ibw') | matches(FileList.name, '0063_20200824_042852_O_K_edge.h5'); % nappPlot(FileList,tmpDataSelection); %% tmpDataSelection = matches(FileList.name,'0067067_O1s_1000eV.ibw') | matches(FileList.name, '0063_20200824_042852_O_K_edge.h5'); nappPlot(FileList,tmpDataSelection); %% Plot data: XPS spectra % % We use the nappPlot function to plot the spectra by selecting % 'spectrum_countsPerSecond' as 'tableVariable'. Further options include % the binding or kinetic energy scale, and each spectrum in a separate % window, or all in one window by setting the 'mode'. This works, of % course, only after the spectrum has been generated using the function % nappGenerateSpectra. %% % % nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond',... % 'mode','AllInOne','energyScale','kinetic'); % %% close all tmpDataSelection = matches(FileList.sample,'Ice with N2')... & ~contains(FileList.sample,'(bad data)')... & contains(FileList.name,'O1s') & FileList.xRayEkinRange_eV(:,1) == 900 ... & FileList.scientaPassEnergy_eV == 50 ... & (month(FileList.lastModifiedDatenum) == 2) ... & (year(FileList.lastModifiedDatenum) == 2022) ... & (day(FileList.lastModifiedDatenum) >= 27); FileList = nappGenerateSpectra(FileList,tmpDataSelection); nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond',... 'mode','AllInOne','energyScale','kinetic'); %% Plot data: NEXAFS spectra % % We use the same, one-and-only nappPlot function to plot the NEXAFS % spectra by selecting 'spectrum_counts' as 'tableVariable' and % 'energyScale' as 'xRay'. Further options include plotting each spectrum % in a separate window, or all in one window by setting the 'mode'. This % works, of course, only after the spectrum has been generated using the % function nappGenerateSpectra. %% % % nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay','mode','OneEach') % %% % close all clc tmpDataSelection = contains(FileList.name, '0063_20200824_042852_O_K_edge'); % Sum Auger-Meitner Spectrum FileList = nappGenerateSpectra(FileList,'tableSelection',tmpDataSelection,'mode','sum'); % Plot nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay','mode','OneEach'); %% Plot data: Figure layout % % The |nappPlot| function has 3 pre-defined figure layouts optimised for % the computer screen, for powerpoint presentation or for word (and other % text) files: %% % % nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay','mode','OneEach','figureMode','screen'); % %% close all clc tmpDataSelection = contains(FileList.name, '0063_20200824_042852_O_K_edge'); % Sum Auger-Meitner Spectrum FileList = nappGenerateSpectra(FileList,'tableSelection',tmpDataSelection,'mode','sum'); % Plot nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay','mode','OneEach','figureMode','screen'); %% % % nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay','mode','OneEach','figureMode','word'); % %% close all clc tmpDataSelection = contains(FileList.name, '0063_20200824_042852_O_K_edge'); % Sum Auger-Meitner Spectrum FileList = nappGenerateSpectra(FileList,'tableSelection',tmpDataSelection,'mode','sum'); % Plot nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay','mode','OneEach','figureMode','word'); %% % % nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay','mode','OneEach','figureMode','powerpoint'); % %% close all clc tmpDataSelection = contains(FileList.name, '0063_20200824_042852_O_K_edge'); % Sum Auger-Meitner Spectrum FileList = nappGenerateSpectra(FileList,'tableSelection',tmpDataSelection,'mode','sum'); % Plot nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay','mode','OneEach','figureMode','powerpoint'); %% Plot data: Export the Figure (for use in powerpoint) % % Either, copy paste the figure, or use this command on the front most % figure in Matlab: %% % % set(gcf,'InvertHardcopy','on'); % print('NameForFigureFile, '-dpng', '-r220'); % %% Plot data: Add region labels to survey % % Here is an example of how to mark regions of interest in survey plots. % For this, a survey must be the topmost figure. %% % dataObjs = findobj(gcf,'-property','YData'); % tmpxShift = 5; % binding energy shift and mono offset % tmpxRayEnergy = 900; % of this survey % tmpyPosition = 0.5E5; % y position of labels, delta to signal height, in axis scale % tmpyPositionTwo = 0.1E5; % optional, to shift neighouring labels up and dow % % n % % Au peaks % nappAnnotateSurvey(tmpxRayEnergy-57-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'Au5p3/2'); % nappAnnotateSurvey(tmpxRayEnergy-74-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Au5p5/2'); % nappAnnotateSurvey(tmpxRayEnergy-84-tmpxShift,tmpyPosition,dataObjs(1),'Au4f7/2'); % nappAnnotateSurvey(tmpxRayEnergy-88-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'Au4f5/2'); % nappAnnotateSurvey(tmpxRayEnergy-107-tmpxShift,tmpyPosition,dataObjs(1),'Au5s'); % nappAnnotateSurvey(tmpxRayEnergy-335-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Au4d1/2'); % nappAnnotateSurvey(tmpxRayEnergy-353-tmpxShift,tmpyPosition,dataObjs(1),'Au4d3/2'); % nappAnnotateSurvey(tmpxRayEnergy-546-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Au4p3/2'); % nappAnnotateSurvey(tmpxRayEnergy-643-tmpxShift,tmpyPosition,dataObjs(1),'Au4p1/2'); % nappAnnotateSurvey(tmpxRayEnergy-762-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Au4s'); % nappAnnotateSurvey(tmpxRayEnergy-8-tmpxShift,tmpyPosition,dataObjs(1),'AuVB'); % % usual suspects % nappAnnotateSurvey(tmpxRayEnergy-285-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'C1s'); % nappAnnotateSurvey(tmpxRayEnergy-534-tmpxShift,tmpyPosition,dataObjs(1),'O1s'); % nappAnnotateSurvey(tmpxRayEnergy-30-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'O2s'); % nappAnnotateSurvey(tmpxRayEnergy-405-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'N1s'); % nappAnnotateSurvey(tmpxRayEnergy-495-tmpxShift,tmpyPosition,dataObjs(1),'Sn3d'); % nappAnnotateSurvey(tmpxRayEnergy-691-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'F1s'); % nappAnnotateSurvey(tmpxRayEnergy-295-tmpxShift,tmpyPosition,dataObjs(1),'K2p'); % nappAnnotateSurvey(tmpxRayEnergy-380-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'K2s'); % nappAnnotateSurvey(tmpxRayEnergy-153-tmpxShift,tmpyPosition,dataObjs(1),'Si2s'); % nappAnnotateSurvey(tmpxRayEnergy-100-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Si2p'); % nappAnnotateSurvey(tmpxRayEnergy-197-tmpxShift,tmpyPosition,dataObjs(1),'Cl2p'); % nappAnnotateSurvey(tmpxRayEnergy-286-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'Sn3p'); % % Some Auger % nappAnnotateSurvey(360-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'N KLL'); % nappAnnotateSurvey(500-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'O KLL'); % % tid up % clearvars tmp* %% close all tmpDataSelection = contains(FileList.name,'007_Survey'); FileList = nappGenerateSpectra(FileList,tmpDataSelection); nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond',... 'mode','AllInOne','energyScale','kinetic'); % add text to Figure dataObjs = findobj(gcf,'-property','YData'); tmpxShift = 6; tmpxRayEnergy = 900; tmpyPosition = 0.5E5; tmpyPositionTwo = 0.1E5; % Au peaks nappAnnotateSurvey(tmpxRayEnergy-57-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'Au5p3/2'); nappAnnotateSurvey(tmpxRayEnergy-74-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Au5p5/2'); nappAnnotateSurvey(tmpxRayEnergy-84-tmpxShift,tmpyPosition,dataObjs(1),'Au4f7/2'); nappAnnotateSurvey(tmpxRayEnergy-88-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'Au4f5/2'); nappAnnotateSurvey(tmpxRayEnergy-107-tmpxShift,tmpyPosition,dataObjs(1),'Au5s'); nappAnnotateSurvey(tmpxRayEnergy-335-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Au4d1/2'); nappAnnotateSurvey(tmpxRayEnergy-353-tmpxShift,tmpyPosition,dataObjs(1),'Au4d3/2'); nappAnnotateSurvey(tmpxRayEnergy-546-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Au4p3/2'); nappAnnotateSurvey(tmpxRayEnergy-643-tmpxShift,tmpyPosition,dataObjs(1),'Au4p1/2'); nappAnnotateSurvey(tmpxRayEnergy-762-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Au4s'); nappAnnotateSurvey(tmpxRayEnergy-8-tmpxShift,tmpyPosition,dataObjs(1),'AuVB'); % usual suspects nappAnnotateSurvey(tmpxRayEnergy-285-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'C1s'); nappAnnotateSurvey(tmpxRayEnergy-534-tmpxShift,tmpyPosition,dataObjs(1),'O1s'); nappAnnotateSurvey(tmpxRayEnergy-30-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'O2s'); nappAnnotateSurvey(tmpxRayEnergy-405-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'N1s'); nappAnnotateSurvey(tmpxRayEnergy-495-tmpxShift,tmpyPosition,dataObjs(1),'Sn3d'); nappAnnotateSurvey(tmpxRayEnergy-691-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'F1s'); nappAnnotateSurvey(tmpxRayEnergy-295-tmpxShift,tmpyPosition,dataObjs(1),'K2p'); nappAnnotateSurvey(tmpxRayEnergy-380-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'K2s'); nappAnnotateSurvey(tmpxRayEnergy-153-tmpxShift,tmpyPosition,dataObjs(1),'Si2s'); nappAnnotateSurvey(tmpxRayEnergy-100-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Si2p'); nappAnnotateSurvey(tmpxRayEnergy-197-tmpxShift,tmpyPosition,dataObjs(1),'Cl2p'); nappAnnotateSurvey(tmpxRayEnergy-286-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'Sn3p'); % Some Auger nappAnnotateSurvey(360-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'N KLL'); nappAnnotateSurvey(500-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'O KLL'); % tid up clearvars tmp* %% Process data: Align sequence iterations in images % % To shift and align the kinetic energy of each sequence iteration relative % to each other, one can use % % # nappDetermineShiftXps: calculate the kinetic energy shift of each % sequence iteration of an image relative to one sequence iteration (first % is default) % # nappCopyShift: optionally copy the kinetic energy shift to other data % # nnappAlignImages: shift each sequence iterations of an image so that % the peak maxima align. %% % % % compile data % tmpDataSelection = contains(FileList.name,'67_O1s') ... % & (month(FileList.lastModifiedDatenum) == 8) ... % & (year(FileList.lastModifiedDatenum) == 2021); % % plot images % nappPlot(FileList,tmpDataSelection,'tableVariable','image'); % % align images % FileList = nappDetermineShiftXps(FileList,'tableSelection',tmpDataSelection,... % 'showFigures','off','tableVariable','image'); % FileList = nappAlignImages(FileList,'tableSelection',tmpDataSelection,... % 'tableVariable','image'); % % plot images % nappPlot(FileList,tmpDataSelection,'tableVariable','image'); %% close all clc % compile data tmpDataSelection = contains(FileList.name,'67_O1s') ... & (month(FileList.lastModifiedDatenum) == 8) ... & (year(FileList.lastModifiedDatenum) == 2021); % plot images nappPlot(FileList,tmpDataSelection,'tableVariable','image'); % align images FileList = nappDetermineShiftXps(FileList,'tableSelection',tmpDataSelection,... 'showFigures','off','tableVariable','image'); FileList = nappAlignImages(FileList,'tableSelection',tmpDataSelection,... 'tableVariable','image'); % plot images nappPlot(FileList,tmpDataSelection,'tableVariable','image'); %% Process data: Generate XPS spectra % % All sequence iterations of an image are summed or the mean of all % sequence iterations is calculated. The following command calculates the % average of all sequence iterations from the filtered files in the % FileList table. The spectrum based on the mean is saved in the column % 'spectrum_countsPerSecond'. %% % % FileList = nappGenerateSpectra(FileList,tmpDataSelection); % %% Process data: Generate NEXAFS spectra % % % All Auger spectra of an image are summed. Options include to sum the % data with the energy interval of the aquisition, or to use the trapz % function to normalise to 1 eV data spacing. The NEXAFS spectrua are % always saved in the column 'spectrum_counts'. %% % % FileList = nappGenerateSpectra(FileList,'tableSelection',tmpDataSelection,'mode','sum'); % %% close all clc tmpDataSelection = contains(FileList.name, '0063_20200824_042852_O_K_edge'); % Sum Auger-Meitner Spectrum FileList = nappGenerateSpectra(FileList,'tableSelection',tmpDataSelection,'mode','sum'); % Plot nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay','mode','OneEach'); %% % % FileList = nappGenerateSpectra(FileList,tmpDataSelection); % %% Process data: Align XPS spectra to background % % To align the spectra to a background the function nappBacktround can % be used. Options include to compute the mean or a linear regression. % Here, we calculate the mean between 367 and 370 eV. %% % % FileList = nappBackground(FileList,367,370,'tableSelection',tmpDataSelection,'... % energyScale','kinetic','mode','mean'); % %% close all clc tmpDataSelection = matches(FileList.sample,'Ice with N2')... & ~contains(FileList.sample,'(bad data)')... & contains(FileList.name,'O1s') & FileList.xRayEkinRange_eV(:,1) == 900 ... & FileList.scientaPassEnergy_eV == 50 ... & (month(FileList.lastModifiedDatenum) == 2) ... & (year(FileList.lastModifiedDatenum) == 2022) ... & (day(FileList.lastModifiedDatenum) >= 27); FileList = nappGenerateSpectra(FileList,tmpDataSelection); FileList = nappBackground(FileList,367,370,'tableSelection',tmpDataSelection,'energyScale','kinetic',... 'mode','mean'); % plot spectra nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond',... 'mode','AllInOne','energyScale','kinetic'); %% Process data: Align NEXAFS spectra to background % % To align the spectra to a background the function nappBacktround can % be used. Options include to compute the mean or a linear regression. % Here, we calculate the mean between 522 and 525 eV xRay energy. %% % % FileList = nappBackground(FileList,522,525,'tableSelection',tmpDataSelection,... % 'tableVariable','spectrum_counts','energyScale','xRay','mode','mean'); % %% close all clc tmpDataSelection = contains(FileList.name, '0063_20200824_042852_O_K_edge'); % Sum Auger-Meitner Spectrum FileList = nappGenerateSpectra(FileList,'tableSelection',tmpDataSelection,'mode','sum'); % Background FileList = nappBackground(FileList,522,525,'tableSelection',tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay',... 'mode','mean'); % Plot nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts','energyScale','xRay','mode','OneEach'); %% Process data: Gauss peak fit % % Gauss fitting can be used to determine area, width, and position of PE % peaks. nappFitGaussXps de-convolutes the PE signal using 4 features. The % fits can be constrained by % % * 'widthPosition' (Default): With of all peaks is identical. Position of % peaks 2-3 is set relative to peak 1. % * 'position': Position of peaks 2-3 is set relative to peak 1. % * 'width': all peaks have same width % * 'unconstrained': Each gauss peak is fitted independent. % * 'unconstrainedAndWidthPosition': One unconstrained peak #3 (for gas phase % feature) and 4 peaks constrained in width and/or position % % % The function needs fit parameters as input, such as min and max peak % area, width, and position; initial values for fitting; and the spectrum % range. % % * spectrum range: define the region of the PE spectrum used for fitting % (plus and minus from peak 1 position). % % position of peak 2-4 are relative to peak 1, that of peak 1 absolute % (either in binding or kinetic energy scale) % * If you are only interested in less than 4 peaks, choose small dummy % constrains for those peaks you don't want to fit. % %% % % initial fit parameters % tmpFitParameters.peakArea = [1E4 5E3 0.1 0.1]; % tmpFitParameters.peakWidth = [2.0 2.0 0.1 0.1]; % tmpFitParameters.peakPos = [363 -1 -2 -3]; % % lower bonds % tmpFitParameters.peakAreaLowerBond = [1E3 5E3 0.1 0.1]; % tmpFitParameters.peakWidthLowerBond = [2.0 2.0 0.1 0.1]; % tmpFitParameters.peakPosLowerBond = 361; % % upper bonds % tmpFitParameters.peakAreaUpperBond = [1E6 10E4 0.1 0.1]; % tmpFitParameters.peakWidthUpperBond = [3.0 2.0 0.1 0.1]; % tmpFitParameters.peakPosUpperBond = 365; % % spectrum range % tmpFitParameters.backgroundRange = [5 5]; % % % „position“ mode % tmpFitParameters.peakArea = [abs#1 abs#2 abs#3 abs#4]; % tmpFitParameters.peakWidth = [abs#1 abs#2 abs#3 abs#4]; % tmpFitParameters.peakPos = [abs#1 rel#2 rel#3 rel#4]; % % tmpFitParameters.peakAreaUpperBond = [#1 #2 #3 #4]; % tmpFitParameters.peakWidthUpperBond = [#1 #2 #3 #4]; % tmpFitParameters.peakPosUpperBond = #1; % tmpFitParameters.peakAreaLowerBond = [#1 #2 #3 #4]; % tmpFitParameters.peakWidthLowerBond = [#1 #2 #3 #4]; % tmpFitParameters.peakPosLowerBond = #1; % % % % „unconstrained“ mode % tmpFitParameters.peakArea = [abs#1 abs#2 abs#3 abs#4]; % tmpFitParameters.peakWidth = [abs#1 abs#2 abs#3 abs#4]; % tmpFitParameters.peakPos = [abs#1 abs#2 abs#3 abs#4]; % % tmpFitParameters.peakAreaUpperBond = [#1 #2 #3 #4]; % tmpFitParameters.peakWidthUpperBond = [#1 #2 #3 #4]; % tmpFitParameters.peakPosUpperBond = [#1 #2 #3 #4]; % tmpFitParameters.peakAreaLowerBond = [#1 #2 #3 #4]; % tmpFitParameters.peakWidthLowerBond = [#1 #2 #3 #4]; % tmpFitParameters.peakPosLowerBond = [#1 #2 #3 #4]; % % % % „ widthPosition“ mode % tmpFitParameters.peakArea = [abs#1 abs#2 abs#3 abs#4]; % tmpFitParameters.peakWidth = [abs#1-#4]; % tmpFitParameters.peakPos = [abs#1 rel#2 rel#3 rel#4]; % % tmpFitParameters.peakAreaUpperBond = [#1 #2 #3 #4]; % tmpFitParameters.peakWidthUpperBond = #1-#4; % tmpFitParameters.peakPosUpperBond = #1; % tmpFitParameters.peakAreaLowerBond = [#1 #2 #3 #4]; % tmpFitParameters.peakWidthLowerBond = #1-#4; % tmpFitParameters.peakPosLowerBond = #1; % % % „ width“ mode % tmpFitParameters.peakArea = [abs#1 abs#2 abs#3 abs#4]; % tmpFitParameters.peakWidth = [abs#1-#4]; % tmpFitParameters.peakPos = [abs#1 abs#2 abs#3 abs#4]; % % tmpFitParameters.peakAreaUpperBond = [#1 #2 #3 #4]; % tmpFitParameters.peakWidthUpperBond = #1-#4; % tmpFitParameters.peakPosUpperBond = [#1 #2 #3 #4]; % tmpFitParameters.peakAreaLowerBond = [#1 #2 #3 #4]; % tmpFitParameters.peakWidthLowerBond = #1-#4; % tmpFitParameters.peakPosLowerBond = [#1 #2 #3 #4]; % % % % „ unconstrainedAndWidthPosition" mode (novel: rel distance fit parameter) % tmpFitParameters.peakArea = [abs#1 abs#2 abs#3 abs#4 abs#5]; % tmpFitParameters.peakWidth = [abs#1,2,4,5 abs#3]; % tmpFitParameters.peakPos = [rel#1 abs#2 abs#3 abs#4 abs#5]; % % tmpFitParameters.peakAreaUpperBond = [#1 #2 #3 #4 #5]; % tmpFitParameters.peakWidthUpperBond = [#1,2,4,5 #3]; % tmpFitParameters.peakPosUpperBond = [#1 #2 #3 #4 #5]; % tmpFitParameters.peakAreaLowerBond = [#1 #2 #3 #4]; % tmpFitParameters.peakWidthLowerBond = [#1,2,4,5 #3]; % tmpFitParameters.peakPosLowerBond = [#1 #2 #3 #4]; % % % FileList = nappFitGaussXps(FileList,tmpDataSelection,tmpFitParameters,'tableSelection',tmpDataSelection,... % 'energyScale','kinetic','mode','position','showFigures','on'); %% % % The fit results are written to the data table. Peak position is only % written to the table if in binding energy mode. Further, results are % plotted to the command line and fits are shown in graphs: %% close all tmpDataSelection = matches(FileList.sample,'Ice with N2')... & ~contains(FileList.sample,'(bad data)')... & contains(FileList.name,'O1s') & FileList.xRayEkinRange_eV(:,1) == 900 ... & FileList.scientaPassEnergy_eV == 50 ... & (month(FileList.lastModifiedDatenum) == 2) ... & (year(FileList.lastModifiedDatenum) == 2022) ... & (day(FileList.lastModifiedDatenum) >= 27); FileList = nappBackground(FileList,367,370,'tableSelection',tmpDataSelection,'energyScale','kinetic',... 'mode','mean'); tmpFitParameters.peakArea = [1E4 5E3 0.1 0.1]; tmpFitParameters.peakWidth = [2.0 2.0 0.1 0.1]; tmpFitParameters.peakPos = [363 -1 -2 -3]; % position of peak 2-4 are relative to peak 1 tmpFitParameters.peakAreaLowerBond = [1E3 5E3 0.1 0.1]; tmpFitParameters.peakWidthLowerBond = [2.0 2.0 0.1 0.1]; tmpFitParameters.peakPosLowerBond = 361; tmpFitParameters.peakAreaUpperBond = [1E6 10E4 0.1 0.1]; tmpFitParameters.peakWidthUpperBond = [3.0 2.0 0.1 0.1]; tmpFitParameters.peakPosUpperBond = 365; tmpFitParameters.backgroundRange = [5 5]; FileList = nappFitGaussXps(FileList,tmpDataSelection,tmpFitParameters,'tableSelection',tmpDataSelection,... 'energyScale','kinetic','mode','position','showFigures','on'); %% Process data: Norm spectra % % To normalise spectra, nappScaleToArea can be used. A typical example is % to normalise C1s to the O1s peak area to compensate for changes in the % working distance. The function uses the peakArea table column, thus % nappFitGaussXps needs to run first. Results are written to the table % variable spectrum_countsNorm (as the unit is no longer countsPerSecond). % To normalise C1s to the O1s peak area, select C1s spectra using a logical % (tmpDataSelection), and choose C1s for regionOld and O1s for regionNew: % % * regionOld: C1s (default) or O1s - region that will be normalised % * regionNew: O1s (default) or C1s - peak area that will be used to normalise % %% % % FileList = nappScale(FileList,tmpDataSelection,'regionOld','C1s','regionNew','O1s'); % nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsNorm'); % %% close all clc tmpDataSelection = matches(FileList.sample,'Ice with N2')... & ~contains(FileList.sample,'(bad data)')... & contains(FileList.name,'O1s') & FileList.xRayEkinRange_eV(:,1) == 900 ... & FileList.scientaPassEnergy_eV == 50 ... & (month(FileList.lastModifiedDatenum) == 2) ... & (year(FileList.lastModifiedDatenum) == 2022) ... & (day(FileList.lastModifiedDatenum) >= 27); % plot spectra nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond',... 'mode','AllInOne','energyScale','kinetic'); % scale to area FileList = nappScale(FileList,tmpDataSelection,'regionOld','O1s','regionNew','O1s'); FileList = nappBackground(FileList,367,370,'tableSelection',tmpDataSelection,'energyScale','kinetic',... 'mode','mean','tableVariable','spectrum_countsNorm'); % plot spectra nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsNorm',... 'mode','AllInOne','energyScale','kinetic'); tmpDataSelection = matches(FileList.sample,'Ice with N2')... & ~contains(FileList.sample,'(bad data)')... & contains(FileList.name,'C1s') & FileList.xRayEkinRange_eV(:,1) == 900 ... & FileList.scientaPassEnergy_eV == 50 ... & (month(FileList.lastModifiedDatenum) == 2) ... & (year(FileList.lastModifiedDatenum) == 2022) ... & (day(FileList.lastModifiedDatenum) >= 27); % Generate spectra FileList = nappGenerateSpectra(FileList,tmpDataSelection); % plot spectra nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond',... 'mode','AllInOne','energyScale','kinetic'); % scale to area FileList = nappScale(FileList,tmpDataSelection,'regionOld','C1s','regionNew','O1s'); FileList = nappBackground(FileList,615,617,'tableSelection',tmpDataSelection,'energyScale','kinetic',... 'mode','mean','tableVariable','spectrum_countsNorm'); % plot spectra nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsNorm'); %% Process data: Binding energy scale % % To calculate the binding energy, you need to % % # nappDetermineShiftXps: calculate the kinetic energy shift relative to a reference value % # nappCopyShift: optionally copy the kinetic energy shift to other data % # nappBindingEnergyXps: calculate the binding energy based on the kinetic % energy shift either determined relative to a reference or copied to the % individual data. % % The following example shows how the kinetic energy shift is calculated % based on selected O1s spectra relative to 535 eV, copied to the C1s data % with the same file number, and finally the binding energy of the C1s data is % calculated (based on the observed shift of the O1s of the same sequence % run) and plotted %% % % close all % % generate spectra for C1s and O1s % tmpDataSelection = matches(FileList.sample,'Ice with N2')... % & ~contains(FileList.sample,'(bad data)')... % & (contains(FileList.name,'O1s') | contains(FileList.name,'C1s'))... % & FileList.xRayEkinRange_eV(:,1) == 900 ... % & FileList.scientaPassEnergy_eV == 50 ... % & (month(FileList.lastModifiedDatenum) == 2) ... % & (year(FileList.lastModifiedDatenum) == 2022) ... % & (day(FileList.lastModifiedDatenum) >= 27); % FileList = nappGenerateSpectra(FileList,tmpDataSelection); % FileList = nappBackground(FileList,367,370,'tableSelection',tmpDataSelection,'energyScale','kinetic',... % 'mode','mean'); % % determine shift of O1s % tmpDataSelection = matches(FileList.sample,'Ice with N2')... % & ~contains(FileList.sample,'(bad data)')... % & contains(FileList.name,'O1s')... % & FileList.xRayEkinRange_eV(:,1) == 900 ... % & FileList.scientaPassEnergy_eV == 50 ... % & (month(FileList.lastModifiedDatenum) == 2) ... % & (year(FileList.lastModifiedDatenum) == 2022) ... % & (day(FileList.lastModifiedDatenum) >= 27); % FileList = nappDetermineShiftXps(FileList,'tableSelection',tmpDataSelection,... % 'showFigures','off','tableVariable','spectrum_countsPerSecond','binEnReference',533); % % copy shift from O1s to C1s % FileList = nappCopyShift(FileList,tmpDataSelection,'energyScale','binding'); % % calculate binding energy of these C1s % tmpDataSelection = matches(FileList.sample,'Ice with N2')... % & ~contains(FileList.sample,'(bad data)')... % & contains(FileList.name,'C1s') & FileList.xRayEkinRange_eV(:,1) == 900 ... % & FileList.scientaPassEnergy_eV == 50 ... % & (month(FileList.lastModifiedDatenum) == 2) ... % & (year(FileList.lastModifiedDatenum) == 2022) ... % & (day(FileList.lastModifiedDatenum) >= 27); % FileList = nappBindingEnergyXps(FileList,'tableSelection',tmpDataSelection); % % plot C1s spectra % nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond',... % 'mode','AllInOne','energyScale','kinetic'); % nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond',... % 'mode','AllInOne','energyScale','binding'); %% % close all tmpDataSelection = matches(FileList.sample,'Ice with N2')... & ~contains(FileList.sample,'(bad data)')... & (contains(FileList.name,'O1s') | contains(FileList.name,'C1s'))... & FileList.xRayEkinRange_eV(:,1) == 900 ... & FileList.scientaPassEnergy_eV == 50 ... & (month(FileList.lastModifiedDatenum) == 2) ... & (year(FileList.lastModifiedDatenum) == 2022) ... & (day(FileList.lastModifiedDatenum) >= 27); FileList = nappGenerateSpectra(FileList,tmpDataSelection); FileList = nappBackground(FileList,367,370,'tableSelection',tmpDataSelection,'energyScale','kinetic',... 'mode','mean'); % determine shift of O1s tmpDataSelection = matches(FileList.sample,'Ice with N2')... & ~contains(FileList.sample,'(bad data)')... & contains(FileList.name,'O1s')... & FileList.xRayEkinRange_eV(:,1) == 900 ... & FileList.scientaPassEnergy_eV == 50 ... & (month(FileList.lastModifiedDatenum) == 2) ... & (year(FileList.lastModifiedDatenum) == 2022) ... & (day(FileList.lastModifiedDatenum) >= 27); FileList = nappDetermineShiftXps(FileList,'tableSelection',tmpDataSelection,... 'showFigures','off','tableVariable','spectrum_countsPerSecond','binEnReference',533); % copy shift from O1s to C1s FileList = nappCopyShift(FileList,tmpDataSelection,'energyScale','binding'); % calculate binding energy of these C1s tmpDataSelection = matches(FileList.sample,'Ice with N2')... & ~contains(FileList.sample,'(bad data)')... & contains(FileList.name,'C1s') & FileList.xRayEkinRange_eV(:,1) == 900 ... & FileList.scientaPassEnergy_eV == 50 ... & (month(FileList.lastModifiedDatenum) == 2) ... & (year(FileList.lastModifiedDatenum) == 2022) ... & (day(FileList.lastModifiedDatenum) >= 27); FileList = nappBindingEnergyXps(FileList,'tableSelection',tmpDataSelection); % plot C1s spectra nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond',... 'mode','AllInOne','energyScale','kinetic'); nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond',... 'mode','AllInOne','energyScale','binding'); %% Process data: Combine spectra % % To get better statistics (signal-to-noise), repeated measurements can be % added or averaged into one spectrum. The results are written into a % matrix with energy in column 1, counts in column2, and standard deviation % in column 3 (only for mean). So, the nappFunctions can no longer be used % for this data format. %% % % tmpDataSelection = contains(FileList.name,'C1s')... % & contains(FileList.sample,'MgO ice AA')... % & ~endsWith(FileList.sample,'(bad data)')... % & FileList.sampleTemp_dC >= -26 & FileList.sampleTemp_dC <= -24; % MgO_C1s_Warm = nappCombineSpectra(FileList,'tableRow',1,... % 'tableSelection',tmpDataSelection,'tableVariable',... % 'spectrum_countsPerSecond','EnergyScale','binding','mode','average'); %% close all tmpDataSelection = contains(FileList.name,'C1s')... & contains(FileList.sample,'MgO ice AA')... & ~endsWith(FileList.sample,'(bad data)')... & FileList.sampleTemp_dC >= -26 & FileList.sampleTemp_dC <= -24; FileList = nappGenerateSpectra(FileList,tmpDataSelection); MgO_C1s_Warm = nappCombineSpectra(FileList,'tableRow',1,... 'tableSelection',tmpDataSelection,'tableVariable',... 'spectrum_countsPerSecond','EnergyScale','kinetic','mode','average'); figure % axes('Parent',gcf,'XDir','reverse') hold(gca,'on'); plot(MgO_C1s_Warm(:,1),MgO_C1s_Warm(:,2),'--','linewidth',2) title('acetic acid adsorption') legend({'ice on MgO, -25°C'},... 'location','SouthOutside','Orientation','horizontal') xlim([704,714]); xlabel('kinetic energy [eV]') ylabel('PE [counts per second]') %% function [myColorMap, PsiFarbe] = initializeMatlab %initializeMatlab Sets NappIce specific settings % Adds Napp files to path and defines file locations for mac, windows, % and Matlab online (which runs on unix) % change working directory path = matlab.desktop.editor.getActiveFilename; [filepath,~,~] = fileparts(path); cd(filepath); % The fitting routines writes quite a lot of feedback and warnings. I shut them off. warning('off','all') warning off backtrace warning off verbose % Functions and helper files path: if ismac % add Napp files to path addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/Add-Ons'); addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/nappIce'); elseif ispc % add Napp files to path addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/Add-Ons'); addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/nappIce'); elseif isunix % add Napp files to path addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/Add-Ons'); addpath('/Users/bartels-rausch/SwitchDrive/PSI_Matlab/nappIce'); end % Color maps myColorMap.red = colormap(autumn(7)); myColorMap.blue = colormap(winter(7)); % 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