| 1 | /* |
| 2 | * mp4_interpolation.hpp |
| 3 | * |
| 4 | * Created on: May 4, 2017 |
| 5 | * Author: i-bird |
| 6 | */ |
| 7 | |
| 8 | #ifndef OPENFPM_NUMERICS_SRC_INTERPOLATION_INTERPOLATION_HPP_ |
| 9 | #define OPENFPM_NUMERICS_SRC_INTERPOLATION_INTERPOLATION_HPP_ |
| 10 | |
| 11 | #include "NN/Mem_type/MemFast.hpp" |
| 12 | #include "NN/CellList/CellList.hpp" |
| 13 | #include "Grid/grid_dist_key.hpp" |
| 14 | #include "Vector/vector_dist_key.hpp" |
| 15 | |
| 16 | #define INTERPOLATION_ERROR_OBJECT std::runtime_error("Runtime interpolation error"); |
| 17 | |
| 18 | constexpr int inte_m2p = 0; |
| 19 | constexpr int inte_p2m = 1; |
| 20 | |
| 21 | /*! \brief It store the offsets of the interpolation points |
| 22 | * |
| 23 | * \tparam n_ele number of interpolation points |
| 24 | * \tparam T type in general an |
| 25 | * |
| 26 | */ |
| 27 | template<unsigned int n_ele> |
| 28 | struct agg_arr |
| 29 | { |
| 30 | //! offset of the interpolation points |
| 31 | size_t ele[n_ele]; |
| 32 | }; |
| 33 | |
| 34 | /*! \brief multiply the src by coeff for several types T |
| 35 | * |
| 36 | * \tparam type T |
| 37 | * |
| 38 | */ |
| 39 | template<typename T> |
| 40 | struct mul_inte |
| 41 | { |
| 42 | /*! \brief multiply the src by coeff for several types T |
| 43 | * |
| 44 | * \param result the result of the multiplication |
| 45 | * \param coeff coefficent to use for of the multiplication |
| 46 | * \param src source |
| 47 | * |
| 48 | */ |
| 49 | inline static void value(T & result, const T & coeff, const T & src) |
| 50 | { |
| 51 | result += coeff * src; |
| 52 | } |
| 53 | }; |
| 54 | |
| 55 | /*! \brief multiply the src by coeff for several types T |
| 56 | * |
| 57 | * \tparam type T |
| 58 | * |
| 59 | */ |
| 60 | template<typename T, unsigned int N1> |
| 61 | struct mul_inte<T[N1]> |
| 62 | { |
| 63 | /*! \brief multiply the src by coeff for several types T |
| 64 | * |
| 65 | * \param result the result of the multiplication |
| 66 | * \param coeff coefficent to use for of the multiplication |
| 67 | * \param src source |
| 68 | * |
| 69 | */ |
| 70 | inline static void value(T (& result)[N1], const T & coeff, const T (& src)[N1]) |
| 71 | { |
| 72 | for (size_t i = 0 ; i < N1 ; i++) |
| 73 | result[i] += coeff * src[i]; |
| 74 | } |
| 75 | }; |
| 76 | |
| 77 | /*! \brief multiply the src by coeff for several types T |
| 78 | * |
| 79 | * \tparam type T |
| 80 | * |
| 81 | */ |
| 82 | template<typename T, unsigned int N1, unsigned int N2> |
| 83 | struct mul_inte<T[N1][N2]> |
| 84 | { |
| 85 | /*! \brief multiply the src by coeff for several types T |
| 86 | * |
| 87 | * \param result the result of the multiplication |
| 88 | * \param coeff coefficent to use for of the multiplication |
| 89 | * \param src source |
| 90 | * |
| 91 | */ |
| 92 | inline static void value(T (& result)[N1][N2], const T & coeff, const T (& src)[N1][N2]) |
| 93 | { |
| 94 | for (size_t i = 0 ; i < N1 ; i++) |
| 95 | for (size_t j = 0 ; j < N2 ; j++) |
| 96 | result[i][j] += coeff * src[i][j]; |
| 97 | } |
| 98 | }; |
| 99 | |
| 100 | /*! \brief Class that select the operation to do differently if we are doing Mesh to particle (m2p) or particle to mesh (p2m) |
| 101 | * |
| 102 | * \tparam prp_g property of the grid to interpolate |
| 103 | * \tparam prp_v property of the vector to interpolate |
| 104 | * \param M2P or P2M |
| 105 | * |
| 106 | */ |
| 107 | template<unsigned int np, unsigned int prp_g, unsigned int prp_v,unsigned int m2p_or_p2m> |
| 108 | struct inte_template |
| 109 | { |
| 110 | /*! \brief Evaluate the interpolation |
| 111 | * |
| 112 | * \tparam np number of kernel points in one direction |
| 113 | * \tparam grid type of grid |
| 114 | * \tparam vector type of vector |
| 115 | * \tparam iterator type of the iterator |
| 116 | * |
| 117 | * \param gd grid for interpolation |
| 118 | * \param vd vector for interpolation |
| 119 | * \param k_dist grid key grid point for interpolation |
| 120 | * \param key_p particle for interpolation |
| 121 | * \param a_int interpolation coefficients pre-calculated |
| 122 | * \param key indicate which pre-calculated coefficient we have to use |
| 123 | * |
| 124 | */ |
| 125 | template<unsigned int np_a_int, typename grid, typename vector, typename iterator> inline static void value(grid & gd, |
| 126 | vector & vd, |
| 127 | const grid_dist_lin_dx & k_dist, |
| 128 | iterator & key_p, |
| 129 | typename vector::stype (& a_int)[np_a_int], |
| 130 | const size_t & key) |
| 131 | { |
| 132 | mul_inte<typename std::remove_reference<decltype(gd.template get<prp_g>(k_dist))>::type>::value(gd.template get<prp_g>(k_dist),a_int[key],vd.template getProp<prp_v>(key_p)); |
| 133 | } |
| 134 | }; |
| 135 | |
| 136 | /*! \brief Class that select the operation to do differently if we are doing Mesh to particle (m2p) or particle to mesh (p2m) |
| 137 | * |
| 138 | * \tparam prp_g property of the grid to interpolate |
| 139 | * \tparam prp_v property of the vector to interpolate |
| 140 | * \param M2P or P2M |
| 141 | * |
| 142 | */ |
| 143 | template<unsigned int np, unsigned int prp_g, unsigned int prp_v> |
| 144 | struct inte_template<np,prp_g,prp_v,inte_m2p> |
| 145 | { |
| 146 | /*! \brief Evaluate the interpolation |
| 147 | * |
| 148 | * \tparam grid type of grid |
| 149 | * \tparam vector type of vector |
| 150 | * \tparam iterator type of the iterator |
| 151 | * \tparam key_type type of the key |
| 152 | * |
| 153 | * \param gd grid for interpolation |
| 154 | * \param vd vector for interpolation |
| 155 | * \param k_dist grid key grid point for interpolation |
| 156 | * \param key_p particle for interpolation |
| 157 | * \param a_int interpolation coefficients pre-calculated |
| 158 | * \param key indicate which pre-calculated coefficient we have to use |
| 159 | * |
| 160 | */ |
| 161 | template<unsigned int np_a_int, typename grid, typename vector, typename iterator> inline static void value(grid & gd, |
| 162 | vector & vd, |
| 163 | const grid_dist_lin_dx & k_dist, |
| 164 | iterator & key_p, |
| 165 | typename vector::stype (& a_int)[np_a_int], |
| 166 | const size_t & key) |
| 167 | { |
| 168 | mul_inte<typename std::remove_reference<decltype(gd.template get<prp_g>(k_dist))>::type>::value(vd.template getProp<prp_v>(key_p),a_int[key],gd.template get<prp_g>(k_dist)); |
| 169 | } |
| 170 | }; |
| 171 | |
| 172 | /*! \brief Calculate aint |
| 173 | * |
| 174 | * This class store |
| 175 | * |
| 176 | */ |
| 177 | template<unsigned int dims, typename vector, unsigned int np> |
| 178 | struct calculate_aint |
| 179 | { |
| 180 | /*! \brief Calculate the coefficients of the interpolation a_int for one particles |
| 181 | * having the 1D kernel values |
| 182 | * |
| 183 | * \param sz size of stencil for the interpolation |
| 184 | * \param a_int coefficients on the stencil points |
| 185 | * \param a coefficients of the kernel for each direction, consider |
| 186 | * that for 3 dimensions the kernel is the multiplication |
| 187 | * the 1D kernel on each direction. The "a" array store the |
| 188 | * calculated coefficient of the 1D kernel on each direction |
| 189 | * |
| 190 | */ |
| 191 | static inline void value(size_t (& sz)[vector::dims], |
| 192 | typename vector::stype a_int[openfpm::math::pow(np,vector::dims)], |
| 193 | typename vector::stype (& a)[vector::dims][np]) |
| 194 | { |
| 195 | grid_sm<vector::dims,void> gs(sz); |
| 196 | grid_key_dx_iterator<vector::dims> kit(gs); |
| 197 | |
| 198 | size_t s = 0; |
| 199 | while (kit.isNext()) |
| 200 | { |
| 201 | auto key = kit.get(); |
| 202 | |
| 203 | a_int[s] = 1; |
| 204 | |
| 205 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 206 | a_int[s] *= a[i][key.get(i)]; |
| 207 | |
| 208 | s++; |
| 209 | ++kit; |
| 210 | } |
| 211 | } |
| 212 | }; |
| 213 | |
| 214 | /*! \brief Calculate aint 2D |
| 215 | * |
| 216 | * |
| 217 | */ |
| 218 | template<typename vector, unsigned int np> |
| 219 | struct calculate_aint<2,vector,np> |
| 220 | { |
| 221 | |
| 222 | /*! \brief Calculate the coefficients of the interpolation a_int for one particles |
| 223 | * having the 1D kernel values |
| 224 | * |
| 225 | * \param sz size of stencil for the interpolation |
| 226 | * \param a_int coefficients on the stencil points |
| 227 | * \param a coefficients of the kernel for each direction, consider |
| 228 | * that for 3 dimensions the kernel is the multiplication |
| 229 | * the 1D kernel on each direction. The "a" array store the |
| 230 | * calculated coefficient of the 1D kernel on each direction |
| 231 | * |
| 232 | */ |
| 233 | static inline void value(size_t (& sz)[vector::dims], |
| 234 | typename vector::stype a_int[openfpm::math::pow(np,vector::dims)], |
| 235 | typename vector::stype (& a)[vector::dims][np]) |
| 236 | { |
| 237 | size_t s = 0; |
| 238 | for (size_t i = 0 ; i < np ; i++) |
| 239 | { |
| 240 | for (size_t j = 0 ; j < np ; j++) |
| 241 | { |
| 242 | a_int[s] = a[0][j]*a[1][i]; |
| 243 | |
| 244 | s++; |
| 245 | } |
| 246 | } |
| 247 | } |
| 248 | }; |
| 249 | |
| 250 | /*! \brief Calculate aint |
| 251 | * |
| 252 | * |
| 253 | */ |
| 254 | template<typename vector, unsigned int np> |
| 255 | struct calculate_aint<3,vector,np> |
| 256 | { |
| 257 | /*! \brief Calculate the coefficients of the interpolation a_int for one particles |
| 258 | * having the 1D kernel values |
| 259 | * |
| 260 | * \param sz size of stencil for the interpolation |
| 261 | * \param a_int coefficients on the stencil points |
| 262 | * \param a coefficients of the kernel for each direction, consider |
| 263 | * that for 3 dimensions the kernel is the multiplication |
| 264 | * the 1D kernel on each direction. The "a" array store the |
| 265 | * calculated coefficient of the 1D kernel on each direction |
| 266 | * |
| 267 | */ |
| 268 | static inline void value(size_t (& sz)[vector::dims], |
| 269 | typename vector::stype a_int[openfpm::math::pow(np,vector::dims)], |
| 270 | typename vector::stype (& a)[vector::dims][np]) |
| 271 | { |
| 272 | size_t s = 0; |
| 273 | for (size_t i = 0 ; i < np ; i++) |
| 274 | { |
| 275 | for (size_t j = 0 ; j < np ; j++) |
| 276 | { |
| 277 | for (size_t k = 0 ; k < np ; k++) |
| 278 | { |
| 279 | a_int[s] = a[0][k]*a[1][j]*a[2][i]; |
| 280 | |
| 281 | s++; |
| 282 | } |
| 283 | } |
| 284 | } |
| 285 | } |
| 286 | }; |
| 287 | |
| 288 | /*! \brief return the sub-domain where this particle must be interpolated |
| 289 | * |
| 290 | * \param p particle position |
| 291 | * |
| 292 | * \return the sub-domain id |
| 293 | * |
| 294 | */ |
| 295 | template<typename vector, typename grid> |
| 296 | inline size_t getSub(Point<vector::dims,typename vector::stype> & p, |
| 297 | const CellList<vector::dims,typename vector::stype,Mem_fast<>,shift<vector::dims,typename vector::stype>> & geo_cell, |
| 298 | grid & gd) |
| 299 | { |
| 300 | size_t cell = geo_cell.getCell(p); |
| 301 | |
| 302 | for (size_t i = 0 ; i < geo_cell.getNelements(cell) ; i++) |
| 303 | { |
| 304 | size_t ns = geo_cell.get(cell,i); |
| 305 | |
| 306 | if (gd.getDecomposition().getSubDomain(ns).isInside(p)) |
| 307 | return ns; |
| 308 | } |
| 309 | |
| 310 | // If we end up here it mean that the particle decomposition and the grid decomposition are at machine precision level |
| 311 | // different. To recover we shift the particle of a machine precision correction inside the domain. |
| 312 | |
| 313 | typename vector::stype dx[vector::dims]; |
| 314 | typename vector::stype best_dx[vector::dims]; |
| 315 | typename vector::stype best_tot_dx; |
| 316 | long int best_sub; |
| 317 | |
| 318 | Box<vector::dims,typename vector::stype> sub_dom = gd.getDecomposition().getSubDomain(0); |
| 319 | |
| 320 | for (size_t j = 0 ; j < vector::dims ; j++) |
| 321 | { |
| 322 | if (sub_dom.getLow(j) > p.get(j)) |
| 323 | {dx[j] = 2*(sub_dom.getLow(j) - p.get(j));} |
| 324 | else if (sub_dom.getHigh(j) < p.get(j)) |
| 325 | {dx[j] = 2*(sub_dom.getHigh(j) - p.get(j));} |
| 326 | else {dx[j] = 0;} |
| 327 | } |
| 328 | |
| 329 | typename vector::stype tot_dx = 0.0; |
| 330 | |
| 331 | for (size_t j = 0 ; j < vector::dims ; j++) |
| 332 | {tot_dx += fabs(dx[j]);} |
| 333 | |
| 334 | best_tot_dx = tot_dx; |
| 335 | for (size_t j = 0 ; j < vector::dims ; j++) |
| 336 | {best_dx[j] = dx[j];} |
| 337 | best_sub = 0; |
| 338 | |
| 339 | for (size_t i = 1 ; i < gd.getDecomposition().getNSubDomain() ; i++) |
| 340 | { |
| 341 | Box<vector::dims,typename vector::stype> sub_dom = gd.getDecomposition().getSubDomain(i); |
| 342 | |
| 343 | for (size_t j = 0 ; j < vector::dims ; j++) |
| 344 | { |
| 345 | if (sub_dom.getLow(j) > p.get(j)) |
| 346 | {dx[j] = 2*(sub_dom.getLow(j) - p.get(j));} |
| 347 | else if (sub_dom.getHigh(j) < p.get(j)) |
| 348 | {dx[j] = 2*(sub_dom.getHigh(j) - p.get(j));} |
| 349 | else {dx[j] = 0;} |
| 350 | } |
| 351 | |
| 352 | typename vector::stype tot_dx = 0.0; |
| 353 | |
| 354 | for (size_t j = 0 ; j < vector::dims ; j++) |
| 355 | {tot_dx += fabs(dx[j]);} |
| 356 | |
| 357 | if (tot_dx < best_tot_dx) |
| 358 | { |
| 359 | best_tot_dx = tot_dx; |
| 360 | for (size_t j = 0 ; j < vector::dims ; j++) |
| 361 | {best_dx[j] = dx[j];} |
| 362 | best_sub = i; |
| 363 | } |
| 364 | } |
| 365 | |
| 366 | // shift xp |
| 367 | |
| 368 | for (size_t j = 0 ; j < vector::dims ; j++) |
| 369 | {p.get(j) += best_dx[j];} |
| 370 | |
| 371 | return best_sub; |
| 372 | } |
| 373 | |
| 374 | /*! \brief calculate the interpolation for one point |
| 375 | * |
| 376 | * \tparam vector of particles |
| 377 | * \tparam kernel type |
| 378 | * |
| 379 | */ |
| 380 | template<typename vector,typename kernel> |
| 381 | struct inte_calc_impl |
| 382 | { |
| 383 | //! Type of the calculations |
| 384 | typedef typename vector::stype arr_type; |
| 385 | |
| 386 | /*! \brief M2P or P2M for one particle |
| 387 | * |
| 388 | * \tparam prp_g property to interpolate from(M2P) or to(P2M) for grid |
| 389 | * \tparam prp_v property to interpolate to(M2P) or from(P2M) for vector |
| 390 | * \tparam m2p_or_p2m mesh to particle or mesh to particle interpolation |
| 391 | * |
| 392 | * \param it iterator used to retrieve the particle p for interpolation |
| 393 | * \param vd vector of particles |
| 394 | * \param domain simulation domain |
| 395 | * \param ip index of the grid on each direction (1D) used for interpolation |
| 396 | * \param gd interpolation grid |
| 397 | * \param dx spacing on each direction |
| 398 | * \param xp Point that store the position of xp |
| 399 | * \param a_int coefficients on the stencil points |
| 400 | * \param a coefficients of the kernel for each direction, consider |
| 401 | * that for 3 dimensions the kernel is the multiplication |
| 402 | * the 1D kernel on each direction. The "a" array store the |
| 403 | * calculated coefficient of the 1D kernel on each direction |
| 404 | * \param x position of |
| 405 | * \param sz grid size |
| 406 | * \param geo_cell cell list to convert particle position into sub-domain id |
| 407 | * \param offsets array where are stored the linearized offset of the |
| 408 | * kernel stencil for each local grid (sub-domain) |
| 409 | * |
| 410 | */ |
| 411 | template<unsigned int prp_g, unsigned int prp_v, unsigned int m2p_or_p2m, unsigned int np_a_int, typename grid> |
| 412 | static inline void inte_calc(const vect_dist_key_dx & key_p, |
| 413 | vector & vd, |
| 414 | const Box<vector::dims,typename vector::stype> & domain, |
| 415 | int (& ip)[vector::dims][kernel::np], |
| 416 | grid & gd, |
| 417 | const typename vector::stype (& dx)[vector::dims], |
| 418 | typename vector::stype (& xp)[vector::dims], |
| 419 | typename vector::stype (& a_int)[np_a_int], |
| 420 | typename vector::stype (& a)[vector::dims][kernel::np], |
| 421 | typename vector::stype (& x)[vector::dims][kernel::np], |
| 422 | size_t (& sz)[vector::dims], |
| 423 | const CellList<vector::dims,typename vector::stype,Mem_fast<>,shift<vector::dims,typename vector::stype>> & geo_cell, |
| 424 | openfpm::vector<agg_arr<openfpm::math::pow(kernel::np,vector::dims)>> & offsets) |
| 425 | { |
| 426 | Point<vector::dims,typename vector::stype> p = vd.getPos(key_p); |
| 427 | |
| 428 | // On which sub-domain we interpolate the particle |
| 429 | size_t sub = getSub<vector>(p,geo_cell,gd); |
| 430 | |
| 431 | typename vector::stype x0[vector::dims]; |
| 432 | |
| 433 | // calculate the position of the particle in the grid |
| 434 | // coordinated |
| 435 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 436 | {x0[i] = (p.get(i)-domain.getLow(i))*dx[i];} |
| 437 | |
| 438 | // convert into integer |
| 439 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 440 | {ip[i][0] = (int)x0[i];} |
| 441 | |
| 442 | // convert the global grid position into local grid position |
| 443 | grid_key_dx<vector::dims> base; |
| 444 | |
| 445 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 446 | {base.set_d(i,ip[i][0] - gd.getLocalGridsInfo().get(sub).origin.get(i) - (long int)kernel::np/2 + 1);} |
| 447 | |
| 448 | // convenient grid of points |
| 449 | |
| 450 | for (size_t j = 0 ; j < kernel::np-1 ; j++) |
| 451 | { |
| 452 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 453 | {ip[i][j+1] = (int)ip[i][j]+1;} |
| 454 | } |
| 455 | |
| 456 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 457 | xp[i] = x0[i] - ip[i][0]; |
| 458 | |
| 459 | for (long int j = 0 ; j < kernel::np ; j++) |
| 460 | { |
| 461 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 462 | {x[i][j] = - xp[i] + typename vector::stype((long int)j - (long int)kernel::np/2 + 1);} |
| 463 | } |
| 464 | |
| 465 | for (size_t j = 0 ; j < kernel::np ; j++) |
| 466 | { |
| 467 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 468 | {a[i][j] = kernel::value(x[i][j],j);} |
| 469 | } |
| 470 | |
| 471 | calculate_aint<vector::dims,vector,kernel::np>::value(sz,a_int,a); |
| 472 | |
| 473 | grid_dist_lin_dx k_dist_lin; |
| 474 | k_dist_lin.setSub(sub); |
| 475 | |
| 476 | size_t k = 0; |
| 477 | auto & gs_info = gd.get_loc_grid(sub).getGrid(); |
| 478 | |
| 479 | size_t lin_base = gs_info.LinId(base); |
| 480 | |
| 481 | for (size_t i = 0 ; i < openfpm::math::pow(kernel::np,vector::dims) ; i++) |
| 482 | { |
| 483 | size_t lin = offsets.get(sub).ele[k] + lin_base; |
| 484 | k_dist_lin.getKeyRef() = lin; |
| 485 | |
| 486 | inte_template<kernel::np,prp_g,prp_v,m2p_or_p2m>::value(gd,vd,k_dist_lin,key_p,a_int,k); |
| 487 | |
| 488 | k++; |
| 489 | } |
| 490 | } |
| 491 | }; |
| 492 | |
| 493 | /*! \brief Main class for interpolation Particle to mest p2m and Mesh to particle m2p |
| 494 | * |
| 495 | * This function is the main class to interpolate from particle to mesh and mesh to particle |
| 496 | * |
| 497 | * \tparam vector type of vector for interpolation |
| 498 | * \tparam grid type of grid for interpolation |
| 499 | * \tparam interpolation kernel |
| 500 | * |
| 501 | */ |
| 502 | template<typename vector,typename grid, typename kernel> |
| 503 | class interpolate |
| 504 | { |
| 505 | //! Cell list used to convert particles position to sub-domain |
| 506 | CellList<vector::dims,typename vector::stype,Mem_fast<>,shift<vector::dims,typename vector::stype>> geo_cell; |
| 507 | |
| 508 | /*! Structure to order boxes by volume |
| 509 | * |
| 510 | * |
| 511 | * |
| 512 | */ |
| 513 | struct Box_vol |
| 514 | { |
| 515 | //! Box |
| 516 | Box<vector::dims,size_t> bv; |
| 517 | |
| 518 | //! Calculated volume |
| 519 | size_t vol; |
| 520 | |
| 521 | /*! \brief operator to reorder |
| 522 | * |
| 523 | * \param bv box to compare with |
| 524 | * |
| 525 | * \return true if bv has volume bigger volume |
| 526 | * |
| 527 | */ |
| 528 | bool operator<(const Box_vol & bv) |
| 529 | { |
| 530 | return vol < bv.vol; |
| 531 | } |
| 532 | }; |
| 533 | |
| 534 | //! particles |
| 535 | vector & vd; |
| 536 | |
| 537 | //! grid |
| 538 | grid & gd; |
| 539 | |
| 540 | //! Type of the calculations |
| 541 | typedef typename vector::stype arr_type; |
| 542 | |
| 543 | //! the offset for each sub-sub-domain |
| 544 | openfpm::vector<agg_arr<openfpm::math::pow(kernel::np,vector::dims)>> offsets; |
| 545 | |
| 546 | //! kernel size |
| 547 | size_t sz[vector::dims]; |
| 548 | |
| 549 | //! grid spacing |
| 550 | typename vector::stype dx[vector::dims]; |
| 551 | |
| 552 | //! Simulation domain |
| 553 | Box<vector::dims,typename vector::stype> domain; |
| 554 | |
| 555 | /*! \brief It calculate the interpolation stencil offsets |
| 556 | * |
| 557 | * \param offsets array where to store the linearized offset of the |
| 558 | * kernel stencil for each local-grid (sub-domain) |
| 559 | * \param sz kernel stencil points in each direction |
| 560 | * |
| 561 | */ |
| 562 | void calculate_the_offsets(openfpm::vector<agg_arr<openfpm::math::pow(kernel::np,vector::dims)>> & offsets, size_t (& sz)[vector::dims]) |
| 563 | { |
| 564 | offsets.resize(gd.getN_loc_grid()); |
| 565 | |
| 566 | for (size_t i = 0 ; i < offsets.size() ; i++) |
| 567 | { |
| 568 | auto & loc_grid = gd.get_loc_grid(i); |
| 569 | const grid_sm<vector::dims,void> & gs = loc_grid.getGrid(); |
| 570 | |
| 571 | grid_sm<vector::dims,void> gs2(sz); |
| 572 | grid_key_dx_iterator<vector::dims> kit2(gs2); |
| 573 | |
| 574 | size_t k = 0; |
| 575 | |
| 576 | while (kit2.isNext()) |
| 577 | { |
| 578 | auto key = kit2.get(); |
| 579 | |
| 580 | long int lin = gs.LinId(key); |
| 581 | |
| 582 | offsets.get(i).ele[k] = lin; |
| 583 | |
| 584 | ++k; |
| 585 | ++kit2; |
| 586 | } |
| 587 | } |
| 588 | } |
| 589 | |
| 590 | public: |
| 591 | |
| 592 | /*! \brief construct an interpolation object between a grid and a vector |
| 593 | * |
| 594 | * When possible and easy to do we suggest to retain the object |
| 595 | * |
| 596 | * \param vd interpolation vector |
| 597 | * \param gd interpolation grid |
| 598 | * |
| 599 | */ |
| 600 | interpolate(vector & vd, grid & gd) |
| 601 | :vd(vd),gd(gd) |
| 602 | { |
| 603 | // get the processor bounding box in grid units |
| 604 | Box<vector::dims,typename vector::stype> bb = gd.getDecomposition().getProcessorBounds(); |
| 605 | Box<vector::dims,typename vector::stype> bunit = gd.getDecomposition().getCellDecomposer().getCellBox(); |
| 606 | |
| 607 | size_t div[vector::dims]; |
| 608 | |
| 609 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 610 | div[i] = (bb.getHigh(i) - bb.getLow(i)) / bunit.getHigh(i); |
| 611 | |
| 612 | geo_cell.Initialize(bb,div); |
| 613 | |
| 614 | // Now draw the domain into the cell list |
| 615 | |
| 616 | auto & dec = gd.getDecomposition(); |
| 617 | |
| 618 | for (size_t i = 0 ; i < dec.getNSubDomain() ; i++) |
| 619 | { |
| 620 | const Box<vector::dims,typename vector::stype> & bx = dec.getSubDomain(i); |
| 621 | |
| 622 | // get the cells this box span |
| 623 | const grid_key_dx<vector::dims> p1 = geo_cell.getCellGrid(bx.getP1()); |
| 624 | const grid_key_dx<vector::dims> p2 = geo_cell.getCellGrid(bx.getP2()); |
| 625 | |
| 626 | // Get the grid and the sub-iterator |
| 627 | auto & gi = geo_cell.getGrid(); |
| 628 | grid_key_dx_iterator_sub<vector::dims> g_sub(gi,p1,p2); |
| 629 | |
| 630 | // add the box-id to the cell list |
| 631 | while (g_sub.isNext()) |
| 632 | { |
| 633 | auto key = g_sub.get(); |
| 634 | geo_cell.addCell(gi.LinId(key),i); |
| 635 | ++g_sub; |
| 636 | } |
| 637 | } |
| 638 | |
| 639 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 640 | {sz[i] = kernel::np;} |
| 641 | |
| 642 | calculate_the_offsets(offsets,sz); |
| 643 | |
| 644 | // calculate spacing |
| 645 | for (size_t i = 0 ; i < vector::dims ; i++) |
| 646 | {dx[i] = 1.0/gd.spacing(i);} |
| 647 | |
| 648 | // simulation domain |
| 649 | domain = vd.getDecomposition().getDomain(); |
| 650 | }; |
| 651 | |
| 652 | /*! \brief Interpolate particles to mesh |
| 653 | * |
| 654 | * Most of the time the particle set and the mesh are the same |
| 655 | * as the one used in the constructor. They also can be different |
| 656 | * as soon as they have the same decomposition |
| 657 | * |
| 658 | * \param gd grid or mesh |
| 659 | * \param vd particle set |
| 660 | * |
| 661 | */ |
| 662 | template<unsigned int prp_v, unsigned int prp_g> void p2m(vector & vd, grid & gd) |
| 663 | { |
| 664 | #ifdef SE_CLASS1 |
| 665 | |
| 666 | if (!vd.getDecomposition().is_equal_ng(gd.getDecomposition()) ) |
| 667 | { |
| 668 | std::cerr << __FILE__ << ":" << __LINE__ << " Error: the distribution of the vector of particles" << |
| 669 | " and the grid is different. In order to interpolate the two data structure must have the" << |
| 670 | " same decomposition" << std::endl; |
| 671 | |
| 672 | ACTION_ON_ERROR(INTERPOLATION_ERROR_OBJECT) |
| 673 | } |
| 674 | |
| 675 | #endif |
| 676 | |
| 677 | // point position |
| 678 | typename vector::stype xp[vector::dims]; |
| 679 | |
| 680 | int ip[vector::dims][kernel::np]; |
| 681 | typename vector::stype x[vector::dims][kernel::np]; |
| 682 | typename vector::stype a[vector::dims][kernel::np]; |
| 683 | |
| 684 | typename vector::stype a_int[openfpm::math::pow(kernel::np,vector::dims)]; |
| 685 | |
| 686 | auto it = vd.getDomainIterator(); |
| 687 | |
| 688 | while (it.isNext() == true) |
| 689 | { |
| 690 | auto key_p = it.get(); |
| 691 | |
| 692 | inte_calc_impl<vector,kernel>::template inte_calc<prp_g,prp_v,inte_p2m,openfpm::math::pow(kernel::np,vector::dims)>(key_p,vd,domain,ip,gd,dx,xp,a_int,a,x,sz,geo_cell,offsets); |
| 693 | |
| 694 | ++it; |
| 695 | } |
| 696 | } |
| 697 | |
| 698 | /*! \brief Interpolate mesh to particle |
| 699 | * |
| 700 | * Most of the time the particle set and the mesh are the same |
| 701 | * as the one used in the constructor. They also can be different |
| 702 | * as soon as they have the same decomposition |
| 703 | * |
| 704 | * \param gd grid or mesh |
| 705 | * \param vd particle set |
| 706 | * |
| 707 | */ |
| 708 | template<unsigned int prp_g, unsigned int prp_v> void m2p(grid & gd, vector & vd) |
| 709 | { |
| 710 | #ifdef SE_CLASS1 |
| 711 | |
| 712 | if (!vd.getDecomposition().is_equal_ng(gd.getDecomposition()) ) |
| 713 | { |
| 714 | std::cerr << __FILE__ << ":" << __LINE__ << " Error: the distribution of the vector of particles" << |
| 715 | " and the grid is different. In order to interpolate the two data structure must have the" << |
| 716 | " same decomposition" << std::endl; |
| 717 | |
| 718 | ACTION_ON_ERROR(INTERPOLATION_ERROR_OBJECT) |
| 719 | } |
| 720 | |
| 721 | #endif |
| 722 | |
| 723 | // point position |
| 724 | typename vector::stype xp[vector::dims]; |
| 725 | |
| 726 | int ip[vector::dims][kernel::np]; |
| 727 | typename vector::stype x[vector::dims][kernel::np]; |
| 728 | typename vector::stype a[vector::dims][kernel::np]; |
| 729 | |
| 730 | // grid_cpu<vector::dims,aggregate<typename vector::stype>> a_int(sz); |
| 731 | // a_int.setMemory(); |
| 732 | typename vector::stype a_int[openfpm::math::pow(kernel::np,vector::dims)]; |
| 733 | |
| 734 | auto it = vd.getDomainIterator(); |
| 735 | |
| 736 | while (it.isNext() == true) |
| 737 | { |
| 738 | auto key_p = it.get(); |
| 739 | |
| 740 | inte_calc_impl<vector,kernel>::template inte_calc<prp_g,prp_v,inte_m2p,openfpm::math::pow(kernel::np,vector::dims)>(key_p,vd,domain,ip,gd,dx,xp,a_int,a,x,sz,geo_cell,offsets); |
| 741 | |
| 742 | ++it; |
| 743 | } |
| 744 | } |
| 745 | |
| 746 | |
| 747 | /*! \brief Interpolate particles to mesh |
| 748 | * |
| 749 | * Most of the time the particle set and the mesh are the same |
| 750 | * as the one used in the constructor. They also can be different |
| 751 | * as soon as they have the same decomposition |
| 752 | * |
| 753 | * \param gd grid or mesh |
| 754 | * \param vd particle set |
| 755 | * \param p particle |
| 756 | * |
| 757 | */ |
| 758 | template<unsigned int prp_v, unsigned int prp_g> inline void p2m(vector & vd, grid & gd,const vect_dist_key_dx & p) |
| 759 | { |
| 760 | #ifdef SE_CLASS1 |
| 761 | |
| 762 | if (!vd.getDecomposition().is_equal_ng(gd.getDecomposition()) ) |
| 763 | { |
| 764 | std::cerr << __FILE__ << ":" << __LINE__ << " Error: the distribution of the vector of particles" << |
| 765 | " and the grid is different. In order to interpolate the two data structure must have the" << |
| 766 | " same decomposition" << std::endl; |
| 767 | |
| 768 | ACTION_ON_ERROR(INTERPOLATION_ERROR_OBJECT) |
| 769 | } |
| 770 | |
| 771 | #endif |
| 772 | |
| 773 | // point position |
| 774 | typename vector::stype xp[vector::dims]; |
| 775 | |
| 776 | int ip[vector::dims][kernel::np]; |
| 777 | typename vector::stype x[vector::dims][kernel::np]; |
| 778 | typename vector::stype a[vector::dims][kernel::np]; |
| 779 | |
| 780 | typename vector::stype a_int[openfpm::math::pow(kernel::np,vector::dims)]; |
| 781 | |
| 782 | /* coverty[uninit_use_in_call] */ |
| 783 | inte_calc_impl<vector,kernel>::template inte_calc<prp_g,prp_v,inte_p2m,openfpm::math::pow(kernel::np,vector::dims)>(p,vd,domain,ip,gd,dx,xp,a_int,a,x,sz,geo_cell,offsets); |
| 784 | } |
| 785 | |
| 786 | /*! \brief Interpolate mesh to particle |
| 787 | * |
| 788 | * Most of the time the particle set and the mesh are the same |
| 789 | * as the one used in the constructor. They also can be different |
| 790 | * as soon as they have the same decomposition |
| 791 | * |
| 792 | * \param gd grid or mesh |
| 793 | * \param vd particle set |
| 794 | * \param p particle |
| 795 | * |
| 796 | */ |
| 797 | template<unsigned int prp_g, unsigned int prp_v> inline void m2p(grid & gd, vector & vd, const vect_dist_key_dx & p) |
| 798 | { |
| 799 | #ifdef SE_CLASS1 |
| 800 | |
| 801 | if (!vd.getDecomposition().is_equal_ng(gd.getDecomposition()) ) |
| 802 | { |
| 803 | std::cerr << __FILE__ << ":" << __LINE__ << " Error: the distribution of the vector of particles" << |
| 804 | " and the grid is different. In order to interpolate the two data structure must have the" << |
| 805 | " same decomposition" << std::endl; |
| 806 | |
| 807 | ACTION_ON_ERROR(INTERPOLATION_ERROR_OBJECT) |
| 808 | } |
| 809 | |
| 810 | #endif |
| 811 | |
| 812 | // point position |
| 813 | typename vector::stype xp[vector::dims]; |
| 814 | |
| 815 | int ip[vector::dims][kernel::np]; |
| 816 | typename vector::stype x[vector::dims][kernel::np]; |
| 817 | typename vector::stype a[vector::dims][kernel::np]; |
| 818 | |
| 819 | // grid_cpu<vector::dims,aggregate<typename vector::stype>> a_int(sz); |
| 820 | // a_int.setMemory(); |
| 821 | typename vector::stype a_int[openfpm::math::pow(kernel::np,vector::dims)]; |
| 822 | |
| 823 | inte_calc_impl<vector,kernel>::template inte_calc<prp_g,prp_v,inte_m2p,openfpm::math::pow(kernel::np,vector::dims)>(p,vd,domain,ip,gd,dx,xp,a_int,a,x,sz,geo_cell,offsets); |
| 824 | } |
| 825 | |
| 826 | }; |
| 827 | |
| 828 | #endif /* OPENFPM_NUMERICS_SRC_INTERPOLATION_INTERPOLATION_HPP_ */ |
| 829 | |