omega_h
Reliable mesh adaptation
Omega_h_fit.hpp
1 #ifndef FIT_HPP
2 #define FIT_HPP
3 
4 /* This code is used to fit a linear polynomial to
5  * element-wise sample points in a cavity.
6  *
7  * We do this by solving a least-squares problem using
8  * a QR decomposition.
9  *
10  * MaxFitPoints denotes the maximum number of adjacent
11  * sample points that will be accepted into the fitting
12  * process.
13  * These limits were chosen to be approximately twice the
14  * number of elements adjacent to a vertex.
15  */
16 
17 #include "Omega_h_adj.hpp"
18 #include "Omega_h_qr.hpp"
19 #include "Omega_h_simplex.hpp"
20 
21 namespace Omega_h {
22 
23 template <Int dim>
24 struct MaxFitPoints {
25  enum { value = SimplexAvgDegree<dim, 0, dim>::value * 3 };
26 };
27 
28 /* Computes the QR decomposition for the Vandermonde
29  * matrix involved in the least-squares fit.
30  * This depends only on the centroids of the adjacent
31  * elements, nothing else.
32  */
33 
34 template <Int dim>
35 OMEGA_H_DEVICE QRFactorization<MaxFitPoints<dim>::value, dim + 1>
36 get_cavity_qr_factorization(LO k, LOs const& k2ke, LOs const& ke2e,
37  LOs const& ev2v, Reals const& coords) {
38  constexpr auto max_fit_pts = MaxFitPoints<dim>::value;
39  Matrix<max_fit_pts, dim + 1> vandermonde;
40  auto begin = k2ke[k];
41  auto end = k2ke[k + 1];
42  auto nfit_pts = end - begin;
43  OMEGA_H_CHECK(nfit_pts >= dim + 1);
44  OMEGA_H_CHECK(nfit_pts <= max_fit_pts);
45  for (auto i = 0; i < nfit_pts; ++i) {
46  auto ke = begin + i;
47  auto e = ke2e[ke];
48  auto eev2v = gather_verts<dim + 1>(ev2v, e);
49  auto eev2x = gather_vectors<dim + 1, dim>(coords, eev2v);
50  auto centroid = average(eev2x);
51  vandermonde[0][i] = 1.0;
52  for (Int j = 0; j < dim; ++j) {
53  vandermonde[1 + j][i] = centroid[j];
54  }
55  }
56  auto qr = factorize_qr_householder(nfit_pts, dim + 1, vandermonde);
57 // workaround CUDA compiler bug that makes these NaN
58 // if and only if we do not check whether they are NaN...
59 #ifdef __CUDA_ARCH__
60  for (int k = 0; k < dim + 1; ++k) {
61  for (int i = k; i < nfit_pts; ++i) {
62  assert(!isnan(qr.v[k][i]));
63  }
64  }
65 #endif
66  return qr;
67 }
68 
69 /* Computes the linear polynomial coefficients
70  * to approximat the distribution of one scalar
71  * value over the cavity.
72  * Typically this scalar is one of several stored
73  * contiguously, hence the "ncomps" and "comp" arguments.
74  * "e_data" contains the scalar data for all elements.
75  * Notice that this function re-uses a pre-computed QR decomposition.
76  */
77 
78 template <Int dim>
79 OMEGA_H_DEVICE Vector<dim + 1> fit_cavity_polynomial(
80  QRFactorization<MaxFitPoints<dim>::value, dim + 1> qr, LO k,
81  LOs const& k2ke, LOs const& ke2e, Reals const& e_data, Int comp,
82  Int ncomps) {
83  constexpr auto max_fit_pts = MaxFitPoints<dim>::value;
84  auto begin = k2ke[k];
85  auto end = k2ke[k + 1];
86  auto nfit_pts = end - begin;
87  OMEGA_H_CHECK(nfit_pts >= dim + 1);
88  OMEGA_H_CHECK(nfit_pts <= max_fit_pts);
89  Vector<max_fit_pts> b;
90  for (auto i = 0; i < nfit_pts; ++i) {
91  auto ke = i + begin;
92  auto e = ke2e[ke];
93  b[i] = e_data[e * ncomps + comp];
94  }
95  for (auto i = nfit_pts; i < max_fit_pts; ++i) {
96  b[i] = 0.0;
97  }
98  auto qtb = implicit_q_trans_b(nfit_pts, dim + 1, qr.v, b);
99  auto coeffs = solve_upper_triangular(dim + 1, qr.r, qtb);
100  return coeffs;
101 }
102 
103 template <Int dim>
104 OMEGA_H_DEVICE Real eval_polynomial(Vector<dim + 1> coeffs, Vector<dim> x) {
105  auto val = coeffs[0];
106  for (Int j = 0; j < dim; ++j) val += coeffs[1 + j] * x[j];
107  return val;
108 }
109 
110 } // end namespace Omega_h
111 
112 #endif
Definition: Omega_h_matrix.hpp:34
Definition: amr_mpi_test.cpp:6
Definition: Omega_h_fit.hpp:24
Definition: Omega_h_qr.hpp:54
Definition: Omega_h_simplex.hpp:347