Good to know I'm smarter than google gemini. That code did not run. fixed it. Also fixed a time issue. Start aquisition is now taken from the logged time in the data file or if that is not present the OS creation date. the end aquisition time is the last modification time of the os for that file.

This commit is contained in:
bartels-rausch committed 2026-03-12 13:35:27 +01:00
1 parent 938eea27e8
commit a26847b332
1 file changed
+106 -26
+106 -26
View File
@@ -448,6 +448,10 @@ else
% Loop through each file in the NEXAFS file list
% TmpFileList{2} contains the full paths to all NEXAFS HDF5 files
% ii is the loop counter (1, 2, 3, ... up to the total number of files)
% Initialize a map to hold the original dates for split files
splitFileDatesMap = containers.Map('KeyType', 'char', 'ValueType', 'any');
for ii = 1:size(TmpFileList{2}, 1)
% Get the filename of the current file being processed
@@ -456,6 +460,7 @@ else
% Read information about the structure of the HDF5 file
% This tells us what groups (datasets) are stored in the file
fileinfo = h5info(current_file);
% Extract the names of all groups at the root level
% Example: {'/scan_1', '/scan_2', '/logs', '/__DATA_TYPES__'}
@@ -465,13 +470,21 @@ else
% Files with more than 3 groups likely contain multiple scans
% (the extra groups beyond scans are typically '/logs' and '/__DATA_TYPES__')
if numel(groupnames) > 3
% 1. Get the true historical dates BEFORE splitting
[orig_cDateOS, orig_mDateOS] = getOSDates(current_file);
% 2. Split the file and get the names of the newly created files
% This file contains multiple scans, so split it
% The splitH5Scans function will:
% - Create separate files for each scan
% - Rename each scan to '/scan_1' within its new file
% - Delete the original multi-scan file when done
splitH5Scans(current_file);
newlyCreatedFiles = splitH5Scans(current_file);
% 3. Store the historical dates in the map using the new filenames as keys
for k = 1:length(newlyCreatedFiles)
splitFileDatesMap(newlyCreatedFiles{k}) = {orig_cDateOS, orig_mDateOS};
end
end
@@ -571,9 +584,7 @@ if ~isempty(TmpFileList{1})
dateStr = [char(regexp(tmp{29},'((?<=Date=).*)','match')) ' ' char(regexp(tmp{30},'((?<=Time=).*)','match'))];
parsedDate = datevec(dateStr);
if size(parsedDate, 2) == 6
current_file_info.creationDate = parsedDate;
current_file_info.lastModifiedDatenum = datenum(parsedDate);
current_file_info.lastModifiedDatestr = dateStr;
current_file_info.creationDate = parsedDate;
end
catch
end
@@ -654,9 +665,9 @@ if ~isempty(TmpFileList{1})
% If the file lacks "Monochromator" in the header and the energy is
% incorrectly tagged as ~1453.6 or 1486.6, overwrite it to 1253.6 (Mg Ka).
% =========================================================================
if ~contains(headerText, 'Monochromator', 'IgnoreCase', true)
if ~any(contains(string(fileLines), 'Monochromator', 'IgnoreCase', true))
% Checking both 1453.6 (as requested) and 1486.61 (as seen in your file)
if (abs(globalExEnergy - 1453.6) < 1) || (abs(globalExEnergy - 1486.61) < 1)
if (abs(globalExEnergy - 1453.61) < 1) || (abs(globalExEnergy - 1486.61) < 1)
globalExEnergy = 1253.6;
end
end
@@ -701,6 +712,15 @@ if ~isempty(TmpFileList{1})
rName = strtrim(extractAfter(lineStr, '# Region:'));
elseif startsWith(lineStr, '# Excitation Energy:')
regionEntry.xRayEkin_eV = sscanf(strtrim(extractAfter(lineStr, '# Excitation Energy:')), '%f');
% =========================================================================
% OFFLINE XPS BUG FIX (Mg vs Al Source) - REGION OVERRIDE
% =========================================================================
if ~any(contains(string(fileLines), 'Monochromator', 'IgnoreCase', true))
if (abs(regionEntry.xRayEkin_eV - 1453.6) < 1) || (abs(regionEntry.xRayEkin_eV - 1486.61) < 1)
regionEntry.xRayEkin_eV = 1253.6;
end
end
% =========================================================================
exEnergyStr = num2str(regionEntry.xRayEkin_eV);
elseif startsWith(lineStr, '# Spectrum ID:')
specID = sscanf(strtrim(extractAfter(lineStr, '# Spectrum ID:')), '%f');
@@ -710,10 +730,10 @@ if ~isempty(TmpFileList{1})
try
dtUTC = datetime(dateStr, 'InputFormat', 'MM/dd/yy HH:mm:ss', 'PivotYear', 2000, 'TimeZone', 'UTC');
dtLocal = datetime(dtUTC, 'TimeZone', 'Europe/Zurich');
regionEntry.lastModifiedDatenum = datenum(dtLocal);
regionEntry.lastModifiedDatestr = datestr(dtLocal);
% ONLY set the Start Time (creationDate). Leave lastModified as OS default!
regionEntry.creationDate = datevec(dtLocal);
catch
regionEntry.lastModifiedDatestr = rawDateStr;
% If parsing fails, it safely falls back to the OS creation date
end
elseif startsWith(lineStr, '# Pass Energy:')
regionEntry.scientaPassEnergy_eV = str2double(extractAfter(lineStr, '# Pass Energy:'));
@@ -852,8 +872,26 @@ for ii = 1:size(TmpFileList{2},1) % do this for each list element
% Get OS Dates
tmpCurrentFile = fullfile(TmpFileList{2}(ii).folder, TmpFileList{2}(ii).name);
[cDateOS, ~] = getOSDates(tmpCurrentFile);
% ==========================================================
% IN-MEMORY DATE RESTORATION
% Check if this file was created by the splitter. If yes,
% retrieve its historical dates from the memory map!
% ==========================================================
if exist('splitFileDatesMap', 'var') && isKey(splitFileDatesMap, TmpFileList{2}(ii).name)
savedDates = splitFileDatesMap(TmpFileList{2}(ii).name);
cDateOS = savedDates{1};
mDateOS = savedDates{2};
else
% Otherwise, just read the dates directly from the OS
[cDateOS, mDateOS] = getOSDates(tmpCurrentFile);
end
% START TIME: OS Creation Date (or mapped historical creation)
TmpFileList{2}(ii).creationDate = datevec(cDateOS);
% END TIME: OS Modification Date (or mapped historical modification)
TmpFileList{2}(ii).lastModifiedDatenum = datenum(mDateOS);
TmpFileList{2}(ii).lastModifiedDatestr = mDateOS;
% ==========================================================
try
@@ -1148,10 +1186,14 @@ for ii = 1:size(TmpFileList{3},1) % do this for each picture in the list
% Get OS Dates
tmpCurrentFile = fullfile(TmpFileList{3}(ii).folder, TmpFileList{3}(ii).name);
[cDateOS, ~] = getOSDates(tmpCurrentFile);
% START TIME: OS Creation Date
TmpFileList{3}(ii).creationDate = datevec(cDateOS);
% END TIME: Robust OS Modification Date
TmpFileList{3}(ii).lastModifiedDatenum = TmpFileList{3}(ii).datenum;
TmpFileList{3}(ii).lastModifiedDatestr = TmpFileList{3}(ii).date;
end
%% Merge lists into one
%
@@ -1674,9 +1716,10 @@ end
end
function splitH5Scans(infile)
function newFiles = splitH5Scans(infile)
% splitH5Scans - Split an HDF5 file containing multiple scans into separate files
%
%
% This function takes an HDF5 file with multiple scan groups (scan_1, scan_2, etc.)
% and creates separate files for each scan. Each output file contains only one
% scan (renamed to scan_1) plus the logs group. The original file is deleted after
@@ -1708,13 +1751,11 @@ function splitH5Scans(infile)
% Read the structure of the HDF5 file to see what groups it contains
% h5info returns information about groups, datasets, and attributes
newFiles = {}; % Initialize the output cell array
fileinfo = h5info(infile);
% Get the original file's modification date before we start
% This will be copied to all new files to preserve the original timestamp
orig_file_info = dir(infile);
orig_mod_datetime = orig_file_info.date; % Get as datetime object
% Get the original file's true OS dates BEFORE we start modifying it!
[orig_cDateOS, orig_mDateOS] = getOSDates(infile);
% Extract the names of all groups at the root level of the file
% Example: {'/scan_1', '/scan_2', '/logs', '/__DATA_TYPES__'}
@@ -1766,6 +1807,10 @@ if numel(groupnames) > 3
% Example: 'C:\Data\0002_20251119_145823_O_Kedge_Nov25_scan_2.h5'
outname = fullfile(filepath, sprintf('%s%s_%s%s', prefix, rest, scan_name_clean, ext));
% Save the new filename to the output array
[~, base_out, ext_out] = fileparts(outname);
newFiles{end+1} = [base_out, ext_out];
% Copy the entire original file to create the new output file
% We'll modify this copy to keep only one scan
copyfile(infile, outname);
@@ -1804,13 +1849,32 @@ if numel(groupnames) > 3
% Close the HDF5 file to save all changes
H5F.close(fid);
% Copy the modification date from the original file to the new file
% Convert MATLAB datenum to timestamp format: YYYYMMDDhhmm.ss
timestamp_str = string(datetime(orig_mod_datetime), 'yyyyMMddHHmm.ss');
if ismac
touch_cmd = sprintf('touch -t %s "%s"', timestamp_str, outname);
system(touch_cmd);
% ==========================================================
% RESTORE ORIGINAL OS DATES TO THE NEW FILE
% ==========================================================
if ispc
% Windows: Use .NET to set BOTH Creation and Modification time
try
fileObj = System.IO.FileInfo(outname);
fileObj.CreationTime = System.DateTime.Parse(orig_cDateOS);
fileObj.LastWriteTime = System.DateTime.Parse(orig_mDateOS);
catch
end
elseif ismac || isunix
% Mac/Linux: Use 'touch' to restore Modification time
try
timestamp_str = string(datetime(orig_mDateOS), 'yyyyMMddHHmm.ss');
system(sprintf('touch -m -t %s "%s"', timestamp_str, outname));
catch
end
% NOTE: Mac OS makes it incredibly difficult to change the Birth (Creation)
% time via standard commands. However, because we restored the Modification
% time perfectly, our "Paradox Check" in the main loop will automatically
% step in, realize Creation is newer than Modification, and fix the
% Creation date for us in the data table!
end
% ==========================================================
% Print confirmation message showing which file was created
% fprintf('Created: %s\n', outname);
@@ -1825,7 +1889,9 @@ else
% disp('File has three or fewer groups. No processing required.');
end
end
end
function [creationDateOS, lastModifiedDate] = getOSDates(fullPath)
@@ -1849,15 +1915,29 @@ if ispc
catch
creationDateOS = d.date; % Fallback
end
elseif ismac || isunix
% macOS/Linux: Use the stat command to get the "Birth" time
[status, cmdOut] = system(['stat -f "%SB" -t "%d-%b-%Y %H:%M:%S" "', fullPath, '"']);
if status == 0
creationDateOS = strtrim(cmdOut);
% ==========================================================
% macOS COPIED FILE WORKAROUND
% If copied/downloaded, macOS sets Birth Time to 'today' but
% keeps the old Modification Time. If Creation > Modification,
% use the older Modification time as the true origin!
% ==========================================================
try
if datetime(creationDateOS) > datetime(lastModifiedDate)
creationDateOS = lastModifiedDate;
end
catch
% Silently continue if datetime conversion fails
end
% ==========================================================
else
creationDateOS = d.date; % Fallback
end
else
creationDateOS = d.date; % Fallback for unknown OS
end
end