RSMesh 1.0.0
一个曲面重构的系统,输入为点云,输出为obj,stl等主流格式的网格文件,使用的方法为径向基函数插值,采取了并行优化、Intel-MKL等优化措施,支持百万级别的点云
载入中...
搜索中...
未找到
ras_preconditioner.cpp
1//
2// Created by RainSure on 2024/2/14.
3//
4
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"
13#include <algorithm>
14#include <cmath>
15#include <iomanip>
16#include <iostream>
17#include <numeric>
18#include <tuple>
19#include <utility>
20
21namespace rsmesh::preconditioner {
22 ras_preconditioner::ras_preconditioner(const model& model, const geometry::points3d& points)
23 : ras_preconditioner(model, points, geometry::points3d(0, 3)) {}
24
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()),
28 points_(points),
29 n_points_(points.rows()),
30 n_grad_points_(grad_points.rows()),
31 n_poly_basis_(model.poly_basis_size()),
32 finest_evaluator_(
33 kReportResidual
34 ? std::make_unique<interpolation::rbf_symmetric_evaluator<Order>>(model, points_)
35 : nullptr) {
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;
41
42 point_idcs_.resize(n_levels_);
43 grad_point_idcs_.resize(n_levels_);
44
45 std::vector<index_t> poly_point_idcs;
46 {
47 auto level = n_levels_ - 1;
48
49 if (n_poly_basis_ > 0) {
50 polynomial::unisolvent_point_set ups(points_, model.poly_dimension(), model.poly_degree());
51
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_);
56
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);
62 }
63 }
64 } else {
65 point_idcs_.at(level).resize(n_points_);
66 std::iota(point_idcs_.at(level).begin(), point_idcs_.at(level).end(), 0);
67 }
68
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);
71 }
72
73 fine_grids_.resize(n_levels_);
74
75 std::cout << std::setw(8) << "level" << std::setw(16) << "n_domains" << std::setw(16)
76 << "n_points" << std::endl;
77
78 for (auto level = n_levels_ - 1; level >= 1; level--) {
79 auto n_mixed_points =
80 static_cast<index_t>(point_idcs_.at(level).size() + grad_point_idcs_.at(level).size());
81
82 auto divider = std::make_unique<domain_divider>(points_, grad_points_, point_idcs_.at(level),
83 grad_point_idcs_.at(level), poly_point_idcs);
84
85 auto ratio = level == 1
86 ? static_cast<double>(n_coarsest_points) / static_cast<double>(n_mixed_points)
87 : coarse_ratio;
88 std::tie(point_idcs_.at(level - 1), grad_point_idcs_.at(level - 1)) =
89 divider->choose_coarse_points(ratio);
90
91 for (auto&& d : divider->into_domains()) {
92 fine_grids_.at(level).emplace_back(model, std::move(d));
93 }
94
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_);
101 }
102 }
103
104 std::cout << std::setw(8) << level << std::setw(16) << n_grids << std::setw(16)
105 << n_mixed_points << std::endl;
106 }
107
108 {
109 auto n_mixed_points =
110 static_cast<index_t>(point_idcs_.at(0).size() + grad_point_idcs_.at(0).size());
111
112 domain coarse_domain;
113 coarse_domain.point_indices = point_idcs_.at(0);
114 coarse_domain.grad_point_indices = grad_point_idcs_.at(0);
115
116 coarse_ = std::make_unique<coarse_grid>(model, std::move(coarse_domain));
117 coarse_->setup(points_, grad_points_, lagrange_pt_);
118
119 std::cout << std::setw(8) << 0 << std::setw(16) << 1 << std::setw(16) << n_mixed_points
120 << std::endl;
121 }
122
123 if (n_levels_ == 1) {
124 return;
125 }
126
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);
131 } else {
132 add_evaluator(level, level - 1, model_without_poly_,
133 points_(point_idcs_.at(level), Eigen::all), bbox);
134 }
135 evaluator(level, level - 1).set_field_points(points_(point_idcs_.at(level - 1), Eigen::all));
136 }
137
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));
141 }
142
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_);
147
148 ap_ = Eigen::MatrixXd(p_.rows(), p_.cols());
149
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();
156 }
157 }
158 }
159
160 valuesd ras_preconditioner::operator()(const valuesd& v) const {
161 RSMESH_ASSERT(v.rows() == size());
162
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;
169 }
170
171 if (kReportResidual) {
172 std::cout << "Initial residual: " << residuals.norm() << std::endl;
173 }
174
175 for (auto level = n_levels_ - 1; level >= 1; level--) {
176 {
177 valuesd weights = valuesd::Zero(n_points_);
178
179 // Solve on level `level`.
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_);
186 }
187 fine.solve(residuals);
188 fine.set_solution_to(weights);
189 if (kRecomputeAndClear) {
190 fine.clear();
191 }
192 }
193
194 // Evaluate residuals on level `level` - 1.
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));
201 }
202 evaluator(level, level - 1).set_weights(finer_weights);
203 } else {
204 evaluator(level, level - 1).set_weights(weights);
205 }
206 auto fit = evaluator(level, level - 1).evaluate();
207
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);
212 }
213
214 if (n_poly_basis_ > 0) {
215 // Orthogonalize weights against P.
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);
221 }
222 }
223
224 weights_total.head(n_points_) += weights;
225
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;
230 }
231 }
232
233 {
234 valuesd weights = valuesd::Zero(n_points_ + n_poly_basis_);
235
236 // Solve on level 0.
237 coarse_->solve(residuals);
238 coarse_->set_solution_to(weights);
239
240 // Update residuals on level `level` - 1.
241 if (level > 1) {
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));
247 }
248 coarse_weights.tail(n_poly_basis_) = weights.tail(n_poly_basis_);
249 evaluator(0, level - 1).set_weights(coarse_weights);
250
251 auto fit = evaluator(0, level - 1).evaluate();
252
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);
257 }
258 }
259
260 weights_total += weights;
261
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;
266 }
267 }
268 }
269
270 return weights_total;
271 }
272
273 index_t ras_preconditioner::size() const { return n_points_ + n_poly_basis_; }
274} // namespace rsmesh::preconditioner
vectors3d points3d
3维点的集合
Definition point3d.h:48
该命名空间下主要定义了关于krylov子空间方法的预处理相关的类和函数