Modified PCA analysis script to run on simulated data.

This commit is contained in:
Karthik 2025-08-11 15:23:16 +02:00
parent 1d178a3d75
commit e3571c12b0

View File

@ -1,78 +1,210 @@
%% STEP 1: Generate synthetic image dataset %% STEP 1: Extract Images
clear; close all; clc; clear; close all; clc;
% Parameters baseDir = 'D:/Results - Numerics/Data_Full3D/PhaseTransition/DTS/Point2';
numImages = 50; % number of images in the dataset JobNumber = 0;
imgSize = [50 50]; % image dimensions runFolder = sprintf('Run_%03d', JobNumber);
savefileName = 'DropletsToStripes'; % Output file name
datafileName = './DropletsToStripes.mat';
reverseOrder = false; % Set this to true to reverse the theta ordering
% Preallocate array TitleString = 'Droplets To Stripes';
images = zeros([imgSize, numImages]);
% Generate base features: a horizontal stripe + diagonal gradient %%
[x, y] = meshgrid(1:imgSize(2), 1:imgSize(1)); baseDir = 'D:/Results - Numerics/Data_Full3D/PhaseTransition/STD/Point2';
JobNumber = 0;
runFolder = sprintf('Run_%03d', JobNumber);
savefileName = 'StripesToDroplets'; % Output file name
datafileName = './StripesToDroplets.mat';
reverseOrder = true; % Set this to true to reverse the theta ordering
for k = 1:numImages TitleString = 'Stripes To Droplets';
% Feature 1: horizontal stripe
stripe = double(y > 20 & y < 30); %%
folderList = dir(baseDir);
% Feature 2: diagonal gradient isValid = [folderList.isdir] & ~ismember({folderList.name}, {'.', '..'});
gradient = (x + y) / max(x(:) + y(:)); folderNames = {folderList(isValid).name};
nimgs = numel(folderNames);
% Random variation in stripe intensity
stripeIntensity = 0.8 + 0.4*randn(1); % Extract theta values from folder names
PolarAngleVals = zeros(1, nimgs);
% Random rotation of gradient strength
gradIntensity = 0.5 + 0.2*randn(1); for k = 1:nimgs
tokens = regexp(folderNames{k}, 'theta_(\d{3})', 'tokens');
% Combine features + Gaussian noise if isempty(tokens)
images(:,:,k) = stripeIntensity*stripe + gradIntensity*gradient + 0.1*randn(imgSize); warning('No theta found in folder name: %s', folderNames{k});
PolarAngleVals(k) = NaN;
else
PolarAngleVals(k) = str2double(tokens{1}{1});
end
end end
%% STEP 2: Visualize some sample images % Choose sort direction
figure; sortDirection = 'ascend';
for i = 1:6 if reverseOrder
subplot(2,3,i); sortDirection = 'descend';
imagesc(images(:,:,i));
axis image off; colormap gray;
title(sprintf('Image %d', i));
end end
sgtitle('Sample Synthetic Images');
% Sort folderNames based on polar angle
[~, sortIdx] = sort(PolarAngleVals, sortDirection);
folderNames = folderNames(sortIdx);
PolarAngleVals = PolarAngleVals(sortIdx); % Optional: if you still want sorted list
imgs = cell(1, nimgs);
alphas = zeros(1, nimgs);
for k = 1:nimgs
folderName = folderNames{k};
SaveDirectory = fullfile(baseDir, folderName, runFolder);
% Extract alpha (theta) again from folder name
tokens = regexp(folderName, 'theta_(\d{3})', 'tokens');
alpha_val = str2double(tokens{1}{1});
alphas(k) = alpha_val;
matPath = fullfile(SaveDirectory, 'psi_gs.mat');
if ~isfile(matPath)
warning('Missing psi_gs.mat in %s', SaveDirectory);
continue;
end
try
Data = load(matPath, 'psi', 'Params', 'Transf', 'Observ');
catch ME
warning('Failed to load %s: %s', matPath, ME.message);
continue;
end
Params = Data.Params;
Transf = Data.Transf;
Observ = Data.Observ;
psi = Data.psi;
if isgpuarray(psi)
psi = gather(psi);
end
if isgpuarray(Observ.residual)
Observ.residual = gather(Observ.residual);
end
% Axes and projection
z = Transf.z * Params.l0 * 1e6;
dz = z(2)-z(1);
if k == 1
x = Transf.x * Params.l0 * 1e6;
y = Transf.y * Params.l0 * 1e6;
% Calculate frequency increment (frequency axes)
Nx = length(x); % grid size along X
Ny = length(y); % grid size along Y
dx = mean(diff(x)); % real space increment in the X direction (in micrometers)
dy = mean(diff(y)); % real space increment in the Y direction (in micrometers)
dvx = 1 / (Nx * dx); % reciprocal space increment in the X direction (in micrometers^-1)
dvy = 1 / (Ny * dy); % reciprocal space increment in the Y direction (in micrometers^-1)
% Create the frequency axes
vx = (-Nx/2:Nx/2-1) * dvx; % Frequency axis in X (micrometers^-1)
vy = (-Ny/2:Ny/2-1) * dvy; % Frequency axis in Y (micrometers^-1)
% Create the Wavenumber axes
kx_full = 2*pi*vx; % Wavenumber axis in X
ky_full = 2*pi*vy; % Wavenumber axis in Y
end
n = abs(psi).^2;
nxy = squeeze(trapz(n * dz, 3));
imgs{k} = nxy;
end
%% STEP 2: Visualize images
figure(1);
set(gcf,'Position',[100 100 950 750])
font = 'Bahnschrift';
t = tiledlayout(4, 3, 'TileSpacing', 'compact', 'Padding', 'compact'); % 1x4 grid
for i = 1:nimgs
ax1 = nexttile;
imagesc(x, y, imgs{i}')
% Define normalized positions (relative to axis limits)
x_offset = 0.025; % 5% offset from the edges
y_offset = 0.025; % 5% offset from the edges
axis square;
hcb = colorbar;
colormap(ax1, Colormaps.plasma());
set(gca, 'FontSize', 14); % For tick labels only
hL = ylabel(hcb, 'Optical Density');
set(hL,'Rotation',-90);
set(gca,'YDir','normal')
% set(gca, 'YTick', linspace(y_min, y_max, 5)); % Define y ticks
% set(gca, 'YTickLabel', flip(linspace(y_min, y_max, 5))); % Flip only the labels
hXLabel = xlabel('x (µm)', 'Interpreter', 'tex');
hYLabel = ylabel('y (µm)', 'Interpreter', 'tex');
hTitle = title('Density', 'Interpreter', 'tex');
set([hXLabel, hYLabel, hL], 'FontName', font)
set([hXLabel, hYLabel, hL], 'FontSize', 14)
set(hTitle, 'FontName', font, 'FontSize', 16, 'FontWeight', 'bold'); % Set font and size for title
end
sgtitle('Ground States');
%% STEP 3: Reshape images into a 2D data matrix %% STEP 3: Reshape images into a 2D data matrix
% Each image is a row, each pixel is a column % Each image will be a row vector, so size(X) = [numImages × numPixels]
X = reshape(images, [], numImages)'; % size: [numImages × numPixels]
% First, convert cell array to numeric 3D array
allImgs = cat(3, imgs{:}); % size: [Nx × Ny × numImages]
% Store image size for reshaping later
imgSize = size(allImgs(:,:,1)); % [Nx, Ny]
% Reshape into 2D matrix for PCA
X = reshape(allImgs, [], nimgs)'; % [numImages × (Nx*Ny)]
%% STEP 4: Perform PCA %% STEP 4: Perform PCA
[coeff, score, latent, tsquared, explained] = pca(X); [coeff, score, latent, tsquared, explained] = pca(X);
% coeff : principal component directions (eigenvectors) in pixel space % coeff : principal component directions (eigenvectors) in pixel space
% score : projection of each image onto the principal components % score : projection of each image onto the principal components
% latent : eigenvalues (variance captured by each PC) % latent : eigenvalues (variance captured by each PC)
% explained : percentage variance explained by each PC % explained : percentage variance explained by each PC
%% STEP 5: Visualize variance explained %% Visualize cumulative variance
figure; figure(2);
pareto(explained); set(gcf,'Position',[100 100 950 750])
xlabel('Principal Component'); cumVar = cumsum(explained);
ylabel('Variance Explained (%)'); plot(cumVar, 'o-', 'LineWidth', 1.5);
title('PCA Variance Explained'); yline(95, '--r', '95% threshold');
xlabel('Number of Principal Components');
ylabel('Cumulative Variance (%)');
title('Minimum number of PCA components required for a basis');
grid on;
%% STEP 6: View first few principal components as "eigenimages" %% Visualize first few principal components
numPCsToShow = 4; numPCsToShow = 7;
figure; figure(3);
set(gcf,'Position',[100 100 950 750])
t = tiledlayout(3, 3, 'TileSpacing', 'compact', 'Padding', 'compact'); % 1x4 grid
for i = 1:numPCsToShow for i = 1:numPCsToShow
pcImage = reshape(coeff(:,i), imgSize); % reshape back to image form pcImage = reshape(coeff(:,i), imgSize); % reshape back to image form
subplot(1,numPCsToShow,i); nexttile;
imagesc(pcImage); imagesc(pcImage)
axis image off; colormap gray; axis image off; colormap(Colormaps.coolwarm());
title(sprintf('PC %d', i)); title(sprintf('PC %d (%.1f%%)', i, explained(i)));
end end
sgtitle('First Principal Components (Eigenimages)'); sgtitle('First Principal Components (Eigenimages)');
%% STEP 7: View projection (scores) in PC space %% Visualize evolution of PCA scores
figure; figure(4);
scatter(score(:,1), score(:,2), 50, 'filled'); set(gcf,'Position',[100 100 950 750])
xlabel('PC 1 Score'); plot(alphas, score(:,1), '-o', 'LineWidth', 1.5, 'DisplayName', 'PC1 Score');
ylabel('PC 2 Score'); hold on;
title('Images in Principal Component Space'); plot(alphas, score(:,2), '-o', 'LineWidth', 1.5, 'DisplayName', 'PC2 Score');
grid on; % plot(alphas, score(:,3), '-o', 'LineWidth', 1.5, 'DisplayName', 'PC3 Score');
% plot(alphas, score(:,4), '-o', 'LineWidth', 1.5, 'DisplayName', 'PC4 Score');
% plot(alphas, score(:,5), '-o', 'LineWidth', 1.5, 'DisplayName', 'PC5 Score');
% plot(alphas, score(:,6), '-o', 'LineWidth', 1.5, 'DisplayName', 'PC6 Score');
% plot(alphas, score(:,7), '-o', 'LineWidth', 1.5, 'DisplayName', 'PC7 Score');
legend('Location', 'northeast');
xlabel('Polar Angle (°)'); ylabel('PC Score');
title('Evolution of PC Scores');
grid on;