Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
cpu_1d_pqm.hpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2016 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_1D_PQM_H
24#define CPU_1D_PQM_H
25
26#include "vec.h"
29
30/*make sure quartic polynomial is monotonic*/
31static inline void filter_pqm_monotonicity(const Vec* __restrict__ values, uint k, Vec &fv_l, Vec &fv_r, Vec &fd_l, Vec &fd_r){
32 /*second derivative coefficients, eq 23 in white et al.*/
33 const Vec b0 = 60.0 * values[k] - 24.0 * fv_r - 36.0 * fv_l + 3.0 * (fd_r - 3.0 * fd_l);
34 const Vec b1 = -360.0 * values[k] + 36.0 * fd_l - 24.0 * fd_r + 168.0 * fv_r + 192.0 * fv_l;
35 const Vec b2 = 360.0 * values[k] + 30.0 * (fd_r - fd_l) - 180.0 * (fv_l + fv_r);
36 /*let's compute sqrt value to be used for computing roots. If we
37 take sqrt of negative numbers, then we instead set a value that
38 will make the root to be +-100 which is well outside range
39 of[0,1]. We do not catch FP exceptions, so sqrt(negative) are okish (add
40 a max(val_to_sqrt,0) if not*/
41 const Vec val_to_sqrt = b1 * b1 - 4 * b0 * b2;
42/*
43 #ifdef VEC16F_AGNER
44 //this sqrt gives 10% more perf on acceleration on KNL. Also fairly
45 //accurate with AVX512ER. On Xeon it is not any faster, and less accurate.
46 const Vec sqrt_val = select(val_to_sqrt < 0.0,
47 b1 + 200.0 * b2,
48 val_to_sqrt * approx_rsqrt(val_to_sqrt));
49 #else
50*/
51 const Vec sqrt_val = select(val_to_sqrt < 0.0,
52 b1 + 200.0 * b2,
53 sqrt(val_to_sqrt));
54//#endif
55 //compute roots. Division is safe with vectorclass (=inf)
56 const Vec root1 = (-b1 + sqrt_val) / (2 * b2);
57 const Vec root2 = (-b1 - sqrt_val) / (2 * b2);
58
59 /*PLM slope, MC limiter*/
60 const Vec plm_slope_l = 2.0 * (values[k] - values[k - 1]);
61 const Vec plm_slope_r = 2.0 * (values[k + 1] - values[k]);
62 const Vec slope_sign = plm_slope_l + plm_slope_r; //it also has some magnitude, but we will only use its sign.
63 /*first derivative coefficients*/
64 const Vec c0 = fd_l;
65 const Vec c1 = b0;
66 const Vec c2 = b1 / 2.0;
67 const Vec c3 = b2 / 3.0;
68 //compute both slopes at inflexion points, at least one of these
69 //is with [0..1]. If the root is not in this range, we
70 //simplify later if statements by setting it to the plm slope
71 //sign
72 const Vec root1_slope = select(root1 >= 0.0 && root1 <= 1.0,
73 c0 + root1 * ( c1 + root1 * (c2 + root1 * c3 ) ),
74 slope_sign);
75 const Vec root2_slope = select(root2 >= 0.0 && root2 <= 1.0,
76 c0 + root2 * ( c1 + root2 * (c2 + root2 * c3 ) ),
77 slope_sign);
78 const Vecb fixInflexion = root1_slope * slope_sign < 0.0 || root2_slope * slope_sign < 0.0;
79 if (horizontal_or (fixInflexion) ) {
80 Realf valuesa[VECL];
81 Realf fva_l[VECL];
82 Realf fva_r[VECL];
83 Realf fda_l[VECL];
84 Realf fda_r[VECL];
85 Realf slope_signa[VECL];
86 values[k].store(valuesa);
87 fv_l.store(fva_l);
88 fd_l.store(fda_l);
89 fv_r.store(fva_r);
90 fd_r.store(fda_r);
91 slope_sign.store(slope_signa);
92 // todo store and then load data to avoid inserts (is it beneficial...?)
93
94 // serialized the handling of inflexion points, these do not happen for smooth regions
95 #pragma omp simd
96 for(uint i = 0;i < VECL; i++) {
97 if(fixInflexion[i]){
98 // need to collapse, at least one inflexion point has wrong sign.
99 if(fabs(plm_slope_l[i]) <= fabs(plm_slope_r[i])) {
100 // collapse to left edge (eq 21)
101 fda_l[i] = 1.0 / 3.0 * ( 10 * valuesa[i] - 2.0 * fva_r[i] - 8.0 * fva_l[i]);
102 fda_r[i] = -10.0 * valuesa[i] + 6.0 * fva_r[i] + 4.0 * fva_l[i];
103 // check if PLM slope is consistent (eq 28 & 29)
104 if (slope_signa[i] * fda_l[i] < 0) {
105 fda_l[i] = 0;
106 fva_r[i] = 5 * valuesa[i] - 4 * fva_l[i];
107 fda_r[i] = 20 * (valuesa[i] - fva_l[i]);
108 } else if (slope_signa[i] * fda_r[i] < 0) {
109 fda_r[i] = 0;
110 fva_l[i] = 0.5 * (5 * valuesa[i] - 3 * fva_r[i]);
111 fda_l[i] = 10.0 / 3.0 * (-valuesa[i] + fva_r[i]);
112 }
113 } else {
114 //collapse to right edge (eq 21)
115 fda_l[i] = 10.0 * valuesa[i] - 6.0 * fva_l[i] - 4.0 * fva_r[i];
116 fda_r[i] = 1.0 / 3.0 * ( - 10.0 * valuesa[i] + 2 * fva_l[i] + 8 * fva_r[i]);
117 //check if PLM slope is consistent (eq 28 & 29)
118 if (slope_signa[i] * fda_l[i] < 0) {
119 fda_l[i] = 0;
120 fva_r[i] = 0.5 * ( 5 * valuesa[i] - 3 * fva_l[i]);
121 fda_r[i] = 10.0 / 3.0 * (valuesa[i] - fva_l[i]);
122 } else if (slope_signa[i] * fda_r[i] < 0) {
123 fda_r[i] = 0;
124 fva_l[i] = 5 * valuesa[i] - 4 * fva_r[i];
125 fda_l[i] = 20.0 * ( - valuesa[i] + fva_r[i]);
126 }
127 }
128 }
129 }
130 fv_l.load(fva_l);
131 fd_l.load(fda_l);
132 fv_r.load(fva_r);
133 fd_r.load(fda_r);
134 }
135}
136
137
138
139
140
141// /*
142// PQM reconstruction as published in:
143// White, Laurent, and Alistair Adcroft. “A High-Order Finite Volume Remapping Scheme for Nonuniform Grids: The Piecewise Quartic Method (PQM).” Journal of Computational Physics 227, no. 15 (July 2008): 7394–7422. doi:10.1016/j.jcp.2008.04.026.
144// */
145
146static inline void compute_pqm_coeff(const Vec* __restrict__ values, face_estimate_order order, uint k, Vec a[5], const Realf threshold)
147{
148 Vec fv_l; /*left face value*/
149 Vec fv_r; /*right face value*/
150 Vec fd_l; /*left face derivative*/
151 Vec fd_r; /*right face derivative*/
152 compute_filtered_face_values_derivatives(values, k, order, fv_l, fv_r, fd_l, fd_r, threshold);
153 filter_pqm_monotonicity(values, k, fv_l, fv_r, fd_l, fd_r);
154 //Fit a second order polynomial for reconstruction see, e.g., White
155 //2008 (PQM article) (note additional integration factors built in,
156 //contrary to White (2008) eq. 4
157 a[0] = fv_l;
158 a[1] = fd_l/2.0;
159 a[2] = 10.0 * values[k] - 4.0 * fv_r - 6.0 * fv_l + 0.5 * (fd_r - 3 * fd_l);
160 a[3] = -15.0 * values[k] + 1.5 * fd_l - fd_r + 7.0 * fv_r + 8 * fv_l;
161 a[4] = 6.0 * values[k] + 0.5 * (fd_r - fd_l) - 3.0 * (fv_l + fv_r);
162}
163
164
165#endif
for i
Definition Dispersion.m:24
sqrt(1.0+vA *vA/(c *c))) % Ion-acoustic wave cS
static void compute_pqm_coeff(const Vec *__restrict__ values, face_estimate_order order, uint k, Vec a[5], const Realf threshold)
static void filter_pqm_monotonicity(const Vec *__restrict__ values, uint k, Vec &fv_l, Vec &fv_r, Vec &fd_l, Vec &fd_r)
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)
float Realf
Definition definitions.h:33
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
An interface to a type with floating point values.
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)