Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
cpu_face_estimates.hpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2021 Finnish Meteorological Institute
4 *
5 * For details of usage, see the COPYING file and read the "Rules of the Road"
6 * at http://www.physics.helsinki.fi/vlasiator/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#ifndef CPU_FACE_ESTIMATES_H
24#define CPU_FACE_ESTIMATES_H
25
26#include "vec.h"
28#include "../definitions.h"
29
31
32/*enum for setting face value and derivative estimates. Implicit ones
33 not supported in the solver, so they are now not listed*/
35
45inline void compute_h8_left_face_value(const Vec * const values, uint k, Vec &fv_l)
46{
47 fv_l = 1.0/840.0 * (
48 - 3.0 * values[k - 4]
49 + 29.0 * values[k - 3]
50 - 139.0 * values[k - 2]
51 + 533.0 * values[k - 1]
52 + 533.0 * values[k]
53 - 139.0 * values[k + 1]
54 + 29.0 * values[k + 2]
55 - 3.0 * values[k + 3]);
56}
57
58
68inline void compute_h7_left_face_derivative(const Vec * const values, uint k, Vec &fd_l){
69 fd_l = 1.0/5040.0 * (
70 + 9.0 * values[k - 4]
71 - 119.0 * values[k - 3]
72 + 889.0 * values[k - 2]
73 - 7175.0 * values[k - 1]
74 + 7175.0 * values[k]
75 - 889.0 * values[k + 1]
76 + 119.0 * values[k + 2]
77 - 9.0 * values[k + 3]);
78}
79
89inline void compute_h6_left_face_value(const Vec * const values, uint k, Vec &fv_l)
90{
91 //compute left value
92 fv_l = 1.0/60.0 * (values[k - 3]
93 - 8.0 * values[k - 2]
94 + 37.0 * values[k - 1]
95 + 37.0 * values[k ]
96 - 8.0 * values[k + 1]
97 + values[k + 2]);
98}
99
109inline void compute_h5_left_face_derivative(const Vec * const values, uint k, Vec &fd_l)
110{
111 fd_l = 1.0/180.0 * (245 * (values[k] - values[k - 1])
112 - 25 * (values[k + 1] - values[k - 2])
113 + 2 * (values[k + 2] - values[k - 3]));
114}
115
123inline void compute_h5_face_values(const Vec * const values, uint k, Vec &fv_l, Vec &fv_r)
124{
125 //compute left values
126 fv_l = 1.0/60.0 * (- 3.0 * values[k - 2]
127 + 27.0 * values[k - 1]
128 + 47.0 * values[k ]
129 - 13.0 * values[k + 1]
130 + 2.0 * values[k + 2]);
131 fv_r = 1.0/60.0 * ( 2.0 * values[k - 2]
132 - 13.0 * values[k - 1]
133 + 47.0 * values[k]
134 + 27.0 * values[k + 1]
135 - 3.0 * values[k + 2]);
136}
137
146inline void compute_h4_left_face_derivative(const Vec * const values, uint k, Vec &fd_l)
147{
148 fd_l = 1.0/12.0 * (15.0 * (values[k] - values[k - 1]) - (values[k + 1] - values[k - 2]));
149}
150
160inline void compute_h4_left_face_value(const Vec * const values, uint k, Vec &fv_l)
161{
162 //compute left value
163 fv_l = 1.0/12.0 * ( - 1.0 * values[k - 2]
164 + 7.0 * values[k - 1]
165 + 7.0 * values[k]
166 - 1.0 * values[k + 1]);
167}
168
169
179inline void compute_h4_left_face_value_nonuniform(const Realf * const h, const Vec * const u, uint k, Vec &fv_l) {
180
181 fv_l = (
182 1.0 / ( h[k - 2] + h[k - 1] + h[k] + h[k + 1] )
183 * ( ( h[k - 2] + h[k - 1] ) * ( h[k] + h[k + 1] ) / ( h[k - 1] + h[k] )
184 * ( u[k - 1] * h[k] + u[k] * h[k - 1] )
185 * (1.0 / ( h[k - 2] + h[k - 1] + h[k] ) + 1.0 / ( h[k - 1] + h[k] + h[k + 1] ) )
186 + ( h[k] * ( h[k] + h[k + 1] ) ) / ( ( h[k - 2] + h[k - 1] + h[k] ) * (h[k - 2] + h[k - 1] ) )
187 * ( u[k - 1] * (h[k - 2] + 2.0 * h[k - 1] ) - ( u[k - 2] * h[k - 1] ) )
188 + h[k - 1] * ( h[k - 2] + h[k - 1] ) / ( ( h[k - 1] + h[k] + h[k + 1] ) * ( h[k] + h[k + 1] ) )
189 * ( u[k] * ( 2.0 * h[k] + h[k + 1] ) - u[k + 1] * h[k] ) )
190 );
191}
192
193
194
204inline void compute_h3_left_face_derivative(const Vec * const values, uint k, Vec &fv_l)
205{
206 /*compute left value*/
207 fv_l = 1.0/12.0 * (15 * (values[k] - values[k - 1]) - (values[k + 1] - values[k - 2]));
208}
209
210/*Filters in section 2.6.1 of white et al. to be used for PQM
211 1) Checks for extrema and flattens them
212 2) Makes face values bounded
213 3) Makes sure face slopes are consistent with PLM slope
214*/
215inline void compute_filtered_face_values_derivatives(const Vec * const values,const uint k,const face_estimate_order order, Vec &fv_l, Vec &fv_r, Vec &fd_l, Vec &fd_r, const Realf threshold)
216{
217 switch(order)
218 {
219 case h4:
220 compute_h4_left_face_value(values, k, fv_l);
221 compute_h4_left_face_value(values, k + 1, fv_r);
222 compute_h3_left_face_derivative(values, k, fd_l);
223 compute_h3_left_face_derivative(values, k + 1, fd_r);
224 break;
225 case h5:
226 compute_h5_face_values(values, k, fv_l, fv_r);
227 compute_h4_left_face_derivative(values, k, fd_l);
228 compute_h4_left_face_derivative(values, k + 1, fd_r);
229 break;
230 default:
231 case h6:
232 compute_h6_left_face_value(values, k, fv_l);
233 compute_h6_left_face_value(values, k + 1, fv_r);
234 compute_h5_left_face_derivative(values, k, fd_l);
235 compute_h5_left_face_derivative(values, k + 1, fd_r);
236 break;
237 case h8:
238 compute_h8_left_face_value(values, k, fv_l);
239 compute_h8_left_face_value(values, k + 1, fv_r);
240 compute_h7_left_face_derivative(values, k, fd_l);
241 compute_h7_left_face_derivative(values, k + 1, fd_r);
242 break;
243 }
244 Vec slope_abs,slope_sign;
245 // scale values closer to 1 for more accurate slope limiter calculation
246 const Realf scale = 1./threshold;
247 slope_limiter(values[k -1]*scale, values[k]*scale, values[k + 1]*scale, slope_abs, slope_sign);
248 slope_abs = slope_abs*threshold;
249 //check for extrema, flatten if it is
250 Vecb is_extrema = (slope_abs == Vec(0.0));
251 if (horizontal_or(is_extrema)) {
252 fv_r = select(is_extrema, values[k], fv_r);
253 fv_l = select(is_extrema, values[k], fv_l);
254 fd_l = select(is_extrema, 0.0 , fd_l);
255 fd_r = select(is_extrema, 0.0 , fd_r);
256 }
257 //Fix left face if needed; boundary value is not bounded or slope is not consistent
258 Vecb filter = (values[k -1] - fv_l) * (fv_l - values[k]) < 0 || slope_sign * fd_l < 0.0;
259 if (horizontal_or (filter)) {
260 //Go to linear (PLM) estimates if not ok (this is always ok!)
261 fv_l=select(filter, values[k ] - slope_sign * 0.5 * slope_abs, fv_l);
262 fd_l=select(filter, slope_sign * slope_abs, fd_l);
263 }
264 //Fix right face if needed; boundary value is not bounded or slope is not consistent
265 filter = (values[k + 1] - fv_r) * (fv_r - values[k]) < 0 || slope_sign * fd_r < 0.0;
266 if (horizontal_or (filter)) {
267 //Go to linear (PLM) estimates if not ok (this is always ok!)
268 fv_r=select(filter, values[k] + slope_sign * 0.5 * slope_abs, fv_r);
269 fd_r=select(filter, slope_sign * slope_abs, fd_r);
270 }
271}
272
273/*Filters in section 2.6.1 of white et al. to be used for PPM
274 1) Checks for extrema and flattens them
275 2) Makes face values bounded
276 3) Makes sure face slopes are consistent with PLM slope
277*/
278inline void compute_filtered_face_values(const Vec * const values,const uint k,const face_estimate_order order, Vec &fv_l, Vec &fv_r, const Realf threshold)
279{
280 switch(order)
281 {
282 case h4:
283 compute_h4_left_face_value(values, k, fv_l);
284 compute_h4_left_face_value(values, k + 1, fv_r);
285 break;
286 case h5:
287 compute_h5_face_values(values, k, fv_l, fv_r);
288 break;
289 default:
290 case h6:
291 compute_h6_left_face_value(values, k, fv_l);
292 compute_h6_left_face_value(values, k + 1, fv_r);
293 break;
294 case h8:
295 compute_h8_left_face_value(values, k, fv_l);
296 compute_h8_left_face_value(values, k + 1, fv_r);
297 break;
298 }
299 Vec slope_abs, slope_sign;
300 // scale values closer to 1 for more accurate slope limiter calculation
301 const Realf scale = 1./threshold;
302 slope_limiter(values[k -1]*scale, values[k]*scale, values[k + 1]*scale, slope_abs, slope_sign);
303 slope_abs = slope_abs*threshold;
304
305 //check for extrema, flatten if it is
306 Vecb is_extrema = (slope_abs == Vec(0.0));
307 if (horizontal_or(is_extrema)) {
308 fv_r = select(is_extrema, values[k], fv_r);
309 fv_l = select(is_extrema, values[k], fv_l);
310 }
311 //Fix left face if needed; boundary value is not bounded
312 Vecb filter = (values[k -1] - fv_l) * (fv_l - values[k]) < 0 ;
313 if (horizontal_or (filter)) {
314 //Go to linear (PLM) estimates if not ok (this is always ok!)
315 fv_l = select(filter, values[k ] - slope_sign * 0.5 * slope_abs, fv_l);
316 }
317 //Fix face if needed; boundary value is not bounded
318 filter = (values[k + 1] - fv_r) * (fv_r - values[k]) < 0;
319 if (horizontal_or (filter)) {
320 //Go to linear (PLM) estimates if not ok (this is always ok!)
321 fv_r = select(filter, values[k] + slope_sign * 0.5 * slope_abs, fv_r);
322 }
323}
324
325
326
327inline void compute_filtered_face_values_nonuniform(const Realf * const dv, const Vec * const values,const uint k,const face_estimate_order order, Vec &fv_l, Vec &fv_r, const Realf threshold){
328 switch(order){
329 case h4:
331 compute_h4_left_face_value_nonuniform(dv, values, k + 1, fv_r);
332 break;
333 // case h5:
334 // compute_h5_face_values(dv, values, k, fv_l, fv_r);
335 // break;
336 // case h6:
337 // compute_h6_left_face_value(dv, values, k, fv_l);
338 // compute_h6_left_face_value(dv, values, k + 1, fv_r);
339 // break;
340 // case h8:
341 // compute_h8_left_face_value(dv, values, k, fv_l);
342 // compute_h8_left_face_value(dv, values, k + 1, fv_r);
343 // break;
344 default:
345 printf("Order %d has not been implemented (yet)\n",order);
346 break;
347 }
348 Vec slope_abs,slope_sign;
349 if (threshold>0) {
350 // scale values closer to 1 for more accurate slope limiter calculation
351 const Realf scale = 1./threshold;
352 slope_limiter(values[k -1]*scale, values[k]*scale, values[k + 1]*scale, slope_abs, slope_sign);
353 slope_abs = slope_abs*threshold;
354 } else {
355 slope_limiter(values[k -1], values[k], values[k + 1], slope_abs, slope_sign);
356 }
357
358 //check for extrema, flatten if it is
359 Vecb is_extrema = (slope_abs == Vec(0.0));
360 if (horizontal_or(is_extrema)) {
361 fv_r = select(is_extrema, values[k], fv_r);
362 fv_l = select(is_extrema, values[k], fv_l);
363 }
364
365 //Fix left face if needed; boundary value is not bounded
366 Vecb filter = (values[k -1] - fv_l) * (fv_l - values[k]) < 0 ;
367 if (horizontal_or (filter)) {
368 //Go to linear (PLM) estimates if not ok (this is always ok!)
369 fv_l=select(filter, values[k ] - slope_sign * 0.5 * slope_abs, fv_l);
370 }
371
372 //Fix face if needed; boundary value is not bounded
373 filter = (values[k + 1] - fv_r) * (fv_r - values[k]) < 0;
374 if (horizontal_or (filter)) {
375 //Go to linear (PLM) estimates if not ok (this is always ok!)
376 fv_r=select(filter, values[k] + slope_sign * 0.5 * slope_abs, fv_r);
377 }
378}
379
380inline Vec get_D2aLim(const Realf * h, const Vec * values,const uint k, const Vec C,const Vec & fv) {
381
382 // Colella & Sekora, eq. 18
383 Vec invh2 = 1.0 / (h[k] * h[k]);
384 Vec d2a = invh2 * 3.0 * (values[k] - 2.0 * fv + values[k + 1]);
385 Vec d2aL = invh2 * (values[k - 1] - 2.0 * values[k] + values[k + 1]);
386 Vec d2aR = invh2 * (values[k] - 2.0 * values[k + 1] + values[k + 2]);
387 Vec d2aLim;
388 if ( (horizontal_or(d2a * d2aL >= 0)) && (horizontal_or(d2a * d2aR >= 0)) &&
389 horizontal_and(d2a != 0)) {
390 d2aLim = d2a / abs(d2a) * min(abs(d2a),min(C*abs(d2aL),C*abs(d2aR)));
391 } else {
392 d2aLim = 0.0;
393 }
394 return d2aLim;
395}
396
397inline void constrain_face_values(const Realf * h,const Vec * values,const uint k,Vec & fv_l, Vec & fv_r) {
398
399 const Vec C = 1.25;
400 Vec invh2 = 1.0 / (h[k] * h[k]);
401
402 // Colella & Sekora, eq 19
403 Vec p_face = 0.5 * (values[k] + values[k + 1])
404 - h[k] * h[k] / 3.0 * get_D2aLim(h,values,k ,C,fv_r);
405 Vec m_face = 0.5 * (values[k-1] + values[k])
406 - h[k-1] * h[k-1] / 3.0 * get_D2aLim(h,values,k-1,C,fv_l);
407
408 // Colella & Sekora, eq 21
409 Vec d2a = -2.0 * invh2 * 6.0 * (values[k] - 3.0 * (m_face + p_face)); // a6,j from eq. 7
410 Vec d2aC = invh2 * (values[k - 1] - 2.0 * values[k ] + values[k + 1]);
411 // Note: Corrected the index of 2nd term in d2aL to k - 1.
412 // In the paper it is k but that is almost certainly an error.
413 Vec d2aL = invh2 * (values[k - 2] - 2.0 * values[k - 1] + values[k ]);
414 Vec d2aR = invh2 * (values[k ] - 2.0 * values[k + 1] + values[k + 2]);
415 Vec d2aLim;
416
417 // Colella & Sekora, eq 22
418 if ( (horizontal_or(d2a * d2aL >= 0)) && (horizontal_or(d2a * d2aR >= 0)) &&
419 (horizontal_or(d2a * d2aC >= 0)) && horizontal_and(d2a != 0)) {
420
421 d2aLim = d2a / abs(d2a) * min(C * abs(d2aL), min(C * abs(d2aR), min(C * abs(d2aC), abs(d2a))));
422 } else {
423 d2aLim = 0.0;
424 if ( horizontal_or(d2a == 0.0)) {
425 // Set a non-zero value for the denominator in eq. 23.
426 // According to the paper the ratio d2aLim/d2a should be 0
427 d2a = 1.0;
428 }
429 }
430
431 // Colella & Sekora, eq 23
432 fv_r = values[k] + (p_face - values[k]) * d2aLim / d2a;
433 fv_l = values[k] + (m_face - values[k]) * d2aLim / d2a;
434
435}
436
437inline void compute_filtered_face_values_nonuniform_conserving(const Realf * const dv, const Vec * const values,const uint k,const face_estimate_order order, Vec &fv_l, Vec &fv_r, const Realf threshold){
438 switch(order){
439 case h4:
441 compute_h4_left_face_value_nonuniform(dv, values, k + 1, fv_r);
442 break;
443 // case h5:
444 // compute_h5_face_values(dv, values, k, fv_l, fv_r);
445 // break;
446 // case h6:
447 // compute_h6_left_face_value(dv, values, k, fv_l);
448 // compute_h6_left_face_value(dv, values, k + 1, fv_r);
449 // break;
450 // case h8:
451 // compute_h8_left_face_value(dv, values, k, fv_l);
452 // compute_h8_left_face_value(dv, values, k + 1, fv_r);
453 // break;
454 default:
455 printf("Order %d has not been implemented (yet)\n",order);
456 break;
457 }
458
459 Vec slope_abs,slope_sign;
460 if (threshold>0) {
461 // scale values closer to 1 for more accurate slope limiter calculation
462 const Realf scale = 1./threshold;
463 slope_limiter(values[k -1]*scale, values[k]*scale, values[k + 1]*scale, slope_abs, slope_sign);
464 slope_abs = slope_abs*threshold;
465 } else {
466 slope_limiter(values[k -1], values[k], values[k + 1], slope_abs, slope_sign);
467 }
468
469 //check for extrema
470 //Vecb is_extrema = (slope_abs == Vec(0.0));
471 //Vecb filter_l = (values[k - 1] - fv_l) * (fv_l - values[k]) < 0 ;
472 //Vecb filter_r = (values[k + 1] - fv_r) * (fv_r - values[k]) < 0;
473 // if(horizontal_or(is_extrema) || horizontal_or(filter_l) || horizontal_or(filter_r)) {
474 // Colella & Sekora, eq. 20
475 if (horizontal_or((fv_r - values[k]) * (values[k] - fv_l) <= Vec(0.0))
476 && horizontal_or((values[k - 1] - values[k]) * (values[k] - values[k + 1]) <= Vec(0.0))) {
477 constrain_face_values(dv, values, k, fv_l, fv_r);
478
479 // fv_r = select(is_extrema, values[k], fv_r);
480 // fv_l = select(is_extrema, values[k], fv_l);
481 } else {
482
483 //Fix left face if needed; boundary value is not bounded
484 Vecb filter = (values[k -1] - fv_l) * (fv_l - values[k]) < 0 ;
485 if (horizontal_or (filter)) {
486 //Go to linear (PLM) estimates if not ok (this is always ok!)
487 fv_l=select(filter, values[k ] - slope_sign * 0.5 * slope_abs, fv_l);
488 }
489
490 //Fix face if needed; boundary value is not bounded
491 filter = (values[k + 1] - fv_r) * (fv_r - values[k]) < 0;
492 if (horizontal_or (filter)) {
493 //Go to linear (PLM) estimates if not ok (this is always ok!)
494 fv_r=select(filter, values[k] + slope_sign * 0.5 * slope_abs, fv_r);
495 }
496 }
497
498 // //Fix left face if needed; boundary value is not bounded
499 // Vecb filter = (values[k -1] - fv_l) * (fv_l - values[k]) < 0 ;
500 // if(horizontal_or (filter)) {
501 // //Go to linear (PLM) estimates if not ok (this is always ok!)
502 // fv_l=select(filter, values[k ] - slope_sign * 0.5 * slope_abs, fv_l);
503 // }
504
505 // //Fix face if needed; boundary value is not bounded
506 // filter = (values[k + 1] - fv_r) * (fv_r - values[k]) < 0;
507 // if(horizontal_or (filter)) {
508 // //Go to linear (PLM) estimates if not ok (this is always ok!)
509 // fv_r=select(filter, values[k] + slope_sign * 0.5 * slope_abs, fv_r);
510 // }
511
512}
513
514#endif
face_estimate_order
void compute_filtered_face_values_derivatives(const Vec *const values, const uint k, const face_estimate_order order, Vec &fv_l, Vec &fv_r, Vec &fd_l, Vec &fd_r, const Realf threshold)
void compute_h7_left_face_derivative(const Vec *const values, uint k, Vec &fd_l)
void compute_h4_left_face_value_nonuniform(const Realf *const h, const Vec *const u, uint k, Vec &fv_l)
void compute_filtered_face_values_nonuniform_conserving(const Realf *const dv, const Vec *const values, const uint k, const face_estimate_order order, Vec &fv_l, Vec &fv_r, const Realf threshold)
void compute_h6_left_face_value(const Vec *const values, uint k, Vec &fv_l)
void compute_h5_face_values(const Vec *const values, uint k, Vec &fv_l, Vec &fv_r)
void compute_h5_left_face_derivative(const Vec *const values, uint k, Vec &fd_l)
void compute_h4_left_face_value(const Vec *const values, uint k, Vec &fv_l)
void compute_filtered_face_values(const Vec *const values, const uint k, const face_estimate_order order, Vec &fv_l, Vec &fv_r, const Realf threshold)
void compute_h8_left_face_value(const Vec *const values, uint k, Vec &fv_l)
Vec get_D2aLim(const Realf *h, const Vec *values, const uint k, const Vec C, const Vec &fv)
void compute_h4_left_face_derivative(const Vec *const values, uint k, Vec &fd_l)
void compute_h3_left_face_derivative(const Vec *const values, uint k, Vec &fv_l)
void constrain_face_values(const Realf *h, const Vec *values, const uint k, Vec &fv_l, Vec &fv_r)
void compute_filtered_face_values_nonuniform(const Realf *const dv, const Vec *const values, const uint k, const face_estimate_order order, Vec &fv_l, Vec &fv_r, const Realf threshold)
float Realf
Definition definitions.h:33
__global__ void vmesh::VelocityMesh **__restrict__ ColumnOffsets split::SplitVector< vmesh::GlobalID > Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > const uint *__restrict__ const Realf const int const int const Realf const Realf dv
const int k
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf threshold
Real slope_limiter(const Real &l, const Real &m, const Real &r)
An interface to a type with floating point values.
static ARCH_HOSTDEV VecSimple< T > min(VecSimple< T > const &l, VecSimple< T > const &r)
static ARCH_HOSTDEV bool horizontal_or(VecSimple< T > const &a)
static ARCH_HOSTDEV VecSimple< T > select(VecSimple< bool > const &a, VecSimple< T > const &b, VecSimple< T > const &c)
static ARCH_HOSTDEV VecSimple< T > abs(const VecSimple< T > &l)
static ARCH_HOSTDEV bool horizontal_and(VecSimple< T > const &a)