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
50
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
602{
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> adaptionData;
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 adaptionData;
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), adaptionData);
644 }
645
646 return adaptionData;
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> adaptionData;
682
683 // Early return if adaption cannot be performed
684 AdaptionMode adaptionMode = getAdaptionMode();
685 if (adaptionMode == ADAPTION_DISABLED) {
686 return adaptionData;
687 }
688
689 AdaptionStatus adaptionStatus = getAdaptionStatus(true);
690 if (adaptionStatus == ADAPTION_CLEAN) {
691 return adaptionData;
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 adaptionData = adaptionAlter(trackAdaption, squeezeStorage);
700
702
703 return adaptionData;
704}
705
719std::vector<adaption::Info> PatchKernel::adaptionPrepare(bool trackAdaption)
720{
721 std::vector<adaption::Info> adaptionData;
722
723 // Early return if adaption cannot be performed
724 AdaptionMode adaptionMode = getAdaptionMode();
725 if (adaptionMode == ADAPTION_DISABLED) {
726 return adaptionData;
727 }
728
729 AdaptionStatus adaptionStatus = getAdaptionStatus(true);
730 if (adaptionStatus == ADAPTION_CLEAN) {
731 return adaptionData;
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 adaptionData = _adaptionPrepare(trackAdaption);
738
739 // Update the status
740 setAdaptionStatus(ADAPTION_PREPARED);
741
742 return adaptionData;
743}
744
760std::vector<adaption::Info> PatchKernel::adaptionAlter(bool trackAdaption, bool squeezeStorage)
761{
762 std::vector<adaption::Info> adaptionData;
763
764 // Early return if adaption cannot be performed
765 AdaptionMode adaptionMode = getAdaptionMode();
766 if (adaptionMode == ADAPTION_DISABLED) {
767 return adaptionData;
768 }
769
770 AdaptionStatus adaptionStatus = getAdaptionStatus();
771 if (adaptionStatus == ADAPTION_CLEAN) {
772 return adaptionData;
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 adaptionData = _adaptionAlter(trackAdaption);
779
780 // Finalize patch alterations
781 finalizeAlterations(squeezeStorage);
782
783 // Update the status
784 setAdaptionStatus(ADAPTION_ALTERED);
785
786 return adaptionData;
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 // Reset the interfaces
1038 _resetInterfaces(false);
1039
1040 // Mark cell interfaces as dirty
1041 setCellAlterationFlags(FLAG_INTERFACES_DIRTY);
1042
1043 // Clear list of altered interfaces
1044 m_alteredInterfaces.clear();
1045}
1046
1057{
1058 for (auto &cell : m_cells) {
1059 cell.resetInterfaces(!release);
1060 }
1061
1062 m_interfaces.clear(release);
1063 if (m_interfaceIdGenerator) {
1064 m_interfaceIdGenerator->reset();
1065 }
1066}
1067
1081bool PatchKernel::reserveVertices(size_t nVertices)
1082{
1084 return false;
1085 }
1086
1087 m_vertices.reserve(nVertices);
1088
1089 return true;
1090}
1091
1104bool PatchKernel::reserveCells(size_t nCells)
1105{
1107 return false;
1108 }
1109
1110 m_cells.reserve(nCells);
1111
1112 return true;
1113}
1114
1129bool PatchKernel::reserveInterfaces(size_t nInterfaces)
1130{
1132 return false;
1133 }
1134
1135 m_interfaces.reserve(nInterfaces);
1136
1137 return true;
1138}
1139
1146void PatchKernel::write(const std::string &filename, VTKWriteMode mode)
1147{
1148 std::string oldFilename = m_vtk.getName();
1149
1150 m_vtk.setName(filename);
1151 write(mode);
1152 m_vtk.setName(oldFilename);
1153}
1154
1162void PatchKernel::write(const std::string &filename, VTKWriteMode mode, double time)
1163{
1164 std::string oldFilename = m_vtk.getName();
1165
1166 m_vtk.setName(filename);
1167 write(mode, time);
1168 m_vtk.setName(oldFilename);
1169}
1170
1177{
1178 _writePrepare();
1179
1180 m_vtk.write(mode);
1181
1183}
1184
1191void PatchKernel::write(VTKWriteMode mode, double time)
1192{
1193 _writePrepare();
1194
1195 m_vtk.write(mode, time);
1196
1198}
1199
1204{
1205 // Get VTK cell count
1206 long vtkCellCount = 0;
1207 if (m_vtkWriteTarget == WRITE_TARGET_CELLS_ALL) {
1208 vtkCellCount = getCellCount();
1209#if BITPIT_ENABLE_MPI==1
1210 } else if (m_vtkWriteTarget == WRITE_TARGET_CELLS_INTERNAL) {
1211 vtkCellCount = getInternalCellCount();
1212#endif
1213 }
1214
1215 // Set the dimensions of the mesh
1216 //
1217 // Even if there is just a single process that needs to write the VTK face stream, than
1218 // all the processes need to write the face stream as well (even the processes whose
1219 // local cells don't require the face steam).
1220 PiercedStorage<bool, long> vertexWriteFlag(1, &m_vertices);
1221 vertexWriteFlag.fill(false);
1222
1223 bool vtkFaceStreamNeeded = false;
1224 for (const Cell &cell : m_cells) {
1225 if (cell.getDimension() > 2 && !cell.hasInfo()) {
1226 vtkFaceStreamNeeded = true;
1227 break;
1228 }
1229 }
1230
1231#if BITPIT_ENABLE_MPI==1
1232 if (isPartitioned()) {
1233 const auto &communicator = getCommunicator();
1234 MPI_Allreduce(MPI_IN_PLACE, &vtkFaceStreamNeeded, 1, MPI_C_BOOL, MPI_LOR, communicator);
1235 }
1236#endif
1237
1238 long vtkConnectSize = 0;
1239 long vtkFaceStreamSize = 0;
1240 for (const Cell &cell : getVTKCellWriteRange()) {
1241 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
1242 const int nCellVertices = cellVertexIds.size();
1243 for (int k = 0; k < nCellVertices; ++k) {
1244 long vertexId = cellVertexIds[k];
1245 vertexWriteFlag.at(vertexId) = true;
1246 }
1247
1248 vtkConnectSize += nCellVertices;
1249 if (vtkFaceStreamNeeded) {
1250 if (cell.getDimension() <= 2 || cell.hasInfo()) {
1251 vtkFaceStreamSize += 1;
1252 } else {
1253 vtkFaceStreamSize += cell.getFaceStreamSize();
1254 }
1255 }
1256 }
1257
1258 int vtkVertexCount = 0;
1259 m_vtkVertexMap.unsetKernel();
1260 m_vtkVertexMap.setStaticKernel(&m_vertices);
1261 VertexConstIterator endItr = vertexConstEnd();
1262 for (VertexConstIterator itr = vertexConstBegin(); itr != endItr; ++itr) {
1263 std::size_t vertexRawId = itr.getRawIndex();
1264 if (vertexWriteFlag.rawAt(vertexRawId)) {
1265 m_vtkVertexMap.rawAt(vertexRawId) = vtkVertexCount++;
1266 } else {
1267 m_vtkVertexMap.rawAt(vertexRawId) = Vertex::NULL_ID;
1268 }
1269 }
1270
1271 m_vtk.setDimensions(vtkCellCount, vtkVertexCount, vtkConnectSize, vtkFaceStreamSize);
1272}
1273
1278{
1279 // Nothing to do
1280}
1281
1288{
1289 return (getAdaptionMode() != ADAPTION_DISABLED);
1290}
1291
1310{
1311 return m_adaptionMode;
1312}
1313
1322{
1323 m_adaptionMode = mode;
1324}
1325
1336{
1337 int adaptionStatus = static_cast<int>(m_adaptionStatus);
1338
1339#if BITPIT_ENABLE_MPI==1
1340 if (global && isPartitioned()) {
1341 const auto &communicator = getCommunicator();
1342 MPI_Allreduce(MPI_IN_PLACE, &adaptionStatus, 1, MPI_INT, MPI_MAX, communicator);
1343 }
1344#else
1345 BITPIT_UNUSED(global);
1346#endif
1347
1348 return static_cast<AdaptionStatus>(adaptionStatus);
1349}
1350
1357{
1358 m_adaptionStatus = status;
1359}
1360
1369bool PatchKernel::isDirty(bool global) const
1370{
1371#if BITPIT_ENABLE_MPI==0
1372 BITPIT_UNUSED(global);
1373#endif
1374
1375 bool isDirty = false;
1376
1377 if (!isDirty) {
1378 isDirty |= areAdjacenciesDirty(false);
1379 }
1380
1381 if (!isDirty) {
1382 isDirty |= !m_alteredCells.empty();
1383 }
1384
1385 if (!isDirty) {
1386 isDirty |= areInterfacesDirty(false);
1387 assert(isDirty || m_alteredInterfaces.empty());
1388 }
1389
1390 if (!isDirty) {
1391 isDirty |= (getAdaptionStatus(false) == ADAPTION_DIRTY);
1392 }
1393
1394 if (!isDirty) {
1395 isDirty |= isBoundingBoxDirty(false);
1396 }
1397
1398#if BITPIT_ENABLE_MPI==1
1399 if (!isDirty) {
1401 }
1402#endif
1403
1404 if (!isDirty) {
1405 isDirty |= !m_vertices.isSynced();
1406 }
1407
1408 if (!isDirty) {
1409 isDirty |= !m_cells.isSynced();
1410 }
1411
1412 if (!isDirty) {
1413 isDirty |= !m_interfaces.isSynced();
1414 }
1415
1416#if BITPIT_ENABLE_MPI==1
1417 // Get the global flag
1418 if (global && isPartitioned()) {
1419 const auto &communicator = getCommunicator();
1420 MPI_Allreduce(MPI_IN_PLACE, &isDirty, 1, MPI_C_BOOL, MPI_LOR, communicator);
1421 }
1422#endif
1423
1424 return isDirty;
1425}
1426
1436void PatchKernel::setExpert(bool expert)
1437{
1438 static AdaptionMode initialAdaptionMode;
1439 if (!expert) {
1440 initialAdaptionMode = m_adaptionMode;
1441 m_adaptionMode = ADAPTION_MANUAL;
1442 } else {
1443 m_adaptionMode = initialAdaptionMode;
1444 }
1445}
1446
1458{
1459 return (m_adaptionMode == ADAPTION_MANUAL);
1460}
1461
1468{
1469 if (id == m_id) {
1470 return;
1471 }
1472
1473 patch::manager().unregisterPatch(this);
1474 patch::manager().registerPatch(this, id);
1475}
1476
1482void PatchKernel::_setId(int id)
1483{
1484 m_id = id;
1485}
1486
1493{
1494 return m_id;
1495}
1496
1502void PatchKernel::setDimension(int dimension)
1503{
1504 if (dimension == m_dimension) {
1505 return;
1506 }
1507
1508 // If the dimension was already assigned, reset the patch
1509 if (m_dimension > 0) {
1510 reset();
1511 }
1512
1513 // Set the dimension
1514 m_dimension = dimension;
1515}
1516
1523{
1524 return m_dimension;
1525}
1526
1533{
1534 return (m_dimension == 3);
1535}
1536
1546{
1547 return static_cast<bool>(m_vertexIdGenerator);
1548}
1549
1559{
1560 if (isVertexAutoIndexingEnabled() == enabled) {
1561 return;
1562 }
1563
1564 if (enabled) {
1565 createVertexIndexGenerator(true);
1566 } else {
1567 m_vertexIdGenerator.reset();
1568 }
1569}
1570
1576void PatchKernel::dumpVertexAutoIndexing(std::ostream &stream) const
1577{
1578 m_vertexIdGenerator->dump(stream);
1579}
1580
1586void PatchKernel::restoreVertexAutoIndexing(std::istream &stream)
1587{
1588 createVertexIndexGenerator(false);
1589 m_vertexIdGenerator->restore(stream);
1590}
1591
1600void PatchKernel::createVertexIndexGenerator(bool populate)
1601{
1602 // Create or reset index generator
1603 if (!m_vertexIdGenerator) {
1604 m_vertexIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>());
1605 } else {
1606 m_vertexIdGenerator->reset();
1607 }
1608
1609 // Populate index generator with current ids
1610 if (populate) {
1611 VertexConstIterator beginItr = m_vertices.cbegin();
1612 VertexConstIterator endItr = m_vertices.cend();
1613 for (VertexConstIterator itr = beginItr; itr != endItr; ++itr) {
1614 m_vertexIdGenerator->setAssigned(itr.getId());
1615 }
1616 }
1617}
1618
1627void PatchKernel::importVertexIndexGenerator(const PatchKernel &source)
1628{
1629 if (source.m_vertexIdGenerator) {
1630 m_vertexIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>(*(source.m_vertexIdGenerator)));
1631 } else {
1632 m_vertexIdGenerator.reset();
1633 }
1634}
1635
1642{
1643 return m_vertices.size();
1644}
1645
1652{
1653 return m_nInternalVertices;
1654}
1655
1662{
1663 return m_vertices;
1664}
1665
1672{
1673 return m_vertices;
1674}
1675
1683{
1684 return m_vertices[id];
1685}
1686
1693const Vertex & PatchKernel::getVertex(long id) const
1694{
1695 return m_vertices[id];
1696}
1697
1704{
1705 return m_vertices[m_lastInternalVertexId];
1706}
1707
1714{
1715 return m_vertices[m_lastInternalVertexId];
1716}
1717
1723PatchKernel::VertexIterator PatchKernel::getVertexIterator(long id)
1724{
1725 return m_vertices.find(id);
1726}
1727
1733PatchKernel::VertexIterator PatchKernel::vertexBegin()
1734{
1735 return m_vertices.begin();
1736}
1737
1743PatchKernel::VertexIterator PatchKernel::vertexEnd()
1744{
1745 return m_vertices.end();
1746}
1747
1753PatchKernel::VertexIterator PatchKernel::internalVertexBegin()
1754{
1755 return m_vertices.begin();
1756}
1757
1763PatchKernel::VertexIterator PatchKernel::internalVertexEnd()
1764{
1765 if (m_nInternalVertices > 0) {
1766 return ++m_vertices.find(m_lastInternalVertexId);
1767 } else {
1768 return m_vertices.end();
1769 }
1770}
1771
1777PatchKernel::VertexConstIterator PatchKernel::getVertexConstIterator(long id) const
1778{
1779 return m_vertices.find(id);
1780}
1781
1787PatchKernel::VertexConstIterator PatchKernel::vertexConstBegin() const
1788{
1789 return m_vertices.cbegin();
1790}
1791
1797PatchKernel::VertexConstIterator PatchKernel::vertexConstEnd() const
1798{
1799 return m_vertices.cend();
1800}
1801
1807PatchKernel::VertexConstIterator PatchKernel::internalVertexConstBegin() const
1808{
1809 return m_vertices.cbegin();
1810}
1811
1817PatchKernel::VertexConstIterator PatchKernel::internalVertexConstEnd() const
1818{
1819 if (m_nInternalVertices > 0) {
1820 return ++m_vertices.find(m_lastInternalVertexId);
1821 } else {
1822 return m_vertices.end();
1823 }
1824}
1825
1844PatchKernel::VertexIterator PatchKernel::addVertex(const Vertex &source, long id)
1845{
1846 Vertex vertex = source;
1847 vertex.setId(id);
1848
1849 return addVertex(std::move(vertex), id);
1850}
1851
1869PatchKernel::VertexIterator PatchKernel::addVertex(Vertex &&source, long id)
1870{
1871 // Get the id
1872 if (id < 0) {
1873 id = source.getId();
1874 }
1875
1876 // Add a dummy vertex
1877 //
1878 // It is not possible to directly add the source into the storage. First a
1879 // dummy vertex is created and then that vertex is replaced with the source.
1880 //
1881 // The corrdinates of the dummy vertex shuold match the coordinates of the
1882 // source, because the bounding box of the patch is updated every time a
1883 // new vertex is added.
1884 VertexIterator iterator = _addInternalVertex(source.getCoords(), id);
1885
1886 // Replace the newly created vertex with the source
1887 //
1888 // Before replacing the newly created vertex we need to set the id
1889 // of the source to the id that has been assigned to the newly created
1890 // vertex, we also need to mark the vertex as internal.
1891 source.setId(iterator->getId());
1892 source.setInterior(true);
1893
1894 Vertex &vertex = (*iterator);
1895 vertex = std::move(source);
1896
1897 return iterator;
1898}
1899
1918PatchKernel::VertexIterator PatchKernel::addVertex(const std::array<double, 3> &coords, long id)
1919{
1921 return vertexEnd();
1922 }
1923
1924 // Add the vertex
1925 VertexIterator iterator = _addInternalVertex(coords, id);
1926
1927 return iterator;
1928}
1929
1944PatchKernel::VertexIterator PatchKernel::_addInternalVertex(const std::array<double, 3> &coords, long id)
1945{
1946 // Get the id
1947 if (m_vertexIdGenerator) {
1948 if (id < 0) {
1949 id = m_vertexIdGenerator->generate();
1950 } else {
1951 m_vertexIdGenerator->setAssigned(id);
1952 }
1953 } else if (id < 0) {
1954 throw std::runtime_error("No valid id has been provided for the vertex.");
1955 }
1956
1957 // Get the id of the vertex before which the new vertex should be inserted
1958#if BITPIT_ENABLE_MPI==1
1959 //
1960 // If there are ghosts vertices, the internal vertex should be inserted
1961 // before the first ghost vertex.
1962#endif
1963 long referenceId;
1964#if BITPIT_ENABLE_MPI==1
1965 referenceId = m_firstGhostVertexId;
1966#else
1967 referenceId = Vertex::NULL_ID;
1968#endif
1969
1970 // Create the vertex
1971 VertexIterator iterator;
1972 if (referenceId == Vertex::NULL_ID) {
1973 iterator = m_vertices.emreclaim(id, id, coords, true);
1974 } else {
1975 iterator = m_vertices.emreclaimBefore(referenceId, id, id, coords, true);
1976 }
1977 m_nInternalVertices++;
1978
1979 // Update the id of the last internal vertex
1980 if (m_lastInternalVertexId < 0) {
1981 m_lastInternalVertexId = id;
1982 } else if (m_vertices.rawIndex(m_lastInternalVertexId) < m_vertices.rawIndex(id)) {
1983 m_lastInternalVertexId = id;
1984 }
1985
1986 // Update the bounding box
1987 addPointToBoundingBox(iterator->getCoords());
1988
1989#if BITPIT_ENABLE_MPI==1
1990 // Set partitioning information as dirty
1991 setPartitioningInfoDirty(true);
1992#endif
1993
1994 return iterator;
1995}
1996
1997#if BITPIT_ENABLE_MPI==0
2008PatchKernel::VertexIterator PatchKernel::restoreVertex(const std::array<double, 3> &coords, long id)
2009{
2011 return vertexEnd();
2012 }
2013
2014 VertexIterator iterator = m_vertices.find(id);
2015 if (iterator == m_vertices.end()) {
2016 throw std::runtime_error("Unable to restore the specified vertex: the kernel doesn't contain an entry for that vertex.");
2017 }
2018
2019 _restoreInternalVertex(iterator, coords);
2020
2021 return iterator;
2022}
2023#endif
2024
2031void PatchKernel::_restoreInternalVertex(const VertexIterator &iterator, const std::array<double, 3> &coords)
2032{
2033 // Restore the vertex
2034 //
2035 // There is no need to set the id of the vertex as assigned, because
2036 // also the index generator will be restored.
2037 Vertex &vertex = *iterator;
2038 vertex.initialize(iterator.getId(), coords, true);
2039 m_nInternalVertices++;
2040
2041 // Update the bounding box
2042 addPointToBoundingBox(vertex.getCoords());
2043}
2044
2051{
2053 return false;
2054 }
2055
2056 // Delete the vertex
2057#if BITPIT_ENABLE_MPI==1
2058 const Vertex &vertex = m_vertices[id];
2059 bool isInternal = vertex.isInterior();
2060 if (isInternal) {
2061 _deleteInternalVertex(id);
2062 } else {
2063 _deleteGhostVertex(id);
2064 }
2065#else
2066 _deleteInternalVertex(id);
2067#endif
2068
2069 return true;
2070}
2071
2077void PatchKernel::_deleteInternalVertex(long id)
2078{
2079 // Update the bounding box
2080 const Vertex &vertex = m_vertices[id];
2082
2083 // Delete vertex
2084 m_vertices.erase(id, true);
2085 m_nInternalVertices--;
2086 if (id == m_lastInternalVertexId) {
2088 }
2089
2090 // Vertex id is no longer used
2091 if (m_vertexIdGenerator) {
2092 m_vertexIdGenerator->trash(id);
2093 }
2094}
2095
2104{
2105 return countBorderVertices();
2106}
2107
2116{
2117 std::unordered_set<long> borderVertices;
2118 for (const Cell &cell : m_cells) {
2119 int nCellFaces = cell.getFaceCount();
2120 for (int i = 0; i < nCellFaces; ++i) {
2121 if (!cell.isFaceBorder(i)) {
2122 continue;
2123 }
2124
2125 int nFaceVertices = cell.getFaceVertexCount(i);
2126 for (int k = 0; k < nFaceVertices; ++k) {
2127 long faceVertexId = cell.getFaceVertexId(i, k);
2128 borderVertices.insert(faceVertexId);
2129 }
2130 }
2131 }
2132
2133 return borderVertices.size();
2134}
2135
2144{
2145 std::unordered_set<long> usedVertices;
2146 for (const Cell &cell : m_cells) {
2147 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
2148 int nCellVertices = cellVertexIds.size();
2149 for (int i = 0; i < nCellVertices; ++i) {
2150 usedVertices.insert(cellVertexIds[i]);
2151 }
2152 }
2153
2154 return (getVertexCount() - usedVertices.size());
2155}
2156
2165{
2166 VertexConstIterator beginItr = m_vertices.cbegin();
2167 VertexConstIterator endItr = m_vertices.cend();
2168
2169 // Detect used vertices
2170 PiercedStorage<bool, long> vertexUsedFlag(1, &m_vertices);
2171 vertexUsedFlag.fill(false);
2172 for (const Cell &cell : m_cells) {
2173 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
2174 int nCellVertices = cellVertexIds.size();
2175 for (int j = 0; j < nCellVertices; ++j) {
2176 long vertexId = cellVertexIds[j];
2177 vertexUsedFlag[vertexId] = true;
2178 }
2179 }
2180
2181 // Count the orphan vertices
2182 std::size_t nOrhpanVertices = 0;
2183 for (VertexConstIterator itr = beginItr; itr != endItr; ++itr) {
2184 std::size_t vertexRawIndex = itr.getRawIndex();
2185 if (!vertexUsedFlag.rawAt(vertexRawIndex)) {
2186 ++nOrhpanVertices;
2187 }
2188 }
2189
2190 // Build a list of unused vertices
2191 std::vector<long> orhpanVertices(nOrhpanVertices);
2192
2193 std::size_t orphanVertexIndex = 0;
2194 for (VertexConstIterator itr = beginItr; itr != endItr; ++itr) {
2195 std::size_t vertexRawIndex = itr.getRawIndex();
2196 if (!vertexUsedFlag.rawAt(vertexRawIndex)) {
2197 orhpanVertices[orphanVertexIndex] = itr.getId();
2198 ++orphanVertexIndex;
2199 }
2200 }
2201
2202 return orhpanVertices;
2203}
2204
2209{
2211 return false;
2212 }
2213
2214 std::vector<long> list = findOrphanVertices();
2215 deleteVertices(list);
2217
2218 return true;
2219}
2220
2228{
2229 std::vector<long> collapsedVertices;
2231 return collapsedVertices;
2232 }
2233
2234 long nVertices = getVertexCount();
2235 if (nVertices == 0) {
2236 return collapsedVertices;
2237 }
2238
2239 // Update bounding box
2241
2242 //
2243 // Collapse double vertices
2244 //
2245 Vertex::Less vertexLess(10 * std::numeric_limits<double>::epsilon());
2246 auto rawVertexLess = [this, &vertexLess](const std::size_t &i, const std::size_t &j)
2247 {
2248 return vertexLess(this->m_vertices.rawAt(i), this->m_vertices.rawAt(j));
2249 };
2250 std::set<std::size_t, decltype(rawVertexLess)> vertexTree(rawVertexLess);
2251
2252 std::unordered_map<long, long> vertexMap;
2253 for (VertexConstIterator vertexItr = m_vertices.cbegin(); vertexItr != m_vertices.cend(); ++vertexItr) {
2254 std::size_t vertexRawId = vertexItr.getRawIndex();
2255 auto vertexTreeItr = vertexTree.find(vertexRawId);
2256 if (vertexTreeItr == vertexTree.end()) {
2257 vertexTree.insert(vertexRawId);
2258 } else {
2259 long vertexId = vertexItr.getId();
2260 long vertexCoincidentId = m_vertices.rawFind(*vertexTreeItr).getId();
2261 vertexMap.insert({vertexId, vertexCoincidentId});
2262 }
2263 }
2264
2265 // Collapse vertices
2266 if (!vertexMap.empty()) {
2267 // Update cells
2268 //
2269 // If the adjacencies are currently up-to-date, they should kept up-to-date.
2270 AdjacenciesBuildStrategy adjacenciesBuildStrategy = getAdjacenciesBuildStrategy();
2271
2272 bool keepAdjacenciesUpToDate;
2273 if (adjacenciesBuildStrategy != ADJACENCIES_NONE) {
2274 keepAdjacenciesUpToDate = (!areAdjacenciesDirty());
2275 } else {
2276 keepAdjacenciesUpToDate = false;
2277 }
2278
2279 for (Cell &cell : m_cells) {
2280 // Renumber cell vertices
2281 int nRenumberedVertices = cell.renumberVertices(vertexMap);
2282
2283 // Mark adjacencies are dirty
2284 //
2285 // If some vertices have been renumbered, the adjacencies of the cells
2286 // are now dirty.
2287 if ((adjacenciesBuildStrategy != ADJACENCIES_NONE) && (nRenumberedVertices > 0)) {
2288 setCellAlterationFlags(cell.getId(), FLAG_ADJACENCIES_DIRTY);
2289 }
2290 }
2291
2292 if (keepAdjacenciesUpToDate) {
2294 }
2295
2296 // Update interface
2297 for (Interface &interface : m_interfaces) {
2298 // Renumber interface vertices
2299 interface.renumberVertices(vertexMap);
2300 }
2301
2302 // Create the list of collapsed vertices
2303 collapsedVertices.resize(vertexMap.size());
2304
2305 std::size_t k = 0;
2306 for (const auto &entry : vertexMap) {
2307 collapsedVertices[k++] = entry.first;
2308 }
2309 }
2310
2311 return collapsedVertices;
2312}
2313
2318{
2320 return false;
2321 }
2322
2323 std::vector<long> verticesToDelete = collapseCoincidentVertices();
2324 deleteVertices(verticesToDelete);
2325
2326 return true;
2327}
2328
2335const std::array<double, 3> & PatchKernel::getVertexCoords(long id) const
2336{
2337 return getVertex(id).getCoords();
2338}
2339
2347void PatchKernel::getVertexCoords(std::size_t nVertices, const long *ids, std::unique_ptr<std::array<double, 3>[]> *coordinates) const
2348{
2349 *coordinates = std::unique_ptr<std::array<double, 3>[]>(new std::array<double, 3>[nVertices]);
2350 getVertexCoords(nVertices, ids, coordinates->get());
2351}
2352
2362void PatchKernel::getVertexCoords(std::size_t nVertices, const long *ids, std::array<double, 3> *coordinates) const
2363{
2364 for (std::size_t i = 0; i < nVertices; ++i) {
2365 coordinates[i] = getVertex(ids[i]).getCoords();
2366 }
2367}
2368
2376bool PatchKernel::empty(bool global) const
2377{
2378 bool isEmpty = (getCellCount() == 0);
2379#if BITPIT_ENABLE_MPI==1
2380 if (global && isPartitioned()) {
2381 MPI_Allreduce(MPI_IN_PLACE, &isEmpty, 1, MPI_C_BOOL, MPI_LAND, getCommunicator());
2382 }
2383#else
2384 BITPIT_UNUSED(global);
2385#endif
2386
2387 return isEmpty;
2388}
2389
2394{
2395 if (m_nInternalVertices == 0) {
2396 m_lastInternalVertexId = Vertex::NULL_ID;
2397 return;
2398 }
2399
2400 VertexIterator lastInternalVertexItr;
2401#if BITPIT_ENABLE_MPI==1
2402 if (m_nGhostVertices == 0) {
2403 lastInternalVertexItr = --m_vertices.end();
2404 m_lastInternalVertexId = lastInternalVertexItr->getId();
2405 } else {
2406 m_lastInternalVertexId = m_vertices.getSizeMarker(m_nInternalVertices - 1, Vertex::NULL_ID);
2407 }
2408#else
2409 lastInternalVertexItr = --m_vertices.end();
2410 m_lastInternalVertexId = lastInternalVertexItr->getId();
2411#endif
2412}
2413
2423{
2424 return static_cast<bool>(m_cellIdGenerator);
2425}
2426
2436{
2437 if (isCellAutoIndexingEnabled() == enabled) {
2438 return;
2439 }
2440
2441 if (enabled) {
2442 createCellIndexGenerator(true);
2443 } else {
2444 m_cellIdGenerator.reset();
2445 }
2446}
2447
2453void PatchKernel::dumpCellAutoIndexing(std::ostream &stream) const
2454{
2455 m_cellIdGenerator->dump(stream);
2456}
2457
2463void PatchKernel::restoreCellAutoIndexing(std::istream &stream)
2464{
2465 createCellIndexGenerator(false);
2466 m_cellIdGenerator->restore(stream);
2467}
2468
2477void PatchKernel::createCellIndexGenerator(bool populate)
2478{
2479 // Create or reset index generator
2480 if (!m_cellIdGenerator) {
2481 m_cellIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>());
2482 } else {
2483 m_cellIdGenerator->reset();
2484 }
2485
2486 // Populate index generator with current ids
2487 if (populate) {
2488 CellConstIterator beginItr = m_cells.cbegin();
2489 CellConstIterator endItr = m_cells.cend();
2490 for (CellConstIterator itr = beginItr; itr != endItr; ++itr) {
2491 m_cellIdGenerator->setAssigned(itr.getId());
2492 }
2493 }
2494}
2495
2504void PatchKernel::importCellIndexGenerator(const PatchKernel &source)
2505{
2506 if (source.m_cellIdGenerator) {
2507 m_cellIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>(*(source.m_cellIdGenerator)));
2508 } else {
2509 m_cellIdGenerator.reset();
2510 }
2511}
2512
2519{
2520 return m_cells.size();
2521}
2522
2529{
2530 return m_nInternalCells;
2531}
2532
2539{
2540 return getInternalCellCount();
2541}
2542
2549{
2550 return m_cells;
2551}
2552
2559{
2560 return m_cells;
2561}
2562
2570{
2571 return m_cells[id];
2572}
2573
2580const Cell & PatchKernel::getCell(long id) const
2581{
2582 return m_cells[id];
2583}
2584
2592{
2593 return m_cells[id].getType();
2594}
2595
2602{
2603 return m_cells[m_lastInternalCellId];
2604}
2605
2612{
2613 return m_cells[m_lastInternalCellId];
2614}
2615
2621PatchKernel::CellIterator PatchKernel::getCellIterator(long id)
2622{
2623 return m_cells.find(id);
2624}
2625
2631PatchKernel::CellIterator PatchKernel::cellBegin()
2632{
2633 return m_cells.begin();
2634}
2635
2641PatchKernel::CellIterator PatchKernel::cellEnd()
2642{
2643 return m_cells.end();
2644}
2645
2651PatchKernel::CellIterator PatchKernel::internalCellBegin()
2652{
2653 return m_cells.begin();
2654}
2655
2661PatchKernel::CellIterator PatchKernel::internalBegin()
2662{
2663 return internalCellBegin();
2664}
2665
2671PatchKernel::CellIterator PatchKernel::internalCellEnd()
2672{
2673 if (m_nInternalCells > 0) {
2674 return ++m_cells.find(m_lastInternalCellId);
2675 } else {
2676 return m_cells.end();
2677 }
2678}
2679
2685PatchKernel::CellIterator PatchKernel::internalEnd()
2686{
2687 return internalCellEnd();
2688}
2689
2695PatchKernel::CellConstIterator PatchKernel::getCellConstIterator(long id) const
2696{
2697 return m_cells.find(id);
2698}
2699
2705PatchKernel::CellConstIterator PatchKernel::cellConstBegin() const
2706{
2707 return m_cells.cbegin();
2708}
2709
2715PatchKernel::CellConstIterator PatchKernel::cellConstEnd() const
2716{
2717 return m_cells.cend();
2718}
2719
2725PatchKernel::CellConstIterator PatchKernel::internalCellConstBegin() const
2726{
2727 return m_cells.cbegin();
2728}
2729
2735PatchKernel::CellConstIterator PatchKernel::internalConstBegin() const
2736{
2737 return internalCellConstBegin();
2738}
2739
2746PatchKernel::CellConstIterator PatchKernel::internalCellConstEnd() const
2747{
2748 if (m_nInternalCells > 0) {
2749 return ++m_cells.find(m_lastInternalCellId);
2750 } else {
2751 return m_cells.cend();
2752 }
2753}
2754
2761PatchKernel::CellConstIterator PatchKernel::internalConstEnd() const
2762{
2763 return internalCellConstEnd();
2764}
2765
2781PatchKernel::CellIterator PatchKernel::addCell(const Cell &source, long id)
2782{
2783 Cell cell = source;
2784 cell.setId(id);
2785
2786 return addCell(std::move(cell), id);
2787}
2788
2803PatchKernel::CellIterator PatchKernel::addCell(Cell &&source, long id)
2804{
2805 // Get the id
2806 if (id < 0) {
2807 id = source.getId();
2808 }
2809
2810 // Add a dummy cell
2811 //
2812 // It is not possible to directly add the source into the storage. First a
2813 // dummy cell is created and then that cell is replaced with the source.
2814 std::unique_ptr<long[]> dummyConnectStorage = std::unique_ptr<long[]>(nullptr);
2815
2816 CellIterator iterator = _addInternalCell(ElementType::UNDEFINED, std::move(dummyConnectStorage), id);
2817
2818 // Replace the newly created cell with the source
2819 //
2820 // Before replacing the newly created cell we need to set the id of the
2821 // source to the id that has been assigned to the newly created cell.
2822 source.setId(iterator->getId());
2823
2824 Cell &cell = (*iterator);
2825 cell = std::move(source);
2826
2827 return iterator;
2828}
2829
2845PatchKernel::CellIterator PatchKernel::addCell(ElementType type, long id)
2846{
2847 std::unique_ptr<long[]> connectStorage;
2849 int connectSize = ReferenceElementInfo::getInfo(type).nVertices;
2850 connectStorage = std::unique_ptr<long[]>(new long[connectSize]);
2851 } else {
2852 connectStorage = std::unique_ptr<long[]>(nullptr);
2853 }
2854
2855 return addCell(type, std::move(connectStorage), id);
2856}
2857
2874PatchKernel::CellIterator PatchKernel::addCell(ElementType type, const std::vector<long> &connectivity,
2875 long id)
2876{
2877 int connectSize = connectivity.size();
2878 std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(new long[connectSize]);
2879 std::copy(connectivity.data(), connectivity.data() + connectSize, connectStorage.get());
2880
2881 return addCell(type, std::move(connectStorage), id);
2882}
2883
2901PatchKernel::CellIterator PatchKernel::addCell(ElementType type, std::unique_ptr<long[]> &&connectStorage,
2902 long id)
2903{
2905 return cellEnd();
2906 }
2907
2908 if (Cell::getDimension(type) > getDimension()) {
2909 return cellEnd();
2910 }
2911
2912 CellIterator iterator = _addInternalCell(type, std::move(connectStorage), id);
2913
2914 return iterator;
2915}
2916
2933PatchKernel::CellIterator PatchKernel::_addInternalCell(ElementType type, std::unique_ptr<long[]> &&connectStorage,
2934 long id)
2935{
2936 // Get the id of the cell
2937 if (m_cellIdGenerator) {
2938 if (id < 0) {
2939 id = m_cellIdGenerator->generate();
2940 } else {
2941 m_cellIdGenerator->setAssigned(id);
2942 }
2943 } else if (id < 0) {
2944 throw std::runtime_error("No valid id has been provided for the cell.");
2945 }
2946
2947 // Get the id of the cell before which the new cell should be inserted
2948#if BITPIT_ENABLE_MPI==1
2949 //
2950 // If there are ghosts cells, the internal cell should be inserted
2951 // before the first ghost cell.
2952#endif
2953 long referenceId;
2954#if BITPIT_ENABLE_MPI==1
2955 referenceId = m_firstGhostCellId;
2956#else
2957 referenceId = Cell::NULL_ID;
2958#endif
2959
2960 // Create the cell
2961 bool storeInterfaces = (getInterfacesBuildStrategy() != INTERFACES_NONE);
2962 bool storeAdjacencies = storeInterfaces || (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE);
2963
2964 CellIterator iterator;
2965 if (referenceId == Cell::NULL_ID) {
2966 iterator = m_cells.emreclaim(id, id, type, std::move(connectStorage), true, storeInterfaces, storeAdjacencies);
2967 } else {
2968 iterator = m_cells.emreclaimBefore(referenceId, id, id, type, std::move(connectStorage), true, storeInterfaces, storeAdjacencies);
2969 }
2970 m_nInternalCells++;
2971
2972 // Update the id of the last internal cell
2973 if (m_lastInternalCellId < 0) {
2974 m_lastInternalCellId = id;
2975 } else if (m_cells.rawIndex(m_lastInternalCellId) < m_cells.rawIndex(id)) {
2976 m_lastInternalCellId = id;
2977 }
2978
2979 // Set the alteration flags of the cell
2980 setAddedCellAlterationFlags(id);
2981
2982#if BITPIT_ENABLE_MPI==1
2983 // Set partitioning information as dirty
2984 setPartitioningInfoDirty(true);
2985#endif
2986
2987 return iterator;
2988}
2989
2998void PatchKernel::setAddedCellAlterationFlags(long id)
2999{
3000 AlterationFlags flags = FLAG_NONE;
3001 if (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE) {
3002 flags |= FLAG_ADJACENCIES_DIRTY;
3003 }
3004 if (getInterfacesBuildStrategy() != INTERFACES_NONE) {
3005 flags |= FLAG_INTERFACES_DIRTY;
3006 }
3007
3008 setCellAlterationFlags(id, flags);
3009}
3010
3011#if BITPIT_ENABLE_MPI==0
3024PatchKernel::CellIterator PatchKernel::restoreCell(ElementType type, std::unique_ptr<long[]> &&connectStorage,
3025 long id)
3026{
3028 return cellEnd();
3029 }
3030
3031 if (Cell::getDimension(type) > getDimension()) {
3032 return cellEnd();
3033 }
3034
3035 CellIterator iterator = m_cells.find(id);
3036 if (iterator == m_cells.end()) {
3037 throw std::runtime_error("Unable to restore the specified cell: the kernel doesn't contain an entry for that cell.");
3038 }
3039
3040 _restoreInternalCell(iterator, type, std::move(connectStorage));
3041
3042 return iterator;
3043}
3044#endif
3045
3054void PatchKernel::_restoreInternalCell(const CellIterator &iterator, ElementType type,
3055 std::unique_ptr<long[]> &&connectStorage)
3056{
3057 // Restore the cell
3058 //
3059 // There is no need to set the id of the cell as assigned, because
3060 // also the index generator will be restored.
3061 bool storeInterfaces = (getInterfacesBuildStrategy() != INTERFACES_NONE);
3062 bool storeAdjacencies = storeInterfaces || (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE);
3063
3064 long cellId = iterator.getId();
3065 Cell &cell = *iterator;
3066 cell.initialize(cellId, type, std::move(connectStorage), true, storeInterfaces, storeAdjacencies);
3067 m_nInternalCells++;
3068
3069 // Set the alteration flags of the cell
3070 setRestoredCellAlterationFlags(cellId);
3071}
3072
3078void PatchKernel::setRestoredCellAlterationFlags(long id)
3079{
3080 AlterationFlags flags = FLAG_NONE;
3081 if (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE) {
3082 flags |= FLAG_ADJACENCIES_DIRTY;
3083 }
3084 if (getInterfacesBuildStrategy() != INTERFACES_NONE) {
3085 flags |= FLAG_INTERFACES_DIRTY;
3086 }
3087
3088 setCellAlterationFlags(id, flags);
3089}
3090
3097{
3099 return false;
3100 }
3101
3102 // Delete cell
3103#if BITPIT_ENABLE_MPI==1
3104 const Cell &cell = m_cells[id];
3105 bool isInternalCell = cell.isInterior();
3106 if (isInternalCell) {
3107 _deleteInternalCell(id);
3108 } else {
3109 _deleteGhostCell(id);
3110 }
3111#else
3112 _deleteInternalCell(id);
3113#endif
3114
3115 return true;
3116}
3117
3123void PatchKernel::_deleteInternalCell(long id)
3124{
3125 // Set the alteration flags of the cell
3126 setDeletedCellAlterationFlags(id);
3127
3128 // Delete cell
3129 m_cells.erase(id, true);
3130 m_nInternalCells--;
3131 if (id == m_lastInternalCellId) {
3133 }
3134
3135 // Cell id is no longer used
3136 if (m_cellIdGenerator) {
3137 m_cellIdGenerator->trash(id);
3138 }
3139}
3140
3148void PatchKernel::setDeletedCellAlterationFlags(long id)
3149{
3150 const Cell &cell = getCell(id);
3151
3152 // Set the alteration flags of the cell
3153 resetCellAlterationFlags(id, FLAG_DELETED);
3154
3155 // Set the alteration flags of the adjacent cells
3156 const int nCellAdjacencies = cell.getAdjacencyCount();
3157 const long *cellAdjacencies = cell.getAdjacencies();
3158 for (int k = 0; k < nCellAdjacencies; ++k) {
3159 long adjacencyId = cellAdjacencies[k];
3160 if (!testCellAlterationFlags(adjacencyId, FLAG_DELETED)) {
3161 AlterationFlags flags = FLAG_DANGLING;
3162 if (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE) {
3163 flags |= FLAG_ADJACENCIES_DIRTY;
3164 }
3165 if (getInterfacesBuildStrategy() != INTERFACES_NONE) {
3166 flags |= FLAG_INTERFACES_DIRTY;
3167 }
3168
3169 setCellAlterationFlags(adjacencyId, flags);
3170 }
3171 }
3172
3173 // Set the alteration flags of the interfaces
3174 const int nCellInterfaces = cell.getInterfaceCount();
3175 const long *cellInterfaces = cell.getInterfaces();
3176 for (int k = 0; k < nCellInterfaces; ++k) {
3177 long interfaceId = cellInterfaces[k];
3178 if (!testInterfaceAlterationFlags(interfaceId, FLAG_DELETED)) {
3179 setInterfaceAlterationFlags(interfaceId, FLAG_DANGLING);
3180 }
3181 }
3182}
3183
3192{
3193 return countBorderCells();
3194}
3195
3204{
3205 long nBorderCells = 0;
3206 for (const Cell &cell : m_cells) {
3207 int nCellFaces = cell.getFaceCount();
3208 for (int i = 0; i < nCellFaces; ++i) {
3209 if (cell.isFaceBorder(i)) {
3210 ++nBorderCells;
3211 break;
3212 }
3213 }
3214 }
3215
3216 return nBorderCells;
3217}
3218
3228{
3229 return findOrphanCells().size();
3230}
3231
3240std::vector<long> PatchKernel::findOrphanCells() const
3241{
3242 // Compute vertex valence
3243 std::unordered_map<long, short> vertexValence;
3244 for (const Cell &cell : m_cells) {
3245 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
3246 int nCellVertices = cellVertexIds.size();
3247 for (int j = 0; j < nCellVertices; j++) {
3248 long vertexId = cellVertexIds[j];
3249 vertexValence[vertexId] += 1;
3250 }
3251 }
3252
3253 // Loop over cells
3254 std::vector<long> orphanCells;
3255 for (const Cell &cell : m_cells) {
3256 long isIsolated = true;
3257 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
3258 int nCellVertices = cellVertexIds.size();
3259 for (int j = 0; j < nCellVertices; j++) {
3260 long vertexId = cellVertexIds[j];
3261 if (vertexValence[vertexId] > 1) {
3262 isIsolated = false;
3263 break;
3264 }
3265 }
3266
3267 if (isIsolated) {
3268 orphanCells.push_back(cell.getId());
3269 }
3270 }
3271
3272 return orphanCells;
3273}
3274
3284{
3285 return findDuplicateCells().size();
3286}
3287
3296std::vector<long> PatchKernel::findDuplicateCells() const
3297{
3298 // Define the hasher and the predicate to be used for lists of vertex ids
3299 //
3300 // These operators should be able to identify that two lists of vertex ids
3301 // are the same regardless of the order in which the ids are listed.
3302 auto hasher = [](const ConstProxyVector<long> &ids)
3303 {
3304 std::size_t hash = std::hash<long>{}(0);
3305 for (long id : ids) {
3306 hash = hash + std::hash<long>{}(id);
3307 }
3308
3309 return hash;
3310 };
3311
3312 std::unordered_map<long, std::size_t > counters;
3313 auto predicate = [&counters](const ConstProxyVector<long> &ids_A, const ConstProxyVector<long> &ids_B)
3314 {
3315 counters.clear();
3316 for (long id : ids_A) {
3317 counters[id]++;
3318 }
3319 for (long id : ids_B) {
3320 counters[id]--;
3321 }
3322
3323 for (const auto &entry : counters) {
3324 if (entry.second != 0) {
3325 return false;
3326 }
3327 }
3328
3329 return true;
3330 };
3331
3332 // Detect if there are cells that share the same list of vertices
3333 //
3334 // For each cell, the list of vertex ids is added into a set. If a collision
3335 // is detected, we have found a duplicate cell.
3336 std::vector<long> duplicateCells;
3337 std::unordered_set<ConstProxyVector<long>, decltype(hasher), decltype(predicate)> vertexStash(getCellCount(), hasher, predicate);
3338 for (const Cell &cell : m_cells) {
3339 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
3340 auto vertexStashItr = vertexStash.find(cellVertexIds);
3341 if (vertexStashItr == vertexStash.end()) {
3342 vertexStash.insert(std::move(cellVertexIds));
3343 } else {
3344 duplicateCells.push_back(cell.getId());
3345 }
3346 }
3347
3348 return duplicateCells;
3349}
3350
3355{
3356 if (m_nInternalCells == 0) {
3357 m_lastInternalCellId = Cell::NULL_ID;
3358 return;
3359 }
3360
3361 CellIterator lastInternalCellItr;
3362#if BITPIT_ENABLE_MPI==1
3363 if (m_nGhostCells == 0) {
3364 lastInternalCellItr = --m_cells.end();
3365 m_lastInternalCellId = lastInternalCellItr->getId();
3366 } else {
3367 m_lastInternalCellId = m_cells.getSizeMarker(m_nInternalCells - 1, Cell::NULL_ID);
3368 }
3369#else
3370 lastInternalCellItr = --m_cells.end();
3371 m_lastInternalCellId = lastInternalCellItr->getId();
3372#endif
3373}
3374
3382{
3383 return id;
3384}
3385
3392std::vector<long> PatchKernel::findCellNeighs(long id) const
3393{
3394 std::vector<long> neighs;
3395 findCellNeighs(id, &neighs);
3396
3397 return neighs;
3398}
3399
3408void PatchKernel::findCellNeighs(long id, std::vector<long> *neighs) const
3409{
3410 _findCellNeighs(id, nullptr, neighs);
3411}
3412
3430std::vector<long> PatchKernel::findCellNeighs(long id, int codimension, bool complete) const
3431{
3432 std::vector<long> neighs;
3433 findCellNeighs(id, codimension, complete, &neighs);
3434
3435 return neighs;
3436}
3437
3458void PatchKernel::findCellNeighs(long id, int codimension, bool complete, std::vector<long> *neighs) const
3459{
3460 assert(codimension >= 1 && codimension <= getDimension());
3461
3462 if (codimension == 1) {
3463 findCellFaceNeighs(id, neighs);
3464 } else if (codimension == getDimension()) {
3465 findCellVertexNeighs(id, complete, neighs);
3466 } else if (codimension == 2) {
3467 findCellEdgeNeighs(id, complete, neighs);
3468 }
3469}
3470
3477std::vector<long> PatchKernel::findCellFaceNeighs(long id) const
3478{
3479 std::vector<long> neighs;
3480 findCellFaceNeighs(id, &neighs);
3481
3482 return neighs;
3483}
3484
3499void PatchKernel::_findCellNeighs(long id, const std::vector<long> *blackList, std::vector<long> *neighs) const
3500{
3501 // Some patches can work (at least partially) without initializing the
3502 // cell list. To handle those patches, if there are no cells the vertex
3503 // count is evaluated using the ReferenceElementInfo associated to the cell.
3504 int nCellVertices;
3505 if (m_cells.size() == 0) {
3506 ElementType cellType = getCellType(id);
3507 const ReferenceElementInfo &cellTypeInfo = ReferenceElementInfo::getInfo(cellType);
3508 nCellVertices = cellTypeInfo.nVertices;
3509 } else {
3510 const Cell &cell = getCell(id);
3511 nCellVertices = cell.getVertexCount();
3512 }
3513
3514 for (int i = 0; i < nCellVertices; ++i) {
3515 _findCellVertexNeighs(id, i, blackList, neighs);
3516 }
3517}
3518
3528void PatchKernel::findCellFaceNeighs(long id, std::vector<long> *neighs) const
3529{
3530 // Some patches can work (at least partially) without initializing the
3531 // cell list. To handle those patches, if there are no cells the face
3532 // count is evaluated using the ReferenceElementInfo associated to the cell.
3533 int nCellFaces;
3534 if (m_cells.size() == 0) {
3535 ElementType cellType = getCellType(id);
3536 const ReferenceElementInfo &cellTypeInfo = ReferenceElementInfo::getInfo(cellType);
3537 nCellFaces = cellTypeInfo.nFaces;
3538 } else {
3539 const Cell &cell = getCell(id);
3540 nCellFaces = cell.getFaceCount();
3541 }
3542
3543 // Get the neighbours
3544 for (int i = 0; i < nCellFaces; ++i) {
3545 _findCellFaceNeighs(id, i, nullptr, neighs);
3546 }
3547}
3548
3556std::vector<long> PatchKernel::findCellFaceNeighs(long id, int face) const
3557{
3558 std::vector<long> neighs;
3559 _findCellFaceNeighs(id, face, nullptr, &neighs);
3560
3561 return neighs;
3562}
3563
3574void PatchKernel::findCellFaceNeighs(long id, int face, std::vector<long> *neighs) const
3575{
3576 _findCellFaceNeighs(id, face, nullptr, neighs);
3577}
3578
3592void PatchKernel::_findCellFaceNeighs(long id, int face, const std::vector<long> *blackList, std::vector<long> *neighs) const
3593{
3594 const Cell &cell = getCell(id);
3595
3596 int nFaceAdjacencies = cell.getAdjacencyCount(face);
3597 const long *faceAdjacencies = cell.getAdjacencies(face);
3598 for (int k = 0; k < nFaceAdjacencies; ++k) {
3599 long neighId = faceAdjacencies[k];
3600 if (!blackList || utils::findInOrderedVector<long>(neighId, *blackList) == blackList->end()) {
3601 utils::addToOrderedVector<long>(neighId, *neighs);
3602 }
3603 }
3604}
3605
3617std::vector<long> PatchKernel::findCellEdgeNeighs(long id, bool complete) const
3618{
3619 std::vector<long> neighs;
3620 findCellEdgeNeighs(id, complete, &neighs);
3621
3622 return neighs;
3623}
3624
3639void PatchKernel::findCellEdgeNeighs(long id, bool complete, std::vector<long> *neighs) const
3640{
3641 assert(isThreeDimensional());
3642 if (!isThreeDimensional()) {
3643 return;
3644 }
3645
3646 // Some patches can work (at least partially) without initializing the
3647 // cell list. To handle those patches, if there are no cells the edge
3648 // count is evaluated using the ReferenceElementInfo associated to the cell.
3649 int nCellEdges;
3650 if (m_cells.size() == 0) {
3651 ElementType cellType = getCellType(id);
3652 const ReferenceElementInfo &cellTypeInfo = ReferenceElementInfo::getInfo(cellType);
3653 nCellEdges = cellTypeInfo.nEdges;
3654 } else {
3655 const Cell &cell = getCell(id);
3656 nCellEdges = cell.getEdgeCount();
3657 }
3658
3659 // Get the neighbours
3660 std::unique_ptr<std::vector<long>> blackList;
3661 if (!complete) {
3662 blackList = std::unique_ptr<std::vector<long>>(new std::vector<long>());
3663 findCellFaceNeighs(id, blackList.get());
3664 }
3665
3666 for (int i = 0; i < nCellEdges; ++i) {
3667 _findCellEdgeNeighs(id, i, blackList.get(), neighs);
3668 }
3669}
3670
3680std::vector<long> PatchKernel::findCellEdgeNeighs(long id, int edge) const
3681{
3682 std::vector<long> neighs;
3683 findCellEdgeNeighs(id, edge, &neighs);
3684
3685 return neighs;
3686}
3687
3700void PatchKernel::findCellEdgeNeighs(long id, int edge, std::vector<long> *neighs) const
3701{
3702 _findCellEdgeNeighs(id, edge, nullptr, neighs);
3703}
3704
3720void PatchKernel::_findCellEdgeNeighs(long id, int edge, const std::vector<long> *blackList, std::vector<long> *neighs) const
3721{
3722 assert(isThreeDimensional());
3723 if (!isThreeDimensional()) {
3724 return;
3725 }
3726
3727 const Cell &cell = getCell(id);
3728 ConstProxyVector<int> edgeVertices = cell.getEdgeLocalConnect(edge);
3729 std::size_t nEdgeVertices = edgeVertices.size();
3730 if (nEdgeVertices < 2) {
3731 return;
3732 }
3733
3734 // Find candidates neighbours
3735 //
3736 // These are the negihbours of the first vertex of the edge.
3737 const int GUESS_NEIGHS_COUNT = 3;
3738
3739 std::vector<long> candidateIds;
3740 candidateIds.reserve(GUESS_NEIGHS_COUNT);
3741 _findCellVertexNeighs(id, edgeVertices[0], blackList, &candidateIds);
3742
3743 // Discard candidates that doesn't contain the last vertex of the edge
3744 long lastEdgeVertexId = cell.getEdgeVertexId(edge, nEdgeVertices - 1);
3745
3746 ConstProxyVector<long> candidateVertexIds;
3747 for (long candidateId : candidateIds) {
3748 const Cell &candidateNeigh = m_cells.at(candidateId);
3749 candidateVertexIds = candidateNeigh.getVertexIds();
3750 std::size_t nCandidateVertices = candidateVertexIds.size();
3751
3752 bool isEdgeNeighbour = false;
3753 for (std::size_t k = 0; k < nCandidateVertices; ++k) {
3754 if (candidateVertexIds[k] == lastEdgeVertexId) {
3755 isEdgeNeighbour = true;
3756 break;
3757 }
3758 }
3759
3760 if (isEdgeNeighbour) {
3761 utils::addToOrderedVector<long>(candidateId, *neighs);
3762 }
3763 }
3764}
3765
3775std::vector<long> PatchKernel::findCellVertexNeighs(long id, bool complete) const
3776{
3777 std::vector<long> neighs;
3778 findCellVertexNeighs(id, complete, &neighs);
3779
3780 return neighs;
3781}
3782
3795void PatchKernel::findCellVertexNeighs(long id, bool complete, std::vector<long> *neighs) const
3796{
3797 // Some patches can work (at least partially) without initializing the
3798 // cell list. To handle those patches, if there are no cells the vertex
3799 // count is evaluated using the ReferenceElementInfo associated to the cell.
3800 int nCellVertices;
3801 if (m_cells.size() == 0) {
3802 ElementType cellType = getCellType(id);
3803 const ReferenceElementInfo &cellTypeInfo = ReferenceElementInfo::getInfo(cellType);
3804 nCellVertices = cellTypeInfo.nVertices;
3805 } else {
3806 const Cell &cell = getCell(id);
3807 nCellVertices = cell.getVertexCount();
3808 }
3809
3810 // Get the neighbours
3811 std::unique_ptr<std::vector<long>> blackList;
3812 if (!complete) {
3813 blackList = std::unique_ptr<std::vector<long>>(new std::vector<long>());
3814 if (isThreeDimensional()) {
3815 findCellEdgeNeighs(id, true, blackList.get());
3816 } else {
3817 findCellFaceNeighs(id, true, blackList.get());
3818 }
3819 }
3820
3821 for (int i = 0; i < nCellVertices; ++i) {
3822 _findCellVertexNeighs(id, i, blackList.get(), neighs);
3823 }
3824}
3825
3833std::vector<long> PatchKernel::findCellVertexNeighs(long id, int vertex) const
3834{
3835 std::vector<long> neighs;
3836 findCellVertexNeighs(id, vertex, &neighs);
3837
3838 return neighs;
3839}
3840
3851void PatchKernel::findCellVertexNeighs(long id, int vertex, std::vector<long> *neighs) const
3852{
3853 _findCellVertexNeighs(id, vertex, nullptr, neighs);
3854}
3855
3885void PatchKernel::_findCellVertexNeighs(long id, int vertex, const std::vector<long> *blackList, std::vector<long> *neighs) const
3886{
3887 const Cell &cell = getCell(id);
3888 long vertexId = cell.getVertexId(vertex);
3889
3890 // Since we are processing a small number of cells it's more efficient to
3891 // store the list of already processed cells in a vector instead of using
3892 // a set or an unordered_set. To speed-up the lookup, the vector is kept
3893 // sorted.
3894 const int GUESS_NEIGHS_COUNT = 8;
3895
3896 std::vector<long> alreadyProcessed;
3897 alreadyProcessed.reserve(GUESS_NEIGHS_COUNT);
3898
3899 std::vector<long> scanQueue;
3900 scanQueue.reserve(GUESS_NEIGHS_COUNT);
3901 scanQueue.push_back(id);
3902
3903 while (!scanQueue.empty()) {
3904 // Pop a cell to process
3905 long scanCellId = scanQueue.back();
3906 const Cell &scanCell = getCell(scanCellId);
3907 scanQueue.pop_back();
3908 utils::addToOrderedVector<long>(scanCell.getId(), alreadyProcessed);
3909
3910 // Get cell information
3911 const ReferenceElementInfo *scanCellInfo = nullptr;
3912 const long *scanCellConnectivity = nullptr;
3913 if (scanCell.hasInfo()) {
3914 scanCellInfo = &(scanCell.getInfo());
3915 scanCellConnectivity = scanCell.getConnect();
3916 }
3917
3918 // Use face adjacencies to find vertex negihbours
3919 int nFaces;
3920 if (scanCellInfo) {
3921 nFaces = scanCellInfo->nFaces;
3922 } else {
3923 nFaces = scanCell.getFaceCount();
3924 }
3925
3926 for (int i = 0; i < nFaces; ++i) {
3927 // Discard faces with no neighbours
3928 if (scanCell.isFaceBorder(i)) {
3929 continue;
3930 }
3931
3932 // Discard faces that don't own the vertex
3933 //
3934 // We use differents algorithm depending on whether the cell has a
3935 // reference element or not. If the cell has a reference element,
3936 // accessing the local connectivity of the face is cheap. If the
3937 // cell has no reference element, it is better to avoid using the
3938 // local connectivity of the face.
3939 //
3940 // Moreover, to optimize the search for cells that has a reference
3941 // element, we work directly on the connectivity inseatd of on the
3942 // list of vertex ids. That's because for reference elements the
3943 // connectivity is just a list of vertices.
3944 bool faceOwnsVertex = false;
3945 if (scanCellInfo) {
3946 const ReferenceElementInfo &faceInfo = ReferenceElementInfo::getInfo(scanCellInfo->faceTypeStorage[i]);
3947 const int *faceLocalConnectivity = scanCellInfo->faceConnectStorage[i].data();
3948 const int nFaceVertices = faceInfo.nVertices;
3949 for (int k = 0; k < nFaceVertices; ++k) {
3950 long faceVertexId = scanCellConnectivity[faceLocalConnectivity[k]];
3951 if (faceVertexId == vertexId) {
3952 faceOwnsVertex = true;
3953 break;
3954 }
3955 }
3956 } else {
3957 ConstProxyVector<long> faceVertexIds = scanCell.getFaceVertexIds(i);
3958 int nFaceVertices = faceVertexIds.size();
3959 for (int k = 0; k < nFaceVertices; ++k) {
3960 long faceVertexId = faceVertexIds[k];
3961 if (faceVertexId == vertexId) {
3962 faceOwnsVertex = true;
3963 break;
3964 }
3965 }
3966 }
3967
3968 if (!faceOwnsVertex) {
3969 continue;
3970 }
3971
3972 // Loop through the adjacencies
3973 //
3974 // Non-manifold patches may have faces with multiple adjacencies.
3975 int nFaceAdjacencies = scanCell.getAdjacencyCount(i);
3976 const long *faceAdjacencies = scanCell.getAdjacencies(i);
3977 for (int k = 0; k < nFaceAdjacencies; ++k) {
3978 long faceNeighId = faceAdjacencies[k];
3979
3980 // Discard neighbours that have already been processed
3981 if (utils::findInOrderedVector<long>(faceNeighId, alreadyProcessed) != alreadyProcessed.end()) {
3982 continue;
3983 }
3984
3985 // Update list of vertex neighbours
3986 if (!blackList || utils::findInOrderedVector<long>(faceNeighId, *blackList) == blackList->end()) {
3987 utils::addToOrderedVector<long>(faceNeighId, *neighs);
3988 }
3989
3990 // Update scan list
3991 scanQueue.push_back(faceNeighId);
3992 }
3993 }
3994 }
3995}
3996
4004std::vector<long> PatchKernel::findCellVertexOneRing(long id, int vertex) const
4005{
4006 std::vector<long> ring;
4007 findCellVertexOneRing(id, vertex, &ring);
4008
4009 return ring;
4010}
4011
4022void PatchKernel::findCellVertexOneRing(long id, int vertex, std::vector<long> *ring) const
4023{
4024 findCellVertexNeighs(id, vertex, ring);
4025 utils::addToOrderedVector<long>(id, *ring);
4026}
4027
4044bool PatchKernel::findFaceNeighCell(long cellId, long neighId, int *cellFace, int *cellAdjacencyId) const
4045{
4046 const Cell &cell = getCell(cellId);
4047
4048 int nFaces = cell.getFaceCount();
4049 for (int i = 0; i < nFaces; ++i) {
4050 int nFaceAdjacencies = cell.getAdjacencyCount(i);
4051 const long *faceAdjacencies = cell.getAdjacencies(i);
4052 for (int k = 0; k < nFaceAdjacencies; ++k) {
4053 long faceNeighId = faceAdjacencies[k];
4054 if (faceNeighId < 0) {
4055 continue;
4056 } else if (faceNeighId == neighId) {
4057 *cellFace = i;
4058 *cellAdjacencyId = k;
4059 return true;
4060 }
4061 }
4062 }
4063
4064 *cellFace = -1;
4065 *cellAdjacencyId = -1;
4066
4067 return false;
4068}
4069
4076{
4077 std::set<int> list;
4078 CellConstIterator endItr = internalCellConstEnd();
4079 for (CellConstIterator itr = internalCellConstBegin(); itr != endItr; ++itr) {
4080 list.insert(itr->getPID());
4081 }
4082
4083 return list;
4084}
4085
4092std::vector<long> PatchKernel::getInternalCellsByPID(int pid)
4093{
4094 std::vector<long> cells;
4095 CellConstIterator endItr = internalCellConstEnd();
4096 for (CellConstIterator itr = internalCellConstBegin(); itr != endItr; ++itr) {
4097 if (itr->getPID() == pid){
4098 cells.push_back(itr.getId());
4099 }
4100 }
4101
4102 return cells;
4103}
4104
4113std::vector<long> PatchKernel::findVertexOneRing(long vertexId) const
4114{
4115 std::vector<long> ring;
4116 findVertexOneRing(vertexId, &ring);
4117
4118 return ring;
4119}
4120
4131void PatchKernel::findVertexOneRing(long vertexId, std::vector<long> *ring) const
4132{
4133 // Find local id of the vertex
4134 //
4135 // Coincident vertices with different ids are not supported, this case is
4136 // special because a cell may contain a point with the vertex coordinates,
4137 // but may not contain the requested vertex (because it contains one of
4138 // the other coincident vertices).
4139 const std::array<double, 3> &coords = getVertexCoords(vertexId);
4140 long cellId = locatePoint(coords);
4141 if (cellId == bitpit::Element::NULL_ID) {
4142 return;
4143 }
4144
4145 int vertexLocalId = getCell(cellId).findVertex(vertexId);
4146 assert(vertexLocalId >= 0);
4147
4148 // Find vertex one-ring
4149 findCellVertexOneRing(cellId, vertexLocalId, ring);
4150}
4151
4161{
4162 return static_cast<bool>(m_interfaceIdGenerator);
4163}
4164
4177{
4178 if (isInterfaceAutoIndexingEnabled() == enabled) {
4179 return;
4180 }
4181
4182 if (enabled) {
4183 createInterfaceIndexGenerator(true);
4184 } else {
4185 if (getInterfacesBuildStrategy() == INTERFACES_AUTOMATIC) {
4186 throw std::runtime_error("Auto-indexing cannot be disabled if interfaces build strategy is set to automatic.");
4187 }
4188
4189 m_interfaceIdGenerator.reset();
4190 }
4191}
4192
4198void PatchKernel::dumpInterfaceAutoIndexing(std::ostream &stream) const
4199{
4200 m_interfaceIdGenerator->dump(stream);
4201}
4202
4208void PatchKernel::restoreInterfaceAutoIndexing(std::istream &stream)
4209{
4210 createInterfaceIndexGenerator(false);
4211 m_interfaceIdGenerator->restore(stream);
4212}
4213
4222void PatchKernel::createInterfaceIndexGenerator(bool populate)
4223{
4224 // Create or reset index generator
4225 if (!m_interfaceIdGenerator) {
4226 m_interfaceIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>());
4227 } else {
4228 m_interfaceIdGenerator->reset();
4229 }
4230
4231 // Populate index generator with current ids
4232 if (populate) {
4233 InterfaceConstIterator beginItr = m_interfaces.cbegin();
4234 InterfaceConstIterator endItr = m_interfaces.cend();
4235 for (InterfaceConstIterator itr = beginItr; itr != endItr; ++itr) {
4236 m_interfaceIdGenerator->setAssigned(itr.getId());
4237 }
4238 }
4239}
4240
4249void PatchKernel::importInterfaceIndexGenerator(const PatchKernel &source)
4250{
4251 if (source.m_interfaceIdGenerator) {
4252 m_interfaceIdGenerator = std::unique_ptr<IndexGenerator<long>>(new IndexGenerator<long>(*(source.m_interfaceIdGenerator)));
4253 } else {
4254 m_interfaceIdGenerator.reset();
4255 }
4256}
4257
4264{
4265 return m_interfaces.size();
4266}
4267
4274{
4275 return m_interfaces;
4276}
4277
4284{
4285 return m_interfaces;
4286}
4287
4295{
4296 return m_interfaces[id];
4297}
4298
4306{
4307 return m_interfaces[id];
4308}
4309
4317{
4318 return m_interfaces[id].getType();
4319}
4320
4326PatchKernel::InterfaceIterator PatchKernel::getInterfaceIterator(long id)
4327{
4328 return m_interfaces.find(id);
4329}
4330
4336PatchKernel::InterfaceIterator PatchKernel::interfaceBegin()
4337{
4338 return m_interfaces.begin();
4339}
4340
4346PatchKernel::InterfaceIterator PatchKernel::interfaceEnd()
4347{
4348 return m_interfaces.end();
4349}
4350
4356PatchKernel::InterfaceConstIterator PatchKernel::getInterfaceConstIterator(long id) const
4357{
4358 return m_interfaces.find(id);
4359}
4360
4366PatchKernel::InterfaceConstIterator PatchKernel::interfaceConstBegin() const
4367{
4368 return m_interfaces.cbegin();
4369}
4370
4376PatchKernel::InterfaceConstIterator PatchKernel::interfaceConstEnd() const
4377{
4378 return m_interfaces.cend();
4379}
4380
4396PatchKernel::InterfaceIterator PatchKernel::addInterface(const Interface &source, long id)
4397{
4398 Interface interface = source;
4399 interface.setId(id);
4400
4401 return addInterface(std::move(interface), id);
4402}
4403
4419PatchKernel::InterfaceIterator PatchKernel::addInterface(Interface &&source, long id)
4420{
4421 // Get the id
4422 if (id < 0) {
4423 id = source.getId();
4424 }
4425
4426 // Add a dummy interface
4427 //
4428 // It is not possible to directly add the source into the storage. First
4429 // a dummy interface is created and then that interface is replaced with
4430 // the source.
4431 std::unique_ptr<long[]> dummyConnectStorage = std::unique_ptr<long[]>(nullptr);
4432
4433 InterfaceIterator iterator = _addInterface(ElementType::UNDEFINED, std::move(dummyConnectStorage), id);
4434
4435 // Replace the newly created interface with the source
4436 //
4437 // Before replacing the newly created interface we need to set the id
4438 // of the source to the id that has been assigned to the newly created
4439 // interface.
4440 source.setId(iterator->getId());
4441
4442 Interface &interface = (*iterator);
4443 interface = std::move(source);
4444
4445 return iterator;
4446}
4447
4463PatchKernel::InterfaceIterator PatchKernel::addInterface(ElementType type, long id)
4464{
4465 int connectSize = ReferenceElementInfo::getInfo(type).nVertices;
4466 std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(new long[connectSize]);
4467
4468 return addInterface(type, std::move(connectStorage), id);
4469}
4470
4486PatchKernel::InterfaceIterator PatchKernel::addInterface(ElementType type,
4487 const std::vector<long> &connectivity,
4488 long id)
4489{
4490 int connectSize = connectivity.size();
4491 std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(new long[connectSize]);
4492 std::copy(connectivity.data(), connectivity.data() + connectSize, connectStorage.get());
4493
4494 return addInterface(type, std::move(connectStorage), id);
4495}
4496
4513PatchKernel::InterfaceIterator PatchKernel::addInterface(ElementType type,
4514 std::unique_ptr<long[]> &&connectStorage,
4515 long id)
4516{
4518 return interfaceEnd();
4519 }
4520
4521 if (Interface::getDimension(type) > (getDimension() - 1)) {
4522 return interfaceEnd();
4523 }
4524
4525 InterfaceIterator iterator = _addInterface(type, std::move(connectStorage), id);
4526
4527 return iterator;
4528}
4529
4546PatchKernel::InterfaceIterator PatchKernel::_addInterface(ElementType type,
4547 std::unique_ptr<long[]> &&connectStorage,
4548 long id)
4549{
4550 // Get the id
4551 if (m_interfaceIdGenerator) {
4552 if (id < 0) {
4553 id = m_interfaceIdGenerator->generate();
4554 } else {
4555 m_interfaceIdGenerator->setAssigned(id);
4556 }
4557 } else if (id < 0) {
4558 throw std::runtime_error("No valid id has been provided for the interface.");
4559 }
4560
4561 // Create the interface
4562 PiercedVector<Interface>::iterator iterator = m_interfaces.emreclaim(id, id, type, std::move(connectStorage));
4563
4564 // Set the alteration flags
4565 setAddedInterfaceAlterationFlags(id);
4566
4567 return iterator;
4568}
4569
4578void PatchKernel::setAddedInterfaceAlterationFlags(long id)
4579{
4580 BITPIT_UNUSED(id);
4581}
4582
4595PatchKernel::InterfaceIterator PatchKernel::restoreInterface(ElementType type,
4596 std::unique_ptr<long[]> &&connectStorage,
4597 long id)
4598{
4600 return interfaceEnd();
4601 }
4602
4603 if (Interface::getDimension(type) > (getDimension() - 1)) {
4604 return interfaceEnd();
4605 }
4606
4607 InterfaceIterator iterator = m_interfaces.find(id);
4608 if (iterator == m_interfaces.end()) {
4609 throw std::runtime_error("Unable to restore the specified interface: the kernel doesn't contain an entry for that interface.");
4610 }
4611
4612 _restoreInterface(iterator, type, std::move(connectStorage));
4613
4614 return iterator;
4615}
4616
4628void PatchKernel::_restoreInterface(const InterfaceIterator &iterator, ElementType type,
4629 std::unique_ptr<long[]> &&connectStorage)
4630{
4631 // Restore the interface
4632 //
4633 // There is no need to set the id of the interfaces as assigned, because
4634 // also the index generator will be restored.
4635 long interfaceId = iterator.getId();
4636 Interface &interface = *iterator;
4637 interface.initialize(interfaceId, type, std::move(connectStorage));
4638
4639 // Set the alteration flags
4640 setRestoredInterfaceAlterationFlags(interfaceId);
4641}
4642
4648void PatchKernel::setRestoredInterfaceAlterationFlags(long id)
4649{
4650 BITPIT_UNUSED(id);
4651}
4652
4659{
4661 return false;
4662 }
4663
4664 _deleteInterface(id);
4665
4666 return true;
4667}
4668
4674void PatchKernel::_deleteInterface(long id)
4675{
4676 // Set the alteration flags
4677 setDeletedInterfaceAlterationFlags(id);
4678
4679 // Delete interface
4680 m_interfaces.erase(id, true);
4681
4682 // Interface id is no longer used
4683 if (m_interfaceIdGenerator) {
4684 m_interfaceIdGenerator->trash(id);
4685 }
4686}
4687
4695void PatchKernel::setDeletedInterfaceAlterationFlags(long id)
4696{
4697 resetInterfaceAlterationFlags(id, FLAG_DELETED);
4698}
4699
4708{
4709 return countBorderInterfaces();
4710}
4711
4720{
4721 long nBorderInterfaces = 0;
4722 for (const Interface &interface : m_interfaces) {
4723 if (interface.getNeigh() < 0) {
4724 ++nBorderInterfaces;
4725 }
4726 }
4727
4728 return nBorderInterfaces;
4729}
4730
4740{
4741 long nOrphanInterfaces = 0;
4742 InterfaceConstIterator endItr = interfaceConstEnd();
4743 for (InterfaceConstIterator itr = interfaceConstBegin(); itr != endItr; ++itr) {
4744 const long interfaceId = itr.getId();
4745 if (isInterfaceOrphan(interfaceId)) {
4746 ++nOrphanInterfaces;
4747 }
4748 }
4749
4750 return nOrphanInterfaces;
4751}
4752
4761std::vector<long> PatchKernel::findOrphanInterfaces() const
4762{
4763 std::vector<long> orphanInterfaces;
4764 InterfaceConstIterator endItr = interfaceConstEnd();
4765 for (InterfaceConstIterator itr = interfaceConstBegin(); itr != endItr; ++itr) {
4766 const long interfaceId = itr.getId();
4767 if (isInterfaceOrphan(interfaceId)) {
4768 orphanInterfaces.push_back(interfaceId);
4769 }
4770 }
4771
4772 return orphanInterfaces;
4773}
4774
4779{
4781 return false;
4782 }
4783
4784 std::vector<long> list = findOrphanInterfaces();
4785 deleteInterfaces(list);
4786
4787 return true;
4788}
4789
4799{
4800 const Interface &interface = getInterface(id);
4801
4802 // Interface is not orphan if it has an owner or a neighbour
4803 long ownerId = interface.getOwner();
4804 long neighId = interface.getNeigh();
4805 if (ownerId >= 0 && neighId >= 0) {
4806 return false;
4807 }
4808
4809 // Interface is not orphan if it's on a border face of an internal cell
4810 if (ownerId >= 0 && neighId < 0) {
4811 const Cell &owner = getCell(ownerId);
4812 if (owner.isInterior()) {
4813 return false;
4814 }
4815 }
4816
4817 return true;
4818}
4819
4826{
4827 double nFaces = 0;
4828 for (const Cell &cell : m_cells) {
4829 int nCellFaces = cell.getFaceCount();
4830 for (int i = 0; i < nCellFaces; ++i) {
4831 if (!cell.isFaceBorder(i)) {
4832 nFaces += 1. / (cell.getAdjacencyCount(i) + 1);
4833 } else {
4834 nFaces += 1.;
4835 }
4836 }
4837 }
4838
4839 return ((long) round(nFaces));
4840}
4841
4850{
4851 return countBorderFaces();
4852}
4853
4862{
4863 long nBorderFaces = 0;
4864 for (const Cell &cell : m_cells) {
4865 int nCellFaces = cell.getFaceCount();
4866 for (int i = 0; i < nCellFaces; ++i) {
4867 if (cell.isFaceBorder(i)) {
4868 ++nBorderFaces;
4869 }
4870 }
4871 }
4872
4873 return nBorderFaces;
4874}
4875
4881void PatchKernel::dumpVertices(std::ostream &stream) const
4882{
4883 // Dump kernel
4884 m_vertices.dumpKernel(stream);
4885
4886 // Dump vertices
4887 for (const Vertex &vertex : m_vertices) {
4888 utils::binary::write(stream, vertex.getId());
4889#if BITPIT_ENABLE_MPI==1
4890 utils::binary::write(stream, getVertexOwner(vertex.getId()));
4891#else
4892 int dummyOwner = 0;
4893 utils::binary::write(stream, dummyOwner);
4894#endif
4895
4896 const std::array<double, 3> &coords = vertex.getCoords();
4897 utils::binary::write(stream, coords[0]);
4898 utils::binary::write(stream, coords[1]);
4899 utils::binary::write(stream, coords[2]);
4900 }
4901
4902 // Dump ghost/internal subdivision
4903#if BITPIT_ENABLE_MPI==1
4904 utils::binary::write(stream, m_firstGhostVertexId);
4905 utils::binary::write(stream, m_lastInternalVertexId);
4906#else
4907 utils::binary::write(stream, Vertex::NULL_ID);
4908 utils::binary::write(stream, Vertex::NULL_ID);
4909#endif
4910}
4911
4917void PatchKernel::restoreVertices(std::istream &stream)
4918{
4919 // Restore kernel
4920 m_vertices.restoreKernel(stream);
4921
4922 // Enable manual adaption
4923 AdaptionMode previousAdaptionMode = getAdaptionMode();
4925
4926 // Restore vertices
4927 long nVertices = m_vertices.size();
4928 for (long i = 0; i < nVertices; ++i) {
4929 long id;
4930 utils::binary::read(stream, id);
4931
4932#if BITPIT_ENABLE_MPI==1
4933 int owner;
4934 utils::binary::read(stream, owner);
4935#else
4936 int dummyOwner;
4937 utils::binary::read(stream, dummyOwner);
4938#endif
4939
4940 std::array<double, 3> coords;
4941 utils::binary::read(stream, coords[0]);
4942 utils::binary::read(stream, coords[1]);
4943 utils::binary::read(stream, coords[2]);
4944
4945#if BITPIT_ENABLE_MPI==1
4946 restoreVertex(std::move(coords), owner, id);
4947#else
4948 restoreVertex(std::move(coords), id);
4949#endif
4950 }
4951
4952 // Restore ghost/internal subdivision
4953#if BITPIT_ENABLE_MPI==1
4954 utils::binary::read(stream, m_firstGhostVertexId);
4955 utils::binary::read(stream, m_lastInternalVertexId);
4956#else
4957 long dummyFirstGhostVertexId;
4958 long dummyLastInternalVertexId;
4959 utils::binary::read(stream, dummyFirstGhostVertexId);
4960 utils::binary::read(stream, dummyLastInternalVertexId);
4961#endif
4962
4963 // Restore previous adaption mode
4964 setAdaptionMode(previousAdaptionMode);
4965}
4966
4972void PatchKernel::dumpCells(std::ostream &stream) const
4973{
4974 // Dump kernel
4975 m_cells.dumpKernel(stream);
4976
4977 // Dump cells
4978 for (const Cell &cell: m_cells) {
4979 utils::binary::write(stream, cell.getId());
4980 utils::binary::write(stream, cell.getPID());
4981 utils::binary::write(stream, cell.getType());
4982
4983#if BITPIT_ENABLE_MPI==1
4984 utils::binary::write(stream, getCellOwner(cell.getId()));
4985 utils::binary::write(stream, getCellHaloLayer(cell.getId()));
4986#else
4987 int dummyOwner = 0;
4988 utils::binary::write(stream, dummyOwner);
4989
4990 int dummyHaloLayer = 0;
4991 utils::binary::write(stream, dummyHaloLayer);
4992#endif
4993
4994 int cellConnectSize = cell.getConnectSize();
4995 utils::binary::write(stream, cellConnectSize);
4996
4997 const long *cellConnect = cell.getConnect();
4998 for (int i = 0; i < cellConnectSize; ++i) {
4999 utils::binary::write(stream, cellConnect[i]);
5000 }
5001 }
5002
5003 // Dump ghost/internal subdivision
5004#if BITPIT_ENABLE_MPI==1
5005 utils::binary::write(stream, m_firstGhostCellId);
5006 utils::binary::write(stream, m_lastInternalCellId);
5007#else
5008 utils::binary::write(stream, Cell::NULL_ID);
5009 utils::binary::write(stream, Cell::NULL_ID);
5010#endif
5011}
5012
5018void PatchKernel::restoreCells(std::istream &stream)
5019{
5020 // Restore kernel
5021 m_cells.restoreKernel(stream);
5022
5023 // Enable manual adaption
5024 AdaptionMode previousAdaptionMode = getAdaptionMode();
5026
5027 // Restore cells
5028 long nCells = m_cells.size();
5029 for (long i = 0; i < nCells; ++i) {
5030 long id;
5031 utils::binary::read(stream, id);
5032
5033 int PID;
5034 utils::binary::read(stream, PID);
5035
5036 ElementType type;
5037 utils::binary::read(stream, type);
5038
5039#if BITPIT_ENABLE_MPI==1
5040 int owner;
5041 utils::binary::read(stream, owner);
5042
5043 int haloLayer;
5044 utils::binary::read(stream, haloLayer);
5045#else
5046 int dummyOwner;
5047 utils::binary::read(stream, dummyOwner);
5048
5049 int dummyHaloLayer;
5050 utils::binary::read(stream, dummyHaloLayer);
5051#endif
5052
5053 int cellConnectSize;
5054 utils::binary::read(stream, cellConnectSize);
5055
5056 std::unique_ptr<long[]> cellConnect = std::unique_ptr<long[]>(new long[cellConnectSize]);
5057 for (int k = 0; k < cellConnectSize; ++k) {
5058 utils::binary::read(stream, cellConnect[k]);
5059 }
5060
5061 CellIterator iterator;
5062#if BITPIT_ENABLE_MPI==1
5063 iterator = restoreCell(type, std::move(cellConnect), owner, haloLayer, id);
5064#else
5065 iterator = restoreCell(type, std::move(cellConnect), id);
5066#endif
5067 iterator->setPID(PID);
5068 }
5069
5070 // Restore ghost/internal subdivision
5071#if BITPIT_ENABLE_MPI==1
5072 utils::binary::read(stream, m_firstGhostCellId);
5073 utils::binary::read(stream, m_lastInternalCellId);
5074#else
5075 long dummyFirstGhostCellId;
5076 long dummyLastInternalCellId;
5077 utils::binary::read(stream, dummyFirstGhostCellId);
5078 utils::binary::read(stream, dummyLastInternalCellId);
5079#endif
5080
5081 // Update adjacencies
5083
5084 // Restore previous adaption mode
5085 setAdaptionMode(previousAdaptionMode);
5086}
5087
5093void PatchKernel::dumpInterfaces(std::ostream &stream) const
5094{
5095 // Early return if the interfaces are not build
5096 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
5097 return;
5098 }
5099
5100 // Dump kernel
5101 m_interfaces.dumpKernel(stream);
5102
5103 // Dump interfaces
5104 for (const Interface &interface : getInterfaces()) {
5105 utils::binary::write(stream, interface.getId());
5106
5107 utils::binary::write(stream, interface.getOwner());
5108 utils::binary::write(stream, interface.getOwnerFace());
5109
5110 long neighId = interface.getNeigh();
5111 utils::binary::write(stream, interface.getNeigh());
5112 if (neighId >= 0) {
5113 utils::binary::write(stream, interface.getNeighFace());
5114 }
5115
5116 utils::binary::write(stream, interface.getPID());
5117 }
5118}
5119
5125void PatchKernel::restoreInterfaces(std::istream &stream)
5126{
5127 // Early return if the interfaces are not build
5128 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
5129 return;
5130 }
5131
5132 // Interfaces need up-to-date adjacencies
5134
5135 // Restore kernel
5136 m_interfaces.restoreKernel(stream);
5137
5138 // Enable manual adaption
5139 AdaptionMode previousAdaptionMode = getAdaptionMode();
5141
5142 // Restore interfaces
5143 long nInterfaces = m_interfaces.size();
5144 for (long n = 0; n < nInterfaces; ++n) {
5145 long interfaceId;
5146 utils::binary::read(stream, interfaceId);
5147
5148 long ownerId;
5149 int ownerFace;
5150 utils::binary::read(stream, ownerId);
5151 utils::binary::read(stream, ownerFace);
5152 Cell *owner = &(m_cells.at(ownerId));
5153
5154 long neighId;
5155 int neighFace;
5156 utils::binary::read(stream, neighId);
5157 Cell *neigh;
5158 if (neighId >= 0) {
5159 utils::binary::read(stream, neighFace);
5160 neigh = &(m_cells.at(neighId));
5161 } else {
5162 neighFace = -1;
5163 neigh = nullptr;
5164 }
5165
5166 int pid;
5167 utils::binary::read(stream, pid);
5168
5169 InterfaceIterator interfaceIterator = buildCellInterface(owner, ownerFace, neigh, neighFace, interfaceId);
5170 interfaceIterator->setPID(pid);
5171 }
5172
5173 // Interfaces are now updated
5174 unsetCellAlterationFlags(FLAG_INTERFACES_DIRTY);
5175 m_alteredInterfaces.clear();
5176
5177 // Restore previous adaption mode
5178 setAdaptionMode(previousAdaptionMode);
5179}
5180
5192std::vector<adaption::Info> PatchKernel::_adaptionPrepare(bool trackAdaption)
5193{
5194 BITPIT_UNUSED(trackAdaption);
5195
5196 return std::vector<adaption::Info>();
5197}
5198
5210std::vector<adaption::Info> PatchKernel::_adaptionAlter(bool trackAdaption)
5211{
5212 BITPIT_UNUSED(trackAdaption);
5213
5214 assert(false && "The patch needs to implement _adaptionAlter");
5215
5216 return std::vector<adaption::Info>();
5217}
5218
5227
5237{
5238 BITPIT_UNUSED(id);
5239
5240 return false;
5241}
5242
5252{
5253 BITPIT_UNUSED(id);
5254
5255 return false;
5256}
5257
5267{
5268 BITPIT_UNUSED(id);
5269
5270 return false;
5271}
5272
5282{
5283 BITPIT_UNUSED(id);
5284
5285 return adaption::MARKER_UNDEFINED;
5286}
5287
5297bool PatchKernel::_enableCellBalancing(long id, bool enabled)
5298{
5299 BITPIT_UNUSED(id);
5300 BITPIT_UNUSED(enabled);
5301
5302 return false;
5303}
5304
5309{
5311 return false;
5312 }
5313
5314 // Sort internal vertices
5315 if (m_nInternalVertices > 0) {
5316 m_vertices.sortBefore(m_lastInternalVertexId, true);
5318 }
5319
5320#if BITPIT_ENABLE_MPI==1
5321 // Sort ghost cells
5322 if (m_nGhostVertices > 0) {
5323 m_vertices.sortAfter(m_firstGhostVertexId, true);
5325 }
5326#endif
5327
5328 // Synchronize storage
5329 m_vertices.sync();
5330
5331 return true;
5332}
5333
5340{
5342 return false;
5343 }
5344
5345 // Sort internal cells
5346 if (m_nInternalCells > 0) {
5347 m_cells.sortBefore(m_lastInternalCellId, true);
5349 }
5350
5351#if BITPIT_ENABLE_MPI==1
5352 // Sort ghost cells
5353 if (m_nGhostCells > 0) {
5354 m_cells.sortAfter(m_firstGhostCellId, true);
5356 }
5357#endif
5358
5359 // Synchronize storage
5360 m_cells.sync();
5361
5362 return true;
5363}
5364
5369{
5371 return false;
5372 }
5373
5374 m_interfaces.sort();
5375
5376 m_interfaces.sync();
5377
5378 return true;
5379}
5380
5386{
5387 bool status = sortVertices();
5388 status |= sortCells();
5389 status |= sortInterfaces();
5390
5391 return status;
5392}
5393
5402{
5404 return false;
5405 }
5406
5407 m_vertices.squeeze();
5408
5409 m_vertices.sync();
5410
5411 return true;
5412}
5413
5422{
5424 return false;
5425 }
5426
5427 m_cells.squeeze();
5428
5429 m_cells.sync();
5430
5431 return true;
5432}
5433
5442{
5444 return false;
5445 }
5446
5447 m_interfaces.squeeze();
5448
5449 m_interfaces.sync();
5450
5451 return true;
5452}
5453
5462{
5463 bool status = true;
5464
5465 // Alteration flags
5466 if (m_alteredCells.empty()) {
5467 AlterationFlagsStorage().swap(m_alteredCells);
5468 }
5469
5470 if (m_alteredInterfaces.empty()) {
5471 AlterationFlagsStorage().swap(m_alteredInterfaces);
5472 }
5473
5474 // Vertices
5475 status |= squeezeVertices();
5476
5477 // Cells
5478 status |= squeezeCells();
5479
5480 // Interfaces
5481 status |= squeezeInterfaces();
5482
5483 return status;
5484}
5485
5492std::array<double, 3> PatchKernel::evalCellCentroid(long id) const
5493{
5494 const Cell &cell = getCell(id);
5495
5496 return evalElementCentroid(cell);
5497}
5498
5506void PatchKernel::evalCellBoundingBox(long id, std::array<double,3> *minPoint, std::array<double,3> *maxPoint) const
5507{
5508 const Cell &cell = getCell(id);
5509
5510 evalElementBoundingBox(cell, minPoint, maxPoint);
5511}
5512
5519ConstProxyVector<std::array<double, 3>> PatchKernel::getCellVertexCoordinates(long id) const
5520{
5521 // Get the vertices ids
5522 const Cell &cell = getCell(id);
5523 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
5524 const int nCellVertices = cellVertexIds.size();
5525
5526 // Build the proxy vector with the coordinates
5527 ConstProxyVector<std::array<double, 3>> vertexCoordinates(ConstProxyVector<std::array<double, 3>>::INTERNAL_STORAGE, nCellVertices);
5528 ConstProxyVector<std::array<double, 3>>::storage_pointer storage = vertexCoordinates.storedData();
5529 getVertexCoords(cellVertexIds.size(), cellVertexIds.data(), storage);
5530
5531 return vertexCoordinates;
5532}
5533
5540void PatchKernel::getCellVertexCoordinates(long id, std::unique_ptr<std::array<double, 3>[]> *coordinates) const
5541{
5542 const Cell &cell = getCell(id);
5543
5544 getElementVertexCoordinates(cell, coordinates);
5545}
5546
5555void PatchKernel::getCellVertexCoordinates(long id, std::array<double, 3> *coordinates) const
5556{
5557 const Cell &cell = getCell(id);
5558
5559 getElementVertexCoordinates(cell, coordinates);
5560}
5561
5568std::array<double, 3> PatchKernel::evalInterfaceCentroid(long id) const
5569{
5570 const Interface &interface = getInterface(id);
5571
5572 return evalElementCentroid(interface);
5573}
5574
5582void PatchKernel::evalInterfaceBoundingBox(long id, std::array<double,3> *minPoint, std::array<double,3> *maxPoint) const
5583{
5584 const Interface &interface = getInterface(id);
5585
5586 evalElementBoundingBox(interface, minPoint, maxPoint);
5587}
5588
5595ConstProxyVector<std::array<double, 3>> PatchKernel::getInterfaceVertexCoordinates(long id) const
5596{
5597 // Get the vertices ids
5598 const Interface &interface = getInterface(id);
5599 ConstProxyVector<long> interfaceVertexIds = interface.getVertexIds();
5600 const int nInterfaceVertices = interfaceVertexIds.size();
5601
5602 // Build the proxy vector with the coordinates
5603 ConstProxyVector<std::array<double, 3>> vertexCoordinates(ConstProxyVector<std::array<double, 3>>::INTERNAL_STORAGE, nInterfaceVertices);
5604 ConstProxyVector<std::array<double, 3>>::storage_pointer storage = vertexCoordinates.storedData();
5605 getVertexCoords(interfaceVertexIds.size(), interfaceVertexIds.data(), storage);
5606
5607 return vertexCoordinates;
5608}
5609
5616void PatchKernel::getInterfaceVertexCoordinates(long id, std::unique_ptr<std::array<double, 3>[]> *coordinates) const
5617{
5618 const Interface &interface = getInterface(id);
5619
5620 getElementVertexCoordinates(interface, coordinates);
5621}
5622
5631void PatchKernel::getInterfaceVertexCoordinates(long id, std::array<double, 3> *coordinates) const
5632{
5633 const Interface &interface = getInterface(id);
5634
5635 getElementVertexCoordinates(interface, coordinates);
5636}
5637
5657bool PatchKernel::intersectInterfacePlane(long id, std::array<double, 3> P, std::array<double, 3> nP,
5658 std::array<std::array<double, 3>, 2> *intersection,
5659 std::vector<std::array<double, 3>> *polygon) const
5660{
5661 double distanceTolerance = getTol();
5662
5663 const Interface &interface = getInterface(id);
5664 ElementType interfaceType = interface.getType();
5665 switch (interfaceType)
5666 {
5667
5668 case ElementType::LINE:
5669 {
5670 const std::array<double, 3> &P0 = getVertexCoords(interface.getVertexId(0));
5671 const std::array<double, 3> &P1 = getVertexCoords(interface.getVertexId(1));
5672
5673 std::array<double, 3> x;
5674 bool intersectionFound = CGElem::intersectSegmentPlane(P0, P1, P, nP, x, distanceTolerance);
5675
5676 if (norm2(x - P0) < distanceTolerance) return false;
5677 if (norm2(x - P1) < distanceTolerance) return false;
5678
5679 if (!intersectionFound) return false;
5680
5681 (*intersection)[0] = x;
5682 (*intersection)[1] = x;
5683 if (dotProduct(P - P0, nP) > 0.) {
5684 polygon->push_back(P0);
5685 polygon->push_back(x);
5686 return true;
5687 }
5688 polygon->push_back(x);
5689 polygon->push_back(P1);
5690 return true;
5691 }
5692
5693 case ElementType::TRIANGLE:
5694 {
5695 const std::array<double, 3> &P0 = getVertexCoords(interface.getVertexId(0));
5696 const std::array<double, 3> &P1 = getVertexCoords(interface.getVertexId(1));
5697 const std::array<double, 3> &P2 = getVertexCoords(interface.getVertexId(2));
5698
5699 return CGElem::intersectPlaneTriangle(P0, P1, P2, P, nP,
5700 *intersection, *polygon, distanceTolerance);
5701 }
5702
5703 case ElementType::PIXEL:
5704 {
5705 // evaluate pixel normal
5706 std::unique_ptr<std::array<double, 3>[]> coordinates;
5707 getElementVertexCoordinates(interface, &coordinates);
5708
5709 return CGElem::intersectPlanePixel(P, nP, coordinates.get(),
5710 *intersection, *polygon, distanceTolerance);
5711 }
5712
5713 default:
5714 {
5715
5716 assert(interfaceType != ElementType::UNDEFINED);
5717 const Reference2DElementInfo &interfaceInfo = static_cast<const Reference2DElementInfo &>(ReferenceElementInfo::getInfo(interfaceType));
5718
5719 ConstProxyVector<long> vertexIds = interface.getVertexIds();
5720 int nVertices = vertexIds.size();
5721
5722 std::vector<std::array<double, 3>> coordinates(nVertices);
5723 for (int i = 0; i < nVertices; ++i) {
5724 long vertexId = vertexIds[interfaceInfo.getCCWOrderedVertex(i)];
5725 coordinates[i] = getVertex(vertexId).getCoords();
5726 }
5727
5728 std::vector<std::array<std::array<double, 3>, 2>> intersections;
5729 std::vector< std::vector<std::array<double, 3>>> polygons;
5730 bool intersectionFound = CGElem::intersectPlanePolygon(P, nP, nVertices, coordinates.data(),
5731 intersections, polygons, distanceTolerance);
5732
5733 if (intersections.size() > 1) {
5734 throw std::runtime_error("Intersection of concave interfaces is not supported.");
5735 }
5736
5737 (*intersection) = intersections[0];
5738 (*polygon) = polygons[0];
5739
5740 return intersectionFound;
5741 }
5742
5743 }
5744 return false;
5745}
5746
5756std::array<double, 3> PatchKernel::evalElementCentroid(const Element &element) const
5757{
5758 ConstProxyVector<long> elementVertexIds = element.getVertexIds();
5759 std::size_t nCellVertices = elementVertexIds.size();
5760 BITPIT_CREATE_WORKSPACE(vertexCoordinates, std::array<double BITPIT_COMMA 3>, nCellVertices, ReferenceElementInfo::MAX_ELEM_VERTICES);
5761 getVertexCoords(nCellVertices, elementVertexIds.data(), vertexCoordinates);
5762
5763 return element.evalCentroid(vertexCoordinates);
5764}
5765
5773void PatchKernel::evalElementBoundingBox(const Element &element, std::array<double,3> *minPoint, std::array<double,3> *maxPoint) const
5774{
5775 ElementType elementType = element.getType();
5776 switch (elementType)
5777 {
5778
5779 case ElementType::VERTEX:
5780 {
5781 const long *elementConnect = element.getConnect();
5782 *minPoint = getVertexCoords(elementConnect[0]);
5783 *maxPoint = *minPoint;
5784 break;
5785 }
5786
5787 case ElementType::PIXEL:
5788 {
5789 const long *elementConnect = element.getConnect();
5790
5791 const std::array<double, 3> &vertexCoord_0 = getVertexCoords(elementConnect[0]);
5792 const std::array<double, 3> &vertexCoord_3 = getVertexCoords(elementConnect[3]);
5793
5794 for (int d = 0; d < 3; ++d) {
5795 (*minPoint)[d] = std::min(vertexCoord_0[d], vertexCoord_3[d]);
5796 (*maxPoint)[d] = std::max(vertexCoord_0[d], vertexCoord_3[d]);
5797 }
5798
5799 break;
5800 }
5801
5802 case ElementType::VOXEL:
5803 {
5804 const long *elementConnect = element.getConnect();
5805
5806 const std::array<double, 3> &vertexCoord_0 = getVertexCoords(elementConnect[0]);
5807 const std::array<double, 3> &vertexCoord_7 = getVertexCoords(elementConnect[7]);
5808
5809 for (int d = 0; d < 3; ++d) {
5810 (*minPoint)[d] = std::min(vertexCoord_0[d], vertexCoord_7[d]);
5811 (*maxPoint)[d] = std::max(vertexCoord_0[d], vertexCoord_7[d]);
5812 }
5813
5814 break;
5815 }
5816
5817 default:
5818 {
5819 ConstProxyVector<long> elementVertexIds = element.getVertexIds();
5820 const int nElementVertices = elementVertexIds.size();
5821
5822 *minPoint = getVertexCoords(elementVertexIds[0]);
5823 *maxPoint = *minPoint;
5824 for (int i = 1; i < nElementVertices; ++i) {
5825 const std::array<double, 3> &vertexCoord = getVertexCoords(elementVertexIds[i]);
5826 for (int d = 0; d < 3; ++d) {
5827 (*minPoint)[d] = std::min(vertexCoord[d], (*minPoint)[d]);
5828 (*maxPoint)[d] = std::max(vertexCoord[d], (*maxPoint)[d]);
5829 }
5830 }
5831
5832 break;
5833 }
5834
5835 }
5836}
5837
5850long PatchKernel::locatePoint(double x, double y, double z) const
5851{
5852 return locatePoint({{x, y, z}});
5853}
5854
5865bool PatchKernel::isSameFace(const Cell &cell_A, int face_A, const Cell &cell_B, int face_B) const
5866{
5867 if (cell_A.getFaceType(face_A) != cell_B.getFaceType(face_B)) {
5868 return false;
5869 }
5870
5871 int nFaceVertices = cell_A.getFaceVertexCount(face_A);
5872
5873 std::vector<long> faceVertexIds_A(nFaceVertices);
5874 std::vector<long> faceVertexIds_B(nFaceVertices);
5875 for (int k = 0; k < nFaceVertices; ++k) {
5876 faceVertexIds_A[k] = cell_A.getFaceVertexId(face_A, k);
5877 faceVertexIds_B[k] = cell_B.getFaceVertexId(face_B, k);
5878 }
5879
5880 std::sort(faceVertexIds_A.begin(), faceVertexIds_A.end());
5881 std::sort(faceVertexIds_B.begin(), faceVertexIds_B.end());
5882
5883 return (faceVertexIds_A == faceVertexIds_B);
5884}
5885
5892{
5893 return m_adjacenciesBuildStrategy;
5894}
5895
5902{
5903 m_adjacenciesBuildStrategy = status;
5904}
5905
5914{
5915 if (getAdjacenciesBuildStrategy() == ADJACENCIES_NONE) {
5916 return false;
5917 }
5918
5919 bool areDirty = false;
5920 for (const auto &entry : m_alteredCells) {
5921 AlterationFlags cellAlterationFlags = entry.second;
5922 if (testAlterationFlags(cellAlterationFlags, FLAG_ADJACENCIES_DIRTY)) {
5923 areDirty = true;
5924 break;
5925 }
5926 }
5927
5928#if BITPIT_ENABLE_MPI==1
5929 if (global && isPartitioned()) {
5930 const auto &communicator = getCommunicator();
5931 MPI_Allreduce(MPI_IN_PLACE, &areDirty, 1, MPI_C_BOOL, MPI_LOR, communicator);
5932 }
5933#else
5934 BITPIT_UNUSED(global);
5935#endif
5936
5937 return areDirty;
5938}
5939
5947{
5948 initializeAdjacencies(ADJACENCIES_AUTOMATIC);
5949}
5950
5960{
5961 // Get current build stategy
5963
5964 // Early return if we don't need adjacencies
5965 if (strategy == ADJACENCIES_NONE) {
5966 if (currentStrategy != ADJACENCIES_NONE) {
5968 }
5969
5970 return;
5971 }
5972
5973 // Update the build strategy
5974 if (currentStrategy != strategy) {
5976 }
5977
5978 // Reset adjacencies
5980
5981 // Update the adjacencies
5983}
5984
5991void PatchKernel::updateAdjacencies(bool forcedUpdated)
5992{
5993 // Early return if adjacencies are not built
5995 if (currentStrategy == ADJACENCIES_NONE) {
5996 return;
5997 }
5998
5999 // Check if the adjacencies are dirty
6000 bool adjacenciesDirty = areAdjacenciesDirty();
6001 if (!adjacenciesDirty && !forcedUpdated) {
6002 return;
6003 }
6004
6005 // Update adjacencies
6006 if (adjacenciesDirty) {
6007 // Prune stale adjacencies
6009
6010 // Update adjacencies
6012
6013 // Adjacencies are now updated
6014 unsetCellAlterationFlags(FLAG_ADJACENCIES_DIRTY);
6015 } else {
6016 initializeAdjacencies(currentStrategy);
6017 }
6018}
6019
6027{
6028 // Early return if no adjacencies have been built
6029 if (getAdjacenciesBuildStrategy() == ADJACENCIES_NONE) {
6030 return;
6031 }
6032
6033 // Destroy the adjacencies
6034 _resetAdjacencies(true);
6035
6036 // Clear list of cells with dirty adjacencies
6037 unsetCellAlterationFlags(FLAG_ADJACENCIES_DIRTY);
6038
6039 // Set adjacencies status
6040 setAdjacenciesBuildStrategy(ADJACENCIES_NONE);
6041}
6042
6050{
6051 // Early return if no adjacencies have been built
6052 if (getAdjacenciesBuildStrategy() == ADJACENCIES_NONE) {
6053 return;
6054 }
6055
6056 // Reset adjacencies
6057 _resetAdjacencies(false);
6058
6059 // All cells have now dirty adjacencies
6060 setCellAlterationFlags(FLAG_ADJACENCIES_DIRTY);
6061}
6062
6073{
6074 for (Cell &cell : m_cells) {
6075 cell.resetAdjacencies(!release);
6076 }
6077}
6078
6086{
6087 // Early return if adjacencies are not built
6089 if (currentStrategy == ADJACENCIES_NONE) {
6090 return;
6091 }
6092
6093 // Remove stale adjacencies
6094 for (const auto &entry : m_alteredCells) {
6095 AlterationFlags cellAlterationFlags = entry.second;
6096 if (!testAlterationFlags(cellAlterationFlags, FLAG_ADJACENCIES_DIRTY)) {
6097 continue;
6098 }
6099
6100 long cellId = entry.first;
6101 Cell &cell = m_cells.at(cellId);
6102 if (cell.getAdjacencyCount() == 0) {
6103 continue;
6104 }
6105
6106 int nCellFaces = cell.getFaceCount();
6107 for (int face = nCellFaces - 1; face >= 0; --face) {
6108 long *faceAdjacencies = cell.getAdjacencies(face);
6109 int nFaceAdjacencies = cell.getAdjacencyCount(face);
6110 for (int i = nFaceAdjacencies - 1; i >= 0; --i) {
6111 long adjacency = faceAdjacencies[i];
6112 if (!testCellAlterationFlags(adjacency, FLAG_DELETED)) {
6113 continue;
6114 }
6115
6116 cell.deleteAdjacency(face, i);
6117 }
6118 }
6119 }
6120}
6121
6131{
6132 int dimension = getDimension();
6133
6134 // Check if multiple adjacencies are allowed
6135 //
6136 // On a three-dimensional patch each internal face is shared between two,
6137 // and only two, half-faces. On lower dimension patches one internal face
6138 // may be shared among multiple half-faces (this happens with non-manifold
6139 // patches).
6140 bool multipleMatchesAllowed = (dimension < 3);
6141
6142 // Define matching windings
6143 //
6144 // If faces can be shared only between two half-faces, there is a one-to-one
6145 // correspondence between the half-faces. Give one half-faces, its matching
6146 // can be found looking for an half-faces with the same vertices but with
6147 // reverse vertex winding order.
6148 //
6149 // If faces can be shared among more than two half-faces, it's not anymore
6150 // possible to define a unique winding order for the vertices of the faces.
6151 // There is no more a one-to-one correspondence between pairs of half-face.
6152 // In this case, when looking for half-face correspondence, it is necessary
6153 // to look for half-faces with reverse vertex winding order and also for
6154 // half-faces with the same vertex winding order.
6155 std::vector<CellHalfFace::Winding> matchingWindings;
6156 matchingWindings.push_back(CellHalfFace::WINDING_REVERSE);
6157 if (multipleMatchesAllowed) {
6158 matchingWindings.push_back(CellHalfFace::WINDING_NATURAL);
6159 }
6160
6161 // Count cells with dirty adjacencies
6162 long nDirtyAdjacenciesCells = 0;
6163 for (const auto &entry : m_alteredCells) {
6164 AlterationFlags cellAlterationFlags = entry.second;
6165 if (!testAlterationFlags(cellAlterationFlags, FLAG_ADJACENCIES_DIRTY)) {
6166 continue;
6167 }
6168
6169 ++nDirtyAdjacenciesCells;
6170 }
6171
6172 // Get the vertices of cells with dirty adjacencies
6173 //
6174 // The list is only needed if multiple matches are allowed and there are
6175 // cells whose adjacencies don't need to be updated.
6176 std::unique_ptr<PiercedStorage<bool, long>> dirtyAdjacenciesVertices;
6177 if (multipleMatchesAllowed && (nDirtyAdjacenciesCells != getCellCount())) {
6178 dirtyAdjacenciesVertices = std::unique_ptr<PiercedStorage<bool, long>>(new PiercedStorage<bool, long>(1, &m_vertices));
6179 dirtyAdjacenciesVertices->fill(false);
6180 for (const auto &entry : m_alteredCells) {
6181 AlterationFlags cellAlterationFlags = entry.second;
6182 if (!testAlterationFlags(cellAlterationFlags, FLAG_ADJACENCIES_DIRTY)) {
6183 continue;
6184 }
6185
6186 long cellId = entry.first;
6187 const Cell &cell = m_cells.at(cellId);
6188 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
6189 for (long vertexId : cellVertexIds) {
6190 dirtyAdjacenciesVertices->at(vertexId) = true;
6191 }
6192 }
6193 }
6194
6195 // List the cells that needs to be processed
6196 //
6197 // The list should contain the cells whose adjacencies need to be updated
6198 // and their neighbours candidates.
6199 //
6200 // Cells whose adjacencies needs to be updated are cells having the dirty
6201 // adjaceny flag set.
6202 //
6203 // Neighbours candidates are all border cells and, if multiple matches are
6204 // allowed, cells that share vertices with a cell with dirty adjacencies.
6205 std::vector<Cell *> processList;
6206 processList.reserve(nDirtyAdjacenciesCells);
6207
6208 std::size_t nMaxHalfFaces = 0;
6209 for (Cell &cell : m_cells) {
6210 // Get cell information
6211 long cellId = cell.getId();
6212 int nCellFaces = cell.getFaceCount();
6213
6214 // Add cells with dirty adjacencies
6215 if (testCellAlterationFlags(cellId, FLAG_ADJACENCIES_DIRTY)) {
6216 nMaxHalfFaces += nCellFaces;
6217 processList.push_back(&cell);
6218 continue;
6219 }
6220
6221 // Add border cells
6222 bool isBorderCell = false;
6223 for (int face = 0; face < nCellFaces; face++) {
6224 if (cell.isFaceBorder(face)) {
6225 isBorderCell = true;
6226 continue;
6227 }
6228 }
6229
6230 if (isBorderCell) {
6231 nMaxHalfFaces += nCellFaces;
6232 processList.push_back(&cell);
6233 continue;
6234 }
6235
6236 // Add cell that share vertices with a cell with dirty adjacencies
6237 //
6238 // For performace reasons, the check is a bit rough. All cells that
6239 // share a number of vertices at least equal to the dimension af the
6240 // patch will be added to the process list. This will add also cells
6241 // that are not neighbour candidates, but it's faster to add some false
6242 // positives, rather trying to filter them out.
6243 if (multipleMatchesAllowed) {
6244 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
6245
6246 int nCelldirtyAdjacenciesVertices = 0;
6247 bool futureNeighbourCandidate = false;
6248 for (long vertexId : cellVertexIds) {
6249 if (dirtyAdjacenciesVertices->at(vertexId)) {
6250 ++nCelldirtyAdjacenciesVertices;
6251 if (nCelldirtyAdjacenciesVertices >= dimension) {
6252 futureNeighbourCandidate = true;
6253 break;
6254 }
6255 }
6256 }
6257
6258 if (futureNeighbourCandidate) {
6259 nMaxHalfFaces += nCellFaces;
6260 processList.push_back(&cell);
6261 }
6262 }
6263 }
6264
6265 // Create the adjacencies
6266 std::unordered_set<CellHalfFace, CellHalfFace::Hasher> halfFaces;
6267 halfFaces.reserve(static_cast<std::size_t>(0.5 * nMaxHalfFaces));
6268
6269 std::vector<std::pair<Cell *, int>> matchingAdjacencies;
6270 for (Cell *cell : processList) {
6271 long cellId = cell->getId();
6272 const int nCellFaces = cell->getFaceCount();
6273 bool areCellAdjacenciesDirty = testCellAlterationFlags(cellId, FLAG_ADJACENCIES_DIRTY);
6274 for (int face = 0; face < nCellFaces; face++) {
6275 // Generate the half-face
6276 CellHalfFace halfFace(*cell, face);
6277
6278 // Find matching half-face
6279 auto matchingHalfFaceItr = halfFaces.end();
6280 for (CellHalfFace::Winding winding : matchingWindings) {
6281 // Set winding order
6282 halfFace.setWinding(winding);
6283
6284 // Search for matching half-face
6285 matchingHalfFaceItr = halfFaces.find(halfFace);
6286 if (matchingHalfFaceItr != halfFaces.end()) {
6287 break;
6288 }
6289 }
6290
6291 // Early return if no matching half-face has been found
6292 //
6293 // If no matching half-face has been found, we need to add the
6294 // current half-face to the list because it may match the face
6295 // of a cell that will be processed later.
6296 if (matchingHalfFaceItr == halfFaces.end()) {
6297 halfFace.setWinding(CellHalfFace::WINDING_NATURAL);
6298 halfFaces.insert(std::move(halfFace));
6299 continue;
6300 }
6301
6302 // Get matching half-face information
6303 const CellHalfFace &matchingHalfFace = *matchingHalfFaceItr;
6304 Cell &matchingCell = matchingHalfFace.getCell();
6305 long matchingCellId = matchingCell.getId();
6306 long matchingFace = matchingHalfFace.getFace();
6307
6308 // Only process cells with dirty adjacencies
6309 //
6310 // In order to limit the half faces that need to be stored, we are
6311 // processing at the same time cells with dirty adjacencies and
6312 // their neighbour candidates. This means we will also find matches
6313 // between faces of cell whose adjacensies are already up-to-date.
6314 bool areMatchingCellAdjacenciesDirty = testCellAlterationFlags(matchingCellId, FLAG_ADJACENCIES_DIRTY);
6315 if (!areCellAdjacenciesDirty && !areMatchingCellAdjacenciesDirty) {
6316 continue;
6317 }
6318
6319 // Identifty matching adjacencies
6320 //
6321 // If multiple matches are allowed, in addition to the entry
6322 // related to the matching half face, we also need to add the
6323 // entries associated to the adjacencies already identified
6324 // for the half face.
6325 matchingAdjacencies.clear();
6326 matchingAdjacencies.emplace_back(std::make_pair<Cell *, int>(&matchingCell, matchingFace));
6327 if (multipleMatchesAllowed) {
6328 const int nMachingFaceNeighs = matchingCell.getAdjacencyCount(matchingFace);
6329 const long *machingFaceNeighs = matchingCell.getAdjacencies(matchingFace);
6330 for (int k = 0; k < nMachingFaceNeighs; ++k) {
6331 long neighId = machingFaceNeighs[k];
6332 if (neighId == cellId) {
6333 continue;
6334 }
6335
6336 Cell &neigh = m_cells.at(neighId);
6337 int neighFace = findAdjoinNeighFace(matchingCell, matchingFace, neigh);
6338 matchingAdjacencies.emplace_back(std::make_pair<Cell *, int>(&neigh, std::move(neighFace)));
6339 }
6340 } else {
6341 // When cell adjacencies are makred dirty this means that some
6342 // adjacencies are dirty not that all adjacencies are dirty.
6343 // The matchin cell may have no adjaceny associated to the
6344 // matching face or a signle adjacency that should match
6345 // the current cell.
6346 assert(matchingCell.getAdjacencyCount(matchingFace) == 0 || (matchingCell.getAdjacencyCount(matchingFace) == 1 && (*(matchingCell.getAdjacencies(matchingFace)) == cellId)));
6347 }
6348
6349 // Create adjacencies
6350 for (const std::pair<Cell *, int> &matchingAdjacency : matchingAdjacencies) {
6351 Cell *adjacentCell = matchingAdjacency.first;
6352 long adjacentCellId = adjacentCell->getId();
6353 int adjacentFace = matchingAdjacency.second;
6354
6355 cell->pushAdjacency(face, adjacentCellId);
6356 adjacentCell->pushAdjacency(adjacentFace, cellId);
6357 }
6358
6359 // Remove the matching half-face from the list
6360 //
6361 // If multiple matches are allowed, we need to keep the half
6362 // face, because that entry may match the face of a cell that
6363 // will be processed later.
6364 if (!multipleMatchesAllowed) {
6365 halfFaces.erase(matchingHalfFaceItr);
6366 }
6367 }
6368 }
6369}
6370
6377{
6378 return m_interfacesBuildStrategy;
6379}
6380
6387{
6388 if (status == INTERFACES_AUTOMATIC) {
6390 throw std::runtime_error("Automatic build strategy requires auto-indexing.");
6391 }
6392 }
6393
6394 m_interfacesBuildStrategy = status;
6395}
6396
6404bool PatchKernel::areInterfacesDirty(bool global) const
6405{
6406 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
6407 return false;
6408 }
6409
6410 bool areDirty = !m_alteredInterfaces.empty();
6411 if (!areDirty) {
6412 for (const auto &entry : m_alteredCells) {
6413 AlterationFlags cellAlterationFlags = entry.second;
6414 if (testAlterationFlags(cellAlterationFlags, FLAG_INTERFACES_DIRTY)) {
6415 areDirty = true;
6416 break;
6417 }
6418 }
6419 }
6420
6421#if BITPIT_ENABLE_MPI==1
6422 if (global && isPartitioned()) {
6423 const auto &communicator = getCommunicator();
6424 MPI_Allreduce(MPI_IN_PLACE, &areDirty, 1, MPI_C_BOOL, MPI_LOR, communicator);
6425 }
6426#else
6427 BITPIT_UNUSED(global);
6428#endif
6429
6430 return areDirty;
6431}
6432
6440{
6441 initializeInterfaces(INTERFACES_AUTOMATIC);
6442}
6443
6456{
6457 // Interfaces need adjacencies
6458 if (getAdjacenciesBuildStrategy() == ADJACENCIES_NONE) {
6459 throw std::runtime_error ("Adjacencies are mandatory for building the interfaces.");
6460 }
6461
6462 // Get current build stategy
6464
6465 // Early return if we don't need interfaces
6466 if (strategy == INTERFACES_NONE) {
6467 if (currentStrategy != INTERFACES_NONE) {
6469 }
6470
6471 return;
6472 }
6473
6474 // Update the build strategy
6475 if (currentStrategy != strategy) {
6477 }
6478
6479 // Reset interfaces
6481
6482 // Update the interfaces
6484}
6485
6492void PatchKernel::updateInterfaces(bool forcedUpdated)
6493{
6494 // Early return if interfaces are not built
6496 if (currentStrategy == INTERFACES_NONE) {
6497 return;
6498 }
6499
6500 // Check if the interfaces are dirty
6501 bool interfacesDirty = areInterfacesDirty();
6502 if (!interfacesDirty && !forcedUpdated) {
6503 return;
6504 }
6505
6506 // Interfaces need up-to-date adjacencies
6507 assert(getAdjacenciesBuildStrategy() != ADJACENCIES_NONE);
6509
6510 // Update interfaces
6511 if (interfacesDirty) {
6512 // Enable manual adaption
6513 AdaptionMode previousAdaptionMode = getAdaptionMode();
6515
6516 // Prune stale interfaces
6518
6519 // Update interfaces
6521
6522 // Interfaces are now updated
6523 unsetCellAlterationFlags(FLAG_INTERFACES_DIRTY);
6524 m_alteredInterfaces.clear();
6525
6526 // Restore previous adaption mode
6527 setAdaptionMode(previousAdaptionMode);
6528 } else {
6529 initializeInterfaces(currentStrategy);
6530 }
6531}
6532
6540{
6541 // Early return if no interfaces have been built
6542 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
6543 return;
6544 }
6545
6546 // Destroy the interfaces
6547 _resetInterfaces(true);
6548
6549 // Clear list of cells with dirty interfaces
6550 unsetCellAlterationFlags(FLAG_INTERFACES_DIRTY);
6551
6552 // Clear list of altered interfaces
6553 m_alteredInterfaces.clear();
6554
6555 // Set interface build strategy
6556 setInterfacesBuildStrategy(INTERFACES_NONE);
6557}
6558
6566{
6567 // Early return if no interfaces have been built
6568 if (getInterfacesBuildStrategy() == INTERFACES_NONE) {
6569 return;
6570 }
6571
6572 // Remove dangling interfaces from cells
6573 for (const auto &entry : m_alteredCells) {
6574 AlterationFlags cellAlterationFlags = entry.second;
6575 if (!testAlterationFlags(cellAlterationFlags, FLAG_INTERFACES_DIRTY)) {
6576 continue;
6577 }
6578
6579 long cellId = entry.first;
6580 Cell &cell = m_cells.at(cellId);
6581 if (cell.getInterfaceCount() == 0) {
6582 continue;
6583 }
6584
6585 int nCellFaces = cell.getFaceCount();
6586 for (int face = nCellFaces - 1; face >= 0; --face) {
6587 long *faceInterfaces = cell.getInterfaces(face);
6588 int nFaceInterfaces = cell.getInterfaceCount(face);
6589 for (int i = nFaceInterfaces - 1; i >= 0; --i) {
6590 long interfaceId = faceInterfaces[i];
6591 if (!testInterfaceAlterationFlags(interfaceId, FLAG_DANGLING)) {
6592 continue;
6593 }
6594
6595 // Delete the interface from the cell
6596 cell.deleteInterface(face, i);
6597 }
6598 }
6599 }
6600
6601 // Delete dangling interfaces
6602 std::vector<long> danglingInterfaces;
6603 danglingInterfaces.reserve(m_alteredInterfaces.size());
6604 for (const auto &entry : m_alteredInterfaces) {
6605 AlterationFlags interfaceAlterationFlags = entry.second;
6606 if (!testAlterationFlags(interfaceAlterationFlags, FLAG_DANGLING)) {
6607 continue;
6608 }
6609
6610 long interfaceId = entry.first;
6611 danglingInterfaces.push_back(interfaceId);
6612 }
6613 deleteInterfaces(danglingInterfaces);
6614}
6615
6623{
6624 // Update interfaces
6625 //
6626 // Adjacencies and interfaces of a face are paired: the i-th face adjacency
6627 // corresponds to the i-th face interface. Moreover if we loop through the
6628 // adjacencies of a face, the adjacencies that have an interface are always
6629 // listed first. This meas that, to update the interfaces, we can count the
6630 // interfaces already associated to a face and loop only on the adjacencies
6631 // which have an index past the one of the last interface.
6632 //
6633 // On border faces of internal cells we need to build an interface, also
6634 // if there are no adjacencies.
6635 for (const auto &entry : m_alteredCells) {
6636 AlterationFlags cellAlterationFlags = entry.second;
6637 if (!testAlterationFlags(cellAlterationFlags, FLAG_INTERFACES_DIRTY)) {
6638 continue;
6639 }
6640
6641 long cellId = entry.first;
6642 Cell &cell = m_cells.at(cellId);
6643 const int nCellFaces = cell.getFaceCount();
6644 for (int face = 0; face < nCellFaces; face++) {
6645 int nFaceInterfaces= cell.getInterfaceCount(face);
6646
6647 bool isFaceBorder = cell.isFaceBorder(face);
6648 if (!isFaceBorder) {
6649 // Find the range of adjacencies that need an interface
6650 int updateEnd = cell.getAdjacencyCount(face);
6651 int updateBegin = nFaceInterfaces;
6652 if (updateBegin == updateEnd) {
6653 continue;
6654 }
6655
6656 // Build an interface for every adjacency
6657 const long *faceAdjacencies = cell.getAdjacencies(face);
6658 for (int k = updateBegin; k < updateEnd; ++k) {
6659 long neighId = faceAdjacencies[k];
6660 Cell *neigh = &m_cells[neighId];
6661
6662 int neighFace = findAdjoinNeighFace(cell, face, *neigh);
6663
6664 buildCellInterface(&cell, face, neigh, neighFace);
6665 }
6666 } else if (nFaceInterfaces == 0) {
6667 // Internal borderes need an interface
6668 buildCellInterface(&cell, face, nullptr, -1);
6669 }
6670 }
6671 }
6672}
6673
6688PatchKernel::InterfaceIterator PatchKernel::buildCellInterface(Cell *cell_1, int face_1, Cell *cell_2, int face_2, long interfaceId)
6689{
6690 // Validate the input
6691 assert(cell_1);
6692 assert(face_1 >= 0);
6693
6694 if (cell_2) {
6695 assert(face_2 >= 0);
6696 } else {
6697 assert(face_2 < 0);
6698 }
6699
6700 // Get the id of the first cell
6701 long id_1 = cell_1->getId();
6702
6703 // Get the id of the second cell
6704 long id_2 = Cell::NULL_ID;
6705 if (cell_2) {
6706 id_2 = cell_2->getId();
6707 }
6708
6709 // Owner and neighbour of the interface
6710 //
6711 // The interface is owned by the cell that has only one adjacency, i.e.,
6712 // by the cell that owns the smallest of the two faces. If the faces
6713 // of both cells have the same size, the interface is owned by the cell
6714 // with the "lower fuzzy positioning". It is not necessary to have a
6715 // precise comparison, it's only necessary to define a repeatable order
6716 // between the two cells. It is therefore possible to use the "fuzzy"
6717 // cell comparison.
6718 bool cellOwnsInterface = true;
6719 if (cell_2) {
6720 if (cell_1->getAdjacencyCount(face_1) > 1) {
6721 cellOwnsInterface = false;
6722 } else if (cell_2->getAdjacencyCount(face_2) == 1) {
6723 assert(cell_1->getAdjacencyCount(face_1) == 1);
6724 cellOwnsInterface = CellFuzzyPositionLess(*this)(id_1, id_2);
6725 }
6726 }
6727
6728 Cell *intrOwner;
6729 Cell *intrNeigh;
6730 long intrOwnerId;
6731 long intrNeighId;
6732 int intrOwnerFace;
6733 int intrNeighFace;
6734 if (cellOwnsInterface) {
6735 intrOwnerId = id_1;
6736 intrOwner = cell_1;
6737 intrOwnerFace = face_1;
6738
6739 if (cell_2) {
6740 intrNeighId = id_2;
6741 intrNeigh = cell_2;
6742 intrNeighFace = face_2;
6743 } else {
6744 intrNeighId = Cell::NULL_ID;
6745 intrNeigh = nullptr;
6746 intrNeighFace = -1;
6747 }
6748 } else {
6749 intrOwnerId = id_2;
6750 intrOwner = cell_2;
6751 intrOwnerFace = face_2;
6752
6753 intrNeighId = id_1;
6754 intrNeigh = cell_1;
6755 intrNeighFace = face_1;
6756 }
6757
6758 // Connectivity of the interface
6759 ConstProxyVector<long> faceConnect = intrOwner->getFaceConnect(intrOwnerFace);
6760
6761 int nInterfaceVertices = faceConnect.size();
6762 std::unique_ptr<long[]> interfaceConnect = std::unique_ptr<long[]>(new long[nInterfaceVertices]);
6763 for (int k = 0; k < nInterfaceVertices; ++k) {
6764 interfaceConnect[k] = faceConnect[k];
6765 }
6766
6767 // Create the interface
6768 Interface *interface;
6769 InterfaceIterator interfaceIterator;
6770
6771 ElementType interfaceType = intrOwner->getFaceType(intrOwnerFace);
6772 if (interfaceId < 0) {
6773 interfaceIterator = addInterface(interfaceType, std::move(interfaceConnect), interfaceId);
6774 interface = &(*interfaceIterator);
6775 interfaceId = interface->getId();
6776 } else {
6777 interfaceIterator = restoreInterface(interfaceType, std::move(interfaceConnect), interfaceId);
6778 interface = &(*interfaceIterator);
6779 }
6780
6781 // Set owner and neighbour
6782 interface->setOwner(intrOwnerId, intrOwnerFace);
6783 if (intrNeighId >= 0) {
6784 interface->setNeigh(intrNeighId, intrNeighFace);
6785 }
6786
6787 // Update owner and neighbour cell data
6788 //
6789 // Adjacencies and interfaces are paired: the i-th adjacency correspondes
6790 // to the i-th interface. Moreover if we loop through the adjacencies of
6791 // a face, the adjacencies that have an interface are always listed first.
6792 // When the interfaces are fully built, each adjacency is associated to an
6793 // interface, however this will not be true during the generation of the
6794 // interfaces. If the adjacencies already associated to an interface are
6795 // listed first, it will be easy to detect which interfaces are still to
6796 // be built: the missing interfaces are associated to the adjacencies which
6797 // have an index past the last interface.
6798 //
6799 // The above only matters if the neighbour cell exists, if there is no
6800 // neighbour there will be only one interface on that face, so there are
6801 // no ordering issues.
6802 intrOwner->pushInterface(intrOwnerFace, interfaceId);
6803 if (intrNeigh) {
6804 intrNeigh->pushInterface(intrNeighFace, interfaceId);
6805
6806 // Fix adjacency order on the owner cell
6807 int ownerInterfaceIndex = intrOwner->getInterfaceCount(intrOwnerFace) - 1;
6808 long ownerPairedAdjacency = intrOwner->getAdjacency(intrOwnerFace, ownerInterfaceIndex);
6809 if (ownerPairedAdjacency != intrNeighId) {
6810 int ownerPairedAdjacencyIndex = intrOwner->findAdjacency(intrOwnerFace, intrNeighId);
6811 assert(ownerPairedAdjacencyIndex >= 0);
6812 intrOwner->setAdjacency(intrOwnerFace, ownerInterfaceIndex, intrNeighId);
6813 intrOwner->setAdjacency(intrOwnerFace, ownerPairedAdjacencyIndex, ownerPairedAdjacency);
6814 }
6815
6816 // Fix adjacency order on the neighbour cell
6817 int neighInterfaceIndex = intrNeigh->getInterfaceCount(intrNeighFace) - 1;
6818 long neighPairedAdjacency = intrNeigh->getAdjacency(intrNeighFace, neighInterfaceIndex);
6819 if (neighPairedAdjacency != intrOwnerId) {
6820 int neighPairedAdjacencyIndex = intrNeigh->findAdjacency(intrNeighFace, intrOwnerId);
6821 assert(neighPairedAdjacencyIndex >= 0);
6822 intrNeigh->setAdjacency(intrNeighFace, neighInterfaceIndex, intrOwnerId);
6823 intrNeigh->setAdjacency(intrNeighFace, neighPairedAdjacencyIndex, neighPairedAdjacency);
6824 }
6825 }
6826
6827 return interfaceIterator;
6828}
6829
6839int PatchKernel::findAdjoinNeighFace(const Cell &cell, int cellFace, const Cell &neigh) const
6840{
6841 // Evaluate list of candidate faces
6842 //
6843 // The cells may be neighbours through multiple faces. Identify which face
6844 // matches the target one is quite expensive. Moreover, if the cells are
6845 // neighbours through a single face (which is the common case), the check
6846 // is not needed at all. Therefore, first we identify all the faces through
6847 // which the two cells are neighbours and then, if and only if there are
6848 // multiple candidates, we identify the face that matches the target one.
6849 long cellId = cell.getId();
6850 const int nNeighFaces = neigh.getFaceCount();
6851
6852 int nCandidates = 0;
6853 BITPIT_CREATE_WORKSPACE(candidates, std::array<int BITPIT_COMMA 3>, nNeighFaces, ReferenceElementInfo::MAX_ELEM_FACES);
6854 for (int neighFace = 0; neighFace < nNeighFaces; neighFace++) {
6855 int nFaceAdjacencies = neigh.getAdjacencyCount(neighFace);
6856 const long *faceAdjacencies = neigh.getAdjacencies(neighFace);
6857 for (int k = 0; k < nFaceAdjacencies; ++k) {
6858 long geussId = faceAdjacencies[k];
6859 if (geussId == cellId) {
6860 (*candidates)[nCandidates] = neighFace;
6861 ++nCandidates;
6862 break;
6863 }
6864 }
6865 }
6866
6867 // Select the face of the neighbour which adjoin the given face
6868 if (nCandidates == 1) {
6869 return (*candidates)[0];
6870 } else {
6871 for (int i = 0; i < nCandidates; ++i) {
6872 int candidateFace = (*candidates)[i];
6873 if (isSameFace(cell, cellFace, neigh, candidateFace)) {
6874 return candidateFace;
6875 }
6876 }
6877 }
6878
6879 return -1;
6880}
6881
6889bool PatchKernel::testCellAlterationFlags(long id, AlterationFlags flags) const
6890{
6891 return testElementAlterationFlags(id, flags, m_alteredCells);
6892}
6893
6900PatchKernel::AlterationFlags PatchKernel::getCellAlterationFlags(long id) const
6901{
6902 return getElementAlterationFlags(id, m_alteredCells);
6903}
6904
6911void PatchKernel::resetCellAlterationFlags(long id, AlterationFlags flags)
6912{
6913 resetElementAlterationFlags(id, flags, &m_alteredCells);
6914}
6915
6921void PatchKernel::setCellAlterationFlags(AlterationFlags flags)
6922{
6923 CellConstIterator endItr = cellConstEnd();
6924 for (CellConstIterator itr = cellConstBegin(); itr != endItr; ++itr) {
6925 setCellAlterationFlags(itr.getId(), flags);
6926 }
6927}
6928
6935void PatchKernel::setCellAlterationFlags(long id, AlterationFlags flags)
6936{
6937 setElementAlterationFlags(id, flags, &m_alteredCells);
6938}
6939
6945void PatchKernel::unsetCellAlterationFlags(AlterationFlags flags)
6946{
6947 unsetElementAlterationFlags(flags, &m_alteredCells);
6948}
6949
6956void PatchKernel::unsetCellAlterationFlags(long id, AlterationFlags flags)
6957{
6958 unsetElementAlterationFlags(id, flags, &m_alteredCells);
6959}
6960
6968bool PatchKernel::testInterfaceAlterationFlags(long id, AlterationFlags flags) const
6969{
6970 return testElementAlterationFlags(id, flags, m_alteredInterfaces);
6971}
6972
6979PatchKernel::AlterationFlags PatchKernel::getInterfaceAlterationFlags(long id) const
6980{
6981 return getElementAlterationFlags(id, m_alteredInterfaces);
6982}
6983
6990void PatchKernel::resetInterfaceAlterationFlags(long id, AlterationFlags flags)
6991{
6992 resetElementAlterationFlags(id, flags, &m_alteredInterfaces);
6993}
6994
7001{
7002 InterfaceConstIterator endItr = interfaceConstEnd();
7003 for (InterfaceConstIterator itr = interfaceConstBegin(); itr != endItr; ++itr) {
7004 setInterfaceAlterationFlags(itr.getId(), flags);
7005 }
7006}
7007
7014void PatchKernel::setInterfaceAlterationFlags(long id, AlterationFlags flags)
7015{
7016 setElementAlterationFlags(id, flags, &m_alteredInterfaces);
7017}
7018
7025{
7026 unsetElementAlterationFlags(flags, &m_alteredInterfaces);
7027}
7028
7035void PatchKernel::unsetInterfaceAlterationFlags(long id, AlterationFlags flags)
7036{
7037 unsetElementAlterationFlags(id, flags, &m_alteredInterfaces);
7038}
7039
7048bool PatchKernel::testElementAlterationFlags(long id, AlterationFlags flags, const AlterationFlagsStorage &flagsStorage) const
7049{
7050 auto storedFlagsItr = flagsStorage.find(id);
7051 if (storedFlagsItr != flagsStorage.end()) {
7052 return testAlterationFlags(storedFlagsItr->second, flags);
7053 } else {
7054 return testAlterationFlags(FLAG_NONE, flags);
7055 }
7056}
7057
7065bool PatchKernel::testAlterationFlags(AlterationFlags availableFlags, AlterationFlags requestedFlags) const
7066{
7067 return ((availableFlags & requestedFlags) == requestedFlags);
7068}
7069
7077PatchKernel::AlterationFlags PatchKernel::getElementAlterationFlags(long id, const AlterationFlagsStorage &flagsStorage) const
7078{
7079 auto storedFlagsItr = flagsStorage.find(id);
7080 if (storedFlagsItr != flagsStorage.end()) {
7081 return storedFlagsItr->second;
7082 } else {
7083 return FLAG_NONE;
7084 }
7085}
7086
7094void PatchKernel::resetElementAlterationFlags(long id, AlterationFlags flags, AlterationFlagsStorage *flagsStorage) const
7095{
7096 if (flags == FLAG_NONE) {
7097 flagsStorage->erase(id);
7098 } else {
7099 (*flagsStorage)[id] = flags;
7100 }
7101}
7102
7110void PatchKernel::setElementAlterationFlags(long id, AlterationFlags flags, AlterationFlagsStorage *flagsStorage) const
7111{
7112 if (flags == FLAG_NONE) {
7113 return;
7114 }
7115
7116 auto storedFlagsItr = flagsStorage->find(id);
7117 if (storedFlagsItr != flagsStorage->end()) {
7118 storedFlagsItr->second |= flags;
7119 } else {
7120 flagsStorage->insert({id, flags});
7121 }
7122}
7123
7130void PatchKernel::unsetElementAlterationFlags(AlterationFlags flags, AlterationFlagsStorage *flagsStorage) const
7131{
7132 if (flags == FLAG_NONE) {
7133 return;
7134 }
7135
7136 for (auto storedFlagsItr = flagsStorage->begin(); storedFlagsItr != flagsStorage->end();) {
7137 storedFlagsItr->second &= ~flags;
7138 if (storedFlagsItr->second == FLAG_NONE) {
7139 storedFlagsItr = flagsStorage->erase(storedFlagsItr);
7140 } else {
7141 ++storedFlagsItr;
7142 }
7143 }
7144}
7145
7153void PatchKernel::unsetElementAlterationFlags(long id, AlterationFlags flags, AlterationFlagsStorage *flagsStorage) const
7154{
7155 if (flags == FLAG_NONE) {
7156 return;
7157 }
7158
7159 auto storedFlagsItr = flagsStorage->find(id);
7160 if (storedFlagsItr == flagsStorage->end()) {
7161 return;
7162 }
7163
7164 storedFlagsItr->second &= ~flags;
7165 if (storedFlagsItr->second == FLAG_NONE) {
7166 flagsStorage->erase(storedFlagsItr);
7167 }
7168}
7169
7176{
7177 for (int k = 0; k < 3; ++k) {
7178 m_boxMinPoint[k] = std::numeric_limits<double>::max();
7179 m_boxMinCounter[k] = 0;
7180
7181 m_boxMaxPoint[k] = - std::numeric_limits<double>::max();
7182 m_boxMaxCounter[k] = 0;
7183 }
7184
7186}
7187
7196void PatchKernel::setBoundingBox(const std::array<double, 3> &minPoint, const std::array<double, 3> &maxPoint)
7197{
7198 m_boxMinPoint = minPoint;
7199 m_boxMaxPoint = maxPoint;
7200
7201 setBoundingBoxDirty(false);
7202}
7203
7210void PatchKernel::getBoundingBox(std::array<double, 3> &minPoint, std::array<double, 3> &maxPoint) const
7211{
7212 getBoundingBox(false, minPoint, maxPoint);
7213}
7214
7223void PatchKernel::getBoundingBox(bool global, std::array<double, 3> &minPoint, std::array<double, 3> &maxPoint) const
7224{
7225 minPoint = m_boxMinPoint;
7226 maxPoint = m_boxMaxPoint;
7227
7228#if BITPIT_ENABLE_MPI==1
7229 if (global && isPartitioned()) {
7230 MPI_Comm communicator = getCommunicator();
7231 MPI_Allreduce(MPI_IN_PLACE, minPoint.data(), 3, MPI_DOUBLE, MPI_MIN, communicator);
7232 MPI_Allreduce(MPI_IN_PLACE, maxPoint.data(), 3, MPI_DOUBLE, MPI_MAX, communicator);
7233 }
7234#else
7235 BITPIT_UNUSED(global);
7236#endif
7237}
7238
7245{
7246 return m_boxFrozen;
7247}
7248
7260{
7261 m_boxFrozen = frozen;
7262}
7263
7271bool PatchKernel::isBoundingBoxDirty(bool global) const
7272{
7273 bool isDirty = m_boxDirty;
7274#if BITPIT_ENABLE_MPI==1
7275 if (global && isPartitioned()) {
7276 const auto &communicator = getCommunicator();
7277 MPI_Allreduce(const_cast<bool *>(&m_boxDirty), &isDirty, 1, MPI_C_BOOL, MPI_LOR, communicator);
7278 }
7279#else
7280 BITPIT_UNUSED(global);
7281#endif
7282
7283 return isDirty;
7284}
7285
7292{
7293 m_boxDirty = dirty;
7294}
7295
7302void PatchKernel::updateBoundingBox(bool forcedUpdated)
7303{
7304 if (isBoundingBoxFrozen()) {
7305 return;
7306 }
7307
7308 // Check if the bounding box is dirty
7309 if (!isBoundingBoxDirty() && !forcedUpdated) {
7310 return;
7311 }
7312
7313 // Initialize bounding box
7315
7316 // Unset the dirty flag in order to be able to update the bounding box
7317 setBoundingBoxDirty(false);
7318
7319 // Compute bounding box
7320 for (const auto &vertex : m_vertices) {
7322 }
7323}
7324
7333void PatchKernel::addPointToBoundingBox(const std::array<double, 3> &point)
7334{
7336 return;
7337 }
7338
7339 for (size_t k = 0; k < point.size(); ++k) {
7340 double value = point[k];
7341
7342 // Update maximum value
7343 if (utils::DoubleFloatingEqual()(value, m_boxMaxPoint[k], getTol())) {
7344 ++m_boxMaxCounter[k];
7345 } else if (value > m_boxMaxPoint[k]) {
7346 m_boxMaxPoint[k] = value;
7347 m_boxMaxCounter[k] = 1;
7348 }
7349
7350 // Update minimum value
7351 if (utils::DoubleFloatingEqual()(value, m_boxMinPoint[k], getTol())) {
7352 ++m_boxMinCounter[k];
7353 } else if (value < m_boxMinPoint[k]) {
7354 m_boxMinPoint[k] = value;
7355 m_boxMinCounter[k] = 1;
7356 }
7357 }
7358}
7359
7368void PatchKernel::removePointFromBoundingBox(const std::array<double, 3> &point)
7369{
7371 return;
7372 }
7373
7374 double tolerance = getTol();
7375 for (size_t k = 0; k < point.size(); ++k) {
7376 double value = point[k];
7377
7378 // Check if maximum value is still valid
7379 if (utils::DoubleFloatingEqual()(value, m_boxMaxPoint[k], tolerance)) {
7380 --m_boxMaxCounter[k];
7381 if (m_boxMaxCounter[k] == 0) {
7382 setBoundingBoxDirty(true);
7383 return;
7384 }
7385 } else if (value > m_boxMaxPoint[k]) {
7386 assert(false && "Bounding box is in inconsistent state.");
7387 setBoundingBoxDirty(true);
7388 return;
7389 }
7390
7391 // Update minimum value
7392 if (utils::DoubleFloatingEqual()(value, m_boxMinPoint[k], tolerance)) {
7393 --m_boxMinCounter[k];
7394 if (m_boxMinCounter[k] == 0) {
7395 setBoundingBoxDirty(true);
7396 return;
7397 }
7398 } else if (value < m_boxMinPoint[k]) {
7399 assert(false && "Bounding box is in inconsistent state.");
7400 setBoundingBoxDirty(true);
7401 return;
7402 }
7403 }
7404}
7405
7412ConstProxyVector<std::array<double, 3>> PatchKernel::getElementVertexCoordinates(const Element &element) const
7413{
7414 // Get the vertices ids
7415 ConstProxyVector<long> elementVertexIds = element.getVertexIds();
7416 const int nElementVertices = elementVertexIds.size();
7417
7418 // Build the proxy vector with the coordinates
7419 ConstProxyVector<std::array<double, 3>> vertexCoordinates(ConstProxyVector<std::array<double, 3>>::INTERNAL_STORAGE, nElementVertices);
7420 ConstProxyVector<std::array<double, 3>>::storage_pointer storage = vertexCoordinates.storedData();
7421 getVertexCoords(elementVertexIds.size(), elementVertexIds.data(), storage);
7422
7423 return vertexCoordinates;
7424}
7425
7432void PatchKernel::getElementVertexCoordinates(const Element &element, std::unique_ptr<std::array<double, 3>[]> *coordinates) const
7433{
7434 ConstProxyVector<long> elementVertexIds = element.getVertexIds();
7435 getVertexCoords(elementVertexIds.size(), elementVertexIds.data(), coordinates);
7436}
7437
7446void PatchKernel::getElementVertexCoordinates(const Element &element, std::array<double, 3> *coordinates) const
7447{
7448 ConstProxyVector<long> elementVertexIds = element.getVertexIds();
7449 getVertexCoords(elementVertexIds.size(), elementVertexIds.data(), coordinates);
7450}
7451
7458std::unordered_map<long, std::vector<long>> PatchKernel::binGroupVertices(int nBins)
7459{
7460 return PatchKernel::binGroupVertices(m_vertices, nBins);
7461}
7462
7470std::unordered_map<long, std::vector<long>> PatchKernel::binGroupVertices(const PiercedVector<Vertex> &vertices, int nBins)
7471{
7472 // Update bounding box
7474
7475 // Bin's spacing
7476 double dx = std::max(1.0e-12, m_boxMaxPoint[0] - m_boxMinPoint[0]) / ((double) nBins);
7477 double dy = std::max(1.0e-12, m_boxMaxPoint[1] - m_boxMinPoint[1]) / ((double) nBins);
7478 double dz = std::max(1.0e-12, m_boxMaxPoint[2] - m_boxMinPoint[2]) / ((double) nBins);
7479
7480 // Identify bins of vertices
7481 std::unordered_map<long, std::vector<long>> bins;
7482 for (const Vertex &vertex : vertices) {
7483 const std::array<double, 3> &coordinates = vertex.getCoords();
7484
7485 int i = std::min(nBins - 1L, (long) ((coordinates[0] - m_boxMinPoint[0]) / dx));
7486 int j = std::min(nBins - 1L, (long) ((coordinates[1] - m_boxMinPoint[1]) / dy));
7487 int k = std::min(nBins - 1L, (long) ((coordinates[2] - m_boxMinPoint[2]) / dz));
7488
7489 long binId = nBins * nBins * k + nBins * j + i;
7490 bins[binId].emplace_back(vertex.getId());
7491 }
7492
7493 return bins;
7494}
7495
7501void PatchKernel::translate(const std::array<double, 3> &translation)
7502{
7503 // Translate the patch
7504 for (auto &vertex : m_vertices) {
7505 vertex.translate(translation);
7506 }
7507
7508 // Update the bounding box
7510 m_boxMinPoint += translation;
7511 m_boxMaxPoint += translation;
7512 }
7513}
7514
7522void PatchKernel::translate(double sx, double sy, double sz)
7523{
7524 translate({{sx, sy, sz}});
7525}
7526
7535void PatchKernel::rotate(const std::array<double, 3> &n0, const std::array<double, 3> &n1, double angle)
7536{
7537 // Translate the patch
7538 for (auto &vertex : m_vertices) {
7539 vertex.rotate(n0, n1, angle);
7540 }
7541
7542 // Update the bounding box
7544 // Save current bounding box
7545 std::array<std::array<double, 3>, 3> originalBox = {{m_boxMinPoint, m_boxMaxPoint}};
7546
7547 // Clear bounding box
7549
7550 // Unset the dirty flag in order to be able to update the bounding box
7551 setBoundingBoxDirty(false);
7552
7553 // Evaluate rotated bounding box
7554 for (int i = 0; i < 2; ++i) {
7555 double xCorner = originalBox[i][0];
7556 for (int j = 0; j < 2; ++j) {
7557 double yCorner = originalBox[j][1];
7558 for (int k = 0; k < 2; ++k) {
7559 double zCorner = originalBox[k][2];
7560
7561 std::array<double, 3> corner = {{xCorner, yCorner, zCorner}};
7562 corner = CGElem::rotatePoint(corner, n0, n1, angle);
7563 addPointToBoundingBox(corner);
7564 }
7565 }
7566 }
7567 }
7568}
7569
7582void PatchKernel::rotate(double n0x, double n0y, double n0z, double n1x,
7583 double n1y, double n1z, double angle)
7584{
7585 rotate({{n0x, n0y, n0z}}, {{n1x, n1y, n1z}}, angle);
7586}
7587
7595void PatchKernel::scale(const std::array<double, 3> &scaling)
7596{
7597 scale(scaling, m_boxMinPoint);
7598}
7599
7606void PatchKernel::scale(const std::array<double, 3> &scaling, const std::array<double, 3> &center)
7607{
7608 // Scale the patch
7609 for (auto &vertex : m_vertices) {
7610 vertex.scale(scaling, center);
7611 }
7612
7613 // Update the bounding box
7615 for (int k = 0; k < 3; ++k) {
7616 m_boxMinPoint[k] = center[k] + scaling[k] * (m_boxMinPoint[k] - center[k]);
7617 m_boxMaxPoint[k] = center[k] + scaling[k] * (m_boxMaxPoint[k] - center[k]);
7618 }
7619 }
7620}
7621
7629void PatchKernel::scale(double scaling)
7630{
7631 scale({{scaling, scaling, scaling}}, m_boxMinPoint);
7632}
7633
7640void PatchKernel::scale(double scaling, const std::array<double, 3> &center)
7641{
7642 scale({{scaling, scaling, scaling}}, center);
7643}
7644
7652void PatchKernel::scale(double sx, double sy, double sz)
7653{
7654 scale({{sx, sy, sz}}, m_boxMinPoint);
7655}
7656
7667void PatchKernel::scale(double sx, double sy, double sz, const std::array<double, 3> &center)
7668{
7669 scale({{sx, sy, sz}}, center);
7670}
7671
7678void PatchKernel::setTol(double tolerance)
7679{
7680 _setTol(tolerance);
7681
7682 m_toleranceCustom = true;
7683}
7684
7691void PatchKernel::_setTol(double tolerance)
7692{
7693 m_tolerance = tolerance;
7694}
7695
7702{
7703 return m_tolerance;
7704}
7705
7710{
7711 _resetTol();
7712
7713 m_toleranceCustom = false;
7714}
7715
7726{
7727 const double DEFAULT_TOLERANCE = 1e-14;
7728
7729 m_tolerance = DEFAULT_TOLERANCE;
7730}
7731
7739{
7740 return m_toleranceCustom;
7741}
7742
7752{
7753
7754 // ====================================================================== //
7755 // RESIZE DATA STRUCTURES //
7756 // ====================================================================== //
7757 envelope.reserveVertices(envelope.getVertexCount() + countBorderVertices());
7758 envelope.reserveCells(envelope.getCellCount() + countBorderFaces());
7759
7760 // ====================================================================== //
7761 // LOOP OVER CELLS //
7762 // ====================================================================== //
7763 std::unordered_map<long, long> vertexMap;
7764 for (const Cell &cell : m_cells) {
7765 int nCellFaces = cell.getFaceCount();
7766 for (int i = 0; i < nCellFaces; ++i) {
7767 if (!cell.isFaceBorder(i)) {
7768 continue;
7769 }
7770
7771 // Add face vertices to the envelope and get face
7772 // connectivity in the envelope
7773 ConstProxyVector<long> faceConnect = cell.getFaceConnect(i);
7774 int nFaceVertices = faceConnect.size();
7775
7776 std::unique_ptr<long[]> faceEnvelopeConnect = std::unique_ptr<long[]>(new long[nFaceVertices]);
7777 for (int j = 0; j < nFaceVertices; ++j) {
7778 long vertexId = faceConnect[j];
7779
7780 // If the vertex is not yet in the envelope
7781 // add it.
7782 if (vertexMap.count(vertexId) == 0) {
7783 const Vertex &vertex = getVertex(vertexId);
7784 VertexIterator envelopeVertex = envelope.addVertex(vertex);
7785 vertexMap[vertexId] = envelopeVertex->getId();
7786 }
7787
7788 // Update face ace connectivity in the envelope
7789 faceEnvelopeConnect[j] = vertexMap.at(vertexId);
7790 }
7791
7792 // Add face to envelope
7793 ElementType faceType = cell.getFaceType(i);
7794 envelope.addCell(faceType, std::move(faceEnvelopeConnect));
7795 }
7796 }
7797}
7798
7806void PatchKernel::displayTopologyStats(std::ostream &out, unsigned int padding) const
7807{
7808 std::string indent = std::string(padding, ' ');
7809
7810 // ====================================================================== //
7811 // VERTEX STATS //
7812 // ====================================================================== //
7813 out << indent<< "Vertices --------------------------------" << std::endl;
7814 out << indent<< " # vertices " << getVertexCount() << std::endl;
7815 out << indent<< " # orphan vertices " << countOrphanVertices() << std::endl;
7816 out << indent<< " # border vertices " << countBorderVertices() << std::endl;
7817 //out << indent<< " # free vertices " << countDoubleVertices() << std::endl;
7818
7819 // ====================================================================== //
7820 // FACE STATS //
7821 // ====================================================================== //
7822 out << indent<< "Faces -----------------------------------" << std::endl;
7823 out << indent<< " # faces " << countFaces() << std::endl;
7824 out << indent<< " # border faces " << countBorderFaces() << std::endl;
7825
7826 // ====================================================================== //
7827 // CELLS STATS //
7828 // ====================================================================== //
7829 out << indent<< "Cells -----------------------------------" << std::endl;
7830 out << indent<< " # cells " << getCellCount() << std::endl;
7831 out << indent<< " # orphan cells " << countOrphanCells() << std::endl;
7832 out << indent<< " # border cells " << countBorderCells() << std::endl;
7833 //out << indent<< " # free vertices " << countDoubleCells() << std::endl;
7834}
7835
7843void PatchKernel::displayVertices(std::ostream &out, unsigned int padding) const
7844{
7845 std::string indent = std::string(padding, ' ');
7846 for (const Vertex &vertex : m_vertices) {
7847 out << indent << "vertex: " << std::endl;
7848 vertex.display(out, padding + 2);
7849 }
7850}
7851
7859void PatchKernel::displayCells(std::ostream &out, unsigned int padding) const
7860{
7861 std::string indent = std::string(padding, ' ');
7862 for (const Cell &cell : m_cells) {
7863 out << indent << "cell: " << std::endl;
7864 cell.display(out, padding + 2);
7865 }
7866}
7867
7875void PatchKernel::displayInterfaces(std::ostream &out, unsigned int padding) const
7876{
7877 std::string indent = std::string(padding, ' ');
7878 for (const Interface &interface : m_interfaces) {
7879 out << indent << "interface: " << std::endl;
7880 interface.display(out, padding + 2);
7881 }
7882}
7883
7890{
7891 return m_vtk;
7892}
7893
7900{
7901 return m_vtk;
7902}
7903
7909PatchKernel::WriteTarget PatchKernel::getVTKWriteTarget() const
7910{
7911 return m_vtkWriteTarget;
7912}
7913
7919void PatchKernel::setVTKWriteTarget(WriteTarget writeTarget)
7920{
7921 m_vtkWriteTarget = writeTarget;
7922}
7923
7929const PatchKernel::CellConstRange PatchKernel::getVTKCellWriteRange() const
7930{
7931 if (m_vtkWriteTarget == WRITE_TARGET_CELLS_ALL) {
7932 return CellConstRange(cellConstBegin(), cellConstEnd());
7933#if BITPIT_ENABLE_MPI==1
7934 } else if (m_vtkWriteTarget == WRITE_TARGET_CELLS_INTERNAL) {
7935 return CellConstRange(internalCellConstBegin(), internalCellConstEnd());
7936#endif
7937 } else {
7938 return CellConstRange(cellConstEnd(), cellConstEnd());
7939 }
7940}
7941
7948void PatchKernel::replaceVTKStreamer(const VTKBaseStreamer *original, VTKBaseStreamer *updated)
7949{
7950 // Update the VTK streamer
7951 //
7952 // The pointer to VTK streamers are copied, if there are pointer to the
7953 // original object they have to be replace with a pointer to this object.
7954 // Geometry fields
7955 std::vector<std::string> streamedGeomFields;
7956 streamedGeomFields.reserve(m_vtk.getGeomDataCount());
7957 for (auto itr = m_vtk.getGeomDataBegin(); itr != m_vtk.getGeomDataEnd(); ++itr) {
7958 const VTKField &field = *itr;
7959 if (&field.getStreamer() != original) {
7960 continue;
7961 }
7962
7963 streamedGeomFields.push_back(field.getName());
7964 }
7965
7966 for (const std::string &name : streamedGeomFields) {
7967 const VTKField &field = *(m_vtk.findGeomData(name));
7968 VTKField updatedField(field);
7969 updatedField.setStreamer(*updated);
7970
7971 m_vtk.setGeomData(std::move(updatedField));
7972 }
7973
7974 std::vector<std::string> streamedDataFields;
7975 streamedDataFields.reserve(m_vtk.getDataCount());
7976 for (auto itr = m_vtk.getDataBegin(); itr != m_vtk.getDataEnd(); ++itr) {
7977 const VTKField &field = *itr;
7978 if (&field.getStreamer() != original) {
7979 continue;
7980 }
7981
7982 streamedDataFields.push_back(field.getName());
7983 }
7984
7985 for (const std::string &name : streamedDataFields) {
7986 const VTKField &field = *(m_vtk.findData(name));
7987 VTKField updatedField(field);
7988 updatedField.setStreamer(*updated);
7989
7990 m_vtk.removeData(field.getName());
7991 m_vtk.addData(std::move(updatedField));
7992 }
7993}
7994
8005void PatchKernel::flushData(std::fstream &stream, const std::string &name, VTKFormat format)
8006{
8007 if (name == "Points") {
8008 VertexConstIterator endItr = vertexConstEnd();
8009 for (VertexConstIterator itr = vertexConstBegin(); itr != endItr; ++itr) {
8010 std::size_t vertexRawId = itr.getRawIndex();
8011 long vertexVTKId = m_vtkVertexMap.rawAt(vertexRawId);
8012 if (vertexVTKId != Vertex::NULL_ID) {
8013 const Vertex &vertex = m_vertices.rawAt(vertexRawId);
8014 flushValue(stream, format,vertex.getCoords());
8015 }
8016 }
8017 } else if (name == "offsets") {
8018 long offset = 0;
8019 for (const Cell &cell : getVTKCellWriteRange()) {
8020 offset += cell.getVertexCount();
8021 flushValue(stream, format,offset);
8022 }
8023 } else if (name == "types") {
8024 for (const Cell &cell : getVTKCellWriteRange()) {
8025 VTKElementType VTKType;
8026 switch (cell.getType()) {
8027
8028 case ElementType::VERTEX:
8029 VTKType = VTKElementType::VERTEX;
8030 break;
8031
8032 case ElementType::LINE:
8033 VTKType = VTKElementType::LINE;
8034 break;
8035
8036 case ElementType::TRIANGLE:
8037 VTKType = VTKElementType::TRIANGLE;
8038 break;
8039
8040 case ElementType::PIXEL:
8041 VTKType = VTKElementType::PIXEL;
8042 break;
8043
8044 case ElementType::QUAD:
8045 VTKType = VTKElementType::QUAD;
8046 break;
8047
8048 case ElementType::POLYGON:
8049 VTKType = VTKElementType::POLYGON;
8050 break;
8051
8052 case ElementType::TETRA:
8053 VTKType = VTKElementType::TETRA;
8054 break;
8055
8056 case ElementType::VOXEL:
8057 VTKType = VTKElementType::VOXEL;
8058 break;
8059
8060 case ElementType::HEXAHEDRON:
8061 VTKType = VTKElementType::HEXAHEDRON;
8062 break;
8063
8064 case ElementType::WEDGE:
8065 VTKType = VTKElementType::WEDGE;
8066 break;
8067
8068 case ElementType::PYRAMID:
8069 VTKType = VTKElementType::PYRAMID;
8070 break;
8071
8072 case ElementType::POLYHEDRON:
8073 VTKType = VTKElementType::POLYHEDRON;
8074 break;
8075
8076 default:
8077 VTKType = VTKElementType::UNDEFINED;
8078 break;
8079
8080 }
8081
8082 flushValue(stream, format,(int) VTKType);
8083 }
8084 } else if (name == "connectivity") {
8085 for (const Cell &cell : getVTKCellWriteRange()) {
8086 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
8087 const int nCellVertices = cellVertexIds.size();
8088 for (int k = 0; k < nCellVertices; ++k) {
8089 long vertexId = cellVertexIds[k];
8090 long vtkVertexId = m_vtkVertexMap.at(vertexId);
8091 flushValue(stream, format,vtkVertexId);
8092 }
8093 }
8094 } else if (name == "faces") {
8095 for (const Cell &cell : getVTKCellWriteRange()) {
8096 if (cell.getDimension() <= 2 || cell.hasInfo()) {
8097 flushValue(stream, format,(long) 0);
8098 } else {
8099 std::vector<long> faceStream = cell.getFaceStream();
8100 Cell::renumberFaceStream(m_vtkVertexMap, &faceStream);
8101 int faceStreamSize = faceStream.size();
8102 for (int k = 0; k < faceStreamSize; ++k) {
8103 flushValue(stream, format,faceStream[k]);
8104 }
8105 }
8106 }
8107 } else if (name == "faceoffsets") {
8108 long offset = 0;
8109 for (const Cell &cell : getVTKCellWriteRange()) {
8110 if (cell.getDimension() <= 2 || cell.hasInfo()) {
8111 offset += 1;
8112 } else {
8113 offset += cell.getFaceStreamSize();
8114 }
8115
8116 flushValue(stream, format,offset);
8117 }
8118 } else if (name == "cellIndex") {
8119 for (const Cell &cell : getVTKCellWriteRange()) {
8120 flushValue(stream, format,cell.getId());
8121 }
8122 } else if (name == "PID") {
8123 for (const Cell &cell : getVTKCellWriteRange()) {
8124 flushValue(stream, format,cell.getPID());
8125 }
8126 } else if (name == "vertexIndex") {
8127 VertexConstIterator endItr = vertexConstEnd();
8128 for (VertexConstIterator itr = vertexConstBegin(); itr != endItr; ++itr) {
8129 std::size_t vertexRawId = itr.getRawIndex();
8130 long vertexVTKId = m_vtkVertexMap.rawAt(vertexRawId);
8131 if (vertexVTKId != Vertex::NULL_ID) {
8132 long vertexId = itr.getId();
8133 flushValue(stream, format,vertexId);
8134 }
8135 }
8136#if BITPIT_ENABLE_MPI==1
8137 } else if (name == "cellGlobalIndex") {
8138 PatchNumberingInfo numberingInfo(this);
8139 for (const Cell &cell : getVTKCellWriteRange()) {
8140 flushValue(stream, format,numberingInfo.getCellGlobalId(cell.getId()));
8141 }
8142 } else if (name == "cellRank") {
8143 for (const Cell &cell : getVTKCellWriteRange()) {
8144 flushValue(stream, format,getCellOwner(cell.getId()));
8145 }
8146 } else if (name == "cellHaloLayer") {
8147 for (const Cell &cell : getVTKCellWriteRange()) {
8148 flushValue(stream, format,getCellHaloLayer(cell.getId()));
8149 }
8150 } else if (name == "vertexRank") {
8151 VertexConstIterator endItr = vertexConstEnd();
8152 for (VertexConstIterator itr = vertexConstBegin(); itr != endItr; ++itr) {
8153 std::size_t vertexRawId = itr.getRawIndex();
8154 long vertexVTKId = m_vtkVertexMap.rawAt(vertexRawId);
8155 if (vertexVTKId != Vertex::NULL_ID) {
8156 flushValue(stream, format,getVertexOwner(itr.getId()));
8157 }
8158 }
8159#endif
8160 }
8161}
8162
8169{
8170 // Renumber vertices
8171 std::unordered_map<long, long > map = consecutiveItemRenumbering(m_vertices, offset);
8172
8173 // Renumber cell connectivity
8174 for(Cell &cell : m_cells) {
8175 cell.renumberVertices(map);
8176 }
8177
8178 // Renumber interface connectivity
8179 for(Interface &interface : getInterfaces()) {
8180 interface.renumberVertices(map);
8181 }
8182
8183 // Reset index generator
8185 createVertexIndexGenerator(true);
8186 }
8187}
8188
8195{
8196 // Renumber cells
8197 std::unordered_map<long, long > map = consecutiveItemRenumbering(m_cells, offset);
8198
8199 // Renumber cell adjacencies
8200 for (auto &cell: m_cells) {
8201 long *adjacencies = cell.getAdjacencies();
8202 int nCellAdjacencies = cell.getAdjacencyCount();
8203 for (int i = 0; i < nCellAdjacencies; ++i) {
8204 long &neighId = adjacencies[i];
8205 neighId = map[neighId];
8206 }
8207 }
8208
8209 // Renumber interface owner and neighbour
8210 for (Interface &interface: m_interfaces) {
8211 long ownerId = interface.getOwner();
8212 int ownerFace = interface.getOwnerFace();
8213 interface.setOwner(map.at(ownerId), ownerFace);
8214
8215 long neighId = interface.getNeigh();
8216 if (neighId >= 0) {
8217 int neighFace = interface.getNeighFace();
8218 interface.setNeigh(map.at(neighId), neighFace);
8219 }
8220 }
8221
8222 // Renumber last internal and first ghost markers
8223 if (m_lastInternalCellId >= 0) {
8224 m_lastInternalCellId = map.at(m_lastInternalCellId);
8225 }
8226
8227#if BITPIT_ENABLE_MPI==1
8228 if (m_firstGhostCellId >= 0) {
8229 m_firstGhostCellId = map.at(m_firstGhostCellId);
8230 }
8231#endif
8232
8233 // Reset index generator
8235 createCellIndexGenerator(true);
8236 }
8237
8238#if BITPIT_ENABLE_MPI==1
8239 // Update partitioning information
8240 if (isPartitioned()) {
8241 updatePartitioningInfo(true);
8242 }
8243#endif
8244}
8245
8252{
8253 // Renumber interfaces
8254 std::unordered_map<long, long > map = consecutiveItemRenumbering(m_interfaces, offset);
8255
8256 // Renumber cell interfaces
8257 for (Cell &cell: m_cells) {
8258 long *interfaces = cell.getInterfaces();
8259 int nCellInterfaces = cell.getInterfaceCount();
8260 for (int i = 0; i < nCellInterfaces; ++i) {
8261 long &interfaceId = interfaces[i];
8262 interfaceId = map.at(interfaceId);
8263 }
8264 }
8265
8266 // Reset index generator
8268 createInterfaceIndexGenerator(true);
8269 }
8270}
8271
8280void PatchKernel::consecutiveRenumber(long vertexOffset, long cellOffset, long interfaceOffset)
8281{
8282 consecutiveRenumberVertices(vertexOffset);
8283 consecutiveRenumberCells(cellOffset);
8284 consecutiveRenumberInterfaces(interfaceOffset);
8285}
8286
8293{
8294 const int KERNEL_DUMP_VERSION = 12;
8295
8296 return (KERNEL_DUMP_VERSION + _getDumpVersion());
8297}
8298
8308bool PatchKernel::dump(std::ostream &stream)
8309{
8310 // Update the patch
8311 update();
8312
8313 // Dump the patch
8314 const PatchKernel *constPatch = this;
8315 return constPatch->dump(stream);
8316}
8317
8329bool PatchKernel::dump(std::ostream &stream) const
8330{
8331 // Dumping a dirty patch is not supported.
8332 bool dirty = isDirty(true);
8333 assert(!dirty && "Dumping a patch that is not up-to-date is not supported.");
8334 if (dirty) {
8335 return false;
8336 }
8337
8338 // Version
8340
8341 // Generic information
8342 utils::binary::write(stream, m_id);
8343 utils::binary::write(stream, m_dimension);
8344 utils::binary::write(stream, m_vtk.getName());
8345#if BITPIT_ENABLE_MPI==1
8346 utils::binary::write(stream, m_haloSize);
8347#else
8348 utils::binary::write(stream, 0);
8349#endif
8350
8351 // Adaption information
8352 utils::binary::write(stream, m_adaptionMode);
8353 utils::binary::write(stream, m_adaptionStatus);
8354
8355 // Partition information
8356#if BITPIT_ENABLE_MPI==1
8357 utils::binary::write(stream, m_partitioningMode);
8358 utils::binary::write(stream, m_partitioningStatus);
8359#else
8360 utils::binary::write(stream, PARTITIONING_DISABLED);
8361 utils::binary::write(stream, PARTITIONING_CLEAN);
8362#endif
8363
8364 // Adjacencies build strategy
8365 utils::binary::write(stream, m_adjacenciesBuildStrategy);
8366
8367 // Dump interfaces build strategy
8368 utils::binary::write(stream, m_interfacesBuildStrategy);
8369
8370 // VTK data
8371 utils::binary::write(stream, m_vtkWriteTarget);
8372
8373 // Specific dump
8374 _dump(stream);
8375
8376 // Geometric tolerance
8377 utils::binary::write(stream, (int) m_toleranceCustom);
8378 if (m_toleranceCustom) {
8379 utils::binary::write(stream, m_tolerance);
8380 }
8381
8382 // Index generators
8383 bool hasVertexAutoIndexing = isVertexAutoIndexingEnabled();
8384 utils::binary::write(stream, hasVertexAutoIndexing);
8385 if (hasVertexAutoIndexing) {
8386 dumpVertexAutoIndexing(stream);
8387 }
8388
8389 bool hasInterfaceAutoIndexing = isInterfaceAutoIndexingEnabled();
8390 utils::binary::write(stream, hasInterfaceAutoIndexing);
8391 if (hasInterfaceAutoIndexing) {
8392 dumpInterfaceAutoIndexing(stream);
8393 }
8394
8395 bool hasCellAutoIndexing = isCellAutoIndexingEnabled();
8396 utils::binary::write(stream, hasCellAutoIndexing);
8397 if (hasCellAutoIndexing) {
8398 dumpCellAutoIndexing(stream);
8399 }
8400
8401 // The patch has been dumped successfully
8402 return true;
8403}
8404
8412void PatchKernel::restore(std::istream &stream, bool reregister)
8413{
8414 // Reset the patch
8415 reset();
8416
8417 // Version
8418 int version;
8419 utils::binary::read(stream, version);
8420 if (version != getDumpVersion()) {
8421 throw std::runtime_error ("The version of the file does not match the required version");
8422 }
8423
8424 // Id
8425 int id;
8426 utils::binary::read(stream, id);
8427 if (reregister) {
8428 setId(id);
8429 }
8430
8431 // Dimension
8432 int dimension;
8433 utils::binary::read(stream, dimension);
8434 setDimension(dimension);
8435
8436 // Name
8437 std::string name;
8438 utils::binary::read(stream, name);
8439 m_vtk.setName(name);
8440
8441 // Halo size
8442#if BITPIT_ENABLE_MPI==1
8443 utils::binary::read(stream, m_haloSize);
8444#else
8445 int dummyHaloSize;
8446 utils::binary::read(stream, dummyHaloSize);
8447#endif
8448
8449 // Adaption information
8450 utils::binary::read(stream, m_adaptionMode);
8451 utils::binary::read(stream, m_adaptionStatus);
8452
8453 // Partition information
8454#if BITPIT_ENABLE_MPI==1
8455 utils::binary::read(stream, m_partitioningMode);
8456 utils::binary::read(stream, m_partitioningStatus);
8457#else
8458 PartitioningStatus dummyPartitioningMode;
8459 utils::binary::read(stream, dummyPartitioningMode);
8460
8461 PartitioningStatus dummyPartitioningStatus;
8462 utils::binary::read(stream, dummyPartitioningStatus);
8463#endif
8464
8465 // Adjacencies build strategy
8466 utils::binary::read(stream, m_adjacenciesBuildStrategy);
8467
8468 // Interfaces build strategy
8469 utils::binary::read(stream, m_interfacesBuildStrategy);
8470
8471 // VTK data
8472 utils::binary::read(stream, m_vtkWriteTarget);
8473
8474 // Specific restore
8475 _restore(stream);
8476
8477#if BITPIT_ENABLE_MPI==1
8478 // Update partitioning information
8479 if (isPartitioned()) {
8480 updatePartitioningInfo(true);
8481 }
8482#endif
8483
8484 // Geometric tolerance
8485 int hasCustomTolerance;
8486 utils::binary::read(stream, hasCustomTolerance);
8487 if (hasCustomTolerance) {
8488 double tolerance;
8489 utils::binary::read(stream, tolerance);
8490 setTol(tolerance);
8491 } else {
8492 resetTol();
8493 }
8494
8495 // Index generators
8496 bool hasVertexAutoIndexing;
8497 utils::binary::read(stream, hasVertexAutoIndexing);
8498 if (hasVertexAutoIndexing) {
8499 restoreVertexAutoIndexing(stream);
8500 } else {
8501 setVertexAutoIndexing(false);
8502 }
8503
8504 bool hasInterfaceAutoIndexing;
8505 utils::binary::read(stream, hasInterfaceAutoIndexing);
8506 if (hasInterfaceAutoIndexing) {
8507 restoreInterfaceAutoIndexing(stream);
8508 } else {
8510 }
8511
8512 bool hasCellAutoIndexing;
8513 utils::binary::read(stream, hasCellAutoIndexing);
8514 if (hasCellAutoIndexing) {
8515 restoreCellAutoIndexing(stream);
8516 } else {
8517 setCellAutoIndexing(false);
8518 }
8519}
8520
8527void PatchKernel::mergeAdaptionInfo(std::vector<adaption::Info> &&source, std::vector<adaption::Info> &destination)
8528{
8529 if (source.empty()) {
8530 return;
8531 } else if (destination.empty()) {
8532 destination.swap(source);
8533 return;
8534 }
8535
8536 throw std::runtime_error ("Unable to merge the adaption info.");
8537}
8538
8539}
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
static int getDimension(ElementType type)
Definition element.cpp:1096
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
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
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)
bool intersectInterfacePlane(long id, std::array< double, 3 > P, std::array< double, 3 > nP, std::array< std::array< double, 3 >, 2 > *intersection, std::vector< std::array< double, 3 > > *polygon) const
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)
long getCellGlobalId(long id) const
id_t getId(const id_t &fallback=-1) const noexcept
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)
iterator end() noexcept
void fill(const value_t &value)
iterator find(const id_t &id) noexcept
Metafunction for generating a pierced vector.
PiercedVectorStorage< value_t, id_t >::iterator iterator
std::size_t size() const
__PXV_POINTER__ data() noexcept
__PXV_STORAGE_POINTER__ storedData() noexcept
__PXV_REFERENCE__ at(std::size_t n)
QualifiedCell & getCell() const
Definition cell.tpp:94
The Reference2DElementInfo class allows to define information about reference two-dimensional element...
virtual int getCCWOrderedVertex(int n) const
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
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
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
bool intersectPlaneTriangle(array3D const &P0, array3D const &P1, array3D const &P2, array3D const &Pp, array3D const &nP, std::array< array3D, 2 > &intersection, std::array< int, 2 > &edges_of_intersection, const double distanceTolerance=DEFAULT_COPLANARITY_TOLERANCE)
Definition CG_elem.cpp:2309
bool intersectPlanePixel(array3D const &Pp, array3D const &nP, array3D const *V, std::array< array3D, 2 > &intersection, std::array< int, 2 > &edges_of_intersection, const double distanceTolerance=DEFAULT_COPLANARITY_TOLERANCE)
Definition CG_elem.cpp:2138
bool intersectSegmentPlane(array3D const &, array3D const &, array3D const &, array3D const &, array3D &, const double distanceTolerance=DEFAULT_DISTANCE_TOLERANCE)
Definition CG_elem.cpp:1872
array3D rotatePoint(const array3D &P, const array3D &n0, const array3D &n1, double angle)
Definition CG_elem.cpp:893
bool intersectPlanePolygon(array3D const &P, array3D const &nP, std::size_t nV, array3D const *V, std::vector< std::array< array3D, 2 > > &Qs, std::vector< std::array< int, 2 > > &edges_of_Qs, const double distanceTolerance=DEFAULT_COPLANARITY_TOLERANCE)
Definition CG_elem.cpp:2460
T dotProduct(const std::array< T, d > &x, const std::array< T, d > &y)
double norm2(const std::array< T, d > &x)
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:1714
PatchManager & manager()