OpenFPM  5.2.0
Project that contain the implementation of distributed structures
RedistancingSussman.hpp
Go to the documentation of this file.
1 //
2 // Created by jstark on 2020-04-06.
3 //
31 #ifndef REDISTANCING_SUSSMAN_REDISTANCINGSUSSMAN_HPP
32 #define REDISTANCING_SUSSMAN_REDISTANCINGSUSSMAN_HPP
33 
34 // Include standard library header files
35 #include <iostream>
36 #include <string>
37 #include <fstream>
38 // Include OpenFPM header files
39 #include "Vector/vector_dist.hpp"
40 #include "Grid/grid_dist_id.hpp"
41 #include "data_type/aggregate.hpp"
42 #include "Decomposition/CartDecomposition.hpp"
43 
44 // Include other header files
45 #include "HelpFunctions.hpp"
46 #include "HelpFunctionsForGrid.hpp"
47 //#include "ComputeGradient.hpp"
49 
58 template <typename phi_type=double>
60 {
61  bool check = true;
65  phi_type value = 1e-15;
67 };
68 
74 template <typename phi_type=double>
76 {
77  bool check = true;
80  phi_type value = 1e-3;
83 };
84 
116 template <typename phi_type=double>
117 struct Redist_options
118 {
119  size_t min_iter = 1e3;
120  size_t max_iter = 1e6;
121 
122  Conv_tol_change<phi_type> convTolChange;
123  Conv_tol_residual<phi_type> convTolResidual;
124 
125  size_t interval_check_convergence = 100;
126  size_t width_NB_in_grid_points = 2;
127  bool print_current_iterChangeResidual = false;
128  bool print_steadyState_iter = true;
129  bool save_temp_grid = false;
130 };
131 
138 template <typename phi_type=double>
140 {
141  phi_type change;
147  phi_type residual;
151  int count;
152 };
153 
154 
160 template <typename grid_in_type, typename phi_type=double>
162 {
163 public:
173  r_grid_in(grid_in),
174  g_temp(grid_in.getDecomposition(),
175  grid_in.getGridInfoVoid().getSize(),
176  Ghost<grid_in_type::dims, long int>(3))
177  {
178  // Get timestep fulfilling CFL condition for velocity=1.0 and courant number=0.1
179  time_step = get_time_step_CFL(grid_in, 1.0, 0.1);
180  order_upwind_gradient = 1;
181 #ifdef SE_CLASS1
182  assure_minimal_thickness_of_NB();
183 #endif // SE_CLASS1
184  }
185 
207 
214  template <size_t Phi_0_in, size_t Phi_SDF_out>
216  {
217  init_temp_grid<Phi_0_in>();
218  init_sign_prop<Phi_n_temp, Phi_0_sign_temp>(g_temp); // Initialize Phi_0_sign_temp with the sign of the
219  // initial (pre-redistancing) Phi_0
220  // Get initial gradients
221  get_upwind_gradient<Phi_n_temp, Phi_0_sign_temp, Phi_grad_temp>(g_temp, order_upwind_gradient, true);
222  iterative_redistancing(g_temp); // Do the redistancing on the temporary grid
223  copy_gridTogrid<Phi_n_temp, Phi_SDF_out>(g_temp, r_grid_in); // Copy resulting SDF function to input grid
224  }
234  template<typename T>
236  {
237  time_step = dt;
238  }
243  {
245  return time_step;
246  }
247 
248  int get_finalIteration()
249  {
250  return final_iter;
251  }
252 
253  auto get_finalChange()
254  {
255  return distFromSol.change;
256  }
257 
258  auto get_finalResidual()
259  {
260  return distFromSol.residual;
261  }
262 
263  int get_finalNumberNbPoints()
264  {
265  return distFromSol.count;
266  }
267 
268 private:
269  // Some indices for better readability
270  static constexpr size_t Phi_n_temp = 0;
271  static constexpr size_t Phi_grad_temp = 1;
272  static constexpr size_t Phi_0_sign_temp = 2;
273 
274  // Member variables
276  grid_in_type &r_grid_in;
277 
279  // point in NB.
280  int final_iter = 0;
281 
283  phi_type kappa = ceil(redistOptions.width_NB_in_grid_points / 2.0) * get_biggest_spacing(g_temp);
287  typename grid_in_type::stype time_step;
288  int order_upwind_gradient;
289  // Member functions
290 #ifdef SE_CLASS1
296  void assure_minimal_thickness_of_NB()
297  {
298  if (redistOptions.width_NB_in_grid_points < 8)
299  {
300  std::cout << "The narrow band thickness that you chose for the convergence check is very small. Consider "
301  "setting redist_options.width_NB_in_grid_points to at least 8" << std::endl;
302  } // check narrow band width of convergence check if defined SE_CLASS1
303  }
304 #endif // SE_CLASS1
308  template<size_t Phi_0_in>
310  {
311  phi_type min_value = get_min_val<Phi_0_in>(r_grid_in); // get minimum Phi_0 value on the input grid
312  init_grid_and_ghost<Phi_n_temp>(g_temp, min_value); // init. Phi_n_temp (incl. ghost) with min. Phi_0
313  copy_gridTogrid<Phi_0_in, Phi_n_temp>(r_grid_in, g_temp); // Copy Phi_0 from the input grid to Phi_n_temp
314  }
315 
326  phi_type get_phi_nplus1(phi_type phi_n, phi_type phi_n_magnOfGrad, typename grid_in_type::stype dt, phi_type
327  sgn_phi_n)
328  {
329  return phi_n + dt * sgn_phi_n * (1 - phi_n_magnOfGrad);
330  }
331 
337  {
338  get_upwind_gradient<Phi_n_temp, Phi_0_sign_temp, Phi_grad_temp>(grid, order_upwind_gradient, true);
339  grid.template ghost_get<Phi_n_temp, Phi_grad_temp>();
340  auto dom = grid.getDomainIterator();
341  while (dom.isNext())
342  {
343  auto key = dom.get();
344  const phi_type phi_n = grid.template get<Phi_n_temp>(key);
345  const phi_type phi_n_magnOfGrad = get_vector_magnitude<Phi_grad_temp>(grid, key);
346  phi_type epsilon = phi_n_magnOfGrad * grid.getSpacing()[0];
347  grid.template get<Phi_n_temp>(key) = get_phi_nplus1(phi_n, phi_n_magnOfGrad, time_step,
348  smooth_S(phi_n, epsilon));
349  ++dom;
350  }
351  }
352 
359  bool lays_inside_NB(phi_type Phi)
360  {
361  return (abs(Phi) <= kappa);
362  }
363 
370  {
371  phi_type max_residual = 0;
372  phi_type max_change = 0;
373  int count = 0;
374  auto dom = grid.getDomainIterator();
375  while (dom.isNext())
376  {
377  auto key = dom.get();
378  if (lays_inside_NB(grid.template get<Phi_n_temp>(key)))
379  {
380  count++;
381  phi_type phi_n_magnOfGrad = get_vector_magnitude<Phi_grad_temp>(grid, key);
382  phi_type epsilon = phi_n_magnOfGrad * grid.getSpacing()[0];
383  phi_type phi_nplus1 = get_phi_nplus1(grid.template get<Phi_n_temp>(key), phi_n_magnOfGrad, time_step,
384  smooth_S(grid.template get<Phi_n_temp>(key), epsilon));
385 
386  if (abs(phi_nplus1 - grid.template get<Phi_n_temp>(key)) > max_change)
387  {
388  max_change = abs(phi_nplus1 - grid.template get<Phi_n_temp>(key));
389  }
390 
391  if (abs(phi_n_magnOfGrad - 1) > max_residual) { max_residual = abs(phi_n_magnOfGrad - 1); }
392  }
393  ++dom;
394  }
395  auto &v_cl = create_vcluster();
396  v_cl.max(max_change);
397  v_cl.max(max_residual);
398  v_cl.sum(count);
399  v_cl.execute();
400 
401  // Update member variable distFromSol
402  distFromSol.change = max_change;
403  distFromSol.residual = max_residual;
404  distFromSol.count = count;
405  }
406 
414  {
416  auto &v_cl = create_vcluster();
417  if (v_cl.rank() == 0)
418  {
419  if (iter == 0)
420  {
421  std::cout << "Iteration,MaxChange,MaxResidual,NumberOfNarrowBandPoints" << std::endl;
422  }
423  std::cout << iter
424  << "," << to_string_with_precision(distFromSol.change, 15)
425  << "," << to_string_with_precision(distFromSol.residual, 15)
426  << "," << distFromSol.count << std::endl;
427  }
428  }
429 
441  {
442  bool steady_state = false;
444  if (redistOptions.convTolChange.check && redistOptions.convTolResidual.check)
445  {
446  steady_state = (
447  distFromSol.change <= redistOptions.convTolChange.value &&
448  distFromSol.residual <= redistOptions.convTolResidual.value &&
449  distFromSol.count > 0
450  );
451  }
452  else
453  {
454  if (redistOptions.convTolChange.check)
455  {
456  steady_state = (distFromSol.change <= redistOptions.convTolChange.value && distFromSol.count > 0);
457  } // Use the normalized total change between two iterations in the narrow bands steady-state criterion
458  if (redistOptions.convTolResidual.check)
459  {
460  steady_state = (distFromSol.residual <= redistOptions.convTolResidual.value && distFromSol.count > 0);
461  } // Use the normalized total residual of phi compared to SDF in the narrow bands steady-state criterion
462  }
463  return steady_state;
464  }
465 
476  {
477  int i = 0;
478  while (i < redistOptions.max_iter)
479  {
480  for (int j = 0; j < redistOptions.interval_check_convergence; j++)
481  {
483  ++i;
484  }
485  if (redistOptions.print_current_iterChangeResidual)
486  {
488  }
489  if (redistOptions.save_temp_grid)
490  {
491  get_upwind_gradient<Phi_n_temp, Phi_0_sign_temp, Phi_grad_temp>(g_temp, order_upwind_gradient, true);
492  g_temp.setPropNames({"Phi_Sussman_Out", "Phi_upwind_gradient", "Phi_0_sign_temp"});
493  g_temp.save("g_temp_redistancing_iteration_" + std::to_string(i) + ".hdf5"); // HDF5 file
494  // g_temp.write_frame("g_temp_redistancing_iteration", i, FORMAT_BINARY); // VTK file
495  }
496  if (i >= redistOptions.min_iter)
497  {
498  if (steady_state_NB(grid))
499  {
500  if (redistOptions.print_steadyState_iter)
501  {
502  auto &v_cl = create_vcluster();
503  if (v_cl.rank() == 0)
504  {
505  std::cout << "Steady state criterion reached at iteration: " << i << std::endl;
506  std::cout << "FinalIteration,MaxChange,MaxResidual" << std::endl;
507  }
509  }
510  break;
511  }
512  }
513  }
515  final_iter = i;
516  // If save_temp_grid set true, save the temporary grid as hdf5 that can be reloaded onto a grid
517  if (redistOptions.save_temp_grid)
518  {
519  get_upwind_gradient<Phi_n_temp, Phi_0_sign_temp, Phi_grad_temp>(g_temp, order_upwind_gradient, true);
520  g_temp.setPropNames({"Phi_Sussman_Out", "Phi_upwind_gradient", "Phi_0_sign_temp"});
521  g_temp.save("g_temp_redistancing_final.hdf5"); // HDF5 file
522  // g_temp.write("g_temp_redistancing_final", FORMAT_BINARY); // VTK file
523  }
524  }
525 };
526 
527 #endif //REDISTANCING_SUSSMAN_REDISTANCINGSUSSMAN_HPP
Header file containing help-functions that perform on OpenFPM-grids.
grid_type::stype get_time_step_CFL(grid_type &grid, typename grid_type::stype u[grid_type::dims], typename grid_type::stype C)
Computes the time step size fulfilling CFL condition according to https://www.cfd-online ....
grid_type::stype get_biggest_spacing(grid_type &grid)
Determines the biggest spacing of a grid which is potentially anisotropic when comparing x,...
Header file containing small mathematical help-functions that are needed e.g. for the Sussman redista...
T smooth_S(T val, T epsilon)
Gets the smoothed sign of a variable.
std::string to_string_with_precision(const T myValue, const size_t n=6)
Converts value into string maintaining a desired precision.
Approximating upwind gradients on a grid with the following options for the order of accuracy: 1,...
Definition: Ghost.hpp:40
Class for reinitializing a level-set function into a signed distance function using Sussman redistanc...
grid_in_type & r_grid_in
Define reference to input grid.
g_temp_type g_temp
Create temporary grid, which is only used inside the class for the redistancing.
int final_iter
Will be set to the final iteration when redistancing ends.
static constexpr size_t Phi_n_temp
Property index of Phi_0 on the temporary grid.
bool steady_state_NB(g_temp_type &grid)
Checks steady-state is reached in the narrow band.
bool lays_inside_NB(phi_type Phi)
Checks if a node lays within the narrow band around the interface.
void init_temp_grid()
Copies values from input grid to internal temporary grid and initializes ghost layer with minimum val...
void run_redistancing()
Runs the Sussman-redistancing.
void update_distFromSol(g_temp_type &grid)
Re-computes the member variables distFromSol.change, distFromSol.residual, distFromSol....
static constexpr size_t Phi_0_sign_temp
Property index of sign of initial (input) Phi_0 (temp. grid).
phi_type kappa
Transform the half-bandwidth in no_of_grid_points into physical half-bandwidth kappa.
DistFromSol< phi_type > distFromSol
Instantiate distance from solution in terms of change, residual, numb.
phi_type get_phi_nplus1(phi_type phi_n, phi_type phi_n_magnOfGrad, typename grid_in_type::stype dt, phi_type sgn_phi_n)
Run one timestep of re-distancing and compute Phi_n+1.
auto get_time_step()
Access the artificial timestep (private member) which will be used for the iterative redistancing.
grid_in_type::stype time_step
Artificial timestep for the redistancing iterations.
static constexpr size_t Phi_grad_temp
Property index of gradient of Phi_n on the temporary grid.
grid_dist_id< grid_in_type::dims, typename grid_in_type::stype, props_temp > g_temp_type
Type definition for the temporary grid.
void iterative_redistancing(g_temp_type &grid)
Runs Sussman re-distancing on the internal temporary grid.
RedistancingSussman(grid_in_type &grid_in, Redist_options< phi_type > &redistOptions)
Constructor initializing the redistancing options, the temporary internal grid and reference variable...
void print_out_iteration_change_residual(g_temp_type &grid, size_t iter)
Prints out the iteration number, max. change, max. residual and number of points in the narrow band o...
Redist_options< phi_type > redistOptions
Instantiate redistancing options.
void go_one_redistancing_step_whole_grid(g_temp_type &grid)
Go one re-distancing time-step on the whole grid.
void set_user_time_step(T dt)
Overwrite the time_step found via CFL condition with an individual time_step.
aggregate< phi_type, phi_type[grid_in_type::dims], int > props_temp
Aggregated properties for the temporary grid.
void save(const std::string &filename) const
Save the grid state on HDF5.
void setPropNames(const openfpm::vector< std::string > &names)
Set the properties names.
KeyT const ValueT ValueT OffsetIteratorT OffsetIteratorT int
[in] The number of segments that comprise the sorting data
Optional convergence criterium checking the total change.
phi_type value
redistancing process is considered as steady-state. (see also DistFromSol::change)
Optional convergence criterium checking the residual.
Bundles total residual and total change over all the grid points.
int count
Integer variable that contains the number of points that could be assigned to the narrow band.
Structure to bundle options for redistancing.
Definition: particle_cp.hpp:33
aggregate of properties, from a list of object if create a struct that follow the OPENFPM native stru...
Definition: aggregate.hpp:221