OpenFPM_pdata  4.1.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"
30 
38 template <typename field_type>
39 static field_type upwinding(field_type dplus, field_type dminus, int sign)
40 {
41  field_type grad_upwind = 0.0;
42  if (dplus * sign < 0
43  && (dminus + dplus) * sign < 0) grad_upwind = dplus;
44 
45  else if (dminus * sign > 0
46  && (dminus + dplus) * sign > 0) grad_upwind = dminus;
47 
48  else if (dminus * sign < 0
49  && dplus * sign > 0) grad_upwind = 0;
50  return grad_upwind;
51 }
52 
53 
69 template <size_t Field, size_t Sign, typename gridtype, typename keytype>
70 auto FD_upwind(gridtype &grid, keytype &key, size_t d, size_t order)
71 {
72 // std::cout << boost::typeindex::type_id_with_cvr<std::decay_t<decltype(first_node)>>() << std::endl;
73 
74  typedef typename std::decay_t<decltype(grid.template get<Field>(key))> field_type;
75  field_type dplus = 0.0, dminus = 0.0;
76  int sign_phi0 = grid.template get<Sign> (key);
77 
78  switch(order)
79  {
80  case 1:
81  dplus = FD_forward<Field>(grid, key, d);
82  dminus = FD_backward<Field>(grid, key, d);
83  break;
84  case 3:
85  dplus = ENO_3_Plus<Field>(grid, key, d);
86  dminus = ENO_3_Minus<Field>(grid, key, d);
87  break;
88  case 5:
89  dplus = WENO_5_Plus<Field>(grid, key, d);
90  dminus = WENO_5_Minus<Field>(grid, key, d);
91  break;
92  default:
93  auto &v_cl = create_vcluster();
94  if (v_cl.rank() == 0) std::cout << "Order of accuracy chosen not valid. Using default order 1." <<
95  std::endl;
96  dplus = FD_forward<Field>(grid, key, d);
97  dminus = FD_backward<Field>(grid, key, d);
98  break;
99  }
100 
101  return upwinding(dplus, dminus, sign_phi0);
102 }
103 
104 
121 // Use upwinding for inner grid points and one sided backward / forward stencil at border (if one_sided_BC=true)
122 template <size_t Field, size_t Sign, size_t Gradient, typename gridtype>
123 void upwind_gradient(gridtype & grid, const bool one_sided_BC, size_t order)
124 {
125  grid.template ghost_get<Field>(KEEP_PROPERTIES);
126  grid.template ghost_get<Sign>(KEEP_PROPERTIES);
127 
128  auto dom = grid.getDomainIterator();
129 
130  if (one_sided_BC)
131  {
132  while (dom.isNext())
133  {
134  auto key = dom.get();
135  auto key_g = grid.getGKey(key);
136 
137  for(size_t d = 0; d < gridtype::dims; d++ )
138  {
139  // Grid nodes inside and distance from boundary > stencil-width
140  if (key_g.get(d) > 2 && key_g.get(d) < grid.size(d) - 3) // if point lays with min. 3 nodes distance to
141  // boundary
142  {
143  grid.template get<Gradient> (key) [d] = FD_upwind<Field, Sign>(grid, key, d, order);
144  }
145 
146  // Grid nodes in stencil-wide vicinity to boundary
147  else if (key_g.get(d) > 0 && key_g.get(d) < grid.size(d) - 1) // if point lays not on the grid boundary
148  {
149  grid.template get<Gradient> (key) [d] = FD_upwind<Field, Sign>(grid, key, d, 1);
150  }
151 
152  else if (key_g.get(d) == 0) // if point lays at left boundary, use right sided kernel
153  {
154  grid.template get<Gradient> (key) [d] = FD_forward<Field>(grid, key, d);
155  }
156 
157  else if (key_g.get(d) >= grid.size(d) - 1) // if point lays at right boundary, use left sided kernel
158  {
159  grid.template get<Gradient> (key) [d] = FD_backward<Field>(grid, key, d);
160  }
161  }
162  ++dom;
163  }
164  }
165 
166  else
167  {
168  while (dom.isNext())
169  {
170  auto key = dom.get();
171  for(size_t d = 0; d < gridtype::dims; d++)
172  {
173  grid.template get<Gradient> (key) [d] = FD_upwind<Field, Sign>(grid, key, d, order);
174  }
175  ++dom;
176  }
177  }
178 }
179 
187 template <typename gridtype>
188 static bool ghost_width_is_sufficient(gridtype & grid, size_t required_width)
189 {
190  auto ghost = grid.getDecomposition().getGhost();
191  int np_ghost[gridtype::dims];
192 
193  for (int d = 0 ; d < gridtype::dims ; d++)
194  {
195  np_ghost[d] = ghost.getHigh(d) / grid.getSpacing()[d];
196  }
197 
198  int min_width = np_ghost[0];
199  for (int d = 0 ; d < gridtype::dims ; d++)
200  {
201  if(np_ghost[d] < min_width) min_width = np_ghost[d];
202  }
203 
204  return (min_width >= required_width);
205 }
206 
216 template <size_t Field_in, size_t Sign, size_t Gradient_out, typename gridtype>
217 void get_upwind_gradient(gridtype & grid, const size_t order=5, const bool one_sided_BC=true)
218 {
219  grid.template ghost_get<Field_in>();
220  grid.template ghost_get<Sign>();
221 
222  if (!one_sided_BC)
223  {
224  auto &v_cl = create_vcluster();
225  if (v_cl.rank() == 0)
226  {
227  // Check if ghost layer thick enough for stencil
228  size_t stencil_width;
229  (order > 1) ? stencil_width = 3 : stencil_width = 1;
230  if (!ghost_width_is_sufficient(grid, stencil_width))
231  {
232  std::cout << "Error: Ghost layer not big enough. Either run with one_sided_BC=true or create a ghost "
233  "layer that has a width of least " << stencil_width << " grid node(s)" << std::endl;
234  abort();
235  }
236  }
237  }
238 
239  switch(order)
240  {
241  case 1:
242  case 3:
243  case 5:
244  upwind_gradient<Field_in, Sign, Gradient_out>(grid, one_sided_BC, order);
245  break;
246  default:
247  auto &v_cl = create_vcluster();
248  if (v_cl.rank() == 0) std::cout << "Order of accuracy chosen not valid. Using default order 1." <<
249  std::endl;
250  upwind_gradient<Field_in, Sign, Gradient_out>(grid, one_sided_BC, 1);
251  break;
252  }
253 
254 
255 }
256 
257 
258 #endif //OPENFPM_NUMERICS_SRC_FINITEDIFFERENCE_UPWIND_GRADIENT_HPP
259 
void upwind_gradient(gridtype &grid, const bool one_sided_BC, size_t order)
Computes upwind gradient with order of accuracy 1, 3 or 5.
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.
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 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.
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.