Skip to content

Feature:gia2plmt-SELEN compatibility#33

Draft
williameclee wants to merge 12 commits intofeature/selenfrom
feature/gia2plmt-selen-compatibility
Draft

Feature:gia2plmt-SELEN compatibility#33
williameclee wants to merge 12 commits intofeature/selenfrom
feature/gia2plmt-selen-compatibility

Conversation

@williameclee
Copy link
Copy Markdown
Owner

No description provided.

@williameclee williameclee requested a review from Copilot April 1, 2026 18:25
@williameclee williameclee self-assigned this Apr 1, 2026
@williameclee williameclee added the feature New feature or request label Apr 1, 2026
@williameclee williameclee marked this pull request as draft April 1, 2026 18:25
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds MATLAB utilities to improve compatibility with SELEN model outputs and to standardize longitude/latitude input parsing and axis tick formatting across plotting helpers.

Changes:

  • Added convertSelenModel to convert SELEN gdot.pix/udot.pix outputs into SLEPIAN-style spherical harmonic .mat files.
  • Added parselonlatinputs to accept lon/lat pairs, lonlat matrices, polyshape, or GeoDomain inputs and return normalized lon/lat plus remaining arguments.
  • Added formatlonticks / formatlatticks to format axes tick labels as geographic coordinates.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 9 comments.

File Description
plotting/parselonlatinputs.m New helper to normalize lon/lat-like inputs for plotting/geometry utilities.
plotting/formatlonticks.m New helper to format x-axis ticks as longitudes.
plotting/formatlatticks.m New helper to format y-axis ticks as latitudes.
dataio/convertSelenModel.m New converter from SELEN output grids to SLEPIAN-compatible coefficient files.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread plotting/formatlonticks.m
Comment thread plotting/formatlonticks.m
Comment thread plotting/formatlonticks.m
Comment thread plotting/formatlatticks.m
Comment thread plotting/formatlatticks.m
Comment thread plotting/parselonlatinputs.m Outdated
Comment thread dataio/convertSelenModel.m Outdated
Comment thread dataio/convertSelenModel.m Outdated
Comment thread dataio/convertSelenModel.m Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 24 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread plotting/formatlonticks.m
Comment thread aux/addanchors.m
Comment on lines +67 to +75
if isempty(needsAnchor)

if nargout == 1

if isPoly
varargout = {p};
else
varargout = {[lon, lat]};
end
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When needsAnchor is empty and the input was a polyshape, this path returns {p} but p is undefined (it was overwritten by vertices). This will throw even though no anchors are needed. Consider returning the original polyshape (store it before overwriting), or reconstruct it from lon/lat (e.g., polyshape(lon, lat, ...)).

Copilot uses AI. Check for mistakes.
Comment thread solvesle.m
if ~beQuiet
wbar = waitbar(0, 'Initialising', ...
"Name", upper(mfilename), "CreateCancelBtn", 'setappdata(gcbf,''canceling'',1)');
cleanup = onCleanup(@() delete(wbar));
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The added onCleanup(@() delete(wbar)) will run even if wbar is deleted manually later (this function calls delete(wbar) in several places). That can lead to a double-delete and an error on function exit. Consider making the cleanup callback resilient (e.g., check ishghandle/isvalid before deleting), or stop manually deleting wbar and rely on the cleanup (or clear the cleanup handle after manual delete).

Suggested change
cleanup = onCleanup(@() delete(wbar));
cleanup = onCleanup(@() (ishghandle(wbar) && delete(wbar)));

Copilot uses AI. Check for mistakes.
Comment thread solvedegree1.m
Comment on lines 165 to 169
%% Loading data
wbar = waitbar(0, 'Loading GRACE data', ...
"Name", upper(mfilename), "CreateCancelBtn", 'setappdata(gcbf,''canceling'',1)');
cleanup = onCleanup(@() delete(wbar));

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as in solvesle: onCleanup(@() delete(wbar)) is added, but the function still manually calls delete(wbar) on cancellation and at the end. This can double-delete the handle and error during cleanup. Make the cleanup callback safe (check handle validity) or remove/replace the manual deletes.

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +39
modelName = regexp(modelFolderSelf, "RUN_([A-Za-z0-9-_]+)", "tokens", "once");
modelInfo = regexp(modelFolderSelf, "RUN_([A-Za-z0-9]+)-R(\d+)-L(\d+)-I(\d+)", "tokens", "once");

