11 #ifndef BEMBEL_SRC_ANSATZSPACE_PROJECTOR_HPP_
12 #define BEMBEL_SRC_ANSATZSPACE_PROJECTOR_HPP_
15 namespace ProjectorRoutines {
19 template <
typename Derived,
unsigned int DF>
21 static Eigen::SparseMatrix<double> makeMatrix(
23 const int knotrepetition) {
24 assert(
false &&
"This needs to be specialized");
25 return Eigen::SparseMatrix<double>(1, 1);
39 template <
typename Derived>
73 const int knot_repetition) {
74 knot_repetition_ = knot_repetition;
75 projector_ = makeProjectionMatrix(super_space, knot_repetition);
76 dofs_before_projector_ = projector_.rows();
77 dofs_after_projector_ = projector_.cols();
112 Eigen::SparseMatrix<double> makeProjectionMatrix(
121 int knot_repetition_;
122 int dofs_before_projector_;
123 int dofs_after_projector_;
124 Eigen::SparseMatrix<double> projector_;
125 Projector(
const Projector<Derived>& other);
127 Projector& operator=(
const Projector<Derived>& other);
128 Projector& operator=(Projector<Derived>&& other);
132 namespace ProjectorRoutines {
140 std::vector<double> vals;
141 std::vector<int> rows;
142 std::vector<int> cols;
147 template <
typename Derived>
165 inline _proj_info makeLocalProjectionTriplets(
167 const int knotrepetition_in) {
168 const int M = super_space.get_refinement_level();
169 const int maximal_polynomial_degree = std::max(pp1x, pp1y);
170 assert(maximal_polynomial_degree == super_space.get_polynomial_degree() + 1 &&
171 "superSpace not suitable for desired ansatz space -> polynomial "
173 const int minp = std::min(pp1x, pp1y);
174 const int knotrepetition = (maximal_polynomial_degree <= knotrepetition_in)
177 const int n = (1 << M);
178 const int patch_number = super_space.get_number_of_patches();
182 assert(std::abs(maximal_polynomial_degree - minp) <= 1);
187 std::vector<double> c_space_knot_x =
188 Spl::MakeUniformKnotVector(pp1x, n - 1, knotrepetition);
189 std::vector<double> c_space_knot_y =
190 Spl::MakeUniformKnotVector(pp1y, n - 1, knotrepetition);
191 const int c_space_dim_x = c_space_knot_x.size() - pp1x;
192 const int c_space_dim_y = c_space_knot_y.size() - pp1y;
193 const int c_space_dim = c_space_dim_x * c_space_dim_y;
197 out.cols.reserve(c_space_dim * maximal_polynomial_degree *
198 maximal_polynomial_degree * patch_number);
199 out.vals.reserve(c_space_dim * maximal_polynomial_degree *
200 maximal_polynomial_degree * patch_number);
201 out.rows.reserve(c_space_dim * maximal_polynomial_degree *
202 maximal_polynomial_degree * patch_number);
204 std::vector<double> mask =
205 Spl::MakeInterpolationMask(maximal_polynomial_degree);
206 const int masksize = mask.size();
209 assert(masksize == maximal_polynomial_degree &&
210 "projector.cpp: System needs to be square");
211 Eigen::Matrix<double, -1, -1> system(
213 maximal_polynomial_degree * maximal_polynomial_degree);
218 double vals_y[Constants::MaxP + 1];
219 double vals_x[Constants::MaxP + 1];
220 for (
int iy = 0; iy < maximal_polynomial_degree; ++iy) {
221 Bembel::Basis::ShapeFunctionHandler::evalBasis(
222 maximal_polynomial_degree - 1, vals_y, mask[iy]);
223 for (
int ix = 0; ix < maximal_polynomial_degree; ++ix) {
224 Bembel::Basis::ShapeFunctionHandler::evalBasis(
225 maximal_polynomial_degree - 1, vals_x, mask[ix]);
226 for (
int jy = 0; jy < maximal_polynomial_degree; ++jy) {
227 for (
int jx = 0; jx < maximal_polynomial_degree; ++jx) {
228 system(iy * masksize + ix, jy * maximal_polynomial_degree + jx) =
229 vals_x[jx] * vals_y[jy];
238 const Eigen::PartialPivLU<Eigen::Matrix<double, -1, -1>> pplu(system);
240 unsigned int element_number = 0;
246 const double pos_x = element->llc_(0);
247 const double pos_y = element->llc_(1);
249 const double h = element->get_h();
250 const double mid_x = pos_x + (.5 * h);
251 const double mid_y = pos_y + (.5 * h);
255 std::vector<double> nonzero_dofs_x;
256 std::vector<double> nonzero_dofs_y;
257 nonzero_dofs_x.reserve(pp1x);
258 nonzero_dofs_y.reserve(pp1y);
259 for (
int dof_y = 0; dof_y < c_space_dim_y; ++dof_y) {
260 if ((c_space_knot_y[dof_y] <= mid_y) &&
261 (c_space_knot_y[dof_y + pp1y] >= mid_y)) {
262 nonzero_dofs_y.push_back(dof_y);
265 for (
int dof_x = 0; dof_x < c_space_dim_x; ++dof_x) {
266 if ((c_space_knot_x[dof_x] <= mid_x) &&
267 (c_space_knot_x[dof_x + pp1x] >= mid_x)) {
268 nonzero_dofs_x.push_back(dof_x);
271 nonzero_dofs_x.shrink_to_fit();
272 nonzero_dofs_y.shrink_to_fit();
275 for (
auto dof_y : nonzero_dofs_y) {
276 for (
auto dof_x : nonzero_dofs_x) {
279 std::vector<double> local_mask_x(masksize);
280 std::vector<double> local_mask_y(masksize);
281 for (
int i = 0; i < masksize; ++i) {
282 local_mask_x[i] = pos_x + (1.0 / n) * mask[i];
283 local_mask_y[i] = pos_y + (1.0 / n) * mask[i];
284 assert(local_mask_x[i] < 1 && local_mask_x[i] > 0);
285 assert(local_mask_y[i] < 1 && local_mask_y[i] > 0);
289 std::vector<double> c_coefs_x(c_space_dim_x, 0.0);
290 std::vector<double> c_coefs_y(c_space_dim_y, 0.0);
291 c_coefs_x[dof_x] = 1.;
292 c_coefs_y[dof_y] = 1.;
295 std::vector<double> vals_x =
296 Spl::DeBoor(c_coefs_x, c_space_knot_x, local_mask_x);
297 std::vector<double> vals_y =
298 Spl::DeBoor(c_coefs_y, c_space_knot_y, local_mask_y);
301 Eigen::VectorXd rhs(masksize * masksize);
302 for (
int iy = 0; iy < masksize; ++iy)
303 for (
int ix = 0; ix < masksize; ++ix)
304 rhs(iy * masksize + ix) = vals_x[ix] * vals_y[iy];
305 Eigen::VectorXd sol = pplu.solve(rhs);
309 i < maximal_polynomial_degree * maximal_polynomial_degree; ++i) {
310 if (std::abs(sol(i)) > Constants::projector_tolerance) {
311 out.cols.push_back(element->patch_ * (c_space_dim) +
312 (c_space_dim_x * dof_y) + dof_x);
313 out.rows.push_back((element_number * maximal_polynomial_degree *
314 maximal_polynomial_degree) +
316 out.vals.push_back(sol(i));
324 out.num_c_dof = c_space_dim_x * c_space_dim_y * patch_number;
325 out.num_dc_dof = maximal_polynomial_degree * maximal_polynomial_degree * n *
328 out.cols.shrink_to_fit();
329 out.rows.shrink_to_fit();
330 out.vals.shrink_to_fit();
332 assert((out.vals.size() == out.rows.size()) &&
333 (out.rows.size() == out.cols.size()) &&
334 "projector.cpp: you made a mistake, try again.");
344 template <
typename Derived>
346 static Eigen::SparseMatrix<double> makeMatrix(
348 const int P = super_space.get_polynomial_degree();
349 assert(P > 0 &&
"P must be 1 or larger for this type of discrete space");
350 assert(knotrepetition <= P &&
351 "Knot repetition must be smaller than P for this type of discrete "
355 Derived, DifferentialForm::Discontinuous>::makeMatrix(super_space,
370 template <
typename Derived>
372 static Eigen::SparseMatrix<double> makeMatrix(
374 assert(super_space.get_polynomial_degree() > 0 &&
375 "P must be 1 or larger for this type of discrete space");
376 assert(knotrepetition <= super_space.get_polynomial_degree() &&
377 "Knot repetition must be smaller than P for this type of discrete "
379 const auto info1 = ProjectorRoutines::makeLocalProjectionTriplets<Derived>(
380 super_space, super_space.get_polynomial_degree() + 1,
381 super_space.get_polynomial_degree(), knotrepetition);
382 const auto info2 = ProjectorRoutines::makeLocalProjectionTriplets<Derived>(
383 super_space, super_space.get_polynomial_degree(),
384 super_space.get_polynomial_degree() + 1, knotrepetition);
385 const int size1 = info1.vals.size();
386 const int size2 = info2.vals.size();
387 assert(size1 == size2);
388 std::vector<Eigen::Triplet<double>> trips;
389 for (
int k = 0; k < size1; ++k) {
391 Eigen::Triplet<double>(info1.rows[k], info1.cols[k], info1.vals[k]));
393 for (
int k = 0; k < size2; ++k) {
394 trips.push_back(Eigen::Triplet<double>(info2.rows[k] + info1.num_dc_dof,
395 info2.cols[k] + info1.num_c_dof,
398 Eigen::SparseMatrix<double> local_matrix(
399 info1.num_dc_dof + info2.num_dc_dof, info1.num_c_dof + info2.num_c_dof);
400 local_matrix.setFromTriplets(trips.begin(), trips.end());
412 template <
typename Derived>
414 static Eigen::SparseMatrix<double> makeMatrix(
416 const auto info = ProjectorRoutines::makeLocalProjectionTriplets<Derived>(
417 super_space, super_space.get_polynomial_degree() + 1,
418 super_space.get_polynomial_degree() + 1, knotrepetition);
419 const int size = info.vals.size();
420 std::vector<Eigen::Triplet<double>> trips;
421 for (
int k = 0; k < size; ++k) {
423 Eigen::Triplet<double>(info.rows[k], info.cols[k], info.vals[k]));
425 Eigen::SparseMatrix<double> local_matrix(info.num_dc_dof, info.num_c_dof);
426 local_matrix.setFromTriplets(trips.begin(), trips.end());
ElementTree & get_element_tree()
getter
ElementTreeNode::const_iterator cpbegin() const
Returns an iterator to the beginning of the sequence represented by the leafs as ElementTreeNodes of ...
ElementTreeNode::const_iterator cpend() const
Returns an iterator one past the end of the sequence represented by the leafs as ElementTreeNodes of ...
The Projector provides routines to assemble smooth B-Splines on each patch.
void init_Projector(const SuperSpace< Derived > &super_space, const int knot_repetition)
init
const Eigen::SparseMatrix< double > & get_projection_matrix()
This function returns the transformation matrix to assemble smooth tensor product B-splines.
int get_knot_repetition() const
getter
int get_dofs_after_projector() const
Return number of smooth B-splines.
Projector(const SuperSpace< Derived > &super_space, const int knot_repetition)
Constructor for the Projector.
Eigen::Matrix< T, -1, -1 > DeBoor(Eigen::Matrix< T, -1, -1 > const &control_points, const std::vector< double > &knot_vector, const std::vector< double > &evaluation_points) noexcept
"By the book" implementations of the Cox-DeBoor formula. Inefficient, do not use at bottlenecks.
Routines for the evalutation of pointwise errors.
struct containing specifications on the linear operator has to be specialized or derived for any part...
Helper struct for assembling the Projector for the different cases.
The superspace manages local polynomial bases on each element of the mesh and provides an interface t...