Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New cubed sphere 2 grid #245

Draft
wants to merge 17 commits into
base: develop
Choose a base branch
from

Conversation

mo-jonasganderton
Copy link

Description

Initial implementation of a new cubed sphere grid.

@odlomax and @wdeconinck can both have a look over to recommend any changes - I expect this will have changed once everything else has also been implemented.

Using this implementation generates the following lonlat points - n=12, red=tile0, purple=tile5, darkest point of each colour is tij=0, lightest point is tij=143. This matches the sequence of the points in the LFRic cubed sphere.
CubedSphere_3_0_2

Impact

Once everything else is also implemented, this makes the cubed sphere more maintainable.

Checklist

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • I have run the unit tests before creating the PR

@FussyDuck
Copy link

FussyDuck commented Nov 22, 2024

CLA assistant check
All committers have signed the CLA.

Copy link
Contributor

@odlomax odlomax left a comment

Choose a reason for hiding this comment

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

Looks good to see a much simpler CS grid! I've added some changes. It's mostly style related. I'm sure @wdeconinck can make some more comments/suggestions.

After this, we should probably plumb the grid into the grid builder.

@wdeconinck, what do you think?


std::string CubedSphere2::name() const {
return "CS-LFR-" + std::to_string(N_) + "-2";
}
Copy link
Contributor

Choose a reason for hiding this comment

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

You should add some tests to check the return values of these functions. It should be relatively straightforward to add a new section to your test that checks the basic API.

Grid::Spec CubedSphere2::spec() const {
Grid::Spec grid_spec;

if (type() == "cubedsphere2") {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't believe we need this if, else structure around the code. Also, for completeness we should add the domain spec to grid_spec.

// Private methods

// Get tile of point given global index
int CubedSphere2::get_tile(idx_t n) const {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this tij index logic could be a bit more readable and with less duplication if we did:

using CSIndices = std::array<idx_t, 3>;

// Useful to have this a public method
idx_t CubedSphere2::N() const {return N_;}

CSIndices CubedSphere2::get_cs_indices(gidx_t n) const {
   ATLAS_ASSERT(n >= size());
   const idx_t tile_size = N() * N();
   const idx_t t = n / tile_size;
   const idx_t ij = n % tile_size;
   const idx_t j = ij / N();
   const idx_t i = ij % N();
   return {t, i, j};
}

You can then use auto [t, i, j] = get_cs_indicies(...) to set separate t, i and j values if you need to.

idx_t N_;

// Number of tiles
static const idx_t nTiles_ = 6;
Copy link
Contributor

Choose a reason for hiding this comment

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

might as well make nTiles_ constexpr.


private:
std::string type_ = {"cubedsphere2"};
static constexpr int lfric_rotations_[6][9] = {
Copy link
Contributor

@odlomax odlomax Nov 22, 2024

Choose a reason for hiding this comment

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

This should be more expressive. For example:

using col = int;
using row = std::array<col, 3>;
using matrix = std::array<row, 3>;

std::array<matrix, nTiles_> rotations_ {matrix{row{0, 0, 1},
                                              row{1, 0, 0},
                                              row{0, -1, 0}},
                                       matrix...}


// Get point between [-pi/4..pi/4] given index and number of points along edge
// Applies offset to get from prime to dual mesh
double CubedSphere2::index_to_curvilinear(idx_t index) const {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the intent is clearer if we define:

using PointAlphaBeta = Point2;

PointAlphaBeta CubedSphere2::ij_to_curvilinear_coord(idx_t i, idx_t j) {
  const auto get_coord = [&](idx_t idx){
    return M_PI / 2 * (-0.5 + (0.5 + idx) / N());
  };
  return {get_coord(i), get_coord(j)};
}

PointXY CubedSphere2::curvilinear_to_tangent_coord(const PointAlphaBeta& curvi_coord) {
  return {std::tan(curvi_coord[0]), std::tan(curvi_coord[1])};
}

PointXYZ CubedSphere2::tangent_to_xyz_coord(const PointXY& tan_coord) {
  /// Perform coordinate rotations...
}

void xy(idx_t n, Point2& point) const;
Point2 xy(idx_t n) const;

void lonlat(idx_t n, Point2& point) const {xy(n, point);}
Copy link
Contributor

Choose a reason for hiding this comment

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

You want to call projection_.xy2lonlat(xy) here.

+ lfric_rotations_[tile][8] * base_point[2];

// 3. Project the point onto a (cubed)sphere
point[0] = std::atan2(xyz[1], xyz[0]) * rad_to_deg_;
Copy link
Contributor

Choose a reason for hiding this comment

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

eckit has cartesian to spherical transforms already implemented here.

Also the degrees to radians constants are already defined here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants