Loading...
Searching...
No Matches
patch_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#include <sstream>
26#include <typeinfo>
27#include <unordered_map>
28#include <unordered_set>
29#if BITPIT_ENABLE_MPI==1
30# include <mpi.h>
31#endif
32
33#include "bitpit_CG.hpp"
34#include "bitpit_common.hpp"
35
36#include "patch_info.hpp"
37#include "patch_kernel.hpp"
38#include "patch_manager.hpp"
39
40namespace bitpit {
41
51#if BITPIT_ENABLE_MPI==1
72PatchKernel::PatchKernel(MPI_Comm communicator, std::size_t haloSize,
73 AdaptionMode adaptionMode, PartitioningMode partitioningMode)
74#else
81#endif
82 : m_adaptionMode(adaptionMode)
83#if BITPIT_ENABLE_MPI==1
84 , m_partitioningMode(partitioningMode)
85#endif
86{
87 // Initialize the patch
88#if BITPIT_ENABLE_MPI==1
89 initialize(communicator, haloSize);
90#else
91 initialize();
92#endif
93
94 // Register the patch
95 patch::manager().registerPatch(this);
96}
97
98#if BITPIT_ENABLE_MPI==1
120PatchKernel::PatchKernel(int dimension, MPI_Comm communicator, std::size_t haloSize,
121 AdaptionMode adaptionMode, PartitioningMode partitioningMode)
122#else
129PatchKernel::PatchKernel(int dimension, AdaptionMode adaptionMode)
130#endif
131 : m_adaptionMode(adaptionMode)
132#if BITPIT_ENABLE_MPI==1
133 , m_partitioningMode(partitioningMode)
134#endif
135{
136 // Initialize the patch
137#if BITPIT_ENABLE_MPI==1
138 initialize(communicator, haloSize);
139#else
140 initialize();
141#endif
142
143 // Register the patch
144 patch::manager().registerPatch(this);
145
146 // Set the dimension
147 setDimension(dimension);
148}
149
150#if BITPIT_ENABLE_MPI==1
173PatchKernel::PatchKernel(int id, int dimension, MPI_Comm communicator, std::size_t haloSize,
174 AdaptionMode adaptionMode, PartitioningMode partitioningMode)
175#else
183PatchKernel::PatchKernel(int id, int dimension, AdaptionMode adaptionMode)
184#endif
185 : m_adaptionMode(adaptionMode)
186#if BITPIT_ENABLE_MPI==1
187 , m_partitioningMode(partitioningMode)
188#endif
189{
190 // Initialize the patch
191#if BITPIT_ENABLE_MPI==1
192 initialize(communicator, haloSize);
193#else
194 initialize();
195#endif
196
197 // Register the patch
198 patch::manager().registerPatch(this, id);
199
200 // Set the dimension
201 //
202 // Here we can only call the base function, if needed, every derived patch
203 // has to call its derived function.
204 PatchKernel::setDimension(dimension);
205}
206
213 : VTKBaseStreamer(other),
214 m_vertices(other.m_vertices),
215 m_cells(other.m_cells),
216 m_interfaces(other.m_interfaces),
217 m_alteredCells(other.m_alteredCells),
218 m_alteredInterfaces(other.m_alteredInterfaces),
219 m_nInternalVertices(other.m_nInternalVertices),
220#if BITPIT_ENABLE_MPI==1
221 m_nGhostVertices(other.m_nGhostVertices),
222#endif
223 m_lastInternalVertexId(other.m_lastInternalVertexId),
224#if BITPIT_ENABLE_MPI==1
225 m_firstGhostVertexId(other.m_firstGhostVertexId),
226#endif
227 m_nInternalCells(other.m_nInternalCells),
228#if BITPIT_ENABLE_MPI==1
229 m_nGhostCells(other.m_nGhostCells),
230#endif
231 m_lastInternalCellId(other.m_lastInternalCellId),
232#if BITPIT_ENABLE_MPI==1
233 m_firstGhostCellId(other.m_firstGhostCellId),
234#endif
235 m_vtk(other.m_vtk),
236 m_vtkWriteTarget(other.m_vtkWriteTarget),
237 m_vtkVertexMap(other.m_vtkVertexMap),
238 m_boxFrozen(other.m_boxFrozen),
239 m_boxDirty(other.m_boxDirty),
240 m_boxMinPoint(other.m_boxMinPoint),
241 m_boxMaxPoint(other.m_boxMaxPoint),
242 m_boxMinCounter(other.m_boxMinCounter),
243 m_boxMaxCounter(other.m_boxMaxCounter),
244 m_adjacenciesBuildStrategy(other.m_adjacenciesBuildStrategy),
245 m_interfacesBuildStrategy(other.m_interfacesBuildStrategy),
246 m_adaptionMode(other.m_adaptionMode),
247 m_adaptionStatus(other.m_adaptionStatus),
248 m_dimension(other.m_dimension),
249 m_toleranceCustom(other.m_toleranceCustom),
250 m_tolerance(other.m_tolerance)
251#if BITPIT_ENABLE_MPI==1
252 , m_partitioningMode(other.m_partitioningMode),
253 m_partitioningStatus(other.m_partitioningStatus),
254 m_owner(other.m_owner),
255 m_haloSize(other.m_haloSize),
256 m_partitioningCellsTag(other.m_partitioningCellsTag),
257 m_partitioningVerticesTag(other.m_partitioningVerticesTag),
258 m_partitioningSerialization(other.m_partitioningSerialization),
259 m_partitioningOutgoings(other.m_partitioningOutgoings),
260 m_partitioningGlobalExchanges(other.m_partitioningGlobalExchanges),
261 m_partitioningInfoDirty(other.m_partitioningInfoDirty),
262 m_ghostVertexInfo(other.m_ghostVertexInfo),
263 m_ghostVertexExchangeTargets(other.m_ghostVertexExchangeTargets),
264 m_ghostVertexExchangeSources(other.m_ghostVertexExchangeSources),
265 m_ghostCellInfo(other.m_ghostCellInfo),
266 m_ghostCellExchangeTargets(other.m_ghostCellExchangeTargets),
267 m_ghostCellExchangeSources(other.m_ghostCellExchangeSources)
268#endif
269{
270#if BITPIT_ENABLE_MPI==1
271 // Initialize the communicator
272 initializeCommunicator(other.getCommunicator());
273#else
274 // Initialize serial communicator
275 initializeSerialCommunicator();
276#endif
277
278 // Create index generators
279 importVertexIndexGenerator(other);
280 importInterfaceIndexGenerator(other);
281 importCellIndexGenerator(other);
282
283 // Register the patch
284 patch::manager().registerPatch(this);
285
286 // Update the VTK streamer
287 replaceVTKStreamer(&other, this);
288}
289
296 : VTKBaseStreamer(std::move(other)),
297 m_vertices(std::move(other.m_vertices)),
298 m_cells(std::move(other.m_cells)),
299 m_interfaces(std::move(other.m_interfaces)),
300 m_alteredCells(std::move(other.m_alteredCells)),
301 m_alteredInterfaces(std::move(other.m_alteredInterfaces)),
302 m_vertexIdGenerator(std::move(other.m_vertexIdGenerator)),
303 m_interfaceIdGenerator(std::move(other.m_interfaceIdGenerator)),
304 m_cellIdGenerator(std::move(other.m_cellIdGenerator)),
305 m_nInternalVertices(std::move(other.m_nInternalVertices)),
306#if BITPIT_ENABLE_MPI==1
307 m_nGhostVertices(std::move(other.m_nGhostVertices)),
308#endif
309 m_lastInternalVertexId(std::move(other.m_lastInternalVertexId)),
310#if BITPIT_ENABLE_MPI==1
311 m_firstGhostVertexId(std::move(other.m_firstGhostVertexId)),
312#endif
313 m_nInternalCells(std::move(other.m_nInternalCells)),
314#if BITPIT_ENABLE_MPI==1
315 m_nGhostCells(std::move(other.m_nGhostCells)),
316#endif
317 m_lastInternalCellId(std::move(other.m_lastInternalCellId)),
318#if BITPIT_ENABLE_MPI==1
319 m_firstGhostCellId(std::move(other.m_firstGhostCellId)),
320#endif
321 m_vtk(std::move(other.m_vtk)),
322 m_vtkWriteTarget(std::move(other.m_vtkWriteTarget)),
323 m_vtkVertexMap(std::move(other.m_vtkVertexMap)),
324 m_boxFrozen(std::move(other.m_boxFrozen)),
325 m_boxDirty(std::move(other.m_boxDirty)),
326 m_boxMinPoint(std::move(other.m_boxMinPoint)),
327 m_boxMaxPoint(std::move(other.m_boxMaxPoint)),
328 m_boxMinCounter(std::move(other.m_boxMinCounter)),
329 m_boxMaxCounter(std::move(other.m_boxMaxCounter)),
330 m_adjacenciesBuildStrategy(std::move(other.m_adjacenciesBuildStrategy)),
331 m_interfacesBuildStrategy(std::move(other.m_interfacesBuildStrategy)),
332 m_adaptionMode(std::move(other.m_adaptionMode)),
333 m_adaptionStatus(std::move(other.m_adaptionStatus)),
334 m_id(std::move(other.m_id)),
335 m_dimension(std::move(other.m_dimension)),
336 m_toleranceCustom(std::move(other.m_toleranceCustom)),
337 m_tolerance(std::move(other.m_tolerance)),
338 m_rank(std::move(other.m_rank)),
339 m_nProcessors(std::move(other.m_nProcessors))
340#if BITPIT_ENABLE_MPI==1
341 , m_communicator(std::move(MPI_COMM_NULL)),
342 m_partitioningMode(other.m_partitioningMode),
343 m_partitioningStatus(std::move(other.m_partitioningStatus)),
344 m_owner(std::move(other.m_owner)),
345 m_haloSize(std::move(other.m_haloSize)),
346 m_partitioningCellsTag(std::move(other.m_partitioningCellsTag)),
347 m_partitioningVerticesTag(std::move(other.m_partitioningVerticesTag)),
348 m_partitioningSerialization(std::move(other.m_partitioningSerialization)),
349 m_partitioningOutgoings(std::move(other.m_partitioningOutgoings)),
350 m_partitioningGlobalExchanges(std::move(other.m_partitioningGlobalExchanges)),
351 m_partitioningInfoDirty(std::move(other.m_partitioningInfoDirty)),
352 m_ghostVertexInfo(std::move(other.m_ghostVertexInfo)),
353 m_ghostVertexExchangeTargets(std::move(other.m_ghostVertexExchangeTargets)),
354 m_ghostVertexExchangeSources(std::move(other.m_ghostVertexExchangeSources)),
355 m_ghostCellInfo(std::move(other.m_ghostCellInfo)),
356 m_ghostCellExchangeTargets(std::move(other.m_ghostCellExchangeTargets)),
357 m_ghostCellExchangeSources(std::move(other.m_ghostCellExchangeSources))
358#endif
359{
360 // Handle patch regstration
361 patch::manager().unregisterPatch(&other);
362
363 patch::manager().registerPatch(this, m_id);
364 patch::manager().registerPatch(&other);
365
366 // Update the VTK streamer
367 //
368 // Pointers to VTK streamers has been copied, we need to replace all the
369 // pointer to the other object with pointer to this object.
370 replaceVTKStreamer(&other, this);
371
372#if BITPIT_ENABLE_MPI==1
373 // Handle the communication
374 std::swap(m_communicator, other.m_communicator);
375#endif
376}
377
384{
385 VTKBaseStreamer::operator=(std::move(other));
386 m_vertices = std::move(other.m_vertices);
387 m_cells = std::move(other.m_cells);
388 m_interfaces = std::move(other.m_interfaces);
389 m_alteredCells = std::move(other.m_alteredCells);
390 m_alteredInterfaces = std::move(other.m_alteredInterfaces);
391 m_vertexIdGenerator = std::move(other.m_vertexIdGenerator);
392 m_interfaceIdGenerator = std::move(other.m_interfaceIdGenerator);
393 m_cellIdGenerator = std::move(other.m_cellIdGenerator);
394 m_nInternalVertices = std::move(other.m_nInternalVertices);
395#if BITPIT_ENABLE_MPI==1
396 m_nGhostVertices = std::move(other.m_nGhostVertices);
397#endif
398 m_lastInternalVertexId = std::move(other.m_lastInternalVertexId);
399#if BITPIT_ENABLE_MPI==1
400 m_firstGhostVertexId = std::move(other.m_firstGhostVertexId);
401#endif
402 m_nInternalCells = std::move(other.m_nInternalCells);
403#if BITPIT_ENABLE_MPI==1
404 m_nGhostCells = std::move(other.m_nGhostCells);
405#endif
406 m_lastInternalCellId = std::move(other.m_lastInternalCellId);
407#if BITPIT_ENABLE_MPI==1
408 m_firstGhostCellId = std::move(other.m_firstGhostCellId);
409#endif
410 m_vtk = std::move(other.m_vtk);
411 m_vtkWriteTarget = std::move(other.m_vtkWriteTarget);
412 m_vtkVertexMap = std::move(other.m_vtkVertexMap);
413 m_boxFrozen = std::move(other.m_boxFrozen);
414 m_boxDirty = std::move(other.m_boxDirty);
415 m_boxMinPoint = std::move(other.m_boxMinPoint);
416 m_boxMaxPoint = std::move(other.m_boxMaxPoint);
417 m_boxMinCounter = std::move(other.m_boxMinCounter);
418 m_boxMaxCounter = std::move(other.m_boxMaxCounter);
419 m_adjacenciesBuildStrategy = std::move(other.m_adjacenciesBuildStrategy);
420 m_interfacesBuildStrategy = std::move(other.m_interfacesBuildStrategy);
421 m_adaptionMode = std::move(other.m_adaptionMode);
422 m_adaptionStatus = std::move(other.m_adaptionStatus);
423 m_id = std::move(other.m_id);
424 m_dimension = std::move(other.m_dimension);
425 m_toleranceCustom = std::move(other.m_toleranceCustom);
426 m_tolerance = std::move(other.m_tolerance);
427 m_rank = std::move(other.m_rank);
428 m_nProcessors = std::move(other.m_nProcessors);
429#if BITPIT_ENABLE_MPI==1
430 m_communicator = std::move(MPI_COMM_NULL);
431 m_partitioningMode = std::move(other.m_partitioningMode);
432 m_partitioningStatus = std::move(other.m_partitioningStatus);
433 m_owner = std::move(other.m_owner);
434 m_haloSize = std::move(other.m_haloSize);
435 m_partitioningCellsTag = std::move(other.m_partitioningCellsTag);
436 m_partitioningVerticesTag = std::move(other.m_partitioningVerticesTag);
437 m_partitioningSerialization = std::move(other.m_partitioningSerialization);
438 m_partitioningOutgoings = std::move(other.m_partitioningOutgoings);
439 m_partitioningGlobalExchanges = std::move(other.m_partitioningGlobalExchanges);
440 m_partitioningInfoDirty = std::move(other.m_partitioningInfoDirty);
441 m_ghostVertexInfo = std::move(other.m_ghostVertexInfo);
442 m_ghostVertexExchangeTargets = std::move(other.m_ghostVertexExchangeTargets);
443 m_ghostVertexExchangeSources = std::move(other.m_ghostVertexExchangeSources);
444 m_ghostCellInfo = std::move(other.m_ghostCellInfo);
445 m_ghostCellExchangeTargets = std::move(other.m_ghostCellExchangeTargets);
446 m_ghostCellExchangeSources = std::move(other.m_ghostCellExchangeSources);
447#endif
448
449 // Handle patch regstration
450 patch::manager().unregisterPatch(this);
451 patch::manager().unregisterPatch(&other);
452
453 patch::manager().registerPatch(this, m_id);
454 patch::manager().registerPatch(&other);
455
456 // Update the VTK streamer
457 //
458 // Pointers to VTK streamers has been moved, we need to replace all the
459 // pointer to the other object with pointer to this object.
460 replaceVTKStreamer(&other, this);
461
462#if BITPIT_ENABLE_MPI==1
463 // Handle the communication
464 std::swap(m_communicator, other.m_communicator);
465#endif
466
467 return *this;
468}
469
473#if BITPIT_ENABLE_MPI==1
480void PatchKernel::initialize(MPI_Comm communicator, std::size_t haloSize)
481#else
482void PatchKernel::initialize()
483#endif
484{
485 // Id
486 m_id = PatchManager::AUTOMATIC_ID;
487
488 // Vertex count
489 m_nInternalVertices = 0;
490#if BITPIT_ENABLE_MPI==1
491 m_nGhostVertices = 0;
492#endif
493
494 m_lastInternalVertexId = Vertex::NULL_ID;
495#if BITPIT_ENABLE_MPI==1
496 m_firstGhostVertexId = Vertex::NULL_ID;
497#endif
498
499 // Cell count
500 m_nInternalCells = 0;
501#if BITPIT_ENABLE_MPI==1
502 m_nGhostCells = 0;
503#endif
504
505 m_lastInternalCellId = Cell::NULL_ID;
506#if BITPIT_ENABLE_MPI==1
507 m_firstGhostCellId = Cell::NULL_ID;
508#endif
509
510 // Dimension
511 m_dimension = -1;
512
513 // Index generators
514 setVertexAutoIndexing(true);
515 setInterfaceAutoIndexing(true);
516 setCellAutoIndexing(true);
517
518 // Set adjacencies build strategy
519 setAdjacenciesBuildStrategy(ADJACENCIES_NONE);
520
521 // Set interfaces build strategy
522 setInterfacesBuildStrategy(INTERFACES_NONE);
523
524 // Set the adaption as clean
525 setAdaptionStatus(ADAPTION_CLEAN);
526
527#if BITPIT_ENABLE_MPI==1
528 // Initialize communicator
529 initializeCommunicator(communicator);
530
531 // Set halo size
532 initializeHaloSize(haloSize);
533
534 // Mark patch as partioned
535 setPartitioningStatus(PARTITIONING_CLEAN);
536
537 // Initialize partitioning tags
538 m_partitioningCellsTag = -1;
539 m_partitioningVerticesTag = -1;
540
541 // Update partitioning information
542 if (isPartitioned()) {
543 updatePartitioningInfo(true);
544 }
545#else
546 // Initialize serial communicator
547 initializeSerialCommunicator();
548#endif
549
550 // Initialize the geometrical tolerance
551 resetTol();
552
553 // Initializes the bounding box
554 setBoundingBoxFrozen(false);
555 clearBoundingBox();
556
557 // Set VTK write target
558 m_vtkWriteTarget = WRITE_TARGET_CELLS_ALL;
559
560 // Set VTK information
561 std::ostringstream convert;
562 convert << getId();
563
564 m_vtk.setName(convert.str());
565 m_vtk.setCodex(VTKFormat::APPENDED);
566
567 // Set VTK Geom Data
568 m_vtk.setGeomData<double>(VTKUnstructuredField::POINTS, this);
569 m_vtk.setGeomData<long>(VTKUnstructuredField::OFFSETS, this);
570 m_vtk.setGeomData<int>(VTKUnstructuredField::TYPES, this);
571 m_vtk.setGeomData<long>(VTKUnstructuredField::CONNECTIVITY, this);
572 m_vtk.setGeomData<long>(VTKUnstructuredField::FACE_STREAMS, this);
573 m_vtk.setGeomData<long>(VTKUnstructuredField::FACE_OFFSETS, this);
574
575 // Add VTK basic patch data
576 m_vtk.addData<long>("cellIndex", VTKFieldType::SCALAR, VTKLocation::CELL, this);
577 m_vtk.addData<int>("PID", VTKFieldType::SCALAR, VTKLocation::CELL, this);
578 m_vtk.addData<long>("vertexIndex", VTKFieldType::SCALAR, VTKLocation::POINT, this);
579#if BITPIT_ENABLE_MPI==1
580 m_vtk.addData<long>("cellGlobalIndex", VTKFieldType::SCALAR, VTKLocation::CELL, this);
581 m_vtk.addData<int>("cellRank", VTKFieldType::SCALAR, VTKLocation::CELL, this);
582 m_vtk.addData<int>("cellHaloLayer", VTKFieldType::SCALAR, VTKLocation::CELL, this);
583 m_vtk.addData<int>("vertexRank", VTKFieldType::SCALAR, VTKLocation::POINT, this);
584#endif
585}
586
587#if BITPIT_ENABLE_MPI!=1
591void PatchKernel::initializeSerialCommunicator()
592{
593 m_rank = 0;
594 m_nProcessors = 1;
595}
596#endif
597
603#if BITPIT_ENABLE_MPI==1
604 freeCommunicator();
605#endif
606
607 try {
608 patch::manager().unregisterPatch(this);
609 } catch (const std::runtime_error &e) {
610 log::cout() << "Unable to unregister the patch" << std::endl;
611 log::cout() << " Error message: " << e.what() << std::endl;
612 }
613}
614
625std::vector<adaption::Info> PatchKernel::update(bool trackAdaption, bool squeezeStorage)
626{
627 std::vector<adaption::Info> updateInfo;
628
629 // Early return if the patch is not dirty
630 //
631 // If we need to squeeze the storage we need to perform the update also
632 // if the patch is not dirty.
633 if (!squeezeStorage && !isDirty(true)) {
634 return updateInfo;
635 }
636
637 // Finalize alterations
638 finalizeAlterations(squeezeStorage);
639
640 // Adaption
641 bool adaptionDirty = (getAdaptionStatus(true) == ADAPTION_DIRTY);
642 if (adaptionDirty) {
643 mergeAdaptionInfo(adaption(trackAdaption, squeezeStorage), updateInfo);
644 }
646 return updateInfo;
647}
648
659void PatchKernel::simulateCellUpdate(const long id, adaption::Marker marker, std::vector<Cell> *virtualCells, PiercedVector<Vertex, long> *virtualVertices) const
660{
661 BITPIT_UNUSED(id);
662 BITPIT_UNUSED(marker);
663 BITPIT_UNUSED(virtualCells);
664 BITPIT_UNUSED(virtualVertices);
665
666 throw std::runtime_error ("This function has not been implemented for the specified patch.");
667}
668
679std::vector<adaption::Info> PatchKernel::adaption(bool trackAdaption, bool squeezeStorage)
680{
681 std::vector<adaption::Info> adaptionInfo;
682
683 // Early return if adaption cannot be performed
684 AdaptionMode adaptionMode = getAdaptionMode();
685 if (adaptionMode == ADAPTION_DISABLED) {
686 return adaptionInfo;
687 }
688
689 AdaptionStatus adaptionStatus = getAdaptionStatus(true);
690 if (adaptionStatus == ADAPTION_CLEAN) {
691 return adaptionInfo;
692 } else if (adaptionStatus != ADAPTION_DIRTY) {
693 throw std::runtime_error ("An adaption is already in progress.");
694 }
695
696 // Run adaption
697 adaptionPrepare(false);
698
699 adaptionInfo = adaptionAlter(trackAdaption, squeezeStorage);
700
702
703 return adaptionInfo;
704}
705
719std::vector<adaption::Info> PatchKernel::adaptionPrepare(bool trackAdaption)
720{
721 std::vector<adaption::Info> adaptionInfo;
722
723 // Early return if adaption cannot be performed
724 AdaptionMode adaptionMode = getAdaptionMode();
725 if (adaptionMode == ADAPTION_DISABLED) {
726 return adaptionInfo;
727 }
728
729 AdaptionStatus adaptionStatus = getAdaptionStatus(true);
730 if (adaptionStatus == ADAPTION_CLEAN) {
731 return adaptionInfo;
732 } else if (adaptionStatus != ADAPTION_DIRTY) {
733 throw std::runtime_error ("An adaption is already in progress.");
734 }
735
736 // Execute the adaption preparation
737 adaptionInfo = _adaptionPrepare(trackAdaption);
738
739 // Update the status
740 setAdaptionStatus(ADAPTION_PREPARED);
741
742 return adaptionInfo;
743}
744
760std::vector<adaption::Info> PatchKernel::adaptionAlter(bool trackAdaption, bool squeezeStorage)
761{
762 std::vector<adaption::Info> adaptionInfo;
763
764 // Early return if adaption cannot be performed
765 AdaptionMode adaptionMode = getAdaptionMode();
766 if (adaptionMode == ADAPTION_DISABLED) {
767 return adaptionInfo;
768 }
769
770 AdaptionStatus adaptionStatus = getAdaptionStatus();
771 if (adaptionStatus == ADAPTION_CLEAN) {
772 return adaptionInfo;
773 } else if (adaptionStatus != ADAPTION_PREPARED) {
774 throw std::runtime_error ("The prepare function has not been called.");
775 }
776
777 // Adapt the patch
778 adaptionInfo = _adaptionAlter(trackAdaption);
779
780 // Finalize patch alterations
781 finalizeAlterations(squeezeStorage);
782
783 // Update the status
784 setAdaptionStatus(ADAPTION_ALTERED);
785
786 return adaptionInfo;
787}
788
795{
796 // Early return if adaption cannot be performed
797 AdaptionMode adaptionMode = getAdaptionMode();
798 if (adaptionMode == ADAPTION_DISABLED) {
799 return;
800 }
801
802 AdaptionStatus adaptionStatus = getAdaptionStatus();
803 if (adaptionStatus == ADAPTION_CLEAN) {
804 return;
805 } else if (adaptionStatus == ADAPTION_PREPARED) {
806 throw std::runtime_error ("It is not yet possible to abort an adaption.");
807 } else if (adaptionStatus != ADAPTION_ALTERED) {
808 throw std::runtime_error ("The alter function has not been called.");
809 }
810
811 // Complete the adaption
813
814 // Update the status
815 setAdaptionStatus(ADAPTION_CLEAN);
816}
817
823{
824 // Nothing to do
825}
826
833void PatchKernel::finalizeAlterations(bool squeezeStorage)
834{
835 // Flush vertex data structures
836 m_vertices.flush();
837
838 // Update bounding box
839 bool boundingBoxDirty = isBoundingBoxDirty();
840 if (boundingBoxDirty) {
842 }
843
844 // Flush cell data structures
845 m_cells.flush();
846
847 // Update adjacencies
848 bool adjacenciesDirty = areAdjacenciesDirty();
849 if (adjacenciesDirty) {
851 }
852
853 // Update interfaces
854 bool interfacesDirty = areInterfacesDirty();
855 if (interfacesDirty) {
857 }
858
859 // Flush interfaces data structures
860 m_interfaces.flush();
861
862#if BITPIT_ENABLE_MPI==1
863 // Update partitioning information
864 bool partitioningInfoDirty = arePartitioningInfoDirty();
865 if (partitioningInfoDirty) {
866 updatePartitioningInfo(true);
867 }
868#endif
869
870 // Clear alteration flags
871 m_alteredCells.clear();
872 m_alteredInterfaces.clear();
873
874 // Squeeze the patch
875 if (squeezeStorage) {
876 squeeze();
877 }
878
879 // Synchronize storage
880 m_cells.sync();
881 m_interfaces.sync();
882 m_vertices.sync();
883}
884
891{
892 bool updated = _markCellForRefinement(id);
893
894 if (updated) {
895 setAdaptionStatus(ADAPTION_DIRTY);
896 }
897}
898
905{
906 bool updated = _markCellForCoarsening(id);
907
908 if (updated) {
909 setAdaptionStatus(ADAPTION_DIRTY);
910 }
911}
912
919{
920 bool updated = _resetCellAdaptionMarker(id);
921
922 if (updated) {
923 setAdaptionStatus(ADAPTION_DIRTY);
924 }
925}
926
938adaption::Marker PatchKernel::getCellAdaptionMarker(long id)
939{
940 return _getCellAdaptionMarker(id);
941}
942
949void PatchKernel::enableCellBalancing(long id, bool enabled)
950{
951 bool updated = _enableCellBalancing(id, enabled);
952
953 if (updated) {
954 setAdaptionStatus(ADAPTION_DIRTY);
955 }
956}
957
962{
964 resetCells();
966}
967
972{
973 m_vertices.clear();
974 if (m_vertexIdGenerator) {
975 m_vertexIdGenerator->reset();
976 }
977 m_nInternalVertices = 0;
978#if BITPIT_ENABLE_MPI==1
979 m_nGhostVertices = 0;
980#endif
981 m_lastInternalVertexId = Vertex::NULL_ID;
982#if BITPIT_ENABLE_MPI==1
983 m_firstGhostVertexId = Vertex::NULL_ID;
984#endif
985
986 for (auto &cell : m_cells) {
987 cell.unsetConnect();
988 }
989}
990
995{
996 m_cells.clear();
997 if (m_cellIdGenerator) {
998 m_cellIdGenerator->reset();
999 }
1000 m_nInternalCells = 0;
1001#if BITPIT_ENABLE_MPI==1
1002 m_nGhostCells = 0;
1003#endif
1004 m_lastInternalCellId = Cell::NULL_ID;
1005#if BITPIT_ENABLE_MPI==1
1006 m_firstGhostCellId = Cell::NULL_ID;
1007#endif
1008
1009#if BITPIT_ENABLE_MPI==1
1010 clearGhostCellsInfo();
1011 clearGhostVerticesInfo();
1012#endif
1013
1015
1016 for (auto &interface : m_interfaces) {
1017 interface.unsetNeigh();
1018 interface.unsetOwner();
1019 }
1020
1021 m_alteredCells.clear();
1022}
1023
1031{
1032 // Early return if no interfaces have been built
1033 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
1034 return;
1035 }
1036
1037 // Prune stale interfaces
1039
1040 // Reset the interfaces
1041 _resetInterfaces(false);
1042
1043 // All remaining interfaces will be deleted
1044 setInterfaceAlterationFlags(FLAG_DELETED);
1045
1046 // Mark cell interfaces as dirty
1047 setCellAlterationFlags(FLAG_INTERFACES_DIRTY);
1048}
1049
1060{
1061 for (auto &cell : m_cells) {
1062 cell.resetInterfaces(!release);
1063 }
1064
1065 m_interfaces.clear(release);
1066 if (m_interfaceIdGenerator) {
1067 m_interfaceIdGenerator->reset();
1068 }
1069}
1070
1084bool PatchKernel::reserveVertices(size_t nVertices)
1085{
1087 return false;
1088 }
1089
1090 m_vertices.reserve(nVertices);
1091
1092 return true;
1093}
1094
1107bool PatchKernel::reserveCells(size_t nCells)
1108{
1110 return false;
1111 }
1112
1113 m_cells.reserve(nCells);
1114
1115 return true;
1116}
1117
1132bool PatchKernel::reserveInterfaces(size_t nInterfaces)
1133{
1135 return false;
1136 }
1137
1138 m_interfaces.reserve(nInterfaces);
1139
1140 return true;
1141}
1142
1149void PatchKernel::write(const std::string &filename, VTKWriteMode mode)
1150{
1151 std::string oldFilename = m_vtk.getName();
1152
1153 m_vtk.setName(filename);
1154 write(mode);
1155 m_vtk.setName(oldFilename);
1156}
1157
1165void PatchKernel::write(const std::string &filename, VTKWriteMode mode, double time)
1166{
1167 std::string oldFilename = m_vtk.getName();
1168
1169 m_vtk.setName(filename);
1170 write(mode, time);
1171 m_vtk.setName(oldFilename);
1172}
1173
1180{
1181 _writePrepare();
1182
1183 m_vtk.write(mode);
1184
1186}
1187
1194void PatchKernel::write(VTKWriteMode mode, double time)
1195{
1196 _writePrepare();
1197
1198 m_vtk.write(mode, time);
1199
1201}
1202
1207{
1208 // Get VTK cell count
1209 long vtkCellCount = 0;
1210 if (m_vtkWriteTarget == WRITE_TARGET_CELLS_ALL) {
1211 vtkCellCount = getCellCount();
1212#if BITPIT_ENABLE_MPI==1
1213 } else if (m_vtkWriteTarget == WRITE_TARGET_CELLS_INTERNAL) {
1214 vtkCellCount = getInternalCellCount();
1215#endif
1216 }
1217
1218 // Set the dimensions of the mesh
1219 //
1220 // Even if there is just a single process that needs to write the VTK face stream, than
1221 // all the processes need to write the face stream as well (even the processes whose
1222 // local cells don't require the face steam).
1223 PiercedStorage<bool, long> vertexWriteFlag(1, &m_vertices);
1224 vertexWriteFlag.fill(false);
1225
1226 bool vtkFaceStreamNeeded = false;
1227 for (const Cell &cell : m_cells) {
1228 if (cell.getDimension() > 2 && !cell.hasInfo()) {
1229 vtkFaceStreamNeeded = true;
1230 break;
1231 }
1232 }
1233
1234#if BITPIT_ENABLE_MPI==1
1235 if (isPartitioned()) {
1236 const auto &communicator = getCommunicator();
1237 MPI_Allreduce(MPI_IN_PLACE, &vtkFaceStreamNeeded, 1, MPI_C_BOOL, MPI_LOR, communicator);
1238 }
1239#endif
1240
1241 long vtkConnectSize = 0;
1242 long vtkFaceStreamSize = 0;
1243 for (const Cell &cell : getVTKCellWriteRange()) {
1244 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
1245 const int nCellVertices = cellVertexIds.size();
1246 for (int k = 0; k < nCellVertices; ++k) {
1247 long vertexId = cellVertexIds[k];
1248 vertexWriteFlag.at(vertexId) = true;
1249 }
1250
1251 vtkConnectSize += nCellVertices;
1252 if (vtkFaceStreamNeeded) {
1253 if (cell.getDimension() <= 2 || cell.hasInfo()) {
1254 vtkFaceStreamSize += 1;
1255 } else {
1256 vtkFaceStreamSize += cell.getFaceStreamSize();
1257 }
1258 }
1259 }
1260
1261 int vtkVertexCount = 0;
1262 m_vtkVertexMap.unsetKernel();
1263 m_vtkVertexMap.setStaticKernel(&m_vertices);
1265 for (VertexConstIterator itr = vertexConstBegin(); itr != endItr; ++itr) {
1266 std::size_t vertexRawId = itr.getRawIndex();
1267 if (vertexWriteFlag.rawAt(vertexRawId)) {
1268 m_vtkVertexMap.rawAt(vertexRawId) = vtkVertexCount++;
1269 } else {
1270 m_vtkVertexMap.rawAt(vertexRawId) = Vertex::NULL_ID;
1271 }
1272 }
1273
1274 m_vtk.setDimensions(vtkCellCount, vtkVertexCount, vtkConnectSize, vtkFaceStreamSize);
1275}
1276
1281{
1282 // Nothing to do
1283}
1284
1291{
1292 return (getAdaptionMode() != ADAPTION_DISABLED);
1293}
1294
1313{
1314 return m_adaptionMode;
1315}
1316
1325{
1326 m_adaptionMode = mode;
1327}
1328
1339{
1340 int adaptionStatus = static_cast<int>(m_adaptionStatus);
1341
1342#if BITPIT_ENABLE_MPI==1
1343 if (global && isPartitioned()) {
1344 const auto &communicator = getCommunicator();
1345 MPI_Allreduce(MPI_IN_PLACE, &adaptionStatus, 1, MPI_INT, MPI_MAX, communicator);
1346 }
1347#else
1348 BITPIT_UNUSED(global);
1349#endif
1350
1351 return static_cast<AdaptionStatus>(adaptionStatus);
1352}
1353
1360{
1361 m_adaptionStatus = status;
1362}
1363
1372bool PatchKernel::isDirty(bool global) const
1373{
1374#if BITPIT_ENABLE_MPI==0
1375 BITPIT_UNUSED(global);
1376#endif
1377
1378 bool isDirty = false;
1379
1380 if (!isDirty) {
1381 isDirty |= areAdjacenciesDirty(false);
1382 }
1383
1384 if (!isDirty) {
1385 isDirty |= !m_alteredCells.empty();
1386 }
1387
1388 if (!isDirty) {
1389 isDirty |= areInterfacesDirty(false);
1390 assert(isDirty || m_alteredInterfaces.empty());
1391 }
1392
1393 if (!isDirty) {
1394 isDirty |= (getAdaptionStatus(false) == ADAPTION_DIRTY);
1395 }
1396
1397 if (!isDirty) {
1398 isDirty |= isBoundingBoxDirty(false);
1399 }
1400
1401#if BITPIT_ENABLE_MPI==1
1402 if (!isDirty) {
1404 }
1405#endif
1406
1407 if (!isDirty) {
1408 isDirty |= !m_vertices.isSynced();
1409 }
1410
1411 if (!isDirty) {
1412 isDirty |= !m_cells.isSynced();
1413 }
1414
1415 if (!isDirty) {
1416 isDirty |= !m_interfaces.isSynced();
1417 }
1418
1419#if BITPIT_ENABLE_MPI==1
1420 // Get the global flag
1421 if (global && isPartitioned()) {
1422 const auto &communicator = getCommunicator();
1423 MPI_Allreduce(MPI_IN_PLACE, &isDirty, 1, MPI_C_BOOL, MPI_LOR, communicator);
1424 }
1425#endif
1426
1427 return isDirty;
1428}
1429
1439void PatchKernel::setExpert(bool expert)
1440{
1441 static AdaptionMode initialAdaptionMode;
1442 if (!expert) {
1443 initialAdaptionMode = m_adaptionMode;
1444 m_adaptionMode = ADAPTION_MANUAL;
1445 } else {
1446 m_adaptionMode = initialAdaptionMode;
1447 }
1448}
1449
1461{
1462 return (m_adaptionMode == ADAPTION_MANUAL);
1463}
1464
1471{
1472 if (id == m_id) {
1473 return;
1474 }
1475
1476 patch::manager().unregisterPatch(this);
1477 patch::manager().registerPatch(this, id);
1478}
1479
1485void PatchKernel::_setId(int id)
1486{
1487 m_id = id;
1488}
1489
1496{
1497 return m_id;
1498}
1499
1505void PatchKernel::setDimension(int dimension)
1506{
1507 if (dimension == m_dimension) {
1508 return;
1509 }
1510
1511 // If the dimension was already assigned, reset the patch
1512 if (m_dimension > 0) {
1513 reset();
1514 }
1515
1516 // Set the dimension
1517 m_dimension = dimension;
1518}
1519
1526{
1527 return m_dimension;
1528}
1529
1536{
1537 return (m_dimension == 3);
1538}
1539
1549{
1550 return static_cast<bool>(m_vertexIdGenerator);
1551}
1552
1562{
1563 if (isVertexAutoIndexingEnabled() == enabled) {
1564 return;
1565 }
1566
1567 if (enabled) {
1568 createVertexIndexGenerator(true);
1569 } else {
1570 m_vertexIdGenerator.reset();
1571 }
1572}
1573
1579void PatchKernel::dumpVertexAutoIndexing(std::ostream &stream) const
1580{
1581 m_vertexIdGenerator->dump(stream);
1582}
1583
1589void PatchKernel::restoreVertexAutoIndexing(std::istream &stream)
1590{
1591 createVertexIndexGenerator(false);
1592 m_vertexIdGenerator->restore(stream);
1593}
1594
1603void PatchKernel::createVertexIndexGenerator(bool populate)
1604{
1605 // Create or reset index generator
1606 if (!m_vertexIdGenerator) {
1607 m_vertexIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>());
1608 } else {
1609 m_vertexIdGenerator->reset();
1610 }
1611
1612 // Populate index generator with current ids
1613 if (populate) {
1614 VertexConstIterator beginItr = m_vertices.cbegin();
1615 VertexConstIterator endItr = m_vertices.cend();
1616 for (VertexConstIterator itr = beginItr; itr != endItr; ++itr) {
1617 m_vertexIdGenerator->setAssigned(itr.getId());
1618 }
1619 }
1620}
1621
1630void PatchKernel::importVertexIndexGenerator(const PatchKernel &source)
1631{
1632 if (source.m_vertexIdGenerator) {
1633 m_vertexIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>(*(source.m_vertexIdGenerator)));
1634 } else {
1635 m_vertexIdGenerator.reset();
1636 }
1637}
1638
1645{
1646 return m_vertices.size();
1647}
1648
1655{
1656 return m_nInternalVertices;
1657}
1658
1665{
1666 return m_vertices;
1667}
1668
1675{
1676 return m_vertices;
1677}
1678
1686{
1687 return m_vertices[id];
1688}
1689
1696const Vertex & PatchKernel::getVertex(long id) const
1697{
1698 return m_vertices[id];
1699}
1700
1707{
1708 return m_vertices[m_lastInternalVertexId];
1709}
1710
1717{
1718 return m_vertices[m_lastInternalVertexId];
1719}
1720
1727{
1728 return m_vertices.find(id);
1729}
1730
1737{
1738 return m_vertices.begin();
1739}
1740
1747{
1748 return m_vertices.end();
1749}
1750
1757{
1758 return m_vertices.begin();
1759}
1760
1767{
1768 if (m_nInternalVertices > 0) {
1769 return ++m_vertices.find(m_lastInternalVertexId);
1770 } else {
1771 return m_vertices.end();
1772 }
1773}
1774
1781{
1782 return m_vertices.find(id);
1783}
1784
1791{
1792 return m_vertices.cbegin();
1793}
1794
1801{
1802 return m_vertices.cend();
1803}
1804
1811{
1812 return m_vertices.cbegin();
1813}
1814
1821{
1822 if (m_nInternalVertices > 0) {
1823 return ++m_vertices.find(m_lastInternalVertexId);
1824 } else {
1825 return m_vertices.end();
1826 }
1827}
1828
1848{
1849 Vertex vertex = source;
1850 vertex.setId(id);
1851
1852 return addVertex(std::move(vertex), id);
1853}
1854
1873{
1874 // Get the id
1875 if (id < 0) {
1876 id = source.getId();
1877 }
1878
1879 // Add a dummy vertex
1880 //
1881 // It is not possible to directly add the source into the storage. First a
1882 // dummy vertex is created and then that vertex is replaced with the source.
1883 //
1884 // The corrdinates of the dummy vertex shuold match the coordinates of the
1885 // source, because the bounding box of the patch is updated every time a
1886 // new vertex is added.
1887 VertexIterator iterator = _addInternalVertex(source.getCoords(), id);
1888
1889 // Replace the newly created vertex with the source
1890 //
1891 // Before replacing the newly created vertex we need to set the id
1892 // of the source to the id that has been assigned to the newly created
1893 // vertex, we also need to mark the vertex as internal.
1894 source.setId(iterator->getId());
1895 source.setInterior(true);
1896
1897 Vertex &vertex = (*iterator);
1898 vertex = std::move(source);
1899
1900 return iterator;
1901}
1902
1921PatchKernel::VertexIterator PatchKernel::addVertex(const std::array<double, 3> &coords, long id)
1922{
1924 return vertexEnd();
1925 }
1926
1927 // Add the vertex
1928 VertexIterator iterator = _addInternalVertex(coords, id);
1929
1930 return iterator;
1931}
1932
1947PatchKernel::VertexIterator PatchKernel::_addInternalVertex(const std::array<double, 3> &coords, long id)
1948{
1949 // Get the id
1950 if (m_vertexIdGenerator) {
1951 if (id < 0) {
1952 id = m_vertexIdGenerator->generate();
1953 } else {
1954 m_vertexIdGenerator->setAssigned(id);
1955 }
1956 } else if (id < 0) {
1957 throw std::runtime_error("No valid id has been provided for the vertex.");
1958 }
1959
1960 // Get the id of the vertex before which the new vertex should be inserted
1961#if BITPIT_ENABLE_MPI==1
1962 //
1963 // If there are ghosts vertices, the internal vertex should be inserted
1964 // before the first ghost vertex.
1965#endif
1966 long referenceId;
1967#if BITPIT_ENABLE_MPI==1
1968 referenceId = m_firstGhostVertexId;
1969#else
1970 referenceId = Vertex::NULL_ID;
1971#endif
1972
1973 // Create the vertex
1974 VertexIterator iterator;
1975 if (referenceId == Vertex::NULL_ID) {
1976 iterator = m_vertices.emreclaim(id, id, coords, true);
1977 } else {
1978 iterator = m_vertices.emreclaimBefore(referenceId, id, id, coords, true);
1979 }
1980 m_nInternalVertices++;
1981
1982 // Update the id of the last internal vertex
1983 if (m_lastInternalVertexId < 0) {
1984 m_lastInternalVertexId = id;
1985 } else if (m_vertices.rawIndex(m_lastInternalVertexId) < m_vertices.rawIndex(id)) {
1986 m_lastInternalVertexId = id;
1987 }
1988
1989 // Update the bounding box
1990 addPointToBoundingBox(iterator->getCoords());
1991
1992#if BITPIT_ENABLE_MPI==1
1993 // Set partitioning information as dirty
1994 setPartitioningInfoDirty(true);
1995#endif
1996
1997 return iterator;
1998}
1999
2000#if BITPIT_ENABLE_MPI==0
2011PatchKernel::VertexIterator PatchKernel::restoreVertex(const std::array<double, 3> &coords, long id)
2012{
2014 return vertexEnd();
2015 }
2016
2017 VertexIterator iterator = m_vertices.find(id);
2018 if (iterator == m_vertices.end()) {
2019 throw std::runtime_error("Unable to restore the specified vertex: the kernel doesn't contain an entry for that vertex.");
2020 }
2021
2022 _restoreInternalVertex(iterator, coords);
2023
2024 return iterator;
2025}
2026#endif
2027
2034void PatchKernel::_restoreInternalVertex(const VertexIterator &iterator, const std::array<double, 3> &coords)
2035{
2036 // Restore the vertex
2037 //
2038 // There is no need to set the id of the vertex as assigned, because
2039 // also the index generator will be restored.
2040 Vertex &vertex = *iterator;
2041 vertex.initialize(iterator.getId(), coords, true);
2042 m_nInternalVertices++;
2043
2044 // Update the bounding box
2045 addPointToBoundingBox(vertex.getCoords());
2046}
2047
2054{
2056 return false;
2057 }
2058
2059 // Delete the vertex
2060#if BITPIT_ENABLE_MPI==1
2061 const Vertex &vertex = m_vertices[id];
2062 bool isInternal = vertex.isInterior();
2063 if (isInternal) {
2064 _deleteInternalVertex(id);
2065 } else {
2066 _deleteGhostVertex(id);
2067 }
2068#else
2069 _deleteInternalVertex(id);
2070#endif
2071
2072 return true;
2073}
2074
2080void PatchKernel::_deleteInternalVertex(long id)
2081{
2082 // Update the bounding box
2083 const Vertex &vertex = m_vertices[id];
2085
2086 // Delete vertex
2087 m_vertices.erase(id, true);
2088 m_nInternalVertices--;
2089 if (id == m_lastInternalVertexId) {
2091 }
2092
2093 // Vertex id is no longer used
2094 if (m_vertexIdGenerator) {
2095 m_vertexIdGenerator->trash(id);
2096 }
2097}
2098
2107{
2108 return countBorderVertices();
2109}
2110
2119{
2120 std::unordered_set<long> borderVertices;
2121 for (const Cell &cell : m_cells) {
2122 int nCellFaces = cell.getFaceCount();
2123 for (int i = 0; i < nCellFaces; ++i) {
2124 if (!cell.isFaceBorder(i)) {
2125 continue;
2126 }
2127
2128 int nFaceVertices = cell.getFaceVertexCount(i);
2129 for (int k = 0; k < nFaceVertices; ++k) {
2130 long faceVertexId = cell.getFaceVertexId(i, k);
2131 borderVertices.insert(faceVertexId);
2132 }
2133 }
2134 }
2135
2136 return borderVertices.size();
2137}
2138
2147{
2148 std::unordered_set<long> usedVertices;
2149 for (const Cell &cell : m_cells) {
2150 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
2151 int nCellVertices = cellVertexIds.size();
2152 for (int i = 0; i < nCellVertices; ++i) {
2153 usedVertices.insert(cellVertexIds[i]);
2154 }
2155 }
2156
2157 return (getVertexCount() - usedVertices.size());
2158}
2159
2168{
2169 VertexConstIterator beginItr = m_vertices.cbegin();
2170 VertexConstIterator endItr = m_vertices.cend();
2171
2172 // Detect used vertices
2173 PiercedStorage<bool, long> vertexUsedFlag(1, &m_vertices);
2174 vertexUsedFlag.fill(false);
2175 for (const Cell &cell : m_cells) {
2176 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
2177 int nCellVertices = cellVertexIds.size();
2178 for (int j = 0; j < nCellVertices; ++j) {
2179 long vertexId = cellVertexIds[j];
2180 vertexUsedFlag[vertexId] = true;
2181 }
2182 }
2183
2184 // Count the orphan vertices
2185 std::size_t nOrhpanVertices = 0;
2186 for (VertexConstIterator itr = beginItr; itr != endItr; ++itr) {
2187 std::size_t vertexRawIndex = itr.getRawIndex();
2188 if (!vertexUsedFlag.rawAt(vertexRawIndex)) {
2189 ++nOrhpanVertices;
2190 }
2191 }
2192
2193 // Build a list of unused vertices
2194 std::vector<long> orhpanVertices(nOrhpanVertices);
2195
2196 std::size_t orphanVertexIndex = 0;
2197 for (VertexConstIterator itr = beginItr; itr != endItr; ++itr) {
2198 std::size_t vertexRawIndex = itr.getRawIndex();
2199 if (!vertexUsedFlag.rawAt(vertexRawIndex)) {
2200 orhpanVertices[orphanVertexIndex] = itr.getId();
2201 ++orphanVertexIndex;
2202 }
2203 }
2204
2205 return orhpanVertices;
2206}
2207
2212{
2214 return false;
2215 }
2216
2217 std::vector<long> list = findOrphanVertices();
2218 deleteVertices(list);
2220
2221 return true;
2222}
2223
2231{
2232 std::vector<long> collapsedVertices;
2234 return collapsedVertices;
2235 }
2236
2237 long nVertices = getVertexCount();
2238 if (nVertices == 0) {
2239 return collapsedVertices;
2240 }
2241
2242 // Update bounding box
2244
2245 //
2246 // Collapse double vertices
2247 //
2248 Vertex::Less vertexLess(10 * std::numeric_limits<double>::epsilon());
2249 auto rawVertexLess = [this, &vertexLess](const std::size_t &i, const std::size_t &j)
2250 {
2251 return vertexLess(this->m_vertices.rawAt(i), this->m_vertices.rawAt(j));
2252 };
2253 std::set<std::size_t, decltype(rawVertexLess)> vertexTree(rawVertexLess);
2254
2255 std::unordered_map<long, long> vertexMap;
2256 for (VertexConstIterator vertexItr = m_vertices.cbegin(); vertexItr != m_vertices.cend(); ++vertexItr) {
2257 std::size_t vertexRawId = vertexItr.getRawIndex();
2258 auto vertexTreeItr = vertexTree.find(vertexRawId);
2259 if (vertexTreeItr == vertexTree.end()) {
2260 vertexTree.insert(vertexRawId);
2261 } else {
2262 long vertexId = vertexItr.getId();
2263 long vertexCoincidentId = m_vertices.rawFind(*vertexTreeItr).getId();
2264 vertexMap.insert({vertexId, vertexCoincidentId});
2265 }
2266 }
2267
2268 // Collapse vertices
2269 if (!vertexMap.empty()) {
2270 // Update cells
2271 //
2272 // If the adjacencies are currently up-to-date, they should kept up-to-date.
2273 AdjacenciesBuildStrategy adjacenciesBuildStrategy = getAdjacenciesBuildStrategy();
2274
2275 bool keepAdjacenciesUpToDate;
2276 if (adjacenciesBuildStrategy != ADJACENCIES_NONE) {
2277 keepAdjacenciesUpToDate = (!areAdjacenciesDirty());
2278 } else {
2279 keepAdjacenciesUpToDate = false;
2280 }
2281
2282 for (Cell &cell : m_cells) {
2283 // Renumber cell vertices
2284 int nRenumberedVertices = cell.renumberVertices(vertexMap);
2285
2286 // Mark adjacencies are dirty
2287 //
2288 // If some vertices have been renumbered, the adjacencies of the cells
2289 // are now dirty.
2290 if ((adjacenciesBuildStrategy != ADJACENCIES_NONE) && (nRenumberedVertices > 0)) {
2291 setCellAlterationFlags(cell.getId(), FLAG_ADJACENCIES_DIRTY);
2292 }
2293 }
2294
2295 if (keepAdjacenciesUpToDate) {
2297 }
2298
2299 // Update interface
2300 for (Interface &interface : m_interfaces) {
2301 // Renumber interface vertices
2302 interface.renumberVertices(vertexMap);
2303 }
2304
2305 // Create the list of collapsed vertices
2306 collapsedVertices.resize(vertexMap.size());
2307
2308 std::size_t k = 0;
2309 for (const auto &entry : vertexMap) {
2310 collapsedVertices[k++] = entry.first;
2311 }
2312 }
2313
2314 return collapsedVertices;
2315}
2316
2321{
2323 return false;
2324 }
2325
2326 std::vector<long> verticesToDelete = collapseCoincidentVertices();
2327 deleteVertices(verticesToDelete);
2328
2329 return true;
2330}
2331
2338const std::array<double, 3> & PatchKernel::getVertexCoords(long id) const
2339{
2340 return getVertex(id).getCoords();
2341}
2342
2350void PatchKernel::getVertexCoords(std::size_t nVertices, const long *ids, std::unique_ptr<std::array<double, 3>[]> *coordinates) const
2351{
2352 *coordinates = std::unique_ptr<std::array<double, 3>[]>(new std::array<double, 3>[nVertices]);
2353 getVertexCoords(nVertices, ids, coordinates->get());
2354}
2355
2365void PatchKernel::getVertexCoords(std::size_t nVertices, const long *ids, std::array<double, 3> *coordinates) const
2366{
2367 for (std::size_t i = 0; i < nVertices; ++i) {
2368 coordinates[i] = getVertex(ids[i]).getCoords();
2369 }
2370}
2371
2379bool PatchKernel::empty(bool global) const
2380{
2381 bool isEmpty = (getCellCount() == 0);
2382#if BITPIT_ENABLE_MPI==1
2383 if (global && isPartitioned()) {
2384 MPI_Allreduce(MPI_IN_PLACE, &isEmpty, 1, MPI_C_BOOL, MPI_LAND, getCommunicator());
2385 }
2386#else
2387 BITPIT_UNUSED(global);
2388#endif
2389
2390 return isEmpty;
2391}
2392
2397{
2398 if (m_nInternalVertices == 0) {
2399 m_lastInternalVertexId = Vertex::NULL_ID;
2400 return;
2401 }
2402
2403 VertexIterator lastInternalVertexItr;
2404#if BITPIT_ENABLE_MPI==1
2405 if (m_nGhostVertices == 0) {
2406 lastInternalVertexItr = --m_vertices.end();
2407 m_lastInternalVertexId = lastInternalVertexItr->getId();
2408 } else {
2409 m_lastInternalVertexId = m_vertices.getSizeMarker(m_nInternalVertices - 1, Vertex::NULL_ID);
2410 }
2411#else
2412 lastInternalVertexItr = --m_vertices.end();
2413 m_lastInternalVertexId = lastInternalVertexItr->getId();
2414#endif
2415}
2416
2426{
2427 return static_cast<bool>(m_cellIdGenerator);
2428}
2429
2439{
2440 if (isCellAutoIndexingEnabled() == enabled) {
2441 return;
2442 }
2443
2444 if (enabled) {
2445 createCellIndexGenerator(true);
2446 } else {
2447 m_cellIdGenerator.reset();
2448 }
2449}
2450
2456void PatchKernel::dumpCellAutoIndexing(std::ostream &stream) const
2457{
2458 m_cellIdGenerator->dump(stream);
2459}
2460
2466void PatchKernel::restoreCellAutoIndexing(std::istream &stream)
2467{
2468 createCellIndexGenerator(false);
2469 m_cellIdGenerator->restore(stream);
2470}
2471
2480void PatchKernel::createCellIndexGenerator(bool populate)
2481{
2482 // Create or reset index generator
2483 if (!m_cellIdGenerator) {
2484 m_cellIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>());
2485 } else {
2486 m_cellIdGenerator->reset();
2487 }
2488
2489 // Populate index generator with current ids
2490 if (populate) {
2491 CellConstIterator beginItr = m_cells.cbegin();
2492 CellConstIterator endItr = m_cells.cend();
2493 for (CellConstIterator itr = beginItr; itr != endItr; ++itr) {
2494 m_cellIdGenerator->setAssigned(itr.getId());
2495 }
2496 }
2497}
2498
2507void PatchKernel::importCellIndexGenerator(const PatchKernel &source)
2508{
2509 if (source.m_cellIdGenerator) {
2510 m_cellIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>(*(source.m_cellIdGenerator)));
2511 } else {
2512 m_cellIdGenerator.reset();
2513 }
2514}
2515
2522{
2523 return m_cells.size();
2524}
2525
2532{
2533 return m_nInternalCells;
2534}
2535
2542{
2543 return getInternalCellCount();
2544}
2545
2552{
2553 return m_cells;
2554}
2555
2562{
2563 return m_cells;
2564}
2565
2573{
2574 return m_cells[id];
2575}
2576
2583const Cell & PatchKernel::getCell(long id) const
2584{
2585 return m_cells[id];
2586}
2587
2595{
2596 return m_cells[id].getType();
2597}
2598
2605{
2606 return m_cells[m_lastInternalCellId];
2607}
2608
2615{
2616 return m_cells[m_lastInternalCellId];
2617}
2618
2625{
2626 return m_cells.find(id);
2627}
2628
2635{
2636 return m_cells.begin();
2637}
2638
2645{
2646 return m_cells.end();
2647}
2648
2655{
2656 return m_cells.begin();
2657}
2658
2668
2675{
2676 if (m_nInternalCells > 0) {
2677 return ++m_cells.find(m_lastInternalCellId);
2678 } else {
2679 return m_cells.end();
2680 }
2681}
2682
2692
2699{
2700 return m_cells.find(id);
2701}
2702
2709{
2710 return m_cells.cbegin();
2711}
2712
2719{
2720 return m_cells.cend();
2721}
2722
2729{
2730 return m_cells.cbegin();
2731}
2732
2742
2750{
2751 if (m_nInternalCells > 0) {
2752 return ++m_cells.find(m_lastInternalCellId);
2753 } else {
2754 return m_cells.cend();
2755 }
2756}
2757
2768
2785{
2786 Cell cell = source;
2787 cell.setId(id);
2788
2789 return addCell(std::move(cell), id);
2790}
2791
2807{
2808 // Get the id
2809 if (id < 0) {
2810 id = source.getId();
2811 }
2812
2813 // Add a dummy cell
2814 //
2815 // It is not possible to directly add the source into the storage. First a
2816 // dummy cell is created and then that cell is replaced with the source.
2817 std::unique_ptr<long[]> dummyConnectStorage = std::unique_ptr<long[]>(nullptr);
2818
2819 CellIterator iterator = _addInternalCell(ElementType::UNDEFINED, std::move(dummyConnectStorage), id);
2820
2821 // Replace the newly created cell with the source
2822 //
2823 // Before replacing the newly created cell we need to set the id of the
2824 // source to the id that has been assigned to the newly created cell.
2825 source.setId(iterator->getId());
2826
2827 Cell &cell = (*iterator);
2828 cell = std::move(source);
2829
2830 return iterator;
2831}
2832
2849{
2850 std::unique_ptr<long[]> connectStorage;
2852 int connectSize = ReferenceElementInfo::getInfo(type).nVertices;
2853 connectStorage = std::unique_ptr<long[]>(new long[connectSize]);
2854 } else {
2855 connectStorage = std::unique_ptr<long[]>(nullptr);
2856 }
2857
2858 return addCell(type, std::move(connectStorage), id);
2859}
2860
2877PatchKernel::CellIterator PatchKernel::addCell(ElementType type, const std::vector<long> &connectivity,
2878 long id)
2879{
2880 int connectSize = connectivity.size();
2881 std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(new long[connectSize]);
2882 std::copy(connectivity.data(), connectivity.data() + connectSize, connectStorage.get());
2883
2884 return addCell(type, std::move(connectStorage), id);
2885}
2886
2904PatchKernel::CellIterator PatchKernel::addCell(ElementType type, std::unique_ptr<long[]> &&connectStorage,
2905 long id)
2906{
2908 return cellEnd();
2909 }
2910
2911 if (Cell::getDimension(type) > getDimension()) {
2912 return cellEnd();
2913 }
2914
2915 CellIterator iterator = _addInternalCell(type, std::move(connectStorage), id);
2916
2917 return iterator;
2918}
2919
2936PatchKernel::CellIterator PatchKernel::_addInternalCell(ElementType type, std::unique_ptr<long[]> &&connectStorage,
2937 long id)
2938{
2939 // Get the id of the cell
2940 if (m_cellIdGenerator) {
2941 if (id < 0) {
2942 id = m_cellIdGenerator->generate();
2943 } else {
2944 m_cellIdGenerator->setAssigned(id);
2945 }
2946 } else if (id < 0) {
2947 throw std::runtime_error("No valid id has been provided for the cell.");
2948 }
2949
2950 // Get the id of the cell before which the new cell should be inserted
2951#if BITPIT_ENABLE_MPI==1
2952 //
2953 // If there are ghosts cells, the internal cell should be inserted
2954 // before the first ghost cell.
2955#endif
2956 long referenceId;
2957#if BITPIT_ENABLE_MPI==1
2958 referenceId = m_firstGhostCellId;
2959#else
2960 referenceId = Cell::NULL_ID;
2961#endif
2962
2963 // Create the cell
2964 bool storeInterfaces = (getInterfacesBuildStrategy() != INTERFACES_NONE);
2965 bool storeAdjacencies = storeInterfaces || (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE);
2966
2967 CellIterator iterator;
2968 if (referenceId == Cell::NULL_ID) {
2969 iterator = m_cells.emreclaim(id, id, type, std::move(connectStorage), true, storeInterfaces, storeAdjacencies);
2970 } else {
2971 iterator = m_cells.emreclaimBefore(referenceId, id, id, type, std::move(connectStorage), true, storeInterfaces, storeAdjacencies);
2972 }
2973 m_nInternalCells++;
2974
2975 // Update the id of the last internal cell
2976 if (m_lastInternalCellId < 0) {
2977 m_lastInternalCellId = id;
2978 } else if (m_cells.rawIndex(m_lastInternalCellId) < m_cells.rawIndex(id)) {
2979 m_lastInternalCellId = id;
2980 }
2981
2982 // Set the alteration flags of the cell
2983 setAddedCellAlterationFlags(id);
2984
2985#if BITPIT_ENABLE_MPI==1
2986 // Set partitioning information as dirty
2987 setPartitioningInfoDirty(true);
2988#endif
2989
2990 return iterator;
2991}
2992
3001void PatchKernel::setAddedCellAlterationFlags(long id)
3002{
3003 AlterationFlags flags = FLAG_NONE;
3004 if (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE) {
3005 flags |= FLAG_ADJACENCIES_DIRTY;
3006 }
3007 if (getInterfacesBuildStrategy() != INTERFACES_NONE) {
3008 flags |= FLAG_INTERFACES_DIRTY;
3009 }
3010
3011 setCellAlterationFlags(id, flags);
3012}
3013
3014#if BITPIT_ENABLE_MPI==0
3027PatchKernel::CellIterator PatchKernel::restoreCell(ElementType type, std::unique_ptr<long[]> &&connectStorage,
3028 long id)
3029{
3031 return cellEnd();
3032 }
3033
3034 if (Cell::getDimension(type) > getDimension()) {
3035 return cellEnd();
3036 }
3037
3038 CellIterator iterator = m_cells.find(id);
3039 if (iterator == m_cells.end()) {
3040 throw std::runtime_error("Unable to restore the specified cell: the kernel doesn't contain an entry for that cell.");
3041 }
3042
3043 _restoreInternalCell(iterator, type, std::move(connectStorage));
3044
3045 return iterator;
3046}
3047#endif
3048
3057void PatchKernel::_restoreInternalCell(const CellIterator &iterator, ElementType type,
3058 std::unique_ptr<long[]> &&connectStorage)
3059{
3060 // Restore the cell
3061 //
3062 // There is no need to set the id of the cell as assigned, because
3063 // also the index generator will be restored.
3064 bool storeInterfaces = (getInterfacesBuildStrategy() != INTERFACES_NONE);
3065 bool storeAdjacencies = storeInterfaces || (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE);
3066
3067 long cellId = iterator.getId();
3068 Cell &cell = *iterator;
3069 cell.initialize(cellId, type, std::move(connectStorage), true, storeInterfaces, storeAdjacencies);
3070 m_nInternalCells++;
3071
3072 // Set the alteration flags of the cell
3073 setRestoredCellAlterationFlags(cellId);
3074}
3075
3081void PatchKernel::setRestoredCellAlterationFlags(long id)
3082{
3083 AlterationFlags flags = FLAG_NONE;
3084 if (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE) {
3085 flags |= FLAG_ADJACENCIES_DIRTY;
3086 }
3087 if (getInterfacesBuildStrategy() != INTERFACES_NONE) {
3088 flags |= FLAG_INTERFACES_DIRTY;
3089 }
3090
3091 setCellAlterationFlags(id, flags);
3092}
3093
3100{
3102 return false;
3103 }
3104
3105 // Delete cell
3106#if BITPIT_ENABLE_MPI==1
3107 const Cell &cell = m_cells[id];
3108 bool isInternalCell = cell.isInterior();
3109 if (isInternalCell) {
3110 _deleteInternalCell(id);
3111 } else {
3112 _deleteGhostCell(id);
3113 }
3114#else
3115 _deleteInternalCell(id);
3116#endif
3117
3118 return true;
3119}
3120
3126void PatchKernel::_deleteInternalCell(long id)
3127{
3128 // Set the alteration flags of the cell
3129 setDeletedCellAlterationFlags(id);
3130
3131 // Delete cell
3132 m_cells.erase(id, true);
3133 m_nInternalCells--;
3134 if (id == m_lastInternalCellId) {
3136 }
3137
3138 // Cell id is no longer used
3139 if (m_cellIdGenerator) {
3140 m_cellIdGenerator->trash(id);
3141 }
3142}
3143
3151void PatchKernel::setDeletedCellAlterationFlags(long id)
3152{
3153 const Cell &cell = getCell(id);
3154
3155 // Set the alteration flags of the cell
3156 resetCellAlterationFlags(id, FLAG_DELETED);
3157
3158 // Set the alteration flags of the adjacent cells
3159 const int nCellAdjacencies = cell.getAdjacencyCount();
3160 const long *cellAdjacencies = cell.getAdjacencies();
3161 for (int k = 0; k < nCellAdjacencies; ++k) {
3162 long adjacencyId = cellAdjacencies[k];
3163 if (!testCellAlterationFlags(adjacencyId, FLAG_DELETED)) {
3164 AlterationFlags flags = FLAG_DANGLING;
3165 if (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE) {
3166 flags |= FLAG_ADJACENCIES_DIRTY;
3167 }
3168 if (getInterfacesBuildStrategy() != INTERFACES_NONE) {
3169 flags |= FLAG_INTERFACES_DIRTY;
3170 }
3171
3172 setCellAlterationFlags(adjacencyId, flags);
3173 }
3174 }
3175
3176 // Set the alteration flags of the interfaces
3177 const int nCellInterfaces = cell.getInterfaceCount();
3178 const long *cellInterfaces = cell.getInterfaces();
3179 for (int k = 0; k < nCellInterfaces; ++k) {
3180 long interfaceId = cellInterfaces[k];
3181 if (!testInterfaceAlterationFlags(interfaceId, FLAG_DELETED)) {
3182 setInterfaceAlterationFlags(interfaceId, FLAG_DANGLING);
3183 }
3184 }
3185}
3186
3195{
3196 return countBorderCells();
3197}
3198
3207{
3208 long nBorderCells = 0;
3209 for (const Cell &cell : m_cells) {
3210 int nCellFaces = cell.getFaceCount();
3211 for (int i = 0; i < nCellFaces; ++i) {
3212 if (cell.isFaceBorder(i)) {
3213 ++nBorderCells;
3214 break;
3215 }
3216 }
3217 }
3218
3219 return nBorderCells;
3220}
3221
3231{
3232 return findOrphanCells().size();
3233}
3234
3243std::vector<long> PatchKernel::findOrphanCells() const
3244{
3245 // Compute vertex valence
3246 std::unordered_map<long, short> vertexValence;
3247 for (const Cell &cell : m_cells) {
3248 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
3249 int nCellVertices = cellVertexIds.size();
3250 for (int j = 0; j < nCellVertices; j++) {
3251 long vertexId = cellVertexIds[j];
3252 vertexValence[vertexId] += 1;
3253 }
3254 }
3255
3256 // Loop over cells
3257 std::vector<long> orphanCells;
3258 for (const Cell &cell : m_cells) {
3259 long isIsolated = true;
3260 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
3261 int nCellVertices = cellVertexIds.size();
3262 for (int j = 0; j < nCellVertices; j++) {
3263 long vertexId = cellVertexIds[j];
3264 if (vertexValence[vertexId] > 1) {
3265 isIsolated = false;
3266 break;
3267 }
3268 }
3269
3270 if (isIsolated) {
3271 orphanCells.push_back(cell.getId());
3272 }
3273 }
3274
3275 return orphanCells;
3276}
3277
3287{
3288 return findDuplicateCells().size();
3289}
3290
3299std::vector<long> PatchKernel::findDuplicateCells() const
3300{
3301 // Define the hasher and the predicate to be used for lists of vertex ids
3302 //
3303 // These operators should be able to identify that two lists of vertex ids
3304 // are the same regardless of the order in which the ids are listed.
3305 auto hasher = [](const ConstProxyVector<long> &ids)
3306 {
3307 std::size_t hash = std::hash<long>{}(0);
3308 for (long id : ids) {
3309 hash = hash + std::hash<long>{}(id);
3310 }
3311
3312 return hash;
3313 };
3314
3315 std::unordered_map<long, std::size_t > counters;
3316 auto predicate = [&counters](const ConstProxyVector<long> &ids_A, const ConstProxyVector<long> &ids_B)
3317 {
3318 counters.clear();
3319 for (long id : ids_A) {
3320 counters[id]++;
3321 }
3322 for (long id : ids_B) {
3323 counters[id]--;
3324 }
3325
3326 for (const auto &entry : counters) {
3327 if (entry.second != 0) {
3328 return false;
3329 }
3330 }
3331
3332 return true;
3333 };
3334
3335 // Detect if there are cells that share the same list of vertices
3336 //
3337 // For each cell, the list of vertex ids is added into a set. If a collision
3338 // is detected, we have found a duplicate cell.
3339 std::vector<long> duplicateCells;
3340 std::unordered_set<ConstProxyVector<long>, decltype(hasher), decltype(predicate)> vertexStash(getCellCount(), hasher, predicate);
3341 for (const Cell &cell : m_cells) {
3342 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
3343 auto vertexStashItr = vertexStash.find(cellVertexIds);
3344 if (vertexStashItr == vertexStash.end()) {
3345 vertexStash.insert(std::move(cellVertexIds));
3346 } else {
3347 duplicateCells.push_back(cell.getId());
3348 }
3349 }
3350
3351 return duplicateCells;
3352}
3353
3358{
3359 if (m_nInternalCells == 0) {
3360 m_lastInternalCellId = Cell::NULL_ID;
3361 return;
3362 }
3363
3364 CellIterator lastInternalCellItr;
3365#if BITPIT_ENABLE_MPI==1
3366 if (m_nGhostCells == 0) {
3367 lastInternalCellItr = --m_cells.end();
3368 m_lastInternalCellId = lastInternalCellItr->getId();
3369 } else {
3370 m_lastInternalCellId = m_cells.getSizeMarker(m_nInternalCells - 1, Cell::NULL_ID);
3371 }
3372#else
3373 lastInternalCellItr = --m_cells.end();
3374 m_lastInternalCellId = lastInternalCellItr->getId();
3375#endif
3376}
3377
3385{
3386 return id;
3387}
3388
3395std::vector<long> PatchKernel::findCellNeighs(long id) const
3396{
3397 std::vector<long> neighs;
3398 findCellNeighs(id, &neighs);
3399
3400 return neighs;
3401}
3402
3411void PatchKernel::findCellNeighs(long id, std::vector<long> *neighs) const
3412{
3413 _findCellNeighs(id, nullptr, neighs);
3414}
3415
3433std::vector<long> PatchKernel::findCellNeighs(long id, int codimension, bool complete) const
3434{
3435 std::vector<long> neighs;
3436 findCellNeighs(id, codimension, complete, &neighs);
3437
3438 return neighs;
3439}
3440
3461void PatchKernel::findCellNeighs(long id, int codimension, bool complete, std::vector<long> *neighs) const
3462{
3463 assert(codimension >= 1 && codimension <= getDimension());
3464
3465 if (codimension == 1) {
3466 findCellFaceNeighs(id, neighs);
3467 } else if (codimension == getDimension()) {
3468 findCellVertexNeighs(id, complete, neighs);
3469 } else if (codimension == 2) {
3470 findCellEdgeNeighs(id, complete, neighs);
3471 }
3472}
3473
3480std::vector<long> PatchKernel::findCellFaceNeighs(long id) const
3481{
3482 std::vector<long> neighs;
3483 findCellFaceNeighs(id, &neighs);
3484
3485 return neighs;
3486}
3487
3502void PatchKernel::_findCellNeighs(long id, const std::vector<long> *blackList, std::vector<long> *neighs) const
3503{
3504 // Some patches can work (at least partially) without initializing the
3505 // cell list. To handle those patches, if there are no cells the vertex
3506 // count is evaluated using the ReferenceElementInfo associated to the cell.
3507 int nCellVertices;
3508 if (m_cells.size() == 0) {
3509 ElementType cellType = getCellType(id);
3510 const ReferenceElementInfo &cellTypeInfo = ReferenceElementInfo::getInfo(cellType);
3511 nCellVertices = cellTypeInfo.nVertices;
3512 } else {
3513 const Cell &cell = getCell(id);
3514 nCellVertices = cell.getVertexCount();
3515 }
3516
3517 for (int i = 0; i < nCellVertices; ++i) {
3518 _findCellVertexNeighs(id, i, blackList, neighs);
3519 }
3520}
3521
3531void PatchKernel::findCellFaceNeighs(long id, std::vector<long> *neighs) const
3532{
3533 // Some patches can work (at least partially) without initializing the
3534 // cell list. To handle those patches, if there are no cells the face
3535 // count is evaluated using the ReferenceElementInfo associated to the cell.
3536 int nCellFaces;
3537 if (m_cells.size() == 0) {
3538 ElementType cellType = getCellType(id);
3539 const ReferenceElementInfo &cellTypeInfo = ReferenceElementInfo::getInfo(cellType);
3540 nCellFaces = cellTypeInfo.nFaces;
3541 } else {
3542 const Cell &cell = getCell(id);
3543 nCellFaces = cell.getFaceCount();
3544 }
3545
3546 // Get the neighbours
3547 for (int i = 0; i < nCellFaces; ++i) {
3548 _findCellFaceNeighs(id, i, nullptr, neighs);
3549 }
3550}
3551
3559std::vector<long> PatchKernel::findCellFaceNeighs(long id, int face) const
3560{
3561 std::vector<long> neighs;
3562 _findCellFaceNeighs(id, face, nullptr, &neighs);
3563
3564 return neighs;
3565}
3566
3577void PatchKernel::findCellFaceNeighs(long id, int face, std::vector<long> *neighs) const
3578{
3579 _findCellFaceNeighs(id, face, nullptr, neighs);
3580}
3581
3595void PatchKernel::_findCellFaceNeighs(long id, int face, const std::vector<long> *blackList, std::vector<long> *neighs) const
3596{
3597 const Cell &cell = getCell(id);
3598
3599 int nFaceAdjacencies = cell.getAdjacencyCount(face);
3600 const long *faceAdjacencies = cell.getAdjacencies(face);
3601 for (int k = 0; k < nFaceAdjacencies; ++k) {
3602 long neighId = faceAdjacencies[k];
3603 if (!blackList || utils::findInOrderedVector<long>(neighId, *blackList) == blackList->end()) {
3604 utils::addToOrderedVector<long>(neighId, *neighs);
3605 }
3606 }
3607}
3608
3620std::vector<long> PatchKernel::findCellEdgeNeighs(long id, bool complete) const
3621{
3622 std::vector<long> neighs;
3623 findCellEdgeNeighs(id, complete, &neighs);
3624
3625 return neighs;
3626}
3627
3642void PatchKernel::findCellEdgeNeighs(long id, bool complete, std::vector<long> *neighs) const
3643{
3644 assert(isThreeDimensional());
3645 if (!isThreeDimensional()) {
3646 return;
3647 }
3648
3649 // Some patches can work (at least partially) without initializing the
3650 // cell list. To handle those patches, if there are no cells the edge
3651 // count is evaluated using the ReferenceElementInfo associated to the cell.
3652 int nCellEdges;
3653 if (m_cells.size() == 0) {
3654 ElementType cellType = getCellType(id);
3655 const ReferenceElementInfo &cellTypeInfo = ReferenceElementInfo::getInfo(cellType);
3656 nCellEdges = cellTypeInfo.nEdges;
3657 } else {
3658 const Cell &cell = getCell(id);
3659 nCellEdges = cell.getEdgeCount();
3660 }
3661
3662 // Get the neighbours
3663 std::unique_ptr<std::vector<long>> blackList;
3664 if (!complete) {
3665 blackList = std::unique_ptr<std::vector<long>>(new std::vector<long>());
3666 findCellFaceNeighs(id, blackList.get());
3667 }
3668
3669 for (int i = 0; i < nCellEdges; ++i) {
3670 _findCellEdgeNeighs(id, i, blackList.get(), neighs);
3671 }
3672}
3673
3683std::vector<long> PatchKernel::findCellEdgeNeighs(long id, int edge) const
3684{
3685 std::vector<long> neighs;
3686 findCellEdgeNeighs(id, edge, &neighs);
3687
3688 return neighs;
3689}
3690
3703void PatchKernel::findCellEdgeNeighs(long id, int edge, std::vector<long> *neighs) const
3704{
3705 _findCellEdgeNeighs(id, edge, nullptr, neighs);
3706}
3707
3723void PatchKernel::_findCellEdgeNeighs(long id, int edge, const std::vector<long> *blackList, std::vector<long> *neighs) const
3724{
3725 assert(isThreeDimensional());
3726 if (!isThreeDimensional()) {
3727 return;
3728 }
3729
3730 const Cell &cell = getCell(id);
3731 ConstProxyVector<int> edgeVertices = cell.getEdgeLocalConnect(edge);
3732 std::size_t nEdgeVertices = edgeVertices.size();
3733 if (nEdgeVertices < 2) {
3734 return;
3735 }
3736
3737 // Find candidates neighbours
3738 //
3739 // These are the negihbours of the first vertex of the edge.
3740 const int GUESS_NEIGHS_COUNT = 3;
3741
3742 std::vector<long> candidateIds;
3743 candidateIds.reserve(GUESS_NEIGHS_COUNT);
3744 _findCellVertexNeighs(id, edgeVertices[0], blackList, &candidateIds);
3745
3746 // Discard candidates that doesn't contain the last vertex of the edge
3747 long lastEdgeVertexId = cell.getEdgeVertexId(edge, nEdgeVertices - 1);
3748
3749 ConstProxyVector<long> candidateVertexIds;
3750 for (long candidateId : candidateIds) {
3751 const Cell &candidateNeigh = m_cells.at(candidateId);
3752 candidateVertexIds = candidateNeigh.getVertexIds();
3753 std::size_t nCandidateVertices = candidateVertexIds.size();
3754
3755 bool isEdgeNeighbour = false;
3756 for (std::size_t k = 0; k < nCandidateVertices; ++k) {
3757 if (candidateVertexIds[k] == lastEdgeVertexId) {
3758 isEdgeNeighbour = true;
3759 break;
3760 }
3761 }
3762
3763 if (isEdgeNeighbour) {
3764 utils::addToOrderedVector<long>(candidateId, *neighs);
3765 }
3766 }
3767}
3768
3778std::vector<long> PatchKernel::findCellVertexNeighs(long id, bool complete) const
3779{
3780 std::vector<long> neighs;
3781 findCellVertexNeighs(id, complete, &neighs);
3782
3783 return neighs;
3784}
3785
3798void PatchKernel::findCellVertexNeighs(long id, bool complete, std::vector<long> *neighs) const
3799{
3800 // Some patches can work (at least partially) without initializing the
3801 // cell list. To handle those patches, if there are no cells the vertex
3802 // count is evaluated using the ReferenceElementInfo associated to the cell.
3803 int nCellVertices;
3804 if (m_cells.size() == 0) {
3805 ElementType cellType = getCellType(id);
3806 const ReferenceElementInfo &cellTypeInfo = ReferenceElementInfo::getInfo(cellType);
3807 nCellVertices = cellTypeInfo.nVertices;
3808 } else {
3809 const Cell &cell = getCell(id);
3810 nCellVertices = cell.getVertexCount();
3811 }
3812
3813 // Get the neighbours
3814 std::unique_ptr<std::vector<long>> blackList;
3815 if (!complete) {
3816 blackList = std::unique_ptr<std::vector<long>>(new std::vector<long>());
3817 if (isThreeDimensional()) {
3818 findCellEdgeNeighs(id, true, blackList.get());
3819 } else {
3820 findCellFaceNeighs(id, true, blackList.get());
3821 }
3822 }
3823
3824 for (int i = 0; i < nCellVertices; ++i) {
3825 _findCellVertexNeighs(id, i, blackList.get(), neighs);
3826 }
3827}
3828
3836std::vector<long> PatchKernel::findCellVertexNeighs(long id, int vertex) const
3837{
3838 std::vector<long> neighs;
3839 findCellVertexNeighs(id, vertex, &neighs);
3840
3841 return neighs;
3842}
3843
3854void PatchKernel::findCellVertexNeighs(long id, int vertex, std::vector<long> *neighs) const
3855{
3856 _findCellVertexNeighs(id, vertex, nullptr, neighs);
3857}
3858
3888void PatchKernel::_findCellVertexNeighs(long id, int vertex, const std::vector<long> *blackList, std::vector<long> *neighs) const
3889{
3890 const Cell &cell = getCell(id);
3891 long vertexId = cell.getVertexId(vertex);
3892
3893 // Since we are processing a small number of cells it's more efficient to
3894 // store the list of already processed cells in a vector instead of using
3895 // a set or an unordered_set. To speed-up the lookup, the vector is kept
3896 // sorted.
3897 const int GUESS_NEIGHS_COUNT = 8;
3898
3899 std::vector<long> alreadyProcessed;
3900 alreadyProcessed.reserve(GUESS_NEIGHS_COUNT);
3901
3902 std::vector<long> scanQueue;
3903 scanQueue.reserve(GUESS_NEIGHS_COUNT);
3904 scanQueue.push_back(id);
3905
3906 while (!scanQueue.empty()) {
3907 // Pop a cell to process
3908 long scanCellId = scanQueue.back();
3909 const Cell &scanCell = getCell(scanCellId);
3910 scanQueue.pop_back();
3911 utils::addToOrderedVector<long>(scanCell.getId(), alreadyProcessed);
3912
3913 // Get cell information
3914 const ReferenceElementInfo *scanCellInfo = nullptr;
3915 const long *scanCellConnectivity = nullptr;
3916 if (scanCell.hasInfo()) {
3917 scanCellInfo = &(scanCell.getInfo());
3918 scanCellConnectivity = scanCell.getConnect();
3919 }
3920
3921 // Use face adjacencies to find vertex negihbours
3922 int nFaces;
3923 if (scanCellInfo) {
3924 nFaces = scanCellInfo->nFaces;
3925 } else {
3926 nFaces = scanCell.getFaceCount();
3927 }
3928
3929 for (int i = 0; i < nFaces; ++i) {
3930 // Discard faces with no neighbours
3931 if (scanCell.isFaceBorder(i)) {
3932 continue;
3933 }
3934
3935 // Discard faces that don't own the vertex
3936 //
3937 // We use differents algorithm depending on whether the cell has a
3938 // reference element or not. If the cell has a reference element,
3939 // accessing the local connectivity of the face is cheap. If the
3940 // cell has no reference element, it is better to avoid using the
3941 // local connectivity of the face.
3942 //
3943 // Moreover, to optimize the search for cells that has a reference
3944 // element, we work directly on the connectivity inseatd of on the
3945 // list of vertex ids. That's because for reference elements the
3946 // connectivity is just a list of vertices.
3947 bool faceOwnsVertex = false;
3948 if (scanCellInfo) {
3949 const ReferenceElementInfo &faceInfo = ReferenceElementInfo::getInfo(scanCellInfo->faceTypeStorage[i]);
3950 const int *faceLocalConnectivity = scanCellInfo->faceConnectStorage[i].data();
3951 const int nFaceVertices = faceInfo.nVertices;
3952 for (int k = 0; k < nFaceVertices; ++k) {
3953 long faceVertexId = scanCellConnectivity[faceLocalConnectivity[k]];
3954 if (faceVertexId == vertexId) {
3955 faceOwnsVertex = true;
3956 break;
3957 }
3958 }
3959 } else {
3960 ConstProxyVector<long> faceVertexIds = scanCell.getFaceVertexIds(i);
3961 int nFaceVertices = faceVertexIds.size();
3962 for (int k = 0; k < nFaceVertices; ++k) {
3963 long faceVertexId = faceVertexIds[k];
3964 if (faceVertexId == vertexId) {
3965 faceOwnsVertex = true;
3966 break;
3967 }
3968 }
3969 }
3970
3971 if (!faceOwnsVertex) {
3972 continue;
3973 }
3974
3975 // Loop through the adjacencies
3976 //
3977 // Non-manifold patches may have faces with multiple adjacencies.
3978 int nFaceAdjacencies = scanCell.getAdjacencyCount(i);
3979 const long *faceAdjacencies = scanCell.getAdjacencies(i);
3980 for (int k = 0; k < nFaceAdjacencies; ++k) {
3981 long faceNeighId = faceAdjacencies[k];
3982
3983 // Discard neighbours that have already been processed
3984 if (utils::findInOrderedVector<long>(faceNeighId, alreadyProcessed) != alreadyProcessed.end()) {
3985 continue;
3986 }
3987
3988 // Update list of vertex neighbours
3989 if (!blackList || utils::findInOrderedVector<long>(faceNeighId, *blackList) == blackList->end()) {
3990 utils::addToOrderedVector<long>(faceNeighId, *neighs);
3991 }
3992
3993 // Update scan list
3994 scanQueue.push_back(faceNeighId);
3995 }
3996 }
3997 }
3998}
3999
4007std::vector<long> PatchKernel::findCellVertexOneRing(long id, int vertex) const
4008{
4009 std::vector<long> ring;
4010 findCellVertexOneRing(id, vertex, &ring);
4011
4012 return ring;
4013}
4014
4025void PatchKernel::findCellVertexOneRing(long id, int vertex, std::vector<long> *ring) const
4026{
4027 findCellVertexNeighs(id, vertex, ring);
4028 utils::addToOrderedVector<long>(id, *ring);
4029}
4030
4047bool PatchKernel::findFaceNeighCell(long cellId, long neighId, int *cellFace, int *cellAdjacencyId) const
4048{
4049 const Cell &cell = getCell(cellId);
4050
4051 int nFaces = cell.getFaceCount();
4052 for (int i = 0; i < nFaces; ++i) {
4053 int nFaceAdjacencies = cell.getAdjacencyCount(i);
4054 const long *faceAdjacencies = cell.getAdjacencies(i);
4055 for (int k = 0; k < nFaceAdjacencies; ++k) {
4056 long faceNeighId = faceAdjacencies[k];
4057 if (faceNeighId < 0) {
4058 continue;
4059 } else if (faceNeighId == neighId) {
4060 *cellFace = i;
4061 *cellAdjacencyId = k;
4062 return true;
4063 }
4064 }
4065 }
4066
4067 *cellFace = -1;
4068 *cellAdjacencyId = -1;
4069
4070 return false;
4071}
4072
4079{
4080 std::set<int> list;
4082 for (CellConstIterator itr = internalCellConstBegin(); itr != endItr; ++itr) {
4083 list.insert(itr->getPID());
4084 }
4085
4086 return list;
4087}
4088
4095std::vector<long> PatchKernel::getInternalCellsByPID(int pid)
4096{
4097 std::vector<long> cells;
4099 for (CellConstIterator itr = internalCellConstBegin(); itr != endItr; ++itr) {
4100 if (itr->getPID() == pid){
4101 cells.push_back(itr.getId());
4102 }
4103 }
4104
4105 return cells;
4106}
4107
4116std::vector<long> PatchKernel::findVertexOneRing(long vertexId) const
4117{
4118 std::vector<long> ring;
4119 findVertexOneRing(vertexId, &ring);
4120
4121 return ring;
4122}
4123
4134void PatchKernel::findVertexOneRing(long vertexId, std::vector<long> *ring) const
4135{
4136 // Find local id of the vertex
4137 //
4138 // Coincident vertices with different ids are not supported, this case is
4139 // special because a cell may contain a point with the vertex coordinates,
4140 // but may not contain the requested vertex (because it contains one of
4141 // the other coincident vertices).
4142 const std::array<double, 3> &coords = getVertexCoords(vertexId);
4143 long cellId = locatePoint(coords);
4144 if (cellId == bitpit::Element::NULL_ID) {
4145 return;
4146 }
4147
4148 int vertexLocalId = getCell(cellId).findVertex(vertexId);
4149 assert(vertexLocalId >= 0);
4150
4151 // Find vertex one-ring
4152 findCellVertexOneRing(cellId, vertexLocalId, ring);
4153}
4154
4164{
4165 return static_cast<bool>(m_interfaceIdGenerator);
4166}
4167
4180{
4181 if (isInterfaceAutoIndexingEnabled() == enabled) {
4182 return;
4183 }
4184
4185 if (enabled) {
4186 createInterfaceIndexGenerator(true);
4187 } else {
4188 if (getInterfacesBuildStrategy() == INTERFACES_AUTOMATIC) {
4189 throw std::runtime_error("Auto-indexing cannot be disabled if interfaces build strategy is set to automatic.");
4190 }
4191
4192 m_interfaceIdGenerator.reset();
4193 }
4194}
4195
4201void PatchKernel::dumpInterfaceAutoIndexing(std::ostream &stream) const
4202{
4203 m_interfaceIdGenerator->dump(stream);
4204}
4205
4211void PatchKernel::restoreInterfaceAutoIndexing(std::istream &stream)
4212{
4213 createInterfaceIndexGenerator(false);
4214 m_interfaceIdGenerator->restore(stream);
4215}
4216
4225void PatchKernel::createInterfaceIndexGenerator(bool populate)
4226{
4227 // Create or reset index generator
4228 if (!m_interfaceIdGenerator) {
4229 m_interfaceIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>());
4230 } else {
4231 m_interfaceIdGenerator->reset();
4232 }
4233
4234 // Populate index generator with current ids
4235 if (populate) {
4236 InterfaceConstIterator beginItr = m_interfaces.cbegin();
4237 InterfaceConstIterator endItr = m_interfaces.cend();
4238 for (InterfaceConstIterator itr = beginItr; itr != endItr; ++itr) {
4239 m_interfaceIdGenerator->setAssigned(itr.getId());
4240 }
4241 }
4242}
4243
4252void PatchKernel::importInterfaceIndexGenerator(const PatchKernel &source)
4253{
4254 if (source.m_interfaceIdGenerator) {
4255 m_interfaceIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>(*(source.m_interfaceIdGenerator)));
4256 } else {
4257 m_interfaceIdGenerator.reset();
4258 }
4259}
4260
4267{
4268 return m_interfaces.size();
4269}
4270
4277{
4278 return m_interfaces;
4279}
4280
4287{
4288 return m_interfaces;
4289}
4290
4298{
4299 return m_interfaces[id];
4300}
4301
4309{
4310 return m_interfaces[id];
4311}
4312
4320{
4321 return m_interfaces[id].getType();
4322}
4323
4330{
4331 return m_interfaces.find(id);
4332}
4333
4340{
4341 return m_interfaces.begin();
4342}
4343
4350{
4351 return m_interfaces.end();
4352}
4353
4360{
4361 return m_interfaces.find(id);
4362}
4363
4370{
4371 return m_interfaces.cbegin();
4372}
4373
4380{
4381 return m_interfaces.cend();
4382}
4383
4400{
4401 Interface interface = source;
4402 interface.setId(id);
4403
4404 return addInterface(std::move(interface), id);
4405}
4406
4423{
4424 // Get the id
4425 if (id < 0) {
4426 id = source.getId();
4427 }
4428
4429 // Add a dummy interface
4430 //
4431 // It is not possible to directly add the source into the storage. First
4432 // a dummy interface is created and then that interface is replaced with
4433 // the source.
4434 std::unique_ptr<long[]> dummyConnectStorage = std::unique_ptr<long[]>(nullptr);
4435
4436 InterfaceIterator iterator = _addInterface(ElementType::UNDEFINED, std::move(dummyConnectStorage), id);
4437
4438 // Replace the newly created interface with the source
4439 //
4440 // Before replacing the newly created interface we need to set the id
4441 // of the source to the id that has been assigned to the newly created
4442 // interface.
4443 source.setId(iterator->getId());
4444
4445 Interface &interface = (*iterator);
4446 interface = std::move(source);
4447
4448 return iterator;
4449}
4450
4467{
4468 int connectSize = ReferenceElementInfo::getInfo(type).nVertices;
4469 std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(new long[connectSize]);
4470
4471 return addInterface(type, std::move(connectStorage), id);
4472}
4473
4490 const std::vector<long> &connectivity,
4491 long id)
4492{
4493 int connectSize = connectivity.size();
4494 std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(new long[connectSize]);
4495 std::copy(connectivity.data(), connectivity.data() + connectSize, connectStorage.get());
4496
4497 return addInterface(type, std::move(connectStorage), id);
4498}
4499
4517 std::unique_ptr<long[]> &&connectStorage,
4518 long id)
4519{
4521 return interfaceEnd();
4522 }
4523
4524 if (Interface::getDimension(type) > (getDimension() - 1)) {
4525 return interfaceEnd();
4526 }
4527
4528 InterfaceIterator iterator = _addInterface(type, std::move(connectStorage), id);
4529
4530 return iterator;
4531}
4532
4549PatchKernel::InterfaceIterator PatchKernel::_addInterface(ElementType type,
4550 std::unique_ptr<long[]> &&connectStorage,
4551 long id)
4552{
4553 // Get the id
4554 if (m_interfaceIdGenerator) {
4555 if (id < 0) {
4556 id = m_interfaceIdGenerator->generate();
4557 } else {
4558 m_interfaceIdGenerator->setAssigned(id);
4559 }
4560 } else if (id < 0) {
4561 throw std::runtime_error("No valid id has been provided for the interface.");
4562 }
4563
4564 // Create the interface
4565 PiercedVector<Interface>::iterator iterator = m_interfaces.emreclaim(id, id, type, std::move(connectStorage));
4566
4567 // Set the alteration flags
4568 setAddedInterfaceAlterationFlags(id);
4569
4570 return iterator;
4571}
4572
4581void PatchKernel::setAddedInterfaceAlterationFlags(long id)
4582{
4583 BITPIT_UNUSED(id);
4584}
4585
4599 std::unique_ptr<long[]> &&connectStorage,
4600 long id)
4601{
4603 return interfaceEnd();
4604 }
4605
4606 if (Interface::getDimension(type) > (getDimension() - 1)) {
4607 return interfaceEnd();
4608 }
4609
4610 InterfaceIterator iterator = m_interfaces.find(id);
4611 if (iterator == m_interfaces.end()) {
4612 throw std::runtime_error("Unable to restore the specified interface: the kernel doesn't contain an entry for that interface.");
4613 }
4614
4615 _restoreInterface(iterator, type, std::move(connectStorage));
4616
4617 return iterator;
4618}
4619
4631void PatchKernel::_restoreInterface(const InterfaceIterator &iterator, ElementType type,
4632 std::unique_ptr<long[]> &&connectStorage)
4633{
4634 // Restore the interface
4635 //
4636 // There is no need to set the id of the interfaces as assigned, because
4637 // also the index generator will be restored.
4638 long interfaceId = iterator.getId();
4639 Interface &interface = *iterator;
4640 interface.initialize(interfaceId, type, std::move(connectStorage));
4641
4642 // Set the alteration flags
4643 setRestoredInterfaceAlterationFlags(interfaceId);
4644}
4645
4651void PatchKernel::setRestoredInterfaceAlterationFlags(long id)
4652{
4653 BITPIT_UNUSED(id);
4654}
4655
4662{
4664 return false;
4665 }
4666
4667 _deleteInterface(id);
4668
4669 return true;
4670}
4671
4677void PatchKernel::_deleteInterface(long id)
4678{
4679 // Set the alteration flags
4680 setDeletedInterfaceAlterationFlags(id);
4681
4682 // Delete interface
4683 m_interfaces.erase(id, true);
4684
4685 // Interface id is no longer used
4686 if (m_interfaceIdGenerator) {
4687 m_interfaceIdGenerator->trash(id);
4688 }
4689}
4690
4698void PatchKernel::setDeletedInterfaceAlterationFlags(long id)
4699{
4700 resetInterfaceAlterationFlags(id, FLAG_DELETED);
4701}
4702
4711{
4712 return countBorderInterfaces();
4713}
4714
4723{
4724 long nBorderInterfaces = 0;
4725 for (const Interface &interface : m_interfaces) {
4726 if (interface.getNeigh() < 0) {
4727 ++nBorderInterfaces;
4728 }
4729 }
4730
4731 return nBorderInterfaces;
4732}
4733
4743{
4744 long nOrphanInterfaces = 0;
4746 for (InterfaceConstIterator itr = interfaceConstBegin(); itr != endItr; ++itr) {
4747 const long interfaceId = itr.getId();
4748 if (isInterfaceOrphan(interfaceId)) {
4749 ++nOrphanInterfaces;
4750 }
4751 }
4752
4753 return nOrphanInterfaces;
4754}
4755
4764std::vector<long> PatchKernel::findOrphanInterfaces() const
4765{
4766 std::vector<long> orphanInterfaces;
4768 for (InterfaceConstIterator itr = interfaceConstBegin(); itr != endItr; ++itr) {
4769 const long interfaceId = itr.getId();
4770 if (isInterfaceOrphan(interfaceId)) {
4771 orphanInterfaces.push_back(interfaceId);
4772 }
4773 }
4774
4775 return orphanInterfaces;
4776}
4777
4782{
4784 return false;
4785 }
4786
4787 std::vector<long> list = findOrphanInterfaces();
4788 deleteInterfaces(list);
4789
4790 return true;
4791}
4792
4802{
4803 const Interface &interface = getInterface(id);
4804
4805 // Interface is not orphan if it has an owner or a neighbour
4806 long ownerId = interface.getOwner();
4807 long neighId = interface.getNeigh();
4808 if (ownerId >= 0 && neighId >= 0) {
4809 return false;
4810 }
4811
4812 // Interface is not orphan if it's on a border face of an internal cell
4813 if (ownerId >= 0 && neighId < 0) {
4814 const Cell &owner = getCell(ownerId);
4815 if (owner.isInterior()) {
4816 return false;
4817 }
4818 }
4819
4820 return true;
4821}
4822
4829{
4830 double nFaces = 0;
4831 for (const Cell &cell : m_cells) {
4832 int nCellFaces = cell.getFaceCount();
4833 for (int i = 0; i < nCellFaces; ++i) {
4834 if (!cell.isFaceBorder(i)) {
4835 nFaces += 1. / (cell.getAdjacencyCount(i) + 1);
4836 } else {
4837 nFaces += 1.;
4838 }
4839 }
4840 }
4841
4842 return ((long) round(nFaces));
4843}
4844
4853{
4854 return countBorderFaces();
4855}
4856
4865{
4866 long nBorderFaces = 0;
4867 for (const Cell &cell : m_cells) {
4868 int nCellFaces = cell.getFaceCount();
4869 for (int i = 0; i < nCellFaces; ++i) {
4870 if (cell.isFaceBorder(i)) {
4871 ++nBorderFaces;
4872 }
4873 }
4874 }
4875
4876 return nBorderFaces;
4877}
4878
4884void PatchKernel::dumpVertices(std::ostream &stream) const
4885{
4886 // Dump kernel
4887 m_vertices.dumpKernel(stream);
4888
4889 // Dump vertices
4890 for (const Vertex &vertex : m_vertices) {
4891 utils::binary::write(stream, vertex.getId());
4892#if BITPIT_ENABLE_MPI==1
4893 utils::binary::write(stream, getVertexOwner(vertex.getId()));
4894#else
4895 int dummyOwner = 0;
4896 utils::binary::write(stream, dummyOwner);
4897#endif
4898
4899 const std::array<double, 3> &coords = vertex.getCoords();
4900 utils::binary::write(stream, coords[0]);
4901 utils::binary::write(stream, coords[1]);
4902 utils::binary::write(stream, coords[2]);
4903 }
4904
4905 // Dump ghost/internal subdivision
4906#if BITPIT_ENABLE_MPI==1
4907 utils::binary::write(stream, m_firstGhostVertexId);
4908 utils::binary::write(stream, m_lastInternalVertexId);
4909#else
4910 utils::binary::write(stream, Vertex::NULL_ID);
4911 utils::binary::write(stream, Vertex::NULL_ID);
4912#endif
4913}
4914
4920void PatchKernel::restoreVertices(std::istream &stream)
4921{
4922 // Restore kernel
4923 m_vertices.restoreKernel(stream);
4924
4925 // Enable manual adaption
4926 AdaptionMode previousAdaptionMode = getAdaptionMode();
4928
4929 // Restore vertices
4930 long nVertices = m_vertices.size();
4931 for (long i = 0; i < nVertices; ++i) {
4932 long id;
4933 utils::binary::read(stream, id);
4934
4935#if BITPIT_ENABLE_MPI==1
4936 int owner;
4937 utils::binary::read(stream, owner);
4938#else
4939 int dummyOwner;
4940 utils::binary::read(stream, dummyOwner);
4941#endif
4942
4943 std::array<double, 3> coords;
4944 utils::binary::read(stream, coords[0]);
4945 utils::binary::read(stream, coords[1]);
4946 utils::binary::read(stream, coords[2]);
4947
4948#if BITPIT_ENABLE_MPI==1
4949 restoreVertex(std::move(coords), owner, id);
4950#else
4951 restoreVertex(std::move(coords), id);
4952#endif
4953 }
4954
4955 // Restore ghost/internal subdivision
4956#if BITPIT_ENABLE_MPI==1
4957 utils::binary::read(stream, m_firstGhostVertexId);
4958 utils::binary::read(stream, m_lastInternalVertexId);
4959#else
4960 long dummyFirstGhostVertexId;
4961 long dummyLastInternalVertexId;
4962 utils::binary::read(stream, dummyFirstGhostVertexId);
4963 utils::binary::read(stream, dummyLastInternalVertexId);
4964#endif
4965
4966 // Restore previous adaption mode
4967 setAdaptionMode(previousAdaptionMode);
4968}
4969
4975void PatchKernel::dumpCells(std::ostream &stream) const
4976{
4977 // Dump kernel
4978 m_cells.dumpKernel(stream);
4979
4980 // Dump cells
4981 for (const Cell &cell: m_cells) {
4982 utils::binary::write(stream, cell.getId());
4983 utils::binary::write(stream, cell.getPID());
4984 utils::binary::write(stream, cell.getType());
4985
4986#if BITPIT_ENABLE_MPI==1
4987 utils::binary::write(stream, getCellOwner(cell.getId()));
4988 utils::binary::write(stream, getCellHaloLayer(cell.getId()));
4989#else
4990 int dummyOwner = 0;
4991 utils::binary::write(stream, dummyOwner);
4992
4993 int dummyHaloLayer = 0;
4994 utils::binary::write(stream, dummyHaloLayer);
4995#endif
4996
4997 int cellConnectSize = cell.getConnectSize();
4998 utils::binary::write(stream, cellConnectSize);
4999
5000 const long *cellConnect = cell.getConnect();
5001 for (int i = 0; i < cellConnectSize; ++i) {
5002 utils::binary::write(stream, cellConnect[i]);
5003 }
5004 }
5005
5006 // Dump ghost/internal subdivision
5007#if BITPIT_ENABLE_MPI==1
5008 utils::binary::write(stream, m_firstGhostCellId);
5009 utils::binary::write(stream, m_lastInternalCellId);
5010#else
5011 utils::binary::write(stream, Cell::NULL_ID);
5012 utils::binary::write(stream, Cell::NULL_ID);
5013#endif
5014}
5015
5021void PatchKernel::restoreCells(std::istream &stream)
5022{
5023 // Restore kernel
5024 m_cells.restoreKernel(stream);
5025
5026 // Enable manual adaption
5027 AdaptionMode previousAdaptionMode = getAdaptionMode();
5029
5030 // Restore cells
5031 long nCells = m_cells.size();
5032 for (long i = 0; i < nCells; ++i) {
5033 long id;
5034 utils::binary::read(stream, id);
5035
5036 int PID;
5037 utils::binary::read(stream, PID);
5038
5039 ElementType type;
5040 utils::binary::read(stream, type);
5041
5042#if BITPIT_ENABLE_MPI==1
5043 int owner;
5044 utils::binary::read(stream, owner);
5045
5046 int haloLayer;
5047 utils::binary::read(stream, haloLayer);
5048#else
5049 int dummyOwner;
5050 utils::binary::read(stream, dummyOwner);
5051
5052 int dummyHaloLayer;
5053 utils::binary::read(stream, dummyHaloLayer);
5054#endif
5055
5056 int cellConnectSize;
5057 utils::binary::read(stream, cellConnectSize);
5058
5059 std::unique_ptr<long[]> cellConnect = std::unique_ptr<long[]>(new long[cellConnectSize]);
5060 for (int k = 0; k < cellConnectSize; ++k) {
5061 utils::binary::read(stream, cellConnect[k]);
5062 }
5063
5064 CellIterator iterator;
5065#if BITPIT_ENABLE_MPI==1
5066 iterator = restoreCell(type, std::move(cellConnect), owner, haloLayer, id);
5067#else
5068 iterator = restoreCell(type, std::move(cellConnect), id);
5069#endif
5070 iterator->setPID(PID);
5071 }
5072
5073 // Restore ghost/internal subdivision
5074#if BITPIT_ENABLE_MPI==1
5075 utils::binary::read(stream, m_firstGhostCellId);
5076 utils::binary::read(stream, m_lastInternalCellId);
5077#else
5078 long dummyFirstGhostCellId;
5079 long dummyLastInternalCellId;
5080 utils::binary::read(stream, dummyFirstGhostCellId);
5081 utils::binary::read(stream, dummyLastInternalCellId);
5082#endif
5083
5084 // Update adjacencies
5086
5087 // Restore previous adaption mode
5088 setAdaptionMode(previousAdaptionMode);
5089}
5090
5096void PatchKernel::dumpInterfaces(std::ostream &stream) const
5097{
5098 // Early return if the interfaces are not build
5099 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
5100 return;
5101 }
5102
5103 // Dump kernel
5104 m_interfaces.dumpKernel(stream);
5105
5106 // Dump interfaces
5107 for (const Interface &interface : getInterfaces()) {
5108 utils::binary::write(stream, interface.getId());
5109
5110 utils::binary::write(stream, interface.getOwner());
5111 utils::binary::write(stream, interface.getOwnerFace());
5112
5113 long neighId = interface.getNeigh();
5114 utils::binary::write(stream, interface.getNeigh());
5115 if (neighId >= 0) {
5116 utils::binary::write(stream, interface.getNeighFace());
5117 }
5118
5119 utils::binary::write(stream, interface.getPID());
5120 }
5121}
5122
5128void PatchKernel::restoreInterfaces(std::istream &stream)
5129{
5130 // Early return if the interfaces are not build
5131 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
5132 return;
5133 }
5134
5135 // Interfaces need up-to-date adjacencies
5137
5138 // Restore kernel
5139 m_interfaces.restoreKernel(stream);
5140
5141 // Enable manual adaption
5142 AdaptionMode previousAdaptionMode = getAdaptionMode();
5144
5145 // Restore interfaces
5146 long nInterfaces = m_interfaces.size();
5147 for (long n = 0; n < nInterfaces; ++n) {
5148 long interfaceId;
5149 utils::binary::read(stream, interfaceId);
5150
5151 long ownerId;
5152 int ownerFace;
5153 utils::binary::read(stream, ownerId);
5154 utils::binary::read(stream, ownerFace);
5155 Cell *owner = &(m_cells.at(ownerId));
5156
5157 long neighId;
5158 int neighFace;
5159 utils::binary::read(stream, neighId);
5160 Cell *neigh;
5161 if (neighId >= 0) {
5162 utils::binary::read(stream, neighFace);
5163 neigh = &(m_cells.at(neighId));
5164 } else {
5165 neighFace = -1;
5166 neigh = nullptr;
5167 }
5168
5169 int pid;
5170 utils::binary::read(stream, pid);
5171
5172 InterfaceIterator interfaceIterator = buildCellInterface(owner, ownerFace, neigh, neighFace, interfaceId);
5173 interfaceIterator->setPID(pid);
5174 }
5175
5176 // Interfaces are now updated
5177 unsetCellAlterationFlags(FLAG_INTERFACES_DIRTY);
5178 m_alteredInterfaces.clear();
5179
5180 // Restore previous adaption mode
5181 setAdaptionMode(previousAdaptionMode);
5182}
5183
5195std::vector<adaption::Info> PatchKernel::_adaptionPrepare(bool trackAdaption)
5196{
5197 BITPIT_UNUSED(trackAdaption);
5198
5199 return std::vector<adaption::Info>();
5200}
5201
5213std::vector<adaption::Info> PatchKernel::_adaptionAlter(bool trackAdaption)
5214{
5215 BITPIT_UNUSED(trackAdaption);
5216
5217 assert(false && "The patch needs to implement _adaptionAlter");
5218
5219 return std::vector<adaption::Info>();
5220}
5221
5230
5240{
5241 BITPIT_UNUSED(id);
5242
5243 return false;
5244}
5245
5255{
5256 BITPIT_UNUSED(id);
5257
5258 return false;
5259}
5260
5270{
5271 BITPIT_UNUSED(id);
5272
5273 return false;
5274}
5275
5285{
5286 BITPIT_UNUSED(id);
5287
5288 return adaption::MARKER_UNDEFINED;
5289}
5290
5300bool PatchKernel::_enableCellBalancing(long id, bool enabled)
5301{
5302 BITPIT_UNUSED(id);
5303 BITPIT_UNUSED(enabled);
5304
5305 return false;
5306}
5307
5312{
5314 return false;
5315 }
5316
5317 // Sort internal vertices
5318 if (m_nInternalVertices > 0) {
5319 m_vertices.sortBefore(m_lastInternalVertexId, true);
5321 }
5322
5323#if BITPIT_ENABLE_MPI==1
5324 // Sort ghost cells
5325 if (m_nGhostVertices > 0) {
5326 m_vertices.sortAfter(m_firstGhostVertexId, true);
5328 }
5329#endif
5330
5331 // Synchronize storage
5332 m_vertices.sync();
5333
5334 return true;
5335}
5336
5343{
5345 return false;
5346 }
5347
5348 // Sort internal cells
5349 if (m_nInternalCells > 0) {
5350 m_cells.sortBefore(m_lastInternalCellId, true);
5352 }
5353
5354#if BITPIT_ENABLE_MPI==1
5355 // Sort ghost cells
5356 if (m_nGhostCells > 0) {
5357 m_cells.sortAfter(m_firstGhostCellId, true);
5359 }
5360#endif
5361
5362 // Synchronize storage
5363 m_cells.sync();
5364
5365 return true;
5366}
5367
5372{
5374 return false;
5375 }
5376
5377 m_interfaces.sort();
5378
5379 m_interfaces.sync();
5380
5381 return true;
5382}
5383
5389{
5390 bool status = sortVertices();
5391 status |= sortCells();
5392 status |= sortInterfaces();
5393
5394 return status;
5395}
5396
5405{
5407 return false;
5408 }
5409
5410 m_vertices.squeeze();
5411
5412 m_vertices.sync();
5413
5414 return true;
5415}
5416
5425{
5427 return false;
5428 }
5429
5430 m_cells.squeeze();
5431
5432 m_cells.sync();
5433
5434 return true;
5435}
5436
5445{
5447 return false;
5448 }
5449
5450 m_interfaces.squeeze();
5451
5452 m_interfaces.sync();
5453
5454 return true;
5455}
5456
5465{
5466 bool status = true;
5467
5468 // Alteration flags
5469 if (m_alteredCells.empty()) {
5470 AlterationFlagsStorage().swap(m_alteredCells);
5471 }
5472
5473 if (m_alteredInterfaces.empty()) {
5474 AlterationFlagsStorage().swap(m_alteredInterfaces);
5475 }
5476
5477 // Vertices
5478 status |= squeezeVertices();
5479
5480 // Cells
5481 status |= squeezeCells();
5482
5483 // Interfaces
5484 status |= squeezeInterfaces();
5485
5486 return status;
5487}
5488
5495std::array<double, 3> PatchKernel::evalCellCentroid(long id) const
5496{
5497 const Cell &cell = getCell(id);
5498
5499 return evalElementCentroid(cell);
5500}
5501
5509void PatchKernel::evalCellBoundingBox(long id, std::array<double,3> *minPoint, std::array<double,3> *maxPoint) const
5510{
5511 const Cell &cell = getCell(id);
5512
5513 evalElementBoundingBox(cell, minPoint, maxPoint);
5514}
5515
5523{
5524 // Get the vertices ids
5525 const Cell &cell = getCell(id);
5526 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
5527 const int nCellVertices = cellVertexIds.size();
5528
5529 // Build the proxy vector with the coordinates
5530 ConstProxyVector<std::array<double, 3>> vertexCoordinates(ConstProxyVector<std::array<double, 3>>::INTERNAL_STORAGE, nCellVertices);
5531 ConstProxyVector<std::array<double, 3>>::storage_pointer storage = vertexCoordinates.storedData();
5532 getVertexCoords(cellVertexIds.size(), cellVertexIds.data(), storage);
5533
5534 return vertexCoordinates;
5535}
5536
5543void PatchKernel::getCellVertexCoordinates(long id, std::unique_ptr<std::array<double, 3>[]> *coordinates) const
5544{
5545 const Cell &cell = getCell(id);
5546
5547 getElementVertexCoordinates(cell, coordinates);
5548}
5549
5558void PatchKernel::getCellVertexCoordinates(long id, std::array<double, 3> *coordinates) const
5559{
5560 const Cell &cell = getCell(id);
5561
5562 getElementVertexCoordinates(cell, coordinates);
5563}
5564
5571std::array<double, 3> PatchKernel::evalInterfaceCentroid(long id) const
5572{
5573 const Interface &interface = getInterface(id);
5574
5575 return evalElementCentroid(interface);
5576}
5577
5585void PatchKernel::evalInterfaceBoundingBox(long id, std::array<double,3> *minPoint, std::array<double,3> *maxPoint) const
5586{
5587 const Interface &interface = getInterface(id);
5588
5589 evalElementBoundingBox(interface, minPoint, maxPoint);
5590}
5591
5599{
5600 // Get the vertices ids
5601 const Interface &interface = getInterface(id);
5602 ConstProxyVector<long> interfaceVertexIds = interface.getVertexIds();
5603 const int nInterfaceVertices = interfaceVertexIds.size();
5604
5605 // Build the proxy vector with the coordinates
5606 ConstProxyVector<std::array<double, 3>> vertexCoordinates(ConstProxyVector<std::array<double, 3>>::INTERNAL_STORAGE, nInterfaceVertices);
5607 ConstProxyVector<std::array<double, 3>>::storage_pointer storage = vertexCoordinates.storedData();
5608 getVertexCoords(interfaceVertexIds.size(), interfaceVertexIds.data(), storage);
5609
5610 return vertexCoordinates;
5611}
5612
5619void PatchKernel::getInterfaceVertexCoordinates(long id, std::unique_ptr<std::array<double, 3>[]> *coordinates) const
5620{
5621 const Interface &interface = getInterface(id);
5622
5623 getElementVertexCoordinates(interface, coordinates);
5624}
5625
5634void PatchKernel::getInterfaceVertexCoordinates(long id, std::array<double, 3> *coordinates) const
5635{
5636 const Interface &interface = getInterface(id);
5637
5638 getElementVertexCoordinates(interface, coordinates);
5639}
5640
5650std::array<double, 3> PatchKernel::evalElementCentroid(const Element &element) const
5651{
5652 ConstProxyVector<long> elementVertexIds = element.getVertexIds();
5653 std::size_t nCellVertices = elementVertexIds.size();
5654 BITPIT_CREATE_WORKSPACE(vertexCoordinates, std::array<double BITPIT_COMMA 3>, nCellVertices, ReferenceElementInfo::MAX_ELEM_VERTICES);
5655 getVertexCoords(nCellVertices, elementVertexIds.data(), vertexCoordinates);
5656
5657 return element.evalCentroid(vertexCoordinates);
5658}
5659
5667void PatchKernel::evalElementBoundingBox(const Element &element, std::array<double,3> *minPoint, std::array<double,3> *maxPoint) const
5668{
5669 ElementType elementType = element.getType();
5670 switch (elementType)
5671 {
5672
5673 case ElementType::VERTEX:
5674 {
5675 const long *elementConnect = element.getConnect();
5676 *minPoint = getVertexCoords(elementConnect[0]);
5677 *maxPoint = *minPoint;
5678 break;
5679 }
5680
5681 case ElementType::PIXEL:
5682 {
5683 const long *elementConnect = element.getConnect();
5684
5685 const std::array<double, 3> &vertexCoord_0 = getVertexCoords(elementConnect[0]);
5686 const std::array<double, 3> &vertexCoord_3 = getVertexCoords(elementConnect[3]);
5687
5688 for (int d = 0; d < 3; ++d) {
5689 (*minPoint)[d] = std::min(vertexCoord_0[d], vertexCoord_3[d]);
5690 (*maxPoint)[d] = std::max(vertexCoord_0[d], vertexCoord_3[d]);
5691 }
5692
5693 break;
5694 }
5695
5696 case ElementType::VOXEL:
5697 {
5698 const long *elementConnect = element.getConnect();
5699
5700 const std::array<double, 3> &vertexCoord_0 = getVertexCoords(elementConnect[0]);
5701 const std::array<double, 3> &vertexCoord_7 = getVertexCoords(elementConnect[7]);
5702
5703 for (int d = 0; d < 3; ++d) {
5704 (*minPoint)[d] = std::min(vertexCoord_0[d], vertexCoord_7[d]);
5705 (*maxPoint)[d] = std::max(vertexCoord_0[d], vertexCoord_7[d]);
5706 }
5707
5708 break;
5709 }
5710
5711 default:
5712 {
5713 ConstProxyVector<long> elementVertexIds = element.getVertexIds();
5714 const int nElementVertices = elementVertexIds.size();
5715
5716 *minPoint = getVertexCoords(elementVertexIds[0]);
5717 *maxPoint = *minPoint;
5718 for (int i = 1; i < nElementVertices; ++i) {
5719 const std::array<double, 3> &vertexCoord = getVertexCoords(elementVertexIds[i]);
5720 for (int d = 0; d < 3; ++d) {
5721 (*minPoint)[d] = std::min(vertexCoord[d], (*minPoint)[d]);
5722 (*maxPoint)[d] = std::max(vertexCoord[d], (*maxPoint)[d]);
5723 }
5724 }
5725
5726 break;
5727 }
5728
5729 }
5730}
5731
5744long PatchKernel::locatePoint(double x, double y, double z) const
5745{
5746 return locatePoint({{x, y, z}});
5747}
5748
5759bool PatchKernel::isSameFace(const Cell &cell_A, int face_A, const Cell &cell_B, int face_B) const
5760{
5761 if (cell_A.getFaceType(face_A) != cell_B.getFaceType(face_B)) {
5762 return false;
5763 }
5764
5765 int nFaceVertices = cell_A.getFaceVertexCount(face_A);
5766
5767 std::vector<long> faceVertexIds_A(nFaceVertices);
5768 std::vector<long> faceVertexIds_B(nFaceVertices);
5769 for (int k = 0; k < nFaceVertices; ++k) {
5770 faceVertexIds_A[k] = cell_A.getFaceVertexId(face_A, k);
5771 faceVertexIds_B[k] = cell_B.getFaceVertexId(face_B, k);
5772 }
5773
5774 std::sort(faceVertexIds_A.begin(), faceVertexIds_A.end());
5775 std::sort(faceVertexIds_B.begin(), faceVertexIds_B.end());
5776
5777 return (faceVertexIds_A == faceVertexIds_B);
5778}
5779
5786{
5787 return m_adjacenciesBuildStrategy;
5788}
5789
5796{
5797 m_adjacenciesBuildStrategy = status;
5798}
5799
5808{
5809 if (getAdjacenciesBuildStrategy() == ADJACENCIES_NONE) {
5810 return false;
5811 }
5812
5813 bool areDirty = false;
5814 for (const auto &entry : m_alteredCells) {
5815 AlterationFlags cellAlterationFlags = entry.second;
5816 if (testAlterationFlags(cellAlterationFlags, FLAG_ADJACENCIES_DIRTY)) {
5817 areDirty = true;
5818 break;
5819 }
5820 }
5821
5822#if BITPIT_ENABLE_MPI==1
5823 if (global && isPartitioned()) {
5824 const auto &communicator = getCommunicator();
5825 MPI_Allreduce(MPI_IN_PLACE, &areDirty, 1, MPI_C_BOOL, MPI_LOR, communicator);
5826 }
5827#else
5828 BITPIT_UNUSED(global);
5829#endif
5830
5831 return areDirty;
5832}
5833
5841{
5842 initializeAdjacencies(ADJACENCIES_AUTOMATIC);
5843}
5844
5854{
5855 // Get current build stategy
5857
5858 // Early return if we don't need adjacencies
5859 if (strategy == ADJACENCIES_NONE) {
5860 if (currentStrategy != ADJACENCIES_NONE) {
5862 }
5863
5864 return;
5865 }
5866
5867 // Update the build strategy
5868 if (currentStrategy != strategy) {
5870 }
5871
5872 // Reset adjacencies
5874
5875 // Update the adjacencies
5877}
5878
5885void PatchKernel::updateAdjacencies(bool forcedUpdated)
5886{
5887 // Early return if adjacencies are not built
5889 if (currentStrategy == ADJACENCIES_NONE) {
5890 return;
5891 }
5892
5893 // Check if the adjacencies are dirty
5894 bool adjacenciesDirty = areAdjacenciesDirty();
5895 if (!adjacenciesDirty && !forcedUpdated) {
5896 return;
5897 }
5898
5899 // Update adjacencies
5900 if (adjacenciesDirty) {
5901 // Prune stale adjacencies
5903
5904 // Update adjacencies
5906
5907 // Adjacencies are now updated
5908 unsetCellAlterationFlags(FLAG_ADJACENCIES_DIRTY);
5909 } else {
5910 initializeAdjacencies(currentStrategy);
5911 }
5912}
5913
5921{
5922 // Early return if no adjacencies have been built
5923 if (getAdjacenciesBuildStrategy() == ADJACENCIES_NONE) {
5924 return;
5925 }
5926
5927 // Destroy the adjacencies
5928 _resetAdjacencies(true);
5929
5930 // Clear list of cells with dirty adjacencies
5931 unsetCellAlterationFlags(FLAG_ADJACENCIES_DIRTY);
5932
5933 // Set adjacencies status
5934 setAdjacenciesBuildStrategy(ADJACENCIES_NONE);
5935}
5936
5944{
5945 // Early return if no adjacencies have been built
5946 if (getAdjacenciesBuildStrategy() == ADJACENCIES_NONE) {
5947 return;
5948 }
5949
5950 // Reset adjacencies
5951 _resetAdjacencies(false);
5952
5953 // All cells have now dirty adjacencies
5954 setCellAlterationFlags(FLAG_ADJACENCIES_DIRTY);
5955}
5956
5967{
5968 for (Cell &cell : m_cells) {
5969 cell.resetAdjacencies(!release);
5970 }
5971}
5972
5980{
5981 // Early return if adjacencies are not built
5983 if (currentStrategy == ADJACENCIES_NONE) {
5984 return;
5985 }
5986
5987 // Remove stale adjacencies
5988 for (const auto &entry : m_alteredCells) {
5989 AlterationFlags cellAlterationFlags = entry.second;
5990 if (!testAlterationFlags(cellAlterationFlags, FLAG_ADJACENCIES_DIRTY)) {
5991 continue;
5992 }
5993
5994 long cellId = entry.first;
5995 Cell &cell = m_cells.at(cellId);
5996 if (cell.getAdjacencyCount() == 0) {
5997 continue;
5998 }
5999
6000 int nCellFaces = cell.getFaceCount();
6001 for (int face = nCellFaces - 1; face >= 0; --face) {
6002 long *faceAdjacencies = cell.getAdjacencies(face);
6003 int nFaceAdjacencies = cell.getAdjacencyCount(face);
6004 for (int i = nFaceAdjacencies - 1; i >= 0; --i) {
6005 long adjacency = faceAdjacencies[i];
6006 if (!testCellAlterationFlags(adjacency, FLAG_DELETED)) {
6007 continue;
6008 }
6009
6010 cell.deleteAdjacency(face, i);
6011 }
6012 }
6013 }
6014}
6015
6025{
6026 int dimension = getDimension();
6027
6028 // Check if multiple adjacencies are allowed
6029 //
6030 // On a three-dimensional patch each internal face is shared between two,
6031 // and only two, half-faces. On lower dimension patches one internal face
6032 // may be shared among multiple half-faces (this happens with non-manifold
6033 // patches).
6034 bool multipleMatchesAllowed = (dimension < 3);
6035
6036 // Define matching windings
6037 //
6038 // If faces can be shared only between two half-faces, there is a one-to-one
6039 // correspondence between the half-faces. Give one half-faces, its matching
6040 // can be found looking for an half-faces with the same vertices but with
6041 // reverse vertex winding order.
6042 //
6043 // If faces can be shared among more than two half-faces, it's not anymore
6044 // possible to define a unique winding order for the vertices of the faces.
6045 // There is no more a one-to-one correspondence between pairs of half-face.
6046 // In this case, when looking for half-face correspondence, it is necessary
6047 // to look for half-faces with reverse vertex winding order and also for
6048 // half-faces with the same vertex winding order.
6049 std::vector<CellHalfFace::Winding> matchingWindings;
6050 matchingWindings.push_back(CellHalfFace::WINDING_REVERSE);
6051 if (multipleMatchesAllowed) {
6052 matchingWindings.push_back(CellHalfFace::WINDING_NATURAL);
6053 }
6054
6055 // Count cells with dirty adjacencies
6056 long nDirtyAdjacenciesCells = 0;
6057 for (const auto &entry : m_alteredCells) {
6058 AlterationFlags cellAlterationFlags = entry.second;
6059 if (!testAlterationFlags(cellAlterationFlags, FLAG_ADJACENCIES_DIRTY)) {
6060 continue;
6061 }
6062
6063 ++nDirtyAdjacenciesCells;
6064 }
6065
6066 // Get the vertices of cells with dirty adjacencies
6067 //
6068 // The list is only needed if multiple matches are allowed and there are
6069 // cells whose adjacencies don't need to be updated.
6070 std::unique_ptr<PiercedStorage<bool, long>> dirtyAdjacenciesVertices;
6071 if (multipleMatchesAllowed && (nDirtyAdjacenciesCells != getCellCount())) {
6072 dirtyAdjacenciesVertices = std::unique_ptr<PiercedStorage<bool, long>>(new PiercedStorage<bool, long>(1, &m_vertices));
6073 dirtyAdjacenciesVertices->fill(false);
6074 for (const auto &entry : m_alteredCells) {
6075 AlterationFlags cellAlterationFlags = entry.second;
6076 if (!testAlterationFlags(cellAlterationFlags, FLAG_ADJACENCIES_DIRTY)) {
6077 continue;
6078 }
6079
6080 long cellId = entry.first;
6081 const Cell &cell = m_cells.at(cellId);
6082 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
6083 for (long vertexId : cellVertexIds) {
6084 dirtyAdjacenciesVertices->at(vertexId) = true;
6085 }
6086 }
6087 }
6088
6089 // List the cells that needs to be processed
6090 //
6091 // The list should contain the cells whose adjacencies need to be updated
6092 // and their neighbours candidates.
6093 //
6094 // Cells whose adjacencies needs to be updated are cells having the dirty
6095 // adjaceny flag set.
6096 //
6097 // Neighbours candidates are all border cells and, if multiple matches are
6098 // allowed, cells that share vertices with a cell with dirty adjacencies.
6099 std::vector<Cell *> processList;
6100 processList.reserve(nDirtyAdjacenciesCells);
6101
6102 std::size_t nMaxHalfFaces = 0;
6103 for (Cell &cell : m_cells) {
6104 // Get cell information
6105 long cellId = cell.getId();
6106 int nCellFaces = cell.getFaceCount();
6107
6108 // Add cells with dirty adjacencies
6109 if (testCellAlterationFlags(cellId, FLAG_ADJACENCIES_DIRTY)) {
6110 nMaxHalfFaces += nCellFaces;
6111 processList.push_back(&cell);
6112 continue;
6113 }
6114
6115 // Add border cells
6116 bool isBorderCell = false;
6117 for (int face = 0; face < nCellFaces; face++) {
6118 if (cell.isFaceBorder(face)) {
6119 isBorderCell = true;
6120 continue;
6121 }
6122 }
6123
6124 if (isBorderCell) {
6125 nMaxHalfFaces += nCellFaces;
6126 processList.push_back(&cell);
6127 continue;
6128 }
6129
6130 // Add cell that share vertices with a cell with dirty adjacencies
6131 //
6132 // For performace reasons, the check is a bit rough. All cells that
6133 // share a number of vertices at least equal to the dimension af the
6134 // patch will be added to the process list. This will add also cells
6135 // that are not neighbour candidates, but it's faster to add some false
6136 // positives, rather trying to filter them out.
6137 if (multipleMatchesAllowed) {
6138 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
6139
6140 int nCelldirtyAdjacenciesVertices = 0;
6141 bool futureNeighbourCandidate = false;
6142 for (long vertexId : cellVertexIds) {
6143 if (dirtyAdjacenciesVertices->at(vertexId)) {
6144 ++nCelldirtyAdjacenciesVertices;
6145 if (nCelldirtyAdjacenciesVertices >= dimension) {
6146 futureNeighbourCandidate = true;
6147 break;
6148 }
6149 }
6150 }
6151
6152 if (futureNeighbourCandidate) {
6153 nMaxHalfFaces += nCellFaces;
6154 processList.push_back(&cell);
6155 }
6156 }
6157 }
6158
6159 // Create the adjacencies
6160 std::unordered_set<CellHalfFace, CellHalfFace::Hasher> halfFaces;
6161 halfFaces.reserve(static_cast<std::size_t>(0.5 * nMaxHalfFaces));
6162
6163 std::vector<std::pair<Cell *, int>> matchingAdjacencies;
6164 for (Cell *cell : processList) {
6165 long cellId = cell->getId();
6166 const int nCellFaces = cell->getFaceCount();
6167 bool areCellAdjacenciesDirty = testCellAlterationFlags(cellId, FLAG_ADJACENCIES_DIRTY);
6168 for (int face = 0; face < nCellFaces; face++) {
6169 // Generate the half-face
6170 CellHalfFace halfFace(*cell, face);
6171
6172 // Find matching half-face
6173 auto matchingHalfFaceItr = halfFaces.end();
6174 for (CellHalfFace::Winding winding : matchingWindings) {
6175 // Set winding order
6176 halfFace.setWinding(winding);
6177
6178 // Search for matching half-face
6179 matchingHalfFaceItr = halfFaces.find(halfFace);
6180 if (matchingHalfFaceItr != halfFaces.end()) {
6181 break;
6182 }
6183 }
6184
6185 // Early return if no matching half-face has been found
6186 //
6187 // If no matching half-face has been found, we need to add the
6188 // current half-face to the list because it may match the face
6189 // of a cell that will be processed later.
6190 if (matchingHalfFaceItr == halfFaces.end()) {
6191 halfFace.setWinding(CellHalfFace::WINDING_NATURAL);
6192 halfFaces.insert(std::move(halfFace));
6193 continue;
6194 }
6195
6196 // Get matching half-face information
6197 const CellHalfFace &matchingHalfFace = *matchingHalfFaceItr;
6198 Cell &matchingCell = matchingHalfFace.getCell();
6199 long matchingCellId = matchingCell.getId();
6200 long matchingFace = matchingHalfFace.getFace();
6201
6202 // Only process cells with dirty adjacencies
6203 //
6204 // In order to limit the half faces that need to be stored, we are
6205 // processing at the same time cells with dirty adjacencies and
6206 // their neighbour candidates. This means we will also find matches
6207 // between faces of cell whose adjacensies are already up-to-date.
6208 bool areMatchingCellAdjacenciesDirty = testCellAlterationFlags(matchingCellId, FLAG_ADJACENCIES_DIRTY);
6209 if (!areCellAdjacenciesDirty && !areMatchingCellAdjacenciesDirty) {
6210 continue;
6211 }
6212
6213 // Identifty matching adjacencies
6214 //
6215 // If multiple matches are allowed, in addition to the entry
6216 // related to the matching half face, we also need to add the
6217 // entries associated to the adjacencies already identified
6218 // for the half face.
6219 matchingAdjacencies.clear();
6220 matchingAdjacencies.emplace_back(std::make_pair<Cell *, int>(&matchingCell, matchingFace));
6221 if (multipleMatchesAllowed) {
6222 const int nMachingFaceNeighs = matchingCell.getAdjacencyCount(matchingFace);
6223 const long *machingFaceNeighs = matchingCell.getAdjacencies(matchingFace);
6224 for (int k = 0; k < nMachingFaceNeighs; ++k) {
6225 long neighId = machingFaceNeighs[k];
6226 if (neighId == cellId) {
6227 continue;
6228 }
6229
6230 Cell &neigh = m_cells.at(neighId);
6231 int neighFace = findAdjoinNeighFace(matchingCell, matchingFace, neigh);
6232 matchingAdjacencies.emplace_back(std::make_pair<Cell *, int>(&neigh, std::move(neighFace)));
6233 }
6234 } else {
6235 // When cell adjacencies are makred dirty this means that some
6236 // adjacencies are dirty not that all adjacencies are dirty.
6237 // The matchin cell may have no adjaceny associated to the
6238 // matching face or a signle adjacency that should match
6239 // the current cell.
6240 assert(matchingCell.getAdjacencyCount(matchingFace) == 0 || (matchingCell.getAdjacencyCount(matchingFace) == 1 && (*(matchingCell.getAdjacencies(matchingFace)) == cellId)));
6241 }
6242
6243 // Create adjacencies
6244 for (const std::pair<Cell *, int> &matchingAdjacency : matchingAdjacencies) {
6245 Cell *adjacentCell = matchingAdjacency.first;
6246 long adjacentCellId = adjacentCell->getId();
6247 int adjacentFace = matchingAdjacency.second;
6248
6249 cell->pushAdjacency(face, adjacentCellId);
6250 adjacentCell->pushAdjacency(adjacentFace, cellId);
6251 }
6252
6253 // Remove the matching half-face from the list
6254 //
6255 // If multiple matches are allowed, we need to keep the half
6256 // face, because that entry may match the face of a cell that
6257 // will be processed later.
6258 if (!multipleMatchesAllowed) {
6259 halfFaces.erase(matchingHalfFaceItr);
6260 }
6261 }
6262 }
6263}
6264
6271{
6272 return m_interfacesBuildStrategy;
6273}
6274
6281{
6282 if (status == INTERFACES_AUTOMATIC) {
6284 throw std::runtime_error("Automatic build strategy requires auto-indexing.");
6285 }
6286 }
6287
6288 m_interfacesBuildStrategy = status;
6289}
6290
6298bool PatchKernel::areInterfacesDirty(bool global) const
6299{
6300 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
6301 return false;
6302 }
6303
6304 bool areDirty = !m_alteredInterfaces.empty();
6305 if (!areDirty) {
6306 for (const auto &entry : m_alteredCells) {
6307 AlterationFlags cellAlterationFlags = entry.second;
6308 if (testAlterationFlags(cellAlterationFlags, FLAG_INTERFACES_DIRTY)) {
6309 areDirty = true;
6310 break;
6311 }
6312 }
6313 }
6314
6315#if BITPIT_ENABLE_MPI==1
6316 if (global && isPartitioned()) {
6317 const auto &communicator = getCommunicator();
6318 MPI_Allreduce(MPI_IN_PLACE, &areDirty, 1, MPI_C_BOOL, MPI_LOR, communicator);
6319 }
6320#else
6321 BITPIT_UNUSED(global);
6322#endif
6323
6324 return areDirty;
6325}
6326
6334{
6335 initializeInterfaces(INTERFACES_AUTOMATIC);
6336}
6337
6350{
6351 // Interfaces need adjacencies
6352 if (getAdjacenciesBuildStrategy() == ADJACENCIES_NONE) {
6353 throw std::runtime_error ("Adjacencies are mandatory for building the interfaces.");
6354 }
6355
6356 // Get current build stategy
6358
6359 // Early return if we don't need interfaces
6360 if (strategy == INTERFACES_NONE) {
6361 if (currentStrategy != INTERFACES_NONE) {
6363 }
6364
6365 return;
6366 }
6367
6368 // Update the build strategy
6369 if (currentStrategy != strategy) {
6371 }
6372
6373 // Reset interfaces
6375
6376 // Update the interfaces
6378}
6379
6386void PatchKernel::updateInterfaces(bool forcedUpdated)
6387{
6388 // Early return if interfaces are not built
6390 if (currentStrategy == INTERFACES_NONE) {
6391 return;
6392 }
6393
6394 // Check if the interfaces are dirty
6395 bool interfacesDirty = areInterfacesDirty();
6396 if (!interfacesDirty && !forcedUpdated) {
6397 return;
6398 }
6399
6400 // Interfaces need up-to-date adjacencies
6401 assert(getAdjacenciesBuildStrategy() != ADJACENCIES_NONE);
6403
6404 // Update interfaces
6405 if (interfacesDirty) {
6406 // Enable manual adaption
6407 AdaptionMode previousAdaptionMode = getAdaptionMode();
6409
6410 // Prune stale interfaces
6412
6413 // Update interfaces
6415
6416 // Interfaces are now updated
6417 unsetCellAlterationFlags(FLAG_INTERFACES_DIRTY);
6418 m_alteredInterfaces.clear();
6419
6420 // Restore previous adaption mode
6421 setAdaptionMode(previousAdaptionMode);
6422 } else {
6423 initializeInterfaces(currentStrategy);
6424 }
6425}
6426
6434{
6435 // Early return if no interfaces have been built
6436 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
6437 return;
6438 }
6439
6440 // Destroy the interfaces
6441 _resetInterfaces(true);
6442
6443 // Clear list of cells with dirty adjacencies
6444 unsetCellAlterationFlags(FLAG_INTERFACES_DIRTY);
6445
6446 // Clear list of altered interfaces
6447 m_alteredInterfaces.clear();
6448
6449 // Set interface build strategy
6450 setInterfacesBuildStrategy(INTERFACES_NONE);
6451}
6452
6460{
6461 // Early return if no interfaces have been built
6462 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
6463 return;
6464 }
6465
6466 // Remove dangling interfaces from cells
6467 for (const auto &entry : m_alteredCells) {
6468 AlterationFlags cellAlterationFlags = entry.second;
6469 if (!testAlterationFlags(cellAlterationFlags, FLAG_INTERFACES_DIRTY)) {
6470 continue;
6471 }
6472
6473 long cellId = entry.first;
6474 Cell &cell = m_cells.at(cellId);
6475 if (cell.getInterfaceCount() == 0) {
6476 continue;
6477 }
6478
6479 int nCellFaces = cell.getFaceCount();
6480 for (int face = nCellFaces - 1; face >= 0; --face) {
6481 long *faceInterfaces = cell.getInterfaces(face);
6482 int nFaceInterfaces = cell.getInterfaceCount(face);
6483 for (int i = nFaceInterfaces - 1; i >= 0; --i) {
6484 long interfaceId = faceInterfaces[i];
6485 if (!testInterfaceAlterationFlags(interfaceId, FLAG_DANGLING)) {
6486 continue;
6487 }
6488
6489 // Delete the interface from the cell
6490 cell.deleteInterface(face, i);
6491 }
6492 }
6493 }
6494
6495 // Delete dangling interfaces
6496 std::vector<long> danglingInterfaces;
6497 danglingInterfaces.reserve(m_alteredInterfaces.size());
6498 for (const auto &entry : m_alteredInterfaces) {
6499 AlterationFlags interfaceAlterationFlags = entry.second;
6500 if (!testAlterationFlags(interfaceAlterationFlags, FLAG_DANGLING)) {
6501 continue;
6502 }
6503
6504 long interfaceId = entry.first;
6505 danglingInterfaces.push_back(interfaceId);
6506 }
6507 deleteInterfaces(danglingInterfaces);
6508}
6509
6517{
6518 //
6519 // Update interfaces
6520 //
6521 // Adjacencies and interfaces of a face are paired: the i-th face adjacency
6522 // corresponds to the i-th face interface. Moreover if we loop through the
6523 // adjacencies of a face, the adjacencies that have an interface are always
6524 // listed first. This meas that, to update the interfaces, we can count the
6525 // interfaces already associated to a face and loop only on the adjacencies
6526 // which have an index past the one of the last interface.
6527 //
6528 // On border faces of internal cells we need to build an interface, also
6529 // if there are no adjacencies.
6530 for (const auto &entry : m_alteredCells) {
6531 AlterationFlags cellAlterationFlags = entry.second;
6532 if (!testAlterationFlags(cellAlterationFlags, FLAG_INTERFACES_DIRTY)) {
6533 continue;
6534 }
6535
6536 long cellId = entry.first;
6537 Cell &cell = m_cells.at(cellId);
6538 const int nCellFaces = cell.getFaceCount();
6539 for (int face = 0; face < nCellFaces; face++) {
6540 int nFaceInterfaces= cell.getInterfaceCount(face);
6541
6542 bool isFaceBorder = cell.isFaceBorder(face);
6543 if (!isFaceBorder) {
6544 // Find the range of adjacencies that need an interface
6545 int updateEnd = cell.getAdjacencyCount(face);
6546 int updateBegin = nFaceInterfaces;
6547 if (updateBegin == updateEnd) {
6548 continue;
6549 }
6550
6551 // Build an interface for every adjacency
6552 const long *faceAdjacencies = cell.getAdjacencies(face);
6553 for (int k = updateBegin; k < updateEnd; ++k) {
6554 long neighId = faceAdjacencies[k];
6555 Cell *neigh = &m_cells[neighId];
6556
6557 int neighFace = findAdjoinNeighFace(cell, face, *neigh);
6558
6559 buildCellInterface(&cell, face, neigh, neighFace);
6560 }
6561 } else if (nFaceInterfaces == 0) {
6562 // Internal borderes need an interface
6563 buildCellInterface(&cell, face, nullptr, -1);
6564 }
6565 }
6566 }
6567}
6568
6583PatchKernel::InterfaceIterator PatchKernel::buildCellInterface(Cell *cell_1, int face_1, Cell *cell_2, int face_2, long interfaceId)
6584{
6585 // Validate the input
6586 assert(cell_1);
6587 assert(face_1 >= 0);
6588
6589 if (cell_2) {
6590 assert(face_2 >= 0);
6591 } else {
6592 assert(face_2 < 0);
6593 }
6594
6595 // Get the id of the first cell
6596 long id_1 = cell_1->getId();
6597
6598 // Get the id of the second cell
6599 long id_2 = Cell::NULL_ID;
6600 if (cell_2) {
6601 id_2 = cell_2->getId();
6602 }
6603
6604 // Owner and neighbour of the interface
6605 //
6606 // The interface is owned by the cell that has only one adjacency, i.e.,
6607 // by the cell that owns the smallest of the two faces. If the faces
6608 // of both cells have the same size, the interface is owned by the cell
6609 // with the "lower fuzzy positioning". It is not necessary to have a
6610 // precise comparison, it's only necessary to define a repeatable order
6611 // between the two cells. It is therefore possible to use the "fuzzy"
6612 // cell comparison.
6613 bool cellOwnsInterface = true;
6614 if (cell_2) {
6615 if (cell_1->getAdjacencyCount(face_1) > 1) {
6616 cellOwnsInterface = false;
6617 } else if (cell_2->getAdjacencyCount(face_2) == 1) {
6618 assert(cell_1->getAdjacencyCount(face_1) == 1);
6619 cellOwnsInterface = CellFuzzyPositionLess(*this)(id_1, id_2);
6620 }
6621 }
6622
6623 Cell *intrOwner;
6624 Cell *intrNeigh;
6625 long intrOwnerId;
6626 long intrNeighId;
6627 int intrOwnerFace;
6628 int intrNeighFace;
6629 if (cellOwnsInterface) {
6630 intrOwnerId = id_1;
6631 intrOwner = cell_1;
6632 intrOwnerFace = face_1;
6633
6634 if (cell_2) {
6635 intrNeighId = id_2;
6636 intrNeigh = cell_2;
6637 intrNeighFace = face_2;
6638 } else {
6639 intrNeighId = Cell::NULL_ID;
6640 intrNeigh = nullptr;
6641 intrNeighFace = -1;
6642 }
6643 } else {
6644 intrOwnerId = id_2;
6645 intrOwner = cell_2;
6646 intrOwnerFace = face_2;
6647
6648 intrNeighId = id_1;
6649 intrNeigh = cell_1;
6650 intrNeighFace = face_1;
6651 }
6652
6653 // Connectivity of the interface
6654 ConstProxyVector<long> faceConnect = intrOwner->getFaceConnect(intrOwnerFace);
6655
6656 int nInterfaceVertices = faceConnect.size();
6657 std::unique_ptr<long[]> interfaceConnect = std::unique_ptr<long[]>(new long[nInterfaceVertices]);
6658 for (int k = 0; k < nInterfaceVertices; ++k) {
6659 interfaceConnect[k] = faceConnect[k];
6660 }
6661
6662 // Create the interface
6663 Interface *interface;
6664 InterfaceIterator interfaceIterator;
6665
6666 ElementType interfaceType = intrOwner->getFaceType(intrOwnerFace);
6667 if (interfaceId < 0) {
6668 interfaceIterator = addInterface(interfaceType, std::move(interfaceConnect), interfaceId);
6669 interface = &(*interfaceIterator);
6670 interfaceId = interface->getId();
6671 } else {
6672 interfaceIterator = restoreInterface(interfaceType, std::move(interfaceConnect), interfaceId);
6673 interface = &(*interfaceIterator);
6674 }
6675
6676 // Set owner and neighbour
6677 interface->setOwner(intrOwnerId, intrOwnerFace);
6678 if (intrNeighId >= 0) {
6679 interface->setNeigh(intrNeighId, intrNeighFace);
6680 }
6681
6682 // Update owner and neighbour cell data
6683 //
6684 // Adjacencies and interfaces are paired: the i-th adjacency correspondes
6685 // to the i-th interface. Moreover if we loop through the adjacencies of
6686 // a face, the adjacencies that have an interface are always listed first.
6687 // When the interfaces are fully built, each adjacency is associated to an
6688 // interface, however this will not be true during the generation of the
6689 // interfaces. If the adjacencies already associated to an interface are
6690 // listed first, it will be easy to detect which interfaces are still to
6691 // be built: the missing interfaces are associated to the adjacencies which
6692 // have an index past the last interface.
6693 //
6694 // The above only matters if the neighbour cell exists, if there is no
6695 // neighbour there will be only one interface on that face, so there are
6696 // no ordering issues.
6697 intrOwner->pushInterface(intrOwnerFace, interfaceId);
6698 if (intrNeigh) {
6699 intrNeigh->pushInterface(intrNeighFace, interfaceId);
6700
6701 // Fix adjacency order on the owner cell
6702 int ownerInterfaceIndex = intrOwner->getInterfaceCount(intrOwnerFace) - 1;
6703 long ownerPairedAdjacency = intrOwner->getAdjacency(intrOwnerFace, ownerInterfaceIndex);
6704 if (ownerPairedAdjacency != intrNeighId) {
6705 int ownerPairedAdjacencyIndex = intrOwner->findAdjacency(intrOwnerFace, intrNeighId);
6706 assert(ownerPairedAdjacencyIndex >= 0);
6707 intrOwner->setAdjacency(intrOwnerFace, ownerInterfaceIndex, intrNeighId);
6708 intrOwner->setAdjacency(intrOwnerFace, ownerPairedAdjacencyIndex, ownerPairedAdjacency);
6709 }
6710
6711 // Fix adjacency order on the neighbour cell
6712 int neighInterfaceIndex = intrNeigh->getInterfaceCount(intrNeighFace) - 1;
6713 long neighPairedAdjacency = intrNeigh->getAdjacency(intrNeighFace, neighInterfaceIndex);
6714 if (neighPairedAdjacency != intrOwnerId) {
6715 int neighPairedAdjacencyIndex = intrNeigh->findAdjacency(intrNeighFace, intrOwnerId);
6716 assert(neighPairedAdjacencyIndex >= 0);
6717 intrNeigh->setAdjacency(intrNeighFace, neighInterfaceIndex, intrOwnerId);
6718 intrNeigh->setAdjacency(intrNeighFace, neighPairedAdjacencyIndex, neighPairedAdjacency);
6719 }
6720 }
6721
6722 return interfaceIterator;
6723}
6724
6734int PatchKernel::findAdjoinNeighFace(const Cell &cell, int cellFace, const Cell &neigh) const
6735{
6736 // Evaluate list of candidate faces
6737 //
6738 // The cells may be neighbours through multiple faces. Identify which face
6739 // matches the target one is quite expensive. Moreover, if the cells are
6740 // neighbours through a single face (which is the common case), the check
6741 // is not needed at all. Therefore, first we identify all the faces through
6742 // which the two cells are neighbours and then, if and only if there are
6743 // multiple candidates, we identify the face that matches the target one.
6744 long cellId = cell.getId();
6745 const int nNeighFaces = neigh.getFaceCount();
6746
6747 int nCandidates = 0;
6748 BITPIT_CREATE_WORKSPACE(candidates, std::array<int BITPIT_COMMA 3>, nNeighFaces, ReferenceElementInfo::MAX_ELEM_FACES);
6749 for (int neighFace = 0; neighFace < nNeighFaces; neighFace++) {
6750 int nFaceAdjacencies = neigh.getAdjacencyCount(neighFace);
6751 const long *faceAdjacencies = neigh.getAdjacencies(neighFace);
6752 for (int k = 0; k < nFaceAdjacencies; ++k) {
6753 long geussId = faceAdjacencies[k];
6754 if (geussId == cellId) {
6755 (*candidates)[nCandidates] = neighFace;
6756 ++nCandidates;
6757 break;
6758 }
6759 }
6760 }
6761
6762 // Select the face of the neighbour which adjoin the given face
6763 if (nCandidates == 1) {
6764 return (*candidates)[0];
6765 } else {
6766 for (int i = 0; i < nCandidates; ++i) {
6767 int candidateFace = (*candidates)[i];
6768 if (isSameFace(cell, cellFace, neigh, candidateFace)) {
6769 return candidateFace;
6770 }
6771 }
6772 }
6773
6774 return -1;
6775}
6776
6784bool PatchKernel::testCellAlterationFlags(long id, AlterationFlags flags) const
6785{
6786 return testElementAlterationFlags(id, flags, m_alteredCells);
6787}
6788
6795PatchKernel::AlterationFlags PatchKernel::getCellAlterationFlags(long id) const
6796{
6797 return getElementAlterationFlags(id, m_alteredCells);
6798}
6799
6806void PatchKernel::resetCellAlterationFlags(long id, AlterationFlags flags)
6807{
6808 resetElementAlterationFlags(id, flags, &m_alteredCells);
6809}
6810
6816void PatchKernel::setCellAlterationFlags(AlterationFlags flags)
6817{
6819 for (CellConstIterator itr = cellConstBegin(); itr != endItr; ++itr) {
6820 setCellAlterationFlags(itr.getId(), flags);
6821 }
6822}
6823
6830void PatchKernel::setCellAlterationFlags(long id, AlterationFlags flags)
6831{
6832 setElementAlterationFlags(id, flags, &m_alteredCells);
6833}
6834
6840void PatchKernel::unsetCellAlterationFlags(AlterationFlags flags)
6841{
6842 unsetElementAlterationFlags(flags, &m_alteredCells);
6843}
6844
6851void PatchKernel::unsetCellAlterationFlags(long id, AlterationFlags flags)
6852{
6853 unsetElementAlterationFlags(id, flags, &m_alteredCells);
6854}
6855
6863bool PatchKernel::testInterfaceAlterationFlags(long id, AlterationFlags flags) const
6864{
6865 return testElementAlterationFlags(id, flags, m_alteredInterfaces);
6866}
6867
6874PatchKernel::AlterationFlags PatchKernel::getInterfaceAlterationFlags(long id) const
6875{
6876 return getElementAlterationFlags(id, m_alteredInterfaces);
6877}
6878
6885void PatchKernel::resetInterfaceAlterationFlags(long id, AlterationFlags flags)
6886{
6887 resetElementAlterationFlags(id, flags, &m_alteredInterfaces);
6888}
6889
6896{
6898 for (InterfaceConstIterator itr = interfaceConstBegin(); itr != endItr; ++itr) {
6899 setInterfaceAlterationFlags(itr.getId(), flags);
6900 }
6901}
6902
6909void PatchKernel::setInterfaceAlterationFlags(long id, AlterationFlags flags)
6910{
6911 setElementAlterationFlags(id, flags, &m_alteredInterfaces);
6912}
6913
6920{
6921 unsetElementAlterationFlags(flags, &m_alteredInterfaces);
6922}
6923
6930void PatchKernel::unsetInterfaceAlterationFlags(long id, AlterationFlags flags)
6931{
6932 unsetElementAlterationFlags(id, flags, &m_alteredInterfaces);
6933}
6934
6943bool PatchKernel::testElementAlterationFlags(long id, AlterationFlags flags, const AlterationFlagsStorage &flagsStorage) const
6944{
6945 auto storedFlagsItr = flagsStorage.find(id);
6946 if (storedFlagsItr != flagsStorage.end()) {
6947 return testAlterationFlags(storedFlagsItr->second, flags);
6948 } else {
6949 return testAlterationFlags(FLAG_NONE, flags);
6950 }
6951}
6952
6960bool PatchKernel::testAlterationFlags(AlterationFlags availableFlags, AlterationFlags requestedFlags) const
6961{
6962 return ((availableFlags & requestedFlags) == requestedFlags);
6963}
6964
6972PatchKernel::AlterationFlags PatchKernel::getElementAlterationFlags(long id, const AlterationFlagsStorage &flagsStorage) const
6973{
6974 auto storedFlagsItr = flagsStorage.find(id);
6975 if (storedFlagsItr != flagsStorage.end()) {
6976 return storedFlagsItr->second;
6977 } else {
6978 return FLAG_NONE;
6979 }
6980}
6981
6989void PatchKernel::resetElementAlterationFlags(long id, AlterationFlags flags, AlterationFlagsStorage *flagsStorage) const
6990{
6991 if (flags == FLAG_NONE) {
6992 flagsStorage->erase(id);
6993 } else {
6994 (*flagsStorage)[id] = flags;
6995 }
6996}
6997
7005void PatchKernel::setElementAlterationFlags(long id, AlterationFlags flags, AlterationFlagsStorage *flagsStorage) const
7006{
7007 if (flags == FLAG_NONE) {
7008 return;
7009 }
7010
7011 auto storedFlagsItr = flagsStorage->find(id);
7012 if (storedFlagsItr != flagsStorage->end()) {
7013 storedFlagsItr->second |= flags;
7014 } else {
7015 flagsStorage->insert({id, flags});
7016 }
7017}
7018
7025void PatchKernel::unsetElementAlterationFlags(AlterationFlags flags, AlterationFlagsStorage *flagsStorage) const
7026{
7027 if (flags == FLAG_NONE) {
7028 return;
7029 }
7030
7031 for (auto storedFlagsItr = flagsStorage->begin(); storedFlagsItr != flagsStorage->end();) {
7032 storedFlagsItr->second &= ~flags;
7033 if (storedFlagsItr->second == FLAG_NONE) {
7034 storedFlagsItr = flagsStorage->erase(storedFlagsItr);
7035 } else {
7036 ++storedFlagsItr;
7037 }
7038 }
7039}
7040
7048void PatchKernel::unsetElementAlterationFlags(long id, AlterationFlags flags, AlterationFlagsStorage *flagsStorage) const
7049{
7050 if (flags == FLAG_NONE) {
7051 return;
7052 }
7053
7054 auto storedFlagsItr = flagsStorage->find(id);
7055 if (storedFlagsItr == flagsStorage->end()) {
7056 return;
7057 }
7058
7059 storedFlagsItr->second &= ~flags;
7060 if (storedFlagsItr->second == FLAG_NONE) {
7061 flagsStorage->erase(storedFlagsItr);
7062 }
7063}
7064
7071{
7072 for (int k = 0; k < 3; ++k) {
7073 m_boxMinPoint[k] = std::numeric_limits<double>::max();
7074 m_boxMinCounter[k] = 0;
7075
7076 m_boxMaxPoint[k] = - std::numeric_limits<double>::max();
7077 m_boxMaxCounter[k] = 0;
7078 }
7079
7081}
7082
7091void PatchKernel::setBoundingBox(const std::array<double, 3> &minPoint, const std::array<double, 3> &maxPoint)
7092{
7093 m_boxMinPoint = minPoint;
7094 m_boxMaxPoint = maxPoint;
7095
7096 setBoundingBoxDirty(false);
7097}
7098
7105void PatchKernel::getBoundingBox(std::array<double, 3> &minPoint, std::array<double, 3> &maxPoint) const
7106{
7107 getBoundingBox(false, minPoint, maxPoint);
7108}
7109
7118void PatchKernel::getBoundingBox(bool global, std::array<double, 3> &minPoint, std::array<double, 3> &maxPoint) const
7119{
7120 minPoint = m_boxMinPoint;
7121 maxPoint = m_boxMaxPoint;
7122
7123#if BITPIT_ENABLE_MPI==1
7124 if (global && isPartitioned()) {
7125 MPI_Comm communicator = getCommunicator();
7126 MPI_Allreduce(MPI_IN_PLACE, minPoint.data(), 3, MPI_DOUBLE, MPI_MIN, communicator);
7127 MPI_Allreduce(MPI_IN_PLACE, maxPoint.data(), 3, MPI_DOUBLE, MPI_MAX, communicator);
7128 }
7129#else
7130 BITPIT_UNUSED(global);
7131#endif
7132}
7133
7140{
7141 return m_boxFrozen;
7142}
7143
7155{
7156 m_boxFrozen = frozen;
7157}
7158
7166bool PatchKernel::isBoundingBoxDirty(bool global) const
7167{
7168 bool isDirty = m_boxDirty;
7169#if BITPIT_ENABLE_MPI==1
7170 if (global && isPartitioned()) {
7171 const auto &communicator = getCommunicator();
7172 MPI_Allreduce(const_cast<bool *>(&m_boxDirty), &isDirty, 1, MPI_C_BOOL, MPI_LOR, communicator);
7173 }
7174#else
7175 BITPIT_UNUSED(global);
7176#endif
7177
7178 return isDirty;
7179}
7180
7187{
7188 m_boxDirty = dirty;
7189}
7190
7197void PatchKernel::updateBoundingBox(bool forcedUpdated)
7198{
7199 if (isBoundingBoxFrozen()) {
7200 return;
7201 }
7202
7203 // Check if the bounding box is dirty
7204 if (!isBoundingBoxDirty() && !forcedUpdated) {
7205 return;
7206 }
7207
7208 // Initialize bounding box
7210
7211 // Unset the dirty flag in order to be able to update the bounding box
7212 setBoundingBoxDirty(false);
7213
7214 // Compute bounding box
7215 for (const auto &vertex : m_vertices) {
7217 }
7218}
7219
7228void PatchKernel::addPointToBoundingBox(const std::array<double, 3> &point)
7229{
7231 return;
7232 }
7233
7234 for (size_t k = 0; k < point.size(); ++k) {
7235 double value = point[k];
7236
7237 // Update maximum value
7238 if (utils::DoubleFloatingEqual()(value, m_boxMaxPoint[k], getTol())) {
7239 ++m_boxMaxCounter[k];
7240 } else if (value > m_boxMaxPoint[k]) {
7241 m_boxMaxPoint[k] = value;
7242 m_boxMaxCounter[k] = 1;
7243 }
7244
7245 // Update minimum value
7246 if (utils::DoubleFloatingEqual()(value, m_boxMinPoint[k], getTol())) {
7247 ++m_boxMinCounter[k];
7248 } else if (value < m_boxMinPoint[k]) {
7249 m_boxMinPoint[k] = value;
7250 m_boxMinCounter[k] = 1;
7251 }
7252 }
7253}
7254
7263void PatchKernel::removePointFromBoundingBox(const std::array<double, 3> &point)
7264{
7266 return;
7267 }
7268
7269 double tolerance = getTol();
7270 for (size_t k = 0; k < point.size(); ++k) {
7271 double value = point[k];
7272
7273 // Check if maximum value is still valid
7274 if (utils::DoubleFloatingEqual()(value, m_boxMaxPoint[k], tolerance)) {
7275 --m_boxMaxCounter[k];
7276 if (m_boxMaxCounter[k] == 0) {
7277 setBoundingBoxDirty(true);
7278 return;
7279 }
7280 } else if (value > m_boxMaxPoint[k]) {
7281 assert(false && "Bounding box is in inconsistent state.");
7282 setBoundingBoxDirty(true);
7283 return;
7284 }
7285
7286 // Update minimum value
7287 if (utils::DoubleFloatingEqual()(value, m_boxMinPoint[k], tolerance)) {
7288 --m_boxMinCounter[k];
7289 if (m_boxMinCounter[k] == 0) {
7290 setBoundingBoxDirty(true);
7291 return;
7292 }
7293 } else if (value < m_boxMinPoint[k]) {
7294 assert(false && "Bounding box is in inconsistent state.");
7295 setBoundingBoxDirty(true);
7296 return;
7297 }
7298 }
7299}
7300
7308{
7309 // Get the vertices ids
7310 ConstProxyVector<long> elementVertexIds = element.getVertexIds();
7311 const int nElementVertices = elementVertexIds.size();
7312
7313 // Build the proxy vector with the coordinates
7314 ConstProxyVector<std::array<double, 3>> vertexCoordinates(ConstProxyVector<std::array<double, 3>>::INTERNAL_STORAGE, nElementVertices);
7315 ConstProxyVector<std::array<double, 3>>::storage_pointer storage = vertexCoordinates.storedData();
7316 getVertexCoords(elementVertexIds.size(), elementVertexIds.data(), storage);
7317
7318 return vertexCoordinates;
7319}
7320
7327void PatchKernel::getElementVertexCoordinates(const Element &element, std::unique_ptr<std::array<double, 3>[]> *coordinates) const
7328{
7329 ConstProxyVector<long> elementVertexIds = element.getVertexIds();
7330 getVertexCoords(elementVertexIds.size(), elementVertexIds.data(), coordinates);
7331}
7332
7341void PatchKernel::getElementVertexCoordinates(const Element &element, std::array<double, 3> *coordinates) const
7342{
7343 ConstProxyVector<long> elementVertexIds = element.getVertexIds();
7344 getVertexCoords(elementVertexIds.size(), elementVertexIds.data(), coordinates);
7345}
7346
7353std::unordered_map<long, std::vector<long>> PatchKernel::binGroupVertices(int nBins)
7354{
7355 return PatchKernel::binGroupVertices(m_vertices, nBins);
7356}
7357
7365std::unordered_map<long, std::vector<long>> PatchKernel::binGroupVertices(const PiercedVector<Vertex> &vertices, int nBins)
7366{
7367 // Update bounding box
7369
7370 // Bin's spacing
7371 double dx = std::max(1.0e-12, m_boxMaxPoint[0] - m_boxMinPoint[0]) / ((double) nBins);
7372 double dy = std::max(1.0e-12, m_boxMaxPoint[1] - m_boxMinPoint[1]) / ((double) nBins);
7373 double dz = std::max(1.0e-12, m_boxMaxPoint[2] - m_boxMinPoint[2]) / ((double) nBins);
7374
7375 // Identify bins of vertices
7376 std::unordered_map<long, std::vector<long>> bins;
7377 for (const Vertex &vertex : vertices) {
7378 const std::array<double, 3> &coordinates = vertex.getCoords();
7379
7380 int i = std::min(nBins - 1L, (long) ((coordinates[0] - m_boxMinPoint[0]) / dx));
7381 int j = std::min(nBins - 1L, (long) ((coordinates[1] - m_boxMinPoint[1]) / dy));
7382 int k = std::min(nBins - 1L, (long) ((coordinates[2] - m_boxMinPoint[2]) / dz));
7383
7384 long binId = nBins * nBins * k + nBins * j + i;
7385 bins[binId].emplace_back(vertex.getId());
7386 }
7387
7388 return bins;
7389}
7390
7396void PatchKernel::translate(const std::array<double, 3> &translation)
7397{
7398 // Translate the patch
7399 for (auto &vertex : m_vertices) {
7400 vertex.translate(translation);
7401 }
7402
7403 // Update the bounding box
7405 m_boxMinPoint += translation;
7406 m_boxMaxPoint += translation;
7407 }
7408}
7409
7417void PatchKernel::translate(double sx, double sy, double sz)
7418{
7419 translate({{sx, sy, sz}});
7420}
7421
7430void PatchKernel::rotate(const std::array<double, 3> &n0, const std::array<double, 3> &n1, double angle)
7431{
7432 // Translate the patch
7433 for (auto &vertex : m_vertices) {
7434 vertex.rotate(n0, n1, angle);
7435 }
7436
7437 // Update the bounding box
7439 // Save current bounding box
7440 std::array<std::array<double, 3>, 3> originalBox = {{m_boxMinPoint, m_boxMaxPoint}};
7441
7442 // Clear bounding box
7444
7445 // Unset the dirty flag in order to be able to update the bounding box
7446 setBoundingBoxDirty(false);
7447
7448 // Evaluate rotated bounding box
7449 for (int i = 0; i < 2; ++i) {
7450 double xCorner = originalBox[i][0];
7451 for (int j = 0; j < 2; ++j) {
7452 double yCorner = originalBox[j][1];
7453 for (int k = 0; k < 2; ++k) {
7454 double zCorner = originalBox[k][2];
7455
7456 std::array<double, 3> corner = {{xCorner, yCorner, zCorner}};
7457 corner = CGElem::rotatePoint(corner, n0, n1, angle);
7458 addPointToBoundingBox(corner);
7459 }
7460 }
7461 }
7462 }
7463}
7464
7477void PatchKernel::rotate(double n0x, double n0y, double n0z, double n1x,
7478 double n1y, double n1z, double angle)
7479{
7480 rotate({{n0x, n0y, n0z}}, {{n1x, n1y, n1z}}, angle);
7481}
7482
7490void PatchKernel::scale(const std::array<double, 3> &scaling)
7491{
7492 scale(scaling, m_boxMinPoint);
7493}
7494
7501void PatchKernel::scale(const std::array<double, 3> &scaling, const std::array<double, 3> &center)
7502{
7503 // Scale the patch
7504 for (auto &vertex : m_vertices) {
7505 vertex.scale(scaling, center);
7506 }
7507
7508 // Update the bounding box
7510 for (int k = 0; k < 3; ++k) {
7511 m_boxMinPoint[k] = center[k] + scaling[k] * (m_boxMinPoint[k] - center[k]);
7512 m_boxMaxPoint[k] = center[k] + scaling[k] * (m_boxMaxPoint[k] - center[k]);
7513 }
7514 }
7515}
7516
7524void PatchKernel::scale(double scaling)
7525{
7526 scale({{scaling, scaling, scaling}}, m_boxMinPoint);
7527}
7528
7535void PatchKernel::scale(double scaling, const std::array<double, 3> &center)
7536{
7537 scale({{scaling, scaling, scaling}}, center);
7538}
7539
7547void PatchKernel::scale(double sx, double sy, double sz)
7548{
7549 scale({{sx, sy, sz}}, m_boxMinPoint);
7550}
7551
7562void PatchKernel::scale(double sx, double sy, double sz, const std::array<double, 3> &center)
7563{
7564 scale({{sx, sy, sz}}, center);
7565}
7566
7573void PatchKernel::setTol(double tolerance)
7574{
7575 _setTol(tolerance);
7576
7577 m_toleranceCustom = true;
7578}
7579
7586void PatchKernel::_setTol(double tolerance)
7587{
7588 m_tolerance = tolerance;
7589}
7590
7597{
7598 return m_tolerance;
7599}
7600
7605{
7606 _resetTol();
7607
7608 m_toleranceCustom = false;
7609}
7610
7621{
7622 const double DEFAULT_TOLERANCE = 1e-14;
7623
7624 m_tolerance = DEFAULT_TOLERANCE;
7625}
7626
7634{
7635 return m_toleranceCustom;
7636}
7637
7647{
7648
7649 // ====================================================================== //
7650 // RESIZE DATA STRUCTURES //
7651 // ====================================================================== //
7652 envelope.reserveVertices(envelope.getVertexCount() + countBorderVertices());
7653 envelope.reserveCells(envelope.getCellCount() + countBorderFaces());
7654
7655 // ====================================================================== //
7656 // LOOP OVER CELLS //
7657 // ====================================================================== //
7658 std::unordered_map<long, long> vertexMap;
7659 for (const Cell &cell : m_cells) {
7660 int nCellFaces = cell.getFaceCount();
7661 for (int i = 0; i < nCellFaces; ++i) {
7662 if (!cell.isFaceBorder(i)) {
7663 continue;
7664 }
7665
7666 // Add face vertices to the envelope and get face
7667 // connectivity in the envelope
7668 ConstProxyVector<long> faceConnect = cell.getFaceConnect(i);
7669 int nFaceVertices = faceConnect.size();
7670
7671 std::unique_ptr<long[]> faceEnvelopeConnect = std::unique_ptr<long[]>(new long[nFaceVertices]);
7672 for (int j = 0; j < nFaceVertices; ++j) {
7673 long vertexId = faceConnect[j];
7674
7675 // If the vertex is not yet in the envelope
7676 // add it.
7677 if (vertexMap.count(vertexId) == 0) {
7678 const Vertex &vertex = getVertex(vertexId);
7679 VertexIterator envelopeVertex = envelope.addVertex(vertex);
7680 vertexMap[vertexId] = envelopeVertex->getId();
7681 }
7682
7683 // Update face ace connectivity in the envelope
7684 faceEnvelopeConnect[j] = vertexMap.at(vertexId);
7685 }
7686
7687 // Add face to envelope
7688 ElementType faceType = cell.getFaceType(i);
7689 envelope.addCell(faceType, std::move(faceEnvelopeConnect));
7690 }
7691 }
7692}
7693
7701void PatchKernel::displayTopologyStats(std::ostream &out, unsigned int padding) const
7702{
7703 std::string indent = std::string(padding, ' ');
7704
7705 // ====================================================================== //
7706 // VERTEX STATS //
7707 // ====================================================================== //
7708 out << indent<< "Vertices --------------------------------" << std::endl;
7709 out << indent<< " # vertices " << getVertexCount() << std::endl;
7710 out << indent<< " # orphan vertices " << countOrphanVertices() << std::endl;
7711 out << indent<< " # border vertices " << countBorderVertices() << std::endl;
7712 //out << indent<< " # free vertices " << countDoubleVertices() << std::endl;
7713
7714 // ====================================================================== //
7715 // FACE STATS //
7716 // ====================================================================== //
7717 out << indent<< "Faces -----------------------------------" << std::endl;
7718 out << indent<< " # faces " << countFaces() << std::endl;
7719 out << indent<< " # border faces " << countBorderFaces() << std::endl;
7720
7721 // ====================================================================== //
7722 // CELLS STATS //
7723 // ====================================================================== //
7724 out << indent<< "Cells -----------------------------------" << std::endl;
7725 out << indent<< " # cells " << getCellCount() << std::endl;
7726 out << indent<< " # orphan cells " << countOrphanCells() << std::endl;
7727 out << indent<< " # border cells " << countBorderCells() << std::endl;
7728 //out << indent<< " # free vertices " << countDoubleCells() << std::endl;
7729}
7730
7738void PatchKernel::displayVertices(std::ostream &out, unsigned int padding) const
7739{
7740 std::string indent = std::string(padding, ' ');
7741 for (const Vertex &vertex : m_vertices) {
7742 out << indent << "vertex: " << std::endl;
7743 vertex.display(out, padding + 2);
7744 }
7745}
7746
7754void PatchKernel::displayCells(std::ostream &out, unsigned int padding) const
7755{
7756 std::string indent = std::string(padding, ' ');
7757 for (const Cell &cell : m_cells) {
7758 out << indent << "cell: " << std::endl;
7759 cell.display(out, padding + 2);
7760 }
7761}
7762
7770void PatchKernel::displayInterfaces(std::ostream &out, unsigned int padding) const
7771{
7772 std::string indent = std::string(padding, ' ');
7773 for (const Interface &interface : m_interfaces) {
7774 out << indent << "interface: " << std::endl;
7775 interface.display(out, padding + 2);
7776 }
7777}
7778
7785{
7786 return m_vtk;
7787}
7788
7795{
7796 return m_vtk;
7797}
7798
7804PatchKernel::WriteTarget PatchKernel::getVTKWriteTarget() const
7805{
7806 return m_vtkWriteTarget;
7807}
7808
7814void PatchKernel::setVTKWriteTarget(WriteTarget writeTarget)
7815{
7816 m_vtkWriteTarget = writeTarget;
7817}
7818
7825{
7826 if (m_vtkWriteTarget == WRITE_TARGET_CELLS_ALL) {
7828#if BITPIT_ENABLE_MPI==1
7829 } else if (m_vtkWriteTarget == WRITE_TARGET_CELLS_INTERNAL) {
7831#endif
7832 } else {
7834 }
7835}
7836
7843void PatchKernel::replaceVTKStreamer(const VTKBaseStreamer *original, VTKBaseStreamer *updated)
7844{
7845 // Update the VTK streamer
7846 //
7847 // The pointer to VTK streamers are copied, if there are pointer to the
7848 // original object they have to be replace with a pointer to this object.
7849 // Geometry fields
7850 std::vector<std::string> streamedGeomFields;
7851 streamedGeomFields.reserve(m_vtk.getGeomDataCount());
7852 for (auto itr = m_vtk.getGeomDataBegin(); itr != m_vtk.getGeomDataEnd(); ++itr) {
7853 const VTKField &field = *itr;
7854 if (&field.getStreamer() != original) {
7855 continue;
7856 }
7857
7858 streamedGeomFields.push_back(field.getName());
7859 }
7860
7861 for (const std::string &name : streamedGeomFields) {
7862 const VTKField &field = *(m_vtk.findGeomData(name));
7863 VTKField updatedField(field);
7864 updatedField.setStreamer(*updated);
7865
7866 m_vtk.setGeomData(std::move(updatedField));
7867 }
7868
7869 std::vector<std::string> streamedDataFields;
7870 streamedDataFields.reserve(m_vtk.getDataCount());
7871 for (auto itr = m_vtk.getDataBegin(); itr != m_vtk.getDataEnd(); ++itr) {
7872 const VTKField &field = *itr;
7873 if (&field.getStreamer() != original) {
7874 continue;
7875 }
7876
7877 streamedDataFields.push_back(field.getName());
7878 }
7879
7880 for (const std::string &name : streamedDataFields) {
7881 const VTKField &field = *(m_vtk.findData(name));
7882 VTKField updatedField(field);
7883 updatedField.setStreamer(*updated);
7884
7885 m_vtk.removeData(field.getName());
7886 m_vtk.addData(std::move(updatedField));
7887 }
7888}
7889
7900void PatchKernel::flushData(std::fstream &stream, const std::string &name, VTKFormat format)
7901{
7902 if (name == "Points") {
7904 for (VertexConstIterator itr = vertexConstBegin(); itr != endItr; ++itr) {
7905 std::size_t vertexRawId = itr.getRawIndex();
7906 long vertexVTKId = m_vtkVertexMap.rawAt(vertexRawId);
7907 if (vertexVTKId != Vertex::NULL_ID) {
7908 const Vertex &vertex = m_vertices.rawAt(vertexRawId);
7909 flushValue(stream, format,vertex.getCoords());
7910 }
7911 }
7912 } else if (name == "offsets") {
7913 long offset = 0;
7914 for (const Cell &cell : getVTKCellWriteRange()) {
7915 offset += cell.getVertexCount();
7916 flushValue(stream, format,offset);
7917 }
7918 } else if (name == "types") {
7919 for (const Cell &cell : getVTKCellWriteRange()) {
7920 VTKElementType VTKType;
7921 switch (cell.getType()) {
7922
7923 case ElementType::VERTEX:
7924 VTKType = VTKElementType::VERTEX;
7925 break;
7926
7927 case ElementType::LINE:
7928 VTKType = VTKElementType::LINE;
7929 break;
7930
7931 case ElementType::TRIANGLE:
7932 VTKType = VTKElementType::TRIANGLE;
7933 break;
7934
7935 case ElementType::PIXEL:
7936 VTKType = VTKElementType::PIXEL;
7937 break;
7938
7939 case ElementType::QUAD:
7940 VTKType = VTKElementType::QUAD;
7941 break;
7942
7943 case ElementType::POLYGON:
7944 VTKType = VTKElementType::POLYGON;
7945 break;
7946
7947 case ElementType::TETRA:
7948 VTKType = VTKElementType::TETRA;
7949 break;
7950
7951 case ElementType::VOXEL:
7952 VTKType = VTKElementType::VOXEL;
7953 break;
7954
7955 case ElementType::HEXAHEDRON:
7956 VTKType = VTKElementType::HEXAHEDRON;
7957 break;
7958
7959 case ElementType::WEDGE:
7960 VTKType = VTKElementType::WEDGE;
7961 break;
7962
7963 case ElementType::PYRAMID:
7964 VTKType = VTKElementType::PYRAMID;
7965 break;
7966
7967 case ElementType::POLYHEDRON:
7968 VTKType = VTKElementType::POLYHEDRON;
7969 break;
7970
7971 default:
7972 VTKType = VTKElementType::UNDEFINED;
7973 break;
7974
7975 }
7976
7977 flushValue(stream, format,(int) VTKType);
7978 }
7979 } else if (name == "connectivity") {
7980 for (const Cell &cell : getVTKCellWriteRange()) {
7981 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
7982 const int nCellVertices = cellVertexIds.size();
7983 for (int k = 0; k < nCellVertices; ++k) {
7984 long vertexId = cellVertexIds[k];
7985 long vtkVertexId = m_vtkVertexMap.at(vertexId);
7986 flushValue(stream, format,vtkVertexId);
7987 }
7988 }
7989 } else if (name == "faces") {
7990 for (const Cell &cell : getVTKCellWriteRange()) {
7991 if (cell.getDimension() <= 2 || cell.hasInfo()) {
7992 flushValue(stream, format,(long) 0);
7993 } else {
7994 std::vector<long> faceStream = cell.getFaceStream();
7995 Cell::renumberFaceStream(m_vtkVertexMap, &faceStream);
7996 int faceStreamSize = faceStream.size();
7997 for (int k = 0; k < faceStreamSize; ++k) {
7998 flushValue(stream, format,faceStream[k]);
7999 }
8000 }
8001 }
8002 } else if (name == "faceoffsets") {
8003 long offset = 0;
8004 for (const Cell &cell : getVTKCellWriteRange()) {
8005 if (cell.getDimension() <= 2 || cell.hasInfo()) {
8006 offset += 1;
8007 } else {
8008 offset += cell.getFaceStreamSize();
8009 }
8010
8011 flushValue(stream, format,offset);
8012 }
8013 } else if (name == "cellIndex") {
8014 for (const Cell &cell : getVTKCellWriteRange()) {
8015 flushValue(stream, format,cell.getId());
8016 }
8017 } else if (name == "PID") {
8018 for (const Cell &cell : getVTKCellWriteRange()) {
8019 flushValue(stream, format,cell.getPID());
8020 }
8021 } else if (name == "vertexIndex") {
8023 for (VertexConstIterator itr = vertexConstBegin(); itr != endItr; ++itr) {
8024 std::size_t vertexRawId = itr.getRawIndex();
8025 long vertexVTKId = m_vtkVertexMap.rawAt(vertexRawId);
8026 if (vertexVTKId != Vertex::NULL_ID) {
8027 long vertexId = itr.getId();
8028 flushValue(stream, format,vertexId);
8029 }
8030 }
8031#if BITPIT_ENABLE_MPI==1
8032 } else if (name == "cellGlobalIndex") {
8033 PatchNumberingInfo numberingInfo(this);
8034 for (const Cell &cell : getVTKCellWriteRange()) {
8035 flushValue(stream, format,numberingInfo.getCellGlobalId(cell.getId()));
8036 }
8037 } else if (name == "cellRank") {
8038 for (const Cell &cell : getVTKCellWriteRange()) {
8039 flushValue(stream, format,getCellOwner(cell.getId()));
8040 }
8041 } else if (name == "cellHaloLayer") {
8042 for (const Cell &cell : getVTKCellWriteRange()) {
8043 flushValue(stream, format,getCellHaloLayer(cell.getId()));
8044 }
8045 } else if (name == "vertexRank") {
8047 for (VertexConstIterator itr = vertexConstBegin(); itr != endItr; ++itr) {
8048 std::size_t vertexRawId = itr.getRawIndex();
8049 long vertexVTKId = m_vtkVertexMap.rawAt(vertexRawId);
8050 if (vertexVTKId != Vertex::NULL_ID) {
8051 flushValue(stream, format,getVertexOwner(itr.getId()));
8052 }
8053 }
8054#endif
8055 }
8056}
8057
8064{
8065 // Renumber vertices
8066 std::unordered_map<long, long > map = consecutiveItemRenumbering(m_vertices, offset);
8067
8068 // Renumber cell connectivity
8069 for(Cell &cell : m_cells) {
8070 cell.renumberVertices(map);
8071 }
8072
8073 // Renumber interface connectivity
8074 for(Interface &interface : getInterfaces()) {
8075 interface.renumberVertices(map);
8076 }
8077
8078 // Reset index generator
8080 createVertexIndexGenerator(true);
8081 }
8082}
8083
8090{
8091 // Renumber cells
8092 std::unordered_map<long, long > map = consecutiveItemRenumbering(m_cells, offset);
8093
8094 // Renumber cell adjacencies
8095 for (auto &cell: m_cells) {
8096 long *adjacencies = cell.getAdjacencies();
8097 int nCellAdjacencies = cell.getAdjacencyCount();
8098 for (int i = 0; i < nCellAdjacencies; ++i) {
8099 long &neighId = adjacencies[i];
8100 neighId = map[neighId];
8101 }
8102 }
8103
8104 // Renumber interface owner and neighbour
8105 for (Interface &interface: m_interfaces) {
8106 long ownerId = interface.getOwner();
8107 int ownerFace = interface.getOwnerFace();
8108 interface.setOwner(map.at(ownerId), ownerFace);
8109
8110 long neighId = interface.getNeigh();
8111 if (neighId >= 0) {
8112 int neighFace = interface.getNeighFace();
8113 interface.setNeigh(map.at(neighId), neighFace);
8114 }
8115 }
8116
8117 // Renumber last internal and first ghost markers
8118 if (m_lastInternalCellId >= 0) {
8119 m_lastInternalCellId = map.at(m_lastInternalCellId);
8120 }
8121
8122#if BITPIT_ENABLE_MPI==1
8123 if (m_firstGhostCellId >= 0) {
8124 m_firstGhostCellId = map.at(m_firstGhostCellId);
8125 }
8126#endif
8127
8128 // Reset index generator
8130 createCellIndexGenerator(true);
8131 }
8132
8133#if BITPIT_ENABLE_MPI==1
8134 // Update partitioning information
8135 if (isPartitioned()) {
8136 updatePartitioningInfo(true);
8137 }
8138#endif
8139}
8140
8147{
8148 // Renumber interfaces
8149 std::unordered_map<long, long > map = consecutiveItemRenumbering(m_interfaces, offset);
8150
8151 // Renumber cell interfaces
8152 for (Cell &cell: m_cells) {
8153 long *interfaces = cell.getInterfaces();
8154 int nCellInterfaces = cell.getInterfaceCount();
8155 for (int i = 0; i < nCellInterfaces; ++i) {
8156 long &interfaceId = interfaces[i];
8157 interfaceId = map.at(interfaceId);
8158 }
8159 }
8160
8161 // Reset index generator
8163 createInterfaceIndexGenerator(true);
8164 }
8165}
8166
8175void PatchKernel::consecutiveRenumber(long vertexOffset, long cellOffset, long interfaceOffset)
8176{
8177 consecutiveRenumberVertices(vertexOffset);
8178 consecutiveRenumberCells(cellOffset);
8179 consecutiveRenumberInterfaces(interfaceOffset);
8180}
8181
8188{
8189 const int KERNEL_DUMP_VERSION = 12;
8190
8191 return (KERNEL_DUMP_VERSION + _getDumpVersion());
8192}
8193
8203bool PatchKernel::dump(std::ostream &stream)
8204{
8205 // Update the patch
8206 update();
8207
8208 // Dump the patch
8209 const PatchKernel *constPatch = this;
8210 return constPatch->dump(stream);
8211}
8212
8224bool PatchKernel::dump(std::ostream &stream) const
8225{
8226 // Dumping a dirty patch is not supported.
8227 bool dirty = isDirty(true);
8228 assert(!dirty && "Dumping a patch that is not up-to-date is not supported.");
8229 if (dirty) {
8230 return false;
8231 }
8232
8233 // Version
8235
8236 // Generic information
8237 utils::binary::write(stream, m_id);
8238 utils::binary::write(stream, m_dimension);
8239 utils::binary::write(stream, m_vtk.getName());
8240#if BITPIT_ENABLE_MPI==1
8241 utils::binary::write(stream, m_haloSize);
8242#else
8243 utils::binary::write(stream, 0);
8244#endif
8245
8246 // Adaption information
8247 utils::binary::write(stream, m_adaptionMode);
8248 utils::binary::write(stream, m_adaptionStatus);
8249
8250 // Partition information
8251#if BITPIT_ENABLE_MPI==1
8252 utils::binary::write(stream, m_partitioningMode);
8253 utils::binary::write(stream, m_partitioningStatus);
8254#else
8255 utils::binary::write(stream, PARTITIONING_DISABLED);
8256 utils::binary::write(stream, PARTITIONING_CLEAN);
8257#endif
8258
8259 // Adjacencies build strategy
8260 utils::binary::write(stream, m_adjacenciesBuildStrategy);
8261
8262 // Dump interfaces build strategy
8263 utils::binary::write(stream, m_interfacesBuildStrategy);
8264
8265 // VTK data
8266 utils::binary::write(stream, m_vtkWriteTarget);
8267
8268 // Specific dump
8269 _dump(stream);
8270
8271 // Geometric tolerance
8272 utils::binary::write(stream, (int) m_toleranceCustom);
8273 if (m_toleranceCustom) {
8274 utils::binary::write(stream, m_tolerance);
8275 }
8276
8277 // Index generators
8278 bool hasVertexAutoIndexing = isVertexAutoIndexingEnabled();
8279 utils::binary::write(stream, hasVertexAutoIndexing);
8280 if (hasVertexAutoIndexing) {
8281 dumpVertexAutoIndexing(stream);
8282 }
8283
8284 bool hasInterfaceAutoIndexing = isInterfaceAutoIndexingEnabled();
8285 utils::binary::write(stream, hasInterfaceAutoIndexing);
8286 if (hasInterfaceAutoIndexing) {
8287 dumpInterfaceAutoIndexing(stream);
8288 }
8289
8290 bool hasCellAutoIndexing = isCellAutoIndexingEnabled();
8291 utils::binary::write(stream, hasCellAutoIndexing);
8292 if (hasCellAutoIndexing) {
8293 dumpCellAutoIndexing(stream);
8294 }
8295
8296 // The patch has been dumped successfully
8297 return true;
8298}
8299
8307void PatchKernel::restore(std::istream &stream, bool reregister)
8308{
8309 // Reset the patch
8310 reset();
8311
8312 // Version
8313 int version;
8314 utils::binary::read(stream, version);
8315 if (version != getDumpVersion()) {
8316 throw std::runtime_error ("The version of the file does not match the required version");
8317 }
8318
8319 // Id
8320 int id;
8321 utils::binary::read(stream, id);
8322 if (reregister) {
8323 setId(id);
8324 }
8325
8326 // Dimension
8327 int dimension;
8328 utils::binary::read(stream, dimension);
8329 setDimension(dimension);
8330
8331 // Name
8332 std::string name;
8333 utils::binary::read(stream, name);
8334 m_vtk.setName(name);
8335
8336 // Halo size
8337#if BITPIT_ENABLE_MPI==1
8338 utils::binary::read(stream, m_haloSize);
8339#else
8340 int dummyHaloSize;
8341 utils::binary::read(stream, dummyHaloSize);
8342#endif
8343
8344 // Adaption information
8345 utils::binary::read(stream, m_adaptionMode);
8346 utils::binary::read(stream, m_adaptionStatus);
8347
8348 // Partition information
8349#if BITPIT_ENABLE_MPI==1
8350 utils::binary::read(stream, m_partitioningMode);
8351 utils::binary::read(stream, m_partitioningStatus);
8352#else
8353 PartitioningStatus dummyPartitioningMode;
8354 utils::binary::read(stream, dummyPartitioningMode);
8355
8356 PartitioningStatus dummyPartitioningStatus;
8357 utils::binary::read(stream, dummyPartitioningStatus);
8358#endif
8359
8360 // Adjacencies build strategy
8361 utils::binary::read(stream, m_adjacenciesBuildStrategy);
8362
8363 // Interfaces build strategy
8364 utils::binary::read(stream, m_interfacesBuildStrategy);
8365
8366 // VTK data
8367 utils::binary::read(stream, m_vtkWriteTarget);
8368
8369 // Specific restore
8370 _restore(stream);
8371
8372#if BITPIT_ENABLE_MPI==1
8373 // Update partitioning information
8374 if (isPartitioned()) {
8375 updatePartitioningInfo(true);
8376 }
8377#endif
8378
8379 // Geometric tolerance
8380 int hasCustomTolerance;
8381 utils::binary::read(stream, hasCustomTolerance);
8382 if (hasCustomTolerance) {
8383 double tolerance;
8384 utils::binary::read(stream, tolerance);
8385 setTol(tolerance);
8386 } else {
8387 resetTol();
8388 }
8389
8390 // Index generators
8391 bool hasVertexAutoIndexing;
8392 utils::binary::read(stream, hasVertexAutoIndexing);
8393 if (hasVertexAutoIndexing) {
8394 restoreVertexAutoIndexing(stream);
8395 } else {
8396 setVertexAutoIndexing(false);
8397 }
8398
8399 bool hasInterfaceAutoIndexing;
8400 utils::binary::read(stream, hasInterfaceAutoIndexing);
8401 if (hasInterfaceAutoIndexing) {
8402 restoreInterfaceAutoIndexing(stream);
8403 } else {
8405 }
8406
8407 bool hasCellAutoIndexing;
8408 utils::binary::read(stream, hasCellAutoIndexing);
8409 if (hasCellAutoIndexing) {
8410 restoreCellAutoIndexing(stream);
8411 } else {
8412 setCellAutoIndexing(false);
8413 }
8414}
8415
8422void PatchKernel::mergeAdaptionInfo(std::vector<adaption::Info> &&source, std::vector<adaption::Info> &destination)
8423{
8424 if (source.empty()) {
8425 return;
8426 } else if (destination.empty()) {
8427 destination.swap(source);
8428 return;
8429 }
8430
8431 throw std::runtime_error ("Unable to merge the adaption info.");
8432}
8433
8434}
The Cell class defines the cells.
Definition cell.hpp:42
bool isInterior() const
Definition cell.cpp:396
bool isFaceBorder(int face) const
Definition cell.cpp:946
bool pushAdjacency(int face, long adjacency)
Definition cell.cpp:771
void deleteInterface(int face, int i)
Definition cell.cpp:522
int getInterfaceCount() const
Definition cell.cpp:535
const long * getAdjacencies() const
Definition cell.cpp:841
const long * getInterfaces() const
Definition cell.cpp:571
void deleteAdjacency(int face, int i)
Definition cell.cpp:792
int getAdjacencyCount() const
Definition cell.cpp:805
void setWinding(Winding winding)
Definition element.tpp:108
The Element class provides an interface for defining elements.
Definition element.hpp:46
long getId() const
Definition element.cpp:510
int getDimension() const
Definition element.cpp:1119
ConstProxyVector< long > getFaceVertexIds(int face) const
Definition element.cpp:1320
ElementType getType() const
Definition element.cpp:551
long getFaceVertexId(int face, int vertex) const
Definition element.cpp:1343
int findVertex(long vertexId) const
Definition element.cpp:1302
const ReferenceElementInfo & getInfo() const
Definition element.cpp:531
ElementType getFaceType(int face) const
Definition element.cpp:701
ConstProxyVector< int > getEdgeLocalConnect(int edge) const
Definition element.cpp:994
long getEdgeVertexId(int edge, int vertex) const
Definition element.cpp:1424
static ConstProxyVector< long > getVertexIds(ElementType type, const long *connectivity)
Definition element.cpp:1193
int getFaceVertexCount(int face) const
Definition element.cpp:743
const long * getConnect() const
Definition element.cpp:609
bool hasInfo() const
Definition element.cpp:521
void setId(long id)
Definition element.cpp:498
ConstProxyVector< long > getFaceConnect(int face) const
Definition element.cpp:848
long getVertexId(int vertex) const
Definition element.cpp:1269
static void renumberFaceStream(const PiercedStorage< long, long > &map, std::vector< long > *faceStream)
Definition element.cpp:2012
int getEdgeCount() const
Definition element.cpp:922
std::array< double, 3 > evalCentroid(const std::array< double, 3 > *coordinates) const
Definition element.cpp:1521
int getFaceCount() const
Definition element.cpp:678
int getVertexCount() const
Definition element.cpp:1152
The Interface class defines the interfaces among cells.
Definition interface.hpp:37
long getOwner() const
void initialize(long id, ElementType type)
The PatchKernel class provides an interface for defining patches.
void initializeAdjacencies(AdjacenciesBuildStrategy strategy=ADJACENCIES_AUTOMATIC)
VertexIterator vertexEnd()
void unsetCellAlterationFlags(AlterationFlags flags)
CellConstIterator cellConstBegin() const
CellIterator cellBegin()
Vertex & getLastInternalVertex()
CellIterator getCellIterator(long id)
void dumpInterfaces(std::ostream &stream) const
CellIterator internalCellBegin()
InterfacesBuildStrategy getInterfacesBuildStrategy() const
CellConstIterator internalConstBegin() const
virtual bool _enableCellBalancing(long id, bool enabled)
CellConstIterator internalCellConstEnd() const
CellIterator internalBegin()
AdjacenciesBuildStrategy getAdjacenciesBuildStrategy() const
virtual bool _markCellForRefinement(long id)
std::vector< long > getInternalCellsByPID(int pid)
void displayVertices(std::ostream &out, unsigned int padding=0) const
int getVertexOwner(long id) const
InterfaceIterator restoreInterface(ElementType type, std::unique_ptr< long[]> &&connectStorage, long id)
std::unordered_map< id_t, id_t > consecutiveItemRenumbering(PiercedVector< item_t, id_t > &container, long offset)
virtual void _findCellEdgeNeighs(long id, int edge, const std::vector< long > *blackList, std::vector< long > *neighs) const
void markCellForRefinement(long id)
std::vector< long > findVertexOneRing(long vertexId) const
virtual std::array< double, 3 > evalInterfaceCentroid(long id) const
void setCellAutoIndexing(bool enabled)
virtual long getInterfaceCount() const
std::vector< adaption::Info > update(bool trackAdaption=true, bool squeezeStorage=false)
InterfaceIterator interfaceBegin()
PiercedVector< Cell > & getCells()
std::vector< long > findOrphanInterfaces() const
bool testAlterationFlags(AlterationFlags availableFlags, AlterationFlags requestedFlags) const
VertexConstIterator vertexConstEnd() const
void dumpVertices(std::ostream &stream) const
virtual void _writeFinalize()
InterfaceIterator interfaceEnd()
Interface & getInterface(long id)
PatchKernel(PatchKernel &&other)
virtual void _resetInterfaces(bool release)
VertexIterator restoreVertex(const std::array< double, 3 > &coords, int owner, long id)
AdaptionMode getAdaptionMode() const
CellIterator restoreCell(ElementType type, std::unique_ptr< long[]> &&connectStorage, int owner, int haloLayer, long id)
void setExpert(bool expert)
long countBorderInterfaces() const
InterfaceIterator addInterface(const Interface &source, long id=Element::NULL_ID)
void dumpCells(std::ostream &stream) const
void setBoundingBoxDirty(bool dirty)
CellConstIterator internalCellConstBegin() const
bool isVertexAutoIndexingEnabled() const
virtual void _writePrepare()
VertexIterator vertexBegin()
InterfaceConstIterator interfaceConstEnd() const
InterfaceConstIterator interfaceConstBegin() const
std::vector< long > collapseCoincidentVertices()
void consecutiveRenumberInterfaces(long offset=0)
bool isCellAutoIndexingEnabled() const
VertexConstIterator vertexConstBegin() const
WriteTarget getVTKWriteTarget() const
virtual long getVertexCount() const
long countOrphanInterfaces() const
virtual void evalCellBoundingBox(long id, std::array< double, 3 > *minPoint, std::array< double, 3 > *maxPoint) const
void restoreCells(std::istream &stream)
virtual void _findCellFaceNeighs(long id, int face, const std::vector< long > *blackList, std::vector< long > *neighs) const
void addPointToBoundingBox(const std::array< double, 3 > &point)
std::vector< long > findDuplicateCells() const
virtual ElementType getInterfaceType(long id) const
VertexIterator addVertex(const Vertex &source, long id=Vertex::NULL_ID)
bool empty(bool global=true) const
std::vector< long > findCellNeighs(long id) const
bool deleteVertex(long id)
void getBoundingBox(std::array< double, 3 > &minPoint, std::array< double, 3 > &maxPoint) const
std::vector< adaption::Info > adaptionPrepare(bool trackAdaption=true)
adaption::Marker getCellAdaptionMarker(long id)
VTKUnstructuredGrid & getVTK()
std::unordered_map< long, std::vector< long > > binGroupVertices(const PiercedVector< Vertex > &vertices, int nBins)
void setBoundingBoxFrozen(bool frozen)
virtual bool isSameFace(const Cell &cell_A, int face_A, const Cell &cell_B, int face_B) const
Cell & getCell(long id)
const CellConstRange getVTKCellWriteRange() const
virtual bool _resetCellAdaptionMarker(long id)
void consecutiveRenumberCells(long offset=0)
virtual void simulateCellUpdate(const long id, adaption::Marker marker, std::vector< Cell > *virtualCells, PiercedVector< Vertex, long > *virtualVertices) const
void setVertexAutoIndexing(bool enabled)
VertexIterator getVertexIterator(long id)
VertexConstIterator getVertexConstIterator(long id) const
PiercedVector< Vertex > & getVertices()
virtual bool _markCellForCoarsening(long id)
std::vector< long > findCellFaceNeighs(long id) const
virtual void _setTol(double tolerance)
bool deleteVertices(const IdStorage &ids)
long locatePoint(double x, double y, double z) const
InterfaceConstIterator getInterfaceConstIterator(long id) const
void flushData(std::fstream &stream, const std::string &name, VTKFormat format) override
virtual adaption::Marker _getCellAdaptionMarker(long id)
CellIterator addCell(const Cell &source, long id=Element::NULL_ID)
void evalElementBoundingBox(const Element &element, std::array< double, 3 > *minPoint, std::array< double, 3 > *maxPoint) const
void resetCellAlterationFlags(long id, AlterationFlags flags=FLAG_NONE)
void updateInterfaces(bool forcedUpdated=false)
void displayTopologyStats(std::ostream &out, unsigned int padding=0) const
virtual void rotate(const std::array< double, 3 > &n0, const std::array< double, 3 > &n1, double angle)
CellIterator cellEnd()
ConstProxyVector< std::array< double BITPIT_COMMA 3 > > getElementVertexCoordinates(const Element &element) const
long countBorderCells() const
void setTol(double tolerance)
CellConstIterator cellConstEnd() const
AlterationFlags getCellAlterationFlags(long id) const
void scale(const std::array< double, 3 > &scaling)
virtual void setDimension(int dimension)
void markCellForCoarsening(long id)
void restoreVertices(std::istream &stream)
virtual void translate(const std::array< double, 3 > &translation)
VertexConstIterator internalVertexConstEnd() const
bool arePartitioningInfoDirty(bool global=true) const
void setInterfaceAutoIndexing(bool enabled)
void setAdaptionStatus(AdaptionStatus status)
bool isInterfaceAutoIndexingEnabled() const
PatchKernel & operator=(PatchKernel &&other)
void setAdjacenciesBuildStrategy(AdjacenciesBuildStrategy status)
VertexIterator internalVertexEnd()
bool reserveInterfaces(size_t nInterfaces)
long countDuplicateCells() const
bool areInterfacesDirty(bool global=false) const
void setInterfacesBuildStrategy(InterfacesBuildStrategy status)
const MPI_Comm & getCommunicator() const
void updateBoundingBox(bool forcedUpdated=false)
void restore(std::istream &stream, bool reregister=false)
virtual void resetVertices()
virtual int findAdjoinNeighFace(const Cell &cell, int cellFace, const Cell &neigh) const
virtual void resetInterfaces()
long countFreeVertices() const
virtual void reset()
long countFreeCells() const
virtual void _updateAdjacencies()
void initializeInterfaces(InterfacesBuildStrategy strategy=INTERFACES_AUTOMATIC)
CellIterator internalEnd()
void enableCellBalancing(long id, bool enabled)
virtual void _resetAdjacencies(bool release)
void setVTKWriteTarget(WriteTarget targetCells)
void displayCells(std::ostream &out, unsigned int padding=0) const
bool testInterfaceAlterationFlags(long id, AlterationFlags flags) const
Vertex & getVertex(long id)
std::set< int > getInternalCellPIDs()
long countOrphanVertices() const
void restoreInterfaces(std::istream &stream)
virtual long getCellCount() const
void unsetInterfaceAlterationFlags(AlterationFlags flags)
virtual void _adaptionCleanup()
bool isBoundingBoxFrozen() const
void removePointFromBoundingBox(const std::array< double, 3 > &point)
void resetCellAdaptionMarker(long id)
std::vector< long > findCellVertexNeighs(long id, bool complete=true) const
void setAdaptionMode(AdaptionMode mode)
bool deleteCell(long id)
virtual void _resetTol()
int getCellHaloLayer(long id) const
bool deleteInterface(long id)
virtual void _findCellNeighs(long id, const std::vector< long > *blackList, std::vector< long > *neighs) const
const std::array< double, 3 > & getVertexCoords(long id) const
virtual long _getCellNativeIndex(long id) const
long countOrphanCells() const
bool dump(std::ostream &stream)
void write(VTKWriteMode mode=VTKWriteMode::DEFAULT)
virtual void _updateInterfaces()
virtual void evalInterfaceBoundingBox(long id, std::array< double, 3 > *minPoint, std::array< double, 3 > *maxPoint) const
void updateAdjacencies(bool forcedUpdated=false)
ConstProxyVector< std::array< double BITPIT_COMMA 3 > > getInterfaceVertexCoordinates(long id) const
bool areAdjacenciesDirty(bool global=false) const
virtual void settleAdaptionMarkers()
VertexConstIterator internalVertexConstBegin() const
long countBorderVertices() const
InterfaceIterator getInterfaceIterator(long id)
AdaptionStatus getAdaptionStatus(bool global=false) const
long getInternalCount() const
bool isDirty(bool global=false) const
std::vector< long > findCellEdgeNeighs(long id, bool complete=true) const
VertexIterator internalVertexBegin()
long countFreeInterfaces() const
bool isTolCustomized() const
CellConstIterator internalConstEnd() const
void consecutiveRenumberVertices(long offset=0)
void extractEnvelope(PatchKernel &envelope) const
long getInternalCellCount() const
std::vector< long > findOrphanCells() const
void displayInterfaces(std::ostream &out, unsigned int padding=0) const
bool isInterfaceOrphan(long id) const
std::vector< adaption::Info > adaption(bool trackAdaption=true, bool squeezeStorage=false)
virtual std::vector< adaption::Info > _adaptionPrepare(bool trackAdaption)
PiercedVector< Interface > & getInterfaces()
virtual ElementType getCellType(long id) const
void setInterfaceAlterationFlags(AlterationFlags flags)
bool testCellAlterationFlags(long id, AlterationFlags flags) const
long getInternalVertexCount() const
long countBorderFaces() const
bool findFaceNeighCell(long cellId, long neighId, int *cellFace, int *cellAdjacencyId) const
void consecutiveRenumber(long offsetVertices, long offsetCells, long offsetInterfaces)
virtual std::vector< adaption::Info > _adaptionAlter(bool trackAdaption)
double getTol() const
std::array< double, 3 > evalElementCentroid(const Element &element) const
virtual std::array< double, 3 > evalCellCentroid(long id) const
std::vector< long > findOrphanVertices()
bool reserveCells(size_t nCells)
AlterationFlags getInterfaceAlterationFlags(long id) const
bool isBoundingBoxDirty(bool global=false) const
void resetInterfaceAlterationFlags(long id, AlterationFlags flags=FLAG_NONE)
void setCellAlterationFlags(AlterationFlags flags)
bool reserveVertices(size_t nVertices)
void setBoundingBox(const std::array< double, 3 > &minPoint, const std::array< double, 3 > &maxPoint)
long countFreeFaces() const
std::vector< long > findCellVertexOneRing(long id, int vertex) const
CellIterator internalCellEnd()
bool isAdaptionSupported() const
CellConstIterator getCellConstIterator(long id) const
ConstProxyVector< std::array< double BITPIT_COMMA 3 > > getCellVertexCoordinates(long id) const
virtual void resetCells()
int getCellOwner(long id) const
std::vector< adaption::Info > adaptionAlter(bool trackAdaption=true, bool squeezeStorage=false)
virtual void _findCellVertexNeighs(long id, int vertex, const std::vector< long > *blackList, std::vector< long > *neighs) const
bool isThreeDimensional() const
bool deleteInterfaces(const IdStorage &ids)
Numbering information about the patch.
long getCellGlobalId(long id) const
id_t getId(const id_t &fallback=-1) const noexcept
Iterator for the class PiercedStorage.
The PiercedStorageRange allow to iterate using range-based loops over a PiercedStorage.
void setStaticKernel(const PiercedKernel< id_t > *kernel)
void unsetKernel(bool release=true)
Metafunction for generating a pierced storage.
__PS_REFERENCE__ at(id_t id, std::size_t k=0)
__PS_REFERENCE__ rawAt(std::size_t pos, std::size_t offset=0)
void fill(const value_t &value)
Metafunction for generating a pierced vector.
PiercedVectorStorage< value_t, id_t >::iterator iterator
Metafunction for generating a list of elements that can be either stored in an external vectror or,...
std::size_t size() const
__PXV_POINTER__ data() noexcept
__PXV_STORAGE_POINTER__ storedData() noexcept
The QualifiedCellHalfFace class defines cell half-faces.
Definition cell.hpp:137
QualifiedCell & getCell() const
Definition cell.tpp:94
The ReferenceElementInfo class allows to define information about reference elements.
static bool hasInfo(ElementType type)
static BITPIT_PUBLIC_API const ReferenceElementInfo & getInfo(ElementType type)
The base class to be used to derive VTK streamers form.
Definition VTK.hpp:209
void flushValue(std::fstream &, VTKFormat, const T &value) const
VTKField handles geometry and data field information for the VTK format.
Definition VTK.hpp:247
const std::string & getName() const
Definition VTKField.cpp:167
const VTKBaseStreamer & getStreamer() const
Definition VTKField.cpp:233
VTK input output for Unstructured Meshes.
Definition VTK.hpp:433
void setDimensions(uint64_t, uint64_t, uint64_t nconn=0, uint64_t nfacestream=0)
void setGeomData(VTKUnstructuredField, std::vector< T > &)
Definition VTK.tpp:94
const VTKField * findGeomData(const std::string &name) const
Definition VTK.cpp:506
std::size_t getDataCount() const
Definition VTK.cpp:454
VTKField & addData(VTKField &&field)
Definition VTK.cpp:281
const VTKField * findData(const std::string &name) const
Definition VTK.cpp:474
std::vector< VTKField >::const_iterator getDataEnd() const
Definition VTK.cpp:427
void removeData(const std::string &)
Definition VTK.cpp:330
std::string getName() const
Definition VTK.cpp:139
void setName(const std::string &)
Definition VTK.cpp:119
std::vector< VTKField >::const_iterator getDataBegin() const
Definition VTK.cpp:418
std::vector< VTKField >::const_iterator getGeomDataBegin() const
Definition VTK.cpp:436
std::vector< VTKField >::const_iterator getGeomDataEnd() const
Definition VTK.cpp:445
std::size_t getGeomDataCount() const
Definition VTK.cpp:463
void write(VTKWriteMode writeMode, double time)
Definition VTK.cpp:704
The Vertex class defines the vertexs.
Definition vertex.hpp:42
void translate(const std::array< double, 3 > &translation)
Definition vertex.cpp:266
void display(std::ostream &out, unsigned short int indent) const
Definition vertex.cpp:351
long getId() const
Definition vertex.cpp:226
void scale(const std::array< double, 3 > &scaling, const std::array< double, 3 > &center)
Definition vertex.cpp:321
void rotate(const std::array< double, 3 > &n0, const std::array< double, 3 > &n1, double angle)
Definition vertex.cpp:293
void setId(long id)
Definition vertex.cpp:216
std::array< double, 3 > & getCoords()
Definition vertex.cpp:246
bool isInterior() const
Definition vertex.cpp:166
array3D rotatePoint(const array3D &P, const array3D &n0, const array3D &n1, double angle)
Definition CG_elem.cpp:892
VTKFormat
Definition VTK.hpp:92
VTKElementType
Definition VTK.hpp:112
VTKWriteMode
Definition VTK.hpp:49
void write(std::ostream &stream, const std::vector< bool > &container)
void read(std::istream &stream, std::vector< bool > &container)
#define BITPIT_UNUSED(variable)
Definition compiler.hpp:63
#define BITPIT_CREATE_WORKSPACE(workspace, item_type, size, stack_size)
Logger & cout(log::Level defaultSeverity, log::Visibility defaultVisibility)
Definition logger.cpp:1705
PatchManager & manager()
--- layout: doxygen_footer ---