ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_LatLonMap.cpp File Reference
#include "ERF_LatLonMap.H"
#include "ERF_NumericalConstants.H"
#include <algorithm>
#include <AMReX_Arena.H>
#include <AMReX_GpuDevice.H>
#include <AMReX_MFIter.H>
#include <AMReX_ParallelDescriptor.H>
Include dependency graph for ERF_LatLonMap.cpp:

Functions

void pack_latlon (MultiFab &latlon, const MultiFab &lat, const MultiFab &lon)
 
void grid_rotation_from_latlon (const Array4< const Real > &ll, const Box &dom, int i, int j, Real &cos_alpha, Real &sin_alpha)
 
LatLonStatus locate_latlon_on_grid (const Array4< const Real > &ll, const Box &dom, const GpuArray< Real, AMREX_SPACEDIM > &problo, const GpuArray< Real, AMREX_SPACEDIM > &dx, Real req_lat, Real req_lon, LatLonLocation &loc)
 

Function Documentation

◆ grid_rotation_from_latlon()

void grid_rotation_from_latlon ( const Array4< const Real > &  ll,
const Box &  dom,
int  i,
int  j,
Real &  cos_alpha,
Real &  sin_alpha 
)
64 {
65  const GradientStencil s = gradient_stencil(dom, i, j);
66 
67  // Displacement on the sphere per cell in i: east and north components, in
68  // degrees of latitude (the common factor, the Earth's radius, cancels)
69  const Real lat = ll(i,j,0,0);
70  const Real north = (ll(s.ip,j,0,0) - ll(s.im,j,0,0)) * s.inv_di;
71  const Real east = wrap_longitude_difference(ll(s.ip,j,0,1) - ll(s.im,j,0,1)) * s.inv_di
72  * std::cos(lat * PI / Real(180.0));
73  const Real norm = std::sqrt(east*east + north*north);
74 
75  if (norm > Real(0.0)) {
76  cos_alpha = east / norm;
77  sin_alpha = north / norm;
78  } else {
79  // A domain one cell wide in x has no i direction to measure
80  cos_alpha = Real(1.0);
81  sin_alpha = Real(0.0);
82  }
83 }
amrex::Real wrap_longitude_difference(amrex::Real dlon)
Definition: ERF_LatLonMap.H:75
constexpr amrex::Real PI
Definition: ERF_NumericalConstants.H:46
Real sin_alpha
Definition: ERF_Plotfile2DInterpolator.cpp:28
Real cos_alpha
Definition: ERF_Plotfile2DInterpolator.cpp:27
amrex::Real Real
Definition: ERF_ShocInterface.H:19

Referenced by locate_latlon_on_grid(), and LatLonMap::rotation_at().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ locate_latlon_on_grid()

