From 90dd950e2d8c1495f2be34bbf1629b2fd82b93ae Mon Sep 17 00:00:00 2001 From: Stephen Nneji Date: Mon, 6 Jul 2026 10:09:18 +0100 Subject: [PATCH 1/3] Refactors NS and Dream to exist quicker when stopped --- minimisers/DREAM/functions/DREAM.m | 2 +- minimisers/DREAM/runDREAM.m | 6 ++++++ minimisers/NS/nestedSampler.m | 3 ++- minimisers/NS/runNestedSampler.m | 5 +++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/minimisers/DREAM/functions/DREAM.m b/minimisers/DREAM/functions/DREAM.m index e6481e570..df486d910 100644 --- a/minimisers/DREAM/functions/DREAM.m +++ b/minimisers/DREAM/functions/DREAM.m @@ -222,7 +222,7 @@ if ~strcmpi(controls.display, coderEnums.displayOptions.Off) triggerEvent(coderEnums.eventTypes.Message, sprintf('Optimisation terminated by user\n')); end - break; + return; end end diff --git a/minimisers/DREAM/runDREAM.m b/minimisers/DREAM/runDREAM.m index 73e98ea05..c2845dd6a 100644 --- a/minimisers/DREAM/runDREAM.m +++ b/minimisers/DREAM/runDREAM.m @@ -87,6 +87,12 @@ % Run the sampler.... [chain,dreamOutput,~] = DREAM(DREAMPar,ParInfo,ratInputs); +if isRATStopped(controls.IPCFilePath) + result = makeEmptyResultStruct(problemStruct.numberOfContrasts, length(problemStruct.fitParams), domains); + outProblemStruct = problemStruct; + return +end + % Combine all chains.... nChains = DREAMPar.nChains; nParams = DREAMPar.nParams; diff --git a/minimisers/NS/nestedSampler.m b/minimisers/NS/nestedSampler.m index e7a4f98b4..f7ce16ea7 100644 --- a/minimisers/NS/nestedSampler.m +++ b/minimisers/NS/nestedSampler.m @@ -263,7 +263,8 @@ if ~strcmpi(controls.display, coderEnums.displayOptions.Off) triggerEvent(coderEnums.eventTypes.Message, sprintf('Optimisation terminated by user\n')); end - break; + post_samples = []; + return; end % update counter j = j+1; diff --git a/minimisers/NS/runNestedSampler.m b/minimisers/NS/runNestedSampler.m index 0a8310e72..1ab17893c 100644 --- a/minimisers/NS/runNestedSampler.m +++ b/minimisers/NS/runNestedSampler.m @@ -49,6 +49,11 @@ [logZ, nestSamples, postSamples, H] = nestedSampler(data, nLive, nMCMC,... tolerance, likelihood, model, priorList, fitNames); +if isRATStopped(controls.IPCFilePath) + result = makeEmptyResultStruct(problemStruct.numberOfContrasts, length(problemStruct.fitParams), domains); + return +end + % Process the results... nParams = length(fitNames); % chain = nest_samples(:,1:end-1); From 84c10c9b39a4b72bb7008d496c89d4e275e48924 Mon Sep 17 00:00:00 2001 From: Stephen Nneji Date: Wed, 8 Jul 2026 14:31:40 +0100 Subject: [PATCH 2/3] Refactors alignALProfiles and make it work for bayes and live plot. --- API/events/triggerEvent.m | 10 +++- utilities/plotting/alignALProfiles.m | 71 ++++++++++++++++++++++++++++ utilities/plotting/bayesShadedPlot.m | 9 ++-- utilities/plotting/plotRefSLD.m | 64 ++----------------------- 4 files changed, 87 insertions(+), 67 deletions(-) create mode 100644 utilities/plotting/alignALProfiles.m diff --git a/API/events/triggerEvent.m b/API/events/triggerEvent.m index 7fe8ecd49..ba13892c1 100644 --- a/API/events/triggerEvent.m +++ b/API/events/triggerEvent.m @@ -30,13 +30,15 @@ function triggerEvent(eventType, varargin) problemStruct = varargin{2}; plotData.reflectivity = result.reflectivity; plotData.shiftedData = result.shiftedData; - plotData.sldProfiles = result.sldProfiles; - plotData.resampledLayers = result.resampledLayers; plotData.subRoughs = result.contrastParams.subRoughs; plotData.resample = problemStruct.resample; plotData.dataPresent = problemStruct.dataPresent; plotData.modelType = problemStruct.modelType; plotData.contrastNames = problemStruct.names.contrasts; + + [slds, resampledLayers, ~] = alignALProfiles(problemStruct.geometry, problemStruct.modelType, result.sldProfiles, result.resampledLayers, {}); + plotData.sldProfiles = slds; + plotData.resampledLayers = resampledLayers; eventManager.notify(eventType, plotData); end @@ -62,6 +64,10 @@ function triggerEvent(eventType, varargin) elseif eventType == coderEnums.eventTypes.Plot result = varargin{1}; problemStruct = varargin{2}; + [slds, resampledLayers, ~] = alignALProfiles(problemStruct.geometry, problemStruct.modelType, result.sldProfiles, result.resampledLayers, {}); + result.sldProfiles = slds; + result.resampledLayers = resampledLayers; + subRoughs = result.contrastParams.subRoughs; nContrast = length(result.reflectivity); [reflect, nReflect] = packCellArray(result.reflectivity, 1); diff --git a/utilities/plotting/alignALProfiles.m b/utilities/plotting/alignALProfiles.m new file mode 100644 index 000000000..3b1511bb1 --- /dev/null +++ b/utilities/plotting/alignALProfiles.m @@ -0,0 +1,71 @@ +function [sldProfiles, resampledLayers, pIntervals] = alignALProfiles(geometry, modelType, sldProfiles, resampledLayers, pIntervals) +% Aligns the A/L SLD profiles so that the substrates line up by padding the +% start of any shorter than the longest profile. Also adjusts resampled +% layers and prediction interval slds as necessary. +% +% Parameters +% ---------- +% geometry : geometryOptions +% The geometry. +% modelType : modelTypes +% The model type. +% sldProfiles : cell +% The sld profiles. +% resampledLayers : cell +% The resampled layers. +% pIntervals : cell +% The slds in the prediction intervals. +% +% Returns +% ------- +% sldProfiles : cell +% The sld profiles, adjusted if necessary. +% resampledLayers : cell +% The resampled layers, adjusted if necessary. +% pIntervals : cell +% The slds in the prediction intervals, adjusted if necessary. + +if ~strcmpi(geometry,'air/substrate') || strcmpi(modelType,'custom xy') + return +end + +% Find the length of the longest profile. +lengths = zeros(size(sldProfiles)); +for i = 1:numel(sldProfiles) + lengths(i) = size(sldProfiles{i}, 1); +end +% Get max length and its index +[maxLen, maxPos] = max(lengths); +maxPos = maxPos(1); +maxLen = maxLen (1); + +maxXValue = sldProfiles{maxPos}(end,1); + +% Get the longest profile... +maxX = sldProfiles{maxPos}(:,1); + +% Pad the start of any profiles that are shorter than this +for i = 1:numel(sldProfiles) + thisSLD = sldProfiles{i}; + thisLen = size(thisSLD,1); + if thisLen < maxLen + diffLen = maxLen - thisLen; + pad = zeros(diffLen,1); + newY = [pad ; thisSLD(:,2)]; + sldProfiles{i} = [maxX(:,1) newY(:)]; + + % For resampled layers, the pad is just one big layer at the start + thisResam = resampledLayers{i}; + if any(thisResam,'all') % not all zeros + totLength = sum(thisResam(:,1)); + padLength = maxXValue - totLength; + resamPad = [padLength 0 0]; + resampledLayers{i} = [resamPad ; thisResam]; + end + + if ~isempty(pIntervals) + pIntervals{i} = [zeros(5, diffLen), pIntervals{i}]; + end + end +end +end diff --git a/utilities/plotting/bayesShadedPlot.m b/utilities/plotting/bayesShadedPlot.m index 38351a8e1..b3141cfa6 100644 --- a/utilities/plotting/bayesShadedPlot.m +++ b/utilities/plotting/bayesShadedPlot.m @@ -50,10 +50,11 @@ function bayesShadedPlot(project, result, options) controls = controlsClass(); [projectStruct,~] = parseClassToStructs(project,controls); +[sldProfiles, ~, pIntervals] = alignALProfiles(projectStruct.geometry, projectStruct.modelType, result.sldProfiles, result.resampledLayers, result.predictionIntervals.sld); % Get the reflectivities and SLDs reflectivityValues = result.predictionIntervals.reflectivity; -sldValues = result.predictionIntervals.sld; +sldValues = pIntervals; shiftedData = result.shiftedData; numberOfContrasts = length(shiftedData); @@ -118,7 +119,7 @@ function bayesShadedPlot(project, result, options) subplot(1,2,2); hold on; box on xlabel('$\textrm{Z} (\AA)$','Interpreter','Latex') ylabel('$\textrm{SLD} (\AA^{-2})$','Interpreter','Latex') -nColumns = size(result.sldProfiles, 2); +nColumns = size(sldProfiles, 2); lines = cell(numberOfContrasts * nColumns, 1); names = cell(numberOfContrasts * nColumns, 1); @@ -128,7 +129,7 @@ function bayesShadedPlot(project, result, options) sld = sldValues{i}(3,:); limits = sldValues{i}; - sldXValues = result.sldProfiles{i}(:,1); + sldXValues = sldProfiles{i}(:,1); min = limits(vals(1),:); max = limits(vals(2),:); @@ -145,7 +146,7 @@ function bayesShadedPlot(project, result, options) sld = sldValues(i,:); limits = sldValues(i,:); - sldXValues = result.sldProfiles(i,:); + sldXValues = sldProfiles(i,:); for j = 1:2 min = limits{j}(vals(1),:); diff --git a/utilities/plotting/plotRefSLD.m b/utilities/plotting/plotRefSLD.m index f3920ac30..383d8250f 100644 --- a/utilities/plotting/plotRefSLD.m +++ b/utilities/plotting/plotRefSLD.m @@ -37,72 +37,14 @@ function plotRefSLD(project, result, options) data.reflectivity = result.reflectivity; data.shiftedData = result.shiftedData; - data.sldProfiles = result.sldProfiles; - data.resampledLayers = result.resampledLayers; data.dataPresent = projectStruct.dataPresent; data.subRoughs = result.contrastParams.subRoughs; data.resample = projectStruct.resample; data.contrastNames = projectStruct.names.contrasts; - % If we have air/substrate geometry, modify the SLD profiles slightly - % so that the substrates line up (for custom XY the user does this - % themselves)... - if strcmpi(projectStruct.geometry,'air/substrate') && ~strcmpi(projectStruct.modelType,'custom xy') - data = alignALProfiles(data); - end - + [slds, resampledLayers, ~] = alignALProfiles(projectStruct.geometry, projectStruct.modelType, result.sldProfiles, result.resampledLayers, {}); + data.sldProfiles = slds; + data.resampledLayers = resampledLayers; plotRefSLDHelper(data, false, options.linearX, options.q4, options.showErrorBar, ... options.showGrid, options.showLegend, options.shiftValue); end - - -function data = alignALProfiles(data) -% Aligns the A/L SLD profiles so that the substrates line up by padding the -% start of any shorter than the longest profile.. - -% Get the sld profiles out of data -slds = data.sldProfiles; -resamLays = data.resampledLayers; - -% Find the length of the longest profile... -f = @(x)size(x{:},1); -lengths = arrayfun(f,slds); -maxPos = find(lengths == max(lengths)); - -% If maxPos is an array we have many of equal (leng) length. -% We can just pick one of them... -if length(maxPos) > 1 - maxPos = maxPos(1); -end - -maxLen = lengths(maxPos); -max_XValue = slds{maxPos}(end,1); - -% Get the longest profile... -max_X = slds{maxPos}(:,1); - -% Pad the start of any profiles that are shorter than this -for i = 1:length(slds) - thisSLD = slds{i}; - thisLen = size(thisSLD,1); - if thisLen < maxLen - diffLen = maxLen - thisLen; - pad = zeros(diffLen,1); - newY = [pad ; thisSLD(:,2)]; - slds{i} = [max_X(:,1) newY(:)]; - - % For resampled layers, the pad is just one big layer at the start - thisResam = resamLays{i}; - if ~all(thisResam,'All') % not all zeros - totLength = sum(thisResam(:,1)); - padLength = max_XValue - totLength; - resamPad = [padLength 0 0]; - resamLays{i} = [resamPad ; thisResam]; - end - end -end - -data.sldProfiles = slds; -data.resampledLayers = resamLays; - -end \ No newline at end of file From 89c191690638370db6f37c2eb04228ca50162c07 Mon Sep 17 00:00:00 2001 From: Stephen Nneji Date: Fri, 10 Jul 2026 10:03:57 +0100 Subject: [PATCH 3/3] Address review comment --- utilities/plotting/alignALProfiles.m | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/utilities/plotting/alignALProfiles.m b/utilities/plotting/alignALProfiles.m index 3b1511bb1..7ef91d992 100644 --- a/utilities/plotting/alignALProfiles.m +++ b/utilities/plotting/alignALProfiles.m @@ -34,11 +34,9 @@ for i = 1:numel(sldProfiles) lengths(i) = size(sldProfiles{i}, 1); end -% Get max length and its index -[maxLen, maxPos] = max(lengths); -maxPos = maxPos(1); -maxLen = maxLen (1); +% Get max length and its index +[maxLen, maxPos] = max(lengths, [], "all"); maxXValue = sldProfiles{maxPos}(end,1); % Get the longest profile...