oILAB
Loading...
Searching...
No Matches
Diff.h
Go to the documentation of this file.
1//
2// Created by Nikhil Chandra Admal on 7/14/23.
3//
4
5#ifndef OILAB_DIFF_H
6#define OILAB_DIFF_H
7
8#include "Operator.h"
9#include "LatticeModule.h"
10#include <unsupported/Eigen/CXX11/Tensor>
11#include "../Math/FFT.h"
12#include <numbers>
13
14namespace oILAB {
15template <int dim> class Diff : public Operator<Diff<dim>, dim> {
16public:
17 using dcomplex = std::complex<double>;
19 const Eigen::array<Eigen::Index, dim> d;
20
21 explicit Diff(const Eigen::array<Eigen::Index, dim> &d_,
22 const Eigen::Matrix<double, dim, dim> &A,
23 const Eigen::array<Eigen::Index, dim> &n_)
24 : Operator<Diff<dim>, dim>(A, n_), d(d_) {
25 for (const auto &order : d)
26 assert(order >= 0);
27 }
28
29 template <int dm = dim>
30 typename std::enable_if<dm == 1, void>::type perform_op(const double *x_in,
31 double *y_out) const {
32 Eigen::TensorMap<const Eigen::Tensor<double, dm>> xReal(x_in, n);
33 const Eigen::Tensor<dcomplex, dm> x = xReal.template cast<dcomplex>();
34 Eigen::TensorMap<Eigen::Tensor<double, dm>> y(y_out, n);
35
36 // if d=0 y_out= x_in and return
37 int totalOrder = 0;
38 for (const auto &order : d) {
39 totalOrder = totalOrder + order;
40 }
41 if (totalOrder == 0) {
42 y = xReal;
43 return;
44 }
45
46 // Compute y = Lx using FFT
47 Eigen::Tensor<dcomplex, dm> xhat(n);
48 xhat.setZero();
49 FFT::fft(x, xhat);
50
51 Eigen::Tensor<dcomplex, dm> d2fhat(n);
52 d2fhat.setZero();
53
54 // only part which is dimension dependent
55 for (int i = 0; i < n[0]; ++i) {
57 dcomplex factor(1, 0);
58 for (int k = 0; k < dim; ++k) {
59 if (d[k] == 0)
60 continue;
61 else if (d[k] % 2 == 0)
62 r << (i <= n[0] / 2 ? i : i - n[0]);
63 else
64 r << (i == n[0] / 2 ? 0 : -n[0] * (i / (n[0] / 2)) + i);
65 factor = factor * std::pow(-2.0 * std::numbers::pi * dcomplex(0, 1) *
66 r.cartesian()(k),
67 d[k]);
68 }
69 d2fhat(i) = xhat(i) * factor;
70 }
71
72 // Laplacian Lf
73 Eigen::Tensor<dcomplex, dm> Lf(n);
74 Lf.setZero();
75 FFT::ifft(d2fhat, Lf);
76 y = Lf.real();
77 }
78
79 template <int dm = dim>
80 typename std::enable_if<dm == 2, void>::type perform_op(const double *x_in,
81 double *y_out) const {
82 Eigen::TensorMap<const Eigen::Tensor<double, 2>> xReal(x_in, n);
83 const Eigen::Tensor<dcomplex, 2> x = xReal.cast<dcomplex>();
84 Eigen::TensorMap<Eigen::Tensor<double, 2>> y(y_out, n);
85
86 // if d=0 y_out= x_in and return
87 int totalOrder = 0;
88 for (const auto &order : d) {
89 totalOrder = totalOrder + order;
90 }
91 if (totalOrder == 0) {
92 y = xReal;
93 return;
94 }
95
96 // Compute y = Lx using FFT
97 Eigen::Tensor<dcomplex, 2> xhat(n);
98 xhat.setZero();
99 FFT::fft(x, xhat);
100
101 Eigen::Tensor<dcomplex, 2> d2fhat(n);
102 d2fhat.setZero();
103
104 // only part which is dimension dependent
105 for (int i = 0; i < n[0]; ++i) {
106 for (int j = 0; j < n[1]; ++j) {
108 dcomplex factor(1, 0);
109 for (int k = 0; k < dim; ++k) {
110 if (d[k] == 0)
111 continue;
112 else if (d[k] % 2 == 0)
113 r << (i <= n[0] / 2 ? i : i - n[0]), (j <= n[1] / 2 ? j : j - n[1]);
114 else
115 r << (i == n[0] / 2 ? 0 : -n[0] * (i / (n[0] / 2)) + i),
116 (j == n[1] / 2 ? 0 : -n[1] * (j / (n[1] / 2)) + j);
117 factor = factor * std::pow(-2.0 * std::numbers::pi * dcomplex(0, 1) *
118 r.cartesian()(k),
119 d[k]);
120 }
121 d2fhat(i, j) = xhat(i, j) * factor;
122 }
123 }
124
125 // Laplacian Lf
126 Eigen::Tensor<dcomplex, 2> Lf(n);
127 Lf.setZero();
128 FFT::ifft(d2fhat, Lf);
129 y = Lf.real();
130 }
131
132 template <int dm = dim>
133 typename std::enable_if<dm == 3, void>::type perform_op(const double *x_in,
134 double *y_out) const {
135 Eigen::TensorMap<const Eigen::Tensor<double, dm>> xReal(x_in, n);
136 const Eigen::Tensor<dcomplex, dm> x = xReal.template cast<dcomplex>();
137 Eigen::TensorMap<Eigen::Tensor<double, dm>> y(y_out, n);
138
139 // if d=0 y_out= x_in and return
140 int totalOrder = 0;
141 for (const auto &order : d) {
142 totalOrder = totalOrder + order;
143 }
144 if (totalOrder == 0) {
145 y = xReal;
146 return;
147 }
148
149 // Compute y = Lx using FFT
150 Eigen::Tensor<dcomplex, dm> xhat(n);
151 xhat.setZero();
152 FFT::fft(x, xhat);
153
154 Eigen::Tensor<dcomplex, dm> d2fhat(n);
155 d2fhat.setZero();
156
157 // only part which is dimension dependent
158 for (int i = 0; i < n[0]; ++i) {
159 for (int j = 0; j < n[1]; ++j) {
160 for (int k = 0; k < n[2]; ++k) {
162 dcomplex factor(1, 0);
163 for (int l = 0; l < dm; ++l) {
164 if (d[l] == 0)
165 continue;
166 else if (d[l] % 2 == 0)
167 r << (i <= n[0] / 2 ? i : i - n[0]),
168 (j <= n[1] / 2 ? j : j - n[1]),
169 (k <= n[2] / 2 ? k : k - n[2]);
170 else
171 r << (i == n[0] / 2 ? 0 : -n[0] * (i / (n[0] / 2)) + i),
172 (j == n[1] / 2 ? 0 : -n[1] * (j / (n[1] / 2)) + j),
173 (k == n[2] / 2 ? 0 : -n[2] * (k / (n[2] / 2)) + k);
174 factor = factor * std::pow(-2.0 * std::numbers::pi *
175 dcomplex(0, 1) * r.cartesian()(l),
176 d[l]);
177 }
178 d2fhat(i, j, k) = xhat(i, j, k) * factor;
179 }
180 }
181 }
182
183 // Laplacian Lf
184 Eigen::Tensor<dcomplex, dm> Lf(n);
185 Lf.setZero();
186 FFT::ifft(d2fhat, Lf);
187 y = Lf.real();
188 }
189 };
190 } // namespace oILAB
191
192#endif //OILAB_DIFF_H
static void ifft(const Eigen::Tensor< dcomplex, 3 > &in, Eigen::Tensor< dcomplex, 3 > &out)
Definition FFT.h:54
static void fft(const Eigen::Tensor< dcomplex, 3 > &in, Eigen::Tensor< dcomplex, 3 > &out)
Definition FFT.h:17
Diff(const Eigen::array< Eigen::Index, dim > &d_, const Eigen::Matrix< double, dim, dim > &A, const Eigen::array< Eigen::Index, dim > &n_)
Definition Diff.h:21
std::enable_if< dm==1, void >::type perform_op(const double *x_in, double *y_out) const
Definition Diff.h:30
std::enable_if< dm==3, void >::type perform_op(const double *x_in, double *y_out) const
Definition Diff.h:133
const Eigen::array< Eigen::Index, dim > d
Definition Diff.h:19
std::enable_if< dm==2, void >::type perform_op(const double *x_in, double *y_out) const
Definition Diff.h:80
std::complex< double > dcomplex
Definition Diff.h:17
const Eigen::array< Eigen::Index, dim > n
Definition Operator.h:17