Added Example Matlab script with most common during beamtime processing
This commit is contained in:
1 parent
53dd8c6080
commit
bbfab45787
7 files changed
+658
-22
No files matched your search
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 13 MiB |
@@ -0,0 +1,131 @@
|
||||
%% How do I ....
|
||||
clc;clear all;close all
|
||||
load FileList.mat
|
||||
|
||||
%% ... quick-and-dirty normalize
|
||||
%
|
||||
% Normalize counts per second to a reference intensity? You need to plot the
|
||||
% two spectra and use the cursor to read the intensities from the figures.
|
||||
% Then change the spectra intensities directly in the table as shown here:
|
||||
%
|
||||
% Do not save the FileList. This way you can reload it from the MAT file to
|
||||
% start fresh.
|
||||
close all;clc
|
||||
tmpDataSelection = matches(FileList.name,"0146146_Cl2p_850eV.ibw");
|
||||
FileList = nappGenerateSpectra(FileList,tmpDataSelection);
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond','mode','OneEach');
|
||||
xlim([647 652])
|
||||
FileList(tmpDataSelection,:).spectrum_countsPerSecond{:} = FileList(tmpDataSelection,:).spectrum_countsPerSecond{:} .* 22335./39687;
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond','mode','OneEach');
|
||||
xlim([647 652])
|
||||
ylabel("counts [norm to Al]")
|
||||
legend
|
||||
distFig
|
||||
|
||||
%% ... quick-and-dirty shift spectra
|
||||
%
|
||||
% If you do not want to generate the binding-energy scale using the
|
||||
% nappMATLAB function.
|
||||
close all;clc
|
||||
% Select your data based on the filename
|
||||
tmpDataSelection = startsWith(FileList.name, "0191191_O1s_VB_525eV");
|
||||
% List the selected files in the command window
|
||||
disp(FileList(tmpDataSelection,{'name','lastModifiedDatestr','scientaPassEnergy_eV'}))
|
||||
% Generate spectra
|
||||
FileList = nappGenerateSpectra(FileList,tmpDataSelection);
|
||||
% Plot in kinetic-energy mode
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond','mode','AllInOne','energyScale','kinetic');
|
||||
% Apply the shift to kinetic energy manually and plot
|
||||
FileList(tmpDataSelection,:).scientaEkin_eV{:} = FileList(tmpDataSelection,:).scientaEkin_eV{:}-20;
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond','mode','AllInOne','energyScale','kinetic');
|
||||
distFig
|
||||
|
||||
%% ... remove a sweep (sequence iteration) from data
|
||||
close all; clc
|
||||
% Remove sweep 3:
|
||||
tmpDataSelection = contains(FileList.name,'0146146_Al2p_850eV.ibw');
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image')
|
||||
FileList(tmpDataSelection,:).image{:}(:,3)=[];
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image')
|
||||
distFig
|
||||
|
||||
%% ... remove several sweeps
|
||||
close all; clc
|
||||
tmpDataSelection = contains(FileList.name,'0146146_Al2p_850eV.ibw');
|
||||
% Remove sweeps 5–9
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image')
|
||||
FileList(tmpDataSelection,:).image{:}(:,5:9)=[];
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image')
|
||||
distFig
|
||||
|
||||
%% ... correct beamline offset
|
||||
% This will correct 1.6 eV on the X-ray energies, which is particularly
|
||||
% important for NEXAFS data. One can also do this on selected data only.
|
||||
FileList.xRayEkin_eV = cellfun(@(x) x+1.6,FileList.xRayEkin_eV,'UniformOutput',false);
|
||||
|
||||
%% ... on-the-fly shift data in a figure
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& contains(FileList.name,"O_Kedge_Resonant") ...
|
||||
& contains(FileList.name,"0025");
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image','mode','AugerMeitner','AugerMeitnerEnergies',[525,545,550]);
|
||||
hax = gca;
|
||||
hax.XDir = 'reverse';
|
||||
xlabel('Auger-Meitner binding energy [eV]');
|
||||
% Shift data (same works in Y direction)
|
||||
dataObjs = findobj(gcf,'-property','YData');
|
||||
dataObjs(1).XData = dataObjs(1).XData -10;
|
||||
dataObjs(2).XData = dataObjs(2).XData +10;
|
||||
dataObjs(3).XData = dataObjs(3).XData +20;
|
||||
|
||||
%% ... on-the-fly smooth data in a figure
|
||||
clc;close all
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& contains(FileList.name,"O_Kedge_Resonant") ...
|
||||
& contains(FileList.name,"0025");
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image','mode','AugerMeitner','AugerMeitnerEnergies',[525,545,550]);
|
||||
hax = gca;
|
||||
hax.XDir = 'reverse';
|
||||
xlabel('Auger-Meitner binding energy [eV]');
|
||||
dataObjs = findobj(gcf,'-property','YData');
|
||||
y = dataObjs(1).YData;
|
||||
dataObjs(1).YData = smoothdata(y ,'sgolay',10);
|
||||
y = dataObjs(2).YData;
|
||||
dataObjs(2).YData = smoothdata(y ,'sgolay',10);
|
||||
y = dataObjs(3).YData;
|
||||
dataObjs(3).YData = smoothdata(y ,'sgolay',10);
|
||||
|
||||
%% ... on-the-fly remove data from a figure
|
||||
clc;close all
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& contains(FileList.name,"O_Kedge_Resonant") ...
|
||||
& contains(FileList.name,"0025");
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image','mode','AugerMeitner','AugerMeitnerEnergies',[525,545,550]);
|
||||
hax = gca;
|
||||
hax.XDir = 'reverse';
|
||||
xlabel('Auger-Meitner binding energy [eV]');
|
||||
|
||||
dataObjs = findobj(gcf,'-property','YData');
|
||||
delete(dataObjs(1))
|
||||
legend('545','550');
|
||||
|
||||
%% ... on-the-fly change colors in a figure
|
||||
clc;close all
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& contains(FileList.name,"O_Kedge_Resonant") ...
|
||||
& contains(FileList.name,"0025");
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image','mode','AugerMeitner','AugerMeitnerEnergies',[525,545,550]);
|
||||
hax = gca;
|
||||
hax.XDir = 'reverse';
|
||||
xlabel('Auger-Meitner binding energy [eV]');
|
||||
|
||||
dataObjs = findobj(gcf,'-property','YData');
|
||||
dataObjs(2).Color = [184 184 185]/255;
|
||||
dataObjs(3).Color = [58 162 190]/255;
|
||||
@@ -0,0 +1,58 @@
|
||||
%% Fitting spectra with Gauss
|
||||
%
|
||||
% The nappFitGaussXps.m allows to set-up your own model reflecting the
|
||||
% physics of your peaks. Here is an example. Check the documentation. This
|
||||
% needs some test-and try.
|
||||
|
||||
%% SES #0157 Ar2p (gas-phase reference)
|
||||
%
|
||||
% * Core level: Ar 2p, file 0157157_Ar2p_850eV.
|
||||
% * Model: Gaussian spin–orbit doublet, splitting fixed at 2.2 eV, area ratio 0.5.
|
||||
% * Peak 1 area: initial 1e5; lower bound 10; upper bound Inf.
|
||||
% * Peak 1 width: initial 0.5 eV; bounds 0.5–3 eV.
|
||||
% * Peak 1 position: initial 603 eV; bounds 602–604 eV.
|
||||
% * Background: linear, 8 eV window below and 5 eV above the peak.
|
||||
|
||||
clc
|
||||
close all
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& ~contains(FileList.name,"Survey") ...
|
||||
& ~contains(FileList.name,"Resonant") ...
|
||||
& startsWith(FileList.name,"0157") ...
|
||||
& contains(FileList.name, "Ar2p");
|
||||
FileList = nappGenerateSpectra(FileList,tmpDataSelection);
|
||||
disp(FileList(tmpDataSelection,{'name','lastModifiedDatestr','scientaPassEnergy_eV'}))
|
||||
|
||||
% Defining the mode as 'widthPositionAreaRatio', the first element of the input
|
||||
% parameters defines the first peak (initial value, upper and lower bond for
|
||||
% fitting) in absolute terms. The second element is then the area ratio
|
||||
% relative to the first, and the position relative to the first.
|
||||
|
||||
tmpFitParameters.peakArea = [1e5 0.5 0.1 0.1 0.1] ;
|
||||
tmpFitParameters.peakWidth = 0.5;
|
||||
tmpFitParameters.peakPos = [603 -2.2 10 10 10];
|
||||
|
||||
tmpFitParameters.peakAreaUpperBond = [Inf 0.5 0.1 0.1 0.1];
|
||||
tmpFitParameters.peakWidthUpperBond = [3 NaN NaN NaN NaN];
|
||||
tmpFitParameters.peakPosUpperBond = [604 -2.2 10 10 10];
|
||||
|
||||
tmpFitParameters.peakAreaLowerBond = [10 0.5 0.1 0.1 0.1];
|
||||
tmpFitParameters.peakWidthLowerBond = [0.5 NaN NaN NaN NaN];
|
||||
tmpFitParameters.peakPosLowerBond = [602 -2.2 0.1 0.1 0.1];
|
||||
% spectrum range
|
||||
tmpFitParameters.backgroundRange = [8 5];
|
||||
|
||||
FileList= nappFitGaussXps(FileList,tmpFitParameters,tmpDataSelection,...
|
||||
'energyScale','kinetic','mode','widthPositionAreaRatio','showFigures','on');
|
||||
|
||||
%% RESULTS – SES 0157 Ar2p (gas-phase reference)
|
||||
% The gas‑phase Ar2p reference is well described by the doublet: peak 1 at
|
||||
% 603.0 eV and peak 2 at 600.8 eV (FWHM ≈ 1.2 eV, width 1.0 eV) match both
|
||||
% the height and the base of the experimental lines. The residuals are very small and essentially
|
||||
% structureless over the full fit range, indicating that, in contrast to
|
||||
% the Cl2p fits, a simple Gaussian doublet provides an excellent and
|
||||
% internally consistent description of the Ar2p line shape.
|
||||
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
%% Generate Spectra
|
||||
%
|
||||
% Here we plot all spectra and all regions to confirm that we get what we
|
||||
% need.
|
||||
%
|
||||
% This file shows some typical out-of-the-box examples.
|
||||
|
||||
%% Start fresh
|
||||
clc
|
||||
close all
|
||||
clearvars
|
||||
|
||||
%% Import Data
|
||||
%
|
||||
% This was generated by importData.m. You can either force that it runs
|
||||
% again before this script runs (preferred, ensures you always have recent
|
||||
% data in MATLAB's data table) or load the FileList.
|
||||
run('importData.m')
|
||||
% load("FileList.mat","FileList")
|
||||
|
||||
%% Plot a Survey
|
||||
for ii = 1
|
||||
%% Start fresh
|
||||
close all
|
||||
clc
|
||||
|
||||
%% Select data
|
||||
|
||||
% It is convenient to add date and year of the beamtime. This ensures you
|
||||
% can use the code also when you work with data from several beamtimes
|
||||
% (indexing of the files starts with 0 for each beamtime by default).
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& contains(FileList.name,"Survey") ...
|
||||
& (contains(FileList.name,"128"));
|
||||
% Always ensure that you select the spectra you intended.
|
||||
disp(FileList(tmpDataSelection,{'name','lastModifiedDatestr'}))
|
||||
|
||||
%% Generate spectrum and plot
|
||||
FileList = nappGenerateSpectra(FileList,tmpDataSelection);
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond','mode','OneEach');
|
||||
|
||||
%% Add annotation to the figure
|
||||
%
|
||||
% In a survey, we usually want to identify all peaks. Here, based on
|
||||
% binding energies from the literature and a shift, we add common regions:
|
||||
%
|
||||
% **Note that the binding energies are rough estimates – to use this further
|
||||
% we need to confirm them and add the source/reference.**
|
||||
dataObjs = findobj(gcf,'-property','YData');
|
||||
tmpxShift = 7;
|
||||
tmpxRayEnergy = 850;
|
||||
tmpyPosition = 0.5E5;
|
||||
tmpyPositionTwo = 0.8E5;
|
||||
|
||||
% 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-271-tmpxShift,tmpyPosition,dataObjs(1),'Cl2s');
|
||||
nappAnnotateSurvey(tmpxRayEnergy-286-tmpxShift,tmpyPosition-tmpyPositionTwo,dataObjs(1),'Sn3p');
|
||||
|
||||
% Clay
|
||||
%nappAnnotateSurvey(tmpxRayEnergy-351-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Ca2p');
|
||||
%nappAnnotateSurvey(tmpxRayEnergy-347-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Ca2p');
|
||||
%nappAnnotateSurvey(tmpxRayEnergy-440-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Ca2s');
|
||||
%nappAnnotateSurvey(tmpxRayEnergy-34-tmpxShift,tmpyPosition+tmpyPosition,dataObjs(1),'Ca3s');
|
||||
%nappAnnotateSurvey(tmpxRayEnergy-26-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Ca3p');
|
||||
%nappAnnotateSurvey(tmpxRayEnergy-297-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'K2p');
|
||||
%nappAnnotateSurvey(tmpxRayEnergy-294-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'K2p');
|
||||
%nappAnnotateSurvey(tmpxRayEnergy-35-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'K3s');
|
||||
%nappAnnotateSurvey(tmpxRayEnergy-19-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'K3p');
|
||||
nappAnnotateSurvey(tmpxRayEnergy-118-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Al');
|
||||
nappAnnotateSurvey(tmpxRayEnergy-72.5-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Al');
|
||||
|
||||
% Ar gas
|
||||
nappAnnotateSurvey(tmpxRayEnergy-245-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Ar2p');
|
||||
nappAnnotateSurvey(tmpxRayEnergy-323-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Ar2s');
|
||||
nappAnnotateSurvey(tmpxRayEnergy-12-tmpxShift,tmpyPosition+tmpyPositionTwo,dataObjs(1),'Ar3p');
|
||||
|
||||
% Some Auger
|
||||
nappAnnotateSurvey(363,tmpyPosition-tmpyPositionTwo,dataObjs(1),'N KLL');
|
||||
nappAnnotateSurvey(203,tmpyPosition-tmpyPositionTwo,dataObjs(1),'Ar LMN');
|
||||
nappAnnotateSurvey(500,tmpyPosition-tmpyPositionTwo,dataObjs(1),'O KLL');
|
||||
end
|
||||
|
||||
%% Plot NEXAFS & Resonant Data
|
||||
%
|
||||
% You can plot images (raw data from SES) without generating the spectra.
|
||||
% (You can also first generate the spectra, but to plot images the spectra
|
||||
% are not needed.)
|
||||
for ii = 1
|
||||
%% Start fresh
|
||||
clc; close all
|
||||
|
||||
%% Select data
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& contains(FileList.name,"O_Kedge_Resonant") ...
|
||||
& contains(FileList.name,"0025");
|
||||
% Always ensure that you select the spectra you intended.
|
||||
disp(FileList(tmpDataSelection,{'name','lastModifiedDatestr'}))
|
||||
|
||||
%% Plot images
|
||||
|
||||
% This one shows x, y in energy scales (data were interpolated).
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image',...
|
||||
'mode','OneEach');
|
||||
% This one shows sweeps (original data).
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image','energyScale','sweep');
|
||||
|
||||
%% Plot selected Auger-Meitner
|
||||
%
|
||||
% This plots the electron intensity vs. kinetic energy for chosen X-ray
|
||||
% energies (directly from the image).
|
||||
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& contains(FileList.name,"O_Kedge_Resonant") ...
|
||||
& contains(FileList.name,"0025");
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image','mode','AugerMeitner','AugerMeitnerEnergies',[525,545,550]);
|
||||
% It also shows an example of how the current plot can be edited manually
|
||||
% after its generation by nappPlot.
|
||||
hax = gca;
|
||||
hax.XDir = 'reverse';
|
||||
xlabel('Auger-Meitner binding energy [eV]');
|
||||
|
||||
%% Plot image interactive
|
||||
%
|
||||
% Use the mouse: click once in the image, then the Auger-Meitner and NEXAFS will
|
||||
% follow the mouse position.
|
||||
|
||||
% Select data (Nov 2025, O_Kedge resonant, and file number 25):
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& contains(FileList.name,"O_Kedge_Resonant") ...
|
||||
& contains(FileList.name,"0025");
|
||||
% Plot the selected data in an interactive figure:
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image','mode','interactive');
|
||||
|
||||
%% Generate spectra and plot
|
||||
|
||||
FileList = nappGenerateSpectra(FileList,tmpDataSelection);
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_counts',...
|
||||
'mode','OneEach');
|
||||
%% arrange figures
|
||||
distFig
|
||||
end
|
||||
|
||||
%% Plot iterations
|
||||
for ii = 1
|
||||
%% Select your data
|
||||
%
|
||||
% You can change the plotStep to show fewer iterations (for example 2 for every second one).
|
||||
% However, the total number of sequence iterations needs to be a multiple of
|
||||
% that factor. This is nice to follow a signal with time, e.g. upon dosing.
|
||||
% It requires that each sequence iteration has long enough dwell time and
|
||||
% iterations to give a signal with decent S/N.
|
||||
|
||||
%% Select data
|
||||
close all; clc
|
||||
tmpDataSelection = startsWith(FileList.name, "0191191_O1s_VB_525eV");
|
||||
% List the selected files in the command window.
|
||||
disp(FileList(tmpDataSelection,{'name','lastModifiedDatestr','scientaPassEnergy_eV'}))
|
||||
|
||||
%% Plot the iterations
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','image','mode','iterations','plotStep',6);
|
||||
|
||||
%% Modify the top figure
|
||||
legend
|
||||
distFig
|
||||
end
|
||||
|
||||
%% Look at all regions
|
||||
%
|
||||
% To confirm you see what you expect or to change the experimental settings
|
||||
% if not.
|
||||
|
||||
for ii = 1
|
||||
%% Start fresh
|
||||
close all
|
||||
clc
|
||||
% Filter data (select all regions of two files).
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& ~contains(FileList.name,"Survey") ...
|
||||
& ~contains(FileList.name,"Resonant") ...
|
||||
& (contains(FileList.name,"146") | contains(FileList.name,"148"));
|
||||
% List the selected files in the command window.
|
||||
disp(FileList(tmpDataSelection,{'name','lastModifiedDatestr','scientaPassEnergy_eV'}))
|
||||
|
||||
%% Generate spectra and plot
|
||||
FileList = nappGenerateSpectra(FileList,tmpDataSelection);
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond','mode','OneEach');
|
||||
distFig
|
||||
%% Discussion
|
||||
%
|
||||
% Your observation and comments could go here
|
||||
end
|
||||
|
||||
%% Look at one region in detail
|
||||
%
|
||||
% To confirm you see what you expect or to change the experimental settings
|
||||
% if not.
|
||||
|
||||
for ii = 1
|
||||
%% Start fresh
|
||||
clc; close all
|
||||
|
||||
%% Select data
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& ~contains(FileList.name,"Survey") ...
|
||||
& ~contains(FileList.name,"Resonant") ...
|
||||
& (contains(FileList.name,"Al2p") | contains(FileList.name,"Cl2p")) ...
|
||||
& (contains(FileList.name,"146") | contains(FileList.name,"148"));
|
||||
% List the selected files in the command window.
|
||||
disp(FileList(tmpDataSelection,{'name','lastModifiedDatestr'}))
|
||||
|
||||
%% Plot
|
||||
FileList = nappGenerateSpectra(FileList,tmpDataSelection);
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond','mode','OneEach');
|
||||
|
||||
%% Normalize Cl2p intensity to that of Al2p
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& ~contains(FileList.name,"Survey") ...
|
||||
& ~contains(FileList.name,"Resonant") ...
|
||||
& contains(FileList.name,"Cl2p") ...
|
||||
& contains(FileList.name,"146");
|
||||
FileList(tmpDataSelection,:).spectrum_countsPerSecond{:} = FileList(tmpDataSelection,:).spectrum_countsPerSecond{:} .* 22335./39687;
|
||||
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& ~contains(FileList.name,"Survey") ...
|
||||
& ~contains(FileList.name,"Resonant") ...
|
||||
& contains(FileList.name,"Al2p") ...
|
||||
& contains(FileList.name,"146");
|
||||
FileList(tmpDataSelection,:).spectrum_countsPerSecond{:} = FileList(tmpDataSelection,:).spectrum_countsPerSecond{:} .* 22335./39687;
|
||||
|
||||
%% Align to same background
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& ~contains(FileList.name,"Survey") ...
|
||||
& ~contains(FileList.name,"Resonant") ...
|
||||
& contains(FileList.name,"Cl2p") ...
|
||||
& (contains(FileList.name,"146") | contains(FileList.name,"148"));
|
||||
FileList = nappBackground(FileList,647,648,'tableSelection',tmpDataSelection,'energyScale','kinetic',...
|
||||
'mode','mean','showFigures','off');
|
||||
|
||||
%% Plot again
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond','mode','AllInOne');
|
||||
% Optimize figure
|
||||
xlim([647 652])
|
||||
ylabel("counts [norm to Al]")
|
||||
legend
|
||||
distFig
|
||||
end
|
||||
|
||||
%% Plot several spectra in one figure
|
||||
clc; close all
|
||||
for ii = 1
|
||||
close all
|
||||
clc
|
||||
tmpDataSelection = month(FileList.lastModifiedDatenum) == 11 ...
|
||||
& year(FileList.lastModifiedDatenum) == 2025 ...
|
||||
& ~contains(FileList.sample,"(bad data)") ...
|
||||
& contains(FileList.name, "Cl2p")...
|
||||
& ~contains(FileList.name,"Survey") ...
|
||||
& contains(FileList.name,"680eV") ...
|
||||
& (contains(FileList.name,"77") | contains(FileList.name,"116") | contains(FileList.name,"130") | contains(FileList.name,"132") | contains(FileList.name,"133"));
|
||||
FileList = nappGenerateSpectra(FileList,tmpDataSelection);
|
||||
nappPlot(FileList,tmpDataSelection,'tableVariable','spectrum_countsPerSecond','mode','AllInOne');
|
||||
disp(FileList(tmpDataSelection,{'name','lastModifiedDatestr','scientaRegionIterations','scientaSequenceIterations','scientaDwellTime_ms','scientaPassEnergy_eV'}))
|
||||
end
|
||||
@@ -0,0 +1,51 @@
|
||||
%% 20251119 ISS BeamTime
|
||||
%
|
||||
% We do this for ALL spectra during each beamtime. The code here is just
|
||||
% for illustration and sample names might not make sense.
|
||||
%% Start fresh
|
||||
close all
|
||||
clearvars
|
||||
clc
|
||||
|
||||
%% Import Data
|
||||
FileList = nappFileList('2025/20251119_NappIss','mode','local','importLabView','off');
|
||||
save("FileList.mat","FileList")
|
||||
|
||||
%% Add sample label
|
||||
%
|
||||
% Typical info includes: sample, gas environment, purpose, project.
|
||||
|
||||
FileList = addSampleNotes(FileList,0:3,'test, empty file',11,2025,".h5");
|
||||
FileList = addSampleNotes(FileList,1,'test, empty file',11,2025,"XPS");
|
||||
FileList = addSampleNotes(FileList,128,'this is a sample description',11,2025,"XPS");
|
||||
FileList = addSampleNotes(FileList,[74,78,80,82,83,84,85,86], ...
|
||||
'Al-oxide, water, optimize peak separation, Celia',11,2025,"XPS"); % not ideal E_kin windows
|
||||
% List selected files
|
||||
tmpDataSelection = startsWith(FileList.name, "0074");
|
||||
disp(FileList(tmpDataSelection,{'name','lastModifiedDatestr','sample'}))
|
||||
|
||||
%% Identify faulty data and files
|
||||
%
|
||||
% We use the phrase "(bad data)" at the end of the sample description to
|
||||
% filter faulty files during the later analysis.
|
||||
%
|
||||
% Running addSampleNotes again will overwrite the old entry. If you want to
|
||||
% keep notes on the sample and only add (bad data) at the end, you need to
|
||||
% paste the whole text string:
|
||||
FileList = addSampleNotes(FileList,[4,6,7,8,19,43],'(bad data)',11,2025,"XPS"); % data file corrupted
|
||||
FileList = addSampleNotes(FileList,[74,78,80,82,83,84,85,86], ...
|
||||
'Al-oxide, water, optimize peak separation, Celia (bad data)',11,2025,"XPS"); % not ideal E_kin windows
|
||||
% List selected files
|
||||
tmpDataSelection = startsWith(FileList.name, "0074");
|
||||
disp(FileList(tmpDataSelection,{'name','lastModifiedDatestr','sample'}))
|
||||
|
||||
%% Add photon energy
|
||||
FileList = addPhotonEnergy(FileList,91:94,750,11,2025);
|
||||
|
||||
%% Save
|
||||
%
|
||||
% The FileList table holds data and metadata for all beamtime data. It is
|
||||
% saved in a mat file for further use.
|
||||
close all
|
||||
clearvars -except FileList
|
||||
save("FileList.mat","FileList")
|
||||
+113
-22
@@ -9,19 +9,39 @@ Everyone is encouraged to use it, break it (gently), fix it, and extend it. 😄
|
||||
|
||||
***
|
||||
|
||||
## Table of contents
|
||||
## Table of contents 🗺️
|
||||
|
||||
- [What this is](#what-this-is)
|
||||
- [Core ideas](#core-ideas)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Installation](#installation)
|
||||
- [Add to the MATLAB path](#add-to-the-matlab-path)
|
||||
- [Data folders and naming](#data-folders-and-naming)
|
||||
- [The shared data table](#the-shared-data-table)
|
||||
- [MATLAB help & docs](#matlab-help--docs)
|
||||
- [Python / pandas side quests](#python--pandas-side-quests)
|
||||
- [Contributing](#contributing)
|
||||
- [License / usage](#license--usage)
|
||||
- [What this is 🧪](#what-this-is)
|
||||
- [Core ideas 💭](#core-ideas)
|
||||
- [Keep an Overview — FAIR and open research 🧭](#-keep-an-overview--fair-and-open-research)
|
||||
- [The Big Idea 💡](#-the-big-idea)
|
||||
- [Data Levels 📊](#-data-levels)
|
||||
- [Processing Workflow 🧪](#-processing-workflow)
|
||||
- [Script Overview ⚙️](#-script-overview)
|
||||
- [Typical Processing Chain 🔁](#-typical-processing-chain)
|
||||
- [Prerequisites 🧰](#prerequisites)
|
||||
- [Installation 💻](#installation)
|
||||
- [Get the code](#1-get-the-code)
|
||||
- [Add to the MATLAB path 🧬](#add-to-the-matlab-path)
|
||||
- [Data folders and naming 📁](#data-folders-and-naming)
|
||||
- [The shared data table 📊](#the-shared-data-table)
|
||||
- [Table Variables: Identification & meta](#table-variables-identification--meta)
|
||||
- [Table Variables: Raw and processed data](#table-variables-raw-and-processed-data)
|
||||
- [Table Variables: Analyzer and X‑ray settings](#table-variables-analyzer-and-xray-settings)
|
||||
- [Table Variables: Sample settings](#table-variables-sample-settings)
|
||||
- [Table Variables: Processing outcome](#table-variables-processing-outcome)
|
||||
- [Live vs Roh columns](#live-vs-roh-columns)
|
||||
- [MATLAB help & function call conventions 📚](#matlab-help--function-call-conventions)
|
||||
- [Basic in‑place call](#basic-inplace-call)
|
||||
- [Getting help from within MATLAB](#getting-help-from-within-matlab)
|
||||
- [Core MATLAB data types 🧠](#core-matlab-data-types)
|
||||
- [Arrays and cell arrays](#arrays-and-cell-arrays)
|
||||
- [Characters vs strings](#characters-vs-strings)
|
||||
- [Data table](#data-table)
|
||||
- [Quick syntax summary](#quick-syntax-summary)
|
||||
- [Python / pandas side quests 🐍🐼](#python--pandas-side-quests-)
|
||||
- [Contributing 🤝](#contributing)
|
||||
- [License / usage 📄](#license--usage)
|
||||
|
||||
***
|
||||
|
||||
@@ -80,6 +100,8 @@ Concretely, concepts like the **ACTRIS data levels** (Level 0 raw, Level 1 calib
|
||||
can be mirrored in how scripts and data tables are named and stored, and aligned with the [SNSF Open Research Data policy](https://www.snf.ch/en/dMILj9t4LNk8NwyR/topic/open-research-data)
|
||||
and the [ACTRIS Data Policy](https://data.actris.eu/data-policy).
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 📊 Data Levels
|
||||
@@ -101,6 +123,10 @@ Beamtime data are processed in *two main phases*:
|
||||
- **Levels 2–3:** after the beamtime 🧠 — selects and combines results from multiple sources (e.g. lab experiments, simulations) and beamtimes.
|
||||
Scripts live in your **personal analysis folder** on the shared drive.
|
||||
|
||||
|
||||
<img src="documentedExampleScripts/Gabathuler2025HexylamineDataFlow.png" alt="DataFlow" width="800">
|
||||
|
||||
|
||||
---
|
||||
|
||||
### ⚙️ Script Overview
|
||||
@@ -236,7 +262,23 @@ save('FileList.mat',"FileList");
|
||||
|
||||
## The shared data table
|
||||
|
||||
All nappMATLAB functions operate on a MATLAB table with one row per file and a set of standard variables (columns). Using the same column (variable) names across users and across software helps to share data and is a prerequisite for programming.
|
||||
All nappMATLAB functions operate on a MATLAB table with one row per file and a set of standard variables (columns). Using the same variable (column) names across users and software helps with data sharing and is a prerequisite for robust scripting.
|
||||
The key point of this whole table exercise is that data can be filtered (and found) across several beamtimes or experimental campaigns. Filtering makes most sense using metadata such as temperature and pressure, but the month of the beamtime or, importantly, the sample description added during the beamtime can also be very useful.
|
||||
Filtering uses standard MATLAB code. The example below filters for all XPS spectra from 3rd of September that are not labeled as N2O5, bad data, excluded data, gas-phase, Survey, or Auger, and that were recorded at 720 eV X-ray energy on the N1s region.
|
||||
|
||||
|
||||
````matlab
|
||||
tmpDataSelection = contains(FileList.name,'.ibw') ...
|
||||
& day(FileList.lastModifiedDatenum) == 3 ...
|
||||
& month(FileList.lastModifiedDatenum) == 9 ...
|
||||
& ~contains(FileList.sample,'N2O5') ...
|
||||
& ~contains(FileList.sample,'(bad data)') & ~contains(FileList.sample,'(excluded data)')...
|
||||
& ~contains(FileList.sample,'gas-phase')...
|
||||
& ~contains(FileList.name,'Survey')...
|
||||
& ~contains(FileList.name,'Auger')...
|
||||
& FileList.xRayEkinRange_eV(:,1) == 720 ...
|
||||
& contains(FileList.name,'N1s');
|
||||
````
|
||||
|
||||
### Table Variables: Identification & meta
|
||||
|
||||
@@ -437,22 +479,26 @@ Each function may define additional options; always check the help text for the
|
||||
|
||||
### Getting help from within MATLAB
|
||||
|
||||
Each function should ship with a short header and usage examples. You can get a list of all functions and a short description by navigating to the function folder `beamtime` in MATLAB and running:
|
||||
Each function should ship with a short header and usage examples. 📝✨
|
||||
You can get a list of all functions and a short description by
|
||||
navigating to the `beamtime` function folder 🧪 in MATLAB and running:
|
||||
|
||||
- `help beamtime`
|
||||
- `help beamtime` 💡
|
||||
|
||||
You can access a more detailed description of each function via standard MATLAB commands:
|
||||
|
||||
- `help nappFunctionAbc`
|
||||
- `doc nappFunctionAbc`
|
||||
- `help nappFunctionAbc` 🔍
|
||||
- `doc nappFunctionAbc` 📖
|
||||
|
||||
The separate MATLAB documents **" WIP will be added soon "** give examples:
|
||||
The nappMATLAB example scripts in the `documentedExampleScripts` folder of this repo
|
||||
are a good starting point for your work with nappMATLAB 🚀:
|
||||
|
||||
- concept and function call patterns,
|
||||
- data structure and table variables,
|
||||
- import workflows,
|
||||
- processing steps from raw data to publication plots. 📚
|
||||
- **importData.m** shows how to import and annotate SLS data.📈🧪
|
||||
- **generateSpectra.m** gives examples how to plot data allready during beamtimes 📊
|
||||
- **HowDoI.m** lists solutions for most common beamtime wishes on data processing 🧠
|
||||
- **gaussFit.m** fitting during beamtimes helps, here is how 🔬
|
||||
|
||||
This assumes you are already familiar with the basic MATLAB tools and usage 🧰:
|
||||
|
||||
|
||||
- **Getting started with MATLAB**
|
||||
@@ -479,6 +525,51 @@ The separate MATLAB documents **" WIP will be added soon "** give examples:
|
||||
Defining your own functions:
|
||||
<https://www.mathworks.com/help/matlab/ref/function.html>
|
||||
|
||||
## Core MATLAB data types.
|
||||
MATLAB has a few central container types: numeric arrays (including matrices),
|
||||
cell arrays, character arrays, and string arrays.
|
||||
Arrays/matrices are homogeneous numeric containers,
|
||||
while cell arrays can hold mixed types; text can be stored either as
|
||||
character arrays (`' '` syntax) or as string arrays (`" "` syntax).
|
||||
|
||||
### Arrays and cell arrays
|
||||
|
||||
- **Numeric array / matrix**: Homogeneous numeric data, typically created as `A = [1 2; 3 4]`.
|
||||
- Index with `A(i,j)` using `()`; result is numeric and the same type as `A`.
|
||||
- **Cell array**: Container where each element ("cell") can hold anything
|
||||
(numbers, char vectors, strings, structs, other cells, …), e.g. `C = {1, 'abc'; [1 2 3], "foo"}`.
|
||||
- `C(i,j)` with `()` returns a **cell array** (wrapper, not the content).
|
||||
- `C{i,j}` with `{}` returns the **content** stored in that cell.
|
||||
|
||||
### Characters vs strings
|
||||
|
||||
- **Character array**: A vector or matrix of `char`, created with single quotes, e.g. `s = 'abc'`.
|
||||
- Index with `s(i)` using `()` to get one or more characters as `char`.
|
||||
- **String array**: Newer text type, created with double quotes, e.g. `t = "abc"`, `S = ["a" "b" "c"]`.
|
||||
- Index with `S(i)` using `()` to get a string scalar (still type `string`).
|
||||
- Recommended for new code; cell arrays of character vectors (`{'a','b'}`) are legacy for text storage.
|
||||
|
||||
|
||||
### Data table
|
||||
Tables and timetables are both *tabular* containers for column-oriented variables that can have different
|
||||
data types, as long as all columns share the same number of rows.
|
||||
- **Table indexing** (same ideas for timetables, but first dimension is time):
|
||||
- `T(rows, vars)` with `()` returns a **subtable**.
|
||||
- `T{rows, vars}` with `{}` returns the **contents as an array** (numeric, cell, etc.), not a table.
|
||||
- `T.VarName` uses **dot notation** to get a single variable as a column vector/array.
|
||||
|
||||
|
||||
### Quick syntax summary
|
||||
|
||||
- `()`
|
||||
- Arrays: content, same type as the array (numeric, string, char, logical, …).
|
||||
- Cell arrays: returns a cell array (one or more cells, still wrapped).
|
||||
- `{}`
|
||||
- Only for cell arrays: unwrap and return the **stored value** (double, char, string, struct, etc.).
|
||||
- `' '`
|
||||
- Create a **character array** (legacy text representation).
|
||||
- `" "`
|
||||
- Create a **string scalar**; multiple elements give a **string array** (preferred for text).
|
||||
|
||||
***
|
||||
|
||||
|
||||
Reference in new issue
Block a user