LatLonStatus locate_latlon_on_grid ( const Array4< const Real > &  ll,
const Box &  dom,
const GpuArray< Real, AMREX_SPACEDIM > &  problo,
const GpuArray< Real, AMREX_SPACEDIM > &  dx,
Real  req_lat,
Real  req_lon,
LatLonLocation &  loc 
)
90 {
91  const int ilo = dom.smallEnd(0), ihi = dom.bigEnd(0);
92  const int jlo = dom.smallEnd(1), jhi = dom.bigEnd(1);
93 
94  const Real cosfac = std::cos(req_lat * PI / Real(180.0));
95  auto dist2 = [&](int i, int j) {
96  const Real dlat = ll(i,j,0,0) - req_lat;
97  const Real dlon = wrap_longitude_difference(ll(i,j,0,1) - req_lon) * cosfac;
98  return dlat*dlat + dlon*dlon;
99  };
100 
101  int bi = ilo, bj = jlo;
102  Real best = dist2(ilo,jlo);
103  for (int j = jlo; j <= jhi; ++j) {
104  for (int i = ilo; i <= ihi; ++i) {
105  const Real d = dist2(i,j);
106  if (d < best) { best = d; bi = i; bj = j; }
107  }
108  }
109 
110  loc.near_lat = ll(bi,bj,0,0);
111  loc.near_lon = ll(bi,bj,0,1);
112 
113  // One linear solve in index space inverts the map: over a cell the
114  // projection is linear to well below a cell width.
115  const GradientStencil s = gradient_stencil(dom, bi, bj);
116 
117  const Real dlat_di = (ll(s.ip,bj,0,0) - ll(s.im,bj,0,0)) * s.inv_di;
118  const Real dlon_di = wrap_longitude_difference(ll(s.ip,bj,0,1) - ll(s.im,bj,0,1)) * s.inv_di;
119  const Real dlat_dj = (ll(bi,s.jp,0,0) - ll(bi,s.jm,0,0)) * s.inv_dj;
120  const Real dlon_dj = wrap_longitude_difference(ll(bi,s.jp,0,1) - ll(bi,s.jm,0,1)) * s.inv_dj;
121 
122  const Real rlat = req_lat - ll(bi,bj,0,0);
123  const Real rlon = wrap_longitude_difference(req_lon - ll(bi,bj,0,1));
124  Real di = Real(0.0), dj = Real(0.0);
125  if (!invert_latlon_offset(rlat, rlon, dlat_di, dlon_di, dlat_dj, dlon_dj, di, dj)) {
127  }
128 
129  // The solve places the point relative to the nearest grid point, so more
130  // than a cell away means the request cannot be trusted: either it is
131  // outside the domain, or the map is too poorly conditioned near it for one
132  // linear solve.
133  if (std::abs(di) > Real(1.0) || std::abs(dj) > Real(1.0)) {
134  return LatLonStatus::TooFar;
135  }
136 
137  loc.x = problo[0] + (Real(bi) + Real(0.5) + di) * dx[0];
138  loc.y = problo[1] + (Real(bj) + Real(0.5) + dj) * dx[1];
139  loc.lat = ll(bi,bj,0,0) + dlat_di*di + dlat_dj*dj;
140  // Resolving a point from a nearest grid point on the other side of the
141  // antimeridian steps the longitude just past +-180; report the longitude
142  // that names the place, not the one that runs off the end of the range
143  loc.lon = wrap_longitude_difference(ll(bi,bj,0,1) + dlon_di*di + dlon_dj*dj);
144 
145  grid_rotation_from_latlon(ll, dom, bi, bj, loc.cos_alpha, loc.sin_alpha);
146 
147  return LatLonStatus::Ok;
148 }
auto problo
Definition: ERF_InitCustomPertVels_ABL.H:36
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
bool invert_latlon_offset(amrex::Real dlat, amrex::Real dlon, amrex::Real dlat_di, amrex::Real dlon_di, amrex::Real dlat_dj, amrex::Real dlon_dj, amrex::Real &di, amrex::Real &dj)
Definition: ERF_LatLonMap.H:52
void grid_rotation_from_latlon(const Array4< const Real > &ll, const Box &dom, int i, int j, Real &cos_alpha, Real &sin_alpha)
Definition: ERF_LatLonMap.cpp:62
real(c_double), private bi
Definition: ERF_module_mp_morr_two_moment.F90:182
real(c_double), private di
Definition: ERF_module_mp_morr_two_moment.F90:203
amrex::Real cos_alpha
Definition: ERF_LatLonMap.H:101
amrex::Real lat
Definition: ERF_LatLonMap.H:93
amrex::Real x
Definition: ERF_LatLonMap.H:88
amrex::Real near_lat
Definition: ERF_LatLonMap.H:97
amrex::Real y
Definition: ERF_LatLonMap.H:89
amrex::Real sin_alpha
Definition: ERF_LatLonMap.H:102
amrex::Real near_lon
Definition: ERF_LatLonMap.H:98
amrex::Real lon
Definition: ERF_LatLonMap.H:94

Referenced by LatLonMap::locate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pack_latlon()

void pack_latlon ( MultiFab &  latlon,
const MultiFab &  lat,
const MultiFab &  lon 
)
47 {
48  for (MFIter mfi(latlon, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
49  const Box& bx = mfi.tilebox();
50  const Array4<Real>& ll = latlon.array(mfi);
51  const Array4<const Real>& lat_arr = lat.const_array(mfi);
52  const Array4<const Real>& lon_arr = lon.const_array(mfi);
53  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
54  {
55  ll(i,j,k,0) = lat_arr(i,j,0);
56  ll(i,j,k,1) = lon_arr(i,j,0);
57  });
58  }
59 }
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})

Referenced by LatLonMap::LatLonMap().

Here is the call graph for this function:
Here is the caller graph for this function: