GeographicLib  2.1
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) <charles@karney.com> 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  : _N(N < 0 ? 0 : N)
21  , _fft(make_shared<fft_t>(fft_t(2 * _N, false)))
22  {}
23 
24  void DST::reset(int N) {
25  N = N < 0 ? 0 : N;
26  if (N == _N) return;
27  _N = N;
28  _fft->assign(2 * _N, 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 (_N == 0) return;
38  if (centerp) {
39  for (int i = 0; i < _N; ++i) {
40  data[_N+i] = data[_N-1-i];
41  data[2*_N+i] = -data[i];
42  data[3*_N+i] = -data[_N-1-i];
43  }
44  } else {
45  data[0] = 0; // set [0]
46  for (int i = 1; i < _N; ++i) data[_N+i] = data[_N-i]; // set [N+1,2*N-1]
47  for (int i = 0; i < 2*_N; ++i) data[2*_N+i] = -data[i]; // [2*N, 4*N-1]
48  }
49  vector<complex<real>> ctemp(2*_N);
50  _fft->transform_real(data, ctemp.data());
51  if (centerp) {
52  real d = -Math::pi()/(4*_N);
53  for (int i = 0, j = 1; i < _N; ++i, j+=2)
54  ctemp[j] *= exp(complex<real>(0, j*d));
55  }
56  for (int i = 0, j = 1; i < _N; ++i, j+=2) {
57  F[i] = -ctemp[j].imag() / (2*_N);
58  }
59  }
60 
61  void DST::fft_transform2(real data[], real F[]) const {
62  // Elements [0,N), of data should be set to the N grid center values and F
63  // should have size of at least 2*N. On input elements [0,N) of F contain
64  // the size N transform; on output elements [0,2*N) of F contain the size
65  // 2*N transform.
66 
67  fft_transform(data, F+_N, true);
68  for (int i = 0; i < _N; ++i) data[i] = F[i+_N];
69  for (int i = _N; i < 2*_N; ++i)
70  F[i] = (-data[2*_N-1-i] + F[2*_N-1-i])/2;
71  for (int i = 0; i < _N; ++i)
72  F[i] = (data[i] + F[i])/2;
73  }
74 
75  void DST::transform(function<real(real)> f, real F[]) const {
76  vector<real> data(4 * _N);
77  real d = Math::pi()/(2 * _N);
78  for (int i = 1; i <= _N; ++i)
79  data[i] = f( i * d );
80  fft_transform(data.data(), F, false);
81  }
82 
83  void DST::refine(function<real(real)> f, real F[]) const {
84  vector<real> data(4 * _N);
85  real d = Math::pi()/(4 * _N);
86  for (int i = 0; i < _N; ++i)
87  data[i] = f( (2*i + 1) * d );
88  fft_transform2(data.data(), F);
89  }
90 
91  Math::real DST::eval(real sinx, real cosx, const real F[], int N) {
92  // Evaluate
93  // y = sum(F[i] * sin((2*i+1) * x), i, 0, N-1)
94  // using Clenshaw summation.
95  // Approx operation count = (N + 5) mult and (2 * N + 2) add
96  real
97  ar = 2 * (cosx - sinx) * (cosx + sinx), // 2 * cos(2 * x)
98  y0 = N & 1 ? F[--N] : 0, y1 = 0; // accumulators for sum
99  // Now N is even
100  while (N > 0) {
101  // Unroll loop x 2, so accumulators return to their original role
102  y1 = ar * y0 - y1 + F[--N];
103  y0 = ar * y1 - y0 + F[--N];
104  }
105  return sinx * (y0 + y1); // sin(x) * (y0 + y1)
106  }
107 
108  Math::real DST::integral(real sinx, real cosx, const real F[], int N) {
109  // Evaluate
110  // y = -sum(F[i]/(2*i+1) * cos((2*i+1) * x), i, 0, N-1)
111  // using Clenshaw summation.
112  // Approx operation count = (N + 5) mult and (2 * N + 2) add
113  int l = N;
114  real
115  ar = 2 * (cosx - sinx) * (cosx + sinx), // 2 * cos(2 * x)
116  y0 = N & 1 ? F[--N]/(2*(--l)+1) : 0, y1 = 0; // accumulators for sum
117  // Now N is even
118  while (N > 0) {
119  // Unroll loop x 2, so accumulators return to their original role
120  y1 = ar * y0 - y1 + F[--N]/(2*(--l)+1);
121  y0 = ar * y1 - y0 + F[--N]/(2*(--l)+1);
122  }
123  return cosx * (y1 - y0); // cos(x) * (y1 - y0)
124  }
125 
126 } // namespace GeographicLib
Header for GeographicLib::DST class.
GeographicLib::Math::real real
Definition: GeodSolve.cpp:31
void reset(int N)
Definition: DST.cpp:24
void transform(std::function< real(real)> f, real F[]) const
Definition: DST.cpp:75
DST(int N=0)
Definition: DST.cpp:19
static real eval(real sinx, real cosx, const real F[], int N)
Definition: DST.cpp:91
int N() const
Definition: DST.hpp:88
void refine(std::function< real(real)> f, real F[]) const
Definition: DST.cpp:83
static real integral(real sinx, real cosx, const real F[], int N)
Definition: DST.cpp:108
static T pi()
Definition: Math.hpp:190
Definition: DST.hpp:19
Namespace for GeographicLib.
Definition: Accumulator.cpp:12