Loading...
Searching...
No Matches
surface_kernel.cpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6 *
7 * -------------------------------------------------------------------------
8 * License
9 * This file is part of bitpit.
10 *
11 * bitpit is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License v3 (LGPL)
13 * as published by the Free Software Foundation.
14 *
15 * bitpit is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 * License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with bitpit. If not, see <http://www.gnu.org/licenses/>.
22 *
23\*---------------------------------------------------------------------------*/
24
25#define _USE_MATH_DEFINES
26
27#include <cmath>
28#include <limits>
29#include <set>
30#if BITPIT_ENABLE_MPI==1
31#include <mpi.h>
32#endif
33
34#if BITPIT_ENABLE_MPI==1
35#include "bitpit_communications.hpp"
36#endif
37
38#include "bitpit_CG.hpp"
39#include "surface_kernel.hpp"
40
41namespace bitpit {
42
53const std::map<ElementType, unsigned short> SurfaceKernel::m_selectionTypes({
54 {ElementType::QUAD, SurfaceKernel::SELECT_QUAD},
55 {ElementType::TRIANGLE, SurfaceKernel::SELECT_TRIANGLE}
56 });
57const unsigned short SurfaceKernel::SELECT_TRIANGLE = 1;
58const unsigned short SurfaceKernel::SELECT_QUAD = 2;
59const unsigned short SurfaceKernel::SELECT_ALL = 3;
60
61#if BITPIT_ENABLE_MPI==1
78SurfaceKernel::SurfaceKernel(MPI_Comm communicator, std::size_t haloSize,
79 AdaptionMode adaptionMode, PartitioningMode partitioningMode)
80 : PatchKernel(communicator, haloSize, adaptionMode, partitioningMode)
81#else
88 : PatchKernel(adaptionMode)
89#endif
90{
91 initialize();
92}
93
94#if BITPIT_ENABLE_MPI==1
112SurfaceKernel::SurfaceKernel(int dimension, MPI_Comm communicator, std::size_t haloSize,
113 AdaptionMode adaptionMode, PartitioningMode partitioningMode)
114 : PatchKernel(dimension, communicator, haloSize, adaptionMode, partitioningMode)
115#else
122SurfaceKernel::SurfaceKernel(int dimension, AdaptionMode adaptionMode)
123 : PatchKernel(dimension, adaptionMode)
124#endif
125{
126 initialize();
127}
128
129#if BITPIT_ENABLE_MPI==1
148SurfaceKernel::SurfaceKernel(int id, int dimension, MPI_Comm communicator, std::size_t haloSize,
149 AdaptionMode adaptionMode, PartitioningMode partitioningMode)
150 : PatchKernel(id, dimension, communicator, haloSize, adaptionMode, partitioningMode)
151#else
159SurfaceKernel::SurfaceKernel(int id, int dimension, AdaptionMode adaptionMode)
160 : PatchKernel(id, dimension, adaptionMode)
161#endif
162{
163}
164
168void SurfaceKernel::initialize()
169{
170 // Nothing to do
171}
172
179{
180 return 1;
181}
182
189{
190 return 0;
191}
192
199{
200 return -1;
201}
202
209{
210 return -2;
211}
212
222{
224}
225
232double SurfaceKernel::evalCellSize(long id) const
233{
234
235 // ====================================================================== //
236 // VARIABLES DECLARATION //
237 // ====================================================================== //
238
239 // Local variables
240 const Cell *cell_ = &m_cells[id];
241
242 // Counters
243 // none
244
245 // ====================================================================== //
246 // COMPUTE CELL SIZE //
247 // ====================================================================== //
248 if ((cell_->getType() == ElementType::UNDEFINED)
249 || (cell_->getType() == ElementType::VERTEX)) return 0.0;
250 if (cell_->getType() == ElementType::LINE) {
251 return evalCellArea(id);
252 }
253 return(sqrt(evalCellArea(id)));
254}
255
263void SurfaceKernel::evalBarycentricCoordinates(long id, const std::array<double, 3> &point, double *lambda) const
264{
265
266 // ====================================================================== //
267 // VARIABLES DECLARATION //
268 // ====================================================================== //
269
270 // Local variables
271 const Cell *cell_ = &m_cells[id];
272
273 // Counters
274 // none
275
276 // ====================================================================== //
277 // COMPUTE BARYCENTRIC COORDINATES
278 // ====================================================================== //
279 switch (cell_->getType()) {
280
281 case ElementType::VERTEX:
282 {
283 lambda[0] = 1.0;
284 return;
285 }
286
287 case ElementType::LINE:
288 {
289 ConstProxyVector<long> vertexIds = cell_->getVertexIds();
290
291 std::array<double,3> point0 = getVertexCoords(vertexIds[0]);
292 std::array<double,3> point1 = getVertexCoords(vertexIds[1]);
293
294 std::array<double, 3> projectionPoint = CGElem::projectPointSegment(point, point0, point1, lambda);
295 BITPIT_UNUSED(projectionPoint);
296 return;
297 }
298
299 case ElementType::TRIANGLE:
300 {
301 ConstProxyVector<long> vertexIds = cell_->getVertexIds();
302
303 std::array<double,3> point0 = getVertexCoords(vertexIds[0]);
304 std::array<double,3> point1 = getVertexCoords(vertexIds[1]);
305 std::array<double,3> point2 = getVertexCoords(vertexIds[2]);
306
307 std::array<double,3> projectionPoint = CGElem::projectPointTriangle(point, point0, point1, point2, lambda);
308 BITPIT_UNUSED(projectionPoint);
309 return;
310 }
311
312 default:
313 {
315
316 std::size_t nVertices = vertexIds.size();
317 BITPIT_CREATE_WORKSPACE(vertexCoords, std::array<double BITPIT_COMMA 3>, nVertices, ReferenceElementInfo::MAX_ELEM_VERTICES);
318 getVertexCoords(vertexIds.size(), vertexIds.data(), vertexCoords);
319
320 std::array<double,3> projectionPoint = CGElem::projectPointPolygon(point, nVertices, vertexCoords, lambda);
321 BITPIT_UNUSED(projectionPoint);
322 return;
323 }
324
325 }
326}
327
336double SurfaceKernel::evalCellArea(long id) const
337{
338 // ====================================================================== //
339 // VARIABLES DECLARATION //
340 // ====================================================================== //
341
342 // Local variables
343 const Cell *cell_ = &m_cells[id];
344 ConstProxyVector<long> cellVertexIds = cell_->getVertexIds();
345
346 // Counters
347 // none
348
349 // ====================================================================== //
350 // EVALUATE FACET AREA //
351 // ====================================================================== //
352 if ((cell_->getType() == ElementType::UNDEFINED)
353 || (cell_->getType() == ElementType::VERTEX)) return 0.0;
354 if (cell_->getType() == ElementType::LINE) {
355 return ( norm2(m_vertices[cellVertexIds[0]].getCoords()
356 - m_vertices[cellVertexIds[1]].getCoords()) );
357 }
358 std::array<double, 3> d1, d2;
359 if (cell_->getType() == ElementType::TRIANGLE) {
360 d1 = m_vertices[cellVertexIds[1]].getCoords() - m_vertices[cellVertexIds[0]].getCoords();
361 d2 = m_vertices[cellVertexIds[2]].getCoords() - m_vertices[cellVertexIds[0]].getCoords();
362 return (0.5*norm2(crossProduct(d1, d2)));
363 }
364 else {
365 int nvert = cellVertexIds.size();
366 double coeff = 0.25;
367 double area = 0.0;
368 for (int i = 0; i < nvert; ++i) {
369 int prevVertex = getFacetOrderedLocalVertex(*cell_, (nvert + i - 1) % nvert);
370 int vertex = getFacetOrderedLocalVertex(*cell_, i);
371 int nextVertex = getFacetOrderedLocalVertex(*cell_, (i + 1) % nvert);
372
373 const std::array<double, 3> &prevVertexCoords = m_vertices[cellVertexIds[prevVertex]].getCoords();
374 const std::array<double, 3> &vertexCoords = m_vertices[cellVertexIds[vertex]].getCoords();
375 const std::array<double, 3> &nextVertexCoords = m_vertices[cellVertexIds[nextVertex]].getCoords();
376
377 d1 = nextVertexCoords - vertexCoords;
378 d2 = prevVertexCoords - vertexCoords;
379 area += coeff*norm2(crossProduct(d1, d2));
380 } //next i
381 return(area);
382 }
383}
384
395double SurfaceKernel::evalEdgeLength(long cellId, int edgeId) const
396{
397 // ====================================================================== //
398 // VARIABLES DECLARATION //
399 // ====================================================================== //
400
401 // Local variables
402 const Cell &cell = m_cells[cellId];
403 double edge_length;
404
405 // Counters
406 // none
407
408 // ====================================================================== //
409 // COMPUTE MIN EDGE SIZE //
410 // ====================================================================== //
411 switch (cell.getType()) {
412
413 case ElementType::LINE:
414 case ElementType::VERTEX:
415 case ElementType::UNDEFINED:
416 {
417 edge_length = 0.;
418 break;
419 }
420
421 default:
422 {
423 ConstProxyVector<long> faceVertexIds = cell.getFaceVertexIds(edgeId);
424 const Vertex &vertex_0 = m_vertices[faceVertexIds[0]];
425 const Vertex &vertex_1 = m_vertices[faceVertexIds[1]];
426 edge_length = norm2(vertex_0.getCoords() - vertex_1.getCoords());
427 break;
428 }
429
430 }
431
432 return edge_length;
433}
434
445double SurfaceKernel::evalMinEdgeLength(long id, int &edge_id) const
446{
447 // ====================================================================== //
448 // VARIABLES DECLARATION //
449 // ====================================================================== //
450
451 // Local variables
452 const Cell *cell_ = &m_cells[id];
453
454 // Counters
455 int i;
456 int n_faces;
457
458 // ====================================================================== //
459 // COMPUTE MIN EDGE SIZE //
460 // ====================================================================== //
461 if ((cell_->getType() == ElementType::LINE)
462 || (cell_->getType() == ElementType::VERTEX)
463 || (cell_->getType() == ElementType::UNDEFINED)) return 0.0;
464
465 double edge_length = std::numeric_limits<double>::max(), tmp;
466 n_faces = cell_->getFaceCount();
467 for (i = 0; i < n_faces; ++i) {
468 tmp = evalEdgeLength(id, i);
469 if (tmp < edge_length) {
470 edge_length = tmp;
471 edge_id = i;
472 }
473 } //next i
474
475 return(edge_length);
476}
477
488double SurfaceKernel::evalMaxEdgeLength(long id, int &edge_id) const
489{
490 // ====================================================================== //
491 // VARIABLES DECLARATION //
492 // ====================================================================== //
493
494 // Local variables
495 const Cell *cell_ = &m_cells[id];
496
497 // Counters
498 int i;
499 int n_faces;
500
501 // ====================================================================== //
502 // COMPUTE MIN EDGE SIZE //
503 // ====================================================================== //
504 if ((cell_->getType() == ElementType::LINE)
505 || (cell_->getType() == ElementType::VERTEX)
506 || (cell_->getType() == ElementType::UNDEFINED)) return 0.0;
507
508 double edge_length = std::numeric_limits<double>::min(), tmp;
509 n_faces = cell_->getFaceCount();
510 for (i = 0; i < n_faces; ++i) {
511 tmp = evalEdgeLength(id, i);
512 if (tmp > edge_length) {
513 edge_length = tmp;
514 edge_id = i;
515 }
516 } //next i
517
518 return(edge_length);
519}
520
532double SurfaceKernel::evalAngleAtVertex(long id, int vertex) const
533{
534 const Cell &cell = m_cells.at(id);
535 ElementType cellType = cell.getType();
536 if (cellType == ElementType::UNDEFINED) {
537 return 0.;
538 } else if (cellType == ElementType::VERTEX) {
539 return 0.;
540 } else if (cellType == ElementType::LINE) {
541 return BITPIT_PI;
542 }
543
544 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
545 int nCellVertices = cellVertexIds.size();
546
547 int prevVertex = getFacetOrderedLocalVertex(cell, (vertex - 1 + nCellVertices) % nCellVertices);
548 int nextVertex = getFacetOrderedLocalVertex(cell, (vertex + 1) % nCellVertices);
549
550 const std::array<double, 3> &prevVertexCoords = m_vertices[cellVertexIds[prevVertex]].getCoords();
551 const std::array<double, 3> &vertexCoords = m_vertices[cellVertexIds[vertex]].getCoords();
552 const std::array<double, 3> &nextVertexCoords = m_vertices[cellVertexIds[nextVertex]].getCoords();
553
554 std::array<double, 3> d1 = prevVertexCoords - vertexCoords;
555 d1 = d1 / norm2(d1);
556
557 std::array<double, 3> d2 = nextVertexCoords - vertexCoords;
558 d2 = d2 / norm2(d2);
559
560 double angle = std::acos(std::min(1., std::max(-1., dotProduct(d1, d2))));
561
562 return angle;
563}
564
574double SurfaceKernel::evalMinAngleAtVertex(long id, int &vertex_id) const
575{
576 // ====================================================================== //
577 // VARIABLES DECLARATION //
578 // ====================================================================== //
579
580 // Local variables
581 const Cell *cell_ = &m_cells[id];
582
583 // Counters
584 // none
585
586 // ====================================================================== //
587 // COMPUTE MINIMAL ANGLE //
588 // ====================================================================== //
589 if ((cell_->getType() == ElementType::UNDEFINED)
590 || (cell_->getType() == ElementType::VERTEX)
591 || (cell_->getType() == ElementType::LINE)) return 0.0;
592
593 double angle = std::numeric_limits<double>::max(), tmp;
594 int n_vert = cell_->getVertexCount();
595 for (int i = 0; i < n_vert; ++i) {
596 tmp = evalAngleAtVertex(id, i);
597 if (tmp < angle) {
598 angle = tmp;
599 vertex_id = i;
600 }
601 } //next i
602
603 return(angle);
604}
605
615double SurfaceKernel::evalMaxAngleAtVertex(long id, int &vertex_id) const
616{
617 // ====================================================================== //
618 // VARIABLES DECLARATION //
619 // ====================================================================== //
620
621 // Local variables
622 const Cell *cell_ = &m_cells[id];
623
624 // Counters
625 // none
626
627 // ====================================================================== //
628 // COMPUTE MINIMAL ANGLE //
629 // ====================================================================== //
630 if ((cell_->getType() == ElementType::UNDEFINED)
631 || (cell_->getType() == ElementType::VERTEX)
632 || (cell_->getType() == ElementType::LINE)) return 0.0;
633
634 double angle = std::numeric_limits<double>::min(), tmp;
635 int n_vert = cell_->getVertexCount();
636 for (int i = 0; i < n_vert; ++i) {
637 tmp = evalAngleAtVertex(id, i);
638 if (tmp > angle) {
639 angle = tmp;
640 vertex_id = i;
641 }
642 } //next i
643
644 return(angle);
645}
646
657double SurfaceKernel::evalAspectRatio(long id, int &edge_id) const
658{
659 // ====================================================================== //
660 // VARIABLES DECLARATION //
661 // ====================================================================== //
662
663 // Local variables
664 const Cell *cell_ = &m_cells[id];
665
666 // Counters
667 // none
668
669 // ====================================================================== //
670 // EVALUATE ASPECT RATIO //
671 // ====================================================================== //
672 if ((cell_->getType() == ElementType::UNDEFINED)
673 || (cell_->getType() == ElementType::VERTEX)
674 || (cell_->getType() == ElementType::LINE)) return 0.0;
675
676 double l_edge;
677 double m_edge = std::numeric_limits<double>::max();
678 double M_edge = std::numeric_limits<double>::min();
679 int nfaces = cell_->getFaceCount();
680 for (int i = 0; i < nfaces; ++i) {
681 l_edge = evalEdgeLength(id, i);
682 if (l_edge < m_edge) {
683 m_edge = l_edge;
684 edge_id = i;
685 }
686 M_edge = std::max(M_edge, l_edge);
687 } //next i
688
689 return (M_edge/m_edge);
690
691}
692
705std::array<double, 3> SurfaceKernel::evalFacetNormal(long id, const std::array<double, 3> &orientation) const
706{
707 // ====================================================================== //
708 // VARIABLES DECLARATION //
709 // ====================================================================== //
710
711 // Local variables
712 std::array<double, 3> normal = {{0.0, 0.0, 0.0}};
713 const Cell *cell_ = &m_cells[id];
714 ConstProxyVector<long> cellVertexIds = cell_->getVertexIds();
715
716 // Counters
717 // none
718
719 // ====================================================================== //
720 // COMPUTE NORMAL //
721 // ====================================================================== //
722 if ((cell_->getType() == ElementType::UNDEFINED)
723 || (cell_->getType() == ElementType::VERTEX)) return normal;
724
725 if (cell_->getType() == ElementType::LINE) {
726 normal = m_vertices[cellVertexIds[1]].getCoords() - m_vertices[cellVertexIds[0]].getCoords();
727 normal = crossProduct(normal, orientation);
728 }
729
730 if (cell_->getType() == ElementType::TRIANGLE) {
731 std::array<double, 3> d1, d2;
732 d1 = m_vertices[cellVertexIds[1]].getCoords() - m_vertices[cellVertexIds[0]].getCoords();
733 d2 = m_vertices[cellVertexIds[2]].getCoords() - m_vertices[cellVertexIds[0]].getCoords();
734 normal = crossProduct(d1, d2);
735 }
736 else {
737 std::array<double, 3> d1, d2;
738 int i, nvert = cellVertexIds.size();
739 double coeff = 1.0/double(nvert);
740 for (i = 0; i < nvert; ++i) {
741 int prevVertex = getFacetOrderedLocalVertex(*cell_, (nvert + i - 1) % nvert);
742 int vertex = getFacetOrderedLocalVertex(*cell_, i);
743 int nextVertex = getFacetOrderedLocalVertex(*cell_, (i + 1) % nvert);
744
745 const std::array<double, 3> &prevVertexCoords = m_vertices[cellVertexIds[prevVertex]].getCoords();
746 const std::array<double, 3> &vertexCoords = m_vertices[cellVertexIds[vertex]].getCoords();
747 const std::array<double, 3> &nextVertexCoords = m_vertices[cellVertexIds[nextVertex]].getCoords();
748
749 d1 = nextVertexCoords - vertexCoords;
750 d2 = prevVertexCoords - vertexCoords;
751 normal += coeff*crossProduct(d1, d2);
752 } //next i
753 }
754 normal = normal/norm2(normal);
755
756 return(normal);
757
758}
759
769std::array<double, 3> SurfaceKernel::evalEdgeNormal(long id, int edge_id) const
770{
771 std::array<double, 3> normal;
772 evalEdgeNormals(id, edge_id, std::numeric_limits<double>::max(), &normal, nullptr);
773
774 return normal;
775}
776
788std::array<double, 3> SurfaceKernel::evalVertexNormal(long id, int vertex) const
789{
790 std::array<double, 3> normal;
791 std::vector<long> vertexNeighs = findCellVertexNeighs(id, vertex);
792 evalVertexNormals(id, vertex, vertexNeighs.size(), vertexNeighs.data(), std::numeric_limits<double>::max(), &normal, nullptr);
793
794 return normal;
795}
796
810std::array<double, 3> SurfaceKernel::evalVertexNormal(long id, int vertex, std::size_t nVertexNeighs, const long *vertexNeighs) const
811{
812 std::array<double, 3> normal;
813 evalVertexNormals(id, vertex, nVertexNeighs, vertexNeighs, std::numeric_limits<double>::max(), &normal, nullptr);
814
815 return normal;
816}
817
834std::array<double, 3> SurfaceKernel::evalLimitedVertexNormal(long id, int vertex, double limit) const
835{
836 std::array<double, 3> normal;
837 std::vector<long> vertexNeighs = findCellVertexNeighs(id, vertex);
838 evalVertexNormals(id, vertex, vertexNeighs.size(), vertexNeighs.data(), limit, nullptr, &normal);
839
840 return normal;
841}
842
861std::array<double, 3> SurfaceKernel::evalLimitedVertexNormal(long id, int vertex, std::size_t nVertexNeighs, const long *vertexNeighs, double limit) const
862{
863 std::array<double, 3> normal;
864 evalVertexNormals(id, vertex, nVertexNeighs, vertexNeighs, limit, nullptr, &normal);
865
866 return normal;
867}
868
893void SurfaceKernel::evalVertexNormals(long id, int vertex, std::size_t nVertexNeighs, const long *vertexNeighs, double limit,
894 std::array<double, 3> *unlimitedNormal, std::array<double, 3> *limitedNormal) const
895{
896 // Early return if no calculation is needed
897 if (!unlimitedNormal && !limitedNormal) {
898 return;
899 }
900
901 // Get vertex id
902 const Cell &cell = getCell(id);
903 long vertexId = cell.getVertexId(vertex);
904
905 // Get cell information
906 double cellVertexAngle = evalAngleAtVertex(id, vertex);
907 std::array<double, 3> cellNormal = evalFacetNormal(id);
908
909 // Initialize unlimited normal
910 if (unlimitedNormal) {
911 *unlimitedNormal = cellVertexAngle * cellNormal;
912 }
913
914 // Initialize limited normal
915 if (limitedNormal) {
916 *limitedNormal = cellVertexAngle * cellNormal;
917 }
918
919 // Add contribution of neighbouring cells
920 for (std::size_t i = 0; i < nVertexNeighs; ++i) {
921 // Get neighbour information
922 long neighId = vertexNeighs[i];
923 const Cell &neigh = getCell(neighId);
924 std::array<double, 3> neighNormal = evalFacetNormal(neighId);
925 double neighVertexAngle = evalAngleAtVertex(neighId, neigh.findVertex(vertexId));
926
927 // Add contribution to unlimited normal
928 if (unlimitedNormal) {
929 *unlimitedNormal += neighVertexAngle * neighNormal;
930 }
931
932 // Add contribution to limited normal
933 //
934 // Only the negihbours whose normal has a misalignment less then the
935 // specified limit are considered.
936 if (limitedNormal) {
937 // The argument of the acos function has to be in the range [-1, 1].
938 // Rounding errors may lead to a dot product slightly outside this
939 // range. Since the arguments of the dot product are unit vectors,
940 // we can safetly clamp the dot product result to be between -1 and
941 // 1.
942 double misalignment = std::acos(std::min(1.0, std::max(-1.0, dotProduct(neighNormal, cellNormal))));
943 if (misalignment <= std::abs(limit)) {
944 *limitedNormal += neighVertexAngle * neighNormal;
945 }
946 }
947 }
948
949 // Normalize the unlimited normal
950 if (unlimitedNormal) {
951 *unlimitedNormal /= norm2(*unlimitedNormal);
952 }
953
954 // Normalize the unlimited normal
955 if (limitedNormal) {
956 *limitedNormal /= norm2(*limitedNormal);
957 }
958}
959
983void SurfaceKernel::evalEdgeNormals(long id, int edge, double limit,
984 std::array<double, 3> *unlimitedNormal,
985 std::array<double, 3> *limitedNormal) const
986{
987 // Early return if no calculation is needed
988 if (!unlimitedNormal && !limitedNormal) {
989 return;
990 }
991
992 // Get cell information
993 const Cell &cell = getCell(id);
994 std::array<double, 3> cellNormal = evalFacetNormal(id);
995 int nEdgeNeighs = cell.getAdjacencyCount(edge);
996 const long *edgeNeighs = cell.getAdjacencies(edge);
997
998 // Initialize unlimited normal
999 if (unlimitedNormal) {
1000 *unlimitedNormal = cellNormal;
1001 }
1002
1003 // Initialize limited normal
1004 if (limitedNormal) {
1005 *limitedNormal = cellNormal;
1006 }
1007
1008 // Add contribution of neighbouring cells
1009 for (int i = 0; i < nEdgeNeighs; ++i) {
1010 // Get neighbour information
1011 long neighId = edgeNeighs[i];
1012 std::array<double, 3> neighNormal = evalFacetNormal(neighId);
1013
1014 // Add contribution to unlimited normal
1015 if (unlimitedNormal) {
1016 *unlimitedNormal += neighNormal;
1017 }
1018
1019 // Add contribution to limited normal
1020 //
1021 // Only the negihbours whose normal has a misalignment less then the
1022 // specified limit are considered.
1023 if (limitedNormal) {
1024 // The argument of the acos function has to be in the range [-1, 1].
1025 // Rounding errors may lead to a dot product slightly outside this
1026 // range. Since the arguments of the dot product are unit vectors,
1027 // we can safetly clamp the dot product result to be between -1 and
1028 // 1.
1029 double misalignment = std::acos(std::min(1.0, std::max(-1.0, dotProduct(neighNormal, cellNormal))));
1030 if (misalignment <= std::abs(limit)) {
1031 *limitedNormal += neighNormal;
1032 }
1033 }
1034 }
1035
1036 // Normalize the unlimited normal
1037 if (unlimitedNormal) {
1038 *unlimitedNormal /= norm2(*unlimitedNormal);
1039 }
1040
1041 // Normalize the unlimited normal
1042 if (limitedNormal) {
1043 *limitedNormal /= norm2(*limitedNormal);
1044 }
1045}
1046
1053{
1056
1057 std::size_t nUnprocessed = getInternalCellCount();
1058 PiercedStorage<bool> alreadyProcessed(1, &(getCells()));
1059 alreadyProcessed.fill(false);
1060
1061 bool consistent = true;
1062 std::vector<std::size_t> processRawList;
1063 for (CellConstIterator seedItr = internalBegin; seedItr != internalEnd; ++seedItr) {
1064 // Get seed information
1065 long seedRawId = seedItr.getRawIndex();
1066 if (alreadyProcessed.rawAt(seedRawId)) {
1067 continue;
1068 }
1069
1070 // Compare seed orientation with the orientation of its neighbours
1071 processRawList.assign(1, seedRawId);
1072 while (!processRawList.empty()) {
1073 // Get cell to process
1074 std::size_t cellRawId = processRawList.back();
1075 processRawList.pop_back();
1076
1077 // Skip cells already processed
1078 if (alreadyProcessed.rawAt(cellRawId)) {
1079 continue;
1080 }
1081
1082 // Process cell
1083 CellConstIterator cellItr = getCells().rawFind(cellRawId);
1084 const Cell &cell = *cellItr;
1085 int nCellFaces = cell.getFaceCount();
1086 for (int face = 0; face < nCellFaces; ++face) {
1087 int nFaceAdjacencies = cell.getAdjacencyCount(face);
1088 const long *faceAdjacencies = cell.getAdjacencies(face);
1089 for (int i = 0; i < nFaceAdjacencies; ++i) {
1090 // Neighbout information
1091 long neighId = faceAdjacencies[i];
1092 CellConstIterator neighItr = getCells().find(neighId);
1093 const Cell &neigh = getCell(neighId);
1094
1095 // Check neighbour consistency
1096 int neighFace = findAdjoinNeighFace(cell, face, neigh);
1097 bool isNeighConsistent = haveSameOrientation(cell, face, neigh, neighFace);
1098 if (!isNeighConsistent) {
1099 consistent = false;
1100 break;
1101 }
1102
1103 // Add neighbour to the process list
1104 //
1105 // Only internal cells needs to be processed.
1106 if (neigh.isInterior()) {
1107 std::size_t neighRawId = neighItr.getRawIndex();
1108 if (!alreadyProcessed.rawAt(neighRawId)) {
1109 processRawList.push_back(neighRawId);
1110 }
1111 }
1112 }
1113
1114 // Stop processing the cell is the orientation is not consistent
1115 if (!consistent) {
1116 break;
1117 }
1118 }
1119
1120 // Cell processing has been completed
1121 alreadyProcessed.rawSet(cellRawId, true);
1122 --nUnprocessed;
1123 if (nUnprocessed == 0) {
1124 break;
1125 }
1126
1127 // Stop processing the patch is the orientation is not consistent
1128 if (!consistent) {
1129 break;
1130 }
1131 }
1132
1133 // Stop processing the patch is the orientation is not consistent
1134 if (!consistent) {
1135 break;
1136 }
1137
1138 // Check if all cells have been processed
1139 if (nUnprocessed == 0) {
1140 break;
1141 }
1142 }
1143
1144#if BITPIT_ENABLE_MPI==1
1145 // Comunicate consistency flag among the partitions
1146 if (isPartitioned()) {
1147 MPI_Allreduce(MPI_IN_PLACE, &consistent, 1, MPI_C_BOOL, MPI_LAND, getCommunicator());
1148 }
1149#endif
1150
1151 return consistent;
1152}
1153
1166{
1167 // Early return if the patch is empty.
1168 if (empty()) {
1169 return false;
1170 }
1171
1172 // Get the first facet
1173 long firstFacetId = Cell::NULL_ID;
1174 if (getCellCount() > 0) {
1175 firstFacetId = getCells().begin()->getId();
1176 }
1177
1178#if BITPIT_ENABLE_MPI==1
1179 if (isPartitioned()) {
1180 int patchRank = getRank();
1181
1182 int firstFacetRank = std::numeric_limits<int>::max();
1183 if (firstFacetId >= 0) {
1184 firstFacetRank = patchRank;
1185 }
1186
1187 MPI_Allreduce(MPI_IN_PLACE, &firstFacetRank, 1, MPI_INT, MPI_MIN, getCommunicator());
1188 if (patchRank != firstFacetRank) {
1189 firstFacetId = Cell::NULL_ID;
1190 }
1191 }
1192#endif
1193
1194 // Adjust cell orientation according to the orientation of the first facet
1195 return adjustCellOrientation(firstFacetId);
1196}
1197
1198
1215bool SurfaceKernel::adjustCellOrientation(long seed, bool invert)
1216{
1217#if BITPIT_ENABLE_MPI==1
1218 // Check if the communications are needed
1219 bool ghostExchangeNeeded = isPartitioned();
1220
1221 // Initialize ghost communications
1222 std::unordered_set<long> flippedCells;
1223 std::unique_ptr<DataCommunicator> ghostCommunicator;
1224 if (ghostExchangeNeeded) {
1225 ghostCommunicator = std::unique_ptr<DataCommunicator>(new DataCommunicator(getCommunicator()));
1226
1227 for (auto &entry : getGhostCellExchangeSources()) {
1228 const int rank = entry.first;
1229 const std::vector<long> &sources = entry.second;
1230 ghostCommunicator->setSend(rank, 2 * sources.size() * sizeof(unsigned char));
1231 }
1232
1233 for (auto &entry : getGhostCellExchangeTargets()) {
1234 const int rank = entry.first;
1235 const std::vector<long> &targets = entry.second;
1236 ghostCommunicator->setRecv(rank, 2 * targets.size() * sizeof(unsigned char));
1237 }
1238 }
1239#endif
1240
1241 // Initialize list of cells to process
1242 std::vector<std::size_t> processRawList;
1243 if (seed != Element::NULL_ID) {
1244 assert(getCells().exists(seed));
1245 processRawList.push_back(getCells().find(seed).getRawIndex());
1246 if (invert) {
1247 flipCellOrientation(seed);
1248#if BITPIT_ENABLE_MPI==1
1249 if (ghostExchangeNeeded) {
1250 flippedCells.insert(seed);
1251 }
1252#endif
1253 }
1254 }
1255
1256 // Orient the surface
1257 PiercedStorage<bool> alreadyProcessed(1, &(getCells()));
1258 alreadyProcessed.fill(false);
1259
1260 bool orientable = true;
1261 while (true) {
1262 while (!processRawList.empty()) {
1263 // Get cell to process
1264 std::size_t cellRawId = processRawList.back();
1265 processRawList.pop_back();
1266
1267 // Skip cells already processed
1268 if (alreadyProcessed.rawAt(cellRawId)) {
1269 continue;
1270 }
1271
1272 // Process cell
1273 CellConstIterator cellItr = getCells().rawFind(cellRawId);
1274 const Cell &cell = *cellItr;
1275 int nCellFaces = cell.getFaceCount();
1276 for (int face = 0; face < nCellFaces; ++face) {
1277 int nFaceAdjacencies = cell.getAdjacencyCount(face);
1278 const long *faceAdjacencies = cell.getAdjacencies(face);
1279 for (int i = 0; i < nFaceAdjacencies; ++i) {
1280 // Neighbout information
1281 long neighId = faceAdjacencies[i];
1282 CellConstIterator neighItr = getCells().find(neighId);
1283 std::size_t neighRawId = neighItr.getRawIndex();
1284 const Cell &neigh = *neighItr;
1285
1286 // Skip ghost neighbours
1287 if (!neigh.isInterior()) {
1288 continue;
1289 }
1290
1291 // Check neighbour orientation
1292 //
1293 // If the neighour has not been processed yet and its orientation
1294 // is wrong we flip the orientation of the facet.If the neighour
1295 // has already been processed and its orientation is wrong the
1296 // surface is not orientable.
1297 int neighFace = findAdjoinNeighFace(cell, face, neigh);
1298 bool isNeighOriented = haveSameOrientation(cell, face, neigh, neighFace);
1299 if (!isNeighOriented) {
1300 if (!alreadyProcessed.rawAt(neighRawId)) {
1301 flipCellOrientation(neighId);
1302#if BITPIT_ENABLE_MPI==1
1303 if (ghostExchangeNeeded) {
1304 flippedCells.insert(neighId);
1305 }
1306#endif
1307 } else {
1308 orientable = false;
1309 break;
1310 }
1311 }
1312
1313 // Add neighbour to the process list
1314 if (!alreadyProcessed.rawAt(neighRawId)) {
1315 processRawList.push_back(neighRawId);
1316 }
1317 }
1318
1319 // Stop processing the cell if the patch is not orientable
1320 if (!orientable) {
1321 break;
1322 }
1323 }
1324
1325 // Stop processing if the patch is not orientable
1326 if (!orientable) {
1327 break;
1328 }
1329
1330 // Cell processing has been completed
1331 alreadyProcessed.rawSet(cellRawId, true);
1332 }
1333
1334 // If the surface is globally not orientable we can exit
1335#if BITPIT_ENABLE_MPI==1
1336 if (ghostExchangeNeeded) {
1337 MPI_Allreduce(MPI_IN_PLACE, &orientable, 1, MPI_C_BOOL, MPI_LAND, getCommunicator());
1338 }
1339#endif
1340
1341 if (!orientable) {
1342 break;
1343 }
1344
1345#if BITPIT_ENABLE_MPI==1
1346 // Add ghost to the process list
1347 //
1348 // A ghost should be added to the process list if:
1349 // - its orientation was flipped by the owner;
1350 // - it has been processed by the owner but is hass't yet processed by
1351 // the current process.
1352 if (ghostExchangeNeeded) {
1353 // Exchange ghost data
1354 ghostCommunicator->startAllRecvs();
1355
1356 for(auto &entry : getGhostCellExchangeSources()) {
1357 int rank = entry.first;
1358 SendBuffer &buffer = ghostCommunicator->getSendBuffer(rank);
1359 for (long cellId : entry.second) {
1360 std::size_t cellRawId = getCells().find(cellId).getRawIndex();
1361
1362 buffer << static_cast<unsigned char>(alreadyProcessed.rawAt(cellRawId));
1363 if (flippedCells.count(cellId) > 0) {
1364 buffer << static_cast<unsigned char>(1);
1365 } else {
1366 buffer << static_cast<unsigned char>(0);
1367 }
1368 }
1369 ghostCommunicator->startSend(rank);
1370 }
1371
1372 int nPendingRecvs = ghostCommunicator->getRecvCount();
1373 while (nPendingRecvs != 0) {
1374 int rank = ghostCommunicator->waitAnyRecv();
1375 RecvBuffer buffer = ghostCommunicator->getRecvBuffer(rank);
1376
1377 for (long cellId : getGhostCellExchangeTargets(rank)) {
1378 unsigned char processed;
1379 buffer >> processed ;
1380
1381 unsigned char ghostFlipped;
1382 buffer >> ghostFlipped;
1383
1384 if (ghostFlipped == 1 || processed == 1) {
1385 std::size_t cellRawId = getCells().find(cellId).getRawIndex();
1386
1387 if (ghostFlipped == 1) {
1388 flipCellOrientation(cellId);
1389 processRawList.push_back(cellRawId);
1390 alreadyProcessed.rawSet(cellRawId, false);
1391 } else if (processed == 1) {
1392 if (!alreadyProcessed.rawAt(cellRawId)) {
1393 processRawList.push_back(cellRawId);
1394 }
1395 }
1396 }
1397 }
1398
1399 --nPendingRecvs;
1400 }
1401
1402 ghostCommunicator->waitAllSends();
1403
1404 // Clear list of flippedCells cells
1405 flippedCells.clear();
1406 }
1407#endif
1408
1409 // Detect if the orientation is completed
1410 bool completed = processRawList.empty();
1411#if BITPIT_ENABLE_MPI==1
1412 if (ghostExchangeNeeded) {
1413 MPI_Allreduce(MPI_IN_PLACE, &completed, 1, MPI_C_BOOL, MPI_LAND, getCommunicator());
1414 }
1415#endif
1416
1417 if (completed) {
1418 break;
1419 }
1420 }
1421
1422 return orientable;
1423}
1424
1446bool SurfaceKernel::haveSameOrientation(const Cell &cell_A, int face_A, const Cell &cell_B, int face_B) const
1447{
1448 //
1449 // Cell information
1450 //
1451 long cellId_A = cell_A.getId();
1452 ConstProxyVector<long> cellVertexIds_A = cell_A.getVertexIds();
1453 std::size_t nCellVertices_A = cellVertexIds_A.size();
1454
1455 long cellId_B = cell_B.getId();
1456 ConstProxyVector<long> cellVertexIds_B = cell_B.getVertexIds();
1457 std::size_t nCellVertices_B = cellVertexIds_B.size();
1458
1459 assert(cell_A.getDimension() == cell_B.getDimension());
1460 int cellDimension = cell_A.getDimension();
1461 assert(cellDimension < 3);
1462
1463 //
1464 // Check relative orientation using vertices
1465 //
1466
1467 // If the facets share at least two consecutive vertices, it is possible
1468 // to detect relative orientation checking the order in which these two
1469 // vertices appear while traversing the list of vertices of the facets.
1470 // If the vertices appear in the same order, the facets have opposite
1471 // orientation, if the vertices appear in reversed order, the facets have
1472 // the same orientation.
1473 for (std::size_t i = 0; i < nCellVertices_A; ++i) {
1474 long vertexId_A = cellVertexIds_A[getFacetOrderedLocalVertex(cell_A, i)];
1475 for (std::size_t j = 0; j < nCellVertices_B; ++j) {
1476 long vertexId_B = cellVertexIds_B[getFacetOrderedLocalVertex(cell_B, j)];
1477 if (vertexId_A == vertexId_B) {
1478 if (cellDimension == 2) {
1479 long previousVertexId_A = cellVertexIds_A[getFacetOrderedLocalVertex(cell_A, (i - 1 + nCellVertices_A) % nCellVertices_A)];
1480 long previousVertexId_B = cellVertexIds_B[getFacetOrderedLocalVertex(cell_B, (j - 1 + nCellVertices_B) % nCellVertices_B)];
1481
1482 long nextVertexId_A = cellVertexIds_A[getFacetOrderedLocalVertex(cell_A, (i + 1) % nCellVertices_A)];
1483 long nextVertexId_B = cellVertexIds_B[getFacetOrderedLocalVertex(cell_B, (j + 1) % nCellVertices_B)];
1484
1485 if (nextVertexId_A == nextVertexId_B || previousVertexId_A == previousVertexId_B) {
1486 return false;
1487 } else if (nextVertexId_A == previousVertexId_B || previousVertexId_A == nextVertexId_B) {
1488 return true;
1489 }
1490 } else if (cellDimension == 1) {
1491 return (i != j);
1492 } else {
1493 throw std::runtime_error("Unable to identify if the factes has the same orientation.");
1494 }
1495 }
1496 }
1497 }
1498
1499 //
1500 // Check relative orientation using facet normals
1501 //
1502
1503 // The faces doesn't have enough common vertices to check the orientation
1504 // using topological checks, we need a geometric check. Starting from the
1505 // first vertex of the face, we identify three non-collinear vertices and
1506 // we detect their winding. The two facets have the same orientation if
1507 // they have the same winding.
1508 //
1509 // To detect the winding of the vertices, we evaluate the normal of the
1510 // plane defined by the vertices and then we calculate the projection of
1511 // that vector along a direction (called winding direction) which is
1512 // chosen equal for both the cells. The sign of the projection defines
1513 // the winding of the vertices. We don't care if the winding of a single
1514 // cell is clockwise or counter-clockwise, all we care about is if the
1515 // two cells have the same winding.
1516
1517 // Pseudo normal directions
1518 //
1519 // For each face, we identify three non-collinear vertices and we evaluate
1520 // the normal direction of the plane defined by those three vertices.
1521 std::size_t nMaxCellVertices = std::max(nCellVertices_A, nCellVertices_B);
1522 BITPIT_CREATE_WORKSPACE(vertexCoordinates, std::array<double BITPIT_COMMA 3>, nMaxCellVertices, ReferenceElementInfo::MAX_ELEM_VERTICES);
1523
1524 ConstProxyVector<int> faceLocalVertexIds_A = cell_A.getFaceLocalVertexIds(face_A);
1525 ConstProxyVector<int> faceLocalVertexIds_B = cell_B.getFaceLocalVertexIds(face_B);
1526
1527 std::array<double, 3> pseudoNormal_A;
1528 std::array<double, 3> pseudoNormal_B;
1529 for (int i = 0; i < 2; ++i) {
1530 std::array<double, 3> *pseudoNormal;
1531 long firstFaceVertexLocalId;
1532 std::size_t nCellVertices;
1533 if (i == 0) {
1534 pseudoNormal = &pseudoNormal_A;
1535 firstFaceVertexLocalId = faceLocalVertexIds_A[0];
1536 nCellVertices = nCellVertices_A;
1537 getCellVertexCoordinates(cellId_A, vertexCoordinates);
1538 } else {
1539 pseudoNormal = &pseudoNormal_B;
1540 firstFaceVertexLocalId = faceLocalVertexIds_B[0];
1541 nCellVertices = nCellVertices_B;
1542 getCellVertexCoordinates(cellId_B, vertexCoordinates);
1543 }
1544 assert(nCellVertices >= 3);
1545
1546 const std::array<double, 3> &V_0 = vertexCoordinates[(firstFaceVertexLocalId + 0) % nCellVertices];
1547 const std::array<double, 3> &V_1 = vertexCoordinates[(firstFaceVertexLocalId + 1) % nCellVertices];
1548 for (std::size_t k = 2; k < nCellVertices; ++k) {
1549 const std::array<double, 3> &V_2 = vertexCoordinates[(firstFaceVertexLocalId + k) % nCellVertices];
1550
1551 *pseudoNormal = crossProduct(V_0 - V_1, V_2 - V_1);
1552 if (!utils::DoubleFloatingEqual()(norm2(*pseudoNormal), 0.)) {
1553 break;
1554 } else if (k == (nCellVertices - 1)) {
1555 throw std::runtime_error("Unable to identify the non-collinear vertices.");
1556 }
1557 }
1558 }
1559
1560 // Direction for evaluating the winding
1561 //
1562 // This direction has to be the same for both the cells and should not be
1563 // perpendicular to the pseudo normals.
1564 std::array<double, 3> windingDirection = {{0., 0., 1.}};
1565 for (int d = 2; d <= 0; --d) {
1566 windingDirection = {{0., 0., 0.}};
1567 windingDirection[d] = 1.;
1568
1569 double pseudNormalProjection_A = dotProduct(pseudoNormal_A, windingDirection);
1570 double pseudNormalProjection_B = dotProduct(pseudoNormal_B, windingDirection);
1571 if (!utils::DoubleFloatingEqual()(pseudNormalProjection_A, 0.) && !utils::DoubleFloatingEqual()(pseudNormalProjection_B, 0.)) {
1572 break;
1573 } else if (d == 0) {
1574 throw std::runtime_error("Unable to identify the relative orientation of the cells.");
1575 }
1576 }
1577
1578 // Identify the winding of the cells
1579 int cellWinding_A = (dotProduct(pseudoNormal_A, windingDirection) > 0.);
1580 int cellWinding_B = (dotProduct(pseudoNormal_B, windingDirection) > 0.);
1581
1582 return (cellWinding_A == cellWinding_B);
1583}
1584
1591{
1592 // Cell information
1593 Cell &cell = getCell(id);
1594
1595 //
1596 // Flip connectivity
1597 //
1598 // In order to flip cell orientation, we need to reverse the order of
1599 // the vertices:
1600 //
1601 // Vertices 0 1 2 3 4
1602 //
1603 // Flipped vertices 4 3 2 1 0
1604 //
1605 // This means we have to invert the connectivity of the cell.
1606 long *connectivity = cell.getConnect();
1607
1608 if (cell.getType() != ElementType::PIXEL) {
1609 int connectBegin = 0;
1610 if (cell.getType() == ElementType::POLYGON) {
1611 ++connectBegin;
1612 }
1613
1614 int nCellVertices = cell.getVertexCount();
1615 for (int i = 0; i < (int) std::floor(nCellVertices / 2); ++i) {
1616 std::swap(connectivity[connectBegin + i], connectivity[connectBegin + nCellVertices - i - 1]);
1617 }
1618 } else {
1619 std::swap(connectivity[0], connectivity[1]);
1620 std::swap(connectivity[2], connectivity[3]);
1621 }
1622
1623 //
1624 // Flip adjacencies and interfaces
1625 //
1626 // Adjacencies and interfaces are associated with the faces of the cells,
1627 // since we have flipped the connectivity we need to flip also adjacencies
1628 // and interfaces.
1629 //
1630 // For two-dimensional elements faces are defined between two vertices:
1631 //
1632 // Vertices 0 1 2 3 4
1633 // Faces 0 1 2 3 4
1634 //
1635 // Flipped vertices 4 3 2 1 0
1636 // Flipped faces 3 2 1 0 4
1637 //
1638 // We have reversed the order of the vertices, this means that we have
1639 // to invert the order of all the faces but the lust one. Pixel elements
1640 // should be handled separately.
1641 //
1642 // For one-dimensional elements faces are defined on the vertices itself:
1643 //
1644 // Vertices 0 1
1645 // Faces 0 1
1646 //
1647 // Flipped vertices 1 0
1648 // Flipped faces 1 0
1649 //
1650 // We have reversed the order of the vertices, this means that we have
1651 // to invert the order of all the faces.
1652 int nCellAdjacencies = cell.getAdjacencyCount();
1653 int nCellInterfaces = cell.getInterfaceCount();
1654 int nCellFaces = cell.getFaceCount();
1655
1656 FlatVector2D<long> flippedCellAdjacencies;
1657 FlatVector2D<long> flippedCellInterfaces;
1658 flippedCellAdjacencies.reserve(nCellFaces, nCellAdjacencies);
1659 flippedCellInterfaces.reserve(nCellFaces, nCellInterfaces);
1660
1661 if (cell.getType() != ElementType::PIXEL) {
1662 int flipOffset;
1663 if (cell.getDimension() == 1) {
1664 flipOffset = 0;
1665 } else {
1666 flipOffset = 1;
1667 }
1668
1669
1670 for (int i = 0; i < nCellFaces - flipOffset; ++i) {
1671 int nFaceAdjacencies = cell.getAdjacencyCount(nCellFaces - i - 1 - flipOffset);
1672 const long *faceAdjacencies = cell.getAdjacencies(nCellFaces - i - 1 - flipOffset);
1673 flippedCellAdjacencies.pushBack(nFaceAdjacencies, faceAdjacencies);
1674
1675 int nFaceInterfaces = cell.getInterfaceCount(nCellFaces - i - 1 - flipOffset);
1676 const long *faceInterfaces = cell.getInterfaces(nCellFaces - i - 1 - flipOffset);
1677 flippedCellInterfaces.pushBack(nFaceInterfaces, faceInterfaces);
1678 }
1679
1680 if (flipOffset == 1) {
1681 int nLastFaceAdjacencies = cell.getAdjacencyCount(nCellFaces - 1);
1682 const long *lastFaceAdjacencies = cell.getAdjacencies(nCellFaces - 1);
1683 flippedCellAdjacencies.pushBack(nLastFaceAdjacencies, lastFaceAdjacencies);
1684
1685 int nLastFaceInterfaces = cell.getInterfaceCount(nCellFaces - 1);
1686 const long *lastFaceInterfaces = cell.getInterfaces(nCellFaces - 1);
1687 flippedCellInterfaces.pushBack(nLastFaceInterfaces, lastFaceInterfaces);
1688 }
1689 } else {
1690 std::array<int, 4> orderedFaces = {{1, 0, 2, 3}};
1691 for (int face : orderedFaces) {
1692 int nFaceAdjacencies = cell.getAdjacencyCount(face);
1693 const long *faceAdjacencies = cell.getAdjacencies(face);
1694 flippedCellAdjacencies.pushBack(nFaceAdjacencies, faceAdjacencies);
1695
1696 int nFaceInterfaces = cell.getInterfaceCount(face);
1697 const long *faceInterfaces = cell.getInterfaces(face);
1698 flippedCellInterfaces.pushBack(nFaceInterfaces, faceInterfaces);
1699 }
1700 }
1701
1702 // Set flipped adjacencies
1703 if (nCellAdjacencies > 0) {
1704 cell.setAdjacencies(std::move(flippedCellAdjacencies));
1705 }
1706
1707 // Set flipped interfaces
1708 //
1709 // After setting the flipped interfaces, we also need to update the face
1710 // associated with the interfaces.
1711 if (nCellInterfaces > 0) {
1712 cell.setInterfaces(std::move(flippedCellInterfaces));
1713
1714 const long *cellInterfaces = cell.getInterfaces();
1715 int nCellInterfaces = cell.getInterfaceCount();
1716 for (int i = 0; i < nCellInterfaces; ++i) {
1717 long interfaceId = cellInterfaces[i];
1718 Interface &interface = getInterface(interfaceId);
1719
1720 long owner = interface.getOwner();
1721 if (owner == id) {
1722 int ownerFace = interface.getOwnerFace();
1723 if (ownerFace != nCellFaces - 1) {
1724 ownerFace = nCellFaces - 2 - ownerFace;
1725 interface.setOwner(id, ownerFace);
1726 }
1727 } else {
1728 int neighFace = interface.getNeighFace();
1729 if (neighFace != nCellFaces - 1) {
1730 neighFace = nCellFaces - 2 - neighFace;
1731 interface.setNeigh(id,neighFace);
1732 }
1733 }
1734 }
1735 }
1736}
1737
1744void SurfaceKernel::displayQualityStats(std::ostream& out, unsigned int padding) const
1745{
1746 // ====================================================================== //
1747 // VARIABLES DECLARATION //
1748 // ====================================================================== //
1749
1750 // Local variables
1751 std::string indent(padding, ' ');
1752
1753 // Counters
1754 // none
1755
1756 // ====================================================================== //
1757 // DISPLAY STATS //
1758 // ====================================================================== //
1759
1760 // Distribution for aspect ratio ---------------------------------------- //
1761 out << indent << "Aspect ratio distribution ---------------" << std::endl;
1762 {
1763 // Scope variables
1764 long count;
1765 std::vector<double> bins, hist;
1766
1767 // Compute histogram
1768 hist = computeHistogram(&SurfaceKernel::evalAspectRatio, bins, count, 8,
1769 SELECT_TRIANGLE | SELECT_QUAD);
1770
1771 // Display histogram
1772 displayHistogram(count, bins, hist, "AR", out, padding + 2);
1773 }
1774
1775 // Distribution of min. angle ------------------------------------------- //
1776 out << indent << "Min. angle distribution -----------------" << std::endl;
1777 {
1778 // Scope variables
1779 long count;
1780 std::vector<double> bins, hist;
1781
1782 // Compute histogram
1784 SELECT_TRIANGLE | SELECT_QUAD);
1785
1786 // Display histogram
1787 displayHistogram(count, bins, hist, "min. angle", out, padding + 2);
1788 }
1789
1790 // Distribution of min. angle ------------------------------------------- //
1791 out << indent << "Max. angle distribution -----------------" << std::endl;
1792 {
1793 // Scope variables
1794 long count;
1795 std::vector<double> bins, hist;
1796
1797 // Compute histogram
1799 SELECT_TRIANGLE | SELECT_QUAD);
1800
1801 // Display histogram
1802 displayHistogram(count, bins, hist, "max. angle", out, padding + 2);
1803 }
1804
1805 return;
1806}
1807
1832std::vector<double> SurfaceKernel::computeHistogram(eval_f_ funct_, std::vector<double> &bins, long &count, int n_intervals, unsigned short mask) const
1833{
1834 // ====================================================================== //
1835 // VARIABLES DECLARATION //
1836 // ====================================================================== //
1837
1838 // Local variables
1839 double m_, M_;
1840 std::vector<double> hist;
1841
1842 // ====================================================================== //
1843 // BUILD BINS FOR HISTOGRAM //
1844 // ====================================================================== //
1845
1846 // Resize bin data structure
1847 if (bins.size() < 2) {
1848 double db;
1849 bins.resize(n_intervals+1);
1850 m_ = 1.0;
1851 M_ = 3.0;
1852 db = (M_ - m_)/double(n_intervals);
1853 for (int i = 0; i < n_intervals+1; ++i) {
1854 bins[i] = m_ + db * double(i);
1855 } //next i
1856 }
1857 else {
1858 n_intervals = bins.size()-1;
1859 }
1860
1861 // Resize histogram data structure
1862 hist.resize(n_intervals+2, 0.0);
1863
1864 // ====================================================================== //
1865 // COMPUTE HISTOGRAM //
1866 // ====================================================================== //
1867
1868 // Scope variables
1869 long id;
1870 int i;
1871 int dummy;
1872 double ar;
1873
1874 // Compute histogram
1875 count = 0;
1876 for (auto &cell_ : m_cells) {
1877 id = cell_.getId();
1878 if (compareSelectedTypes(mask, cell_.getType())) {
1879 ar = (this->*funct_)(id, dummy);
1880 i = 0;
1881 while ((bins[i] - ar < 1.0e-5) && (i < n_intervals+1)) ++i;
1882 ++hist[i];
1883 ++count;
1884 }
1885 } //next cell_
1886
1887 // Normalize histogram
1888 hist = 100.0 * hist/double(count);
1889
1890 return(hist);
1891}
1892
1903void SurfaceKernel::displayHistogram(
1904 long count,
1905 const std::vector<double> &bins,
1906 const std::vector<double> &hist,
1907 const std::string &stats_name,
1908 std::ostream &out,
1909 unsigned int padding
1910) const {
1911 // ====================================================================== //
1912 // VARIABLES DECLARATION //
1913 // ====================================================================== //
1914
1915 // Local variables
1916 int nbins = bins.size();
1917 size_t n_fill;
1918 std::string indent(padding, ' ');
1919 std::stringstream ss;
1920
1921 // Counters
1922 int i;
1923
1924 // ====================================================================== //
1925 // DISPLAY HISTOGRAM //
1926 // ====================================================================== //
1927
1928 // Set stream properties
1929 ss << std::setprecision(3);
1930
1931 // Display histograms
1932 out << indent << "poll size: " << count << std::endl;
1933 out << indent;
1934 ss << hist[0];
1935 n_fill = ss.str().length();
1936 ss << std::string(std::max(size_t(0), 6 - n_fill), ' ');
1937 out << ss.str() << "%, with " << stats_name << " < ";
1938 ss.str("");
1939 ss << bins[0];
1940 out << ss.str() << std::endl;
1941 ss.str("");
1942 for (i = 0; i < nbins-1; ++i) {
1943 out << indent;
1944 ss << hist[i+1];
1945 n_fill = ss.str().length();
1946 ss << std::string(std::max(size_t(0), 6 - n_fill), ' ');
1947 out << ss.str() << "%, with ";
1948 ss.str("");
1949 ss << bins[i];
1950 n_fill = ss.str().length();
1951 ss << std::string(std::max(size_t(0), 6 - n_fill), ' ');
1952 out << ss.str() << " < " << stats_name << " < ";
1953 ss.str("");
1954 ss << bins[i+1];
1955 out << ss.str() << std::endl;
1956 ss.str("");
1957 } //next i
1958 out << indent;
1959 ss << hist[i+1];
1960 n_fill = ss.str().length();
1961 ss << std::string(std::max(size_t(0), 6 - n_fill), ' ');
1962 out << ss.str() << "%, with ";
1963 ss.str("");
1964 ss << bins[i];
1965 n_fill = ss.str().length();
1966 ss << std::string(std::max(size_t(0), 6 - n_fill), ' ');
1967 out << ss.str() << " < " << stats_name << std::endl;
1968 ss.str("");
1969
1970 return;
1971}
1972
1980bool SurfaceKernel::compareSelectedTypes(unsigned short mask_, ElementType type_) const
1981{
1982 unsigned short masked = m_selectionTypes.at(type_);
1983 return ( (mask_ & masked) == masked );
1984}
1985
1993{
1994 ConstProxyVector<long> vertexIds = facet.getVertexIds();
1995 if (areFacetVerticesOrdered(facet)) {
1996 return vertexIds;
1997 }
1998
1999 std::size_t nVertices = vertexIds.size();
2001 ConstProxyVector<long>::storage_pointer orderedVertexIdsStorage = orderedVertexIds.storedData();
2002 for (std::size_t k = 0; k < nVertices; ++k) {
2003 int vertex = getFacetOrderedLocalVertex(facet, k);
2004 orderedVertexIdsStorage[k] = vertexIds[vertex];
2005 }
2006
2007 return orderedVertexIds;
2008}
2009
2018{
2019 // Early return for low-dimension elements
2020 if (getDimension() <= 1) {
2021 return true;
2022 }
2023
2024 // Check if vertices are ordered
2025 ElementType facetType = facet.getType();
2026 switch (facetType) {
2027
2028 case (ElementType::POLYGON):
2029 {
2030 return true;
2031 }
2032
2033 default:
2034 {
2035 assert(facetType != ElementType::UNDEFINED);
2036 const Reference2DElementInfo &facetInfo = static_cast<const Reference2DElementInfo &>(facet.getInfo());
2037 return facetInfo.areVerticesCCWOrdered();
2038 }
2039
2040 }
2041}
2042
2052int SurfaceKernel::getFacetOrderedLocalVertex(const Cell &facet, std::size_t n) const
2053{
2054 // Early return for low-dimension elements
2055 if (getDimension() <= 1) {
2056 return n;
2057 }
2058
2059 // Get the request index
2060 ElementType facetType = facet.getType();
2061 switch (facetType) {
2062
2063 case (ElementType::POLYGON):
2064 {
2065 return n;
2066 }
2067
2068 default:
2069 {
2070 assert(facetType != ElementType::UNDEFINED);
2071 const Reference2DElementInfo &facetInfo = static_cast<const Reference2DElementInfo &>(facet.getInfo());
2072 return facetInfo.getCCWOrderedVertex(n);
2073 }
2074
2075 }
2076}
2077
2085{
2086 std::size_t nEdges = facet.getFaceCount();
2088 ConstProxyVector<long>::storage_pointer orderedEdgeIdsStorage = orderedEdgeIds.storedData();
2089 for (std::size_t k = 0; k < nEdges; ++k) {
2090 orderedEdgeIdsStorage[k] = getFacetOrderedLocalEdge(facet, k);
2091 }
2092
2093 return orderedEdgeIds;
2094}
2095
2104{
2105 // Early return for low-dimension elements
2106 if (getDimension() <= 1) {
2107 return true;
2108 }
2109
2110 // Check if edges are ordered
2111 ElementType facetType = facet.getType();
2112 switch (facetType) {
2113
2114 case (ElementType::POLYGON):
2115 {
2116 return true;
2117 }
2118
2119 default:
2120 {
2121 assert(facetType != ElementType::UNDEFINED);
2122 const Reference2DElementInfo &facetInfo = static_cast<const Reference2DElementInfo &>(facet.getInfo());
2123 return facetInfo.areFacesCCWOrdered();
2124 }
2125
2126 }
2127}
2128
2138int SurfaceKernel::getFacetOrderedLocalEdge(const Cell &facet, std::size_t n) const
2139{
2140 // Early return for low-dimension elements
2141 if (getDimension() <= 1) {
2142 return n;
2143 }
2144
2145 // Get the request index
2146 ElementType facetType = facet.getType();
2147 switch (facetType) {
2148
2149 case (ElementType::POLYGON):
2150 {
2151 return n;
2152 }
2153
2154 default:
2155 {
2156 assert(facetType != ElementType::UNDEFINED);
2157 const Reference2DElementInfo &facetInfo = static_cast<const Reference2DElementInfo &>(facet.getInfo());
2158 return facetInfo.getCCWOrderedFace(n);
2159 }
2160
2161 }
2162}
2163
2164}
The Cell class defines the cells.
Definition cell.hpp:42
bool isInterior() const
Definition cell.cpp:396
void setInterfaces(const std::vector< std::vector< long > > &interfaces)
Definition cell.cpp:450
int getInterfaceCount() const
Definition cell.cpp:535
const long * getAdjacencies() const
Definition cell.cpp:841
const long * getInterfaces() const
Definition cell.cpp:571
int getAdjacencyCount() const
Definition cell.cpp:805
void setAdjacencies(const std::vector< std::vector< long > > &adjacencies)
Definition cell.cpp:720
The DataCommunicator class provides the infrastructure needed to exchange data among processes.
long getId() const
Definition element.cpp:510
ConstProxyVector< long > getFaceVertexIds(int face) const
Definition element.cpp:1320
static int getDimension(ElementType type)
Definition element.cpp:1096
ElementType getType() const
Definition element.cpp:551
int findVertex(long vertexId) const
Definition element.cpp:1302
const ReferenceElementInfo & getInfo() const
Definition element.cpp:531
ConstProxyVector< int > getFaceLocalVertexIds(int face) const
Definition element.cpp:1372
static ConstProxyVector< long > getVertexIds(ElementType type, const long *connectivity)
Definition element.cpp:1193
const long * getConnect() const
Definition element.cpp:609
long getVertexId(int vertex) const
Definition element.cpp:1269
int getFaceCount() const
Definition element.cpp:678
int getVertexCount() const
Definition element.cpp:1152
Metafunction for generation of a flattened vector of vectors.
void reserve(std::size_t nVectors, std::size_t nItems=0)
The Interface class defines the interfaces among cells.
Definition interface.hpp:37
long getOwner() const
The PatchKernel class provides an interface for defining patches.
CellConstIterator internalCellConstEnd() const
CellIterator internalBegin()
const std::unordered_map< int, std::vector< long > > & getGhostCellExchangeSources() const
PiercedVector< Cell > & getCells()
CellConstIterator internalCellConstBegin() const
const std::unordered_map< int, std::vector< long > > & getGhostCellExchangeTargets() const
bool empty(bool global=true) const
Cell & getCell(long id)
const MPI_Comm & getCommunicator() const
virtual int findAdjoinNeighFace(const Cell &cell, int cellFace, const Cell &neigh) const
CellIterator internalEnd()
virtual long getCellCount() const
std::vector< long > findCellVertexNeighs(long id, bool complete=true) const
const std::array< double, 3 > & getVertexCoords(long id) const
void extractEnvelope(PatchKernel &envelope) const
long getInternalCellCount() const
ConstProxyVector< std::array< double BITPIT_COMMA 3 > > getCellVertexCoordinates(long id) const
std::size_t getRawIndex() const noexcept
Iterator for the class PiercedStorage.
Metafunction for generating a pierced storage.
__PS_REFERENCE__ rawAt(std::size_t pos, std::size_t offset=0)
void fill(const value_t &value)
void rawSet(std::size_t pos, const value_t &value)
Metafunction for generating a list of elements that can be either stored in an external vectror or,...
container_type::pointer storage_pointer
std::size_t size() const
__PXV_POINTER__ data() noexcept
__PXV_STORAGE_POINTER__ storedData() noexcept
Buffer to be used for receive communications.
The Reference2DElementInfo class allows to define information about reference two-dimensional element...
virtual int getCCWOrderedVertex(int n) const
virtual int getCCWOrderedFace(int n) const
virtual bool areVerticesCCWOrdered() const
Buffer to be used for send communications.
The SurfaceKernel class provides an interface for defining surface patches.
int getVolumeCodimension() const override
int getPointCodimension() const override
int getFacetOrderedLocalEdge(const Cell &facet, std::size_t n) const
virtual void evalVertexNormals(long id, int vertex, std::size_t nVertexNeighs, const long *vertexNeighs, double limit, std::array< double, 3 > *unlimitedNormal, std::array< double, 3 > *limitedNormal) const
void displayQualityStats(std::ostream &, unsigned int padding=0) const
virtual double evalAspectRatio(long, int &) const
virtual double evalMinEdgeLength(long, int &) const
void flipCellOrientation(long id)
bool areFacetVerticesOrdered(const Cell &facet) const
int getLineCodimension() const override
std::vector< double > computeHistogram(eval_f_ funct_, std::vector< double > &bins, long &count, int n_intervals=8, unsigned short mask=SELECT_ALL) const
void extractEnvelope(LineKernel &envelope) const
ConstProxyVector< long > getFacetOrderedEdgeIds(const Cell &facet) const
int getSurfaceCodimension() const override
virtual double evalMaxAngleAtVertex(long, int &) const
virtual std::array< double, 3 > evalFacetNormal(long, const std::array< double, 3 > &orientation={{0., 0., 1.}}) const
int getFacetOrderedLocalVertex(const Cell &facet, std::size_t n) const
SurfaceKernel(MPI_Comm communicator, std::size_t haloSize, AdaptionMode adaptionMode, PartitioningMode partitioningMode)
bool areFacetEdgesOrdered(const Cell &facet) const
bool isCellOrientationConsistent() const
std::array< double, 3 > evalEdgeNormal(long, int) const
ConstProxyVector< long > getFacetOrderedVertexIds(const Cell &facet) const
std::array< double, 3 > evalLimitedVertexNormal(long, int, double) const
virtual double evalCellArea(long) const
void evalBarycentricCoordinates(long id, const std::array< double, 3 > &point, double *lambda) const
virtual void evalEdgeNormals(long id, int edge, double limit, std::array< double, 3 > *unlimitedNormal, std::array< double, 3 > *limitedNormal) const
virtual double evalMaxEdgeLength(long, int &) const
virtual double evalMinAngleAtVertex(long, int &) const
double evalCellSize(long id) const override
std::array< double, 3 > evalVertexNormal(long, int) const
virtual double evalAngleAtVertex(long, int) const
virtual double evalEdgeLength(long, int) const
The Vertex class defines the vertexs.
Definition vertex.hpp:42
std::array< double, 3 > & getCoords()
Definition vertex.cpp:246
array3D projectPointTriangle(array3D const &, array3D const &, array3D const &, array3D const &)
Definition CG_elem.cpp:1049
array3D projectPointSegment(array3D const &, array3D const &, array3D const &)
Definition CG_elem.cpp:996
array3D projectPointPolygon(array3D const &, std::vector< array3D > const &)
Definition CG_elem.cpp:1214
std::array< T, 3 > crossProduct(const std::array< T, 3 > &x, const std::array< T, 3 > &y)
T dotProduct(const std::array< T, d > &x, const std::array< T, d > &y)
double norm2(const std::array< T, d > &x)
#define BITPIT_UNUSED(variable)
Definition compiler.hpp:63
#define BITPIT_CREATE_WORKSPACE(workspace, item_type, size, stack_size)
--- layout: doxygen_footer ---