OpenFPM  5.2.0
Project that contain the implementation of distributed structures
auxFunc.hpp
1 // ------------------------------------------------------------------------------------------
2 // ActiveGelsOnDeformableSurfaces
3 // Copyright (C) 2020 ---- foggia
4 //
5 // This file is part of the ActiveGelsOnDeformableSurfaces software.
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 // ------------------------------------------------------------------------------------------
20 //
21 // Created by foggia on 22-04-11
22 //
23 
24 
25 // 1) Function to compute analytically the SDF and the normal for the sphere in the whole domain
26 template <typename grid_type, int SDF, int normal>
27 void init_surfaceAndNormal(grid_type & grid,
28  const std::array<double,grid_type::dims> & center,
29  const double radius) {
30 
31  const int x{0};
32  const int y{1};
33  const int z{2};
34  double dist, arg, theta, phi;
35  std::array<double, grid_type::dims> coord;
36 
37  auto it = grid.getDomainIterator();
38  while(it.isNext()) {
39  auto key = it.get();
40 
41  dist = 0;
42  for (int d = 0; d < grid_type::dims; ++d) {
43  coord[d] = grid.getPos(key)[d];
44  dist += (coord[d]-center[d])*(coord[d]-center[d]);
45  }
46  arg = (coord[x]-center[x]) * (coord[x]-center[x]) + (coord[y]-center[y]) * (coord[y]-center[y]);
47  theta = std::atan2(std::sqrt(arg),(coord[z]-center[z]));
48  phi = std::atan2((coord[y]-center[y]),(coord[x]-center[x]));
49 
50  grid.template get<SDF>(key) = std::sqrt(dist) - radius;
51  grid.template get<normal>(key)[x] = std::sin(theta)*std::cos(phi);
52  grid.template get<normal>(key)[y] = std::sin(theta)*std::sin(phi);
53  grid.template get<normal>(key)[z] = std::cos(theta);
54 
55  ++it;
56  }
57 }
58 
59 // 2) Function to compute analytically the SDF and the normal for the sphere in the whole domain
60 template <typename grid_type, int SDF>
61 void init_surface(grid_type & grid,
62  const std::array<double,grid_type::dims> & center,
63  const double radius) {
64 
65  double dist;
66  std::array<double, grid_type::dims> coord;
67 
68  auto it = grid.getDomainIterator();
69  while(it.isNext()) {
70  auto key = it.get();
71 
72  dist = 0;
73  for (int d = 0; d < grid_type::dims; ++d) {
74  coord[d] = grid.getPos(key)[d];
75  dist += (coord[d]-center[d])*(coord[d]-center[d]);
76  }
77 
78  grid.template get<SDF>(key) = std::sqrt(dist) - radius;
79  ++it;
80  }
81 }
82 
83 // 3a) Function to initialize the value of the quantity (spherical harmonic (4,0)) on the narrow band
84 // Y(4,0) = 3/16 * sqrt(1/pi) * (35*cos^4(theta) - 30*cos^2(theta) + 3)
85 template <typename grid_type, int qty, typename key_type>
86 void init_qty(grid_type & grid,
87  const std::array<double,grid_type::dims> & center,
88  std::vector<key_type> & nb_keys) {
89 
90  const int x{0};
91  const int y{1};
92  const int z{2};
93  double arg, theta, cos2;
94  const double pi{3.14159265358979323846};
95  const double prefactor{3.0/16.0 * std::sqrt(1.0/pi)};
96  std::array<double,grid.dims> coord;
97 
98  for (int i = 0; i < nb_keys.size(); ++i) {
99 
100  for (int d = 0; d < grid.dims; ++d)
101  coord[d] = grid.getPos(nb_keys[i])[d];
102 
103  arg = (coord[x]-center[x]) * (coord[x]-center[x]) + (coord[y]-center[y]) * (coord[y]-center[y]);
104  theta = std::atan2(std::sqrt(arg),(coord[z]-center[z]));
105  cos2 = std::cos(theta)*std::cos(theta);
106 
107  grid.template get<qty>(nb_keys[i]) = prefactor * (cos2*(35.0*cos2 - 30.0) + 3.0);
108 
109  }
110 }
111 
112 // 3b) Function to initialize the value of the quantity (spherical harmonic (4,0)) on the whole grid
113 // Y(4,0) = 3/16 * sqrt(1/pi) * (35*cos^4(theta) - 30*cos^2(theta) + 3)
114 template <typename grid_type, int qty>
115 void init_qty(grid_type & grid,
116  const std::array<double,grid_type::dims> & center) {
117 
118  const int x{0};
119  const int y{1};
120  const int z{2};
121  double arg, theta, cos2;
122  const double pi{3.14159265358979323846};
123  const double prefactor{3.0/16.0 * std::sqrt(1.0/pi)};
124  std::array<double,grid.dims> coord;
125 
126  auto it = grid.getDomainIterator();
127  while(it.isNext()) {
128  auto key = it.get();
129 
130  for (int d = 0; d < grid.dims; ++d)
131  coord[d] = grid.getPos(key)[d];
132 
133  arg = (coord[x]-center[x]) * (coord[x]-center[x]) + (coord[y]-center[y]) * (coord[y]-center[y]);
134  theta = std::atan2(std::sqrt(arg),(coord[z]-center[z]));
135  cos2 = std::cos(theta)*std::cos(theta);
136 
137  grid.template get<qty>(key) = prefactor * (cos2*(35.0*cos2 - 30.0) + 3.0);
138  ++it;
139  }
140 }
141 // 4) Function to compute the analytical solution of the LB operator in the whole domain
142 template <typename grid_type, int qty, int sol>
143 void init_analytSol(grid_type & grid,
144  const std::array<double,grid_type::dims> & center,
145  const double radius) {
146 
147  const int x{0};
148  const int y{1};
149  const int z{2};
150  double arg, theta, cos2;
151  const double pi{3.14159265358979323846};
152  const double prefactor{3.0/16.0 * std::sqrt(1.0/pi)};
153  std::array<double,grid.dims> coord;
154 
155  auto it = grid.getDomainIterator();
156  while(it.isNext()) {
157  auto key = it.get();
158 
159  for (int d = 0; d < grid.dims; ++d)
160  coord[d] = grid.getPos(key)[d];
161 
162  arg = (coord[x]-center[x]) * (coord[x]-center[x]) + (coord[y]-center[y]) * (coord[y]-center[y]);
163  theta = std::atan2(std::sqrt(arg),(coord[z]-center[z]));
164  cos2 = std::cos(theta)*std::cos(theta);
165 
166  grid.template get<sol>(key) = -20.0 * prefactor * (cos2*(35.0*cos2 - 30.0) + 3.0);
167  ++it;
168  }
169 }
170 
171 // 5) Functions to get the points on a NB around the surface (from jstark - Sussman code)
172 bool within_narrow_band(double phi,
173  double b_low,
174  double b_up) {
175  return (phi >= b_low && phi <= b_up);
176 }
177 
178 template<typename grid_type, size_t prop, typename key_type>
179 void get_NB_indices(grid_type & grid,
180  double thickness, // NOT grid points
181  std::vector<key_type> & nb_keys) {
182 
183  double b_low = -thickness/2.0;
184  double b_up = thickness/2.0;
185 
186  auto it{grid.getDomainIterator()};
187  while (it.isNext()) {
188 
189  auto key{it.get()};
190  if (within_narrow_band(grid.template get<prop>(key),b_low,b_up))
191  nb_keys.push_back(key);
192  ++it;
193  }
194 }
195 
196 // 6) Functions to compute the L2 and Linf norms (from jstark)
197 struct L_norms {
198  double l2;
199  double linf;
200 };
201 
202 template<typename grid_type, int PropNumeric, int PropAnalytic, int Error, typename key_type>
204  std::vector<key_type> & nb_keys) {
205  for (int i = 0; i < nb_keys.size(); ++i)
206  grid.template getProp<Error>(nb_keys[i]) = std::fabs(grid.template getProp<PropAnalytic>(nb_keys[i]) - (grid.template getProp<PropNumeric>(nb_keys[i])));
207 }
208 
209 template<typename grid_type, int error, typename key_type>
210 L_norms get_l_norms_NB(grid_type & grid,
211  std::vector<key_type> & nb_keys) {
212 
213  double maxError{0};
214  double sumErrorSq{0};
215  size_t num_nb{nb_keys.size()};
216 
217  for (int i = 0; i < nb_keys.size(); ++i) {
218 
219  sumErrorSq += grid.template getProp<error>(nb_keys[i]) * grid.template getProp<error>(nb_keys[i]);
220  if (grid.template getProp<error>(nb_keys[i]) > maxError)
221  maxError = grid.template getProp<error>(nb_keys[i]); // update maxError
222  }
223 
224  // Communicate between processes
225  auto &v_cl = create_vcluster();
226  v_cl.sum(num_nb);
227  v_cl.sum(sumErrorSq);
228  v_cl.max(maxError);
229  v_cl.execute();
230 
231  double l2{std::sqrt(sumErrorSq / (double)num_nb)};
232  // std::cout << "sum of num_nb: " << (double)num_nb << "\n";
233  double linf{maxError};
234  return {l2, linf};
235 }
236 
237 template<typename T>
238 void write_lnorms_to_file(T N, L_norms l_norms, std::string filename, std::string path_output) {
239  auto &v_cl = create_vcluster();
240  if (v_cl.rank() == 0) {
241  std::string path_output_lnorm{path_output + "/" + filename + ".csv"};
242  create_file_if_not_exist(path_output_lnorm);
243 
244  std::ofstream l_out;
245  l_out.open(path_output_lnorm, std::ios::app); // append instead of overwrite
246  l_out << N << ',' << std::setprecision(6) << std::scientific << l_norms.l2 << ',' << l_norms.linf
247  << std::endl;
248  l_out.close();
249  }
250 }
251 
252 // Function to set particle property to zero
253 template<typename vector_type, int prop>
254 void set_prop2zero(vector_type & vec) {
255  auto it = vec.getDomainIterator();
256 
257  while (it.isNext()) {
258  auto key = it.get();
259  vec.template getProp<prop>(key) = 0.0;
260  ++it;
261  }
262 }
263 
264 
265 // 7) Function to initialize the projection matrix of the surface
266 // template<typename grid_type, int normal, int projMat_prop>
267 // void init_projMat(grid_type & grid) {
268 
269 // double ni, nj;
270 // auto it{grid.getDomainIterator()};
271 // while (it.isNext()) {
272 // auto key{it.get()};
273 // for (int i = 0; i < DIM; ++i) {
274 // ni = grid.template get<normal>(key)[i];
275 // for (int j = 0; j < DIM; ++j) {
276 // nj = grid.template get<normal>(key)[j];
277 // grid.template get<projMat_prop>(key)[i][j] = (i==j)*(1-ni*nj) - !(i==j)*(ni*nj);
278 // }
279 // }
280 // ++it;
281 // }
282 // }
283 
284 
285 // 8) Function to compute the surface gradient of a quantity
286 // template<typename grid_type, int QTY, int GRAD, int SURFGRAD, int PROJMAT, typename DX, typename DY, typename DZ, typename key_type>
287 // void SGrad(grid_type & grid,
288 // DX & Dx,
289 // DY & Dy,
290 // DZ & Dz) {
291 
292 // auto qty{FD::getV<QTY>(grid)};
293 // auto grad_qty{FD::getV<GRAD>(grid)};
294 
295 // grid.template ghost_get<QTY,GRAD,PROJMAT>();
296 
297 // grad_qty[0] = Dx(qty);
298 // grad_qty[1] = Dy(qty);
299 // grad_qty[2] = Dz(qty);
300 
301 // // Projection
302 // auto it{grid.getDomainIterator()};
303 // while (it.isNext()) {
304 
305 // auto key{it.get()};
306 
307 // for (int l = 0; l < DIM; ++l)
308 // for (int k = 0; k < DIM; ++k)
309 // for (int t = 0; t < DIM; ++t)
310 // for (int h = 0; h < DIM; ++h)
311 // grid.template get<SURFGRAD>(key)[l][k] += grid.template get<PROJMAT>(key)[l][t] * grid.template get<PROJMAT>(key)[k][h] * grid.template get<EUCGRAD>(key)[t][h];
312 // ++it;
313 // }
314 
315 // }
void get_absolute_error(gridtype &grid)
At each grid node, the absolute error is computed and stored in another property.
Definition: LNorms.hpp:43
static void create_file_if_not_exist(std::string path)
Creates a file if not already existent.
This is a distributed grid.
static const unsigned int dims
Number of dimensions.
vect_dist_key_dx get()
Get the actual key.
Distributed vector.
vector_dist_iterator getDomainIterator() const
Get an iterator that traverse the particles in the domain.