PolyFEM
Loading...
Searching...
No Matches
RBFWithQuadraticLagrange.cpp
Go to the documentation of this file.
1
4
8
9#include <igl/Timer.h>
10#include <Eigen/Dense>
11#include <iostream>
12#include <fstream>
13#include <array>
15
16using namespace polyfem;
17using namespace polyfem::assembler;
18using namespace polyfem::basis;
19using namespace polyfem::quadrature;
20using namespace polyfem::utils;
21
22namespace
23{
24
25 // Harmonic kernel
26 double kernel(const bool is_volume, const double r)
27 {
28 if (r < 1e-8)
29 {
30 return 0;
31 }
32
33 if (is_volume)
34 {
35 return 1 / r;
36 }
37 else
38 {
39 return log(r);
40 }
41 }
42
43 double kernel_prime(const bool is_volume, const double r)
44 {
45 if (r < 1e-8)
46 {
47 return 0;
48 }
49
50 if (is_volume)
51 {
52 return -1 / (r * r);
53 }
54 else
55 {
56 return 1 / r;
57 }
58 }
59
60 // Biharmonic kernel (2d only)
61 // double kernel(const bool is_volume, const double r) {
62 // assert(!is_volume);
63 // if (r < 1e-8) { return 0; }
64
65 // return r * r * (log(r)-1);
66 // }
67
68 // double kernel_prime(const bool is_volume, const double r) {
69 // assert(!is_volume);
70 // if (r < 1e-8) { return 0; }
71
72 // return r * ( 2 * log(r) - 1);
73 // }
74
75} // anonymous namespace
76
78
80 const LinearAssembler &assembler,
81 const Eigen::MatrixXd &centers,
82 const Eigen::MatrixXd &collocation_points,
83 const Eigen::MatrixXd &local_basis_integral,
84 const Quadrature &quadr,
85 Eigen::MatrixXd &rhs,
86 bool with_constraints)
87 : centers_(centers)
88{
89 // centers_.resize(0, centers.cols());
90 compute_weights(assembler, collocation_points, local_basis_integral, quadr, rhs, with_constraints);
91}
92
93// -----------------------------------------------------------------------------
94
95void RBFWithQuadraticLagrange::basis(const int local_index, const Eigen::MatrixXd &samples, Eigen::MatrixXd &val) const
96{
97 Eigen::MatrixXd tmp;
98 bases_values(samples, tmp);
99 val = tmp.col(local_index);
100}
101
102// -----------------------------------------------------------------------------
103
104void RBFWithQuadraticLagrange::grad(const int local_index, const Eigen::MatrixXd &samples, Eigen::MatrixXd &val) const
105{
106 Eigen::MatrixXd tmp;
107 const int dim = centers_.cols();
108 val.resize(samples.rows(), dim);
109 for (int d = 0; d < dim; ++d)
110 {
111 bases_grads(d, samples, tmp);
112 val.col(d) = tmp.col(local_index);
113 }
114}
115
117
118void RBFWithQuadraticLagrange::bases_values(const Eigen::MatrixXd &samples, Eigen::MatrixXd &val) const
119{
120 // Compute A
121 Eigen::MatrixXd A;
122 compute_kernels_matrix(samples, A);
123
124 // Multiply by the weights
125 val = A * weights_;
126}
127
128// -----------------------------------------------------------------------------
129
130void RBFWithQuadraticLagrange::bases_grads(const int axis, const Eigen::MatrixXd &samples, Eigen::MatrixXd &val) const
131{
132 const int num_kernels = centers_.rows();
133 const int dim = (is_volume() ? 3 : 2);
134
135 // Compute ∇xA
136 Eigen::MatrixXd A_prime(samples.rows(), num_kernels + 1 + dim + dim * (dim + 1) / 2);
137 A_prime.setZero();
138
139 for (int j = 0; j < num_kernels; ++j)
140 {
141 A_prime.col(j) = (samples.rowwise() - centers_.row(j)).rowwise().norm().unaryExpr([this](double x) { return kernel_prime(is_volume(), x) / x; });
142 A_prime.col(j) = (samples.col(axis).array() - centers_(j, axis)) * A_prime.col(j).array();
143 }
144 // Linear terms
145 A_prime.middleCols(num_kernels + 1 + axis, 1).setOnes();
146 // Mixed terms
147 if (dim == 2)
148 {
149 A_prime.col(num_kernels + 1 + dim) = samples.col(1 - axis);
150 }
151 else
152 {
153 A_prime.col(num_kernels + 1 + dim + axis) = samples.col((axis + 1) % dim);
154 A_prime.col(num_kernels + 1 + dim + (axis + 2) % dim) = samples.col((axis + 2) % dim);
155 }
156 // Quadratic terms
157 A_prime.rightCols(dim).col(axis) = 2.0 * samples.col(axis);
158
159 // Apply weights
160 val = A_prime * weights_;
161}
162
164
165void RBFWithQuadraticLagrange::compute_kernels_matrix(const Eigen::MatrixXd &samples, Eigen::MatrixXd &A) const
166{
167 // Compute A
168 const int num_kernels = centers_.rows();
169 const int dim = (is_volume() ? 3 : 2);
170
171 A.resize(samples.rows(), num_kernels + 1 + dim + dim * (dim + 1) / 2);
172 for (int j = 0; j < num_kernels; ++j)
173 {
174 A.col(j) = (samples.rowwise() - centers_.row(j)).rowwise().norm().unaryExpr([this](double x) { return kernel(is_volume(), x); });
175 }
176 A.col(num_kernels).setOnes(); // constant term
177 A.middleCols(num_kernels + 1, dim) = samples; // linear terms
178 if (dim == 2)
179 {
180 A.middleCols(num_kernels + dim + 1, 1) = samples.rowwise().prod(); // mixed terms
181 }
182 else if (dim == 3)
183 {
184 A.middleCols(num_kernels + dim + 1, 3) = samples;
185 A.middleCols(num_kernels + dim + 1 + 0, 1).array() *= samples.col(1).array();
186 A.middleCols(num_kernels + dim + 1 + 1, 1).array() *= samples.col(2).array();
187 A.middleCols(num_kernels + dim + 1 + 2, 1).array() *= samples.col(0).array();
188 }
189 A.rightCols(dim) = samples.array().square(); // quadratic terms
190}
191
192// -----------------------------------------------------------------------------
193
195 const int num_bases, const Quadrature &quadr, Eigen::MatrixXd &C) const
196{
197 const int num_kernels = centers_.rows();
198 const int dim = centers_.cols();
199 assert(dim == 2);
200
201 // K_cst = ∫φj
202 // K_lin = ∫∇x(φj), ∫∇y(φj)
203 // K_mix = ∫y·∇x(φj), ∫x·∇y(φj)
204 // K_sqr = ∫x·∇x(φj), ∫y·∇y(φj)
205 Eigen::VectorXd K_cst = Eigen::VectorXd::Zero(num_kernels);
206 Eigen::MatrixXd K_lin = Eigen::MatrixXd::Zero(num_kernels, dim);
207 Eigen::MatrixXd K_mix = Eigen::MatrixXd::Zero(num_kernels, dim);
208 Eigen::MatrixXd K_sqr = Eigen::MatrixXd::Zero(num_kernels, dim);
209 for (int j = 0; j < num_kernels; ++j)
210 {
211 // ∫∇x(φj)(p) = Σ_q (xq - xk) * 1/r * h'(r) * wq
212 // - xq is the x coordinate of the q-th quadrature point
213 // - wq is the q-th quadrature weight
214 // - r is the distance from pq to the kernel center
215 // - h is the RBF kernel (scalar function)
216 for (int q = 0; q < quadr.points.rows(); ++q)
217 {
218 const RowVectorNd p = quadr.points.row(q) - centers_.row(j);
219 const double r = p.norm();
220 const RowVectorNd gradPhi = p * kernel_prime(is_volume(), r) / r * quadr.weights(q);
221 K_cst(j) += kernel(is_volume(), r) * quadr.weights(q);
222 K_lin.row(j) += gradPhi;
223 K_mix(j, 0) += quadr.points(q, 1) * gradPhi(0);
224 K_mix(j, 1) += quadr.points(q, 0) * gradPhi(1);
225 K_sqr.row(j) += (quadr.points.row(q).array() * gradPhi.array()).matrix();
226 }
227 }
228
229 // I_lin = ∫x, ∫y
230 // I_mix = ∫xy
231 // I_sqr = ∫x², ∫y²
232 Eigen::RowVectorXd I_lin = (quadr.points.array().colwise() * quadr.weights.array()).colwise().sum();
233 Eigen::RowVectorXd I_mix = (quadr.points.rowwise().prod().array() * quadr.weights.array()).colwise().sum();
234 Eigen::RowVectorXd I_sqr = (quadr.points.array().square().colwise() * quadr.weights.array()).colwise().sum();
235 double volume = quadr.weights.sum();
236
237 // TODO
238 // std::cout << I_lin << std::endl;
239 // std::cout << I_mix << std::endl;
240 // std::cout << I_sqr << std::endl;
241
242 // Compute M
243 Eigen::Matrix<double, 5, 5> M;
244 M << volume, 0, I_lin(1), 2 * I_lin(0), 0,
245 0, volume, I_lin(0), 0, 2 * I_lin(1),
246 I_lin(1), I_lin(0), I_sqr(0) + I_sqr(1), 2 * I_mix(0), 2 * I_mix(0),
247 4 * I_lin(0), 2 * I_lin(1), 4 * I_mix(0), 6 * I_sqr(0), 2 * I_sqr(1),
248 2 * I_lin(0), 4 * I_lin(1), 4 * I_mix(0), 2 * I_sqr(0), 6 * I_sqr(1);
249 Eigen::FullPivLU<Eigen::Matrix<double, 5, 5>> lu(M);
250
252
253 // Compute L
254 C.resize(5, num_kernels + 1 + dim + dim * (dim + 1) / 2);
255 C.setZero();
256 C.block(0, 0, dim, num_kernels) = K_lin.transpose();
257 C.block(dim, 0, 1, num_kernels) = K_mix.transpose().colwise().sum();
258 C.block(dim + 1, 0, dim, num_kernels) = 2.0 * (K_sqr.colwise() + K_cst).transpose();
259 C.block(dim + 1, num_kernels, dim, 1).setConstant(2.0 * volume);
260 C.bottomRightCorner(5, 5) = M;
261 // std::cout << L.bottomRightCorner(10, 10) << std::endl;
262}
263
265 const int num_bases, const Quadrature &quadr, Eigen::MatrixXd &C) const
266{
267 // TODO
268 const double t = 0;
269 const int num_kernels = centers_.rows();
270 const int space_dim = centers_.cols();
271 const int assembler_dim = assembler.is_tensor() ? 2 : 1;
272 assert(space_dim == 2);
273
274 std::array<Eigen::MatrixXd, 5> strong;
275
276 // ass_val = [q_10, q_01, q_11, q_20, q_02, psi_0, ..., psi_k]
277 ElementAssemblyValues ass_val;
278 ass_val.has_parameterization = false;
279 ass_val.basis_values.resize(5 + num_kernels);
280
281 // evaluating monomial and grad of monomials at quad points
283 RBFWithQuadratic::setup_monomials_strong_2d(assembler_dim, assembler, quadr.points, quadr.weights.array(), strong);
284
285 // evaluating psi and grad psi at quadr points
286 for (int j = 0; j < num_kernels; ++j)
287 {
288 ass_val.basis_values[5 + j].val = Eigen::MatrixXd(quadr.points.rows(), 1);
289 ass_val.basis_values[5 + j].grad = Eigen::MatrixXd(quadr.points.rows(), quadr.points.cols());
290
291 for (int q = 0; q < quadr.points.rows(); ++q)
292 {
293 const RowVectorNd p = quadr.points.row(q) - centers_.row(j);
294 const double r = p.norm();
295
296 ass_val.basis_values[5 + j].val(q) = kernel(is_volume(), r);
297 ass_val.basis_values[5 + j].grad.row(q) = p * kernel_prime(is_volume(), r) / r;
298 }
299 }
300
301 for (size_t i = 5; i < ass_val.basis_values.size(); ++i)
302 {
303 ass_val.basis_values[i].grad_t_m = ass_val.basis_values[i].grad;
304 }
305
306 // Compute C
307 C.resize(RBFWithQuadratic::index_mapping(assembler_dim - 1, assembler_dim - 1, 4, assembler_dim) + 1, num_kernels + 1 + 5);
308 C.setZero();
309
310 for (int d = 0; d < 5; ++d)
311 {
312 // first num_kernels bases
313 for (int i = 0; i < num_kernels; ++i)
314 {
315 const auto tmp = assembler.assemble(LinearAssemblerData(ass_val, t, d, 5 + i, quadr.weights));
316 for (int alpha = 0; alpha < assembler_dim; ++alpha)
317 {
318 for (int beta = 0; beta < assembler_dim; ++beta)
319 {
320 const int loc_index = alpha * assembler_dim + beta;
321 C(RBFWithQuadratic::index_mapping(alpha, beta, d, assembler_dim), i) = tmp(loc_index) + (strong[d].row(loc_index).transpose().array() * ass_val.basis_values[5 + i].val.array()).sum();
322 }
323 }
324 }
325
326 // second the q_i
327 for (int i = 0; i < 5; ++i)
328 {
329 const auto tmp = assembler.assemble(LinearAssemblerData(ass_val, t, d, i, quadr.weights));
330 for (int alpha = 0; alpha < assembler_dim; ++alpha)
331 {
332 for (int beta = 0; beta < assembler_dim; ++beta)
333 {
334 const int loc_index = alpha * assembler_dim + beta;
335 C(RBFWithQuadratic::index_mapping(alpha, beta, d, assembler_dim), num_kernels + i + 1) = tmp(loc_index) + (strong[d].row(loc_index).transpose().array() * ass_val.basis_values[i].val.array()).sum();
336 }
337 }
338 }
339
340 // finally the constant
341 for (int alpha = 0; alpha < assembler_dim; ++alpha)
342 {
343 for (int beta = 0; beta < assembler_dim; ++beta)
344 {
345 // std::cout<<alpha <<" "<< beta <<" "<< d <<" "<< assembler_dim<< " -> r = "<< RBFWithQuadratic::index_mapping(alpha, beta, d, assembler_dim)<<std::endl;
346 const int loc_index = alpha * assembler_dim + beta;
347 C(RBFWithQuadratic::index_mapping(alpha, beta, d, assembler_dim), num_kernels) = strong[d].row(loc_index).sum();
348 }
349 }
350 }
351
352 // {
353 // std::ofstream file;
354 // file.open("C.txt");
355 // file << C;
356 // file.close();
357 // }
358
359 // Eigen::MatrixXd Cold;
360 // compute_constraints_matrix_2d_old(num_bases, quadr,Cold);
361 // {
362 // std::ofstream file;
363 // file.open("Cold.txt");
364 // file << Cold;
365 // file.close();
366 // }
367}
368
369// -----------------------------------------------------------------------------
370
372 const int num_bases, const Quadrature &quadr, Eigen::MatrixXd &C) const
373{
374 const int num_kernels = centers_.rows();
375 const int dim = centers_.cols();
376 assert(dim == 3);
377
378 // K_cst = ∫φj
379 // K_lin = ∫∇x(φj), ∫∇y(φj), ∫∇z(φj)
380 // K_mix = ∫(y·∇x(φj)+x·∇y(φj)), ∫(z·∇y(φj)+y·∇z(φj)), ∫(x·∇z(φj)+z·∇x(φj))
381 // K_sqr = ∫x·∇x(φj), ∫y·∇y(φj), ∫z·∇z(φj)
382 Eigen::VectorXd K_cst = Eigen::VectorXd::Zero(num_kernels);
383 Eigen::MatrixXd K_lin = Eigen::MatrixXd::Zero(num_kernels, dim);
384 Eigen::MatrixXd K_mix = Eigen::MatrixXd::Zero(num_kernels, dim);
385 Eigen::MatrixXd K_sqr = Eigen::MatrixXd::Zero(num_kernels, dim);
386 for (int j = 0; j < num_kernels; ++j)
387 {
388 // ∫∇x(φj)(p) = Σ_q (xq - xk) * 1/r * h'(r) * wq
389 // - xq is the x coordinate of the q-th quadrature point
390 // - wq is the q-th quadrature weight
391 // - r is the distance from pq to the kernel center
392 // - h is the RBF kernel (scalar function)
393 for (int q = 0; q < quadr.points.rows(); ++q)
394 {
395 const RowVectorNd p = quadr.points.row(q) - centers_.row(j);
396 const double r = p.norm();
397 const RowVectorNd gradPhi = p * kernel_prime(is_volume(), r) / r * quadr.weights(q);
398 K_cst(j) += kernel(is_volume(), r) * quadr.weights(q);
399 K_lin.row(j) += gradPhi;
400 for (int d = 0; d < dim; ++d)
401 {
402 K_mix(j, d) += quadr.points(q, (d + 1) % dim) * gradPhi(d) + quadr.points(q, d) * gradPhi((d + 1) % dim);
403 }
404 K_sqr.row(j) += (quadr.points.row(q).array() * gradPhi.array()).matrix();
405 }
406 }
407
408 // I_lin = ∫x, ∫y, ∫z
409 // I_sqr = ∫x², ∫y², ∫z²
410 // I_mix = ∫xy, ∫yz, ∫zx
411 Eigen::RowVectorXd I_lin = (quadr.points.array().colwise() * quadr.weights.array()).colwise().sum();
412 Eigen::RowVectorXd I_sqr = (quadr.points.array().square().colwise() * quadr.weights.array()).colwise().sum();
413 Eigen::RowVectorXd I_mix(3);
414 I_mix(0) = (quadr.points.col(0).array() * quadr.points.col(1).array() * quadr.weights.array()).sum();
415 I_mix(1) = (quadr.points.col(1).array() * quadr.points.col(2).array() * quadr.weights.array()).sum();
416 I_mix(2) = (quadr.points.col(2).array() * quadr.points.col(0).array() * quadr.weights.array()).sum();
417 double volume = quadr.weights.sum();
418
419 // std::cout << I_lin << std::endl;
420 // std::cout << I_mix << std::endl;
421 // std::cout << I_sqr << std::endl;
422
423 // Compute M
424 Eigen::Matrix<double, 9, 9> M;
425 M << volume, 0, 0, I_lin(1), 0, I_lin(2), 2 * I_lin(0), 0, 0,
426 0, volume, 0, I_lin(0), I_lin(2), 0, 0, 2 * I_lin(1), 0,
427 0, 0, volume, 0, I_lin(1), I_lin(0), 0, 0, 2 * I_lin(2),
428 I_lin(1), I_lin(0), 0, I_sqr(0) + I_sqr(1), I_mix(2), I_mix(1), 2 * I_mix(0), 2 * I_mix(0), 0,
429 0, I_lin(2), I_lin(1), I_mix(2), I_sqr(1) + I_sqr(2), I_mix(0), 0, 2 * I_mix(1), 2 * I_mix(1),
430 I_lin(2), 0, I_lin(0), I_mix(1), I_mix(0), I_sqr(2) + I_sqr(0), 2 * I_mix(2), 0, 2 * I_mix(2),
431 2 * I_lin(0), 0, 0, 2 * I_mix(0), 0, 2 * I_mix(2), 4 * I_sqr(0), 0, 0,
432 0, 2 * I_lin(1), 0, 2 * I_mix(0), 2 * I_mix(1), 0, 0, 4 * I_sqr(1), 0,
433 0, 0, 2 * I_lin(2), 0, 2 * I_mix(1), 2 * I_mix(2), 0, 0, 4 * I_sqr(2);
434 Eigen::Matrix<double, 1, 9> M_rhs;
435 M_rhs.segment<3>(0) = I_lin;
436 M_rhs.segment<3>(3) = I_mix;
437 M_rhs.segment<3>(6) = I_sqr;
438 // M_rhs << I_lin, I_mix, I_sqr;
439 M.bottomRows(dim).rowwise() += 2.0 * M_rhs;
440 // TODO
441 // assert(false);
442
444
445 // Compute L
446 C.resize(9, num_kernels + 1 + dim + dim * (dim + 1) / 2);
447 C.setZero();
448 C.block(0, 0, dim, num_kernels) = K_lin.transpose();
449 C.block(dim, 0, dim, num_kernels) = K_mix.transpose();
450 C.block(dim + dim, 0, dim, num_kernels) = 2.0 * (K_sqr.colwise() + K_cst).transpose();
451 C.block(dim + dim, num_kernels, dim, 1).setConstant(2.0 * volume);
452 C.bottomRightCorner(9, 9) = M;
453 // std::cout << C.bottomRightCorner(9, 12) << std::endl;
454}
455
456// -----------------------------------------------------------------------------
457
458void RBFWithQuadraticLagrange::compute_weights(const LinearAssembler &assembler, const Eigen::MatrixXd &samples,
459 const Eigen::MatrixXd &local_basis_integral, const Quadrature &quadr,
460 Eigen::MatrixXd &b, bool with_constraints)
461{
462 logger().trace("#kernel centers: {}", centers_.rows());
463 logger().trace("#collocation points: {}", samples.rows());
464 logger().trace("#quadrature points: {}", quadr.weights.size());
465 logger().trace("#non-vanishing bases: {}", b.cols());
466 logger().trace("#constraints: {}", b.cols());
467
468 // Compute A
469 Eigen::MatrixXd A;
470 compute_kernels_matrix(samples, A);
471
472 if (!with_constraints)
473 {
474 // Solve the system
475 const int num_kernels = centers_.rows();
476 logger().trace("-- Solving system of size {}x{}", num_kernels, num_kernels);
477 weights_ = (A.transpose() * A).ldlt().solve(A.transpose() * b);
478 logger().trace("-- Solved!");
479
480 return;
481 }
482
483 const int num_bases = b.cols();
484
485 const Eigen::MatrixXd At = A.transpose();
486
487 // Compute C
488 Eigen::MatrixXd C;
489 if (is_volume())
490 {
491 compute_constraints_matrix_3d(num_bases, quadr, C);
492 }
493 else
494 {
495 compute_constraints_matrix_2d(assembler, num_bases, quadr, C);
496 }
497
498 const int dim = centers_.cols();
499 assert(centers_.rows() + 1 + dim + dim * (dim + 1) / 2 > C.rows());
500 logger().trace("#constraints: {}", C.rows());
501
502 // Compute rhs = [ A^T b; d ]
503 assert(local_basis_integral.cols() == C.rows());
504 assert(local_basis_integral.rows() == b.cols());
505 assert(A.rows() == b.rows());
506 Eigen::MatrixXd rhs(A.cols() + local_basis_integral.cols(), b.cols());
507 rhs.topRows(A.cols()) = At * b;
508 rhs.bottomRows(local_basis_integral.cols()) = local_basis_integral.transpose();
509
510 // Compute M = [ A^T A, C^T; C, 0]
511 assert(C.cols() == A.cols());
512 assert(A.rows() == b.rows());
513 Eigen::MatrixXd M(A.cols() + C.rows(), A.cols() + C.rows());
514 M.topLeftCorner(A.cols(), A.cols()) = At * A;
515 M.topRightCorner(A.cols(), C.rows()) = C.transpose();
516 M.bottomLeftCorner(C.rows(), A.cols()) = C;
517 M.bottomRightCorner(C.rows(), C.rows()).setZero();
518
519 // std::cout << M.bottomRightCorner(10, 10) << std::endl;
520
521 // Solve the system
522 logger().trace("-- Solving system of size {}x{}", M.rows(), M.cols());
523 auto ldlt = M.ldlt();
524 if (ldlt.info() == Eigen::NumericalIssue)
525 {
526 logger().error("-- WARNING: Numerical issues when solving the harmonic least square.");
527 }
528 const auto tmp = ldlt.solve(rhs);
529 weights_ = tmp.topRows(A.cols());
530 logger().trace("-- Solved!");
531 logger().trace("-- Mean residual: {}", (A * weights_ - b).array().abs().colwise().maxCoeff().mean());
532 logger().trace("-- Max constraints error: {}", (C * weights_ - local_basis_integral.transpose()).array().abs().maxCoeff());
533
534 // {
535 // std::ofstream file;
536 // file.open("M.txt");
537 // file << M;
538 // file.close();
539 // }
540
541 // {
542 // std::ofstream file;
543 // file.open("C.txt");
544 // file << C;
545 // file.close();
546 // }
547
548 // {
549 // std::ofstream file;
550 // file.open("b.txt");
551 // file << local_basis_integral.transpose();
552 // file.close();
553 // }
554
555 // {
556 // std::ofstream file;
557 // file.open("rhs.txt");
558 // file << rhs;
559 // file.close();
560 // }
561
562 // std::cout << M.bottomRightCorner(10, 10) << std::endl;
563
564#if 0
565 // Compute rhs = [ A^T b; d ]
566 assert(local_basis_integral.cols() == C.rows());
567 assert(local_basis_integral.rows() == b.cols());
568 assert(A.rows() == b.rows());
569 Eigen::MatrixXd rhs(A.cols() + local_basis_integral.cols(), b.cols());
570 rhs.topRows(A.cols()) = At * b;
571 rhs.bottomRows(local_basis_integral.cols()) = local_basis_integral.transpose();
572
573 // Compute M = [ A^T A, C^T; C, 0]
574 assert(C.cols() == A.cols());
575 assert(A.rows() == b.rows());
576 Eigen::MatrixXd M(A.cols() + C.rows(), A.cols() + C.rows());
577 M.topLeftCorner(A.cols(), A.cols()) = At * A;
578 M.topRightCorner(A.cols(), C.rows()) = C.transpose();
579 M.bottomLeftCorner(C.rows(), A.cols()) = C;
580 M.bottomRightCorner(C.rows(), C.rows()).setZero();
581
582 // std::cout << M.bottomRightCorner(10, 10) << std::endl;
583
584 // Solve the system
585 logger().trace("-- Solving system of size {}x{}", M.rows(), M.cols());
586 auto ldlt = M.ldlt();
587 if (ldlt.info() == Eigen::NumericalIssue) {
588 logger().error("-- WARNING: Numerical issues when solving the harmonic least square.");
589 }
590 weights_ = ldlt.solve(rhs).topRows(A.cols());
591 logger().trace("-- Solved!");
592 logger().trace("-- Mean residual: {}", (A * weights_ - b).array().abs().colwise().maxCoeff().mean());
593
594
595 Eigen::MatrixXd MM, x, dx, val;
596 basis(0, quadr.points, val);
597 grad(0, quadr.points, MM);
598 int dim = (is_volume() ? 3 : 2);
599 for (int d = 0; d < dim; ++d) {
600 // basis(0, quadr.points, x);
601 // auto asd = quadr.points;
602 // asd.col(d).array() += 1e-7;
603 // basis(0, asd, dx);
604 // std::cout << (dx - x) / 1e-7 - MM.col(d) << std::endl;
605 std::cout << (MM.col(d).array() * quadr.weights.array()).sum() - local_basis_integral(0, d) << std::endl;
606 std::cout << ((
607 MM.col((d+1)%dim).array() * quadr.points.col(d).array()
608 + MM.col(d).array() * quadr.points.col((d+1)%dim).array()
609 ) * quadr.weights.array()).sum() - local_basis_integral(0, (dim == 2 ? 2 : (dim+d) )) << std::endl;
610 std::cout << 2.0 * (
611 (quadr.points.col(d).array() * MM.col(d).array()
612 + val.array())
613 * quadr.weights.array()
614 ).sum() - local_basis_integral(0, (dim == 2 ? (3 + d) : (dim+dim+d))) << std::endl;
615 }
616#endif
617}
double val
Definition Assembler.cpp:86
int x
virtual bool is_tensor() const
stores per element basis values at given quadrature points and geometric mapping
assemble matrix based on the local assembler local assembler is eg Laplace, LinearElasticity etc
void assemble(const bool is_volume, const int n_basis, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &cache, const double t, StiffnessMatrix &stiffness, const bool is_mass=false) const override
assembles the stiffness matrix for the given basis the bilinear form (local assembler) is encoded by ...
static void setup_monomials_strong_2d(const int dim, const assembler::LinearAssembler &assembler, const Eigen::MatrixXd &pts, const QuadratureVector &da, std::array< Eigen::MatrixXd, 5 > &strong)
static void setup_monomials_vals_2d(const int star_index, const Eigen::MatrixXd &pts, assembler::ElementAssemblyValues &vals)
static int index_mapping(const int alpha, const int beta, const int d, const int ass_dim)
void compute_constraints_matrix_2d_old(const int num_bases, const quadrature::Quadrature &quadr, Eigen::MatrixXd &C) const
void bases_grads(const int axis, const Eigen::MatrixXd &samples, Eigen::MatrixXd &val) const
Batch evaluates the gradient of the RBF + polynomials on a set of sample points.
void compute_constraints_matrix_2d(const assembler::LinearAssembler &assembler, const int num_bases, const quadrature::Quadrature &quadr, Eigen::MatrixXd &C) const
void bases_values(const Eigen::MatrixXd &samples, Eigen::MatrixXd &val) const
Batch evaluates the RBF + polynomials on a set of sample points.
void compute_weights(const assembler::LinearAssembler &assembler, const Eigen::MatrixXd &collocation_points, const Eigen::MatrixXd &local_basis_integral, const quadrature::Quadrature &quadr, Eigen::MatrixXd &rhs, bool with_constraints)
void grad(const int local_index, const Eigen::MatrixXd &uv, Eigen::MatrixXd &val) const
Evaluates the gradient of one RBF function over a list of coordinates.
void compute_constraints_matrix_3d(const int num_bases, const quadrature::Quadrature &quadr, Eigen::MatrixXd &C) const
void basis(const int local_index, const Eigen::MatrixXd &uv, Eigen::MatrixXd &val) const
Evaluates one RBF function over a list of coordinates.
void compute_kernels_matrix(const Eigen::MatrixXd &samples, Eigen::MatrixXd &A) const
RBFWithQuadraticLagrange(const assembler::LinearAssembler &assembler, const Eigen::MatrixXd &centers, const Eigen::MatrixXd &collocation_points, const Eigen::MatrixXd &local_basis_integral, const quadrature::Quadrature &quadr, Eigen::MatrixXd &rhs, bool with_constraints=true)
Initialize RBF functions over a polytope element.
Used for test only.
void show_matrix_stats(const Eigen::MatrixXd &M)
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:42
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13