PLaSK library
Loading...
Searching...
No Matches
fftpack.cpp
Go to the documentation of this file.
1/*
2 * This file is part of PLaSK (https://plask.app) by Photonics Group at TUL
3 * Copyright (c) 2022 Lodz University of Technology
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#include "fft.hpp"
15
16#ifndef USE_FFTW // use fftpacx instead of fftw
17
18#include <fftpacx/fftpacx.h>
19
20#define lensav(n) (2*n + int(log2(n)) + 6)
21
22namespace plask { namespace optical { namespace modal { namespace FFT {
23
25
27 n(old.n), strid(old.strid),
28 symmetry(old.symmetry),
29 wsave(old.wsave) {
30 old.wsave = nullptr;
31}
32
34 n = old.n; strid = old.strid;
35 symmetry = old.symmetry;
36 aligned_free(wsave);
37 wsave = old.wsave;
38 old.wsave = nullptr;
39 return *this;
40}
41
42Forward1D::Forward1D(std::size_t strid, std::size_t n, Symmetry symmetry):
43 n(int(n)), strid(int(strid)), symmetry(symmetry), wsave(aligned_malloc<double>(lensav(n))) {
44 try {
45 int ier;
46 switch (symmetry) {
47 case SYMMETRY_NONE:
48 cfftmi_(this->n, wsave, lensav(this->n), ier); return;
49 case SYMMETRY_EVEN_2:
50 cosqmi_(this->n, wsave, lensav(this->n), ier); return;
51 case SYMMETRY_EVEN_1:
52 costmi_(this->n, wsave, lensav(this->n), ier); return;
53 case SYMMETRY_ODD_2:
54 sinqmi_(this->n, wsave, lensav(this->n), ier); return;
55 case SYMMETRY_ODD_1:
56 sintmi_(this->n, wsave, lensav(this->n), ier); return;
57 }
58 } catch (const std::string& msg) {
59 throw CriticalException("FFT::Forward1D::Forward1D: {0}", msg);
60 }
61}
62
63void Forward1D::execute(dcomplex* data, int lot) {
64 if (!wsave) throw CriticalException("FFTPACX not initialized");
65 if (lot == 0) lot = strid;
66 try {
67 int ier;
68 std::unique_ptr<double[]> work(new double[(symmetry != SYMMETRY_ODD_1)? 2*lot*(n+1) : 2*lot*(2*n+4)]);
69 double factor;
70 switch (symmetry) {
71 case SYMMETRY_NONE:
72 cfftmf_(lot, 1, n, strid, data, strid*n, wsave, lensav(n), work.get(), 2*lot*n, ier);
73 break;
74 case SYMMETRY_EVEN_2:
75 cosqmb_(2*lot, 1, n, 2*strid, (double*)data, 2*strid*n, wsave, lensav(n), work.get(), 2*lot*n, ier);
76 factor = 1./n;
77 for (int i = 0, N = strid*n; i < N; i += strid)
78 for (int j = 0; j < lot; ++j)
79 data[i+j] *= factor;
80 break;
81 case SYMMETRY_EVEN_1:
82 costmf_(2*lot, 1, n, 2*strid, (double*)data, 2*strid*n, wsave, lensav(n), work.get(), 2*lot*(n+1), ier);
83 for (int i = lot, end = n*lot; i < end; ++i) *(data+i) *= 0.5;
84 break;
85 case SYMMETRY_ODD_2:
86 sinqmb_(2*lot, 1, n, 2*strid, (double*)data, 2*strid*n, wsave, lensav(n), work.get(), 2*lot*n, ier);
87 factor = 1./n;
88 for (int i = 0, N = strid*n; i < N; i += strid)
89 for (int j = 0; j < lot; ++j)
90 data[i+j] *= factor;
91 break;
92 case SYMMETRY_ODD_1:
93 sintmf_(2*lot, 1, n, 2*strid, (double*)data, 2*strid*n, wsave, lensav(n), work.get(), 2*lot*(2*n+4), ier);
94 for (int i = lot, end = n*lot; i < end; ++i) *(data+i) *= 0.5;
95 break;
96 }
97 } catch (const std::string& msg) {
98 throw CriticalException("FFT::Forward1D::execute: {0}", msg);
99 }
100}
101
105
106
107
108
110
112 n(old.n), strid(old.strid),
113 symmetry(old.symmetry),
114 wsave(old.wsave) {
115 old.wsave = nullptr;
116}
117
119 n = old.n; strid = old.strid;
120 symmetry = old.symmetry;
121 aligned_free(wsave);
122 wsave = old.wsave;
123 old.wsave = nullptr;
124 return *this;
125}
126
127Backward1D::Backward1D(std::size_t strid, std::size_t n, Symmetry symmetry):
128 n(int(n)), strid(int(strid)), symmetry(symmetry), wsave(aligned_malloc<double>(lensav(n))) {
129 try {
130 int ier;
131 switch (symmetry) {
132 case SYMMETRY_NONE:
133 cfftmi_(this->n, wsave, lensav(this->n), ier); return;
134 case SYMMETRY_EVEN_2:
135 cosqmi_(this->n, wsave, lensav(this->n), ier); return;
136 case SYMMETRY_ODD_2:
137 sinqmi_(this->n, wsave, lensav(this->n), ier); return;
138 case SYMMETRY_EVEN_1:
139 costmi_(this->n, wsave, lensav(this->n), ier); return;
140 case SYMMETRY_ODD_1:
141 throw NotImplemented("backward FFT type 1 for odd symmetry");
142 }
143 } catch (const std::string& msg) {
144 throw CriticalException("FFT::Backward1D::Backward1D: {0}", msg);
145 }
146}
147
148void Backward1D::execute(dcomplex* data, int lot) {
149 if (!wsave) throw CriticalException("FFTPACX not initialized");
150 if (lot == 0) lot = strid;
151 try {
152 int ier;
153 std::unique_ptr<double[]> work(new double[(symmetry != SYMMETRY_ODD_1)? 2*lot*(n+1) : 2*lot*(2*n+4)]);
154 switch (symmetry) {
155 case SYMMETRY_NONE:
156 cfftmb_(lot, 1, n, strid, data, strid*n, wsave, lensav(n), work.get(), 2*lot*n, ier);
157 return;
158 case SYMMETRY_EVEN_2:
159 cosqmf_(2*lot, 1, n, 2*strid, (double*)data, 2*strid*n, wsave, lensav(n), work.get(), 2*lot*n, ier);
160 break;
161 case SYMMETRY_ODD_2:
162 sinqmf_(2*lot, 1, n, 2*strid, (double*)data, 2*strid*n, wsave, lensav(n), work.get(), 2*lot*n, ier);
163 break;
164 case SYMMETRY_EVEN_1:
165 for (int i = lot, end = n*lot; i < end; ++i) *(data+i) *= 2.;
166 costmb_(2*lot, 1, n, 2*strid, (double*)data, 2*strid*n, wsave, lensav(n), work.get(), 2*lot*(n+1), ier);
167 return;
168 case SYMMETRY_ODD_1:
169 for (int i = lot, end = n*lot; i < end; ++i) *(data+i) *= 2.;
170 sintmb_(2*lot, 1, n, 2*strid, (double*)data, 2*strid*n, wsave, lensav(n), work.get(), 2*lot*(2*n+4), ier);
171 return;
172 }
173 double factor = n;
174 for (int i = 0, N = strid*n; i < N; i += strid)
175 for (int j = 0; j < lot; ++j)
176 data[i+j] *= factor;
177 } catch (const std::string& msg) {
178 throw CriticalException("FFT::Backward1D::execute: {0}", msg);
179 }
180}
181
185
186
188
190 n1(old.n1), n2(old.n2),
191 strid1(old.strid1), strid2(old.strid2),
192 symmetry1(old.symmetry1), symmetry2(old.symmetry2),
193 wsave1(old.wsave1), wsave2(old.wsave2) {
194 old.wsave1 = nullptr; if (old.wsave2 != old.wsave1) old.wsave2 = nullptr;
195}
196
198 n1 = old.n1; n2 = old.n2;
199 strid1 = old.strid1; strid2 = old.strid2;
200 symmetry1 = old.symmetry1; symmetry2 = old.symmetry2;
201 aligned_free(wsave1); if (wsave2 != wsave1) aligned_free(wsave2);
202 wsave1 = old.wsave1; wsave2 = old.wsave2;
203 old.wsave1 = nullptr; if (old.wsave2 != old.wsave1) old.wsave2 = nullptr;
204 return *this;
205}
206
207Forward2D::Forward2D(std::size_t strid, std::size_t n1, std::size_t n2, Symmetry symmetry1, Symmetry symmetry2, std::size_t ld):
208 n1(int(n1)), n2(int(n2)), strid1(int(strid)), strid2(int(strid*(ld?ld:n1))), symmetry1(symmetry1), symmetry2(symmetry2),
209 wsave1(aligned_malloc<double>(lensav(n1))) {
210 if (n1 == n2 && symmetry1 == symmetry2) wsave2 = wsave1;
211 else wsave2 = aligned_malloc<double>(lensav(n2));
212 try {
213 int ier;
214 switch (symmetry1) {
215 case SYMMETRY_NONE:
216 cfftmi_(this->n1, wsave1, lensav(this->n1), ier); break;
217 case SYMMETRY_EVEN_2:
218 cosqmi_(this->n1, wsave1, lensav(this->n1), ier); break;
219 case SYMMETRY_EVEN_1:
220 costmi_(this->n1, wsave1, lensav(this->n1), ier); break;
221 case SYMMETRY_ODD_2:
222 sinqmi_(this->n1, wsave1, lensav(this->n1), ier); break;
223 case SYMMETRY_ODD_1:
224 sintmi_(this->n1, wsave1, lensav(this->n1), ier); break;
225 }
226 if (wsave1 != wsave2) {
227 switch (symmetry2) {
228 case SYMMETRY_NONE:
229 cfftmi_(this->n2, wsave2, lensav(this->n2), ier); break;
230 case SYMMETRY_EVEN_2:
231 cosqmi_(this->n2, wsave2, lensav(this->n2), ier); break;
232 case SYMMETRY_EVEN_1:
233 costmi_(this->n2, wsave2, lensav(this->n2), ier); break;
234 case SYMMETRY_ODD_2:
235 sinqmi_(this->n2, wsave2, lensav(this->n2), ier); break;
236 case SYMMETRY_ODD_1:
237 sintmi_(this->n2, wsave2, lensav(this->n2), ier); break;
238 }
239 }
240 } catch (const std::string& msg) {
241 throw CriticalException("FFT::Forward2D::Forward2D: {0}", msg);
242 }
243}
244
245void Forward2D::execute(dcomplex* data, int lot) {
246 if (!wsave1 || !wsave2) throw CriticalException("FFTPACX not initialized");
247 if (lot == 0) lot = strid1;
248 try {
249 int ier;
250 std::unique_ptr<double[]> work(new double[symmetry1 != SYMMETRY_ODD_1 || symmetry2 != SYMMETRY_ODD_1?
251 2*lot*(max(n1,n2)+1) : 2*lot*(2*max(n1,n2)+4)]);
252 // n1 is changing faster than n2
253 double factor1 = 1./n1;
254 switch (symmetry1) {
255 case SYMMETRY_NONE:
256 for (int i = 0; i != n2; ++i)
257 cfftmf_(lot, 1, n1, strid1, data+strid2*i, strid2, wsave1, lensav(n1), work.get(), 2*lot*n1, ier);
258 break;
259 case SYMMETRY_EVEN_2:
260 for (int i = 0; i != n2; ++i) {
261 cosqmb_(2*lot, 1, n1, 2*strid1, (double*)data+2*strid2*i, 2*strid2, wsave1, lensav(n1), work.get(), 2*lot*n1, ier);
262 for (int j = 0, dist = strid2*i, end = strid1*n1; j < end; j += strid1)
263 for (int l = 0; l < lot; ++l)
264 data[dist+j+l] *= factor1;
265 }
266 break;
267 case SYMMETRY_EVEN_1:
268 for (int i = 0; i != n2; ++i) {
269 costmf_(2*lot, 1, n1, 2*strid1, (double*)data+2*strid2*i, 2*strid2, wsave1, lensav(n1), work.get(), 2*lot*(n1+1), ier);
270 for (int j = strid1, dist = strid2*i, end = strid1*n1; j < end; j += strid1)
271 for (int l = 0; l < lot; ++l)
272 data[dist+j+l] *= 0.5;
273 }
274 break;
275 case SYMMETRY_ODD_2:
276 for (int i = 0; i != n2; ++i) {
277 sinqmb_(2*lot, 1, n1, 2*strid1, (double*)data+2*strid2*i, 2*strid2, wsave1, lensav(n1), work.get(), 2*lot*n1, ier);
278 for (int j = 0, dist = strid2*i, end = strid1*n1; j < end; j += strid1)
279 for (int l = 0; l < lot; ++l)
280 data[dist+j+l] *= factor1;
281 }
282 break;
283 case SYMMETRY_ODD_1:
284 for (int i = 0; i != n2; ++i) {
285 sintmf_(2*lot, 1, n1, 2*strid1, (double*)data+2*strid2*i, 2*strid2, wsave1, lensav(n1), work.get(), 2*lot*(2*n1+4), ier);
286 for (int j = strid1, dist = strid2*i, end = strid1*n1; j < end; j += strid1)
287 for (int l = 0; l < lot; ++l)
288 data[dist+j+l] *= 0.5;
289 }
290 break;
291 }
292 double factor2 = 1./n2;
293 switch (symmetry2) {
294 case SYMMETRY_NONE:
295 for (int i = 0; i != n1; ++i)
296 cfftmf_(lot, 1, n2, strid2, data+strid1*i, strid1+strid2*(n2-1), wsave2, lensav(n2), work.get(), 2*lot*n2, ier);
297 break;
298 case SYMMETRY_EVEN_2:
299 for (int i = 0; i != n1; ++i) {
300 cosqmb_(2*lot, 1, n2, 2*strid2, (double*)data+2*strid1*i, 2*(strid1+strid2*(n2-1)), wsave2, lensav(n2), work.get(), 2*lot*n2, ier);
301 for (int j = 0, dist = strid1*i, end = n2*strid2; j < end; j += strid2)
302 for (int l = 0; l < lot; ++l)
303 data[dist+j+l] *= factor2;
304 }
305 break;
306 case SYMMETRY_EVEN_1:
307 for (int i = 0; i != n1; ++i) {
308 costmf_(2*lot, 1, n2, 2*strid2, (double*)data+2*strid1*i, 2*(strid1+strid2*(n2-1)), wsave2, lensav(n2), work.get(), 2*lot*(n2+1), ier);
309 for (int j = strid2, dist = strid1*i, end = strid2*n2; j < end; j += strid2)
310 for (int l = 0; l < lot; ++l)
311 data[dist+j+l] *= 0.5;
312 }
313 break;
314 case SYMMETRY_ODD_2:
315 for (int i = 0; i != n1; ++i) {
316 sinqmb_(2*lot, 1, n2, 2*strid2, (double*)data+2*strid1*i, 2*(strid1+strid2*(n2-1)), wsave2, lensav(n2), work.get(), 2*lot*n2, ier);
317 for (int j = 0, dist = strid1*i, end = n2*strid2; j < end; j += strid2)
318 for (int l = 0; l < lot; ++l)
319 data[dist+j+l] *= factor2;
320 }
321 break;
322 case SYMMETRY_ODD_1:
323 for (int i = 0; i != n1; ++i) {
324 sintmf_(2*lot, 1, n2, 2*strid2, (double*)data+2*strid1*i, 2*(strid1+strid2*(n2-1)), wsave2, lensav(n2), work.get(), 2*lot*(2*n2+4), ier);
325 for (int j = strid2, dist = strid1*i, end = strid2*n2; j < end; j += strid2)
326 for (int l = 0; l < lot; ++l)
327 data[dist+j+l] *= 0.5;
328 }
329 break;
330 }
331 } catch (const std::string& msg) {
332 throw CriticalException("FFT::Forward2D::execute: {0}", msg);
333 }
334}
335
337 if (wsave2 != wsave1) aligned_free(wsave2);
338 aligned_free(wsave1);
339}
340
341
342
344
346 n1(old.n1), n2(old.n2),
347 strid1(old.strid1), strid2(old.strid2),
348 symmetry1(old.symmetry1), symmetry2(old.symmetry2),
349 wsave1(old.wsave1), wsave2(old.wsave2) {
350 old.wsave1 = nullptr; if (old.wsave2 != old.wsave1) old.wsave2 = nullptr;
351}
352
354 n1 = old.n1; n2 = old.n2;
355 strid1 = old.strid1; strid2 = old.strid2;
356 symmetry1 = old.symmetry1; symmetry2 = old.symmetry2;
357 aligned_free(wsave1); if (wsave2 != wsave1) aligned_free(wsave2);
358 wsave1 = old.wsave1; wsave2 = old.wsave2;
359 old.wsave1 = nullptr; if (old.wsave2 != old.wsave1) old.wsave2 = nullptr;
360 return *this;
361}
362
363Backward2D::Backward2D(std::size_t strid, std::size_t n1, std::size_t n2, Symmetry symmetry1, Symmetry symmetry2, std::size_t ld):
364 n1(int(n1)), n2(int(n2)), strid1(int(strid)), strid2(int(strid*(ld?ld:n1))), symmetry1(symmetry1), symmetry2(symmetry2),
365 wsave1(aligned_malloc<double>(lensav(n1))) {
366 if (n1 == n2 && symmetry1 == symmetry2) wsave2 = wsave1;
367 else wsave2 = aligned_malloc<double>(lensav(n2));
368 try {
369 int ier;
370 switch (symmetry1) {
371 case SYMMETRY_NONE:
372 cfftmi_(this->n1, wsave1, lensav(this->n1), ier); break;
373 case SYMMETRY_EVEN_2:
374 cosqmi_(this->n1, wsave1, lensav(this->n1), ier); break;
375 case SYMMETRY_ODD_2:
376 sinqmi_(this->n1, wsave1, lensav(this->n1), ier); break;
377 case SYMMETRY_EVEN_1:
378 costmi_(this->n1, wsave1, lensav(this->n1), ier); break;
379 case SYMMETRY_ODD_1:
380 sintmi_(this->n1, wsave1, lensav(this->n1), ier); break;
381 }
382 if (wsave1 != wsave2) {
383 switch (symmetry2) {
384 case SYMMETRY_NONE:
385 cfftmi_(this->n2, wsave2, lensav(this->n2), ier); break;
386 case SYMMETRY_EVEN_2:
387 cosqmi_(this->n2, wsave2, lensav(this->n2), ier); break;
388 case SYMMETRY_ODD_2:
389 sinqmi_(this->n2, wsave2, lensav(this->n2), ier); break;
390 case SYMMETRY_EVEN_1:
391 costmi_(this->n2, wsave2, lensav(this->n2), ier); break;
392 case SYMMETRY_ODD_1:
393 sintmi_(this->n2, wsave2, lensav(this->n2), ier); break;
394 }
395 }
396 } catch (const std::string& msg) {
397 throw CriticalException("FFT::Backward2D::Backward2D: {0}", msg);
398 }
399}
400
401void Backward2D::execute(dcomplex* data, int lot) {
402 if (!wsave1 || !wsave2) throw CriticalException("FFTPACX not initialized");
403 if (lot == 0) lot = strid1;
404 try {
405 int ier;
406 std::unique_ptr<double[]> work(new double[symmetry1 != SYMMETRY_ODD_1 || symmetry2 != SYMMETRY_ODD_1?
407 2*lot*(max(n1,n2)+1) : 2*lot*(2*max(n1,n2)+4)]);
408 // n1 is changing faster than n2
409 double factor1 = n1;
410 switch (symmetry1) {
411 case SYMMETRY_NONE:
412 for (int i = 0; i != n2; ++i)
413 cfftmb_(lot, 1, n1, strid1, data+strid2*i, strid2, wsave1, lensav(n1), work.get(), 2*lot*n1, ier);
414 break;
415 case SYMMETRY_EVEN_2:
416 for (int i = 0; i != n2; ++i) {
417 cosqmf_(2*lot, 1, n1, 2*strid1, (double*)data+2*strid2*i, 2*strid2, wsave1, lensav(n1), work.get(), 2*lot*n1, ier);
418 for (int j = 0, dist = strid2*i, end = strid1*n1; j < end; j += strid1)
419 for (int l = 0; l < lot; ++l)
420 data[j+l+dist] *= factor1;
421 }
422 break;
423 case SYMMETRY_ODD_2:
424 for (int i = 0; i != n2; ++i) {
425 sinqmf_(2*lot, 1, n1, 2*strid1, (double*)data+2*strid2*i, 2*strid2, wsave1, lensav(n1), work.get(), 2*lot*n1, ier);
426 for (int j = 0, dist = strid2*i, end = strid1*n1; j < end; j += strid1)
427 for (int l = 0; l < lot; ++l)
428 data[j+l+dist] *= factor1;
429 }
430 break;
431 case SYMMETRY_EVEN_1:
432 for (int i = 0; i != n2; ++i) {
433 for (int j = strid1, dist = strid2*i, end = strid1*n1; j < end; j += strid1)
434 for (int l = 0; l < lot; ++l)
435 data[j+l+dist] *= 2.;
436 costmb_(2*lot, 1, n1, 2*strid1, (double*)data+2*strid2*i, 2*strid2, wsave1, lensav(n1), work.get(), 2*lot*(n1+1), ier);
437 }
438 break;
439 case SYMMETRY_ODD_1:
440 for (int i = 0; i != n2; ++i) {
441 for (int j = strid1, dist = strid2*i, end = strid1*n1; j < end; j += strid1)
442 for (int l = 0; l < lot; ++l)
443 data[j+l+dist] *= 2.;
444 sintmb_(2*lot, 1, n1, 2*strid1, (double*)data+2*strid2*i, 2*strid2, wsave1, lensav(n1), work.get(), 2*lot*(2*n1+4), ier);
445 }
446 break;
447 }
448 double factor2 = n2;
449 switch (symmetry2) {
450 case SYMMETRY_NONE:
451 for (int i = 0; i != n1; ++i)
452 cfftmb_(lot, 1, n2, strid2, data+strid1*i, strid1+strid2*(n2-1), wsave2, lensav(n2), work.get(), 2*lot*n2, ier);
453 break;
454 case SYMMETRY_EVEN_2:
455 for (int i = 0; i != n1; ++i) {
456 cosqmf_(2*lot, 1, n2, 2*strid2, (double*)data+2*strid1*i, 2*(strid1+strid2*(n2-1)), wsave2, lensav(n2), work.get(), 2*lot*n2, ier);
457 for (int j = 0, dist = strid1*i, N = n2*strid2; j < N; j += strid2)
458 for (int l = 0; l < lot; ++l)
459 data[dist+j+l] *= factor2;
460 }
461 break;
462 case SYMMETRY_ODD_2:
463 for (int i = 0; i != n1; ++i) {
464 sinqmf_(2*lot, 1, n2, 2*strid2, (double*)data+2*strid1*i, 2*(strid1+strid2*(n2-1)), wsave2, lensav(n2), work.get(), 2*lot*n2, ier);
465 for (int j = 0, dist = strid1*i, N = n2*strid2; j < N; j += strid2)
466 for (int l = 0; l < lot; ++l)
467 data[dist+j+l] *= factor2;
468 }
469 break;
470 case SYMMETRY_EVEN_1:
471 for (int i = 0; i != n1; ++i) {
472 for (int j = strid2, dist = strid1*i, end = n2*strid2; j < end; j += strid2)
473 for (int l = 0; l < lot; ++l)
474 data[dist+j+l] *= 2.;
475 costmb_(2*lot, 1, n2, 2*strid2, (double*)data+2*strid1*i, 2*(strid1+strid2*(n2-1)), wsave2, lensav(n2), work.get(), 2*lot*(n2+1), ier);
476 }
477 break;
478 case SYMMETRY_ODD_1:
479 for (int i = 0; i != n1; ++i) {
480 for (int j = strid2, dist = strid1*i, end = n2*strid2; j < end; j += strid2)
481 for (int l = 0; l < lot; ++l)
482 data[dist+j+l] *= 2.;
483 sintmb_(2*lot, 1, n2, 2*strid2, (double*)data+2*strid1*i, 2*(strid1+strid2*(n2-1)), wsave2, lensav(n2), work.get(), 2*lot*(2*n2+4), ier);
484 }
485 break;
486 }
487 } catch (const std::string& msg) {
488 throw CriticalException("FFT::Backward2D::execute: {0}", msg);
489 }
490}
491
493 if (wsave2 != wsave1) aligned_free(wsave2);
494 aligned_free(wsave1);
495}
496
497}}}} // namespace plask::optical::modal
498
499#endif // USE_FFTW