CoMMA 1.3.2
A geometric agglomerator for unstructured meshes
Loading...
Searching...
No Matches
Util.h
Go to the documentation of this file.
1#ifndef COMMA_PROJECT_UTIL_H
2#define COMMA_PROJECT_UTIL_H
3
4/*
5 * CoMMA
6 *
7 * Copyright © 2024 ONERA
8 *
9 * Authors: Nicolas Lantos, Alberto Remigi, and Riccardo Milani
10 * Contributors: Karim Anemiche
11 *
12 * This Source Code Form is subject to the terms of the Mozilla Public
13 * License, v. 2.0. If a copy of the MPL was not distributed with this
14 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
15 */
16
17#include <algorithm>
18#include <cassert>
19#include <cmath>
20#include <functional>
21#include <iterator>
22#include <map>
23#include <numeric>
24#include <queue>
25#include <set>
26#include <unordered_map>
27#include <unordered_set>
28#include <utility>
29#include <vector>
30
31#include "CoMMA/Args.h"
32
33namespace comma {
34
38#define CoMMAUnused(var) (void)(var)
39
43constexpr double deviate_thresh = 0.9396926207859084;
44
50template<typename T>
51inline T constexpr _sq(const T x) {
52 return x * x;
53}
54
60template<typename T>
61inline T constexpr _cb(const T x) {
62 return x * x * x;
63}
64
71template<unsigned int p, typename T>
72inline T constexpr int_power(const T x) {
73 // See https://stackoverflow.com/a/1505791/12152457
74 if constexpr (p == 0) return 1;
75 if constexpr (p == 1) return x;
76 if constexpr (p == 2) return x * x;
77 if constexpr (p == 3) return x * x * x;
78
79 constexpr int tmp = int_power<p / 2>(x);
80 if constexpr ((p % 2) == 0) {
81 return tmp * tmp;
82 } else {
83 return x * tmp * tmp;
84 }
85}
86
93template<typename T>
94inline bool constexpr dot_deviate(const T dot) {
95 return fabs(dot) < decltype(fabs(dot)){deviate_thresh};
96}
97
105template<typename T>
106inline T dot_product(const std::vector<T> &a, const std::vector<T> &b) {
107#if 0
108 const CoMMAWeightType dot = inner_product(
109 prev_dir.begin(), prev_dir.end(), cur_dir.begin(),
110 CoMMAWeightType{0.});
111#endif
112 T dot{0.};
113 for (auto i = decltype(a.size()){0}; i < a.size(); ++i)
114 dot += a[i] * b[i];
115 return dot;
116}
117
127template<typename T>
129 const std::vector<T> &a, const std::vector<T> &b, std::vector<T> &dir
130) {
131 T norm{0.};
132 for (auto i = decltype(a.size()){0}; i < a.size(); ++i) {
133 const T di = b[i] - a[i];
134 dir[i] = di;
135 norm += di * di;
136 }
137 norm = sqrt(norm);
138 const T ov_norm = T{1.} / norm;
139 for (auto &di : dir)
140 di *= ov_norm;
141 return norm;
142}
143
154template<typename T>
156 const std::vector<T> &a, const std::vector<T> &b
157) {
158#if 0
159 return
160 transform_reduce(a.cbegin(), a.cend(), b.cbegin(), T{0.},
161 [](const auto sum, const auto val){return sum + val*val;},
162 minus<T>());
163#endif
164 T dist{0.};
165 for (auto i = decltype(a.size()){0}; i < a.size(); ++i) {
166 const auto diff = a[i] - b[i];
167 dist += diff * diff;
168 }
169 return dist;
170}
171
177template<class PairT>
187 inline bool operator()(const PairT &left, const PairT &right) const {
188 if (left.second < right.second) return true;
189 if (left.second > right.second) return false;
190 /* left.second == right.second */
191 return left.first > right.first;
192 }
193};
194
200template<typename PairT>
210 inline bool operator()(const PairT &left, const PairT &right) const {
211 // I tried this: return !CustomPairLessFunctor<PairT>()(left,right);
212 // but it didn't work well for equality
213 if (left.second > right.second) return true;
214 if (left.second < right.second) return false;
215 /* left.second == right.second */
216 return left.first < right.first;
217 }
218};
219
224template<typename PairT>
232 inline bool operator()(const PairT &left, const PairT &right) const {
233 return left.second < right.second;
234 }
235};
236
243template<typename CoMMAContainerPairType>
244inline std::vector<typename CoMMAContainerPairType::value_type::first_type>
245vector_of_first_elements(const CoMMAContainerPairType &cont) {
246 std::vector<typename CoMMAContainerPairType::value_type::first_type> fe;
247 fe.reserve(cont.size());
248 for (const auto &pr : cont)
249 fe.emplace_back(pr.first);
250 return fe;
251}
252
257template<typename PairT>
259public:
262 _target(){};
266 // NOLINTNEXTLINE
267 PairFindFirstBasedFunctor(const typename PairT::first_type &target) :
268 _target(target){};
271
277 inline bool operator()(const PairT &pr) const { return pr.first == _target; }
278
279private:
281 typename PairT::first_type _target;
282};
283
290template<typename KeyT, typename ValueT>
291inline std::unordered_set<KeyT> d_keys_to_set(
292 const std::unordered_map<KeyT, ValueT> &dict
293) {
294 std::unordered_set<KeyT> s_neighbours_of_seed = {};
295 for (const auto &i_k_v : dict) {
296 s_neighbours_of_seed.insert(i_k_v.first);
297 }
298 return s_neighbours_of_seed;
299}
300
310template<typename IndexT, typename IntT>
312 const std::vector<IndexT> &indices,
313 const std::vector<IntT> &n_bnd_faces,
314 const std::unordered_set<IntT> &allowed,
315 std::vector<IndexT> &filtered
316) {
317 filtered.clear();
318 auto target = decltype(allowed){};
319 std::copy_if(
320 allowed.begin(),
321 allowed.end(),
322 std::inserter(target, target.begin()),
323 [](const auto n) { return n > 0; }
324 );
325 if (!target.empty()) {
326 const auto n_cells = static_cast<IndexT>(n_bnd_faces.size());
327 filtered.reserve(n_cells);
328 for (auto c = decltype(n_cells){0}; c < n_cells; ++c) {
329 if (allowed.find(
330 static_cast<IntT>(indices[c + 1] - indices[c] + n_bnd_faces[c])
331 )
332 != allowed.end())
333 filtered.emplace_back(c);
334 }
335 filtered.shrink_to_fit();
336 }
337}
338
360template<typename IndexT, typename DistT>
362 const std::vector<IndexT> &neigh_idxs,
363 const std::vector<IndexT> &neighs,
364 const std::vector<IndexT> &wall,
365 std::vector<DistT> &dist
366) {
367 static_assert(
368 std::is_signed<DistT>::value,
369 "The distance type should be signed to allow flags (negative values)"
370 );
371 dist.resize(neigh_idxs.size() - 1);
372 std::fill(dist.begin(), dist.end(), DistT{-1});
373 std::queue<IndexT> to_visit{};
374 for (const auto &cell : wall) {
375 dist[cell] = DistT{0};
376 to_visit.emplace(cell);
377 }
378 while (!to_visit.empty()) {
379 // If you get wrong results, this could might be to the fact that one should
380 // consider not specially the first of the queue, but the one with lowest
381 // distance visited so far. So, the definition of `cur` below should be
382 // changed, and with that, another container should be used instead of a
383 // queue, since one might pop from whenever and not only the front (a deque
384 // should work).
385 const auto cur = to_visit.front();
386 to_visit.pop();
387 const auto cur_dist = dist[cur] + DistT{1};
388 for (auto neigh = neighs.cbegin() + neigh_idxs[cur];
389 neigh < neighs.cbegin() + neigh_idxs[cur + 1];
390 ++neigh) {
391 if (dist[*neigh] < DistT{0}) {
392 dist[*neigh] = cur_dist;
393 to_visit.emplace(*neigh);
394 } else if (dist[*neigh] > cur_dist) {
395 dist[*neigh] = cur_dist;
396 }
397 }
398 }
399}
400
423template<typename IndexT, typename RealT, typename IntT>
425 const std::vector<IndexT> &f2c,
426 const std::vector<IndexT> &f_adj_idx,
427 const std::vector<IndexT> &f_adj,
428 const std::vector<RealT> &f_weights,
429 const std::vector<RealT> &f_volumes,
430 const std::vector<std::vector<RealT>> &f_centers,
431 const std::vector<RealT> &f_priority,
432 const std::vector<IntT> &f_n_bnd,
433 // output
434 std::vector<IndexT> &c_adj_idx,
435 std::vector<IndexT> &c_adj,
436 std::vector<RealT> &c_weights,
437 std::vector<RealT> &c_volumes,
438 std::vector<std::vector<RealT>> &c_centers,
439 std::vector<RealT> &c_priority,
440 std::vector<IntT> &c_n_bnd
441) {
442 const auto n_cells = *(std::max_element(f2c.begin(), f2c.end())) + 1;
443 const auto dim = static_cast<IntT>(f_centers[0].size());
444 // Preparing outputs
445 c_adj_idx.clear();
446 c_adj_idx.emplace_back(0);
447 c_adj.clear();
448 c_weights.clear();
449 // For these, we have the final size
450 c_volumes.clear();
451 c_volumes.resize(n_cells);
452 std::fill(c_volumes.begin(), c_volumes.end(), RealT{0});
453 c_n_bnd.clear();
454 c_n_bnd.resize(n_cells);
455 c_priority.clear();
456 c_priority.resize(n_cells);
457 std::fill(c_n_bnd.begin(), c_n_bnd.end(), IntT{0});
458 c_centers.clear();
459 c_centers.reserve(n_cells);
460 for (auto cc = decltype(n_cells){0}; cc < n_cells; ++cc) {
461 // https://stackoverflow.com/questions/18189362/how-best-to-fill-a-vector-of-vectors-avoiding-wasting-memory-and-unnecessary-al
462 auto tmp = std::vector<RealT>(dim, RealT{0});
463 c_centers.emplace_back(std::move(tmp));
464 } // for cc
465 // Now building
466 // For each coarse cell, find its fine cells
467 std::vector<std::set<IndexT>> c2f(n_cells);
468 for (auto fc = decltype(f2c.size()){0}; fc < f2c.size(); ++fc) {
469 const auto cc = f2c[fc];
470 // Adding FC to CC
471 c2f[cc].emplace(fc);
472 // Adding volume
473 c_volumes[cc] += f_volumes[fc];
474 // Updating center - Weighted average
475 for (auto xyz = decltype(dim){0}; xyz < dim; ++xyz)
476 c_centers[cc][xyz] += f_volumes[fc] * f_centers[fc][xyz];
477 } // for fc
478 for (auto cc = decltype(n_cells){0}; cc < n_cells; ++cc) {
479 const auto &fcs = c2f[cc];
480 const RealT ov_n_fc(RealT{1.} / fcs.size());
481 // Finishing center
482 for (auto xyz = decltype(dim){0}; xyz < dim; ++xyz)
483 c_centers[cc][xyz] *= ov_n_fc;
484 auto n_bnd = std::numeric_limits<IntT>::min();
485 auto priority = std::numeric_limits<RealT>::min();
486 std::map<IndexT, RealT> cc_neighs;
487 for (const auto fc : fcs) {
488 if (f_n_bnd[fc] > n_bnd) n_bnd = f_n_bnd[fc];
489 if (f_priority[fc] > priority) priority = f_priority[fc];
490 for (auto fc_neigh = f_adj.cbegin() + f_adj_idx[fc];
491 fc_neigh != f_adj.cbegin() + f_adj_idx[fc + 1];
492 ++fc_neigh) {
493 // Update if not one of the FC of the CC
494 if (fcs.find(*fc_neigh) == fcs.end()) {
495 const auto cc_neigh = f2c[*fc_neigh];
496 // Add if not yet present
497 cc_neighs.try_emplace(cc_neigh, 0.0);
498 cc_neighs.at(cc_neigh) += f_weights[*fc_neigh];
499 }
500 } // for fc_neigh
501 } // for fc
502 // Max of f_bnd
503 c_n_bnd[cc] = n_bnd;
504 c_priority[cc] = priority;
505 c_adj_idx.emplace_back(c_adj_idx.back() + cc_neighs.size());
506 for (const auto &[neigh, weight] : cc_neighs) {
507 c_adj.emplace_back(neigh);
508 c_weights.emplace_back(weight);
509 }
510 } // for cc
511}
512
513} // end namespace comma
514
515#endif // COMMA_PROJECT_UTIL_H
Functor implementing an operator telling if a given value if the first one of pair.
Definition: Util.h:258
bool operator()(const PairT &pr) const
Operator telling if the first value of the given pair is equal to the reference one.
Definition: Util.h:277
~PairFindFirstBasedFunctor()=default
Destructor.
PairFindFirstBasedFunctor()
Constructor.
Definition: Util.h:261
PairFindFirstBasedFunctor(const typename PairT::first_type &target)
Constructor.
Definition: Util.h:267
Definition: Agglomerator.h:37
void build_coarse_graph(const std::vector< IndexT > &f2c, const std::vector< IndexT > &f_adj_idx, const std::vector< IndexT > &f_adj, const std::vector< RealT > &f_weights, const std::vector< RealT > &f_volumes, const std::vector< std::vector< RealT > > &f_centers, const std::vector< RealT > &f_priority, const std::vector< IntT > &f_n_bnd, std::vector< IndexT > &c_adj_idx, std::vector< IndexT > &c_adj, std::vector< RealT > &c_weights, std::vector< RealT > &c_volumes, std::vector< std::vector< RealT > > &c_centers, std::vector< RealT > &c_priority, std::vector< IntT > &c_n_bnd)
Build a coarse graph from the fine graph and the result of a previous agglomeration.
Definition: Util.h:424
T constexpr _cb(const T x)
Cube.
Definition: Util.h:61
T dot_product(const std::vector< T > &a, const std::vector< T > &b)
Compute the dot product between two vectors. No check on size is performed.
Definition: Util.h:106
T squared_euclidean_distance(const std::vector< T > &a, const std::vector< T > &b)
Compute the squared Euclidean distance between two points seen as vectors. We use vectors because we ...
Definition: Util.h:155
bool constexpr dot_deviate(const T dot)
Tell whether the dot product given as input comes from two parallel vectors. Compared against deviate...
Definition: Util.h:94
T get_direction(const std::vector< T > &a, const std::vector< T > &b, std::vector< T > &dir)
Compute the direction from point a to point b and store it as unit vector in dir.
Definition: Util.h:128
T constexpr _sq(const T x)
Square.
Definition: Util.h:51
void filter_cells_by_n_edges(const std::vector< IndexT > &indices, const std::vector< IntT > &n_bnd_faces, const std::unordered_set< IntT > &allowed, std::vector< IndexT > &filtered)
Given the connectivity of the graph, filter cells keeping only those with the desired number of edges...
Definition: Util.h:311
constexpr double deviate_thresh
Threshold used in combination with a dot product to tell whether two vector deviate....
Definition: Util.h:43
std::unordered_set< KeyT > d_keys_to_set(const std::unordered_map< KeyT, ValueT > &dict)
Utility function for creating a set out of the keys of a map.
Definition: Util.h:291
std::vector< typename CoMMAContainerPairType::value_type::first_type > vector_of_first_elements(const CoMMAContainerPairType &cont)
Given a container of pairs, return a vector with first elements only.
Definition: Util.h:245
T constexpr int_power(const T x)
Raise a quantity to an integer power.
Definition: Util.h:72
void compute_neighbourhood_based_wall_distance(const std::vector< IndexT > &neigh_idxs, const std::vector< IndexT > &neighs, const std::vector< IndexT > &wall, std::vector< DistT > &dist)
Compute a neighbourhood-base wall-distance, that is, the distance of a given cell from a wall is the ...
Definition: Util.h:361
Functor for pairs implementing a custom 'greater than'. It relies on the 'greater than' operator for ...
Definition: Util.h:201
bool operator()(const PairT &left, const PairT &right) const
Functor for pairs implementing a custom 'greater than'. It relies on the 'greater than' operator for ...
Definition: Util.h:210
Functor for pairs implementing a custom 'less than'. It relies on the 'less than' operator for the se...
Definition: Util.h:178
bool operator()(const PairT &left, const PairT &right) const
Functor for pairs implementing a custom 'less than'. It relies on the 'less than' operator for the se...
Definition: Util.h:187
Functor for pairs implementing a less operator based only on the second element of the pair.
Definition: Util.h:225
bool operator()(const PairT &left, const PairT &right) const
Functor for pairs implementing a less operator based only on the second element of the pair.
Definition: Util.h:232