Loading...
Searching...
No Matches
patch_kernel.tpp
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#ifndef __BITPIT_PATCH_KERNEL_TPP__
26#define __BITPIT_PATCH_KERNEL_TPP__
27
28#include <stdexcept>
29
30namespace bitpit {
31
38template<typename patch_t>
39std::unique_ptr<patch_t> PatchKernel::clone(const patch_t *original)
40{
41 static_assert(std::is_base_of<PatchKernel, patch_t>::value, "Specified pointer is not derived from PatchKernel");
42
43 patch_t *clone = static_cast<patch_t *>(original->clone().release());
44
45 return std::unique_ptr<patch_t>(clone);
46}
47
53template<typename IdStorage>
54bool PatchKernel::deleteCells(const IdStorage &ids)
55{
57 return false;
58 }
59
60 // Deleteing the last internal cell requires some additional work. If the
61 // ids of cells to be deleted contains the last internal cell, we delete
62 // that cell ater deleting all other cells. In this way we make sure to
63 // deleting the last internal cells just once (after deleting the last
64 // internal, another cells becomes the last one and that cells may be
65 // on the deletion list, and on and so forth). The same applies for the
66 // first ghost.
67 bool deleteLastInternalCell = false;
68#if BITPIT_ENABLE_MPI==1
69 bool deleteFirstGhostCell = false;
70#endif
71 for (long id : ids) {
72 if (id == m_lastInternalCellId) {
73 deleteLastInternalCell = true;
74 continue;
75 }
76#if BITPIT_ENABLE_MPI==1
77 else if (id == m_firstGhostCellId) {
78 deleteFirstGhostCell = true;
79 continue;
80 }
81#endif
82
83 deleteCell(id);
84 }
85
86 if (deleteLastInternalCell) {
87 deleteCell(m_lastInternalCellId);
88 }
89
90#if BITPIT_ENABLE_MPI==1
91 if (deleteFirstGhostCell) {
92 deleteCell(m_firstGhostCellId);
93 }
94#endif
95
96 return true;
97}
98
104template<typename IdStorage>
105bool PatchKernel::deleteVertices(const IdStorage &ids)
106{
108 return false;
109 }
110
111 // Deleting the last vertex requires some additional work. If the ids
112 // of vertices to be deleted contain the last vertex, that vertex is
113 // deleted after deleting all other vertices. In this way we make sure
114 // to delete the last vertex just once (after deleting the last vertex,
115 // another vertex becomes the last one and that vertex may be on the
116 // deletion list as well, and on and so forth). The same applies for
117 // the first ghost.
118 bool deleteLastInternalVertex = false;
119#if BITPIT_ENABLE_MPI==1
120 bool deleteFirstGhostVertex = false;
121#endif
122 for (long id : ids) {
123 if (id == m_lastInternalVertexId) {
124 deleteLastInternalVertex = true;
125 continue;
126 }
127#if BITPIT_ENABLE_MPI==1
128 else if (id == m_firstGhostVertexId) {
129 deleteFirstGhostVertex = true;
130 continue;
131 }
132#endif
133
134 deleteVertex(id);
135 }
136
137 if (deleteLastInternalVertex) {
138 deleteVertex(m_lastInternalVertexId);
139 }
140
141#if BITPIT_ENABLE_MPI==1
142 if (deleteFirstGhostVertex) {
143 deleteVertex(m_firstGhostVertexId);
144 }
145#endif
146
147 return true;
148}
149
155template<typename IdStorage>
156bool PatchKernel::deleteInterfaces(const IdStorage &ids)
157{
159 return false;
160 }
161
162 // Deleting the last interface requires some additional work. If the ids
163 // of interfaces to be deleted contain the last interface, that interface
164 // is deleted after deleting all other interfaces. In this way we make
165 // sure to delete the last interface just once (after deleting the last
166 // interface, another interface becomes the last one and that interface
167 // may be on the deletion list as well, and on and so forth).
168 long lastId;
169 if (!m_interfaces.empty()) {
170 lastId = m_interfaces.back().getId();
171 } else {
172 lastId = Interface::NULL_ID;
173 }
174
175 bool deleteLast = false;
176 for (long id : ids) {
177 if (id == lastId) {
178 deleteLast = true;
179 continue;
180 }
181
182 deleteInterface(id);
183 }
184
185 if (deleteLast) {
186 deleteInterface(lastId);
187 }
188
189 return true;
190}
191
198template<typename item_t, typename id_t>
199std::unordered_map<id_t, id_t> PatchKernel::consecutiveItemRenumbering(PiercedVector<item_t, id_t> &container, long offset)
200{
201 // Build renumber map
202 std::unordered_map<id_t, id_t> renumberMap;
203
204 id_t counter = offset;
205 for(const item_t &item : container) {
206 id_t originalId = item.getId();
207 id_t finalId = counter++;
208
209 renumberMap.insert({originalId, finalId});
210 }
211
212 // Renumber items
213 mappedItemRenumbering(container, renumberMap);
214
215 return renumberMap;
216}
217
224template<typename item_t, typename id_t>
226 const std::unordered_map<id_t, id_t> &renumberMap)
227{
228 // Find an unused id
229 id_t unusedId = std::numeric_limits<id_t>::max();
230 while (container.exists(unusedId)) {
231 --unusedId;
232 if (unusedId < 0) {
233 break;
234 }
235 }
236
237 // Renumber the items
238 std::unordered_map<id_t, id_t> conflictMap;
239
240 for(const item_t &item : container) {
241 // Original id of the item
242 //
243 // To get the original id of the item we use the conflict map, once
244 // we get the id of an item we can remove it from the conflict map.
245 id_t currentId = item.getId();
246
247 id_t originalId;
248 auto conflictMapItr = conflictMap.find(currentId);
249 if (conflictMapItr != conflictMap.end()) {
250 originalId = conflictMapItr->second;
251 conflictMap.erase(conflictMapItr);
252 } else {
253 originalId = currentId;
254 }
255
256 // Final id of the item
257 id_t finalId = renumberMap.at(originalId);
258
259 // Nothing else to do if the item has already the correct id, otherwise
260 // we need to renumber the item.
261 if (currentId == finalId) {
262 continue;
263 }
264
265 // Check if the final id is already in the container.
266 //
267 // If there is a conflict, the item that holds the final id will
268 // be temporarly renumbered with the unused id find before, the current
269 // item will be renumberd with is final id and eventually the item with
270 // the temporary id will be assoicated with the, now avilable, id of
271 // the current item.
272 id_t oldConflictId;
273 id_t newConflicdId;
274 id_t tmpConflictId;
275
276 bool conflict = container.exists(finalId);
277 if (conflict) {
278 if (unusedId < 0) {
279 throw std::runtime_error("Renumbering requires an unused id, but all ids are used.");
280 }
281
282 oldConflictId = finalId;
283 newConflicdId = currentId;
284 tmpConflictId = unusedId;
285 }
286
287 // Temporary renumber of the conflicting item
288 //
289 // There is no need to change the id of the element, it is sufficient
290 // update the container. The id will be updated later.
291 if (conflict) {
292 container.updateId(oldConflictId, tmpConflictId);
293 }
294
295 // Renumber of the current element
296 container[currentId].setId(finalId);
297 container.updateId(currentId, finalId);
298
299 // Renumber the conflicting element with the previous id of the item
300 if (conflict) {
301 container.updateId(tmpConflictId, newConflicdId);
302 container[newConflicdId].setId(newConflicdId);
303
304 // Update conflic map
305 auto conflictMapItr = conflictMap.find(oldConflictId);
306 if (conflictMapItr == conflictMap.end()) {
307 conflictMap.insert({newConflicdId, oldConflictId});
308 } else {
309 conflictMap.insert({newConflicdId, conflictMapItr->second});
310 conflictMap.erase(conflictMapItr);
311 }
312 }
313 }
314}
315
331template<typename Function>
332void PatchKernel::processCellNeighbours(long seedId, int nLayers, Function function) const
333{
334 auto selector = [](long neighId) {
335 BITPIT_UNUSED(neighId);
336
337 return true;
338 };
339
340 processCellNeighbours(seedId, nLayers, selector, function);
341}
342
365template<typename Selector, typename Function>
366void PatchKernel::processCellNeighbours(long seedId, int nLayers, Selector selector, Function function) const
367{
368 if (nLayers == 1) {
369 assert(getAdjacenciesBuildStrategy() != ADJACENCIES_NONE);
370
371 std::vector<long> neighIds;
372 findCellNeighs(seedId, &neighIds);
373 for (long neighId : neighIds) {
374 if (!selector(neighId)) {
375 continue;
376 }
377
378 bool stop = function(neighId, 0);
379 if (stop) {
380 return;
381 }
382 }
383 } else {
384 processCellsNeighbours(std::array<long, 1>{{seedId}}, nLayers, selector, function);
385 }
386}
387
407template<typename Function, typename SeedContainer>
408void PatchKernel::processCellsNeighbours(const SeedContainer &seeds, int nLayers, Function function) const
409{
410 auto selector = [](long neighId) {
411 BITPIT_UNUSED(neighId);
412
413 return true;
414 };
415
416 processCellsNeighbours(seeds, nLayers, selector, function);
417}
418
440template<typename Selector, typename Function, typename SeedContainer>
441void PatchKernel::processCellsNeighbours(const SeedContainer &seedIds, int nLayers,
442 Selector selector, Function function) const
443{
444 assert(getAdjacenciesBuildStrategy() != ADJACENCIES_NONE);
445
446 std::unordered_set<long> previousSeedIds;
447 std::unordered_set<long> currentSeedIds;
448 std::unordered_set<long> futureSeeds(seedIds.begin(), seedIds.end());
449
450 std::vector<long> neighIds;
451 for (int layer = 0; layer < nLayers; ++layer) {
452 previousSeedIds.swap(currentSeedIds);
453 currentSeedIds.swap(futureSeeds);
454 futureSeeds.clear();
455
456 for (long seedId : currentSeedIds) {
457 neighIds.clear();
458 findCellNeighs(seedId, &neighIds);
459 for (long neighId : neighIds) {
460 if (previousSeedIds.count(neighId) > 0) {
461 continue;
462 } else if (currentSeedIds.count(neighId) > 0) {
463 continue;
464 } else if (futureSeeds.count(neighId) > 0) {
465 continue;
466 } else if (!selector(neighId)) {
467 continue;
468 }
469
470 bool stop = function(neighId, layer);
471 if (stop) {
472 return;
473 }
474
475 futureSeeds.insert(neighId);
476 }
477 }
478 }
479}
480
496template<typename Function>
497void PatchKernel::processCellFaceNeighbours(long seedId, int nLayers, Function function) const
498{
499 auto selector = [](long neighId) {
500 BITPIT_UNUSED(neighId);
501
502 return true;
503 };
504
505 processCellFaceNeighbours(seedId, nLayers, selector, function);
506}
507
529template<typename Selector, typename Function>
530void PatchKernel::processCellFaceNeighbours(long seedId, int nLayers, Selector selector, Function function) const
531{
532 if (nLayers == 1) {
533 bool cellAdjacenciesAvailable = (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE);
534 if (cellAdjacenciesAvailable) {
535 cellAdjacenciesAvailable = !m_cells.empty();
536 }
537
538 std::unique_ptr<std::vector<long>> neighStorage;
539 if (!cellAdjacenciesAvailable) {
540 neighStorage = std::unique_ptr<std::vector<long>>(new std::vector<long>());
541 }
542
543 const long *neighs;
544 std::size_t nNeighs;
545 if (cellAdjacenciesAvailable) {
546 const Cell &cell = getCell(seedId);
547 neighs = cell.getAdjacencies();
548 nNeighs = cell.getAdjacencyCount();
549 } else {
550 findCellFaceNeighs(seedId, neighStorage.get());
551 neighs = neighStorage->data();
552 nNeighs = neighStorage->size();
553 }
554
555 for(std::size_t n = 0; n < nNeighs; ++n){
556 long neighId = neighs[n];
557 if (!selector(neighId)) {
558 continue;
559 }
560
561 bool stop = function(neighId, 0);
562 if (stop) {
563 return;
564 }
565 }
566 } else {
567 processCellsFaceNeighbours(std::array<long, 1>{{seedId}}, nLayers, selector, function);
568 }
569}
570
586template<typename Function, typename SeedContainer>
587void PatchKernel::processCellsFaceNeighbours(const SeedContainer &seedIds, int nLayers, Function function) const
588{
589 auto selector = [](long neighId) {
590 BITPIT_UNUSED(neighId);
591
592 return true;
593 };
594
595 processCellsFaceNeighbours(seedIds, nLayers, selector, function);
596}
597
619template<typename Selector, typename Function, typename SeedContainer>
620void PatchKernel::processCellsFaceNeighbours(const SeedContainer &seedIds, int nLayers,
621 Selector selector, Function function) const
622{
623 // Early return if there are no layers to process
624 if (nLayers == 0) {
625 return;
626 }
627
628 // Initialize neighbour evaluation
629 bool cellAdjacenciesAvailable = (getAdjacenciesBuildStrategy() != ADJACENCIES_NONE);
630
631 std::unique_ptr<std::vector<long>> neighStorage;
632 if (!cellAdjacenciesAvailable) {
633 neighStorage = std::unique_ptr<std::vector<long>>(new std::vector<long>());
634 }
635
636 // Process neighbours
637 std::unordered_set<long> previousSeedIds;
638 std::unordered_set<long> currentSeedIds;
639 std::unordered_set<long> futureSeeds(seedIds.begin(), seedIds.end());
640
641 for (int layer = 0; layer < nLayers; ++layer) {
642 previousSeedIds.swap(currentSeedIds);
643 currentSeedIds.swap(futureSeeds);
644 futureSeeds.clear();
645
646 for (long seedId : currentSeedIds) {
647 const long *neighs;
648 std::size_t nNeighs;
649 if (cellAdjacenciesAvailable) {
650 const Cell &cell = getCell(seedId);
651 neighs = cell.getAdjacencies();
652 nNeighs = cell.getAdjacencyCount();
653 } else {
654 findCellFaceNeighs(seedId, neighStorage.get());
655 neighs = neighStorage->data();
656 nNeighs = neighStorage->size();
657 }
658
659 for(std::size_t n = 0; n < nNeighs; ++n){
660 long neighId = neighs[n];
661 if (previousSeedIds.count(neighId) > 0) {
662 continue;
663 } else if (currentSeedIds.count(neighId) > 0) {
664 continue;
665 } else if (futureSeeds.count(neighId) > 0) {
666 continue;
667 } else if (!selector(neighId)) {
668 continue;
669 }
670
671 bool stop = function(neighId, layer);
672 if (stop) {
673 return;
674 }
675
676 futureSeeds.insert(neighId);
677 }
678 }
679 }
680}
681
682}
683
684#endif
The Cell class defines the cells.
Definition cell.hpp:42
const long * getAdjacencies() const
Definition cell.cpp:841
int getAdjacencyCount() const
Definition cell.cpp:805
void processCellNeighbours(long seedId, int nLayers, Function function) const
void mappedItemRenumbering(PiercedVector< item_t, id_t > &container, const std::unordered_map< id_t, id_t > &renumberMap)
AdjacenciesBuildStrategy getAdjacenciesBuildStrategy() const
std::unordered_map< id_t, id_t > consecutiveItemRenumbering(PiercedVector< item_t, id_t > &container, long offset)
AdaptionMode getAdaptionMode() const
std::vector< long > findCellNeighs(long id) const
bool deleteVertex(long id)
void processCellsNeighbours(const SeedContainer &seedIds, int nLayers, Function function) const
Cell & getCell(long id)
std::vector< long > findCellFaceNeighs(long id) const
bool deleteVertices(const IdStorage &ids)
void processCellFaceNeighbours(long seedId, int nLayers, Function function) const
bool deleteCell(long id)
bool deleteInterface(long id)
static std::unique_ptr< patch_t > clone(const patch_t *original)
bool deleteCells(const IdStorage &ids)
void processCellsFaceNeighbours(const SeedContainer &seedIds, int nLayers, Function function) const
bool deleteInterfaces(const IdStorage &ids)
void updateId(const id_t &currentId, const id_t &updatedId)
const_iterator find(const id_t &id) const noexcept
Metafunction for generating a pierced vector.
#define BITPIT_UNUSED(variable)
Definition compiler.hpp:63
--- layout: doxygen_footer ---