atlas
CubedSphere.h
1 /*
2  * (C) Copyright 2020 UCAR
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  */
7 
8 #pragma once
9 
10 #include <array>
11 #include <functional>
12 #include <iostream>
13 #include <memory>
14 #include <numeric>
15 #include <vector>
16 
17 #include "eckit/types/Types.h"
18 
19 #include "atlas/array.h"
20 #include "atlas/grid/Spacing.h"
21 #include "atlas/grid/Tiles.h"
22 #include "atlas/grid/detail/grid/Grid.h"
23 #include "atlas/library/config.h"
24 #include "atlas/projection/detail/CubedSphereProjectionBase.h"
25 #include "atlas/runtime/Exception.h"
26 #include "atlas/runtime/Log.h"
27 #include "atlas/util/CoordinateEnums.h"
28 #include "atlas/util/Object.h"
29 #include "atlas/util/ObjectHandle.h"
30 #include "atlas/util/Point.h"
31 
32 namespace atlas {
33 namespace grid {
34 namespace detail {
35 namespace grid {
36 
37 
48 
49 class CubedSphere : public Grid {
50 private:
51  // Get the position in the xy plane and return as PointXY object
52  struct ComputePointXY {
53  ComputePointXY( const CubedSphere& grid ) : grid_( grid ) {}
54  void operator()( idx_t i, idx_t j, idx_t t, PointXY& point ) { grid_.xy( i, j, t, point.data() ); }
55  const CubedSphere& grid_;
56  };
57 
58  // Get the lonlat and return as PointLonLat object
59  struct ComputePointLonLat {
60  ComputePointLonLat( const CubedSphere& grid ) : grid_( grid ) {}
61  void operator()( idx_t i, idx_t j, idx_t t, PointLonLat& point ) { grid_.lonlat( i, j, t, point.data() ); }
62  const CubedSphere& grid_;
63  };
64 
65  class PointTIJ : public std::array<idx_t, 3> {
66  public:
67  using std::array<idx_t, 3>::array;
68  idx_t t() const { return data()[0]; }
69  idx_t i() const { return data()[1]; }
70  idx_t j() const { return data()[2]; }
71  idx_t& t() { return data()[0]; }
72  idx_t& i() { return data()[1]; }
73  idx_t& j() { return data()[2]; }
74  };
75 
76  struct ComputePointTIJ {
77  ComputePointTIJ( const CubedSphere& grid ) : grid_( grid ) {}
78  void operator()( idx_t i, idx_t j, idx_t t, PointTIJ& point ) {
79  point.t() = t;
80  point.i() = i;
81  point.j() = j;
82  }
83  const CubedSphere& grid_;
84  };
85 
86  // -----------------------------------------------------------------------------------------------
87 
88  template <typename Base, typename ComputePoint>
89  class CubedSphereIterator : public Base {
90  public:
91  // Create an iterator and return the first or last point. If begin is true it starts at the
92  // beginning of the iterator, otherwise at the end. Class is templated and point can be xy or
93  // lonlat.
94  CubedSphereIterator( const CubedSphere& grid, bool begin = true ) :
95  grid_( grid ),
96  i_( begin ? 0 : grid_.N() ),
97  j_( begin ? 0 : grid_.N() ),
98  t_( begin ? 0 : 5 ),
99  size_( grid_.size() ),
100  n_( begin ? 0 : size_ ),
101  compute_point{grid_} {
102  // Check that point lies in grid and if so return the xy/lonlat
103  if ( grid_.inGrid( i_, j_, t_ ) ) {
104  compute_point( i_, j_, t_, point_ );
105  }
106  }
107 
108  // Return the point and move iterator to the next location
109  virtual bool next( typename Base::value_type& point ) {
110  if ( n_ != size_ ) {
111  compute_point( i_, j_, t_, point );
112  std::unique_ptr<int[]> ijt = grid_.nextElement( i_, j_, t_ );
113  i_ = ijt[0];
114  j_ = ijt[1];
115  t_ = ijt[2];
116  ++n_;
117  return true;
118  }
119  return false;
120  }
121 
122  // * operator
123  virtual const typename Base::reference operator*() const { return point_; }
124 
125  // ++ operator, move to next element in grid iterator and return point
126  virtual const Base& operator++() {
127  std::unique_ptr<int[]> ijt = grid_.nextElement( i_, j_, t_ );
128  i_ = ijt[0];
129  j_ = ijt[1];
130  t_ = ijt[2];
131  ++n_;
132  if ( n_ != size_ ) {
133  compute_point( i_, j_, t_, point_ );
134  }
135  return *this;
136  }
137 
138  // += operator, move some distance d through the iterator and return point
139  virtual const Base& operator+=( typename Base::difference_type distance ) {
140  idx_t d = distance;
141  // Following loop could be optimised to not iterate through every point,
142  // but rather jump through a tile at a time if possible.
143  // Then OpenMP algorithms can be made much quicker.
144  for ( int n = 0; n < d; n++ ) {
145  std::unique_ptr<int[]> ijt = grid_.nextElement( i_, j_, t_ );
146  i_ = ijt[0];
147  j_ = ijt[1];
148  t_ = ijt[2];
149  }
150  n_ += d;
151  if ( n_ != size_ ) {
152  compute_point( i_, j_, t_, point_ );
153  }
154  return *this;
155  }
156 
157  // Given two positions in the grid iterator return the distance, which for the cubed-sphere
158  // grid is just the number of grid points between the two points.
159  virtual typename Base::difference_type distance( const Base& other ) const {
160  const auto& _other = static_cast<const CubedSphereIterator&>( other );
161  typename Base::difference_type d = 0;
162  idx_t i = i_;
163  idx_t j = j_;
164  idx_t t = t_;
165  bool found = false;
166  for ( int n = 0; n < grid_.size(); n++ ) {
167  if ( i == _other.i_ && j == _other.j_ && t == _other.t_ ) {
168  found = true;
169  break;
170  }
171  std::unique_ptr<int[]> ijt = grid_.nextElement( i, j, t );
172  i = ijt[0];
173  j = ijt[1];
174  t = ijt[2];
175  ++d;
176  }
177  ATLAS_ASSERT( !found, "CubedSphereIterator.distance: cycled entire grid without finding other" );
178  return d;
179  }
180 
181  // == operator for checking two positions in the iterator are equal
182  virtual bool operator==( const Base& other ) const {
183  return i_ == static_cast<const CubedSphereIterator&>( other ).i_ &&
184  j_ == static_cast<const CubedSphereIterator&>( other ).j_ &&
185  t_ == static_cast<const CubedSphereIterator&>( other ).t_;
186  }
187 
188  // != operator for checking that two positions in the iterator are not equal
189  virtual bool operator!=( const Base& other ) const {
190  return i_ != static_cast<const CubedSphereIterator&>( other ).i_ ||
191  j_ != static_cast<const CubedSphereIterator&>( other ).j_ ||
192  t_ != static_cast<const CubedSphereIterator&>( other ).t_;
193  }
194 
195  // Clone the grid iterator
196  virtual std::unique_ptr<Base> clone() const {
197  auto result = new CubedSphereIterator( grid_, false );
198  result->i_ = i_;
199  result->j_ = j_;
200  result->t_ = t_;
201  result->point_ = point_;
202  result->size_ = size_;
203  result->n_ = n_;
204  return std::unique_ptr<Base>( result );
205  }
206 
207  const CubedSphere& grid_;
208  idx_t i_;
209  idx_t j_;
210  idx_t t_;
211  idx_t size_;
212  idx_t n_;
213  typename Base::value_type point_;
214  ComputePoint compute_point;
215  };
216 
217  // -----------------------------------------------------------------------------------------------
218 
219 public:
220  // Iterators for returning xy or lonlat
221  using IteratorXY = CubedSphereIterator<Grid::IteratorXY, ComputePointXY>;
222  using IteratorLonLat = CubedSphereIterator<Grid::IteratorLonLat, ComputePointLonLat>;
223 
224  class IteratorTIJ_Base : public IteratorT<IteratorTIJ_Base, PointTIJ> {};
225  using IteratorTIJ = CubedSphereIterator<IteratorTIJ_Base, ComputePointTIJ>;
226 
227  static std::string static_type();
228 
229  // Constructors
230  CubedSphere( const std::string&, int, Projection, const std::string& stagger );
231  CubedSphere( int, Projection, const std::string& stagger );
232  CubedSphere( const CubedSphere& );
233 
234  // Destructor
235  virtual ~CubedSphere() override;
236 
237  // Return total grid size
238  virtual idx_t size() const override { return accumulate( npts_.begin(), npts_.end(), 0 ); }
239 
240  // Return information about the grid
241  virtual Spec spec() const override;
242  virtual std::string name() const override;
243  virtual std::string type() const override;
244 
245  // Return number of faces on cube
246  inline idx_t N() const { return N_; }
247 
248  // Access to the tile class
249  inline atlas::grid::CubedSphereTiles tiles() const { return tiles_; }
250 
251  // Tile specific access to x and y locations
252  // -----------------------------------------
253 
254  inline double xsPlusIndex( idx_t idx, idx_t t ) const {
255  return static_cast<double>( xs_[t] ) + static_cast<double>( idx );
256  }
257 
258  inline double xsrMinusIndex( idx_t idx, idx_t t ) const {
259  return static_cast<double>( xsr_[t] ) - static_cast<double>( idx );
260  }
261 
262  inline double ysPlusIndex( idx_t idx, idx_t t ) const {
263  return static_cast<double>( ys_[t] ) + static_cast<double>( idx );
264  }
265 
266  inline double ysrMinusIndex( idx_t idx, idx_t t ) const {
267  return static_cast<double>( ysr_[t] ) - static_cast<double>( idx );
268  }
269 
270  // Lambdas for access to appropriate functions for tile
271  // ----------------------------------------------------
272 
273  std::vector<std::function<double( int, int, int )>> xtile;
274  std::vector<std::function<double( int, int, int )>> ytile;
275 
276  // Functions for returning xy
277  // --------------------------
278 
279  inline void xyt( idx_t i, idx_t j, idx_t t, double crd[] ) const {
280  crd[0] = xtile.at( t )( i, j, t );
281  crd[1] = ytile.at( t )( i, j, t );
282  crd[2] = static_cast<double>( t );
283  }
284 
285  PointXY xyt( idx_t i, idx_t j, idx_t t ) const {
286  return PointXY( xtile.at( t )( i, j, t ), ytile.at( t )( i, j, t ) );
287  }
288 
289  inline void xy( idx_t i, idx_t j, idx_t t, double xy[] ) const {
290  double crd[3];
291  this->xyt( i, j, t, crd );
292  this->xyt2xy( crd, xy );
293  }
294 
295  PointXY xy( idx_t i, idx_t j, idx_t t ) const {
296  double crd[2];
297  this->xy( i, j, t, crd );
298  return PointXY( crd[0], crd[1] );
299  }
300 
301  // Functions for returning lonlat, either as array or PointLonLat
302  // --------------------------------------------------------------
303 
304  void lonlat( idx_t i, idx_t j, idx_t t, double lonlat[] ) const {
305  this->xy( i, j, t, lonlat ); // outputing xy in lonlat
306  projection_.xy2lonlat( lonlat ); // converting xy to lonlat
307  }
308 
309  PointLonLat lonlat( idx_t i, idx_t j, idx_t t ) const {
310  double lonlat[2];
311  this->lonlat( i, j, t, lonlat );
312  return PointLonLat( lonlat[LON], lonlat[LAT] );
313  }
314 
315  // Check whether i, j, t is in grid
316  // --------------------------------
317  inline bool inGrid( idx_t i, idx_t j, idx_t t ) const {
318  constexpr idx_t tmax = 5;
319  if ( t >= 0 && t <= tmax ) {
320  if ( j >= jmin_[t] && j <= jmax_[t] ) {
321  if ( i >= imin_[t][j] && i <= imax_[t][j] ) {
322  return true;
323  }
324  }
325  }
326  return false;
327  }
328 
329  // Check on whether the final element
330  // ----------------------------------
331 
332  bool finalElement( idx_t i, idx_t j, idx_t t ) const {
333  constexpr idx_t tmax = 5;
334  if ( t == tmax ) {
335  idx_t jmax = jmax_[tmax];
336  if ( j == jmax ) {
337  if ( i == imax_[tmax][jmax] ) {
338  return true;
339  }
340  }
341  }
342  return false;
343  }
344 
345  // Move to next grid element in an iterator
346  // ----------------------------------------
347 
348  // Note that i is the fastest index, followed by j, followed by t
349  std::unique_ptr<int[]> nextElement( const idx_t i, const idx_t j, const idx_t t ) const {
350  std::unique_ptr<int[]> ijt( new int[3] );
351 
352  ijt[0] = i;
353  ijt[1] = j;
354  ijt[2] = t;
355 
356  if ( i < imax_[t][j] ) {
357  ijt[0] = i + 1;
358  ijt[1] = j;
359  ijt[2] = t;
360  return ijt;
361  }
362 
363  if ( i == imax_[t][j] ) {
364  if ( j < jmax_[t] ) {
365  // move to next column
366  ijt[0] = 0;
367  ijt[1] = j + 1;
368  ijt[2] = t;
369  return ijt;
370  }
371 
372  if ( j == jmax_[t] ) {
373  if ( t < nTiles_ - 1 ) {
374  // move to next tile
375  ijt[0] = 0;
376  ijt[1] = 0;
377  ijt[2] = t + 1;
378  return ijt;
379  }
380 
381  if ( t == nTiles_ - 1 ) {
382  // We are at the final point so we go to
383  // to a point that defines the "end()" of the
384  // iterator i.e. it is not a point on the grid
385  // For now it is set at (N_, N_, nTiles -1)
386  ijt[0] = N_;
387  ijt[1] = N_;
388  ijt[2] = nTiles_ - 1;
389  return ijt;
390  }
391  }
392  }
393 
394  return ijt;
395  }
396 
397  // Iterator start/end positions
398  // ----------------------------
399 
400  virtual std::unique_ptr<Grid::IteratorXY> xy_begin() const override {
401  return std::unique_ptr<Grid::IteratorXY>( new IteratorXY( *this ) );
402  }
403  virtual std::unique_ptr<Grid::IteratorXY> xy_end() const override {
404  return std::unique_ptr<Grid::IteratorXY>( new IteratorXY( *this, false ) );
405  }
406  virtual std::unique_ptr<Grid::IteratorLonLat> lonlat_begin() const override {
407  return std::unique_ptr<Grid::IteratorLonLat>( new IteratorLonLat( *this ) );
408  }
409  virtual std::unique_ptr<Grid::IteratorLonLat> lonlat_end() const override {
410  return std::unique_ptr<Grid::IteratorLonLat>( new IteratorLonLat( *this, false ) );
411  }
412  virtual std::unique_ptr<IteratorTIJ> tij_begin() const {
413  return std::unique_ptr<IteratorTIJ>( new IteratorTIJ( *this ) );
414  }
415  virtual std::unique_ptr<IteratorTIJ> tij_end() const {
416  return std::unique_ptr<IteratorTIJ>( new IteratorTIJ( *this, false ) );
417  }
418 
419  // Default configurations
420 
421  Config meshgenerator() const override;
422 
423  Config partitioner() const override;
424 
425  const std::string& stagger() const { return stagger_; }
426 
427 protected:
428  virtual void print( std::ostream& ) const override;
429 
430  virtual void hash( eckit::Hash& ) const override;
431 
432  virtual RectangularLonLatDomain lonlatBoundingBox() const override;
433 
434  Domain computeDomain() const;
435 
436 private:
437  void xy2xyt( const double xy[], double xyt[] ) const; // note: unused!
438 
439  void xyt2xy( const double xyt[], double xy[] ) const;
440 
441 protected:
442  // Number of faces on tile
443  idx_t N_;
444 
445  // Number of tiles
446  static const idx_t nTiles_ = 6;
447 
448  // Start points in x,y direction
449  double xs_[nTiles_];
450  double ys_[nTiles_];
451  double xsr_[nTiles_]; // x order reversed
452  double ysr_[nTiles_]; // y order reversed (for FV3 panels 4, 5, 6)
453 
454  // Number of unique points on each tile
455  std::vector<int> npts_;
456 
457  std::string tileType_;
458 
459  std::array<idx_t, 6> jmin_;
460  std::array<idx_t, 6> jmax_;
461  std::vector<std::vector<idx_t>> imin_;
462  std::vector<std::vector<idx_t>> imax_;
463 
464  std::string stagger_;
465 
466 private:
467  std::string name_ = {"cubedsphere"};
468  CubedSphereProjectionBase* cs_projection_; // store pointer to dynamic_cast for convenience
470  std::array<std::array<double, 6>, 2> tiles_offsets_xy2ab_;
471  std::array<std::array<double, 6>, 2> tiles_offsets_ab2xy_;
472 };
473 
474 
475 } // namespace grid
476 } // namespace detail
477 } // namespace grid
478 } // namespace atlas
std::string hash() const
Definition: Grid.cc:127
virtual void print(std::ostream &) const override
Fill provided me.
Definition: CubedSphere.cc:232
This file contains classes and functions working on points.
Point in longitude-latitude coordinate system.
Definition: Point.h:103
Definition: Projection.h:49
Definition: Domain.h:130
virtual std::string name() const override
Human readable name (may not be unique)
Definition: CubedSphere.cc:53
Definition: CubedSphere.h:49
Definition: Grid.h:42
Definition: Domain.h:48
virtual idx_t size() const override
Definition: CubedSphere.h:238
virtual RectangularLonLatDomain lonlatBoundingBox() const override
Definition: CubedSphere.cc:254
Definition: Tiles.h:48
Point in arbitrary XY-coordinate system.
Definition: Point.h:40
Contains all atlas classes and methods.
Definition: atlas-grids.cc:33
long idx_t
Integer type for indices in connectivity tables.
Definition: config.h:42
Definition: CubedSphereProjectionBase.h:24
Configuration class used to construct various atlas components.
Definition: Config.h:27