21 if (lon >= -180 and lon < 180)
29#pragma GCC diagnostic push
30#pragma GCC diagnostic ignored "-Wconversion"
54 const Numeric x = std::cos(theta);
61 P(1, 1) = - sqrt(1.0 - pow2(x));
65 for (Index n=2; n<N; ++n) {
66 P(n, 0) = ((2 * (n-1) + 1) * x * P(n-1, 0) - (n - 1) * P(n-2, 0)) / n;
69 dP(nmax, 0) = nmax / (pow2(x) - 1) * (x * P(nmax, 0) - P(nmax-1, 0));
70 for (Index n=2; n<nmax; ++n) {
71 dP(n, 0) = (n + 1) / (pow2(x) - 1) * (P(n+1, 0) - x * P(n, 0));
74 Numeric Cm = sqrt(2.0);
75 for (Index m=1; m<N; ++m) {
76 Cm /= sqrt(Numeric(2*m * (2*m - 1)));
77 P(m, m) = std::pow(1 - pow2(x), 0.5*m) * Cm;
79 for (Index i=1; i<m; ++i) {
83 dP(m, m) = -P(m, m) * m * x / sqrt(1 - pow2(x));
87 for (Index n=m+1; n<N; ++n) {
88 P(n, m) = (x * (2*n - 1) * P(n-1, m) - sqrt(Numeric((n+m-1) * (n-m-1))) * twoago) / sqrt(Numeric(pow2(n) - pow2(m)));
94 for (Index n=2; n<N; ++n) {
95 for (Index m=1; m<n; ++m) {
96 dP(n, m) = sqrt(Numeric((n-m) * (n+m+1))) * P(n, m+1) - P(n, m) * m * x / sqrt(1 - pow2(x));
105 const Numeric r,
const Numeric lat,
const Numeric lon)
ARTS_NOEXCEPT {
106 ARTS_ASSERT(lat >= -90 and lat <= 90,
"Latitude is ", lat,
" should be in [-90, 90]")
108 const Index N = h.nrows();
112 const Numeric sin_theta = std::sin(effective_theta);
115 const auto [P, dP] =
schmidt(effective_theta, N - 1);
118 std::vector<Numeric> cosm(N);
119 std::vector<Numeric> sinm(N);
121 if (low_lat or high_lat) {
122 for (Index m=0; m<N; ++m) {
127 for (Index m=0; m<N; ++m) {
135 for (Index n=1; n<N; ++n) {
136 const Numeric ratn = std::pow(r0 / r, n + 2);
137 for (Index m=0; m<n+1; ++m) {
138 F.
U += (g(n, m) * cosm[m] + h(n, m) * sinm[m]) * P(n, m) * (n + 1) * ratn;
139 F.
S += (g(n, m) * cosm[m] + h(n, m) * sinm[m]) * dP(n, m) * ratn;
140 F.
E += (g(n, m) * sinm[m] + h(n, m) * cosm[m]) * P(n, m) * m * ratn;
147 if (high_lat or low_lat) {
157 ARTS_ASSERT(lat >= -90 and lat <= 90,
"Latitude is ", lat,
" should be in [-90, 90]")
159 const Index N = h.nrows();
160 const Index nlon = lonv.nelem();
161 const Index nr = rv.nelem();
165 const Numeric sin_theta = std::sin(effective_theta);
168 const auto [P, dP] =
schmidt(effective_theta, N - 1);
172 for (Index ir=0; ir<nr; ir++) {
173 ARTS_ASSERT(rv[ir] > 0,
"Radius are [", rv,
"] must be in (0, inf]")
174 for (Index n=1; n<N; ++n) {
175 ratnm(ir, n) = std::pow(r0 / rv[ir], n + 2);
180 for (Index ilon=0; ilon<nlon; ilon++) {
183 std::vector<Numeric> cosm(N);
184 std::vector<Numeric> sinm(N);
186 if (low_lat or high_lat) {
187 for (Index m=0; m<N; ++m) {
192 for (Index m=0; m<N; ++m) {
199 for (Index ir=0; ir<nr; ir++) {
201 for (Index n=1; n<N; ++n) {
202 const Numeric ratn = ratnm(ir, n);
203 for (Index m=0; m<n+1; ++m) {
204 const Numeric gnm{g(n, m)};
205 const Numeric hnm{h(n, m)};
206 const Numeric cosmm{cosm[m]};
207 const Numeric sinmm{sinm[m]};
208 const Numeric Pnm{P(n, m)};
210 F.
U += (gnm * cosmm + hnm * sinmm) * Pnm * (n + 1) * ratn;
211 F.
S += (gnm * cosmm + hnm * sinmm) * dP(n, m) * ratn;
212 F.
E += (gnm * sinmm + hnm * cosmm) * Pnm * m * ratn;
219 if (high_lat or low_lat) {
228#pragma GCC diagnostic pop
231std::array<Numeric, 3>
to_geodetic(
const std::array<Numeric, 3> xyz,
const std::array<Numeric, 2> ell)
noexcept {
236 const Numeric X = std::get<0>(xyz);
237 const Numeric Y = std::get<1>(xyz);
238 const Numeric Z = std::get<2>(xyz);
239 const Numeric
a = std::get<0>(ell);
240 const Numeric e = std::get<1>(ell);
241 const Numeric
b =
a * std::sqrt(1 - pow2(e));
244 std::array<Numeric, 3> pos;
246 if (std::abs(X) > 1 /
a or std::abs(Y) > 1 /
a) {
247 const Numeric DZ = std::sqrt(1 - pow2(e)) * Z;
248 const Numeric r = std::hypot(X, Y);
249 const Numeric e2p = (pow2(
a) - pow2(
b)) / pow2(
b);
250 const Numeric F = 54 * pow2(
b * Z);
251 const Numeric G = pow2(r) + pow2(DZ) - pow2(e) * (pow2(
a) - pow2(
b));
252 const Numeric
c = pow4(e) * F * pow2(r) / pow3(G);
253 const Numeric s = std::cbrt(1 +
c + std::sqrt(pow2(
c) + 2 *
c));
254 const Numeric fP = F / (3 * pow2(G * (s + 1 / s + 1)));
255 const Numeric Q = std::sqrt(1 + 2 * pow4(e) * fP);
256 const Numeric r0 = (-fP * pow2(e) * r) / (1 + Q) + sqrt(0.5 * pow2(
a) * (1 + 1 / Q) - fP * pow2(DZ) / (Q * (1 + Q)) - 0.5 * fP * pow2(r));
257 const Numeric U = std::hypot(r - pow2(e) * r0, Z);
258 const Numeric V = std::hypot(r - pow2(e) * r0, DZ);
259 const Numeric z0 = pow2(
b) * Z / (
a * V);
261 pos[0] = U * (1 - pow2(
b) / (
a * V));
264 }
else if (std::abs(Z) < 1 /
b) {
269 pos[0] = std::abs(Z) -
b;
270 pos[1] = Z < 0 ? -90 : 90;
#define ARTS_ASSERT(condition,...)
constexpr Numeric pi
The following mathematical constants are generated in python Decimal package by the code:
Namespace containing several practical unit conversions, physical and mathematical.
constexpr auto deg2rad(auto x) noexcept
Converts degrees to radians.
auto sind(auto x) noexcept
Returns the sine of the deg2rad of the input.
auto cosd(auto x) noexcept
Returns the cosine of the deg2rad of the input.
auto atan2d(auto y, auto x) noexcept
Returns rad2deg of the arc-tangent of inputs #T1/#T2
std::array< Numeric, 3 > to_geodetic(const std::array< Numeric, 3 > xyz, const std::array< Numeric, 2 > ell) noexcept
Computes the altitude, latitude and longitude in relation to the ellopsiod using non-iterative method...
SphericalField schmidt_fieldcalc(const Matrix &g, const Matrix &h, const Numeric r0, const Numeric r, const Numeric lat, const Numeric lon) ARTS_NOEXCEPT
Computes the spherical field.
std::pair< Matrix, Matrix > schmidt(const Numeric theta, const Index nmax) ARTS_NOEXCEPT
Returns the Schmidt normalized Lagrange polynominal and its derivative.
constexpr Numeric longitude_clamp(const Numeric lon)
Clamps the longitude in the range [-180, 180)
constexpr auto pow3(auto x) noexcept
power of three
constexpr auto pow4(auto x) noexcept
power of four
constexpr auto pow2(auto x) noexcept
power of two
Converts latitude to co-latitude with a small distance from the poles and flags if this was activated...
constexpr ColatitudeConversion(const Numeric latitude) noexcept
static constexpr Numeric dlat_lim
Stores the up (U), south (S), east (E) values of a field relative to the sphere.
Numeric total_horizontal() const noexcept
Returns the total strength of the field.