5#include "preconditioner/ras_preconditioner.h"
6#include "common/macros.h"
7#include "common/orthonormalize.h"
8#include "geometry/bbox3d.h"
9#include "polynomial/monomial_basis.h"
10#include "polynomial/unisolvent_point_set.h"
11#include "preconditioner/domain.h"
12#include "preconditioner/domain_divider.h"
22 ras_preconditioner::ras_preconditioner(
const model& model,
const geometry::points3d& points)
23 : ras_preconditioner(model, points, geometry::
points3d(0, 3)) {}
25 ras_preconditioner::ras_preconditioner(
const model& model,
const geometry::points3d& points,
26 const geometry::points3d& grad_points)
27 : model_without_poly_(model.without_poly()),
29 n_points_(points.rows()),
30 n_grad_points_(grad_points.rows()),
31 n_poly_basis_(model.poly_basis_size()),
34 ? std::make_unique<interpolation::rbf_symmetric_evaluator<Order>>(model, points_)
36 auto n_fine_levels = std::max(
37 0,
static_cast<int>(std::ceil(std::log(
static_cast<double>(n_points_ + n_grad_points_) /
38 static_cast<double>(n_coarsest_points)) /
39 log(1.0 / coarse_ratio))));
40 n_levels_ = n_fine_levels + 1;
42 point_idcs_.resize(n_levels_);
43 grad_point_idcs_.resize(n_levels_);
45 std::vector<index_t> poly_point_idcs;
47 auto level = n_levels_ - 1;
49 if (n_poly_basis_ > 0) {
50 polynomial::unisolvent_point_set ups(points_, model.poly_dimension(), model.poly_degree());
52 poly_point_idcs = ups.point_indices();
53 polynomial::lagrange_basis lagrange_basis(model.poly_dimension(), model.poly_degree(),
54 points_(poly_point_idcs, Eigen::all));
55 lagrange_pt_ = lagrange_basis.evaluate(points_);
57 point_idcs_.at(level) = poly_point_idcs;
58 point_idcs_.at(level).reserve(n_points_);
59 for (index_t i = 0; i < n_points_; i++) {
60 if (!std::binary_search(poly_point_idcs.begin(), poly_point_idcs.end(), i)) {
61 point_idcs_.at(level).push_back(i);
65 point_idcs_.at(level).resize(n_points_);
66 std::iota(point_idcs_.at(level).begin(), point_idcs_.at(level).end(), 0);
69 grad_point_idcs_.at(level).resize(n_grad_points_);
70 std::iota(grad_point_idcs_.at(level).begin(), grad_point_idcs_.at(level).end(), 0);
73 fine_grids_.resize(n_levels_);
75 std::cout << std::setw(8) <<
"level" << std::setw(16) <<
"n_domains" << std::setw(16)
76 <<
"n_points" << std::endl;
78 for (
auto level = n_levels_ - 1; level >= 1; level--) {
80 static_cast<index_t
>(point_idcs_.at(level).size() + grad_point_idcs_.at(level).size());
82 auto divider = std::make_unique<domain_divider>(points_, grad_points_, point_idcs_.at(level),
83 grad_point_idcs_.at(level), poly_point_idcs);
85 auto ratio = level == 1
86 ?
static_cast<double>(n_coarsest_points) /
static_cast<double>(n_mixed_points)
88 std::tie(point_idcs_.at(level - 1), grad_point_idcs_.at(level - 1)) =
89 divider->choose_coarse_points(ratio);
91 for (
auto&& d : divider->into_domains()) {
92 fine_grids_.at(level).emplace_back(model, std::move(d));
95 auto n_grids =
static_cast<index_t
>(fine_grids_.at(level).size());
96 if (!kRecomputeAndClear) {
97#pragma omp parallel for
98 for (index_t i = 0; i < n_grids; i++) {
99 auto& fine = fine_grids_.at(level).at(i);
100 fine.setup(points_, lagrange_pt_);
104 std::cout << std::setw(8) << level << std::setw(16) << n_grids << std::setw(16)
105 << n_mixed_points << std::endl;
109 auto n_mixed_points =
110 static_cast<index_t
>(point_idcs_.at(0).size() + grad_point_idcs_.at(0).size());
112 domain coarse_domain;
113 coarse_domain.point_indices = point_idcs_.at(0);
114 coarse_domain.grad_point_indices = grad_point_idcs_.at(0);
116 coarse_ = std::make_unique<coarse_grid>(model, std::move(coarse_domain));
117 coarse_->setup(points_, grad_points_, lagrange_pt_);
119 std::cout << std::setw(8) << 0 << std::setw(16) << 1 << std::setw(16) << n_mixed_points
123 if (n_levels_ == 1) {
127 auto bbox = geometry::bbox3d::from_points(points_);
128 for (
auto level = 1; level < n_levels_; level++) {
129 if (level == n_levels_ - 1) {
130 add_evaluator(level, level - 1, model_without_poly_, points_, bbox);
132 add_evaluator(level, level - 1, model_without_poly_,
133 points_(point_idcs_.at(level), Eigen::all), bbox);
135 evaluator(level, level - 1).set_field_points(points_(point_idcs_.at(level - 1), Eigen::all));
138 for (
auto level = 1; level < n_levels_ - 1; level++) {
139 add_evaluator(0, level, model, points_(point_idcs_.at(0), Eigen::all), bbox);
140 evaluator(0, level).set_field_points(points_(point_idcs_.at(level), Eigen::all));
143 if (n_poly_basis_ > 0) {
144 polynomial::monomial_basis poly(model.poly_dimension(), model.poly_degree());
145 p_ = poly.evaluate(points_).transpose();
146 common::orthonormalize_cols(p_);
148 ap_ = Eigen::MatrixXd(p_.rows(), p_.cols());
150 auto finest_evaluator =
151 interpolation::rbf_symmetric_evaluator<Order>(model_without_poly_, points_);
152 auto n_cols = p_.cols();
153 for (index_t i = 0; i < n_cols; i++) {
154 finest_evaluator.set_weights(p_.col(i));
155 ap_.col(i) = finest_evaluator.evaluate();
160 valuesd ras_preconditioner::operator()(
const valuesd& v)
const {
161 RSMESH_ASSERT(v.rows() == size());
163 valuesd residuals = v.head(n_points_);
164 valuesd weights_total = valuesd::Zero(size());
165 if (n_levels_ == 1) {
166 coarse_->solve(residuals);
167 coarse_->set_solution_to(weights_total);
168 return weights_total;
171 if (kReportResidual) {
172 std::cout <<
"Initial residual: " << residuals.norm() << std::endl;
175 for (
auto level = n_levels_ - 1; level >= 1; level--) {
177 valuesd weights = valuesd::Zero(n_points_);
180 auto n_grids =
static_cast<index_t
>(fine_grids_.at(level).size());
181#pragma omp parallel for schedule(guided)
182 for (index_t i = 0; i < n_grids; i++) {
183 auto& fine = fine_grids_.at(level).at(i);
184 if (kRecomputeAndClear) {
185 fine.setup(points_, lagrange_pt_);
187 fine.solve(residuals);
188 fine.set_solution_to(weights);
189 if (kRecomputeAndClear) {
195 if (level < n_levels_ - 1) {
196 const auto& finer_indices = point_idcs_.at(level);
197 auto n_finer_points =
static_cast<index_t
>(finer_indices.size());
198 valuesd finer_weights(n_finer_points);
199 for (index_t i = 0; i < n_finer_points; i++) {
200 finer_weights(i) = weights(finer_indices.at(i));
202 evaluator(level, level - 1).set_weights(finer_weights);
204 evaluator(level, level - 1).set_weights(weights);
206 auto fit = evaluator(level, level - 1).evaluate();
208 const auto& indices = point_idcs_.at(level - 1);
209 auto n_points =
static_cast<index_t
>(indices.size());
210 for (index_t i = 0; i < n_points; i++) {
211 residuals(indices.at(i)) -= fit(i);
214 if (n_poly_basis_ > 0) {
216 auto n_cols = p_.cols();
217 for (index_t i = 0; i < n_cols; i++) {
218 auto dot = p_.col(i).dot(weights);
219 weights -= dot * p_.col(i);
220 residuals += dot * ap_.col(i);
224 weights_total.head(n_points_) += weights;
226 if (kReportResidual) {
227 finest_evaluator_->set_weights(weights_total);
228 valuesd test_residuals = v.head(n_points_) - finest_evaluator_->evaluate();
229 std::cout <<
"Residual after level " << level <<
": " << test_residuals.norm() << std::endl;
234 valuesd weights = valuesd::Zero(n_points_ + n_poly_basis_);
237 coarse_->solve(residuals);
238 coarse_->set_solution_to(weights);
242 const auto& coarse_indices = point_idcs_.at(0);
243 auto n_coarse_points =
static_cast<index_t
>(coarse_indices.size());
244 valuesd coarse_weights(n_coarse_points + n_poly_basis_);
245 for (index_t i = 0; i < n_coarse_points; i++) {
246 coarse_weights(i) = weights(coarse_indices.at(i));
248 coarse_weights.tail(n_poly_basis_) = weights.tail(n_poly_basis_);
249 evaluator(0, level - 1).set_weights(coarse_weights);
251 auto fit = evaluator(0, level - 1).evaluate();
253 const auto& indices = point_idcs_.at(level - 1);
254 auto n_points =
static_cast<index_t
>(indices.size());
255 for (index_t i = 0; i < n_points; i++) {
256 residuals(indices.at(i)) -= fit(i);
260 weights_total += weights;
262 if (kReportResidual) {
263 finest_evaluator_->set_weights(weights_total);
264 valuesd test_residuals = v.head(n_points_) - finest_evaluator_->evaluate();
265 std::cout <<
"Residual after level 0: " << test_residuals.norm() << std::endl;
270 return weights_total;
273 index_t ras_preconditioner::size()
const {
return n_points_ + n_poly_basis_; }
该命名空间下主要定义了关于krylov子空间方法的预处理相关的类和函数