GeographicLib  2.6
DST.cpp
Go to the documentation of this file.
1 /**
2  * \file DST.cpp
3  * \brief Implementation for GeographicLib::DST class
4  *
5  * Copyright (c) Charles Karney (2022) <karney@alum.mit.edu> and licensed under
6  * the MIT/X11 License. For more information, see
7  * https://geographiclib.sourceforge.io/
8  **********************************************************************/
9 
10 #include <GeographicLib/DST.hpp>
11 #include <vector>
12 
13 #include "kissfft.hh"
14 
15 namespace GeographicLib {
16 
17  using namespace std;
18 
19  DST::DST(int N)
20  : _nN(N < 0 ? 0 : N)
21  , _fft(make_shared<fft_t>(fft_t(2 * _nN, false)))
22  {}
23 
24  void DST::reset(int N) {
25  N = N < 0 ? 0 : N;
26  if (N == _nN) return;
27  _nN = N;
28  _fft->assign(2 * _nN, false);
29  }
30 
31  void DST::fft_transform(real data[], real F[], bool centerp) const {
32  // Implement DST-III (centerp = false) or DST-IV (centerp = true).
33 
34  // Elements (0,N], resp. [0,N), of data should be set on input for centerp
35  // = false, resp. true. F must have a size of at least N and on output
36  // elements [0,N) of F contain the transform.
37  if (_nN == 0) return;
38  if (centerp) {
39  for (int i = 0; i < _nN; ++i) {
40  data[_nN+i] = data[_nN-1-i];
41  data[2*_nN+i] = -data[i];
42  data[3*_nN+i] = -data[_nN-1-i];
43  }
44  } else {
45  data[0] = 0; // set [0]
46  for (int i = 1; i < _nN; ++i)
47  data[_nN+i] = data[_nN-i]; // set [N+1,2*N-1]
48  for (int i = 0; i < 2*_nN; ++i)
49  data[2*_nN+i] = -data[i]; // [2*N, 4*N-1]
50  }
51  vector<complex<real>> ctemp(2*_nN);
52  _fft->transform_real(data, ctemp.data());
53  if (centerp) {
54  real d = -Math::pi()/(4*_nN);
55  for (int i = 0, j = 1; i < _nN; ++i, j+=2)
56  ctemp[j] *= exp(complex<real>(0, j*d));
57  }
58  for (int i = 0, j = 1; i < _nN; ++i, j+=2) {
59  F[i] = -ctemp[j].imag() / (2*_nN);
60  }
61  }
62 
63  void DST::fft_transform2(real data[], real F[]) const {
64  // Elements [0,N), of data should be set to the N grid center values and F
65  // should have size of at least 2*N. On input elements [0,N) of F contain
66  // the size N transform; on output elements [0,2*N) of F contain the size
67  // 2*N transform.
68  fft_transform(data, F+_nN, true);
69  // Copy DST-IV order N tx to [0,N) elements of data
70  for (int i = 0; i < _nN; ++i) data[i] = F[i+_nN];
71  for (int i = _nN; i < 2*_nN; ++i)
72  // (DST-IV order N - DST-III order N) / 2
73  F[i] = (data[2*_nN-1-i] - F[2*_nN-1-i])/2;
74  for (int i = 0; i < _nN; ++i)
75  // (DST-IV order N + DST-III order N) / 2
76  F[i] = (data[i] + F[i])/2;
77  }
78 
79  void DST::transform(function<real(real)> f, real F[]) const {
80  vector<real> data(4 * _nN);
81  real d = Math::pi()/(2 * _nN);
82  for (int i = 1; i <= _nN; ++i)
83  data[i] = f( i * d );
84  fft_transform(data.data(), F, false);
85  }
86 
87  void DST::refine(function<real(real)> f, real F[]) const {
88  vector<real> data(4 * _nN);
89  real d = Math::pi()/(4 * _nN);
90  for (int i = 0; i < _nN; ++i)
91  data[i] = f( (2*i + 1) * d );
92  fft_transform2(data.data(), F);
93  }
94 
95  Math::real DST::eval(real sinx, real cosx, const real F[], int N) {
96  // Evaluate
97  // y = sum(F[i] * sin((2*i+1) * x), i, 0, N-1)
98  // using Clenshaw summation.
99  // Approx operation count = (N + 5) mult and (2 * N + 2) add
100  real
101  ar = 2 * (cosx - sinx) * (cosx + sinx), // 2 * cos(2 * x)
102  y0 = N & 1 ? F[--N] : 0, y1 = 0; // accumulators for sum
103  // Now N is even
104  while (N > 0) {
105  // Unroll loop x 2, so accumulators return to their original role
106  y1 = ar * y0 - y1 + F[--N];
107  y0 = ar * y1 - y0 + F[--N];
108  }
109  return sinx * (y0 + y1); // sin(x) * (y0 + y1)
110  }
111 
112  Math::real DST::integral(real sinx, real cosx, const real F[], int N) {
113  // Evaluate
114  // y = -sum(F[i]/(2*i+1) * cos((2*i+1) * x), i, 0, N-1)
115  // using Clenshaw summation.
116  // Approx operation count = (N + 5) mult and (2 * N + 2) add
117  real
118  ar = 2 * (cosx - sinx) * (cosx + sinx), // 2 * cos(2 * x)
119  y0 = 0, y1 = 0; // accumulators for sum
120  for (--N; N >= 0; --N) {
121  real t = ar * y0 - y1 + F[N]/(2*N+1);
122  y1 = y0; y0 = t;
123  }
124  return cosx * (y1 - y0); // cos(x) * (y1 - y0)
125  }
126 
127  Math::real DST::integral(real sinx, real cosx, real siny, real cosy,
128  const real F[], int N) {
129  // return integral(siny, cosy, F, N) - integral(sinx, cosx, F, N);
130  real
131  // 2*cos(y-x)*cos(y+x) -> 2 * cos(2 * x)
132  ac = +2 * (cosy * cosx + siny * sinx) * (cosy * cosx - siny * sinx),
133  // -2*sin(y-x)*sin(y+x) -> 0
134  as = -2 * (siny * cosx - cosy * sinx) * (siny * cosx + cosy * sinx),
135  y0 = 0, y1 = 0, z0 = 0, z1 = 0; // accumulators for sum
136  for (--N; N >= 0; --N) {
137  real
138  ty = ac * y0 + as * z0 - y1 + F[N]/(2*N+1),
139  tz = as * y0 + ac * z0 - z1;
140  y1 = y0; y0 = ty;
141  z1 = z0; z0 = tz;
142  }
143  // B[0] - B[1] = [y0-y1, z0-z1]
144  // F[0] = [cosy + cosx, cosy - cosx] -> [2 * cosx, 0]
145  // (B[0] - B[1]) . F[0]
146  // = [(y0 - y1) * (cosy + cosx) + (z0 - z1) * (cosy - cosx),
147  // (y0 - y1) * (cosy - cosx) + (z0 - z1) * (cosy + cosx),
148  // return -(2nd element)
149  return (y1 - y0) * (cosy - cosx) + (z1 - z0) * (cosy + cosx);
150  }
151 
152 } // namespace GeographicLib
static T pi()
Definition: Math.hpp:187
void transform(std::function< real(real)> f, real F[]) const
Definition: DST.cpp:79
DST(int N=0)
Definition: DST.cpp:19
Header for GeographicLib::DST class.
static real eval(real sinx, real cosx, const real F[], int N)
Definition: DST.cpp:95
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
GeographicLib::Math::real real
Definition: Geod3Solve.cpp:25
void refine(std::function< real(real)> f, real F[]) const
Definition: DST.cpp:87
void reset(int N)
Definition: DST.cpp:24
static real integral(real sinx, real cosx, const real F[], int N)
Definition: DST.cpp:112
int N() const
Definition: DST.hpp:97