13
13
#include < limits>
14
14
#include < tbb/parallel_for.h>
15
15
#include < unsupported/Eigen/NNLS>
16
+ #include < utility>
16
17
17
18
namespace pbat {
18
19
namespace math {
@@ -169,9 +170,11 @@ Vector<TDerivedXg1::ColsAtCompileTime> TransferQuadrature(
169
170
* @param Xi2 |#dims|x|#old quad.pts.| array of quadrature point positions defined in reference
170
171
* simplex space
171
172
* @param wi2 |#old quad.pts.|x1 array of quadrature weights
173
+ * @param bEvaluateError Whether to compute the integration error on the new quadrature rule
172
174
* @param maxIterations Maximum number of non-negative least-squares active set solver
173
175
* @param precision Convergence threshold
174
- * @return
176
+ * @return (w, e) where w are the quadrature weights associated with points Xi1, and e is the
177
+ * integration error in each simplex (zeros if not bEvaluateError).
175
178
*/
176
179
template <
177
180
auto Order,
@@ -180,82 +183,99 @@ template <
180
183
class TDerivedS2 ,
181
184
class TDerivedXi2 ,
182
185
class TDerivedWg2 >
183
- VectorX TransferQuadrature (
186
+ std::pair< VectorX, VectorX> TransferQuadrature (
184
187
Eigen::DenseBase<TDerivedS1> const & S1,
185
188
Eigen::MatrixBase<TDerivedXi1> const & Xi1,
186
189
Eigen::DenseBase<TDerivedS2> const & S2,
187
190
Eigen::MatrixBase<TDerivedXi2> const & Xi2,
188
191
Eigen::MatrixBase<TDerivedWg2> const & wi2,
192
+ bool bEvaluateError = false ,
189
193
Index maxIterations = 10 ,
190
194
Scalar precision = std::numeric_limits<Scalar>::epsilon())
191
195
{
192
196
// Compute adjacency graph from simplices s to their quadrature points Xi
197
+ using common::ArgSort;
198
+ using common::Counts;
199
+ using common::CumSum;
200
+ using common::ToEigen;
193
201
auto nsimplices =
194
202
std::max (*std::max_element (S1.begin (), S1.end ()), *std::max_element (S2.begin (), S2.end ())) +
195
203
1 ;
196
- std::vector<Index> S1P =
197
- common::CumSum (common::Counts<Index>(S1.begin (), S1.end (), nsimplices));
198
- std::vector<Index> S2P =
199
- common::CumSum (common::Counts<Index>(S2.begin (), S2.end (), nsimplices));
200
- std::vector<Index> S1N =
201
- common::ArgSort<Index>(S1.size (), [](auto si, auto sj) { return S1 (si) < S1 (sj); });
202
- std::vector<Index> S2N =
203
- common::ArgSort<Index>(S2.size (), [](auto si, auto sj) { return S2 (si) < S2 (sj); });
204
+ std::vector<Index> S1P = CumSum (Counts<Index>(S1.begin (), S1.end (), nsimplices));
205
+ std::vector<Index> S2P = CumSum (Counts<Index>(S2.begin (), S2.end (), nsimplices));
206
+ IndexVectorX S1N =
207
+ ToEigen (ArgSort<Index>(S1.size (), [&](auto si, auto sj) { return S1 (si) < S1 (sj); }));
208
+ IndexVectorX S2N =
209
+ ToEigen (ArgSort<Index>(S2.size (), [&](auto si, auto sj) { return S2 (si) < S2 (sj); }));
204
210
// Find weights wg1 that fit the given quadrature rule Xi2, wi2 on simplices S2
205
- auto fSolveWeights = [maxIterations,
206
- precision](MatrixX const & Xg1, MatrixX const & Xg2, VectorX const & wg2) {
211
+ auto fSolveWeights = [maxIterations, precision, bEvaluateError](
212
+ MatrixX const & Xg1,
213
+ MatrixX const & Xg2,
214
+ VectorX const & wg2) {
207
215
if (Xg1.rows () == 1 )
208
216
{
209
- return TransferQuadrature (
210
- OrthonormalPolynomialBasis<1 , Order>{},
211
- Xg1,
212
- Xg2,
213
- wg2,
214
- maxIterations,
215
- precision);
217
+ OrthonormalPolynomialBasis<1 , Order> P{};
218
+ auto w = TransferQuadrature (P, Xg1, Xg2, wg2, maxIterations, precision);
219
+ Scalar error (0 );
220
+ if (bEvaluateError)
221
+ {
222
+ auto b1 = math::Integrate (P, Xg1, w);
223
+ auto b2 = math::Integrate (P, Xg2, wg2);
224
+ error = (b1 - b2).squaredNorm ();
225
+ }
226
+ return std::make_pair (w, error);
216
227
}
217
228
if (Xg1.rows () == 2 )
218
229
{
219
- return TransferQuadrature (
220
- OrthonormalPolynomialBasis<2 , Order>{},
221
- Xg1,
222
- Xg2,
223
- wg2,
224
- maxIterations,
225
- precision);
230
+ OrthonormalPolynomialBasis<2 , Order> P{};
231
+ auto w = TransferQuadrature (P, Xg1, Xg2, wg2, maxIterations, precision);
232
+ Scalar error (0 );
233
+ if (bEvaluateError)
234
+ {
235
+ auto b1 = math::Integrate (P, Xg1, w);
236
+ auto b2 = math::Integrate (P, Xg2, wg2);
237
+ error = (b1 - b2).squaredNorm ();
238
+ }
239
+ return std::make_pair (w, error);
226
240
}
227
241
if (Xg1.rows () == 3 )
228
242
{
229
- return TransferQuadrature (
230
- OrthonormalPolynomialBasis<3 , Order>{},
231
- Xg1,
232
- Xg2,
233
- wg2,
234
- maxIterations,
235
- precision);
243
+ OrthonormalPolynomialBasis<3 , Order> P{};
244
+ auto w = TransferQuadrature (P, Xg1, Xg2, wg2, maxIterations, precision);
245
+ Scalar error (0 );
246
+ if (bEvaluateError)
247
+ {
248
+ auto b1 = math::Integrate (P, Xg1, w);
249
+ auto b2 = math::Integrate (P, Xg2, wg2);
250
+ error = (b1 - b2).squaredNorm ();
251
+ }
252
+ return std::make_pair (w, error);
236
253
}
237
254
throw std::invalid_argument (
238
255
" Expected quadrature points in reference simplex space of dimensions (i.e. rows) 1,2 "
239
256
" or 3." );
240
257
};
241
258
242
- VectorX wg1 = VectorX::Zero (Xi1.cols ());
259
+ VectorX error = VectorX::Zero (nsimplices);
260
+ VectorX wi1 = VectorX::Zero (Xi1.cols ());
243
261
tbb::parallel_for (Index (0 ), nsimplices, [&](Index s) {
244
262
auto S1begin = S1P[s];
245
263
auto S1end = S1P[s + 1 ];
246
264
if (S1end > S1begin)
247
265
{
248
- auto s1inds = S1N (Eigen::seq (S1begin, S1end - 1 ));
249
- MatrixX Xg1 = Xi1 (Eigen::placeholders::all, s1inds);
250
- auto S2begin = S2P[s];
251
- auto S2end = S2P[s + 1 ];
252
- auto s2inds = S2N (Eigen::seq (S2begin, S2end - 1 ));
253
- MatrixX Xg2 = Xi2 (Eigen::placeholders::all, s2inds);
254
- VectorX wg2 = wi2 (s2inds);
255
- wg1 (s1inds) = fSolveWeights (Xg1, Xg2, wg2);
266
+ auto s1inds = S1N (Eigen::seq (S1begin, S1end - 1 ));
267
+ MatrixX Xg1 = Xi1 (Eigen::placeholders::all, s1inds);
268
+ auto S2begin = S2P[s];
269
+ auto S2end = S2P[s + 1 ];
270
+ auto s2inds = S2N (Eigen::seq (S2begin, S2end - 1 ));
271
+ MatrixX Xg2 = Xi2 (Eigen::placeholders::all, s2inds);
272
+ VectorX wg2 = wi2 (s2inds);
273
+ auto [wg1, err] = fSolveWeights (Xg1, Xg2, wg2);
274
+ wi1 (s1inds) = wg1;
275
+ error (s) = err;
256
276
}
257
277
});
258
- return wg1 ;
278
+ return {wi1, error} ;
259
279
}
260
280
261
281
} // namespace math
0 commit comments