beamtime/nappFileList.m - Fix h5 LensMode: translate numeric codes to descriptive text (e.g. 1 -> T_HiPPHAXPES) to match what .ibw files already store, applied across all three h5read fallback branches, not just the oldest-format one beamtime/nappGenerateSpectra.m - Bug fixes beamtime/nappPlot.m - Bug fixes import/importData.m (new) - Ground script for one beamtime: import (nappFileList, nappGenerateSpectra), sample/spot and photon-energy assignment per row range, campaign metadata (CustomProperties) and column descriptions/units set inline, tidy-up, and export to .csv/.mat/.h5 (via nappExportH5). Leaves FileList in the workspace for PublishReport.m and callOpenbisSync.m to run against afterward. import/nappExportH5.m (new) - Export FileList + campaign metadata + raw source files to a self-contained HDF5 archive - Low-level HDF5 API (H5F/H5G/H5D/H5A/H5T/H5S/H5P) to fix H5FD_truncate/"too many open files" errors from the top-level h5create/h5write functions each reopening the file internally - Explicit rowIndex attribute per row group, since HDF5 group listing order isn't guaranteed to match table row order openBIS/ (new) - nappSyncToOpenbis.py, callOpenbisSync.m, testpybis.m, README.md - openBIS sync pipeline: create-or-update per row matched by $name, correct lowercase property codes, timestamp formatting, parent linking, raw file upload, plot/photo/video thumbnail embedding, config/engine split for maintainability -- see README.md for full details
230 lines
10 KiB
Matlab
230 lines
10 KiB
Matlab
function DataTable = nappGenerateSpectra(DataTable,varargin)
|
|
%NAPPGENERATESPECTRA Generate 1D spectra from image spectra.
|
|
% DataTable = NAPPGENERATESPECTRA(DataTable) processes all data in the
|
|
% input table and generates spectra for the data files in each row. The
|
|
% spectra are written back into the table into new columns (table
|
|
% variables).
|
|
%
|
|
% DataTable = NAPPGENERATESPECTRA(DataTable, tableSelection) restricts
|
|
% processing to the rows where tableSelection is true. The length of
|
|
% tableSelection must match the number of rows in DataTable.
|
|
%
|
|
% DataTable = NAPPGENERATESPECTRA(DataTable, tableSelection, Name, Value)
|
|
% additionally customizes the source variable, reduction mode, and energy
|
|
% or iteration ranges via Name-Value arguments.
|
|
%
|
|
% Required input
|
|
% --------------
|
|
% DataTable
|
|
% Table that contains at least the variables:
|
|
% - name : file name as character vector or string
|
|
% - image or imageRoh : 2D image or image stack stored in a cell
|
|
% - scientaEkin_eV : kinetic energy axis
|
|
%
|
|
% Optional positional input
|
|
% -------------------------
|
|
% tableSelection
|
|
% Logical vector selecting rows to process.
|
|
% Size: [height(DataTable) 1] or [1 height(DataTable)]
|
|
% Default: all rows true
|
|
%
|
|
% Name-Value arguments
|
|
% --------------------
|
|
% 'tableVariable'
|
|
% Name of the variable in DataTable that contains the image data.
|
|
% Type : char or string
|
|
% Values : 'image' (default) | 'imageRoh'
|
|
%
|
|
% 'mode'
|
|
% Reduction mode used to generate the spectra.
|
|
% Type : char or string
|
|
% Values : 'mean' (default) | 'sum' | 'trapz' | 'AugerMeitnerMean'
|
|
% Behaviour:
|
|
% - For '.h5' entries:
|
|
% 'sum' or 'mean' : sum over the selected kinetic energy range
|
|
% (currently identical behaviour; no
|
|
% normalization by time implemented).
|
|
% 'trapz' : trapezoidal integration over kinetic
|
|
% energy for each column.
|
|
% - For '.ibw' entries:
|
|
% 'mean' or 'trapz': mean over the selected iteration range
|
|
% (2nd dimension) and store as a column
|
|
% vector.
|
|
% 'sum' : sum over the selected iteration range.
|
|
%
|
|
% 'iterationRange'
|
|
% Iteration indices for '.ibw' image stacks (2nd dimension).
|
|
% Type : numeric 1x2 vector [startIdx endIdx]
|
|
% Default: [0 0] -> use full range 1 : size(image,2)
|
|
%
|
|
% 'eKinStart'
|
|
% Lower kinetic energy limit for '.h5' data.
|
|
% Type : numeric scalar
|
|
% Default: 0 -> use first element of scientaEkin_eV
|
|
%
|
|
% 'eKinEnd'
|
|
% Upper kinetic energy limit for '.h5' data.
|
|
% Type : numeric scalar
|
|
% Default: 0 -> use last element of scientaEkin_eV
|
|
%
|
|
% Output
|
|
% ------
|
|
% DataTable
|
|
% Same table as input, with the following variables ensured and
|
|
% updated for the selected rows:
|
|
%
|
|
% spectrum_counts
|
|
% Cell array. Each cell contains a spectrum generated from the
|
|
% selected image data, depending on file type and mode
|
|
% ('sum', 'mean', or 'trapz').
|
|
%
|
|
% spectrum_countsPerSecond
|
|
% Cell array. For '.ibw' entries and modes 'mean' or 'trapz',
|
|
% this stores the spectrum obtained by averaging over the chosen
|
|
% iteration range.
|
|
%
|
|
% logNappGenerateSpectraMode
|
|
% String array specifying the mode used for each processed row.
|
|
%
|
|
% logNappGenerateSpectraRange
|
|
% Numeric matrix with two columns. For '.h5' entries this stores
|
|
% [eKinStart eKinEnd]. For '.ibw' entries this stores
|
|
% [iterationStart iterationEnd].
|
|
%
|
|
% logNappGenerateSpectraDate
|
|
% String array containing the date and time when the spectra
|
|
% were generated for each processed row.
|
|
%
|
|
% logNappGenerateSpectraCaller
|
|
% String array containing the file path of the script or
|
|
% function that called nappGenerateSpectra, for provenance.%
|
|
% Notes
|
|
% -----
|
|
% - The function distinguishes between '.h5' and '.ibw' files based on
|
|
% the file name stored in the variable 'name'.
|
|
|
|
|
|
% Define conditions and defaults of input
|
|
defaultTableVariable = 'image';
|
|
expectedTableVariable = {'image','imageRoh'};
|
|
defaultMode = 'mean';
|
|
expectedMode = {'mean','sum','trapz','AugerMeitnerMean'};
|
|
defaultEkinStart = 0;
|
|
defaultEkinEnd = 0;
|
|
defaultTableSelection = true(size(DataTable,1),1);
|
|
|
|
% Parse input
|
|
p = inputParser;
|
|
addRequired(p,'DataTable',@istable);
|
|
addOptional(p,'tableSelection',defaultTableSelection,@islogical);
|
|
addParameter(p,'tableVariable',defaultTableVariable,...
|
|
@(x) any(validatestring(x,expectedTableVariable)));
|
|
addParameter(p,'mode',defaultMode,...
|
|
@(x) any(validatestring(x,expectedMode)));
|
|
addParameter(p,'iterationRange',[0:0]);
|
|
addParameter(p,'eKinStart',defaultEkinStart,@isnumeric)
|
|
addParameter(p,'eKinEnd',defaultEkinEnd,@isnumeric)
|
|
parse(p,DataTable,varargin{:});
|
|
|
|
% add empty variable to table
|
|
existColumn = strcmp('spectrum_countsPerSecond',p.Results.DataTable.Properties.VariableNames);
|
|
if ~any(existColumn)
|
|
DataTable.spectrum_countsPerSecond = cell(size(p.Results.DataTable,1),1);
|
|
end
|
|
existColumn = strcmp('spectrum_counts',p.Results.DataTable.Properties.VariableNames);
|
|
if ~any(existColumn)
|
|
DataTable.spectrum_counts = cell(size(p.Results.DataTable,1),1);
|
|
end
|
|
existColumn = strcmp('logNappGenerateSpectraRange',p.Results.DataTable.Properties.VariableNames);
|
|
if ~any(existColumn)
|
|
DataTable.logNappGenerateSpectraRange = NaN(size(p.Results.DataTable,1),2);
|
|
end
|
|
existColumn = strcmp('logNappGenerateSpectraMode',p.Results.DataTable.Properties.VariableNames);
|
|
if ~any(existColumn)
|
|
DataTable.logNappGenerateSpectraMode = repmat("",size(p.Results.DataTable,1),1);
|
|
end
|
|
existColumn = strcmp('logNappGenerateSpectraDate',p.Results.DataTable.Properties.VariableNames);
|
|
if ~any(existColumn)
|
|
DataTable.logNappGenerateSpectraDate = repmat("",size(p.Results.DataTable,1),1);
|
|
end
|
|
existColumn = strcmp('logNappGenerateSpectraCaller',p.Results.DataTable.Properties.VariableNames);
|
|
if ~any(existColumn)
|
|
DataTable.logNappGenerateSpectraCaller = repmat("",size(p.Results.DataTable,1),1);
|
|
end
|
|
|
|
% check input (all elements of input variable need to have non-zero size)
|
|
if ~all(cell2mat(cellfun(@size,p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable),'UniformOutput',false)),'all')
|
|
disp('The table variable appears to be empty. I quit now')
|
|
error('The table variable appears to be empty.')
|
|
end
|
|
|
|
% create empty variables
|
|
tmp_3 = cell(size(p.Results.DataTable(p.Results.tableSelection,:),1),1);
|
|
tmp_6 = cell(size(p.Results.DataTable(p.Results.tableSelection,:),1),1);
|
|
tmp_4 = NaN(size(p.Results.DataTable(p.Results.tableSelection,:),1),1);
|
|
tmp_5 = NaN(size(p.Results.DataTable(p.Results.tableSelection,:),1),1);
|
|
% repeat this for all columns in input.
|
|
for ii = 1:size(p.Results.DataTable(p.Results.tableSelection,:),1)
|
|
if endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'h5') % let's do NEXAFS first.
|
|
% Get index of EkinStart and EkinEnd
|
|
if (p.Results.eKinStart) == 0
|
|
tmp_1 = 1;
|
|
else
|
|
tmp_1 = find(p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii} >= p.Results.eKinStart,1);
|
|
end
|
|
if (p.Results.eKinEnd) == 0
|
|
tmp_2 = length(p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii});
|
|
else
|
|
tmp_2 = find(p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii} >= p.Results.eKinEnd,1);
|
|
end
|
|
|
|
if contains(p.Results.mode,'trapz')
|
|
tmp_3(ii,1)= {trapz(p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii}(tmp_1:tmp_2),...
|
|
p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}(tmp_1:tmp_2,:))'};
|
|
elseif (contains(p.Results.mode,'sum') | contains(p.Results.mode,'mean'))
|
|
|
|
tmp_3(ii,1) = {sum(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}(tmp_1:tmp_2,:),1)'}; %#ok<*AGROW>
|
|
end
|
|
% log
|
|
tmp_4(ii,1) = p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii}(tmp_1);
|
|
tmp_5(ii,1) = p.Results.DataTable(p.Results.tableSelection,:).scientaEkin_eV{ii}(tmp_2);
|
|
elseif endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'ibw') || endsWith(p.Results.DataTable(p.Results.tableSelection,:).name{ii},'xy') % then do Igorfiles or xy files
|
|
if p.Results.iterationRange(1) == 0
|
|
startRange = 1;
|
|
endRange = size(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii},2);
|
|
else
|
|
startRange = p.Results.iterationRange(1);
|
|
endRange = p.Results.iterationRange(2);
|
|
end
|
|
|
|
if (contains(p.Results.mode,'mean') | contains(p.Results.mode,'trapz'))
|
|
tmp_6(ii,1)= {mean(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}(:,startRange:endRange),2)};
|
|
elseif contains(p.Results.mode,'sum')
|
|
tmp_3(ii,1) = {sum(p.Results.DataTable(p.Results.tableSelection,:).(p.Results.tableVariable){ii}(:,startRange:endRange),2)}; %#ok<*AGROW>
|
|
end
|
|
% log
|
|
tmp_4(ii,1) = startRange;
|
|
tmp_5(ii,1) = endRange;
|
|
end
|
|
end
|
|
|
|
% write results to table
|
|
DataTable.spectrum_counts(p.Results.tableSelection) = tmp_3;
|
|
DataTable.spectrum_countsPerSecond(p.Results.tableSelection) = tmp_6;
|
|
% write log to table
|
|
processIdx = find(p.Results.tableSelection);
|
|
|
|
DataTable.logNappGenerateSpectraRange(processIdx,:) = [tmp_4 tmp_5];
|
|
DataTable.logNappGenerateSpectraMode(processIdx) = string(p.Results.mode);
|
|
DataTable.logNappGenerateSpectraDate(processIdx) = string(datetime('now', 'Format', 'yyyy-MM-dd HH:mm:ss'));
|
|
|
|
% Determine the calling script using the call stack
|
|
stackInfo = dbstack;
|
|
if length(stackInfo) > 1
|
|
callerScript = string(stackInfo(2).file); % The script that called this function
|
|
else
|
|
callerScript = " "; % Called directly from the command window
|
|
end
|
|
DataTable.logNappGenerateSpectraCaller(processIdx) = callerScript;
|
|
end
|