FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
slip_filter_assembler.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, FEAT
9#include <kernel/assembly/base.hpp>
10#include <kernel/assembly/unit_filter_assembler.hpp>
11#include <kernel/lafem/slip_filter.hpp>
12#include <kernel/lafem/sparse_vector_blocked.hpp>
13#include <kernel/geometry/mesh_node.hpp>
14#include <kernel/geometry/intern/face_index_mapping.hpp>
15#include <kernel/space/lagrange1/element.hpp>
16#include <kernel/space/lagrange2/element.hpp>
17
18// includes, system
19#include <vector>
20
21namespace FEAT
22{
23 namespace Assembly
24 {
25
27 namespace Intern
28 {
29 template<typename Space_, int shape_dim_ = Space_::shape_dim>
30 class Lagrange2InterpolatorWrapper;
31 }
33
59 template<typename Trafo_>
61 {
62 public:
64 typedef Trafo_ TrafoType;
66 typedef typename TrafoType::MeshType MeshType;
68 typedef typename MeshType::ShapeType ShapeType;
70 // i.e. Simplex<2> faces for a Simplex<3> mesh
71 typedef typename Shape::FaceTraits<ShapeType, ShapeType::dimension - 1>::ShapeType FacetType;
72
74 static constexpr int facet_dim = ShapeType::dimension-1;
76 static constexpr int world_dim = MeshType::world_dim;
77
79 //static constexpr int nvt_loc = TrafoType::num_coeff_facet;
81
83 typedef typename MeshType::CoordType CoordType;
84
106 static void compute_orientations(CoordType* orientation, const Index* facets, const MeshType& mesh)
107 {
108 // Various index sets for the parent
109 const auto& idx_vert_at_facet(mesh.template get_index_set<facet_dim, 0>());
110 const auto& idx_vert_at_shape(mesh.template get_index_set<ShapeType::dimension, 0>());
111 const auto& idx_facet_at_shape(mesh.template get_index_set<ShapeType::dimension, facet_dim>());
112
113 // This will contain the local vertex indices in the reference cell numbering
114 typename MeshType::template IndexSet<facet_dim, 0>::Type::IndexTupleType reference_numbering;
115 // This will contain the local vertex indices as they are numbered in the mesh
116 typename MeshType::template IndexSet<facet_dim, 0>::Type::IndexTupleType my_numbering;
117 Index num_elements = mesh.get_num_elements();
118
119 // Go check all cells in the mesh
120 FEAT_PRAGMA_OMP(parallel for)
121 for(Index k = 0; k < num_elements; ++k)
122 {
123 // Check all facets
124 for(int l(0); l < Shape::FaceTraits<ShapeType, facet_dim>::count; ++l)
125 {
126 // Index of the l-th facet in the parent mesh
127 Index parent_l(idx_facet_at_shape[k][l]);
128
129 // If the facet is in the meshpart ...
130 if(facets[parent_l] != ~Index(0))
131 {
132 // ... check the numbering
133 for(int i(0); i < nvt_loc; ++i)
134 {
135 // The FaceIndexMapping gives us the reference cell numbering of the facet
136 int j(Geometry::Intern::FaceIndexMapping<ShapeType, facet_dim, 0>::map(l,i));
137 reference_numbering[i] = idx_vert_at_shape[k][j];
138
139 // This is how the facet is numbered in the mesh
140 my_numbering[i] = idx_vert_at_facet[parent_l][i];
141 }
142
143 // Get the orientation code. This describes if the facet given by my_numbering is a rotation of the
144 // reference facet or a rotation of an inverted reference facet
145 int orientation_code = Geometry::Intern::CongruencySampler<FacetType>::compare(reference_numbering, my_numbering);
146
147 // The orientation of the facet is the (possibly inverted) orientation of the appropriate facet in
148 // the reference cell
149 orientation[parent_l] = CoordType(
150 Geometry::Intern::CongruencySampler<FacetType>::orientation(orientation_code)
152 }
153 } // facets
154 } // cells
155 } // compute_orientations
156
186 template<typename VectorType_, typename TrafoType_>
188 VectorType_& nu,
189 const Index* facets,
190 const CoordType* orientation,
191 const TrafoType_& trafo)
192 {
193 typedef typename VectorType_::DataType DataType;
194
195 nu.format(DataType(0));
196 // Vertex at facet index set from the parent
197 auto& idx(trafo.get_mesh().template get_index_set<facet_dim,0>());
198 // Temporary vector for holding one normal at a time
199 Tiny::Vector<DataType, world_dim> tmp(DataType(0));
200
201 // create a facet trafo evaluator
202 typename TrafoType_::template Evaluator<FacetType, CoordType>::Type facet_evaluator(trafo);
203
204 // For every cell in the meshpart, compute the outer normal vectors in all local Lagrange points of the
205 // element's transformation
206 for(Index k(0); k < trafo.get_mesh().get_num_entities(facet_dim); ++k)
207 {
208 if(facets[k] != ~Index(0) )
209 {
210 facet_evaluator.prepare(k);
211 CoordType vol = facet_evaluator.volume();
212 facet_evaluator.finish();
213 //CoordType vol(trafo.template compute_vol<FacetType>(k));
214
215 // Compute all normals
217
218 // Add the local contributions to the vector that is numbered according to the parent
219 for(int l(0); l < nvt_loc; ++l)
220 {
221 tmp = nu(idx[k][l]) + nu_loc[l]*DataType(orientation[k]*vol);
222 nu(idx[k][l], tmp);
223 }
224 }
225 }
226
228 //for(Index i(0); i < nu.used_elements(); ++i)
229 //{
230 // Index j(nu.indices()[i]);
231 // tmp = nu(j);
232 // tmp.normalize();
233
234 // nu(j,tmp);
235 //}
236 } // compute_outer_unit_normal
237
248 template<typename TrafoType_>
250 {
251 // Evaluator on Faces
252 typedef typename TrafoType_::template Evaluator<FacetType, CoordType>::Type FaceEvaluator;
253 // Type of the Jacobian it returns
254 typedef typename FaceEvaluator::JacobianMatrixType JacobianMatrixType;
255
256 // Evaluator for the trafo
257 FaceEvaluator trafo_eval(trafo);
258 trafo_eval.prepare(k);
259
260 // This will be the coordinates of the Lagrange points on the reference cell the face is parametrized over
261 Tiny::Matrix<CoordType, nvt_loc, ShapeType::dimension - 1> xloc(CoordType(0));
262 for(int i(0); i < nvt_loc; ++i)
263 {
264 for(int d(0); d < ShapeType::dimension - 1 ; ++d)
265 xloc(i,d) = Shape::ReferenceCell<FacetType>::template vertex<CoordType>(i,d);
266 }
267
268 // The Jacobian matrix of the transformation
269 JacobianMatrixType jac_mat;
270 // This will hold the local tangential surface coordinate system at one Lagrange point of the local face
271 Tiny::Matrix<CoordType, MeshType::world_dim-1, MeshType::world_dim> tau(CoordType(0));
272
273 // This will hold the oriented unit normal vector for all Lagrange points of the face
275 for(int i(0); i < nvt_loc; ++i)
276 {
277 tau.format();
278
279 // Compute the tangential vectors at the Lagrange points: They are the gradients wrt. the parametrization
280 // of the transformation evaluated in the Lagrange points
281 trafo_eval.calc_jac_mat(jac_mat, xloc[i]);
282
283 // Now write the cross product of the tangentials into nu[i]
284 nu[i] = Tiny::orthogonal(jac_mat);
285 // Normalize nu
286 nu[i].normalize();
287 }
288
289 return nu;
290
291 } // compute_oriented_normals
292
293 }; // struct OuterNormalComputer
294
308 template<typename Trafo_>
310 {
311 public:
313 typedef Trafo_ TrafoType;
315 typedef typename TrafoType::MeshType MeshType;
317 typedef typename MeshType::CoordType CoordType;
319 typedef typename Geometry::TargetSetHolder<typename MeshType::ShapeType> TargetSetHolderType;
321 static constexpr int facet_dim = MeshType::shape_dim-1;
323 static constexpr int world_dim = MeshType::world_dim;
324
325 private:
329 std::vector<Index> _facets;
331 std::vector<CoordType> _orientation;
335 Index _num_entities[MeshType::shape_dim+1];
338
339 public:
349 explicit SlipFilterAssembler(const TrafoType& trafo) :
350 _trafo(trafo),
351 _facets(trafo.get_mesh().get_num_entities(facet_dim), ~Index(0)),
352 _orientation(trafo.get_mesh().get_num_entities(facet_dim), CoordType(0)),
353 _recompute(false),
355 {
356 for(int i(0); i < MeshType::shape_dim+1; ++i)
357 _num_entities[i] = Index(0);
358 }
359
366
371 {
372 }
373
384 {
385 // Adding a MeshPart changes the structures
386 this->_recompute = true;
387 const auto& facet_target(meshpart.template get_target_set<facet_dim>());
388
389 for(Index l(0); l < facet_target.get_num_entities(); l++)
390 {
391 // Add the new facet if it is not already there
392 if(_facets[facet_target[l]] == ~Index(0))
393 {
394 _facets[facet_target[l]] = _num_entities[facet_dim];
396 }
397 }
398 }
399
408 {
409 // We know how many facets we have from add_mesh_part
411
412 auto& facet_targets = _target_set_holder.template get_target_set<facet_dim>();
413
414 // Copy the facet information from the marker array
415 for(Index l(0); l < mesh.get_num_entities(facet_dim); ++l)
416 {
417 if(_facets[l] != ~Index(0))
418 facet_targets[_facets[l]] = l;
419 }
420
421 // Now we deduct the vertices/edges/whatever at the slip boundary from the facet target mapping
422 Geometry::Intern::template TargetSetComputer<facet_dim, 0>::top_to_bottom(
423 _target_set_holder, mesh.get_index_set_holder());
424
425 // Update num_entities information from the possibly modified _target_set_holder
426 for(int d(0); d <= facet_dim; ++d)
427 _num_entities[d] = _target_set_holder.get_num_entities(d);
428 }
429
448 template<typename DataType_, typename IndexType_>
450 {
451 // Allocate the filter if necessary
452 if(filter.get_nu().size() == Index(0))
453 {
455 (space.get_trafo().get_mesh().get_num_entities(0), space.get_num_dofs());
456 }
457
458 // Compute orientations if necessary
459 if(_recompute)
460 {
462 }
463
464 // Compute the weighted outer unit normal field
466 filter.get_nu(), _facets.data(), _orientation.data(), space.get_trafo());
467
468 // Generate the filter vector. For the Lagrange 1 with standard trafo case, this is just a clone operation
469 filter.get_filter_vector().clone(filter.get_nu());
470 }
471
497 template<typename DataType_, typename IndexType_>
499 {
500 typedef Space::Lagrange2::Element<Trafo_> SpaceType;
501
502 // The mesh the FE space lives on
503 const auto& mesh = space.get_trafo().get_mesh();
504
505 // Allocate the filter if necessary
506 if(filter.get_nu().size() == Index(0))
507 {
509 (mesh.get_num_entities(0), space.get_num_dofs());
510 }
511
512 // Compute orientations if necessary
513 if(_recompute)
514 {
515 recompute_target_set_holder(space.get_trafo().get_mesh());
517 }
518
519 // Compute the weighted outer unit normal field
521 filter.get_nu(), _facets.data(), _orientation.data(), space.get_trafo());
522
523 // We only have something to do if the filter is not empty after recompute_target_set_holder()
524 if(filter.get_nu().used_elements() > Index(0))
525 {
526 Intern::Lagrange2InterpolatorWrapper<SpaceType>::project(
527 filter.get_filter_vector(), filter.get_nu(), space, &_target_set_holder);
528
529 // re-normalize
530 auto* nu = filter.get_values();
531 for(Index i(0); i < filter.used_elements(); ++i)
532 nu[i].normalize();
533 }
534 }
535 }; // class SlipFilterAssembler
536
538 namespace Intern
539 {
540 /*
541 * This is a hackish implementation of a Lagrange 1 to Lagrange 2 interpolator and mostly copied from
542 * interpolator.hpp. The critical thing is that it requires the application of node functionals of one space
543 * to FE functions from another space, so in general this will not be well-defined (like applying Q2 node
544 * functionals (which are point evaluations) to Q1~ functions (which are not continuous). In the case of
545 * conforming Lagrange elements, it is well-defined however, and implemented below.
546 */
547 template<typename Vector_, typename Space_, int shape_dim_>
548 struct Lagrange2InterpolatorCore
549 {
550 public:
551 template< typename TSH_>
552 static void project(Vector_& lagrange_2_vector, const Vector_& lagrange_1_vector, const Space_& space, const TSH_* tsh)
553 {
554 typedef typename Vector_::DataType DataType;
555 typedef typename Vector_::ValueType ValueType;
556
557 // define dof assignment
558 typedef typename Space_::template DofAssignment<shape_dim_, DataType>::Type DofAssignType;
559 DofAssignType dof_assign(space);
560
561 // skip empty dof assignments
562 if(dof_assign.get_max_assigned_dofs() < 1)
563 return;
564
565 // Vertex at shape index set
566 auto& idx(space.get_trafo().get_mesh().template get_index_set<shape_dim_, 0>());
567
568 // loop over all entities
569 if(tsh == nullptr)
570 {
571 const Index num_shapes = space.get_mesh().get_num_entities(shape_dim_);
572 for(Index shape(0); shape < num_shapes; ++shape)
573 {
574 ValueType tmp(DataType(0));
575
576 // evaluate the "node functional"
577 for(int j(0); j < idx.get_num_indices(); ++j)
578 tmp += lagrange_1_vector(idx(shape, j));
579
580 tmp *= DataType(1)/DataType(idx.get_num_indices());
581 tmp.normalize();
582
583 // prepare dof-assignment
584 dof_assign.prepare(shape);
585
586 // loop over all contributions
587 Index dof_index(dof_assign.get_index(0));
588 lagrange_2_vector(dof_index, tmp);
589
590 // finish
591 dof_assign.finish();
592 }
593 }
594 else
595 {
596 auto& ts = tsh->template get_target_set<shape_dim_>();
597
598 // loop over all entities
599 const Index num_shapes = ts.get_num_entities();
600
601 for(Index shape(0); shape < num_shapes; ++shape)
602 {
603 ValueType tmp(DataType(0));
604
605 // evaluate the "node functional"
606 for(int j(0); j < idx.get_num_indices(); ++j)
607 tmp += lagrange_1_vector(idx(ts[shape], j));
608
609 tmp *= DataType(1)/DataType(idx.get_num_indices());
610 tmp.normalize();
611
612 // prepare dof-assignment
613 dof_assign.prepare(ts[shape]);
614
615 // loop over all contributions
616 Index dof_index(dof_assign.get_index(0));
617 lagrange_2_vector(dof_index, tmp);
618
619 // finish
620 dof_assign.finish();
621 }
622 }
623 }
624 };
625
626 template<typename Vector_, typename Space_>
627 struct Lagrange2InterpolatorCore<Vector_, Space_, 0>
628 {
629 public:
630 template<typename TSH_>
631 static void project(Vector_& lagrange_2_vector, const Vector_& lagrange_1_vector, const Space_& space, const TSH_* tsh)
632 {
633 typedef typename Vector_::DataType DataType;
634 typedef typename Vector_::ValueType ValueType;
635
636 // define dof assignment
637 typedef typename Space_::template DofAssignment<0, DataType>::Type DofAssignType;
638 DofAssignType dof_assign(space);
639
640 if(tsh == nullptr)
641 {
642 // loop over all entities
643 const Index num_verts = space.get_mesh().get_num_entities(0);
644 for(Index vert(0); vert < num_verts; ++vert)
645 {
646 // prepare dof-assignment
647 dof_assign.prepare(vert);
648
649 // "loop over all contributions"
650 Index dof_index(dof_assign.get_index(0));
651
652 // evaluate the "node functional"
653 ValueType tmp(lagrange_1_vector(vert));
654 lagrange_2_vector(dof_index, tmp);
655
656 // finish
657 dof_assign.finish();
658 }
659 }
660 else
661 {
662 auto& ts = tsh->template get_target_set<0>();
663 // loop over all entities
664 const Index num_verts = ts.get_num_entities();
665 for(Index vert(0); vert < num_verts; ++vert)
666 {
667 // prepare dof-assignment
668 dof_assign.prepare(ts[vert]);
669
670 // "loop over all contributions"
671 Index dof_index(dof_assign.get_index(0));
672
673 // evaluate the "node functional"
674 ValueType tmp(lagrange_1_vector(ts[vert]));
675 lagrange_2_vector(dof_index, tmp);
676
677 // finish
678 dof_assign.finish();
679 }
680 }
681 }
682 };
683
684 template<typename Space_, int shape_dim_>
685 class Lagrange2InterpolatorWrapper
686 {
687 public:
688 template<typename Vector_, typename TSH_>
689 static void project(Vector_& lagrange_2_vector, const Vector_& lagrange_1_vector, const Space_& space, const TSH_* tsh)
690 {
691 // recurse down
692 Lagrange2InterpolatorWrapper<Space_, shape_dim_ - 1>::project(lagrange_2_vector, lagrange_1_vector, space, tsh);
693
694 // call interpolator core
695 Lagrange2InterpolatorCore<Vector_, Space_, shape_dim_>::project(lagrange_2_vector, lagrange_1_vector, space, tsh);
696 }
697 };
698
699 template<typename Space_>
700 class Lagrange2InterpolatorWrapper<Space_, 0>
701 {
702 public:
703 template<typename Vector_, typename TSH_>
704 static void project(Vector_& lagrange_2_vector, const Vector_& lagrange_1_vector, const Space_& space, const TSH_* tsh)
705 {
706 // call interpolator core
707 Lagrange2InterpolatorCore<Vector_, Space_, 0>::project(lagrange_2_vector, lagrange_1_vector, space, tsh);
708 }
709 };
710
711 } // namespace Intern
713
714 } //namespace Assembly
715} // namespace FEAT
Helper class that computes a weighted outer unit normal field.
MeshType::CoordType CoordType
Floating point type.
static void compute_orientations(CoordType *orientation, const Index *facets, const MeshType &mesh)
Computes facet orientations.
TrafoType::MeshType MeshType
The underlying mesh type.
static constexpr int facet_dim
The shape dimension of the boundary faces.
static constexpr int world_dim
The number of coordinates for each vertex.
Shape::FaceTraits< ShapeType, ShapeType::dimension-1 >::ShapeType FacetType
Shape of the facets that make up the boundary we want to compute the normals for,.
static Tiny::Matrix< CoordType, nvt_loc, MeshType::world_dim > compute_oriented_normals(const TrafoType_ &trafo, Index k)
Computes all oriented normals on one face.
Trafo_ TrafoType
Type for the transformation.
static constexpr int nvt_loc
The number of vertices that make up a Facet, i.e. 4 for a Hypercube<2>
MeshType::ShapeType ShapeType
Shape of the mesh's cells.
static void compute_outer_unit_normal(VectorType_ &nu, const Index *facets, const CoordType *orientation, const TrafoType_ &trafo)
Computes an outer unit normal field.
Contains routines to assemble slip filters.
virtual ~SlipFilterAssembler()
Virtual destructor.
SlipFilterAssembler(const TrafoType &trafo)
Constructor from mesh.
SlipFilterAssembler & operator=(SlipFilterAssembler &&)=delete
Explicitly delete the move assignment operator.
static constexpr int world_dim
The number of coordinates for each vertex.
bool _recompute
Flag when to recompute _facets and _orientation (i.e. if MeshParts get added)
void assemble(LAFEM::SlipFilter< DataType_, IndexType_, world_dim > &filter, const Space::Lagrange2::Element< Trafo_ > &space)
Assembles a homogeneous SlipFilter for a Lagrange 2 FE space.
void add_mesh_part(const Geometry::MeshPart< MeshType > &meshpart)
Adds a MeshPart to the assembler.
SlipFilterAssembler(SlipFilterAssembler &&)=delete
Explicitly delete the move constructor.
MeshType::CoordType CoordType
Floating point type.
Geometry::TargetSetHolder< typename MeshType::ShapeType > TargetSetHolderType
Type for the mapping of slip boundary entities to mesh entities.
std::vector< CoordType > _orientation
For every facet in the mesh, this is its orientation in the mesh.
TrafoType::MeshType MeshType
The mesh type.
static constexpr int facet_dim
shape dimension
void recompute_target_set_holder(const MeshType &mesh)
Recomputes the target mapping for geometric entities.
const TrafoType & _trafo
a reference to the trafo that we want to assemble on
std::vector< Index > _facets
Facets for the slip condition get marked by this.
Index _num_entities[MeshType::shape_dim+1]
Number of entities of various shape dimensions in the slip boundary represented by this filter.
void assemble(LAFEM::SlipFilter< DataType_, IndexType_, world_dim > &filter, const Space::Lagrange1::Element< Trafo_ > &space)
Assembles a homogeneous SlipFilter for a Lagrange 1 FE space.
SlipFilterAssembler(const SlipFilterAssembler &)=delete
Explicitly delete the copy constructor.
TargetSetHolderType _target_set_holder
Mapping of boundary entities to mesh entities (i.e. vertices, edges, facets)
Class template for partial meshes.
Definition: mesh_part.hpp:90
Slip Filter class template.
Definition: slip_filter.hpp:67
TrafoType & get_trafo()
Returns a reference to the trafo.
Standard Lagrange-1 Finite-Element space class template.
Definition: element.hpp:39
Index get_num_dofs() const
Returns the number of dofs.
Definition: element.hpp:120
Standard Lagrange-2 Finite-Element space class template.
Definition: element.hpp:39
Index get_num_dofs() const
Returns the number of dofs.
Definition: element.hpp:121
Tiny Matrix class template.
Tiny Vector class template.
Vector< T_, m_ > orthogonal(const Matrix< T_, m_, m_-1, sm_, sn_ > &tau)
Computes the positively oriented orthogonal vector to the columns of a m_ x (m_-1) Matrix.
FEAT namespace.
Definition: adjactor.hpp:12
std::uint64_t Index
Index data type.
@ jac_mat
specifies whether the trafo should supply jacobian matrices
Face traits tag struct template.
Definition: shape.hpp:106
Reference cell traits structure.
Definition: shape.hpp:230