% Prepare grid for interpolation
L = str2double(modelInfo{3});
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modelName is extracted via regexp(...,'tokens','once'), which returns a cell array; passing that directly to sprintf('%s_SD.mat', modelName) will error. Also, modelInfo is parsed with a pattern that doesn’t allow dashes/underscores in the model name; if the folder name includes them (allowed by the modelName regex), modelInfo will be empty and modelInfo{3} will error. Consider normalising to string/char (modelName = string(modelName{1})) and validating modelInfo before indexing (or use a single regex that captures name and L robustly).

Suggested change
modelName = regexp(modelFolderSelf, "RUN_([A-Za-z0-9-_]+)", "tokens", "once");
modelInfo = regexp(modelFolderSelf, "RUN_([A-Za-z0-9]+)-R(\d+)-L(\d+)-I(\d+)", "tokens", "once");
% Prepare grid for interpolation
L = str2double(modelInfo{3});
modelInfo = regexp(modelFolderSelf, "^RUN_([A-Za-z0-9_-]+)-R(\d+)-L(\d+)-I(\d+)$", "tokens", "once");
if isempty(modelInfo)
error("convertSelenModel:InvalidModelFolderName", ...
"Model folder name '%s' does not match expected pattern RUN_<name>-R<number>-L<number>-I<number>.", ...
modelFolderSelf);
end
modelName = modelInfo{1};
% Prepare grid for interpolation
L = str2double(modelInfo{3});
if isnan(L)
error("convertSelenModel:InvalidModelDegree", ...
"Unable to parse spherical harmonic degree L from model folder name '%s'.", ...
modelFolderSelf);
end

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +82
if ~isempty(newModel)
newModel = sprintf("%s-%s_V%s_T%s", newModel, upper(icesheet), ...
replace(replace(sprintf("%+03.0f", volumeChangeFrac * 100), "+", "p"), "-", "n"), ...
replace(replace(sprintf("%+03d", timeDelay), "+", "p"), "-", "n"));
end

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newModel naming logic appears inverted: the doc says an empty newModel should trigger auto-generation, but the code only modifies newModel when it is not empty. As written, leaving newModel empty will produce newModelPath pointing at the SELEN/DATA folder (and fopen will fail). Also, newModelPath does not append the .pix extension even though the input model is .pix. Consider generating a default filename when newModel is empty and ensuring the output path ends with .pix.

Suggested change
if ~isempty(newModel)
newModel = sprintf("%s-%s_V%s_T%s", newModel, upper(icesheet), ...
replace(replace(sprintf("%+03.0f", volumeChangeFrac * 100), "+", "p"), "-", "n"), ...
replace(replace(sprintf("%+03d", timeDelay), "+", "p"), "-", "n"));
end
newModelBase = char(newModel);
if isempty(newModelBase)
newModelBase = char(model);
end
newModel = sprintf("%s-%s_V%s_T%s", newModelBase, upper(icesheet), ...
replace(replace(sprintf("%+03.0f", volumeChangeFrac * 100), "+", "p"), "-", "n"), ...
replace(replace(sprintf("%+03d", timeDelay), "+", "p"), "-", "n"));
if ~endsWith(newModel, ".pix")
newModel = strcat(newModel, ".pix");
end

Copilot uses AI. Check for mistakes.
Comment thread domains/icesheetPoly.m Outdated
@@ -0,0 +1,55 @@
%% ICESHEETPOLY - Gets approximate
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header line is incomplete ("Gets approximate") and doesn’t describe what the function returns (ice sheet polygon). Consider updating the first doc line to a complete summary consistent with other functions’ headers.

Suggested change
%% ICESHEETPOLY - Gets approximate
%% ICESHEETPOLY - Gets an approximate ice sheet polygon

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants