| 1 | /* |
| 2 | * Kernels_unit_tests.hpp |
| 3 | * |
| 4 | * Created on: Feb 16, 2016 |
| 5 | * Author: i-bird |
| 6 | */ |
| 7 | |
| 8 | #ifndef OPENFPM_NUMERICS_SRC_PSE_KERNELS_TEST_UTIL_HPP_ |
| 9 | #define OPENFPM_NUMERICS_SRC_PSE_KERNELS_TEST_UTIL_HPP_ |
| 10 | |
| 11 | #include "Kernels.hpp" |
| 12 | #include "Space/Ghost.hpp" |
| 13 | #include "Vector/vector_dist.hpp" |
| 14 | #include "data_type/aggregate.hpp" |
| 15 | #include "Decomposition/CartDecomposition.hpp" |
| 16 | |
| 17 | struct PSEError |
| 18 | { |
| 19 | double l2_error; |
| 20 | double linf_error; |
| 21 | }; |
| 22 | |
| 23 | |
| 24 | template<typename T> T f_xex2(T x) |
| 25 | { |
| 26 | return x*exp(-x*x); |
| 27 | } |
| 28 | |
| 29 | template<typename T> T f_xex2(Point<1,T> & x) |
| 30 | { |
| 31 | return x.get(0)*exp(-x.get(0)*x.get(0)); |
| 32 | } |
| 33 | |
| 34 | template<typename T> T Lapf_xex2(Point<1,T> & x) |
| 35 | { |
| 36 | return 2.0*x.get(0)*(2.0*x.get(0)*x.get(0) - 3.0)*exp(-x.get(0)*x.get(0)); |
| 37 | } |
| 38 | |
| 39 | /* |
| 40 | * Given the Number of particles, it calculate the error produced by the standard |
| 41 | * second order PSE kernel to approximate the laplacian of x*e^{-x^2} in the point |
| 42 | * 0.5 (1D) |
| 43 | * |
| 44 | * The spacing h is calculated as |
| 45 | * |
| 46 | * \$ h = 1.0 / N_{part} \$ |
| 47 | * |
| 48 | * epsilon of the 1D kernel is calculated as |
| 49 | * |
| 50 | * \$ \epsilon=overlap * h \$ |
| 51 | * |
| 52 | * this mean that |
| 53 | * |
| 54 | * \$ overlap = \frac{\epsilon}{h} \$ |
| 55 | * |
| 56 | * While the particles that are considered in the neighborhood of 0.5 are |
| 57 | * calculated as |
| 58 | * |
| 59 | * \$ \N_contrib = 20*eps/spacing \$ |
| 60 | * |
| 61 | * \param N_part Number of particles in the domain |
| 62 | * \param overlap overlap parameter |
| 63 | * |
| 64 | * |
| 65 | */ |
| 66 | template<typename T, typename Kernel> void PSE_test(size_t Npart, size_t overlap,struct PSEError & error) |
| 67 | { |
| 68 | // The domain |
| 69 | Box<1,T> box({0.0},{4.0}); |
| 70 | |
| 71 | // Calculated spacing |
| 72 | T spacing = box.getHigh(0) / Npart; |
| 73 | |
| 74 | // Epsilon of the particle kernel |
| 75 | const T eps = overlap*spacing; |
| 76 | |
| 77 | // Laplacian PSE kernel 1 dimension, on double, second order |
| 78 | Kernel lker(eps); |
| 79 | |
| 80 | // For convergence we need less particles |
| 81 | Npart = static_cast<size_t>(20*eps/spacing); |
| 82 | |
| 83 | // Middle particle |
| 84 | long int mp = Npart / 2; |
| 85 | |
| 86 | size_t bc[1]={NON_PERIODIC}; |
| 87 | Ghost<1,T> g(20*eps); |
| 88 | |
| 89 | vector_dist<1,T, aggregate<T> > vd(Npart,box,bc,g); |
| 90 | |
| 91 | auto it2 = vd.getIterator(); |
| 92 | |
| 93 | while (it2.isNext()) |
| 94 | { |
| 95 | auto key = it2.get(); |
| 96 | |
| 97 | // set the position of the particles |
| 98 | vd.getPos(key)[0] = 0.448000 - ((long int)key.getKey() - mp) * spacing; |
| 99 | //set the property of the particles |
| 100 | T d = vd.getPos(key)[0]; |
| 101 | |
| 102 | vd.template getProp<0>(key) = f_xex2(d); |
| 103 | |
| 104 | ++it2; |
| 105 | } |
| 106 | |
| 107 | vect_dist_key_dx key; |
| 108 | key.setKey(mp); |
| 109 | |
| 110 | // get and construct the Cell list |
| 111 | auto cl = vd.getCellList(0.5); |
| 112 | |
| 113 | // Maximum infinity norm |
| 114 | double linf = 0.0; |
| 115 | |
| 116 | // PSE integration accumulator |
| 117 | T pse = 0; |
| 118 | |
| 119 | // Get the position of the particle |
| 120 | Point<1,T> p = vd.getPos(key); |
| 121 | |
| 122 | // Get f(x) at the position of the particle |
| 123 | T prp_x = vd.template getProp<0>(key); |
| 124 | |
| 125 | // Get the neighborhood of the particles |
| 126 | auto NN = cl.template getNNIterator<NO_CHECK>(cl.getCell(p)); |
| 127 | while(NN.isNext()) |
| 128 | { |
| 129 | auto nnp = NN.get(); |
| 130 | |
| 131 | // Calculate contribution given by the kernel value at position p, |
| 132 | // given by the Near particle, exclude itself |
| 133 | if (nnp != key.getKey()) |
| 134 | { |
| 135 | Point<1,T> xp = vd.getPos(nnp); |
| 136 | |
| 137 | // W(x-y) |
| 138 | T ker = lker.value(p,xp); |
| 139 | |
| 140 | // f(y) |
| 141 | T prp_y = vd.template getProp<0>(nnp); |
| 142 | |
| 143 | // 1.0/(eps)^2 [f(y)-f(x)]*W(x,y)*V_q |
| 144 | T prp = 1.0/eps/eps * spacing * (prp_y - prp_x); |
| 145 | pse += prp * ker; |
| 146 | } |
| 147 | |
| 148 | // Next particle |
| 149 | ++NN; |
| 150 | } |
| 151 | |
| 152 | // Here we calculate the L_infinity norm or the maximum difference |
| 153 | // of the analytic solution from the PSE calculated |
| 154 | |
| 155 | T sol = Lapf_xex2(p); |
| 156 | |
| 157 | if (fabs(pse - sol) > linf) |
| 158 | linf = static_cast<double>(fabs(pse - sol)); |
| 159 | |
| 160 | |
| 161 | error.linf_error = (double)linf; |
| 162 | } |
| 163 | |
| 164 | |
| 165 | #endif /* OPENFPM_NUMERICS_SRC_PSE_KERNELS_TEST_UTIL_HPP_ */ |
| 166 | |