OpenFPM  5.2.0
Project that contain the implementation of distributed structures
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 
39 template <typename field_type>
40 static 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 
61 template <typename velocity_type>
62 inline int get_sign_velocity(velocity_type v, size_t d)
63 {
64  return sgn(v);
65 }
66 
74 template <typename velocity_type>
75 inline int get_sign_velocity(velocity_type v[], size_t d)
76 {
77  return sgn(v[d]);
78 }
79 
94 template <size_t Field, size_t Velocity, typename gridtype, typename keytype>
95 auto 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)
148 template <size_t Field, size_t Velocity, size_t Gradient, typename gridtype>
149 void 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 
213 template <typename gridtype>
214 static 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 
241 template <size_t Field_in, size_t Velocity, size_t Gradient_out, typename gridtype>
242 void 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 
upwind_gradient
void upwind_gradient(gridtype &grid, const bool one_sided_BC, size_t order)
Computes upwind gradient with order of accuracy 1, 3 or 5.
Definition: Upwind_gradient.hpp:149
grid
Definition: grid_test.hpp:218
HelpFunctions.hpp
Header file containing small mathematical help-functions that are needed e.g. for the Sussman redista...
upwinding
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.
Definition: Upwind_gradient.hpp:40
ghost_width_is_sufficient
static bool ghost_width_is_sufficient(gridtype &grid, size_t required_width)
Checks if ghost layer is thick enough for a given stencil-width.
Definition: Upwind_gradient.hpp:214
get_upwind_gradient
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.
Definition: Upwind_gradient.hpp:242
sgn
int sgn(T val)
Gets the sign of a variable.
Definition: HelpFunctions.hpp:24
get_sign_velocity
int get_sign_velocity(velocity_type v, size_t d)
Returns the sign of a scalar velocity field.
Definition: Upwind_gradient.hpp:62
FD_upwind
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.
Definition: Upwind_gradient.hpp:95