BioDynaMo  v1.05.120-25dc9790
euler_grid.cc
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------
2 //
3 // Copyright (C) 2021 CERN & University of Surrey for the benefit of the
4 // BioDynaMo collaboration. All Rights Reserved.
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 //
9 // See the LICENSE file distributed with this work for details.
10 // See the NOTICE file distributed with this work for additional information
11 // regarding copyright ownership.
12 //
13 // -----------------------------------------------------------------------------
14 
16 #include "core/resource_manager.h"
17 #include "core/simulation.h"
18 
19 namespace bdm {
20 
22  const auto nx = resolution_;
23  const auto ny = resolution_;
24  const auto nz = resolution_;
25 
26  const real_t ibl2 = 1 / (box_length_ * box_length_);
27  const real_t d = 1 - dc_[0];
28 
29  constexpr size_t YBF = 16;
30 #pragma omp parallel for collapse(2)
31  for (size_t yy = 0; yy < ny; yy += YBF) {
32  for (size_t z = 0; z < nz; z++) {
33  size_t ymax = yy + YBF;
34  if (ymax >= ny) {
35  ymax = ny;
36  }
37  for (size_t y = yy; y < ymax; y++) {
38  size_t x{0};
39  size_t c{0};
40  size_t n{0};
41  size_t s{0};
42  size_t b{0};
43  size_t t{0};
44  c = x + y * nx + z * nx * ny;
45 #pragma omp simd
46  for (x = 1; x < nx - 1; x++) {
47  ++c;
48 
49  if (y == 0 || y == (ny - 1) || z == 0 || z == (nz - 1)) {
50  continue;
51  }
52 
53  n = c - nx;
54  s = c + nx;
55  b = c - nx * ny;
56  t = c + nx * ny;
57 
58  c2_[c] = c1_[c] * (1 - mu_ * dt) +
59  (d * dt * ibl2) *
60  (c1_[c - 1] - 2 * c1_[c] + c1_[c + 1] + c1_[s] -
61  2 * c1_[c] + c1_[n] + c1_[b] - 2 * c1_[c] + c1_[t]);
62  }
63  } // tile ny
64  } // tile nz
65  } // block ny
66  c1_.swap(c2_);
67 }
68 
70  const auto nx = resolution_;
71  const auto ny = resolution_;
72  const auto nz = resolution_;
73 
74  const real_t ibl2 = 1 / (box_length_ * box_length_);
75  const real_t d = 1 - dc_[0];
76  std::array<int, 4> l;
77 
78  constexpr size_t YBF = 16;
79 #pragma omp parallel for collapse(2)
80  for (size_t yy = 0; yy < ny; yy += YBF) {
81  for (size_t z = 0; z < nz; z++) {
82  size_t ymax = yy + YBF;
83  if (ymax >= ny) {
84  ymax = ny;
85  }
86  for (size_t y = yy; y < ymax; y++) {
87  size_t x{0};
88  size_t c{0};
89  size_t n{0};
90  size_t s{0};
91  size_t b{0};
92  size_t t{0};
93  c = x + y * nx + z * nx * ny;
94 
95  l.fill(1);
96 
97  if (y == 0) {
98  n = c;
99  l[0] = 0;
100  } else {
101  n = c - nx;
102  }
103 
104  if (y == ny - 1) {
105  s = c;
106  l[1] = 0;
107  } else {
108  s = c + nx;
109  }
110 
111  if (z == 0) {
112  b = c;
113  l[2] = 0;
114  } else {
115  b = c - nx * ny;
116  }
117 
118  if (z == nz - 1) {
119  t = c;
120  l[3] = 0;
121  } else {
122  t = c + nx * ny;
123  }
124 
125  c2_[c] = c1_[c] * (1 - mu_ * dt) +
126  (d * dt * ibl2) *
127  (0 - 2 * c1_[c] + c1_[c + 1] + c1_[s] - 2 * c1_[c] +
128  c1_[n] + c1_[b] - 2 * c1_[c] + c1_[t]);
129 #pragma omp simd
130  for (x = 1; x < nx - 1; x++) {
131  ++c;
132  ++n;
133  ++s;
134  ++b;
135  ++t;
136  c2_[c] =
137  c1_[c] * (1 - mu_ * dt) +
138  (d * dt * ibl2) * (c1_[c - 1] - 2 * c1_[c] + c1_[c + 1] +
139  l[0] * c1_[s] - 2 * c1_[c] + l[1] * c1_[n] +
140  l[2] * c1_[b] - 2 * c1_[c] + l[3] * c1_[t]);
141  }
142  ++c;
143  ++n;
144  ++s;
145  ++b;
146  ++t;
147  c2_[c] = c1_[c] * (1 - mu_ * dt) +
148  (d * dt * ibl2) *
149  (c1_[c - 1] - 2 * c1_[c] + 0 + c1_[s] - 2 * c1_[c] +
150  c1_[n] + c1_[b] - 2 * c1_[c] + c1_[t]);
151  } // tile ny
152  } // tile nz
153  } // block ny
154  c1_.swap(c2_);
155 }
156 
158  const auto nx = resolution_;
159  const auto ny = resolution_;
160  const auto nz = resolution_;
161 
162  const real_t ibl2 = 1 / (box_length_ * box_length_);
163  const real_t d = 1 - dc_[0];
164 
165  const auto sim_time = GetSimulatedTime();
166 
167  constexpr size_t YBF = 16;
168 #pragma omp parallel for collapse(2)
169  for (size_t yy = 0; yy < ny; yy += YBF) {
170  for (size_t z = 0; z < nz; z++) {
171  size_t ymax = yy + YBF;
172  if (ymax >= ny) {
173  ymax = ny;
174  }
175  for (size_t y = yy; y < ymax; y++) {
176  size_t x{0};
177  size_t c{0};
178  size_t n{0};
179  size_t s{0};
180  size_t b{0};
181  size_t t{0};
182  c = x + y * nx + z * nx * ny;
183 #pragma omp simd
184  for (x = 0; x < nx; x++) {
185  if (x == 0 || x == (nx - 1) || y == 0 || y == (ny - 1) || z == 0 ||
186  z == (nz - 1)) {
187  // For all boxes on the boundary, we simply evaluate the boundary
188  real_t real_x = grid_dimensions_[0] + x * box_length_;
189  real_t real_y = grid_dimensions_[0] + y * box_length_;
190  real_t real_z = grid_dimensions_[0] + z * box_length_;
191  c2_[c] =
192  boundary_condition_->Evaluate(real_x, real_y, real_z, sim_time);
193  } else {
194  // For inner boxes, we compute the regular stencil update
195  n = c - nx;
196  s = c + nx;
197  b = c - nx * ny;
198  t = c + nx * ny;
199 
200  c2_[c] = c1_[c] * (1 - mu_ * dt) +
201  (d * dt * ibl2) *
202  (c1_[c - 1] - 2 * c1_[c] + c1_[c + 1] + c1_[s] -
203  2 * c1_[c] + c1_[n] + c1_[b] - 2 * c1_[c] + c1_[t]);
204  }
205  ++c;
206  }
207  } // tile ny
208  } // tile nz
209  } // block ny
210  c1_.swap(c2_);
211 }
212 
214  const size_t nx = resolution_;
215  const size_t ny = resolution_;
216  const size_t nz = resolution_;
217  const size_t num_boxes = nx * ny * nz;
218 
219  const real_t ibl2 = 1 / (box_length_ * box_length_);
220  const real_t d = 1 - dc_[0];
221 
222  const auto sim_time = GetSimulatedTime();
223 
224  constexpr size_t YBF = 16;
225 #pragma omp parallel for collapse(2)
226  for (size_t yy = 0; yy < ny; yy += YBF) {
227  for (size_t z = 0; z < nz; z++) {
228  size_t ymax = yy + YBF;
229  if (ymax >= ny) {
230  ymax = ny;
231  }
232  for (size_t y = yy; y < ymax; y++) {
233  size_t x{0};
234  size_t c{0};
235  size_t n{0};
236  size_t s{0};
237  size_t b{0};
238  size_t t{0};
239  c = x + y * nx + z * nx * ny;
240 #pragma omp simd
241  for (x = 0; x < nx; x++) {
242  n = c - nx;
243  s = c + nx;
244  b = c - nx * ny;
245  t = c + nx * ny;
246 
247  // Clamp to avoid out of bounds access. Clamped values are initialized
248  // to a wrong value but will be overwritten by the boundary condition
249  // evaluation. All other values are correct.
250  real_t left{c1_[std::clamp(c - 1, size_t{0}, num_boxes - 1)]};
251  real_t right{c1_[std::clamp(c + 1, size_t{0}, num_boxes - 1)]};
252  real_t bottom{c1_[std::clamp(b, size_t{0}, num_boxes - 1)]};
253  real_t top{c1_[std::clamp(t, size_t{0}, num_boxes - 1)]};
254  real_t north{c1_[std::clamp(n, size_t{0}, num_boxes - 1)]};
255  real_t south{c1_[std::clamp(s, size_t{0}, num_boxes - 1)]};
256  real_t center_factor{6.0};
257 
258  if (x == 0 || x == (nx - 1) || y == 0 || y == (ny - 1) || z == 0 ||
259  z == (nz - 1)) {
260  real_t real_x = grid_dimensions_[0] + x * box_length_;
261  real_t real_y = grid_dimensions_[0] + y * box_length_;
262  real_t real_z = grid_dimensions_[0] + z * box_length_;
263  real_t boundary_value =
264  -box_length_ *
265  boundary_condition_->Evaluate(real_x, real_y, real_z, sim_time);
266 
267  if (x == 0) {
268  left = boundary_value;
269  center_factor -= 1.0;
270  } else if (x == (nx - 1)) {
271  right = boundary_value;
272  center_factor -= 1.0;
273  }
274 
275  if (y == 0) {
276  north = boundary_value;
277  center_factor -= 1.0;
278  } else if (y == (ny - 1)) {
279  south = boundary_value;
280  center_factor -= 1.0;
281  }
282 
283  if (z == 0) {
284  bottom = boundary_value;
285  center_factor -= 1.0;
286  } else if (z == (nz - 1)) {
287  top = boundary_value;
288  center_factor -= 1.0;
289  }
290  }
291 
292  c2_[c] = c1_[c] * (1 - mu_ * dt) +
293  (d * dt * ibl2) * (left + right + south + north + top +
294  bottom - center_factor * c1_[c]);
295 
296  ++c;
297  }
298  } // tile ny
299  } // tile nz
300  } // block ny
301  c1_.swap(c2_);
302 }
303 
305  const size_t nx = resolution_;
306  const size_t ny = resolution_;
307  const size_t nz = resolution_;
308 
309  const real_t dx = box_length_;
310  const real_t d = 1 - dc_[0];
311 
312  constexpr size_t YBF = 16;
313 #pragma omp parallel for collapse(2)
314  for (size_t yy = 0; yy < ny; yy += YBF) {
315  for (size_t z = 0; z < nz; z++) {
316  size_t ymax = yy + YBF;
317  if (ymax >= ny) {
318  ymax = ny;
319  }
320  for (size_t y = yy; y < ymax; y++) {
321  size_t l{0};
322  size_t r{0};
323  size_t n{0};
324  size_t s{0};
325  size_t b{0};
326  size_t t{0};
327  size_t c = y * nx + z * nx * ny;
328 #pragma omp simd
329  for (size_t x = 0; x < nx; x++) {
330  l = c - 1;
331  r = c + 1;
332  n = c - nx;
333  s = c + nx;
334  b = c - nx * ny;
335  t = c + nx * ny;
336 
337  // Adapt neighbor indices for boundary boxes for periodic boundary
338  if (x == 0) {
339  l = nx - 1 + y * nx + z * nx * ny;
340  } else if (x == (nx - 1)) {
341  r = 0 + y * nx + z * nx * ny;
342  }
343 
344  if (y == 0) {
345  n = x + (ny - 1) * nx + z * nx * ny;
346  } else if (y == (ny - 1)) {
347  s = x + 0 * nx + z * nx * ny;
348  }
349 
350  if (z == 0) {
351  b = x + y * nx + (nz - 1) * nx * ny;
352  } else if (z == (nz - 1)) {
353  t = x + y * nx + 0 * nx * ny;
354  }
355 
356  // Stencil update
357  c2_[c] = c1_[c] * (1 - (mu_ * dt)) +
358  ((d * dt / (dx * dx)) * (c1_[l] + c1_[r] + c1_[n] + c1_[s] +
359  c1_[t] + c1_[b] - 6.0 * c1_[c]));
360 
361  ++c;
362  }
363  } // tile ny
364  } // tile nz
365  } // block ny
366  c1_.swap(c2_);
367 }
368 
369 } // namespace bdm
bdm::DiffusionGrid::boundary_condition_
std::unique_ptr< BoundaryCondition > boundary_condition_
Object that implements the boundary conditions.
Definition: diffusion_grid.h:417
bdm::DiffusionGrid::grid_dimensions_
std::array< int32_t, 2 > grid_dimensions_
The grid dimensions of the diffusion grid (cubic shaped)
Definition: diffusion_grid.h:396
bdm::EulerGrid::DiffuseWithDirichlet
void DiffuseWithDirichlet(real_t dt) override
Definition: euler_grid.cc:157
bdm
Definition: agent.cc:39
bdm::DiffusionGrid::mu_
real_t mu_
The decay constant.
Definition: diffusion_grid.h:394
bdm::real_t
double real_t
Definition: real_t.h:21
bdm::DiffusionGrid::c1_
ParallelResizeVector< real_t > c1_
The array of concentration values.
Definition: diffusion_grid.h:382
bdm::EulerGrid::DiffuseWithOpenEdge
void DiffuseWithOpenEdge(real_t dt) override
Definition: euler_grid.cc:69
bdm::EulerGrid::DiffuseWithNeumann
void DiffuseWithNeumann(real_t dt) override
Definition: euler_grid.cc:213
bdm::DiffusionGrid::box_length_
real_t box_length_
The side length of each box.
Definition: diffusion_grid.h:375
euler_grid.h
bdm::DiffusionGrid::resolution_
size_t resolution_
Definition: diffusion_grid.h:403
bdm::EulerGrid::DiffuseWithPeriodic
void DiffuseWithPeriodic(real_t dt) override
Definition: euler_grid.cc:304
simulation.h
resource_manager.h
bdm::EulerGrid::DiffuseWithClosedEdge
void DiffuseWithClosedEdge(real_t dt) override
Definition: euler_grid.cc:21
bdm::Continuum::GetSimulatedTime
real_t GetSimulatedTime() const
Returns the time simulated by the continuum.
Definition: continuum_interface.h:99
bdm::DiffusionGrid::dc_
std::array< real_t, 7 > dc_
The diffusion coefficients [cc, cw, ce, cs, cn, cb, ct].
Definition: diffusion_grid.h:392
bdm::DiffusionGrid::c2_
ParallelResizeVector< real_t > c2_
An extra concentration data buffer for faster value updating.
Definition: diffusion_grid.h:384
bdm::ParallelResizeVector::swap
void swap(ParallelResizeVector &other)
Definition: parallel_resize_vector.h:77