1 #ifndef MEDUSA_BITS_DOMAINS_DOMAINDISCRETIZATION_HPP_
2 #define MEDUSA_BITS_DOMAINS_DOMAINDISCRETIZATION_HPP_
20 template <
class vec_t>
24 for (
int i = 0; i < N; ++i) {
25 sizes[i] = supportSize(i);
30 template <
class vec_t>
32 assert_msg(0 <= i && i <= size(),
"Index %d out of range [0, %d)", i, size());
33 assert_msg(types_[i] < 0,
"Node %d must be a boundary node, got type %d.", i, types_[i]);
34 assert_msg(boundary_map_[i] != -1,
"Node %d does not have a normal. Maybe you manually set"
35 " supports and positions instead of using addInternalNode* methods?", i);
36 return normals_[boundary_map_[i]];
39 template <
class vec_t>
41 assert_msg(0 <= i && i <= size(),
"Index %d out of range [0, %d)", i, size());
42 assert_msg(types_[i] < 0,
"Node %d must be a boundary node, got type %d.", i, types_[i]);
43 assert_msg(boundary_map_[i] != -1,
"Node %d does not have a normal. Maybe you manually set"
44 " supports and positions instead of using addInternalNode* methods?", i);
45 return normals_[boundary_map_[i]];
48 template <
class vec_t>
50 assert_msg(type > 0,
"This function is for adding internal points, but got type %d, which is "
51 "not positive. Use addBoundaryNode to add boundary nodes.", type);
52 return addNode(point, type);
55 template <
class vec_t>
57 const vec_t& point,
int type,
const vec_t& normal) {
58 assert_msg(type < 0,
"Type of boundary points must be negative, got %d.", type);
59 int idx = addNode(point, type);
60 boundary_map_[idx] = normals_.size();
61 normals_.push_back(normal);
65 template <
class vec_t>
67 positions_.push_back(point);
68 types_.push_back(type);
69 support_.emplace_back();
70 boundary_map_.push_back(-1);
71 return positions_.size()-1;
74 template <
class vec_t>
76 const vec_t& normal) {
77 assert_msg(0 <= i && i < size(),
"Index %d out of range [0, %d).", i, size());
78 assert_msg(types_[i] >= 0,
"Point %d is already a boundary point with type %d.", i,
80 assert_msg(type < 0,
"New type must be negative, got %d.", type);
81 positions_[i] = point;
83 boundary_map_[i] = normals_.size();
84 normals_.push_back(normal);
87 template <
class vec_t>
89 assert_msg(0 <= i && i < size(),
"Index %d out of range [0, %d).", i, size());
90 assert_msg(types_[i] <= 0,
"Point %d is already an interior point with type %d.", i, types_[i]);
91 assert_msg(type > 0,
"New type must be positive, got %d.", type);
92 positions_[i] = point;
94 normals_.remove({boundary_map_[i]});
95 for (
int idx = 0; idx < boundary_map_.size(); ++idx) {
96 if (boundary_map_[idx] != -1 && boundary_map_[idx] > boundary_map_[i]) {
97 boundary_map_[idx] -= 1;
100 boundary_map_[i] = -1;
103 template <
class vec_t>
106 for (
int i = 0; i < d.
size(); ++i) {
108 indexes[i] = addBoundaryNode(d.
pos(i), d.
type(i), d.
normal(i));
110 indexes[i] = addInternalNode(d.
pos(i), d.
type(i));
116 template <
class vec_t>
120 remove_mask[to_remove] =
true;
122 for (
int i = 0; i < n; ++i) {
123 if (boundary_map_[i] >= 0 && remove_mask[i]) {
124 remove_normals.push_back(boundary_map_[i]);
125 }
else if (boundary_map_[i] >= 0) {
126 boundary_map_[i] -= remove_normals.
size();
129 normals_.remove(remove_normals);
130 boundary_map_.remove(to_remove);
131 types_.remove(to_remove);
132 positions_.remove(to_remove);
133 if (support_.size() == n) support_.remove(to_remove);
136 template <
class vec_t>
138 return addGhostNodes([=](
const vec_t&) {
return h; }, type);
141 template <
class vec_t>
144 return addGhostNodes([=](
const vec_t&) {
return h; }, type, indexes);
147 template <
class vec_t>
148 template <
typename func_t>
150 return addGhostNodes(h, type, boundary());
153 template <
class vec_t>
154 template <
typename func_t>
158 assert_msg(0 <= i && i < size(),
"Index %d out of range [0, %d)", i, size());
159 assert_msg(types_[i] < 0,
"Only boundary nodes can have associated ghost nodes, "
160 "node %d has type %d.", i, types_[i]);
162 if (type > 0) gh[i] = addInternalNode(pos(i) + ch*normal(i), type);
163 else if (type < 0) gh[i] = addBoundaryNode(pos(i) + ch*normal(i), type, normal(i));
164 else if (type == 0) gh[i] = addNode(pos(i) + ch*normal(i), type);
169 template <
class vec_t>
175 boundary_map_.clear();
178 template <
class vec_t>
181 assert_msg(N == types_.size(),
"Number of node type entries (%d) not equal to domain size "
182 "(%d).", types_.size(), N);
183 assert_msg(N == boundary_map_.size(),
"Number of boundary map entries (%d) not equal to domain"
184 " size (%d).", types_.size(), N);
185 assert_msg(N == support_.size(),
"Number of node supports (%d) not equal to domain size "
186 "(%d).", types_.size(), N);
187 assert_msg(N == positions_.size(),
"Number of node positions (%d) not equal to domain size "
188 "(%d).", types_.size(), N);
190 for (
int i = 0; i < N; ++i) {
192 assert_msg(0 <= boundary_map_[i] && boundary_map_[i] < normals_.size(),
193 "Boundary map index %d of node %d must lie in interval [0, %d).",
194 boundary_map_[i], i, normals_.size());
196 }
else if (types_[i] > 0) {
197 assert_msg(boundary_map_[i] == -1,
"Expected boundary map of internal node %d "
198 "to be -1, got %d.", i, boundary_map_[i]);
200 assert_msg(shape_->contains(pos(i)),
"Position %s at index %d is not contained "
201 "in the domain.", pos(i), i);
203 assert_msg(num_bnd == normals_.size(),
"Number of boundary nodes not the same as number "
204 "of normals, got %d nodes with negative type, but %d normals.",
205 num_bnd, normals_.size());
208 template <
class vec_t>
210 int internal_count = (types_ > 0).size();
211 int boundary_count = (types_ < 0).size();
212 std::size_t mem =
sizeof(*this);
213 std::size_t mem_pos =
mem_used(positions_);
214 std::size_t mem_types =
mem_used(types_);
215 std::size_t mem_supp =
mem_used(support_);
216 int max_support_size = -1;
217 for (
int i = 0; i < support_.size(); ++i) {
218 max_support_size = std::max(max_support_size, support_[i].size());
221 std::size_t mem_bnd_map =
mem_used(boundary_map_);
222 std::size_t mem_normals =
mem_used(normals_);
223 std::size_t mem_total = mem + mem_pos + mem_types + mem_supp + mem_bnd_map + mem_normals;
224 os <<
" dimension: " <<
dim <<
'\n'
225 <<
" shape: " << *shape_ <<
'\n'
226 <<
" number of points: " << size() <<
" of which " << internal_count
227 <<
" internal and " << boundary_count <<
" boundary\n"
228 <<
" max support size: ";
229 if (max_support_size == -1) os <<
"support not found yet";
230 else os << max_support_size;
231 os <<
"\n mem used total: " <<
mem2str(mem_total) <<
'\n'
232 <<
" pos & types: " <<
mem2str(mem_pos + mem_types) <<
'\n'
233 <<
" supp: " <<
mem2str(mem_supp) <<
'\n'
234 <<
" bnd & normals: " <<
mem2str(mem_bnd_map + mem_normals) <<
'\n';
238 template <
class vec_t>
242 template <
class vec_t>
248 const bool tree_ok = relevant.
size() >= 2;
252 for (
int i = 0; i < size(); ++i) {
253 if (d.
shape().contains(pos(i))) {
254 to_remove.push_back(i);
259 auto r = tree.
query(pos(i));
260 int idx = r.first[0];
263 not_ok = dist < 0.75*dx;
266 to_remove.push_back(i);
269 removeNodes(std::move(to_remove));
272 template <
class vec_t>
280 for (
int i = 0; i < d.
size(); ++i) {
281 if (d.
type(i) > 0 || !shape().contains(d.
pos(i))) {
286 for (
int i : to_add) {
290 addInternalNode(d.
pos(i), d.
type(i));
293 shape_ = shape() + d.
shape();
297 template <
class vec_t>
301 for (
int i = 0; i < d.
size(); ++i) {
302 if (d.
type(i) < 0 && shape().contains(d.
pos(i))) {
307 for (
int i : to_add) {
310 shape_ = shape() - d.
shape();
314 template <
class vec_t>
316 assert_msg((shape_->hasContains()),
"Domain shape does not have a `contains` method, "
317 "try using `discreteContains`.");
318 return shape_->contains(point);
321 template <
class vec_t>
322 template <
typename search_structure_t>
324 const vec_t& point,
const search_structure_t& search)
const {
325 assert_msg((search.size() != 0),
"Search structure should not be empty.");
326 int closest_index = search.query(point, 1).first[0];
327 auto closest_point = search.get(closest_index);
328 auto n = normals_[closest_index];
330 return n.dot(point - closest_point) < 0;
333 template <
class vec_t>
334 template <
typename search_structure_t>
336 if (shape_->hasContains())
return shape_->contains(p);
337 else return discreteContains(p, search);
340 template <
class vec_t>
341 template <
typename search_structure_t>
343 int size = boundary().size();
345 for (
int i = 0; i < boundary_map_.size(); i++) {
346 if (boundary_map_[i] == -1)
continue;
347 boundary_points[boundary_map_[i]] = positions_[i];
349 search.reset(boundary_points);
352 template <
class vec_t>
353 template <
typename hdf5_file>
355 const std::string& name) {
356 file.openGroup(name);
357 auto pos = file.readDouble2DArray(
"pos");
364 for (
int i = 0; i < n; ++i) {
365 assert_msg(pos[i].size() ==
dim,
"Node %d has invalid number of coordinates: %s, "
366 "expected %d.", i, pos[i].size(),
dim);
367 for (
int j = 0; j <
dim; ++j) {
369 if (pos[i][j] <= low[j]) low[j] = pos[i][j];
370 if (pos[i][j] >= high[j]) high[j] = pos[i][j];
373 domain.
types_ = file.readIntArray(
"types");
374 int bnd_count = (domain.
types_ < 0).size();
377 "Number of nodes with boundary index (%d) in bmap is not the same as number "
378 "of nodes with negative type (%d).",
380 auto normals = file.readDouble2DArray(
"normals");
381 assert_msg(
static_cast<int>(normals.size()) == bnd_count,
382 "Number of normals (%d) must be equal to number of boundary nodes (%d).",
383 normals.size(), bnd_count);
384 domain.
normals_.resize(normals.size());
385 for (
int i = 0; i < bnd_count; ++i) {
386 assert_msg(normals[i].size() ==
dim,
"Normal %d has invalid number of coordinates: %s, "
387 "expected %d.", i, normals[i].size(),
dim);
388 for (
int j = 0; j <
dim; ++j) {
389 domain.
normals_[i][j] = normals[i][j];
393 for (
int i = 0; i < n; ++i) {
394 if (domain.
types_[i] < 0) {
396 "Normals list and boundary map inconsistent. Node %d with type %d "
397 "has boundary index %d, but the list of normals is only %d long.",
401 "Boundary map assigned a normal to an internal node %d with type %d, "
402 "bmap[%d] = %d, but should be -1.",
410 template <
class vec_t>
413 for (
int i = 0; i < size(); ++i) {
419 template <
class vec_t>
421 const Eigen::Matrix<scalar_t, dim, dim>& Q) {
423 for (
int i = 0; i < size(); ++i) {
424 positions_[i] = Q*positions_[i];
425 if (boundary_map_[i] != -1) normals_[boundary_map_[i]] = Q*normals_[boundary_map_[i]];
430 template <
class vec_t>
432 assert_msg(
dim == 2,
"Angle rotation only available in 2D.");
435 Eigen::Matrix<double, dim, dim> Q; Q << c, -s, s, c;
439 template <
class vec_t>
440 template <
typename compare_t>
443 std::vector<std::pair<vec_t, int>> nodes(N);
444 for (
int i = 0; i < N; ++i) nodes[i] = {pos(i), i};
445 std::sort(nodes.begin(), nodes.end(), cmp);
447 for (
int i = 0; i < N; ++i) permutation[i] = nodes[i].second;
448 shuffleNodes(permutation);
452 template <
class vec_t>
455 assert_msg(
static_cast<int>(permutation.size()) == N,
456 "Permutation size %d must be equal to domain size %d.", permutation.size(), N);
458 for (
int i = 0; i < N; ++i) {
459 assert_msg(0 <= permutation[i] && permutation[i] < N,
"Invalid index %d in permutation.",
461 assert_msg(pinv[permutation[i]] == -1,
"Duplicate index %d in permutation.",
463 pinv[permutation[i]] = i;
465 for (
int i = 0; i < N; ++i) {
466 for (
int j = 0; j < supportSize(i); ++j) {
467 support_[i][j] = pinv[support_[i][j]];
470 positions_ = positions_[permutation].asRange();
471 types_ = types_[permutation].asRange();
472 boundary_map_ = boundary_map_[permutation].asRange();
473 support_ = support_[permutation].asRange();
478 #endif // MEDUSA_BITS_DOMAINS_DOMAINDISCRETIZATION_HPP_