OpenFPM_pdata  4.1.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;
62  phi_type value = 1e-15;
66 };
68 
74 template <typename phi_type=double>
76 {
77  bool check = true;
78  phi_type value = 1e-3;
81 };
84 
116 template <typename phi_type=double>
118 {
119  size_t min_iter = 1e5;
120  size_t max_iter = 1e12;
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 = 8;
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;
142  phi_type residual;
148  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  time_step = get_time_step_CFL(grid_in);
179  order_upwind_gradient = 1;
180 #ifdef SE_CLASS1
181  assure_minimal_thickness_of_NB();
182 #endif // SE_CLASS1
183  }
184 
206 
213  template <size_t Phi_0_in, size_t Phi_SDF_out>
215  {
216  init_temp_grid<Phi_0_in>();
217  init_sign_prop<Phi_n_temp, Phi_0_sign_temp>(g_temp); // Initialize Phi_0_sign_temp with the sign of the
218  // initial (pre-redistancing) Phi_0
219  // Get initial gradients
220  get_upwind_gradient<Phi_n_temp, Phi_0_sign_temp, Phi_grad_temp>(g_temp, order_upwind_gradient, true);
221  iterative_redistancing(g_temp); // Do the redistancing on the temporary grid
222  copy_gridTogrid<Phi_n_temp, Phi_SDF_out>(g_temp, r_grid_in); // Copy resulting SDF function to input grid
223  }
233  template<typename T>
235  {
236  time_step = dt;
237  }
242  {
244  return time_step;
245  }
246 
247  int get_finalIteration()
248  {
249  return final_iter;
250  }
251 
252  auto get_finalChange()
253  {
254  return distFromSol.change;
255  }
256 
257  auto get_finalResidual()
258  {
259  return distFromSol.residual;
260  }
261 
262  int get_finalNumberNbPoints()
263  {
264  return distFromSol.count;
265  }
266 
267 private:
268  // Some indices for better readability
269  static constexpr size_t Phi_n_temp = 0;
270  static constexpr size_t Phi_grad_temp = 1;
271  static constexpr size_t Phi_0_sign_temp = 2;
272 
273  // Member variables
275  grid_in_type &r_grid_in;
276 
278  // point in NB.
279  int final_iter = 0;
280 
282  phi_type kappa = ceil(redistOptions.width_NB_in_grid_points / 2.0) * get_biggest_spacing(g_temp);
286  typename grid_in_type::stype time_step;
287  int order_upwind_gradient;
288  // Member functions
289 #ifdef SE_CLASS1
290 
295  void assure_minimal_thickness_of_NB()
296  {
297  if (redistOptions.width_NB_in_grid_points < 8)
298  {
299  std::cout << "The narrow band thickness that you chose for the convergence check is very small. Consider "
300  "setting redist_options.width_NB_in_grid_points to at least 8" << std::endl;
301  } // check narrow band width of convergence check if defined SE_CLASS1
302  }
303 #endif // SE_CLASS1
304 
307  template<size_t Phi_0_in>
309  {
310  phi_type min_value = get_min_val<Phi_0_in>(r_grid_in); // get minimum Phi_0 value on the input grid
311  init_grid_and_ghost<Phi_n_temp>(g_temp, min_value); // init. Phi_n_temp (incl. ghost) with min. Phi_0
312  copy_gridTogrid<Phi_0_in, Phi_n_temp>(r_grid_in, g_temp); // Copy Phi_0 from the input grid to Phi_n_temp
313  }
314 
325  phi_type get_phi_nplus1(phi_type phi_n, phi_type phi_n_magnOfGrad, typename grid_in_type::stype dt, phi_type
326  sgn_phi_n)
327  {
328  return phi_n + dt * sgn_phi_n * (1 - phi_n_magnOfGrad);
329  }
330 
336  {
337  get_upwind_gradient<Phi_n_temp, Phi_0_sign_temp, Phi_grad_temp>(grid, order_upwind_gradient, true);
338  grid.template ghost_get<Phi_n_temp, Phi_grad_temp>();
339  auto dom = grid.getDomainIterator();
340  while (dom.isNext())
341  {
342  auto key = dom.get();
343  const phi_type phi_n = grid.template get<Phi_n_temp>(key);
344  const phi_type phi_n_magnOfGrad = get_vector_magnitude<Phi_grad_temp>(grid, key);
345  phi_type epsilon = phi_n_magnOfGrad * grid.getSpacing()[0];
346  grid.template get<Phi_n_temp>(key) = get_phi_nplus1(phi_n, phi_n_magnOfGrad, time_step,
347  smooth_S(phi_n, epsilon));
348  ++dom;
349  }
350  }
351 
358  bool lays_inside_NB(phi_type Phi)
359  {
360  return (abs(Phi) <= kappa);
361  }
362 
369  {
370  phi_type max_residual = 0;
371  phi_type max_change = 0;
372  int count = 0;
373  auto dom = grid.getDomainIterator();
374  while (dom.isNext())
375  {
376  auto key = dom.get();
377  if (lays_inside_NB(grid.template get<Phi_n_temp>(key)))
378  {
379  count++;
380  phi_type phi_n_magnOfGrad = get_vector_magnitude<Phi_grad_temp>(grid, key);
381  phi_type epsilon = phi_n_magnOfGrad * grid.getSpacing()[0];
382  phi_type phi_nplus1 = get_phi_nplus1(grid.template get<Phi_n_temp>(key), phi_n_magnOfGrad, time_step,
383  smooth_S(grid.template get<Phi_n_temp>(key), epsilon));
384 
385  if (abs(phi_nplus1 - grid.template get<Phi_n_temp>(key)) > max_change)
386  {
387  max_change = abs(phi_nplus1 - grid.template get<Phi_n_temp>(key));
388  }
389 
390  if (abs(phi_n_magnOfGrad - 1) > max_residual) { max_residual = abs(phi_n_magnOfGrad - 1); }
391  }
392  ++dom;
393  }
394  auto &v_cl = create_vcluster();
395  v_cl.max(max_change);
396  v_cl.max(max_residual);
397  v_cl.sum(count);
398  v_cl.execute();
399 
400  // Update member variable distFromSol
401  distFromSol.change = max_change;
402  distFromSol.residual = max_residual;
403  distFromSol.count = count;
404  }
405 
413  {
415  auto &v_cl = create_vcluster();
416  if (v_cl.rank() == 0)
417  {
418  if (iter == 0)
419  {
420  std::cout << "Iteration,MaxChange,MaxResidual,NumberOfNarrowBandPoints" << std::endl;
421  }
422  std::cout << iter
423  << "," << to_string_with_precision(distFromSol.change, 15)
424  << "," << to_string_with_precision(distFromSol.residual, 15)
425  << "," << distFromSol.count << std::endl;
426  }
427  }
428 
440  {
441  bool steady_state = false;
443  if (redistOptions.convTolChange.check && redistOptions.convTolResidual.check)
444  {
445  steady_state = (
446  distFromSol.change <= redistOptions.convTolChange.value &&
447  distFromSol.residual <= redistOptions.convTolResidual.value &&
448  distFromSol.count > 0
449  );
450  }
451  else
452  {
453  if (redistOptions.convTolChange.check)
454  {
455  steady_state = (distFromSol.change <= redistOptions.convTolChange.value && distFromSol.count > 0);
456  } // Use the normalized total change between two iterations in the narrow bands steady-state criterion
457  if (redistOptions.convTolResidual.check)
458  {
459  steady_state = (distFromSol.residual <= redistOptions.convTolResidual.value && distFromSol.count > 0);
460  } // Use the normalized total residual of phi compared to SDF in the narrow bands steady-state criterion
461  }
462  return steady_state;
463  }
464 
475  {
476  int i = 0;
477  while (i < redistOptions.max_iter)
478  {
479  for (int j = 0; j < redistOptions.interval_check_convergence; j++)
480  {
482  ++i;
483  }
484  if (redistOptions.print_current_iterChangeResidual)
485  {
487  }
488  if (redistOptions.save_temp_grid)
489  {
490  get_upwind_gradient<Phi_n_temp, Phi_0_sign_temp, Phi_grad_temp>(g_temp, order_upwind_gradient, true);
491  g_temp.setPropNames({"Phi_Sussman_Out", "Phi_upwind_gradient", "Phi_0_sign_temp"});
492  g_temp.save("g_temp_redistancing_iteration_" + std::to_string(i) + ".hdf5"); // HDF5 file
493  // g_temp.write_frame("g_temp_redistancing_iteration", i, FORMAT_BINARY); // VTK file
494  }
495  if (i >= redistOptions.min_iter)
496  {
497  if (steady_state_NB(grid))
498  {
499  if (redistOptions.print_steadyState_iter)
500  {
501  auto &v_cl = create_vcluster();
502  if (v_cl.rank() == 0)
503  {
504  std::cout << "Steady state criterion reached at iteration: " << i << std::endl;
505  std::cout << "FinalIteration,MaxChange,MaxResidual" << std::endl;
506  }
508  }
509  break;
510  }
511  }
512  }
514  final_iter = i;
515  // If save_temp_grid set true, save the temporary grid as hdf5 that can be reloaded onto a grid
516  if (redistOptions.save_temp_grid)
517  {
518  get_upwind_gradient<Phi_n_temp, Phi_0_sign_temp, Phi_grad_temp>(g_temp, order_upwind_gradient, true);
519  g_temp.setPropNames({"Phi_Sussman_Out", "Phi_upwind_gradient", "Phi_0_sign_temp"});
520  g_temp.save("g_temp_redistancing_final.hdf5"); // HDF5 file
521  // g_temp.write("g_temp_redistancing_final", FORMAT_BINARY); // VTK file
522  }
523  }
524 };
525 
526 #endif //REDISTANCING_SUSSMAN_REDISTANCINGSUSSMAN_HPP
auto get_time_step()
Access the artificial timestep (private member) which will be used for the iterative redistancing.
bool steady_state_NB(g_temp_type &grid)
Checks steady-state is reached in the narrow band.
static constexpr size_t Phi_n_temp
Property index of Phi_0 on the temporary grid.
aggregate< phi_type, phi_type[grid_in_type::dims], int > props_temp
Aggregated properties for the temporary grid.
Header file containing help-functions that perform on OpenFPM-grids.
void update_distFromSol(g_temp_type &grid)
Re-computes the member variables distFromSol.change, distFromSol.residual, distFromSol....
grid_in_type::stype time_step
Artificial timestep for the redistancing iterations.
phi_type value
redistancing process is considered as steady-state. (see also DistFromSol::change)
DistFromSol< phi_type > distFromSol
Instantiate distance from solution in terms of change, residual, numb.
Structure to bundle options for redistancing.
Definition: Ghost.hpp:39
std::string to_string_with_precision(const T myValue, const size_t n=6)
Converts value into string maintaining a desired precision.
void run_redistancing()
Runs the Sussman-redistancing.
void save(const std::string &filename) const
Save the grid state on HDF5.
Redist_options< phi_type > redistOptions
Instantiate redistancing options.
Class for reinitializing a level-set function into a signed distance function using Sussman redistanc...
Optional convergence criterium checking the total change.
grid_in_type & r_grid_in
Define reference to input grid.
void go_one_redistancing_step_whole_grid(g_temp_type &grid)
Go one re-distancing time-step on the whole grid.
void iterative_redistancing(g_temp_type &grid)
Runs Sussman re-distancing on the internal temporary grid.
void init_temp_grid()
Copies values from input grid to internal temporary grid and initializes ghost layer with minimum val...
g_temp_type g_temp
Create temporary grid, which is only used inside the class for the redistancing.
Approximating upwind gradients on a grid with the following options for the order of accuracy: 1,...
KeyT const ValueT ValueT OffsetIteratorT OffsetIteratorT int
[in] The number of segments that comprise the sorting data
static constexpr size_t Phi_grad_temp
Property index of gradient of Phi_n on the temporary grid.
grid_type::stype get_biggest_spacing(grid_type &grid)
Determines the biggest spacing of a grid which is potentially anisotropic when comparing x,...
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.
void setPropNames(const openfpm::vector< std::string > &names)
Set the properties names.
phi_type kappa
Transform the half-bandwidth in no_of_grid_points into physical half-bandwidth kappa.
bool lays_inside_NB(phi_type Phi)
Checks if a node lays within the narrow band around the interface.
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.
int final_iter
Will be set to the final iteration when redistancing ends.
T smooth_S(T val, T epsilon)
Gets the smoothed sign of a variable.
aggregate of properties, from a list of object if create a struct that follow the OPENFPM native stru...
Definition: aggregate.hpp:214
RedistancingSussman(grid_in_type &grid_in, Redist_options< phi_type > &redistOptions)
Constructor initializing the redistancing options, the temporary internal grid and reference variable...
static constexpr size_t Phi_0_sign_temp
Property index of sign of initial (input) Phi_0 (temp. grid).
grid_dist_id< grid_in_type::dims, typename grid_in_type::stype, props_temp > g_temp_type
Type definition for the temporary grid.
grid_type::stype get_time_step_CFL(grid_type &grid)
Computes the time step for the iterative re-distancing fulfilling CFL condition.
void set_user_time_step(T dt)
Overwrite the time_step found via CFL condition with an individual time_step.
Header file containing small mathematical help-functions that are needed e.g. for the Sussman redista...
Optional convergence criterium checking the residual.
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...