VM2D 1.14
Vortex methods for 2D flows simulation
Loading...
Searching...
No Matches
simple_math.h
Go to the documentation of this file.
1#pragma once
2#ifndef __NVCC__
3#include <oneapi/tbb/parallel_for.h>
4#endif
5#include <vector>
6#include <complex>
7#include <numbers>
8#include <functional>
9#include <fstream>
10//#include "cuda_utils.h"
11#include "mpi_utils.h"
12#include <iostream>
13
14
15
16namespace fmm {
17
18#ifdef max
19#undef max
20#endif
21
22#ifdef min
23#undef min
24#endif
25
26namespace detail {
27
28template<int n>
30{
31 std::array<double, n * n> cft;
32 int dim;
33
34 constexpr BinomNewton_wrapper() : cft(), dim(n)
35 {
36 cft[0 * dim + 0] = 1.0;
37
38 for (int i = 1; i < n; ++i)
39 {
40 cft[i * dim + 0] = 1.0;
41 cft[i * dim + i] = 1.0;
42 for (int j = 1; j < i; ++j)
43 cft[i * dim + j] = cft[(i - 1) * dim + j] + cft[(i - 1) * dim + (j - 1)];
44 }
45 }
46 constexpr double operator()(int p, int q) const
47 {
48 return cft[p * dim + q];
49 }
50};
51
53
54}
55
57{
58public:
59 std::vector<double> cft;
60 int dim;
61
62public:
64 : dim(n + 1)
65 {
66 cft.resize(dim * dim, 0.0);
67 cft[0 * dim + 0] = 1.0;
68
69 for (int i = 1; i <= n; ++i)
70 {
71 cft[i * dim + 0] = 1.0;
72 cft[i * dim + i] = 1.0;
73 for (int j = 1; j < i; ++j)
74 cft[i * dim + j] = cft[(i - 1) * dim + j] + cft[(i - 1) * dim + (j - 1)];
75 }
76 }
77
78 double operator()(int p, int q) const
79 {
80 return cft[p * dim + q];
81 }
82};
83
84template <typename T>
85__DEVICE__ __HOST__ constexpr T MyPow(T base, unsigned int exp)
86{
87 T res = 1;
88 while (exp) {
89 if (exp & 1)
90 {
91 res *= base;
92 }
93 exp >>= 1;
94 base *= base;
95 }
96 return res;
97}
98
99__DEVICE__ __HOST__ constexpr inline double ni(int n)
100{
101 return ((n & 1) == 1) ? -1.0 : 1.0;
102}
103
105{
106 const double eps = 1e-12;
107 Vector3d c;
108 c[0] = abs(vec) + eps;
109 c[1] = acos(vec[2] / c[0]);
110 if (fabs(vec[0]) + fabs(vec[1]) < eps) {
111 c[2] = 0;
112 }
113 else if (fabs(vec[0]) < eps) {
114 c[2] = vec[1] / fabs(vec[1]) * /*std::numbers::pi*/ 3.14159265358979323846 * 0.5;
115 }
116 else {
117 c[2] = atan2(vec[1], vec[0]);
118 }
119 return c;
120}
121
122inline double Potential2d(const particle2d& p1, const particle2d& p2)
123{
124 return p2.q * 0.5 * log(std::max(norm(p1.center - p2.center), FORCE_EPS2));
125}
126
127inline std::complex<double> Force2d(const particle2d& p1, const particle2d& p2)
128{
129 auto dz = p1.center - p2.center;
130 return p2.q * std::conj(dz) / std::max(norm(dz), FORCE_EPS2);
131}
132
133inline double Potential3d(const particle3d& p1, const particle3d& p2)
134{
135 return p2.q / std::max(abs(p1.center - p2.center), FORCE_EPS);
136}
137
138inline Vector3d Force3d(const particle3d& p1, const particle3d& p2)
139{
140 auto dr = p1.center - p2.center;
141 return p2.q * dr / MyPow(std::max(abs(dr), FORCE_EPS), 3);
142}
143
144inline Vector3d Force3d(const particle3d3& p1, const particle3d3& p2)
145{
146 auto dr = p1.center - p2.center;
147 return cross(p2.q, dr) / MyPow(std::max(abs(dr), FORCE_EPS), 3);
148}
149
150// ── Kernel interpolation tables ──────────────────────────────────────────────
151// lambdaEta / lambdaEtaA are called for every near-field pair (argLE < 3.0).
152// Replacing std::erf + std::exp with a linear-interpolation table gives a
153// ~10–20× speedup for the leaf direct computation.
154//
155// Table range [0, XI_MAX_INTERP] with TABLE_SIZE points; step = XI_MAX_INTERP/(N-1).
156// For argLE outside the table the original analytical formula is used as fallback.
157
158namespace detail_interp {
159
160static constexpr int TABLE_SIZE = 2049;
161static constexpr double XI_MAX_INTERP = 5.0;
162static constexpr double INV_STEP = (TABLE_SIZE - 1) / XI_MAX_INTERP;
163
169
171 constexpr double sqrtPi = 1.7724538509055159; // sqrt(π)
172 for (int i = 0; i < TABLE_SIZE; ++i) {
173 double xi = i / INV_STEP;
174 if (xi < 1e-10) {
175 lambda[i] = 8.0 / (3.0 * sqrtPi);
176 eta[i] = 8.0 / (5.0 * sqrtPi);
177 lambdaA[i] = 0.0;
178 etaA[i] = 0.0;
179 } else {
180 double xi2 = xi * xi, xi3 = xi2 * xi, xi4 = xi2 * xi2;
181 double xi5 = xi3 * xi2, xi6 = xi4 * xi2;
182 double e = std::erf(xi), ex = std::exp(-xi2);
183 lambda[i] = -e/xi3 + (2/sqrtPi)*(2 + 1/xi2)*ex;
184 eta[i] = 3*e/xi5 - (2/sqrtPi/xi2)*(2 + 3/xi2)*ex;
185 lambdaA[i] = 3*e/xi4 - (8/sqrtPi)*(3/(4*xi3) + 1/(2*xi) + xi)*ex;
186 etaA[i] = -15*e/xi6 + (1/sqrtPi)*(8/xi + 20/xi3 + 30/xi5)*ex;
187 }
188 }
189 }
190};
191
192inline const KernelTables& tables() {
193 static const KernelTables t;
194 return t;
195}
196
197inline std::pair<double,double> lookup2(const double* tA, const double* tB, double xi) {
198 double idx_f = xi * INV_STEP;
199 int idx = static_cast<int>(idx_f);
200 if (idx >= TABLE_SIZE - 1) idx = TABLE_SIZE - 2;
201 double frac = idx_f - idx;
202 double a = tA[idx] * (1.0 - frac) + tA[idx + 1] * frac;
203 double b = tB[idx] * (1.0 - frac) + tB[idx + 1] * frac;
204 return {a, b};
205}
206
207} // namespace detail_interp
208
209// Generic template — used for non-double types (e.g. future SIMD)
210template <typename T>
211std::pair<T, T> lambdaEta(T xi)
212{
213 T sqrtPi = sqrt((T)3.141592653589793);
214 if (fabs(xi) < 1e-10)
215 return { 8.0 / (3.0 * sqrtPi), 8.0 / (5.0 * sqrtPi) };
216 T xi2 = xi * xi, xi3 = xi2 * xi, xi5 = xi3 * xi2;
217 T e = std::erf(xi), ex = std::exp(-xi2);
218 return {
219 -e/xi3 + (2/sqrtPi) *(2 + 1/xi2)*ex,
220 3 * e/xi5 - (2/sqrtPi/xi2)*(2 + 3/xi2)*ex
221 };
222};
223
224// double specialisation — uses interpolation tables (no erf/exp)
225template <>
226inline std::pair<double, double> lambdaEta<double>(double xi)
227{
229 // far-field fallback (power-law, no erf/exp needed)
230 double xi3 = xi*xi*xi, xi5 = xi3*xi*xi;
231 return { -1.0/xi3, 3.0/xi5 };
232 }
233 const auto& t = detail_interp::tables();
234 return detail_interp::lookup2(t.lambda, t.eta, xi);
235}
236
237template <typename T>
238std::pair<T, T> lambdaEtaA(T xi)
239{
240 T sqrtPi = sqrt((T)3.141592653589793);
241 if (fabs(xi) < 1e-10) return { 0.0, 0.0 };
242 T xi2 = xi*xi, xi3 = xi2*xi, xi4 = xi2*xi2, xi5 = xi3*xi2, xi6 = xi4*xi2;
243 T e = std::erf(xi), ex = std::exp(-xi2);
244 return {
245 3*e/xi4 - (8/sqrtPi)*(3/(4*xi3) + 1/(2*xi) + xi)*ex,
246 -15*e/xi6 + (1/sqrtPi)*(8/xi + 20/xi3 + 30/xi5)*ex
247 };
248};
249
250// double specialisation — uses interpolation tables (no erf/exp)
251template <>
252inline std::pair<double, double> lambdaEtaA<double>(double xi)
253{
255 double xi4 = xi*xi*xi*xi, xi6 = xi4*xi*xi;
256 return { 3.0/xi4, -15.0/xi6 };
257 }
258 const auto& t = detail_interp::tables();
259 return detail_interp::lookup2(t.lambdaA, t.etaA, xi);
260}
261
262
263inline Vector3d velDipole3d(const particle3d3& p1, const particle3d3& p2)
264{
265 auto dr = (p1.center - p2.center);
266 auto Ldr = abs(dr);
267
268 auto argLE = (Ldr / FORCE_EPS);
269 if (argLE < 3.0)
270 {
271 auto [lambda, eta] = lambdaEta(argLE);
272 auto result = p2.q * lambda / FORCE_EPS3 + dot(p2.q, dr) * dr * eta / FORCE_EPS5;
273 //if (std::isnan(result[0]) || std::isnan(result[1]) || std::isnan(result[2]))
274 // std::cout << "AAA" << std::endl;
275 return result;
276 }
277 else
278 {
279 auto Ldr2 = Ldr * Ldr;
280 auto Ldr3 = Ldr2 * Ldr;
281 auto Ldr5 = Ldr3 * Ldr2;
282 auto result = p2.q / (-Ldr3) + 3 * dot(p2.q, dr) * dr / Ldr5;
283 //if (std::isnan(result[0]) || std::isnan(result[1]) || std::isnan(result[2]))
284 // std::cout << "BBB" << std::endl;
285 return result;
286 }
287}
288
289inline Vector3d momDipole3d(const particle3d3& p1, const particle3d3& p2)
290{
291 //p1 - �����������, p2 - ��������
292 auto dr = (p1.center - p2.center);
293 auto Ldr = abs(dr);
294
295 auto argLE = (Ldr / FORCE_EPS);
296 if (argLE < 3.0)
297 {
298 auto [lambda, eta] = lambdaEta(argLE);
299 auto [lambdaA, etaA] = lambdaEtaA(argLE);
300
301 auto result = -1 * ((dot(p1.q, p2.q) * lambdaA / FORCE_EPS4 + dot(p2.q, dr) * dot(p1.q, dr) * etaA / FORCE_EPS6) / std::max(Ldr, 1e-10) * dr + \
302 (p2.q * dot(p1.q, dr) + p1.q * dot(p2.q, dr)) * eta / FORCE_EPS5);
303
304 //if (std::isnan(result[0]) || std::isnan(result[1]) || std::isnan(result[2]))
305 // std::cout << "AAA" << std::endl;
306 return result;
307 }
308 else
309 {
310 auto Ldr2 = Ldr * Ldr;
311 auto Ldr3 = Ldr2 * Ldr;
312 auto Ldr4 = Ldr2 * Ldr2;
313 auto Ldr5 = Ldr3 * Ldr2;
314 auto Ldr6 = Ldr3 * Ldr3;
315 auto result = -1 * ((dot(p1.q, p2.q) * (3 / Ldr4) + dot(p2.q, dr) * dot(p1.q, dr) * (-15 / Ldr6)) / std::max(Ldr, 1e-10) * dr + \
316 (p2.q * dot(p1.q, dr) + p1.q * dot(p2.q, dr)) * 3 / Ldr5);
317
318 //if (std::isnan(result[0]) || std::isnan(result[1]) || std::isnan(result[2]))
319 // std::cout << "BBB" << std::endl;
320 return result;
321 }
322}
323
324
325inline void Potential3dMutual(const particle3d& p1, const particle3d& p2, double& potential1, double& potential2)
326{
327 auto invdr = 1.0 / std::max(abs(p1.center - p2.center), FORCE_EPS);
328 potential1 += p2.q * invdr;
329 potential2 += p1.q * invdr;
330}
331
332inline void Force3dMutual(const particle3d& p1, const particle3d& p2, Vector3d& force1, Vector3d& force2)
333{
334 auto dr = p1.center - p2.center;
335 auto invdr = dr / MyPow(std::max(abs(dr), FORCE_EPS), 3);
336 force1 += p2.q * invdr;
337 force2 -= p1.q * invdr;
338}
339
340inline void Force3dMutual(const particle3d3& p1, const particle3d3& p2, Vector3d& force1, Vector3d& force2)
341{
342 auto dr = p1.center - p2.center;
343 auto invdr = dr / MyPow(std::max(abs(dr), FORCE_EPS), 3);
344 force1 += cross(p2.q, invdr);
345 force2 -= cross(p1.q, invdr);
346}
347
348inline void Potential2dMutual(const particle2d& p1, const particle2d& p2, double& potential1, double& potential2)
349{
350 double dz = 0.5 * log(std::max(norm(p1.center - p2.center), FORCE_EPS2));
351 potential1 += p2.q * dz;
352 potential2 += p1.q * dz;
353}
354
355inline void Force2dMutual(const particle2d& p1, const particle2d& p2, std::complex<double>& force1, std::complex<double>& force2)
356{
357 auto dz = p1.center - p2.center;
358 auto invdz = std::conj(dz) / std::max(norm(dz), FORCE_EPS2);
359 force1 += p2.q * invdz;
360 force2 -= p1.q * invdz;
361}
362
363#ifdef __NVCC__
364__device__ inline double Potential2d(const gpu::particle2d& p1, const gpu::particle2d& p2)
365{
366 return p2.q * 0.5 * log(max(cuda::std::norm(p1.center - p2.center), CUDA_FORCE_EPS2));
367}
368
369__device__ inline gpu::cuda_complex Force2d(const gpu::particle2d& p1, const gpu::particle2d& p2)
370{
371 auto dz = p1.center - p2.center;
372 return p2.q * cuda::std::conj(dz) / max(cuda::std::norm(dz), CUDA_FORCE_EPS2);
373}
374
375__device__ inline double Potential3d(const gpu::particle3d& p1, const gpu::particle3d& p2)
376{
377 double dr2 = max(norm(p1.center - p2.center), CUDA_FORCE_EPS2);
378 return p2.q * rsqrt(dr2);
379}
380
381__device__ inline Vector3d Force3d(const gpu::particle3d& p1, const gpu::particle3d& p2)
382{
383 auto dr = p1.center - p2.center;
384 auto dr2 = max(norm(dr), CUDA_FORCE_EPS2);
385 return p2.q * dr * MyPow(rsqrt(dr2), 3);
386}
387
388__device__ inline Vector3d Force3d(const gpu::particle3d3& p1, const gpu::particle3d3& p2)
389{
390 auto dr = p1.center - p2.center;
391 auto dr2 = max(norm(dr), CUDA_FORCE_EPS2);
392 return cross(p2.q, dr) * MyPow(rsqrt(dr2), 3);
393}
394#endif
395
396#ifndef __NVCC__
397template <typename point_type, typename interaction_type, typename value_type>
398void ComputeExact(const std::vector<particle<point_type, value_type>>& source_particles,
399 const std::vector<particle<point_type, value_type>>& target_particles,
400 std::function<interaction_type(const particle<point_type, value_type>&, const particle<point_type, value_type>&)> func, std::string filename)
401{
402 size_t num_particles = target_particles.size();
403#ifdef FMM_MPI
404 auto [shift, end_part] = LocalPart(0, num_particles);
405 size_t local_size = end_part - shift;
406#else
407 size_t shift = 0, local_size = num_particles;
408#endif
409 std::vector<interaction_type> exact(local_size);
410
411 auto particles_ptr = target_particles.data() + shift;
412 tbb::parallel_for(size_t(0), local_size, [&](size_t i)
413 {
414 const auto& p1 = particles_ptr[i];
415 for (const auto& p2 : source_particles)
416 {
417 exact[i] += func(p1, p2);
418 }
419 });
420
421#ifdef FMM_MPI
422 std::vector<int> sizes(NProc());
423 std::vector<int> displs(NProc());
424 std::vector<interaction_type> buf(num_particles);
425 for (int j = 0; j < NProc(); ++j)
426 {
427 sizes[j] = LocalPart(0, num_particles, j);
428 }
429 for (int j = 1; j < NProc(); ++j)
430 {
431 displs[j] = displs[j - 1] + sizes[j - 1];
432 }
433 if constexpr (std::is_same_v<interaction_type,double>)
434 MPI_Allgatherv(exact.data(), local_size, MPI_DOUBLE,
435 buf.data(), sizes.data(), displs.data(), MPI_DOUBLE, MPI_COMM_WORLD);
436 if constexpr (std::is_same_v<interaction_type,std::complex<double>>)
437 MPI_Allgatherv(exact.data(), local_size, MPI_COMPLEX16,
438 buf.data(), sizes.data(), displs.data(), MPI_COMPLEX16, MPI_COMM_WORLD);
439 if constexpr (std::is_same_v<interaction_type, Vector3d>)
440 {
441 MPI_Datatype MPI_VECTOR3;
442 MPI_Type_contiguous(3, MPI_DOUBLE, &MPI_VECTOR3);
443 MPI_Type_commit(&MPI_VECTOR3);
444 MPI_Allgatherv(exact.data(), local_size, MPI_VECTOR3,
445 buf.data(), sizes.data(), displs.data(), MPI_VECTOR3, MPI_COMM_WORLD);
446 }
447#endif
448
449 std::ofstream fout(filename);
450 fout.precision(12);
451#ifdef FMM_MPI
452 for (const auto& x : buf)
453 fout << x << "\n";
454#else
455 for (const auto& x : exact)
456 fout << x << "\n";
457#endif
458}
459#endif
460
461/*
462namespace gpu {
463
464namespace detail {
465
466template <InteractionType it, typename interaction_type, typename point_type, typename value_type, typename gpu_interaction_type, typename gpu_point_type>
467struct ComputeExact {
468 static void Compute(const std::vector<fmm::particle<point_type, value_type>>& source_particles, const std::vector<fmm::particle<point_type, value_type>>& target_particles);
469}; }
470
471template <InteractionType it, typename point_type, typename value_type>
472void ComputeExact(const std::vector<fmm::particle<point_type, value_type>>& source_particles, const std::vector<fmm::particle<point_type, value_type>>& target_particles)
473{
474 if constexpr (it == fmm::InteractionType::Potential2d)
475 fmm::gpu::detail::ComputeExact<fmm::InteractionType::Potential2d, double, fmm::point2d, value_type, double, fmm::gpu::point2d>::Compute(source_particles, target_particles);
476 if constexpr (it == fmm::InteractionType::Force2d)
477 fmm::gpu::detail::ComputeExact<fmm::InteractionType::Force2d, fmm::point2d, fmm::point2d, value_type, fmm::gpu::point2d, fmm::gpu::point2d>::Compute(source_particles, target_particles);
478 if constexpr (it == fmm::InteractionType::Potential3d)
479 fmm::gpu::detail::ComputeExact<fmm::InteractionType::Potential3d, double, fmm::point3d, value_type, double, fmm::gpu::point3d>::Compute(source_particles, target_particles);
480 if constexpr (it == fmm::InteractionType::Force3d)
481 fmm::gpu::detail::ComputeExact<fmm::InteractionType::Force3d, fmm::point3d, fmm::point3d, value_type, fmm::gpu::point3d, fmm::gpu::point3d>::Compute(source_particles, target_particles);
482}
483
484template <InteractionType it, typename point_type, typename value_type>
485void ComputeExact(const std::vector<fmm::particle<point_type, value_type>>& particles)
486{
487 fmm::gpu::ComputeExact<it, point_type, value_type>(particles, particles);
488}
489
490}
491*/
492
493template <InteractionType it, typename point_type, typename value_type>
494void ComputeExact(const std::vector<particle<point_type, value_type>>& source_particles, const std::vector<particle<point_type, value_type>>& target_particles)
495{
496 if constexpr (it == fmm::InteractionType::Potential2d) {
497 auto foo = [](const particle2d& p1, const particle2d& p2) {return Potential2d(p1, p2); };
498 ComputeExact<point2d, double, value_type>(source_particles, target_particles, foo, "potential2d_exact.txt");
499 }
500 if constexpr (it == fmm::InteractionType::Force2d) {
501 auto foo = [](const particle2d& p1, const particle2d& p2) {return Force2d(p1, p2); };
502 ComputeExact<point2d, point2d, value_type>(source_particles, target_particles, foo, "force2d_exact.txt");
503 }
504 if constexpr (it == fmm::InteractionType::Potential3d)
505 {
506 auto foo = [](const particle3d& p1, const particle3d& p2) {return Potential3d(p1, p2); };
507 ComputeExact<point3d, double, value_type>(source_particles, target_particles, foo, "potential3d_exact.txt");
508 }
509 if constexpr (it == fmm::InteractionType::Force3d)
510 {
511 auto foo = [](const particle<point_type, value_type>& p1, const particle<point_type, value_type>& p2) {return Force3d(p1, p2); };
512 ComputeExact<point3d, Vector3d, value_type>(source_particles, target_particles, foo, "force3d_exact.txt");
513 }
514 if constexpr (it == fmm::InteractionType::VelDipole3d)
515 {
516 auto foo = [](const particle<point_type, value_type>& p1, const particle<point_type, value_type>& p2) {return velDipole3d(p1, p2); };
517 ComputeExact<point3d, Vector3d, value_type>(source_particles, target_particles, foo, "velDipole3d_exact.txt");
518 }
519 if constexpr (it == fmm::InteractionType::MomDipole3d)
520 {
521 auto foo = [](const particle<point_type, value_type>& p1, const particle<point_type, value_type>& p2) {return momDipole3d(p1, p2); };
522 ComputeExact<point3d, Vector3d, value_type>(source_particles, target_particles, foo, "momDipole3d_exact.txt");
523 }
524}
525
526template <InteractionType it, typename point_type, typename value_type>
527void ComputeExact(const std::vector<particle<point_type, value_type>>& particles)
528{
529 ComputeExact<it, point_type, value_type>(particles, particles);
530}
531
532template <InteractionType it, typename T>
533void ReadError(const std::vector<T>& res)
534{
535 size_t num_particles = res.size();
536 std::vector<T> exact(num_particles);
537
538 std::string filename;
539 switch (it)
540 {
542 filename = "potential2d_exact.txt";
543 break;
545 filename = "force2d_exact.txt";
546 break;
548 filename = "potential3d_exact.txt";
549 break;
551 filename = "force3d_exact.txt";
552 break;
554 filename = "velDipole3d_exact.txt";
555 break;
556 default:
557 break;
558 }
559
560 std::ifstream fin(filename);
561 for (auto& x : exact)
562 fin >> x;
563
564 double max_error = 0.0;
565 double err1 = 0.0, err2 = 0.0;
566 double l2error = 0.0;
567//#pragma omp parallel for reduction(+: err1, err2, l2error) reduction(max: max_error)
568 for (int i = 0; i < num_particles; ++i)
569 {
570 double err = 0;
571 if constexpr ((it != InteractionType::Force3d) && (it != InteractionType::VelDipole3d))
572 err = std::abs(exact[i] - res[i]);
573 else
574 err = abs(exact[i] - res[i]);
575 max_error = std::max(max_error, err);
576
577 err1 += err;
578
579 if constexpr ((it != InteractionType::Force3d) && (it != InteractionType::VelDipole3d))
580 {
581 err2 += std::abs(exact[i]);
582 l2error += (err / std::abs(exact[i])) * (err / std::abs(exact[i]));
583 }
584 else
585 {
586 err2 += abs(exact[i]);
587 l2error += (err / abs(exact[i])) * (err / abs(exact[i]));
588 }
589
590 }
591 l2error /= num_particles;
592 //std::cout << "--------------------------------" << std::endl;
593 //std::cout << "max error = " << max_error << std::endl;
594 //std::cout << "l2 error = " << sqrt(l2error) << std::endl;
595 std::cout << "FMM relative error = " << err1 / err2 << std::endl;
596 //std::cout << "--------------------------------" << std::endl;
597}
598
599
600inline void ReadErrorHyb(const std::vector<std::array<double, 2>>& res)
601{
602 size_t num_particles = res.size();
603 std::vector<std::complex<double>> exact(num_particles);
604
605 std::string filename = "force2d_exact.txt";
606
607 std::ifstream fin(filename);
608 for (auto& x : exact)
609 fin >> x;
610
611 double max_error = 0.0;
612 double err1 = 0.0, err2 = 0.0;
613 double l2error = 0.0;
614 //#pragma omp parallel for reduction(+: err1, err2, l2error) reduction(max: max_error)
615
616 for (int i = 0; i < num_particles; ++i)
617 {
618 double err = 0;
619
620 std::array<double, 2> hyb = { res[i][1] * 6.283185307179586476925286766559, res[i][0] * 6.283185307179586476925286766559 };
621
622 err = sqrt((exact[i].real() - hyb[0]) * (exact[i].real() - hyb[0]) +
623 (exact[i].imag() - hyb[1]) * (exact[i].imag() - hyb[1]));
624
625 max_error = std::max(max_error, err);
626
627 err1 += err;
628
629
630 err2 += std::abs(exact[i]);
631 l2error += (err / std::abs(exact[i])) * (err / std::abs(exact[i]));
632
633
634 }
635 l2error /= num_particles;
636 //std::cout << "--------------------------------" << std::endl;
637 //std::cout << "max error = " << max_error << std::endl;
638 //std::cout << "l2 error = " << sqrt(l2error) << std::endl;
639 std::cout << "Hybrid relative error = " << err1 / err2 << std::endl;
640 std::cout << "--------------------------------" << std::endl;
641}
642
643} // fmm
#define __DEVICE__
Definition defs.h:21
#define __HOST__
Definition defs.h:20
std::vector< double > cft
Definition simple_math.h:59
double operator()(int p, int q) const
Definition simple_math.h:78
static constexpr int TABLE_SIZE
const KernelTables & tables()
std::pair< double, double > lookup2(const double *tA, const double *tB, double xi)
static constexpr double INV_STEP
static constexpr double XI_MAX_INTERP
constexpr BinomNewton_wrapper< 2 *_2d_MAX_MULTIPOLE_NUM > binom
Definition simple_math.h:52
Definition avx.h:5
constexpr double FORCE_EPS6
Definition defs.h:33
constexpr T MyPow(T base, unsigned int exp)
Definition simple_math.h:85
constexpr Vector3d imag(const Vector3cd &rhs)
Definition utils.h:103
constexpr double ni(int n)
Definition simple_math.h:99
void ReadError(const std::vector< T > &res)
Vector3d momDipole3d(const particle3d3 &p1, const particle3d3 &p2)
constexpr Vector3d real(const Vector3cd &rhs)
Definition utils.h:98
Vector3d DecToSph(const Vector3d &vec)
void ComputeExact(const std::vector< particle< point_type, value_type > > &source_particles, const std::vector< particle< point_type, value_type > > &target_particles, std::function< interaction_type(const particle< point_type, value_type > &, const particle< point_type, value_type > &)> func, std::string filename)
constexpr double FORCE_EPS4
Definition defs.h:31
Vector3d velDipole3d(const particle3d3 &p1, const particle3d3 &p2)
double norm(const Vector3< T > &vec)
Definition utils.h:119
void Force3dMutual(const particle3d &p1, const particle3d &p2, Vector3d &force1, Vector3d &force2)
constexpr double FORCE_EPS2
Definition defs.h:29
std::pair< double, double > lambdaEtaA< double >(double xi)
void ReadErrorHyb(const std::vector< std::array< double, 2 > > &res)
void Potential2dMutual(const particle2d &p1, const particle2d &p2, double &potential1, double &potential2)
double abs(const Vector3< T > &vec)
Definition utils.h:122
std::pair< double, double > lambdaEta< double >(double xi)
constexpr double FORCE_EPS3
Definition defs.h:30
std::pair< T, T > lambdaEtaA(T xi)
constexpr double FORCE_EPS5
Definition defs.h:32
constexpr double dot(const Vector3d &lhs, const Vector3d &rhs)
Definition utils.h:110
std::pair< T, T > lambdaEta(T xi)
constexpr double FORCE_EPS
Definition defs.h:28
Vector3< double > Vector3d
Definition utils.h:63
constexpr Vector3< T > cross(const Vector3< T > &lhs, const Vector3< T > &rhs)
Definition utils.h:108
particle< point3d, point3d > particle3d3
Definition utils.h:157
void Force2dMutual(const particle2d &p1, const particle2d &p2, std::complex< double > &force1, std::complex< double > &force2)
void Potential3dMutual(const particle3d &p1, const particle3d &p2, double &potential1, double &potential2)
particle< point3d, double > particle3d
Definition utils.h:156
constexpr double operator()(int p, int q) const
Definition simple_math.h:46
std::array< double, n *n > cft
Definition simple_math.h:31
value q
Definition utils.h:33
point center
Definition utils.h:32