Calculations/Data-Analyzer/+Helper/processRawData.m

193 lines
7.8 KiB
Matlab

function [full_od_imgs, full_bkg_imgs, raw_scan_parameter_values, raw_file_list] = processRawData(options)
%% Reads HDF5 files, computes OD images, supports disk-backed storage in blocks
fprintf('\n[INFO] Processing raw data files at %s ...\n', options.folderPath);
groupList = ["/images/MOT_3D_Camera/in_situ_absorption", ...
"/images/ODT_1_Axis_Camera/in_situ_absorption", ...
"/images/ODT_2_Axis_Camera/in_situ_absorption", ...
"/images/Horizontal_Axis_Camera/in_situ_absorption", ...
"/images/Vertical_Axis_Camera/in_situ_absorption"];
% --- Validate camera index ---
if options.cam < 1 || options.cam > numel(groupList)
error('Invalid camera index: %d', options.cam);
end
files = dir(fullfile(options.folderPath, '*.h5'));
nFiles = numel(files);
if nFiles == 0
error('No HDF5 files found in %s', options.folderPath);
end
% Determine image size
testFile = fullfile(files(1).folder, files(1).name);
atm_test = double(imrotate(h5read(testFile, append(groupList(options.cam), "/atoms")), options.angle, 'bilinear', 'crop'));
[ny, nx] = size(atm_test);
full_od_imgs = [];
full_bkg_imgs = [];
raw_scan_parameter_values = zeros(1, nFiles);
raw_file_list = string(zeros(1,nFiles)); % always string array
if options.SAVE_TO_WORKSPACE
fprintf('\n[INFO] Creating in-memory arrays of raw data...\n');
full_od_imgs = nan(ny, nx, nFiles, 'single');
full_bkg_imgs = nan(ny, nx, nFiles, 'single');
else
% --- Create uniquely identified full OD image folder ---
dataSource = makeDataSourceStruct(options.folderPath);
runID = sprintf('%s_%s_Run%04d', ...
dataSource{1}.sequence, ...
strrep(dataSource{1}.date,'/','-'), ...
dataSource{1}.runs);
% --- Determine parent folder for FullODImages ---
if isfield(options, 'FullODImagesFolder') && ...
~isempty(options.FullODImagesFolder) && ...
isfolder(options.FullODImagesFolder)
parentFolder = options.FullODImagesFolder;
else
parentFolder = options.saveDirectory;
end
% --- Create uniquely identified full OD image folder ---
fullODImageFolder = fullfile(parentFolder, ['FullODImages_' runID]);
if ~exist(fullODImageFolder,'dir'), mkdir(fullODImageFolder); end
fprintf('\n[INFO] Creating folder of full OD images on disk: %s\n', fullODImageFolder);
% --- Save metadata for this run ---
metadata.options = options;
metadata.timestamp = datetime; % still record analysis time
metadata.runID = runID; % traceable to experiment run
metadata.imageSize = [ny, nx];
metadata.fileList = string(arrayfun(@(f) fullfile(f.folder, f.name), files, 'UniformOutput', false));
save(fullfile(fullODImageFolder,'metadata.mat'),'metadata','-v7.3');
end
% --- Prepare file names ---
fullFileNames = string(arrayfun(@(f) fullfile(f.folder, f.name), files, 'UniformOutput', false));
% --- Check for Parallel Computing Toolbox ---
useParallel = license('test','Distrib_Computing_Toolbox') && ~options.SAVE_TO_WORKSPACE;
if useParallel
fprintf('\n[INFO] Parallel Computing Toolbox detected. Using parallelization for raw data processing...\n');
% --- Preallocate scan parameters and file list for parallel mode ---
raw_scan_parameter_values = nan(1, nFiles, 'single');
raw_file_list = fullFileNames;
% --- Parallel loop without progress bar ---
parfor k = 1:nFiles
[od_img, bkg_img, val] = readAndComputeOD(fullFileNames(k), options, groupList, ny, nx);
if options.SAVE_TO_WORKSPACE
full_od_imgs(:,:,k) = single(od_img);
full_bkg_imgs(:,:,k) = single(bkg_img);
else
writeFullODImagesToDisk(fullODImageFolder, od_img, bkg_img, val, fullFileNames(k), k);
end
raw_scan_parameter_values(k) = val;
end
else
% --- Standard for-loop with your progress bar ---
showPB = isfield(options,'showProgressBar') && options.showProgressBar;
if showPB && options.SAVE_TO_WORKSPACE
pb = Helper.ProgressBar();
pb.run('Progress: ');
end
for k = 1:nFiles
[od_img, bkg_img, val] = readAndComputeOD(fullFileNames(k), options, groupList, ny, nx);
if options.SAVE_TO_WORKSPACE
full_od_imgs(:,:,k) = single(od_img);
full_bkg_imgs(:,:,k) = single(bkg_img);
else
writeFullODImagesToDisk(fullODImageFolder, od_img, bkg_img, val, fullFileNames(k), k);
end
raw_scan_parameter_values(k) = val;
raw_file_list(k) = fullFileNames(k);
if showPB && options.SAVE_TO_WORKSPACE
progressPercent = round(k/nFiles*100);
pb.run(progressPercent);
end
end
if showPB && options.SAVE_TO_WORKSPACE
pb.run(' Done!');
end
end
end
%% --- Local helper functions ---
function [od_img, bkg_img, val] = readAndComputeOD(fullFileName, options, groupList, ny, nx)
try
atm_img = double(imrotate(h5read(fullFileName, append(groupList(options.cam), "/atoms")), options.angle, 'bilinear', 'crop'));
bkg_img = double(imrotate(h5read(fullFileName, append(groupList(options.cam), "/background")), options.angle, 'bilinear', 'crop'));
dark_img = double(imrotate(h5read(fullFileName, append(groupList(options.cam), "/dark")), options.angle, 'bilinear', 'crop'));
od_img = Helper.calculateODImage(atm_img, bkg_img, dark_img, options.ImagingMode, options.PulseDuration);
catch
warning('\nMissing data in %s, storing NaNs.', fullFileName);
od_img = nan(ny, nx);
bkg_img = nan(ny, nx);
end
% --- Extract scan parameter safely ---
try
info = h5info(fullFileName, '/globals');
attrNames = string({info.Attributes.Name});
if ismember(options.scan_parameter, attrNames)
val = h5readatt(fullFileName, '/globals', options.scan_parameter);
if strcmp(options.scan_parameter,'ps_rot_mag_fin_pol_angle')
val = 180 - val;
end
else
val = NaN;
end
catch
val = NaN;
end
end
function writeFullODImagesToDisk(fullODImageFolder, od_img, bkg_img, scan_val, file_name, idx)
% Writes a single OD/BKG image + scan parameter to a MAT file
matFilePath = fullfile(fullODImageFolder, sprintf('Image_%04d.mat', idx));
OD = single(od_img);
BKG = single(bkg_img);
Scan = single(scan_val);
File = string(file_name);
save(matFilePath, 'OD','BKG','Scan','File','-v7.3');
end
function dataSource = makeDataSourceStruct(folderPath)
% Split by file separators (handles / or \)
parts = regexp(folderPath, '[\\/]', 'split');
% Remove empty parts caused by leading slashes
parts = parts(~cellfun('isempty', parts));
% Extract sequence, date, and run number
% Now the indices are correct:
% parts = {'DyLabNAS', 'Data', 'StructuralPhaseTransition', '2025', '08', '13', '0062'}
sequence = parts{3}; % "StructuralPhaseTransition"
year = parts{4}; % "2025"
month = parts{5}; % "08"
day = parts{6}; % "13"
runStr = parts{7}; % "0062"
% Build date string
dateStr = sprintf('%s/%s/%s', year, month, day);
% Convert run string to number
runNum = str2double(runStr);
% Construct struct inside a cell array
dataSource = {
struct('sequence', sequence, ...
'date', dateStr, ...
'runs', runNum)
};
end