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