28#include "bitpit_operators.hpp"
31#include "ParaTree.hpp"
85 : sendAction(ACTION_UNDEFINED), recvAction(ACTION_UNDEFINED)
97 : sendRanges(_sendRanges), recvRanges(_recvRanges)
100 sendAction = ACTION_DELETE;
101 recvAction = ACTION_NONE;
103 sendAction = ACTION_SEND;
104 recvAction = ACTION_RECEIVE;
112 sendAction = ACTION_UNDEFINED;
115 recvAction = ACTION_UNDEFINED;
132#if BITPIT_ENABLE_MPI==1
140#if BITPIT_ENABLE_MPI==1
141 : m_comm(MPI_COMM_NULL)
144#if BITPIT_ENABLE_MPI==1
145 initialize(logfile, comm);
157#if BITPIT_ENABLE_MPI==1
165 : m_octree(dim), m_trans(dim)
166#if BITPIT_ENABLE_MPI==1
167 , m_comm(MPI_COMM_NULL)
170#if BITPIT_ENABLE_MPI==1
171 initialize(dim, logfile, comm);
173 initialize(dim, logfile);
187#if BITPIT_ENABLE_MPI==1
195#if BITPIT_ENABLE_MPI==1
196 : m_comm(MPI_COMM_NULL)
199#if BITPIT_ENABLE_MPI==1
200 initialize(logfile, comm);
212#if BITPIT_ENABLE_MPI==1
224 : m_partitionFirstDesc(other.m_partitionFirstDesc),
225 m_partitionLastDesc(other.m_partitionLastDesc),
226 m_partitionRangeGlobalIdx(other.m_partitionRangeGlobalIdx),
227 m_partitionRangeGlobalIdx0(other.m_partitionRangeGlobalIdx0),
228 m_globalNumOctants(other.m_globalNumOctants),
229 m_maxDepth(other.m_maxDepth),
230 m_treeConstants(other.m_treeConstants),
231 m_nofGhostLayers(other.m_nofGhostLayers),
232 m_octree(other.m_octree),
233 m_bordersPerProc(other.m_bordersPerProc),
234 m_internals(other.m_internals),
235 m_pborders(other.m_pborders),
236 m_mapIdx(other.m_mapIdx),
237 m_loadBalanceRanges(other.m_loadBalanceRanges),
238 m_errorFlag(other.m_errorFlag),
239 m_serial(other.m_serial),
241 m_trans(other.m_trans),
243 m_periodic(other.m_periodic),
244 m_status(other.m_status),
245 m_lastOp(other.m_lastOp),
247#if BITPIT_ENABLE_MPI==1
248 , m_comm(MPI_COMM_NULL)
251#if BITPIT_ENABLE_MPI==1
252 _initializeCommunicator(other.m_comm);
254 _initializeSerialCommunicator();
262#if BITPIT_ENABLE_MPI==1
271 ParaTree::_initializeCommunicator(MPI_Comm communicator)
275 throw std::runtime_error (
"PABLO communicator can be set just once");
279 if (communicator == MPI_COMM_NULL) {
280 m_comm = MPI_COMM_NULL;
293 MPI_Comm_dup(communicator, &m_comm);
296 MPI_Comm_size(m_comm, &m_nproc);
297 MPI_Comm_rank(m_comm, &m_rank);
304 ParaTree::_initializeSerialCommunicator()
316 ParaTree::_initializePartitions() {
318 m_partitionFirstDesc.resize(m_nproc);
319 m_partitionLastDesc.resize(m_nproc);
320 m_partitionRangeGlobalIdx.resize(m_nproc);
321 m_partitionRangeGlobalIdx0.resize(m_nproc);
322 uint64_t lastDescMorton = m_octree.getLastDescMorton();
323 uint64_t firstDescMorton = m_octree.getFirstDescMorton();
324 for(
int p = 0; p < m_nproc; ++p){
325 m_partitionRangeGlobalIdx0[p] = 0;
326 m_partitionRangeGlobalIdx[p] = m_globalNumOctants - 1;
327 m_partitionLastDesc[p] = lastDescMorton;
328 m_partitionFirstDesc[p] = firstDescMorton;
337 ParaTree::_initialize(uint8_t dim,
const std::string &logfile) {
345 initializeLogger(logfile);
351 m_globalNumOctants = 0;
354 m_nofGhostLayers = 1;
361#if BITPIT_ENABLE_MPI==1
366 ParaTree::initialize(
const std::string &logfile, MPI_Comm comm) {
369 ParaTree::initialize(
const std::string &logfile) {
371#if BITPIT_ENABLE_MPI==1
373 _initializeCommunicator(comm);
376 _initializeSerialCommunicator();
380 _initialize(0, logfile);
383 _initializePartitions();
390#if BITPIT_ENABLE_MPI==1
396#if BITPIT_ENABLE_MPI==1
397 ParaTree::initialize(uint8_t dim,
const std::string &logfile, MPI_Comm comm) {
399 ParaTree::initialize(uint8_t dim,
const std::string &logfile) {
401#if BITPIT_ENABLE_MPI==1
403 _initializeCommunicator(comm);
406 _initializeSerialCommunicator();
410 if (dim < 2 || dim > 3) {
411 throw std::runtime_error (
"Invalid value for the dimension");
414 _initialize(dim, logfile);
417 _initializePartitions();
425 ParaTree::reinitialize(uint8_t dim,
const std::string &logfile) {
427 if (dim < 2 || dim > 3) {
428 throw std::runtime_error (
"Invalid value for the dimension");
431 _initialize(dim, logfile);
434 _initializePartitions();
440 ParaTree::initializeLogger(
const std::string &logfile){
466 m_octree.reset(createRoot);
471 m_bordersPerProc.clear();
475 m_loadBalanceRanges.
clear();
477 std::fill(m_periodic.begin(), m_periodic.end(),
false);
479 _initializePartitions();
490 const int DUMP_VERSION = 1;
518 for (
int i = 0; i < m_treeConstants->
nFaces; i++) {
529 for (uint32_t i = 0; i < nOctants; i++) {
530 const Octant &octant = m_octree.m_octants[i];
538 for (
size_t k = 0; k < Octant::INFO_ITEM_COUNT; ++k) {
547 for (
int k = 0; k < m_nproc; ++k) {
551 for (
int k = 0; k < m_nproc; ++k) {
555 for (
int k = 0; k < m_nproc; ++k) {
563 if (m_lastOp == OP_ADAPT_MAPPED){
564 for (
auto idx : m_mapIdx) {
569 for (
auto lastGhostBrother : m_octree.m_lastGhostBros) {
573 else if (m_lastOp == OP_LOADBALANCE || m_lastOp == OP_LOADBALANCE_FIRST){
574 for (
int i = 0; i < m_nproc; ++i) {
594 throw std::runtime_error (
"The version of the file does not match the required version");
600 if (nProcs != m_nproc) {
601 throw std::runtime_error (
"The restart was saved with a different number of processes.");
608 m_octree.initialize(dimension);
609 m_trans.initialize(dimension);
610 reinitialize(dimension, m_log->
getName());
619 bool balanceCodimension;
623 for (
int i = 0; i < m_treeConstants->
nFaces; i++) {
635 uint64_t nGlobalOctants;
637 m_globalNumOctants = nGlobalOctants;
639 m_octree.m_octants.clear();
640 m_octree.m_octants.reserve(nOctants);
641 for (uint32_t i = 0; i < nOctants; i++) {
655 Octant octant(
false, m_dim, level, x, y, z);
662 for (
size_t k = 0; k < Octant::INFO_ITEM_COUNT; ++k) {
665 octant.m_info.set(k, bit);
679 m_octree.m_octants.push_back(std::move(octant));
682 m_octree.updateLocalMaxDepth();
685 m_partitionFirstDesc.resize(m_nproc);
686 for (
int k = 0; k < m_nproc; ++k) {
689 m_partitionFirstDesc[k] = descendant;
691 m_octree.m_firstDescMorton = m_partitionFirstDesc[m_rank];
693 m_partitionLastDesc.resize(m_nproc);
694 for (
int k = 0; k < m_nproc; ++k) {
697 m_partitionLastDesc[k] = descendant;
699 m_octree.m_lastDescMorton = m_partitionLastDesc[m_rank];
702 m_partitionRangeGlobalIdx.resize(m_nproc);
703 for (
int k = 0; k < m_nproc; ++k) {
704 uint64_t rangeGlobalIdx;
706 m_partitionRangeGlobalIdx[k] = rangeGlobalIdx;
709#if BITPIT_ENABLE_MPI==1
718 for (
int i = 0; i < m_nproc; ++i) {
719 m_partitionRangeGlobalIdx0[i] = 0;
726 if (m_lastOp == OP_ADAPT_MAPPED) {
727 m_mapIdx.resize(m_octree.m_octants.size());
728 for (
size_t i = 0; i < m_octree.m_octants.size(); ++i) {
732 size_t lastGhostBrosSize;
734 m_octree.m_lastGhostBros.resize(lastGhostBrosSize);
735 for (
size_t i = 0; i < lastGhostBrosSize; ++i) {
739 else if (m_lastOp == OP_LOADBALANCE || m_lastOp == OP_LOADBALANCE_FIRST){
740 for (
int i = 0; i < m_nproc; ++i) {
757 (*m_log) <<
"---------------------------------------------" << endl;
758 (*m_log) <<
"- PABLO PArallel Balanced Linear Octree -" << endl;
759 (*m_log) <<
"---------------------------------------------" << endl;
760 (*m_log) <<
" " << endl;
761 (*m_log) <<
"---------------------------------------------" << endl;
762 (*m_log) <<
"- PABLO restart -" << endl;
763 (*m_log) <<
"---------------------------------------------" << endl;
764 (*m_log) <<
" Number of proc : " + to_string(
static_cast<unsigned long long>(m_nproc)) << endl;
765 (*m_log) <<
" Dimension : " + to_string(
static_cast<unsigned long long>(m_dim)) << endl;
766 (*m_log) <<
" Max allowed level : " + to_string(
static_cast<unsigned long long>(m_treeConstants->
maxLevel)) << endl;
767 (*m_log) <<
" Number of octants : " + to_string(
static_cast<unsigned long long>(m_globalNumOctants)) << endl;
768 (*m_log) <<
"---------------------------------------------" << endl;
769 (*m_log) <<
" " << endl;
789 return m_globalNumOctants;
840#if BITPIT_ENABLE_MPI==1
851 if (communicator == MPI_COMM_NULL) {
852 throw std::runtime_error (
"PABLO communicator is not valid");
856 _initializeCommunicator(communicator);
859 _initializePartitions();
882 throw std::runtime_error (
"PABLO communicator is not set");
891 MPI_Comm_rank(communicator, &updatedRank);
894 int isValid = (updatedRank == currentRank) ? 1 : 0;
895 MPI_Allreduce(MPI_IN_PLACE, &isValid, 1, MPI_INT, MPI_LAND, m_comm);
897 throw std::runtime_error (
"New communicator is not valid");
901 if (previousCommunicator) {
902 *previousCommunicator = m_comm;
903 m_comm = MPI_COMM_NULL;
923 MPI_Finalized(&finalizedCalled);
924 if (finalizedCalled) {
928 MPI_Comm_free(&m_comm);
937 return (
getComm() != MPI_COMM_NULL);
954 const std::vector<uint64_t> &
956 return m_partitionRangeGlobalIdx;
964 const std::vector<uint64_t> &
966 return m_partitionFirstDesc;
974 const std::vector<uint64_t> &
976 return m_partitionLastDesc;
984 return m_trans.m_origin;
992 return m_trans.m_origin[0];
1000 return m_trans.m_origin[1];
1008 return m_trans.m_origin[2];
1032 return m_treeConstants->
lengths[0];
1040 return m_treeConstants->
nNodes;
1048 return m_treeConstants->
nFaces;
1056 return m_treeConstants->
nEdges;
1080 for (
int i=0; i<6; i++){
1081 for (
int j=0; j<3; j++){
1082 normals[i][j] = m_treeConstants->
normals[i][j];
1094 for (
int j=0; j<6; j++){
1105 for (
int i=0; i<6; i++){
1106 for (
int j=0; j<4; j++){
1107 facenode[i][j] = m_treeConstants->
faceNode[i][j];
1118 for (
int i=0; i<8; i++){
1119 for (
int j=0; j<3; j++){
1120 nodeface[i][j] = m_treeConstants->
nodeFace[i][j];
1131 for (
int i=0; i<12; i++){
1132 for (
int j=0; j<2; j++){
1133 edgeface[i][j] = m_treeConstants->
edgeFace[i][j];
1143 for (
int i=0; i<8; i++){
1144 nodecoeffs[i][2] = 0;
1145 for (
int j=0; j<m_dim; j++){
1146 nodecoeffs[i][j] = m_treeConstants->
nodeCoeffs[i][j];
1156 for (
int i=0; i<12; i++){
1157 for (
int j=0; j<3; j++){
1158 edgecoeffs[i][j] = m_treeConstants->
edgeCoeffs[i][j];
1168 return m_treeConstants->
normals;
1238 return m_periodic[i];
1253 m_periodic[i] =
true;
1255 m_octree.setPeriodic(m_periodic);
1276 return m_trans.mapCoordinates(m_octree.m_octants[idx].getLogicalCoordinates());
1285 return m_trans.mapX(m_octree.m_octants[idx].getLogicalCoordinates(0));
1294 return m_trans.mapY(m_octree.m_octants[idx].getLogicalCoordinates(1));
1303 return m_trans.mapZ(m_octree.m_octants[idx].getLogicalCoordinates(2));
1312 return m_trans.mapSize(m_octree.m_octants[idx].getLogicalSize());
1321 return m_trans.mapArea(m_octree.m_octants[idx].getLogicalArea());
1330 return m_trans.mapVolume(m_octree.m_octants[idx].getLogicalVolume());
1339 darray3 centerCoords_ = m_octree.m_octants[idx].getLogicalCenter();
1340 m_trans.mapCenter(centerCoords_, centerCoords);
1349 darray3 centerCoords = {{0., 0., 0.}};
1350 darray3 centerCoords_ = m_octree.m_octants[idx].getLogicalCenter();
1351 m_trans.mapCenter(centerCoords_, centerCoords);
1352 return centerCoords;
1362 darray3 centerCoords = {{0., 0., 0.}};
1363 darray3 centerCoords_ = m_octree.m_octants[idx].getLogicalFaceCenter(face);
1364 m_trans.mapCenter(centerCoords_, centerCoords);
1365 return centerCoords;
1375 darray3 centerCoords_ = m_octree.m_octants[idx].getLogicalFaceCenter(face);
1376 m_trans.mapCenter(centerCoords_, centerCoords);
1386 darray3 nodeCoords = {{0., 0., 0.}};
1387 u32array3 nodeCoords_ = m_octree.m_octants[idx].getLogicalNode(node);
1388 m_trans.mapNode(nodeCoords_, nodeCoords);
1399 u32array3 nodeCoords_ = m_octree.m_octants[idx].getLogicalNode(node);
1400 m_trans.mapNode(nodeCoords_, nodeCoords);
1409 u32arr3vector nodesCoords_;
1410 m_octree.m_octants[idx].getLogicalNodes(nodesCoords_);
1411 m_trans.mapNodes(nodesCoords_, nodesCoords);
1420 darr3vector nodesCoords;
1421 u32arr3vector nodesCoords_;
1422 m_octree.m_octants[idx].getLogicalNodes(nodesCoords_);
1423 m_trans.mapNodes(nodesCoords_, nodesCoords);
1435 m_octree.m_octants[idx].getNormal(face, normal_, m_treeConstants->
normals);
1436 m_trans.mapNormals(normal_, normal);
1446 darray3 normal = {{0., 0., 0.}};
1447 i8array3 normal_ = {{0, 0, 0}};
1448 m_octree.m_octants[idx].getNormal(face, normal_, m_treeConstants->
normals);
1449 m_trans.mapNormals(normal_, normal);
1459 return m_octree.getMarker(idx);
1469 if (m_lastOp != OP_PRE_ADAPT) {
1470 throw std::runtime_error(
"Last operation different from preadapt, unable to call getPreMarker function");
1473 return m_octree.getMarker(idx);
1482 return m_octree.getLevel(idx);
1491 return m_octree.getMorton(idx);
1502 return m_octree.computeNodePersistentKey(idx, node);
1511 return m_octree.getBalance(idx);
1521 return m_octree.m_octants[idx].getBound(face);
1530 return m_octree.m_octants[idx].getBound();
1540 return m_octree.m_octants[idx].getPbound(face);
1549 return m_octree.m_octants[idx].getPbound();
1558 return m_octree.m_octants[idx].getIsNewR();
1567 return m_octree.m_octants[idx].getIsNewC();
1577 return m_partitionRangeGlobalIdx[m_rank-1] + uint64_t(idx + 1);
1580 return uint64_t(idx);
1592 return uint32_t(gidx - 1 - m_partitionRangeGlobalIdx[rank-1]);
1595 return uint32_t(gidx);
1618 return uint32_t(gidx - 1 - m_partitionRangeGlobalIdx[m_rank-1]);
1621 return uint32_t(gidx);
1633 typename u64vector::const_iterator findResult;
1634 findResult = std::find(m_octree.m_globalIdxGhosts.begin(),m_octree.m_globalIdxGhosts.end(),gidx);
1635 if(findResult != m_octree.m_globalIdxGhosts.end()){
1636 index =
static_cast<uint32_t
>(std::distance(m_octree.m_globalIdxGhosts.begin(),findResult));
1639 index = std::numeric_limits<uint32_t>::max();
1651 uint32_t nGhosts = m_octree.getNumGhosts();
1653 return m_octree.m_globalIdxGhosts[idx];
1655 return uint64_t(nGhosts);
1665 ParaTree::isInternal(uint64_t gidx)
const {
1666 if (gidx > m_partitionRangeGlobalIdx[m_rank]){
1670 if (m_rank != 0 && gidx <= m_partitionRangeGlobalIdx[m_rank - 1]){
1687 persistent |= level;
1697 if (m_lastOp == OP_PRE_ADAPT) {
1698 throw std::runtime_error(
"It is not possible to update the tree until the adaption is completed");
1701 m_octree.setMarker(idx, marker);
1710 if (m_lastOp == OP_PRE_ADAPT) {
1711 throw std::runtime_error(
"It is not possible to update the tree until the adaption is completed");
1714 m_octree.setBalance(idx, balance);
1791 m_trans.mapCenter(centerCoords_, centerCoords);
1800 darray3 centerCoords = {{0., 0., 0.}};
1802 m_trans.mapCenter(centerCoords_, centerCoords);
1803 return centerCoords;
1813 darray3 centerCoords = {{0., 0., 0.}};
1815 m_trans.mapCenter(centerCoords_, centerCoords);
1816 return centerCoords;
1827 m_trans.mapCenter(centerCoords_, centerCoords);
1837 darray3 nodeCoords = {{0., 0., 0.}};
1839 m_trans.mapNode(nodeCoords_, nodeCoords);
1851 m_trans.mapNode(nodeCoords_, nodeCoords);
1860 u32arr3vector nodesCoords_;
1862 m_trans.mapNodes(nodesCoords_, nodes);
1872 u32arr3vector nodesCoords_;
1874 m_trans.mapNodes(nodesCoords_, nodes);
1887 m_trans.mapNormals(normal_, normal);
1897 darray3 normal = {{0., 0., 0.}};
1898 i8array3 normal_ = {{0, 0, 0}};
1900 m_trans.mapNormals(normal_, normal);
1920 if (m_lastOp != OP_PRE_ADAPT) {
1921 throw std::runtime_error(
"Last operation different from preadapt, unable to call getPreMarker function");
2036#if BITPIT_ENABLE_MPI==1
2038 return m_octree.findGhostMorton(oct->
getMorton());
2041 return m_octree.findMorton(oct->
getMorton());
2050 uint32_t idx =
getIdx(oct);
2051#if BITPIT_ENABLE_MPI==1
2053 return m_octree.m_globalIdxGhosts[idx];
2057 return m_partitionRangeGlobalIdx[m_rank-1] + uint64_t(idx + 1);
2059 return uint64_t(idx);
2072 persistent |= level;
2082 if (m_lastOp == OP_PRE_ADAPT) {
2083 throw std::runtime_error(
"It is not possible to update the tree until the adaption is completed");
2095 if (m_lastOp == OP_PRE_ADAPT) {
2096 throw std::runtime_error(
"It is not possible to update the tree until the adaption is completed");
2119 return m_octree.getNumOctants();
2127 return m_octree.getNumGhosts();
2135 return m_octree.m_nodes.size();
2143 return m_octree.getLocalMaxDepth();
2151 uint32_t size = uint32_t(1)<<(m_treeConstants->
maxLevel-m_octree.getLocalMaxDepth());
2152 return m_trans.mapSize(size);
2163 for (uint32_t idx = 0; idx < nocts; idx++){
2165 if (octSize > size) size = octSize;
2175 return m_octree.getBalanceCodim();
2182 return m_octree.getFirstDescMorton();
2189 return m_octree.getLastDescMorton();
2198 return m_octree.m_octants[idx].computeLastDescMorton();
2206 return m_internals.begin();
2214 return m_internals.end();
2222 return m_pborders.begin();
2230 return m_pborders.end();
2238 if (m_lastOp == OP_PRE_ADAPT) {
2239 throw std::runtime_error(
"It is not possible to update the tree until the adaption is completed");
2242 m_octree.setBalanceCodim(b21codim);
2254 return m_octree.m_intersections.size();
2263 if (idx < m_octree.m_intersections.size()){
2264 return &m_octree.m_intersections[idx];
2275 if(inter->m_finer && inter->m_isghost)
2276 return m_octree.extractGhostOctant(inter->m_owners[inter->m_finer]).
getLevel();
2278 return m_octree.extractOctant(inter->m_owners[inter->m_finer]).
getLevel();
2287 return inter->m_finer;
2296 return inter->getBound();
2305 return inter->getIsGhost();
2314 return inter->getPbound();
2323 return inter->m_iface;
2332 u32vector owners(2);
2333 owners[0] = inter->m_owners[0];
2334 owners[1] = inter->m_owners[1];
2344 return inter->getIn();
2353 return inter->getOut();
2362 return inter->getOutIsGhost();
2372 if(inter->m_finer && inter->m_isghost)
2373 Size = m_octree.extractGhostOctant(inter->m_owners[inter->m_finer]).
getLogicalSize();
2375 Size = m_octree.extractOctant(inter->m_owners[inter->m_finer]).
getLogicalSize();
2376 return m_trans.mapSize(Size);
2386 if(inter->m_finer && inter->m_isghost)
2387 Area = m_octree.extractGhostOctant(inter->m_owners[1]).
getLogicalArea();
2389 Area = m_octree.extractOctant(inter->m_owners[inter->m_finer]).
getLogicalArea();
2390 return m_trans.mapArea(Area);
2400 if(inter->m_finer && inter->m_isghost)
2401 oct = m_octree.extractGhostOctant(inter->m_owners[inter->m_finer]);
2403 oct = m_octree.extractOctant(inter->m_owners[inter->m_finer]);
2405 darray3 center = {{0., 0., 0.}};
2407 int sign = ( int(2*((inter->m_iface)%2)) - 1);
2409 centerCoords_[inter->m_iface/2] = uint32_t(
int(centerCoords_[inter->m_iface/2]) + deplace);
2410 m_trans.mapCenter(centerCoords_, center);
2422 if(inter->m_finer && inter->m_isghost)
2423 oct = m_octree.extractGhostOctant(inter->m_owners[inter->m_finer]);
2425 oct = m_octree.extractOctant(inter->m_owners[inter->m_finer]);
2426 uint8_t face = inter->m_iface;
2427 u32arr3vector nodesCoords_all;
2431 for (
int j=0; j<3; j++){
2432 nodesCoords_[i][j] = nodesCoords_all[m_treeConstants->
faceNode[face][i]][j];
2435 m_trans.mapNodesIntersection(nodesCoords_, nodes);
2446 if(inter->m_finer && inter->m_isghost)
2447 oct = m_octree.extractGhostOctant(inter->m_owners[inter->m_finer]);
2449 oct = m_octree.extractOctant(inter->m_owners[inter->m_finer]);
2451 uint8_t face = inter->m_iface;
2452 darray3 normal = {{0., 0., 0.}};
2453 i8array3 normal_ = {{0, 0, 0}};
2455 m_trans.mapNormals(normal_, normal);
2470 return (m_octree.m_octants.data() + idx);
2480 return (m_octree.m_octants.data() + idx);
2490 return (m_octree.m_ghosts.data() + idx);
2500 return (m_octree.m_ghosts.data() + idx);
2527 return m_loadBalanceRanges;
2535 return m_nofGhostLayers;
2543 if (m_nofGhostLayers == 0) {
2544 throw std::runtime_error (
"It is not possible to disable the ghost halo!");
2548 typedef std::make_unsigned<layer_t>::type ulayer_t;
2549 ulayer_t maxNofGhostLayers = std::numeric_limits<layer_t>::max() + (ulayer_t) 1;
2550 if (nofGhostLayers > maxNofGhostLayers) {
2551 throw std::runtime_error (
"Halo size exceeds the maximum allowed value.");
2554 m_nofGhostLayers = nofGhostLayers;
2561 return m_bordersPerProc;
2571 ParaTree::setDim(uint8_t dim){
2575 m_periodic.resize(m_treeConstants->
nFaces,
false);
2577 m_treeConstants =
nullptr;
2582#if BITPIT_ENABLE_MPI==1
2586 ParaTree::updateGlobalFirstDescMorton(){
2589 uint64_t firstDescMorton = m_octree.getFirstDescMorton();
2590 m_errorFlag = MPI_Allgather(&firstDescMorton,1,MPI_UINT64_T,m_partitionFirstDesc.data(),1,MPI_UINT64_T,m_comm);
2594 if (m_partitionRangeGlobalIdx[pp] == m_partitionRangeGlobalIdx[pp-1]){
2595 m_partitionFirstDesc[pp] = std::numeric_limits<uint64_t>::max();
2597 m_octree.m_firstDescMorton = std::numeric_limits<uint64_t>::max();
2600 for (
int p = pp-1; p > 0; --p){
2601 if (m_partitionRangeGlobalIdx[p] == m_partitionRangeGlobalIdx[p-1]){
2602 m_partitionFirstDesc[p] = m_partitionFirstDesc[p+1];
2604 m_octree.m_firstDescMorton = m_partitionFirstDesc[p+1];
2613 ParaTree::updateGlobalLasttDescMorton(){
2616 uint64_t lastDescMorton = m_octree.getLastDescMorton();
2617 m_errorFlag = MPI_Allgather(&lastDescMorton,1,MPI_UINT64_T,m_partitionLastDesc.data(),1,MPI_UINT64_T,m_comm);
2622 for (
int p = 1; p < m_nproc; ++p){
2623 if (m_partitionRangeGlobalIdx[p] == m_partitionRangeGlobalIdx[p-1]){
2624 m_partitionLastDesc[p] = m_partitionLastDesc[p-1];
2626 m_octree.m_lastDescMorton = m_partitionLastDesc[p-1];
2652 ParaTree::findNeighbours(
const Octant* oct, uint8_t entityIdx, uint8_t entityCodim, u32vector & neighbours, bvector & isghost,
bool onlyinternal,
bool append)
const{
2654 if (entityCodim == 1){
2655 m_octree.findNeighbours(oct, entityIdx, neighbours, isghost, onlyinternal, append);
2657 else if (entityCodim == 2 && m_dim == 3){
2658 m_octree.findEdgeNeighbours(oct, entityIdx, neighbours, isghost, onlyinternal, append);
2660 else if (entityCodim == m_dim){
2661 m_octree.findNodeNeighbours(oct, entityIdx, neighbours, isghost, onlyinternal, append);
2679 ParaTree::findNeighbours(uint32_t idx, uint8_t entityIdx, uint8_t entityCodim, u32vector & neighbours, bvector & isghost)
const {
2681 const Octant* oct = &m_octree.m_octants[idx];
2683 findNeighbours(oct, entityIdx, entityCodim, neighbours, isghost,
false,
false);
2694 ParaTree::findNeighbours(uint32_t idx, uint8_t entityIdx, uint8_t entityCodim, u32vector & neighbours)
const {
2696 const Octant* oct = &m_octree.m_octants[idx];
2698 findNeighbours(oct, entityIdx, entityCodim, neighbours, isghost,
true,
false);
2711 ParaTree::findNeighbours(
const Octant* oct, uint8_t entityIdx, uint8_t entityCodim, u32vector & neighbours, bvector & isghost)
const {
2713 findNeighbours(oct, entityIdx, entityCodim, neighbours, isghost,
false,
false);
2727 const Octant* oct = &m_octree.m_ghosts[idx];
2729 findNeighbours(oct, entityIdx, entityCodim, neighbours, isghost,
true,
false);
2745 const Octant* oct = &m_octree.m_ghosts[idx];
2746 findNeighbours(oct, entityIdx, entityCodim, neighbours, isghost,
false,
false);
2762 findNeighbours(oct, entityIdx, entityCodim, neighbours, isghost,
false,
false);
2778 u32vector codimNeighnours;
2779 bvector codimIsGhost;
2782 findNeighbours(oct, node, m_dim, neighbours, isghost,
false,
false);
2795 for (
int edge : m_treeConstants->
nodeEdge[node]) {
2796 findNeighbours(oct, edge, 2, codimNeighnours, codimIsGhost,
false,
false);
2797 for (std::size_t i = 0; i < codimNeighnours.size(); ++i) {
2798 const Octant* neighOctant;
2799 if (codimIsGhost[i]==0) {
2800 neighOctant = &m_octree.m_octants[codimNeighnours[i]];
2803 neighOctant = &m_octree.m_ghosts[codimNeighnours[i]];
2805 int neighOctantLevel =
getLevel(neighOctant);
2806 if (neighOctantLevel <= octantLevel) {
2807 neighbours.push_back(codimNeighnours[i]);
2808 isghost.push_back(codimIsGhost[i]);
2810 neighbours.push_back(codimNeighnours[i]);
2811 isghost.push_back(codimIsGhost[i]);
2827 for (
int j = 0; j < dim; ++j) {
2828 int face = m_treeConstants->
nodeFace[node][j];
2829 findNeighbours(oct, face, 1, codimNeighnours, codimIsGhost,
false,
false);
2830 for (std::size_t i = 0; i < codimNeighnours.size(); ++i) {
2831 const Octant* neighOctant;
2832 if (codimIsGhost[i]==0) {
2833 neighOctant = &m_octree.m_octants[codimNeighnours[i]];
2836 neighOctant = &m_octree.m_ghosts[codimNeighnours[i]];
2838 int neighOctantLevel =
getLevel(neighOctant);
2839 if (neighOctantLevel <= octantLevel) {
2840 neighbours.push_back(codimNeighnours[i]);
2841 isghost.push_back(codimIsGhost[i]);
2843 neighbours.push_back(codimNeighnours[i]);
2844 isghost.push_back(codimIsGhost[i]);
2887 std::array<uint8_t, 4> nCodimensionItems;
2888 nCodimensionItems[0] = 0;
2898 int initalCapacity =
uipow(3, m_dim) - 1;
2899 neighbours.reserve(initalCapacity);
2900 isghost.reserve(initalCapacity);
2902 for(uint8_t codim = 1; codim <= m_dim; ++codim){
2903 for(
int item = 0; item < nCodimensionItems[codim]; ++item){
2904 findNeighbours(oct,item,codim,neighbours,isghost,
false,
true);
2943 if(idx < numeric_limits<uint32_t>::max())
2944 return &m_octree.m_octants[idx];
2957 if(idx < numeric_limits<uint32_t>::max())
2959 return &m_octree.m_ghosts[idx];
2961 return &m_octree.m_octants[idx];
2974 if(idx < numeric_limits<uint32_t>::max())
2975 return &m_octree.m_octants[idx];
2988 if(idx < numeric_limits<uint32_t>::max())
2990 return &m_octree.m_ghosts[idx];
2992 return &m_octree.m_octants[idx];
3022 assert(point.size() >= 3);
3033 assert(point.size() >= 3);
3045 uint64_t morton = evalPointAnchorMorton(point);
3046 if (morton == PABLO::INVALID_MORTON) {
3047 return numeric_limits<uint32_t>::max();
3051 if (
findOwner(morton) != m_rank && (!m_serial)) {
3052 return numeric_limits<uint32_t>::max();
3059 uint32_t pointOwnerIdx;
3060 uint64_t pointOwnerMorton;
3061 m_octree.findMortonUpperBound(morton, m_octree.m_octants, &pointOwnerIdx, &pointOwnerMorton);
3064 return pointOwnerIdx;
3074 uint64_t morton = evalPointAnchorMorton(point);
3075 if (morton == PABLO::INVALID_MORTON) {
3078 return numeric_limits<uint32_t>::max();
3082 isghost = (
findOwner(morton) != m_rank);
3089 uint32_t pointOwnerIdx;
3090 uint64_t pointOwnerMorton;
3092 m_octree.findMortonUpperBound(morton, m_octree.m_octants, &pointOwnerIdx, &pointOwnerMorton);
3095 m_octree.findMortonUpperBound(morton, m_octree.m_ghosts, &pointOwnerIdx, &pointOwnerMorton);
3096 while (pointOwnerIdx > 0) {
3101 double octantSize =
getSize(octant);
3104 for (
int i = 0; i < m_dim; ++i) {
3105 if (point[i] < octantAnchor[i] - m_tol || point[i] > (octantAnchor[i] + octantSize + m_tol)) {
3112 return pointOwnerIdx;
3116 return numeric_limits<uint32_t>::max();
3119 return pointOwnerIdx;
3129 uint64_t morton = evalPointAnchorMorton(point.data());
3130 if (morton == PABLO::INVALID_MORTON) {
3145 ParaTree::evalPointAnchorMorton(
const double * point)
const {
3147 if (m_octree.m_octants.empty()) {
3148 return PABLO::INVALID_MORTON;
3152 if (point[0] > 1+m_tol || point[1] > 1+m_tol || point[2] > 1+m_tol) {
3153 return PABLO::INVALID_MORTON;
3154 }
else if (point[0] < -m_tol || point[1] < -m_tol || point[2] < -m_tol) {
3155 return PABLO::INVALID_MORTON;
3159 uint32_t x = m_trans.mapX(std::min(std::max(point[0], 0.0), 1.0));
3160 uint32_t y = m_trans.mapY(std::min(std::max(point[1], 0.0), 1.0));
3161 uint32_t z = m_trans.mapZ(std::min(std::max(point[2], 0.0), 1.0));
3164 if (x == maxLength) x = x - 1;
3165 if (y == maxLength) y = y - 1;
3166 if (z == maxLength) z = z - 1;
3168 return PABLO::computeMorton(m_dim, x, y, z);
3189 if (oct ==
nullptr || result ==
nullptr){
3195 result->resize(nChildren);
3198 else if (marker < 0){
3203 result->push_back(*oct);
3217 if (idx >= m_mapIdx.size()){
3218 throw std::runtime_error (
"Invalid value for input index in getMapping");
3225 int nChildren = m_treeConstants->
nChildren;
3227 int nInternalChildren = nChildren;
3229 nInternalChildren -= m_octree.m_lastGhostBros.size();
3233 mapper.resize(nChildren);
3234 isghost.resize(nChildren);
3236 for (
int i = 0; i < nInternalChildren; i++){
3237 mapper[i] = m_mapIdx[idx] + i;
3241 for (
int i = nInternalChildren; i < nChildren; i++){
3242 mapper[i] = m_octree.m_lastGhostBros[i - nInternalChildren];
3249 mapper[0] = m_mapIdx[idx];
3267 if (m_lastOp == OP_ADAPT_MAPPED){
3269 int n = isghost.size();
3271 for (
int i=0; i<n; i++){
3275 else if (m_lastOp == OP_LOADBALANCE || m_lastOp == OP_LOADBALANCE_FIRST){
3280 uint64_t previousIdx = gidx;
3281 for (
int iproc=0; iproc<m_nproc; ++iproc){
3282 if (m_partitionRangeGlobalIdx0[iproc]>=gidx){
3284 previousIdx -= m_partitionRangeGlobalIdx0[iproc-1] + 1;
3285 rank[0] = (m_lastOp == OP_LOADBALANCE_FIRST ? m_rank : iproc);
3290 mapper[0] =
static_cast<uint32_t
>(previousIdx);
3303 if (m_lastOp != OP_PRE_ADAPT) {
3304 throw std::runtime_error(
"Last operation different from preadapt, unable to call getPreMarker function");
3311 std::size_t firstGsize = m_octree.m_firstGhostBros.size();
3312 std::size_t lastGsize = m_octree.m_lastGhostBros.size();
3320 for (uint32_t
id : m_octree.m_firstGhostBros){
3321 int8_t marker = m_octree.m_ghosts[id].getMarker();
3323 markers.push_back(marker);
3324 isghost.push_back(
true);
3329 for (uint32_t count = 0; count < m_octree.getNumOctants(); count++){
3330 int8_t marker = m_octree.m_octants[count].getMarker();
3332 idx.push_back(count);
3333 markers.push_back(marker);
3334 isghost.push_back(
false);
3341 for (uint32_t
id : m_octree.m_lastGhostBros){
3342 int8_t marker = m_octree.m_ghosts[id].getMarker();
3344 markers.push_back(marker);
3345 isghost.push_back(
true);
3359 int dim = octant->
getDim();
3362 std::array<uint32_t, 3> nodeCoords = nodeOctant->
getLogicalNode(nodeIndex);
3365 std::array<uint32_t, 3> minOctantCoords = octant->
getLogicalNode(0);
3366 std::array<uint32_t, 3> maxOctantCoords = octant->
getLogicalNode(3 + 4 * (dim - 2));
3372 for (
int i = 0; i < dim; ++i) {
3374 uint32_t nodeCoord = nodeCoords[i];
3377 uint32_t minOctantBBCoord = minOctantCoords[i];
3378 uint32_t maxOctantBBCoord = maxOctantCoords[i];
3381 if (nodeCoord < minOctantBBCoord) {
3383 }
else if (nodeCoord > maxOctantBBCoord) {
3401 int dim = octant->
getDim();
3405 const uint8_t (*edgeNodes)[2] = &m_treeConstants->
edgeNode[edgeIndex];
3406 std::array<uint32_t, 3> minEdgeCoords = edgeOctant->
getLogicalNode((*edgeNodes)[0]);
3407 std::array<uint32_t, 3> maxEdgeCoords = edgeOctant->
getLogicalNode((*edgeNodes)[1]);
3410 std::array<uint32_t, 3> minOctantCoords = octant->
getLogicalNode(0);
3411 std::array<uint32_t, 3> maxOctantCoords = octant->
getLogicalNode(7);
3417 for (
int i = 0; i < dim; ++i) {
3419 uint32_t minEdgeCoord = minEdgeCoords[i];
3420 uint32_t maxEdgeCoord = maxEdgeCoords[i];
3423 uint32_t minOctantBBCoord = minOctantCoords[i];
3424 uint32_t maxOctantBBCoord = maxOctantCoords[i];
3427 if (minEdgeCoord < minOctantBBCoord && maxEdgeCoord < minOctantBBCoord) {
3429 }
else if (minEdgeCoord > maxOctantBBCoord && maxEdgeCoord > maxOctantBBCoord) {
3446 int dim = octant->
getDim();
3449 const uint8_t (*faceNodes)[6][4] = &m_treeConstants->
faceNode;
3450 std::array<uint32_t, 3> minFaceCoords = faceOctant->
getLogicalNode((*faceNodes)[faceIndex][0]);
3451 std::array<uint32_t, 3> maxFaceCoords = faceOctant->
getLogicalNode((*faceNodes)[faceIndex][2 * dim - 1]);
3454 std::array<uint32_t, 3> minOctantCoords = octant->
getLogicalNode(0);
3455 std::array<uint32_t, 3> maxOctantCoords = octant->
getLogicalNode(3 + 4 * (dim - 2));
3458 for (
int i = 0; i < dim; ++i) {
3460 uint32_t minFaceCoord = minFaceCoords[i];
3461 uint32_t maxFaceCoord = maxFaceCoords[i];
3464 uint32_t minOctantBBCoord = minOctantCoords[i];
3465 uint32_t maxOctantBBCoord = maxOctantCoords[i];
3468 if (minFaceCoord < minOctantBBCoord && maxFaceCoord < minOctantBBCoord) {
3470 }
else if (minFaceCoord > maxOctantBBCoord && maxFaceCoord > maxOctantBBCoord) {
3493 (*m_log) <<
"---------------------------------------------" << endl;
3494 (*m_log) <<
" SETTLE MARKERS " << endl;
3496 balance21(
true,
false);
3498 (*m_log) <<
" " << endl;
3499 (*m_log) <<
"---------------------------------------------" << endl;
3512 balance21(
true,
false);
3514 m_lastOp = OP_PRE_ADAPT;
3516 (*m_log) <<
"---------------------------------------------" << endl;
3517 (*m_log) <<
" PRE-ADAPT " << endl;
3519 (*m_log) <<
" " << endl;
3520 (*m_log) <<
"---------------------------------------------" << endl;
3530 bool lcheck =
false;
3531 bool gcheck =
false;
3532 octvector::iterator it = m_octree.m_octants.begin();
3533 octvector::iterator itend = m_octree.m_octants.end();
3534 while(!lcheck && it != itend){
3535 lcheck = (it->getMarker() != 0);
3542#if BITPIT_ENABLE_MPI==1
3543 m_errorFlag = MPI_Allreduce(&lcheck,&gcheck,1,MPI_C_BOOL,MPI_LOR,m_comm);
3562 done = private_adapt_mapidx(mapper_flag);
3576 vector<Octant>::iterator iter, iterend = m_octree.m_octants.end();
3578 for (iter = m_octree.m_octants.begin(); iter != iterend; ++iter){
3579 iter->m_info[Octant::INFO_NEW4REFINEMENT] =
false;
3580 iter->m_info[Octant::INFO_NEW4COARSENING] =
false;
3584 m_mapIdx.resize(nocts0);
3585 m_mapIdx.shrink_to_fit();
3586 for (uint32_t i=0; i<nocts0; i++){
3591 bool globalDone =
false;
3592#if BITPIT_ENABLE_MPI==1
3595 (*m_log) <<
"---------------------------------------------" << endl;
3596 (*m_log) <<
" ADAPT (Global Refine)" << endl;
3597 (*m_log) <<
" " << endl;
3599 (*m_log) <<
" " << endl;
3600 (*m_log) <<
" Initial Number of octants : " + to_string(
static_cast<unsigned long long>(
getNumOctants())) << endl;
3603 while(m_octree.globalRefine(m_mapIdx));
3607 (*m_log) <<
" Number of octants after Refine : " + to_string(
static_cast<unsigned long long>(
getNumOctants())) << endl;
3610 (*m_log) <<
" " << endl;
3611 (*m_log) <<
"---------------------------------------------" << endl;
3612#if BITPIT_ENABLE_MPI==1
3615 (*m_log) <<
"---------------------------------------------" << endl;
3616 (*m_log) <<
" ADAPT (Global Refine)" << endl;
3617 (*m_log) <<
" " << endl;
3619 (*m_log) <<
" " << endl;
3620 (*m_log) <<
" Initial Number of octants : " + to_string(
static_cast<unsigned long long>(m_globalNumOctants)) << endl;
3623 while(m_octree.globalRefine(m_mapIdx));
3625 bool localDone =
false;
3630 (*m_log) <<
" Number of octants after Refine : " + to_string(
static_cast<unsigned long long>(m_globalNumOctants)) << endl;
3632 m_errorFlag = MPI_Allreduce(&localDone,&globalDone,1,MPI_C_BOOL,MPI_LOR,m_comm);
3633 (*m_log) <<
" " << endl;
3634 (*m_log) <<
"---------------------------------------------" << endl;
3640 m_lastOp = OP_ADAPT_MAPPED;
3643 m_lastOp = OP_ADAPT_UNMAPPED;
3657 vector<Octant>::iterator iter, iterend = m_octree.m_octants.end();
3659 for (iter = m_octree.m_octants.begin(); iter != iterend; ++iter){
3660 iter->m_info[Octant::INFO_NEW4REFINEMENT] =
false;
3661 iter->m_info[Octant::INFO_NEW4COARSENING] =
false;
3665 m_mapIdx.resize(nocts0);
3666 for (uint32_t i=0; i<nocts0; i++){
3672 m_mapIdx.shrink_to_fit();
3674 bool globalDone =
false;
3675#if BITPIT_ENABLE_MPI==1
3678 (*m_log) <<
"---------------------------------------------" << endl;
3679 (*m_log) <<
" ADAPT (Global Coarse)" << endl;
3680 (*m_log) <<
" " << endl;
3683 balance21(
true,
false);
3685 (*m_log) <<
" " << endl;
3686 (*m_log) <<
" Initial Number of octants : " + to_string(
static_cast<unsigned long long>(
getNumOctants())) << endl;
3689 while(m_octree.globalCoarse(m_mapIdx));
3690 updateAfterCoarse();
3691 balance21(
false,
true);
3692 while(m_octree.refine(m_mapIdx));
3699 (*m_log) <<
" Number of octants after Coarse : " + to_string(
static_cast<unsigned long long>(
getNumOctants())) << endl;
3700 (*m_log) <<
" " << endl;
3701 (*m_log) <<
"---------------------------------------------" << endl;
3702#if BITPIT_ENABLE_MPI==1
3705 (*m_log) <<
"---------------------------------------------" << endl;
3706 (*m_log) <<
" ADAPT (Global Coarse)" << endl;
3707 (*m_log) <<
" " << endl;
3710 balance21(
true,
false);
3712 (*m_log) <<
" " << endl;
3713 (*m_log) <<
" Initial Number of octants : " + to_string(
static_cast<unsigned long long>(m_globalNumOctants)) << endl;
3716 while(m_octree.globalCoarse(m_mapIdx));
3717 updateAfterCoarse();
3719 balance21(
false,
true);
3720 while(m_octree.refine(m_mapIdx));
3724 bool localDone =
false;
3729 m_errorFlag = MPI_Allreduce(&localDone,&globalDone,1,MPI_C_BOOL,MPI_LOR,m_comm);
3730 (*m_log) <<
" Number of octants after Coarse : " + to_string(
static_cast<unsigned long long>(m_globalNumOctants)) << endl;
3731 (*m_log) <<
" " << endl;
3732 (*m_log) <<
"---------------------------------------------" << endl;
3755 if (morton <= m_partitionLastDesc[0]) {
3758 if (morton > m_partitionLastDesc[m_nproc-1]) {
3765 int end = m_nproc -1;
3766 int seed = m_nproc/2;
3768 if(morton <= m_partitionLastDesc[seed]){
3770 if(morton > m_partitionLastDesc[seed-1])
3775 if(morton <= m_partitionLastDesc[seed+1])
3778 seed = beg + (end - beg) / 2;
3781 while(m_partitionLastDesc[beg] == m_partitionLastDesc[beg-1]){
3799 std::vector<uint64_t>::const_iterator rankItr = std::lower_bound (m_partitionRangeGlobalIdx.begin(), m_partitionRangeGlobalIdx.end(), globalIndex);
3803 if (rankItr == m_partitionRangeGlobalIdx.end()) {
3806 ownerRank =
static_cast<int>(std::distance(m_partitionRangeGlobalIdx.begin(), rankItr));
3816 m_octree.computeConnectivity();
3826 m_octree.clearConnectivity(release);
3833 m_octree.updateConnectivity();
3842 return m_octree.m_connectivity;
3852 return m_octree.m_connectivity[idx];
3861 return m_octree.m_connectivity[
getIdx(oct)];
3867 const u32arr3vector &
3869 return m_octree.m_nodes;
3878 return m_octree.m_nodes[node];
3887 return m_trans.mapCoordinates(m_octree.m_nodes[node]);
3896 return m_octree.m_ghostsConnectivity;
3906 return m_octree.m_ghostsConnectivity[idx];
3916 return m_octree.m_ghostsConnectivity[
getIdx(oct)];
3930 uint8_t maxCodim = balanceCodim;
3934 for(uint8_t c = 1; c <= maxCodim; ++c){
3936 for(uint32_t i = 0; i < nocts; ++i){
3938 for(uint8_t f = 0; f < nCodimSubelements; ++f){
3939 findNeighbours(i,f,c,neighs,isghost);
3940 size_t nsize = neighs.size();
3941 for(
size_t n = 0; n < nsize; ++n){
3944 levelDiff = uint8_t(
abs(
int(nlevel)-
int(level)));
3948 (*m_log) <<
"---------------------------------------------" << std::endl;
3949 (*m_log) <<
"LOCALLY 2:1 UNBALANCED OCTREE" << std::endl;
3950 (*m_log) <<
"I'm " <<
getRank() <<
": element " << i <<
" is not 2:1 balanced across " << int(f) <<
" subentity of codim " << int(c) <<
", relative to " << (isghost[n] ?
"ghost" :
"internal") <<
"neighbour " << neighs[n] << std::endl;
3951 (*m_log) <<
"---------------------------------------------" << std::endl;
3968#if BITPIT_ENABLE_MPI==1
3969 MPI_Allreduce(&balanced,&gBalanced,1,MPI_C_BOOL,MPI_LAND,
getComm());
3971 gBalanced = balanced;
3975 (*m_log) <<
"---------------------------------------------" << std::endl;
3976 (*m_log) <<
"CORRECTLY GLOBAL 2:1 BALANCED OCTREE" << std::endl;
3977 (*m_log) <<
"---------------------------------------------" << std::endl;
3980 (*m_log) <<
"---------------------------------------------" << std::endl;
3981 (*m_log) <<
"UNCORRECTLY GLOBAL 2:1 BALANCED OCTREE" << std::endl;
3982 (*m_log) <<
"---------------------------------------------" << std::endl;
3989#if BITPIT_ENABLE_MPI==1
4000 (*m_log) <<
"---------------------------------------------" << endl;
4001 (*m_log) <<
" LOAD BALANCE " << endl;
4003 m_lastOp = OP_LOADBALANCE;
4006 std::vector<uint32_t> partition(m_nproc);
4008 computePartition(partition.data());
4010 computePartition(weight, partition.data());
4014 privateLoadBalance<DummyDataLBImpl>(partition.data(),
nullptr);
4017 (*m_log) <<
" " << endl;
4018 (*m_log) <<
" Final Parallel partition : " << endl;
4019 (*m_log) <<
" Octants for proc "+ to_string(
static_cast<unsigned long long>(0))+
" : " + to_string(
static_cast<unsigned long long>(m_partitionRangeGlobalIdx[0]+1)) << endl;
4020 for(
int ii=1; ii<m_nproc; ii++){
4021 (*m_log) <<
" Octants for proc "+ to_string(
static_cast<unsigned long long>(ii))+
" : " + to_string(
static_cast<unsigned long long>(m_partitionRangeGlobalIdx[ii]-m_partitionRangeGlobalIdx[ii-1])) << endl;
4023 (*m_log) <<
" " << endl;
4024 (*m_log) <<
"---------------------------------------------" << endl;
4028 (*m_log) <<
" " << endl;
4029 (*m_log) <<
" Serial partition : " << endl;
4030 (*m_log) <<
" Octants for proc "+ to_string(
static_cast<unsigned long long>(0))+
" : " + to_string(
static_cast<unsigned long long>(m_partitionRangeGlobalIdx[0]+1)) << endl;
4031 (*m_log) <<
" " << endl;
4032 (*m_log) <<
"---------------------------------------------" << endl;
4047 (*m_log) <<
"---------------------------------------------" << endl;
4048 (*m_log) <<
" LOAD BALANCE " << endl;
4050 m_lastOp = OP_LOADBALANCE;
4053 std::vector<uint32_t> partition(m_nproc);
4054 computePartition(level, weight, partition.data());
4056 privateLoadBalance<DummyDataLBImpl>(partition.data(),
nullptr);
4059 (*m_log) <<
" " << endl;
4060 (*m_log) <<
" Final Parallel partition : " << endl;
4061 (*m_log) <<
" Octants for proc "+ to_string(
static_cast<unsigned long long>(0))+
" : " + to_string(
static_cast<unsigned long long>(m_partitionRangeGlobalIdx[0]+1)) << endl;
4062 for(
int ii=1; ii<m_nproc; ii++){
4063 (*m_log) <<
" Octants for proc "+ to_string(
static_cast<unsigned long long>(ii))+
" : " + to_string(
static_cast<unsigned long long>(m_partitionRangeGlobalIdx[ii]-m_partitionRangeGlobalIdx[ii-1])) << endl;
4065 (*m_log) <<
" " << endl;
4066 (*m_log) <<
"---------------------------------------------" << endl;
4070 (*m_log) <<
" " << endl;
4071 (*m_log) <<
" Serial partition : " << endl;
4072 (*m_log) <<
" Octants for proc "+ to_string(
static_cast<unsigned long long>(0))+
" : " + to_string(
static_cast<unsigned long long>(m_partitionRangeGlobalIdx[0]+1)) << endl;
4073 (*m_log) <<
" " << endl;
4074 (*m_log) <<
"---------------------------------------------" << endl;
4094 loadBalanceInfo.sendAction = LoadBalanceRanges::ACTION_NONE;
4095 loadBalanceInfo.recvAction = LoadBalanceRanges::ACTION_NONE;
4097 return loadBalanceInfo;
4101 std::vector<uint32_t> updatedPartition(m_nproc);
4103 computePartition(weights, updatedPartition.data());
4105 computePartition(updatedPartition.data());
4132 loadBalanceInfo.sendAction = LoadBalanceRanges::ACTION_NONE;
4133 loadBalanceInfo.recvAction = LoadBalanceRanges::ACTION_NONE;
4135 return loadBalanceInfo;
4139 std::vector<uint32_t> updatedPartition(m_nproc);
4140 computePartition(level, weights, updatedPartition.data());
4159 LoadBalanceRanges loadBalanceInfo;
4160 loadBalanceInfo.sendAction = LoadBalanceRanges::ACTION_NONE;
4161 loadBalanceInfo.recvAction = LoadBalanceRanges::ACTION_NONE;
4163 return loadBalanceInfo;
4166 ExchangeRanges sendRanges = evalLoadBalanceSendRanges(updatedPartition);
4167 ExchangeRanges recvRanges = evalLoadBalanceRecvRanges(updatedPartition);
4169 return LoadBalanceRanges(m_serial, std::move(sendRanges), std::move(recvRanges));
4180 ParaTree::evalLoadBalanceSendRanges(
const uint32_t *updatedPartition){
4190 std::vector<uint32_t> currentPartition(m_nproc, 0);
4192 currentPartition[0] = m_partitionRangeGlobalIdx[0] + 1;
4193 for (
int i = 1; i < m_nproc; ++i) {
4194 currentPartition[i] = m_partitionRangeGlobalIdx[i] - m_partitionRangeGlobalIdx[i - 1];
4201 PartitionIntersections globalIntersections = evalPartitionIntersections(currentPartition.data(), m_rank, updatedPartition);
4204 uint64_t offset = 0;
4205 for (
int i = 0; i < m_rank; ++i) {
4206 offset += currentPartition[i];
4209 for (
const auto &intersectionEntry : globalIntersections) {
4210 int rank = intersectionEntry.first;
4211 if (rank == m_rank) {
4215 const std::array<uint64_t, 2> &intersection = intersectionEntry.second;
4217 std::array<uint32_t, 2> &sendRange = sendRanges[rank];
4218 sendRange[0] = intersection[0] - offset;
4219 sendRange[1] = intersection[1] - offset;
4234 ParaTree::evalLoadBalanceRecvRanges(
const uint32_t *updatedPartition){
4244 std::vector<uint32_t> currentPartition(m_nproc, 0);
4246 currentPartition[0] = m_partitionRangeGlobalIdx[0] + 1;
4247 for (
int i = 1; i < m_nproc; ++i) {
4248 currentPartition[i] = m_partitionRangeGlobalIdx[i] - m_partitionRangeGlobalIdx[i - 1];
4255 PartitionIntersections globalIntersections = evalPartitionIntersections(updatedPartition, m_rank, currentPartition.data());
4258 uint64_t offset = 0;
4259 for (
int i = 0; i < m_rank; ++i) {
4260 offset += updatedPartition[i];
4263 for (
const auto &intersectionEntry : globalIntersections) {
4264 int rank = intersectionEntry.first;
4265 if (rank == m_rank) {
4269 const std::array<uint64_t, 2> &intersection = intersectionEntry.second;
4271 std::array<uint32_t, 2> &recvRange = recvRanges[rank];
4272 recvRange[0] = intersection[0] - offset;
4273 recvRange[1] = intersection[1] - offset;
4296 ParaTree::PartitionIntersections
4297 ParaTree::evalPartitionIntersections(
const uint32_t *partition_A,
int rank_A,
const uint32_t *partition_B){
4299 PartitionIntersections intersections;
4302 if (partition_A[rank_A] == 0) {
4303 return intersections;
4307 std::vector<uint64_t> offsets_A(m_nproc + 1, 0);
4308 std::vector<uint64_t> offsets_B(m_nproc + 1, 0);
4309 for (
int i = 0; i < m_nproc; ++i) {
4310 offsets_A[i + 1] = offsets_A[i] + partition_A[i];
4311 offsets_B[i + 1] = offsets_B[i] + partition_B[i];
4314 uint64_t beginGlobalId_A = offsets_A[m_rank];
4315 uint64_t endGlobalId_A = offsets_A[m_rank + 1];
4317 auto firstRankItr = std::upper_bound(offsets_B.begin(), offsets_B.end(), beginGlobalId_A);
4318 assert(firstRankItr != offsets_B.begin());
4321 for (
auto itr = firstRankItr; itr != offsets_B.end(); ++itr) {
4322 int rank_B =
static_cast<int>(std::distance(offsets_B.begin(), itr));
4323 uint64_t beginGlobalId_B = offsets_B[rank_B];
4324 uint64_t endGlobalId_B = offsets_B[rank_B + 1];
4326 std::array<uint64_t, 2> &intersection = intersections[rank_B];
4327 intersection[0] = std::max(beginGlobalId_A, beginGlobalId_B);
4328 intersection[1] = std::min(endGlobalId_A, endGlobalId_B);
4330 if (endGlobalId_B >= endGlobalId_A) {
4335 return intersections;
4345 uint32_t size = uint32_t(1)<<(m_treeConstants->
maxLevel-level);
4346 return m_trans.mapSize(size);
4357 m_octree.computeIntersections();
4369 ParaTree::extractOctant(uint32_t idx) {
4370 return m_octree.extractOctant(idx) ;
4377 ParaTree::private_adapt_mapidx(
bool mapflag) {
4380 m_loadBalanceRanges.
clear();
4382 vector<Octant >::iterator iter, iterend = m_octree.m_octants.end();
4384 for (iter = m_octree.m_octants.begin(); iter != iterend; ++iter){
4385 iter->m_info[Octant::INFO_NEW4REFINEMENT] =
false;
4386 iter->m_info[Octant::INFO_NEW4COARSENING] =
false;
4391 m_mapIdx.resize(nocts0);
4392 for (uint32_t i=0; i<nocts0; i++){
4398 m_mapIdx.shrink_to_fit();
4400 bool globalDone =
false;
4401#if BITPIT_ENABLE_MPI==1
4404 (*m_log) <<
"---------------------------------------------" << endl;
4405 (*m_log) <<
" ADAPT (Refine/Coarse)" << endl;
4406 (*m_log) <<
" " << endl;
4409 if (m_lastOp != OP_PRE_ADAPT) {
4410 balance21(
true,
false);
4413 (*m_log) <<
" " << endl;
4414 (*m_log) <<
" Initial Number of octants : " + to_string(
static_cast<unsigned long long>(
getNumOctants())) << endl;
4417 while(m_octree.refine(m_mapIdx));
4420 (*m_log) <<
" Number of octants after Refine : " + to_string(
static_cast<unsigned long long>(
getNumOctants())) << endl;
4425 while(m_octree.coarse(m_mapIdx));
4426 updateAfterCoarse();
4431 (*m_log) <<
" Number of octants after Coarse : " + to_string(
static_cast<unsigned long long>(
getNumOctants())) << endl;
4432 (*m_log) <<
" " << endl;
4433 (*m_log) <<
"---------------------------------------------" << endl;
4434#if BITPIT_ENABLE_MPI==1
4437 (*m_log) <<
"---------------------------------------------" << endl;
4438 (*m_log) <<
" ADAPT (Refine/Coarse)" << endl;
4439 (*m_log) <<
" " << endl;
4442 if (m_lastOp != OP_PRE_ADAPT) {
4443 balance21(
true,
false);
4446 (*m_log) <<
" " << endl;
4447 (*m_log) <<
" Initial Number of octants : " + to_string(
static_cast<unsigned long long>(m_globalNumOctants)) << endl;
4450 while(m_octree.refine(m_mapIdx));
4451 bool localDone =
false;
4456 (*m_log) <<
" Number of octants after Refine : " + to_string(
static_cast<unsigned long long>(m_globalNumOctants)) << endl;
4461 while(m_octree.coarse(m_mapIdx));
4462 updateAfterCoarse();
4468 m_errorFlag = MPI_Allreduce(&localDone,&globalDone,1,MPI_C_BOOL,MPI_LOR,m_comm);
4469 (*m_log) <<
" Number of octants after Coarse : " + to_string(
static_cast<unsigned long long>(m_globalNumOctants)) << endl;
4470 (*m_log) <<
" " << endl;
4471 (*m_log) <<
"---------------------------------------------" << endl;
4477 m_lastOp = OP_ADAPT_MAPPED;
4480 m_lastOp = OP_ADAPT_UNMAPPED;
4489 ParaTree::updateAdapt(){
4490#if BITPIT_ENABLE_MPI==1
4494 for (
int iproc=0; iproc<m_nproc; iproc++){
4495 m_partitionRangeGlobalIdx0[iproc] = m_partitionRangeGlobalIdx[iproc];
4497 m_maxDepth = m_octree.m_localMaxDepth;
4499 for(
int p = 0; p < m_nproc; ++p){
4500 m_partitionRangeGlobalIdx[p] = m_globalNumOctants - 1;
4504 octvector::iterator itend = m_octree.m_octants.end();
4505 for (octvector::iterator it = m_octree.m_octants.begin(); it != itend; ++it){
4506 m_internals[i] = &(*it);
4509#if BITPIT_ENABLE_MPI==1
4513 for (
int iproc=0; iproc<m_nproc; iproc++){
4514 m_partitionRangeGlobalIdx0[iproc] = m_partitionRangeGlobalIdx[iproc];
4517 m_errorFlag = MPI_Allreduce(&m_octree.m_localMaxDepth,&m_maxDepth,1,MPI_INT8_T,MPI_MAX,m_comm);
4520 m_errorFlag = MPI_Allreduce(&local_num_octants,&m_globalNumOctants,1,MPI_UINT64_T,MPI_SUM,m_comm);
4522 uint64_t* rbuff =
new uint64_t[m_nproc];
4523 m_errorFlag = MPI_Allgather(&local_num_octants,1,MPI_UINT64_T,rbuff,1,MPI_UINT64_T,m_comm);
4524 for(
int p = 0; p < m_nproc; ++p){
4525 m_partitionRangeGlobalIdx[p] = 0;
4526 for(
int pp = 0; pp <=p; ++pp)
4527 m_partitionRangeGlobalIdx[p] += rbuff[pp];
4528 --m_partitionRangeGlobalIdx[p];
4530 delete [] rbuff; rbuff = NULL;
4535#if BITPIT_ENABLE_MPI==1
4542 ParaTree::computePartition(uint32_t* partition){
4544 uint32_t division_result = 0;
4545 uint32_t remind = 0;
4547 division_result = uint32_t(m_globalNumOctants/(uint64_t)m_nproc);
4548 remind = (uint32_t)(m_globalNumOctants%(uint64_t)m_nproc);
4550 for(uint32_t i = 0; i < (uint32_t)m_nproc; ++i)
4552 partition[i] = division_result + 1;
4554 partition[i] = division_result;
4565 ParaTree::computePartition(
const dvector *weight, uint32_t *partition){
4567 assert(weight->size() >= m_octree.getNumOctants());
4573 std::vector<double> globalWeightsStorage;
4575 const double *globalWeights;
4577 globalWeights = weight->data();
4582 assert(m_globalNumOctants <= INT_MAX);
4583 std::vector<int> currentPartition(m_nproc);
4584 int nOctants = m_octree.getNumOctants();
4585 MPI_Allgather(&nOctants, 1, MPI_INT, currentPartition.data(), 1, MPI_INT, m_comm);
4587 std::vector<int> displacements(m_nproc);
4588 displacements[0] = 0;
4589 for(
int i = 1; i < m_nproc; ++i){
4590 displacements[i] = displacements[i - 1] + currentPartition[i - 1];
4593 globalWeightsStorage.resize(m_globalNumOctants);
4594 globalWeights = globalWeightsStorage.data();
4595 MPI_Allgatherv(weight->data(), nOctants, MPI_DOUBLE, globalWeightsStorage.data(),
4596 currentPartition.data(), displacements.data(), MPI_DOUBLE, m_comm);
4600 for (
int i = 0; i < m_nproc; ++i) {
4610 uint32_t nAssigendOctants = 0;
4611 for (
int i = 0; i < m_nproc - 1; ++i) {
4612 double unassignedWeight = 0.;
4613 for (uint32_t n=nAssigendOctants; n<m_globalNumOctants; n++){
4614 unassignedWeight += globalWeights[n];
4616 double targetWeight = unassignedWeight / (m_nproc - i);
4618 double partitionWeight = 0.;
4619 while(partitionWeight < targetWeight){
4620 partitionWeight += globalWeights[nAssigendOctants];
4624 if (nAssigendOctants == m_globalNumOctants) {
4629 if (nAssigendOctants == m_globalNumOctants) {
4633 partition[m_nproc-1] =
static_cast<uint32_t
>(m_globalNumOctants - nAssigendOctants);
4649 ParaTree::computePartition(uint8_t level_,
const dvector *weight, uint32_t *partition) {
4652 uint32_t* partition_temp =
new uint32_t[m_nproc];
4654 computePartition(partition_temp);
4657 computePartition(weight, partition_temp);
4665 uint8_t level = uint8_t(
min(
int(
max(
int(m_maxDepth) -
int(level_),
int(1))) ,
int(m_treeConstants->
maxLevel)));
4666 uint8_t* new_boundary_owner =
new uint8_t[m_nproc-1];
4667 uint8_t new_interfaces_count;
4668 uint8_t first_new_interface_rank_index;
4669 uint8_t* new_interfaces_count_per_rank =
new uint8_t[m_nproc];
4670 uint8_t* first_new_interface_rank_index_per_rank =
new uint8_t[m_nproc];
4672 uint32_t Dh = uint32_t(
pow(
double(2),
double(m_treeConstants->
maxLevel-level)));
4673 uint32_t istart, nocts, rest;
4674 uint32_t forw = 0, backw = 0;
4675 uint32_t i = 0, iproc, j;
4677 int32_t* pointercomm;
4678 int32_t* deplace =
new int32_t[m_nproc-1];
4685 for (iproc=0; iproc<(uint32_t)(m_nproc-1); iproc++){
4686 sum += partition_temp[iproc];
4687 while(
sum > m_partitionRangeGlobalIdx[j]){
4690 new_boundary_owner[iproc] = j;
4699 new_interfaces_count = 0;
4704 first_new_interface_rank_index = 0;
4706 for (iproc=0; iproc<(uint32_t)(m_nproc-1); iproc++){
4708 sum += partition_temp[iproc];
4713 if (new_boundary_owner[iproc] == m_rank){
4714 if (new_interfaces_count == 0){
4715 first_new_interface_rank_index = iproc;
4717 new_interfaces_count++;
4721 istart =
static_cast<uint32_t
>(
sum - m_partitionRangeGlobalIdx[m_rank-1] - 1);
4723 istart =
static_cast<uint32_t
>(
sum);
4728 rest = m_octree.m_octants[i].getLogicalCoordinates(0)%Dh + m_octree.m_octants[i].getLogicalCoordinates(1)%Dh;
4730 rest += m_octree.m_octants[i].getLogicalCoordinates(2)%Dh;
4741 rest = m_octree.m_octants[i].getLogicalCoordinates(0)%Dh + m_octree.m_octants[i].getLogicalCoordinates(1)%Dh;
4743 rest += m_octree.m_octants[i].getLogicalCoordinates(2)%Dh;
4752 rest = m_octree.m_octants[i].getLogicalCoordinates(0)%Dh + m_octree.m_octants[i].getLogicalCoordinates(1)%Dh;
4754 rest += m_octree.m_octants[i].getLogicalCoordinates(2)%Dh;
4762 rest = m_octree.m_octants[i].getLogicalCoordinates(0)%Dh + m_octree.m_octants[i].getLogicalCoordinates(1)%Dh;
4764 rest += m_octree.m_octants[i].getLogicalCoordinates(2)%Dh;
4777 deplace[iproc] = forw;
4779 deplace[iproc] = -(int32_t)backw;
4784 m_errorFlag = MPI_Allgather(&new_interfaces_count,1,MPI_UINT8_T,new_interfaces_count_per_rank,1,MPI_UINT8_T,m_comm);
4785 m_errorFlag = MPI_Allgather(&first_new_interface_rank_index,1,MPI_UINT8_T,first_new_interface_rank_index_per_rank,1,MPI_UINT8_T,m_comm);
4786 for (iproc=0; iproc<(uint32_t)(m_nproc); iproc++){
4787 pointercomm = &deplace[first_new_interface_rank_index_per_rank[iproc]];
4788 m_errorFlag = MPI_Bcast(pointercomm, new_interfaces_count_per_rank[iproc], MPI_INT32_T, iproc, m_comm);
4796 for (iproc=0; iproc<(uint32_t)(m_nproc); iproc++){
4797 if (iproc < (uint32_t)(m_nproc-1))
4798 partition[iproc] = partition_temp[iproc] + deplace[iproc];
4800 partition[iproc] = partition_temp[iproc];
4802 partition[iproc] = partition[iproc] - deplace[iproc-1];
4805 delete [] partition_temp; partition_temp = NULL;
4806 delete [] new_boundary_owner; new_boundary_owner = NULL;
4807 delete [] new_interfaces_count_per_rank; new_interfaces_count_per_rank = NULL;
4808 delete [] first_new_interface_rank_index_per_rank; first_new_interface_rank_index_per_rank = NULL;
4809 delete [] deplace; deplace = NULL;
4815 ParaTree::updateLoadBalance() {
4817 m_octree.updateLocalMaxDepth();
4818 uint64_t* rbuff =
new uint64_t[m_nproc];
4821 m_errorFlag = MPI_Allgather(&local_num_octants,1,MPI_UINT64_T,rbuff,1,MPI_UINT64_T,m_comm);
4822 for (
int iproc=0; iproc<m_nproc; iproc++){
4823 m_partitionRangeGlobalIdx0[iproc] = m_partitionRangeGlobalIdx[iproc];
4825 for(
int p = 0; p < m_nproc; ++p){
4826 m_partitionRangeGlobalIdx[p] = 0;
4827 for(
int pp = 0; pp <=p; ++pp)
4828 m_partitionRangeGlobalIdx[p] += rbuff[pp];
4829 --m_partitionRangeGlobalIdx[p];
4834 delete [] rbuff; rbuff = NULL;
4837 m_octree.setFirstDescMorton();
4838 m_octree.setLastDescMorton();
4839 updateGlobalFirstDescMorton();
4840 updateGlobalLasttDescMorton();
4847 ParaTree::setPboundGhosts() {
4858 m_bordersPerProc.clear();
4864 std::set<int> neighProcs;
4865 std::vector<std::array<int64_t, 3>> virtualNeighOffsets;
4866 for (uint32_t idx = 0; idx < m_octree.getNumOctants(); ++idx) {
4868 Octant &octant = m_octree.m_octants[idx];
4869 u32array3 octantCoord = octant.getLogicalCoordinates();
4870 uint8_t octantLevel = octant.getLevel();
4873 uint8_t maxFaceNeighLevel = std::min(m_octree.
getMaxNeighLevel(octant),
static_cast<uint8_t
>(m_maxDepth));
4874 for(uint8_t i = 0; i < m_treeConstants->
nFaces; ++i){
4875 bool isFacePeriodic = m_octree.isPeriodic(&octant, i);
4876 if (!isFacePeriodic) {
4877 bool isFaceBoundary = octant.getBound(i);
4878 if (isFaceBoundary) {
4883 std::array<uint32_t, 3> virtualOctantOrigin = octantCoord;
4884 if (isFacePeriodic) {
4886 virtualOctantOrigin[0] =
static_cast<uint32_t
>(virtualOctantOrigin[0] + periodicOffset[0]);
4887 virtualOctantOrigin[1] =
static_cast<uint32_t
>(virtualOctantOrigin[1] + periodicOffset[1]);
4888 virtualOctantOrigin[2] =
static_cast<uint32_t
>(virtualOctantOrigin[2] + periodicOffset[2]);
4893 bool isFacePbound =
false;
4894 for(
const std::array<int64_t, 3> &virtualNeighOffset : virtualNeighOffsets){
4895 std::array<uint32_t, 3> virtualNeighCoord = virtualOctantOrigin;
4896 virtualNeighCoord[0] =
static_cast<uint32_t
>(virtualNeighCoord[0] + virtualNeighOffset[0]);
4897 virtualNeighCoord[1] =
static_cast<uint32_t
>(virtualNeighCoord[1] + virtualNeighOffset[1]);
4898 virtualNeighCoord[2] =
static_cast<uint32_t
>(virtualNeighCoord[2] + virtualNeighOffset[2]);
4899 uint64_t virtualNeighMorton = PABLO::computeMorton(m_dim, virtualNeighCoord[0], virtualNeighCoord[1], virtualNeighCoord[2]);
4901 int virtualNeighProc =
findOwner(virtualNeighMorton);
4902 if (virtualNeighProc != m_rank) {
4903 neighProcs.insert(virtualNeighProc);
4904 isFacePbound =
true;
4908 octant.setPbound(i, isFacePbound);
4912 uint8_t maxEdgeNeighLevel = std::min(m_octree.
getMaxEdgeNeighLevel(octant),
static_cast<uint8_t
>(m_maxDepth));
4913 for(uint8_t e = 0; e < m_treeConstants->
nEdges; ++e){
4914 bool isEdgePeriodic = m_octree.isEdgePeriodic(&octant, e);
4915 if (!isEdgePeriodic) {
4916 bool isEdgeBoundary = octant.getEdgeBound(e);
4917 if (isEdgeBoundary) {
4922 std::array<uint32_t, 3> virtualOctantOrigin = octantCoord;
4923 if (isEdgePeriodic) {
4925 virtualOctantOrigin[0] =
static_cast<uint32_t
>(virtualOctantOrigin[0] + periodicOffset[0]);
4926 virtualOctantOrigin[1] =
static_cast<uint32_t
>(virtualOctantOrigin[1] + periodicOffset[1]);
4927 virtualOctantOrigin[2] =
static_cast<uint32_t
>(virtualOctantOrigin[2] + periodicOffset[2]);
4932 for(
const std::array<int64_t, 3> &virtualNeighOffset : virtualNeighOffsets){
4933 std::array<uint32_t, 3> virtualNeighCoord = virtualOctantOrigin;
4934 virtualNeighCoord[0] =
static_cast<uint32_t
>(virtualNeighCoord[0] + virtualNeighOffset[0]);
4935 virtualNeighCoord[1] =
static_cast<uint32_t
>(virtualNeighCoord[1] + virtualNeighOffset[1]);
4936 virtualNeighCoord[2] =
static_cast<uint32_t
>(virtualNeighCoord[2] + virtualNeighOffset[2]);
4937 uint64_t virtualNeighMorton = PABLO::computeMorton(m_dim, virtualNeighCoord[0], virtualNeighCoord[1], virtualNeighCoord[2]);
4939 int virtualNeighProc =
findOwner(virtualNeighMorton);
4940 if (virtualNeighProc != m_rank) {
4941 neighProcs.insert(virtualNeighProc);
4947 uint8_t maxNodeNeighLevel = std::min(m_octree.
getMaxNodeNeighLevel(octant),
static_cast<uint8_t
>(m_maxDepth));
4948 for(uint8_t c = 0; c < m_treeConstants->
nNodes; ++c){
4949 bool isNodePeriodic = m_octree.isNodePeriodic(&octant, c);
4950 if (!isNodePeriodic) {
4951 bool isNodeBoundary = octant.getNodeBound(c);
4952 if (isNodeBoundary) {
4957 std::array<uint32_t, 3> virtualOctantOrigin = octantCoord;
4958 if (isNodePeriodic) {
4960 virtualOctantOrigin[0] =
static_cast<uint32_t
>(virtualOctantOrigin[0] + periodicOffset[0]);
4961 virtualOctantOrigin[1] =
static_cast<uint32_t
>(virtualOctantOrigin[1] + periodicOffset[1]);
4962 virtualOctantOrigin[2] =
static_cast<uint32_t
>(virtualOctantOrigin[2] + periodicOffset[2]);
4967 for(
const std::array<int64_t, 3> &virtualNeighOffset : virtualNeighOffsets){
4968 std::array<uint32_t, 3> virtualNeighCoord = virtualOctantOrigin;
4969 virtualNeighCoord[0] =
static_cast<uint32_t
>(virtualNeighCoord[0] + virtualNeighOffset[0]);
4970 virtualNeighCoord[1] =
static_cast<uint32_t
>(virtualNeighCoord[1] + virtualNeighOffset[1]);
4971 virtualNeighCoord[2] =
static_cast<uint32_t
>(virtualNeighCoord[2] + virtualNeighOffset[2]);
4972 uint64_t virtualNeighMorton = PABLO::computeMorton(m_dim, virtualNeighCoord[0], virtualNeighCoord[1], virtualNeighCoord[2]);
4974 int virtualNeighProc =
findOwner(virtualNeighMorton);
4975 if (virtualNeighProc != m_rank) {
4976 neighProcs.insert(virtualNeighProc);
4982 if (neighProcs.empty()){
4983 m_internals[countint] = &octant;
4986 m_pborders[countpbd] = &octant;
4989 for (
int neighProc : neighProcs) {
4990 assert(neighProc != m_rank);
4991 m_bordersPerProc[neighProc].push_back(idx);
4995 m_pborders.resize(countpbd);
4996 m_pborders.shrink_to_fit();
4997 m_internals.resize(countint);
4998 m_internals.shrink_to_fit();
5001 buildGhostOctants(m_bordersPerProc, std::vector<AccretionData>());
5008 ParaTree::computeGhostHalo(){
5013 if(m_nofGhostLayers <= 1){
5052 std::unordered_map<uint32_t, std::vector<uint64_t>> oneRingsCache;
5056 DataCommunicator accretionDataCommunicator(m_comm);
5059 std::vector<AccretionData> accretions;
5060 initializeGhostHaloAccretions(&accretions);
5063 for(std::size_t layer = 1; layer < m_nofGhostLayers; ++layer){
5068 exchangeGhostHaloAccretions(&accretionDataCommunicator, &accretions);
5071 growGhostHaloAccretions(&oneRingsCache, &accretions);
5078 exchangeGhostHaloAccretions(&accretionDataCommunicator, &accretions);
5087 for(
const AccretionData &accretion : accretions){
5088 int targetRank = accretion.targetRank;
5090 std::vector<uint32_t> &rankBordersPerProc = m_bordersPerProc[targetRank];
5091 rankBordersPerProc.resize(accretion.population.size());
5093 std::size_t index = 0;
5094 for (
const auto &populationEntry : accretion.population) {
5095 uint64_t globalIdx = populationEntry.first;
5097 rankBordersPerProc[index] = localIdx;
5101 std::sort(rankBordersPerProc.begin(), rankBordersPerProc.end());
5107 buildGhostOctants(m_bordersPerProc, accretions);
5119 ParaTree::initializeGhostHaloAccretions(std::vector<AccretionData> *accretions) {
5121 const int FIRST_LAYER = 0;
5123 accretions->reserve(m_bordersPerProc.size());
5124 for(
const auto &bordersPerProcEntry : m_bordersPerProc){
5125 accretions->emplace_back();
5126 AccretionData &accretion = accretions->back();
5129 int targetRank = bordersPerProcEntry.first;
5130 accretion.targetRank = targetRank;
5136 const std::vector<uint32_t> &rankBordersPerProc = bordersPerProcEntry.second;
5137 const std::size_t nRankBordersPerProc = rankBordersPerProc.size();
5139 accretion.population.reserve(m_nofGhostLayers * nRankBordersPerProc);
5140 accretion.internalSeeds.reserve(nRankBordersPerProc);
5141 accretion.foreignSeeds.reserve(nRankBordersPerProc);
5142 for(uint32_t pborderLocalIdx : rankBordersPerProc){
5143 uint64_t pborderGlobalIdx =
getGlobalIdx(pborderLocalIdx);
5144 if (isInternal(pborderGlobalIdx)) {
5145 accretion.population.insert({pborderGlobalIdx, FIRST_LAYER});
5146 accretion.internalSeeds.insert({pborderGlobalIdx, FIRST_LAYER});
5148 accretion.foreignSeeds.insert({pborderGlobalIdx, FIRST_LAYER});
5164 ParaTree::growGhostHaloAccretions(std::unordered_map<uint32_t, std::vector<uint64_t>> *oneRingsCache,
5165 std::vector<AccretionData> *accretions) {
5168 u32vector seedNeighLocalIds;
5169 bvector seedNeighGhostFlag;
5170 for(AccretionData &accretion : *accretions){
5172 std::size_t nSeeds = accretion.internalSeeds.size();
5178 const int targetRank = accretion.targetRank;
5184 std::unordered_map<uint64_t, int> currentInternalSeeds;
5185 currentInternalSeeds.reserve(accretion.internalSeeds.size());
5186 accretion.internalSeeds.swap(currentInternalSeeds);
5190 for(
const auto &seedEntry : currentInternalSeeds){
5192 int seedLayer = seedEntry.second;
5193 uint64_t seedGlobalIdx = seedEntry.first;
5194 uint32_t seedLocalIdx =
getLocalIdx(seedGlobalIdx);
5197 auto oneRingsCacheItr = oneRingsCache->find(seedLocalIdx);
5198 if (oneRingsCacheItr == oneRingsCache->end()) {
5199 const Octant *seedOctant =
getOctant(seedLocalIdx);
5201 size_t nSeedNeighs = seedNeighLocalIds.size();
5203 oneRingsCacheItr = oneRingsCache->insert({seedLocalIdx, std::vector<uint64_t>()}).first;
5204 oneRingsCacheItr->second.resize(nSeedNeighs + 1);
5205 for(
size_t n = 0; n < nSeedNeighs; ++n){
5206 if (!seedNeighGhostFlag[n]) {
5207 oneRingsCacheItr->second[n] =
getGlobalIdx(seedNeighLocalIds[n]);
5212 oneRingsCacheItr->second[nSeedNeighs] =
getGlobalIdx(seedLocalIdx);
5214 const std::vector<uint64_t> &seedOneRing = oneRingsCacheItr->second;
5217 for(uint64_t neighGlobalIdx : seedOneRing){
5219 if (accretion.population.count(neighGlobalIdx) > 0) {
5224 bool isNeighInternal = isInternal(neighGlobalIdx);
5227 if (isNeighInternal) {
5236 if (isNeighInternal) {
5237 accretion.population.insert({neighGlobalIdx, seedLayer + 1});
5246 if (isNeighInternal) {
5247 accretion.internalSeeds.insert({neighGlobalIdx, seedLayer + 1});
5248 }
else if (neighRank != targetRank) {
5249 accretion.foreignSeeds.insert({neighGlobalIdx, seedLayer + 1});
5267 ParaTree::exchangeGhostHaloAccretions(DataCommunicator *dataCommunicator,
5268 std::vector<AccretionData> *accretions) {
5278 std::unordered_map<int, std::vector<AccretionData>> foreignAccretions;
5279 for(
const AccretionData &accretion : *accretions){
5280 for(
const auto &seedEntry : accretion.foreignSeeds){
5283 std::vector<AccretionData> &foreignRankAccretions = foreignAccretions[seedRank];
5285 auto foreignRankAccretionsItr = foreignRankAccretions.begin();
5286 for (; foreignRankAccretionsItr != foreignRankAccretions.end(); ++foreignRankAccretionsItr) {
5287 if (foreignRankAccretionsItr->targetRank!= accretion.targetRank) {
5294 if (foreignRankAccretionsItr == foreignRankAccretions.end()) {
5295 foreignRankAccretions.emplace_back();
5296 foreignRankAccretionsItr = foreignRankAccretions.begin() + foreignRankAccretions.size() - 1;
5297 foreignRankAccretionsItr->targetRank = accretion.targetRank;
5300 AccretionData &foreignAccretion = *foreignRankAccretionsItr;
5303 foreignAccretion.internalSeeds.insert(seedEntry);
5308 bool foreignAccrationExchangeNeeded = (foreignAccretions.size() > 0);
5309 MPI_Allreduce(MPI_IN_PLACE, &foreignAccrationExchangeNeeded, 1, MPI_C_BOOL, MPI_LOR, m_comm);
5310 if (!foreignAccrationExchangeNeeded) {
5315 dataCommunicator->clearAllSends();
5316 dataCommunicator->clearAllRecvs();
5319 for(
const auto &foreignAccretionEntry : foreignAccretions){
5320 int receiverRank = foreignAccretionEntry.first;
5323 std::size_t buffSize = 0;
5324 buffSize +=
sizeof(std::size_t);
5325 for(
const auto &foreignAccretion: foreignAccretionEntry.second){
5326 std::size_t nSeeds = foreignAccretion.internalSeeds.size();
5328 buffSize +=
sizeof(int);
5329 buffSize +=
sizeof(std::size_t);
5330 buffSize += nSeeds * (
sizeof(uint64_t) +
sizeof(
int));
5333 dataCommunicator->setSend(receiverRank, buffSize);
5336 SendBuffer &sendBuffer = dataCommunicator->getSendBuffer(receiverRank);
5338 const std::vector<AccretionData> &foreignRankAccretions = foreignAccretionEntry.second;
5340 sendBuffer << foreignRankAccretions.size();
5341 for(
const auto &foreignAccretion: foreignRankAccretions){
5342 sendBuffer << foreignAccretion.targetRank;
5343 sendBuffer << foreignAccretion.internalSeeds.size();
5344 for(
const auto &seedEntry : foreignAccretion.internalSeeds){
5345 sendBuffer << seedEntry.first;
5346 sendBuffer << seedEntry.second;
5352 dataCommunicator->discoverRecvs();
5353 dataCommunicator->startAllRecvs();
5354 dataCommunicator->startAllSends();
5357 int nCompletedRecvs = 0;
5358 while (nCompletedRecvs < dataCommunicator->getRecvCount()) {
5359 int senderRank = dataCommunicator->waitAnyRecv();
5360 RecvBuffer &recvBuffer = dataCommunicator->getRecvBuffer(senderRank);
5362 std::size_t nForeignAccretions;
5363 recvBuffer >> nForeignAccretions;
5365 for (std::size_t k = 0; k < nForeignAccretions; ++k) {
5368 recvBuffer >> targetRank;
5374 auto accretionsItr = accretions->begin();
5375 for(; accretionsItr != accretions->end(); ++accretionsItr){
5376 if (accretionsItr->targetRank!= targetRank) {
5383 if (accretionsItr == accretions->end()) {
5384 accretions->emplace_back();
5385 accretionsItr = accretions->begin() + accretions->size() - 1;
5386 accretionsItr->targetRank = targetRank;
5389 AccretionData &accretion = *accretionsItr;
5397 recvBuffer >> nSeeds;
5399 for(std::size_t n = 0; n < nSeeds; ++n){
5401 recvBuffer >> globalIdx;
5404 recvBuffer >> layer;
5406 assert(isInternal(globalIdx));
5407 accretion.population.insert({globalIdx, layer});
5408 accretion.internalSeeds.insert({globalIdx, layer});
5416 dataCommunicator->waitAllSends();
5425 ParaTree::buildGhostOctants(
const std::map<int, u32vector> &bordersPerProc,
5426 const std::vector<AccretionData> &accretions){
5428 DataCommunicator ghostDataCommunicator(m_comm);
5431 const std::size_t GHOST_ENTRY_BINARY_SIZE =
sizeof(uint64_t) +
Octant::getBinarySize() +
sizeof(int);
5437 for(
const auto &bordersPerProcEntry : bordersPerProc){
5438 int rank = bordersPerProcEntry.first;
5439 const std::vector<uint32_t> &rankBordersPerProc = bordersPerProcEntry.second;
5440 std::size_t nRankBordersPerProc = rankBordersPerProc.size();
5446 std::vector<AccretionData>::const_iterator accretionsItr;
5447 if (accretions.size() > 0) {
5448 bool accretionFound =
false;
5450 accretionsItr = accretions.begin();
5451 for (; accretionsItr != accretions.end(); ++accretionsItr) {
5452 if (accretionsItr->targetRank == rank) {
5453 accretionFound =
true;
5457 assert(accretionFound);
5459 accretionsItr = accretions.end();
5463 std::size_t buffSize = GHOST_ENTRY_BINARY_SIZE * nRankBordersPerProc;
5464 ghostDataCommunicator.setSend(rank, buffSize);
5467 SendBuffer &sendBuffer = ghostDataCommunicator.getSendBuffer(rank);
5468 for(uint32_t sourceLocalIdx : rankBordersPerProc){
5470 uint64_t sourceGlobalIdx =
getGlobalIdx(sourceLocalIdx);
5471 sendBuffer << sourceGlobalIdx;
5474 sendBuffer << m_octree.m_octants[sourceLocalIdx];
5481 if (accretionsItr != accretions.end()) {
5482 layer = accretionsItr->population.at(sourceGlobalIdx);
5487 sendBuffer << layer;
5492 ghostDataCommunicator.discoverRecvs();
5493 ghostDataCommunicator.startAllRecvs();
5494 ghostDataCommunicator.startAllSends();
5497 std::vector<int> ghostCommunicatorRecvsRanks = ghostDataCommunicator.getRecvRanks();
5498 std::sort(ghostCommunicatorRecvsRanks.begin(), ghostCommunicatorRecvsRanks.end());
5501 uint32_t nGhosts = 0;
5502 for (
int rank : ghostCommunicatorRecvsRanks) {
5503 RecvBuffer &recvBuffer = ghostDataCommunicator.getRecvBuffer(rank);
5504 std::size_t nRankGhosts = recvBuffer.getSize() / GHOST_ENTRY_BINARY_SIZE;
5505 nGhosts += nRankGhosts;
5508 m_octree.m_ghosts.resize(nGhosts);
5509 m_octree.m_globalIdxGhosts.resize(nGhosts);
5514 uint32_t ghostLocalIdx = 0;
5515 for (
int rank : ghostCommunicatorRecvsRanks) {
5516 ghostDataCommunicator.waitRecv(rank);
5517 RecvBuffer &recvBuffer = ghostDataCommunicator.getRecvBuffer(rank);
5519 std::size_t nRankGhosts = recvBuffer.getSize() / GHOST_ENTRY_BINARY_SIZE;
5520 for(std::size_t n = 0; n < nRankGhosts; ++n){
5522 uint64_t ghostGlobalIdx;
5523 recvBuffer >> ghostGlobalIdx;
5524 m_octree.m_globalIdxGhosts[ghostLocalIdx] = ghostGlobalIdx;
5530 Octant &ghostOctant = m_octree.m_ghosts[ghostLocalIdx];
5531 recvBuffer >> ghostOctant;
5535 recvBuffer >> ghostLayer;
5536 ghostOctant.setGhostLayer(ghostLayer);
5544 ghostDataCommunicator.waitAllSends();
5552 ParaTree::commMarker() {
5559 const std::size_t MARKER_ENTRY_BINARY_SIZE =
sizeof(Octant::m_marker);
5566 DataCommunicator markerCommunicator(m_comm);
5568 for(
const auto &bordersPerProcEntry : m_bordersPerProc){
5569 int rank = bordersPerProcEntry.first;
5570 const std::vector<uint32_t> &rankBordersPerProc = m_bordersPerProc.at(rank);
5571 const std::size_t nRankBorders = rankBordersPerProc.size();
5573 std::size_t buffSize = nRankBorders * MARKER_ENTRY_BINARY_SIZE;
5574 markerCommunicator.setSend(rank, buffSize);
5576 SendBuffer &sendBuffer = markerCommunicator.getSendBuffer(rank);
5577 for(std::size_t i = 0; i < nRankBorders; ++i){
5578 const Octant &octant = m_octree.m_octants[rankBordersPerProc[i]];
5579 sendBuffer << octant.getMarker();
5583 markerCommunicator.discoverRecvs();
5584 markerCommunicator.startAllRecvs();
5585 markerCommunicator.startAllSends();
5591 std::vector<int> recvRanks = markerCommunicator.getRecvRanks();
5592 std::sort(recvRanks.begin(), recvRanks.end());
5594 bool updated =
false;
5595 uint32_t ghostIdx = 0;
5596 for(
int rank : recvRanks){
5597 markerCommunicator.waitRecv(rank);
5598 RecvBuffer &recvBuffer = markerCommunicator.getRecvBuffer(rank);
5600 const std::size_t nRankGhosts = recvBuffer.getSize() / MARKER_ENTRY_BINARY_SIZE;
5601 for(std::size_t i = 0; i < nRankGhosts; ++i){
5603 recvBuffer >> marker;
5605 Octant &octant = m_octree.m_ghosts[ghostIdx];
5606 if (octant.getMarker() != marker) {
5607 octant.setMarker(marker);
5615 markerCommunicator.waitAllSends();
5625 ParaTree::updateAfterCoarse(){
5629#if BITPIT_ENABLE_MPI==1
5631 updateGlobalFirstDescMorton();
5632 updateGlobalLasttDescMorton();
5644 ParaTree::balance21(
bool verbose,
bool balanceNewOctants){
5648 (*m_log) <<
"---------------------------------------------" << endl;
5649 (*m_log) <<
" 2:1 BALANCE (balancing Marker before Adapt)" << endl;
5650 (*m_log) <<
" " << endl;
5651 (*m_log) <<
" Iterative procedure " << endl;
5652 (*m_log) <<
" " << endl;
5655 bool initialStep =
true;
5657#if BITPIT_ENABLE_MPI==1
5660 bool markersUpdated = commMarker();
5662 MPI_Allreduce(MPI_IN_PLACE, &markersUpdated, 1, MPI_C_BOOL, MPI_LOR, m_comm);
5663 if (!markersUpdated) {
5675 bool checkInterior = initialStep;
5676 bool checkGhosts =
true;
5678 bool balanceUpdated = m_octree.localBalance(balanceNewOctants, checkInterior, checkGhosts);
5679#if BITPIT_ENABLE_MPI==1
5681 MPI_Allreduce(MPI_IN_PLACE, &balanceUpdated, 1, MPI_C_BOOL, MPI_LOR, m_comm);
5682 if (!balanceUpdated) {
5694 initialStep =
false;
5700 (*m_log) <<
" 2:1 Balancing reached " << endl;
5701 (*m_log) <<
" " << endl;
5702 (*m_log) <<
"---------------------------------------------" << endl;
5719 m_octree.updateConnectivity();
5723 name <<
"s" << std::setfill(
'0') << std::setw(4) << m_nproc <<
"-p" << std::setfill(
'0') << std::setw(4) << m_rank <<
"-" << filename <<
".vtu";
5725 ofstream out(name.str().c_str());
5728 ss << filename <<
"*.vtu cannot be opened and it won't be written." << endl;
5729 (*m_log) << ss.str();
5732 int nofNodes = m_octree.m_nodes.size();
5733 int nofOctants = m_octree.m_connectivity.size();
5734 int nofGhosts = m_octree.m_ghostsConnectivity.size();
5735 int nofAll = nofGhosts + nofOctants;
5736 out <<
"<?xml version=\"1.0\"?>" << endl
5737 <<
"<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"BigEndian\">" << endl
5738 <<
" <UnstructuredGrid>" << endl
5739 <<
" <Piece NumberOfCells=\"" << m_octree.m_connectivity.size() + m_octree.m_ghostsConnectivity.size() <<
"\" NumberOfPoints=\"" << m_octree.m_nodes.size() <<
"\">" << endl;
5740 out <<
" <Points>" << endl
5741 <<
" <DataArray type=\"Float64\" Name=\"Coordinates\" NumberOfComponents=\""<< 3 <<
"\" format=\"ascii\">" << endl
5742 <<
" " << std::fixed;
5743 for(
int i = 0; i < nofNodes; i++)
5745 for(
int j = 0; j < 3; ++j){
5746 if (j==0) out << std::setprecision(6) << m_trans.mapX(m_octree.m_nodes[i][j]) <<
" ";
5747 if (j==1) out << std::setprecision(6) << m_trans.mapY(m_octree.m_nodes[i][j]) <<
" ";
5748 if (j==2) out << std::setprecision(6) << m_trans.mapZ(m_octree.m_nodes[i][j]) <<
" ";
5750 if((i+1)%4==0 && i!=nofNodes-1)
5753 out << endl <<
" </DataArray>" << endl
5754 <<
" </Points>" << endl
5755 <<
" <Cells>" << endl
5756 <<
" <DataArray type=\"UInt64\" Name=\"connectivity\" NumberOfComponents=\"1\" format=\"ascii\">" << endl
5758 for(
int i = 0; i < nofOctants; i++)
5760 for(
int j = 0; j < m_treeConstants->
nNodes; j++)
5774 out << m_octree.m_connectivity[i][jj] <<
" ";
5776 if((i+1)%3==0 && i!=nofOctants-1)
5779 for(
int i = 0; i < nofGhosts; i++)
5781 for(
int j = 0; j < m_treeConstants->
nNodes; j++)
5795 out << m_octree.m_ghostsConnectivity[i][jj] <<
" ";
5797 if((i+1)%3==0 && i!=nofGhosts-1)
5800 out << endl <<
" </DataArray>" << endl
5801 <<
" <DataArray type=\"UInt64\" Name=\"offsets\" NumberOfComponents=\"1\" format=\"ascii\">" << endl
5803 for(
int i = 0; i < nofAll; i++)
5805 out << (i+1)*m_treeConstants->
nNodes <<
" ";
5806 if((i+1)%12==0 && i!=nofAll-1)
5809 out << endl <<
" </DataArray>" << endl
5810 <<
" <DataArray type=\"UInt8\" Name=\"types\" NumberOfComponents=\"1\" format=\"ascii\">" << endl
5812 for(
int i = 0; i < nofAll; i++)
5815 type = 5 + (m_dim*2);
5817 if((i+1)%12==0 && i!=nofAll-1)
5820 out << endl <<
" </DataArray>" << endl
5821 <<
" </Cells>" << endl
5822 <<
" </Piece>" << endl
5823 <<
" </UnstructuredGrid>" << endl
5824 <<
"</VTKFile>" << endl;
5829 name <<
"s" << std::setfill(
'0') << std::setw(4) << m_nproc <<
"-" << filename <<
".pvtu";
5830 ofstream pout(name.str().c_str());
5831 if(!pout.is_open()){
5833 ss << filename <<
"*.pvtu cannot be opened and it won't be written." << endl;
5834 (*m_log) << ss.str();
5838 pout <<
"<?xml version=\"1.0\"?>" << endl
5839 <<
"<VTKFile type=\"PUnstructuredGrid\" version=\"0.1\" byte_order=\"BigEndian\">" << endl
5840 <<
" <PUnstructuredGrid GhostLevel=\"0\">" << endl
5841 <<
" <PPointData>" << endl
5842 <<
" </PPointData>" << endl
5843 <<
" <PCellData Scalars=\"\">" << endl;
5844 pout <<
" </PCellData>" << endl
5845 <<
" <PPoints>" << endl
5846 <<
" <PDataArray type=\"Float64\" Name=\"Coordinates\" NumberOfComponents=\"3\"/>" << endl
5847 <<
" </PPoints>" << endl;
5848 for(
int i = 0; i < m_nproc; i++)
5849 pout <<
" <Piece Source=\"s" << std::setw(4) << std::setfill(
'0') << m_nproc <<
"-p" << std::setw(4) << std::setfill(
'0') << i <<
"-" << filename <<
".vtu\"/>" << endl;
5850 pout <<
" </PUnstructuredGrid>" << endl
5856#if BITPIT_ENABLE_MPI==1
5858 MPI_Barrier(m_comm);
5874 m_octree.updateConnectivity();
5878 name <<
"s" << std::setfill(
'0') << std::setw(4) << m_nproc <<
"-p" << std::setfill(
'0') << std::setw(4) << m_rank <<
"-" << filename <<
".vtu";
5880 ofstream out(name.str().c_str());
5883 ss << filename <<
"*.vtu cannot be opened and it won't be written.";
5884 (*m_log) << ss.str();
5887 int nofNodes = m_octree.m_nodes.size();
5888 int nofOctants = m_octree.m_connectivity.size();
5889 int nofAll = nofOctants;
5890 out <<
"<?xml version=\"1.0\"?>" << endl
5891 <<
"<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"BigEndian\">" << endl
5892 <<
" <UnstructuredGrid>" << endl
5893 <<
" <Piece NumberOfCells=\"" << m_octree.m_connectivity.size() <<
"\" NumberOfPoints=\"" << m_octree.m_nodes.size() <<
"\">" << endl;
5894 out <<
" <CellData Scalars=\"Data\">" << endl;
5895 out <<
" <DataArray type=\"Float64\" Name=\"Data\" NumberOfComponents=\"1\" format=\"ascii\">" << endl
5896 <<
" " << std::fixed;
5897 int ndata = m_octree.m_connectivity.size();
5898 for(
int i = 0; i < ndata; i++)
5900 out << std::setprecision(6) << data[i] <<
" ";
5901 if((i+1)%4==0 && i!=ndata-1)
5904 out << endl <<
" </DataArray>" << endl
5905 <<
" </CellData>" << endl
5906 <<
" <Points>" << endl
5907 <<
" <DataArray type=\"Float64\" Name=\"Coordinates\" NumberOfComponents=\""<< 3 <<
"\" format=\"ascii\">" << endl
5908 <<
" " << std::fixed;
5909 for(
int i = 0; i < nofNodes; i++)
5911 for(
int j = 0; j < 3; ++j){
5912 if (j==0) out << std::setprecision(6) << m_trans.mapX(m_octree.m_nodes[i][j]) <<
" ";
5913 if (j==1) out << std::setprecision(6) << m_trans.mapY(m_octree.m_nodes[i][j]) <<
" ";
5914 if (j==2) out << std::setprecision(6) << m_trans.mapZ(m_octree.m_nodes[i][j]) <<
" ";
5916 if((i+1)%4==0 && i!=nofNodes-1)
5919 out << endl <<
" </DataArray>" << endl
5920 <<
" </Points>" << endl
5921 <<
" <Cells>" << endl
5922 <<
" <DataArray type=\"UInt64\" Name=\"connectivity\" NumberOfComponents=\"1\" format=\"ascii\">" << endl
5924 for(
int i = 0; i < nofOctants; i++)
5926 for(
int j = 0; j < m_treeConstants->
nNodes; j++)
5940 out << m_octree.m_connectivity[i][jj] <<
" ";
5942 if((i+1)%3==0 && i!=nofOctants-1)
5945 out << endl <<
" </DataArray>" << endl
5946 <<
" <DataArray type=\"UInt64\" Name=\"offsets\" NumberOfComponents=\"1\" format=\"ascii\">" << endl
5948 for(
int i = 0; i < nofAll; i++)
5950 out << (i+1)*m_treeConstants->
nNodes <<
" ";
5951 if((i+1)%12==0 && i!=nofAll-1)
5954 out << endl <<
" </DataArray>" << endl
5955 <<
" <DataArray type=\"UInt8\" Name=\"types\" NumberOfComponents=\"1\" format=\"ascii\">" << endl
5957 for(
int i = 0; i < nofAll; i++)
5960 type = 5 + (m_dim*2);
5962 if((i+1)%12==0 && i!=nofAll-1)
5965 out << endl <<
" </DataArray>" << endl
5966 <<
" </Cells>" << endl
5967 <<
" </Piece>" << endl
5968 <<
" </UnstructuredGrid>" << endl
5969 <<
"</VTKFile>" << endl;
5974 name <<
"s" << std::setfill(
'0') << std::setw(4) << m_nproc <<
"-" << filename <<
".pvtu";
5975 ofstream pout(name.str().c_str());
5976 if(!pout.is_open()){
5978 ss << filename <<
"*.pvtu cannot be opened and it won't be written." << endl;
5979 (*m_log) << ss.str();
5983 pout <<
"<?xml version=\"1.0\"?>" << endl
5984 <<
"<VTKFile type=\"PUnstructuredGrid\" version=\"0.1\" byte_order=\"BigEndian\">" << endl
5985 <<
" <PUnstructuredGrid GhostLevel=\"0\">" << endl
5986 <<
" <PPointData>" << endl
5987 <<
" </PPointData>" << endl
5988 <<
" <PCellData Scalars=\"Data\">" << endl
5989 <<
" <PDataArray type=\"Float64\" Name=\"Data\" NumberOfComponents=\"1\"/>" << endl
5990 <<
" </PCellData>" << endl
5991 <<
" <PPoints>" << endl
5992 <<
" <PDataArray type=\"Float64\" Name=\"Coordinates\" NumberOfComponents=\"3\"/>" << endl
5993 <<
" </PPoints>" << endl;
5994 for(
int i = 0; i < m_nproc; i++)
5995 pout <<
" <Piece Source=\"s" << std::setw(4) << std::setfill(
'0') << m_nproc <<
"-p" << std::setw(4) << std::setfill(
'0') << i <<
"-" << filename <<
".vtu\"/>" << endl;
5996 pout <<
" </PUnstructuredGrid>" << endl
6002#if BITPIT_ENABLE_MPI==1
6004 MPI_Barrier(m_comm);
Intersection class definition.
void computeVirtualNodeNeighOffsets(uint8_t level, uint8_t inode, uint8_t neighLevel, std::vector< std::array< int64_t, 3 > > *neighOffsets) const
uint8_t getMaxEdgeNeighLevel(const Octant &octant) const
uint8_t getMaxNeighLevel(const Octant &octant) const
uint8_t getMaxNodeNeighLevel(const Octant &octant) const
std::array< int64_t, 3 > getEdgePeriodicOffset(const Octant &octant, uint8_t iedge) const
std::array< int64_t, 3 > getPeriodicOffset(const Octant &octant, uint8_t iface) const
void computeVirtualEdgeNeighOffsets(uint8_t level, uint8_t iedge, uint8_t neighLevel, std::vector< std::array< int64_t, 3 > > *neighOffsets) const
void computeVirtualNeighOffsets(uint8_t level, uint8_t iface, uint8_t neighLevel, std::vector< std::array< int64_t, 3 > > *neighOffsets) const
std::array< int64_t, 3 > getNodePeriodicOffset(const Octant &octant, uint8_t inode) const
void create(const std::string &name, bool reset=false, int nProcesses=1, int rank=0)
void setDefaultVisibility(log::Visibility visibility)
log::Visibility getDefaultVisibility()
std::string getName() const
uint64_t computeNodePersistentKey(uint8_t inode) const
int getGhostLayer() const
bool getPbound(uint8_t face) const
uint8_t countChildren() const
void getLogicalNode(u32array3 &node, uint8_t inode) const
void getLogicalNodes(u32arr3vector &nodes) const
u32array3 getLogicalCoordinates() const
static unsigned int getBinarySize()
void getNormal(uint8_t iface, i8array3 &normal, const int8_t(&normals)[6][3]) const
Octant buildFather() const
uint64_t getMorton() const
void setMarker(int8_t marker)
bool getBound(uint8_t face) const
uint32_t getLogicalSize() const
void setBalance(bool balance)
uint64_t getLogicalArea() const
darray3 getLogicalCenter() const
std::vector< Octant > buildChildren() const
void setGhostLayer(int ghostLayer)
darray3 getLogicalFaceCenter(uint8_t iface) const
uint8_t getFamilySplittingNode() const
uint64_t getLogicalVolume() const
uint64_t computeLastDescMorton() const
Para Tree is the user interface class.
uint8_t getNnodesperface() const
Octant * getPointOwner(const dvector &point)
void write(const std::string &filename)
uint32_t getLocalIdx(uint64_t gidx) const
double levelToSize(uint8_t level) const
uint32_t getGhostLocalIdx(uint64_t gidx) const
void setMarker(uint32_t idx, int8_t marker)
bool isFaceOnOctant(const Octant *faceOctant, uint8_t faceIndex, const Octant *octant) const
const u32array3 & getNodeLogicalCoordinates(uint32_t node) const
uint32_t getNumIntersections() const
int8_t getMaxDepth() const
uint32_t getNumOctants() const
uint8_t getNchildren() const
void getPreMapping(u32vector &idx, std::vector< int8_t > &markers, std::vector< bool > &isghost)
const uint8_t(* getFacenode() const)[4]
bool getPbound(uint32_t idx, uint8_t face) const
void expectedOctantAdapt(const Octant *octant, int8_t marker, octvector *result) const
const u32arr3vector & getNodes() const
bool adaptGlobalCoarse(bool mapper_flag=false)
uint8_t getFamilySplittingNode(const Octant *) const
bool adapt(bool mapper_flag=false)
const int8_t(* getNormals() const)[3]
void findAllNodeNeighbours(uint32_t idx, uint32_t node, u32vector &neighbours, bvector &isghost)
void findGhostAllCodimensionNeighbours(uint32_t idx, u32vector &neighbours, bvector &isghost)
Octant * getOctant(uint32_t idx)
void getMapping(uint32_t idx, u32vector &mapper, bvector &isghost) const
octantID getPersistentIdx(uint32_t idx) const
virtual void restore(std::istream &stream)
bool getBalance(uint32_t idx) const
double getLocalMinSize() const
void loadBalance(const dvector *weight=NULL)
void setNofGhostLayers(std::size_t nofGhostLayers)
uint64_t getMorton(uint32_t idx) const
void computeConnectivity()
ParaTree(const std::string &logfile=DEFAULT_LOG_FILE, MPI_Comm comm=MPI_COMM_WORLD)
darray3 getFaceCenter(uint32_t idx, uint8_t face) const
uint8_t getNnodes() const
uint64_t getLastDescMorton() const
int getPointOwnerRank(const darray3 &point)
bool getBound(uint32_t idx, uint8_t face) const
int findOwner(uint64_t morton) const
static BITPIT_PUBLIC_API const std::string DEFAULT_LOG_FILE
uint32_t getIn(const Intersection *inter) const
const uint8_t(* getEdgeface() const)[2]
Operation getLastOperation() const
const std::vector< uint64_t > & getPartitionLastDesc() const
uint32_t getMaxLength() const
bool adaptGlobalRefine(bool mapper_flag=false)
octantIterator getInternalOctantsBegin()
double getSize(uint32_t idx) const
const std::vector< uint64_t > & getPartitionFirstDesc() const
LoadBalanceRanges evalLoadBalanceRanges(dvector *weights)
double getY(uint32_t idx) const
const int8_t(* getEdgecoeffs() const)[3]
const std::vector< uint64_t > & getPartitionRangeGlobalIdx() const
bvector getPeriodic() const
uint32_t getPointOwnerIdx(const double *point) const
void setBalanceCodimension(uint8_t b21codim)
darray3 getNode(uint32_t idx, uint8_t node) const
void writeTest(const std::string &filename, dvector data)
bool isNodeOnOctant(const Octant *nodeOctant, uint8_t nodeIndex, const Octant *octant) const
double getZ(uint32_t idx) const
const std::map< int, std::vector< uint32_t > > & getBordersPerProc() const
const LoadBalanceRanges & getLoadBalanceRanges() const
void setTol(double tol=1.0e-14)
bool getFiner(const Intersection *inter) const
uint64_t computeNodePersistentKey(uint32_t idx, uint8_t node) const
double getArea(uint32_t idx) const
bool getIsGhost(const Intersection *inter) const
uint32_t getIdx(const Octant *oct) const
bool isEdgeOnOctant(const Octant *edgeOctant, uint8_t edgeIndex, const Octant *octant) const
std::size_t getNofGhostLayers() const
void findAllCodimensionNeighbours(uint32_t idx, u32vector &neighbours, bvector &isghost)
uint64_t getFirstDescMorton() const
void findGhostNeighbours(uint32_t idx, uint8_t face, uint8_t codim, u32vector &neighbours) const
darray3 getCoordinates(uint32_t idx) const
octantIterator getPboundOctantsBegin()
uint8_t getFace(const Intersection *inter) const
int8_t getMarker(uint32_t idx) const
uint32_t getNumGhosts() const
const u32vector2D & getGhostConnectivity() const
uint8_t getNedges() const
const uint8_t(* getNodeface() const)[3]
int getOwnerRank(uint64_t globalIdx) const
octantIterator getInternalOctantsEnd()
uint64_t getGlobalNumOctants() const
uint32_t getNumNodes() const
uint32_t getOut(const Intersection *inter) const
void updateConnectivity()
uint8_t getNfaces() const
bool getOutIsGhost(const Intersection *inter) const
uint8_t getLocalMaxDepth() const
int getGhostLayer(const Octant *oct) const
double getVolume(uint32_t idx) const
virtual int getDumpVersion() const
const int8_t(* getNodecoeffs() const)[3]
uint8_t getLevel(uint32_t idx) const
const uint8_t * getOppface() const
void clearConnectivity(bool release=true)
double getX(uint32_t idx) const
void computeIntersections()
void replaceComm(MPI_Comm communicator, MPI_Comm *previousCommunicator=nullptr)
bool getIsNewC(uint32_t idx) const
uint64_t getGlobalIdx(uint32_t idx) const
void getCenter(uint32_t idx, darray3 ¢erCoords) const
darray3 getNodeCoordinates(uint32_t node) const
u32vector getOwners(const Intersection *inter) const
void setPeriodic(uint8_t i)
const u32vector2D & getConnectivity() const
void setBalance(uint32_t idx, bool balance)
int8_t getPreMarker(uint32_t idx)
virtual void dump(std::ostream &stream, bool full=true)
uint64_t getGhostGlobalIdx(uint32_t idx) const
void setComm(MPI_Comm communicator)
uint8_t getBalanceCodimension() const
void getNormal(uint32_t idx, uint8_t face, darray3 &normal) const
octantIterator getPboundOctantsEnd()
uint64_t getStatus() const
Intersection * getIntersection(uint32_t idx)
Octant * getGhostOctant(uint32_t idx)
double getLocalMaxSize() const
darray3 getOrigin() const
bool getIsNewR(uint32_t idx) const
std::array< T, d > abs(const std::array< T, d > &x)
void sum(const std::array< T, d > &x, T1 &s)
std::array< T, d > max(const std::array< T, d > &x, const std::array< T, d > &y)
std::array< T, d > pow(std::array< T, d > &x, double p)
T uipow(const T &, unsigned int)
std::array< T, d > min(const std::array< T, d > &x, const std::array< T, d > &y)
std::unordered_map< int, std::array< uint32_t, 2 > > ExchangeRanges
void write(std::ostream &stream, const std::vector< bool > &container)
void read(std::istream &stream, std::vector< bool > &container)
#define BITPIT_UNUSED(variable)
Logger & cout(log::Level defaultSeverity, log::Visibility defaultVisibility)
LoggerManager & manager()
LoggerManipulator< std::string > context(const std::string &context)
std::vector< uint32_t > lengths
static BITPIT_PUBLIC_API const TreeConstants & instance(uint8_t dim)