OpenFPM  5.2.0
Project that contain the implementation of distributed structures
main.cu
1 //
2 // Created by jstark on 2023-05-05.
3 //
38 #include <iostream>
40 #include <typeinfo>
41 
42 #include "CSVReader/CSVReader.hpp"
43 
44 // Include redistancing files
45 #include "util/PathsAndFiles.hpp"
48 #include "level_set/redistancing_Sussman/HelpFunctionsForGrid.hpp" // For the ghost initialization
49 #include "include/RemoveLines.hpp" // For removing thin (diagonal or straight) lines
50 
51 #include "FiniteDifference/FD_simple.hpp"
52 
53 #include "include/DiffusionSpace_sparseGrid.hpp"
54 #include "include/HelpFunctions_diffusion.hpp"
55 
56 #include "Decomposition/Distribution/BoxDistribution.hpp"
57 
58 const size_t dims = 3;
59 
60 // Property indices full grid
61 const size_t PHI_FULL = 0;
62 
64 
65 const openfpm::vector<std::string> prop_names_full = {"Phi_Sussman_Out"};
66 
67 
68 // Property indices sparse grid
69 const size_t PHI_PHASE = 0;
70 const size_t U_N = 1;
71 const size_t U_NPLUS1 = 2;
72 const size_t K_SINK = 3;
73 
74 
76 const openfpm::vector<std::string> prop_names_sparse = {"PHI_PHASE",
77  "U_N",
78  "U_NPLUS1",
79  "K_SINK"};
80 
81 
82 // Space indices
83 constexpr size_t x = 0, y = 1, z = 2;
84 
85 // input
86 const std::string path_to_redistancing_result =
87  "output_sussman_sparse_grid_porousCeramics_1216x1016x941/";
88 
89 const std::string redistancing_filename = "sparseGrid_initial.hdf5";
90 
91 const std::string path_to_size = path_to_redistancing_result;
92 
93 const std::string output_name = "output_heat_conduction_porous_ceramics_1216x1016x941_sparse_grid";
94 
95 
96 int main(int argc, char* argv[])
97 {
98  // Initialize library.
99  openfpm_init(&argc, &argv);
100  auto & v_cl = create_vcluster();
101 
102  timer t_total;
103  timer t_iterative_diffusion_total;
104  timer t_iteration_wct;
105  timer t_GPU;
106 
107 
108  t_total.start();
109 
111  // Set current working directory, define output paths and create folders where output will be saved
112  std::string cwd = get_cwd();
113  const std::string path_output = cwd + "/" + output_name + "/";
114  create_directory_if_not_exist(path_output);
115 
116  if(v_cl.rank()==0) std::cout << "Redistancing result will be loaded from " << path_to_redistancing_result << redistancing_filename << std::endl;
117 
118  if(v_cl.rank()==0) std::cout << "Outputs will be saved to " << path_output << std::endl;
119 
123  // Create full grid and load redistancing result
125  // Read size of sussman redistancing output grid from csv files
128 
129  size_t m, n;
130  read_csv_to_vector(path_to_size + "/N.csv", v_sz, m, n);
131  read_csv_to_vector(path_to_size + "/L.csv", v_L, m, n);
132 
133  const float Lx_low = 0.0;
134  const float Lx_up = v_L.get(x);
135  const float Ly_low = 0.0;
136  const float Ly_up = v_L.get(y);
137  const float Lz_low = 0.0;
138  const float Lz_up = v_L.get(z);
139 
141  size_t sz[dims] = {v_sz.get(x), v_sz.get(y), v_sz.get(z)};
142  Box<dims, float> box({Lx_low, Ly_low, Lz_low}, {Lx_up, Ly_up, Lz_up});
143  Ghost<dims, long int> ghost(1);
144 
145  // Defining the decomposition and the input grid type
147  typedef grid_dist_id<dims, float, props_full, Dec> grid_in_type;
148  grid_in_type g_dist(sz, box, ghost);
149 
150  std::cout << "Rank " << v_cl.rank() << " starts loading redistancing result..." << std::endl;
151  g_dist.load(path_to_redistancing_result + "/" + redistancing_filename); // Load SDF
152  std::cout << "Rank " << v_cl.rank() << " finished loading redistancing result." << std::endl;
153 
156  // Get sparse grid of heat conduction domain
158  // Create sparse grid
159  std::cout << "Rank " << v_cl.rank() << " starts creating sparse grid." << std::endl;
160 
161 
162  typedef sgrid_dist_id_gpu<dims, float, props_sparse, CudaMemory, Dec> sparse_grid_type;
163  sparse_grid_type g_sparse(sz, box, ghost);
164  g_sparse.setPropNames(prop_names_sparse);
165 
166 
167  const float d_low = 0.0, d_up = Lx_up;
168  get_diffusion_domain_sparse_grid<PHI_FULL, PHI_PHASE>(g_dist, g_sparse, d_low, d_up);
169 
170  // Alternatively: load sparse grid of diffusion domain from HDF5 file
171  // g_sparse.load(path_to_redistancing_result + "/" + redistancing_filename);
172 
173  std::cout << "Rank " << v_cl.rank() << " finished creating sparse grid." << std::endl;
174 
176  // Define parameters for heat conduction
178  const float u0 = 1.0; // Initial heat from one side
179  const float D = 0.1; // Heat diffusivity
180  const float sink_rate = 0.1; // Rate of heat loss at solid-air interface
181  std::cout << "Diffusion coefficient in s/(mm^2): " << D << std::endl;
182  std::cout << "Sink rate in 1/s: " << sink_rate << std::endl;
183 
184  // Set initial condition: initial heat source is a sphere of radius R at the domain center
185  const float center[dims] = {(Lx_up+Lx_low)/(float)2,
186  (Ly_up+Ly_low)/(float)2,
187  (Lz_up+Lz_low)/(float)2};
188  const float R = Lz_up / 4.0;
189 
190  auto dom = g_sparse.getDomainIterator();
191  while(dom.isNext())
192  {
193  auto key = dom.get();
194 
195  // Initial condition: heat comes from sphere at center
196  Point<dims, float> coords = g_sparse.getPos(key);
197 
198  if(((coords.get(x) - center[x]) * (coords.get(x) - center[x])
199  + (coords.get(y) - center[y]) * (coords.get(y) - center[y])
200  + (coords.get(z) - center[z]) * (coords.get(z) - center[z])) <= R * R)
201  {
202  g_sparse.template insertFlush<U_N>(key) = u0;
203  }
204  else g_sparse.template insertFlush<U_N>(key) = 0.0;
205 
206  ++dom;
207  }
208 
210 
215  // Defining the functor that will be passed to the GPU to simulate reaction-diffusion
216  // GetCpBlockType<typename SGridGpu, unsigned int prp, unsigned int stencil_size>
217  typedef typename GetCpBlockType<decltype(g_sparse),0,1>::type CpBlockType;
218 
219  const float dx = g_sparse.spacing(x), dy = g_sparse.spacing(y), dz = g_sparse.spacing(z);
220  // Stability criterion for FTCS : dt = 1/4 * 1/(1/dx^2 + 1/dy^2)
221  const float dt = diffusion_time_step(g_sparse, D);
222  std::cout << "dx, dy, dz = " << g_sparse.spacing(x) << "," << g_sparse.spacing(y) << "," << g_sparse.spacing(z) << std::endl;
223  std::cout << "dt = 1/(4D) * 1/(1/dx^2 + 1/dy^2 + 1/dz^2) = " << dt << std::endl;
224 
225  auto func_heatDiffusion_withSink = [dx, dy, dz, dt, d_low, D, sink_rate] __device__ (
226  float & u_out, // concentration output
227  float & phi_out, // sdf of domain output (dummy)
228  CpBlockType & u, // concentration input
229  CpBlockType & phi, // sdf of domain (for boundary conditions)
230  auto & block,
231  int offset,
232  int i,
233  int j,
234  int k
235  )
236  {
238  // Stencil
239  // Concentration
240  float u_c = u(i, j, k);
241  float u_px = u(i+1, j, k);
242  float u_mx = u(i-1, j, k);
243  float u_py = u(i, j+1, k);
244  float u_my = u(i, j-1, k);
245  float u_pz = u(i, j, k+1);
246  float u_mz = u(i, j, k-1);
247 
248  // Signed distance function
249  float phi_c = phi(i, j, k);
250  float phi_px = phi(i+1, j, k);
251  float phi_mx = phi(i-1, j, k);
252  float phi_py = phi(i, j+1, k);
253  float phi_my = phi(i, j-1, k);
254  float phi_pz = phi(i, j, k+1);
255  float phi_mz = phi(i, j, k-1);
256 
257  // Get sink term
258  float k_sink = 0; // Sink equal to zero in bulk and equal to sink_rate only at the surfaces
259 
260  // Impose no-flux boundary conditions and sink term at the surface (i.e., when neighbor is outside)
261  if (phi_px <= d_low + std::numeric_limits<float>::epsilon()) {u_px = u_c; k_sink = sink_rate;}
262  if (phi_mx <= d_low + std::numeric_limits<float>::epsilon()) {u_mx = u_c; k_sink = sink_rate;}
263  if (phi_py <= d_low + std::numeric_limits<float>::epsilon()) {u_py = u_c; k_sink = sink_rate;}
264  if (phi_my <= d_low + std::numeric_limits<float>::epsilon()) {u_my = u_c; k_sink = sink_rate;}
265  if (phi_pz <= d_low + std::numeric_limits<float>::epsilon()) {u_pz = u_c; k_sink = sink_rate;}
266  if (phi_mz <= d_low + std::numeric_limits<float>::epsilon()) {u_mz = u_c; k_sink = sink_rate;}
267 
268  block.template get<K_SINK>()[offset] = k_sink; // Just for checking in paraview
269 
270  // Compute concentration of next time point
271  u_out = u_c + dt * ( D * ((u_px + u_mx - 2 * u_c)/(dx * dx)
272  + (u_py + u_my - 2 * u_c)/(dy * dy)
273  + (u_pz + u_mz - 2 * u_c)/(dz * dz))
274  - k_sink * u_c);
275 
276 
277  // dummy outs
278  phi_out = phi_c;
279  };
280 
282 
283 
285  // Create text file to which wall clock time for iteration incl. ghost communication will be saved
286  std::string path_time_filewct = path_output + "/time_wct_incl_ghostCommunication" + std::to_string(v_cl.rank()) + ".txt";
287  std::ofstream out_wct_file(path_time_filewct, std::ios_base::app);
288 
289  // Create text file to which GPU time will be saved
290  std::string path_time_filegpu = path_output + "/time_GPU" + std::to_string(v_cl.rank()) + ".txt";
291  std::ofstream out_GPUtime_file(path_time_filegpu, std::ios_base::app);
292 
293 
294  // Iterative diffusion
295  // const size_t iterations = 1e6;
296  const size_t iterations = 103;
297  const size_t number_write_outs = 10;
298  const size_t interval_write = iterations / number_write_outs; // Find interval for writing to reach
299  size_t iter = 0;
300  float t = 0;
301 
302  // Copy from host to GPU for simulation
303  g_sparse.template hostToDevice<U_N, U_NPLUS1, K_SINK, PHI_PHASE>();
304  g_sparse.template ghost_get<PHI_PHASE, K_SINK>(RUN_ON_DEVICE | SKIP_LABELLING);
305  t_iterative_diffusion_total.start();
306  while(iter <= iterations)
307  {
308  if (iter % 2 == 0)
309  {
310  t_iteration_wct.start();
311  g_sparse.template ghost_get<U_N>(RUN_ON_DEVICE | SKIP_LABELLING);
312  t_GPU.startGPU();
313  g_sparse.template conv2_b<
314  U_N,
315  PHI_PHASE,
316  U_NPLUS1,
317  PHI_PHASE, 1>
318  ({0, 0, 0},
319  {(long int) sz[x]-1, (long int) sz[y]-1, (long int) sz[z]-1},
320  func_heatDiffusion_withSink);
321  t_GPU.stopGPU();
322  t_iteration_wct.stop();
323 
324  // Write out time to text-file
325  out_wct_file << t_iteration_wct.getwct() << ",";
326  out_GPUtime_file << t_GPU.getwctGPU() << ",";
327 
328  t_iteration_wct.reset();
329  }
330  else
331  {
332  t_iteration_wct.start();
333  g_sparse.template ghost_get<U_NPLUS1>(RUN_ON_DEVICE | SKIP_LABELLING);
334  t_GPU.startGPU();
335  g_sparse.template conv2_b<
336  U_NPLUS1,
337  PHI_PHASE,
338  U_N,
339  PHI_PHASE, 1>
340  ({0, 0, 0},
341  {(long int) sz[x]-1, (long int) sz[y]-1, (long int) sz[z]-1},
342  func_heatDiffusion_withSink);
343  t_GPU.stopGPU();
344  t_iteration_wct.stop();
345 
346  // Write out time to text-file
347  out_wct_file << t_iteration_wct.getwct() << ",";
348  out_GPUtime_file << t_GPU.getwctGPU() << ",";
349 
350  t_iteration_wct.reset();
351  }
352 
353 
354  if (iter % interval_write == 0)
355  {
356  // Copy from GPU to host for writing
357  g_sparse.template deviceToHost<U_N, U_NPLUS1, K_SINK, PHI_PHASE>();
358 
359  // Write g_sparse to vtk
360  g_sparse.write_frame(path_output + "g_sparse_diffuse", iter, FORMAT_BINARY);
361 
362  if (iter % 2 == 0)
363  {
364  monitor_total_concentration<U_N>(g_sparse, t, iter, path_output,"total_conc.csv");
365  }
366  else
367  {
368  monitor_total_concentration<U_NPLUS1>(g_sparse, t, iter, path_output,"total_conc.csv");
369  }
370  }
371 
372  t += dt;
373  iter += 1;
374  }
375  t_iterative_diffusion_total.stop();
376  std::cout << "Rank " << v_cl.rank() << " total time for iterative diffusion incl. write outs: " << t_iterative_diffusion_total.getwct() << std::endl;
377  std::cout << "Rank " << v_cl.rank() << " finished diffusion." << std::endl;
378 
383  t_total.stop();
384  std::cout << "Rank " << v_cl.rank() << " total time for the whole programm : " << t_total.getwct() << std::endl;
385 
386 
387  openfpm_finalize();
388  return 0;
389 }
390 
Header file containing help-functions that perform on OpenFPM-grids.
Header file containing functions for loading pixel values from 2D image or 3D image stack (volume) st...
Header file containing functions for creating files and folders.
static void create_directory_if_not_exist(std::string path, bool silent=0)
Creates a directory if not already existent.
static std::string get_cwd()
Gets the current working directory and returns path as string.
Class for reinitializing a level-set function into a signed distance function using Sussman redistanc...
This class represent an N-dimensional box.
Definition: Box.hpp:60
This class decompose a space into sub-sub-domains and distribute them across processors.
Derivative second order on h (spacing)
Definition: Derivative.hpp:29
Definition: Ghost.hpp:40
This class implement the point shape in an N-dimensional space.
Definition: Point.hpp:28
__device__ __host__ const T & get(unsigned int i) const
Get coordinate.
Definition: Point.hpp:172
This is a distributed grid.
Class for cpu time benchmarking.
Definition: timer.hpp:28
void stop()
Stop the timer.
Definition: timer.hpp:119
void reset()
Reset the timer.
Definition: timer.hpp:154
void start()
Start the timer.
Definition: timer.hpp:90
double getwct()
Return the elapsed real time.
Definition: timer.hpp:130
KeyT const ValueT ValueT OffsetIteratorT OffsetIteratorT int
[in] The number of segments that comprise the sorting data
get the type of the block
aggregate of properties, from a list of object if create a struct that follow the OPENFPM native stru...
Definition: aggregate.hpp:221