1
+ #ifndef PBAT_MATH_MOMENT_FITTING_H
2
+ #define PBAT_MATH_MOMENT_FITTING_H
3
+
4
+ #include " Concepts.h"
5
+ #include " pbat/Aliases.h"
6
+ #include " pbat/common/Eigen.h"
7
+
8
+ #include < limits>
9
+ #include < tbb/parallel_for.h>
10
+ #include < unsupported/Eigen/NNLS>
11
+
12
+ namespace pbat {
13
+ namespace math {
14
+
15
+ template <int Dims, int Order>
16
+ struct DynamicQuadrature
17
+ {
18
+ static auto constexpr kOrder = Order;
19
+ static auto constexpr kDims = Dims;
20
+
21
+ MatrixX points; // /< |kDims| x |#weights| array of quadrature points Xg
22
+ VectorX weights; // /< Array of quadrature weights wg associated with Xg
23
+ };
24
+
25
+ template <CPolynomialBasis TBasis, CFixedPointPolynomialQuadratureRule TQuad>
26
+ Matrix<TBasis::kSize , TQuad::kPoints > ReferenceMomentFittingMatrix (TBasis const & Pb, TQuad const & Q)
27
+ {
28
+ static_assert (
29
+ TBasis::kDims == TQuad::kDims ,
30
+ " Dimensions of the quadrature rule and the polynomial basis must match, i.e. a k-D "
31
+ " polynomial must be fit in a k-D integration domain." );
32
+ Matrix<TBasis::kSize , TQuad::kPoints > P{};
33
+ auto Xg = common::ToEigen (Q.points ).reshaped (TQuad::kDims + 1 , TQuad::kPoints );
34
+ // Eigen::Map<Matrix<TQuad::kDims + 1, TQuad::kPoints> const> Xg(Q.points.data());
35
+ for (auto g = 0u ; g < TQuad::kPoints ; ++g)
36
+ P.col (g) = Pb.eval (Xg.col (g).template segment <TQuad::kDims >(1 ));
37
+ return P;
38
+ }
39
+
40
+ template <CPolynomialBasis TBasis, CPolynomialQuadratureRule TQuad>
41
+ Matrix<TBasis::kSize , Eigen::Dynamic> ReferenceMomentFittingMatrix (TBasis const & Pb, TQuad const & Q)
42
+ {
43
+ static_assert (
44
+ TBasis::kDims == TQuad::kDims ,
45
+ " Dimensions of the quadrature rule and the polynomial basis must match, i.e. a k-D "
46
+ " polynomial must be fit in a k-D integration domain." );
47
+ Matrix<TBasis::kSize , Eigen::Dynamic> P (TBasis::kSize , Q.weights .size ());
48
+ auto Xg = common::ToEigen (Q.points ).reshaped (TQuad::kDims + 1 , Q.weights .size ());
49
+ for (auto g = 0u ; g < Xg.cols (); ++g)
50
+ P.col (g) = Pb.eval (Xg.col (g).template segment <TQuad::kDims >(1 ));
51
+ return P;
52
+ }
53
+
54
+ template <CPolynomialBasis TBasis, int Dims, int Order>
55
+ Matrix<TBasis::kSize , Eigen::Dynamic>
56
+ ReferenceMomentFittingMatrix (TBasis const & Pb, DynamicQuadrature<Dims, Order> const & Q)
57
+ {
58
+ using QuadratureType = DynamicQuadrature<Dims, Order>;
59
+ static_assert (
60
+ TBasis::kDims == QuadratureType::kDims ,
61
+ " Dimensions of the quadrature rule and the polynomial basis must match, i.e. a k-D "
62
+ " polynomial must be fit in a k-D integration domain." );
63
+ Matrix<TBasis::kSize , Eigen::Dynamic> P (TBasis::kSize , Q.weights .size ());
64
+ auto Xg = common::ToEigen (Q.points ).reshaped (QuadratureType::kDims , Q.weights .size ());
65
+ for (auto g = 0u ; g < Xg.cols (); ++g)
66
+ P.col (g) = Pb.eval (Xg.col (g));
67
+ return P;
68
+ }
69
+
70
+ template <class TDerivedP , class TDerivedB >
71
+ VectorX MomentFittedWeights (
72
+ Eigen::MatrixBase<TDerivedP> const & P,
73
+ Eigen::DenseBase<TDerivedB> const & b,
74
+ Index maxIterations = 10 ,
75
+ Scalar precision = std::numeric_limits<Scalar>::epsilon())
76
+ {
77
+ using MatrixType = TDerivedP;
78
+ Eigen::NNLS<MatrixType> nnls{};
79
+ nnls.compute (P.derived ());
80
+ nnls.setMaxIterations (maxIterations);
81
+ nnls.setTolerance (precision);
82
+ auto w = nnls.solve (b);
83
+ return w;
84
+ }
85
+
86
+ } // namespace math
87
+ } // namespace pbat
88
+
89
+ #endif // PBAT_MATH_MOMENT_FITTING_H
0 commit comments