FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
trace_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/asm_traits.hpp>
10#include <kernel/geometry/mesh_part.hpp>
11#include <kernel/geometry/intern/face_ref_trafo.hpp>
12#include <kernel/geometry/intern/congruency_sampler.hpp>
13#include <kernel/geometry/intern/congruency_trafo.hpp>
14#include <kernel/geometry/intern/index_representative.hpp>
15#include <kernel/lafem/dense_vector.hpp>
16#include <kernel/lafem/dense_vector_blocked.hpp>
17
18#include <vector>
19
20namespace FEAT
21{
22 namespace Assembly
23 {
25 namespace Intern
26 {
27 template<typename Outer_, typename Shape_, int cell_dim_>
28 class CompIndexMap
29 {
30 protected:
31 const Outer_& _outer;
32 int _idx;
33
34 public:
35 explicit CompIndexMap(const Outer_& outer, int idx) : _outer(outer), _idx(idx) {}
36
37 Index operator[](int i) const
38 {
39 return _outer[Geometry::Intern::FaceIndexMapping<Shape_, cell_dim_, 0>::map(_idx,i)];
40 }
41 }; // class CompIndexMap
42 } // namespace Intern
44
45#ifdef DOXYGEN
62 {
63 public:
180 class Task
181 {
182 public:
186 static constexpr bool assemble_pairwise = true or false;
187
192 static constexpr bool need_scatter = true or false;
193
198 static constexpr bool need_combine = true or false;
199
213 explicit Task(TraceAssemblyJob& job);
214
242 void prepare(Index facet, Index cell, int local_facet, int facet_ori);
243
270 void prepare(Index facet, Index cell_a, Index cell_b, int local_facet_a, int local_facet_b, int facet_ori_a, int facet_ori_b);
271
283 void assemble();
284
302 void scatter();
303
315 void finish();
316
333 void combine();
334 }; // class Task
335 }; // class TraceAssemblyJob
336#endif // DOXYGEN
337
371 template<typename Trafo_>
373 {
374 public:
375 typedef Trafo_ TrafoType;
376 typedef typename TrafoType::MeshType MeshType;
377 typedef typename TrafoType::ShapeType ShapeType;
378
379 static constexpr int shape_dim = ShapeType::dimension;
380 static constexpr int facet_dim = shape_dim-1;
381
382 protected:
384 const TrafoType& _trafo;
386 std::vector<int> _facet_mask, _cell_facet, _facet_ori;
388 std::vector<Index> _cells, _facets;
389
390 public:
397 explicit TraceAssembler(const TrafoType& trafo) :
398 _trafo(trafo),
399 _facet_mask(trafo.get_mesh().get_num_entities(facet_dim), 0)
400 {
401 }
402
404 const TrafoType& get_trafo() const
405 {
406 return _trafo;
407 }
408
412 void clear()
413 {
414 _cell_facet.clear();
415 _facet_ori.clear();
416 _cells.clear();
417 _facets.clear();
418 for(auto& f : _facets)
419 f = Index(0);
420 }
421
428 void add_facet(Index ifacet)
429 {
430 ASSERTM(ifacet < Index(_facet_mask.size()), "invalid facet index");
431 _facet_mask.at(ifacet) = 1;
432 }
433
441 {
442 const auto& trg = mesh_part.template get_target_set<facet_dim>();
443 for(Index i(0); i < trg.get_num_entities(); ++i)
444 _facet_mask.at(trg[i]) = 1;
445 }
446
457 void compile()
458 {
459 _cell_facet.clear();
460 _facet_ori.clear();
461 _cells.clear();
462 _facets.clear();
463
464 // build elements-at-facet graph
466 _trafo.get_mesh().template get_index_set<shape_dim, facet_dim>());
467
468 // loop over all facets
469 for(Index iface(0); iface < Index(_facet_mask.size()); ++iface)
470 {
471 // use this facet?
472 if(_facet_mask[iface] == 0)
473 continue;
474
475 // ensure that this is a boundary facet if required
476 //if(only_boundary && (elem_at_facet.degree(iface) != Index(1)))
477 //XABORTM("facet is adjacent to more than 1 element");
478
479 // add all elements
480 for(auto it = elem_at_facet.image_begin(iface); it != elem_at_facet.image_end(iface); ++it)
481 {
482 Index icell = *it;
483
484 // try to compute local facet index and orientation
485 int loc_face(0), face_ori(0);
486 if(!_find_local_facet(iface, icell, loc_face, face_ori))
487 XABORTM("failed to find local facet");
488
489 // alright, add this facet to our list
490 _facets.push_back(iface);
491 _cells.push_back(icell);
492 _cell_facet.push_back(loc_face);
493 _facet_ori.push_back(face_ori);
494 }
495 }
496 }
497
508 void compile_all_facets(bool inner, bool outer)
509 {
510 _cell_facet.clear();
511 _facet_ori.clear();
512 _cells.clear();
513 _facets.clear();
514
515 // build elements-at-facet graph
517 _trafo.get_mesh().template get_index_set<shape_dim, facet_dim>());
518
519 // loop over all facets
520 for(Index iface(0); iface < Index(_facet_mask.size()); ++iface)
521 {
522 // how many elements are adjacent to this facet?
523 const int degree = int(elem_at_facet.degree(iface));
524 XASSERT(degree > 0);
525 XASSERT(degree < 3);
526
527 // outer facet with only 1 adjacent element?
528 if((degree == 1) && !outer)
529 continue;
530
531 // inner facet with 2 adjacent elements?
532 if((degree == 2) && !inner)
533 continue;
534
535 // add all elements
536 for(auto it = elem_at_facet.image_begin(iface); it != elem_at_facet.image_end(iface); ++it)
537 {
538 Index icell = *it;
539
540 // try to compute local facet index and orientation
541 int loc_face(0), face_ori(0);
542 if(!_find_local_facet(iface, icell, loc_face, face_ori))
543 XABORTM("failed to find local facet");
544
545 // alright, add this facet to our list
546 _facets.push_back(iface);
547 _cells.push_back(icell);
548 _cell_facet.push_back(loc_face);
549 _facet_ori.push_back(face_ori);
550 }
551 }
552 }
553
561 template<typename Job_>
562 void assemble(Job_& job)
563 {
564 typedef typename Job_::Task TaskType;
565
566 //XASSERTM(_compiled, "assembler has not been compiled yet");
567
568 // no facets to assemble on?
569 if(this->_facets.empty())
570 return;
571
572 // create a task for this thread
573 std::unique_ptr<TaskType> task(new TaskType(job));
574
575 // note: in the case of inner facets, a single inner facet is stored twice in the _facets
576 // vector in two successive elements, i.e. one has _facets[i] == _facets[i+1], and the
577 // corresponding two adjacent cells are given by _cells[i] and _cells[i+1]
578
579 // loop over all facets that have been added to the assembler
580 for(Index fi(0); fi < Index(_facets.size()); ++fi)
581 {
582 // prepare task -- either pairwise or not
583 if constexpr(TaskType::assemble_pairwise)
584 {
585 // task supports pairwise assembly, so let's check if the next facet is an inner facet
586 Index fj = fi+1u;
587 if((fj < Index(_facets.size())) && (_facets[fi] == _facets[fj]))
588 {
589 // that's an inner facet, so assemble pairwise here
590 task->prepare(_facets[fi], _cells[fi], _cells[fj], _cell_facet[fi], _cell_facet[fj], _facet_ori[fi], _facet_ori[fj]);
591
592 // make sure we don't try to assemble on fi+1 again
593 ++fi;
594 }
595 else
596 {
597 // not an inner facet, so call single-cell prepare overload
598 task->prepare(_facets[fi], _cells[fi], _cell_facet[fi], _facet_ori[fi]);
599 }
600 }
601 else
602 {
603 // task does not support pairwise assembly, so always call the single-cell prepare overload
604 task->prepare(_facets[fi], _cells[fi], _cell_facet[fi], _facet_ori[fi]);
605 }
606
607 // assemble task
608 task->assemble();
609
610 // scatter
611 if(task->need_scatter)
612 {
613 task->scatter();
614 }
615
616 // finish
617 task->finish();
618 }
619
620 // do we have to combine the assembly?
621 if(task->need_combine)
622 {
623 // combine the assembly
624 task->combine();
625 }
626
627 // delete task object
628 task.reset();
629 }
630
631 protected:
652 bool _find_local_facet(Index face, Index cell, int& facet, int& ori)
653 {
655 static constexpr int num_facets = Shape::FaceTraits<ShapeType, shape_dim-1>::count;
656 static constexpr int num_vaf = Shape::FaceTraits<FacetType, 0>::count;
657
658 typedef Geometry::Intern::IndexRepresentative<FacetType> FacetRepr;
659
660 const auto& vert_at_elem = _trafo.get_mesh().template get_index_set<shape_dim, 0>();
661 const auto& vert_at_face = _trafo.get_mesh().template get_index_set<facet_dim, 0>();
662
663 Index face_verts[num_vaf];
664 FacetRepr::compute(face_verts, vert_at_face[face]);
665
666 for(int li(0); li < num_facets; ++li)
667 {
668 Intern::CompIndexMap<decltype(vert_at_elem[0]), ShapeType, shape_dim-1> cim(vert_at_elem[cell], li);
669 Index lf_verts[num_vaf];
670 FacetRepr::compute(lf_verts, cim);
671 bool match = true;
672 for(int k(0); k < num_vaf; ++k)
673 {
674 if(lf_verts[k] != face_verts[k])
675 {
676 match = false;
677 break;
678 }
679 }
680 if(match)
681 {
682 ori = Geometry::Intern::CongruencySampler<FacetType>::compare(vert_at_face[face], cim);
683 facet = li;
684 return true;
685 }
686 }
687 return false;
688 }
689 }; // class TraceAssembler<...>
690 } // namespace Assembly
691} // namespace FEAT
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define ASSERTM(expr, msg)
Debug-Assertion macro definition with custom message.
Definition: assertion.hpp:230
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
Adjacency Graph implementation.
Definition: graph.hpp:34
ImageIterator image_begin(Index domain_node) const
Returns an iterator for the first adjacent image node.
Definition: graph.hpp:958
ImageIterator image_end(Index domain_node) const
Returns an iterator for the first position past the last adjacent image node.
Definition: graph.hpp:966
Index degree(Index domain_node) const
Returns the degree of a domain node.
Definition: graph.hpp:333
Trace Integral Assembler class template.
void assemble(Job_ &job)
Executes a trace assembly job.
void add_mesh_part(const Geometry::MeshPart< MeshType > &mesh_part)
Adds all facets of a mesh part to the assembler.
bool _find_local_facet(Index face, Index cell, int &facet, int &ori)
Helper function: tries to find the local facet index for a given facet/cell pair.
std::vector< Index > _cells
the indices of all cells and facets to loop over during assembly
void compile_all_facets(bool inner, bool outer)
Compiles the assembler for all inner and/our outer facets of the underlying mesh.
void add_facet(Index ifacet)
Adds a single facet to the assembler.
TraceAssembler(const TrafoType &trafo)
Constructor.
std::vector< int > _facet_mask
the facet masks, local cell facet indices and facet orientation codes
const TrafoType & get_trafo() const
const TrafoType & _trafo
a reference to the trafo
void compile()
Compiles the assembler for all facets that have been added manually.
void clear()
Clears the assembler.
Task(TraceAssemblyJob &job)
Mandatory Constructor.
void prepare(Index facet, Index cell_a, Index cell_b, int local_facet_a, int local_facet_b, int facet_ori_a, int facet_ori_b)
Prepares the task for assembly for a facet on both of its adjacent elements.
static constexpr bool need_combine
Specifies whether this task fas a combine() function, which is required to be called from within a cr...
void prepare(Index facet, Index cell, int local_facet, int facet_ori)
Prepares the task for assembly for a facet on a single one of its adjacent elements.
static constexpr bool assemble_pairwise
Specifies whether this task assembles element pairs on inner facets simultaenously.
void assemble()
Performs the local assembly on the current facet.
void scatter()
Scatters the local assembly into the global system.
static constexpr bool need_scatter
Specifies whether this task has a scatter() function, which is required to be called from within a cr...
void combine()
Finishes the overall assembly and combines all local results.
void finish()
Finishes the task on the current cell.
Interface description of a trace assembly job.
Class template for partial meshes.
Definition: mesh_part.hpp:90
@ injectify_transpose
Render-Injectified-Transpose mode.
FEAT namespace.
Definition: adjactor.hpp:12
std::uint64_t Index
Index data type.
Face traits tag struct template.
Definition: shape.hpp:106