OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
 
Loading...
Searching...
No Matches
Upwind_gradient.hpp
Go to the documentation of this file.
1//
2// Created by jstark on 17.05.21.
3//
20#ifndef OPENFPM_NUMERICS_SRC_FINITEDIFFERENCE_UPWIND_GRADIENT_HPP
21#define OPENFPM_NUMERICS_SRC_FINITEDIFFERENCE_UPWIND_GRADIENT_HPP
22
23// Include standard libraries
24#include <cmath>
25
26// Include OpenFPM header files
27#include "Grid/grid_dist_id.hpp"
28#include "FD_simple.hpp"
29#include "Eno_Weno.hpp"
31
39template <typename field_type>
40static field_type upwinding(field_type dplus, field_type dminus, int sign)
41{
42 field_type grad_upwind = 0.0;
43 if (dplus * sign < 0
44 && (dminus + dplus) * sign < 0) grad_upwind = dplus;
45
46 else if (dminus * sign > 0
47 && (dminus + dplus) * sign > 0) grad_upwind = dminus;
48
49 else if (dminus * sign < 0
50 && dplus * sign > 0) grad_upwind = 0;
51 return grad_upwind;
52}
53
61template <typename velocity_type>
62inline int get_sign_velocity(velocity_type v, size_t d)
63{
64 return sgn(v);
65}
66
74template <typename velocity_type>
75inline int get_sign_velocity(velocity_type v[], size_t d)
76{
77 return sgn(v[d]);
78}
79
94template <size_t Field, size_t Velocity, typename gridtype, typename keytype>
95auto FD_upwind(gridtype &grid, keytype &key, size_t d, size_t order)
96{
97// std::cout << boost::typeindex::type_id_with_cvr<std::decay_t<decltype(first_node)>>() << std::endl;
98
99 typedef typename std::decay_t<decltype(grid.template get<Field>(key))> field_type;
100 field_type dplus = 0.0, dminus = 0.0;
101
102 // Get the sign of the velocity for the current dimension
103 int sign_velocity = get_sign_velocity(grid.template get<Field>(key), d);
104
105 switch(order)
106 {
107 case 1:
108 dplus = FD_forward<Field>(grid, key, d);
109 dminus = FD_backward<Field>(grid, key, d);
110 break;
111 case 3:
112 dplus = ENO_3_Plus<Field>(grid, key, d);
113 dminus = ENO_3_Minus<Field>(grid, key, d);
114 break;
115 case 5:
116 dplus = WENO_5_Plus<Field>(grid, key, d);
117 dminus = WENO_5_Minus<Field>(grid, key, d);
118 break;
119 default:
120 auto &v_cl = create_vcluster();
121 if (v_cl.rank() == 0) std::cout << "Order of accuracy chosen not valid. Using default order 1." <<
122 std::endl;
123 dplus = FD_forward<Field>(grid, key, d);
124 dminus = FD_backward<Field>(grid, key, d);
125 break;
126 }
127
128 return upwinding(dplus, dminus, sign_velocity);
129}
130
131
147// Use upwinding for inner grid points and one sided backward / forward stencil at border (if one_sided_BC=true)
148template <size_t Field, size_t Velocity, size_t Gradient, typename gridtype>
149void upwind_gradient(gridtype & grid, const bool one_sided_BC, size_t order)
150{
151 grid.template ghost_get<Field>(KEEP_PROPERTIES);
152 grid.template ghost_get<Velocity>(KEEP_PROPERTIES);
153
154 auto dom = grid.getDomainIterator();
155
156 if (one_sided_BC)
157 {
158 while (dom.isNext())
159 {
160 auto key = dom.get();
161 auto key_g = grid.getGKey(key);
162
163 for(size_t d = 0; d < gridtype::dims; d++ )
164 {
165 // Grid nodes inside and distance from boundary > stencil-width
166 if (key_g.get(d) > 2 && key_g.get(d) < grid.size(d) - 3) // if point lays with min. 3 nodes distance to
167 // boundary
168 {
169 grid.template get<Gradient> (key) [d] = FD_upwind<Field, Velocity>(grid, key, d, order);
170 }
171
172 // Grid nodes in stencil-wide vicinity to boundary
173 else if (key_g.get(d) > 0 && key_g.get(d) < grid.size(d) - 1) // if point lays not on the grid boundary
174 {
175 grid.template get<Gradient> (key) [d] = FD_upwind<Field, Velocity>(grid, key, d, 1);
176 }
177
178 else if (key_g.get(d) == 0) // if point lays at left boundary, use right sided kernel
179 {
180 grid.template get<Gradient> (key) [d] = FD_forward<Field>(grid, key, d);
181 }
182
183 else if (key_g.get(d) >= grid.size(d) - 1) // if point lays at right boundary, use left sided kernel
184 {
185 grid.template get<Gradient> (key) [d] = FD_backward<Field>(grid, key, d);
186 }
187 }
188 ++dom;
189 }
190 }
191
192 else
193 {
194 while (dom.isNext())
195 {
196 auto key = dom.get();
197 for(size_t d = 0; d < gridtype::dims; d++)
198 {
199 grid.template get<Gradient> (key) [d] = FD_upwind<Field, Velocity>(grid, key, d, order);
200 }
201 ++dom;
202 }
203 }
204}
205
213template <typename gridtype>
214static bool ghost_width_is_sufficient(gridtype & grid, size_t required_width)
215{
216 auto ghost = grid.getDecomposition().getGhost();
217 int np_ghost[gridtype::dims];
218
219 for (int d = 0 ; d < gridtype::dims ; d++)
220 {
221 np_ghost[d] = ghost.getHigh(d) / grid.getSpacing()[d];
222 }
223
224 int min_width = np_ghost[0];
225 for (int d = 0 ; d < gridtype::dims ; d++)
226 {
227 if(np_ghost[d] < min_width) min_width = np_ghost[d];
228 }
229
230 return (min_width >= required_width);
231}
232
241template <size_t Field_in, size_t Velocity, size_t Gradient_out, typename gridtype>
242void get_upwind_gradient(gridtype & grid, const size_t order=5, const bool one_sided_BC=true)
243{
244 grid.template ghost_get<Field_in>();
245 grid.template ghost_get<Velocity>();
246
247 if (!one_sided_BC)
248 {
249 auto &v_cl = create_vcluster();
250 if (v_cl.rank() == 0)
251 {
252 // Check if ghost layer thick enough for stencil
253 size_t stencil_width;
254 (order > 1) ? stencil_width = 3 : stencil_width = 1;
255 if (!ghost_width_is_sufficient(grid, stencil_width))
256 {
257 std::cout << "Error: Ghost layer not big enough. Either run with one_sided_BC=true or create a ghost "
258 "layer that has a width of least " << stencil_width << " grid node(s)" << std::endl;
259 abort();
260 }
261 }
262 }
263
264 switch(order)
265 {
266 case 1:
267 case 3:
268 case 5:
269 upwind_gradient<Field_in, Velocity, Gradient_out>(grid, one_sided_BC, order);
270 break;
271 default:
272 auto &v_cl = create_vcluster();
273 if (v_cl.rank() == 0) std::cout << "Order of accuracy chosen not valid. Using default order 1." <<
274 std::endl;
275 upwind_gradient<Field_in, Velocity, Gradient_out>(grid, one_sided_BC, 1);
276 break;
277 }
278
279
280}
281
282
283#endif //OPENFPM_NUMERICS_SRC_FINITEDIFFERENCE_UPWIND_GRADIENT_HPP
284
Header file containing small mathematical help-functions that are needed e.g. for the Sussman redista...
int sgn(T val)
Gets the sign of a variable.
auto FD_upwind(gridtype &grid, keytype &key, size_t d, size_t order)
Get the upwind finite difference of a scalar property on the current grid node.
void get_upwind_gradient(gridtype &grid, const size_t order=5, const bool one_sided_BC=true)
Calls upwind_gradient. Computes upwind gradient of desired order {1, 3, 5} for the whole n-dim grid.
static field_type upwinding(field_type dplus, field_type dminus, int sign)
Upwinding: For a specific dimension, from the forward and backward gradient find the upwind side.
int get_sign_velocity(velocity_type v, size_t d)
Returns the sign of a scalar velocity field.
static bool ghost_width_is_sufficient(gridtype &grid, size_t required_width)
Checks if ghost layer is thick enough for a given stencil-width.
void upwind_gradient(gridtype &grid, const bool one_sided_BC, size_t order)
Computes upwind gradient with order of accuracy 1, 3 or 5.