MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
CartesianGrid< nDim > Class Template Reference

#include <cartesiangrid.h>

Collaboration diagram for CartesianGrid< nDim >:
[legend]

Classes

struct  azimuthalBbox
 

Public Types

using MInt_dyn_array = MInt *
 
using Tree = maia::grid::tree::Tree< nDim >
 
using Cell = typename Tree::Cell
 

Public Member Functions

MBool hasCutOff () const
 Returns weather the grid has a cutOff. More...
 
MLonga_parentId (const MInt cellId)
 Returns the parent of the cell cellId. More...
 
MLong a_parentId (const MInt cellId) const
 Returns the parent of the cell cellId. More...
 
MLong a_parentId (const MInt cellId, const MInt solverId) const
 Returns the parent of the cell cellId. More...
 
MBool a_hasParent (const MInt cellId) const
 Returns if the cell cellId has a parent. More...
 
MBool a_hasParent (const MInt cellId, const MInt solverId) const
 Returns if the cell cellId has a parent. More...
 
MLonga_childId (const MInt cellId, const MInt pos)
 Returns the child id of the cell cellId at position pos. More...
 
MLong a_childId (const MInt cellId, const MInt pos) const
 Returns the child id of the cell cellId at position pos. More...
 
MLong a_childId (const MInt cellId, const MInt pos, const MInt solverId) const
 Returns the child id of the cell cellId at position pos. More...
 
MLong noPartitionCellsGlobal () const
 
MInta_level (const MInt cellId)
 Returns the level of the cell cellId. More...
 
MInt a_level (const MInt cellId) const
 Returns the level of the cell cellId. More...
 
MFloat a_workload (const MInt cellId) const
 Returns the workload of the cell cellId. More...
 
MFloata_workload (const MInt cellId)
 Returns the workload of the cell cellId. More...
 
MInt a_noOffsprings (const MInt cellId) const
 Returns the noOffsprings of the cell . More...
 
MInta_noOffsprings (const MInt cellId)
 Returns the noOffsprings of the cell . More...
 
MLonga_globalId (const MInt cellId)
 Returns the globalId of the cell cellId in collector cells_. More...
 
MLong a_globalId (const MInt cellId) const
 Returns the globalId of the cell cellId in collector cells_. More...
 
MFloata_weight (const MInt cellId)
 Returns the weight of the cell cellId. More...
 
MFloat a_weight (const MInt cellId) const
 Returns the weight of the cell cellId. More...
 
MInt a_noChildren (const MInt cellId) const
 Returns the no. of children of the cell cellId. More...
 
MInt a_hasChildren (const MInt cellId) const
 Returns if the cell cellId has children. More...
 
MInt a_hasChildren (const MInt cellId, const MInt solverId) const
 Returns if the cell cellId has children. More...
 
MInt a_hasChild (const MInt cellId, const MInt pos) const
 Returns if the cell cellId has a child at position pos. More...
 
MInt a_hasChild (const MInt cellId, const MInt pos, const MInt solverId) const
 Returns if the cell cellId has a child at position pos. More...
 
maia::grid::cell::BitsetType::reference a_isToDelete (const MInt cellId)
 Returns the delete of the cell cellId. More...
 
MBool a_isToDelete (const MInt cellId) const
 Returns the delete of the cell cellId. More...
 
MLonga_neighborId (const MInt cellId, const MInt dir)
 Returns the neighbor id of the cell cellId dir. More...
 
MLong a_neighborId (const MInt cellId, const MInt dir) const
 Returns the neighbor id of the cell cellId dir. More...
 
MLong a_neighborId (const MInt cellId, const MInt dir, const MInt solverId) const
 Returns the neighbor id of the cell cellId dir. More...
 
MFloata_coordinate (const MInt cellId, const MInt dir)
 Returns the coordinate of the cell cellId for direction dir. More...
 
MFloat a_coordinate (const MInt cellId, const MInt dir) const
 Returns the coordinate of the cell cellId for direction dir. More...
 
template<class U >
MFloat a_coordinate (Collector< U > *NotUsed(cells_), const MInt cellId, const MInt dir) const
 Returns the coordinate of the cell cellId in collector cells_ for direction dir. More...
 
MBool a_isLeafCell (const MInt cellId) const
 Returns whether cell is leaf cellId. More...
 
maia::grid::tree::SolverBitsetType::reference a_isLeafCell (const MInt cellId, const MInt solverId)
 Returns whether cell is leaf cellId. More...
 
MBool a_isLeafCell (const MInt cellId, const MInt solverId) const
 Returns whether cell is leaf cellId. More...
 
MBool a_hasNeighbor (const MInt cellId, const MInt dir) const
 Returns noNeighborIds of the cell CellId. More...
 
MBool a_hasNeighbor (const MInt cellId, const MInt dir, const MInt solverId) const
 Returns noNeighborIds of the cell CellId. More...
 
void a_resetProperties (const MInt cellId)
 Returns property p of the cell cellId. More...
 
void a_copyProperties (const MInt fromCellId, const MInt toCellId)
 Returns property p of the cell cellId. More...
 
maia::grid::cell::BitsetType::reference a_hasProperty (const MInt cellId, const Cell p)
 Returns property p of the cell cellId. More...
 
MBool a_hasProperty (const MInt cellId, const Cell p) const
 Returns property p of the cell cellId. More...
 
MString a_propertiesToString (const MInt cellId)
 
MBool a_isHalo (const MInt cellId) const
 Returns property p of the cell cellId. More...
 
maia::grid::tree::SolverBitsetType::reference a_solver (const MInt cellId, const MInt solverId)
 Returns if cell cellId is used by solver solverId. More...
 
void setSolver (const MInt cellId, const MInt solverId, MBool flag)
 Sets if cell is used by solver. More...
 
MBool addSolverToGrid ()
 
MBool wasAdapted () const
 
MBool wasBalanced () const
 
MBool wasBalancedAtLeastOnce () const
 
template<class F >
MInt reduceToLevel (const MInt reductionLevel, F interpolateToParentCells)
 Reduces the current grid to a certain level. More...
 
MFloat cellLengthAtLevel (const MInt level) const
 Returns cell length at cell level level. More...
 
MFloat cellLengthAtCell (const MInt cellId) const
 Returns the cell length of cell cellId. More...
 
MFloat halfCellLength (const MInt cellId) const
 Returns the half cell length of cell cellId. More...
 
MFloat cellVolumeAtLevel (const MInt level) const
 
void boundingBox (MFloat *const box) const
 
const MFloatglobalBoundingBox () const
 return global Bounding box More...
 
void centerOfGravity (MFloat *const center) const
 
MFloat lengthLevel0 () const
 Return the length of the level 0 cell. More...
 
MInt noInternalCells () const
 Return number of internal cells (i.e., excluding halo cells) More...
 
MInt noNeighborDomains () const
 Return number of neighbor domains. More...
 
const MIntneighborDomain (const MInt id) const
 Return neighbor domain. More...
 
const std::vector< MInt > & neighborDomains () const
 Return vector of neighbor domains. More...
 
const MLongdomainOffset (const MInt id) const
 Return domain offset. More...
 
MInt noHaloCells (const MInt domainId) const
 Return number of halo cells for given domain. More...
 
constexpr MBool paraViewPlugin () const
 
MInt haloCell (const MInt domainId, const MInt cellId) const
 Return halo cell id. More...
 
const std::vector< std::vector< MInt > > & haloCells () const
 
MInt noWindowCells (const MInt domainId) const
 Return number of window cells for given domain. More...
 
MInt windowCell (const MInt domainId, const MInt cellId) const
 Return window cell id. More...
 
const std::vector< std::vector< MInt > > & windowCells () const
 
MInt windowLayer (const MInt domainId, const MInt cellId, const MInt solverId) const
 
MBool isSolverWindowCell (const MInt domainId, const MInt cellId, const MInt solverId) const
 
MInt noSolverWindowCells (const MInt domainId, const MInt solverId) const
 
MInt noSolverHaloCells (const MInt domainId, const MInt solverId, const MBool periodicCells) const
 
MInt noAzimuthalNeighborDomains () const
 Return number of azimuthal neighbor domains. More...
 
const MIntazimuthalNeighborDomain (const MInt id) const
 Return azimuthal neighbor domain. More...
 
const std::vector< MInt > & azimuthalNeighborDomains () const
 Return vector of azimuthal neighbor domains. More...
 
MInt noAzimuthalHaloCells (const MInt domainId) const
 Return number of azimuthal Halo cells for given domain. More...
 
MInt azimuthalHaloCell (const MInt domainId, const MInt cellId) const
 Return azimuthal Halo cell id. More...
 
const std::vector< std::vector< MInt > > & azimuthalHaloCells () const
 
MInt noAzimuthalUnmappedHaloCells () const
 
MInt azimuthalUnmappedHaloCell (const MInt cellId) const
 
MInt azimuthalUnmappedHaloDomain (const MInt cellId) const
 
MInt noAzimuthalWindowCells (const MInt domainId) const
 Return number of azimuthal window cells for given domain. More...
 
MInt azimuthalWindowCell (const MInt domainId, const MInt cellId) const
 Return azimuthal window cell id. More...
 
const std::vector< std::vector< MInt > > & azimuthalWindowCells () const
 
MString gridInputFileName () const
 Return grid file name. More...
 
MInt maxUniformRefinementLevel () const
 Return maximum homogeneously-refined level. More...
 
MFloat reductionFactor () const
 Return the reductionFactor. More...
 
MInt maxRefinementLevel () const
 Return maximum possible refinement level. More...
 
MInt centerOfGravity (MInt dir) const
 Return the center of gravity. More...
 
MInt noMinCells () const
 Return the number of Cells on the minLevel. More...
 
MInt minCell (const MInt id) const
 Return min-level cell id. More...
 
MLong noCellsGlobal () const
 Return the Global-noCells. More...
 
MInt noHaloLayers () const
 Return noHalo-a_noHaloLayers. More...
 
constexpr MInt noHaloLayers (const MInt solverId) const
 
MInt haloMode () const
 
MLong localPartitionCellOffsets (const MInt index) const
 
MInt periodicCartesianDir (const MInt dir) const
 
MFloat periodicCartesianLength (const MInt dir) const
 
MFloat gridCellVolume (const MInt level) const
 
MBool checkOutsideAzimuthalDomain (MFloat *)
 
void tagAzimuthalHigherLevelExchangeCells (std::vector< MLong > &, std::vector< MLong > &, MInt)
 Tag azimuthal halo cells for refinement. More...
 
void tagAzimuthalUnmappedHaloCells (std::vector< std::vector< MLong > > &, std::vector< MLong > &, std::vector< MInt > &, MInt)
 Tag azimuthal halo cells for refinement. More...
 
void correctAzimuthalSolverBits ()
 Corrects solver bits on azimuthal halo cells Ensure that azimuthal halo cells have all children or are not refined at all. Further ensure that parent cells have solverBit = true. More...
 
MInt localPartitionCellLocalIds (const MInt id) const
 
constexpr MInt noPartitionCells () const
 
constexpr MBool allowInterfaceRefinement () const
 
void gridSanityChecks ()
 Perform grid sanity checks. More...
 
void checkWindowHaloConsistency (const MBool fullCheck=false, const MString a="")
 Checks consistency of window/halo cells. More...
 
void checkAzimuthalWindowHaloConsistency ()
 Checks consistency of aimuthal window/halo cells. More...
 
void dumpCellData (const MString name)
 Write the cell data of the local tree to some file for debugging purposes. More...
 
MBool updatedPartitionCells () const
 
void setUpdatedPartitionCells (const MBool flag)
 
 CartesianGrid (MInt maxCells, const MFloat *const bBox, const MPI_Comm comm, const MString &fileName="")
 
 ~CartesianGrid ()
 
Treetreeb ()
 Full access to tree (for now) More...
 
const Treetreeb () const
 
MInt maxLevel () const
 
MInt minLevel () const
 
MInt targetGridMinLevel () const
 
MInt maxPartitionLevelShift () const
 
MInt maxNoCells () const
 
MPI_Comm mpiComm () const
 Return the MPI communicator used by this grid. More...
 
MLong bitOffset () const
 Return the 32-BitOffset. More...
 
template<MBool t_correct = false>
MInt findContainingPartitionCell (const MFloat *const coord, const MInt solverId=-1, std::function< MFloat *(MInt, MFloat *const)> correctCellCoord=nullptr)
 Return the cell Id of the partition cell containing the coords. More...
 
MInt intersectingWithPartitioncells (MFloat *const center, MFloat const radius)
 
MInt intersectingWithHaloCells (MFloat *const center, MFloat const radius, MInt domainId, MBool onlyPartition)
 
MBool intersectingWithLocalBoundingBox (MFloat *const center, MFloat const radius)
 
MBool boxSphereIntersection (const MFloat *bMin, const MFloat *bMax, const MFloat *const sphereCenter, MFloat const radius)
 
MBool hollowBoxSphereIntersection (const MFloat *bMin, const MFloat *bMax, const MFloat *const sphereCenter, MFloat const radius)
 
MInt ancestorPartitionCellId (const MInt cellId) const
 Return the cell Id of the partition cell that has the given cellId as a descendant. More...
 
MInt findContainingHaloPartitionCell (const MFloat *const coors, const MInt solverId=-1)
 Return the cell id of the halo partition cell containing the coords. More...
 
template<MBool t_correct = false>
MInt findContainingHaloCell (const MFloat *const coord, const MInt solverId, MInt domainId, MBool onlyPartitionCells, std::function< MFloat *(MInt, MFloat *const)> correctCellCoord=nullptr)
 Return the cell id of the halo partition cell containing the coords. More...
 
template<MBool t_correct = false>
MInt findContainingLeafCell (const MFloat *coord, std::function< MFloat *(MInt, MFloat *const)> correctCellCoord=nullptr, const MInt solverId=-1)
 Return the cell Id of the leaf cell containing the coords. More...
 
template<MBool t_correct = false>
MInt findContainingLeafCell (const std::array< MFloat, nDim > &coord, const MInt startId, std::function< MFloat *(MInt, MFloat *const)> *correctCellCoord=nullptr, const MInt solverId=-1, const MBool allowNonLeafHalo=false)
 
template<MBool t_correct = false>
MInt findContainingLeafCell (const MFloat *const coord, const MInt startId, std::function< MFloat *(MInt, MFloat *const)> correctCellCoord=nullptr, const MInt solverId=-1, const MBool allowNonLeafHalo=false)
 
template<MBool t_correct = false, MBool insideLimit>
MBool pointWthCell (const std::array< MFloat, nDim > &coord, const MInt cellId, std::function< MFloat *(MInt, MFloat *const)> correctCellCoord=nullptr) const
 
template<MBool t_correct = false, MBool insideLimit>
MBool pointWthCell (const MFloat *const coord, const MInt cellId, std::function< MFloat *(MInt, MFloat *const)> correctCellCoord=nullptr) const
 
MFloatdummyCorrect (const MInt cellId, MFloat *coords)
 
void computeLocalBoundingBox (MFloat *const bbox)
 Compute the bounding box of all local cells. More...
 
MBool pointInLocalBoundingBox (const MFloat *coord)
 Check if the given point lies in the local bounding box. More...
 
void propagateDistance (std::vector< MInt > &list, MIntScratchSpace &distMem, MInt dist)
 propagates a given distance from a given list of cells on equal level neighbours More...
 
void propagationStep (MInt cellId, MInt dist, MInt *distMem, MInt endDist)
 starts the propagation on a cell and continues calling the function for the neighbours More...
 
template<typename DATATYPE >
void exchangeNotInPlace (DATATYPE *exchangeVar, DATATYPE *recvMem)
 communicates a variable from windows to halos but does not overwrite halo values. Window values are stored in a buffer. More...
 
template<typename DATATYPE >
void generalExchange (MInt noVars, const MInt *vars, DATATYPE **exchangeVar, MInt noDomSend, MInt *domSend, const MInt *noCellsSendPerDom, const MInt *cellIdsSend, MInt noDomRecv, MInt *domRecv, const MInt *noCellsRecvPerDom, const MInt *cellIdsRecv)
 
void createGridSlice (const MString &axis, const MFloat intercept, const MString &fileName)
 Overload method of createGridSlice to provide usage with or without return of cellIds which are in the slice. More...
 
void createGridSlice (const MString &axis, const MFloat intercept, const MString &fileName, const MInt solverId, MInt *const noSliceCellIds, MInt *const sliceCellIds, MInt *const noSliceHilbertIds=nullptr, MInt *const sliceHilbertInfo=nullptr, MInt *const noSliceContHilbertIds=nullptr, MInt *const sliceContiguousHilbertInfo=nullptr)
 Create a valid 2D grid which represents a slice from a 3D grid. More...
 
void computeGlobalIds ()
 Update number of internal cells, recalculate domain offsets, recalculate global ids for all internal cells and update global ids of all halo cells. More...
 
void localToGlobalIds ()
 Convert parent ids, neighbor ids, and child ids from local to global cell ids. More...
 
void descendNoOffsprings (const MLong cellId, const MLong offset=0)
 
void storeMinLevelCells (const MBool updateMinlevel=false)
 Store cell ids of all min-level cells. More...
 
void computeLeafLevel ()
 Compute distance to leaf level. More...
 
void determineNoPartitionCellsAndOffsets (MLong *const noPartitionCells, MLong *const partitionCellOffsets)
 Determine the number of partition cells on each domain and the corresponding offsets. More...
 
void determinePartLvlAncestorHaloWindowCells (std::vector< std::vector< MInt > > &partLvlAncestorHaloCells, std::vector< std::vector< MInt > > &partLvlAncestorWindowCells)
 Store partition level ancestor window/halo cells. More...
 
void balance (const MInt *const noCellsToReceiveByDomain, const MInt *const noCellsToSendByDomain, const MInt *const sortedCellId, const MLong *const offset, const MLong *const globalIdOffsets)
 Balance the grid according to the given cell send/recv counts. More...
 
MBool updatePartitionCells (MInt offspringThreshold, MFloat workloadThreshold)
 Determine new partition cells (i.e. in/decrease the partition level shifts) and change the grid accordingly such that these partition cells are used for load balancing. More...
 
MLong generateHilbertIndex (const MInt cellId, const MInt targetMinLevel)
 
void saveGrid (const MChar *, const std::vector< std::vector< MInt > > &, const std::vector< std::vector< MInt > > &, const std::vector< std::vector< MInt > > &, const std::vector< MInt > &, const std::vector< std::vector< MInt > > &, MInt *recalcIdTree=nullptr)
 
void saveGrid (const MChar *, MInt *recalcIdTree)
 
void savePartitionFile ()
 Save current grid partitioning to file. More...
 
void loadPartitionFile (const MString &partitionFileName, MLong *partitionCellOffsets)
 Load a grid partitioning from a file. More...
 
void savePartitionCellWorkloadsGridFile ()
 Update the partition cell workloads in the grid file. More...
 
void deletePeriodicConnection (const MBool=true)
 Delete the Connection of periodic-Halo-Cells at the bounding box. More...
 
void restorePeriodicConnection ()
 Delete the Connection of periodic-Halo-Cells at the bounding box. More...
 
MInt findNeighborDomainId (const MLong globalId)
 
MInt findNeighborDomainId (const MLong globalId, const MInt noDomains, const MLong *domainOffsets)
 Find domain id containing a given global cell id. More...
 
void createLeafCellMapping (const MInt donorSolverId, const MInt gridCellId, std::vector< MInt > &mappedLeafCells, MBool allChilds=false)
 Identify all leaf cells of one solver which are mapped to a given grid cell. More...
 
MInt globalIdToLocalId (const MLong &globalId, const MBool termIfNotExisting=false)
 Global to local id mapping. More...
 
MInt noDomains () const
 
MInt domainId () const
 Return the domainId (rank) More...
 
void cartesianToCylindric (const MFloat *, MFloat *)
 Transform cartesian cell coordinate to cylindrcal coordinats using the / using the azimuthal periodic center. More...
 
void rotateCartesianCoordinates (MFloat *, MFloat)
 Rotate caresian coordinates by angle. Azimuthal periodic center is used. More...
 
template<MBool t_correct>
MInt findContainingPartitionCell (const MFloat *const coord, const MInt solverId, function< MFloat *(MInt, MFloat *const)> correctCellCoord)
 Find the partition cell containing a given coordinate (if any). If a valid solverId is given it is also checked that the found partition cell belongs to this solver. More...
 
template<MBool t_correct>
MInt findContainingHaloCell (const MFloat *const coord, const MInt solverId, MInt domainId, MBool onlyPartitionCells, function< MFloat *(MInt, MFloat *const)> correctCellCoord)
 
template<MBool t_correct>
MInt findContainingLeafCell (const MFloat *coord, function< MFloat *(MInt, MFloat *const)> correctCellCoord, const MInt solverId)
 returns the local id of the leaf cell (global or for solver) containing some coordinates p More...
 
template<MBool t_correct>
MInt findContainingLeafCell (const MFloat *const coord, const MInt startId, function< MFloat *(MInt, MFloat *const)> correctCellCoord, const MInt solverId, const MBool allowNonLeafHalo)
 returns the local id of the leaf cell (global or for solver) containing some coordinates p based on a given startId NOTE: also cells on the same rank, but far away from the startId are considered! More...
 

Static Public Member Functions

static constexpr MInt nDim_ ()
 

Public Attributes

MBool m_wasAdapted = false
 
MBool m_wasBalanced = false
 
MBool m_wasBalancedAtLeastOnce = false
 
MInt m_noPeriodicCartesianDirs = 0
 
std::array< MInt, 3 > m_periodicCartesianDir {}
 
MFloat m_periodicCartesianLength [3] {}
 
MBool m_azimuthalPer = false
 
std::array< MFloat, 3 > m_azimuthalPerCenter {}
 
std::array< MInt, 2 > m_azimuthalPeriodicDir {}
 
MInt m_azimuthalAxialDir = -1
 
MFloat m_azimuthalAngle = F0
 
azimuthalBbox m_azimuthalBbox
 
MLong m_noCellsGlobal {}
 
MInt m_noInternalCells {}
 
MInt m_noDomains {}
 
MInt m_maxUniformRefinementLevel = -1
 
MInt m_maxRfnmntLvl = -1
 
MInt m_maxLevel = -1
 The max Level of refinement of the solver length. More...
 
MInt m_minLevel = -1
 The min Level of refinement of the solver length. More...
 
MInt m_newMinLevel = -1
 The new min Level which has been increased at the restart! More...
 
MBool m_allowInterfaceRefinement = false
 
MInt m_cutOff = 0
 
MBool m_lowMemAdaptation = true
 
MFloatm_gridCellVolume = nullptr
 
MString m_gridInputFileName = ""
 
MInt m_counter1D {}
 
MInt m_counter2D {}
 
MInt m_counter3D {}
 
MIntm_paths1D = nullptr
 
MInt ** m_paths2D = nullptr
 
MInt ** m_paths3D = nullptr
 
std::array< MInt, 11+(nDim - 2) *32 > m_neighborCode {}
 
std::map< MLong, MIntm_globalToLocalId {}
 Mapping: global cell id -> local cell id. More...
 
MBool m_lbGridChecks
 
MFloat m_coarseRatio = 0.2
 
MBool m_allowCoarsening = true
 
std::set< MIntm_freeIndices
 
std::vector< MIntm_nghbrDomainIndex
 
std::vector< MIntm_azimuthalNghbrDomainIndex
 
MIntm_localPartitionCellLocalIdsRestart = nullptr
 
MLong m_localPartitionCellOffsetsRestart [3] {static_cast<MLong>(-1), static_cast<MLong>(-1), static_cast<MLong>(-1)}
 

Static Public Attributes

static constexpr MInt m_maxNoSensors = 64
 

Private Member Functions

void createGlobalToLocalIdMapping ()
 Create the mapping from global to local cell ids. More...
 
void changeGlobalToLocalIds ()
 Change global child/neighbor/parent cell ids into local cell ids. Requires that m_globalToLocalId contains the current mapping from global to local cell ids (see createGlobalToLocalIdMapping()). More...
 
void descendStoreGlobalId (MInt cellId, MInt &localCnt)
 Recursively descend subtree to reset global id for internal cells. More...
 
void refineCell (const MInt cellId, const MLong *const refineChildIds=nullptr, const MBool mayHaveChildren=false, const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &=std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> >(), const std::bitset< maia::grid::tree::Tree< nDim >::maxNoSolvers()> refineFlag=std::bitset< maia::grid::tree::Tree< nDim >::maxNoSolvers()>(1ul))
 
void removeChilds (const MInt cellId)
 removes the children of the given cell More...
 
template<MBool removeChilds>
void removeCell (const MInt cellId)
 removes the children of the given cell More...
 
MInt deleteCell (const MInt cellId)
 Deletes a cell (without collector fragmentation) and returns new collector size. More...
 
void createPaths ()
 Necessary for extractPointIdsFromGrid function. More...
 
void setLevel ()
 Set minimum und maximum cell levels. More...
 
void updatePartitionCellInformation ()
 Update the partition cell local/global ids and the partition cell global offsets. More...
 
void setGridInputFilename (MBool=false)
 Read grid file name from properties or restart files. More...
 
void loadGridFile (const MInt, const MInt)
 Load grid from disk and setup communication. More...
 
MLong hilbertIndexGeneric (const MFloat *const coords, const MFloat *const center, const MFloat length0, const MInt baseLevel) const
 Return the hilbert index for the given coordinates in 2D/3D. More...
 
MLong hilbertIndexGeneric (const MFloat *const coords) const
 
MLong generateHilbertIndex (const MInt cellId)
 
template<class ITERATOR , typename U >
MInt findIndex (ITERATOR, ITERATOR, const U &)
 Find index in array [first,last) with matching entry 'val'. More...
 
template<typename TA , typename TB , typename TC >
MInt setNeighborDomainIndex (const MInt, std::vector< TA > &, std::vector< TB > &, std::vector< TC > &)
 Find neighbor domain index or create new if not existing. More...
 
template<typename TA , typename TB >
MInt setNeighborDomainIndex (const MInt, std::vector< TA > &, std::vector< TB > &)
 Find neighbor domain index or create new if not existing. More...
 
MInt setAzimuthalNeighborDomainIndex (const MInt, std::vector< std::vector< MInt > > &, std::vector< std::vector< MInt > > &)
 Find azimuthal neighbor domain index or create new if not existing. More...
 
MInt setAzimuthalNeighborDomainIndex (const MInt, std::vector< std::vector< MInt > > &, std::vector< std::vector< MLong > > &)
 Find azimuthal neighbor domain index or create new if not existing. More...
 
template<std::size_t N>
void exchangeSolverBitset (std::bitset< N > *const data, const MBool defaultVal=false)
 
void checkWindowLayer (const MString a)
 Checks variable m_windowLayer_. More...
 
void loadGrid (const MString &fileName)
 Load a grid file writen with saveGridDomainPar. More...
 
void resetCell (const MInt &cellId)
 Reset cell to default values. More...
 
void initGridMap ()
 
void createGridMap (const MString &donorGridFileName, const MString &gridMapFileName)
 Create file that contains mapping from donor to target cell. More...
 
void saveDonorGridPartition (const MString &gridMapFileName, const MString &gridPartitionFileName)
 Create and store donor grid partition for volume-coupled simulations. More...
 
void loadDonorGridPartition (const MLong *const partitionCellsId, const MInt noPartitionCells)
 Return partition cell offsets based on grid partition file. More...
 
void savePartitionFile (const MString &partitionFileNameBase, const MLong partitionCellOffset)
 Save given partitioning to file. More...
 
template<typename CELLTYPE >
void calculateNoOffspringsAndWorkload (Collector< CELLTYPE > *input_cells, MInt input_noCells)
 Caluclate the number of offsprings and the workload for each cell. More...
 
void partitionParallel (const MInt tmpCount, const MLong tmpOffset, const MFloat *const partitionCellsWorkload, const MLong *const partitionCellsGlobalId, const MFloat totalWorkload, MLong *partitionCellOffsets, MLong *globalIdOffsets, MBool computeOnlyPartition=false)
 
void updateHaloCellCollectors ()
 Fill m_nghbrDomains, m_haloCells and m_windowCells with data from temporary buffers. More...
 
void tagActiveWindows (std::vector< MLong > &, MInt)
 Flag m_noHaloLayers layers of halo cells adjacent to internal cells on this domain. More...
 
void tagActiveWindows2_ (std::vector< MLong > &, const MInt)
 NOTE: Actually the most clever way of tagging is to go from highest level to lower levels, but that means quite some work to do! More...
 
void tagActiveWindowsOnLeafLvl3 (const MInt maxLevel, const MBool duringMeshAdaptation, const std::vector< std::function< void(const MInt)> > &=std::vector< std::function< void(const MInt)> >())
 Don't touch this function, because you don't know what you are doing NOTE: Actually the most clever way of tagging is to go from highest level to lower levels (if we want to have the predefined number of halo layers on leaf level), but that means quite some work to do! More...
 
void tagActiveWindowsAtMinLevel (const MInt)
 Actually the most clever way of tagging is to go from highest level to lower levels, but that means quite some work to do! More...
 
MInt getAdjacentGridCells (MInt, MIntScratchSpace &, MInt, MBool diagonalNeighbors=true)
 Retrieves all direct and diagonal neighboring cells of the given cell on the child level if available. More...
 
template<MBool finer, MBool coarser>
MInt getAdjacentGridCells5 (const MInt, MInt *const, const MInt level=-1, const MBool diagonalNeighbors=true)
 
template<MBool finer, MBool coarser>
void getAdjacentGridCells1d5 (std::set< MInt > &, const MInt, const MInt, const MInt dimNext=-1, const MInt dimNextNext=-1, const uint_fast8_t childCodes=(uint_fast8_t)~0)
 
void setupWindowHaloCellConnectivity ()
 Create window and halo cell connectivity between domains. More...
 
void createMinLevelExchangeCells ()
 Create window-halo-connectivity based on hilbertIndex matching for regular and periodic exchange cells. More...
 
void createHigherLevelExchangeCells (const MInt onlyLevel=-1, const MBool duringMeshAdaptation=false, const std::vector< std::function< void(const MInt)> > &=std::vector< std::function< void(const MInt)> >(), const std::vector< std::function< void(const MInt)> > &=std::vector< std::function< void(const MInt)> >(), const MBool forceLeafLvlCorrection=false)
 Iteratively create window and halo cells on levels m_minLevel+1...m_maxLevel, starting from m_minLevel exchange cells. More...
 
void createHigherLevelExchangeCells_old (const MInt onlyLevel=-1, const std::vector< std::function< void(const MInt)> > &=std::vector< std::function< void(const MInt)> >())
 Iteratively create window and halo cells on levels m_minLevel+1...m_maxLevel, starting from m_minLevel exchange cells. More...
 
MInt createAdjacentHaloCell (const MInt, const MInt, const MLong *, std::unordered_multimap< MLong, MInt > &, const MFloat *, MInt *const, std::vector< std::vector< MInt > > &, std::vector< std::vector< MLong > > &)
 Create a new halo cell (candidate) as neighbor of cellId in direction dir and find matching neighbor domain from hilbertIndex. More...
 
MInt createAzimuthalHaloCell (const MInt, const MInt, const MLong *, std::unordered_multimap< MLong, MInt > &, const MFloat *, MInt *const, std::vector< std::vector< MInt > > &, std::vector< std::vector< MLong > > &)
 Create a new azimuthal halo cell as neighbor of cellId in direction dir and find matching neighbor domain from hilbertIndex. More...
 
void meshAdaptation (std::vector< std::vector< MFloat > > &, std::vector< MFloat > &, std::vector< std::bitset< 64 > > &, std::vector< MInt > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt, const MInt)> > &, const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &, const std::vector< std::function< void()> > &)
 
void meshAdaptationLowMem (std::vector< std::vector< MFloat > > &, std::vector< MFloat > &, std::vector< std::bitset< 64 > > &, std::vector< MInt > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt, const MInt)> > &, const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &, const std::vector< std::function< void()> > &)
 Performs mesh adaptation and continuously updates the window/halo cells. More...
 
void meshAdaptationDefault (std::vector< std::vector< MFloat > > &, std::vector< MFloat > &, std::vector< std::bitset< 64 > > &, std::vector< MInt > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt, const MInt)> > &, const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &, const std::vector< std::function< void()> > &)
 Performs mesh adaptation and continuously updates the window/halo cells. More...
 
void compactCells (const std::vector< std::function< void(const MInt, const MInt)> > &=std::vector< std::function< void(const MInt, const MInt)> >())
 Removes all holes in the cell collector and moves halo cells to the back of the collector. More...
 
void swapCells (const MInt cellId, const MInt otherId)
 swap two cells; the window/halo cell arrays have to be update elsewhere for performance reasons More...
 
MBool refineCheck (const MInt cellId, const MInt solverId, const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &cellOutsideSolver)
 checks if the given cell may be refined More...
 
MBool coarsenCheck (const MInt cellId, const MInt solverId)
 checks if the given cell's children may be removed More...
 
void exchangeProperties ()
 Exchange properties of window/halo cells. More...
 
void setChildSolverFlag (const MInt cellId, const MInt solver, const std::function< MInt(const MFloat *, const MInt, const MInt)> &cellOutsideSolver)
 
MBool isMpiRoot () const
 Return true if this is domain zero (a.k.a. as the root domain) More...
 

Private Attributes

MFloat m_centerOfGravity [3] {}
 coordinates of the root cell More...
 
MFloat m_boundingBox [6] {}
 
MFloat m_boundingBoxBackup [6] {}
 
MFloat m_localBoundingBox [6] {}
 Local bounding box for fast checking if a point lies outside the local domain. More...
 
MBool m_localBoundingBoxInit = false
 
MFloat m_targetGridBoundingBox [6] {}
 Multisolver grid information. More...
 
MFloat m_targetGridCenterOfGravity [3] {}
 
MFloat m_targetGridLengthLevel0 = -1
 
MInt m_targetGridMinLevel = -1
 
MBool m_hasMultiSolverBoundingBox = false
 
MFloat m_lengthLevel0 {}
 The initial length of the solver. More...
 
MInt m_maxNoCells = -1
 
MInt m_haloMode = -1
 
MInt m_noHaloLayers = -1
 
MIntm_noSolverHaloLayers = nullptr
 
std::vector< MIntm_nghbrDomains
 
std::vector< MIntm_azimuthalNghbrDomains
 
std::vector< std::tuple< MInt, MInt, MInt > > m_neighborBackup
 
const MInt m_revDir [6] = {1, 0, 3, 2, 5, 4}
 
std::vector< std::vector< MInt > > m_windowCells
 
std::vector< std::vector< MInt > > m_haloCells
 
std::vector< std::unordered_map< MInt, M32X4bit< true > > > m_windowLayer_
 
std::vector< std::vector< MInt > > m_azimuthalHigherLevelConnectivity
 
std::vector< std::vector< MInt > > m_azimuthalWindowCells
 
std::vector< std::vector< MInt > > m_azimuthalHaloCells
 
std::vector< MIntm_azimuthalUnmappedHaloCells
 
std::vector< MIntm_azimuthalUnmappedHaloDomains
 
std::vector< MIntm_gridBndryCells
 
MInt m_partitionCellOffspringThreshold
 
MFloat m_partitionCellWorkloadThreshold
 
MLongm_domainOffsets = nullptr
 
MInt m_noPartitionCells {}
 
MLong m_noPartitionCellsGlobal {}
 
MInt m_noHaloPartitionLevelAncestors {}
 
MLong m_localPartitionCellOffsets [3] {static_cast<MLong>(-1), static_cast<MLong>(-1), static_cast<MLong>(-1)}
 
MLongm_localPartitionCellGlobalIds = nullptr
 
MIntm_localPartitionCellLocalIds = nullptr
 
MBool m_updatePartitionCellsOnRestart = true
 
MBool m_updatingPartitionCells = false
 
MBool m_updatedPartitionCells = false
 
MInt m_noPartitionLevelAncestors {}
 Local number of partition level ancestors on this domain (without halos) More...
 
MLong m_noPartitionLevelAncestorsGlobal {}
 
MLong m_32BitOffset = 0
 
MBool m_restart
 
MInt m_noMinLevelCellsGlobal {}
 
std::vector< MIntm_minLevelCells {}
 
MInt m_maxPartitionLevelShift {}
 
MBoolm_checkRefinementHoles = nullptr
 
MBoolm_diagSmoothing = nullptr
 
MInt m_noIdenticalSolvers = 0
 
MIntm_identicalSolvers = nullptr
 
MIntm_identicalSolverMaxLvl = nullptr
 
MIntm_identicalSolverLvlJumps = nullptr
 
std::vector< MIntm_partitionLevelAncestorIds {}
 Partition level shift. More...
 
std::vector< MLongm_partitionLevelAncestorChildIds {}
 
std::vector< MIntm_partitionLevelAncestorNghbrDomains {}
 
std::vector< std::vector< MInt > > m_partitionLevelAncestorHaloCells {}
 
std::vector< std::vector< MInt > > m_partitionLevelAncestorWindowCells {}
 
MInt ** m_neighborList = nullptr
 
MFloat m_reductionFactor {}
 
MInt m_decisiveDirection {}
 
MString m_outputDir = ""
 
MString m_restartDir = ""
 
MBool m_loadGridPartition = false
 
MBool m_loadPartition = false
 
MBool m_partitionParallelSplit = false
 
MBool m_addSolverToGrid = false
 
MInt m_referenceSolver = -1
 
const MPI_Comm m_mpiComm
 
Tree m_tree
 Store the tree. More...
 
const MBool m_paraViewPlugin
 
const MInt m_maxNoNghbrs
 
MBool m_zonal
 
MInt m_domainId {}
 

Static Private Attributes

static constexpr const auto WINDOWLAYER_MAX = decltype(m_windowLayer_)::value_type::mapped_type::MAX
 
static constexpr MInt m_noDirs = 2 * nDim
 
static constexpr MInt m_maxNoChilds = IPOW2(nDim)
 

Friends

template<MInt nDim_, class SysEqn >
class FvCartesianSolverXD
 
template<MInt nDim_>
class LsCartesianSolver
 
template<MInt nDim_, class SysEqn >
class FvBndryCnd2D
 
template<MInt nDim_, class SysEqn >
class FvBndryCnd3D
 
template<MInt nDim_, class SysEqn >
class FvMbCartesianSolverXD
 
template<MInt nDim_>
class LbSolver
 
template<MInt nDim_, class SysEqn >
class DgCartesianSolver
 
class maia::grid::Controller< nDim >
 
class maia::grid::IO< CartesianGrid< nDim > >
 
template<MInt nDim_, class SysEqn >
class FvCartesianSolverXD
 

Detailed Description

template<MInt nDim>
class CartesianGrid< nDim >

Template class for the operations and data structures of the grid

Definition at line 47 of file cartesiangrid.h.

Member Typedef Documentation

◆ Cell

template<MInt nDim>
using CartesianGrid< nDim >::Cell = typename Tree::Cell

Definition at line 80 of file cartesiangrid.h.

◆ MInt_dyn_array

template<MInt nDim>
using CartesianGrid< nDim >::MInt_dyn_array = MInt*

Definition at line 76 of file cartesiangrid.h.

◆ Tree

template<MInt nDim>
using CartesianGrid< nDim >::Tree = maia::grid::tree::Tree<nDim>

Definition at line 77 of file cartesiangrid.h.

Constructor & Destructor Documentation

◆ CartesianGrid()

template<MInt nDim>
CartesianGrid< nDim >::CartesianGrid ( MInt  maxCells,
const MFloat *const  bBox,
const MPI_Comm  comm,
const MString fileName = "" 
)

◆ ~CartesianGrid()

template<MInt nDim>
CartesianGrid< nDim >::~CartesianGrid

Destructor

Definition at line 699 of file cartesiangrid.cpp.

699 {
700 TRACE();
701
706}
MBool mDeallocate(T *&a)
deallocates the memory previously allocated for element 'a'
Definition: alloc.h:544
MInt ** m_neighborList
MInt ** m_paths2D
MInt ** m_paths3D

Member Function Documentation

◆ a_childId() [1/3]

template<MInt nDim>
MLong & CartesianGrid< nDim >::a_childId ( const MInt  cellId,
const MInt  pos 
)
inline

Definition at line 108 of file cartesiangrid.h.

108{ return m_tree.child(cellId, pos); }
Tree m_tree
Store the tree.
MLong & child(const MInt id, const MInt pos)
Accessor for child node.

◆ a_childId() [2/3]

template<MInt nDim>
MLong CartesianGrid< nDim >::a_childId ( const MInt  cellId,
const MInt  pos 
) const
inline

Definition at line 111 of file cartesiangrid.h.

111{ return m_tree.child(cellId, pos); }

◆ a_childId() [3/3]

template<MInt nDim>
MLong CartesianGrid< nDim >::a_childId ( const MInt  cellId,
const MInt  pos,
const MInt  solverId 
) const
inline

Definition at line 114 of file cartesiangrid.h.

114 {
115 return (m_tree.child(cellId, pos) > -1 && m_tree.solver(m_tree.child(cellId, pos), solverId))
116 ? m_tree.child(cellId, pos)
117 : -1;
118 }
SolverBitsetType::reference solver(const MInt id, const MInt solverId)
Accessor for solver usage.

◆ a_coordinate() [1/3]

template<MInt nDim>
template<class U >
MFloat CartesianGrid< nDim >::a_coordinate ( Collector< U > *  NotUsedcells_,
const MInt  cellId,
const MInt  dir 
) const
inline

Definition at line 198 of file cartesiangrid.h.

198 {
199 return a_coordinate(cellId, dir);
200 }
MFloat & a_coordinate(const MInt cellId, const MInt dir)
Returns the coordinate of the cell cellId for direction dir.

◆ a_coordinate() [2/3]

template<MInt nDim>
MFloat & CartesianGrid< nDim >::a_coordinate ( const MInt  cellId,
const MInt  dir 
)
inline

Definition at line 191 of file cartesiangrid.h.

191{ return m_tree.coordinate(cellId, dir); }
MFloat & coordinate(const MInt id, const MInt dim)
Accessor for coordinates.

◆ a_coordinate() [3/3]

template<MInt nDim>
MFloat CartesianGrid< nDim >::a_coordinate ( const MInt  cellId,
const MInt  dir 
) const
inline

Definition at line 194 of file cartesiangrid.h.

194{ return m_tree.coordinate(cellId, dir); }

◆ a_copyProperties()

template<MInt nDim>
void CartesianGrid< nDim >::a_copyProperties ( const MInt  fromCellId,
const MInt  toCellId 
)
inline

Definition at line 232 of file cartesiangrid.h.

232 {
233 m_tree.properties(toCellId) = m_tree.properties(fromCellId);
234 }
PropertyBitsetType & properties(const MInt id)
Accessor for properties.

◆ a_globalId() [1/2]

template<MInt nDim>
MLong & CartesianGrid< nDim >::a_globalId ( const MInt  cellId)
inline

Definition at line 141 of file cartesiangrid.h.

141{ return m_tree.globalId(cellId); }
MLong & globalId(const MInt id)
Accessor for global id.

◆ a_globalId() [2/2]

template<MInt nDim>
MLong CartesianGrid< nDim >::a_globalId ( const MInt  cellId) const
inline

Definition at line 144 of file cartesiangrid.h.

144{ return m_tree.globalId(cellId); }

◆ a_hasChild() [1/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::a_hasChild ( const MInt  cellId,
const MInt  pos 
) const
inline

Definition at line 162 of file cartesiangrid.h.

162{ return m_tree.hasChild(cellId, pos); }
MBool hasChild(const MInt id, const MInt pos) const
Return whether node has child at given position.

◆ a_hasChild() [2/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::a_hasChild ( const MInt  cellId,
const MInt  pos,
const MInt  solverId 
) const
inline

Definition at line 165 of file cartesiangrid.h.

165 {
166 return m_tree.hasChild(cellId, pos) && m_tree.solver(m_tree.child(cellId, pos), solverId);
167 }

◆ a_hasChildren() [1/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::a_hasChildren ( const MInt  cellId) const
inline

Definition at line 156 of file cartesiangrid.h.

156{ return m_tree.hasChildren(cellId); }
MBool hasChildren(const MInt id) const
Return whether node has any children.

◆ a_hasChildren() [2/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::a_hasChildren ( const MInt  cellId,
const MInt  solverId 
) const
inline

Definition at line 159 of file cartesiangrid.h.

159{ return m_tree.hasChildren(cellId, solverId); }

◆ a_hasNeighbor() [1/2]

template<MInt nDim>
MBool CartesianGrid< nDim >::a_hasNeighbor ( const MInt  cellId,
const MInt  dir 
) const
inline

Definition at line 215 of file cartesiangrid.h.

215{ return m_tree.hasNeighbor(cellId, dir); }
MBool hasNeighbor(const MInt id, const MInt dir) const
Return whether node has same-level neighbor in given direction.

◆ a_hasNeighbor() [2/2]

template<MInt nDim>
MBool CartesianGrid< nDim >::a_hasNeighbor ( const MInt  cellId,
const MInt  dir,
const MInt  solverId 
) const
inline

Definition at line 218 of file cartesiangrid.h.

218 {
219 if(treeb().noSolvers() == 1 && m_tree.hasNeighbor(cellId, dir)
220 && !m_tree.solver(m_tree.neighbor(cellId, dir), solverId)) {
221 std::cerr << "mis " << cellId << " " << dir << " " << m_tree.neighbor(cellId, dir) << " " << solverId << " "
222 << m_tree.solver(m_tree.neighbor(cellId, dir), solverId) << std::endl;
223 ASSERT(false, "");
224 }
225 return m_tree.hasNeighbor(cellId, dir) && m_tree.solver(m_tree.neighbor(cellId, dir), solverId);
226 }
Tree & treeb()
Full access to tree (for now)
MLong & neighbor(const MInt id, const MInt dir)
Accessor for neighbor node.
MInt noSolvers
Definition: maiatypes.h:73
void const MInt cellId
Definition: collector.h:239

◆ a_hasParent() [1/2]

template<MInt nDim>
MBool CartesianGrid< nDim >::a_hasParent ( const MInt  cellId) const
inline

Definition at line 100 of file cartesiangrid.h.

100{ return m_tree.hasParent(cellId); }
MBool hasParent(const MInt id) const
Return whether node has parent.

◆ a_hasParent() [2/2]

template<MInt nDim>
MBool CartesianGrid< nDim >::a_hasParent ( const MInt  cellId,
const MInt  solverId 
) const
inline

Definition at line 103 of file cartesiangrid.h.

103 {
104 return m_tree.hasParent(cellId) && m_tree.solver(m_tree.parent(cellId), solverId);
105 }
MLong & parent(const MInt id)
Accessor for parent node.

◆ a_hasProperty() [1/2]

template<MInt nDim>
maia::grid::cell::BitsetType::reference CartesianGrid< nDim >::a_hasProperty ( const MInt  cellId,
const Cell  p 
)
inline

Definition at line 238 of file cartesiangrid.h.

238 {
239 return m_tree.hasProperty(cellId, p);
240 }
PropertyBitsetType::reference hasProperty(const MInt id, const Cell p)
Accessor for properties.

◆ a_hasProperty() [2/2]

template<MInt nDim>
MBool CartesianGrid< nDim >::a_hasProperty ( const MInt  cellId,
const Cell  p 
) const
inline

Definition at line 243 of file cartesiangrid.h.

243{ return m_tree.hasProperty(cellId, p); }

◆ a_isHalo()

template<MInt nDim>
MBool CartesianGrid< nDim >::a_isHalo ( const MInt  cellId) const
inline

Definition at line 248 of file cartesiangrid.h.

248{ return m_tree.hasProperty(cellId, Cell::IsHalo); }

◆ a_isLeafCell() [1/3]

template<MInt nDim>
MBool CartesianGrid< nDim >::a_isLeafCell ( const MInt  cellId) const
inline

Definition at line 204 of file cartesiangrid.h.

204{ return m_tree.isLeafCell(cellId); }
MBool isLeafCell(const MInt id) const
Accessor for isLeafCell usage (const version).

◆ a_isLeafCell() [2/3]

template<MInt nDim>
maia::grid::tree::SolverBitsetType::reference CartesianGrid< nDim >::a_isLeafCell ( const MInt  cellId,
const MInt  solverId 
)
inline

Definition at line 207 of file cartesiangrid.h.

207 {
208 return m_tree.isLeafCell(cellId, solverId);
209 }

◆ a_isLeafCell() [3/3]

template<MInt nDim>
MBool CartesianGrid< nDim >::a_isLeafCell ( const MInt  cellId,
const MInt  solverId 
) const
inline

Definition at line 212 of file cartesiangrid.h.

212{ return m_tree.isLeafCell(cellId, solverId); }

◆ a_isToDelete() [1/2]

template<MInt nDim>
maia::grid::cell::BitsetType::reference CartesianGrid< nDim >::a_isToDelete ( const MInt  cellId)
inline

Definition at line 170 of file cartesiangrid.h.

170 {
171 return m_tree.hasProperty(cellId, Cell::IsToDelete);
172 }

◆ a_isToDelete() [2/2]

template<MInt nDim>
MBool CartesianGrid< nDim >::a_isToDelete ( const MInt  cellId) const
inline

Definition at line 175 of file cartesiangrid.h.

175{ return m_tree.hasProperty(cellId, Cell::IsToDelete); }

◆ a_level() [1/2]

template<MInt nDim>
MInt & CartesianGrid< nDim >::a_level ( const MInt  cellId)
inline

Definition at line 123 of file cartesiangrid.h.

123{ return m_tree.level(cellId); }
MInt & level(const MInt id)
Accessor for level.

◆ a_level() [2/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::a_level ( const MInt  cellId) const
inline

Definition at line 126 of file cartesiangrid.h.

126{ return m_tree.level(cellId); }

◆ a_neighborId() [1/3]

template<MInt nDim>
MLong & CartesianGrid< nDim >::a_neighborId ( const MInt  cellId,
const MInt  dir 
)
inline

Definition at line 178 of file cartesiangrid.h.

178{ return m_tree.neighbor(cellId, dir); }

◆ a_neighborId() [2/3]

template<MInt nDim>
MLong CartesianGrid< nDim >::a_neighborId ( const MInt  cellId,
const MInt  dir 
) const
inline

Definition at line 181 of file cartesiangrid.h.

181{ return m_tree.neighbor(cellId, dir); }

◆ a_neighborId() [3/3]

template<MInt nDim>
MLong CartesianGrid< nDim >::a_neighborId ( const MInt  cellId,
const MInt  dir,
const MInt  solverId 
) const
inline

Definition at line 184 of file cartesiangrid.h.

184 {
185 return (m_tree.neighbor(cellId, dir) > -1 && m_tree.solver(m_tree.neighbor(cellId, dir), solverId))
186 ? m_tree.neighbor(cellId, dir)
187 : -1;
188 }

◆ a_noChildren()

template<MInt nDim>
MInt CartesianGrid< nDim >::a_noChildren ( const MInt  cellId) const
inline

Definition at line 153 of file cartesiangrid.h.

153{ return m_tree.noChildren(cellId); }
MInt noChildren(const MInt id) const
Return number of children of given node.

◆ a_noOffsprings() [1/2]

template<MInt nDim>
MInt & CartesianGrid< nDim >::a_noOffsprings ( const MInt  cellId)
inline

Definition at line 138 of file cartesiangrid.h.

138{ return m_tree.noOffsprings(cellId); }
MInt & noOffsprings(const MInt id)
Accessor for noOffsprings.

◆ a_noOffsprings() [2/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::a_noOffsprings ( const MInt  cellId) const
inline

Definition at line 135 of file cartesiangrid.h.

135{ return m_tree.noOffsprings(cellId); }

◆ a_parentId() [1/3]

template<MInt nDim>
MLong & CartesianGrid< nDim >::a_parentId ( const MInt  cellId)
inline

Definition at line 89 of file cartesiangrid.h.

89{ return m_tree.parent(cellId); }

◆ a_parentId() [2/3]

template<MInt nDim>
MLong CartesianGrid< nDim >::a_parentId ( const MInt  cellId) const
inline

Definition at line 92 of file cartesiangrid.h.

92{ return m_tree.parent(cellId); }

◆ a_parentId() [3/3]

template<MInt nDim>
MLong CartesianGrid< nDim >::a_parentId ( const MInt  cellId,
const MInt  solverId 
) const
inline

Definition at line 95 of file cartesiangrid.h.

95 {
96 return (m_tree.parent(cellId) > -1 && m_tree.solver(m_tree.parent(cellId), solverId)) ? m_tree.parent(cellId) : -1;
97 }

◆ a_propertiesToString()

template<MInt nDim>
MString CartesianGrid< nDim >::a_propertiesToString ( const MInt  cellId)
inline

Definition at line 245 of file cartesiangrid.h.

245{ return m_tree.propertiesToString(cellId); }
MString propertiesToString(const MInt id) const
Convert properties to string.

◆ a_resetProperties()

template<MInt nDim>
void CartesianGrid< nDim >::a_resetProperties ( const MInt  cellId)
inline

Definition at line 229 of file cartesiangrid.h.

229{ m_tree.resetProperties(cellId); }
void resetProperties(const MInt id)
Reset all properties.

◆ a_solver()

template<MInt nDim>
maia::grid::tree::SolverBitsetType::reference CartesianGrid< nDim >::a_solver ( const MInt  cellId,
const MInt  solverId 
)
inline

Definition at line 251 of file cartesiangrid.h.

251 {
252 return m_tree.solver(cellId, solverId);
253 }

◆ a_weight() [1/2]

template<MInt nDim>
MFloat & CartesianGrid< nDim >::a_weight ( const MInt  cellId)
inline

Definition at line 147 of file cartesiangrid.h.

147{ return m_tree.weight(cellId); }
MFloat & weight(const MInt id)
Accessor for weight.

◆ a_weight() [2/2]

template<MInt nDim>
MFloat CartesianGrid< nDim >::a_weight ( const MInt  cellId) const
inline

Definition at line 150 of file cartesiangrid.h.

150{ return m_tree.weight(cellId); }

◆ a_workload() [1/2]

template<MInt nDim>
MFloat & CartesianGrid< nDim >::a_workload ( const MInt  cellId)
inline

Definition at line 132 of file cartesiangrid.h.

132{ return m_tree.workload(cellId); }
MFloat & workload(const MInt id)
Accessor for workload.

◆ a_workload() [2/2]

template<MInt nDim>
MFloat CartesianGrid< nDim >::a_workload ( const MInt  cellId) const
inline

Definition at line 129 of file cartesiangrid.h.

129{ return m_tree.workload(cellId); }

◆ addSolverToGrid()

template<MInt nDim>
MBool CartesianGrid< nDim >::addSolverToGrid ( )
inline

Definition at line 258 of file cartesiangrid.h.

258{ return m_addSolverToGrid; }
MBool m_addSolverToGrid

◆ allowInterfaceRefinement()

template<MInt nDim>
constexpr MBool CartesianGrid< nDim >::allowInterfaceRefinement ( ) const
inlineconstexpr

Definition at line 579 of file cartesiangrid.h.

MBool m_allowInterfaceRefinement

◆ ancestorPartitionCellId()

template<MInt nDim>
MInt CartesianGrid< nDim >::ancestorPartitionCellId ( const MInt  cellId) const
inline

Definition at line 10874 of file cartesiangrid.cpp.

10874 {
10875 TERMM(1, "function not used anywhere, check this code!");
10876
10877 if(a_hasProperty(cellId, Cell::IsPartitionCell)) {
10878 return cellId;
10879 }
10880
10881 MInt parentId = a_parentId(cellId);
10882 while(!a_hasProperty(parentId, Cell::IsPartitionCell)) {
10883 parentId = a_parentId(parentId);
10884 }
10885 return parentId;
10886}
maia::grid::cell::BitsetType::reference a_hasProperty(const MInt cellId, const Cell p)
Returns property p of the cell cellId.
MLong & a_parentId(const MInt cellId)
Returns the parent of the cell cellId.
Definition: cartesiangrid.h:89
int32_t MInt
Definition: maiatypes.h:62

◆ azimuthalHaloCell()

template<MInt nDim>
MInt CartesianGrid< nDim >::azimuthalHaloCell ( const MInt  domainId,
const MInt  cellId 
) const
inline

Definition at line 512 of file cartesiangrid.h.

512 {
514 }
std::vector< std::vector< MInt > > m_azimuthalHaloCells
MInt domainId() const
Return the domainId (rank)

◆ azimuthalHaloCells()

template<MInt nDim>
const std::vector< std::vector< MInt > > & CartesianGrid< nDim >::azimuthalHaloCells ( ) const
inline

Definition at line 517 of file cartesiangrid.h.

517{ return m_azimuthalHaloCells; };

◆ azimuthalNeighborDomain()

template<MInt nDim>
const MInt & CartesianGrid< nDim >::azimuthalNeighborDomain ( const MInt  id) const
inline

Definition at line 503 of file cartesiangrid.h.

503{ return m_azimuthalNghbrDomains[id]; }
std::vector< MInt > m_azimuthalNghbrDomains
MInt id
Definition: maiatypes.h:71

◆ azimuthalNeighborDomains()

template<MInt nDim>
const std::vector< MInt > & CartesianGrid< nDim >::azimuthalNeighborDomains ( ) const
inline

Definition at line 506 of file cartesiangrid.h.

506{ return m_azimuthalNghbrDomains; }

◆ azimuthalUnmappedHaloCell()

template<MInt nDim>
MInt CartesianGrid< nDim >::azimuthalUnmappedHaloCell ( const MInt  cellId) const
inline

Definition at line 523 of file cartesiangrid.h.

std::vector< MInt > m_azimuthalUnmappedHaloCells

◆ azimuthalUnmappedHaloDomain()

template<MInt nDim>
MInt CartesianGrid< nDim >::azimuthalUnmappedHaloDomain ( const MInt  cellId) const
inline

Definition at line 526 of file cartesiangrid.h.

std::vector< MInt > m_azimuthalUnmappedHaloDomains

◆ azimuthalWindowCell()

template<MInt nDim>
MInt CartesianGrid< nDim >::azimuthalWindowCell ( const MInt  domainId,
const MInt  cellId 
) const
inline

Definition at line 532 of file cartesiangrid.h.

532 {
534 }
std::vector< std::vector< MInt > > m_azimuthalWindowCells

◆ azimuthalWindowCells()

template<MInt nDim>
const std::vector< std::vector< MInt > > & CartesianGrid< nDim >::azimuthalWindowCells ( ) const
inline

Definition at line 537 of file cartesiangrid.h.

537{ return m_azimuthalWindowCells; };

◆ balance()

template<MInt nDim>
void CartesianGrid< nDim >::balance ( const MInt *const  noCellsToReceiveByDomain,
const MInt *const  noCellsToSendByDomain,
const MInt *const  sortedCellId,
const MLong *const  partitionCellOffsets,
const MLong *const  globalIdOffsets 
)
Author
Jerry Grimmen, Lennart Schneiders, Ansgar Niemoeller

Definition at line 10348 of file cartesiangrid.cpp.

10352 {
10353 TRACE();
10354
10355 const MInt noCells = m_tree.size();
10356 const MInt receiveSize = noCellsToReceiveByDomain[noDomains()];
10357
10358 // Note: cellInfo needs to be communicated since it cannot be fully reconstructed from the
10359 // communicated data but it is required to communicate the partition level ancestor data and
10360 // setup the missing subtrees of the grid
10361 ScratchSpace<MUchar> cellInfo(receiveSize, AT_, "cellInfo");
10362 {
10363 // Temporary buffers
10364 ScratchSpace<MUint> cellInfoSend(noCells, AT_, "cellInfoSend");
10365 ScratchSpace<MUint> cellInfoRecv(receiveSize, AT_, "cellInfoRecv");
10366
10367 // TODO labels:GRID,DLB since the cell info needs to be communicated maybe some of the other grid information is
10368 // not required anymore if the tree is rebuild with the cell info?
10369 for(MInt i = 0; i < noCells; i++) {
10370 // TODO labels:GRID,DLB make cellInfo computation a function that can be reused?
10371 const MUint noChilds = (MUint)a_noChildren(i);
10372 const MUint isMinLevel = (a_level(i) == m_minLevel);
10373 const MInt parent = m_globalToLocalId[a_parentId(i)];
10374 MUint position = 0;
10375 if(parent > -1) {
10376 for(MUint j = 0; j < (unsigned)m_maxNoChilds; j++) {
10377 if(a_childId(parent, j) == a_globalId(i)) {
10378 position = j;
10379 }
10380 }
10381 }
10382 const MUint tmpBit = noChilds | (position << 4) | (isMinLevel << 7);
10383 cellInfoSend[i] = tmpBit;
10384 }
10385
10386 // Redistribute cell info
10387 maia::mpi::communicateData(&cellInfoSend[0], noCells, sortedCellId, noDomains(), domainId(), mpiComm(),
10388 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &cellInfoRecv[0]);
10389
10390 for(MInt i = 0; i < receiveSize; i++) {
10391 // Convert cell info
10392 cellInfo[i] = static_cast<MUchar>(cellInfoRecv[i]);
10393 }
10394 }
10395
10396
10397 // ScratchSpaces to hold cell datas
10398 MLongScratchSpace parentId(receiveSize, FUN_, "parentId");
10399 MLongScratchSpace childIds(receiveSize, IPOW2(nDim), FUN_, "childIds");
10400 MLongScratchSpace nghbrIds(receiveSize, m_noDirs, FUN_, "nghbrIds");
10401 MLongScratchSpace globalId(receiveSize, FUN_, "globalId");
10402 MIntScratchSpace level(receiveSize, FUN_, "level");
10403
10404 MFloatScratchSpace coordinates(receiveSize, nDim, FUN_, "coordinates");
10405 MFloatScratchSpace weight(receiveSize, FUN_, "weight");
10406
10407 ScratchSpace<maia::grid::tree::SolverBitsetType> solver(receiveSize, FUN_, "solver");
10408 ScratchSpace<maia::grid::tree::PropertyBitsetType> properties(receiveSize, AT_, "properties");
10409
10410 // Reset ScratchSpaces
10411 parentId.fill(-1);
10412 childIds.fill(-1);
10413 nghbrIds.fill(-1);
10414 globalId.fill(-1);
10415 level.fill(-1);
10416
10417 coordinates.fill(-1.0);
10418 weight.fill(1.0);
10419
10421 properties.fill(maia::grid::tree::PropertyBitsetType());
10422
10423 // Communicate Cell Data
10424 maia::mpi::communicateData(&a_parentId(0), noCells, sortedCellId, noDomains(), domainId(), mpiComm(),
10425 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &parentId[0]);
10426 maia::mpi::communicateData(&a_childId(0, 0), noCells, sortedCellId, noDomains(), domainId(), mpiComm(),
10427 noCellsToSendByDomain, noCellsToReceiveByDomain, IPOW2(nDim), &childIds[0]);
10428 maia::mpi::communicateData(&a_neighborId(0, 0), noCells, sortedCellId, noDomains(), domainId(), mpiComm(),
10429 noCellsToSendByDomain, noCellsToReceiveByDomain, m_noDirs, &nghbrIds[0]);
10430 maia::mpi::communicateData(&a_level(0), noCells, sortedCellId, noDomains(), domainId(), mpiComm(),
10431 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &level[0]);
10432 maia::mpi::communicateData(&a_globalId(0), noCells, sortedCellId, noDomains(), domainId(), mpiComm(),
10433 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &globalId[0]);
10434 maia::mpi::communicateData(&a_coordinate(0, 0), noCells, sortedCellId, noDomains(), domainId(), mpiComm(),
10435 noCellsToSendByDomain, noCellsToReceiveByDomain, nDim, &coordinates[0]);
10436 maia::mpi::communicateData(&a_weight(0), noCells, sortedCellId, noDomains(), domainId(), mpiComm(),
10437 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &weight[0]);
10438 maia::mpi::communicateBitsetData(&m_tree.solverBits(0), noCells, sortedCellId, noDomains(), domainId(), mpiComm(),
10439 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &solver[0]);
10440
10441 maia::mpi::communicateBitsetData(&m_tree.properties(0), noCells, sortedCellId, noDomains(), domainId(), mpiComm(),
10442 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &properties[0]);
10443
10444 std::map<MLong, MInt>().swap(m_globalToLocalId);
10445
10446 // Reset tree
10447 m_tree.clear();
10448
10449 // Storage for min-level cell information
10450 vector<MInt> localMinLevelCells(0);
10451 vector<MLong> minLevelCellsTreeId(0);
10452 ScratchSpace<MInt> localMinLevelId(receiveSize, AT_, "localMinLevelId");
10453 localMinLevelId.fill(-1);
10454
10455 vector<MLong> partitionCells(0);
10456
10457 // Iterate over all received cells and add each cell individually (cells are sorted by global id).
10458 for(MInt i = 0; i < receiveSize; i++) {
10459 // Determine cell id and append to collector
10460 const MInt cellId = m_tree.size();
10461 if(globalIdOffsets[domainId()] + (MLong)cellId != globalId(i)) {
10462 TERMM(1,
10463 "Global id mismatch." + to_string(m_domainOffsets[domainId()] + (MLong)cellId) + " "
10464 + to_string(globalId(i)));
10465 }
10466 m_tree.append();
10467
10468 // Set tree information
10469 a_parentId(cellId) = parentId(i);
10470 for(MInt j = 0; j < IPOW2(nDim); j++) {
10471 a_childId(cellId, j) = childIds(i, j);
10472 }
10473 for(MInt j = 0; j < m_noDirs; j++) {
10474 a_neighborId(cellId, j) = nghbrIds(i, j);
10475 }
10476 a_globalId(cellId) = globalId(i);
10477 a_level(cellId) = level(i);
10478 for(MInt j = 0; j < nDim; j++) {
10479 a_coordinate(cellId, j) = coordinates(i, j);
10480 }
10481 a_weight(cellId) = weight(i);
10482 m_tree.solverBits(cellId) = solver(i);
10483
10484 // Reset offsprings/workload and rebuild list of min cells
10485 a_noOffsprings(cellId) = 0;
10486 a_workload(cellId) = F0;
10487
10488 // Store min-level cell information
10489 if(a_level(cellId) == m_minLevel) {
10490 localMinLevelId[i] = (MInt)localMinLevelCells.size();
10491 localMinLevelCells.push_back(i);
10492
10493 MLong treeId = -1;
10494 maia::grid::hilbert::coordinatesToTreeId<nDim>(treeId, &a_coordinate(cellId, 0), (MLong)m_targetGridMinLevel,
10496 minLevelCellsTreeId.push_back(treeId);
10497 }
10498
10499 // Set partition cell and partition level ancestor properties
10500 const maia::grid::tree::PropertyBitsetType cellProp = properties(i);
10501 const MBool isPartitionCell = cellProp[maia::grid::cell::p(Cell::IsPartitionCell)];
10502 const MBool isPartLvlAncestor = cellProp[maia::grid::cell::p(Cell::IsPartLvlAncestor)];
10503 m_tree.resetProperties(cellId);
10504 a_hasProperty(cellId, Cell::IsPartitionCell) = isPartitionCell;
10505 a_hasProperty(cellId, Cell::IsPartLvlAncestor) = isPartLvlAncestor;
10506
10507 // Store global ids of partition cells
10508 if(isPartitionCell) {
10509 partitionCells.push_back(globalId(i));
10510 }
10511 }
10513
10514 m_log << "Partition level shift: level diff of first cell is " << a_level(0) - m_minLevel << std::endl;
10515#ifndef NDEBUG
10516 std::cerr << domainId() << " Partition level shift: level diff of first cell is " << a_level(0) - m_minLevel
10517 << std::endl;
10518#endif
10519
10520 std::vector<MInt>().swap(m_minLevelCells);
10521
10522 // Set new global domain offsets
10523 std::copy_n(&globalIdOffsets[0], noDomains() + 1, &m_domainOffsets[0]);
10524
10525 m_localPartitionCellOffsets[0] = partitionCellOffsets[domainId()];
10526 m_localPartitionCellOffsets[1] = partitionCellOffsets[domainId() + 1];
10528 m_noPartitionCells = partitionCellOffsets[domainId() + 1] - partitionCellOffsets[domainId()];
10529
10530 const MLong noCellsCheck = globalIdOffsets[domainId() + 1] - globalIdOffsets[domainId()];
10531 if(noCellsCheck != m_noInternalCells) {
10532 TERMM(1, "Wrong number of internal cells: " + std::to_string(m_noInternalCells)
10533 + " != " + std::to_string(noCellsCheck));
10534 }
10535
10536 TERMM_IF_COND(m_noPartitionCells <= 0, "Cannot allocate array with " + to_string(m_noPartitionCells) + " elements.");
10537
10538 // Reallocate partition cell arrays with new size
10540 mAlloc(m_localPartitionCellGlobalIds, m_noPartitionCells, "m_localPartitionCellGlobalIds", static_cast<MLong>(-1),
10541 AT_);
10543 mAlloc(m_localPartitionCellLocalIds, m_noPartitionCells, "m_localPartitionCellLocalIds", -1, AT_);
10544
10545 const MInt maxPartLvl = m_minLevel + m_maxPartitionLevelShift;
10546 // Store partition cell global ids and determine number of offsprings for all cells starting at
10547 // the partition level (required for communicatePartitionLevelAncestorData())
10548 for(MInt i = 0; i < m_noPartitionCells; i++) {
10549 auto cellId = (MInt)(partitionCells[i] - m_domainOffsets[domainId()]);
10550 const MInt partLevel = a_level(cellId);
10551 TERMM_IF_NOT_COND(a_hasProperty(cellId, Cell::IsPartitionCell), "Partition cell flag not set.");
10552 TERMM_IF_COND(partitionCells[i] != a_globalId(cellId), "Error: partition level cell global id mismatch.");
10553 TERMM_IF_COND(partLevel < m_minLevel || partLevel > maxPartLvl, "Invalid level for partition cell.");
10554
10555 m_localPartitionCellGlobalIds[i] = partitionCells[i];
10556 // TODO labels:DLB,GRID @ansgar does not work properly for PLS!
10558 }
10559
10560 // Determine global min and max levels
10561 setLevel();
10562
10563 // Rebuild global-to-local id mapping and convert global ids back to local ids
10564 {
10566
10567 const MInt noMinLevelCells = localMinLevelCells.size();
10568 if(noMinLevelCells == 0) {
10569 localMinLevelCells.push_back(-1);
10570 minLevelCellsTreeId.push_back(-1);
10571 }
10572
10573 // Communicate the partition level ancestor data and create the missing parts of the tree from
10574 // the min-level up to the partition level
10575 maia::grid::IO<CartesianGrid<nDim>>::communicatePartitionLevelAncestorData(
10576 *this, noMinLevelCells, &localMinLevelCells[0], &localMinLevelId[0], &minLevelCellsTreeId[0], &cellInfo[0]);
10577
10578 for(MInt i = m_noInternalCells; i < m_tree.size(); ++i) {
10579 ASSERT(a_hasProperty(i, Cell::IsPartLvlAncestor), "Cell is not a partition level ancestor.");
10580 a_hasProperty(i, Cell::IsHalo) = true;
10581 }
10582
10583 // Set neighbor ids
10584 maia::grid::IO<CartesianGrid<nDim>>::propagateNeighborsFromMinLevelToMaxLevel(*this);
10585
10586 // Update the global to local id mapping and change global ids in the tree into local ids
10589
10590 // Rebuild window/halo cell information
10592 }
10593
10594 setLevel();
10595
10596 // TODO labels:GRID,DLB @ansgar_pls is this still required here? after windowHalo?
10598
10599 // Update local bounding box
10601
10602 // Set balance status
10604 m_wasBalanced = true;
10605
10606#ifdef MAIA_GRID_SANITY_CHECKS
10608#endif
10609}
void mAlloc(T *&a, const MLong N, const MString &objectName, MString function)
allocates memory for one-dimensional array 'a' of size N
Definition: alloc.h:173
MInt noDomains() const
MLong * m_domainOffsets
void computeGlobalIds()
Update number of internal cells, recalculate domain offsets, recalculate global ids for all internal ...
MInt a_noChildren(const MInt cellId) const
Returns the no. of children of the cell cellId.
MFloat & a_weight(const MInt cellId)
Returns the weight of the cell cellId.
MLong m_localPartitionCellOffsets[3]
void computeLocalBoundingBox(MFloat *const bbox)
Compute the bounding box of all local cells.
MBool m_wasBalancedAtLeastOnce
MInt m_noPartitionCells
void changeGlobalToLocalIds()
Change global child/neighbor/parent cell ids into local cell ids. Requires that m_globalToLocalId con...
MPI_Comm mpiComm() const
Return the MPI communicator used by this grid.
MInt a_noOffsprings(const MInt cellId) const
Returns the noOffsprings of the cell .
MInt m_maxPartitionLevelShift
MFloat m_targetGridCenterOfGravity[3]
MInt & a_level(const MInt cellId)
Returns the level of the cell cellId.
void descendNoOffsprings(const MLong cellId, const MLong offset=0)
void setLevel()
Set minimum und maximum cell levels.
MInt m_minLevel
The min Level of refinement of the solver length.
MLong & a_childId(const MInt cellId, const MInt pos)
Returns the child id of the cell cellId at position pos.
void setupWindowHaloCellConnectivity()
Create window and halo cell connectivity between domains.
MLong m_noPartitionCellsGlobal
MFloat a_workload(const MInt cellId) const
Returns the workload of the cell cellId.
MInt * m_localPartitionCellLocalIds
std::map< MLong, MInt > m_globalToLocalId
Mapping: global cell id -> local cell id.
MLong * m_localPartitionCellGlobalIds
MLong & a_globalId(const MInt cellId)
Returns the globalId of the cell cellId in collector cells_.
static constexpr MInt m_noDirs
MFloat m_localBoundingBox[6]
Local bounding box for fast checking if a point lies outside the local domain.
MFloat m_targetGridLengthLevel0
void createGlobalToLocalIdMapping()
Create the mapping from global to local cell ids.
MInt m_noInternalCells
void gridSanityChecks()
Perform grid sanity checks.
MLong & a_neighborId(const MInt cellId, const MInt dir)
Returns the neighbor id of the cell cellId dir.
static constexpr MInt m_maxNoChilds
std::vector< MInt > m_minLevelCells
MInt m_targetGridMinLevel
This class is a ScratchSpace.
Definition: scratch.h:758
void clear()
Clear tree by invalidating all nodes and setting size to zero.
Definition: container.h:395
constexpr MInt size() const
Return size (i.e., currently used number of nodes)
Definition: container.h:89
void append(const MInt count)
Append nodes to end of tree.
Definition: container.h:223
SolverBitsetType & solverBits(const MInt id)
Accessor for properties.
InfoOutFile m_log
constexpr MLong IPOW2(MInt x)
uint32_t MUint
Definition: maiatypes.h:63
unsigned char MUchar
Definition: maiatypes.h:57
int64_t MLong
Definition: maiatypes.h:64
bool MBool
Definition: maiatypes.h:58
constexpr std::underlying_type< GridCell >::type p(const GridCell property)
Converts property name to underlying integer value.
maia::grid::cell::BitsetType PropertyBitsetType
Underlying bitset type for property storage.
std::bitset< MAIA_MULTISOLVER_MAX_NO_SOLVERS > SolverBitsetType
Underlying bitset type for solver use storage (Note: If there are more solvers, change size here)
void communicateData(const DataType *const data, const MInt noCells, const MInt *const sortedCellId, const MInt noDomains, const MInt domainId, const MPI_Comm mpiComm, const MInt *const noCellsToSendByDomain, const MInt *const noCellsToReceiveByDomain, const MInt dataBlockSize, DataType *const buffer)
Assemble given data in send buffer and communicate.
Definition: mpiexchange.h:858
void communicateBitsetData(const std::bitset< N > *const data, const MInt noCells, const MInt *const sortedCellId, const MInt noDomains, const MInt domainId, const MPI_Comm mpiComm, const MInt *const noCellsToSendByDomain, const MInt *const noCellsToReceiveByDomain, const MInt dataBlockSize, std::bitset< N > *const buffer)
Definition: mpiexchange.h:873

◆ bitOffset()

template<MInt nDim>
MLong CartesianGrid< nDim >::bitOffset ( ) const
inline

Definition at line 803 of file cartesiangrid.h.

803{ return m_32BitOffset; }

◆ boundingBox()

template<MInt nDim>
void CartesianGrid< nDim >::boundingBox ( MFloat *const  box) const
inline

Store the grid bounding box.

Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-03-10
Parameters
[out]boxLocation where bounding box information is to be stored. Must be at least of size 2 * dim.

The bounding box is stored as follows: 2D: min_x | min_y | max_x | max_y 3D: min_x | min_y | min_z | max_x | max_y | max_z

Definition at line 406 of file cartesiangrid.h.

406{ std::copy_n(&m_boundingBox[0], 2 * nDim, box); }
MFloat m_boundingBox[6]

◆ boxSphereIntersection()

template<MInt nDim>
MBool CartesianGrid< nDim >::boxSphereIntersection ( const MFloat bMin,
const MFloat bMax,
const MFloat *const  sphereCenter,
MFloat const  radius 
)

Definition at line 10767 of file cartesiangrid.cpp.

10768 {
10769 MFloat dmin = 0;
10770 for(MInt n = 0; n < nDim; n++) {
10771 if(sphereCenter[n] < bMin[n]) {
10772 dmin += pow((sphereCenter[n] - bMin[n]), 2);
10773 } else if(sphereCenter[n] > bMax[n]) {
10774 dmin += pow((sphereCenter[n] - bMax[n]), 2);
10775 }
10776 }
10777 return (dmin <= pow(radius, 2));
10778}
double MFloat
Definition: maiatypes.h:52

◆ calculateNoOffspringsAndWorkload()

template<MInt nDim>
template<typename CELLTYPE >
template void CartesianGrid< nDim >::calculateNoOffspringsAndWorkload ( Collector< CELLTYPE > *  input_cells,
MInt  input_noCells 
)
private
  1. Assign each cell with the max possible level (as those can't have childs) the value 1 as offSprings and the value m_weight as workload.
  2. Assign each cell with one level up (the parents of the cells of the previous step) the value 1 + value of each child if it has any (offSprings) and the value m_weight + workload of each child if it has any (workload).
  3. Repeat step 2 for each level until ones reachs the minimum level.
Template Parameters

in] T Cell type

Definition at line 10700 of file cartesiangrid.cpp.

10700 {
10701 TRACE();
10702 vector<vector<MInt>> partitionLevelAncestorHaloCells;
10703 vector<vector<MInt>> partitionLevelAncestorWindowCells;
10704
10705 if(m_maxPartitionLevelShift > 0) {
10706 determinePartLvlAncestorHaloWindowCells(partitionLevelAncestorHaloCells, partitionLevelAncestorWindowCells);
10707 } else {
10708 partitionLevelAncestorHaloCells.resize(noNeighborDomains());
10709 partitionLevelAncestorWindowCells.resize(noNeighborDomains());
10710 }
10711
10713 *this, input_cells, input_noCells, m_haloCells, m_windowCells, partitionLevelAncestorWindowCells,
10714 partitionLevelAncestorHaloCells);
10715}
void calculateNoOffspringsAndWorkload(Collector< CELLTYPE > *input_cells, MInt input_noCells)
Caluclate the number of offsprings and the workload for each cell.
MInt noNeighborDomains() const
Return number of neighbor domains.
std::vector< std::vector< MInt > > m_windowCells
void determinePartLvlAncestorHaloWindowCells(std::vector< std::vector< MInt > > &partLvlAncestorHaloCells, std::vector< std::vector< MInt > > &partLvlAncestorWindowCells)
Store partition level ancestor window/halo cells.
std::vector< std::vector< MInt > > m_haloCells

◆ cartesianToCylindric()

template<MInt nDim>
void CartesianGrid< nDim >::cartesianToCylindric ( const MFloat coords,
MFloat coordsCyl 
)
Author
Thomas Hoesgen
Date
November 2020

Definition at line 13717 of file cartesiangrid.cpp.

13717 {
13718 TRACE();
13719
13720 MFloat radius = F0;
13721
13722 for(MInt d = 0; d < nDim; d++) {
13723 if(m_periodicCartesianDir[d] == 0) {
13724 coordsCyl[nDim - 1] = coords[d];
13725 } else {
13726 radius += pow((coords[d] - m_azimuthalPerCenter[d]), 2);
13727 }
13728 }
13729 radius = sqrt(radius);
13730
13731 MFloat fac = F0;
13732 if(coords[m_azimuthalPeriodicDir[0]] >= F0) {
13733 fac = 1.0;
13734 } else {
13735 fac = -1.0;
13736 }
13737 MFloat phi = fac * acos(coords[m_azimuthalPeriodicDir[1]] / radius);
13738
13739 coordsCyl[0] = radius;
13740 coordsCyl[1] = phi;
13741}
std::array< MInt, 3 > m_periodicCartesianDir
std::array< MFloat, 3 > m_azimuthalPerCenter
std::array< MInt, 2 > m_azimuthalPeriodicDir

◆ cellLengthAtCell()

template<MInt nDim>
MFloat CartesianGrid< nDim >::cellLengthAtCell ( const MInt  cellId) const
inline

Definition at line 388 of file cartesiangrid.h.

388{ return cellLengthAtLevel(a_level(cellId)); }
MFloat cellLengthAtLevel(const MInt level) const
Returns cell length at cell level level.

◆ cellLengthAtLevel()

template<MInt nDim>
MFloat CartesianGrid< nDim >::cellLengthAtLevel ( const MInt  level) const
inline

Note cell length h = h_0 / 2^level where h_0 is the length of the grid's root cell.

Definition at line 386 of file cartesiangrid.h.

386{ return m_lengthLevel0 * FFPOW2(level); }
MFloat m_lengthLevel0
The initial length of the solver.
constexpr MFloat FFPOW2(MInt x)

◆ cellVolumeAtLevel()

template<MInt nDim>
MFloat CartesianGrid< nDim >::cellVolumeAtLevel ( const MInt  level) const
inline

Definition at line 391 of file cartesiangrid.h.

391 {
392 return (nDim == 3) ? POW3(cellLengthAtLevel(level)) : POW2(cellLengthAtLevel(level));
393 }
constexpr Real POW3(const Real x)
Definition: functions.h:123
constexpr Real POW2(const Real x)
Definition: functions.h:119

◆ centerOfGravity() [1/2]

template<MInt nDim>
void CartesianGrid< nDim >::centerOfGravity ( MFloat *const  center) const
inline

Store center of gravity coordinates.

Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-03-10
Parameters
[out]centerLocation where coordinates are to be stored. Must be at least of size nDim.

Definition at line 418 of file cartesiangrid.h.

418{ std::copy_n(m_centerOfGravity, nDim, center); }
MFloat m_centerOfGravity[3]
coordinates of the root cell

◆ centerOfGravity() [2/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::centerOfGravity ( MInt  dir) const
inline

Definition at line 551 of file cartesiangrid.h.

551{ return m_centerOfGravity[dir]; }

◆ changeGlobalToLocalIds()

template<MInt nDim>
void CartesianGrid< nDim >::changeGlobalToLocalIds
private
Author
Stephan Schlimpert
Date
9.12.2012

Definition at line 9926 of file cartesiangrid.cpp.

9926 {
9927 TRACE();
9928
9929 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
9930 // local childIds
9931 for(MInt childId = 0; childId < m_maxNoChilds; childId++) {
9932 if(a_childId(cellId, childId) == -1) {
9933 continue;
9934 }
9935
9936 if(m_globalToLocalId.count(a_childId(cellId, childId)) > 0) {
9937 a_childId(cellId, childId) = m_globalToLocalId[a_childId(cellId, childId)];
9938 } else {
9939 a_childId(cellId, childId) = -1;
9940 }
9941 }
9942 // this is commented out, because the noChildIds of the non leaf level halo cells on the second layer would be
9943 // corrected here to zero such that certain parts of the code will use different neighbor and surface informations
9944 // especially at the cut boundaries. This leads to serial-parallel inconsistencies because m_noChildIds is used as a
9945 // trigger for some algorithms
9946 /*
9947 a_noChildren( cellId ) = 0;
9948 for (MInt childId = 0; childId < m_maxNoChilds; childId++) {
9949 if (a_childId( cellId , childId ) > -1) {
9950 a_noChildren( cellId )++;
9951 }
9952 }
9953 */
9954 // local neighbor Ids
9955 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
9956 if(a_neighborId(cellId, dirId) > -1) {
9957 if(m_globalToLocalId.count(a_neighborId(cellId, dirId)) > 0) {
9958 a_neighborId(cellId, dirId) = m_globalToLocalId[a_neighborId(cellId, dirId)];
9959 } else {
9960 a_neighborId(cellId, dirId) = -1;
9961 }
9962 }
9963 }
9964
9965 // local parentId
9966 if(a_parentId(cellId) == -1) {
9967 a_parentId(cellId) = -1;
9968 } else {
9969 if(m_globalToLocalId.count(a_parentId(cellId)) > 0) {
9970 a_parentId(cellId) = m_globalToLocalId[a_parentId(cellId)];
9971 } else {
9972 a_parentId(cellId) = -1;
9973 }
9974 }
9975 }
9976}

◆ checkAzimuthalWindowHaloConsistency()

template<MInt nDim>
void CartesianGrid< nDim >::checkAzimuthalWindowHaloConsistency
Author
Thomas Hoesgen
Date
November 2020

Definition at line 14595 of file cartesiangrid.cpp.

14595 {
14596 TRACE();
14597 if(globalNoDomains() == 1) {
14598 return;
14599 }
14600
14601 m_log << "checkWindowHaloConsistency azimuthal... ";
14602
14604 // Check #1: number of azimuthal window/halo cells match
14606 // Start receiving number of window cells from each neighbor domain
14607 ScratchSpace<MPI_Request> recvRequests(std::max(1, noAzimuthalNeighborDomains()), AT_, "recvRequests");
14608 MIntScratchSpace noWindowCellsRecv(std::max(1, noAzimuthalNeighborDomains()), AT_, "noWindowCellsRecv");
14609 for(MInt d = 0; d < noAzimuthalNeighborDomains(); d++) {
14610 noWindowCellsRecv[d] = -1;
14611 MPI_Irecv(&noWindowCellsRecv[d], 1, type_traits<MInt>::mpiType(), azimuthalNeighborDomain(d),
14612 azimuthalNeighborDomain(d), mpiComm(), &recvRequests[d], AT_, "noWindowCellsRecv[d]");
14613 }
14614
14615 // Start sending number of window cells to each neighbor domain
14616 ScratchSpace<MPI_Request> sendRequests(std::max(1, noAzimuthalNeighborDomains()), AT_, "sendRequests");
14617 MIntScratchSpace noWindowCellsSend(std::max(1, noAzimuthalNeighborDomains()), AT_, "noWindowCellsSend");
14618 for(MInt d = 0; d < noAzimuthalNeighborDomains(); d++) {
14619 noWindowCellsSend[d] = noAzimuthalWindowCells(d);
14620 MPI_Isend(&noWindowCellsSend[d], 1, type_traits<MInt>::mpiType(), azimuthalNeighborDomain(d), domainId(), mpiComm(),
14621 &sendRequests[d], AT_, "noWindowCellsSend[d]");
14622 }
14623
14624 // Finish MPI communication
14625 MPI_Waitall(noAzimuthalNeighborDomains(), &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
14626 MPI_Waitall(noAzimuthalNeighborDomains(), &sendRequests[0], MPI_STATUSES_IGNORE, AT_);
14627
14628 // Check if received number of window cells matches the local number of halo cells
14629 for(MInt d = 0; d < noAzimuthalNeighborDomains(); d++) {
14630 if(noWindowCellsRecv[d] != noAzimuthalHaloCells(d)) {
14631 TERMM(1, "Cartesian Grid : Number of azimuthal window cells from domain " + to_string(azimuthalNeighborDomain(d))
14632 + " does not match local number of azimuthal halo cells; window: " + to_string(noWindowCellsRecv[d])
14633 + " ,halo: " + to_string(noAzimuthalHaloCells(d)));
14634 }
14635 }
14636
14638 // Check #2: grid global ids of window/halo cells match
14640 // Start receiving window cell global ids from each neighbor domain
14641 fill(recvRequests.begin(), recvRequests.end(), MPI_REQUEST_NULL);
14642 const MInt totalNoWindowCellsRecv = accumulate(noWindowCellsRecv.begin(), noWindowCellsRecv.end(), 0);
14643
14644 MIntScratchSpace windowCellsRecv(max(1, totalNoWindowCellsRecv), AT_, "windowCellsRecv");
14645 fill(windowCellsRecv.begin(), windowCellsRecv.end(), -1);
14646 for(MInt d = 0, offset = 0; d < noAzimuthalNeighborDomains(); d++) {
14647 if(noAzimuthalHaloCells(d) > 0) {
14648 MPI_Irecv(&windowCellsRecv[offset], noAzimuthalHaloCells(d), type_traits<MInt>::mpiType(),
14649 azimuthalNeighborDomain(d), azimuthalNeighborDomain(d), mpiComm(), &recvRequests[d], AT_,
14650 "windowCellsRecv[offset]");
14651 }
14652 offset += noAzimuthalHaloCells(d);
14653 }
14654
14655 // Start sending window cell global ids to each neighbor domain
14656 fill(sendRequests.begin(), sendRequests.end(), MPI_REQUEST_NULL);
14657 const MInt totalNoWindowCellsSend = accumulate(noWindowCellsSend.begin(), noWindowCellsSend.end(), 0);
14658 MIntScratchSpace windowCellsSend(max(1, totalNoWindowCellsSend), AT_, "windowCellsSend");
14659
14660 for(MInt d = 0, offset = 0; d < noAzimuthalNeighborDomains(); d++) {
14661 for(MInt c = 0; c < noWindowCellsSend[d]; c++) {
14662 TERMM_IF_NOT_COND(a_hasProperty(azimuthalWindowCell(d, c), Cell::IsWindow), "not a window cell");
14663 windowCellsSend[offset + c] = a_globalId(azimuthalWindowCell(d, c));
14664 }
14665 if(noAzimuthalWindowCells(d) > 0) {
14666 MPI_Isend(&windowCellsSend[offset], noAzimuthalWindowCells(d), type_traits<MInt>::mpiType(),
14667 azimuthalNeighborDomain(d), domainId(), mpiComm(), &sendRequests[d], AT_, "windowCellsSend[offset]");
14668 }
14669 offset += noAzimuthalWindowCells(d);
14670 }
14671
14672 // Finish MPI communication
14673 MPI_Waitall(noAzimuthalNeighborDomains(), &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
14674 MPI_Waitall(noAzimuthalNeighborDomains(), &sendRequests[0], MPI_STATUSES_IGNORE, AT_);
14675
14676 // Check if received window cell global ids match the local halo cell global ids
14677 for(MInt d = 0, offset = 0; d < noAzimuthalNeighborDomains(); d++) {
14678 for(MInt c = 0; c < noAzimuthalHaloCells(d); c++) {
14679 const MInt cellId = azimuthalHaloCell(d, c);
14680 TERMM_IF_NOT_COND(a_isHalo(cellId), "not a halo cell");
14681 const MInt globalId = a_globalId(cellId);
14682 // If halo cell has periodic flag, its global id should be -1
14683 if(windowCellsRecv[offset + c] != globalId && !(a_hasProperty(cellId, Cell::IsPeriodic) && globalId == -1)) {
14684 TERMM(1, "Global id of window cell " + to_string(c) + " from domain " + to_string(azimuthalNeighborDomain(d))
14685 + " does not match local halo cell gobal id (" + to_string(windowCellsRecv[offset + c]) + " vs. "
14686 + to_string(a_globalId(azimuthalHaloCell(d, c))) + ")");
14687 }
14688 }
14689 offset += noAzimuthalHaloCells(d);
14690 }
14691
14692 m_log << "done" << std::endl;
14693}
MInt noAzimuthalNeighborDomains() const
Return number of azimuthal neighbor domains.
const MInt & azimuthalNeighborDomain(const MInt id) const
Return azimuthal neighbor domain.
MInt noAzimuthalHaloCells(const MInt domainId) const
Return number of azimuthal Halo cells for given domain.
MBool a_isHalo(const MInt cellId) const
Returns property p of the cell cellId.
MInt azimuthalHaloCell(const MInt domainId, const MInt cellId) const
Return azimuthal Halo cell id.
MInt azimuthalWindowCell(const MInt domainId, const MInt cellId) const
Return azimuthal window cell id.
MInt noAzimuthalWindowCells(const MInt domainId) const
Return number of azimuthal window cells for given domain.
MInt globalNoDomains()
Return global number of domains.
int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Isend
int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Irecv
int MPI_Waitall(int count, MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Waitall

◆ checkOutsideAzimuthalDomain()

template<MInt nDim>
MBool CartesianGrid< nDim >::checkOutsideAzimuthalDomain ( MFloat )

◆ checkWindowHaloConsistency()

template<MInt nDim>
void CartesianGrid< nDim >::checkWindowHaloConsistency ( const MBool  fullCheck = false,
const MString  a = "" 
)

TODO labels:GRID copied/adapted from gridproxy, generalize to avoid duplicate code?

Definition at line 13056 of file cartesiangrid.cpp.

13056 {
13057 TRACE();
13058 if(globalNoDomains() == 1) {
13059 return;
13060 }
13061
13062 m_log << "checkWindowHaloConsistency... ";
13063
13064 // WH_old
13065 if(m_haloMode > 0) {
13066 ScratchSpace<MBool> isWindowCell(m_tree.size(), AT_, "isWindowCell");
13067 ScratchSpace<MBool> isHaloCell(m_tree.size(), AT_, "isHaloCell");
13068 isWindowCell.fill(false);
13069 isHaloCell.fill(false);
13070
13071 ScratchSpace<MPI_Request> recvRequests(std::max(1, noNeighborDomains()), AT_, "recvRequests");
13072 ScratchSpace<MPI_Request> sendRequests(std::max(1, noNeighborDomains()), AT_, "sendRequests");
13073
13074 for(MInt solver = 0; solver < treeb().noSolvers(); ++solver) {
13076 // Check #1: number of window/halo cells match
13078 // Start receiving number of window cells from each neighbor domain
13079 fill(recvRequests.begin(), recvRequests.end(), MPI_REQUEST_NULL);
13080 MIntScratchSpace noWindowCellsRecv(std::max(1, noNeighborDomains()), AT_, "noWindowCellsRecv");
13081 for(MInt d = 0; d < noNeighborDomains(); d++) {
13082 noWindowCellsRecv[d] = -1;
13083 MPI_Irecv(&noWindowCellsRecv[d], 1, type_traits<MInt>::mpiType(), neighborDomain(d), neighborDomain(d),
13084 mpiComm(), &recvRequests[d], AT_, "noWindowCellsRecv[d]");
13085 }
13086
13087 // Start sending number of window cells to each neighbor domain
13088 fill(sendRequests.begin(), sendRequests.end(), MPI_REQUEST_NULL);
13089 MIntScratchSpace noWindowCellsSend(std::max(1, noNeighborDomains()), AT_, "noWindowCellsSend");
13090 for(MInt d = 0; d < noNeighborDomains(); d++) {
13091 // //TODO_SS labels:GRID,COMM currently without duplicate window cells for periodic ...
13092 noWindowCellsSend[d] = noSolverWindowCells(d, solver); // noWindowCells(d);
13093 MPI_Isend(&noWindowCellsSend[d], 1, type_traits<MInt>::mpiType(), neighborDomain(d), domainId(), mpiComm(),
13094 &sendRequests[d], AT_, "noWindowCellsSend[d]");
13095 }
13096
13097 // Finish MPI communication
13098 MPI_Waitall(noNeighborDomains(), &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
13099 MPI_Waitall(noNeighborDomains(), &sendRequests[0], MPI_STATUSES_IGNORE, AT_);
13100
13101 // Check if received number of window cells matches the local number of halo cells
13102 for(MInt d = 0; d < noNeighborDomains(); d++) {
13103 if(noWindowCellsRecv[d] != noSolverHaloCells(d, solver, true) /*noHaloCells(d)*/) {
13104 TERMM(1, "Cartesian Grid : Number of window cells from domain " + to_string(neighborDomain(d))
13105 + " does not match local number of halo cells; window: " + to_string(noWindowCellsRecv[d])
13106 + " ,halo: " + to_string(noSolverHaloCells(d, solver, true) /*noHaloCells(d)*/) + " " + a
13107 + " d=" + to_string(domainId()) + " solver=" + to_string(solver));
13108 }
13109 }
13110 }
13111
13113 // Check #2: grid global ids of window/halo cells match
13115 // Start receiving window cell global ids from each neighbor domain
13116 fill(recvRequests.begin(), recvRequests.end(), MPI_REQUEST_NULL);
13117 // const MInt totalNoWindowCellsRecv = accumulate(noWindowCellsRecv.begin(), noWindowCellsRecv.end(), 0);
13118 MInt totalNoWindowCellsRecv = 0;
13119 for(MInt d = 0; d < noNeighborDomains(); d++)
13120 totalNoWindowCellsRecv += noHaloCells(d);
13121
13122 MIntScratchSpace windowCellsRecv(max(1, totalNoWindowCellsRecv), AT_, "windowCellsRecv");
13123 fill(windowCellsRecv.begin(), windowCellsRecv.end(), -1);
13124 for(MInt d = 0, offset = 0; d < noNeighborDomains(); d++) {
13125 if(noHaloCells(d) > 0) {
13126 MPI_Irecv(&windowCellsRecv[offset], noHaloCells(d), type_traits<MInt>::mpiType(), neighborDomain(d),
13127 neighborDomain(d), mpiComm(), &recvRequests[d], AT_, "windowCellsRecv[offset]");
13128 }
13129 offset += noHaloCells(d);
13130 }
13131
13132 // Start sending window cell global ids to each neighbor domain
13133 fill(sendRequests.begin(), sendRequests.end(), MPI_REQUEST_NULL);
13134 // const MInt totalNoWindowCellsSend = accumulate(noWindowCellsSend.begin(), noWindowCellsSend.end(), 0);
13135 MInt totalNoWindowCellsSend = 0;
13136 for(MInt d = 0; d < noNeighborDomains(); d++)
13137 totalNoWindowCellsSend += noWindowCells(d);
13138 MIntScratchSpace windowCellsSend(max(1, totalNoWindowCellsSend), AT_, "windowCellsSend");
13139
13140 for(MInt d = 0, offset = 0; d < noNeighborDomains(); d++) {
13141 for(MInt c = 0; c < noWindowCells(d) /*noWindowCellsSend[d]*/; c++) {
13142 // TERMM_IF_NOT_COND(a_hasProperty(windowCell(d, c), Cell::IsWindow), a+"not a window cell");
13143 windowCellsSend[offset + c] = a_globalId(windowCell(d, c));
13144 isWindowCell(windowCell(d, c)) = true;
13145 }
13146 if(noWindowCells(d) > 0) {
13147 MPI_Isend(&windowCellsSend[offset], noWindowCells(d), type_traits<MInt>::mpiType(), neighborDomain(d),
13148 domainId(), mpiComm(), &sendRequests[d], AT_, "windowCellsSend[offset]");
13149 }
13150 offset += noWindowCells(d);
13151 }
13152
13153 // Finish MPI communication
13154 MPI_Waitall(noNeighborDomains(), &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
13155 MPI_Waitall(noNeighborDomains(), &sendRequests[0], MPI_STATUSES_IGNORE, AT_);
13156
13157 // Check if received window cell global ids match the local halo cell global ids
13158 for(MInt d = 0, offset = 0; d < noNeighborDomains(); d++) {
13159 for(MInt c = 0; c < noHaloCells(d); c++) {
13160 const MInt cellId = haloCell(d, c);
13161 TERMM_IF_NOT_COND(a_isHalo(cellId), "not a halo cell");
13162 isHaloCell(haloCell(d, c)) = true;
13163 const MInt globalId = a_globalId(cellId);
13164 // If halo cell has periodic flag, its global id should be -1
13165 if(windowCellsRecv[offset + c] != globalId && !(a_hasProperty(cellId, Cell::IsPeriodic) && globalId == -1)) {
13166 TERMM(1, a + "Global id of window cell " + to_string(c) + " from domain " + to_string(neighborDomain(d))
13167 + " does not match local halo cell gobal id (" + to_string(windowCellsRecv[offset + c]) + " vs. "
13168 + to_string(a_globalId(haloCell(d, c))) + ")");
13169 }
13170 }
13171 offset += noHaloCells(d);
13172 }
13173
13174 // So if-statements below do not fail
13175 if(m_azimuthalPer) {
13176 for(MInt d = 0; d < noAzimuthalNeighborDomains(); d++) {
13177 for(MInt c = 0; c < noAzimuthalWindowCells(d); c++) {
13178 isWindowCell(azimuthalWindowCell(d, c)) = true;
13179 }
13180 for(MInt c = 0; c < noAzimuthalHaloCells(d); c++) {
13181 isHaloCell(azimuthalHaloCell(d, c)) = true;
13182 }
13183 }
13184 for(MInt c = 0; c < noAzimuthalUnmappedHaloCells(); c++) {
13185 isHaloCell(azimuthalUnmappedHaloCell(c)) = true;
13186 }
13187 }
13188
13189 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
13190 // check that only cells in m_windowCells are marked as window!
13191 if(!isWindowCell(cellId)) {
13192 TERMM_IF_NOT_COND(!a_hasProperty(cellId, Cell::IsWindow),
13193 "cell is marked as window but not in m_windowCells: " + std::to_string(cellId) + a);
13194 }
13195 // check that only cells in m_haloCells are marked as halo!
13196 if(!isHaloCell(cellId) && !a_hasProperty(cellId, Cell::IsPartLvlAncestor)) {
13197 TERMM_IF_NOT_COND(!a_isHalo(cellId),
13198 "cell is marked as halo but not in m_haloCells: " + std::to_string(cellId));
13199 }
13200 }
13201 } else {
13203 // Check #1: number of window/halo cells match
13205 // Start receiving number of window cells from each neighbor domain
13206 ScratchSpace<MPI_Request> recvRequests(std::max(1, noNeighborDomains()), AT_, "recvRequests");
13207 MIntScratchSpace noWindowCellsRecv(std::max(1, noNeighborDomains()), AT_, "noWindowCellsRecv");
13208 for(MInt d = 0; d < noNeighborDomains(); d++) {
13209 noWindowCellsRecv[d] = -1;
13210 MPI_Irecv(&noWindowCellsRecv[d], 1, type_traits<MInt>::mpiType(), neighborDomain(d), neighborDomain(d), mpiComm(),
13211 &recvRequests[d], AT_, "noWindowCellsRecv[d]");
13212 }
13213
13214 // Start sending number of window cells to each neighbor domain
13215 ScratchSpace<MPI_Request> sendRequests(std::max(1, noNeighborDomains()), AT_, "sendRequests");
13216 MIntScratchSpace noWindowCellsSend(std::max(1, noNeighborDomains()), AT_, "noWindowCellsSend");
13217 for(MInt d = 0; d < noNeighborDomains(); d++) {
13218 noWindowCellsSend[d] = noWindowCells(d);
13219 MPI_Isend(&noWindowCellsSend[d], 1, type_traits<MInt>::mpiType(), neighborDomain(d), domainId(), mpiComm(),
13220 &sendRequests[d], AT_, "noWindowCellsSend[d]");
13221 }
13222
13223 // Finish MPI communication
13224 MPI_Waitall(noNeighborDomains(), &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
13225 MPI_Waitall(noNeighborDomains(), &sendRequests[0], MPI_STATUSES_IGNORE, AT_);
13226
13227 // Check if received number of window cells matches the local number of halo cells
13228 for(MInt d = 0; d < noNeighborDomains(); d++) {
13229 if(noWindowCellsRecv[d] != noHaloCells(d)) {
13230 TERMM(1, "Cartesian Grid : Number of window cells from domain " + to_string(neighborDomain(d))
13231 + " does not match local number of halo cells; window: " + to_string(noWindowCellsRecv[d])
13232 + " ,halo: " + to_string(noHaloCells(d)));
13233 }
13234 }
13235
13237 // Check #2: grid global ids of window/halo cells match
13239 // Start receiving window cell global ids from each neighbor domain
13240 fill(recvRequests.begin(), recvRequests.end(), MPI_REQUEST_NULL);
13241 const MInt totalNoWindowCellsRecv = accumulate(noWindowCellsRecv.begin(), noWindowCellsRecv.end(), 0);
13242
13243 MLongScratchSpace windowCellsRecv(max(1, totalNoWindowCellsRecv), AT_, "windowCellsRecv");
13244 fill(windowCellsRecv.begin(), windowCellsRecv.end(), -1);
13245 for(MInt d = 0, offset = 0; d < noNeighborDomains(); d++) {
13246 if(noHaloCells(d) > 0) {
13247 MPI_Irecv(&windowCellsRecv[offset], noHaloCells(d), type_traits<MLong>::mpiType(), neighborDomain(d),
13248 neighborDomain(d), mpiComm(), &recvRequests[d], AT_, "windowCellsRecv[offset]");
13249 }
13250 offset += noHaloCells(d);
13251 }
13252
13253 // Start sending window cell global ids to each neighbor domain
13254 fill(sendRequests.begin(), sendRequests.end(), MPI_REQUEST_NULL);
13255 const MInt totalNoWindowCellsSend = accumulate(noWindowCellsSend.begin(), noWindowCellsSend.end(), 0);
13256 MLongScratchSpace windowCellsSend(max(1, totalNoWindowCellsSend), AT_, "windowCellsSend");
13257
13258 ScratchSpace<MBool> isWindowCell(m_tree.size(), AT_, "isWindowCell");
13259 ScratchSpace<MBool> isHaloCell(m_tree.size(), AT_, "isHaloCell");
13260 isWindowCell.fill(false);
13261 isHaloCell.fill(false);
13262
13263 for(MInt d = 0, offset = 0; d < noNeighborDomains(); d++) {
13264 for(MInt c = 0; c < noWindowCellsSend[d]; c++) {
13265 TERMM_IF_NOT_COND(a_hasProperty(windowCell(d, c), Cell::IsWindow), "not a window cell");
13266 windowCellsSend[offset + c] = a_globalId(windowCell(d, c));
13267 isWindowCell(windowCell(d, c)) = true;
13268 }
13269 if(noWindowCells(d) > 0) {
13270 MPI_Isend(&windowCellsSend[offset], noWindowCells(d), type_traits<MLong>::mpiType(), neighborDomain(d),
13271 domainId(), mpiComm(), &sendRequests[d], AT_, "windowCellsSend[offset]");
13272 }
13273 offset += noWindowCells(d);
13274 }
13275
13276 // Finish MPI communication
13277 MPI_Waitall(noNeighborDomains(), &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
13278 MPI_Waitall(noNeighborDomains(), &sendRequests[0], MPI_STATUSES_IGNORE, AT_);
13279
13280 // Check if received window cell global ids match the local halo cell global ids
13281 for(MInt d = 0, offset = 0; d < noNeighborDomains(); d++) {
13282 for(MInt c = 0; c < noHaloCells(d); c++) {
13283 const MInt cellId = haloCell(d, c);
13284 TERMM_IF_NOT_COND(a_isHalo(cellId), "not a halo cell");
13285 isHaloCell(haloCell(d, c)) = true;
13286 const MLong globalId = a_globalId(cellId);
13287 // If halo cell has periodic flag, its global id should be -1
13288 if(windowCellsRecv[offset + c] != globalId && !(a_hasProperty(cellId, Cell::IsPeriodic) && globalId == -1)) {
13289 TERMM(1, "Global id of window cell " + to_string(c) + " from domain " + to_string(neighborDomain(d))
13290 + " does not match local halo cell gobal id (" + to_string(windowCellsRecv[offset + c]) + " vs. "
13291 + to_string(a_globalId(haloCell(d, c))) + ")");
13292 }
13293 }
13294 offset += noHaloCells(d);
13295 }
13296
13297 // So if-statements below do not fail
13298 if(m_azimuthalPer) {
13299 for(MInt d = 0; d < noAzimuthalNeighborDomains(); d++) {
13300 for(MInt c = 0; c < noAzimuthalWindowCells(d); c++) {
13301 isWindowCell(azimuthalWindowCell(d, c)) = true;
13302 }
13303 for(MInt c = 0; c < noAzimuthalHaloCells(d); c++) {
13304 isHaloCell(azimuthalHaloCell(d, c)) = true;
13305 }
13306 }
13307 for(MInt c = 0; c < noAzimuthalUnmappedHaloCells(); c++) {
13308 isHaloCell(azimuthalUnmappedHaloCell(c)) = true;
13309 }
13310 }
13311
13312 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
13313 // check that only cells in m_windowCells are marked as window!
13314 if(!isWindowCell(cellId)) {
13315 TERMM_IF_NOT_COND(!a_hasProperty(cellId, Cell::IsWindow),
13316 "cell is marked as window but not in m_windowCells: " + std::to_string(cellId));
13317 }
13318 // check that only cells in m_haloCells are marked as halo!
13319 if(!isHaloCell(cellId) && !a_hasProperty(cellId, Cell::IsPartLvlAncestor)) {
13320 TERMM_IF_NOT_COND(!a_isHalo(cellId),
13321 "cell is marked as halo but not in m_haloCells: " + std::to_string(cellId));
13322 }
13323 }
13324 }
13325
13326 // Check parent/child/neighbor global ids (if != -1)
13327 // Note: not working if the global ids are not computed/updated yet (e.g. during adaptation)!
13328 // Note: assumes that internal and halo cells are separated
13329 if(fullCheck && noNeighborDomains() > 0) {
13330 ScratchSpace<MLong> parentData(m_tree.size(), AT_, "parentData");
13331 ScratchSpace<MLong> childData(m_tree.size(), m_maxNoChilds, AT_, "childData");
13332 parentData.fill(-1);
13333 childData.fill(-1);
13334
13335 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
13336 TERMM_IF_COND(a_isHalo(cellId), "cell is a halo" + a);
13337 const MInt parentId = a_parentId(cellId);
13338 parentData[cellId] = (parentId > -1) ? a_globalId(parentId) : -1;
13339
13340 for(MInt j = 0; j < m_maxNoChilds; j++) {
13341 const MInt childId = a_childId(cellId, j);
13342 childData(cellId, j) = (childId > -1) ? a_globalId(childId) : -1;
13343 }
13344 }
13345
13347
13350
13351 for(MInt d = 0; d < noNeighborDomains(); d++) {
13352 for(MInt c = 0; c < noHaloCells(d); c++) {
13353 const MInt cellId = haloCell(d, c);
13354 TERMM_IF_NOT_COND(a_isHalo(cellId), "not a halo cell");
13355 const MInt parentId = a_parentId(cellId);
13356 if(parentId > -1) {
13357 TERMM_IF_NOT_COND(a_globalId(parentId) == parentData[cellId],
13358 "Halo cell parent global id mismatch: cell" + std::to_string(cellId) + " parent"
13359 + std::to_string(parentId) + "; " + std::to_string(a_globalId(parentId))
13360 + " != " + std::to_string(parentData[cellId]));
13361 }
13362
13363 for(MInt j = 0; j < m_maxNoChilds; j++) {
13364 const MInt childId = a_childId(cellId, j);
13365 if(childId > -1) {
13366 TERMM_IF_NOT_COND(a_globalId(childId) == childData(cellId, j),
13367 "Halo cell child global id mismatch: cell" + std::to_string(cellId) + " child"
13368 + std::to_string(childId) + "; " + std::to_string(a_globalId(childId))
13369 + " != " + std::to_string(childData(cellId, j)));
13370 }
13371 }
13372 }
13373 }
13374 }
13375
13376 m_log << "done" << std::endl;
13377
13378 if(m_azimuthalPer) {
13380 }
13381}
MInt noHaloCells(const MInt domainId) const
Return number of halo cells for given domain.
MInt windowCell(const MInt domainId, const MInt cellId) const
Return window cell id.
MInt noWindowCells(const MInt domainId) const
Return number of window cells for given domain.
const MInt & neighborDomain(const MInt id) const
Return neighbor domain.
MInt noSolverHaloCells(const MInt domainId, const MInt solverId, const MBool periodicCells) const
MInt haloCell(const MInt domainId, const MInt cellId) const
Return halo cell id.
std::vector< MInt > m_nghbrDomains
MInt noAzimuthalUnmappedHaloCells() const
MInt azimuthalUnmappedHaloCell(const MInt cellId) const
MBool m_azimuthalPer
void checkAzimuthalWindowHaloConsistency()
Checks consistency of aimuthal window/halo cells.
MInt noSolverWindowCells(const MInt domainId, const MInt solverId) const
constexpr MInt noSolvers() const
Return currently set number of solvers.
void exchangeData(const MInt noNghbrDomains, const MInt *const nghbrDomains, const MInt *const noHaloCells, const MInt **const, const MInt *const noWindowCells, const MInt **const windowCells, const MPI_Comm comm, const U *const data, U *const haloBuffer, const MInt noDat=1)
Generic exchange of data.
Definition: mpiexchange.h:295
Definition: contexttypes.h:19

◆ checkWindowLayer()

template<MInt nDim>
void CartesianGrid< nDim >::checkWindowLayer ( const MString  text)
private
Date
21th century

Definition at line 14780 of file cartesiangrid.cpp.

14780 {
14781 TRACE();
14782
14783 TERMM_IF_COND((signed)m_windowLayer_.size() < noNeighborDomains(), text);
14784 // Ensure that all cells in m_windowLayer_ have proper layer
14785 for(MInt d = 0; d < noNeighborDomains(); ++d) {
14786 for(const auto item : m_windowLayer_[d]) {
14787 const MInt cellId = item.first;
14788 TERMM_IF_NOT_COND(cellId > -1 && cellId < m_tree.size(), "");
14789 TERMM_IF_COND(item.second.all(), "This entry is unnecessary!");
14790
14791 for(MInt solver = 0; solver < treeb().noSolvers(); ++solver) {
14792 TERMM_IF_COND(item.second.get(solver) <= m_noSolverHaloLayers[solver] /*M32X4bit<>::MAX*/
14793 && !m_tree.solver(cellId, solver),
14794 text);
14795 }
14796 }
14797 }
14798
14799 // Check that all cells in m_windowCells are also in m_windowLayer_
14800 for(MInt i = 0; i < noNeighborDomains(); i++) {
14801 std::set<MInt> allWs(m_windowCells[i].begin(), m_windowCells[i].end());
14802 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
14803 const MInt cellId = m_windowCells[i][j];
14804 if(m_windowLayer_[i].find(cellId) == m_windowLayer_[i].end()) {
14805 stringstream ss;
14806 ss << " domainId=" << domainId() << ": i=" << i << " j=" << j << " cellId=" << cellId
14807 << " globalId=" << a_globalId(cellId) << " nghbrDom=" << m_nghbrDomains[i] << endl;
14808 TERMM(1, text + ss.str());
14809 }
14810 }
14811
14812 // Check that all cells in m_windowLayers_ are also in m_windowCells
14813 std::set<std::pair<MInt, MInt>> del;
14814 for(auto m : m_windowLayer_[i]) {
14815 if(allWs.find(m.first) == allWs.end()) {
14816 // Note: If following assert fails, one could try to uncomment the next line
14817 // del.insert(make_pair(i,m.first)); continue;
14818 std::stringstream ss;
14819 ss << text << " d=" << domainId() << " nghbrDom=" << m_nghbrDomains[i] << "(" << i
14820 << ") minLevel=" << m_minLevel << " cell_level=" << a_level(m.first) << " isHalo=" << a_isHalo(m.first)
14821 << " cellId=" << m.first << " cellLayer=" << m.second.get(0) << "|" << m.second.get(1)
14822 << " parentId=" << a_parentId(m.first) << " parentIsHalo=" << a_isHalo(std::max(0, (int)a_parentId(m.first)))
14823 << " " << isSolverWindowCell(i, m.first, 0);
14824 TERMM(1, ss.str());
14825 }
14826 }
14827 for(auto d : del) {
14828 m_windowLayer_[d.first].erase(m_windowLayer_[d.first].find(d.second));
14829 }
14830
14831 if(m_noPeriodicCartesianDirs == 0) TERMM_IF_NOT_COND(m_windowCells[i].size() == m_windowLayer_[i].size(), text);
14832 }
14833}
MInt * m_noSolverHaloLayers
MBool isSolverWindowCell(const MInt domainId, const MInt cellId, const MInt solverId) const
std::vector< std::unordered_map< MInt, M32X4bit< true > > > m_windowLayer_
MInt m_noPeriodicCartesianDirs

◆ coarsenCheck()

template<MInt nDim>
MBool CartesianGrid< nDim >::coarsenCheck ( const MInt  cellId,
const MInt  solver 
)
private
Author
Lennart Schneiders, Andreas Lintermann
Date
23.04.2019

The check is performed by:

  1. running over all children and 1.1 checking if any of the existing children has children (do not coarsen) 1.2 (switch) diagonal level jumps exist (do not coarsen)
  2. additionally checking if the current cell has a missing neighbor. In this case and if it has children, it has to be a boundary cell and it's children need to be marked as non-coarsenable cells (past function call).
Parameters
[in]cellIdthe cell id to check
[in]solverthe solver id

Definition at line 8660 of file cartesiangrid.cpp.

8660 {
8661 // Enables grid consistency checks(coarsening) for lattice boltzmann methods
8662 MBool extendCheckTo2ndNeighbor = m_lbGridChecks;
8663 MBool restrictDiagonalLevelJumps = m_lbGridChecks;
8664 MBool lbBndCheck = m_lbGridChecks;
8665
8666 ASSERT(m_tree.solver(cellId, solver), "");
8667
8668 // Check that coarse neighbor has all children
8669 // --> checks if coarse neighbor contains a boundary
8670 // --> checks that no interface parents with missing children are created
8671 // Use enhanced computations of directions in above check (See refine check)
8672 // for checking diagonal neighbors (corners) in 3D, too.
8673 if(lbBndCheck) {
8674 for(MInt dir = 0; dir < m_noDirs; dir++) {
8675 if(!a_hasNeighbor(cellId, dir, solver)) /*continue*/
8676 return false; // Avoid coarsening of boundary cells
8677 MInt cartesianNeighbor = a_neighborId(cellId, dir, solver);
8678 if(a_noChildren(cartesianNeighbor) != m_maxNoChilds && a_noChildren(cartesianNeighbor) != 0) return false;
8679 MInt d0 = dir / 2;
8680 MInt d1 = (d0 + 1) % nDim;
8681 for(MInt p = 0; p < 2; p++) {
8682 MInt dir1 = 2 * d1 + p;
8683 if(!a_hasNeighbor(cartesianNeighbor, dir1, solver)) continue;
8684 MInt diagonalNeighbor = a_neighborId(cartesianNeighbor, dir1, solver);
8685 if(a_noChildren(diagonalNeighbor) != m_maxNoChilds && a_noChildren(diagonalNeighbor) != 0) return false;
8686 IF_CONSTEXPR(nDim == 3) {
8687 MInt d2 = (d1 + 1) % nDim;
8688 for(MInt q = 0; q < 2; q++) {
8689 MInt dir2 = 2 * d2 + q;
8690 if(!a_hasNeighbor(diagonalNeighbor, dir2, solver)) continue;
8691 MInt cornerNeighbor = a_neighborId(diagonalNeighbor, dir2, solver);
8692 if(a_noChildren(cornerNeighbor) != m_maxNoChilds && a_noChildren(cornerNeighbor) != 0) return false;
8693 }
8694 }
8695 }
8696 }
8697 }
8698
8699
8700 // 1. run over all children
8701 for(MInt child = 0; child < m_maxNoChilds; child++) {
8702 MInt childId = a_childId(cellId, child, solver);
8703
8704 if(childId < 0) continue;
8705 if(a_hasChildren(childId, solver)) return false;
8706 for(MInt i = 0; i < m_noDirs; i++) {
8707 if(childCode[i][child]) continue;
8708 if(a_hasNeighbor(childId, i, solver) > 0) {
8709 // 1.1 check if any of the existing children has children (do not coarsen)
8710 if(a_hasChildren(a_neighborId(childId, i, solver), solver) > 0) {
8711 return false;
8712 }
8713
8714 // Extend to second Cartesian neighbor of child to prevent double interpolation in LB case
8715 if(extendCheckTo2ndNeighbor) {
8716 if(a_hasNeighbor(a_neighborId(childId, i, solver), i, solver)) {
8717 if(a_hasChildren(a_neighborId(a_neighborId(childId, i, solver), i, solver)) > 0) {
8718 return false;
8719 }
8720 }
8721 }
8722
8723 // Change compiler flag to if statement
8724 // #ifdef RESTRICT_DIAGONAL_LEVEL_JUMPS
8725 // 1.3. switch to restrict diagonal level jumps
8726 if(restrictDiagonalLevelJumps) {
8727 for(MInt j = 0; j < m_noDirs; j++) {
8728 if(j / 2 == i / 2) continue;
8729 if(a_hasNeighbor(a_neighborId(childId, i, solver), j, solver) > 0) {
8730 if(a_hasChildren(a_neighborId(a_neighborId(childId, i, solver), j, solver), solver)) {
8731 return false;
8732 }
8733
8734 // Extend to second diagonal neighbor of child to prevent double interpolation in LB case
8735 if(extendCheckTo2ndNeighbor) {
8736 MInt diagNeighbor = a_neighborId(a_neighborId(childId, i, solver), j, solver);
8737 if(a_hasNeighbor(diagNeighbor, i, solver) > 0) {
8738 // Test check for children along path ??
8739 if(a_hasChildren(a_neighborId(diagNeighbor, i, solver), solver)) return false;
8740
8741 if(a_hasNeighbor(a_neighborId(diagNeighbor, i, solver), j, solver) > 0) {
8742 if(a_hasChildren(a_neighborId(a_neighborId(diagNeighbor, i, solver), j, solver), solver)) {
8743 return false;
8744 }
8745 }
8746 }
8747 }
8748
8749 IF_CONSTEXPR(nDim == 3) {
8750 for(MInt k = 0; k < m_noDirs; k++) {
8751 // if ( k/2 == i/2 || k/2 == i/2) continue; // TODO labels:GRID old version, was this a typo
8752 // and meant something else?
8753 if(k / 2 == i / 2) continue;
8754 if(a_hasNeighbor(a_neighborId(a_neighborId(childId, i, solver), j, solver), k, solver) > 0) {
8755 if(a_hasChildren(a_neighborId(a_neighborId(a_neighborId(childId, i, solver), j, solver), k, solver),
8756 solver)
8757 > 0) {
8758 return false;
8759 }
8760
8761 // Extend to second corner neighbor of child to prevent double interplation in LB case
8762 if(extendCheckTo2ndNeighbor) {
8763 MInt cornerNeighbor =
8764 a_neighborId(a_neighborId(a_neighborId(childId, i, solver), j, solver), k, solver);
8765 if(a_hasNeighbor(cornerNeighbor, i, solver) > 0) {
8766 // Test check for children along path ??
8767 if(a_hasChildren(a_neighborId(cornerNeighbor, i, solver), solver)) return false;
8768
8769 if(a_hasNeighbor(a_neighborId(cornerNeighbor, i, solver), j, solver) > 0) {
8770 // Test check for children along path ??
8771 if(a_hasChildren(a_neighborId(a_neighborId(cornerNeighbor, i, solver), j, solver), solver))
8772 return false;
8773
8774 if(a_hasNeighbor(a_neighborId(a_neighborId(cornerNeighbor, i, solver), j, solver), k, solver)
8775 > 0) {
8777 a_neighborId(a_neighborId(cornerNeighbor, i, solver), j, solver), k, solver)))
8778 return false;
8779 }
8780 }
8781 }
8782 }
8783 }
8784 }
8785 }
8786 }
8787 }
8788 }
8789 //#endif
8790 }
8791 }
8792 }
8793
8794 // Not needed for lb adaptation
8795 if(!m_lbGridChecks) {
8796 // 2. additionally checks if the current cell has a missing neighbor. In this case and if it has children, it has to
8797 // be a boundary cell and
8798 // it's children need to be marked as non-coarsenable cells (this is past this function horizon).
8800 for(MInt i = 0; i < m_noDirs; i++)
8801 if(!a_hasNeighbor(cellId, i, solver)) return false;
8802 }
8803 return true;
8804}
MBool m_lbGridChecks
MBool a_hasNeighbor(const MInt cellId, const MInt dir) const
Returns noNeighborIds of the cell CellId.
MInt a_hasChildren(const MInt cellId) const
Returns if the cell cellId has children.
constexpr std::underlying_type< FcCell >::type p(const FcCell property)
Converts property name to underlying integer value.

◆ compactCells()

template<MInt nDim>
void CartesianGrid< nDim >::compactCells ( const std::vector< std::function< void(const MInt, const MInt)> > &  swapCellsSolver = std::vector<std::function<void(const MInt, const MInt)>>())
private
Author
Lennart Schneiders

Definition at line 8397 of file cartesiangrid.cpp.

8398 {
8399 MIntScratchSpace oldCellId(m_maxNoCells, AT_, "oldCellId");
8400 MIntScratchSpace isToDelete(m_maxNoCells, AT_, "isToDelete");
8401 oldCellId.fill(-1);
8402 isToDelete.fill(0);
8403 for(auto& i : m_freeIndices) {
8404 isToDelete(i) = 1;
8405 }
8406 std::set<MInt>().swap(m_freeIndices);
8407
8408 // 1. determine number of cells and internal cells
8409 MInt noCells = 0;
8411 oldCellId.fill(-1);
8412 for(MInt cellId = 0; cellId < treeb().size(); cellId++) {
8413 if(isToDelete(cellId)) continue;
8414 oldCellId(cellId) = cellId;
8415 if(!a_hasProperty(cellId, Cell::IsHalo)) m_noInternalCells++;
8416 noCells++;
8417 }
8418
8419 // 2. remove holes created by previously deleted cells and move halo cells to the back
8420 MInt otherId = treeb().size() - 1;
8421 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
8422 if(isToDelete(cellId) || a_hasProperty(cellId, Cell::IsHalo)) {
8423 while(isToDelete(otherId) || a_hasProperty(otherId, Cell::IsHalo)) {
8424 otherId--;
8425 }
8426 ASSERT(cellId < otherId, "");
8427 swapCells(cellId, otherId);
8428 for(auto& swp : swapCellsSolver) {
8429 swp(cellId, otherId); // call swapCells() function in each solver
8430 }
8431 std::swap(oldCellId(cellId), oldCellId(otherId));
8432 std::swap(isToDelete(cellId), isToDelete(otherId));
8433 ASSERT(!a_hasProperty(cellId, Cell::IsHalo), "");
8434 ASSERT(isToDelete(otherId) || a_hasProperty(otherId, Cell::IsHalo), "");
8435 }
8436 ASSERT(!a_hasProperty(cellId, Cell::IsHalo) && !isToDelete(cellId), "");
8437 ASSERT(a_level(cellId) > -1, "");
8438 }
8439
8440
8441 // 3. remove holes in the range of halo cells
8442 otherId = treeb().size() - 1;
8443 for(MInt cellId = m_noInternalCells; cellId < noCells; cellId++) {
8444 if(isToDelete(cellId)) {
8445 while(isToDelete(otherId)) {
8446 otherId--;
8447 }
8448 ASSERT(cellId < otherId, "");
8449 ASSERT(otherId >= noCells, "");
8450 ASSERT(a_hasProperty(otherId, Cell::IsHalo) && !isToDelete(otherId), "");
8451 swapCells(cellId, otherId);
8452 for(auto& swp : swapCellsSolver) {
8453 swp(cellId, otherId); // call swapCells() function in each solver
8454 }
8455 std::swap(oldCellId(cellId), oldCellId(otherId));
8456 std::swap(isToDelete(cellId), isToDelete(otherId));
8457 }
8458 ASSERT(a_hasProperty(cellId, Cell::IsHalo) && !isToDelete(cellId), "");
8459 ASSERT(a_level(cellId) > -1, "");
8460 }
8461
8462 // 4. update window/halo cell ids
8463 treeb().size(noCells);
8464 MIntScratchSpace newCellId(m_maxNoCells, AT_, "newCellId");
8465 newCellId.fill(-1);
8466 for(MInt cellId = 0; cellId < noCells; cellId++) {
8467 if(oldCellId(cellId) < 0) continue;
8468 newCellId(oldCellId(cellId)) = cellId;
8469 }
8470 for(MInt i = 0; i < noNeighborDomains(); i++) {
8471 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
8472 MInt cellId = m_haloCells[i][j];
8473 if(newCellId(cellId) > -1) {
8474 m_haloCells[i][j] = newCellId(cellId);
8475 }
8476 }
8477 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
8478 MInt cellId = m_windowCells[i][j];
8479 if(newCellId(cellId) > -1) {
8480 m_windowCells[i][j] = newCellId(cellId);
8481 }
8482 }
8483
8484 // TODO_SS labels:GRID,toenhance maybe think of something more efficient
8485 if(m_haloMode > 0) { // WH_old
8486 std::unordered_map<MInt, M32X4bit<true>> windowLayerBak_(m_windowLayer_[i]);
8487 m_windowLayer_[i].clear();
8488 for(auto m : windowLayerBak_) {
8489 if(newCellId(m.first) > -1) {
8490 m_windowLayer_[i].insert({newCellId(m.first), m.second});
8491 }
8492 }
8493 }
8494 }
8495
8496 if(m_azimuthalPer) {
8497 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
8498 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
8500 if(newCellId(cellId) > -1) {
8501 m_azimuthalHaloCells[i][j] = newCellId(cellId);
8502 }
8503 }
8504 for(MInt j = 0; j < (signed)m_azimuthalWindowCells[i].size(); j++) {
8506 if(newCellId(cellId) > -1) {
8507 m_azimuthalWindowCells[i][j] = newCellId(cellId);
8508 }
8509 }
8510 }
8511 for(MInt c = 0; c < noAzimuthalUnmappedHaloCells(); c++) {
8513 if(newCellId(cellId) > -1) {
8514 m_azimuthalUnmappedHaloCells[c] = newCellId(cellId);
8515 }
8516 }
8517 }
8518
8519 // Update partition level ancestor data
8520 {
8521 std::vector<MInt> oldPartLevelAncestorIds(m_partitionLevelAncestorIds);
8522 const MInt noPartLvlAncestorIds = oldPartLevelAncestorIds.size();
8523
8524 // m_partitionLevelAncestorChildIds.clear();
8525 // Note: the variables below seem to be not required at the moment
8526 std::vector<MInt>().swap(m_partitionLevelAncestorIds);
8527 std::vector<MInt>().swap(m_partitionLevelAncestorNghbrDomains);
8528 std::vector<std::vector<MInt>>().swap(m_partitionLevelAncestorHaloCells);
8529 std::vector<std::vector<MInt>>().swap(m_partitionLevelAncestorWindowCells);
8531
8532 // Update partition level ancestor ids and their child (global) ids
8533 for(MInt i = 0; i < noPartLvlAncestorIds; i++) {
8534 const MInt oldId = oldPartLevelAncestorIds[i];
8535 const MInt newId = newCellId(oldId);
8536 m_partitionLevelAncestorIds.push_back(newId);
8537
8538 // TODO labels:GRID Since we store the global ids of the childs, there is no need to update them.
8539 // If we would do so, we need to keep in mind that some children may reside on
8540 // neighbor domains, so we need to communicate.
8541 // for(MInt child = 0; child < m_maxNoChilds; child++) {
8542 // const MInt childId = a_childId(newId, child);
8543 // const MLong childGlobalId = (childId > -1) ? a_globalId(childId) : -1;
8544 // m_partitionLevelAncestorChildIds.push_back(childGlobalId);
8545 // }
8546 }
8547 }
8548}
std::vector< std::vector< MInt > > m_partitionLevelAncestorWindowCells
std::vector< MInt > m_partitionLevelAncestorNghbrDomains
std::vector< MInt > m_partitionLevelAncestorIds
Partition level shift.
std::set< MInt > m_freeIndices
std::vector< std::vector< MInt > > m_partitionLevelAncestorHaloCells
void swapCells(const MInt cellId, const MInt otherId)
swap two cells; the window/halo cell arrays have to be update elsewhere for performance reasons
MInt m_noHaloPartitionLevelAncestors
void swap(Tensor< TT > &a, Tensor< TT > &b)
Non-member swap exchanges the contents of two Tensors.
Definition: tensor.h:752

◆ computeGlobalIds()

template<MInt nDim>
void CartesianGrid< nDim >::computeGlobalIds
Author
Lennart Schneiders

Definition at line 10012 of file cartesiangrid.cpp.

10012 {
10013 // Update list of min-level cell ids (required later)
10015
10016 // Update number of internal cells
10018 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
10019 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
10020 if(a_isToDelete(cellId)) continue;
10022 }
10023
10024 // Exchange number of internal cells per domain
10025 const MInt noCells = m_noInternalCells;
10026 MIntScratchSpace noCellsPerDomain(noDomains(), AT_, "noCellsPerDomain");
10027 MPI_Allgather(&noCells, 1, type_traits<MInt>::mpiType(), &noCellsPerDomain[0], 1, type_traits<MInt>::mpiType(),
10028 mpiComm(), AT_, "noCells", "noCellsPerDomain[0]");
10029 ASSERT(noCellsPerDomain[domainId()] == noCells, "Local number of cells does not match.");
10030
10031 if(m_domainOffsets == nullptr) {
10032 mAlloc(m_domainOffsets, noDomains() + 1, "m_domainOffsets", 0L, AT_);
10033 }
10034
10035 // Re-calculate domain offsets
10037 for(MInt d = 0; d < noDomains(); d++) {
10038 m_domainOffsets[d + 1] = m_domainOffsets[d] + static_cast<MLong>(noCellsPerDomain[d]);
10039 }
10040
10042
10043 // Note: requirement is that min-level cells are stored, done above!
10044 const MInt firstMinLvlCell = m_minLevelCells[0];
10045 MInt localCnt = 0;
10046
10047 // Check the first min-level cell: if it is a partition-level ancestor and a halo it is the root
10048 // cell of the first local partition cell. The subtree starting from that min-level halo cell with
10049 // all locally relevant partition-level ancestor cells is contained in the local tree,
10050 // descendStoreGlobalId will skip any halo cell and will assign the first local cell the global id
10051 // corresponding to the domain offset and then continue with all offspring cells.
10052 if(a_hasProperty(firstMinLvlCell, Cell::IsPartLvlAncestor) && a_hasProperty(firstMinLvlCell, Cell::IsHalo)) {
10053 descendStoreGlobalId(firstMinLvlCell, localCnt);
10054 }
10055
10056 // Re-calculate global ids for all internal cells starting from the min-level cells
10057 // Iteration starts at 1 if first min-lvl cell is a halo partLvlAncestor (see above)
10058 for(MUint i = std::max(0, std::min(1, localCnt)); i < m_minLevelCells.size(); i++) {
10059 const MInt cellId = m_minLevelCells[i];
10060
10061 // skip halos, the only relevant halo min-level cell in case of a partition level shift is
10062 // handled above
10063 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
10064 descendStoreGlobalId(cellId, localCnt);
10065 }
10066
10067 // Update global ids for all halo cells
10068 if(noNeighborDomains() > 0) {
10069 ScratchSpace<MLong> globalId(m_tree.size(), AT_, "globalId");
10070 for(MInt i = 0; i < noNeighborDomains(); i++) {
10071 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
10072 MInt cellId = m_windowCells[i][j];
10073 globalId(cellId) = a_globalId(cellId);
10074 ASSERT(globalId(cellId) >= m_domainOffsets[domainId()] && globalId(cellId) < m_domainOffsets[domainId() + 1],
10075 "");
10076 }
10077 }
10079
10080 for(MInt i = 0; i < noNeighborDomains(); i++) {
10081 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
10082 MInt cellId = m_haloCells[i][j];
10083 a_globalId(cellId) = globalId(cellId);
10084 }
10085 }
10086 }
10087
10089 ScratchSpace<MLong> globalId(m_tree.size(), AT_, "globalId");
10090 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
10091 for(MInt j = 0; j < (signed)m_azimuthalWindowCells[i].size(); j++) {
10093 globalId(cellId) = a_globalId(cellId);
10094 ASSERT(globalId(cellId) >= m_domainOffsets[domainId()] && globalId(cellId) < m_domainOffsets[domainId() + 1],
10095 "");
10096 }
10097 }
10099 &globalId[0], 1);
10100 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
10101 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
10103 a_globalId(cellId) = globalId(cellId);
10104 }
10105 }
10106 }
10107
10108 // Update the global to local id mapping
10110
10111 // Note: when updating the partition cells it can be possible that a rank currently does not have
10112 // a partition cell anymore
10113 TERMM_IF_NOT_COND(m_noPartitionCells > 0 || m_updatingPartitionCells,
10114 "Error: number of partition cells needs to be at least 1.");
10115
10117}
MLong m_noCellsGlobal
void descendStoreGlobalId(MInt cellId, MInt &localCnt)
Recursively descend subtree to reset global id for internal cells.
maia::grid::cell::BitsetType::reference a_isToDelete(const MInt cellId)
Returns the delete of the cell cellId.
void storeMinLevelCells(const MBool updateMinlevel=false)
Store cell ids of all min-level cells.
MBool m_updatingPartitionCells
void updatePartitionCellInformation()
Update the partition cell local/global ids and the partition cell global offsets.
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgather

◆ computeLeafLevel()

template<MInt nDim>
void CartesianGrid< nDim >::computeLeafLevel
Author
Lennart Schneiders

Definition at line 10293 of file cartesiangrid.cpp.

10293 {
10294 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
10295 m_tree.resetIsLeafCell(cellId);
10296 }
10297 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
10298 for(MInt solverId = 0; solverId < m_tree.noSolvers(); solverId++) {
10299 if(m_tree.solver(cellId, solverId)) {
10300 a_isLeafCell(cellId, solverId) =
10301 !a_hasChildren(cellId, solverId) && !a_hasProperty(cellId, Cell::IsPartLvlAncestor);
10302 }
10303 }
10304 }
10305
10306 if(noNeighborDomains() > 0) {
10308 m_tree.size());
10309 }
10310
10311 if(m_azimuthalPer) {
10312 if(noAzimuthalNeighborDomains() > 0) {
10315 }
10316
10317 // Since connection between two different cell levels is possible in
10318 // azimuthal periodicity. Azimuthal halos need to be adjusted.
10319 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
10320 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
10322 for(MInt solverId = 0; solverId < m_tree.noSolvers(); solverId++) {
10323 if(m_tree.solver(cellId, solverId)) {
10324 a_isLeafCell(cellId, solverId) =
10325 !a_hasChildren(cellId, solverId) && !a_hasProperty(cellId, Cell::IsPartLvlAncestor);
10326 }
10327 }
10328 }
10329 }
10330 for(MInt i = 0; i < noAzimuthalUnmappedHaloCells(); i++) {
10332 for(MInt solverId = 0; solverId < m_tree.noSolvers(); solverId++) {
10333 if(m_tree.solver(cellId, solverId)) {
10334 a_isLeafCell(cellId, solverId) =
10335 !a_hasChildren(cellId, solverId) && !a_hasProperty(cellId, Cell::IsPartLvlAncestor);
10336 }
10337 }
10338 }
10339 }
10340}
MBool a_isLeafCell(const MInt cellId) const
Returns whether cell is leaf cellId.
SolverBitsetType & leafCellBits(const MInt id)
Accessor for properties.
void resetIsLeafCell(const MInt id)
Reset all isLeafCell.
void exchangeBitset(const std::vector< MInt > &nghbrDomains, const std::vector< std::vector< MInt > > &haloCellVec, const std::vector< std::vector< MInt > > &windowCellVec, const MPI_Comm comm, std::bitset< N > *const data, const MInt noCells, const MInt noDat=1)
Generic exchange of data.
Definition: mpiexchange.h:516

◆ computeLocalBoundingBox()

template<MInt nDim>
void CartesianGrid< nDim >::computeLocalBoundingBox ( MFloat *const  bbox)

Compute the local bounding box of all internal cells.

Definition at line 12880 of file cartesiangrid.cpp.

12880 {
12881 TRACE();
12882
12883 for(MInt i = 0; i < nDim; i++) {
12884 bbox[i] = numeric_limits<MFloat>::max();
12885 bbox[nDim + i] = numeric_limits<MFloat>::lowest();
12886 }
12887
12888 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
12889 if(a_hasProperty(cellId, Cell::IsHalo)) {
12890 continue;
12891 }
12892
12893 const MFloat halfCellLength = F1B2 * cellLengthAtLevel(a_level(cellId));
12894 for(MInt i = 0; i < nDim; i++) {
12895 bbox[i] = mMin(bbox[i], a_coordinate(cellId, i) - halfCellLength);
12896 bbox[nDim + i] = mMax(bbox[nDim + i], a_coordinate(cellId, i) + halfCellLength);
12897 }
12898 }
12899 // See createMinLevelExchangeCells()
12900 const MFloat halfLength0 = 0.5 * ((F1 + F1 / FPOW2(30)) * m_lengthLevel0);
12901 for(MInt i = 0; i < nDim; i++) {
12902 ASSERT(bbox[i] > m_centerOfGravity[i] - halfLength0 && bbox[nDim + i] < m_centerOfGravity[i] + halfLength0,
12903 "local bounding box error");
12904 }
12905
12907}
MBool m_localBoundingBoxInit
MFloat halfCellLength(const MInt cellId) const
Returns the half cell length of cell cellId.
constexpr T mMin(const T &x, const T &y)
Definition: functions.h:90
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
constexpr MFloat FPOW2(MInt x)

◆ correctAzimuthalSolverBits()

template<MInt nDim>
void CartesianGrid< nDim >::correctAzimuthalSolverBits
Author
Thomas Hoesgen
Date
November 2020

Definition at line 14703 of file cartesiangrid.cpp.

14703 {
14704 TRACE();
14705
14707 for(MInt level = m_maxUniformRefinementLevel; level < maxLvl; level++) {
14708 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
14709 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
14711 if(a_level(cellId) != level) continue;
14712 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
14713 if(m_tree.solver(cellId, solver)) {
14714 MBool noRefine = false;
14715 for(MInt child = 0; child < m_maxNoChilds; child++) {
14716 MInt childId = a_childId(cellId, child);
14717 if(childId == -1) continue;
14718 if(!m_tree.solver(childId, solver)) {
14719 noRefine = true;
14720 break;
14721 }
14722 }
14723 if(noRefine) {
14724 for(MInt child = 0; child < m_maxNoChilds; child++) {
14725 MInt childId = a_childId(cellId, child);
14726 if(childId == -1) continue;
14727 m_tree.solver(childId, solver) = false;
14728 }
14729 }
14730 } else {
14731 for(MInt child = 0; child < m_maxNoChilds; child++) {
14732 MInt childId = a_childId(cellId, child);
14733 if(childId == -1) continue;
14734 m_tree.solver(childId, solver) = false;
14735 }
14736 }
14737 }
14738 }
14739 }
14740
14741
14742 for(MInt i = 0; i < (signed)m_azimuthalUnmappedHaloCells.size(); i++) {
14744 if(a_level(cellId) != level) continue;
14745 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
14746 if(m_tree.solver(cellId, solver)) {
14747 MBool noRefine = false;
14748 for(MInt child = 0; child < m_maxNoChilds; child++) {
14749 MInt childId = a_childId(cellId, child);
14750 if(childId == -1) continue;
14751 if(!m_tree.solver(childId, solver)) {
14752 noRefine = true;
14753 break;
14754 }
14755 }
14756 if(noRefine) {
14757 for(MInt child = 0; child < m_maxNoChilds; child++) {
14758 MInt childId = a_childId(cellId, child);
14759 if(childId == -1) continue;
14760 m_tree.solver(childId, solver) = false;
14761 }
14762 }
14763 } else {
14764 for(MInt child = 0; child < m_maxNoChilds; child++) {
14765 MInt childId = a_childId(cellId, child);
14766 if(childId == -1) continue;
14767 m_tree.solver(childId, solver) = false;
14768 }
14769 }
14770 }
14771 }
14772 }
14773}
MInt m_maxLevel
The max Level of refinement of the solver length.
MInt m_maxUniformRefinementLevel

◆ createAdjacentHaloCell()

template<MInt nDim>
MInt CartesianGrid< nDim >::createAdjacentHaloCell ( const MInt  cellId,
const MInt  dir,
const MLong hilbertOffsets,
std::unordered_multimap< MLong, MInt > &  hilbertToLocal,
const MFloat bbox,
MInt * const  noHalos,
std::vector< std::vector< MInt > > &  halos,
std::vector< std::vector< MLong > > &  hilbertIds 
)
private
Author
Lennart Schneiders
Date
October 2017

Definition at line 3984 of file cartesiangrid.cpp.

3987 {
3988 static constexpr MInt revDir[6] = {1, 0, 3, 2, 5, 4};
3989 const MFloat cellLength = cellLengthAtCell(cellId);
3990
3991 MFloat coords[3];
3992 MFloat dcoords[3];
3993 MFloat dummyCoords[3];
3994 for(MInt i = 0; i < nDim; i++) {
3995 coords[i] = a_coordinate(cellId, i);
3996 }
3997 coords[dir / 2] += ((dir % 2) == 0 ? -F1 : F1) * cellLength;
3998
3999 for(MInt i = 0; i < nDim; i++) {
4000 if(!m_periodicCartesianDir[dir / 2] && (coords[dir / 2] < bbox[dir / 2] || coords[dir / 2] > bbox[nDim + dir / 2]))
4001 return -1;
4002 }
4003
4004 MBool insd = true;
4005 for(MInt i = 0; i < nDim; i++) {
4006 if(coords[i] < bbox[i] || coords[i] > bbox[nDim + i]) insd = false;
4007 }
4008 MBool isPeriodic = !insd;
4009
4010 if(m_azimuthalPer && isPeriodic) return -1;
4011
4012 MFloat dx[3];
4013 for(MInt i = 0; i < nDim; i++) {
4014 dx[i] = bbox[nDim + i] - bbox[i];
4015 }
4016 for(MInt i = 0; i < nDim; i++) {
4017 dummyCoords[i] = coords[i];
4018 }
4019 if(isPeriodic) {
4020 for(MInt i = 0; i < nDim; i++) {
4021 if(coords[i] < bbox[i])
4022 dummyCoords[i] += dx[i];
4023 else if(coords[i] > bbox[nDim + i])
4024 dummyCoords[i] -= dx[i];
4025 }
4026 }
4027
4028 for(MInt i = 0; i < nDim; i++) {
4029 if(dummyCoords[i] < bbox[i] || dummyCoords[i] > bbox[nDim + i]) {
4030 mTerm(1, AT_, "Halo cell coords outside domain");
4031 }
4032 }
4033
4034 const MLong hilbertIndex = hilbertIndexGeneric(&dummyCoords[0]);
4035 MInt ndom = -1;
4036 while(hilbertIndex >= hilbertOffsets[ndom + 1]) {
4037 ndom++;
4038 if(ndom == noDomains() - 1) break;
4039 }
4040 ASSERT(ndom > -1, "");
4041 ASSERT(hilbertIndex >= hilbertOffsets[ndom] && hilbertIndex < hilbertOffsets[ndom + 1],
4042 to_string(hilbertIndex) + " " + to_string(hilbertOffsets[ndom]) + " " + to_string(hilbertOffsets[ndom + 1]));
4043
4044 const MInt haloCellId = m_tree.size();
4045 m_tree.append();
4046
4047 for(MInt i = 0; i < nDim; i++) {
4048 a_level(haloCellId) = a_level(cellId);
4049 }
4050
4051 for(MInt i = 0; i < nDim; i++) {
4052 a_coordinate(haloCellId, i) = coords[i];
4053 }
4054
4055 hilbertToLocal.insert(make_pair(hilbertIndex, haloCellId));
4056
4057 for(MInt i = 0; i < m_noDirs; i++) {
4058 a_neighborId(haloCellId, i) = -1;
4059 }
4060 for(MInt i = 0; i < m_maxNoChilds; i++) {
4061 a_childId(haloCellId, i) = -1;
4062 }
4063 a_parentId(haloCellId) = -1;
4064
4065 a_neighborId(cellId, dir) = haloCellId;
4066 a_neighborId(haloCellId, revDir[dir]) = cellId;
4067 for(MInt otherDir = 0; otherDir < m_noDirs; otherDir++) {
4068 if(otherDir / 2 == dir / 2) continue;
4069 if(a_hasNeighbor(cellId, otherDir) == 0) continue;
4070 MInt nghbrId = a_neighborId(cellId, otherDir);
4071 if(a_hasNeighbor(nghbrId, dir) > 0) {
4072 nghbrId = a_neighborId(nghbrId, dir);
4073 a_neighborId(nghbrId, revDir[otherDir]) = haloCellId;
4074 a_neighborId(haloCellId, otherDir) = nghbrId;
4075 }
4076 }
4077 for(MInt ndir = 0; ndir < m_noDirs; ndir++) {
4078 if(a_hasNeighbor(haloCellId, ndir) > 0) continue;
4079 for(MInt i = 0; i < nDim; i++) {
4080 dummyCoords[i] = a_coordinate(haloCellId, i);
4081 }
4082 dummyCoords[ndir / 2] += ((ndir % 2) == 0 ? -F1 : F1) * cellLength;
4083 for(MInt i = 0; i < nDim; i++) {
4084 dcoords[i] = dummyCoords[i];
4085 }
4086 for(MInt i = 0; i < nDim; i++) {
4087 if(dummyCoords[i] < bbox[i])
4088 dummyCoords[i] += dx[i];
4089 else if(dummyCoords[i] > bbox[nDim + i])
4090 dummyCoords[i] -= dx[i];
4091 }
4092 const MLong nghbrHilbertId = hilbertIndexGeneric(&dummyCoords[0]);
4093 MInt nghbrId = -1;
4094 auto range = hilbertToLocal.equal_range(nghbrHilbertId);
4095 for(auto it = range.first; it != range.second; ++it) {
4096 MFloat dist = F0;
4097 for(MInt i = 0; i < nDim; i++) {
4098 dist += POW2(a_coordinate(it->second, i) - dcoords[i]);
4099 }
4100 dist = sqrt(dist);
4101 if(dist < 0.001 * cellLength) {
4102 if(nghbrId > -1) cerr << "duplicate " << hilbertToLocal.count(nghbrHilbertId) << endl;
4103 nghbrId = it->second;
4104 }
4105 }
4106 if(nghbrId < 0) continue;
4107
4108#ifndef NDEBUG
4109 for(MInt i = 0; i < nDim; i++) {
4110 ASSERT(fabs(a_coordinate(nghbrId, i) - a_coordinate(haloCellId, i)) < cellLength * 1.0001, "");
4111 }
4112#endif
4113 a_neighborId(nghbrId, revDir[ndir]) = haloCellId;
4114 a_neighborId(haloCellId, ndir) = nghbrId;
4115 }
4116
4117 a_resetProperties(haloCellId);
4118 a_hasProperty(haloCellId, Cell::IsHalo) = true;
4119 a_hasProperty(haloCellId, Cell::IsPeriodic) = isPeriodic;
4120
4121 MInt idx = setNeighborDomainIndex(ndom, halos, hilbertIds);
4122 ASSERT(idx > -1, "");
4123 halos[idx].push_back(haloCellId);
4124 hilbertIds[idx].push_back(hilbertIndex);
4125 noHalos[ndom]++;
4126
4127 return haloCellId;
4128}
void a_resetProperties(const MInt cellId)
Returns property p of the cell cellId.
MLong hilbertIndexGeneric(const MFloat *const coords, const MFloat *const center, const MFloat length0, const MInt baseLevel) const
Return the hilbert index for the given coordinates in 2D/3D.
MInt setNeighborDomainIndex(const MInt, std::vector< TA > &, std::vector< TB > &, std::vector< TC > &)
Find neighbor domain index or create new if not existing.
MFloat cellLengthAtCell(const MInt cellId) const
Returns the cell length of cell cellId.
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54

◆ createAzimuthalHaloCell()

template<MInt nDim>
MInt CartesianGrid< nDim >::createAzimuthalHaloCell ( const MInt  cellId,
const MInt  dir,
const MLong hilbertOffsets,
std::unordered_multimap< MLong, MInt > &  hilbertToLocal,
const MFloat bbox,
MInt * const  noHalos,
std::vector< std::vector< MInt > > &  halos,
std::vector< std::vector< MLong > > &  hilbertIds 
)
private
Author
Thomas Hoesgen

Definition at line 14174 of file cartesiangrid.cpp.

14177 {
14178 static constexpr MInt revDir[6] = {1, 0, 3, 2, 5, 4};
14179 const MFloat cellLength = cellLengthAtCell(cellId);
14180
14181 MFloat coords[3];
14182 MFloat coordsCyl[3];
14183 MFloat dcoords[3];
14184 MFloat dummyCoords[3];
14185 MFloat dxCyl = F0;
14186 for(MInt i = 0; i < nDim; i++) {
14187 coords[i] = a_coordinate(cellId, i);
14188 }
14189 coords[dir / 2] += ((dir % 2) == 0 ? -F1 : F1) * cellLength;
14190
14191 if(!m_periodicCartesianDir[dir / 2] && (coords[dir / 2] < bbox[dir / 2] || coords[dir / 2] > bbox[nDim + dir / 2])) {
14192 return -1;
14193 }
14194
14195 MBool isPeriodic = false;
14196
14197 for(MInt i = 0; i < nDim; i++) {
14198 dummyCoords[i] = coords[i];
14199 }
14200
14201 cartesianToCylindric(coords, coordsCyl);
14202 dxCyl = m_azimuthalAngle;
14203
14204 if(coordsCyl[1] < m_azimuthalBbox.azimuthalBoundary(coords, -1) - MFloatEps) {
14205 isPeriodic = true;
14206 rotateCartesianCoordinates(dummyCoords, -dxCyl);
14207 } else if(coordsCyl[1] > m_azimuthalBbox.azimuthalBoundary(coords, 1) + MFloatEps) {
14208 isPeriodic = true;
14209 rotateCartesianCoordinates(dummyCoords, dxCyl);
14210 } else if(approx(dxCyl, 0.5 * PI, pow(10, -12))) {
14211 if(m_azimuthalBbox.azimuthalCenter(/*coords*/) > F0 && m_azimuthalBbox.azimuthalCenter(/*coords*/) < 0.5 * PI) {
14212 if(dir / 2 == 1 && coords[1] < bbox[1]) {
14213 isPeriodic = true;
14214 rotateCartesianCoordinates(dummyCoords, -dxCyl);
14215 }
14216 if(dir / 2 == 2 && coords[2] < bbox[2]) {
14217 isPeriodic = true;
14218 rotateCartesianCoordinates(dummyCoords, dxCyl);
14219 }
14220 } else {
14221 mTerm(1, AT_, "Do some implementing!");
14222 }
14223 }
14224
14225 if(!isPeriodic) return -1;
14226
14227 const MInt hilbertIndex = hilbertIndexGeneric(&dummyCoords[0]);
14228
14229 MInt ndom = -1;
14230 while(hilbertIndex >= hilbertOffsets[ndom + 1]) {
14231 ndom++;
14232 if(ndom == noDomains() - 1) break;
14233 }
14234 ASSERT(ndom > -1, "");
14235 ASSERT(hilbertIndex >= hilbertOffsets[ndom] && hilbertIndex < hilbertOffsets[ndom + 1],
14236 to_string(hilbertIndex) + " " + to_string(hilbertOffsets[ndom]) + " " + to_string(hilbertOffsets[ndom + 1]));
14237
14238 const MInt haloCellId = m_tree.size();
14239 m_tree.append();
14240
14241 for(MInt i = 0; i < nDim; i++) {
14242 a_level(haloCellId) = a_level(cellId);
14243 }
14244
14245 for(MInt i = 0; i < nDim; i++) {
14246 a_coordinate(haloCellId, i) = coords[i];
14247 }
14248
14249 hilbertToLocal.insert(make_pair(hilbertIndex, haloCellId));
14250
14251 for(MInt i = 0; i < m_noDirs; i++) {
14252 a_neighborId(haloCellId, i) = -1;
14253 }
14254 for(MInt i = 0; i < m_maxNoChilds; i++) {
14255 a_childId(haloCellId, i) = -1;
14256 }
14257 a_parentId(haloCellId) = -1;
14258
14259 a_neighborId(cellId, dir) = haloCellId;
14260 a_neighborId(haloCellId, revDir[dir]) = cellId;
14261 for(MInt otherDir = 0; otherDir < m_noDirs; otherDir++) {
14262 if(otherDir / 2 == dir / 2) continue;
14263 if(a_hasNeighbor(cellId, otherDir) == 0) continue;
14264 MInt nghbrId = a_neighborId(cellId, otherDir);
14265 if(a_hasNeighbor(nghbrId, dir) > 0) {
14266 nghbrId = a_neighborId(nghbrId, dir);
14267 a_neighborId(nghbrId, revDir[otherDir]) = haloCellId;
14268 a_neighborId(haloCellId, otherDir) = nghbrId;
14269 }
14270 }
14271
14272 for(MInt ndir = 0; ndir < m_noDirs; ndir++) {
14273 if(a_hasNeighbor(haloCellId, ndir) > 0) continue;
14274 for(MInt i = 0; i < nDim; i++) {
14275 dummyCoords[i] = a_coordinate(haloCellId, i);
14276 }
14277 dummyCoords[ndir / 2] += ((ndir % 2) == 0 ? -F1 : F1) * cellLength;
14278 for(MInt i = 0; i < nDim; i++) {
14279 dcoords[i] = dummyCoords[i];
14280 }
14281 MLong nghbrHilbertId = hilbertIndexGeneric(&dummyCoords[0]);
14282 MInt nghbrId = -1;
14283 auto range = hilbertToLocal.equal_range(nghbrHilbertId);
14284 for(auto it = range.first; it != range.second; ++it) {
14285 MFloat dist = F0;
14286 for(MInt i = 0; i < nDim; i++) {
14287 dist += POW2(a_coordinate(it->second, i) - dcoords[i]);
14288 }
14289 dist = sqrt(dist);
14290 if(dist < 0.001 * cellLength) {
14291 if(nghbrId > -1) cerr << "duplicate " << hilbertToLocal.count(nghbrHilbertId) << endl;
14292 nghbrId = it->second;
14293 }
14294 }
14295 if(nghbrId > -1) {
14296 a_neighborId(nghbrId, revDir[ndir]) = haloCellId;
14297 a_neighborId(haloCellId, ndir) = nghbrId;
14298#ifndef NDEBUG
14299 for(MInt i = 0; i < nDim; i++) {
14300 ASSERT(fabs(a_coordinate(nghbrId, i) - a_coordinate(haloCellId, i)) < cellLength * 1.0001, "");
14301 }
14302#endif
14303 continue;
14304 }
14305
14306 for(MInt i = 0; i < nDim; i++) {
14307 cartesianToCylindric(dummyCoords, coordsCyl);
14308 dxCyl = m_azimuthalAngle;
14309 if(coordsCyl[1] < m_azimuthalBbox.azimuthalBoundary(coords, -1)) {
14310 rotateCartesianCoordinates(dummyCoords, -dxCyl);
14311 } else if(coordsCyl[1] > m_azimuthalBbox.azimuthalBoundary(coords, 1)) {
14312 rotateCartesianCoordinates(dummyCoords, dxCyl);
14313 }
14314 }
14315 nghbrHilbertId = hilbertIndexGeneric(&dummyCoords[0]);
14316 nghbrId = -1;
14317 range = hilbertToLocal.equal_range(nghbrHilbertId);
14318 for(auto it = range.first; it != range.second; ++it) {
14319 MFloat dist = F0;
14320 for(MInt i = 0; i < nDim; i++) {
14321 dist += POW2(a_coordinate(it->second, i) - dcoords[i]);
14322 }
14323 dist = sqrt(dist);
14324 if(dist < 0.001 * cellLength) {
14325 if(nghbrId > -1) cerr << "duplicate " << hilbertToLocal.count(nghbrHilbertId) << endl;
14326 nghbrId = it->second;
14327 }
14328 }
14329 if(nghbrId > -1) {
14330 a_neighborId(nghbrId, revDir[ndir]) = haloCellId;
14331 a_neighborId(haloCellId, ndir) = nghbrId;
14332#ifndef NDEBUG
14333 for(MInt i = 0; i < nDim; i++) {
14334 ASSERT(fabs(a_coordinate(nghbrId, i) - a_coordinate(haloCellId, i)) < cellLength * 1.0001, "");
14335 }
14336#endif
14337 }
14338 }
14339
14340 a_resetProperties(haloCellId);
14341 a_hasProperty(haloCellId, Cell::IsHalo) = true;
14342 a_hasProperty(haloCellId, Cell::IsPeriodic) = isPeriodic;
14343
14344 MInt idx = setAzimuthalNeighborDomainIndex(ndom, halos, hilbertIds);
14345 ASSERT(idx > -1, "");
14346 halos[idx].push_back(haloCellId);
14347 hilbertIds[idx].push_back(hilbertIndex);
14348 noHalos[ndom]++;
14349
14350 return haloCellId;
14351}
void rotateCartesianCoordinates(MFloat *, MFloat)
Rotate caresian coordinates by angle. Azimuthal periodic center is used.
MFloat m_azimuthalAngle
void cartesianToCylindric(const MFloat *, MFloat *)
Transform cartesian cell coordinate to cylindrcal coordinats using the / using the azimuthal periodic...
azimuthalBbox m_azimuthalBbox
MInt setAzimuthalNeighborDomainIndex(const MInt, std::vector< std::vector< MInt > > &, std::vector< std::vector< MInt > > &)
Find azimuthal neighbor domain index or create new if not existing.
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
MFloat azimuthalBoundary(const MFloat *coords, MInt side)

◆ createGlobalToLocalIdMapping()

template<MInt nDim>
void CartesianGrid< nDim >::createGlobalToLocalIdMapping
private

Definition at line 9893 of file cartesiangrid.cpp.

9893 {
9894 TRACE();
9895
9896 std::map<MLong, MInt>().swap(m_globalToLocalId);
9897 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
9898 // multiple periodic cells with identical globalId may appear
9899 // if neccessary, m_globalToLocalId should be changed to a multimap
9900 if(a_hasProperty(cellId, Cell::IsPeriodic)) continue;
9901
9902 if(a_hasProperty(cellId, Cell::IsToDelete)) continue;
9903
9904 if(a_globalId(cellId) > -1) {
9905 ASSERT(m_globalToLocalId.count(a_globalId(cellId)) == 0,
9906 "Global id already in map: " + std::to_string(a_globalId(cellId)) + " " + std::to_string(cellId) + " "
9907 + std::to_string(m_globalToLocalId[a_globalId(cellId)]));
9909 } else if(!a_isToDelete(cellId)) {
9910 TERMM(1,
9911 "Error: invalid global id for cell #" + std::to_string(cellId) + ": " + std::to_string(a_globalId(cellId)));
9912 }
9913 }
9914}

◆ createGridMap()

template<MInt nDim>
void CartesianGrid< nDim >::createGridMap ( const MString donorGridFileName,
const MString gridMapFileName 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-03-16
Parameters
[in]donorGridFileNameName of the original (donor) grid file.
[in]gridMapFileNameName of the file where grid map should be stored.

The grid map file contains an array 'cellIds' with a value for each cell of the loaded grid file. The value is either -1 if no corresponding cell exists in the donor grid, or the corresponding cell id (global id). Additionally, there is an array 'noOffspring' that contains the number of mapped donor cell offspring for each target cell. This value is 0 if either a target cell has zero or only one donor cell. Otherwise, for a target cell without children it contains the number of offspring of the donor cell, i.e. the number of all smaller cells contained in this cell on the donor grid that are mapped to this target cell.

Note: Currently only one-to-one and multiple-to-one mappings are allowed, multiple-to-one mappings are not supported yet. That is, the donor cells must be smaller or at the same level as the target cells, while coarser donor cells are not allowed yet.

const MBool hasDiff = any_of(partitionCellsLvlDiff.cbegin(),

Definition at line 9272 of file cartesiangrid.cpp.

9272 {
9273 TRACE();
9274
9275 m_log << "Creating grid map from donor grid " << donorGridFileName << " to target grid " << m_gridInputFileName
9276 << " and writing the results to " << gridMapFileName << "..." << endl;
9277
9279 // Step 0: sanity checks
9281
9282 // Open donor grid for reading
9283 using namespace parallel_io;
9284 ParallelIo donorGrid(donorGridFileName, PIO_READ, mpiComm());
9285
9286 // Check extents
9287 array<MFloat, nDim> donorCenter;
9288 // donorGrid.setOffset(nDim, 0);
9289 // donorGrid.readArray(&donorCenter[0], "centerOfGravity");
9290 donorGrid.getAttribute(&donorCenter[0], "centerOfGravity", nDim);
9291 MFloat donorLengthLevel0 = NAN;
9292 // donorGrid.readScalar(&donorLengthLevel0, "lengthLevel0");
9293 donorGrid.getAttribute(&donorLengthLevel0, "lengthLevel0");
9294 const array<MString, 3> dirs = {{"x", "y", "z"}};
9295 for(MInt dir = 0; dir < nDim; dir++) {
9296 const array<MFloat, 2> donorExtent = {
9297 {donorCenter[dir] - 0.5 * donorLengthLevel0, donorCenter[dir] + 0.5 * donorLengthLevel0}};
9298 const array<MFloat, 2> targetExtent = {
9299 {m_centerOfGravity[dir] - 0.5 * lengthLevel0(), m_centerOfGravity[dir] + 0.5 * lengthLevel0()}};
9300 if(donorExtent[0] < targetExtent[0]) {
9301 TERMM(1, "Donor grid extents exceed target grid in negative " + dirs[dir] + "-direction");
9302 }
9303 if(donorExtent[1] > targetExtent[1]) {
9304 TERMM(1, "Donor grid extents exceed target grid in positive " + dirs[dir] + "-direction");
9305 }
9306 }
9307
9308 // Define epsilon for floating point comparisons (argh!)... the original
9309 // definition is taken from the constructor but it must be clear to anyone
9310 // that this is a less-than-optimal solution
9311 const MFloat eps = 1.0 / FPOW2(30) * m_lengthLevel0;
9312
9313 // Check cell length at min level
9314 MInt donorMinLevel = 0;
9315 // donorGrid.readScalar(&donorMinLevel, "minLevel");
9316 donorGrid.getAttribute(&donorMinLevel, "minLevel");
9317 const MFloat donorMinLevelLength = donorLengthLevel0 * FFPOW2(donorMinLevel);
9318 const MFloat targetMinLevelLength = cellLengthAtLevel(minLevel());
9319 if(fabs(donorMinLevelLength - targetMinLevelLength) > eps) {
9320 TERMM(1,
9321 "Length of min level cells do not match between donor and target "
9322 "grid: donor: "
9323 + to_string(donorMinLevelLength) + "; target: " + to_string(targetMinLevelLength));
9324 }
9325
9326 // Check if grid centers are displaced by an integer multiple of the min
9327 // level length
9328 for(MInt dir = 0; dir < nDim; dir++) {
9329 const MFloat displacement = fabs(donorCenter[dir] - m_centerOfGravity[dir]);
9330 const MFloat quotient = displacement / targetMinLevelLength;
9331 if(!isApproxInt(quotient, eps)) {
9332 TERMM(1, "The grid centers are displaced in the " + dirs[dir]
9333 + "-direction by a non-integer multiple of the length of a "
9334 "partition cell: "
9335 + to_string(quotient));
9336 }
9337 }
9338
9339
9341 // Step 1: partition donor grid
9343
9344 // Read partition cells and partition donor grid
9345 // const MInt noPartitionCells = donorGrid.getArraySize("partitionCellsId");
9347 donorGrid.getAttribute(&noPartitionCells, "noPartitionCells");
9348
9349 // Read data only on MPI root by setting the offsets accordingly
9350 donorGrid.setOffset(isMpiRoot() ? noPartitionCells : 0, 0);
9351
9352 // Ensure that there are no partition level shifts as this is not yet supported
9353 {
9354 // MIntScratchSpace partitionCellsLvlDiff(noPartitionCells, AT_, "partitionCellsLvlDiff");
9355 // donorGrid.readArray(&partitionCellsLvlDiff[0], "partitionCellsLvlDiff");
9357 // partitionCellsLvlDiff.cend(),
9358 // [](MInt diff) { return diff != 0; });
9359 MInt hasDiff = 0;
9360 donorGrid.getAttribute(&hasDiff, "maxPartitionLevelShift");
9361 if(hasDiff != 0) {
9362 TERMM(1, "partition level shifts not supported but level difference found");
9363 }
9364 }
9365
9366 // Determine offsets
9367 MIntScratchSpace partitionCellsId(noPartitionCells, AT_, "partitionCellsId");
9368 MIntScratchSpace globalIdOffsets(noDomains(), AT_, "globalIdOffsets");
9369 {
9370 // Determine partition cell offsets
9371 MIntScratchSpace offsets(noDomains() + 1, AT_, "offsets");
9372 MFloatScratchSpace partitionCellsWorkLoad(noPartitionCells, AT_, "partitionCellsWorkLoad");
9373 // donorGrid.readArray(&partitionCellsWorkLoad[0], "partitionCellsWorkLoad");
9374 donorGrid.readArray(&partitionCellsWorkLoad[0], "partitionCellsWorkload");
9375 if(isMpiRoot() && noDomains() > 1) {
9376 grid::optimalPartitioningSerial(&partitionCellsWorkLoad[0], noPartitionCells, noDomains(), &offsets[0]);
9377 }
9378
9379 // Determine global id offsets
9380 // MIntScratchSpace partitionCellsNoOffsprings(noPartitionCells, AT_,
9381 // "partitionCellsNoOffsprings");
9382 // donorGrid.readArray(&partitionCellsNoOffsprings[0], "partitionCellsNoOffsprings");
9383 // donorGrid.readArray(&partitionCellsId[0], "partitionCellsId");
9384 donorGrid.readArray(&partitionCellsId[0], "partitionCellsGlobalId");
9385 if(isMpiRoot() && noDomains() > 1) {
9386 grid::partitionCellToGlobalOffsets(&offsets[0], &partitionCellsId[0], noDomains(), &globalIdOffsets[0]);
9387 }
9388 }
9389
9390 // Distribute global id offsets
9391 MPI_Bcast(&globalIdOffsets[0], noDomains(), type_traits<MInt>::mpiType(), 0, mpiComm(), AT_, "globalIdOffsets[0]");
9392
9393 // Distribute partition cells ids
9394 MPI_Bcast(&partitionCellsId[0], noPartitionCells, type_traits<MInt>::mpiType(), 0, mpiComm(), AT_,
9395 "partitionCellsId[0]");
9396
9397
9399 // Step 2: calculate Hilbert indices for donor grid and current cells
9401
9402 // Determine Hilbert index for all partition cells for which coordinates were read
9403 MIntScratchSpace hilbertIds(noPartitionCells, AT_, "hilbertIds");
9404 const MInt noCells = m_noInternalCells;
9405 MIntScratchSpace localHilbertIds(noCells, AT_, "localHilbertIds");
9406 {
9407 // Determine offset and length for reading coordinate information
9408 // const MInt globalCount = donorGrid.getArraySize("parentId");
9409 MInt globalCount = 0;
9410 donorGrid.getAttribute(&globalCount, "noCells");
9411 const MInt globalIdOffset = globalIdOffsets[domainId()];
9412 const MInt localCount = (domainId() == noDomains() - 1)
9413 ? globalCount - globalIdOffsets[domainId()]
9414 : globalIdOffsets[domainId() + 1] - globalIdOffsets[domainId()];
9415
9416 // Read coordinates
9417 MFloatScratchSpace coordinates(nDim * localCount, AT_, "coordinates");
9418 /*donorGrid.setOffset(localCount, globalIdOffset);
9419 for (MInt i = 0; i < nDim; i++) {
9420 const MString name = "coordinates_" + to_string(i);
9421 donorGrid.readArray(&coordinates[i], name, nDim);
9422 }*/
9423 MLongScratchSpace minLevelCellsTreeId(noPartitionCells, AT_, "minLevelCellsTreeId");
9424 {
9425 donorGrid.setOffset(noPartitionCells, 0);
9426 donorGrid.readArray(minLevelCellsTreeId.data(), "minLevelCellsTreeId");
9427 }
9428
9429 // Determine Hilbert index
9430 fill(hilbertIds.begin(), hilbertIds.end(), -1);
9431 for(MInt i = 0; i < noPartitionCells; i++) {
9432 // Skip partition cells that are outside the range
9433 const MInt globalId = partitionCellsId[i];
9434 if(globalId < globalIdOffset || globalId >= globalIdOffset + localCount) {
9435 continue;
9436 }
9437
9438 // Determine coordinates relative to unit cube
9439 array<MFloat, nDim> x;
9440 const MInt localCellId = globalId - globalIdOffset;
9441 maia::grid::hilbert::treeIdToCoordinates<nDim>(&coordinates[localCellId * nDim], minLevelCellsTreeId[i],
9442 (MLong)m_minLevel, &donorCenter[0], donorLengthLevel0);
9443 for(MInt j = 0; j < nDim; j++) {
9444 x[j] = (coordinates[localCellId * nDim + j] - m_centerOfGravity[j] + 0.5 * lengthLevel0()) / lengthLevel0();
9445 }
9446
9447 // Calculate Hilbert index
9448 hilbertIds[i] = maia::grid::hilbert::index<nDim>(&x[0], minLevel());
9449 }
9450
9451 // Determine Hilbert index for all cells on current domain
9452 for(MInt cellId = 0; cellId < noCells; cellId++) {
9453 // Skip cells that are not partition cells
9454 if(a_level(cellId) != minLevel()) {
9455 continue;
9456 }
9457
9458 // Determine coordinates relative to unit cube
9459 array<MFloat, nDim> x;
9460 for(MInt j = 0; j < nDim; j++) {
9461 x[j] = (a_coordinate(cellId, j) - m_centerOfGravity[j] + 0.5 * lengthLevel0()) / lengthLevel0();
9462 }
9463
9464 // Calculate Hilbert index
9465 localHilbertIds[cellId] = maia::grid::hilbert::index<nDim>(&x[0], minLevel());
9466 }
9467 }
9468
9469
9471 // Step 3: exchange Hilbert ids of donor grid with all domains (parallel only)
9473
9474 // Determine how much data is to exchange and how to receive it
9475 {
9476 MIntScratchSpace dataCount(noDomains(), AT_, "dataCount");
9477 const MInt noCellsFound = count_if(hilbertIds.begin(), hilbertIds.end(), [](const MInt a) { return a != -1; });
9478 dataCount[domainId()] = noCellsFound;
9479 MPI_Allgather(MPI_IN_PLACE, 1, maia::type_traits<MInt>::mpiType(), &dataCount[0], 1,
9480 maia::type_traits<MInt>::mpiType(), mpiComm(), AT_, "MPI_IN_PLACE", "dataCount[0]");
9481 MIntScratchSpace displacements(noDomains(), AT_, "displacements");
9482 displacements[0] = 0;
9483 for(MInt i = 1; i < noDomains(); i++) {
9484 displacements[i] = displacements[i - 1] + dataCount[i - 1];
9485 }
9486 MIntScratchSpace sendBuffer(noCellsFound, AT_, "sendBuffer");
9487
9488 // Exchange partition cell ids
9489 for(MInt count = 0, i = 0; i < noPartitionCells; i++) {
9490 if(hilbertIds[i] == -1) {
9491 continue;
9492 }
9493 sendBuffer[count++] = partitionCellsId[i];
9494 }
9495 MPI_Allgatherv(&sendBuffer[0], noCellsFound, maia::type_traits<MInt>::mpiType(), &partitionCellsId[0],
9496 &dataCount[0], &displacements[0], maia::type_traits<MInt>::mpiType(), mpiComm(), AT_,
9497 "sendBuffer[0]", "partitionCellsId[0]");
9498
9499 // Exchange Hilbert ids
9500 for(MInt count = 0, i = 0; i < noPartitionCells; i++) {
9501 if(hilbertIds[i] == -1) {
9502 continue;
9503 }
9504 sendBuffer[count++] = hilbertIds[i];
9505 }
9506 MPI_Allgatherv(&sendBuffer[0], noCellsFound, maia::type_traits<MInt>::mpiType(), &hilbertIds[0], &dataCount[0],
9507 &displacements[0], maia::type_traits<MInt>::mpiType(), mpiComm(), AT_, "sendBuffer[0]",
9508 "hilbertIds[0]");
9509 }
9510
9511
9513 // Step 4: determine grid map and write to file
9515
9516 // Sort partition cell ids (and Hilbert ids) by Hilbert id
9517 {
9519 for(MInt i = 0; i < noPartitionCells; i++) {
9520 s[i][0] = hilbertIds[i];
9521 s[i][1] = partitionCellsId[i];
9522 }
9523 sort(s.begin(), s.end(), [](const array<MInt, 2>& a, const array<MInt, 2>& b) { return a[0] < b[0]; });
9524 for(MInt i = 0; i < noPartitionCells; i++) {
9525 hilbertIds[i] = s[i][0];
9526 partitionCellsId[i] = s[i][1];
9527 }
9528 }
9529
9530 MIntScratchSpace gridMap(noCells, AT_, "gridMap");
9531 fill(gridMap.begin(), gridMap.end(), -1);
9532
9533 MInt firstMappedPartitionCellId = std::numeric_limits<MInt>::max();
9534 MInt noMappedPartitionCells = 0;
9535
9536 // Determine matching partition cells, the first mapped partition cell id and the number
9537 // of mapped partition cells on this domain
9538 for(MInt cellId = 0; cellId < noCells; cellId++) {
9539 // Skip cells that are not partition cells
9540 if(a_level(cellId) != minLevel()) {
9541 continue;
9542 }
9543
9544 // Find corresponding Hilbert id
9545 const MInt hilbertId = localHilbertIds[cellId];
9546 MInt* const lower = lower_bound(hilbertIds.data(), (hilbertIds.data() + hilbertIds.size()), hilbertId);
9547
9548 // If id was not found, no mapped cell exists; continue with next cell
9549 if(lower == (hilbertIds.data() + hilbertIds.size()) || *lower != hilbertId) {
9550 continue;
9551 }
9552
9553 // Store corresponding partition cell id to grid map
9554 const MInt partitionCellId = distance(hilbertIds.data(), lower);
9555 gridMap[cellId] = partitionCellsId[partitionCellId];
9556
9557 // Determine first partition cell id
9558 firstMappedPartitionCellId = min(firstMappedPartitionCellId, partitionCellId);
9559
9560 // Increase number of mapped min-cells
9561 noMappedPartitionCells++;
9562 }
9563
9564 // First mapped cell id on this domain
9565 const MInt firstMappedCellId = (noMappedPartitionCells > 0) ? partitionCellsId[firstMappedPartitionCellId] : 0;
9566
9567 // Determine the total number of donor cells on this domain
9568 MInt noDonorCells = 0;
9569 {
9570 // Read partitionCellsNoOffsprings from donor grid
9571 MIntScratchSpace partitionCellsNoOffsprings(max(noMappedPartitionCells, 1), AT_, "partitionCellsNoOffsprings");
9572 MIntScratchSpace partitionCellsId2(noPartitionCells, AT_, "partitionCellsId2");
9573 // const MInt partitionCellOffset
9574 // = (noMappedPartitionCells > 0) ? firstMappedPartitionCellId : 0;
9575 // donorGrid.setOffset(noMappedPartitionCells, partitionCellOffset);
9576 // donorGrid.readArray(&partitionCellsNoOffsprings[0], "partitionCellsNoOffsprings");
9577 donorGrid.setOffset(noPartitionCells, 0);
9578 donorGrid.readArray(&partitionCellsId2[0], "partitionCellsGlobalId");
9579 MInt globalCount;
9580 donorGrid.getAttribute(&globalCount, "noCells");
9581 for(MInt i = 0; i < noMappedPartitionCells; i++) {
9582 MInt id = firstMappedPartitionCellId + i;
9583 MInt nextId = (id == noPartitionCells - 1) ? globalCount : partitionCellsId2[id + 1];
9584 partitionCellsNoOffsprings[i] = nextId - partitionCellsId2[id];
9585 ASSERT(partitionCellsNoOffsprings[i] > 0, "");
9586 }
9587
9588 // Sum up the number of offsprings of all partition cells on this domain
9589 for(MInt i = 0; i < noMappedPartitionCells; i++) {
9590 noDonorCells += partitionCellsNoOffsprings[i];
9591 }
9592 }
9593
9594 // Calculate the donor grid domain offset
9595 ParallelIo::size_type offset, totalCount;
9596 ParallelIo::calcOffset(noDonorCells, &offset, &totalCount, mpiComm());
9597
9598 // Read the noChildIds array of the donor grid
9599 MIntScratchSpace noChildIds(max(noDonorCells, 1), AT_, "noChildIds");
9600 donorGrid.setOffset(noDonorCells, offset);
9601 // donorGrid.readArray(&noChildIds[0], "noChildIds");
9602 vector<MUchar> cellInfo(noDonorCells);
9603 donorGrid.readArray(cellInfo.data(), "cellInfo");
9604 for(MInt i = 0; i < noDonorCells; i++) {
9605 const MUint childCnt = static_cast<MUint>(cellInfo[i]) & 15u;
9606 noChildIds[i] = (MInt)childCnt;
9607 }
9608
9609 // Storage for the number of donor cell offspring for each target cell
9610 MIntScratchSpace gridMapNoOffspring(noCells, AT_, "gridMapNoOffspring");
9611 fill(gridMapNoOffspring.begin(), gridMapNoOffspring.end(), 0);
9612
9613 // Auxiliary method: Return the number of offspring, i.e. child cells,
9614 // child-child cells etc., for a given cell based on a list of number of
9615 // children for each cell, ordered depth-first. For a cell without children, 0
9616 // is returned.
9617 auto getNoOffspring = [](const MInt cellId, const MInt* const noChilds) {
9618 // Initialize with the number of child cells of considered cell
9619 MInt noOffspring = noChilds[cellId];
9620
9621 // Loop until all childs of childs of ... are taken into account
9622 // If there are only leaf cells left 'noOffspring' wont increase any more
9623 // since the number of children is zero from there on and the loop will end.
9624 MInt offspringId = 1;
9625 while(offspringId <= noOffspring) {
9626 noOffspring += noChilds[cellId + offspringId];
9627 offspringId++;
9628 }
9629 return noOffspring;
9630 };
9631
9632 // Determine all matching offspring cells of the mapped partition cells
9633 MInt noOneToMultipleMappings = 0;
9634 for(MInt cellId = 0; cellId < noCells;) {
9635 // Check if this is a partition cell with mapped, corresponding donor cell and
9636 // continue with the next cell if not. Non-partition cells will never be
9637 // considered as the else-condition below will take care of them.
9638 MInt donorGlobalCellId = gridMap[cellId];
9639 if(donorGlobalCellId == -1) {
9640 cellId++;
9641 continue;
9642 }
9643
9644 // Store child cells in grid map
9645 if(a_noChildren(cellId) == 0) {
9646 // No child cells on target grid, store the number of offspring on the
9647 // donor grid (0 if the donor cell has no children)
9648 const MInt donorLocalCellId = donorGlobalCellId - firstMappedCellId;
9649 gridMapNoOffspring[cellId] = getNoOffspring(donorLocalCellId, &noChildIds[0]);
9650
9651 // Continue with next cell
9652 cellId++;
9653 } else {
9654 // partition cell on target grid has children
9655 // Loop as long as the current cell is a descendant of the considered min
9656 // cell
9657 const MInt partitionCellLevel = a_level(cellId);
9658 // 'cellId' belongs to the partition cell, check the next cell in the first
9659 // iteration
9660 MInt currentCellId = cellId + 1;
9661
9662 while(currentCellId < noCells && a_level(currentCellId) > partitionCellLevel) {
9663 MInt donorLocalCellId = donorGlobalCellId - firstMappedCellId;
9664 // No child cells on the donor grid
9665 if(noChildIds[donorLocalCellId] == 0) {
9666 // Store mapping for matching cell
9667 gridMap[cellId] = donorGlobalCellId;
9668 const MInt parentLevel = a_level(cellId);
9669
9670 // Continue with next cell, this will either be a child of the last
9671 // cell, i.e. there is a one-to-many mapping, or it has the same or a
9672 // lower level, i.e. the last cell belongs to a one-to-one mapping.
9673 cellId++;
9674 // Loop over all offspring of the current target cell if there are any
9675 while(cellId < noCells && a_level(cellId) > parentLevel) {
9676 gridMap[cellId] = donorGlobalCellId; // The same for all offspring
9677 // Use -1 to indicate 'no additional donor cell' for this cell
9678 gridMapNoOffspring[cellId] = -1;
9679 noOneToMultipleMappings++;
9680
9681 // Continue with next cell
9682 cellId++;
9683 }
9684 // Move on to the next donor cell (one-to-one or one-to-many finished)
9685 donorGlobalCellId++;
9686 } else { // Donor cell has children
9687 if(a_noChildren(cellId) == 0) {
9688 // Target cell has no children, i.e. many-to-one mapping
9689 gridMap[cellId] = donorGlobalCellId;
9690
9691 // Store number of offspring on the donor grid
9692 donorLocalCellId = donorGlobalCellId - firstMappedCellId;
9693 const MInt noOffspring = getNoOffspring(donorLocalCellId, &noChildIds[0]);
9694 gridMapNoOffspring[cellId] = noOffspring;
9695
9696 // Increase the global donor cell id by the number of mapped cells
9697 donorGlobalCellId += noOffspring + 1;
9698 } else { // Both cells have children
9699 // Store mapping and move to next donor cell (and next target cell)
9700 gridMap[cellId] = donorGlobalCellId;
9701 donorGlobalCellId++;
9702 }
9703 // Continue with next cell
9704 cellId++;
9705 }
9706 // Set current cell id which to check in while() loop if it is still a
9707 // descendant of the considered partition cell
9708 currentCellId = cellId;
9709 }
9710 }
9711 }
9712
9713 // Open grid map file and write to it
9714 ParallelIo gridMapFile(gridMapFileName, PIO_REPLACE, mpiComm());
9715 gridMapFile.setAttribute(donorGridFileName, "donorGridFileName");
9716 gridMapFile.setAttribute(m_gridInputFileName, "gridFile");
9717 gridMapFile.defineScalar(PIO_INT, "noCells");
9718 gridMapFile.defineArray(PIO_INT, "cellIds", m_domainOffsets[noDomains()]);
9719 gridMapFile.defineArray(PIO_INT, "noOffspring", m_domainOffsets[noDomains()]);
9720 gridMapFile.setOffset(noCells, m_domainOffsets[domainId()]);
9721 gridMapFile.writeScalar(m_domainOffsets[noDomains()], "noCells");
9722 gridMapFile.writeArray(&gridMap[0], "cellIds");
9723 gridMapFile.writeArray(&gridMapNoOffspring[0], "noOffspring");
9724
9725 m_log << "Created & saved grid map file." << endl;
9726 if(noOneToMultipleMappings > 0) {
9727 m_log << "WARNING: There were " << noOneToMultipleMappings
9728 << " cells on the target grid that are finer than the "
9729 "corresponding donor cell."
9730 << endl;
9731 }
9732}
MString m_gridInputFileName
constexpr MInt noPartitionCells() const
MInt minLevel() const
MFloat lengthLevel0() const
Return the length of the level 0 cell.
MBool isMpiRoot() const
Return true if this is domain zero (a.k.a. as the root domain)
MBool isApproxInt(const T &, const T)
Definition: functions.h:284
int MPI_Allgatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgatherv
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm, const MString &name, const MString &varname)
same as MPI_Bcast
void partitionCellToGlobalOffsets(const IdType *const partitionCellOffsets, const IdType *const partitionCellToGlobalIds, const IdType noDomains, IdType *const globalIdOffsets)
Translates a list of partition cell offsets to global offsets.
Definition: partition.h:40
WeightType optimalPartitioningSerial(const WeightType *const weights, const IdType noWeights, const IdType noPartitions, IdType *const offsets)
Serial algorithm to find the optimal (not ideal) partitioning with given workloads based on a probing...
Definition: partition.h:61
MFloat distance(const MFloat *a, const MFloat *b)
Definition: maiamath.h:249
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292

◆ createGridSlice() [1/2]

template<MInt nDim>
void CartesianGrid< nDim >::createGridSlice ( const MString axis,
const MFloat  intercept,
const MString fileName 
)
Author
Marcus Wiens (marcus) marcu.nosp@m.s.wi.nosp@m.ens@r.nosp@m.wth-.nosp@m.aache.nosp@m.n.de
Date
01.06.2016

Definition at line 11363 of file cartesiangrid.cpp.

11363 {
11364 TRACE();
11365
11366 createGridSlice(axis, intercept, fileName, -1, nullptr, nullptr, nullptr, nullptr);
11367}
void createGridSlice(const MString &axis, const MFloat intercept, const MString &fileName)
Overload method of createGridSlice to provide usage with or without return of cellIds which are in th...

◆ createGridSlice() [2/2]

template<MInt nDim>
void CartesianGrid< nDim >::createGridSlice ( const MString axis,
const MFloat  intercept,
const MString fileName,
const MInt  solverId,
MInt *const  noSliceCellIds,
MInt *const  sliceCellIds,
MInt *const  noSliceHilbertIds = nullptr,
MInt *const  sliceHilbertInfo = nullptr,
MInt *const  noSliceContHilbertIds = nullptr,
MInt *const  sliceContiguousHilbertInfo = nullptr 
)
Author
Marcus Wiens (marcus) marcu.nosp@m.s.wi.nosp@m.ens@r.nosp@m.wth-.nosp@m.aache.nosp@m.n.de
Date
06.01.2016
Parameters
[in]axisAxis to which the slice should be orthogonal ("x", "y", or "z").
[in]interceptAbsolute value of the axis position for the slice.
[in]fileNameFile name (including output directory path) to which the slice grid should be written.
[out]noSliceCellIdsStores the number of cells in the slice from this domain. If nullptr is given, no data is stored.
[out]sliceCellIdsStores a list of all cells that are in the slice. Thus, a pointer to storage of size >= m_noInternalCells should be provided. If nullptr is given, no data is stored.
[out]noSliceHilbertIdsStores the number of hilbertIds in the slice from this domain. If nullptr is given, no data is stored.
[out]sliceHilbertIdsStores a list of all hilbertIds of the slice. Thus, a pointer of the storage of size >= m_noInternalCells * 3 should be provided. If nullptr is given, no data is stored.

This method is structured in 4 parts: Step 1: Identify cells in slice and sort them by their sliceHilbertId. First the data is saved a collector and after identification sorted. Then the data is distrubted into single arrays. Step 2: Create MPI communicator only for domains with slice cells Step 3: Gather all data for slice grid file. First the hilbertId information is exchanged globally. Then the global offsets for the local data can be determined on every domain. It is important to understand, that the number of hilbertIds is different on every domain and that they can be distributed in in any order, since a slice of a 3D hilbert curve is performed. After that the neighbor domains are determined to exchange cellIds to determine the cell mapping to slice globalId completly. At the end the data arrays are determined. Step 4: Write grid file with slice data. Since the data is sorted by slice HilbertId, the data writing is done in data chunks with the same hilbertId. If a domain has less hilbertIds than others, then dummy calls a performed.

Definition at line 11406 of file cartesiangrid.cpp.

11415 {
11416 TRACE();
11417
11418 // Check if maximum and minimum cell levels are equal
11419 if(m_minLevel == m_maxLevel) {
11420 if(domainId() == 0) {
11421 // TODO FIXME labels:GRID what is the reason for this?
11422 std::cerr << "Warning: CartesianGrid::createGridSlice minLevel and maxLevel grid are equal! "
11423 << "(hang-up might occur)" << std::endl;
11424 }
11425 }
11426
11427 // Dimension check
11428 IF_CONSTEXPR(nDim != 3) { TERMM(1, "Can not create a 2D slice from a 2D grid."); }
11429
11430 m_log << "Creating 2D slice from grid... ";
11431
11432 // New number of dimension
11433 const MInt nDimSlice = 2;
11434
11435 // Check for slice orientation
11436 MInt axisNum;
11437 // Reference to relevant coordinates
11438 array<MInt, nDimSlice> coordArray{};
11439 if(axis == "x") {
11440 axisNum = 0;
11441 coordArray = {{1, 2}};
11442 } else if(axis == "y") {
11443 axisNum = 1;
11444 coordArray = {{0, 2}};
11445 } else if(axis == "z") {
11446 axisNum = 2;
11447 coordArray = {{0, 1}};
11448 } else {
11449 TERMM(1, "Unknown axis! Check your property file.");
11450 }
11451
11452 MBool isAtCenterOfGravity = false;
11453 // Check whether intercept is located at the centroid of the specified axis
11454 if(approx(intercept, m_targetGridCenterOfGravity[axisNum], MFloatEps)) {
11455 isAtCenterOfGravity = true;
11456 }
11457
11459 // Step 1: identify cells in slice
11461
11462 // Get center of gravity (needed for hilbertId in slice)
11463 std::array<MFloat, nDimSlice> centerOfGravity{};
11464 centerOfGravity[0] = m_centerOfGravity[coordArray[0]];
11465 centerOfGravity[1] = m_centerOfGravity[coordArray[1]];
11466
11467 std::array<MFloat, nDimSlice> targetGridCenterOfGravity{};
11468 targetGridCenterOfGravity[0] = m_targetGridCenterOfGravity[coordArray[0]];
11469 targetGridCenterOfGravity[1] = m_targetGridCenterOfGravity[coordArray[1]];
11470
11471 // Contains all cell ids relevant to slice
11472 MInt noSlicePartitionCells = 0;
11473 MInt noSliceMinLevelCells = 0;
11474 MInt noSliceCells = 0;
11475 MLong noLeafCells = 0;
11476 // SliceCellCollector for all local sliceCells with localCellId, hilbertId, isPartitionCell and
11477 // isMinCell information. This collector is useful for sorting this data in groups
11478 // After sorting the data is separated into single arrays
11479 ScratchSpace<array<MInt, 4>> sliceCellCollector(m_noInternalCells, AT_, "sliceCellCollector");
11480 for(MInt i = 0; i < m_noInternalCells; i++) {
11481 sliceCellCollector[i].fill(0);
11482 }
11483 // Determine partition cells of slice
11484 const MInt noLocalPartitionCells = m_localPartitionCellOffsets[1] - m_localPartitionCellOffsets[0];
11485
11486 // Scratch to access partitionCells in following for loop
11487 MIntScratchSpace localPartitionCellGlobalIds(noLocalPartitionCells + 1, AT_, "localPartitionCellGlobalIds");
11488 copy_n(&m_localPartitionCellGlobalIds[0], noLocalPartitionCells, &localPartitionCellGlobalIds[0]);
11489 // This partitionCell would be located on the next domain, slice cell search on this
11490 // domains is perfmored until this global cellId
11491 localPartitionCellGlobalIds[noLocalPartitionCells] = m_noInternalCells + m_domainOffsets[domainId()];
11492
11493 // Count how many cells belong to a hilbertId (for this solver) on this domain. Needed for mapping and file writing
11494 std::map<MInt, MInt> hilbertIdCount;
11495 std::map<MInt, MInt> hilbertIdCountSolver;
11496
11497 for(MInt i = 0, cellId = 0; i < noLocalPartitionCells; i++) {
11498 // get local partition cellId
11499 const MInt partitionCellId = localPartitionCellGlobalIds[i] - m_domainOffsets[domainId()];
11500 MInt isPartitionCell = 0;
11501 // Skip partition cell if not intersected by slice
11502 MFloat eps = 0.0;
11503 if(isAtCenterOfGravity) {
11504 eps = MFloatEps;
11505 }
11506 if(fabs((intercept + eps) - a_coordinate(partitionCellId, axisNum)) < halfCellLength(partitionCellId)) {
11507 isPartitionCell = 1;
11508 noSlicePartitionCells++;
11509 } else {
11510 // Skip all offsprings
11511 cellId = partitionCellId + a_noOffsprings(partitionCellId);
11512 }
11513
11514 // Search for all cells between two partitionCells and collect information
11515 const MInt nextPartitionCell = localPartitionCellGlobalIds[i + 1] - m_domainOffsets[domainId()];
11516 while(cellId < nextPartitionCell) {
11517 // Skip cell if not intersected by slice
11518 if(!(fabs((intercept + eps) - a_coordinate(cellId, axisNum)) < halfCellLength(cellId))) {
11519 cellId++;
11520 continue;
11521 }
11522
11523 // save partitionCell indicator
11524 if(cellId == partitionCellId) {
11525 sliceCellCollector[noSliceCells][2] = isPartitionCell;
11526 isPartitionCell = 0;
11527 }
11528
11529 // Count hilbertIds of slice in 2D grid
11530 const MFloat* const sliceCoord = &a_coordinate(cellId, 0);
11531 // Coordinates mapped to unit cube
11532 array<MFloat, 2> normedSliceCoord{};
11533 normedSliceCoord[0] =
11534 (sliceCoord[coordArray[0]] - targetGridCenterOfGravity[0] + 1e-12 + m_targetGridLengthLevel0 * 0.5)
11536 normedSliceCoord[1] =
11537 (sliceCoord[coordArray[1]] - targetGridCenterOfGravity[1] + 1e-12 + m_targetGridLengthLevel0 * 0.5)
11539 const MLong sliceHilbertId =
11540 maia::grid::hilbert::index<2>(&normedSliceCoord[0], static_cast<MLong>(m_targetGridMinLevel));
11541 // count cells per slice hilbertId
11542 hilbertIdCount[sliceHilbertId]++;
11543 sliceCellCollector[noSliceCells][1] = sliceHilbertId;
11544
11545 // Count solver-cells per slice hilbertId
11546 if(solverId > -1 && a_solver(cellId, solverId)) hilbertIdCountSolver[sliceHilbertId]++;
11547
11548 // Check if current cell is a minLevelCell
11549 if(a_level(cellId) == m_minLevel) {
11550 sliceCellCollector[noSliceCells][3] = 1;
11551 noSliceMinLevelCells++;
11552 }
11553
11554 // Count number of leaf cells
11555 if(a_isLeafCell(cellId)) {
11556 noLeafCells++;
11557 }
11558 // Add cell to list of slice cells
11559 sliceCellCollector[noSliceCells][0] = cellId;
11560 noSliceCells++;
11561
11562 // next cell id
11563 cellId++;
11564 }
11565 }
11566
11568 // Step 1.1: sort slice cells by slice hilbertÍd
11570
11571 // Allocate memory for slice partition cells
11572 MIntScratchSpace slicePartitionCells(noSlicePartitionCells + 1, AT_, "slicePartitionCells");
11573 // Allocate memory for slice minLevel cells
11574 MIntScratchSpace sliceMinLevelCells(noSliceMinLevelCells, AT_, "sliceMinLevelCells");
11575 // Allocate memory for slice cells
11576 MIntScratchSpace cellIdsInSlice(noSliceCells, AT_, "cellIdsInSlice");
11577 // save hilbert id keys for easy access and sort slice cell arrays
11578 MIntScratchSpace hIdKeys(hilbertIdCount.size(), AT_, "hIdKeys");
11579 // Count and save hilbertIds for partition and minLevelCells
11580 std::map<MInt, MInt> hilbertIdMinLevelCellsCount;
11581 std::map<MInt, MInt> hilbertIdPartitionCellsCount;
11582
11583 if(noSliceCells > 0) {
11584 // create hilbert key array for easy access
11585 MInt noHilbertIds = 0;
11586 for(auto const& ent1 : hilbertIdCount) {
11587 hIdKeys[noHilbertIds] = ent1.first;
11588 noHilbertIds++;
11589 }
11590
11591 // sort slice cell info by slice hilbertId
11592 std::stable_sort(sliceCellCollector.begin(), sliceCellCollector.begin() + noSliceCells,
11593 [](const array<MInt, 4>& a, const array<MInt, 4>& b) { return a[1] < b[1]; });
11594
11595 // Split slice cell info into seperate arrays
11596 for(MInt i = 0, j = 0, k = 0; i < noSliceCells; i++) {
11597 cellIdsInSlice[i] = sliceCellCollector[i][0];
11598 // fill slicePartitionCells
11599 if(sliceCellCollector[i][2] == 1) {
11600 slicePartitionCells[j] = sliceCellCollector[i][0];
11601 hilbertIdPartitionCellsCount[sliceCellCollector[i][1]]++;
11602 j++;
11603 }
11604 // fill sliceMinLevelCells
11605 if(sliceCellCollector[i][3] == 1) {
11606 sliceMinLevelCells[k] = sliceCellCollector[i][0];
11607 hilbertIdMinLevelCellsCount[sliceCellCollector[i][1]]++;
11608 k++;
11609 }
11610 }
11611 // Save total number of slice partitionCells (need for noOffsprings search)
11612 slicePartitionCells[noSlicePartitionCells] = cellIdsInSlice[noSliceCells - 1] + 1;
11613 }
11614
11615 if(solverId < 0) {
11616 // return noSliceCells and cellIds
11617 if(noSliceCellIds != nullptr) {
11618 *noSliceCellIds = noSliceCells;
11619 }
11620 if(sliceCellIds != nullptr && noSliceCells > 0) {
11621 std::copy_n(&cellIdsInSlice[0], noSliceCells, sliceCellIds);
11622 }
11623 } else {
11624 // Find number of cells and cell ids for given solverId
11625 MIntScratchSpace cellIdsInSliceSolver(noSliceCells, AT_, "cellIdsInSliceSolver");
11626 MInt noSliceCellsSolver = 0;
11627 for(MInt i = 0; i < noSliceCells; i++) {
11628 if(a_solver(cellIdsInSlice[i], solverId)) {
11629 cellIdsInSliceSolver[noSliceCellsSolver] = cellIdsInSlice[i];
11630 noSliceCellsSolver++;
11631 }
11632 }
11633
11634 // return number of cells for solver and cell ids
11635 if(noSliceCellIds != nullptr) {
11636 *noSliceCellIds = noSliceCellsSolver;
11637 }
11638 if(sliceCellIds != nullptr && noSliceCellsSolver > 0) {
11639 std::copy_n(&cellIdsInSliceSolver[0], noSliceCellsSolver, sliceCellIds);
11640 }
11641 }
11642
11644 // Step 2: create MPI communicator only for domains with slice cells
11646
11647 // Create a new MPI Communicator for all slice domains
11648 MPI_Comm mpiCommSlice = MPI_COMM_NULL;
11649 MIntScratchSpace sliceRanks(globalNoDomains(), AT_, "sliceRanks");
11650
11651 // Get Rank if points are relevant
11652 MInt rank = -1;
11653 if(noSliceCells > 0) {
11654 MPI_Comm_rank(mpiComm(), &rank);
11655 }
11656 // Combine all ranks to get relevant ranks
11657 MPI_Allgather(&rank, 1, type_traits<MInt>::mpiType(), &sliceRanks[0], 1, type_traits<MInt>::mpiType(), mpiComm(), AT_,
11658 "rank", "sliceRanks[0]");
11659
11660 // Check for relevant ranks and save them to create the new communicator
11661 const MInt noRelDomains = count_if(sliceRanks.begin(), sliceRanks.end(), [](const MInt a) { return a != -1; });
11662 MIntScratchSpace relDomains(noRelDomains, AT_, "relDomains");
11663 // A domainMap is needed to refer from sliceDomain to global domains
11664 map<MInt, MInt> domainMap;
11665 MInt position = 0;
11666 for(auto&& slice : sliceRanks) {
11667 if(slice != -1) {
11668 relDomains[position] = slice;
11669 domainMap[slice] = position;
11670 position++;
11671 }
11672 }
11673 // Create new point data mpi group
11674 MPI_Group globalGroup, localGroup;
11675 MPI_Comm_group(mpiComm(), &globalGroup, AT_, "globalGroup");
11676 MPI_Group_incl(globalGroup, noRelDomains, &relDomains[0], &localGroup, AT_);
11677
11678 // Create new communicator and clean up
11679 MPI_Comm_create(mpiComm(), localGroup, &mpiCommSlice, AT_, "mpiCommSlice");
11680
11681 MPI_Group_free(&globalGroup, AT_);
11682 MPI_Group_free(&localGroup, AT_);
11683
11684 // Leave function if not relevant to slice
11685 if(noSliceCells < 1) {
11686 return;
11687 }
11688
11689
11691 // Step 3: gather all data for slice grid file
11693
11694 // This part determines the new global cells order by slice hilbertId. Information about global
11695 // order must be avialable on all domains that the local order can be determined on every domain.
11696 // The new global order determines the offset for file writing and this is computed in this step.
11697
11698 // Determine total global number of slice cells for each domain
11699 MInt noSliceDomains = -1;
11700 MPI_Comm_size(mpiCommSlice, &noSliceDomains);
11701 // Get domainId in slice mpi comm to access domainOffset
11702 MInt sliceDomain = -1;
11703 MPI_Comm_rank(mpiCommSlice, &sliceDomain);
11704
11705 // Determine total no of slice hilbertIds
11706 MIntScratchSpace noLocalHilbertIds(noSliceDomains, AT_, "noLocalHilbertIds");
11707 noLocalHilbertIds[sliceDomain] = hilbertIdCount.size();
11708
11709 // Gather the number of unique number of slice hilbert ids on each domain
11710 MPI_Allgather(MPI_IN_PLACE, 1, MPI_INT, &noLocalHilbertIds[0], 1, MPI_INT, mpiCommSlice, AT_, "MPI_IN_PLACE",
11711 "noLocalHilbertIds[0]");
11712
11713 // Compute offsets for recieveing data
11714 MIntScratchSpace offsetsRecvData(noSliceDomains, AT_, "offsetsRecvData");
11715 offsetsRecvData[0] = 0;
11716 for(MInt i = 1; i < noSliceDomains; i++) {
11717 offsetsRecvData[i] = offsetsRecvData[i - 1] + noLocalHilbertIds[i - 1] * 6;
11718 }
11719 MInt noTotalRecvData = offsetsRecvData[noSliceDomains - 1] + noLocalHilbertIds[noSliceDomains - 1] * 6;
11720
11721 // Create exchange data (every domain gets info about hilbert ids and offsets for cellInfo,
11722 // partitionCells and minLevelCells). From this offsets for file writing are determined for every
11723 // variable indepently.
11724 MIntScratchSpace sendHilbertData(noLocalHilbertIds[sliceDomain] * 6, AT_, "sendHilbertData");
11725 for(MUlong i = 0; i < hIdKeys.size(); i++) {
11726 sendHilbertData[i * 6] = hIdKeys[i];
11727 sendHilbertData[i * 6 + 1] = domainId();
11728 sendHilbertData[i * 6 + 2] = hilbertIdCount[hIdKeys[i]];
11729 sendHilbertData[i * 6 + 3] = hilbertIdPartitionCellsCount[hIdKeys[i]];
11730 sendHilbertData[i * 6 + 4] = hilbertIdMinLevelCellsCount[hIdKeys[i]];
11731 sendHilbertData[i * 6 + 5] = hilbertIdCountSolver[hIdKeys[i]];
11732 }
11733
11734 // Exchange number of slice hilbert ids
11735 MIntScratchSpace recvHilbertData(noTotalRecvData, AT_, "recvHilbertData");
11736 MInt noSendData = sendHilbertData.size();
11737 MIntScratchSpace noRecvData(noSliceDomains, AT_, "noRecvData");
11738 for(MInt i = 0; i < noSliceDomains; i++) {
11739 noRecvData[i] = noLocalHilbertIds[i] * 6;
11740 }
11741 MPI_Allgatherv(&sendHilbertData[0], noSendData, MPI_INT, &recvHilbertData[0], &noRecvData[0], &offsetsRecvData[0],
11742 MPI_INT, mpiCommSlice, AT_, "sendHilbertData[0]", "recvHilbertData[0]");
11743
11744 // Create sliceGlobalHilbertInfo
11745 ScratchSpace<array<MInt, 6>> sliceGlobalHilbertInfo(noTotalRecvData / 6, AT_, "sliceGlobalHilbertInfo");
11746 // Store globally recieved data in sliceGlobalHilbertInfo
11747 for(MInt i = 0; i < noTotalRecvData / 6; i++) {
11748 sliceGlobalHilbertInfo[i][0] = recvHilbertData[i * 6];
11749 sliceGlobalHilbertInfo[i][1] = recvHilbertData[i * 6 + 1];
11750 sliceGlobalHilbertInfo[i][2] = recvHilbertData[i * 6 + 2];
11751 sliceGlobalHilbertInfo[i][3] = recvHilbertData[i * 6 + 3];
11752 sliceGlobalHilbertInfo[i][4] = recvHilbertData[i * 6 + 4];
11753 sliceGlobalHilbertInfo[i][5] = recvHilbertData[i * 6 + 5];
11754 }
11755
11756 // Sort sliceGlobalHilbertInfo by domainId...
11757 std::stable_sort(sliceGlobalHilbertInfo.begin(), sliceGlobalHilbertInfo.end(),
11758 [](const array<MInt, 6>& a, const array<MInt, 6>& b) { return a[1] < b[1]; });
11759 // ... and then sort stable by hilbertId -> list ordered by hilbertId and then nested for each hilbertId by domainId
11760 std::stable_sort(sliceGlobalHilbertInfo.begin(), sliceGlobalHilbertInfo.end(),
11761 [](const array<MInt, 6>& a, const array<MInt, 6>& b) { return a[0] < b[0]; });
11762
11763 // Determine hilbertId offsets (cells in slice file will be sorted by hilbertId)
11764 // For I/O it is necessary to call writeData() on all domains equally. If a slice has less then
11765 // maxNoHilbertIds then its array is filled with zero. Then a cell of writeData() will happen, but
11766 // without writing data.
11767 MInt maxNoHilbertIds = *std::max_element(noLocalHilbertIds.begin(), noLocalHilbertIds.end());
11768 MIntScratchSpace hilbertDomainOffset(maxNoHilbertIds, AT_, "hilbertDomainOffset");
11769 hilbertDomainOffset.fill(0);
11770 MIntScratchSpace hilbertPartitionDomainOffset(maxNoHilbertIds, AT_, "hilbertDomainOffset");
11771 hilbertPartitionDomainOffset.fill(0);
11772 MIntScratchSpace hilbertMinLevelDomainOffset(maxNoHilbertIds, AT_, "hilbertDomainOffset");
11773 hilbertMinLevelDomainOffset.fill(0);
11774
11775 // Offsets for solver cells
11776 MIntScratchSpace hilbertDomainOffsetSolver(maxNoHilbertIds, AT_, "hilbertDomainOffsetSolver");
11777 hilbertDomainOffsetSolver.fill(0);
11778
11779 // Calculate offsets by hilbert ids for output arrays
11780 // The data in sliceGlobalHilbertInfo is sorted by their hilbertId on the first level. On the
11781 // second level by domainId. Example:
11782 // [hilbertId, domaindId, noCells, noPartitionCells noMinLevelCells]
11783 // sliceGlobalHilbertInfo[0] = [0, 0, 20, 1, 1]
11784 // sliceGlobalHilbertInfo[1] = [0, 2, 10, 1, 0]
11785 // sliceGlobalHilbertInfo[2] = [1, 1, 6, 0 ,0]
11786 // sliceGlobalHilbertInfo[3] = [1, 2, 8, 1 ,1]
11787 //
11788 // To determine the global offset for the local data (for each local hilbertId), count the number
11789 // of cells of all hilbertIds below the current one. If this hilbertId is distributed on
11790 // multiple domains, then count also the next number of nodes till the local domainid is reached
11791 // in sliceGlobalHilbertInfo. In the example above the offset for hilbertId 1 on domain 1 would
11792 // be 30.
11793 for(MInt i = 0; i < noLocalHilbertIds[sliceDomain]; i++) {
11794 MInt offset = 0, offsetPart = 0, offsetMin = 0, offsetSolver = 0, j = 0;
11795 // Count until current hilbertId is reached
11796 while(sliceGlobalHilbertInfo[j][0] < hIdKeys[i]) {
11797 offset += sliceGlobalHilbertInfo[j][2];
11798 offsetPart += sliceGlobalHilbertInfo[j][3];
11799 offsetMin += sliceGlobalHilbertInfo[j][4];
11800 offsetSolver += sliceGlobalHilbertInfo[j][5];
11801 j++;
11802 }
11803 // Count until this domain is reached
11804 while(sliceGlobalHilbertInfo[j][1] < domainId()) {
11805 offset += sliceGlobalHilbertInfo[j][2];
11806 offsetPart += sliceGlobalHilbertInfo[j][3];
11807 offsetMin += sliceGlobalHilbertInfo[j][4];
11808 offsetSolver += sliceGlobalHilbertInfo[j][5];
11809 j++;
11810 }
11811 hilbertDomainOffset[i] = offset;
11812 hilbertPartitionDomainOffset[i] = offsetPart;
11813 hilbertMinLevelDomainOffset[i] = offsetMin;
11814
11815 if(solverId > -1) {
11816 hilbertDomainOffsetSolver[i] = offsetSolver;
11817 TERMM_IF_COND(!g_multiSolverGrid && offsetSolver != offset, "Error: fixme");
11818 }
11819 }
11820
11821 // Contains offset for every domain to determine global slice cellId
11822 MIntScratchSpace domainOffset(noSliceDomains + 1, AT_, "domainOffset");
11823 // Collect number of slice cells for each domain
11825 mpiCommSlice, AT_, "noSliceCells", "domainOffset[0]");
11826
11827 // Calculate offsets from received noSliceCells
11828 for(MInt i = 0, offset = 0, tmp = 0; i < (noSliceDomains + 1); i++) {
11829 tmp = domainOffset[i];
11830 domainOffset[i] = offset;
11831 offset += tmp;
11832 }
11833
11834 MInt noLocalHilbertIdsSolver = 0;
11835
11836 if(solverId < 0) {
11837 // return noHilbertIds
11838 if(noSliceHilbertIds != nullptr) {
11839 *noSliceHilbertIds = noLocalHilbertIds[sliceDomain];
11840 }
11841 // return HilbertInfo (how many cells per HilbertId and offset for file writing)
11842 if(sliceHilbertInfo != nullptr) {
11843 MIntScratchSpace hilbertInfo(noLocalHilbertIds[sliceDomain] * 3, AT_, "hilbertInfo");
11844 for(MInt i = 0; i < noLocalHilbertIds[sliceDomain]; i++) {
11845 hilbertInfo[i * 3] = hIdKeys[i];
11846 hilbertInfo[i * 3 + 1] = hilbertIdCount[hIdKeys[i]];
11847 hilbertInfo[i * 3 + 2] = hilbertDomainOffset[i];
11848 }
11849 std::copy_n(&hilbertInfo[0], noLocalHilbertIds[sliceDomain] * 3, sliceHilbertInfo);
11850 }
11851 } else {
11852 TERMM_IF_COND(noSliceHilbertIds == nullptr || sliceHilbertInfo == nullptr,
11853 "Error: solverId given, pointers need to be != nullptr.");
11854
11855 MIntScratchSpace hilbertInfoSolver(noLocalHilbertIds[sliceDomain] * 3, AT_, "hilbertInfo");
11856 MInt noHIdsSolver = 0;
11857 for(MInt i = 0; i < noLocalHilbertIds[sliceDomain]; i++) {
11858 if(hilbertIdCountSolver[hIdKeys[i]] > 0) {
11859 hilbertInfoSolver[noHIdsSolver * 3] = hIdKeys[i];
11860 hilbertInfoSolver[noHIdsSolver * 3 + 1] = hilbertIdCountSolver[hIdKeys[i]];
11861 hilbertInfoSolver[noHIdsSolver * 3 + 2] = hilbertDomainOffsetSolver[i];
11862 noHIdsSolver++;
11863 }
11864 }
11865
11866 noLocalHilbertIdsSolver = noHIdsSolver;
11867 // return noHilbertIds for solver
11868 *noSliceHilbertIds = noHIdsSolver;
11869 // return HilbertInfo (how many solver-cells per HilbertId and offset for file writing)
11870 std::copy_n(&hilbertInfoSolver[0], noHIdsSolver * 3, sliceHilbertInfo);
11871 }
11872
11873
11875 // Step 3.1: determine neighbor domains and compute partition data
11877
11878 // The neighbor domains are needed to create correct mapping of neighbor cells which are on other
11879 // domains
11880
11881 // Reference to relevant neighbor cells
11882 array<MInt, nDimSlice * 2> nghbrArray{};
11883 if(axis == "x") {
11884 nghbrArray = {{2, 3, 4, 5}};
11885 } else if(axis == "y") {
11886 nghbrArray = {{0, 1, 4, 5}};
11887 } else if(axis == "z") {
11888 nghbrArray = {{0, 1, 2, 3}};
11889 }
11890
11891 // Collector for related domains of slice to create global cellId map
11892 std::set<MInt> relatedDomains;
11893
11894 // Check for neighbor cell of all slice cells on other domain
11895 for(MInt i = 0; i < noSliceMinLevelCells; i++) { // TODO labels:GRID this is not exactly what the comment above states
11896 // Only check for neighbors in slice directions
11897 for(MInt j = 0; j < (nDimSlice * 2); j++) {
11898 // Skip if no neighbor in current direction
11899 if(!a_hasNeighbor(sliceMinLevelCells[i], nghbrArray[j])) {
11900 continue;
11901 }
11902 // Save related domain
11903 MInt nId = a_neighborId(sliceMinLevelCells[i], nghbrArray[j]);
11904 const MInt nghbrDomainId = findNeighborDomainId(a_globalId(nId));
11905 if(domainId() != nghbrDomainId) {
11906 relatedDomains.insert(nghbrDomainId);
11907 }
11908 }
11909 }
11910
11911 // Determine partition level shift in slice
11912 MInt partitionLevelShift = 0;
11913 for(MInt i = 0; i < noSlicePartitionCells; ++i) {
11914 const MInt levelDiff = a_level(slicePartitionCells[i]) - m_minLevel;
11915 partitionLevelShift = mMax(levelDiff, partitionLevelShift);
11916 }
11917
11918 // Determine partition level ancestors (parent cells of partition cells)
11919 set<MLong> partitionLevelAncestorIds;
11920 for(MInt i = 0; i < noSliceCells; i++) {
11921 const MInt cellId = cellIdsInSlice[i];
11922 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor) && !a_hasProperty(cellId, Cell::IsHalo)) {
11923 partitionLevelAncestorIds.insert(cellId);
11924 }
11925 }
11926
11927
11929 // Step 3.2: Map (and exchange) globalIds to new globalIds in slice
11931
11932 // Create idMap to map from globalId to global slice cellId for the local cells
11933 map<MInt, MInt> idMap;
11934 // CellId -1 should be invariant
11935 idMap[-1] = -1;
11936 // Map global cellIds of locally founded slice cells to global slice cellIds
11937 for(MInt i = 0, j = 0, h = 0; i < noSliceCells; i++, j++) {
11938 // set next hilbertr offset and reset counter
11939 if(j == hilbertIdCount[hIdKeys[h]]) {
11940 h++;
11941 j = 0;
11942 }
11943 idMap[cellIdsInSlice[i] + m_domainOffsets[domainId()]] = j + hilbertDomainOffset[h];
11944 }
11945
11946 // If slice has no related domains, skip slice data exchange step
11947 if(!relatedDomains.empty()) {
11948 // Get unique domainIds form set
11949 std::vector<MInt> sliceRelatedDomains(relatedDomains.begin(), relatedDomains.end());
11950
11951 // All cellIds from other domains will be saved in a single vector.
11952 // Determine offset for this vector for each
11953 MInt noRecvCells = 0;
11954 MIntScratchSpace relDomainOffsets(sliceRelatedDomains.size() + 1, AT_, "relDomainOffsets");
11955 for(MUlong i = 0; i < sliceRelatedDomains.size(); i++) {
11956 relDomainOffsets[i] = noRecvCells;
11957 noRecvCells +=
11958 domainOffset[domainMap[sliceRelatedDomains[i]] + 1] - domainOffset[domainMap[sliceRelatedDomains[i]]];
11959 }
11960 // Save total number of cellIds which will be received
11961 relDomainOffsets[sliceRelatedDomains.size()] = noRecvCells;
11962
11963 // Scratch to save all cellIds from other domains
11964 MIntScratchSpace recvIds(noRecvCells, AT_, "recvIds");
11965 recvIds.fill(-1);
11966
11967 // Save mpi requests
11968 ScratchSpace<MPI_Request> sendRequests(sliceRelatedDomains.size(), AT_, "sendRequests");
11969 fill(sendRequests.begin(), sendRequests.end(), MPI_REQUEST_NULL);
11970 ScratchSpace<MPI_Request> recvRequests(sliceRelatedDomains.size(), AT_, "recvRequests");
11971 fill(recvRequests.begin(), recvRequests.end(), MPI_REQUEST_NULL);
11972
11973 // Start receiving
11974 for(MUlong i = 0; i < sliceRelatedDomains.size(); i++) {
11975 MInt d = sliceRelatedDomains[i];
11976 MPI_Irecv(&recvIds[relDomainOffsets[i]], domainOffset[domainMap[d] + 1] - domainOffset[domainMap[d]],
11977 type_traits<MInt>::mpiType(), domainMap[d], domainMap[d], mpiCommSlice, &recvRequests[i], AT_,
11978 "recvIds[relDomainOffsets[i]]");
11979 }
11980
11981 // Start sending
11982 for(MUlong i = 0; i < sliceRelatedDomains.size(); i++) {
11983 MPI_Isend(&cellIdsInSlice[0], noSliceCells, type_traits<MInt>::mpiType(), domainMap[sliceRelatedDomains[i]],
11984 domainMap[domainId()], mpiCommSlice, &sendRequests[i], AT_, "cellIdsInSlice[0]");
11985 }
11986
11987 // Finish receiving
11988 MPI_Waitall(sliceRelatedDomains.size(), &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
11989
11990 // Finish sending
11991 MPI_Waitall(sliceRelatedDomains.size(), &sendRequests[0], MPI_STATUSES_IGNORE, AT_);
11992
11993 // Map relevant cellIds for each related domain
11994 for(MUlong j = 0; j < sliceRelatedDomains.size(); j++) {
11995 MInt d = sliceRelatedDomains[j];
11996 std::vector<MInt> hId(noLocalHilbertIds[domainMap[d]]);
11997 std::vector<MInt> hCount(noLocalHilbertIds[domainMap[d]]);
11998 std::vector<MInt> hOffsets(noLocalHilbertIds[domainMap[d]]);
11999
12000 // Calculate hilbertDomainOffset for related domain
12001 for(MUlong k = 0, i = 0; i < hId.size(); k++) {
12002 if(sliceGlobalHilbertInfo[k][1] == d) {
12003 hId[i] = sliceGlobalHilbertInfo[k][0];
12004 hCount[i] = sliceGlobalHilbertInfo[k][2];
12005
12006 MInt m = 0;
12007 MInt offset = 0;
12008 while(sliceGlobalHilbertInfo[m][0] < hId[i]) {
12009 offset += sliceGlobalHilbertInfo[m][2];
12010 m++;
12011 }
12012 while(sliceGlobalHilbertInfo[m][1] < d) {
12013 offset += sliceGlobalHilbertInfo[m][2];
12014 m++;
12015 }
12016 hOffsets[i] = offset;
12017 i++;
12018 }
12019 }
12020
12021 // Map global cellIds of related cellIds to global slice cellIds
12022 for(MInt i = 0, n = 0, h = 0; i < (relDomainOffsets[j + 1] - relDomainOffsets[j]); i++, n++) {
12023 if(n == hCount[h]) {
12024 h++;
12025 n = 0;
12026 }
12027 idMap[recvIds[i + relDomainOffsets[j]] + m_domainOffsets[d]] = n + hOffsets[h];
12028 }
12029 }
12030 }
12031 // Check if only cells where found, but no partitionCells (e.g. parent is located on this domain,
12032 // but the first partitionCell which belongs to the slice is on next domain
12033 MBool onlySliceCells = false;
12034 if(noSlicePartitionCells < 1) {
12035 onlySliceCells = true;
12036 }
12037
12038 // Create articifal mapped id for partitioncell on next domain, and update slicePartitionCells.
12039 // Needed for computation of workload.
12040 if(noSlicePartitionCells > 0) {
12041 std::map<MInt, MInt>::iterator it;
12042 MInt lastKeyId = hIdKeys.size() - 1;
12043 MInt val = hilbertIdCount[hIdKeys[lastKeyId]] + hilbertDomainOffset[lastKeyId];
12044
12045 it = idMap.find(slicePartitionCells[noSlicePartitionCells] + m_domainOffsets[domainId()]);
12046
12047 auto result = std::find_if(idMap.begin(), idMap.end(), [val](const auto& mo) { return mo.second == val; });
12048
12049 if(it == idMap.end() && result == idMap.end()) {
12050 idMap[slicePartitionCells[noSlicePartitionCells] + m_domainOffsets[domainId()]] =
12051 hilbertIdCount[hIdKeys[lastKeyId]] + hilbertDomainOffset[lastKeyId];
12052 } else if(result != idMap.end()) {
12053 MInt foundKey = result->first;
12054 slicePartitionCells[noSlicePartitionCells] = foundKey - m_domainOffsets[domainId()];
12055 }
12056 }
12057
12059 // Step 3.3: determine partition cell information and workload
12061
12062 // New number of childs in a refinement step
12063 const MUint noChildInRef = pow(2, nDimSlice);
12064
12065 // Create Variables to hold slice grid information
12066 MIntScratchSpace partitionCellsId(noSlicePartitionCells, AT_, "partitionCellsId");
12067 MFloatScratchSpace partitionCellsWorkload(noSlicePartitionCells, AT_, "partitionCellsWorkLoad");
12068 MInt maxNoOffsprings = 0;
12069 MFloat maxWorkload = 0.0;
12070 MFloat totalWorkload = 0.0;
12071
12072 for(MInt i = 0, c = 0, partitionCellNoOffsprings = 0; i < noSlicePartitionCells; i++) {
12073 partitionCellsId[i] = idMap[slicePartitionCells[i] + m_domainOffsets[domainId()]];
12074 // Count number of offsprings for partitionCells (start with 1)
12075 partitionCellNoOffsprings = 1;
12076 // Search all sliceCells between 2 slice partitionCells for offsprings. The id mapping is used
12077 // here since the mapped ids are sorted by the slice hilbertId
12078 while(idMap[a_globalId(cellIdsInSlice[c])] < idMap[slicePartitionCells[i + 1] + m_domainOffsets[domainId()]]) {
12079 // Only count cells which are on a higher level than current partitionCell
12080 if(a_level(cellIdsInSlice[c]) > a_level(slicePartitionCells[i])) {
12081 partitionCellNoOffsprings++;
12082 }
12083 c++;
12084 if(c == noSliceCells) {
12085 break;
12086 }
12087 }
12088
12089 // partitionCellsWorkload
12090 partitionCellsWorkload[i] = partitionCellNoOffsprings;
12091 // totalWorkload
12092 totalWorkload += partitionCellsWorkload[i];
12093 // maxNoOfssprings
12094 maxNoOffsprings = mMax(partitionCellNoOffsprings, maxNoOffsprings);
12095 // maxWorkload
12096 maxWorkload = mMax(partitionCellsWorkload[i], maxWorkload);
12097 }
12098
12099 // Get total number of partition level ancestors
12100 MLong totalNoPartitionLevelAncestors = 0;
12101 MLong localPartitionLevelAncestorCount = (signed)partitionLevelAncestorIds.size();
12102 MPI_Allreduce(&localPartitionLevelAncestorCount, &totalNoPartitionLevelAncestors, 1, MPI_LONG, MPI_SUM, mpiCommSlice,
12103 AT_, "localPartitionLevelAncestorCount", "totalNoPartitionLevelAncestors");
12104 // max partition level shift
12106 MPI_Allreduce(&partitionLevelShift, &maxPartitionLevelShift, 1, MPI_INT, MPI_MAX, mpiCommSlice, AT_,
12107 "partitionLevelShift", "maxPartitionLevelShift");
12108
12109 // Get max number of offsprings and calculate maxCPU
12110 MPI_Allreduce(MPI_IN_PLACE, &maxNoOffsprings, 1, MPI_INT, MPI_MAX, mpiCommSlice, AT_, "MPI_IN_PLACE",
12111 "maxNoOffsprings");
12112 // Get total workload by sum
12113 MPI_Allreduce(MPI_IN_PLACE, &totalWorkload, 1, MPI_DOUBLE, MPI_SUM, mpiCommSlice, AT_, "MPI_IN_PLACE",
12114 "totalWorkload");
12115 MPI_Allreduce(MPI_IN_PLACE, &maxWorkload, 1, MPI_DOUBLE, MPI_MAX, mpiCommSlice, AT_, "MPI_IN_PLACE", "maxWorkload");
12116 MFloat maxNoCPUs = totalWorkload / maxWorkload;
12117
12118
12120 // Step 3.4: determine min level cell information
12122
12123 // Mapping of child positions from 3D to 2D
12124 array<MInt, 8> childArray{};
12125 if(axis == "x") {
12126 childArray = {{0, 0, 1, 1, 2, 2, 3, 3}};
12127 } else if(axis == "y") {
12128 childArray = {{0, 1, 0, 1, 2, 3, 2, 3}};
12129 } else if(axis == "z") {
12130 childArray = {{0, 1, 2, 3, 0, 1, 2, 3}};
12131 }
12132
12133 // Get boundingBox and decisiveDirection for the slice
12134 const array<MFloat, nDimSlice* 2> boundingBox = {{m_boundingBox[coordArray[0]], m_boundingBox[coordArray[1]],
12135 m_boundingBox[coordArray[0] + 3],
12136 m_boundingBox[coordArray[1] + 3]}};
12137 const array<MFloat, nDimSlice* 2> targetGridBoundingBox = {
12138 {m_targetGridBoundingBox[coordArray[0]], m_targetGridBoundingBox[coordArray[1]],
12139 m_targetGridBoundingBox[coordArray[0] + 3], m_targetGridBoundingBox[coordArray[1] + 3]}};
12140 array<MFloat, nDimSlice * 2> geometryExtents{};
12141 MInt decisiveDirection = 0;
12142 for(MInt dir = 0; dir < nDimSlice; dir++) {
12143 geometryExtents[dir] = targetGridBoundingBox[dir + nDimSlice] - targetGridBoundingBox[dir];
12144 decisiveDirection = geometryExtents[dir] > geometryExtents[decisiveDirection] ? dir : decisiveDirection;
12145 }
12146
12147 // minLevelCellsTreeId
12148 MLongScratchSpace sliceMinLevelCellsTreeId(noSliceMinLevelCells, AT_, "sliceMinLevelCellsTreeId");
12149 for(MInt i = 0; i < noSliceMinLevelCells; ++i) {
12150 std::array<MFloat, nDimSlice> coord = {
12151 {a_coordinate(sliceMinLevelCells[i], coordArray[0]), a_coordinate(sliceMinLevelCells[i], coordArray[1])}};
12152 maia::grid::hilbert::coordinatesToTreeId<nDimSlice>(sliceMinLevelCellsTreeId[i], &coord[0],
12153 (MLong)m_targetGridMinLevel, &targetGridCenterOfGravity[0],
12155 }
12156
12157 // minLevelCellsNghbrIds
12158 MLongScratchSpace sliceMinLevelCellsNghbrIds(noSliceMinLevelCells, 2 * nDimSlice, AT_, "sliceMinLevelCellsNghbrIds");
12159 for(MInt i = 0; i < noSliceMinLevelCells; ++i) {
12160 for(MInt j = 0; j < (nDimSlice * 2); j++) {
12161 MInt nghbrId = a_neighborId(sliceMinLevelCells[i], nghbrArray[j]);
12162 if(nghbrId == -1) {
12163 sliceMinLevelCellsNghbrIds(i, j) = -1;
12164 } else {
12165 sliceMinLevelCellsNghbrIds(i, j) = idMap[a_globalId(nghbrId)];
12166 }
12167 }
12168 }
12169
12170
12172 // Step 3.5: determine cell information
12174
12175 MInt maxLevel = -1;
12176 ScratchSpace<MUchar> sliceCellInfo(noSliceCells, AT_, "sliceCellInfo");
12177 // cell info
12178 for(MInt i = 0; i < noSliceCells; ++i) {
12179 MLong cellId = cellIdsInSlice[i];
12180 MUint noChilds = 0;
12181 MUint curChildPos = 0;
12182 // Counting how many childs of current Cell belong to the slice
12183 for(MInt j = 0; j < pow(2, nDim) && curChildPos < noChildInRef; j++) {
12184 if(a_childId(cellIdsInSlice[i], j) != -1) {
12185 // Check to ensure that child cellId is also in slice
12186 if(fabs(intercept - a_coordinate(a_childId(cellIdsInSlice[i], j), axisNum))
12187 > halfCellLength(a_childId(cellIdsInSlice[i], j))) {
12188 continue;
12189 }
12190 noChilds += 1;
12191 curChildPos++;
12192 }
12193 }
12194 // Position of current cell in the child array of its parent
12195 MUint pos = 0;
12196 if(a_parentId(cellId) > -1) {
12197 MInt parentId = a_parentId(cellId);
12198 for(MUint j = 0; j < (unsigned)m_maxNoChilds; j++) {
12199 if(a_childId(parentId, j) == cellId) {
12200 pos = childArray[j];
12201 }
12202 }
12203 }
12204 // MinLevelCell indicator
12205 MUint isMinLvl = 0;
12206 if(a_level(cellId) == m_minLevel) {
12207 isMinLvl = (MUint)1;
12208 }
12209 MUint tmpBit = noChilds | (pos << 4) | (isMinLvl << 7);
12210 sliceCellInfo[i] = static_cast<MUchar>(tmpBit);
12211
12212 // Determine max level in slice
12213 if(a_level(cellId) > maxLevel) {
12214 maxLevel = a_level(cellId);
12215 }
12216 }
12217
12218
12220 // Step 4: write grid file with slice data
12222
12223 // Create slice grid flle
12224 using namespace maia::parallel_io;
12225
12226 // Create File
12227 const MString gridFileName = fileName + ParallelIo::fileExt();
12228 ParallelIo file(gridFileName, PIO_REPLACE, mpiCommSlice);
12229
12230 // Determine offsets and total number of cells
12231 ParallelIo::size_type sliceCellsOffset, noTotalCells;
12232 ParallelIo::calcOffset(noSliceCells, &sliceCellsOffset, &noTotalCells, mpiCommSlice);
12233 // If only none partitionCells are found, set noSlicePartitionCells to 0, to write no data in
12234 // partitionCell array
12235 if(onlySliceCells) {
12236 noSlicePartitionCells = 0;
12237 }
12238 // Determine offsets and total number of partition cells
12239 ParallelIo::size_type partitionOffset, noPartitionCells;
12240 ParallelIo::calcOffset(noSlicePartitionCells, &partitionOffset, &noPartitionCells, mpiCommSlice);
12241
12242 ParallelIo::size_type minLevelCellsOffset, noTotalMinLevelCells;
12243 ParallelIo::calcOffset(noSliceMinLevelCells, &minLevelCellsOffset, &noTotalMinLevelCells, mpiCommSlice);
12244
12245 MFloat avgWorkload = totalWorkload / ((MFloat)noPartitionCells);
12246 MFloat avgOffspring = ((MFloat)noTotalCells) / ((MFloat)noPartitionCells);
12247
12248 // Define arrays
12249 file.defineArray(PIO_LONG, "partitionCellsGlobalId", noPartitionCells);
12250 file.defineArray(PIO_FLOAT, "partitionCellsWorkload", noPartitionCells);
12251 file.defineArray(PIO_LONG, "minLevelCellsTreeId", noTotalMinLevelCells);
12252 file.defineArray(PIO_LONG, "minLevelCellsNghbrIds", 2 * nDimSlice * noTotalMinLevelCells);
12253 file.defineArray(PIO_UCHAR, "cellInfo", noTotalCells);
12254
12255 const MInt noSolvers = m_tree.noSolvers();
12256 const MBool writeSolver = (noSolvers > 1 || g_multiSolverGrid);
12257 ScratchSpace<MUchar> solverBits(max(noSliceCells, 1), AT_, "solverBits");
12258 if(writeSolver) {
12259 file.defineArray(PIO_UCHAR, "solver", noTotalCells);
12260
12261 for(MInt i = 0; i < noSliceCells; ++i) {
12262 const MLong cellId = cellIdsInSlice[i];
12263 MUint tmpBit = 0;
12264 for(MInt solver = 0; solver < noSolvers; solver++) {
12265 if(m_tree.solver(cellId, solver)) {
12266 tmpBit |= (1 << solver);
12267 }
12268 }
12269 solverBits[i] = static_cast<MUchar>(tmpBit);
12270 }
12271 }
12272
12273 // Set attributes
12274 MInt tstep = 0;
12275 MPI_Allreduce(MPI_IN_PLACE, &maxLevel, 1, MPI_INT, MPI_MAX, mpiCommSlice, AT_, "MPI_IN_PLACE", "maxLevel");
12276 // Get total number of leaf cells
12277 MPI_Allreduce(MPI_IN_PLACE, &noLeafCells, 1, MPI_LONG, MPI_SUM, mpiCommSlice, AT_, "MPI_IN_PLACE", "noLeafCells");
12278
12279 // Count number of cells per solver and set as attribute
12280 if(g_multiSolverGrid) {
12281 for(MInt b = 0; b < noSolvers; b++) {
12282 MLong solverCount = 0;
12283 for(MInt i = 0; i < noSliceCells; i++) {
12284 const MLong cellId = cellIdsInSlice[i];
12285 if(m_tree.solver(cellId, b) == true) {
12286 solverCount++;
12287 }
12288 }
12289 MPI_Allreduce(MPI_IN_PLACE, &solverCount, 1, MPI_LONG, MPI_SUM, mpiCommSlice, AT_, "MPI_IN_PLACE", "solverCount");
12290 file.setAttributes(&solverCount, "noCells_" + std::to_string(b), 1);
12291 }
12292 }
12293
12294 // Set all attributes
12295 file.setAttributes(&nDimSlice, "nDim", 1);
12296 file.setAttributes(&noSolvers, "noSolvers", 1);
12297 file.setAttributes(&tstep, "globalTimeStep", 1);
12298 file.setAttributes(&noTotalCells, "noCells", 1);
12299 file.setAttributes(&noLeafCells, "noLeafCells", 1);
12300 file.setAttributes(&noTotalMinLevelCells, "noMinLevelCells", 1);
12301 file.setAttributes(&noPartitionCells, "noPartitionCells", 1);
12302 file.setAttributes(&totalNoPartitionLevelAncestors, "noPartitionLevelAncestors", 1);
12303 file.setAttributes(&m_minLevel, "minLevel", 1);
12304 file.setAttributes(&maxLevel, "maxLevel", 1);
12305 file.setAttributes(&m_maxUniformRefinementLevel, "maxUniformRefinementLevel", 1);
12306 file.setAttributes(&maxPartitionLevelShift, "maxPartitionLevelShift", 1);
12307 file.setAttributes(&m_lengthLevel0, "lengthLevel0", 1);
12308 file.setAttributes(&centerOfGravity[0], "centerOfGravity", nDimSlice);
12309 file.setAttributes(&boundingBox[0], "boundingBox", 2 * nDimSlice);
12310
12311 // Add additional multisolver information if grid is reordered by a different Hilbert curve
12313 file.setAttributes(&m_targetGridLengthLevel0, "multiSolverLengthLevel0", 1);
12314 file.setAttributes(&m_targetGridMinLevel, "multiSolverMinLevel", 1);
12315 file.setAttributes(&targetGridCenterOfGravity[0], "multiSolverCenterOfGravity", nDimSlice);
12316 file.setAttributes(&targetGridBoundingBox[0], "multiSolverBoundingBox", 2 * nDimSlice);
12317 }
12318
12319 file.setAttributes(&m_reductionFactor, "reductionFactor", 1);
12320 file.setAttributes(&decisiveDirection, "decisiveDirection", 1);
12321 file.setAttributes(&totalWorkload, "totalWorkload", 1);
12322 file.setAttributes(&maxWorkload, "partitionCellMaxWorkload", 1);
12323 file.setAttributes(&avgWorkload, "partitionCellAverageWorkload", 1);
12324 file.setAttributes(&maxNoOffsprings, "partitionCellMaxNoOffspring", 1);
12325 file.setAttributes(&avgOffspring, "partitionCellAverageNoOffspring", 1);
12326 file.setAttributes(&m_partitionCellWorkloadThreshold, "partitionCellWorkloadThreshold", 1);
12327 file.setAttributes(&m_partitionCellOffspringThreshold, "partitionCellOffspringThreshold", 1);
12328 file.setAttributes(&maxNoCPUs, "maxNoBalancedCPUs", 1);
12329
12330 // Save slice axis and intercept to identify the grid file
12331 file.setAttribute(axis, "sliceAxis");
12332 file.setAttribute(intercept, "sliceIntercept");
12333
12334 MBool optimizedSliceIo = true;
12335 optimizedSliceIo = Context::getBasicProperty<MBool>("optimizedSliceIo", AT_, &optimizedSliceIo);
12336
12337 // Write data in chunks of contiguous hilbert-ids/min-cells
12338 if(optimizedSliceIo) {
12339 std::vector<MInt> contHilbertIdsPartitionCounts{};
12340 std::vector<MInt> contHilbertIdsPartitionOffset{};
12341
12342 std::vector<MInt> contHilbertIdCount{};
12343 std::vector<MInt> contHilbertIdOffset{};
12344
12345 std::vector<MInt> contHilbertIdMinCellCount{};
12346 std::vector<MInt> contHilbertIdMinCellOffset{};
12347
12348 { // Min-cells
12349 MInt contHIdMinCellCount = -1;
12350 std::vector<MInt> minCellCount{};
12351 std::vector<MInt> minCellOffset{};
12352 // Store min-cell counts/offsets
12353 for(MInt i = 0, localMinOffset = 0; i < noLocalHilbertIds[sliceDomain]; i++) {
12354 const MInt count = hilbertIdMinLevelCellsCount[hIdKeys[i]];
12355 const MInt offset = hilbertMinLevelDomainOffset[i];
12356 if(localMinOffset < noSliceMinLevelCells) {
12357 if(count > 0) {
12358 minCellCount.push_back(count);
12359 minCellOffset.push_back(offset);
12360 }
12361 }
12362 localMinOffset += count;
12363 }
12364
12365 contHIdMinCellCount = (noSliceMinLevelCells > 0) ? minCellCount[0] : -1;
12366 if(noSliceMinLevelCells == 1) { // Only one min-cell
12367 contHilbertIdMinCellCount.push_back(contHIdMinCellCount);
12368 contHilbertIdMinCellOffset.push_back(minCellOffset[0]);
12369 }
12370
12371 // Find contiguous min-cells and store counts/offsets for writing
12372 for(MInt h = 1, i = 0; h < noSliceMinLevelCells; h++) {
12373 if(minCellCount[h - 1] + minCellOffset[h - 1] == minCellOffset[h]) {
12374 contHIdMinCellCount += minCellCount[h];
12375 } else {
12376 contHilbertIdMinCellCount.push_back(contHIdMinCellCount);
12377 contHilbertIdMinCellOffset.push_back(minCellOffset[i]);
12378
12379 i = h;
12380 contHIdMinCellCount = minCellCount[h];
12381 }
12382
12383 // Last index
12384 if(h == noSliceMinLevelCells - 1) {
12385 contHilbertIdMinCellCount.push_back(contHIdMinCellCount);
12386 contHilbertIdMinCellOffset.push_back(minCellOffset[i]);
12387 }
12388 }
12389 }
12390
12391 { // Cells and partition cells
12392 MInt contHIdPartitionCellCount = hilbertIdPartitionCellsCount[hIdKeys[0]];
12393 MInt contHIdCount = hilbertIdCount[hIdKeys[0]];
12394
12395 if(noLocalHilbertIds[sliceDomain] == 1) { // Only one hilbert id
12396 contHilbertIdsPartitionCounts.push_back(contHIdPartitionCellCount);
12397 contHilbertIdsPartitionOffset.push_back(hilbertPartitionDomainOffset[0]);
12398
12399 contHilbertIdCount.push_back(contHIdCount);
12400 contHilbertIdOffset.push_back(hilbertDomainOffset[0]);
12401 }
12402
12403 // Find contiguous cells/partition-cells and store counts/offsets for writing
12404 for(MInt h = 1, i = 0; h < noLocalHilbertIds[sliceDomain]; h++) {
12405 // Check if current hilbertId is contiguous; if so increase the current cell counts
12406 if(hilbertIdPartitionCellsCount[hIdKeys[h - 1]] + hilbertPartitionDomainOffset[h - 1]
12407 == hilbertPartitionDomainOffset[h]) {
12408 TERMM_IF_NOT_COND(hilbertIdCount[hIdKeys[h - 1]] + hilbertDomainOffset[h - 1] == hilbertDomainOffset[h],
12409 "Error: cells not contiguous");
12410 contHIdPartitionCellCount += hilbertIdPartitionCellsCount[hIdKeys[h]];
12411 contHIdCount += hilbertIdCount[hIdKeys[h]];
12412 } else {
12413 // Not contiguous: store cell counts/offsets and start over with current cell
12414 contHilbertIdsPartitionCounts.push_back(contHIdPartitionCellCount);
12415 contHilbertIdsPartitionOffset.push_back(hilbertPartitionDomainOffset[i]);
12416
12417 contHilbertIdCount.push_back(contHIdCount);
12418 contHilbertIdOffset.push_back(hilbertDomainOffset[i]);
12419
12420 i = h;
12421 contHIdPartitionCellCount = hilbertIdPartitionCellsCount[hIdKeys[h]];
12422 contHIdCount = hilbertIdCount[hIdKeys[h]];
12423 }
12424
12425 // Last hilbert id, store final counts/offsets
12426 if(h == noLocalHilbertIds[sliceDomain] - 1) {
12427 contHilbertIdsPartitionCounts.push_back(contHIdPartitionCellCount);
12428 contHilbertIdsPartitionOffset.push_back(hilbertPartitionDomainOffset[i]);
12429
12430 contHilbertIdCount.push_back(contHIdCount);
12431 contHilbertIdOffset.push_back(hilbertDomainOffset[i]);
12432 }
12433 }
12434 }
12435 const MInt noContHilbertIds = contHilbertIdsPartitionCounts.size();
12436
12437 if(solverId > -1 && noSliceContHilbertIds != nullptr) {
12438 TERMM_IF_COND(sliceContiguousHilbertInfo == nullptr,
12439 "Error: sliceContiguousHilbertInfo is a nullptr but noSliceContHilbertIds is not.");
12440
12441 std::vector<MInt> hIdCountSolver;
12442 std::vector<MInt> hDomainOffsetSolver;
12443 for(MInt i = 0; i < noLocalHilbertIds[sliceDomain]; i++) {
12444 if(hilbertIdCountSolver[hIdKeys[i]] > 0) {
12445 hIdCountSolver.push_back(hilbertIdCountSolver[hIdKeys[i]]);
12446 hDomainOffsetSolver.push_back(hilbertDomainOffsetSolver[i]);
12447 }
12448 }
12449
12450 std::vector<MInt> contHilbertIdCountSolver{};
12451 std::vector<MInt> contHilbertIdOffsetSolver{};
12452
12453 // Note: can be empty if domain has no cells of this solver
12454 MInt contHIdCountSolver = (hIdCountSolver.size() > 0) ? hIdCountSolver[0] : 0;
12455
12456 if(noLocalHilbertIdsSolver == 1) { // Only one hilbert id
12457 contHilbertIdCountSolver.push_back(contHIdCountSolver);
12458 contHilbertIdOffsetSolver.push_back(hDomainOffsetSolver[0]);
12459 }
12460
12461 // Find contiguous cells and store counts/offsets for writing
12462 for(MInt h = 1, i = 0; h < noLocalHilbertIdsSolver; h++) {
12463 // Check if current hilbertId is contiguous; if so increase the current cell counts
12464 if(hIdCountSolver[h - 1] + hDomainOffsetSolver[h - 1] == hDomainOffsetSolver[h]) {
12465 contHIdCountSolver += hIdCountSolver[h];
12466 } else {
12467 // Not contiguous: store cell counts/offsets and start over with current cell
12468 contHilbertIdCountSolver.push_back(contHIdCountSolver);
12469 contHilbertIdOffsetSolver.push_back(hDomainOffsetSolver[i]);
12470
12471 i = h;
12472 contHIdCountSolver = hIdCountSolver[h];
12473 }
12474
12475 // Last hilbert id, store final count/offset
12476 if(h == noLocalHilbertIdsSolver - 1) {
12477 contHilbertIdCountSolver.push_back(contHIdCountSolver);
12478 contHilbertIdOffsetSolver.push_back(hDomainOffsetSolver[i]);
12479 }
12480 }
12481
12482 const MInt noContHilbertIdsSolver = contHilbertIdCountSolver.size();
12483 *noSliceContHilbertIds = noContHilbertIdsSolver;
12484
12485 if(noContHilbertIdsSolver > 0) {
12486 MIntScratchSpace contHilbertInfo(noContHilbertIdsSolver * 3, AT_, "contHilbertInfo");
12487 for(MInt i = 0; i < noContHilbertIdsSolver; i++) {
12488 contHilbertInfo[i * 3] = -1; // Note: cell id not required at the moment
12489 contHilbertInfo[i * 3 + 1] = contHilbertIdCountSolver[i];
12490 contHilbertInfo[i * 3 + 2] = contHilbertIdOffsetSolver[i];
12491 }
12492 std::copy_n(&contHilbertInfo[0], noContHilbertIdsSolver * 3, sliceContiguousHilbertInfo);
12493 }
12494 } else if(solverId < 0) {
12495 // return number of contiguous hilbert id chunks
12496 if(noSliceContHilbertIds != nullptr) {
12497 *noSliceContHilbertIds = noContHilbertIds;
12498 }
12499 // return contiguous HilbertInfo (how many cells per chunks of HilbertIds and offset for file writing)
12500 if(sliceContiguousHilbertInfo != nullptr) {
12501 MIntScratchSpace contHilbertInfo(noContHilbertIds * 3, AT_, "contHilbertInfo");
12502 for(MInt i = 0; i < noContHilbertIds; i++) {
12503 contHilbertInfo[i * 3] = -1; // Note: cell id not required at the moment
12504 contHilbertInfo[i * 3 + 1] = contHilbertIdCount[i];
12505 contHilbertInfo[i * 3 + 2] = contHilbertIdOffset[i];
12506 }
12507 std::copy_n(&contHilbertInfo[0], noContHilbertIds * 3, sliceContiguousHilbertInfo);
12508 }
12509 }
12510
12511 const MFloat writeTimeStart = wallTime();
12512 for(MInt i = 0, localOffset = 0, localPartOffset = 0; i < hilbertDomainOffset.size0(); i++) {
12513 // Write data for every contiguous range of hilbertIds on this domain
12514 if(i < noContHilbertIds) {
12515 // Write partitionCells
12516 file.setOffset(contHilbertIdsPartitionCounts[i], contHilbertIdsPartitionOffset[i]);
12517 file.writeArray(&partitionCellsId[0] + localPartOffset, "partitionCellsGlobalId");
12518 file.writeArray(&partitionCellsWorkload[0] + localPartOffset, "partitionCellsWorkload");
12519 localPartOffset += contHilbertIdsPartitionCounts[i];
12520
12521 // Write cellInfo
12522 file.setOffset(contHilbertIdCount[i], contHilbertIdOffset[i]);
12523 file.writeArray(&sliceCellInfo[0] + localOffset, "cellInfo");
12524 // Write solver bits
12525 if(writeSolver) {
12526 file.writeArray(&solverBits[0] + localOffset, "solver");
12527 }
12528 localOffset += contHilbertIdCount[i];
12529 } else {
12530 // dummy calls of writing function, if this domain has finished writing data, but other domains not
12531 file.setOffset(0, 0);
12532 file.writeArray(&partitionCellsId[0], "partitionCellsGlobalId");
12533 file.writeArray(&partitionCellsWorkload[0], "partitionCellsWorkload");
12534
12535 file.writeArray(&sliceCellInfo[0], "cellInfo");
12536 if(writeSolver) {
12537 file.writeArray(&solverBits[0], "solver");
12538 }
12539 }
12540 }
12541
12542 const MInt noContMinCells = contHilbertIdMinCellCount.size();
12543 for(MInt i = 0, localMinOffset = 0; i < hilbertDomainOffset.size0(); i++) {
12544 // Write data for every contiguous range of min-cells on this domain
12545 if(i < noContMinCells) {
12546 // Write min level cells tree id array
12547 file.setOffset(contHilbertIdMinCellCount[i], contHilbertIdMinCellOffset[i]);
12548 file.writeArray(&sliceMinLevelCellsTreeId[0] + localMinOffset, "minLevelCellsTreeId");
12549 // Write min level cells neighbor ids array
12550 file.setOffset(contHilbertIdMinCellCount[i] * 2 * nDimSlice, contHilbertIdMinCellOffset[i] * 2 * nDimSlice);
12551 file.writeArray(&sliceMinLevelCellsNghbrIds[0] + localMinOffset * 2 * nDimSlice, "minLevelCellsNghbrIds");
12552 localMinOffset += contHilbertIdMinCellCount[i];
12553 } else {
12554 // Dummy call if all minCell data is written or no minCell data is on this domain
12555 file.setOffset(0, 0);
12556 file.writeArray(&partitionCellsId[0], "minLevelCellsTreeId");
12557 file.writeArray(&partitionCellsId[0], "minLevelCellsNghbrIds");
12558 }
12559 }
12560
12561 const MFloat writeTimeTotal = wallTime() - writeTimeStart;
12562 if(sliceDomain == 0) std::cerr << "Slice grid " << gridFileName << " write time: " << writeTimeTotal << std::endl;
12563 } else { // !optimizedSliceIo
12564 // Note: this is quite inefficient on a large number of cores or just for many min/partition cells. The optimized
12565 // version above should be used instead, however, for debugging/checking the output the original slow version below
12566 // should be kept.
12567 const MFloat writeTimeStart = wallTime();
12568
12569 // Make sure anyone requesing the contiguous info uses the optimized version were the info is available
12570 if(noSliceContHilbertIds != nullptr || sliceContiguousHilbertInfo != nullptr) {
12571 TERMM(1, "Error: using non-optimized slice IO but contiguous Hilbert info requested by passing non-nullptr as "
12572 "arguments.");
12573 }
12574
12575 // Write data in chunks which have the same hilbertId. The number of calls of the writing function
12576 // is equal on all domains
12577 for(MInt i = 0, localOffset = 0, localPartOffset = 0, localMinOffset = 0; i < hilbertDomainOffset.size0(); i++) {
12578 if(i < noLocalHilbertIds[sliceDomain]) {
12579 // Write data for every hilbertId on this domain
12580
12581 // Write partitionCells
12582 file.setOffset(hilbertIdPartitionCellsCount[hIdKeys[i]], hilbertPartitionDomainOffset[i]);
12583 file.writeArray(&partitionCellsId[0] + localPartOffset, "partitionCellsGlobalId");
12584 file.writeArray(&partitionCellsWorkload[0] + localPartOffset, "partitionCellsWorkload");
12585 localPartOffset += hilbertIdPartitionCellsCount[hIdKeys[i]];
12586
12587 // NOTE: cellInfo was written at last before, however this seems to occassionally result in the cellInfo array
12588 // not being fully written to the file (observed for the case when each slice-rank writes only a single cellInfo
12589 // entry)
12590 // Write cellInfo
12591 file.setOffset(hilbertIdCount[hIdKeys[i]], hilbertDomainOffset[i]);
12592 file.writeArray(&sliceCellInfo[0] + localOffset, "cellInfo");
12593
12594 // Write solver bits
12595 if(writeSolver) {
12596 file.writeArray(&solverBits[0] + localOffset, "solver");
12597 }
12598
12599 // Write only minCell arrays if some are found
12600 if(localMinOffset < noSliceMinLevelCells) {
12601 // Write min level cells tree id array
12602 file.setOffset(hilbertIdMinLevelCellsCount[hIdKeys[i]], hilbertMinLevelDomainOffset[i]);
12603 file.writeArray(&sliceMinLevelCellsTreeId[0] + localMinOffset, "minLevelCellsTreeId");
12604 // Write min level cells neighbor ids array
12605 file.setOffset(hilbertIdMinLevelCellsCount[hIdKeys[i]] * 2 * nDimSlice,
12606 hilbertMinLevelDomainOffset[i] * 2 * nDimSlice);
12607 file.writeArray(&sliceMinLevelCellsNghbrIds[0] + localMinOffset * 2 * nDimSlice, "minLevelCellsNghbrIds");
12608 } else {
12609 // Dummy call if all minCell data is written or no minCell data is on this domain
12610 file.setOffset(0, 0);
12611 file.writeArray(&partitionCellsId[0], "minLevelCellsTreeId");
12612 file.writeArray(&partitionCellsId[0], "minLevelCellsNghbrIds");
12613 }
12614 localMinOffset += hilbertIdMinLevelCellsCount[hIdKeys[i]];
12615
12616 localOffset += hilbertIdCount[hIdKeys[i]];
12617 } else {
12618 // dummy calls of writing function, if this domain has finished writing data, but other
12619 // domains not
12620 file.setOffset(0, 0);
12621 file.writeArray(&partitionCellsId[0], "partitionCellsGlobalId");
12622 file.writeArray(&partitionCellsWorkload[0], "partitionCellsWorkload");
12623
12624 file.writeArray(&partitionCellsId[0], "minLevelCellsTreeId");
12625 file.writeArray(&partitionCellsId[0], "minLevelCellsNghbrIds");
12626
12627 file.writeArray(&sliceCellInfo[0], "cellInfo");
12628 if(writeSolver) {
12629 file.writeArray(&solverBits[0], "solver");
12630 }
12631 }
12632 }
12633 const MFloat writeTimeTotal = wallTime() - writeTimeStart;
12634 if(sliceDomain == 0) std::cerr << "Slice grid " << gridFileName << " write time: " << writeTimeTotal << std::endl;
12635 }
12636
12637 // Close the grid file explicitely here and finish writing before the MPI communicator is freed
12638 file.close();
12639
12640 // Free the now unneeded MPI communicator
12641 MPI_Comm_free(&mpiCommSlice, AT_, "mpiCommSlice");
12642
12643 m_log << "done!" << endl;
12644}
MFloat m_partitionCellWorkloadThreshold
MInt maxPartitionLevelShift() const
MInt m_partitionCellOffspringThreshold
MBool m_hasMultiSolverBoundingBox
MInt maxLevel() const
maia::grid::tree::SolverBitsetType::reference a_solver(const MInt cellId, const MInt solverId)
Returns if cell cellId is used by solver solverId.
MInt findNeighborDomainId(const MLong globalId)
void centerOfGravity(MFloat *const center) const
void boundingBox(MFloat *const box) const
const MLong & domainOffset(const MInt id) const
Return domain offset.
MFloat m_reductionFactor
MFloat m_targetGridBoundingBox[6]
Multisolver grid information.
MFloat wallTime()
Definition: functions.h:80
MBool g_multiSolverGrid
std::basic_string< char > MString
Definition: maiatypes.h:55
uint64_t MUlong
Definition: maiatypes.h:65
int MPI_Comm_free(MPI_Comm *comm, const MString &name, const MString &varname)
same as MPI_Comm_free, but updates the number of MPI communicators
int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm, const MString &name, const MString &varname)
same as MPI_Comm_create, but updates the number of MPI communicators
int MPI_Group_incl(MPI_Group group, int n, const int ranks[], MPI_Group *newgroup, const MString &name)
same as MPI_Group_incl
int MPI_Comm_group(MPI_Comm comm, MPI_Group *group, const MString &name, const MString &varname)
same as MPI_Comm_group
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
int MPI_Group_free(MPI_Group *group, const MString &name)
same as MPI_Group_free

◆ createHigherLevelExchangeCells()

template<MInt nDim>
void CartesianGrid< nDim >::createHigherLevelExchangeCells ( const MInt  onlyLevel = -1,
const MBool  duringMeshAdaptation = false,
const std::vector< std::function< void(const MInt)> > &  refineCellSolver = std::vector<std::function<void(const MInt)>>(),
const std::vector< std::function< void(const MInt)> > &  removeCellSolver = std::vector<std::function<void(const MInt)>>(),
const MBool  forceLeafLvlCorrection = false 
)
private
Author
Lennart Schneiders
Date
October 2017

— PartLvlShift (*) — ///

— PartLvlShift Ends — ///

Definition at line 1848 of file cartesiangrid.cpp.

1850 {
1851 TRACE();
1852
1853 auto logDuration = [this] (const MFloat timeStart, const MString comment) {
1854 logDuration_(timeStart, "WINDOW/HALO HIGHER LEVEL", comment, mpiComm(), domainId(), noDomains());
1855 };
1856
1857 ScratchSpace<MInt> plaMap(m_maxNoCells, AT_, "plaMap");
1858 vector<MLong> refineChildIds;
1859 vector<MLong> recvChildIds;
1860 vector<vector<MInt>> haloMap;
1861 vector<vector<MInt>> windMap;
1862 vector<MInt> refineIds;
1863
1864 if(domainId() == 0 && onlyLevel < 0) cerr << " * create higher level exchange cells...";
1865
1866 plaMap.fill(-1);
1867 if(m_maxPartitionLevelShift > 0) {
1868 for(MUint i = 0; i < m_partitionLevelAncestorIds.size(); i++) {
1869 plaMap[m_partitionLevelAncestorIds[i]] = i;
1870 }
1871 }
1872
1873 if(m_azimuthalPer && onlyLevel <= m_minLevel) {
1874 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1876 }
1877 }
1878
1879 // given window-halo cell connectivity on minLevel established in setupWindowHaloCellConnectivity(),
1880 // iteratively create connectivity on ascending levels
1881 for(MInt level = m_minLevel; level < m_maxLevel; level++) {
1882 if(onlyLevel > -1 && onlyLevel != level) continue;
1883
1884 const MFloat levelTimeStart = wallTime();
1885#ifndef NDEBUG
1886 // for debugging, check consistency before new level
1887 checkWindowHaloConsistency(false, "createHigherLevelExchangeCells level=" + to_string(level) + ": ");
1888#endif
1889
1890 refineIds.clear();
1891 MInt haloCnt = 0;
1892 MInt windowCnt = 0;
1893 haloMap.resize(noNeighborDomains());
1894 windMap.resize(noNeighborDomains());
1895
1896 // Sets to hold halo/window cells for each neighbor domain to allow fast searching if cells are
1897 // already present
1898 vector<std::set<MInt>> haloCellSet(noNeighborDomains());
1899 vector<std::set<MInt>> windCellSet(noNeighborDomains());
1900
1901 for(MInt i = 0; i < noNeighborDomains(); i++) {
1902 haloMap[i].resize(m_haloCells[i].size());
1903 windMap[i].resize(m_windowCells[i].size());
1904 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
1905 haloMap[i][j] = haloCnt++;
1906 }
1907 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
1908 windMap[i][j] = windowCnt++;
1909 }
1910
1911 haloCellSet[i].insert(m_haloCells[i].begin(), m_haloCells[i].end());
1912 windCellSet[i].insert(m_windowCells[i].begin(), m_windowCells[i].end());
1913 }
1914
1915 recvChildIds.resize(haloCnt * m_maxNoChilds);
1916 fill(recvChildIds.begin(), recvChildIds.end(), -1);
1917 refineChildIds.clear();
1918 refineChildIds.resize(windowCnt * m_maxNoChilds);
1919 fill(refineChildIds.begin(), refineChildIds.end(), -1);
1920
1921#ifndef NDEBUG
1922 for (MInt cellId = 0; cellId < m_tree.size(); ++cellId) {
1923 if (!a_isToDelete(cellId)) {
1924 if (a_hasProperty(cellId, Cell::IsPartLvlAncestor) && !a_hasProperty(cellId, Cell::IsPeriodic)) {
1925 const MInt minNghbrDomId = findNeighborDomainId(a_globalId(cellId));
1926 const MInt maxNghbrDomId =
1928 if (domainId()>=minNghbrDomId && domainId()<=maxNghbrDomId) {
1929 TERMM_IF_NOT_COND(a_hasChildren(cellId), "d=" + to_string(domainId()) + " nghbrs="
1930 + to_string(minNghbrDomId) + "|" + to_string(maxNghbrDomId) + " isHalo=" + to_string(a_isHalo(cellId)));
1931 }
1932 }
1933 }
1934 }
1935
1936 TERMM_IF_COND(bitOffset() && m_maxPartitionLevelShift>0, "Not a good idea to use bitOffset==true & partLvlShift!");
1937 if (!bitOffset()) {
1938 for(MInt i = 0; i < noNeighborDomains(); i++) {
1939 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
1940 const MInt cellId = m_windowCells[i][j];
1941
1942 if (!a_hasProperty(cellId, Cell::IsPartLvlAncestor)) {
1943 const MInt minNghbrDomId = findNeighborDomainId(a_globalId(cellId));
1944 // I don't know why but some cells in testcase LS/3D_minLevelIncrease have a_noOffsprings(cellId)==0
1945 const MInt maxNghbrDomId =
1946 findNeighborDomainId(mMin(m_noCellsGlobal - 1, a_globalId(cellId) + (MLong)std::max(1,a_noOffsprings(cellId))-1));
1947 TERMM_IF_NOT_COND(minNghbrDomId==maxNghbrDomId && minNghbrDomId==domainId(),
1948 "Window cell is not partLvlAncestor, but seems to have children on different domains!");
1949 }
1950 }
1951 }
1952 }
1953#endif
1954
1956 // In the following we provide all window cells, whose parent cell is partLvlAncestor and has children on more
1957 // then one domain, with the information they need and store it in the variable 'windowTemp'
1958
1959 // In periodic case we might need to add same window cell twice, therefore multimap. Save for all
1960 // window children of partLvlAncestor parents with children on more then one domain the connectivity to all halos.
1961 std::multimap<std::pair<MInt/*nghbrDomainIdx*/,MInt/*cellId*/>, M32X4bit<true>> windowsTemp;
1963 // 1) Refine all partLvlAncestor cells with level+1 children on more than one domain
1964 std::set<MInt> partLvlAncSet;
1965 for(MUint i = 0; i < m_partitionLevelAncestorIds.size(); i++) {
1967 if (a_level(cellId)!=level) continue;
1968
1969 ASSERT(a_hasProperty(cellId, Cell::IsPartLvlAncestor),
1970 "not a partition level ancestor: cellId" + std::to_string(cellId) + " halo"
1971 + std::to_string(a_hasProperty(cellId, Cell::IsHalo)) + " domain" + std::to_string(domainId()));
1972 ASSERT(a_hasProperty(cellId, Cell::IsHalo) || findNeighborDomainId(a_globalId(cellId)) == domainId(), "");
1973 ASSERT(a_noChildren(cellId)>0, "PartLvlAncestor cell must have children!");
1974 ASSERT((signed)i==plaMap[cellId], "");
1975
1976 // Guess: during meshAdaptation partLvlAncestor cells may already have halo children
1977 // Note: if cell is halo cell, we may have the situation that neither of the children on level+1 is on current domain
1978 std::set<MInt> nghbrDomIds;
1979 for(MInt child = 0; child < m_maxNoChilds; child++) {
1980 if(m_partitionLevelAncestorChildIds[i * m_maxNoChilds + child] > -1) {
1982 }
1983 }
1984 const MBool multikultiCell = nghbrDomIds.size()>1;
1985
1986 const MInt noChildren = a_noChildren(cellId);
1987 if(multikultiCell) {
1988 partLvlAncSet.insert(cellId);
1989
1991 if(accumulate(childIds, childIds + m_maxNoChilds, static_cast<MLong>(-1),
1992 [](const MLong& a, const MLong& b) { return std::max(a, b); })
1993 > -1) {
1994 refineCell(cellId, childIds, a_hasProperty(cellId, Cell::IsPartLvlAncestor));
1995 // Note: If function is called during meshAdaptation all children should already exist,
1996 // i.e.a_noChildren(cellId)==noChildren
1997 if (a_noChildren(cellId)>noChildren)
1998 refineIds.push_back(cellId); //TODO_SS labels:GRID,totest is it correct? is it necessary?
1999
2000 for(MInt child = 0; child < m_maxNoChilds; child++) {
2001 const MInt childId = a_childId(cellId, child);
2002 if(childId < 0) continue;
2003
2004 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
2005 ASSERT(a_globalId(childId) > -1, "");
2006 const MInt ndom = findNeighborDomainId(a_globalId(childId));
2007 ASSERT(ndom > -1, "");
2008
2009 if (a_isHalo(childId)) {
2010 // There can be partLvlHalo childs and non-partLvlHalo childs (the latter are newly craeted ones)
2011 ASSERT(ndom!=domainId(), "");
2012 } else {
2013 ASSERT(ndom==domainId(), "");
2014 }
2015 //TODO_SS labels:GRID,totest check the following
2016 a_hasProperty(childId, Cell::IsPeriodic) = a_hasProperty(cellId, Cell::IsPeriodic);
2017 }
2018 // The following check fails during meshAdaptation
2019 //TERMM_IF_NOT_COND(a_noChildren(cellId)-noChildren==noHaloChilds, "Expected non-partLvlAncestor halo child!");
2020 // Debug output
2021/* stringstream ss;
2022 ss << " PartLvlAncestor Refinement: d=" << domainId() << " cellId=" << cellId << " (halo=" << a_isHalo(cellId)
2023 << "): Created " << noHaloChilds << " halos on level=" << level+1;
2024 for (MInt child = 0; child < m_maxNoChilds; child++) {
2025 ss << "\n\t1) childId=" << childInfos[3*child];
2026 if (childInfos[3*child+1]==domainId())
2027 ss << " isWindow";
2028 else
2029 ss << " isHalo nghbrDom=" << childInfos[3*child+1] << " isPartLvlHalo=" << childInfos[3*child+2];
2031 }*/
2032
2033 }
2034 }
2035 }
2036
2037 // 2)
2038 // Determine all pairs of neighbor domains to connect:
2039 // For simplicity, if a window cell has children on level+1, which reside on different domains, then the
2040 // window/halo connectivity of the window cell is propagated to all the children, meaning that if domains
2041 // 2,5,11,23 have current cell as halo cell, they also have all children as halo cells.
2042 // Determine window cells on current domain with children on level+1, which reside on different domain (*).
2043 // Determine all neighbors, which have current window cell as halo cell and inform domain (*) about these neighbors.
2044 vector<MInt> sendDomIdx;
2045 vector<M32X4bit<>::type> sendData;
2046 MBoolScratchSpace cellFlag(m_tree.size(), AT_, "cellFlag");
2047 fill(cellFlag.begin(), cellFlag.end(), false);
2048 for(MInt i = 0; i < noNeighborDomains(); i++) {
2049 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
2050 const MInt cellId = m_windowCells[i][j];
2051 ASSERT(m_windowLayer_[i].find(cellId)!=m_windowLayer_[i].end(), "");
2052
2053 if (partLvlAncSet.find(cellId)!=partLvlAncSet.end()) {
2054 ASSERT(a_level(cellId) == level && a_noChildren(cellId) > 0, "");
2055 // Save all domains which own at least one child of current cell
2056 std::set<MInt> nghbrs;
2057 // Boolean to verify that current window cell has at least one window child
2058 MBool windowChild = false;
2059 for(MInt child = 0; child < m_maxNoChilds; child++) {
2060 const MInt cnt = windMap[i][j];
2061
2062 // The purpose of the following is to tag childs which don't reside on current domain because of pls
2063 const MInt pId = plaMap[cellId];
2064 ASSERT(pId>-1, "");
2065 if(m_partitionLevelAncestorChildIds[pId * m_maxNoChilds + child] > -1) {
2066 refineChildIds[m_maxNoChilds * cnt + child] = m_partitionLevelAncestorChildIds[pId * m_maxNoChilds + child];
2067 const MInt domainChild = findNeighborDomainId(m_partitionLevelAncestorChildIds[pId * m_maxNoChilds + child]);
2068 if (domainChild != domainId()) {
2069 nghbrs.insert(domainChild);
2070 } else {
2071 windowChild = true;
2072 const MInt childId = a_childId(cellId, child);
2073 ASSERT(childId>-1, " ");
2074 // In periodic case duplicate window cells possible
2075 TERMM_IF_COND(windowsTemp.find(std::make_pair(m_nghbrDomains[i],childId))!=windowsTemp.end()
2076 && m_noPeriodicCartesianDirs==0, " ");
2077 M32X4bit<true> windowLayer = m_windowLayer_[i].find(childId)!=m_windowLayer_[i].end()
2078 ? m_windowLayer_[i].at(childId) : m_windowLayer_[i].at(cellId);//M32X4bit<true>{};
2079 windowsTemp.insert({std::make_pair(m_nghbrDomains[i],childId), windowLayer});
2080 }
2081 }
2082 }
2083 ASSERT(windowChild, "At least one child must reside on current domain!");
2084 ASSERT(nghbrs.size()>0, "At least one child must reside on a different domain!");
2085
2086 for (const auto ndom : nghbrs) {
2087 const MInt idx = findIndex(m_nghbrDomains.begin(), m_nghbrDomains.end(), ndom);
2088 ASSERT(idx > -1, "");
2089 ASSERT(m_nghbrDomains[idx] == ndom, "");
2090 // In periodic case a neighbor domain can have the cell twice, meaning that current window cell is sending
2091 // the data to two halo cells of the same domain;
2092 // In periodic case we can also have the situation that a child belongs to a neighbor domain,
2093 // and that neighbor domain also has that cell as a periodic halo cell.
2094 if (ndom != m_nghbrDomains[i] || m_noPeriodicCartesianDirs>0) {
2095 sendDomIdx.push_back(idx);
2096 sendData.push_back(m_nghbrDomains[i]);
2097 sendData.push_back(a_globalId(cellId));
2099 sendData.push_back(windowLayer.data());
2100 }
2101 if (!cellFlag[cellId]) {
2102 sendDomIdx.push_back(idx);
2103 sendData.push_back(domainId());
2104 sendData.push_back(a_globalId(cellId));
2106 sendData.push_back(windowLayer.data());
2107 }
2108 }
2109 cellFlag[cellId] = true;
2110 }
2111 }
2112 }
2113
2114 // exchange redirected communication info
2115 vector<MInt> recvOffs;
2116 vector<M32X4bit<>::type> recvData;
2117 maia::mpi::exchangeScattered(m_nghbrDomains, sendDomIdx, sendData, mpiComm(), recvOffs, recvData, 3);
2118
2119 // create window cells if this domain is affected by redirected communication links
2120 const MInt noNgbrDomainsBak = noNeighborDomains();
2121 for(MInt i = 0; i < noNgbrDomainsBak; i++) {
2122 set<MInt> check4PeriodicHalos;
2123 for(MInt j = recvOffs[i]; j < recvOffs[i + 1]; j++) {
2124 auto ndom = static_cast<MInt>(recvData[3 * j]);
2125 const MLong globalCellId = recvData[3 * j + 1];
2126 if (ndom==domainId()) { //might occur in periodic case
2127 // If in periodic case a window cell appears multiple times, skip it one time
2128 ASSERT(m_noPeriodicCartesianDirs>0, "");
2129 if (check4PeriodicHalos.find(globalCellId)==check4PeriodicHalos.end()) {
2130 check4PeriodicHalos.insert(globalCellId);
2131 continue;
2132 }
2133 }
2134 auto windowLayer = recvData[3 * j + 2];
2135 ASSERT(ndom>-1, "");
2136 ASSERT(m_globalToLocalId.find(globalCellId)!=m_globalToLocalId.end(), "");
2137 const MInt cellId = m_globalToLocalId[globalCellId];
2138 ASSERT(cellId > -1, "");
2139 ASSERT(a_globalId(cellId) == globalCellId, "");
2140 ASSERT(findNeighborDomainId(globalCellId) != domainId(), "");
2141// const MInt idx = setNeighborDomainIndex(ndom, m_haloCells, m_windowCells, m_windowLayer_);
2142// TERMM_IF_NOT_COND(idx > -1, "");
2143
2144 // New neighbor domain, create new cell sets
2145// if(idx == static_cast<MInt>(windCellSet.size())) {
2146// windCellSet.emplace_back();
2147// haloCellSet.emplace_back();
2148// }
2149
2150 //const MInt pId = plaMap[cellId];
2151 //TERMM_IF_NOT_COND(pId>-1, "");
2152
2153 MBool foundWindow = false;
2154 for(MInt child = 0; child < m_maxNoChilds; child++) {
2155 const MInt childId = a_childId(cellId, child);
2156 if(childId < 0 || a_isHalo(childId)) continue;
2157 foundWindow = true;
2158
2159 // In periodic case duplicate window cells possible
2160 ASSERT(windowsTemp.find(std::make_pair(ndom,childId))==windowsTemp.end()
2161 || m_noPeriodicCartesianDirs>0, " ");
2162
2163// m_windowCells[idx].push_back(childId);
2164// windCellSet[idx].insert(childId);
2165 windowsTemp.insert({std::make_pair(ndom,childId), M32X4bit<true>(windowLayer)});
2166 }
2167 ASSERT(foundWindow, "");
2168 }
2169 }
2170 }
2172
2173
2174 // since setNeighborDomainIndex is called in tagActiveWindows2_ we might get new neighbors, so save old state
2175 std::vector<MInt> nghbrDomains(m_nghbrDomains);
2176
2177 tagActiveWindows2_(refineChildIds, level);
2178
2179 // We might have added a neighbor domain
2180 haloCellSet.resize(noNeighborDomains());
2181 windCellSet.resize(noNeighborDomains());
2182
2183// set globalIds of each windowCells's child
2184#ifdef _OPENMP
2185#pragma omp parallel for
2186#endif
2187 for(MInt i = 0; i < noNeighborDomains(); i++) {
2188 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
2189 const MInt cellId = m_windowCells[i][j];
2190
2191 if(a_level(cellId) == level && a_noChildren(cellId) > 0) {
2192 for(MInt child = 0; child < m_maxNoChilds; child++) {
2193 const MInt cnt = windMap[i][j];
2194
2195 if(refineChildIds[m_maxNoChilds * cnt + child] > 0) {
2196 const MInt childId = a_childId(cellId, child);
2197 ASSERT(childId > -1, "");
2198 ASSERT((a_globalId(static_cast<MInt>(childId)) >= m_domainOffsets[domainId()]
2199 && a_globalId(static_cast<MInt>(childId)) < m_domainOffsets[domainId() + 1])
2200 || a_hasProperty(cellId, Cell::IsPartLvlAncestor),
2201 to_string(a_globalId(static_cast<MInt>(childId))) + " "
2202 + to_string(m_domainOffsets[domainId()]) + " " + to_string(m_domainOffsets[domainId() + 1]));
2203 refineChildIds[m_maxNoChilds * cnt + child] = a_globalId(static_cast<MInt>(childId));
2204 }
2205 }
2206 }
2207 }
2208 }
2209
2210 // exchange childIds
2211 maia::mpi::exchangeBuffer(nghbrDomains,//m_nghbrDomains,
2214 mpiComm(),
2215 refineChildIds.data(),
2216 recvChildIds.data(),
2218
2219#ifndef NDEBUG
2220 if(m_maxPartitionLevelShift > 0) {
2221 for(MInt i = 0; i < noNeighborDomains(); i++) {
2222 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
2223 MInt cellId = m_haloCells[i][j];
2224 if(a_level(cellId) == level) {
2225 MInt pId = plaMap[cellId];
2226 if(m_maxPartitionLevelShift > 0 && pId > -1) {
2227 MInt cnt = haloMap[i][j];
2228 for(MInt child = 0; child < m_maxNoChilds; child++) {
2229 const MLong childId = m_partitionLevelAncestorChildIds[pId * m_maxNoChilds + child];
2230 ASSERT(childId == recvChildIds[m_maxNoChilds * cnt + child],
2231 std::to_string(childId) + " != " + std::to_string(recvChildIds[m_maxNoChilds * cnt + child])
2232 + "; c" + std::to_string(cellId) + "; g" + std::to_string(a_globalId(cellId)) + "; p"
2233 + std::to_string(pId));
2234 }
2235 }
2236 }
2237 }
2238 }
2239 }
2240#endif
2241
2242
2243 // This is the continuation of 'PartLvlShift (*)'
2245 for (const auto& item : windowsTemp) {
2246 // ndom -> domain to which current window cell needs to send the data to
2247 const MInt ndom = item.first.first;
2248 // childId -> cellId of the current window cell
2249 const MInt childId = item.first.second;
2250 ASSERT(a_hasProperty(a_parentId(childId), Cell::IsPartLvlAncestor), "");
2251 const M32X4bit<true> windowLayer = item.second;
2253 ASSERT(idx > -1, "");
2254// TERMM_IF_NOT_COND(a_isHalo(a_parentId(childId)) && a_hasProperty(a_parentId(childId), Cell::IsPartLvlAncestor), "");
2255 ASSERT(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell), "");
2256
2257 // New neighbor domain, create new cell sets
2258 if(idx == static_cast<MInt>(windCellSet.size())) {
2259 windCellSet.emplace_back();
2260 haloCellSet.emplace_back();
2261 }
2262
2264 if(windCellSet[idx].find(childId) != windCellSet[idx].end())
2265 continue;
2266 } else {
2267 // Note: we can also have 4 halo cells mapped to same window cell (see DG/3D_cube_linearscalaradv_linear_periodic)
2268 //TERMM_IF_COND(windowsTemp.count(std::make_pair(ndom,childId))>2 || std::count(m_windowCells[idx].begin(), m_windowCells[idx].end(), childId)>2, "");
2269 if ((signed)windowsTemp.count(std::make_pair(ndom,childId))<=std::count(m_windowCells[idx].begin(), m_windowCells[idx].end(), childId)) //performance wise this is a shit
2270 continue;
2271 }
2272
2273 m_windowCells[idx].push_back(childId);
2274 windCellSet[idx].insert(childId);
2275
2276 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
2277 if (m_tree.solver(childId, solver) && !isSolverWindowCell(idx,childId,solver) && windowLayer.get(solver)<=m_noSolverHaloLayers[solver]) {
2278 const MInt w = std::max(windowLayer.get(solver), m_noSolverHaloLayers[solver]);
2279 m_windowLayer_[idx][childId].set(solver, w/*windowLayer.get(solver)*//*m_noSolverHaloLayers[solver]*/);
2280 }
2281 }
2282
2283 //TODO_SS labels:GRID,toenhance find a better way
2284 if (m_windowLayer_[idx].find(childId)==m_windowLayer_[idx].end()) {
2285 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
2286// if (m_tree.solver(childId, solver)) {
2287 //TERMM_IF_NOT_COND(m_tree.solver(a_parentId(childId), solver), "");
2288 // We can have cases that a partLvlAnc cell belongs to a solver, but one of its children
2289 // does not. So we can not just propagate the information from parent cell to children cell.
2290 // So we invalidate those window cells by setting layer to m_noSolverHaloLayers[solver]+1.
2291 const MInt w = m_tree.solver(childId, solver) ?
2292 std::max(windowLayer.get(solver), m_noSolverHaloLayers[solver]):
2293 m_noSolverHaloLayers[solver]+1;
2294 m_windowLayer_[idx][childId].set(solver, w/*windowLayer.get(solver)*//*m_noSolverHaloLayers[solver]*//*m_noHaloLayers+1*/);
2295// }
2296 }
2297 }
2298 }
2299 }
2300
2301
2302 // update regular window cells between this domain and m_nghbrDomains[i] to include the level+1 cells
2303 for(MInt i = 0; i < noNeighborDomains(); i++) {
2304 if (m_windowCells[i].size()==0) continue;
2305 vector<MInt> oldWindowVec(m_windowCells[i]);
2306 std::set<MInt> oldWindCellSet(windCellSet[i]);
2307
2308 std::vector<MInt>().swap(m_windowCells[i]);
2309 windCellSet[i].clear();
2310
2311 for(MInt j = 0; j < (signed)oldWindowVec.size(); j++) {
2312 MInt cellId = oldWindowVec[j];
2313
2314 ASSERT(m_noPeriodicCartesianDirs > 0 || windCellSet[i].find(cellId) == windCellSet[i].end(),
2315 "duplicate window cell: " + std::to_string(cellId) + " " + std::to_string(a_globalId(cellId)) + " "
2316 + std::to_string(j));
2317
2318 m_windowCells[i].push_back(cellId);
2319 windCellSet[i].insert(cellId);
2320
2321 ASSERT(cellId < m_tree.size(), to_string(level));
2322
2323 if(a_level(cellId) == level && a_noChildren(cellId) > 0) {
2324 for(MInt child = 0; child < m_maxNoChilds; child++) {
2325 MInt cnt = windMap[i][j];
2326
2327 const MInt childId = a_childId(cellId, child);
2328 if(childId < 0) continue;
2329
2330 // Skip child if it is already part of the old window cell vector and is handled by the
2331 // outer loop
2332 if(oldWindCellSet.find(childId) != oldWindCellSet.end()) {
2333 ASSERT(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell),
2334 "not a partition level ancestor or partition cell");
2335 continue;
2336 }
2337
2338 const MLong globalChildId = refineChildIds[m_maxNoChilds * cnt + child];
2339 if(globalChildId > -1) {
2340 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
2341 // ASSERT( childId > -1 && childId < m_noInternalCells, to_string(childId) + " " +
2342 // to_string(m_noInternalCells) );
2343 MInt ndom = findNeighborDomainId(globalChildId);
2344 if(ndom == domainId()) {
2345 ASSERT(globalChildId == a_globalId(childId), "");
2346
2347 ASSERT(m_noPeriodicCartesianDirs > 0 || windCellSet[i].find(childId) == windCellSet[i].end(),
2348 "duplicate window cell: " + std::to_string(childId));
2349
2350 m_windowCells[i].push_back(childId);
2351// if (m_windowLayer_[i].find(childId)==m_windowLayer_[i].end()) {
2352 // I think the following fails because of testingFix_partitionLevelShift
2353 //TERMM_IF_NOT_COND(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell), "");
2354 // Note: it is dangerous to set windowLayer=m_noHaloLayers+1, since in case
2355 // !isSolverWindowCell(i,childId,solver) for all solvers, we might get
2356 // a halo cell which is completly disabled
2357// for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
2358// if (m_tree.solver(childId, solver) && !isSolverWindowCell(i,childId,solver)) {
2359// m_windowLayer_[i][childId].set(solver, m_noHaloLayers+1/*1*/);
2360// }
2361// }
2362#ifndef NDEBUG
2363 MBool validWindow = false;
2364 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
2365 if (isSolverWindowCell(i,childId,solver)) {
2366 validWindow = true;
2367 break;
2368 }
2369 }
2370 TERMM_IF_NOT_COND(validWindow, "");
2371#endif
2372// }
2373 windCellSet[i].insert(childId);
2374 }
2375 }
2376 }
2377 }
2378 }
2379 }
2380
2381
2382 // create level+1 halo cells existing on other domains
2383 for(MInt i = 0; i < noNeighborDomains(); i++) {
2384 if (m_haloCells[i].size()==0) continue;
2385 vector<MInt> oldHaloVec(m_haloCells[i]);
2386 std::set<MInt> oldHaloCellSet(haloCellSet[i]);
2387
2388 std::vector<MInt>().swap(m_haloCells[i]);
2389 haloCellSet[i].clear();
2390
2391 for(MInt j = 0; j < (signed)oldHaloVec.size(); j++) {
2392 MInt cellId = oldHaloVec[j];
2393
2394 ASSERT(haloCellSet[i].find(cellId) == haloCellSet[i].end(),
2395 "duplicate halo cell: " + std::to_string(cellId) + " " + std::to_string(a_globalId(cellId)) + " "
2396 + std::to_string(j));
2397
2398 m_haloCells[i].push_back(cellId);
2399 haloCellSet[i].insert(cellId);
2400
2401 if(a_level(cellId) == level) {
2402 MInt cnt = haloMap[i][j];
2403
2404 if(accumulate(&recvChildIds[m_maxNoChilds * cnt], &recvChildIds[m_maxNoChilds * cnt] + m_maxNoChilds,
2405 static_cast<MLong>(-1), [](const MLong& a, const MLong& b) { return std::max(a, b); })
2406 > -1) {
2407 refineCell(cellId, &recvChildIds[m_maxNoChilds * cnt], a_hasProperty(cellId, Cell::IsPartLvlAncestor));
2408 refineIds.push_back(cellId);
2409
2410 for(MInt child = 0; child < m_maxNoChilds; child++) {
2411 const MInt childId = a_childId(cellId, child);
2412 if(childId < 0) continue;
2413
2414 // Skip halo child already present in case of partition level shifts
2415 if(oldHaloCellSet.find(childId) != oldHaloCellSet.end()) {
2416 ASSERT(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell),
2417 "not a partition level ancestor or partition cell");
2418 continue;
2419 }
2420
2421 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
2422 ASSERT(a_globalId(childId) > -1, "");
2423 MInt ndom = findNeighborDomainId(a_globalId(childId));
2424 ASSERT(ndom > -1, "");
2425 if(recvChildIds[m_maxNoChilds * cnt + child] > -1)
2426 ASSERT(a_globalId(childId) == recvChildIds[m_maxNoChilds * cnt + child], "");
2427 if(recvChildIds[m_maxNoChilds * cnt + child] < 0) ASSERT(ndom == domainId(), "");
2428 if(ndom == m_nghbrDomains[i]) {
2429 if(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell)) {
2430 // In case of a partition level shift skip if the child is already a halo cell
2431 if(haloCellSet[i].find(childId) != haloCellSet[i].end()) {
2432 continue;
2433 }
2434 }
2435
2436 m_haloCells[i].push_back(childId);
2437 haloCellSet[i].insert(childId);
2438 } else if(m_maxPartitionLevelShift > 0) {
2439 //if(a_hasProperty(cellId, Cell::IsPartLvlAncestor) && a_hasProperty(cellId, Cell::IsPeriodic))
2440 // mTerm(1, AT_, "check code here!!!");
2441#ifndef NDEBUG
2442 if (ndom==domainId() && a_hasProperty(cellId, Cell::IsPeriodic))
2443 TERMM_IF_NOT_COND(a_hasProperty(cellId, Cell::IsPartLvlAncestor), "");
2444#endif
2445 // Here also the case ndom==domainId(), where child halo lies on current domain because of periodicty
2446 // is dealt with
2447 if(ndom != domainId() || a_hasProperty(cellId, Cell::IsPeriodic)) {
2449 ASSERT(idx > -1, "");
2450
2451 // New neighbor domain, create new cell sets
2452 if(idx == static_cast<MInt>(windCellSet.size())) {
2453 windCellSet.emplace_back();
2454 haloCellSet.emplace_back();
2455 }
2456
2457 if(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell)) {
2458 // In case of a partition level shift skip if the child is already a halo cell
2459 if(haloCellSet[idx].find(childId) != haloCellSet[idx].end()) {
2460 continue;
2461 }
2462 }
2463
2464 m_haloCells[idx].push_back(childId);
2465 haloCellSet[idx].insert(childId);
2466 }
2467 }
2468 a_hasProperty(childId, Cell::IsPeriodic) = a_hasProperty(cellId, Cell::IsPeriodic);
2469 }
2470 if(a_noChildren(cellId) == 0) mTerm(1, AT_, "all children gone");
2471 }
2472 }
2473 }
2474 }
2475
2476 // also create level+1 halo cells for local partitionLevelAncestors with children on different domains
2477 if(m_maxPartitionLevelShift > 0) {
2478 for(MUint i = 0; i < m_partitionLevelAncestorIds.size(); i++) {
2480
2481 ASSERT(a_hasProperty(cellId, Cell::IsPartLvlAncestor),
2482 "not a partition level ancestor: cellId" + std::to_string(cellId) + " halo"
2483 + std::to_string(a_hasProperty(cellId, Cell::IsHalo)) + " domain" + std::to_string(domainId()));
2484
2485 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
2486 ASSERT(findNeighborDomainId(a_globalId(cellId)) == domainId(), "");
2487 if(a_level(cellId) == level) {
2489 if(accumulate(childIds, childIds + m_maxNoChilds, static_cast<MLong>(-1),
2490 [](const MLong& a, const MLong& b) { return std::max(a, b); })
2491 > -1) {
2492 refineCell(cellId, childIds, a_hasProperty(cellId, Cell::IsPartLvlAncestor));
2493 refineIds.push_back(cellId);
2494
2495 for(MInt child = 0; child < m_maxNoChilds; child++) {
2496 const MInt childId = a_childId(cellId, child);
2497 if(childId < 0) continue;
2498 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
2499 a_globalId(childId) = childIds[child];
2500 MInt ndom = findNeighborDomainId(a_globalId(childId));
2501 ASSERT(ndom > -1, "");
2502 if(ndom != domainId()) {
2504 ASSERT(idx > -1, "");
2505
2506 // New neighbor domain, create new cell sets
2507 if(idx == static_cast<MInt>(windCellSet.size())) {
2508 windCellSet.emplace_back();
2509 haloCellSet.emplace_back();
2510 }
2511
2512 if(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell)) {
2513 // In case of a partition level shift skip if the child is already a halo cell
2514 if(haloCellSet[idx].find(childId) != haloCellSet[idx].end()) {
2515 continue;
2516 }
2517 }
2518
2519 m_haloCells[idx].push_back(childId);
2520 haloCellSet[idx].insert(childId);
2521 }
2522 a_hasProperty(childId, Cell::IsPeriodic) = a_hasProperty(cellId, Cell::IsPeriodic);
2523 }
2524 }
2525 if(a_noChildren(cellId) == 0) mTerm(1, AT_, "all children gone");
2526 }
2527 }
2528 }
2529
2530 // Refinement of the azimuthal periodic halo cells
2531 if(m_azimuthalPer) {
2532 refineChildIds.clear();
2533 recvChildIds.clear();
2534
2535 // In this function cells are tagged for refinement
2536 tagAzimuthalHigherLevelExchangeCells(refineChildIds, recvChildIds, level);
2537
2538 vector<vector<MLong>> shiftWindows;
2539 shiftWindows.resize(noDomains());
2540 MIntScratchSpace noShiftWindows(noNeighborDomains(), AT_, "noShiftWindows");
2541 noShiftWindows.fill(0);
2542
2543 MInt cnt = 0;
2544 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
2545 vector<MInt> oldWindowVec(m_azimuthalWindowCells[i]);
2546 vector<MInt> oldHigherLevelCon(m_azimuthalHigherLevelConnectivity[i]);
2547
2548 m_azimuthalWindowCells[i].clear();
2550
2551 for(MInt j = 0; j < (signed)oldWindowVec.size(); j++) {
2552 MInt cellId = oldWindowVec[j];
2553
2554 if(find(oldHigherLevelCon.begin(), oldHigherLevelCon.end(), j) != oldHigherLevelCon.end()) {
2556 }
2557 m_azimuthalWindowCells[i].push_back(cellId);
2558
2559 ASSERT(cellId < m_tree.size(), to_string(level));
2560
2561 if(a_level(cellId) == level) {
2562 for(MInt child = 0; child < m_maxNoChilds; child++) {
2563 const MLong globalChildId = refineChildIds[m_maxNoChilds * cnt + child];
2564 // If the correspondig halo cell will be refiened, add child to azimuthal window cell vector
2565 if(globalChildId > -1) {
2566 MInt ndom = findNeighborDomainId(globalChildId);
2567 // Since azimuthal halo cells and azimuthal window cells are not complete copies
2568 // in the sense of the cartesian grid, the corresponding internal cells for the children of
2569 // an azimuthal halo cell might not lie in the internal cell which is mapped to the parent
2570 // halo cell. Therefore, it might be a child of an azimuthal halo cell is connected to a
2571 // differnt mpi rank. This is handled by the shiftWindows.
2572 if(ndom == domainId()) {
2573 const MInt childId = globalIdToLocalId(globalChildId, true);
2574 if(level == m_minLevel && a_level(childId) <= m_minLevel) {
2576 }
2577 m_azimuthalWindowCells[i].push_back(childId);
2578 } else {
2579 ASSERT(m_nghbrDomainIndex[ndom] > -1, "");
2580 shiftWindows[m_nghbrDomainIndex[ndom]].push_back(globalChildId);
2581 shiftWindows[m_nghbrDomainIndex[ndom]].push_back(azimuthalNeighborDomain(i));
2582 noShiftWindows[m_nghbrDomainIndex[ndom]]++;
2583 }
2584 }
2585 }
2586 }
2587 cnt++;
2588 }
2589 }
2590
2591 vector<vector<MInt>> shiftHalos;
2592 shiftHalos.resize(noDomains());
2593 vector<vector<MInt>> shiftHaloDoms;
2594 shiftHaloDoms.resize(noDomains());
2595 MIntScratchSpace noShiftHalos(noDomains(), AT_, "noShiftHalos");
2596 noShiftHalos.fill(0);
2597 cnt = 0;
2598 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
2599 vector<MInt> oldHaloVec(m_azimuthalHaloCells[i]);
2600
2601 m_azimuthalHaloCells[i].clear();
2602
2603 for(MInt j = 0; j < (signed)oldHaloVec.size(); j++) {
2604 MInt cellId = oldHaloVec[j];
2605
2606 m_azimuthalHaloCells[i].push_back(cellId);
2607
2608 if(a_level(cellId) == level) {
2609 if(accumulate(&recvChildIds[m_maxNoChilds * cnt], &recvChildIds[m_maxNoChilds * cnt] + m_maxNoChilds,
2610 static_cast<MLong>(-2), [](const MLong& a, const MLong& b) { return std::max(a, b); })
2611 > -2) {
2612
2613 // Refine the azimuthal halo cell
2614 refineCell(cellId, nullptr, a_hasProperty(cellId, Cell::IsPartLvlAncestor));
2615 refineIds.push_back(cellId);
2616
2617 for(MInt child = 0; child < m_maxNoChilds; child++) {
2618 const MInt childId = a_childId(cellId, child);
2619 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
2620 a_hasProperty(childId, Cell::IsHalo) = a_hasProperty(cellId, Cell::IsHalo);
2621 a_hasProperty(childId, Cell::IsPeriodic) = a_hasProperty(cellId, Cell::IsPeriodic);
2622 a_globalId(childId) = recvChildIds[m_maxNoChilds * cnt + child];
2623 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
2624 treeb().solver(childId, solver) = treeb().solver(cellId, solver);
2625 }
2626
2627 // If the globalId of the child == -1, it has no corresponding interal window cell.
2628 // Since it still might be required is becomes an unmapped halo cell
2629 if(a_globalId(childId) == -1) {
2630 m_azimuthalUnmappedHaloCells.push_back(childId);
2632 continue;
2633 }
2634
2635 ASSERT(a_globalId(childId) > -1,"");
2636 MInt ndom = findNeighborDomainId(a_globalId(childId));
2637
2638 // Since azimuthal halo cells and azimuthal window cells are not complete copies
2639 // in the sense of the cartesian grid, the corresponding internal cells for the children of
2640 // an azimuthal halo cell might not lie in the internal cell which is mapped to the parent
2641 // halo cell. Therefore, it might be a child of an azimuthal halo cell is connected to a
2642 // differnt mpi rank. This is handled by the shiftHalos.
2643 if(ndom == azimuthalNeighborDomain(i)) {
2644 m_azimuthalHaloCells[i].push_back(childId);
2645 } else {
2646 shiftHalos[ndom].push_back(childId);
2647 shiftHaloDoms[ndom].push_back(azimuthalNeighborDomain(i));
2648 noShiftHalos[ndom]++;
2649 }
2650 }
2651 }
2652 }
2653 cnt++;
2654 }
2655 }
2656
2657 // Finally, the shiftWindows and shiftHalos are mapped.
2658 vector<vector<MLong>> newWindows;
2659 newWindows.resize(noNeighborDomains());
2660 MIntScratchSpace noNewWindows(noNeighborDomains(), AT_, "noNewWindows");
2661 noNewWindows.fill(0);
2662 vector<MInt> noValsToReceive;
2663 noValsToReceive.assign(noNeighborDomains(), 1);
2664 maia::mpi::exchangeBuffer(m_nghbrDomains, noValsToReceive, mpiComm(), noShiftWindows.data(), noNewWindows.getPointer());
2665
2666
2667 for(MInt i = 0; i < noNeighborDomains(); i++) {
2668 newWindows[i].resize(2*noNewWindows[i]);
2669 }
2670
2671 ScratchSpace<MPI_Request> sendReq(noNeighborDomains(), AT_, "sendReq");
2672 sendReq.fill(MPI_REQUEST_NULL);
2673
2674 const MInt magic_mpi_tag = 12;
2675 for(MInt i = 0; i < noNeighborDomains(); i++) {
2676 if(noShiftWindows[i] == 0) { continue;
2677}
2678 MPI_Issend(&shiftWindows[i][0], 2 * noShiftWindows[i], type_traits<MLong>::mpiType(), neighborDomain(i), magic_mpi_tag, mpiComm(), &sendReq[i], AT_, "shiftWindows[i][0]");
2679 }
2680
2681 for(MInt i = 0; i < noNeighborDomains(); i++) {
2682 if(noNewWindows[i] == 0) { continue;
2683}
2684 MPI_Recv(&newWindows[i][0], 2 * noNewWindows[i], type_traits<MLong>::mpiType(), neighborDomain(i), magic_mpi_tag, mpiComm(), MPI_STATUS_IGNORE, AT_, "newWindows[i][0]");
2685 }
2686
2687 for(MInt i = 0; i < noNeighborDomains(); i++) {
2688 if(noShiftWindows[i] == 0) { continue;
2689}
2690 MPI_Wait(&sendReq[i], MPI_STATUSES_IGNORE, AT_);
2691 }
2692
2693 // Sort windows - optimize as in updateHaloCellCollectors?
2694 for(MInt i = 0; i < noDomains(); i++) {
2695 shiftWindows[i].clear();
2696 for(MInt d = 0; d < noDomains(); d++) {
2697 MInt nghbrDomId = m_nghbrDomainIndex[d];
2698 if(nghbrDomId == -1) { continue;
2699}
2700 for(MInt j = 0; j < noNewWindows[nghbrDomId]; j++ ) {
2701 MInt haloDomain = newWindows[nghbrDomId][j*2 + 1];
2702 if(haloDomain == i) { shiftWindows[i].push_back(newWindows[nghbrDomId][j*2]);
2703}
2704 }
2705 }
2706 }
2707
2708 // New windows
2709 for(MInt i = 0; i < noDomains(); i++) {
2710 for(MUint j = 0; j < shiftWindows[i].size(); j++ ) {
2711 const MLong globalChildId = shiftWindows[i][j];
2712 ASSERT(findNeighborDomainId(globalChildId) == domainId(),"Wrong domain!");
2713
2714 const MInt childId = globalIdToLocalId(globalChildId, true);
2716
2717 if(level == m_minLevel && a_level(childId) <= m_minLevel) {
2719 }
2720 m_azimuthalWindowCells[idx].push_back(childId);
2721 }
2722 }
2723
2724 // Sort halos
2725 for(MInt i = 0; i < noDomains(); i++) {
2726 vector<MInt> shiftHalosBck(shiftHalos[i]);
2727 shiftHalos[i].clear();
2728 for(MInt d = 0; d < noDomains(); d++) {
2729 for(MInt j = 0; j < noShiftHalos[i]; j++ ) {
2730 MInt nghbrDomain = shiftHaloDoms[i][j];
2731
2732 if(nghbrDomain == d) { shiftHalos[i].push_back(shiftHalosBck[j]);
2733}
2734 }
2735 }
2736 }
2737
2738 // Create new halos
2739 for(MInt i = 0; i < noDomains(); i++) {
2740 for(MInt j = 0; j < noShiftHalos[i]; j++ ) {
2741 const MInt childId = shiftHalos[i][j];
2743
2744 m_azimuthalHaloCells[idx].push_back(childId);
2745 }
2746 }
2747
2748 // Refine unmapped halos
2749 if(!refineCellSolver.empty()) {
2750 if(domainId() == 0) { cerr << "Attention: Unmapped halo are not refined during adaptation!" << endl;
2751}
2752 } else {
2753 shiftWindows.clear();
2754 recvChildIds.clear();
2755 vector<MInt> recvChildDomainIds;
2756 tagAzimuthalUnmappedHaloCells(shiftWindows, recvChildIds, recvChildDomainIds, level);
2757
2758 // Newly mapped windows
2759 // If a child of an unmapped azimuthal halo cell has an adequate internal cell
2760 // This child becomes an regular azimuthal halo cell. Thus, also the internal window cell
2761 // is added to the azimuthal window cell vector
2762 for(MInt i = 0; i < noDomains(); i++) {
2763 for(MUint j = 0; j < shiftWindows[i].size(); j++ ) {
2764 const MLong globalChildId = shiftWindows[i][j];
2765 if(globalChildId < 0) { continue;
2766}
2767
2768 ASSERT(findNeighborDomainId(globalChildId) == domainId(),"Wrong domain! " + to_string(globalChildId) + " " + to_string(findNeighborDomainId(globalChildId)) + " " + to_string(domainId()));
2769
2771
2772 const MInt childId = globalIdToLocalId(globalChildId, true);
2773 m_azimuthalWindowCells[idx].push_back(childId);
2774 }
2775 }
2776
2777 // Newly mapped halos
2778 // If a child of an unmapped azimuthal halo cell has an adequate internal cell
2779 // This child becomes an regular azimuthal halo cell. Thus, it is added to the azimuthal halo cell vector
2780 // Otherwise the child becomes an unmapped azimuthal halo cell
2781 MInt noUnmappedCells = noAzimuthalUnmappedHaloCells();
2782 for(MInt i = 0; i < noUnmappedCells; i++ ) {
2784 if(a_level(cellId) == level) {
2785 if(accumulate(&recvChildIds[m_maxNoChilds * i], &recvChildIds[m_maxNoChilds * i] + m_maxNoChilds,
2786 static_cast<MLong>(-2), [](const MLong& a, const MLong& b) { return std::max(a, b); })
2787 > -2) {
2788
2789 refineCell(cellId, nullptr, a_hasProperty(cellId, Cell::IsPartLvlAncestor));
2790 refineIds.push_back(cellId);
2791
2792 for(MInt child = 0; child < m_maxNoChilds; child++) {
2793 const MInt childId = a_childId(cellId, child);
2794
2795 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
2796 a_hasProperty(childId, Cell::IsHalo) = a_hasProperty(cellId, Cell::IsHalo);
2797 a_hasProperty(childId, Cell::IsPeriodic) = a_hasProperty(cellId, Cell::IsPeriodic);
2798 a_globalId(childId) = recvChildIds[m_maxNoChilds * i + child];
2799 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
2800 treeb().solver(childId, solver) = treeb().solver(cellId, solver);
2801 }
2802
2803 MInt dom = recvChildDomainIds[m_maxNoChilds * i + child];
2804
2805 if(a_globalId(childId) == -1) {
2806 m_azimuthalUnmappedHaloCells.push_back(childId);
2807 m_azimuthalUnmappedHaloDomains.push_back(dom);
2808 continue;
2809 }
2810
2811 ASSERT(findNeighborDomainId(a_globalId(childId)) == dom, "Wrong domain! " + to_string(a_globalId(childId)) + " " + to_string(findNeighborDomainId(a_globalId(childId))) + " " + to_string(dom) + " " + to_string(domainId()) + " " + to_string(cellId));
2812
2814
2815 m_azimuthalHaloCells[idx].push_back(childId);
2816 }
2817 }
2818 }
2819 }
2820 }
2821
2822 // Update grid bndry cells
2823 MBool adaptation = false;
2824 adaptation = Context::getBasicProperty<MBool>("adaptation", AT_, &adaptation);
2825 if(!adaptation) {
2826 std::array<MFloat, 2*nDim> bbox;
2827 for(MInt i = 0; i < nDim; i++) {
2828 bbox[i] = numeric_limits<MFloat>::max();
2829 bbox[nDim + i] = numeric_limits<MFloat>::lowest();
2830 }
2831 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
2832 for(MInt i = 0; i < nDim; i++) {
2833 bbox[i] = mMin(bbox[i], a_coordinate(cellId, i) - F1B2 * cellLengthAtLevel(a_level(cellId)));
2834 bbox[nDim + i] = mMax(bbox[nDim + i], a_coordinate(cellId, i) + F1B2 * cellLengthAtLevel(a_level(cellId)));
2835 }
2836 }
2837 MPI_Allreduce(MPI_IN_PLACE, &bbox[0], nDim, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "bbox[0]");
2838 MPI_Allreduce(MPI_IN_PLACE, &bbox[nDim], nDim, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "bbox[nDim]");
2839 MBool isBndry = false;
2840 for(MInt i = 0; i < m_noInternalCells; i++) {
2841 MInt cellId =i;
2842 if(a_level(cellId) != level+1) { continue;
2843}
2844 isBndry = false;
2845 for(MInt dir = 0; dir < m_noDirs; dir++) {
2846 if(a_hasNeighbor(cellId, dir) > 0) { continue;
2847}
2848 if(a_hasParent(cellId) && a_hasNeighbor(a_parentId(cellId), dir) > 0) {
2849 MInt nghbrParentId = a_neighborId(a_parentId(cellId),dir);
2850 if(a_noChildren(nghbrParentId) == 0) {
2851 continue;
2852 }
2853 }
2854 if(!m_periodicCartesianDir[dir/2]) {
2855 std::array<MFloat, nDim> coords;
2856 for(MInt d = 0; d < nDim; d++) {
2857 coords[d] = a_coordinate(cellId,d);
2858 }
2859 coords[dir / 2] += ((dir % 2) == 0 ? -F1 : F1) * cellLengthAtLevel(m_minLevel);
2860 if(coords[dir / 2] < bbox[dir / 2] || coords[dir / 2] > bbox[nDim + dir / 2]) {
2861 continue;
2862}
2863 }
2864 isBndry = true;
2865 }
2866 if(isBndry) {
2867 if(!a_isHalo(cellId)) { m_gridBndryCells.push_back(cellId);
2868}
2869 for(MInt dir = 0; dir < m_noDirs; dir++) {
2870 if(a_hasNeighbor(cellId, dir) > 0) {
2871 MInt nghbrId = a_neighborId(cellId, dir);
2872 if(!a_isHalo(nghbrId)) {
2873 m_gridBndryCells.push_back(nghbrId);
2874 }
2875 }
2876 }
2877 }
2878 }
2879 }
2880 }
2881
2882 // sort halo and window cells by globalId to get matching connectivity
2883 // this may not even be required, check whether ordering is implicity matching for
2884 // a complex case with multiple partition level shifts
2885 if(m_maxPartitionLevelShift > 0) {
2886 for(MInt i = 0; i < noNeighborDomains(); i++) {
2887 sort(m_haloCells[i].begin(), m_haloCells[i].end(),
2888 [this](const MInt& a, const MInt& b) { return a_globalId(a) < a_globalId(b); });
2889 sort(m_windowCells[i].begin(), m_windowCells[i].end(),
2890 [this](const MInt& a, const MInt& b) { return a_globalId(a) < a_globalId(b); });
2891 }
2892 }
2893
2894 // Exchange solverBits also in case of 1 solver, because solverBits are used to disable halo cells, which
2895 // are created, but in tagActiveWindowsAtMinLevel seen to be superfluous; if we can ensure that in case of
2896 // noSolvers==0, all cells in m_windowCells have a windowLayer<=m_noSolverHaloLayers, we might recomment the
2897 // following if-statement
2898 //if(treeb().noSolvers() > 1) { // Exchange solver info
2900 //}
2903 m_tree.size());
2904
2905 // To ensure that azimuthal halo cells are fully refined (have all children)
2906 // or are not refined at all, solver Bits need to be checked!
2908 }
2909
2910 // trigger refineCell() for halo cells on the solvers
2911 if(!refineCellSolver.empty()) {
2912 // initially empty during solver startup, no solver refinement needed then.
2913 for(auto& cellId : refineIds) {
2914 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
2915 if(!m_tree.solver(cellId, solver)) continue;
2916 if(a_hasChildren(cellId, solver)) {
2917 refineCellSolver[solver](cellId); // call refineCell() function in each solver
2918 }
2919 }
2920 }
2921 refineIds.clear();
2922 }
2923
2924 // When we arrive at the highest level, we can optionally delete uneccesary cells
2925 if (m_haloMode==2 && (forceLeafLvlCorrection || (onlyLevel==-1 && level==m_maxLevel-1))) {
2926 tagActiveWindowsOnLeafLvl3(level+1, duringMeshAdaptation, removeCellSolver);
2927 }
2928
2929 // --- Exchange Cell::IsPartLvlAncestor & noOffsprings --- //
2930 // exchange some window cell data
2931 ScratchSpace<MInt> bprops(m_tree.size(), 2, AT_, "bprops");
2932 bprops.fill(-1);
2933 // Note: changed loop to iterate over whole tree, internal and halo cells not sorted!
2934 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
2935 if(a_isHalo(cellId) || a_isToDelete(cellId)) {
2936 continue;
2937 }
2938 bprops(cellId, 0) = (MInt)a_hasProperty(cellId, Cell::IsPartLvlAncestor);
2939 bprops(cellId, 1) = a_noOffsprings(cellId);
2940
2941 ASSERT(bprops(cellId, 0) > -1 && bprops(cellId, 1) > 0,
2942 std::to_string(cellId) + " " + std::to_string(bprops(cellId, 0)) + " "
2943 + std::to_string(bprops(cellId, 1)));
2944 }
2945
2947
2948 // Note: loop only over the current haloCells since only for these data is exchanged, this does
2949 // not work properly if in case of a partition level shift some halo cell is not part of
2950 // m_haloCells yet such that its property IsPartLvlAncestor is reset!
2951 for(MInt i = 0; i < noNeighborDomains(); i++) {
2952 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
2953 const MInt cellId = m_haloCells[i][j];
2954 ASSERT(!a_isToDelete(cellId), "");
2955 ASSERT(bprops(cellId, 0) > -1 && bprops(cellId, 1) > 0,
2956 std::to_string(cellId) + " " + std::to_string(bprops(cellId, 0)) + " "
2957 + std::to_string(bprops(cellId, 1)));
2958 a_hasProperty(cellId, Cell::IsPartLvlAncestor) = (MBool)bprops(cellId, 0);
2959 a_noOffsprings(cellId) = bprops(cellId, 1);
2960 }
2961 }
2962 // --- Exchange Cell::IsPartLvlAncestor & noOffsprings --- //
2963
2964 // Set window/halo flags
2965 for(MInt i = 0; i < noNeighborDomains(); i++) {
2966 // Halo flag are already set in refineCell
2967#ifndef NDEBUG
2968 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
2969 ASSERT(!a_hasProperty(m_haloCells[i][j], Cell::IsWindow), "halo cell is marked as window");
2970 ASSERT(a_hasProperty(m_haloCells[i][j], Cell::IsHalo), "halo cell flag not set!");
2971 // a_hasProperty(m_haloCells[i][j], Cell::IsHalo) = true;
2972 // a_hasProperty(m_haloCells[i][j], Cell::IsWindow) = false;
2973 }
2974#endif
2975 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
2976 ASSERT(!a_isHalo(m_windowCells[i][j]), "window cell is marked as halo");
2977 // a_hasProperty( m_windowCells[i][j], Cell::IsHalo ) = false;
2978 a_hasProperty(m_windowCells[i][j], Cell::IsWindow) = true;
2979 }
2980 }
2981 if(m_azimuthalPer) {
2982 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
2983 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
2984 ASSERT(!a_hasProperty(m_azimuthalHaloCells[i][j], Cell::IsWindow), "azimuthal halo cell is marked as window");
2985 a_hasProperty(m_azimuthalHaloCells[i][j], Cell::IsHalo) = true;
2986 }
2987 for(MInt j = 0; j < (signed)m_azimuthalWindowCells[i].size(); j++) {
2988 ASSERT(!a_isHalo(m_azimuthalWindowCells[i][j]), "azimuthal window cell is marked as halo");
2989 a_hasProperty(m_azimuthalWindowCells[i][j], Cell::IsWindow) = true;
2990 }
2991 }
2992 for(MInt j = 0; j < noAzimuthalUnmappedHaloCells(); j++ ) {
2993 ASSERT(!a_hasProperty(m_azimuthalUnmappedHaloCells[j], Cell::IsWindow), "azimuthal halo cell is marked as window");
2994 a_hasProperty(m_azimuthalUnmappedHaloCells[j], Cell::IsHalo) = true;
2995 }
2996 }
2997
2998#ifndef NDEBUG
2999 // Sanity check, that parent of a halo cell is also a halo cell
3000 for (MInt i = 0; i < noNeighborDomains(); i++) {
3001 // We need to reinit set, because in tagActiveWindowsOnLeafLvl3 the ordering might change
3002 haloCellSet[i].clear();
3003 std::copy(m_haloCells[i].begin(), m_haloCells[i].end(), std::inserter(haloCellSet[i], haloCellSet[i].begin()));
3004 for (MInt j = 0; j < (signed)m_haloCells[i].size(); ++j) {
3005 MInt parentId = m_haloCells[i][j];
3006 TERMM_IF_NOT_COND(a_isHalo(parentId), "");
3007 char isSolverHalo = 0;
3008 for (MInt solver = 0; solver < treeb().noSolvers(); ++solver) {
3009 if (m_tree.solver(parentId,solver)) {
3010 isSolverHalo = isSolverHalo | (1 << solver);
3011 }
3012 }
3013 while(a_parentId(parentId)>-1) {
3014 parentId = a_parentId(parentId);
3015 TERMM_IF_NOT_COND(a_isHalo(parentId) || a_hasProperty(parentId, Cell::IsPartLvlAncestor), "");
3016 TERMM_IF_NOT_COND(haloCellSet[i].find(parentId)!=haloCellSet[i].end()
3017 || a_hasProperty(parentId, Cell::IsPartLvlAncestor), "");
3018 for (MInt solver = 0; solver < treeb().noSolvers(); ++solver) {
3019 if (isSolverHalo & (1<<solver)) {
3020 TERMM_IF_NOT_COND(m_tree.solver(parentId,solver), "");
3021 }
3022 if (m_tree.solver(parentId,solver)) {
3023 isSolverHalo = isSolverHalo | (1 << solver);
3024 }
3025 }
3026 }
3027 }
3028 }
3029 // for debugging, check consistency before new level
3030 checkWindowHaloConsistency(false, "createHigherLevelExchangeCells completed on level="+to_string(level)+": ");
3031#endif
3032
3033 logDuration(levelTimeStart, "level #"+std::to_string(level)+" total");
3034 }
3035
3036#ifndef NDEBUG
3037 if (onlyLevel==-1 || forceLeafLvlCorrection)
3038 checkWindowLayer("createHigherLevelExchangeCells completed: ");
3039#endif
3040
3041 if(domainId() == 0 && onlyLevel < 0) cerr << endl;
3042}
void refineCell(const MInt cellId, const MLong *const refineChildIds=nullptr, const MBool mayHaveChildren=false, const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &=std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> >(), const std::bitset< maia::grid::tree::Tree< nDim >::maxNoSolvers()> refineFlag=std::bitset< maia::grid::tree::Tree< nDim >::maxNoSolvers()>(1ul))
MInt findIndex(ITERATOR, ITERATOR, const U &)
Find index in array [first,last) with matching entry 'val'.
void tagActiveWindowsOnLeafLvl3(const MInt maxLevel, const MBool duringMeshAdaptation, const std::vector< std::function< void(const MInt)> > &=std::vector< std::function< void(const MInt)> >())
Don't touch this function, because you don't know what you are doing NOTE: Actually the most clever w...
MBool a_hasParent(const MInt cellId) const
Returns if the cell cellId has a parent.
void checkWindowHaloConsistency(const MBool fullCheck=false, const MString a="")
Checks consistency of window/halo cells.
void tagAzimuthalUnmappedHaloCells(std::vector< std::vector< MLong > > &, std::vector< MLong > &, std::vector< MInt > &, MInt)
Tag azimuthal halo cells for refinement.
std::vector< MLong > m_partitionLevelAncestorChildIds
std::vector< MInt > m_gridBndryCells
MInt globalIdToLocalId(const MLong &globalId, const MBool termIfNotExisting=false)
Global to local id mapping.
void correctAzimuthalSolverBits()
Corrects solver bits on azimuthal halo cells Ensure that azimuthal halo cells have all children or ar...
std::vector< MInt > m_nghbrDomainIndex
MInt windowLayer(const MInt domainId, const MInt cellId, const MInt solverId) const
MLong bitOffset() const
Return the 32-BitOffset.
void tagActiveWindows2_(std::vector< MLong > &, const MInt)
NOTE: Actually the most clever way of tagging is to go from highest level to lower levels,...
void exchangeSolverBitset(std::bitset< N > *const data, const MBool defaultVal=false)
void tagAzimuthalHigherLevelExchangeCells(std::vector< MLong > &, std::vector< MLong > &, MInt)
Tag azimuthal halo cells for refinement.
std::vector< std::vector< MInt > > m_azimuthalHigherLevelConnectivity
void checkWindowLayer(const MString a)
Checks variable m_windowLayer_.
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status, const MString &name, const MString &varname)
same as MPI_Recv
int MPI_Issend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Issend
int MPI_Wait(MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Wait
void exchangeScattered(const std::vector< MInt > &nghbrDomains, std::vector< MInt > &sendDomainIndices, std::vector< U > &sendData, const MPI_Comm comm, std::vector< MInt > &recvOffsets, std::vector< U > &recvBuffer, const MInt noDat=1)
Generic exchange of data.
Definition: mpiexchange.h:613
void exchangeBuffer(const MInt noExDomains, const MInt *const exDomainId, const MInt *const recvSize, const MInt *const sendSize, const MPI_Comm comm, U *const receiveBuffer, const U *const sendBuffer, const MInt noDat=1)
Generic exchange of data.
Definition: mpiexchange.h:44
void logDuration_(const MFloat timeStart, const MString module, const MString comment, const MPI_Comm comm, const MInt domainId, const MInt noDomains)
Output the min/max/average duration of a code section over the ranks in a communicator Note: only use...
Definition: timer.cpp:171

◆ createHigherLevelExchangeCells_old()

template<MInt nDim>
void CartesianGrid< nDim >::createHigherLevelExchangeCells_old ( const MInt  onlyLevel = -1,
const std::vector< std::function< void(const MInt)> > &  refineCellSolver = std::vector<std::function<void(const MInt)>>() 
)
private
Author
Lennart Schneiders
Date
October 2017

Definition at line 3053 of file cartesiangrid.cpp.

3054 {
3055 TRACE();
3056
3057 ScratchSpace<MInt> plaMap(m_maxNoCells, AT_, "plaMap");
3058 vector<MLong> refineChildIds;
3059 vector<MLong> recvChildIds;
3060 vector<vector<MInt>> haloMap;
3061 vector<vector<MInt>> windMap;
3062 vector<MInt> refineIds;
3063
3064 if(domainId() == 0 && onlyLevel < 0) cerr << " * create higher level exchange cells...";
3065
3066 plaMap.fill(-1);
3067 if(m_maxPartitionLevelShift > 0) {
3068 for(MUint i = 0; i < m_partitionLevelAncestorIds.size(); i++) {
3069 plaMap[m_partitionLevelAncestorIds[i]] = i;
3070 }
3071 }
3072
3073 if(m_azimuthalPer && onlyLevel <= m_minLevel) {
3074 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
3076 }
3077 }
3078
3079 // given window-halo cell connectivity on minLevel established in setupWindowHaloCellConnectivity(),
3080 // iteratively create connectivity on ascending levels
3081 for(MInt level = m_minLevel; level < m_maxLevel; level++) {
3082 if(onlyLevel > -1 && onlyLevel != level) continue;
3083
3084 // for debugging, check consistency before new level
3085 // checkWindowHaloConsistency();
3086
3087 refineIds.clear();
3088 MInt haloCnt = 0;
3089 MInt windowCnt = 0;
3090 haloMap.resize(noNeighborDomains());
3091 windMap.resize(noNeighborDomains());
3092
3093 // Sets to hold halo/window cells for each neighbor domain to allow fast searching if cells are
3094 // already present
3095 vector<std::set<MInt>> haloCellSet(noNeighborDomains());
3096 vector<std::set<MInt>> windCellSet(noNeighborDomains());
3097
3098 for(MInt i = 0; i < noNeighborDomains(); i++) {
3099 haloMap[i].resize(m_haloCells[i].size());
3100 windMap[i].resize(m_windowCells[i].size());
3101 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
3102 haloMap[i][j] = haloCnt++;
3103 }
3104 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
3105 windMap[i][j] = windowCnt++;
3106 }
3107
3108 haloCellSet[i].insert(m_haloCells[i].begin(), m_haloCells[i].end());
3109 windCellSet[i].insert(m_windowCells[i].begin(), m_windowCells[i].end());
3110 }
3111
3112 recvChildIds.resize(haloCnt * m_maxNoChilds);
3113 fill(recvChildIds.begin(), recvChildIds.end(), -1);
3114 refineChildIds.clear();
3115 tagActiveWindows(refineChildIds, level);
3116
3117
3118// set globalIds of each windowCells's child
3119#ifdef _OPENMP
3120#pragma omp parallel for
3121#endif
3122 for(MInt i = 0; i < noNeighborDomains(); i++) {
3123 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
3124 MInt cellId = m_windowCells[i][j];
3125
3126 if(a_level(cellId) == level && a_noChildren(cellId) > 0) {
3127 for(MInt child = 0; child < m_maxNoChilds; child++) {
3128 MInt cnt = windMap[i][j];
3129
3130 if(refineChildIds[m_maxNoChilds * cnt + child] > 0) {
3131 ASSERT(a_childId(cellId, child) > -1, "");
3132 ASSERT((a_globalId(static_cast<MInt>(a_childId(cellId, child))) >= m_domainOffsets[domainId()]
3133 && a_globalId(static_cast<MInt>(a_childId(cellId, child))) < m_domainOffsets[domainId() + 1])
3134 || a_hasProperty(cellId, Cell::IsPartLvlAncestor),
3135 to_string(a_globalId(static_cast<MInt>(a_childId(cellId, child)))) + " "
3136 + to_string(m_domainOffsets[domainId()]) + " " + to_string(m_domainOffsets[domainId() + 1]));
3137 refineChildIds[m_maxNoChilds * cnt + child] = a_globalId(static_cast<MInt>(a_childId(cellId, child)));
3138 }
3139
3140 MInt pId = plaMap[cellId];
3141 if(m_maxPartitionLevelShift > 0 && pId > -1) {
3142 if(m_partitionLevelAncestorChildIds[pId * m_maxNoChilds + child] > -1) {
3143 ASSERT(refineChildIds[m_maxNoChilds * cnt + child] < 0
3144 || refineChildIds[m_maxNoChilds * cnt + child]
3146 std::to_string(refineChildIds[m_maxNoChilds * cnt + child]) + " plac"
3147 + std::to_string(m_partitionLevelAncestorChildIds[pId * m_maxNoChilds + child]) + "; c"
3148 + std::to_string(cellId) + "; pId" + std::to_string(pId) + "; cnt" + std::to_string(cnt));
3149
3150 refineChildIds[m_maxNoChilds * cnt + child] =
3152 }
3153 }
3154 }
3155 }
3156 }
3157 }
3158
3159 // exchange childIds
3163 mpiComm(),
3164 refineChildIds.data(),
3165 recvChildIds.data(),
3167
3168#ifndef NDEBUG
3169 if(m_maxPartitionLevelShift > 0) {
3170 for(MInt i = 0; i < noNeighborDomains(); i++) {
3171 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
3172 MInt cellId = m_haloCells[i][j];
3173 if(a_level(cellId) == level) {
3174 MInt pId = plaMap[cellId];
3175 if(m_maxPartitionLevelShift > 0 && pId > -1) {
3176 MInt cnt = haloMap[i][j];
3177 for(MInt child = 0; child < m_maxNoChilds; child++) {
3178 const MLong childId = m_partitionLevelAncestorChildIds[pId * m_maxNoChilds + child];
3179 ASSERT(childId == recvChildIds[m_maxNoChilds * cnt + child],
3180 std::to_string(childId) + " != " + std::to_string(recvChildIds[m_maxNoChilds * cnt + child])
3181 + "; c" + std::to_string(cellId) + "; g" + std::to_string(a_globalId(cellId)) + "; p"
3182 + std::to_string(pId));
3183 }
3184 }
3185 }
3186 }
3187 }
3188 }
3189#endif
3190
3191
3192 // initiate communication between two other domains, if one of my childs lies on a different domain (due to
3193 // partitionLevelShift)
3194 if(m_maxPartitionLevelShift > 0) {
3195 // determine all pairs of neighbor domains to connect
3196 vector<MInt> sendDomIdx;
3197 vector<MLong> sendData;
3198 // Note: this assumed that internal and halo cells are separated which is not true if called from meshAdaptation!
3199 // MBoolScratchSpace cellFlag(m_noInternalCells, AT_, "cellFlag");
3200 MBoolScratchSpace cellFlag(m_tree.size(), AT_, "cellFlag");
3201 fill(cellFlag.begin(), cellFlag.end(), false);
3202
3203 for(MInt i = 0; i < noNeighborDomains(); i++) {
3204 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
3205 const MInt cellId = m_windowCells[i][j];
3206 ASSERT(!a_hasProperty(cellId, Cell::IsHalo), "window cell marked as halo");
3207
3208 if(a_level(cellId) == level && a_noChildren(cellId) > 0) {
3209 for(MInt child = 0; child < m_maxNoChilds; child++) {
3210 const MLong childId = refineChildIds[m_maxNoChilds * windMap[i][j] + child];
3211 if(childId < 0) continue;
3212 MInt ndom = findNeighborDomainId(childId);
3213 ASSERT(ndom > -1 && ndom < noDomains(), "");
3214 if(ndom != domainId()) {
3215 ASSERT(a_hasProperty(cellId, Cell::IsPartLvlAncestor), "");
3216 MInt idx = findIndex(m_nghbrDomains.begin(), m_nghbrDomains.end(), ndom);
3217 ASSERT(idx > -1, "");
3218 ASSERT(m_nghbrDomains[idx] == ndom, "");
3219 if(ndom != m_nghbrDomains[i]) {
3220 sendDomIdx.push_back(idx);
3221 sendData.push_back(m_nghbrDomains[i]);
3222 sendData.push_back(childId);
3223 }
3224 if(!cellFlag[cellId]) {
3225 sendDomIdx.push_back(idx);
3226 sendData.push_back(domainId());
3227 sendData.push_back(childId);
3228 }
3229 }
3230 }
3231 }
3232 cellFlag[cellId] = true;
3233 }
3234 }
3235
3236 // exchange redirected communication info
3237 vector<MInt> recvOffs;
3238 vector<MLong> recvData;
3239 maia::mpi::exchangeScattered(m_nghbrDomains, sendDomIdx, sendData, mpiComm(), recvOffs, recvData, 2);
3240
3241 // create window cells if this domain is affected by redirected communication links
3242 const MInt noNgbrDomainsBak = noNeighborDomains();
3243 for(MInt i = 0; i < noNgbrDomainsBak; i++) {
3244 for(MInt j = recvOffs[i]; j < recvOffs[i + 1]; j++) {
3245 auto ndom = static_cast<MInt>(recvData[2 * j]);
3246 MLong globalChildId = recvData[2 * j + 1];
3247 if(ndom > -1) {
3248 MInt childId = m_globalToLocalId[globalChildId];
3249 ASSERT(childId > -1, "");
3250 ASSERT(a_globalId(childId) == globalChildId, "");
3251 ASSERT(findNeighborDomainId(globalChildId) == domainId(), "");
3253 ASSERT(idx > -1, "");
3254
3255 // New neighbor domain, create new cell sets
3256 if(idx == static_cast<MInt>(windCellSet.size())) {
3257 windCellSet.emplace_back();
3258 haloCellSet.emplace_back();
3259 }
3260
3261 if(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell)) {
3262 // In case of a partition level shift skip if the child is already a window cell
3263 if(windCellSet[idx].find(childId) != windCellSet[idx].end()) {
3264 continue;
3265 }
3266 }
3267
3268 ASSERT(windCellSet[idx].find(childId) == windCellSet[idx].end(),
3269 "duplicate window cell: " + std::to_string(childId));
3270
3271 m_windowCells[idx].push_back(childId);
3272 windCellSet[idx].insert(childId);
3273 }
3274 }
3275 }
3276
3277 } // ( m_maxPartitionLevelShift > 0 )
3278
3279
3280 // update regular window cells between this domain and m_nghbrDomains[i] to include the level+1 cells
3281 for(MInt i = 0; i < noNeighborDomains(); i++) {
3282 vector<MInt> oldWindowVec(m_windowCells[i]);
3283 std::set<MInt> oldWindCellSet(windCellSet[i]);
3284
3285 std::vector<MInt>().swap(m_windowCells[i]);
3286 windCellSet[i].clear();
3287
3288 for(MInt j = 0; j < (signed)oldWindowVec.size(); j++) {
3289 MInt cellId = oldWindowVec[j];
3290
3291 // TODO labels:GRID fix duplicate window cells in periodic cases!
3292 ASSERT(m_noPeriodicCartesianDirs > 0 || windCellSet[i].find(cellId) == windCellSet[i].end(),
3293 "duplicate window cell: " + std::to_string(cellId) + " " + std::to_string(a_globalId(cellId)) + " "
3294 + std::to_string(j));
3295
3296 m_windowCells[i].push_back(cellId);
3297 windCellSet[i].insert(cellId);
3298
3299 ASSERT(cellId < m_tree.size(), to_string(level));
3300
3301 if(a_level(cellId) == level && a_noChildren(cellId) > 0) {
3302 for(MInt child = 0; child < m_maxNoChilds; child++) {
3303 MInt cnt = windMap[i][j];
3304
3305 const MInt childId = a_childId(cellId, child);
3306 if(childId < 0) continue;
3307
3308 // Skip child if it is already part of the old window cell vector and is handled by the
3309 // outer loop
3310 if(oldWindCellSet.find(childId) != oldWindCellSet.end()) {
3311 ASSERT(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell),
3312 "not a partition level ancestor or partition cell");
3313 continue;
3314 }
3315
3316 const MLong globalChildId = refineChildIds[m_maxNoChilds * cnt + child];
3317 if(globalChildId > -1) {
3318 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
3319 // ASSERT( childId > -1 && childId < m_noInternalCells, to_string(childId) + " " +
3320 // to_string(m_noInternalCells) );
3321 MInt ndom = findNeighborDomainId(globalChildId);
3322 if(ndom == domainId()) {
3323 ASSERT(globalChildId == a_globalId(childId), "");
3324
3325 // TODO labels:GRID fix duplicate window cells in periodic cases!
3326 ASSERT(m_noPeriodicCartesianDirs > 0 || windCellSet[i].find(childId) == windCellSet[i].end(),
3327 "duplicate window cell: " + std::to_string(childId));
3328
3329 m_windowCells[i].push_back(childId);
3330 windCellSet[i].insert(childId);
3331 }
3332 }
3333 }
3334 }
3335 }
3336 }
3337
3338
3339 // create level+1 halo cells existing on other domains
3340 for(MInt i = 0; i < noNeighborDomains(); i++) {
3341 vector<MInt> oldHaloVec(m_haloCells[i]);
3342 std::set<MInt> oldHaloCellSet(haloCellSet[i]);
3343
3344 std::vector<MInt>().swap(m_haloCells[i]);
3345 haloCellSet[i].clear();
3346
3347 for(MInt j = 0; j < (signed)oldHaloVec.size(); j++) {
3348 MInt cellId = oldHaloVec[j];
3349
3350 ASSERT(haloCellSet[i].find(cellId) == haloCellSet[i].end(),
3351 "duplicate halo cell: " + std::to_string(cellId) + " " + std::to_string(a_globalId(cellId)) + " "
3352 + std::to_string(j));
3353
3354 m_haloCells[i].push_back(cellId);
3355 haloCellSet[i].insert(cellId);
3356
3357 if(a_level(cellId) == level) {
3358 MInt cnt = haloMap[i][j];
3359
3360 if(accumulate(&recvChildIds[m_maxNoChilds * cnt], &recvChildIds[m_maxNoChilds * cnt] + m_maxNoChilds,
3361 static_cast<MLong>(-1), [](const MLong& a, const MLong& b) { return std::max(a, b); })
3362 > -1) {
3363 // NOTE: this leads to different noChilds on window/halo-Cells!
3364 // TODO labels:GRID,totest
3365 // check if halo cell, that is to be refined, is on the second periodic layer
3366 // if so, do not refine this cell
3367 // if(a_hasProperty(cellId,Cell::IsPeriodic)){
3368
3369 // }
3370
3371 refineCell(cellId, &recvChildIds[m_maxNoChilds * cnt], a_hasProperty(cellId, Cell::IsPartLvlAncestor));
3372 refineIds.push_back(cellId);
3373
3374 for(MInt child = 0; child < m_maxNoChilds; child++) {
3375 const MInt childId = a_childId(cellId, child);
3376 if(childId < 0) continue;
3377
3378 // Skip halo child already present in case of partition level shifts
3379 if(oldHaloCellSet.find(childId) != oldHaloCellSet.end()) {
3380 ASSERT(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell),
3381 "not a partition level ancestor or partition cell");
3382 continue;
3383 }
3384
3385 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
3386 ASSERT(a_globalId(childId) > -1, "");
3387 MInt ndom = findNeighborDomainId(a_globalId(childId));
3388 ASSERT(ndom > -1, "");
3389 if(recvChildIds[m_maxNoChilds * cnt + child] > -1)
3390 ASSERT(a_globalId(childId) == recvChildIds[m_maxNoChilds * cnt + child], "");
3391 if(recvChildIds[m_maxNoChilds * cnt + child] < 0) ASSERT(ndom == domainId(), "");
3392 if(ndom == m_nghbrDomains[i]) {
3393 if(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell)) {
3394 // In case of a partition level shift skip if the child is already a halo cell
3395 if(haloCellSet[i].find(childId) != haloCellSet[i].end()) {
3396 continue;
3397 }
3398 }
3399
3400 m_haloCells[i].push_back(childId);
3401 haloCellSet[i].insert(childId);
3402 } else if(m_maxPartitionLevelShift > 0) {
3403 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor) && a_hasProperty(cellId, Cell::IsPeriodic))
3404 mTerm(1, AT_, "check code here!!!");
3405 if(ndom != domainId()) {
3407 ASSERT(idx > -1, "");
3408
3409 // New neighbor domain, create new cell sets
3410 if(idx == static_cast<MInt>(windCellSet.size())) {
3411 windCellSet.emplace_back();
3412 haloCellSet.emplace_back();
3413 }
3414
3415 if(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell)) {
3416 // In case of a partition level shift skip if the child is already a halo cell
3417 if(haloCellSet[idx].find(childId) != haloCellSet[idx].end()) {
3418 continue;
3419 }
3420 }
3421
3422 m_haloCells[idx].push_back(childId);
3423 haloCellSet[idx].insert(childId);
3424 }
3425 }
3426 a_hasProperty(childId, Cell::IsPeriodic) = a_hasProperty(cellId, Cell::IsPeriodic);
3427 }
3428 if(a_noChildren(cellId) == 0) mTerm(1, AT_, "all children gone");
3429 }
3430 }
3431 }
3432 }
3433
3434 // also create level+1 halo cells for local partitionLevelAncestors with children on different domains
3435 if(m_maxPartitionLevelShift > 0) {
3436 for(MUint i = 0; i < m_partitionLevelAncestorIds.size(); i++) {
3438
3439 ASSERT(a_hasProperty(cellId, Cell::IsPartLvlAncestor),
3440 "not a partition level ancestor: cellId" + std::to_string(cellId) + " halo"
3441 + std::to_string(a_hasProperty(cellId, Cell::IsHalo)) + " domain" + std::to_string(domainId()));
3442
3443 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
3444 ASSERT(findNeighborDomainId(a_globalId(cellId)) == domainId(), "");
3445 if(a_level(cellId) == level) {
3447 if(accumulate(childIds, childIds + m_maxNoChilds, static_cast<MLong>(-1),
3448 [](const MLong& a, const MLong& b) { return std::max(a, b); })
3449 > -1) {
3450 refineCell(cellId, childIds, a_hasProperty(cellId, Cell::IsPartLvlAncestor));
3451 refineIds.push_back(cellId);
3452
3453 for(MInt child = 0; child < m_maxNoChilds; child++) {
3454 const MInt childId = a_childId(cellId, child);
3455 if(childId < 0) continue;
3456 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
3457 a_globalId(childId) = childIds[child];
3458 MInt ndom = findNeighborDomainId(a_globalId(childId));
3459 ASSERT(ndom > -1, "");
3460 if(ndom != domainId()) {
3462 ASSERT(idx > -1, "");
3463
3464 // New neighbor domain, create new cell sets
3465 if(idx == static_cast<MInt>(windCellSet.size())) {
3466 windCellSet.emplace_back();
3467 haloCellSet.emplace_back();
3468 }
3469
3470 if(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell)) {
3471 // In case of a partition level shift skip if the child is already a halo cell
3472 if(haloCellSet[idx].find(childId) != haloCellSet[idx].end()) {
3473 continue;
3474 }
3475 }
3476
3477 m_haloCells[idx].push_back(childId);
3478 haloCellSet[idx].insert(childId);
3479 }
3480 a_hasProperty(childId, Cell::IsPeriodic) = a_hasProperty(cellId, Cell::IsPeriodic);
3481 }
3482 }
3483 if(a_noChildren(cellId) == 0) mTerm(1, AT_, "all children gone");
3484 }
3485 }
3486 }
3487
3488 // Refinement of the azimuthal periodic halo cells
3489 if(m_azimuthalPer) {
3490 refineChildIds.clear();
3491 recvChildIds.clear();
3492
3493 // In this function cells are tagged for refinement
3494 tagAzimuthalHigherLevelExchangeCells(refineChildIds, recvChildIds, level);
3495
3496 vector<vector<MLong>> shiftWindows;
3497 shiftWindows.resize(noDomains());
3498 MIntScratchSpace noShiftWindows(noNeighborDomains(), AT_, "noShiftWindows");
3499 noShiftWindows.fill(0);
3500
3501 MInt cnt = 0;
3502 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
3503 vector<MInt> oldWindowVec(m_azimuthalWindowCells[i]);
3504 vector<MInt> oldHigherLevelCon(m_azimuthalHigherLevelConnectivity[i]);
3505
3506 m_azimuthalWindowCells[i].clear();
3508
3509 for(MInt j = 0; j < (signed)oldWindowVec.size(); j++) {
3510 MInt cellId = oldWindowVec[j];
3511
3512 if(find(oldHigherLevelCon.begin(), oldHigherLevelCon.end(), j) != oldHigherLevelCon.end()) {
3514 }
3515 m_azimuthalWindowCells[i].push_back(cellId);
3516
3517 ASSERT(cellId < m_tree.size(), to_string(level));
3518
3519 if(a_level(cellId) == level) {
3520 for(MInt child = 0; child < m_maxNoChilds; child++) {
3521 const MLong globalChildId = refineChildIds[m_maxNoChilds * cnt + child];
3522 // If the correspondig halo cell will be refiened, add child to azimuthal window cell vector
3523 if(globalChildId > -1) {
3524 MInt ndom = findNeighborDomainId(globalChildId);
3525 // Since azimuthal halo cells and azimuthal window cells are not complete copies
3526 // in the sense of the cartesian grid, the corresponding internal cells for the children of
3527 // an azimuthal halo cell might not lie in the internal cell which is mapped to the parent
3528 // halo cell. Therefore, it might be a child of an azimuthal halo cell is connected to a
3529 // differnt mpi rank. This is handled by the shiftWindows.
3530 if(ndom == domainId()) {
3531 const MInt childId = globalIdToLocalId(globalChildId, true);
3532 if(level == m_minLevel && a_level(childId) <= m_minLevel) {
3534 }
3535 m_azimuthalWindowCells[i].push_back(childId);
3536 } else {
3537 ASSERT(m_nghbrDomainIndex[ndom] > -1, "");
3538 shiftWindows[m_nghbrDomainIndex[ndom]].push_back(globalChildId);
3539 shiftWindows[m_nghbrDomainIndex[ndom]].push_back(azimuthalNeighborDomain(i));
3540 noShiftWindows[m_nghbrDomainIndex[ndom]]++;
3541 }
3542 }
3543 }
3544 }
3545 cnt++;
3546 }
3547 }
3548
3549 vector<vector<MInt>> shiftHalos;
3550 shiftHalos.resize(noDomains());
3551 vector<vector<MInt>> shiftHaloDoms;
3552 shiftHaloDoms.resize(noDomains());
3553 MIntScratchSpace noShiftHalos(noDomains(), AT_, "noShiftHalos");
3554 noShiftHalos.fill(0);
3555 cnt = 0;
3556 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
3557 vector<MInt> oldHaloVec(m_azimuthalHaloCells[i]);
3558
3559 m_azimuthalHaloCells[i].clear();
3560
3561 for(MInt j = 0; j < (signed)oldHaloVec.size(); j++) {
3562 MInt cellId = oldHaloVec[j];
3563
3564 m_azimuthalHaloCells[i].push_back(cellId);
3565
3566 if(a_level(cellId) == level) {
3567 if(accumulate(&recvChildIds[m_maxNoChilds * cnt], &recvChildIds[m_maxNoChilds * cnt] + m_maxNoChilds,
3568 static_cast<MLong>(-2), [](const MLong& a, const MLong& b) { return std::max(a, b); })
3569 > -2) {
3570
3571 // Refine the azimuthal halo cell
3572 refineCell(cellId, nullptr, a_hasProperty(cellId, Cell::IsPartLvlAncestor));
3573 refineIds.push_back(cellId);
3574
3575 for(MInt child = 0; child < m_maxNoChilds; child++) {
3576 const MInt childId = a_childId(cellId, child);
3577 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
3578 a_hasProperty(childId, Cell::IsHalo) = a_hasProperty(cellId, Cell::IsHalo);
3579 a_hasProperty(childId, Cell::IsPeriodic) = a_hasProperty(cellId, Cell::IsPeriodic);
3580 a_globalId(childId) = recvChildIds[m_maxNoChilds * cnt + child];
3581 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
3582 treeb().solver(childId, solver) = treeb().solver(cellId, solver);
3583 }
3584
3585 // If the globalId of the child == -1, it has no corresponding interal window cell.
3586 // Since it still might be required is becomes an unmapped halo cell
3587 if(a_globalId(childId) == -1) {
3588 m_azimuthalUnmappedHaloCells.push_back(childId);
3590 continue;
3591 }
3592
3593 ASSERT(a_globalId(childId) > -1,"");
3594 MInt ndom = findNeighborDomainId(a_globalId(childId));
3595
3596 // Since azimuthal halo cells and azimuthal window cells are not complete copies
3597 // in the sense of the cartesian grid, the corresponding internal cells for the children of
3598 // an azimuthal halo cell might not lie in the internal cell which is mapped to the parent
3599 // halo cell. Therefore, it might be a child of an azimuthal halo cell is connected to a
3600 // differnt mpi rank. This is handled by the shiftHalos.
3601 if(ndom == azimuthalNeighborDomain(i)) {
3602 m_azimuthalHaloCells[i].push_back(childId);
3603 } else {
3604 shiftHalos[ndom].push_back(childId);
3605 shiftHaloDoms[ndom].push_back(azimuthalNeighborDomain(i));
3606 noShiftHalos[ndom]++;
3607 }
3608 }
3609 }
3610 }
3611 cnt++;
3612 }
3613 }
3614
3615 // Finally, the shiftWindows and shiftHalos are mapped.
3616 vector<vector<MLong>> newWindows;
3617 newWindows.resize(noNeighborDomains());
3618 MIntScratchSpace noNewWindows(noNeighborDomains(), AT_, "noNewWindows");
3619 noNewWindows.fill(0);
3620 vector<MInt> noValsToReceive;
3621 noValsToReceive.assign(noNeighborDomains(), 1);
3622 maia::mpi::exchangeBuffer(m_nghbrDomains, noValsToReceive, mpiComm(), noShiftWindows.data(), noNewWindows.getPointer());
3623
3624
3625 for(MInt i = 0; i < noNeighborDomains(); i++) {
3626 newWindows[i].resize(2*noNewWindows[i]);
3627 }
3628
3629 ScratchSpace<MPI_Request> sendReq(noNeighborDomains(), AT_, "sendReq");
3630 sendReq.fill(MPI_REQUEST_NULL);
3631
3632 for(MInt i = 0; i < noNeighborDomains(); i++) {
3633 if(noShiftWindows[i] == 0) continue;
3634 MPI_Issend(&shiftWindows[i][0], 2 * noShiftWindows[i], type_traits<MLong>::mpiType(), neighborDomain(i), 12, mpiComm(), &sendReq[i], AT_, "shiftWindows[i][0]");
3635 }
3636
3637 for(MInt i = 0; i < noNeighborDomains(); i++) {
3638 if(noNewWindows[i] == 0) continue;
3639 MPI_Recv(&newWindows[i][0], 2 * noNewWindows[i], type_traits<MLong>::mpiType(), neighborDomain(i), 12, mpiComm(), MPI_STATUS_IGNORE, AT_, "newWindows[i][0]");
3640 }
3641
3642 for(MInt i = 0; i < noNeighborDomains(); i++) {
3643 if(noShiftWindows[i] == 0) continue;
3644 MPI_Wait(&sendReq[i], MPI_STATUSES_IGNORE, AT_);
3645 }
3646
3647 // Sort windows - optimize as in updateHaloCellCollectors?
3648 for(MInt i = 0; i < noDomains(); i++) {
3649 shiftWindows[i].clear();
3650 for(MInt d = 0; d < noDomains(); d++) {
3651 MInt nghbrDomId = m_nghbrDomainIndex[d];
3652 if(nghbrDomId == -1) continue;
3653 for(MInt j = 0; j < noNewWindows[nghbrDomId]; j++ ) {
3654 MInt haloDomain = newWindows[nghbrDomId][j*2 + 1];
3655 if(haloDomain == i) shiftWindows[i].push_back(newWindows[nghbrDomId][j*2]);
3656 }
3657 }
3658 }
3659
3660 // New windows
3661 for(MInt i = 0; i < noDomains(); i++) {
3662 for(MUint j = 0; j < shiftWindows[i].size(); j++ ) {
3663 const MLong globalChildId = shiftWindows[i][j];
3664 ASSERT(findNeighborDomainId(globalChildId) == domainId(),"Wrong domain!");
3665
3666 const MInt childId = globalIdToLocalId(globalChildId, true);
3668
3669 if(level == m_minLevel && a_level(childId) <= m_minLevel) {
3671 }
3672 m_azimuthalWindowCells[idx].push_back(childId);
3673 }
3674 }
3675
3676 // Sort halos
3677 for(MInt i = 0; i < noDomains(); i++) {
3678 vector<MInt> shiftHalosBck(shiftHalos[i]);
3679 shiftHalos[i].clear();
3680 for(MInt d = 0; d < noDomains(); d++) {
3681 for(MInt j = 0; j < noShiftHalos[i]; j++ ) {
3682 MInt nghbrDomain = shiftHaloDoms[i][j];
3683
3684 if(nghbrDomain == d) shiftHalos[i].push_back(shiftHalosBck[j]);
3685 }
3686 }
3687 }
3688
3689 // Create new halos
3690 for(MInt i = 0; i < noDomains(); i++) {
3691 for(MInt j = 0; j < noShiftHalos[i]; j++ ) {
3692 const MInt childId = shiftHalos[i][j];
3694
3695 m_azimuthalHaloCells[idx].push_back(childId);
3696 }
3697 }
3698
3699 // Refine unmapped halos
3700 if(!refineCellSolver.empty()) {
3701 if(domainId() == 0) cerr << "Attention: Unmapped halo are not refined during adaptation!" << endl;
3702 } else {
3703 shiftWindows.clear();
3704 recvChildIds.clear();
3705 vector<MInt> recvChildDomainIds;
3706 tagAzimuthalUnmappedHaloCells(shiftWindows, recvChildIds, recvChildDomainIds, level);
3707
3708 // Newly mapped windows
3709 // If a child of an unmapped azimuthal halo cell has an adequate internal cell
3710 // This child becomes an regular azimuthal halo cell. Thus, also the internal window cell
3711 // is added to the azimuthal window cell vector
3712 for(MInt i = 0; i < noDomains(); i++) {
3713 for(MUint j = 0; j < shiftWindows[i].size(); j++ ) {
3714 const MLong globalChildId = shiftWindows[i][j];
3715 if(globalChildId < 0) continue;
3716
3717 ASSERT(findNeighborDomainId(globalChildId) == domainId(),"Wrong domain! " + to_string(globalChildId) + " " + to_string(findNeighborDomainId(globalChildId)) + " " + to_string(domainId()));
3718
3720
3721 const MInt childId = globalIdToLocalId(globalChildId, true);
3722 m_azimuthalWindowCells[idx].push_back(childId);
3723 }
3724 }
3725
3726 // Newly mapped halos
3727 // If a child of an unmapped azimuthal halo cell has an adequate internal cell
3728 // This child becomes an regular azimuthal halo cell. Thus, it is added to the azimuthal halo cell vector
3729 // Otherwise the child becomes an unmapped azimuthal halo cell
3730 MInt noUnmappedCells = noAzimuthalUnmappedHaloCells();
3731 for(MInt i = 0; i < noUnmappedCells; i++ ) {
3733 if(a_level(cellId) == level) {
3734 if(accumulate(&recvChildIds[m_maxNoChilds * i], &recvChildIds[m_maxNoChilds * i] + m_maxNoChilds,
3735 static_cast<MLong>(-2), [](const MLong& a, const MLong& b) { return std::max(a, b); })
3736 > -2) {
3737
3738 refineCell(cellId, nullptr, a_hasProperty(cellId, Cell::IsPartLvlAncestor));
3739 refineIds.push_back(cellId);
3740
3741 for(MInt child = 0; child < m_maxNoChilds; child++) {
3742 const MInt childId = a_childId(cellId, child);
3743
3744 ASSERT(childId > -1 && childId < m_tree.size(), to_string(childId) + " " + to_string(m_tree.size()));
3745 a_hasProperty(childId, Cell::IsHalo) = a_hasProperty(cellId, Cell::IsHalo);
3746 a_hasProperty(childId, Cell::IsPeriodic) = a_hasProperty(cellId, Cell::IsPeriodic);
3747 a_globalId(childId) = recvChildIds[m_maxNoChilds * i + child];
3748 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
3749 treeb().solver(childId, solver) = treeb().solver(cellId, solver);
3750 }
3751
3752 MInt dom = recvChildDomainIds[m_maxNoChilds * i + child];
3753
3754 if(a_globalId(childId) == -1) {
3755 m_azimuthalUnmappedHaloCells.push_back(childId);
3756 m_azimuthalUnmappedHaloDomains.push_back(dom);
3757 continue;
3758 }
3759
3760 ASSERT(findNeighborDomainId(a_globalId(childId)) == dom, "Wrong domain! " + to_string(a_globalId(childId)) + " " + to_string(findNeighborDomainId(a_globalId(childId))) + " " + to_string(dom) + " " + to_string(domainId()) + " " + to_string(cellId));
3761
3763
3764 m_azimuthalHaloCells[idx].push_back(childId);
3765 }
3766 }
3767 }
3768 }
3769 }
3770
3771 // Update grid bndry cells
3772 MBool adaptation = false;
3773 adaptation = Context::getBasicProperty<MBool>("adaptation", AT_, &adaptation);
3774 if(!adaptation) {
3775 std::array<MFloat, 2 * nDim> bbox;
3776 for(MInt i = 0; i < nDim; i++) {
3777 bbox[i] = numeric_limits<MFloat>::max();
3778 bbox[nDim + i] = numeric_limits<MFloat>::lowest();
3779 }
3780 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
3781 for(MInt i = 0; i < nDim; i++) {
3782 bbox[i] = mMin(bbox[i], a_coordinate(cellId, i) - F1B2 * cellLengthAtLevel(a_level(cellId)));
3783 bbox[nDim + i] = mMax(bbox[nDim + i], a_coordinate(cellId, i) + F1B2 * cellLengthAtLevel(a_level(cellId)));
3784 }
3785 }
3786 MPI_Allreduce(MPI_IN_PLACE, &bbox[0], nDim, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "bbox[0]");
3787 MPI_Allreduce(MPI_IN_PLACE, &bbox[nDim], nDim, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "bbox[nDim]");
3788 MBool isBndry = false;
3789 for(MInt i = 0; i < m_noInternalCells; i++) {
3790 MInt cellId =i;
3791 if(a_level(cellId) != level+1) { continue;
3792}
3793 isBndry = false;
3794 for(MInt dir = 0; dir < m_noDirs; dir++) {
3795 if(a_hasNeighbor(cellId, dir) > 0) { continue;
3796}
3797 if(a_hasParent(cellId) && a_hasNeighbor(a_parentId(cellId), dir) > 0) {
3798 MInt nghbrParentId = a_neighborId(a_parentId(cellId),dir);
3799 if(a_noChildren(nghbrParentId) == 0) {
3800 continue;
3801 }
3802 }
3803 if(!m_periodicCartesianDir[dir/2]) {
3804 std::array<MFloat, nDim> coords;
3805 for(MInt d = 0; d < nDim; d++) {
3806 coords[d] = a_coordinate(cellId,d);
3807 }
3808 coords[dir / 2] += ((dir % 2) == 0 ? -F1 : F1) * cellLengthAtLevel(m_minLevel);
3809 if(coords[dir / 2] < bbox[dir / 2] || coords[dir / 2] > bbox[nDim + dir / 2]) {
3810 continue;
3811}
3812 }
3813 isBndry = true;
3814 }
3815 if(isBndry) {
3816 if(!a_isHalo(cellId)) { m_gridBndryCells.push_back(cellId);
3817}
3818 for(MInt dir = 0; dir < m_noDirs; dir++) {
3819 if(a_hasNeighbor(cellId, dir) > 0) {
3820 MInt nghbrId = a_neighborId(cellId, dir);
3821 if(!a_isHalo(nghbrId)) {
3822 m_gridBndryCells.push_back(nghbrId);
3823 }
3824 }
3825 }
3826 }
3827 }
3828 }
3829 }
3830
3831 // sort halo and window cells by globalId to get matching connectivity
3832 // this may not even be required, check whether ordering is implicity matching for
3833 // a complex case with multiple partition level shifts
3834 if(m_maxPartitionLevelShift > 0) {
3835 for(MInt i = 0; i < noNeighborDomains(); i++) {
3836 sort(m_haloCells[i].begin(), m_haloCells[i].end(),
3837 [this](const MInt& a, const MInt& b) { return a_globalId(a) < a_globalId(b); });
3838 sort(m_windowCells[i].begin(), m_windowCells[i].end(),
3839 [this](const MInt& a, const MInt& b) { return a_globalId(a) < a_globalId(b); });
3840 }
3841 }
3842
3843
3844 if(treeb().noSolvers() > 1) { // Exchange solver info
3846 m_tree.size());
3849 m_tree.size());
3850
3851 // To ensure that azimuthal halo cells are fully refined (have all children)
3852 // or are not refined at all, solver Bits need to be checked!
3854 }
3855 }
3856
3857 // trigger refineCell() for halo cells on the solvers
3858 if(!refineCellSolver.empty()) {
3859 // initially empty during solver startup, no solver refinement needed then.
3860 for(auto& cellId : refineIds) {
3861 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
3862 if(!m_tree.solver(cellId, solver)) continue;
3863 if(a_hasChildren(cellId, solver)) {
3864 refineCellSolver[solver](cellId); // call refineCell() function in each solver
3865 }
3866 }
3867 }
3868 refineIds.clear();
3869 }
3870
3871 // Set window/halo flags
3872 for(MInt i = 0; i < noNeighborDomains(); i++) {
3873 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
3874 ASSERT(!a_hasProperty(m_haloCells[i][j], Cell::IsWindow), "halo cell is marked as window");
3875 a_hasProperty(m_haloCells[i][j], Cell::IsHalo) = true;
3876 // a_hasProperty(m_haloCells[i][j], Cell::IsWindow) = false;
3877 }
3878 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
3879 ASSERT(!a_isHalo(m_windowCells[i][j]), "window cell is marked as halo");
3880 // a_hasProperty( m_windowCells[i][j], Cell::IsHalo ) = false;
3881 a_hasProperty(m_windowCells[i][j], Cell::IsWindow) = true;
3882 }
3883 }
3884 if(m_azimuthalPer) {
3885 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
3886 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
3887 ASSERT(!a_hasProperty(m_azimuthalHaloCells[i][j], Cell::IsWindow), "azimuthal halo cell is marked as window");
3888 a_hasProperty(m_azimuthalHaloCells[i][j], Cell::IsHalo) = true;
3889 }
3890 for(MInt j = 0; j < (signed)m_azimuthalWindowCells[i].size(); j++) {
3891 ASSERT(!a_isHalo(m_azimuthalWindowCells[i][j]), "azimuthal window cell is marked as halo");
3892 a_hasProperty(m_azimuthalWindowCells[i][j], Cell::IsWindow) = true;
3893 }
3894 }
3895 for(MInt j = 0; j < noAzimuthalUnmappedHaloCells(); j++ ) {
3896 ASSERT(!a_hasProperty(m_azimuthalUnmappedHaloCells[j], Cell::IsWindow), "azimuthal halo cell is marked as window");
3897 a_hasProperty(m_azimuthalUnmappedHaloCells[j], Cell::IsHalo) = true;
3898 }
3899 }
3900 }
3901
3902 if(domainId() == 0 && onlyLevel < 0) cerr << endl;
3903
3904}
void tagActiveWindows(std::vector< MLong > &, MInt)
Flag m_noHaloLayers layers of halo cells adjacent to internal cells on this domain.

◆ createLeafCellMapping()

template<MInt nDim>
void CartesianGrid< nDim >::createLeafCellMapping ( const MInt  donorSolverId,
const MInt  gridCellId,
std::vector< MInt > &  mappedLeafCells,
MBool  allChilds = false 
)
Author
ansgar
Parameters
[in]donorSolverIdDonor solver id.
[in]gridCellIdGrid cell to create mapping for.
[out]mappedLeafCellsVector of all mapped leaf cells of the donor solver.

Definition at line 12655 of file cartesiangrid.cpp.

12656 {
12657 TRACE();
12658
12659 mappedLeafCells.clear();
12660
12661 std::stack<MInt> cellStack;
12662
12663 // Check if this cell is used by the donor solver
12664 if(a_solver(gridCellId, donorSolverId)) {
12665 // Initialize cell stack to process
12666 cellStack.push(gridCellId);
12667
12668 // Iterate until cellstack is empty
12669 // else add all children to cell stack
12670 while(!cellStack.empty()) {
12671 // Get current cell to check and remove from stack
12672 const MInt cellId = cellStack.top();
12673 cellStack.pop();
12674
12675 // Check if this is a leaf cell of the donor solver
12676 if(a_isLeafCell(cellId, donorSolverId)) {
12677 // Add to mapped cells
12678 mappedLeafCells.push_back(cellId);
12679 } else {
12680 // Not a leaf cell, add all child cells to the cell stack and continue
12681 for(MInt childId = 0; childId < m_maxNoChilds; childId++) {
12682 if(a_hasChild(cellId, childId, donorSolverId)) {
12683 cellStack.push(a_childId(cellId, childId, donorSolverId));
12684 if(allChilds) {
12685 mappedLeafCells.push_back(a_childId(cellId, childId, donorSolverId));
12686 }
12687 }
12688 }
12689 }
12690 }
12691 } else {
12692 // Check parent cells until cell belonging to donor solver is found or there is no parent cell
12693 // anymore
12694 MBool foundMappedParent = false;
12695 MInt parentId = gridCellId;
12696 while(!foundMappedParent && a_hasParent(parentId)) {
12697 parentId = a_parentId(parentId);
12698 if(a_solver(parentId, donorSolverId) && a_isLeafCell(parentId, donorSolverId)) {
12699 foundMappedParent = true;
12700 }
12701 }
12702
12703 if(foundMappedParent) {
12704 mappedLeafCells.push_back(parentId);
12705 }
12706 }
12707
12708 // Sort mapped leaf cell ids
12709 std::sort(mappedLeafCells.begin(), mappedLeafCells.end());
12710}
MInt a_hasChild(const MInt cellId, const MInt pos) const
Returns if the cell cellId has a child at position pos.

◆ createMinLevelExchangeCells()

template<MInt nDim>
void CartesianGrid< nDim >::createMinLevelExchangeCells
private
Author
Lennart Schneiders
Date
October 2017

Definition at line 1167 of file cartesiangrid.cpp.

1167 {
1168 TRACE();
1169
1170 if(domainId() == 0) cerr << " * create minLevel exchange cells...";
1171
1172 const MInt oldNoCells = m_tree.size();
1173 ScratchSpace<MInt> noHalos(noDomains(), AT_, "noHalos");
1174 ScratchSpace<MInt> noWindows(noDomains(), AT_, "noWindows");
1175 ScratchSpace<MLong> hilbertOffsets(noDomains() + 1, AT_, "hilbertOffsets");
1176 vector<vector<MInt>> halos;
1177 vector<vector<MLong>> hilbertIds;
1178 vector<vector<MLong>> recvHilbertIds;
1179 MInt noMinLevelCells = 0;
1180 MFloat bbox[2 * nDim];
1181 for(MInt i = 0; i < nDim; i++) {
1182 bbox[i] = numeric_limits<MFloat>::max();
1183 bbox[nDim + i] = numeric_limits<MFloat>::lowest();
1184 }
1185 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
1186 for(MInt i = 0; i < nDim; i++) {
1187 bbox[i] = mMin(bbox[i], a_coordinate(cellId, i) - F1B2 * cellLengthAtLevel(a_level(cellId)));
1188 bbox[nDim + i] = mMax(bbox[nDim + i], a_coordinate(cellId, i) + F1B2 * cellLengthAtLevel(a_level(cellId)));
1189 }
1190 }
1191 // Note: use epsilon based on lenght0 (was F1B2 * m_lengthLevel0 +- 1e-12 before), required for
1192 // multisolver grids with multisolver bounding box and shifted center of gravity
1193 const MFloat halfLength0 = 0.5 * ((F1 + F1 / FPOW2(30)) * m_lengthLevel0);
1194 for(MInt i = 0; i < nDim; i++) {
1195 ASSERT(bbox[i] > m_centerOfGravity[i] - halfLength0 && bbox[nDim + i] < m_centerOfGravity[i] + halfLength0,
1196 "bbox " + std::to_string(bbox[i]) + "," + std::to_string(bbox[nDim + i]) + ", center = "
1197 + std::to_string(m_centerOfGravity[i]) + ", halfLenght0 = " + std::to_string(halfLength0));
1198 }
1199 MPI_Allreduce(MPI_IN_PLACE, &bbox[0], nDim, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "bbox[0]");
1200 MPI_Allreduce(MPI_IN_PLACE, &bbox[nDim], nDim, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "bbox[nDim]");
1201
1202 if(((MLong)pow(2.0, m_targetGridMinLevel * nDim)) > std::numeric_limits<MLong>::max()) {
1203 mTerm(1, AT_, "Error: minLevel cell size is bigger than std::numeric_limits<MInt>::max()");
1204 }
1205
1206 // Count the min-level cells on this domain (including partition level ancestors)
1207 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
1208 a_isToDelete(cellId) = false;
1209 if(a_level(cellId) == m_minLevel) {
1210 noMinLevelCells++;
1211 }
1212 }
1213 ASSERT(noMinLevelCells > 0, "Error: no min-level cell (including partition level ancestors) found.");
1214
1215 unordered_multimap<MLong, MInt> hilbertToLocal;
1216 hilbertToLocal.reserve(noMinLevelCells + noMinLevelCells / 5);
1217 noHalos.fill(0);
1218 noWindows.fill(0);
1219
1220 MLong minHilbertIndex = std::numeric_limits<MLong>::max();
1221 MLong prevHilbertIndex = std::numeric_limits<MLong>::min();
1222 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
1223 if(a_level(cellId) != m_minLevel) continue;
1224 const MLong hilbertId = hilbertIndexGeneric(&a_coordinate(cellId, 0));
1225 hilbertToLocal.insert(make_pair(hilbertId, cellId));
1226 if(a_hasProperty(cellId, Cell::IsHalo)) {
1227 MInt ndom = findNeighborDomainId(a_globalId(cellId));
1228 ASSERT(a_hasProperty(cellId, Cell::IsPartLvlAncestor), "");
1229 ASSERT(ndom > -1, "");
1230 MInt idx = setNeighborDomainIndex(ndom, halos, hilbertIds);
1231 ASSERT(idx > -1, "");
1232 halos[idx].push_back(cellId);
1233 hilbertIds[idx].push_back(hilbertId);
1234 noHalos[ndom]++;
1235 }
1236 ASSERT((cellId < m_noInternalCells) != a_hasProperty(cellId, Cell::IsHalo), "");
1237 ASSERT(a_hasProperty(cellId, Cell::IsHalo)
1238 == (a_hasProperty(cellId, Cell::IsPartLvlAncestor) && (cellId >= m_noInternalCells)),
1239 "");
1240 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
1241 minHilbertIndex = mMin(minHilbertIndex, hilbertId);
1242 ASSERT(hilbertId > prevHilbertIndex,
1243 "Min level cells not sorted by Hilbert id: " + to_string(hilbertId) + " > " + to_string(prevHilbertIndex));
1244 prevHilbertIndex = hilbertId;
1245 }
1246 MPI_Allgather(&minHilbertIndex, 1, MPI_LONG, &hilbertOffsets[0], 1, MPI_LONG, mpiComm(), AT_, "minHilbertIndex",
1247 "hilbertOffsets[0]");
1248 hilbertOffsets[0] = 0;
1249 hilbertOffsets[noDomains()] = std::numeric_limits<MLong>::max();
1250
1251 // some domains may not have any min level cells at all (partition level shift)
1252 for(MInt cpu = noDomains() - 1; cpu >= 0; cpu--) {
1253 if(hilbertOffsets[cpu] == std::numeric_limits<MLong>::max()) {
1254 hilbertOffsets[cpu] = hilbertOffsets[cpu + 1];
1255 }
1256 ASSERT(hilbertOffsets[cpu] <= hilbertOffsets[cpu + 1], "");
1257 }
1258
1259 // const MInt maxNoAdjacentCells = ICUBE[2*m_noHaloLayers+1];
1260 const MInt maxNoAdjacentCells = ipow(2 * m_noHaloLayers + 1, 3);
1261 ScratchSpace<MInt> cellList(maxNoAdjacentCells, AT_, "cellList");
1262 MInt ifcDirs[m_noDirs];
1263
1264 vector<pair<MInt, MInt>> interfaceCells;
1265 for(MInt cellId = 0; cellId < oldNoCells; cellId++) {
1266 if(a_level(cellId) > m_minLevel) continue;
1267 for(MInt dir = 0; dir < m_noDirs; dir++) {
1268 if(a_hasNeighbor(cellId, dir) > 0) continue;
1269 interfaceCells.emplace_back(cellId, dir);
1270 }
1271 }
1272
1273 // find direct and diagonal neighboring cells
1274 MUint cnt = 0;
1275 while(cnt < interfaceCells.size()) {
1276 fill(&ifcDirs[0], &ifcDirs[0] + m_noDirs, 0);
1277 const MInt cellId = interfaceCells[cnt].first;
1278 while(cnt < interfaceCells.size() && cellId == interfaceCells[cnt].first) {
1279 ifcDirs[interfaceCells[cnt].second] = 1;
1280 cnt++;
1281 }
1282 MInt cellCnt = 0;
1283 cellList[cellCnt++] = cellId;
1284 for(MInt dim = 0; dim < nDim; dim++) {
1285 const MInt cellCnt0 = cellCnt;
1286 for(MInt ori = 0; ori < 2; ori++) {
1287 const MInt dir = 2 * dim + ori;
1288 if(!ifcDirs[dir]) continue;
1289 for(MInt c = 0; c < cellCnt0; c++) {
1290 MInt nextId = cellList[c];
1291 for(MInt layer = 0; layer < m_noHaloLayers; layer++) {
1292 if(a_hasNeighbor(nextId, dir) > 0)
1293 nextId = a_neighborId(nextId, dir);
1294 else
1295 nextId = createAdjacentHaloCell(nextId, dir, &hilbertOffsets[0], hilbertToLocal, bbox, &noHalos[0], halos,
1296 hilbertIds);
1297 if(nextId < 0) break;
1298 cellList[cellCnt++] = nextId;
1299 }
1300 }
1301 }
1302 }
1303 }
1304
1305 MPI_Alltoall(&noHalos[0], 1, MPI_INT, &noWindows[0], 1, MPI_INT, mpiComm(), AT_, "noHalos[0]", "noWindows[0]");
1306
1307 for(MInt i = 0; i < noDomains(); i++) {
1308 if(noHalos[i] == 0 && noWindows[i] > 0) {
1309 ASSERT(m_nghbrDomainIndex[i] < 0, "");
1310 setNeighborDomainIndex(i, halos, hilbertIds);
1311 }
1312 }
1313
1314 ScratchSpace<MPI_Request> sendReq(noNeighborDomains(), AT_, "sendReq");
1315 sendReq.fill(MPI_REQUEST_NULL);
1316 recvHilbertIds.resize(noNeighborDomains());
1317 for(MInt i = 0; i < noNeighborDomains(); i++) {
1318 ASSERT(m_nghbrDomains[i] > -1 && m_nghbrDomains[i] < noDomains(), "");
1319 recvHilbertIds[i].resize(noWindows[m_nghbrDomains[i]]);
1320 }
1321 for(MInt i = 0; i < noNeighborDomains(); i++) {
1322 for(MInt k = 0; k < noHalos[m_nghbrDomains[i]]; k++) {
1323 ASSERT(hilbertIds[i][k] >= hilbertOffsets[m_nghbrDomains[i]]
1324 && hilbertIds[i][k] < hilbertOffsets[m_nghbrDomains[i] + 1],
1325 to_string(hilbertIds[i][k]) + " " + to_string(hilbertOffsets[m_nghbrDomains[i]]) + " "
1326 + to_string(hilbertOffsets[m_nghbrDomains[i] + 1]));
1327 }
1328 }
1329 for(MInt i = 0; i < noNeighborDomains(); i++) {
1330 MPI_Issend(&hilbertIds[i][0], noHalos[m_nghbrDomains[i]], MPI_LONG, m_nghbrDomains[i], 34, mpiComm(), &sendReq[i],
1331 AT_, "hilbertIds[i][0]");
1332 }
1333 for(MInt i = 0; i < noNeighborDomains(); i++) {
1334 MPI_Recv(&recvHilbertIds[i][0], noWindows[m_nghbrDomains[i]], MPI_LONG, m_nghbrDomains[i], 34, mpiComm(),
1335 MPI_STATUS_IGNORE, AT_, "recvHilbertIds[i][0]");
1336 }
1337 if(noNeighborDomains() > 0) MPI_Waitall(noNeighborDomains(), &sendReq[0], MPI_STATUSES_IGNORE, AT_);
1338 for(MInt i = 0; i < noNeighborDomains(); i++) {
1339 for(MInt k = 0; k < noWindows[m_nghbrDomains[i]]; k++) {
1340 ASSERT(recvHilbertIds[i][k] >= hilbertOffsets[domainId()]
1341 && recvHilbertIds[i][k] < hilbertOffsets[domainId() + 1],
1342 "");
1343 }
1344 }
1345
1346 vector<vector<MLong>> sendGlobalIds;
1347 vector<vector<MLong>> recvGlobalIds;
1348 sendGlobalIds.resize(noNeighborDomains());
1349 recvGlobalIds.resize(noNeighborDomains());
1350 for(MInt i = 0; i < noNeighborDomains(); i++) {
1351 ASSERT(m_nghbrDomains[i] > -1 && m_nghbrDomains[i] < noDomains(), "");
1352 sendGlobalIds[i].resize(noWindows[m_nghbrDomains[i]]);
1353 recvGlobalIds[i].resize(noHalos[m_nghbrDomains[i]]);
1354 }
1355
1356 for(MInt i = 0; i < noNeighborDomains(); i++) {
1357 m_windowCells.push_back(vector<MInt>());
1358 for(MInt k = 0; k < noWindows[m_nghbrDomains[i]]; k++) {
1359 MInt windowId = -1;
1360 auto range = hilbertToLocal.equal_range(recvHilbertIds[i][k]);
1361 for(auto it = range.first; it != range.second; ++it) {
1362 if(!a_hasProperty(it->second, Cell::IsPeriodic) && !a_hasProperty(it->second, Cell::IsHalo)) {
1363 windowId = it->second;
1364 }
1365 }
1366 ASSERT(windowId > -2 && windowId < m_noInternalCells, to_string(windowId) + " " + to_string(m_noInternalCells));
1367 if(windowId > -1) {
1368 ASSERT(a_level(windowId) == m_minLevel, "");
1369 m_windowCells[i].push_back(windowId);
1370 sendGlobalIds[i][k] = a_globalId(windowId);
1371 } else {
1372 sendGlobalIds[i][k] = -1;
1373 }
1374 }
1375 }
1376
1377 // send back globalId when the queried cell exists, -1 if not existing
1378 sendReq.fill(MPI_REQUEST_NULL);
1379 for(MInt i = 0; i < noNeighborDomains(); i++) {
1380 MPI_Issend(&sendGlobalIds[i][0], noWindows[m_nghbrDomains[i]], MPI_LONG, m_nghbrDomains[i], 35, mpiComm(),
1381 &sendReq[i], AT_, "sendGlobalIds[i][0]");
1382 }
1383 for(MInt i = 0; i < noNeighborDomains(); i++) {
1384 MPI_Recv(&recvGlobalIds[i][0], noHalos[m_nghbrDomains[i]], MPI_LONG, m_nghbrDomains[i], 35, mpiComm(),
1385 MPI_STATUS_IGNORE, AT_, "recvGlobalIds[i][0]");
1386 }
1387 if(noNeighborDomains() > 0) MPI_Waitall(noNeighborDomains(), &sendReq[0], MPI_STATUSES_IGNORE, AT_);
1388
1389 {
1390 ScratchSpace<MInt> posMapping(m_tree.size(), AT_, "posMapping");
1391 posMapping.fill(-1);
1392 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
1393 posMapping[cellId] = cellId;
1394 }
1395
1396 ScratchSpace<MInt> delFlag(m_tree.size(), AT_, "delFlag");
1397 delFlag.fill(0);
1398 for(MInt i = 0; i < noNeighborDomains(); i++) {
1399 for(MInt k = 0; k < noHalos[m_nghbrDomains[i]]; k++) {
1400 MInt cellId = halos[i][k];
1401 MLong globalId = recvGlobalIds[i][k];
1402 a_globalId(cellId) = globalId;
1403 if(globalId < 0) {
1404 ASSERT(cellId >= oldNoCells, "Attempting to delete parent gap halo cell.");
1405 delFlag[cellId] = 1;
1406 posMapping[cellId] = -1;
1407 }
1408 }
1409 }
1410
1411 for(MInt cellId = oldNoCells; cellId < m_tree.size(); cellId++) {
1412 if(delFlag[cellId]) {
1413 MInt otherCellId = deleteCell(cellId);
1414 if(otherCellId > -1) {
1415 ASSERT(delFlag[otherCellId] || posMapping[otherCellId] == otherCellId, "");
1416 if(!delFlag[otherCellId]) posMapping[otherCellId] = cellId;
1417 delFlag[cellId] = delFlag[otherCellId];
1418 delFlag[otherCellId] = 0;
1419 cellId--;
1420 }
1421 }
1422 }
1423
1424 for(MInt i = 0; i < noNeighborDomains(); i++) {
1425 m_haloCells.push_back(vector<MInt>());
1426 for(MInt k = 0; k < noHalos[m_nghbrDomains[i]]; k++) {
1427 MLong globalId = recvGlobalIds[i][k];
1428 if(globalId > -1) {
1429 ASSERT(posMapping[halos[i][k]] > -1, "");
1430 MInt cellId = posMapping[halos[i][k]];
1431 ASSERT(cellId > -1 && cellId < m_tree.size(), "");
1432 ASSERT(a_globalId(cellId) == globalId, "");
1433 m_haloCells[i].push_back(cellId);
1434 }
1435 }
1436 }
1437 }
1438
1439 for(MInt i = 0; i < nDim; i++) {
1440 if(m_periodicCartesianDir[i] > 0) {
1441 m_periodicCartesianLength[i] = bbox[nDim + i] - bbox[i];
1442 } else {
1443#ifdef MAIA_PGI_COMPILER
1444 m_periodicCartesianLength[i] = numeric_limits<MFloat>::quiet_NaN();
1445#else
1446 m_periodicCartesianLength[i] = numeric_limits<MFloat>::signaling_NaN();
1447#endif
1448 }
1449 }
1450
1451 IF_CONSTEXPR(nDim == 3) {
1452 if(m_azimuthalPer) {
1453 // First the azimuthal bounding box is determined
1454 // It is used determine where azimuthal halos cells are required
1455 for(MInt i = 0; i < nDim; i++) {
1456 MFloat dirLength = bbox[i + nDim] - bbox[i];
1457 MInt nBins = (MInt)(dirLength / cellLengthAtLevel(m_minLevel));
1458 m_azimuthalBbox.minCoord[i] = bbox[i];
1459 m_azimuthalBbox.boxLength[i] = dirLength;
1460 m_azimuthalBbox.nBins[i] = nBins;
1461 }
1462
1466 MFloatScratchSpace minPer1(perSize1, AT_, "minPer1");
1467 minPer1.fill(std::numeric_limits<MFloat>::max());
1468 MFloatScratchSpace maxPer1(perSize1, AT_, "maxPer1");
1469 maxPer1.fill(-std::numeric_limits<MFloat>::max());
1470 MFloatScratchSpace minPer2(perSize2, AT_, "minPer2");
1471 minPer2.fill(std::numeric_limits<MFloat>::max());
1472 MFloatScratchSpace maxPer2(perSize2, AT_, "maxPer2");
1473 maxPer2.fill(-std::numeric_limits<MFloat>::max());
1474
1475 MFloatScratchSpace minPer3(perSize1 * perSize2, AT_, "minPer3");
1476 minPer3.fill(std::numeric_limits<MFloat>::max());
1477 MFloatScratchSpace maxPer3(perSize1 * perSize2, AT_, "maxPer3");
1478 maxPer3.fill(-std::numeric_limits<MFloat>::max());
1479
1480 MFloat coordsCyl[3];
1481 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
1482 if(a_level(cellId) != m_minLevel) continue;
1483
1486 cartesianToCylindric(&a_coordinate(cellId, 0), coordsCyl);
1487 minPer1[ind1] = mMin(coordsCyl[1], minPer1[ind1]);
1488 maxPer1[ind1] = mMax(coordsCyl[1], maxPer1[ind1]);
1489 minPer2[ind2] = mMin(coordsCyl[1], minPer2[ind2]);
1490 maxPer2[ind2] = mMax(coordsCyl[1], maxPer2[ind2]);
1491
1492 minPer3[ind1 * perSize2 + ind2] = mMin(coordsCyl[1], minPer3[ind1 * perSize2 + ind2]);
1493 maxPer3[ind1 * perSize2 + ind2] = mMax(coordsCyl[1], maxPer3[ind1 * perSize2 + ind2]);
1494 }
1495 MPI_Allreduce(MPI_IN_PLACE, &minPer1[0], perSize1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
1496 "minPer1[0]");
1497 MPI_Allreduce(MPI_IN_PLACE, &maxPer1[1], perSize1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
1498 "maxPer1[0]");
1499 MPI_Allreduce(MPI_IN_PLACE, &minPer2[0], perSize2, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
1500 "minPer2[0]");
1501 MPI_Allreduce(MPI_IN_PLACE, &maxPer2[1], perSize2, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
1502 "maxPer2[0]");
1503
1504 MPI_Allreduce(MPI_IN_PLACE, &minPer3[0], perSize1 * perSize2, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
1505 "minPer3[0]");
1506 MPI_Allreduce(MPI_IN_PLACE, &maxPer3[1], perSize1 * perSize2, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
1507 "maxPer3[0]");
1508
1509 MFloat minPhi = minPer1[0];
1510 MFloat maxPhi = maxPer1[0];
1511 for(MInt p = 0; p < perSize1; p++) {
1512 minPhi = mMin(minPhi, minPer1[p]);
1513 maxPhi = mMax(maxPhi, maxPer1[p]);
1514 }
1515 for(MInt p = 0; p < perSize2; p++) {
1516 minPhi = mMin(minPhi, minPer2[p]);
1517 maxPhi = mMax(maxPhi, maxPer2[p]);
1518 }
1519 MFloat center = F1B2 * (minPhi + maxPhi);
1520
1521 std::copy_n(&minPer3[0], perSize1 * perSize2, &m_azimuthalBbox.minPer3[0]);
1522 std::copy_n(&maxPer3[0], perSize1 * perSize2, &m_azimuthalBbox.maxPer3[0]);
1523 m_azimuthalBbox.center = center;
1524
1525 // Now create the azimuthal periodic halo cells
1526 noHalos.fill(0);
1527 noWindows.fill(0);
1528 for(MInt i = 0; i < noNeighborDomains(); i++) {
1529 halos[i].clear();
1530 hilbertIds[i].clear();
1531 }
1532 hilbertToLocal.clear();
1533 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
1534 if(a_level(cellId) != m_minLevel) continue;
1535 const MLong hilbertId = hilbertIndexGeneric(&a_coordinate(cellId, 0));
1536 hilbertToLocal.insert(make_pair(hilbertId, cellId));
1537 }
1538
1539 // find direct and diagonal neighboring cells
1540 cnt = 0;
1541 ScratchSpace<MInt> cellLayer(maxNoAdjacentCells, AT_, "cellLayer");
1542 while(cnt < interfaceCells.size()) {
1543 fill(&ifcDirs[0], &ifcDirs[0] + m_noDirs, 0);
1544 const MInt cellId = interfaceCells[cnt].first;
1545 while(cnt < interfaceCells.size() && cellId == interfaceCells[cnt].first) {
1546 ifcDirs[interfaceCells[cnt].second] = 1;
1547 cnt++;
1548 }
1549 MInt cellCnt = 0;
1550 cellList[cellCnt] = cellId;
1551 cellLayer[cellCnt++] = 0;
1552 for(MInt dim = 0; dim < nDim; dim++) {
1553 const MInt cellCnt0 = cellCnt;
1554 for(MInt ori = 0; ori < 2; ori++) {
1555 const MInt dir = 2 * dim + ori;
1556 if(!ifcDirs[dir]) continue;
1557 for(MInt c = 0; c < cellCnt0; c++) {
1558 MInt nextId = cellList[c];
1559 MInt startLayer = cellLayer[c];
1560 for(MInt layer = startLayer; layer < m_noHaloLayers; layer++) {
1561 if(a_hasNeighbor(nextId, dir) > 0)
1562 nextId = a_neighborId(nextId, dir);
1563 else
1564 nextId = createAzimuthalHaloCell(nextId, dir, &hilbertOffsets[0], hilbertToLocal, bbox, &noHalos[0],
1565 halos, hilbertIds);
1566 if(nextId < 0) break;
1567 cellList[cellCnt] = nextId;
1568 cellLayer[cellCnt++] = layer;
1569 }
1570 }
1571 }
1572 }
1573 }
1574
1575 MPI_Alltoall(&noHalos[0], 1, MPI_INT, &noWindows[0], 1, MPI_INT, mpiComm(), AT_, "noHalos[0]", "noWindows[0]");
1576
1577 for(MInt i = 0; i < noDomains(); i++) {
1578 if(noHalos[i] == 0 && noWindows[i] > 0) {
1579 setAzimuthalNeighborDomainIndex(i, halos, hilbertIds);
1580 }
1581 }
1582
1583 ScratchSpace<MPI_Request> sendReqAzi(noAzimuthalNeighborDomains(), AT_, "sendReqAzi");
1584 sendReqAzi.fill(MPI_REQUEST_NULL);
1585 recvHilbertIds.resize(noAzimuthalNeighborDomains());
1586 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1587 ASSERT(m_azimuthalNghbrDomains[i] > -1 && m_azimuthalNghbrDomains[i] < noDomains(), "");
1588 recvHilbertIds[i].resize(noWindows[m_azimuthalNghbrDomains[i]]);
1589 }
1590 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1591 for(MInt k = 0; k < noHalos[m_azimuthalNghbrDomains[i]]; k++) {
1592 ASSERT(hilbertIds[i][k] >= hilbertOffsets[m_azimuthalNghbrDomains[i]]
1593 && hilbertIds[i][k] < hilbertOffsets[m_azimuthalNghbrDomains[i] + 1],
1594 to_string(hilbertIds[i][k]) + " " + to_string(hilbertOffsets[m_azimuthalNghbrDomains[i]]) + " "
1595 + to_string(hilbertOffsets[m_azimuthalNghbrDomains[i] + 1]));
1596 }
1597 }
1598 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1599 MPI_Issend(&hilbertIds[i][0], noHalos[m_azimuthalNghbrDomains[i]], MPI_LONG, m_azimuthalNghbrDomains[i], 34,
1600 mpiComm(), &sendReqAzi[i], AT_, "hilbertIds[i][0]");
1601 }
1602 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1603 MPI_Recv(&recvHilbertIds[i][0], noWindows[m_azimuthalNghbrDomains[i]], MPI_LONG, m_azimuthalNghbrDomains[i], 34,
1604 mpiComm(), MPI_STATUS_IGNORE, AT_, "recvHilbertIds[i][0]");
1605 }
1607 MPI_Waitall(noAzimuthalNeighborDomains(), &sendReqAzi[0], MPI_STATUSES_IGNORE, AT_);
1608 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1609 for(MInt k = 0; k < noWindows[m_azimuthalNghbrDomains[i]]; k++) {
1610 ASSERT(recvHilbertIds[i][k] >= hilbertOffsets[domainId()]
1611 && recvHilbertIds[i][k] < hilbertOffsets[domainId() + 1],
1612 "");
1613 }
1614 }
1615
1616 sendGlobalIds.resize(noAzimuthalNeighborDomains());
1617 recvGlobalIds.resize(noAzimuthalNeighborDomains());
1618 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1619 ASSERT(m_azimuthalNghbrDomains[i] > -1 && m_azimuthalNghbrDomains[i] < noDomains(), "");
1620 sendGlobalIds[i].resize(noWindows[m_azimuthalNghbrDomains[i]]);
1621 recvGlobalIds[i].resize(noHalos[m_azimuthalNghbrDomains[i]]);
1622 }
1623
1624 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1625 m_azimuthalWindowCells.push_back(vector<MInt>());
1626 for(MInt k = 0; k < noWindows[m_azimuthalNghbrDomains[i]]; k++) {
1627 MInt windowId = -1;
1628 auto range = hilbertToLocal.equal_range(recvHilbertIds[i][k]);
1629 for(auto it = range.first; it != range.second; ++it) {
1630 if(!a_hasProperty(it->second, Cell::IsPeriodic) && !a_hasProperty(it->second, Cell::IsHalo)) {
1631 windowId = it->second;
1632 }
1633 }
1634 ASSERT(windowId > -2 && windowId < m_noInternalCells,
1635 to_string(windowId) + " " + to_string(m_noInternalCells));
1636 if(windowId > -1) {
1637 ASSERT(a_level(windowId) == m_minLevel, "");
1638 m_azimuthalWindowCells[i].push_back(windowId);
1639 sendGlobalIds[i][k] = a_globalId(windowId);
1640 } else {
1641 sendGlobalIds[i][k] = -1;
1642 }
1643 }
1644 }
1645
1646 // send back globalId when the queried cell exists, -1 if not existing
1647 sendReqAzi.fill(MPI_REQUEST_NULL);
1648 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1649 MPI_Issend(&sendGlobalIds[i][0], noWindows[m_azimuthalNghbrDomains[i]], MPI_LONG, m_azimuthalNghbrDomains[i],
1650 35, mpiComm(), &sendReqAzi[i], AT_, "sendGlobalIds[i][0]");
1651 }
1652 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1653 MPI_Recv(&recvGlobalIds[i][0], noHalos[m_azimuthalNghbrDomains[i]], MPI_LONG, m_azimuthalNghbrDomains[i], 35,
1654 mpiComm(), MPI_STATUS_IGNORE, AT_, "recvGlobalIds[i][0]");
1655 }
1657 MPI_Waitall(noAzimuthalNeighborDomains(), &sendReqAzi[0], MPI_STATUSES_IGNORE, AT_);
1658
1659 {
1660 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1661 m_azimuthalHaloCells.push_back(vector<MInt>());
1662 for(MInt k = 0; k < noHalos[m_azimuthalNghbrDomains[i]]; k++) {
1663 MInt cellId = halos[i][k];
1664 MLong globalId = recvGlobalIds[i][k];
1665 if(globalId > -1) {
1666 ASSERT(cellId > -1 && cellId < m_tree.size(), "");
1667 a_globalId(cellId) = globalId;
1668 m_azimuthalHaloCells[i].push_back(cellId);
1669 } else { // Still keep it! Cell might be necessary. Solver flag will be adjusted in proxy
1670 ASSERT(cellId > -1 && cellId < m_tree.size(), "");
1671 a_globalId(cellId) = -1;
1672 m_azimuthalUnmappedHaloCells.push_back(cellId);
1674 }
1675 }
1676 }
1677 }
1678
1679 // Determine the gridBndryCells. These cells are the outer cells of the grid
1680 // Tagging them is necessary for the refinement of the azimuthal periodic halo cells
1681 std::vector<MInt>().swap(m_gridBndryCells);
1682 MBool adaptation = false;
1683 adaptation = Context::getBasicProperty<MBool>("adaptation", AT_, &adaptation);
1684 if(adaptation) {
1685 if(domainId() == 0)
1686 cerr << endl << "Azimuthal periodic cells are not refined at grid bndry if adaption is on!" << endl;
1687 } else {
1688 if(domainId() == 0) cerr << "Set gridBndryCells on minLevel." << endl;
1689 MIntScratchSpace gridBndryCells(m_tree.size(), AT_, "gridBndryCells");
1690 gridBndryCells.fill(-1);
1691 MBool isBndry = false;
1692 for(MInt cellId = 0; cellId < oldNoCells; cellId++) {
1693 if(a_level(cellId) != m_minLevel) continue;
1694 isBndry = false;
1695 for(MInt dir = 0; dir < m_noDirs; dir++) {
1696 if(a_hasNeighbor(cellId, dir) > 0) continue;
1697 if(!m_periodicCartesianDir[dir / 2]) {
1698 MFloat coords[nDim];
1699 for(MInt d = 0; d < nDim; d++) {
1700 coords[d] = a_coordinate(cellId, d);
1701 }
1702 coords[dir / 2] += ((dir % 2) == 0 ? -F1 : F1) * cellLengthAtLevel(m_minLevel);
1703 if(coords[dir / 2] < bbox[dir / 2] || coords[dir / 2] > bbox[nDim + dir / 2]) continue;
1704 }
1705 isBndry = true;
1706 }
1707 if(isBndry) {
1708 if(!a_isHalo(cellId)) m_gridBndryCells.push_back(cellId);
1709 gridBndryCells[cellId] = 1;
1710 for(MInt dir = 0; dir < m_noDirs; dir++) {
1711 if(a_hasNeighbor(cellId, dir) > 0) {
1712 MInt nghbrId = a_neighborId(cellId, dir);
1713 if(!a_isHalo(nghbrId)) m_gridBndryCells.push_back(nghbrId);
1714 gridBndryCells[nghbrId] = 1;
1715 }
1716 }
1717 }
1718 }
1720 for(MInt i = 0; i < noNeighborDomains(); i++) {
1721 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
1722 if(gridBndryCells[m_windowCells[i][j]] == 1) {
1723 m_gridBndryCells.push_back(m_windowCells[i][j]);
1724 }
1725 }
1726 }
1727 }
1728 }
1729 }
1730
1731 // It's very polite to clear the data, but we don't need it
1732 /* halos.clear();
1733 hilbertIds.clear();
1734 recvHilbertIds.clear();
1735 hilbertToLocal.clear();*/
1736
1737 // Set window/halo flags
1738 for(MInt i = 0; i < noNeighborDomains(); i++) {
1739 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
1740 ASSERT(!a_hasProperty(m_haloCells[i][j], Cell::IsWindow), "halo cell is marked as window");
1741 a_hasProperty(m_haloCells[i][j], Cell::IsHalo) = true;
1742 }
1743 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
1744 ASSERT(!a_isHalo(m_windowCells[i][j]), "window cell is marked as halo");
1745 a_hasProperty(m_windowCells[i][j], Cell::IsWindow) = true;
1746 }
1747 }
1748 if(m_azimuthalPer) {
1749 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1750 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
1751 ASSERT(!a_hasProperty(m_azimuthalHaloCells[i][j], Cell::IsWindow), "azimuthal halo cell is marked as window");
1752 a_hasProperty(m_azimuthalHaloCells[i][j], Cell::IsHalo) = true;
1753 }
1754 for(MInt j = 0; j < (signed)m_azimuthalWindowCells[i].size(); j++) {
1755 ASSERT(!a_isHalo(m_azimuthalWindowCells[i][j]), "azimuthal window cell is marked as halo");
1756 a_hasProperty(m_azimuthalWindowCells[i][j], Cell::IsWindow) = true;
1757 }
1758 }
1759 for(MInt j = 0; j < noAzimuthalUnmappedHaloCells(); j++) {
1760 ASSERT(!a_hasProperty(m_azimuthalUnmappedHaloCells[j], Cell::IsWindow),
1761 "azimuthal halo cell is marked as window");
1762 a_hasProperty(m_azimuthalUnmappedHaloCells[j], Cell::IsHalo) = true;
1763 }
1764 }
1765
1766 if(m_haloMode > 0) {
1768#ifndef NDEBUG
1769 checkWindowLayer("tagActiveWindowsAtMinLevel completed: ");
1770#endif
1771 // Exchange solverBits also in case of 1 solver, because solverBits are used to disable halo cells, which
1772 // are created, but in tagActiveWindowsAtMinLevel seen to be superfluous
1773 // if(treeb().noSolvers() > 1) {
1775 //}
1776
1777 if(m_haloMode == 2) {
1778 for(MInt i = 0; i < noNeighborDomains(); i++) {
1779 std::vector<MInt> haloCells;
1780 haloCells.reserve(m_haloCells[i].size());
1781 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
1782 const MInt haloCellId = m_haloCells[i][j];
1783 if(m_tree.solverBits(haloCellId).any())
1784 haloCells.push_back(haloCellId);
1785 else {
1786 removeCell<false>(haloCellId);
1787 }
1788 }
1790
1791 //
1792 std::vector<MInt> windowCells;
1793 windowCells.reserve(m_windowCells[i].size());
1794 std::set<MInt> erased;
1795 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
1796 const MInt windowCellId = m_windowCells[i][j];
1797 ASSERT(m_windowLayer_[i].find(windowCellId) != m_windowLayer_[i].end()
1798 || erased.find(windowCellId) != erased.end(),
1799 "");
1800 MBool validWindow = false;
1801 for(MInt solverId = 0; solverId < treeb().noSolvers(); ++solverId) {
1802 if(isSolverWindowCell(i, windowCellId, solverId)) {
1803 windowCells.push_back(windowCellId);
1804 validWindow = true;
1805 break;
1806 }
1807 }
1808 if(!validWindow) {
1809 const MBool ok = m_windowLayer_[i].erase(windowCellId);
1810 ASSERT(ok || erased.find(windowCellId) != erased.end(), "");
1811 erased.insert(windowCellId);
1812 MBool isWindow = false;
1813 for(const auto& w : m_windowLayer_) {
1814 if(w.find(windowCellId) != w.end()) {
1815 isWindow = true;
1816 break;
1817 }
1818 }
1819 if(!isWindow) a_hasProperty(windowCellId, Cell::IsWindow) = false;
1820 }
1821 }
1823 }
1824
1825 compactCells();
1826 }
1827
1828#ifndef NDEBUG
1829 // for debugging, check consistency before new level
1830 checkWindowHaloConsistency(false, "createMinLevelExchangeCells completed: ");
1831#endif
1832 }
1833
1834
1835 cerr0 << " done." << endl;
1836}
MInt createAzimuthalHaloCell(const MInt, const MInt, const MLong *, std::unordered_multimap< MLong, MInt > &, const MFloat *, MInt *const, std::vector< std::vector< MInt > > &, std::vector< std::vector< MLong > > &)
Create a new azimuthal halo cell as neighbor of cellId in direction dir and find matching neighbor do...
void tagActiveWindowsAtMinLevel(const MInt)
Actually the most clever way of tagging is to go from highest level to lower levels,...
void compactCells(const std::vector< std::function< void(const MInt, const MInt)> > &=std::vector< std::function< void(const MInt, const MInt)> >())
Removes all holes in the cell collector and moves halo cells to the back of the collector.
MFloat m_periodicCartesianLength[3]
const std::vector< std::vector< MInt > > & haloCells() const
MInt createAdjacentHaloCell(const MInt, const MInt, const MLong *, std::unordered_multimap< MLong, MInt > &, const MFloat *, MInt *const, std::vector< std::vector< MInt > > &, std::vector< std::vector< MLong > > &)
Create a new halo cell (candidate) as neighbor of cellId in direction dir and find matching neighbor ...
MInt deleteCell(const MInt cellId)
Deletes a cell (without collector fragmentation) and returns new collector size.
const std::vector< std::vector< MInt > > & windowCells() const
MInt ipow(MInt base, MInt exp)
Integer exponent function for non-negative exponents.
Definition: functions.h:317
std::ostream cerr0
int MPI_Alltoall(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Alltoall
MInt index(const MFloat *coord, MInt dir)
void init(MFloat angle, MInt periodicDir1, MInt periodicDir2, MInt noLayers)

◆ createPaths()

template<MInt nDim>
void CartesianGrid< nDim >::createPaths
private

This function creates all possible paths from a cell to its adjacent neighbors (in a uniform grid) and saves them. Of course the possible paths could also be hardcoded but I'm too lazy, so feel free to take the output of this function and to hardcode it into a fixed array.

Definition at line 6107 of file cartesiangrid.cpp.

6107 {
6108 TRACE();
6109
6110 MInt offset[6] = {2, 2, 4, 4, 6, 6};
6111 MInt offset2[4] = {2, 2, 0, 0};
6112 MInt allNeighbors[(nDim == 2) ? 8 : 12];
6113 MInt secondLevelNeighbors[8];
6114
6115 IF_CONSTEXPR(nDim == 2) {
6116 MInt allNeighbors2D[8] = {0, 1, 2, 3, 0, 1, 2, 3};
6117 for(MInt i = 0; i < 8; i++) {
6118 allNeighbors[i] = allNeighbors2D[i];
6119 }
6120 // Holds the corresponding neighbor directions for the binary codes according to D2Q9.
6121 // 9 means in 2D that the corresponding code doesn't exist.
6122 MInt neighborCode2D[11] = {9, 0, 1, 9, 2, 6, 5, 9, 3, 7, 4};
6123 for(MInt i = 0; i < 11; i++) {
6124 m_neighborCode[i] = neighborCode2D[i];
6125 }
6126 }
6127 else {
6128 MInt allNeighbors3D[12] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5};
6129 for(MInt i = 0; i < 12; i++) {
6130 allNeighbors[i] = allNeighbors3D[i];
6131 }
6132 // Holds the corresponding neighbor directions for the binary codes according to D3Q27.
6133 // 27 means in 3D that the corresponding code doesn't exist.
6134 MInt neighborCode3D[43] = {27, 0, 1, 27, 2, 6, 8, 27, 3, 7, 9, 27, 27, 27, 27, 27, 4, 10, 12, 27, 14, 18,
6135 22, 27, 16, 20, 24, 27, 27, 27, 27, 27, 5, 11, 13, 27, 15, 19, 23, 27, 17, 21, 25};
6136 for(MInt i = 0; i < 43; i++) {
6137 m_neighborCode[i] = neighborCode3D[i];
6138 }
6139 }
6140 m_counter1D = 0;
6141 m_counter2D = 0;
6142 m_counter3D = 0;
6143
6144 // Determine counters
6145 // All 1D neighbors
6146 for(MInt i = 0; i < nDim * 2; i++) {
6147 m_counter1D++;
6148 // Remaining possible neighbors
6149 for(MInt j = 0; j < (nDim * 2 - 2); j++) {
6150 m_counter2D++;
6151 // Remaining possible neighbors
6152 for(MInt k = 0; k < nDim * 2 - 2 - 2; k++) {
6153 m_counter3D++;
6154 }
6155 }
6156 }
6157
6158 // Allocate memory
6160 mAlloc(m_paths1D, m_counter1D, "m_paths1D", AT_);
6162 mAlloc(m_paths2D, m_counter2D, 2, "m_paths2D", AT_);
6163 IF_CONSTEXPR(nDim == 3) {
6165 mAlloc(m_paths3D, m_counter3D, 3, "m_paths3D", AT_);
6166 }
6167
6168 m_counter1D = 0;
6169 m_counter2D = 0;
6170 m_counter3D = 0;
6171
6172 // save the paths...
6173 for(MInt i = 0; i < nDim * 2; i++) {
6174 // Save 1D paths
6175 m_paths1D[m_counter1D] = allNeighbors[i];
6176 m_counter1D++;
6177 // Remaining possible neighbors
6178 for(MInt j = 0; j < (nDim * 2 - 2); j++) {
6179 // Fill secondeLevelNeighbors twice!
6180 secondLevelNeighbors[j] = allNeighbors[offset[i] + j];
6181 secondLevelNeighbors[j + nDim * 2 - 2] = allNeighbors[offset[i] + j];
6182 }
6183 for(MInt j = 0; j < (nDim * 2 - 2); j++) {
6184 // Save 2D paths
6185 m_paths2D[m_counter2D][0] = allNeighbors[i];
6186 m_paths2D[m_counter2D][1] = secondLevelNeighbors[j];
6187 m_counter2D++;
6188 // Remaining possible neighbors
6189 IF_CONSTEXPR(nDim == 3) {
6190 MInt thirdLevelNeighbors[2];
6191 for(MInt k = 0; k < nDim * 2 - 2 - 2; k++) {
6192 // Fill thirdLevelNeighbors
6193 thirdLevelNeighbors[k] = secondLevelNeighbors[offset2[j] + k];
6194 // Save 3D paths
6195 m_paths3D[m_counter3D][0] = allNeighbors[i];
6196 m_paths3D[m_counter3D][1] = secondLevelNeighbors[j];
6197 m_paths3D[m_counter3D][2] = thirdLevelNeighbors[k];
6198
6199 m_counter3D++;
6200 }
6201 }
6202 }
6203 }
6204}
std::array< MInt, 11+(nDim - 2) *32 > m_neighborCode

◆ deleteCell()

template<MInt nDim>
MInt CartesianGrid< nDim >::deleteCell ( const MInt  id)
private
Author
?, adjusted by Claudia Guenther, Nov 2012

Definition at line 8950 of file cartesiangrid.cpp.

8950 {
8951 if(m_tree.size() == 0) {
8952 mTerm(1, AT_, " Error in CartesianGrid::deleteCell(), collector is empty.");
8953 }
8954 if(id >= m_tree.size()) {
8955 mTerm(1, AT_, " Error in CartesianGrid::deleteCell(), cell out of range.");
8956 }
8957
8959
8960 // If the cell to delete is the last cell, return -1, otherwise return the previously largest id
8961 const MInt lastId = m_tree.size() - 1;
8962 const MInt returnValue = (lastId <= id) ? -1 : lastId;
8963
8964 // Erase cell, move last cell to gap, shrink tree
8966
8967 return returnValue;
8968}
void removeAndFill(const MInt begin, const MInt end)
Definition: container.h:374

◆ deletePeriodicConnection()

template<MInt nDim>
void CartesianGrid< nDim >::deletePeriodicConnection ( const MBool  saveBackup = true)
Author
Tim Wegmann

Definition at line 10618 of file cartesiangrid.cpp.

10618 {
10619 TRACE();
10620
10621 m_neighborBackup.clear();
10622
10623 // For all halo cells that are periodic, reset globalId to -1
10624 // For all non-halo neighbors of periodic halo cells, reset neighbor id to -1
10625 for(MInt i = 0; i < noNeighborDomains(); i++) {
10626 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
10627 MInt cellId = m_haloCells[i][j];
10628 if(!a_hasProperty(cellId, Cell::IsPeriodic)) continue;
10629 if(!saveBackup) a_globalId(cellId) = -1;
10630 for(MInt dir = 0; dir < m_noDirs; dir++) {
10631 if(a_hasNeighbor(cellId, dir) == 0) continue;
10632 MInt nghbrId = a_neighborId(cellId, dir);
10633 if(!a_hasProperty(nghbrId, Cell::IsHalo)) {
10634 if(saveBackup) m_neighborBackup.push_back(make_tuple(cellId, nghbrId, dir));
10635 a_neighborId(cellId, dir) = -1;
10636 a_neighborId(nghbrId, m_revDir[dir]) = -1;
10637 }
10638 }
10639 }
10640 }
10641
10642 if(m_azimuthalPer) {
10643 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
10644 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
10646 ASSERT(a_hasProperty(cellId, Cell::IsPeriodic), "");
10647 if(!saveBackup) a_globalId(cellId) = -1;
10648 for(MInt dir = 0; dir < m_noDirs; dir++) {
10649 if(a_hasNeighbor(cellId, dir) == 0) continue;
10650 MInt nghbrId = a_neighborId(cellId, dir);
10651 if(!a_hasProperty(nghbrId, Cell::IsHalo)) {
10652 if(saveBackup) m_neighborBackup.push_back(make_tuple(cellId, nghbrId, dir));
10653 a_neighborId(cellId, dir) = -1;
10654 a_neighborId(nghbrId, m_revDir[dir]) = -1;
10655 }
10656 }
10657 }
10658 }
10659 }
10660}
std::vector< std::tuple< MInt, MInt, MInt > > m_neighborBackup
const MInt m_revDir[6]

◆ descendNoOffsprings()

template<MInt nDim>
void CartesianGrid< nDim >::descendNoOffsprings ( const MLong  cellId,
const MLong  offset = 0 
)

Recursively update noOffsprings and workLoad for all descendants of cellId NOTE: this will not work properly for partition level ancestors in case of partition level shifts, use calculateNoOffspringsAndWorkload() instead

Definition at line 10208 of file cartesiangrid.cpp.

10208 {
10209 ASSERT(!a_hasProperty(cellId, Cell::IsPartLvlAncestor), "not supposed to be called for a partition level ancestor");
10210 a_noOffsprings(cellId) = 1;
10211 a_workload(cellId) = a_weight(cellId);
10212 if(a_noChildren(cellId) > 0) {
10213 for(MInt child = 0; child < ipow(2, nDim); child++) {
10214 if(a_childId(cellId, child) < 0) continue;
10215 MLong childId = a_childId(cellId, child) - offset;
10216 descendNoOffsprings(childId, offset);
10217 a_noOffsprings(cellId) += a_noOffsprings(childId);
10218 a_workload(cellId) += a_workload(childId);
10219 }
10220 }
10221}

◆ descendStoreGlobalId()

template<MInt nDim>
void CartesianGrid< nDim >::descendStoreGlobalId ( MInt  cellId,
MInt localCnt 
)
private

Note: This algorithm only makes sense if called in-order for all local min cells /// or /// in case of a partition level shift starting with the min-level halo partition level ancestor whos offspring is the first local partition cell and the called in-order for all local min-level cells

Author
Lennart Schneiders

Definition at line 10185 of file cartesiangrid.cpp.

10185 {
10186 // Update global id (unless it is a halo cell)
10187 if(!a_hasProperty(cellId, Cell::IsHalo)) {
10188 ASSERT(localCnt < m_noInternalCells, "");
10189 a_globalId(cellId) = m_domainOffsets[domainId()] + localCnt++;
10190 ASSERT(a_globalId(cellId) >= m_domainOffsets[domainId()] && a_globalId(cellId) < m_domainOffsets[domainId() + 1],
10191 "Error: global id outside of global id range for this domain.");
10192 }
10193
10194 // Descend tree to all children
10195 for(MInt child = 0; child < ipow(2, nDim); child++) {
10196 if(a_childId(cellId, child) < 0) {
10197 continue;
10198 }
10199 descendStoreGlobalId(a_childId(cellId, child), localCnt);
10200 }
10201}

◆ determineNoPartitionCellsAndOffsets()

template<MInt nDim>
void CartesianGrid< nDim >::determineNoPartitionCellsAndOffsets ( MLong *const  noPartitionCells,
MLong *const  partitionCellOffsets 
)
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Parameters
[out]noPartitionCellsPointer to storage of size noDomains() that will hold the number of partition cells on each domain.
[out]partitionCellOffsetsPointer to storage of size noDomains()+1 that will hold the partition cell offsets for all domains and the total number of partition cells as the last entry.

Definition at line 12723 of file cartesiangrid.cpp.

12724 {
12725 TRACE();
12726
12727 const MLong localNoPartitionCells = m_noPartitionCells;
12728 // Gather local number of partition cells on all domains
12729 MPI_Allgather(&localNoPartitionCells, 1, type_traits<MLong>::mpiType(), &noPartitionCells[0], 1,
12730 type_traits<MLong>::mpiType(), mpiComm(), AT_, "localNoPartitionCells", "noPartitionCells[0]");
12731
12732 // Partition cell offset on first domain is zero
12733 partitionCellOffsets[0] = 0;
12734 // Determine partition cell offsets for all domains (except first), last entry contains total
12735 // number of partition cells
12736 for(MInt i = 1; i < noDomains() + 1; i++) {
12737 partitionCellOffsets[i] = partitionCellOffsets[i - 1] + noPartitionCells[i - 1];
12738 }
12739
12740 // Check partition cell count
12741 if(partitionCellOffsets[noDomains()] != m_noPartitionCellsGlobal) {
12742 TERMM(1, "determineNoPartitionCellsAndOffsets(): Partition cell count does not match: "
12743 + std::to_string(partitionCellOffsets[noDomains()])
12744 + " != " + std::to_string(m_noPartitionCellsGlobal));
12745 }
12746}

◆ determinePartLvlAncestorHaloWindowCells()

template<MInt nDim>
void CartesianGrid< nDim >::determinePartLvlAncestorHaloWindowCells ( std::vector< std::vector< MInt > > &  partLvlAncestorHaloCells,
std::vector< std::vector< MInt > > &  partLvlAncestorWindowCells 
)

Definition at line 13655 of file cartesiangrid.cpp.

13657 {
13658 TRACE();
13659
13660 partLvlAncestorHaloCells.clear();
13661 partLvlAncestorWindowCells.clear();
13662
13663 partLvlAncestorHaloCells.resize(noNeighborDomains());
13664 partLvlAncestorWindowCells.resize(noNeighborDomains());
13665
13666 for(MInt i = 0; i < noNeighborDomains(); i++) {
13667 for(MInt j = 0; j < (signed)m_haloCells[i].size(); ++j) {
13668 if(a_hasProperty(m_haloCells[i][j], Cell::IsPartLvlAncestor)) {
13669 partLvlAncestorHaloCells[i].push_back(m_haloCells[i][j]);
13670 }
13671 }
13672 for(MInt j = 0; j < (signed)m_windowCells[i].size(); ++j) {
13673 if(a_hasProperty(m_windowCells[i][j], Cell::IsPartLvlAncestor)) {
13674 partLvlAncestorWindowCells[i].push_back(m_windowCells[i][j]);
13675 }
13676 }
13677 }
13678}

◆ domainId()

template<MInt nDim>
MInt CartesianGrid< nDim >::domainId ( ) const
inline

Definition at line 1057 of file cartesiangrid.h.

1057{ return m_domainId; }

◆ domainOffset()

template<MInt nDim>
const MLong & CartesianGrid< nDim >::domainOffset ( const MInt  id) const
inline

Definition at line 441 of file cartesiangrid.h.

441{ return m_domainOffsets[id]; }

◆ dummyCorrect()

template<MInt nDim>
MFloat * CartesianGrid< nDim >::dummyCorrect ( const MInt  cellId,
MFloat coords 
)
inline

Definition at line 861 of file cartesiangrid.h.

861 {
862 std::copy(&a_coordinate(cellId, 0), &a_coordinate(cellId, nDim - 1), coords);
863 return coords;
864 }

◆ dumpCellData()

template<MInt nDim>
void CartesianGrid< nDim >::dumpCellData ( const MString  name)

Definition at line 13386 of file cartesiangrid.cpp.

13386 {
13387 ofstream logfile;
13388 logfile.open(name + "_" + std::to_string(domainId()));
13389
13390 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
13391 logfile << cellId << " g" << a_globalId(cellId) << " l" << a_level(cellId) << " p" << a_parentId(cellId);
13392 for(MUint j = 0; j < (unsigned)m_maxNoChilds; j++) {
13393 logfile << " c" << a_childId(cellId, j);
13394 }
13395 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
13396 logfile << " n" << a_neighborId(cellId, dirId);
13397 }
13398 logfile << " " << a_propertiesToString(cellId);
13399 logfile << " w" << a_weight(cellId);
13400 logfile << " o" << a_noOffsprings(cellId) << std::endl;
13401 }
13402 logfile << std::endl;
13403
13404 for(MUint i = 0; i < m_minLevelCells.size(); i++) {
13405 logfile << "m" << i << " " << m_minLevelCells[i] << std::endl;
13406 }
13407 logfile << std::endl;
13408
13409 for(MInt i = 0; i < m_noPartitionCells; i++) {
13410 logfile << "p" << i << " g" << m_localPartitionCellGlobalIds[i] << " l" << m_localPartitionCellLocalIds[i]
13411 << " level" << a_level(m_localPartitionCellLocalIds[i]) << std::endl;
13412 }
13413 logfile << std::endl;
13414
13415 MInt count = 0;
13416 for(auto& id : m_globalToLocalId) {
13417 logfile << "g2l" << count++ << " g" << id.first << " l" << id.second << std::endl;
13418 }
13419 logfile << std::endl;
13420
13421 for(MInt i = 0; i < noNeighborDomains(); i++) {
13422 logfile << "window " << i << " " << m_nghbrDomains[i] << " " << m_windowCells[i].size() << std::endl;
13423 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
13424 logfile << "window " << m_nghbrDomains[i] << " " << j << " w" << m_windowCells[i][j] << " g"
13425 << a_globalId(m_windowCells[i][j]) << std::endl;
13426 }
13427 logfile << std::endl;
13428
13429 logfile << "halo " << i << " " << m_nghbrDomains[i] << " " << m_haloCells[i].size() << std::endl;
13430 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
13431 logfile << "halo " << m_nghbrDomains[i] << " " << j << " h" << m_haloCells[i][j]
13432
13433 << " g" << a_globalId(m_haloCells[i][j]) << std::endl;
13434 }
13435 logfile << std::endl;
13436 }
13437}
MString a_propertiesToString(const MInt cellId)

◆ exchangeNotInPlace()

template<MInt nDim>
template<typename DATATYPE >
void CartesianGrid< nDim >::exchangeNotInPlace ( DATATYPE *  exchangeVar,
DATATYPE *  recvMem 
)
Author
Thomas Schilden
Date
18.10.2016
Parameters
[in]variableto exchange
[in]buffermemory

Definition at line 11292 of file cartesiangrid.cpp.

11292 {
11293 TRACE();
11295}

◆ exchangeProperties()

template<MInt nDim>
void CartesianGrid< nDim >::exchangeProperties
private
Author
Lennart Schneiders

Definition at line 8369 of file cartesiangrid.cpp.

8369 {
8370 ScratchSpace<MInt> isPeriodic(m_tree.size() - m_noInternalCells, AT_, "isPeriodic");
8371 for(MInt cellId = m_noInternalCells; cellId < m_tree.size(); cellId++) {
8372 ASSERT(a_hasProperty(cellId, Cell::IsHalo), "not a halo cell");
8373 isPeriodic[cellId - m_noInternalCells] = a_hasProperty(cellId, Cell::IsPeriodic);
8374 }
8376 m_tree.size());
8379 &m_tree.properties(0), m_tree.size());
8380 }
8381 for(MInt cellId = m_noInternalCells; cellId < m_tree.size(); cellId++) {
8382 a_hasProperty(cellId, Cell::IsHalo) = true;
8383 a_hasProperty(cellId, Cell::IsWindow) = false;
8384 a_hasProperty(cellId, Cell::IsPeriodic) = isPeriodic[cellId - m_noInternalCells];
8385 }
8386}

◆ exchangeSolverBitset()

template<MInt nDim>
template<std::size_t N>
void CartesianGrid< nDim >::exchangeSolverBitset ( std::bitset< N > *const  data,
const MBool  defaultVal = false 
)
private

Definition at line 3917 of file cartesiangrid.cpp.

3917 {
3918 TRACE();
3919
3920 //maia::mpi::exchangeBitset(m_nghbrDomains, m_haloCells, m_windowCells, mpiComm(), &m_tree.solverBits(0),
3921 // m_tree.size());
3922 // return;
3923
3924 // There might be the case that a halo cell resides inside the domain of a solver, but since that solver
3925 // does not require that many layers we disable that cell for that solver. Sounds crazy, but trust me.
3926 static_assert(N <= 64, "conversion to ulong not appropriate, change to ullong!");
3927 ScratchSpace<MPI_Request> recvRequests(max(1, noNeighborDomains()), AT_, "recvRequests");
3928 fill(recvRequests.begin(), recvRequests.end(), MPI_REQUEST_NULL);
3929 MInt receiveCount = 0;
3930 for (const auto& vecHalo : m_haloCells) receiveCount+=vecHalo.size();
3931 ScratchSpace<MUlong> haloBuffer(max(1, receiveCount), AT_, "haloBuffer");
3932 for (MInt i = 0, offset = 0; i < noNeighborDomains(); i++) {
3933 const MInt noHaloCells = m_haloCells[i].size();
3934 if (noHaloCells<1) continue;
3935
3937 m_nghbrDomains[i], mpiComm(), &recvRequests[i], AT_, "haloBuffer[offset]");
3938
3939 offset += noHaloCells;
3940 }
3941
3942
3943 ScratchSpace<MPI_Request> sendRequests(max(1, noNeighborDomains()), AT_, "sendRequests");
3944 fill(sendRequests.begin(), sendRequests.end(), MPI_REQUEST_NULL);
3945 MInt sendCount = 0;
3946 for (const auto& vecWindow : m_windowCells) sendCount+=vecWindow.size();
3947 ScratchSpace<MUlong> tmp_data(sendCount, AT_, "tmp_data");
3948 for (MInt i = 0, idx = 0; i < noNeighborDomains(); i++) {
3949 const MInt offset = idx;
3950 const MInt noWindowCells = m_windowCells[i].size();
3951 if (noWindowCells<1) continue;
3952 for (const auto cellId : m_windowCells[i]) {
3953 const auto backup = data[cellId].to_ulong();
3954 ASSERT(m_windowLayer_[i].find(cellId)!=m_windowLayer_[i].end(), "You don't know what you are doing!");
3955 for (MInt solverId = 0; solverId < treeb().noSolvers(); ++solverId) {
3956 if (!isSolverWindowCell(i, cellId, solverId)) {
3957 data[cellId][solverId] = defaultVal;
3958 }
3959 }
3960 tmp_data[idx++] = data[cellId].to_ulong();
3961 data[cellId] = std::bitset<N>(backup);
3962 }
3963 ASSERT(idx-offset==noWindowCells, "");
3964
3966 mpiComm(), &sendRequests[i], AT_, "tmp_data");
3967 }
3968
3969 // Finish MPI communication
3970 MPI_Waitall(noNeighborDomains(), &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
3971 MPI_Waitall(noNeighborDomains(), &sendRequests[0], MPI_STATUSES_IGNORE, AT_);
3972
3973 for (MInt i = 0, idx = 0; i < noNeighborDomains(); i++) {
3974 for (const auto cellId : m_haloCells[i])
3975 data[cellId] = std::bitset<N>(haloBuffer[idx++]);
3976 }
3977}

◆ findContainingHaloCell() [1/2]

template<MInt nDim>
template<MBool t_correct>
template MInt CartesianGrid< nDim >::findContainingHaloCell< true > ( const MFloat *const  coord,
const MInt  solverId,
MInt  domainId,
MBool  onlyPartitionCells,
function< MFloat *(MInt, MFloat *const)>  correctCellCoord 
)

Definition at line 10930 of file cartesiangrid.cpp.

10932 {
10933 ASSERT(solverId >= -1 && solverId < treeb().noSolvers(), "Invalid solver id " + to_string(solverId));
10934
10935 MInt n = domainId;
10936 for(MInt i = 0; i < noHaloCells(n); i++) {
10937 const MInt curId = haloCell(n, i);
10938
10939 if(onlyPartitionCells && !a_hasProperty(curId, Cell::IsPartitionCell)) {
10940 continue;
10941 }
10942
10943 MBool isInCell = pointWthCell<t_correct, false>(coord, curId, correctCellCoord);
10944
10945 if(isInCell) {
10946 if(solverId < 0) {
10947 return curId;
10948 } else {
10949 // If a solverId is given check if partition cell belongs to solver
10950 if(a_solver(curId, solverId)) {
10951 return curId;
10952 } else {
10953 return -1;
10954 }
10955 }
10956 }
10957 }
10958 return -1;
10959}

◆ findContainingHaloCell() [2/2]

template<MInt nDim>
template<MBool t_correct = false>
MInt CartesianGrid< nDim >::findContainingHaloCell ( const MFloat *const  coord,
const MInt  solverId,
MInt  domainId,
MBool  onlyPartitionCells,
std::function< MFloat *(MInt, MFloat *const)>  correctCellCoord = nullptr 
)

◆ findContainingHaloPartitionCell()

template<MInt nDim>
MInt CartesianGrid< nDim >::findContainingHaloPartitionCell ( const MFloat *const  coors,
const MInt  solverId = -1 
)
inline

Definition at line 10889 of file cartesiangrid.cpp.

10889 {
10890 // loop over all halo cells
10891 for(MInt n = 0; n < noNeighborDomains(); n++) {
10892 for(MInt i = 0; i < noHaloCells(n); i++) {
10893 const MInt curId = haloCell(n, i);
10894
10895 if(!a_hasProperty(curId, Cell::IsPartitionCell)) {
10896 continue;
10897 }
10898
10899 MBool isInCell = true;
10900
10901 const MFloat* cellCoords = m_tree.coordinate(curId);
10902 const MFloat _halfCellLength = halfCellLength(curId);
10903
10904 for(MInt dimId = 0; dimId < nDim; dimId++) {
10905 if(coord[dimId] < cellCoords[dimId] - _halfCellLength or coord[dimId] >= cellCoords[dimId] + _halfCellLength) {
10906 isInCell = false;
10907 break;
10908 }
10909 }
10910
10911 if(isInCell) {
10912 if(solverId < 0) {
10913 return curId;
10914 } else {
10915 // If a solverId is given check if partition cell belongs to solver
10916 if(a_solver(curId, solverId)) {
10917 return curId;
10918 } else {
10919 return -1;
10920 }
10921 }
10922 }
10923 }
10924 }
10925 return -1;
10926}

◆ findContainingLeafCell() [1/5]

template<MInt nDim>
template<MBool t_correct>
MInt CartesianGrid< nDim >::findContainingLeafCell ( const MFloat *const  coord,
const MInt  startId,
function< MFloat *(MInt, MFloat *const)>  correctCellCoord,
const MInt  solverId,
const MBool  allowNonLeafHalo 
)
Author
Sven Berger, Tim Wegmann
Date
March 2019

The algorithm does the following:

  1. Determine direction of the coordinate relative to the center of the start cell
  2. Find neighbor cell including diagonals in that direction
Parameters
[in]coordinatesof the point
[in]cellIdfrom which to start searching
[in]allowNonLeafHalooption to return the non-leaf halo cell which contains the coordiante instead of returning -1 as not found! Thus the neighbor-Domain which contains the leaf cell is known and can be used for communication!
[out]localcell Id, -1 if not found

Definition at line 11048 of file cartesiangrid.cpp.

11050 {
11051 TRACE();
11052
11053 // Check if the lookup should be global or on a solver basis using the given solverId
11054 const MBool global = (solverId < 0);
11055
11056 MInt cellId = startId;
11057 array<MFloat, nDim> tmp;
11058
11059 auto findExistingNghbr = [&](const MInt _cellId, const MInt _dir, const MInt _solverId) {
11060 MInt curId = _cellId;
11061 if(_solverId < 0) {
11062 while(curId > -1 && a_neighborId(_cellId, _dir) < 0) {
11063 curId = a_parentId(_cellId);
11064 }
11065 } else {
11066 while(curId > -1 && a_neighborId(curId, _dir, _solverId) < 0) {
11067 curId = a_parentId(curId, _solverId);
11068 }
11069 }
11070 if(curId > -1 && solverId > -1) {
11071 return a_neighborId(curId, _dir, _solverId);
11072 } else if(curId > -1 && solverId < 0) {
11073 return a_neighborId(_cellId, _dir);
11074 } else {
11075 return static_cast<MLong>(-1);
11076 }
11077 };
11078
11079 set<MInt> checkedCells;
11080 // iterate overall neighbors till found
11081 while(!pointWthCell<t_correct, true>(coord, cellId, correctCellCoord)) {
11082 // current cellCoords
11083 const MFloat* tmpCoord = m_tree.coordinate(cellId);
11084 const MFloat* cellCoords = t_correct ? (correctCellCoord)(cellId, &tmp[0]) : tmpCoord;
11085 const MFloat halfCellLength = cellLengthAtLevel(a_level(cellId) + 1);
11086
11087 checkedCells.insert(cellId);
11088
11089 MInt direction = -1;
11090
11091 // determine which cell side is crossed
11092 for(MInt i = 0; i < nDim; i++) {
11093 const MFloat difference = coord[i] - cellCoords[i];
11094 const MFloat absDifference = fabs(difference);
11095 if(absDifference > halfCellLength) {
11096 const MInt temp = 2 * i + ((difference > 0.0) ? 1 : 0);
11097 const MLong neighborId = findExistingNghbr(cellId, temp, solverId);
11098 if(neighborId > -1) {
11099 direction = temp;
11100 cellId = neighborId;
11101 break;
11102 } else if(a_parentId(cellId) > -1
11103 && pointWthCell<t_correct, true>(coord, a_parentId(cellId), correctCellCoord)) {
11104 // point is within the parent cell but not within any of the cells-neighbors
11105 // this means, that the matching child where the point should be is outside the STL geometry
11106 return -1;
11107 }
11108 }
11109 }
11110
11111 if(direction == -1) {
11112 // no valid cell in any direction of coords
11113 // meaning that the cell is to far (in all directions) from the startId
11114 // start a general search in the entire domain instead
11115 return findContainingLeafCell<t_correct>(coord, correctCellCoord, solverId);
11116 }
11117
11118 // If tmpCoord is located on the cell surface of two cells, this loop would jump between these cells until the end
11119 // of time.
11120 if(checkedCells.find(cellId) != checkedCells.end()) break;
11121 }
11122
11123 // loop down to leaf cell (global or for solver) containing coord
11124 while((global) ? a_hasChildren(cellId) : a_hasChildren(cellId, solverId)) {
11125 MInt childId = 0;
11126 for(; childId < IPOW2(nDim); childId++) {
11127 const MInt childCellId = (global) ? a_childId(cellId, childId) : a_childId(cellId, childId, solverId);
11128 if(childCellId < 0) {
11129 continue;
11130 }
11131 MInt cnt = 0;
11132 const MFloat* cellCoords = m_tree.coordinate(childCellId);
11133 // TODO FIXME labels:GRID
11134 // const MFloat* cellCoords = t_correct ? (*correctCellCoord)(curId, &tmp[0]): tmpCoord;
11135 const MFloat constHalfCellLength = halfCellLength(childCellId);
11136
11137 for(MInt dimId = 0; dimId < nDim; dimId++) {
11138 MFloat dist = coord[dimId] - cellCoords[dimId];
11139 if(coord[dimId] >= cellCoords[dimId] - constHalfCellLength
11140 && coord[dimId] < cellCoords[dimId] + constHalfCellLength) {
11141 cnt++;
11142 } else {
11143 const MFloat increaseOrderOfMagnitude = 10.0; // MFloatEps is to small.
11144 if(approx(fabs(dist), constHalfCellLength, increaseOrderOfMagnitude * MFloatEps)) {
11145 MInt dir = (dist > F0) ? 1 : 0;
11146 if(a_neighborId(childCellId, dimId + dir) > -1) {
11147 if(a_parentId(a_neighborId(childCellId, dimId + dir)) != a_parentId(childCellId)) {
11148 // Point on surface of parent cell
11149 cnt++;
11150 } else {
11151 if(dist > F0) {
11152 // Point in center of parent cell. Choose cell with smaller cellCoords[dimId].
11153 cnt++;
11154 }
11155 }
11156 } else {
11157 // Point musst be on surface of parent cell. Else neighbor would exist.
11158 cnt++;
11159 }
11160 }
11161 }
11162 }
11163
11164 if(cnt == nDim) {
11165 cellId = childCellId;
11166 break;
11167 }
11168 }
11169 if(childId == IPOW2(nDim)) {
11170 if(!a_isHalo(cellId)) {
11171 mTerm(1, AT_, "No matching child during loop down!");
11172 } else {
11173 if(!allowNonLeafHalo) {
11174 cout << "dom: " << domainId() << " no matching child during loop down" << endl;
11175 return -1;
11176 } else {
11177 return cellId;
11178 }
11179 }
11180 }
11181 }
11182
11183 if(global) {
11184 ASSERT(m_tree.isLeafCell(cellId), "No leaf cell... " + std::to_string(cellId));
11185 } else {
11186 ASSERT(!a_hasChildren(cellId, solverId), "No leaf cell... " + std::to_string(cellId));
11187 }
11188
11189 return cellId;
11190}

◆ findContainingLeafCell() [2/5]

template<MInt nDim>
template<MBool t_correct = false>
MInt CartesianGrid< nDim >::findContainingLeafCell ( const MFloat *const  coord,
const MInt  startId,
std::function< MFloat *(MInt, MFloat *const)>  correctCellCoord = nullptr,
const MInt  solverId = -1,
const MBool  allowNonLeafHalo = false 
)

◆ findContainingLeafCell() [3/5]

template<MInt nDim>
template<MBool t_correct>
MInt CartesianGrid< nDim >::findContainingLeafCell ( const MFloat coord,
function< MFloat *(MInt, MFloat *const)>  correctCellCoord,
const MInt  solverId 
)
Author
Thomas Schilden
Date
10.05.2016

The algorithm does the following:

  1. Check if the point is inside the local bounding box, else return early
  2. Loops over the partition cells to find the partition cell that contains p
  3. loops down the children to the leaf cell definition of inside: all coordinates fulfill: x_c,min <= x_p < x_c,max
Parameters
[in]coordinatesof the point
[out]localcell Id, -1 if not in domain

Definition at line 10980 of file cartesiangrid.cpp.

10981 {
10982 TRACE();
10983
10984 // Return early if point is not inside the local bounding box
10985 if(!pointInLocalBoundingBox(coord)) {
10986 return -1;
10987 }
10988
10989 ASSERT(solverId >= -1 && solverId < treeb().noSolvers(), "Invalid solver id " + to_string(solverId));
10990 // Check if the lookup should be global or on a solver basis using the given solverId
10991 const MBool global = (solverId < 0);
10992
10993 MInt cellId = findContainingPartitionCell<t_correct>(coord, solverId, correctCellCoord);
10994
10995 // return -1 if not in local partition cells
10996 if(cellId == -1) {
10997 return -1;
10998 }
10999
11000 // loop down to leaf cell (global or for solver) containing coord
11001 while((global) ? a_hasChildren(cellId) : a_hasChildren(cellId, solverId)) {
11002 MInt childId = 0;
11003 for(; childId < IPOW2(nDim); childId++) {
11004 const MInt childCellId = (global) ? a_childId(cellId, childId) : a_childId(cellId, childId, solverId);
11005 if(childCellId < 0) continue;
11006 MBool isInCell = pointWthCell<t_correct, false>(coord, childCellId, correctCellCoord);
11007 if(isInCell) {
11008 cellId = childCellId;
11009 break;
11010 }
11011 }
11012 if(childId == IPOW2(nDim)) {
11013 mTerm(1, AT_, "No matching child during loop down!");
11014 }
11015 }
11016
11017 if(global) {
11018 ASSERT(m_tree.isLeafCell(cellId), "No leaf cell... " + std::to_string(cellId));
11019 } else {
11020 ASSERT(!a_hasChildren(cellId, solverId), "No leaf cell... " + std::to_string(cellId));
11021 }
11022 return cellId;
11023}
MBool pointInLocalBoundingBox(const MFloat *coord)
Check if the given point lies in the local bounding box.

◆ findContainingLeafCell() [4/5]

template<MInt nDim>
template<MBool t_correct = false>
template MInt CartesianGrid< nDim >::findContainingLeafCell< true > ( const MFloat coord,
std::function< MFloat *(MInt, MFloat *const)>  correctCellCoord = nullptr,
const MInt  solverId = -1 
)

◆ findContainingLeafCell() [5/5]

template<MInt nDim>
template<MBool t_correct = false>
MInt CartesianGrid< nDim >::findContainingLeafCell ( const std::array< MFloat, nDim > &  coord,
const MInt  startId,
std::function< MFloat *(MInt, MFloat *const)> *  correctCellCoord = nullptr,
const MInt  solverId = -1,
const MBool  allowNonLeafHalo = false 
)
inline

Definition at line 841 of file cartesiangrid.h.

843 {
844 return findContainingLeafCell<t_correct>(&coord[0], startId, correctCellCoord, solverId, allowNonLeafHalo);
845 }

◆ findContainingPartitionCell() [1/2]

template<MInt nDim>
template<MBool t_correct>
template MInt CartesianGrid< nDim >::findContainingPartitionCell< true > ( const MFloat *const  coord,
const MInt  solverId,
function< MFloat *(MInt, MFloat *const)>  correctCellCoord 
)

Definition at line 10734 of file cartesiangrid.cpp.

10735 {
10736 ASSERT(solverId >= -1 && solverId < treeb().noSolvers(), "Invalid solver id " + to_string(solverId));
10737
10738 // array<MFloat, nDim> tmp;
10739 const MInt noLocalPartitionCells = m_localPartitionCellOffsets[1] - m_localPartitionCellOffsets[0];
10740
10741 // loop over partition cells
10742 for(MInt i = 0; i < noLocalPartitionCells; i++) {
10743 const MInt curId = m_localPartitionCellLocalIds[i];
10744
10745 MBool isInCell = pointWthCell<t_correct, false>(coord, curId, correctCellCoord);
10746
10747 if(isInCell) {
10748 if(solverId < 0) {
10749 return curId;
10750 } else {
10751 // If a solverId is given check if partition cell belongs to solver
10752 if(a_solver(curId, solverId)) {
10753 return curId;
10754 } else {
10755 return -1;
10756 }
10757 }
10758 }
10759 }
10760 return -1;
10761}

◆ findContainingPartitionCell() [2/2]

template<MInt nDim>
template<MBool t_correct = false>
MInt CartesianGrid< nDim >::findContainingPartitionCell ( const MFloat *const  coord,
const MInt  solverId = -1,
std::function< MFloat *(MInt, MFloat *const)>  correctCellCoord = nullptr 
)

◆ findIndex()

template<MInt nDim>
template<class ITERATOR , typename U >
MInt CartesianGrid< nDim >::findIndex ( ITERATOR  first,
ITERATOR  last,
const U &  val 
)
private
Author
Lennart Schneiders
Date
October 2017

Definition at line 912 of file cartesiangrid.cpp.

912 {
913 if(distance(first, last) <= 0) return -1;
914 auto idx = (MInt)distance(first, find(first, last, val));
915 if(idx == (MInt)distance(first, last)) idx = -1;
916 return idx;
917}

◆ findNeighborDomainId() [1/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::findNeighborDomainId ( const MLong  globalId)
inline

Definition at line 962 of file cartesiangrid.h.

962 {
964 };

◆ findNeighborDomainId() [2/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::findNeighborDomainId ( const MLong  globalId,
const MInt  noDomains,
const MLong domainOffsets 
)
Author
ansgar
Date
Nov 2021
Parameters
[in]globalIdglobal cell id
Returns
domain id containing globalId

Note: this function utilized a linear search before, which was quite inefficient for large cases on O(100000) cores and e.g. slowed down the window/halo cell generation significantly

Definition at line 884 of file cartesiangrid.cpp.

884 {
885 if(globalId < domainOffsets[0] || globalId > domainOffsets[noDomains]) {
886 TERMM(1, "Invalid global id: " + std::to_string(globalId)
887 + "; domainOffset[0]=" + std::to_string(domainOffsets[noDomains])
888 + "; domainOffset[noDomains]=" + std::to_string(domainOffsets[noDomains]));
889 return -1;
890 }
891
892 // Search for global cell id in (the sorted) domain offsets array in logarithmic time
893 auto lowerBound = std::lower_bound(&domainOffsets[0], &domainOffsets[0] + noDomains, globalId);
894 const MInt dist = std::distance(&domainOffsets[0], lowerBound);
895 // Check if this cell is a domain offset (i.e. in the offsets list)
896 const MBool isDomainOffset = (*lowerBound == globalId);
897 // Determine neighbor domain id
898 const MInt domain = (isDomainOffset) ? dist : dist - 1;
899 return domain;
900}

◆ generalExchange()

template<MInt nDim>
template<typename DATATYPE >
void CartesianGrid< nDim >::generalExchange ( MInt  noVars,
const MInt vars,
DATATYPE **  exchangeVar,
MInt  noDomSend,
MInt domSend,
const MInt noCellsSendPerDom,
const MInt cellIdsSend,
MInt  noDomRecv,
MInt domRecv,
const MInt noCellsRecvPerDom,
const MInt cellIdsRecv 
)

Definition at line 11299 of file cartesiangrid.cpp.

11302 {
11303 TRACE();
11304
11305 // recv info
11306 MIntScratchSpace recvMemOffset(noDomRecv + 1, AT_, "recvMemOffset");
11307 recvMemOffset.fill(0);
11308 MInt allRecv = 0;
11309 for(MInt dom = 0; dom < noDomRecv; dom++) {
11310 allRecv += noCellsRecvPerDom[dom];
11311 recvMemOffset[dom + 1] = allRecv;
11312 }
11313 ScratchSpace<DATATYPE> recvMem(allRecv, AT_, "recvMem");
11314
11315 // send info
11316 MIntScratchSpace sendMemOffset(noDomSend + 1, AT_, "sendMemOffset");
11317 sendMemOffset.fill(0);
11318 MInt allSend = 0;
11319 for(MInt dom = 0; dom < noDomSend; dom++) {
11320 allSend += noCellsSendPerDom[dom];
11321 sendMemOffset[dom + 1] = allSend;
11322 }
11323 ScratchSpace<DATATYPE> sendMem(allSend, AT_, "sendMem");
11324
11325 DATATYPE* ptr = &(exchangeVar[0][0]);
11326
11327 for(MInt i = 0; i < noVars; i++) {
11328 MInt var = vars[i];
11329
11330 // fill the send mem
11331 for(MInt j = 0; j < allSend; j++)
11332 sendMem[j] = ptr[cellIdsSend[j] * noVars + var];
11333
11334 // communicate
11335 ScratchSpace<MPI_Request> mpi_request_(noDomSend, AT_, "mpi_request_");
11336
11337 for(MInt dom = 0; dom < noDomSend; dom++)
11338 MPI_Issend(&(sendMem[sendMemOffset[dom]]), noCellsSendPerDom[dom] * sizeof(DATATYPE), MPI_CHAR, domSend[dom], 0,
11339 mpiComm(), &mpi_request_[dom], AT_, "(sendMem[sendMemOffset[dom]])");
11340
11341 MPI_Status status_;
11342 for(MInt dom = 0; dom < noDomRecv; dom++)
11343 MPI_Recv(&(recvMem[recvMemOffset[dom]]), noCellsRecvPerDom[dom] * sizeof(DATATYPE), MPI_CHAR, domRecv[dom], 0,
11344 mpiComm(), &status_, AT_, "(recvMem[recvMemOffset[dom]])");
11345
11346 for(MInt dom = 0; dom < noDomSend; dom++)
11347 MPI_Wait(&mpi_request_[dom], &status_, AT_);
11348
11349 // distribute the recv mem
11350 for(MInt j = 0; j < allRecv; j++)
11351 ptr[cellIdsRecv[j] * noVars + var] = recvMem[j];
11352 }
11353}

◆ generateHilbertIndex() [1/2]

template<MInt nDim>
MLong CartesianGrid< nDim >::generateHilbertIndex ( const MInt  cellId)
inlineprivate

Definition at line 935 of file cartesiangrid.h.

935{ return hilbertIndexGeneric(&a_coordinate(cellId, 0)); }

◆ generateHilbertIndex() [2/2]

template<MInt nDim>
MLong CartesianGrid< nDim >::generateHilbertIndex ( const MInt  cellId,
const MInt  targetMinLevel 
)
inline

Definition at line 903 of file cartesiangrid.h.

903 {
905 targetMinLevel);
906 }

◆ getAdjacentGridCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::getAdjacentGridCells ( MInt  cellId,
MIntScratchSpace adjacentCells,
MInt  level,
MBool  diagonalNeighbors = true 
)
private
Author
Lennart Schneiders

Definition at line 5626 of file cartesiangrid.cpp.

5627 {
5628 set<MInt> nghbrs;
5629 for(MInt dir0 = 0; dir0 < m_noDirs; dir0++) {
5630 MInt nghbrId0 = -1;
5631 if(a_hasNeighbor(cellId, dir0) > 0)
5632 nghbrId0 = a_neighborId(cellId, dir0);
5633 else if(a_parentId(cellId) > -1) {
5634 if(a_hasNeighbor(a_parentId(cellId), dir0) > 0) {
5635 nghbrId0 = a_neighborId(a_parentId(cellId), dir0);
5636 }
5637 }
5638
5639 if(nghbrId0 < 0) continue;
5640 if(a_noChildren(nghbrId0) > 0 && a_level(nghbrId0) <= level) {
5641 for(MInt child = 0; child < m_maxNoChilds; child++) {
5642 if(!childCode[dir0][child]) continue;
5643 if(a_childId(nghbrId0, child) > -1) nghbrs.insert(a_childId(nghbrId0, child));
5644 }
5645 } else {
5646 nghbrs.insert(nghbrId0);
5647 }
5648
5649 if(diagonalNeighbors) {
5650 for(MInt dir1 = 0; dir1 < m_noDirs; dir1++) {
5651 if((dir1 / 2) == (dir0 / 2)) continue;
5652 MInt nghbrId1 = -1;
5653 if(a_hasNeighbor(nghbrId0, dir1) > 0)
5654 nghbrId1 = a_neighborId(nghbrId0, dir1);
5655 else if(a_parentId(nghbrId0) > -1)
5656 if(a_hasNeighbor(a_parentId(nghbrId0), dir1) > 0) nghbrId1 = a_neighborId(a_parentId(nghbrId0), dir1);
5657 if(nghbrId1 < 0) continue;
5658 if(a_noChildren(nghbrId1) > 0 && a_level(nghbrId1) <= level) {
5659 for(MInt child = 0; child < m_maxNoChilds; child++) {
5660 if(!childCode[dir0][child] || !childCode[dir1][child]) continue;
5661 if(a_childId(nghbrId1, child) > -1) nghbrs.insert(a_childId(nghbrId1, child));
5662 }
5663 } else
5664 nghbrs.insert(nghbrId1);
5665 IF_CONSTEXPR(nDim == 3) {
5666 for(MInt dir2 = 0; dir2 < m_noDirs; dir2++) {
5667 if(((dir2 / 2) == (dir0 / 2)) || ((dir2 / 2) == (dir1 / 2))) continue;
5668 MInt nghbrId2 = -1;
5669 if(a_hasNeighbor(nghbrId1, dir2) > 0)
5670 nghbrId2 = a_neighborId(nghbrId1, dir2);
5671 else if(a_parentId(nghbrId1) > -1)
5672 if(a_hasNeighbor(a_parentId(nghbrId1), dir2) > 0) nghbrId2 = a_neighborId(a_parentId(nghbrId1), dir2);
5673 if(nghbrId2 < 0) continue;
5674 if(a_noChildren(nghbrId2) > 0 && a_level(nghbrId2) <= level) {
5675 for(MInt child = 0; child < m_maxNoChilds; child++) {
5676 if(!childCode[dir0][child] || !childCode[dir1][child] || !childCode[dir2][child]) continue;
5677 if(a_childId(nghbrId2, child) > -1) nghbrs.insert(a_childId(nghbrId2, child));
5678 }
5679 } else
5680 nghbrs.insert(nghbrId2);
5681 }
5682 }
5683 }
5684 }
5685 }
5686
5687
5688 MInt cnt = 0;
5689 for(MInt nghbr : nghbrs) {
5690 ASSERT(a_level(nghbr) <= level + 1, "");
5691 ASSERT(cnt < (signed)adjacentCells.size(), "");
5692 adjacentCells[cnt] = nghbr;
5693 cnt++;
5694 }
5695 return cnt;
5696}
size_type size() const
Definition: scratch.h:302

◆ getAdjacentGridCells1d5()

template<MInt nDim>
template<MBool finer, MBool coarser>
void CartesianGrid< nDim >::getAdjacentGridCells1d5 ( std::set< MInt > &  nghbrs,
const MInt  cellId,
const MInt  dim,
const MInt  dimNext = -1,
const MInt  dimNextNext = -1,
const uint_fast8_t  childCodes = (uint_fast8_t)~0 
)
inlineprivate
Author
me

(childCodes_ & (1<<child))

Definition at line 5750 of file cartesiangrid.cpp.

5752 {
5753 TRACE();
5754
5755 for(MInt dir = 2 * dim; dir < 2 * dim + 2; ++dir) {
5756 auto childCodes_ = childCodes & childCodePro[dir];
5757 if(a_hasNeighbor(cellId, dir) > 0) {
5758 const MInt nghbrId0 = a_neighborId(cellId, dir);
5759 if(finer && a_noChildren(nghbrId0) > 0) {
5760 // The neighbor might have children, but which are not adjacent
5761 MBool childFound = false;
5762 for(MInt child = 0; child < m_maxNoChilds; child++) {
5763 if( !childCode[dir][child]) continue;
5764 if(a_childId(nghbrId0, child) > -1) {
5765 const MInt childId = a_childId(nghbrId0, child);
5766 // TODO_SS labels:GRID Can this cell have children and what to do in that case?!
5767 // if (nghbrs.find(childId)!=nghbrs.end()) continue;
5768 nghbrs.insert(childId);
5769 childFound = true;
5770 if(dimNext > -1)
5771 getAdjacentGridCells1d5<false, true>(nghbrs, childId, dimNext, dimNextNext, -1, childCodes_);
5772 if(dimNextNext > -1)
5773 getAdjacentGridCells1d5<false, true>(nghbrs, childId, dimNextNext, dimNext, -1, childCodes_);
5774 }
5775 }
5776 if(!childFound) { // TODO_SS labels:GRID,totest Check if this is required
5777 // if (nghbrs.find(nghbrId0)!=nghbrs.end()) continue;
5778 nghbrs.insert(nghbrId0);
5779 if(dimNext > -1)
5780 getAdjacentGridCells1d5<finer, coarser>(nghbrs, nghbrId0, dimNext, dimNextNext, -1, childCodes_);
5781 if(dimNextNext > -1)
5782 getAdjacentGridCells1d5<finer, coarser>(nghbrs, nghbrId0, dimNextNext, dimNext, -1, childCodes_);
5783 }
5784 } else {
5785 // if (nghbrs.find(nghbrId0)!=nghbrs.end()) continue;
5786 nghbrs.insert(nghbrId0);
5787 if(dimNext > -1)
5788 getAdjacentGridCells1d5<finer, coarser>(nghbrs, nghbrId0, dimNext, dimNextNext, -1, childCodes_);
5789 if(dimNextNext > -1)
5790 getAdjacentGridCells1d5<finer, coarser>(nghbrs, nghbrId0, dimNextNext, dimNext, -1, childCodes_);
5791 }
5792 } else if(coarser && a_parentId(cellId) > -1) {
5793 if(a_hasNeighbor(a_parentId(cellId), dir) > 0) {
5794 const MInt nghbrId0 = a_neighborId(a_parentId(cellId), dir);
5795 // TODO_SS labels:GRID Can this cell have children and what to do in that case?!
5796 // if (nghbrs.find(nghbrId0)!=nghbrs.end()) continue;
5797 nghbrs.insert(nghbrId0);
5798 // TODO_SS labels:GRID,totest check the following
5799 // TERMM_IF_COND(a_hasChildren(nghbrId0), "");
5800 if(dimNext > -1) getAdjacentGridCells1d5<true, false>(nghbrs, nghbrId0, dimNext, dimNextNext, -1, childCodes_);
5801 if(dimNextNext > -1)
5802 getAdjacentGridCells1d5<true, false>(nghbrs, nghbrId0, dimNextNext, dimNext, -1, childCodes_);
5803 }
5804 }
5805 }
5806}

◆ getAdjacentGridCells5()

template<MInt nDim>
template<MBool finer, MBool coarser>
MInt CartesianGrid< nDim >::getAdjacentGridCells5 ( const MInt  cellId,
MInt * const  adjacentCells,
const MInt  level = -1,
const MBool  diagonalNeighbors = true 
)
inlineprivate

Definition at line 5703 of file cartesiangrid.cpp.

5704 {
5705 static constexpr const MInt dimConverter[3][2] = {{1, 2}, {0, 2}, {0, 1}};
5706 set<MInt> nghbrs;
5707
5708 if(diagonalNeighbors) {
5709 for(MInt dim = 0; dim < nDim; ++dim) {
5710 if(nDim == 2)
5711 getAdjacentGridCells1d5<finer, coarser>(nghbrs, cellId, dim, dimConverter[dim][0]);
5712 else if(nDim == 3)
5713 getAdjacentGridCells1d5<finer, coarser>(nghbrs, cellId, dim, dimConverter[dim][0], dimConverter[dim][1]);
5714 }
5715 } else {
5716 for(MInt dim = 0; dim < nDim; ++dim) {
5717 getAdjacentGridCells1d5<finer, coarser>(nghbrs, cellId, dim);
5718 }
5719 }
5720
5721 ASSERT(nghbrs.size() <= 27 * m_maxNoChilds, "");
5722
5723 if(!finer && !coarser) {
5724 // same level
5725 const MInt noNghbrs = nghbrs.size();
5726 std::copy(nghbrs.begin(), nghbrs.end(), adjacentCells);
5727 return noNghbrs;
5728 } else if(level == -1) {
5729 // all levels
5730 const MInt noNghbrs = nghbrs.size();
5731 std::copy(nghbrs.begin(), nghbrs.end(), adjacentCells);
5732 return noNghbrs;
5733 } else {
5734 MInt cnt = 0;
5735 for(auto cellId_ : nghbrs) {
5736 if(a_level(cellId_) == level) {
5737 adjacentCells[cnt++] = cellId_;
5738 }
5739 }
5740 return cnt;
5741 }
5742}

◆ globalBoundingBox()

template<MInt nDim>
const MFloat * CartesianGrid< nDim >::globalBoundingBox ( ) const
inline

Definition at line 409 of file cartesiangrid.h.

409{ return &m_boundingBox[0]; }

◆ globalIdToLocalId()

template<MInt nDim>
MInt CartesianGrid< nDim >::globalIdToLocalId ( const MLong globalId,
const MBool  termIfNotExisting = false 
)
inline
Author
Lennart Schneiders

Definition at line 9129 of file cartesiangrid.cpp.

9129 {
9130 ASSERT(m_globalToLocalId.size() > 0, "Error: m_globalToLocalId is empty.");
9131 auto it = m_globalToLocalId.find(globalId);
9132 if(it != m_globalToLocalId.end()) {
9133 return it->second;
9134 } else {
9135 TERMM_IF_COND(termIfNotExisting, "Mapping from global to local id not found.");
9136 return -1;
9137 }
9138}

◆ gridCellVolume()

template<MInt nDim>
MFloat CartesianGrid< nDim >::gridCellVolume ( const MInt  level) const
inline

Definition at line 571 of file cartesiangrid.h.

571{ return m_gridCellVolume[level]; }
MFloat * m_gridCellVolume

◆ gridInputFileName()

template<MInt nDim>
MString CartesianGrid< nDim >::gridInputFileName ( ) const
inline

Definition at line 539 of file cartesiangrid.h.

539{ return m_gridInputFileName; }

◆ gridSanityChecks()

template<MInt nDim>
void CartesianGrid< nDim >::gridSanityChecks

Definition at line 12929 of file cartesiangrid.cpp.

12929 {
12930 m_log << "Performing grid sanity checks... ";
12931
12932 const MInt noCells = m_tree.size();
12933
12934 // Check that number internal cells and the interval between domain offsets is consistent
12935 TERMM_IF_NOT_COND(m_noInternalCells == m_domainOffsets[domainId() + 1] - m_domainOffsets[domainId()],
12936 "Error: number of internal cells does not match with interval between domain offsets.");
12937
12938 // Partition cell checks
12939 {
12940 ScratchSpace<MBool> isPartitionCell(noCells, AT_, "isPartitionCell");
12941 isPartitionCell.fill(false);
12942
12943 MLong lastGlobalId = -1;
12944 for(MInt i = 0; i < m_noPartitionCells; i++) {
12945 const MInt localId = m_localPartitionCellLocalIds[i];
12946 const MLong globalId = m_localPartitionCellGlobalIds[i];
12947
12948 // Check that partition cell property is set
12949 TERMM_IF_NOT_COND(a_hasProperty(localId, Cell::IsPartitionCell), "Error: Cell is not a partition cell.");
12950 // Check the partition cell global id
12951 TERMM_IF_NOT_COND(globalId == a_globalId(localId), "Error: partition cell global id mismatch.");
12952 // Check that partition cells are sorted by global ids
12953 TERMM_IF_NOT_COND(globalId > lastGlobalId, "Error: partition cells not sorted by global id.");
12954
12955 isPartitionCell[localId] = true;
12956 lastGlobalId = a_globalId(localId);
12957 }
12958
12959 // Make sure that all other internal cells dont have the partition cell property set
12960 for(MInt i = 0; i < noCells; i++) {
12961 if(isPartitionCell[i] || a_isToDelete(i) || a_isHalo(i)) continue;
12962 TERMM_IF_COND(a_hasProperty(i, Cell::IsPartitionCell),
12963 "Error: cell marked as partition cell but not in partition cell list " + std::to_string(i));
12964 }
12965
12967 "Error: global number of partition cells mismatch.");
12968
12969 MLongScratchSpace localPartitionCellCounts(noDomains(), AT_, "localPartitionCellCounts");
12970 MLongScratchSpace localPartitionCellOffsets(noDomains() + 1, AT_, "localPartitionCellOffsets");
12971 // Determine the number of partition cells on all domains and the partition cell offsets
12972 determineNoPartitionCellsAndOffsets(&localPartitionCellCounts[0], &localPartitionCellOffsets[0]);
12973
12975 "Error: partition cell offset mismatch.");
12976 TERMM_IF_NOT_COND(m_localPartitionCellOffsets[1] == localPartitionCellOffsets[domainId() + 1],
12977 "Error: next partition cell offset mismatch.");
12978 }
12979
12980 // Check the global to local id mapping
12981 for(MInt i = 0; i < noCells; i++) {
12982 if(a_isToDelete(i) || a_hasProperty(i, Cell::IsPeriodic)) continue;
12983 TERMM_IF_NOT_COND(m_globalToLocalId[a_globalId(i)] == i,
12984 "Error in global to local id mapping: l" + to_string(i) + " g" + to_string(a_globalId(i)) + " g2l"
12985 + to_string(m_globalToLocalId[a_globalId(i)]));
12986 }
12987
12988 // Check partition level ancestors
12989 {
12990 ScratchSpace<MBool> isPartLvlAncestor(noCells, AT_, "isPartLvlAncestor");
12991 isPartLvlAncestor.fill(false);
12992
12993 MInt noLocalPartLvlAncestors = 0;
12994 MInt count = 0;
12995 for(auto& i : m_partitionLevelAncestorIds) {
12996 TERMM_IF_NOT_COND(a_hasProperty(i, Cell::IsPartLvlAncestor), "Error: cell is not a partition level ancestor.");
12997 TERMM_IF_COND(a_isToDelete(i), "Error: partition level ancestor marked for deletion.");
12998 isPartLvlAncestor[i] = true;
12999
13000 // Check global ids of childs
13001 for(MInt child = 0; child < m_maxNoChilds; child++) {
13002 const MInt childId = a_childId(i, child);
13003 const MLong childGlobalId = (childId > -1) ? a_globalId(childId) : -1;
13004 const MInt index = count * m_maxNoChilds + child;
13005 TERMM_IF_NOT_COND(m_partitionLevelAncestorChildIds[index] == childGlobalId,
13006 "Error: partition level ancestor child id mismatch. "
13007 + std::to_string(m_partitionLevelAncestorChildIds[index])
13008 + " != " + std::to_string(childGlobalId) + "; " + std::to_string(i) + "; "
13009 + std::to_string(child));
13010 }
13011 count++;
13012
13013 if(!a_isHalo(i)) {
13014 noLocalPartLvlAncestors++;
13015 }
13016 }
13017
13018 // Check the number of internal partition level ancestor cells
13019 TERMM_IF_NOT_COND(noLocalPartLvlAncestors == m_noPartitionLevelAncestors,
13020 "Error: number of local partition level ancestors mismatch.");
13021
13022 // All other internal cells shouldnt be marked
13023 for(MInt i = 0; i < noCells; i++) {
13024 if(isPartLvlAncestor[i] || a_isToDelete(i) || a_isHalo(i)) continue;
13025 TERMM_IF_COND(a_hasProperty(i, Cell::IsPartLvlAncestor),
13026 "Error: cell marked as partition level ancestor but is not in corresponding list.");
13027 }
13028
13029 // TODO labels:GRID check other partition level ancestor info
13030 }
13031
13032 // Check min-level cells
13033 {
13034 ScratchSpace<MBool> isMinLevelCell(noCells, AT_, "isMinLevelCell");
13035 isMinLevelCell.fill(false);
13036
13037 for(auto& minLevelCell : m_minLevelCells) {
13038 TERMM_IF_NOT_COND(a_level(minLevelCell) == m_minLevel, "Error: level of min-level cell mismatch.");
13039 isMinLevelCell[minLevelCell] = true;
13040 }
13041
13042 for(MInt i = 0; i < noCells; i++) {
13043 if(isMinLevelCell[i] || a_isToDelete(i)) continue;
13044 TERMM_IF_COND(a_level(i) <= m_minLevel, "Error: non-min-level cell has level <= minLevel");
13045 }
13046 }
13047
13048 m_log << "done" << std::endl;
13049}
void determineNoPartitionCellsAndOffsets(MLong *const noPartitionCells, MLong *const partitionCellOffsets)
Determine the number of partition cells on each domain and the corresponding offsets.
MInt m_noPartitionLevelAncestors
Local number of partition level ancestors on this domain (without halos)
MLong localPartitionCellOffsets(const MInt index) const
IdType index(const FloatType *const x, const IdType level)
Return Hilbert index for given location and level in 2D or 3D.
Definition: hilbert.h:165

◆ halfCellLength()

template<MInt nDim>
MFloat CartesianGrid< nDim >::halfCellLength ( const MInt  cellId) const
inline

Definition at line 390 of file cartesiangrid.h.

390{ return F1B2 * cellLengthAtCell(cellId); }

◆ haloCell()

template<MInt nDim>
MInt CartesianGrid< nDim >::haloCell ( const MInt  domainId,
const MInt  cellId 
) const
inline

Definition at line 448 of file cartesiangrid.h.

448{ return m_haloCells[domainId][cellId]; }

◆ haloCells()

template<MInt nDim>
const std::vector< std::vector< MInt > > & CartesianGrid< nDim >::haloCells ( ) const
inline

Definition at line 451 of file cartesiangrid.h.

451{ return m_haloCells; };

◆ haloMode()

template<MInt nDim>
MInt CartesianGrid< nDim >::haloMode ( ) const
inline

Definition at line 566 of file cartesiangrid.h.

566{ return m_haloMode; }

◆ hasCutOff()

template<MInt nDim>
MBool CartesianGrid< nDim >::hasCutOff ( ) const
inline

Definition at line 83 of file cartesiangrid.h.

83{ return m_cutOff; }

◆ hilbertIndexGeneric() [1/2]

template<MInt nDim>
MLong CartesianGrid< nDim >::hilbertIndexGeneric ( const MFloat *const  coords) const
inlineprivate

◆ hilbertIndexGeneric() [2/2]

template<MInt nDim>
MLong CartesianGrid< nDim >::hilbertIndexGeneric ( const MFloat *const  coords,
const MFloat *const  center,
const MFloat  length0,
const MInt  baseLevel 
) const
private

This function normalizes the cell coordinates and calls the hilbertIndex function.

IMPORTANT: The baseLevel is the normal refinement level - 1 (e.g. if your refinement level is 3, base level is 2). NOTE: this IMPORTANT information seems to be outdated!

Definition at line 8983 of file cartesiangrid.cpp.

8986 {
8987 // TRACE();
8988 ASSERT(length0 > 0.0, "length needs to be > 0.");
8989 // Relate to unit cube
8990 MFloat x[nDim];
8991 for(MInt i = 0; i < nDim; i++) {
8992 x[i] = (coords[i] - center[i] + 1e-12 + F1B2 * length0) / length0;
8993 ASSERT(x[i] > F0 && x[i] < F1,
8994 "Normalized coordinate outside of range (0,1): " + std::to_string(x[i])
8995 + "; length0 = " + std::to_string(length0) + "; baseLevel = " + std::to_string(baseLevel)
8996 + "; coord = " + std::to_string(coords[i]) + "; center = " + std::to_string(center[i]));
8997 }
8998 const MLong hilbertId = maia::grid::hilbert::index<nDim>(&x[0], (MLong)baseLevel);
8999 ASSERT(hilbertId > -1, "Invalid hilbert id");
9000 return hilbertId;
9001}

◆ hollowBoxSphereIntersection()

template<MInt nDim>
MBool CartesianGrid< nDim >::hollowBoxSphereIntersection ( const MFloat bMin,
const MFloat bMax,
const MFloat *const  sphereCenter,
MFloat const  radius 
)

Definition at line 10784 of file cartesiangrid.cpp.

10785 {
10786 MFloat dmin = 0;
10787 MBool face = false;
10788 for(MInt i = 0; i < nDim; i++) {
10789 if(sphereCenter[i] < bMin[i]) {
10790 face = true;
10791 dmin += pow(sphereCenter[i] - bMin[i], 2);
10792 } else if(sphereCenter[i] > bMax[i]) {
10793 face = true;
10794 dmin += pow(sphereCenter[i] - bMax[i], 2);
10795 } else if(sphereCenter[i] - bMin[i] <= radius) {
10796 face = true;
10797 } else if(bMax[i] - sphereCenter[i] <= radius) {
10798 face = true;
10799 }
10800 }
10801 return (face && (dmin <= pow(radius, 2)));
10802}

◆ initGridMap()

template<MInt nDim>
void CartesianGrid< nDim >::initGridMap ( )
private

◆ intersectingWithHaloCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::intersectingWithHaloCells ( MFloat *const  center,
MFloat const  radius,
MInt  domainId,
MBool  onlyPartition 
)

Definition at line 10832 of file cartesiangrid.cpp.

10833 {
10834 MBool intersectsACell = false;
10835 MInt intersectingCellId = -1;
10836 std::vector<MFloat> bMin(nDim);
10837 std::vector<MFloat> bMax(nDim);
10838
10839 for(MInt i = 0; i < noHaloCells(domainId); i++) {
10840 const MInt curId = haloCell(domainId, i);
10841 // skip all non-partition cells
10842 if(onlyPartition && !a_hasProperty(curId, Cell::IsPartitionCell)) {
10843 continue;
10844 }
10845
10846 const MFloat _halfCellLength = halfCellLength(curId);
10847 const MFloat* cCoord = m_tree.coordinate(curId);
10848
10849 for(MInt n = 0; n < nDim; n++) {
10850 // std::cout << " GRID POS: " << cCoord[n];
10851 bMin[n] = cCoord[n] - _halfCellLength;
10852 bMax[n] = cCoord[n] + _halfCellLength;
10853 }
10854
10855 intersectsACell = boxSphereIntersection(bMin.data(), bMax.data(), center, radius);
10856 if(intersectsACell) {
10857 intersectingCellId = curId;
10858 break;
10859 }
10860 }
10861 return intersectingCellId;
10862}
MBool boxSphereIntersection(const MFloat *bMin, const MFloat *bMax, const MFloat *const sphereCenter, MFloat const radius)

◆ intersectingWithLocalBoundingBox()

template<MInt nDim>
MBool CartesianGrid< nDim >::intersectingWithLocalBoundingBox ( MFloat *const  center,
MFloat const  radius 
)

Definition at line 10865 of file cartesiangrid.cpp.

10865 {
10866 const MFloat* bMin = &m_localBoundingBox[0];
10867 const MFloat* bMax = &m_localBoundingBox[nDim];
10868
10869 MBool intersecting = boxSphereIntersection(bMin, bMax, center, radius);
10870 return intersecting;
10871}

◆ intersectingWithPartitioncells()

template<MInt nDim>
MInt CartesianGrid< nDim >::intersectingWithPartitioncells ( MFloat *const  center,
MFloat const  radius 
)

Definition at line 10805 of file cartesiangrid.cpp.

10805 {
10806 const MInt noLocalPartitionCells = m_localPartitionCellOffsets[1] - m_localPartitionCellOffsets[0];
10807 MFloat bMin[nDim];
10808 MFloat bMax[nDim];
10809
10810 MBool intersectsACell = false;
10811 MInt intersectingCellId = -1;
10812 for(MInt i = 0; i < noLocalPartitionCells; i++) {
10813 const MInt curId = m_localPartitionCellLocalIds[i];
10814 const MFloat _halfCellLength = halfCellLength(curId);
10815 const MFloat* cCoord = m_tree.coordinate(curId);
10816
10817 for(MInt n = 0; n < nDim; n++) {
10818 bMin[n] = cCoord[n] - _halfCellLength;
10819 bMax[n] = cCoord[n] + _halfCellLength;
10820 }
10821
10822 intersectsACell = boxSphereIntersection(bMin, bMax, center, radius);
10823
10824 if(intersectsACell) {
10825 intersectingCellId = curId;
10826 }
10827 }
10828 return intersectingCellId;
10829}

◆ isMpiRoot()

template<MInt nDim>
MBool CartesianGrid< nDim >::isMpiRoot ( ) const
inlineprivate

Definition at line 1067 of file cartesiangrid.h.

1067{ return domainId() == 0; }

◆ isSolverWindowCell()

template<MInt nDim>
MBool CartesianGrid< nDim >::isSolverWindowCell ( const MInt  domainId,
const MInt  cellId,
const MInt  solverId 
) const
inline

Definition at line 467 of file cartesiangrid.h.

467 {
468#ifndef NDEBUG
469 if(m_windowLayer_[domainId].find(cellId) != m_windowLayer_[domainId].end()
470 && m_windowLayer_[domainId].at(cellId).get(solverId) <= m_noSolverHaloLayers[solverId])
471 TERMM_IF_COND(!m_tree.solver(cellId, solverId), "");
472#endif
473 return m_windowLayer_[domainId].find(cellId) != m_windowLayer_[domainId].end()
474 && m_windowLayer_[domainId].at(cellId).get(solverId) <= m_noSolverHaloLayers[solverId];
475 }

◆ lengthLevel0()

template<MInt nDim>
MFloat CartesianGrid< nDim >::lengthLevel0 ( ) const
inline
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-03-10
Returns
Length of the cell at level 0.

Definition at line 426 of file cartesiangrid.h.

426{ return m_lengthLevel0; }

◆ loadDonorGridPartition()

template<MInt nDim>
void CartesianGrid< nDim >::loadDonorGridPartition ( const MLong *const  partitionCellsId,
const MInt  noPartitionCells 
)
private
Author
Michael Schlottke-Lakemper (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-07-07
Parameters
[in]gridPartitionFileNameName of grid partition file to use.
[in]partitionCellsIdPoint to list of partition cells ids.
[in]noPartitionCellsNumber of partition cells.
[out]offsetsResulting offsets.

This method is a drop-in replacement for maia::grid::partition(...). It is intended for coupled multi-solver simulations, where both solvers need to exchange volume data and thus corresponding partition cells and their subtrees must end up on the same MPI rank.

Definition at line 9794 of file cartesiangrid.cpp.

9794 {
9795 TRACE();
9796
9797 MLongScratchSpace partitionCellOffsets(noDomains() + 1, AT_, "partitionCellOffsets");
9798
9799 if(domainId() == 0) {
9800 MString gridPartitionFileName = m_outputDir + "partition.Netcdf";
9801 gridPartitionFileName = Context::getBasicProperty<MString>("gridPartitionFileName", AT_, &gridPartitionFileName);
9802
9803 // Open grid partition file and read out first cell ids for each domain
9804 using namespace maia::parallel_io;
9805 ParallelIo file(gridPartitionFileName, PIO_READ, MPI_COMM_SELF);
9806 const MInt noTargetDomains = file.getArraySize("firstCellIds");
9807 file.setOffset(noTargetDomains, 0);
9808 MIntScratchSpace firstCellIds(noTargetDomains, AT_, "firstCellIds");
9809 file.readArray(&firstCellIds[0], "firstCellIds");
9810
9811 // Sanity check: make sure that first cell ids are monotonically increasing
9812 MInt previous = -1;
9813 for(auto&& first : firstCellIds) {
9814 // Skip if first id is -1 as it means there are no cells on that domain
9815 if(first == -1) {
9816 continue;
9817 }
9818
9819 // Abort if cell id is less than previous one
9820 if(first < previous) {
9821 TERMM(1, "Cell ids not monotonically increasing: " + to_string(first) + " < " + to_string(previous)
9822 + ". Did you forget to set 'targetGridFileName' when "
9823 "generating the donor grid file?");
9824 }
9825
9826 // Store id for next iteration
9827 previous = first;
9828 }
9829
9830 // Determine partition cell offsets. For each domain, find the position of the first
9831 // cell id in the list of mincell ids. This position is the desired offset.
9832 // First, store pointers for convenience
9833 const MLong* first = partitionCellsId;
9834 const MLong* const last = first + noPartitionCells;
9835 MInt donorDomainId = 0;
9836 for(MInt d = 0; d < noTargetDomains; d++) {
9837 // Skip target domain if it does not receive donor cells
9838 const MInt firstCellId = firstCellIds[d];
9839 if(firstCellId == -1) {
9840 continue;
9841 }
9842
9843 // Search list of partition cells for first cell id and store pointer
9844 const auto bound = lower_bound(first, last, firstCellId);
9845 if(distance(bound, last) == 0) {
9846 // If value was not found, somewhere (here or in the generation of the
9847 // grid partition file) an error must have occurred
9848 TERMM(1, "partition cell not found, this should not happen. Go fix your code!");
9849 } else {
9850 // If value was found, store the distance between the beginning of the
9851 // array and the found value as the offset that is searched for
9852 partitionCellOffsets[donorDomainId] = distance(partitionCellsId, bound);
9853
9854 // Reduce search space for increased efficiency
9855 first = bound;
9856
9857 // Increment domain id
9858 donorDomainId++;
9859 }
9860 }
9861
9862 partitionCellOffsets[noDomains()] = noPartitionCells;
9863 m_log << "Cartesian grid loaded grid partition from " << gridPartitionFileName << endl;
9864
9865 m_domainOffsets[0] = 0;
9866 for(MInt i = 1; i < noDomains(); i++) {
9867 m_domainOffsets[i] = partitionCellsId[partitionCellOffsets[i]];
9868 }
9870
9871 // Sanity check: donorDomainId must be equal to number of domains after last
9872 // iteration
9873 if(donorDomainId != noDomains()) {
9874 TERMM(1, "mismatch between number of donor domains in partition file and "
9875 "actual number of "
9876 "donor domains");
9877 }
9878 }
9879 MPI_Bcast(partitionCellOffsets.data(), noDomains() + 1, MPI_LONG, 0, mpiComm(), AT_, "partitionCellOffsets.data()");
9880 MPI_Bcast(m_domainOffsets, noDomains() + 1, MPI_LONG, 0, mpiComm(), AT_, "m_domainOffsets");
9881 m_noPartitionCells = partitionCellOffsets[domainId() + 1] - partitionCellOffsets[domainId()];
9883 partitionCellOffsets[domainId()]; // begin of the local partitionCells in the gobal partitionCell array
9884 m_localPartitionCellOffsets[1] = partitionCellOffsets[domainId() + 1]; // end index of the gobal partitionCell array
9886 m_noPartitionCellsGlobal; // end of the local partitionCells in the gobal partitionCell array
9888}
MString m_outputDir

◆ loadGrid()

template<MInt nDim>
void CartesianGrid< nDim >::loadGrid ( const MString fileName)
private
Author
Jerry Grimmen
Date
06.2012

Definition at line 9116 of file cartesiangrid.cpp.

9116 {
9117 TRACE();
9118 maia::grid::IO<CartesianGrid<nDim>>::load(*this, fileName);
9119}

◆ loadGridFile()

template<MInt nDim>
void CartesianGrid< nDim >::loadGridFile ( const MInt  timerLoadGridPar,
const MInt  timerCreateMB 
)
private
Author
Lennart Schneiders
Date
October 2017

Definition at line 840 of file cartesiangrid.cpp.

840 {
841 TRACE();
842
843 // 1. read grid from disk
844 RECORD_TIMER_START(timerLoadGridPar);
846 RECORD_TIMER_STOP(timerLoadGridPar);
847
848 // ---
849 // At this point, parentIds, childIds, and nghbrIds are local ids with respect to the collector
850
851 // 2. create window and halo cells
852 if(noDomains() > 1 || m_noPeriodicCartesianDirs > 0) {
853 RECORD_TIMER_START(timerCreateMB);
854 // also calls storeMinLevelCells and computeLeafLevel!
856 RECORD_TIMER_STOP(timerCreateMB);
857 } else {
860 }
861
862#ifdef MAIA_GRID_SANITY_CHECKS
865#endif
866}
MString m_restartDir
void computeLeafLevel()
Compute distance to leaf level.
void loadGrid(const MString &fileName)
Load a grid file writen with saveGridDomainPar.

◆ loadPartitionFile()

template<MInt nDim>
void CartesianGrid< nDim >::loadPartitionFile ( const MString partitionFileName,
MLong partitionCellOffsets 
)

Definition at line 12794 of file cartesiangrid.cpp.

12794 {
12795 TRACE();
12796
12797 using namespace maia::parallel_io;
12798
12799 if(domainId() == 0) {
12800 // Open grid partition file
12801 ParallelIo file(partitionFileName, PIO_READ, MPI_COMM_SELF);
12802
12804 file.getAttribute(&noPartitionCells, "noPartitionCells");
12805 TERMM_IF_NOT_COND(noPartitionCells == m_noPartitionCellsGlobal, "global number of partition cell mismatch");
12806
12807 if(file.getArraySize("partitionCellOffset", 0) != noDomains()) {
12808 TERMM(1, "array size does not match number of domains");
12809 }
12810 file.setOffset(noDomains(), 0);
12811 file.readArray(partitionCellOffsets, "partitionCellOffset");
12812 }
12813
12814 // Distribute partition cells ids
12815 MPI_Bcast(&partitionCellOffsets[0], noDomains(), type_traits<MLong>::mpiType(), 0, mpiComm(), AT_,
12816 "partitionCellOffsets");
12817
12818 m_log << "Loaded partition from file '" << partitionFileName << "'." << endl;
12819}

◆ localPartitionCellLocalIds()

template<MInt nDim>
MInt CartesianGrid< nDim >::localPartitionCellLocalIds ( const MInt  id) const
inline

Definition at line 577 of file cartesiangrid.h.

◆ localPartitionCellOffsets()

template<MInt nDim>
MLong CartesianGrid< nDim >::localPartitionCellOffsets ( const MInt  index) const
inline

Definition at line 568 of file cartesiangrid.h.

◆ localToGlobalIds()

template<MInt nDim>
void CartesianGrid< nDim >::localToGlobalIds

Definition at line 9984 of file cartesiangrid.cpp.

9984 {
9985 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
9986 if(a_parentId(cellId) > -1) {
9987 a_parentId(cellId) = a_globalId(static_cast<MInt>(a_parentId(cellId)));
9988 }
9989
9990 for(MInt i = 0; i < m_noDirs; i++) {
9991 if(a_hasNeighbor(cellId, i)) {
9992 a_neighborId(cellId, i) = a_globalId(static_cast<MInt>(a_neighborId(cellId, i)));
9993 }
9994 }
9995
9996 for(MInt i = 0; i < IPOW2(nDim); i++) {
9997 if(a_childId(cellId, i) > -1) {
9998 a_childId(cellId, i) = a_globalId(static_cast<MInt>(a_childId(cellId, i)));
9999 }
10000 }
10001 }
10002}

◆ maxLevel()

template<MInt nDim>
MInt CartesianGrid< nDim >::maxLevel ( ) const
inline

Definition at line 789 of file cartesiangrid.h.

789{ return m_maxLevel; };

◆ maxNoCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::maxNoCells ( ) const
inline

Definition at line 797 of file cartesiangrid.h.

797{ return m_maxNoCells; };

◆ maxPartitionLevelShift()

template<MInt nDim>
MInt CartesianGrid< nDim >::maxPartitionLevelShift ( ) const
inline

Definition at line 793 of file cartesiangrid.h.

793{ return m_maxPartitionLevelShift; };

◆ maxRefinementLevel()

template<MInt nDim>
MInt CartesianGrid< nDim >::maxRefinementLevel ( ) const
inline

Definition at line 548 of file cartesiangrid.h.

548{ return m_maxRfnmntLvl; }

◆ maxUniformRefinementLevel()

template<MInt nDim>
MInt CartesianGrid< nDim >::maxUniformRefinementLevel ( ) const
inline

Definition at line 542 of file cartesiangrid.h.

◆ meshAdaptation()

template<MInt nDim>
void CartesianGrid< nDim >::meshAdaptation ( std::vector< std::vector< MFloat > > &  sensors,
std::vector< MFloat > &  sensorWeight,
std::vector< std::bitset< 64 > > &  sensorCellFlag,
std::vector< MInt > &  sensorSolverId,
const std::vector< std::function< void(const MInt)> > &  refineCellSolver,
const std::vector< std::function< void(const MInt)> > &  removeChildsSolver,
const std::vector< std::function< void(const MInt)> > &  removeCellSolver,
const std::vector< std::function< void(const MInt, const MInt)> > &  swapCellsSolver,
const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &  cellOutsideSolver,
const std::vector< std::function< void()> > &  resizeGridMapSolver 
)
private

Wrapper function to choose between two different adaptation modes based on m_lowMemAdaptation True: uses a new adaptation procedure in which information of partition level ancestors is exchanged serially for every neighbor domain. This avoids vast allocations of memory but is potentially slower False: uses the old adpatation procedure in which information of partition level ancestors in exchanged for all domains at once. This can require large amounts of memory for high numbers of neighbor domains

Definition at line 6216 of file cartesiangrid.cpp.

6223 {
6224 TRACE();
6225
6226 if(m_lowMemAdaptation) {
6227 this->meshAdaptationLowMem(sensors, sensorWeight, sensorCellFlag, sensorSolverId, refineCellSolver,
6228 removeChildsSolver, removeCellSolver, swapCellsSolver, cellOutsideSolver,
6229 resizeGridMapSolver);
6230 } else {
6231 this->meshAdaptationDefault(sensors, sensorWeight, sensorCellFlag, sensorSolverId, refineCellSolver,
6232 removeChildsSolver, removeCellSolver, swapCellsSolver, cellOutsideSolver,
6233 resizeGridMapSolver);
6234 }
6235}
void meshAdaptationDefault(std::vector< std::vector< MFloat > > &, std::vector< MFloat > &, std::vector< std::bitset< 64 > > &, std::vector< MInt > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt, const MInt)> > &, const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &, const std::vector< std::function< void()> > &)
Performs mesh adaptation and continuously updates the window/halo cells.
void meshAdaptationLowMem(std::vector< std::vector< MFloat > > &, std::vector< MFloat > &, std::vector< std::bitset< 64 > > &, std::vector< MInt > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt)> > &, const std::vector< std::function< void(const MInt, const MInt)> > &, const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &, const std::vector< std::function< void()> > &)
Performs mesh adaptation and continuously updates the window/halo cells.
MBool m_lowMemAdaptation

◆ meshAdaptationDefault()

template<MInt nDim>
void CartesianGrid< nDim >::meshAdaptationDefault ( std::vector< std::vector< MFloat > > &  sensors,
std::vector< MFloat > &  sensorWeight,
std::vector< std::bitset< 64 > > &  sensorCellFlag,
std::vector< MInt > &  sensorSolverId,
const std::vector< std::function< void(const MInt)> > &  refineCellSolver,
const std::vector< std::function< void(const MInt)> > &  removeChildsSolver,
const std::vector< std::function< void(const MInt)> > &  removeCellSolver,
const std::vector< std::function< void(const MInt, const MInt)> > &  swapCellsSolver,
const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &  cellOutsideSolver,
const std::vector< std::function< void()> > &  resizeGridMapSolver 
)
private
Author
Lennart Schneiders
Parameters
[in]sensorsHolds the mesh refinement sensor(s) for each cell
[in]sensorWeightWeighting of this sensor in relation to other sensors if greater than zero, otherwise indicating a true/false-type sensor
[in]sensorCellFlagIndicator whether a sensor was set for this particular cell
[out]oldCellIdMapping from new grid cells to their original cellId, or -1 if they did not exist previously
[out]oldNoCellsNumber of cells in the map

Definition at line 7316 of file cartesiangrid.cpp.

7323 {
7324 TRACE();
7325
7326 //----------------------------
7327 // 0. init
7328 const MInt noCells = treeb().size();
7331
7332 const MInt noSensors = (signed)sensorWeight.size();
7333 ASSERT(sensorWeight.size() == sensors.size(), "");
7334 ASSERT(sensorWeight.size() == sensorSolverId.size(), "");
7335 ScratchSpace<MFloat> sensorCnt(noSensors, 2, AT_, "sensorCnt");
7336 ScratchSpace<MFloat> sensorThresholds(noSensors, 2, AT_, "sensorThresholds");
7339 ASSERT(m_freeIndices.empty(), "");
7340 std::set<MInt>().swap(m_freeIndices);
7341 sensorCnt.fill(F0);
7342 for(MInt c = 0; c < maxNoCells; c++) {
7343 refineFlag[c].reset();
7344 coarseFlag[c].reset();
7345 }
7346 // these flags indicate which cells have changed for the subsequent reinitialization by the solvers
7347 for(MInt cellId = 0; cellId < noCells; cellId++) {
7348 a_hasProperty(cellId, Cell::IsToDelete) = false;
7349 a_hasProperty(cellId, Cell::WasNewlyCreated) = false;
7350 a_hasProperty(cellId, Cell::WasCoarsened) = false;
7351 a_hasProperty(cellId, Cell::WasRefined) = false;
7352
7353 // Reset the window cell flag,
7354 // is set for all preserved window cells when added to m_windowCells
7355 a_hasProperty(cellId, Cell::IsWindow) = false;
7356 }
7357
7358 //----------------------------
7359 // 1. exchange sensors and compute RMS values
7360 // TODO labels:GRID move these parts to the cartesian solver and do this sort of smoothing
7361 // on the solver grid in setSensors, after all sensors have been set there!!!!
7362 // the cartesiangrid should only get one refine/coarse flags for each cell from the solver!
7363 for(MInt cellId = 0; cellId < noCells; cellId++) {
7364 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
7365 if(a_isToDelete(cellId)) continue;
7366
7367 // Note: sensors for partition level ancestors might not be set correctly!
7368 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor)) {
7369 continue;
7370 }
7371
7372 for(MInt s = 0; s < noSensors; s++) {
7373 if(sensorCellFlag[cellId][s]) {
7374 ASSERT(sensorWeight[s] < F0 || std::fabs(sensors[s][cellId]) < MFloatMaxSqrt,
7375 "invalid sensor value: " + std::to_string(sensors[s][cellId]));
7376 sensorCnt(s, 0) += POW2(sensors[s][cellId]);
7377 sensorCnt(s, 1) += F1;
7378 }
7379 }
7380 }
7381
7382 if(noSensors > 0) {
7383 MPI_Allreduce(MPI_IN_PLACE, &sensorCnt(0), 2 * noSensors, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
7384 "sensorCnt(0)");
7385 }
7386
7387 // TODO labels:GRID,ADAPTATION introduce sensor type to replace this weight hack
7388 for(MInt s = 0; s < noSensors; s++) {
7389 if(sensorWeight[s] < F0) { // true/false sensor
7390 sensorThresholds(s, 0) = -1e-12;
7391 sensorThresholds(s, 1) = 1e-12;
7392 } else { // continuous sensor
7393 sensorThresholds(s, 1) = sensorWeight[s] * sqrt(mMax(1e-14, (sensorCnt(s, 0) / sensorCnt(s, 1))));
7394 sensorThresholds(s, 0) = m_coarseRatio * sensorThresholds(s, 1);
7395 }
7396 }
7397
7398 //---------------------------(1)
7399
7400 const MBool hasPartLvlShift = (m_maxPartitionLevelShift > 0);
7401 const MInt tmpScratchSize = (hasPartLvlShift) ? m_tree.size() : 1;
7402
7403 ScratchSpace<MBool> isHaloPartLvlAncestor(tmpScratchSize, AT_, "isHaloPartLvlAncestor");
7404 // TODO labels:GRID,ADAPTATION make this work using less memory, e.g., use one bit for each neighbor?
7405 ScratchSpace<MBool> isWindowPartLvlAncestor(tmpScratchSize, noNeighborDomains(), AT_, "isWindowPartLvlAncestor");
7406
7407 isHaloPartLvlAncestor.fill(false);
7408 isWindowPartLvlAncestor.fill(false);
7409
7410 // Determine relevant halo partition level ancestor window/halo cells that need to be preserved
7411 if(m_maxPartitionLevelShift > 0) {
7412 MInt totalNoWindowCells = 0;
7413 for(MInt d = 0; d < noNeighborDomains(); d++) {
7414 totalNoWindowCells += noWindowCells(d);
7415 }
7416 ScratchSpace<MBool> recvIsHaloPartLvlAncestor(std::max(totalNoWindowCells, 1), AT_, "recvIsHaloPartLvlAncestor");
7417
7418 for(auto& i : m_partitionLevelAncestorIds) {
7419 TERMM_IF_NOT_COND(a_hasProperty(i, Cell::IsPartLvlAncestor),
7420 "cell is not a partition level ancestor: " + std::to_string(i));
7421 // Mark halo partition level ancestors (which are part of the missing subtree of the grid)
7422 if(a_hasProperty(i, Cell::IsHalo)) {
7423 isHaloPartLvlAncestor[i] = true;
7424 }
7425 // Mark all halo childs of partition level ancestors (required for exchange of e.g. global
7426 // ids!)
7427 for(MInt child = 0; child < m_maxNoChilds; child++) {
7428 const MInt childId = a_childId(i, child);
7429 if(childId > -1 && a_isHalo(childId)) {
7430 isHaloPartLvlAncestor[childId] = true;
7431 }
7432 }
7433 }
7434
7435 // Reverse exchange markers from halo cells to corresponding window cells
7436 if(noNeighborDomains() > 0) {
7437#ifndef PVPLUGIN
7439 &recvIsHaloPartLvlAncestor[0]);
7440#else
7441 TERMM(1, "not working for compilation of paraview plugin");
7442#endif
7443 }
7444
7445 MInt cnt = 0;
7446 for(MInt d = 0; d < noNeighborDomains(); d++) {
7447 for(MInt j = 0; j < noWindowCells(d); j++) {
7448 const MInt cellId = windowCell(d, j);
7449 // Store marker for window cell separately for each neighbor domain!
7450 isWindowPartLvlAncestor(cellId, d) = recvIsHaloPartLvlAncestor[cnt];
7451 cnt++;
7452 }
7453 }
7454 }
7455
7456 //----------------------------
7457 // 2. tag cells for coarsening / refinement
7458
7459 // init parent cells with coarse flag true and set false if any child intervenes
7460 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
7461 ASSERT(!a_hasProperty(cellId, Cell::IsHalo), "");
7462 ASSERT(!a_isToDelete(cellId), "");
7463 if(a_level(cellId) > m_maxUniformRefinementLevel) {
7464 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7465 if(!m_tree.solver(cellId, solver)) continue;
7466 if(a_hasChildren(cellId, solver)) continue;
7467
7468 const MInt parentId = a_parentId(cellId, solver);
7469 ASSERT(parentId > -1, "");
7470 // Partition level shift, parent is a halo cell and cannot be coarsened
7471 if(a_isHalo(parentId) || a_hasProperty(parentId, Cell::IsPartLvlAncestor)) continue;
7472
7473 for(MInt s = 0; s < noSensors; s++) {
7474 if(sensorSolverId[s] != solver) continue;
7475 if(sensorCellFlag[cellId][s] || sensorCellFlag[parentId][s]) {
7476 // only coarsen cells if they are above the newMinLevel!
7477 if(a_level(cellId) > m_newMinLevel && m_allowCoarsening) {
7478 coarseFlag[a_parentId(cellId)][solver] = true;
7479 }
7480 }
7481 }
7482 }
7483 }
7484 }
7485
7486 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
7487 ASSERT(!a_hasProperty(cellId, Cell::IsHalo), "");
7488 ASSERT(!a_isToDelete(cellId), "");
7489 const MInt level = a_level(cellId);
7490 //---
7491 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7492 if(!m_tree.solver(cellId, solver)) continue;
7493 if(a_hasChildren(cellId, solver)) continue;
7494 const MInt parentId = a_parentId(cellId, solver);
7495 // Partition level shift, if parent is a halo it cannot be coarsened and e.g.
7496 // sensors/coarseFlag[parentId] should not be accessed!
7497 const MBool partLvlAncestorParent = (parentId > -1) ? a_hasProperty(parentId, Cell::IsPartLvlAncestor) : false;
7498
7499 // cell should be marked for refinement
7500 MBool refine = false;
7501 // cell should be marked for coarsened
7502 MBool coarsen = true;
7503 // cell should be marked for refinement regardless
7504 // whether a different sensor marks this cell for coarsening
7505 MBool forceRefine = false;
7506 for(MInt s = 0; s < noSensors; s++) {
7507 if(sensorSolverId[s] != solver) continue;
7508 if(sensorCellFlag[cellId][s]) {
7509 coarsen = coarsen && (sensors[s][cellId] < sensorThresholds(s, 0));
7510 }
7511 if(level > m_maxUniformRefinementLevel && !partLvlAncestorParent && sensorCellFlag[parentId][s]) {
7512 coarsen = coarsen && (sensors[s][parentId] < sensorThresholds(s, 0));
7513 }
7514 // this sensor would refine the cell
7515 const MBool refineSensor = sensors[s][cellId] > sensorThresholds(s, 1) && sensorCellFlag[cellId][s];
7516 refine = refine || refineSensor;
7517
7518 // a true/false sensor marks the cell for refinement
7519 if(refineSensor && sensorWeight[s] < F0) {
7520 forceRefine = true;
7521 }
7522 }
7523 if(level < m_maxRfnmntLvl) {
7524 refineFlag[cellId][solver] = refine;
7525 }
7526
7527 if(level > m_maxUniformRefinementLevel && !partLvlAncestorParent) {
7528 coarseFlag[parentId][solver] = coarseFlag[parentId][solver] && coarsen;
7529 }
7530 // force a refinement of a cell:
7531 // for all minLevel cells which should be raised to the newMinLevel
7532 // for the cells forced by any true/false sensor!
7533 if((forceRefine && level < m_maxRfnmntLvl) || a_level(cellId) < m_newMinLevel) {
7534 refineFlag[cellId][solver] = true;
7535 coarseFlag[cellId][solver] = false;
7536 if(level > m_maxUniformRefinementLevel) {
7537 coarseFlag[parentId][solver] = false;
7538 }
7539 }
7540 }
7541 }
7542
7543 // 3. Exchange since consistency checks need neighbor values
7544 if(noNeighborDomains() > 0) {
7546 m_tree.size());
7548 m_tree.size());
7549 }
7550
7551 //----------------------------
7552 // 4. consistency check for internal cells
7553 if(m_checkRefinementHoles != nullptr) {
7554 // necessary for solution adaptive refinement (i.e. at shocks)
7555 const MInt adaptationHoleLimit = nDim;
7556 MBool gridUpdated = true;
7557
7558 MInt loopCount = 0;
7559 while(gridUpdated && loopCount < 25) {
7560 MInt noChanges = 0;
7561 loopCount++;
7562 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7563 if(!m_checkRefinementHoles[solver]) continue;
7564 for(MInt cellId = 0; cellId < noCells; cellId++) {
7565 if(a_isToDelete(cellId)) continue;
7566 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
7567 if(!m_tree.solver(cellId, solver)) continue;
7568 if(a_hasChildren(cellId, solver)) continue;
7569
7570 // check, if current cell is a hole in the refinement => refine cell aswell
7571 if(!refineFlag[cellId][solver]
7572 || (a_parentId(cellId, solver) > -1 && coarseFlag[a_parentId(cellId, solver)][solver])) {
7573 MInt checkRefinedNeighbors = 0;
7574 MInt currentHoleLimit = adaptationHoleLimit;
7575 for(MInt dir = 0; dir < m_noDirs; dir++) {
7576 if(a_hasNeighbor(cellId, dir, solver) > 0) {
7577 const MInt nghbrId = a_neighborId(cellId, dir, solver);
7578 if(refineFlag[nghbrId][solver] || a_hasChildren(nghbrId, solver)) {
7579 checkRefinedNeighbors += 1;
7580 }
7581 } else {
7582 // Lower limit at boundaries
7583 currentHoleLimit--;
7584 }
7585 }
7586 if(checkRefinedNeighbors > adaptationHoleLimit) {
7587 refineFlag[cellId][solver] = true;
7588 coarseFlag[cellId][solver] = false;
7589 const MInt parentId = a_parentId(cellId, solver);
7590 if(parentId > -1) coarseFlag[parentId][solver] = false;
7591 noChanges += 1;
7592 }
7593 }
7594
7595 // check, if current cell coarsening would create a hole in the refinement => do not coarsen cell
7596 const MInt parentId = a_parentId(cellId, solver);
7597 if(parentId < 0) continue;
7598 if(coarseFlag[parentId][solver]) {
7599 ASSERT(!a_isHalo(parentId) && !a_hasProperty(parentId, Cell::IsPartLvlAncestor),
7600 "Partition level ancestor parent cell has coarseFlag set.");
7601 MInt checkRefinedNeighbors = 0;
7602 MInt currentHoleLimit = adaptationHoleLimit;
7603 for(MInt dir = 0; dir < m_noDirs; dir++) {
7604 if(a_hasNeighbor(parentId, dir, solver) > 0) {
7605 const MInt parNghbrId = a_neighborId(parentId, dir, solver);
7606 if(!coarseFlag[parNghbrId][solver]
7607 && (refineFlag[parNghbrId][solver] || a_hasChildren(parNghbrId, solver))) {
7608 checkRefinedNeighbors += 1;
7609 }
7610 } else {
7611 // Lower limit at boundaries
7612 currentHoleLimit--;
7613 }
7614 }
7615 if(checkRefinedNeighbors > adaptationHoleLimit) {
7616 coarseFlag[parentId][solver] = false;
7617 noChanges += 1;
7618 }
7619 }
7620
7621 // Check if the coarsening of neighboring cells would create a refined cell island => coarsen cell aswell
7622 if(!coarseFlag[parentId][solver]) {
7623 ASSERT(!a_isHalo(parentId) && !a_hasProperty(parentId, Cell::IsPartLvlAncestor),
7624 "Partition level ancestor parent cell has coarseFlag set.");
7625 MInt checkCoarseNeighbors = 0;
7626 MInt currentHoleLimit = adaptationHoleLimit;
7627 for(MInt dir = 0; dir < m_noDirs; dir++) {
7628 if(a_hasNeighbor(parentId, dir, solver) > 0) {
7629 const MInt parNghbrId = a_neighborId(parentId, dir, solver);
7630 if(coarseFlag[parNghbrId][solver]
7631 || (!refineFlag[parNghbrId][solver] && !a_hasChildren(parNghbrId, solver))) {
7632 checkCoarseNeighbors += 1;
7633 }
7634 } else {
7635 // Lower limit at boundaries
7636 currentHoleLimit--;
7637 }
7638 }
7639 if(checkCoarseNeighbors > currentHoleLimit) {
7640 coarseFlag[parentId][solver] = true;
7641 noChanges += 1;
7642 }
7643 }
7644
7645 // check if the current cell refinement creates a refined cell island => do not refine cell
7646 if(refineFlag[cellId][solver]) {
7647 MInt checkRefinedNeighbors = 0;
7648 for(MInt dir = 0; dir < m_noDirs; dir++) {
7649 if(a_hasNeighbor(cellId, dir, solver) > 0) {
7650 const MInt nghbrId = a_neighborId(cellId, dir, solver);
7651 if(refineFlag[nghbrId][solver] || a_hasChildren(nghbrId, solver)) {
7652 checkRefinedNeighbors += 1;
7653 }
7654 }
7655 }
7656 if(checkRefinedNeighbors == 0) {
7657 refineFlag[cellId][solver] = false;
7658 noChanges += 1;
7659 }
7660 }
7661 }
7662 }
7663 if(noChanges == 0) {
7664 gridUpdated = false;
7665 }
7666 }
7667 }
7668
7669 // smooth diagonal level jumps,
7670 // even if already existing in the base grid!
7671 if(m_diagSmoothing != nullptr) {
7672 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7673 if(!m_diagSmoothing[solver]) continue;
7674 for(MInt lvl = maxLevel - 1; lvl >= minLevel(); lvl--) {
7675 for(MInt cellId = 0; cellId < noCells; cellId++) {
7676 if(a_level(cellId) != lvl) continue;
7677 if(!a_isLeafCell(cellId)) continue;
7678 if(!m_tree.solver(cellId, solver)) continue;
7679 if(refineFlag[cellId][solver]) continue;
7680 for(MInt i = 0; i < m_noDirs; i++) {
7681 const MInt nghbrId = a_neighborId(cellId, i, solver);
7682 if(nghbrId < 0) continue;
7683 if(a_isLeafCell(nghbrId)) continue;
7684 for(MInt child = 0; child < m_maxNoChilds; child++) {
7685 MInt childId = a_childId(nghbrId, child, solver);
7686 if(childId < 0) continue;
7687 if(!a_isLeafCell(childId)) {
7688 refineFlag[cellId][solver] = true;
7689 coarseFlag[cellId][solver] = false;
7690 MInt parentId = a_parentId(cellId, solver);
7691 if(parentId > -1) {
7692 coarseFlag[cellId][solver] = false;
7693 }
7694 break;
7695 }
7696 }
7697 for(MInt j = 0; j < m_noDirs; j++) {
7698 if(j / 2 == i / 2) continue;
7699 const MInt diagNghbrId = a_neighborId(nghbrId, j, solver);
7700 if(diagNghbrId < 0) continue;
7701 if(a_isLeafCell(diagNghbrId)) continue;
7702 for(MInt child = 0; child < m_maxNoChilds; child++) {
7703 MInt childId = a_childId(diagNghbrId, child, solver);
7704 if(childId < 0) continue;
7705 if(!a_isLeafCell(childId)) {
7706 refineFlag[cellId][solver] = true;
7707 coarseFlag[cellId][solver] = false;
7708 MInt parentId = a_parentId(cellId, solver);
7709 if(parentId > -1) {
7710 coarseFlag[cellId][solver] = false;
7711 }
7712 break;
7713 }
7714 }
7715 }
7716 }
7717 }
7718 }
7719 }
7720 }
7721
7722 // Additional consistency checks fixing contradictory flags
7723 for(MInt cellId = 0; cellId < noCells; cellId++) {
7724 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
7725 if(a_isToDelete(cellId)) continue;
7726
7727 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7728 if(!m_tree.solver(cellId, solver)) continue;
7729 if(a_hasChildren(cellId, solver)) continue;
7730 const MInt parentId = a_parentId(cellId, solver);
7731 if(refineFlag[cellId][solver] && coarseFlag[cellId][solver]) {
7732 refineFlag[cellId][solver] = false;
7733 coarseFlag[cellId][solver] = false;
7734 }
7735
7736 // TODO labels:GRID,ADAPTATION,totest check for multisolver!!!!!
7737 if(refineFlag[cellId][solver]) {
7738 if(parentId > -1) {
7739 if(coarseFlag[parentId][solver]) {
7740 ASSERT(!a_isHalo(parentId) && !a_hasProperty(parentId, Cell::IsPartLvlAncestor),
7741 "Partition level ancestor parent cell has coarseFlag set.");
7742 coarseFlag[parentId][solver] = false;
7743 for(MInt child = 0; child < m_maxNoChilds; child++) {
7744 MInt childId = a_childId(parentId, child, solver);
7745 if(childId > -1) {
7746 refineFlag[childId][solver] = false;
7747 }
7748 }
7749 }
7750 }
7751 }
7752 }
7753 }
7754 //---------------------------(4)
7755
7756 // ensure the same refinement between two different solvers in the combined/overlapping region!
7757 if(m_noIdenticalSolvers > 0) {
7758 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
7759 for(MInt pair = 0; pair < m_noIdenticalSolvers; pair++) {
7760 const MInt slaveId = m_identicalSolvers[pair * 2];
7761 const MInt masterId = m_identicalSolvers[pair * 2 + 1];
7762 if(treeb().solver(cellId, slaveId) && treeb().solver(cellId, masterId)) {
7763 if(!coarseFlag[cellId][masterId]) {
7764 coarseFlag[cellId][slaveId] = coarseFlag[cellId][masterId];
7765 }
7766 if(m_identicalSolverLvlJumps[pair] == 0) {
7767 refineFlag[cellId][slaveId] = refineFlag[cellId][masterId];
7768 } else if(m_identicalSolverLvlJumps[pair] == 1) {
7769 if(a_level(cellId) < m_identicalSolverMaxLvl[pair] && a_hasChildren(cellId, masterId)) {
7770 if(!a_hasChildren(cellId, slaveId)) {
7771 refineFlag[cellId][slaveId] = true;
7772 }
7773 coarseFlag[cellId][slaveId] = false;
7774 }
7775 } else {
7776 if(a_level(cellId) < m_identicalSolverMaxLvl[pair] && a_hasChildren(cellId, masterId)
7777 && a_childId(cellId, 0) > -1 && treeb().solver(a_childId(cellId, 0), masterId)
7778 && a_hasChildren(a_childId(cellId, 0), masterId)) {
7779 if(!a_hasChildren(cellId, slaveId)) {
7780 refineFlag[cellId][slaveId] = true;
7781 }
7782 coarseFlag[cellId][slaveId] = false;
7783 }
7784 }
7785 }
7786 }
7787 }
7788 }
7789
7790
7791 //----------------------------
7792 // 5. Coarsening step: loop from maxLevel to minLevel and exchange coarseFlags to retrieve
7793 // consistent refinement at domain interfaces; update window/halo collectors
7794 for(MInt level = m_maxRfnmntLvl - 1; level >= m_maxUniformRefinementLevel; level--) {
7795 for(MInt cellId = 0; cellId < noCells; cellId++) {
7796 if(a_level(cellId) != level) continue;
7797 if(a_isToDelete(cellId)) continue;
7798 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
7799
7800 // TODO labels:GRID,ADAPTATION,totest check for multisolver setting.. neighborIds solver aware!!
7801 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7802 if(!m_tree.solver(cellId, solver)) continue;
7803 if(!a_hasChildren(cellId, solver)) continue;
7804
7805 // Partition level ancestor cell cannot be coarsened (exept if its a partition cell)
7806 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor) && !a_hasProperty(cellId, Cell::IsPartitionCell)) {
7807 coarseFlag[cellId][solver] = false;
7808 }
7809
7810 if(coarseFlag[cellId][solver]) {
7811 if(!coarsenCheck(cellId, solver)) {
7812 coarseFlag[cellId][solver] = false;
7813 }
7814 }
7815 }
7816 }
7817
7818 if(noNeighborDomains() > 0) {
7819 // exchangeSolverBitset(coarseFlag.data());
7821 m_tree.size());
7822 }
7823
7824 for(MInt cellId = 0; cellId < noCells; cellId++) {
7825 if(a_level(cellId) != level) continue;
7826 if(a_isToDelete(cellId)) continue;
7827 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
7828
7829 // TODO labels:GRID,ADAPTATION,totest check for multisolver setting.. neighborIds solver aware!!
7830 if(level < m_maxRfnmntLvl - 1) {
7831 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7832 if(!m_tree.solver(cellId, solver)) continue;
7833 if(a_hasChildren(cellId, solver)) continue;
7834 if(!refineFlag[cellId][solver] && !coarseFlag[cellId][solver]) {
7835 for(MInt dir = 0; dir < m_noDirs; dir++) {
7836 if(a_hasNeighbor(cellId, dir, solver) > 0) {
7837 MInt nghbrId = a_neighborId(cellId, dir, solver);
7838 if(m_azimuthalPer && a_hasProperty(nghbrId, Cell::IsPeriodic)) continue;
7839 if(a_hasChildren(nghbrId, solver) > 0) {
7840 for(MInt child = 0; child < m_maxNoChilds; child++) {
7841 if(!childCode[dir][child]) continue;
7842 MInt childId = a_childId(nghbrId, child, solver);
7843 if(childId < 0) continue;
7844 if(refineFlag[childId][solver]) {
7845 refineFlag[cellId][solver] = true;
7846 }
7847 }
7848 }
7849 }
7850 }
7851 }
7852 }
7853 }
7854 }
7855
7856 if(noNeighborDomains() > 0) {
7857 // exchangeSolverBitset(refineFlag.data());
7859 m_tree.size());
7860 }
7861
7862 for(MInt cellId = 0; cellId < noCells; cellId++) {
7863 if(a_level(cellId) != level) continue;
7864 if(a_isToDelete(cellId)) continue;
7865 if(m_azimuthalPer && a_hasProperty(cellId, Cell::IsPeriodic)) continue;
7866
7867 // Partition level ancestor cell cannot be coarsened (exept if its a partition cell)
7868 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor) && !a_hasProperty(cellId, Cell::IsPartitionCell)) {
7869 continue;
7870 }
7871
7872 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7873 if(!m_tree.solver(cellId, solver)) continue;
7874 if(coarseFlag[cellId][solver]) {
7875 for(MInt child = 0; child < m_maxNoChilds; child++) {
7876 MInt childId = a_childId(cellId, child, solver);
7877 if(childId > -1) {
7878 coarseFlag[childId][solver] = false;
7879 refineFlag[childId][solver] = false;
7880 }
7881 }
7882 if(a_hasChildren(cellId, solver)) {
7883 removeChildsSolver[solver](cellId);
7884 // call removeChilds() function in each solver before child links are deleted
7885 refineFlag[cellId][solver] = false;
7886 for(MInt child = 0; child < m_maxNoChilds; child++) {
7887 MInt childId = a_childId(cellId, child);
7888 if(childId > -1) {
7889 treeb().solver(childId, solver) = false;
7890 }
7891 }
7892 }
7893 }
7894 }
7895 // check if the child can also be removed from the cartesian/combined grid
7896 // if the child is no-longer in any of the solvers, the grid child will be removed!
7897 if(a_noChildren(cellId) > 0) {
7898 MBool rmChilds = true;
7899 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7900 if(a_hasChildren(cellId, solver)) {
7901 rmChilds = false;
7902 }
7903 }
7904 if(rmChilds) {
7905 removeChilds(cellId);
7906 }
7907 }
7908 }
7909
7910 for(MInt i = 0; i < noNeighborDomains(); i++) {
7911 std::set<MInt> deleted;
7912 // WH_old
7913 if(m_haloMode > 0) {
7914 for(auto it_ = m_windowLayer_[i].begin(); it_ != m_windowLayer_[i].end();) {
7915 if(a_isToDelete(it_->first)) {
7916 it_ = m_windowLayer_[i].erase(it_);
7917 } else {
7918 // We might have deleted a cell from a solver
7919 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7920 if(it_->second.get(solver) < WINDOWLAYER_MAX /*<=m_noSolverHaloLayers[solver]*/
7921 && !m_tree.solver(it_->first, solver))
7922 it_->second.set(solver, WINDOWLAYER_MAX);
7923 if(it_->second.get(solver) > m_noSolverHaloLayers[solver]) it_->second.set(solver, WINDOWLAYER_MAX);
7924 }
7925 if(it_->second.all()) {
7926 deleted.insert(it_->first);
7927 it_ = m_windowLayer_[i].erase(it_);
7928 } else
7929 ++it_;
7930 }
7931 }
7932 }
7933
7934 // 1. coarsen window cells
7935 vector<MInt> oldWindowVec(m_windowCells[i]);
7936#ifndef NDEBUG
7937 std::set<MInt> windCellSet;
7938 std::set<MInt> haloCellSet;
7939#endif
7940
7941 std::vector<MInt>().swap(m_windowCells[i]);
7942 auto it = oldWindowVec.begin();
7943 for(it = oldWindowVec.begin(); it < oldWindowVec.end(); it++) {
7944 const MInt cellId = *it;
7945 if(!a_isToDelete(cellId) && (deleted.find(cellId) == deleted.end() || m_haloMode == 0)) { // WH_old
7946 ASSERT(cellId < treeb().size(), "");
7947
7948#ifndef NDEBUG
7949 // TODO labels:GRID,ADAPTATION fix duplicate window cells in periodic cases!
7950 ASSERT(m_noPeriodicCartesianDirs > 0 || windCellSet.find(cellId) == windCellSet.end(),
7951 "duplicate window cell: " + std::to_string(cellId));
7952 windCellSet.insert(cellId);
7953#endif
7954
7955 m_windowCells[i].push_back(cellId);
7956 }
7957 }
7958 oldWindowVec.clear();
7959
7960 // 2. coarsen halo cells
7961 vector<MInt> oldHaloVec(m_haloCells[i]);
7962 std::vector<MInt>().swap(m_haloCells[i]);
7963 for(it = oldHaloVec.begin(); it < oldHaloVec.end(); it++) {
7964 const MInt cellId = *it;
7965 if(!a_isToDelete(cellId)) {
7966 ASSERT(cellId < treeb().size(), "");
7967
7968#ifndef NDEBUG
7969 ASSERT(haloCellSet.find(cellId) == haloCellSet.end(), "duplicate halo cell: " + std::to_string(cellId));
7970 haloCellSet.insert(cellId);
7971#endif
7972
7973 if(m_tree.solverBits(cellId).any() || m_haloMode == 0) m_haloCells[i].push_back(cellId);
7974 }
7975 }
7976 oldHaloVec.clear();
7977 }
7978 }
7979 //---------------------------(5)
7980
7981
7982 //----------------------------
7983 // 6. Remove all halo cells, for levels > maxUniformRefinementLevel
7984 // since the number of halo layers is inconsistent at this point
7985 // Note: preserve halo partition level ancestors of the missing grid subtree in case of a
7986 // partition level shift
7987
7988 {
7989 for(MInt level = maxLevel - 1; level >= m_maxUniformRefinementLevel; level--) {
7990 for(MInt cellId = 0; cellId < noCells; cellId++) {
7991 if(a_isToDelete(cellId)) continue;
7992 if(!a_hasProperty(cellId, Cell::IsHalo)) continue;
7993 if(a_level(cellId) == level) {
7994 if(a_noChildren(cellId) > 0) {
7995 // Preserve partition level ancestor halos (and their childs) if they are part of the
7996 // missing subtree of the grid in case of a partition level shift
7997 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor) && !a_hasProperty(cellId, Cell::IsPartitionCell)) {
7998 if(std::find(m_partitionLevelAncestorIds.begin(), m_partitionLevelAncestorIds.end(), cellId)
7999 != m_partitionLevelAncestorIds.end()) {
8000 continue;
8001 }
8002 }
8003
8004 for(MInt child = 0; child < m_maxNoChilds; child++) {
8005 MInt childId = a_childId(cellId, child);
8006 if(childId < 0) continue;
8007 refineFlag[childId].reset();
8008 coarseFlag[childId].reset();
8009 }
8010 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
8011 if(!m_tree.solver(cellId, solver)) continue;
8012 if(a_hasChildren(cellId, solver)) {
8013 removeChildsSolver[solver](cellId);
8014 }
8015 }
8016 removeChilds(cellId);
8017 coarseFlag[cellId].reset();
8018 refineFlag[cellId].reset();
8019 }
8020 }
8021 }
8022 }
8023 for(MInt i = 0; i < noNeighborDomains(); i++) {
8024 vector<MInt> oldWindowVec(m_windowCells[i]);
8025 std::vector<MInt>().swap(m_windowCells[i]);
8026 auto it = oldWindowVec.begin();
8027 for(it = oldWindowVec.begin(); it < oldWindowVec.end(); it++) {
8028 const MInt cellId = *it;
8029
8030 // Add partition level ancestor window cells if required
8031 const MBool addWindow = (hasPartLvlShift) ? isWindowPartLvlAncestor(cellId, i) : false;
8032
8033 if((a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) || addWindow) {
8034 m_windowCells[i].push_back(cellId);
8035 // Set window cell flag for preserved window cells
8036 a_hasProperty(cellId, Cell::IsWindow) = true;
8037 }
8038 }
8039 oldWindowVec.clear();
8040
8041 // WH_old
8042 if(m_haloMode > 0) {
8043 for(auto it_ = m_windowLayer_[i].begin(); it_ != m_windowLayer_[i].end();) {
8044 const MInt cellId = it_->first;
8045
8046 // Add partition level ancestor window cells if required
8047 const MBool addWindow = (hasPartLvlShift) ? isWindowPartLvlAncestor(cellId, i) : false;
8048
8049 if((a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) || addWindow)
8050 ++it_;
8051 else
8052 it_ = m_windowLayer_[i].erase(it_);
8053 }
8054 }
8055
8056 vector<MInt> oldHaloVec(m_haloCells[i]);
8057 std::vector<MInt>().swap(m_haloCells[i]);
8058 for(it = oldHaloVec.begin(); it < oldHaloVec.end(); it++) {
8059 const MInt cellId = *it;
8060
8061 // Add partition level ancestor halo cells if required
8062 const MBool addHalo = (hasPartLvlShift) ? isHaloPartLvlAncestor[cellId] : false;
8063
8064 if((a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) || addHalo) {
8065 ASSERT(cellId > -1 && cellId < treeb().size(), to_string(cellId) + " " + to_string(treeb().size()));
8066 m_haloCells[i].push_back(cellId);
8067 }
8068 }
8069 oldHaloVec.clear();
8070 }
8071
8072 if(m_azimuthalPer) {
8073 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
8074 vector<MInt> oldAzimuthalWindowVec(m_azimuthalWindowCells[i]);
8075
8076 m_azimuthalWindowCells[i].clear();
8077 auto it = oldAzimuthalWindowVec.begin();
8078 for(MInt j = 0; j < (signed)oldAzimuthalWindowVec.size(); j++) {
8079 // Remove higher level azimuthal window cells from collector
8080 // If an azimuthal halo cell on a higher level is mapped to an
8081 // azimuthal window cell on a lower level. This azimuthal window cell
8082 // musst also be removed from the collector
8083 const MInt cellId = oldAzimuthalWindowVec[j];
8084 MBool keepWindow = true;
8087 keepWindow = false;
8088 }
8089 if(a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel && keepWindow) {
8090 m_azimuthalWindowCells[i].push_back(cellId);
8091 a_hasProperty(cellId, Cell::IsWindow) = true;
8092 }
8093 }
8094 oldAzimuthalWindowVec.clear();
8095
8096 vector<MInt> oldAzimuthalHaloVec(m_azimuthalHaloCells[i]);
8097 m_azimuthalHaloCells[i].clear();
8098 for(it = oldAzimuthalHaloVec.begin(); it < oldAzimuthalHaloVec.end(); it++) {
8099 const MInt cellId = *it;
8100 if(a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) {
8101 ASSERT(cellId > -1 && cellId < treeb().size(), "");
8102 m_azimuthalHaloCells[i].push_back(cellId);
8103 }
8104 }
8105 oldAzimuthalHaloVec.clear();
8106 }
8107
8108 // Remove higher level unmapped azimuthal halo cells
8109 vector<MInt> oldUnmappedHaloVec(m_azimuthalUnmappedHaloCells);
8110 vector<MInt> oldUnmappedHaloDomVec(m_azimuthalUnmappedHaloDomains);
8113 for(MUint i = 0; i < oldUnmappedHaloVec.size(); i++) {
8114 MInt cellId = oldUnmappedHaloVec[i];
8115 if(a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) {
8116 ASSERT(cellId > -1 && cellId < treeb().size(), "");
8117 m_azimuthalUnmappedHaloCells.push_back(cellId);
8118 m_azimuthalUnmappedHaloDomains.push_back(oldUnmappedHaloDomVec[i]);
8119 }
8120 }
8121 oldUnmappedHaloVec.clear();
8122 oldUnmappedHaloDomVec.clear();
8123
8124 // Update gridBndryCells
8125 vector<MInt> oldGridBndryVec(m_gridBndryCells);
8126 m_gridBndryCells.clear();
8127 for(MUint i = 0; i < oldGridBndryVec.size(); i++) {
8128 MInt cellId = oldGridBndryVec[i];
8129 if(a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) {
8130 m_gridBndryCells.push_back(cellId);
8131 }
8132 }
8133 oldGridBndryVec.clear();
8134 }
8135 }
8136
8137 //---------------------------(6)
8138 //----------------------------
8139 // 7. Refinement step: loop from minLevel to maxLevel and exchange refineFlags to retrieve
8140 // a consistent refinement at domain interfaces; update window/halo connectivity at each level
8141 for(MInt level = m_maxUniformRefinementLevel; level < maxLevel; level++) {
8142 for(MInt cellId = 0; cellId < noCells; cellId++) {
8143 if(a_level(cellId) != level) continue;
8144 if(a_isToDelete(cellId)) continue;
8145 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
8146
8147 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
8148 if(!m_tree.solver(cellId, solver)) continue;
8149 if(a_hasChildren(cellId, solver)) continue;
8150 if(refineFlag[cellId][solver]) {
8151 if(!refineCheck(cellId, solver, cellOutsideSolver)) {
8152 refineFlag[cellId][solver] = 0;
8153 }
8154 }
8155 }
8156
8157 if(refineFlag[cellId].any()) {
8158 refineCell(cellId, nullptr, false, cellOutsideSolver, refineFlag[cellId]);
8159
8160 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
8161 if(!a_hasChildren(cellId, solver) && false) { // sohel false
8162 // this is somehow destroying multisolver cases
8163 // if one solver already has a cell the other solver doesnt get it even if it needs it..
8164 // i think the solver flag is not set correctly in the refineCell function of cartesiangrid
8165 refineFlag[cellId][solver] = false;
8166 }
8167 if(refineFlag[cellId][solver]) {
8168 // Set solver flag for child cells
8169 setChildSolverFlag(cellId, solver, cellOutsideSolver[solver]);
8170 refineCellSolver[solver](cellId); // call refineCell() function in each solver
8171 }
8172 }
8173 for(MInt child = 0; child < m_maxNoChilds; child++) {
8174 MInt childId = a_childId(cellId, child);
8175 if(childId > -1 && a_hasProperty(childId, Cell::WasNewlyCreated)) {
8176 // Timw: only reset the child-flags if the cell was neawly created
8177 // otherwise this stops a refinement of the childs of a different solver!
8178 coarseFlag[childId].reset();
8179 refineFlag[childId].reset();
8180 }
8181 }
8182 }
8183 }
8184
8185 setLevel();
8186
8188
8189 // WH_old
8190 if(m_haloMode > 0)
8191 // noOffspring required in createHigherLevelExchangeCells
8193
8194 // Update child ids of partition level ancestors (stored as global ids)
8196 const MInt noPartLvlAncestorIds = m_partitionLevelAncestorIds.size();
8197 for(MInt i = 0; i < noPartLvlAncestorIds; i++) {
8199
8200 for(MInt child = 0; child < m_maxNoChilds; child++) {
8201 const MInt childId = a_childId(cellId, child);
8202 const MLong childGlobalId = (childId > -1) ? a_globalId(childId) : -1;
8203 m_partitionLevelAncestorChildIds.push_back(childGlobalId);
8204 }
8205 }
8206
8207 if(noDomains() > 1 || m_noPeriodicCartesianDirs > 0) {
8209
8210 // WH_old
8211 if(m_haloMode > 0) {
8212 createHigherLevelExchangeCells(level, true, refineCellSolver, removeCellSolver, level == maxLevel - 1);
8213 // createHigherLevelExchangeCells(level, swapCellsSolver, refineCellSolver);
8214 } else
8215 createHigherLevelExchangeCells_old(level, refineCellSolver);
8216 }
8217
8218 for(MInt i = 0; i < noNeighborDomains(); i++) {
8219 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
8220 MInt cellId = m_haloCells[i][j];
8221 if(a_level(cellId) != level) continue;
8222 for(MInt child = 0; child < m_maxNoChilds; child++) {
8223 const MInt childId = a_childId(cellId, child);
8224 if(childId < 0) continue;
8225
8226 // Partition level shift: do not reset flags if the child of a halo cell is an internal
8227 // cell and already existed!
8228 if(!a_isHalo(childId)) {
8229 ASSERT(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell),
8230 "child is not a partition level ancestor or a partition cell");
8231 a_hasProperty(cellId, Cell::WasRefined) = true;
8232 } else {
8233 coarseFlag[childId].reset();
8234 refineFlag[childId].reset();
8235 a_hasProperty(childId, Cell::WasNewlyCreated) = true;
8236 a_hasProperty(cellId, Cell::WasRefined) = true;
8237 }
8238 }
8239 }
8240 }
8241
8242 if(m_azimuthalPer) {
8243 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
8244 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
8246 if(a_level(cellId) != level) continue;
8247 for(MInt child = 0; child < m_maxNoChilds; child++) {
8248 const MInt childId = a_childId(cellId, child);
8249 if(childId < 0) continue;
8250 if(!a_isHalo(childId)) {
8251 mTerm(1, AT_, "");
8252 } else {
8253 coarseFlag[childId].reset();
8254 refineFlag[childId].reset();
8255 a_hasProperty(childId, Cell::WasNewlyCreated) = true;
8256 a_hasProperty(cellId, Cell::WasRefined) = true;
8257 }
8258 }
8259 }
8260 }
8261 }
8262 }
8263
8264 //---------------------------(7)
8265
8266 //----------------------------
8267 // 8. finalize; synchonize window/halo cell order
8268 setLevel();
8270 for(auto& rgm : resizeGridMapSolver) {
8271 rgm(); // make sure grid2solver is large enough
8272 }
8273 compactCells(swapCellsSolver);
8274 // Update after cells have been shifted (min-level cells, globalToLocalId, partitionCellIds, etc)
8276 for(auto& rgm : resizeGridMapSolver) {
8277 rgm(); // update grid2solver after cell swapping
8278 }
8279 if(noDomains() > 1 || m_noPeriodicCartesianDirs > 0) {
8281 }
8283 //---------------------------(8)
8284
8285
8286 //----------------------------
8287 // 9. finalize
8290 }
8291
8292 // Update local bounding box
8294 //---------------------------(9)
8295
8296 if(treeb().noSolvers() > 1 && noNeighborDomains() > 0) { // Exchange solver info
8297 // WH_old
8298 if(m_haloMode > 0) {
8300 } else
8302 m_tree.size());
8303 }
8304
8307 &m_tree.solverBits(0), m_tree.size());
8308 // To ensure that azimuthal halo cells are fully refined (have all children)
8309 // or are not refined at all, solver Bits need to be checked!
8311 }
8312
8313
8314 // TODO labels:GRID,ADAPTATION update noOffspring? not updated during adaptation --> noOffspring required by
8315 // createHigherLevelExchangeCells, so added above
8316 // calculateNoOffspringsAndWorkload(static_cast<Collector<void>*>(nullptr), m_tree.size());
8317
8318 /*
8319 for ( MInt solver = 0; solver < treeb().noSolvers(); solver++ ){
8320 MInt debugHalo=0;
8321 MInt debugWindow=0;
8322 for ( MInt i = 0; i < noNeighborDomains(); i++ ) {
8323 for ( MInt j = 0; j < (signed)m_haloCells[i].size(); j++ ) {
8324 MInt id=m_haloCells[i][j];
8325 if(m_tree.solver( id, solver )){
8326 debugHalo++;
8327 }
8328 }
8329 for ( MInt j = 0; j < (signed)m_windowCells[i].size(); j++ ) {
8330 MInt id=m_windowCells[i][j];
8331 if(m_tree.solver( id, solver )){
8332 debugWindow++;
8333 }
8334 }
8335
8336 cerr << " neighbor: " << i << "--------------" << endl;
8337 cerr <<"count of halos for solver: " << solver << " : " << debugHalo << endl;
8338 cerr <<"count of windows for solver: " << solver << " : " << debugWindow << endl;
8339 cerr <<"total size halo: " << m_haloCells[i].size() << " window: " << m_windowCells[i].size() << endl;
8340 }
8341 }*/
8342
8343 // Update the partition cells when writing the next restart file (in case this is not previously
8344 // done via updatePartitionCells() during balancing)
8345 // TODO labels:GRID,DLB,ADAPTATION partition files written at final time step might not be usable since partition
8346 // cells are updated during new grid output
8348
8349#ifdef MAIA_GRID_SANITY_CHECKS
8352 if(m_haloMode > 0) // WH_old
8353 checkWindowLayer("meshAdaptation completed: ");
8354#endif
8355
8356 // Set adaptation status
8357 m_wasAdapted = true;
8358}
MInt * m_identicalSolverLvlJumps
static constexpr const auto WINDOWLAYER_MAX
MInt * m_identicalSolvers
void updateHaloCellCollectors()
Fill m_nghbrDomains, m_haloCells and m_windowCells with data from temporary buffers.
MInt m_noIdenticalSolvers
MInt * m_identicalSolverMaxLvl
MFloat m_coarseRatio
void createHigherLevelExchangeCells_old(const MInt onlyLevel=-1, const std::vector< std::function< void(const MInt)> > &=std::vector< std::function< void(const MInt)> >())
Iteratively create window and halo cells on levels m_minLevel+1...m_maxLevel, starting from m_minLeve...
void exchangeProperties()
Exchange properties of window/halo cells.
MInt maxNoCells() const
MBool * m_diagSmoothing
MBool coarsenCheck(const MInt cellId, const MInt solverId)
checks if the given cell's children may be removed
MBool m_updatedPartitionCells
void removeChilds(const MInt cellId)
removes the children of the given cell
MInt m_newMinLevel
The new min Level which has been increased at the restart!
void setChildSolverFlag(const MInt cellId, const MInt solver, const std::function< MInt(const MFloat *, const MInt, const MInt)> &cellOutsideSolver)
MBool refineCheck(const MInt cellId, const MInt solverId, const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &cellOutsideSolver)
checks if the given cell may be refined
MBool * m_checkRefinementHoles
void createHigherLevelExchangeCells(const MInt onlyLevel=-1, const MBool duringMeshAdaptation=false, const std::vector< std::function< void(const MInt)> > &=std::vector< std::function< void(const MInt)> >(), const std::vector< std::function< void(const MInt)> > &=std::vector< std::function< void(const MInt)> >(), const MBool forceLeafLvlCorrection=false)
Iteratively create window and halo cells on levels m_minLevel+1...m_maxLevel, starting from m_minLeve...
MBool m_allowCoarsening
void reverseExchangeData(const MInt noNghbrDomains, const MInt *const nghbrDomains, const MInt *const noHaloCells, const MInt **const haloCells, const MInt *const noWindowCells, const MInt **const, const MPI_Comm comm, const U *const data, U *const windowBuffer, const MInt noDat=1)
Generic reverse exchange of data.
Definition: mpiexchange.h:400

◆ meshAdaptationLowMem()

template<MInt nDim>
void CartesianGrid< nDim >::meshAdaptationLowMem ( std::vector< std::vector< MFloat > > &  sensors,
std::vector< MFloat > &  sensorWeight,
std::vector< std::bitset< 64 > > &  sensorCellFlag,
std::vector< MInt > &  sensorSolverId,
const std::vector< std::function< void(const MInt)> > &  refineCellSolver,
const std::vector< std::function< void(const MInt)> > &  removeChildsSolver,
const std::vector< std::function< void(const MInt)> > &  removeCellSolver,
const std::vector< std::function< void(const MInt, const MInt)> > &  swapCellsSolver,
const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &  cellOutsideSolver,
const std::vector< std::function< void()> > &  resizeGridMapSolver 
)
private
Author
Lennart Schneiders
Parameters
[in]sensorsHolds the mesh refinement sensor(s) for each cell
[in]sensorWeightWeighting of this sensor in relation to other sensors if greater than zero, otherwise indicating a true/false-type sensor
[in]sensorCellFlagIndicator whether a sensor was set for this particular cell
[out]oldCellIdMapping from new grid cells to their original cellId, or -1 if they did not exist previously
[out]oldNoCellsNumber of cells in the map

Definition at line 6249 of file cartesiangrid.cpp.

6256 {
6257 TRACE();
6258
6259 //----------------------------
6260 // 0. init
6261 const MInt noCells = treeb().size();
6264
6265 const MInt noSensors = (signed)sensorWeight.size();
6266 ASSERT(sensorWeight.size() == sensors.size(), "");
6267 ASSERT(sensorWeight.size() == sensorSolverId.size(), "");
6268 ScratchSpace<MFloat> sensorCnt(noSensors, 2, AT_, "sensorCnt");
6269 ScratchSpace<MFloat> sensorThresholds(noSensors, 2, AT_, "sensorThresholds");
6272 ASSERT(m_freeIndices.empty(), "");
6273 m_freeIndices.clear();
6274 sensorCnt.fill(F0);
6275 for(MInt c = 0; c < maxNoCells; c++) {
6276 refineFlag[c].reset();
6277 coarseFlag[c].reset();
6278 }
6279 // these flags indicate which cells have changed for the subsequent reinitialization by the solvers
6280 for(MInt cellId = 0; cellId < noCells; cellId++) {
6281 a_hasProperty(cellId, Cell::IsToDelete) = false;
6282 a_hasProperty(cellId, Cell::WasNewlyCreated) = false;
6283 a_hasProperty(cellId, Cell::WasCoarsened) = false;
6284 a_hasProperty(cellId, Cell::WasRefined) = false;
6285
6286 // Reset the window cell flag,
6287 // is set for all preserved window cells when added to m_windowCells
6288 a_hasProperty(cellId, Cell::IsWindow) = false;
6289 }
6290
6291 //----------------------------
6292 // 1. exchange sensors and compute RMS values
6293 // TODO labels:GRID move these parts to the cartesian solver and do this sort of smoothing
6294 // on the solver grid in setSensors, after all sensors have been set there!!!!
6295 // the cartesiangrid should only get one refine/coarse flags for each cell from the solver!
6296 for(MInt cellId = 0; cellId < noCells; cellId++) {
6297 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
6298 if(a_isToDelete(cellId)) continue;
6299
6300 // Note: sensors for partition level ancestors might not be set correctly!
6301 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor)) {
6302 continue;
6303 }
6304
6305 for(MInt s = 0; s < noSensors; s++) {
6306 if(sensorCellFlag[cellId][s]) {
6307 ASSERT(sensorWeight[s] < F0 || std::fabs(sensors[s][cellId]) < MFloatMaxSqrt,
6308 "invalid sensor value: " + std::to_string(sensors[s][cellId]));
6309 sensorCnt(s, 0) += POW2(sensors[s][cellId]);
6310 sensorCnt(s, 1) += F1;
6311 }
6312 }
6313 }
6314
6315 if(noSensors > 0) {
6316 MPI_Allreduce(MPI_IN_PLACE, &sensorCnt(0), 2 * noSensors, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
6317 "sensorCnt(0)");
6318 }
6319
6320 // TODO labels:GRID,ADAPTATION introduce sensor type to replace this weight hack
6321 for(MInt s = 0; s < noSensors; s++) {
6322 if(sensorWeight[s] < F0) { // true/false sensor
6323 sensorThresholds(s, 0) = -1e-12;
6324 sensorThresholds(s, 1) = 1e-12;
6325 } else { // continuous sensor
6326 sensorThresholds(s, 1) = sensorWeight[s] * sqrt(mMax(1e-14, (sensorCnt(s, 0) / sensorCnt(s, 1))));
6327 sensorThresholds(s, 0) = m_coarseRatio * sensorThresholds(s, 1);
6328 }
6329 }
6330
6331 //---------------------------(1)
6332
6333 const MBool hasPartLvlShift = (m_maxPartitionLevelShift > 0);
6334 const MInt tmpScratchSize = (hasPartLvlShift) ? m_tree.size() : 1;
6335
6336 ScratchSpace<MBool> isHaloPartLvlAncestor(tmpScratchSize, AT_, "isHaloPartLvlAncestor");
6337
6338 isHaloPartLvlAncestor.fill(false);
6339
6340 // Determine relevant halo partition level ancestor window/halo cells that need to be preserved
6341 std::vector<std::vector<MInt>> oldWindowCells;
6342 std::vector<MInt> oldNoWindowCells;
6343 MInt totalNoWindowCells = 0;
6344
6345 for(MInt d = 0; d < noNeighborDomains(); d++) {
6346 oldWindowCells.push_back(m_windowCells[d]);
6347 oldNoWindowCells.push_back(noWindowCells(d));
6348 totalNoWindowCells += noWindowCells(d);
6349 }
6350
6351 MInt recvSize = (m_maxPartitionLevelShift > 0) ? totalNoWindowCells : 1;
6352 ScratchSpace<MBool> recvIsHaloPartLvlAncestor(recvSize, AT_, "recvIsHaloPartLvlAncestor");
6353
6354 if(m_maxPartitionLevelShift > 0) {
6355 for(auto& i : m_partitionLevelAncestorIds) {
6356 TERMM_IF_NOT_COND(a_hasProperty(i, Cell::IsPartLvlAncestor),
6357 "cell is not a partition level ancestor: " + std::to_string(i));
6358 // Mark halo partition level ancestors (which are part of the missing subtree of the grid)
6359 if(a_hasProperty(i, Cell::IsHalo)) {
6360 isHaloPartLvlAncestor[i] = true;
6361 }
6362 // Mark all halo childs of partition level ancestors (required for exchange of e.g. global
6363 // ids!)
6364 for(MInt child = 0; child < m_maxNoChilds; child++) {
6365 const MInt childId = a_childId(i, child);
6366 if(childId > -1 && a_isHalo(childId)) {
6367 isHaloPartLvlAncestor[childId] = true;
6368 }
6369 }
6370 }
6371
6372 // Reverse exchange markers from halo cells to corresponding window cells
6373 if(noNeighborDomains() > 0) {
6374#ifndef PVPLUGIN
6376 &recvIsHaloPartLvlAncestor[0]);
6377#else
6378 TERMM(1, "not working for compilation of paraview plugin");
6379#endif
6380 }
6381 }
6382
6383 //----------------------------
6384 // 2. tag cells for coarsening / refinement
6385
6386 // init parent cells with coarse flag true and set false if any child intervenes
6387 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
6388 ASSERT(!a_hasProperty(cellId, Cell::IsHalo), "");
6389 ASSERT(!a_isToDelete(cellId), "");
6390 if(a_level(cellId) > m_maxUniformRefinementLevel) {
6391 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6392 if(!m_tree.solver(cellId, solver)) continue;
6393 if(a_hasChildren(cellId, solver)) continue;
6394
6395 const MInt parentId = a_parentId(cellId, solver);
6396 ASSERT(parentId > -1, "");
6397 // Partition level shift, parent is a halo cell and cannot be coarsened
6398 if(a_isHalo(parentId) || a_hasProperty(parentId, Cell::IsPartLvlAncestor)) continue;
6399
6400 for(MInt s = 0; s < noSensors; s++) {
6401 if(sensorSolverId[s] != solver) continue;
6402 if(sensorCellFlag[cellId][s] || sensorCellFlag[parentId][s]) {
6403 // only coarsen cells if they are above the newMinLevel!
6404 if(a_level(cellId) > m_newMinLevel && m_allowCoarsening) {
6405 coarseFlag[a_parentId(cellId)][solver] = true;
6406 }
6407 }
6408 }
6409 }
6410 }
6411 }
6412
6413 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
6414 ASSERT(!a_hasProperty(cellId, Cell::IsHalo), "");
6415 ASSERT(!a_isToDelete(cellId), "");
6416 const MInt level = a_level(cellId);
6417 //---
6418 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6419 if(!m_tree.solver(cellId, solver)) continue;
6420 if(a_hasChildren(cellId, solver)) continue;
6421 const MInt parentId = a_parentId(cellId, solver);
6422 // Partition level shift, if parent is a halo it cannot be coarsened and e.g.
6423 // sensors/coarseFlag[parentId] should not be accessed!
6424 const MBool partLvlAncestorParent = (parentId > -1) ? a_hasProperty(parentId, Cell::IsPartLvlAncestor) : false;
6425
6426 // cell should be marked for refinement
6427 MBool refine = false;
6428 // cell should be marked for coarsened
6429 MBool coarsen = true;
6430 // cell should be marked for refinement regardless
6431 // whether a different sensor marks this cell for coarsening
6432 MBool forceRefine = false;
6433 for(MInt s = 0; s < noSensors; s++) {
6434 if(sensorSolverId[s] != solver) continue;
6435 if(sensorCellFlag[cellId][s]) {
6436 coarsen = coarsen && (sensors[s][cellId] < sensorThresholds(s, 0));
6437 }
6438 if(level > m_maxUniformRefinementLevel && !partLvlAncestorParent && sensorCellFlag[parentId][s]) {
6439 coarsen = coarsen && (sensors[s][parentId] < sensorThresholds(s, 0));
6440 }
6441 // this sensor would refine the cell
6442 const MBool refineSensor = sensors[s][cellId] > sensorThresholds(s, 1) && sensorCellFlag[cellId][s];
6443 refine = refine || refineSensor;
6444
6445 // a true/false sensor marks the cell for refinement
6446 if(refineSensor && sensorWeight[s] < F0) {
6447 forceRefine = true;
6448 }
6449 }
6450 if(level < m_maxRfnmntLvl) {
6451 refineFlag[cellId][solver] = refine;
6452 }
6453
6454 if(level > m_maxUniformRefinementLevel && !partLvlAncestorParent) {
6455 coarseFlag[parentId][solver] = coarseFlag[parentId][solver] && coarsen;
6456 }
6457 // force a refinement of a cell:
6458 // for all minLevel cells which should be raised to the newMinLevel
6459 // for the cells forced by any true/false sensor!
6460 if((forceRefine && level < m_maxRfnmntLvl) || a_level(cellId) < m_newMinLevel) {
6461 refineFlag[cellId][solver] = true;
6462 coarseFlag[cellId][solver] = false;
6463 if(level > m_maxUniformRefinementLevel) {
6464 coarseFlag[parentId][solver] = false;
6465 }
6466 }
6467 }
6468 }
6469
6470 // 3. Exchange since consistency checks need neighbor values
6471 if(noNeighborDomains() > 0) {
6473 m_tree.size());
6475 m_tree.size());
6476 }
6477
6478 //----------------------------
6479 // 4. consistency check for internal cells
6480 if(m_checkRefinementHoles != nullptr) {
6481 // necessary for solution adaptive refinement (i.e. at shocks)
6482 const MInt adaptationHoleLimit = nDim;
6483 MBool gridUpdated = true;
6484
6485 MInt loopCount = 0;
6486 while(gridUpdated && loopCount < 25) {
6487 MInt noChanges = 0;
6488 loopCount++;
6489 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6490 if(!m_checkRefinementHoles[solver]) continue;
6491 for(MInt cellId = 0; cellId < noCells; cellId++) {
6492 if(a_isToDelete(cellId)) continue;
6493 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
6494 if(!m_tree.solver(cellId, solver)) continue;
6495 if(a_hasChildren(cellId, solver)) continue;
6496
6497 // check, if current cell is a hole in the refinement => refine cell aswell
6498 if(!refineFlag[cellId][solver]
6499 || (a_parentId(cellId, solver) > -1 && coarseFlag[a_parentId(cellId, solver)][solver])) {
6500 MInt checkRefinedNeighbors = 0;
6501 MInt currentHoleLimit = adaptationHoleLimit;
6502 for(MInt dir = 0; dir < m_noDirs; dir++) {
6503 if(a_hasNeighbor(cellId, dir, solver) > 0) {
6504 const MInt nghbrId = a_neighborId(cellId, dir, solver);
6505 if(refineFlag[nghbrId][solver] || a_hasChildren(nghbrId, solver)) {
6506 checkRefinedNeighbors += 1;
6507 }
6508 } else {
6509 // Lower limit at boundaries
6510 currentHoleLimit--;
6511 }
6512 }
6513 if(checkRefinedNeighbors > adaptationHoleLimit) {
6514 refineFlag[cellId][solver] = true;
6515 coarseFlag[cellId][solver] = false;
6516 const MInt parentId = a_parentId(cellId, solver);
6517 if(parentId > -1) coarseFlag[parentId][solver] = false;
6518 noChanges += 1;
6519 }
6520 }
6521
6522 // check, if current cell coarsening would create a hole in the refinement => do not coarsen cell
6523 const MInt parentId = a_parentId(cellId, solver);
6524 if(parentId < 0) continue;
6525 if(coarseFlag[parentId][solver]) {
6526 ASSERT(!a_isHalo(parentId) && !a_hasProperty(parentId, Cell::IsPartLvlAncestor),
6527 "Partition level ancestor parent cell has coarseFlag set.");
6528 MInt checkRefinedNeighbors = 0;
6529 MInt currentHoleLimit = adaptationHoleLimit;
6530 for(MInt dir = 0; dir < m_noDirs; dir++) {
6531 if(a_hasNeighbor(parentId, dir, solver) > 0) {
6532 const MInt parNghbrId = a_neighborId(parentId, dir, solver);
6533 if(!coarseFlag[parNghbrId][solver]
6534 && (refineFlag[parNghbrId][solver] || a_hasChildren(parNghbrId, solver))) {
6535 checkRefinedNeighbors += 1;
6536 }
6537 } else {
6538 // Lower limit at boundaries
6539 currentHoleLimit--;
6540 }
6541 }
6542 if(checkRefinedNeighbors > adaptationHoleLimit) {
6543 coarseFlag[parentId][solver] = false;
6544 noChanges += 1;
6545 }
6546 }
6547
6548 // Check if the coarsening of neighboring cells would create a refined cell island => coarsen cell aswell
6549 if(!coarseFlag[parentId][solver]) {
6550 ASSERT(!a_isHalo(parentId) && !a_hasProperty(parentId, Cell::IsPartLvlAncestor),
6551 "Partition level ancestor parent cell has coarseFlag set.");
6552 MInt checkCoarseNeighbors = 0;
6553 MInt currentHoleLimit = adaptationHoleLimit;
6554 for(MInt dir = 0; dir < m_noDirs; dir++) {
6555 if(a_hasNeighbor(parentId, dir, solver) > 0) {
6556 const MInt parNghbrId = a_neighborId(parentId, dir, solver);
6557 if(coarseFlag[parNghbrId][solver]
6558 || (!refineFlag[parNghbrId][solver] && !a_hasChildren(parNghbrId, solver))) {
6559 checkCoarseNeighbors += 1;
6560 }
6561 } else {
6562 // Lower limit at boundaries
6563 currentHoleLimit--;
6564 }
6565 }
6566 if(checkCoarseNeighbors > currentHoleLimit) {
6567 coarseFlag[parentId][solver] = true;
6568 noChanges += 1;
6569 }
6570 }
6571
6572 // check if the current cell refinement creates a refined cell island => do not refine cell
6573 if(refineFlag[cellId][solver]) {
6574 MInt checkRefinedNeighbors = 0;
6575 for(MInt dir = 0; dir < m_noDirs; dir++) {
6576 if(a_hasNeighbor(cellId, dir, solver) > 0) {
6577 const MInt nghbrId = a_neighborId(cellId, dir, solver);
6578 if(refineFlag[nghbrId][solver] || a_hasChildren(nghbrId, solver)) {
6579 checkRefinedNeighbors += 1;
6580 }
6581 }
6582 }
6583 if(checkRefinedNeighbors == 0) {
6584 refineFlag[cellId][solver] = false;
6585 noChanges += 1;
6586 }
6587 }
6588 }
6589 }
6590 if(noChanges == 0) {
6591 gridUpdated = false;
6592 }
6593 }
6594 }
6595
6596 // smooth diagonal level jumps,
6597 // even if already existing in the base grid!
6598 if(m_diagSmoothing != nullptr) {
6599 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6600 if(!m_diagSmoothing[solver]) continue;
6601 for(MInt lvl = maxLevel - 1; lvl >= minLevel(); lvl--) {
6602 for(MInt cellId = 0; cellId < noCells; cellId++) {
6603 if(a_level(cellId) != lvl) continue;
6604 if(!a_isLeafCell(cellId)) continue;
6605 if(!m_tree.solver(cellId, solver)) continue;
6606 if(refineFlag[cellId][solver]) continue;
6607 for(MInt i = 0; i < m_noDirs; i++) {
6608 const MInt nghbrId = a_neighborId(cellId, i, solver);
6609 if(nghbrId < 0) continue;
6610 if(a_isLeafCell(nghbrId)) continue;
6611 for(MInt child = 0; child < m_maxNoChilds; child++) {
6612 MInt childId = a_childId(nghbrId, child, solver);
6613 if(childId < 0) continue;
6614 if(!a_isLeafCell(childId)) {
6615 refineFlag[cellId][solver] = true;
6616 coarseFlag[cellId][solver] = false;
6617 MInt parentId = a_parentId(cellId, solver);
6618 if(parentId > -1) {
6619 coarseFlag[cellId][solver] = false;
6620 }
6621 break;
6622 }
6623 }
6624 for(MInt j = 0; j < m_noDirs; j++) {
6625 if(j / 2 == i / 2) continue;
6626 const MInt diagNghbrId = a_neighborId(nghbrId, j, solver);
6627 if(diagNghbrId < 0) continue;
6628 if(a_isLeafCell(diagNghbrId)) continue;
6629 for(MInt child = 0; child < m_maxNoChilds; child++) {
6630 MInt childId = a_childId(diagNghbrId, child, solver);
6631 if(childId < 0) continue;
6632 if(!a_isLeafCell(childId)) {
6633 refineFlag[cellId][solver] = true;
6634 coarseFlag[cellId][solver] = false;
6635 MInt parentId = a_parentId(cellId, solver);
6636 if(parentId > -1) {
6637 coarseFlag[cellId][solver] = false;
6638 }
6639 break;
6640 }
6641 }
6642 }
6643 }
6644 }
6645 }
6646 }
6647 }
6648
6649 // Additional consistency checks fixing contradictory flags
6650 for(MInt cellId = 0; cellId < noCells; cellId++) {
6651 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
6652 if(a_isToDelete(cellId)) continue;
6653
6654 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6655 if(!m_tree.solver(cellId, solver)) continue;
6656 if(a_hasChildren(cellId, solver)) continue;
6657 const MInt parentId = a_parentId(cellId, solver);
6658 if(refineFlag[cellId][solver] && coarseFlag[cellId][solver]) {
6659 refineFlag[cellId][solver] = false;
6660 coarseFlag[cellId][solver] = false;
6661 }
6662
6663 // TODO labels:GRID,ADAPTATION,totest check for multisolver!!!!!
6664 if(refineFlag[cellId][solver]) {
6665 if(parentId > -1) {
6666 if(coarseFlag[parentId][solver]) {
6667 ASSERT(!a_isHalo(parentId) && !a_hasProperty(parentId, Cell::IsPartLvlAncestor),
6668 "Partition level ancestor parent cell has coarseFlag set.");
6669 coarseFlag[parentId][solver] = false;
6670 for(MInt child = 0; child < m_maxNoChilds; child++) {
6671 MInt childId = a_childId(parentId, child, solver);
6672 if(childId > -1) {
6673 refineFlag[childId][solver] = false;
6674 }
6675 }
6676 }
6677 }
6678 }
6679 }
6680 }
6681 //---------------------------(4)
6682
6683 // ensure the same refinement between two different solvers in the combined/overlapping region!
6684 if(m_noIdenticalSolvers > 0) {
6685 for(MInt cellId = 0; cellId < m_noInternalCells; cellId++) {
6686 for(MInt pair = 0; pair < m_noIdenticalSolvers; pair++) {
6687 const MInt slaveId = m_identicalSolvers[pair * 2];
6688 const MInt masterId = m_identicalSolvers[pair * 2 + 1];
6689 if(treeb().solver(cellId, slaveId) && treeb().solver(cellId, masterId)) {
6690 if(!coarseFlag[cellId][masterId]) {
6691 coarseFlag[cellId][slaveId] = coarseFlag[cellId][masterId];
6692 }
6693 if(m_identicalSolverLvlJumps[pair] == 0) {
6694 refineFlag[cellId][slaveId] = refineFlag[cellId][masterId];
6695 } else if(m_identicalSolverLvlJumps[pair] == 1) {
6696 if(a_level(cellId) < m_identicalSolverMaxLvl[pair] && a_hasChildren(cellId, masterId)) {
6697 if(!a_hasChildren(cellId, slaveId)) {
6698 refineFlag[cellId][slaveId] = true;
6699 }
6700 coarseFlag[cellId][slaveId] = false;
6701 }
6702 } else {
6703 if(a_level(cellId) < m_identicalSolverMaxLvl[pair] && a_hasChildren(cellId, masterId)
6704 && a_childId(cellId, 0) > -1 && treeb().solver(a_childId(cellId, 0), masterId)
6705 && a_hasChildren(a_childId(cellId, 0), masterId)) {
6706 if(!a_hasChildren(cellId, slaveId)) {
6707 refineFlag[cellId][slaveId] = true;
6708 }
6709 coarseFlag[cellId][slaveId] = false;
6710 }
6711 }
6712 }
6713 }
6714 }
6715 }
6716
6717
6718 //----------------------------
6719 // 5. Coarsening step: loop from maxLevel to minLevel and exchange coarseFlags to retrieve
6720 // consistent refinement at domain interfaces; update window/halo collectors
6721 for(MInt level = m_maxRfnmntLvl - 1; level >= m_maxUniformRefinementLevel; level--) {
6722 for(MInt cellId = 0; cellId < noCells; cellId++) {
6723 if(a_level(cellId) != level) continue;
6724 if(a_isToDelete(cellId)) continue;
6725 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
6726
6727 // TODO labels:GRID,ADAPTATION,totest check for multisolver setting.. neighborIds solver aware!!
6728 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6729 if(!m_tree.solver(cellId, solver)) continue;
6730 if(!a_hasChildren(cellId, solver)) continue;
6731
6732 // Partition level ancestor cell cannot be coarsened (exept if its a partition cell)
6733 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor) && !a_hasProperty(cellId, Cell::IsPartitionCell)) {
6734 coarseFlag[cellId][solver] = false;
6735 }
6736
6737 if(coarseFlag[cellId][solver]) {
6738 if(!coarsenCheck(cellId, solver)) {
6739 coarseFlag[cellId][solver] = false;
6740 }
6741 }
6742 }
6743 }
6744
6745 if(noNeighborDomains() > 0) {
6746 // exchangeSolverBitset(coarseFlag.data());
6748 m_tree.size());
6749 }
6750
6751 for(MInt cellId = 0; cellId < noCells; cellId++) {
6752 if(a_level(cellId) != level) continue;
6753 if(a_isToDelete(cellId)) continue;
6754 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
6755
6756 // TODO labels:GRID,ADAPTATION,totest check for multisolver setting.. neighborIds solver aware!!
6757 if(level < m_maxRfnmntLvl - 1) {
6758 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6759 if(!m_tree.solver(cellId, solver)) continue;
6760 if(a_hasChildren(cellId, solver)) continue;
6761 if(!refineFlag[cellId][solver] && !coarseFlag[cellId][solver]) {
6762 for(MInt dir = 0; dir < m_noDirs; dir++) {
6763 if(a_hasNeighbor(cellId, dir, solver) > 0) {
6764 MInt nghbrId = a_neighborId(cellId, dir, solver);
6765 if(m_azimuthalPer && a_hasProperty(nghbrId, Cell::IsPeriodic)) continue;
6766 if(a_hasChildren(nghbrId, solver) > 0) {
6767 for(MInt child = 0; child < m_maxNoChilds; child++) {
6768 if(!childCode[dir][child]) continue;
6769 MInt childId = a_childId(nghbrId, child, solver);
6770 if(childId < 0) continue;
6771 if(refineFlag[childId][solver]) {
6772 refineFlag[cellId][solver] = true;
6773 }
6774 }
6775 }
6776 }
6777 }
6778 }
6779 }
6780 }
6781 }
6782
6783 if(noNeighborDomains() > 0) {
6784 // exchangeSolverBitset(refineFlag.data());
6786 m_tree.size());
6787 }
6788
6789 for(MInt cellId = 0; cellId < noCells; cellId++) {
6790 if(a_level(cellId) != level) continue;
6791 if(a_isToDelete(cellId)) continue;
6792 if(m_azimuthalPer && a_hasProperty(cellId, Cell::IsPeriodic)) continue;
6793
6794 // Partition level ancestor cell cannot be coarsened (exept if its a partition cell)
6795 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor) && !a_hasProperty(cellId, Cell::IsPartitionCell)) {
6796 continue;
6797 }
6798
6799 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6800 if(!m_tree.solver(cellId, solver)) continue;
6801 if(coarseFlag[cellId][solver]) {
6802 for(MInt child = 0; child < m_maxNoChilds; child++) {
6803 MInt childId = a_childId(cellId, child, solver);
6804 if(childId > -1) {
6805 coarseFlag[childId][solver] = false;
6806 refineFlag[childId][solver] = false;
6807 }
6808 }
6809 if(a_hasChildren(cellId, solver)) {
6810 removeChildsSolver[solver](cellId);
6811 // call removeChilds() function in each solver before child links are deleted
6812 refineFlag[cellId][solver] = false;
6813 for(MInt child = 0; child < m_maxNoChilds; child++) {
6814 MInt childId = a_childId(cellId, child);
6815 if(childId > -1) {
6816 treeb().solver(childId, solver) = false;
6817 }
6818 }
6819 }
6820 }
6821 }
6822 // check if the child can also be removed from the cartesian/combined grid
6823 // if the child is no-longer in any of the solvers, the grid child will be removed!
6824 if(a_noChildren(cellId) > 0) {
6825 MBool rmChilds = true;
6826 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6827 if(a_hasChildren(cellId, solver)) {
6828 rmChilds = false;
6829 }
6830 }
6831 if(rmChilds) {
6832 removeChilds(cellId);
6833 }
6834 }
6835 }
6836
6837 for(MInt i = 0; i < noNeighborDomains(); i++) {
6838 std::set<MInt> deleted;
6839 // WH_old
6840 if(m_haloMode > 0) {
6841 for(auto it_ = m_windowLayer_[i].begin(); it_ != m_windowLayer_[i].end();) {
6842 if(a_isToDelete(it_->first)) {
6843 it_ = m_windowLayer_[i].erase(it_);
6844 } else {
6845 // We might have deleted a cell from a solver
6846 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6847 if(it_->second.get(solver) < WINDOWLAYER_MAX /*<=m_noSolverHaloLayers[solver]*/
6848 && !m_tree.solver(it_->first, solver))
6849 it_->second.set(solver, WINDOWLAYER_MAX);
6850 if(it_->second.get(solver) > m_noSolverHaloLayers[solver]) it_->second.set(solver, WINDOWLAYER_MAX);
6851 }
6852 if(it_->second.all()) {
6853 deleted.insert(it_->first);
6854 it_ = m_windowLayer_[i].erase(it_);
6855 } else
6856 ++it_;
6857 }
6858 }
6859 }
6860
6861 // 1. coarsen window cells
6862#ifndef NDEBUG
6863 std::set<MInt> windCellSet;
6864 std::set<MInt> haloCellSet;
6865#endif
6866
6867 m_windowCells[i].clear();
6868
6869 auto it = oldWindowCells[i].begin();
6870
6871 for(it = oldWindowCells[i].begin(); it < oldWindowCells[i].end(); it++) {
6872 const MInt cellId = *it;
6873 if(!a_isToDelete(cellId) && (deleted.find(cellId) == deleted.end() || m_haloMode == 0)) { // WH_old
6874 ASSERT(cellId < treeb().size(), "");
6875
6876#ifndef NDEBUG
6877 // TODO labels:GRID,ADAPTATION fix duplicate window cells in periodic cases!
6878 ASSERT(m_noPeriodicCartesianDirs > 0 || windCellSet.find(cellId) == windCellSet.end(),
6879 "duplicate window cell: " + std::to_string(cellId));
6880 windCellSet.insert(cellId);
6881#endif
6882
6883 m_windowCells[i].push_back(cellId);
6884 }
6885 }
6886
6887 // 2. coarsen halo cells
6888 vector<MInt> oldHaloVec(m_haloCells[i]);
6889 m_haloCells[i].clear();
6890 for(it = oldHaloVec.begin(); it < oldHaloVec.end(); it++) {
6891 const MInt cellId = *it;
6892 if(!a_isToDelete(cellId)) {
6893 ASSERT(cellId < treeb().size(), "");
6894
6895#ifndef NDEBUG
6896 ASSERT(haloCellSet.find(cellId) == haloCellSet.end(), "duplicate halo cell: " + std::to_string(cellId));
6897 haloCellSet.insert(cellId);
6898#endif
6899
6900 if(m_tree.solverBits(cellId).any() || m_haloMode == 0) m_haloCells[i].push_back(cellId);
6901 }
6902 }
6903 oldHaloVec.clear();
6904 }
6905 }
6906 //---------------------------(5)
6907
6908
6909 //----------------------------
6910 // 6. Remove all halo cells, for levels > maxUniformRefinementLevel
6911 // since the number of halo layers is inconsistent at this point
6912 // Note: preserve halo partition level ancestors of the missing grid subtree in case of a
6913 // partition level shift
6914
6915 {
6916 for(MInt level = maxLevel - 1; level >= m_maxUniformRefinementLevel; level--) {
6917 for(MInt cellId = 0; cellId < noCells; cellId++) {
6918 if(a_isToDelete(cellId)) continue;
6919 if(!a_hasProperty(cellId, Cell::IsHalo)) continue;
6920 if(a_level(cellId) == level) {
6921 if(a_noChildren(cellId) > 0) {
6922 // Preserve partition level ancestor halos (and their childs) if they are part of the
6923 // missing subtree of the grid in case of a partition level shift
6924 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor) && !a_hasProperty(cellId, Cell::IsPartitionCell)) {
6925 if(std::find(m_partitionLevelAncestorIds.begin(), m_partitionLevelAncestorIds.end(), cellId)
6926 != m_partitionLevelAncestorIds.end()) {
6927 continue;
6928 }
6929 }
6930
6931 for(MInt child = 0; child < m_maxNoChilds; child++) {
6932 MInt childId = a_childId(cellId, child);
6933 if(childId < 0) continue;
6934 refineFlag[childId].reset();
6935 coarseFlag[childId].reset();
6936 }
6937 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
6938 if(!m_tree.solver(cellId, solver)) continue;
6939 if(a_hasChildren(cellId, solver)) {
6940 removeChildsSolver[solver](cellId);
6941 }
6942 }
6943 removeChilds(cellId);
6944 coarseFlag[cellId].reset();
6945 refineFlag[cellId].reset();
6946 }
6947 }
6948 }
6949 }
6950
6951 ScratchSpace<MBool> isWindowPartLvlAncestor_(tmpScratchSize, AT_, "isWindowPartLvLAncestor");
6952 MInt cnt = 0;
6953 for(MInt i = 0; i < noNeighborDomains(); i++) {
6954 isWindowPartLvlAncestor_.fill(false);
6955 // now take data from recvIsHaloPartLvlAncestor and store it for this neighborDomain
6956 if(hasPartLvlShift) {
6957 for(MInt j = 0; j < oldNoWindowCells[i]; j++) {
6958 const MInt cellId = oldWindowCells[i][j];
6959 isWindowPartLvlAncestor_(cellId) = recvIsHaloPartLvlAncestor[cnt];
6960 cnt++;
6961 }
6962 }
6963
6964 m_windowCells[i].clear();
6965
6966 auto it = oldWindowCells[i].begin();
6967 for(it = oldWindowCells[i].begin(); it < oldWindowCells[i].end(); it++) {
6968 const MInt cellId = *it;
6969
6970 // Add partition level ancestor window cells if required
6971 const MBool addWindow = (hasPartLvlShift) ? isWindowPartLvlAncestor_(cellId) : false;
6972
6973 if((a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) || addWindow) {
6974 m_windowCells[i].push_back(cellId);
6975 // Set window cell flag for preserved window cells
6976 a_hasProperty(cellId, Cell::IsWindow) = true;
6977 }
6978 }
6979
6980 // WH_old
6981 if(m_haloMode > 0) {
6982 for(auto it_ = m_windowLayer_[i].begin(); it_ != m_windowLayer_[i].end();) {
6983 const MInt cellId = it_->first;
6984
6985 // Add partition level ancestor window cells if required
6986 const MBool addWindow = (hasPartLvlShift) ? isWindowPartLvlAncestor_(cellId) : false;
6987
6988 if((a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) || addWindow)
6989 ++it_;
6990 else
6991 it_ = m_windowLayer_[i].erase(it_);
6992 }
6993 }
6994
6995 vector<MInt> oldHaloVec(m_haloCells[i]);
6996 m_haloCells[i].clear();
6997 for(it = oldHaloVec.begin(); it < oldHaloVec.end(); it++) {
6998 const MInt cellId = *it;
6999
7000 // Add partition level ancestor halo cells if required
7001 const MBool addHalo = (hasPartLvlShift) ? isHaloPartLvlAncestor[cellId] : false;
7002
7003 if((a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) || addHalo) {
7004 ASSERT(cellId > -1 && cellId < treeb().size(), to_string(cellId) + " " + to_string(treeb().size()));
7005 m_haloCells[i].push_back(cellId);
7006 }
7007 }
7008 oldHaloVec.clear();
7009 }
7010
7011 if(m_azimuthalPer) {
7012 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
7013 vector<MInt> oldAzimuthalWindowVec(m_azimuthalWindowCells[i]);
7014
7015 m_azimuthalWindowCells[i].clear();
7016 auto it = oldAzimuthalWindowVec.begin();
7017 for(MInt j = 0; j < (signed)oldAzimuthalWindowVec.size(); j++) {
7018 // Remove higher level azimuthal window cells from collector
7019 // If an azimuthal halo cell on a higher level is mapped to an
7020 // azimuthal window cell on a lower level. This azimuthal window cell
7021 // musst also be removed from the collector
7022 const MInt cellId = oldAzimuthalWindowVec[j];
7023 MBool keepWindow = true;
7026 keepWindow = false;
7027 }
7028 if(a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel && keepWindow) {
7029 m_azimuthalWindowCells[i].push_back(cellId);
7030 a_hasProperty(cellId, Cell::IsWindow) = true;
7031 }
7032 }
7033 oldAzimuthalWindowVec.clear();
7034
7035 vector<MInt> oldAzimuthalHaloVec(m_azimuthalHaloCells[i]);
7036 m_azimuthalHaloCells[i].clear();
7037 for(it = oldAzimuthalHaloVec.begin(); it < oldAzimuthalHaloVec.end(); it++) {
7038 const MInt cellId = *it;
7039 if(a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) {
7040 ASSERT(cellId > -1 && cellId < treeb().size(), "");
7041 m_azimuthalHaloCells[i].push_back(cellId);
7042 }
7043 }
7044 oldAzimuthalHaloVec.clear();
7045 }
7046
7047 // Remove higher level unmapped azimuthal halo cells
7048 vector<MInt> oldUnmappedHaloVec(m_azimuthalUnmappedHaloCells);
7049 vector<MInt> oldUnmappedHaloDomVec(m_azimuthalUnmappedHaloDomains);
7052 for(MUint i = 0; i < oldUnmappedHaloVec.size(); i++) {
7053 MInt cellId = oldUnmappedHaloVec[i];
7054 if(a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) {
7055 ASSERT(cellId > -1 && cellId < treeb().size(), "");
7056 m_azimuthalUnmappedHaloCells.push_back(cellId);
7057 m_azimuthalUnmappedHaloDomains.push_back(oldUnmappedHaloDomVec[i]);
7058 }
7059 }
7060 oldUnmappedHaloVec.clear();
7061 oldUnmappedHaloDomVec.clear();
7062
7063 // Update gridBndryCells
7064 vector<MInt> oldGridBndryVec(m_gridBndryCells);
7065 m_gridBndryCells.clear();
7066 for(MUint i = 0; i < oldGridBndryVec.size(); i++) {
7067 MInt cellId = oldGridBndryVec[i];
7068 if(a_level(cellId) > -1 && a_level(cellId) <= m_maxUniformRefinementLevel) {
7069 m_gridBndryCells.push_back(cellId);
7070 }
7071 }
7072 oldGridBndryVec.clear();
7073 }
7074 }
7075
7076 //---------------------------(6)
7077 //----------------------------
7078 // 7. Refinement step: loop from minLevel to maxLevel and exchange refineFlags to retrieve
7079 // a consistent refinement at domain interfaces; update window/halo connectivity at each level
7080 for(MInt level = m_maxUniformRefinementLevel; level < maxLevel; level++) {
7081 for(MInt cellId = 0; cellId < noCells; cellId++) {
7082 if(a_level(cellId) != level) continue;
7083 if(a_isToDelete(cellId)) continue;
7084 if(a_hasProperty(cellId, Cell::IsHalo)) continue;
7085
7086 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7087 if(!m_tree.solver(cellId, solver)) continue;
7088 if(a_hasChildren(cellId, solver)) continue;
7089 if(refineFlag[cellId][solver]) {
7090 if(!refineCheck(cellId, solver, cellOutsideSolver)) {
7091 // comment out for stl interface refinement, causes weird remaining cells
7092 refineFlag[cellId][solver] = 0;
7093 }
7094 }
7095 }
7096
7097 if(refineFlag[cellId].any()) {
7098 refineCell(cellId, nullptr, false, cellOutsideSolver, refineFlag[cellId]);
7099
7100 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
7101 if(!a_hasChildren(cellId, solver) && false) { // sohel false
7102 // this is somehow destroying multisolver cases
7103 // if one solver already has a cell the other solver doesnt get it even if it needs it..
7104 // i think the solver flag is not set correctly in the refineCell function of cartesiangrid
7105 refineFlag[cellId][solver] = false;
7106 }
7107 if(refineFlag[cellId][solver]) {
7108 // Set solver flag for child cells
7109 setChildSolverFlag(cellId, solver, cellOutsideSolver[solver]);
7110 refineCellSolver[solver](cellId); // call refineCell() function in each solver
7111 }
7112 }
7113 for(MInt child = 0; child < m_maxNoChilds; child++) {
7114 MInt childId = a_childId(cellId, child);
7115 if(childId > -1 && a_hasProperty(childId, Cell::WasNewlyCreated)) {
7116 // Timw: only reset the child-flags if the cell was neawly created
7117 // otherwise this stops a refinement of the childs of a different solver!
7118 coarseFlag[childId].reset();
7119 refineFlag[childId].reset();
7120 }
7121 }
7122 }
7123 }
7124
7125 setLevel();
7126
7128
7129 // WH_old
7130 if(m_haloMode > 0)
7131 // noOffspring required in createHigherLevelExchangeCells
7133
7134 // Update child ids of partition level ancestors (stored as global ids)
7136 const MInt noPartLvlAncestorIds = m_partitionLevelAncestorIds.size();
7137 for(MInt i = 0; i < noPartLvlAncestorIds; i++) {
7139
7140 for(MInt child = 0; child < m_maxNoChilds; child++) {
7141 const MInt childId = a_childId(cellId, child);
7142 const MLong childGlobalId = (childId > -1) ? a_globalId(childId) : -1;
7143 m_partitionLevelAncestorChildIds.push_back(childGlobalId);
7144 }
7145 }
7146
7147 if(noDomains() > 1 || m_noPeriodicCartesianDirs > 0) {
7149
7150 // WH_old
7151 if(m_haloMode > 0) {
7152 createHigherLevelExchangeCells(level, true, refineCellSolver, removeCellSolver, level == maxLevel - 1);
7153 // createHigherLevelExchangeCells(level, swapCellsSolver, refineCellSolver);
7154 } else
7155 createHigherLevelExchangeCells_old(level, refineCellSolver);
7156 }
7157
7158 for(MInt i = 0; i < noNeighborDomains(); i++) {
7159 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
7160 MInt cellId = m_haloCells[i][j];
7161 if(a_level(cellId) != level) continue;
7162 for(MInt child = 0; child < m_maxNoChilds; child++) {
7163 const MInt childId = a_childId(cellId, child);
7164 if(childId < 0) continue;
7165
7166 // Partition level shift: do not reset flags if the child of a halo cell is an internal
7167 // cell and already existed!
7168 if(!a_isHalo(childId)) {
7169 ASSERT(a_hasProperty(childId, Cell::IsPartLvlAncestor) || a_hasProperty(childId, Cell::IsPartitionCell),
7170 "child is not a partition level ancestor or a partition cell");
7171 a_hasProperty(cellId, Cell::WasRefined) = true;
7172 } else {
7173 coarseFlag[childId].reset();
7174 refineFlag[childId].reset();
7175 a_hasProperty(childId, Cell::WasNewlyCreated) = true;
7176 a_hasProperty(cellId, Cell::WasRefined) = true;
7177 }
7178 }
7179 }
7180 }
7181
7182 if(m_azimuthalPer) {
7183 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
7184 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
7186 if(a_level(cellId) != level) continue;
7187 for(MInt child = 0; child < m_maxNoChilds; child++) {
7188 const MInt childId = a_childId(cellId, child);
7189 if(childId < 0) continue;
7190 if(!a_isHalo(childId)) {
7191 mTerm(1, AT_, "");
7192 } else {
7193 coarseFlag[childId].reset();
7194 refineFlag[childId].reset();
7195 a_hasProperty(childId, Cell::WasNewlyCreated) = true;
7196 a_hasProperty(cellId, Cell::WasRefined) = true;
7197 }
7198 }
7199 }
7200 }
7201 }
7202 }
7203
7204 //---------------------------(7)
7205
7206 //----------------------------
7207 // 8. finalize; synchonize window/halo cell order
7208 setLevel();
7210 for(auto& rgm : resizeGridMapSolver) {
7211 rgm(); // make sure grid2solver is large enough
7212 }
7213 compactCells(swapCellsSolver);
7214 // Update after cells have been shifted (min-level cells, globalToLocalId, partitionCellIds, etc)
7216 for(auto& rgm : resizeGridMapSolver) {
7217 rgm(); // update grid2solver after cell swapping
7218 }
7219 if(noDomains() > 1 || m_noPeriodicCartesianDirs > 0) {
7221 }
7223 //---------------------------(8)
7224
7225
7226 //----------------------------
7227 // 9. finalize
7230 }
7231
7232 // Update local bounding box
7234 //---------------------------(9)
7235
7236 if(treeb().noSolvers() > 1 && noNeighborDomains() > 0) { // Exchange solver info
7237 // WH_old
7238 if(m_haloMode > 0) {
7240 } else
7242 m_tree.size());
7243 }
7244
7247 &m_tree.solverBits(0), m_tree.size());
7248 // To ensure that azimuthal halo cells are fully refined (have all children)
7249 // or are not refined at all, solver Bits need to be checked!
7251 }
7252
7253
7254 // TODO labels:GRID,ADAPTATION update noOffspring? not updated during adaptation --> noOffspring required by
7255 // createHigherLevelExchangeCells, so added above
7256 // calculateNoOffspringsAndWorkload(static_cast<Collector<void>*>(nullptr), m_tree.size());
7257
7258 /*
7259 for ( MInt solver = 0; solver < treeb().noSolvers(); solver++ ){
7260 MInt debugHalo=0;
7261 MInt debugWindow=0;
7262 for ( MInt i = 0; i < noNeighborDomains(); i++ ) {
7263 for ( MInt j = 0; j < (signed)m_haloCells[i].size(); j++ ) {
7264 MInt id=m_haloCells[i][j];
7265 if(m_tree.solver( id, solver )){
7266 debugHalo++;
7267 }
7268 }
7269 for ( MInt j = 0; j < (signed)m_windowCells[i].size(); j++ ) {
7270 MInt id=m_windowCells[i][j];
7271 if(m_tree.solver( id, solver )){
7272 debugWindow++;
7273 }
7274 }
7275
7276 cerr << " neighbor: " << i << "--------------" << endl;
7277 cerr <<"count of halos for solver: " << solver << " : " << debugHalo << endl;
7278 cerr <<"count of windows for solver: " << solver << " : " << debugWindow << endl;
7279 cerr <<"total size halo: " << m_haloCells[i].size() << " window: " << m_windowCells[i].size() << endl;
7280 }
7281 }*/
7282
7283 // Update the partition cells when writing the next restart file (in case this is not previously
7284 // done via updatePartitionCells() during balancing)
7285 // TODO labels:GRID,DLB,ADAPTATION partition files written at final time step might not be usable since partition
7286 // cells are updated during new grid output
7288
7289#ifdef MAIA_GRID_SANITY_CHECKS
7292 if(m_haloMode > 0) // WH_old
7293 checkWindowLayer("meshAdaptation completed: ");
7294#endif
7295
7296 // Set adaptation status
7297 m_wasAdapted = true;
7298
7299 // cout << "dom: " << domainId() << " noNeighborDomains: " << noNeighborDomains() << " windowCell: " <<
7300 // windowCell_pre_size << " noWindowCells: " << noWindowCells_pre_size<< " isWindowPartLvlAncestor: " <<
7301 // isWindowPartLvlAncestor_size << endl;
7302}

◆ minCell()

template<MInt nDim>
MInt CartesianGrid< nDim >::minCell ( const MInt  id) const
inline

Definition at line 557 of file cartesiangrid.h.

557{ return m_minLevelCells[id]; }

◆ minLevel()

template<MInt nDim>
MInt CartesianGrid< nDim >::minLevel ( ) const
inline

Definition at line 790 of file cartesiangrid.h.

790{ return m_minLevel; };

◆ mpiComm()

template<MInt nDim>
MPI_Comm CartesianGrid< nDim >::mpiComm ( ) const
inline

Definition at line 800 of file cartesiangrid.h.

800{ return m_mpiComm; }
const MPI_Comm m_mpiComm

◆ nDim_()

template<MInt nDim>
static constexpr MInt CartesianGrid< nDim >::nDim_ ( )
inlinestaticconstexpr

Definition at line 75 of file cartesiangrid.h.

75{ return nDim; }

◆ neighborDomain()

template<MInt nDim>
const MInt & CartesianGrid< nDim >::neighborDomain ( const MInt  id) const
inline

Definition at line 435 of file cartesiangrid.h.

435{ return m_nghbrDomains[id]; }

◆ neighborDomains()

template<MInt nDim>
const std::vector< MInt > & CartesianGrid< nDim >::neighborDomains ( ) const
inline

Definition at line 438 of file cartesiangrid.h.

438{ return m_nghbrDomains; }

◆ noAzimuthalHaloCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::noAzimuthalHaloCells ( const MInt  domainId) const
inline

Definition at line 509 of file cartesiangrid.h.

509{ return m_azimuthalHaloCells[domainId].size(); }

◆ noAzimuthalNeighborDomains()

template<MInt nDim>
MInt CartesianGrid< nDim >::noAzimuthalNeighborDomains ( ) const
inline

Definition at line 500 of file cartesiangrid.h.

500{ return (signed)m_azimuthalNghbrDomains.size(); }

◆ noAzimuthalUnmappedHaloCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::noAzimuthalUnmappedHaloCells ( ) const
inline

Definition at line 520 of file cartesiangrid.h.

520{ return m_azimuthalUnmappedHaloCells.size(); };

◆ noAzimuthalWindowCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::noAzimuthalWindowCells ( const MInt  domainId) const
inline

Definition at line 529 of file cartesiangrid.h.

529{ return m_azimuthalWindowCells[domainId].size(); }

◆ noCellsGlobal()

template<MInt nDim>
MLong CartesianGrid< nDim >::noCellsGlobal ( ) const
inline

Definition at line 560 of file cartesiangrid.h.

560{ return m_noCellsGlobal; }

◆ noDomains()

template<MInt nDim>
MInt CartesianGrid< nDim >::noDomains ( ) const
inline

Return the total number of domains (total number of ranks in current MPI communicator)

Definition at line 1054 of file cartesiangrid.h.

1054{ return m_noDomains; }

◆ noHaloCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::noHaloCells ( const MInt  domainId) const
inline

Definition at line 444 of file cartesiangrid.h.

444{ return m_haloCells[domainId].size(); }

◆ noHaloLayers() [1/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::noHaloLayers ( ) const
inline

Definition at line 563 of file cartesiangrid.h.

563{ return m_noHaloLayers; }

◆ noHaloLayers() [2/2]

template<MInt nDim>
constexpr MInt CartesianGrid< nDim >::noHaloLayers ( const MInt  solverId) const
inlineconstexpr

Definition at line 564 of file cartesiangrid.h.

564{ return m_noSolverHaloLayers[solverId]; }

◆ noInternalCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::noInternalCells ( ) const
inline

Definition at line 429 of file cartesiangrid.h.

429{ return m_noInternalCells; }

◆ noMinCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::noMinCells ( ) const
inline

Definition at line 554 of file cartesiangrid.h.

554{ return m_minLevelCells.size(); }

◆ noNeighborDomains()

template<MInt nDim>
MInt CartesianGrid< nDim >::noNeighborDomains ( ) const
inline

Definition at line 432 of file cartesiangrid.h.

432{ return (signed)m_nghbrDomains.size(); }

◆ noPartitionCells()

template<MInt nDim>
constexpr MInt CartesianGrid< nDim >::noPartitionCells ( ) const
inlineconstexpr

Definition at line 578 of file cartesiangrid.h.

578{ return m_noPartitionCells; }

◆ noPartitionCellsGlobal()

template<MInt nDim>
MLong CartesianGrid< nDim >::noPartitionCellsGlobal ( ) const
inline

Definition at line 120 of file cartesiangrid.h.

120{ return m_noPartitionCellsGlobal; }

◆ noSolverHaloCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::noSolverHaloCells ( const MInt  domainId,
const MInt  solverId,
const MBool  periodicCells 
) const
inline

Definition at line 489 of file cartesiangrid.h.

489 {
490 MInt cnt = 0;
491 for(const auto& cellId : m_haloCells[domainId]) {
492 if(m_tree.solver(cellId, solverId)) {
493 if(periodicCells || !a_hasProperty(cellId, Cell::IsPeriodic)) ++cnt;
494 }
495 }
496 return cnt;
497 }

◆ noSolverWindowCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::noSolverWindowCells ( const MInt  domainId,
const MInt  solverId 
) const
inline

Definition at line 477 of file cartesiangrid.h.

477 {
478 MInt cnt = 0;
479 for(const auto& cellId : m_windowCells[domainId]) {
480 ASSERT(m_windowLayer_[domainId].find(cellId) != m_windowLayer_[domainId].end(), "");
481 if(m_windowLayer_[domainId].at(cellId).get(solverId) <= m_noSolverHaloLayers[solverId]) {
482 ASSERT(m_tree.solver(cellId, solverId), "");
483 ++cnt;
484 }
485 }
486 return cnt;
487 }

◆ noWindowCells()

template<MInt nDim>
MInt CartesianGrid< nDim >::noWindowCells ( const MInt  domainId) const
inline

Definition at line 454 of file cartesiangrid.h.

454{ return m_windowCells[domainId].size(); }

◆ paraViewPlugin()

template<MInt nDim>
constexpr MBool CartesianGrid< nDim >::paraViewPlugin ( ) const
inlineconstexpr

Definition at line 445 of file cartesiangrid.h.

445{ return m_paraViewPlugin; }
const MBool m_paraViewPlugin

◆ partitionParallel()

template<MInt nDim>
void CartesianGrid< nDim >::partitionParallel ( const MInt  tmpCount,
const MLong  tmpOffset,
const MFloat *const  partitionCellsWorkload,
const MLong *const  partitionCellsGlobalId,
const MFloat  totalWorkload,
MLong partitionCellOffsets,
MLong globalIdOffsets,
MBool  computeOnlyPartition = false 
)
private

Definition at line 10719 of file cartesiangrid.cpp.

10723 {
10724 maia::grid::IO<CartesianGrid<nDim>>::partitionParallel(*this, tmpCount, tmpOffset, partitionCellsWorkload,
10725 partitionCellsGlobalId, totalWorkload, partitionCellOffsets,
10726 globalIdOffsets, computeOnlyPartition);
10727}
void partitionParallel(const MInt tmpCount, const MLong tmpOffset, const MFloat *const partitionCellsWorkload, const MLong *const partitionCellsGlobalId, const MFloat totalWorkload, MLong *partitionCellOffsets, MLong *globalIdOffsets, MBool computeOnlyPartition=false)

◆ periodicCartesianDir()

template<MInt nDim>
MInt CartesianGrid< nDim >::periodicCartesianDir ( const MInt  dir) const
inline

Definition at line 569 of file cartesiangrid.h.

569{ return m_periodicCartesianDir[dir]; }

◆ periodicCartesianLength()

template<MInt nDim>
MFloat CartesianGrid< nDim >::periodicCartesianLength ( const MInt  dir) const
inline

Definition at line 570 of file cartesiangrid.h.

570{ return m_periodicCartesianLength[dir]; }

◆ pointInLocalBoundingBox()

template<MInt nDim>
MBool CartesianGrid< nDim >::pointInLocalBoundingBox ( const MFloat coord)

Checks if given point is inside the local bounding box.

Definition at line 12911 of file cartesiangrid.cpp.

12911 {
12912 // Not initialized, fast check not possible
12914 return true;
12915 }
12916
12917 const MFloat eps = 1e-12;
12918 for(MInt i = 0; i < nDim; i++) {
12919 if(coord[i] < m_localBoundingBox[i] - eps || coord[i] > m_localBoundingBox[nDim + i] + eps) {
12920 return false;
12921 }
12922 }
12923 return true;
12924}

◆ pointWthCell() [1/2]

template<MInt nDim>
template<MBool t_correct, MBool insideLimit>
MBool CartesianGrid< nDim >::pointWthCell ( const MFloat *const  coord,
const MInt  cellId,
std::function< MFloat *(MInt, MFloat *const)>  correctCellCoord = nullptr 
) const
inline

Definition at line 12852 of file cartesiangrid.cpp.

12853 {
12854 array<MFloat, nDim> tmp;
12855 const MFloat* tmpCoord = m_tree.coordinate(cellId);
12856 const MFloat* cellCenter = t_correct ? (correctCellCoord)(cellId, &tmp[0]) : tmpCoord;
12857 const MFloat _halfCellLength = halfCellLength(cellId);
12858 MBool isInCell = true;
12859
12860 if(insideLimit) {
12861 IF_CONSTEXPR(nDim == 3) {
12862 return fabs(cellCenter[0] - coord[0]) <= _halfCellLength && fabs(cellCenter[1] - coord[1]) <= _halfCellLength
12863 && fabs(cellCenter[2] - coord[2]) <= _halfCellLength;
12864 }
12865 return fabs(cellCenter[0] - coord[0]) <= _halfCellLength && fabs(cellCenter[1] - coord[1]) <= _halfCellLength;
12866 } else {
12867 for(MInt dimId = 0; dimId < nDim; dimId++) {
12868 if(coord[dimId] < cellCenter[dimId] - _halfCellLength || coord[dimId] >= cellCenter[dimId] + _halfCellLength) {
12869 isInCell = false;
12870 break;
12871 }
12872 }
12873 }
12874
12875 return isInCell;
12876}

◆ pointWthCell() [2/2]

template<MInt nDim>
template<MBool t_correct = false, MBool insideLimit>
MBool CartesianGrid< nDim >::pointWthCell ( const std::array< MFloat, nDim > &  coord,
const MInt  cellId,
std::function< MFloat *(MInt, MFloat *const)>  correctCellCoord = nullptr 
) const
inline

Definition at line 852 of file cartesiangrid.h.

853 {
854 return pointWthCell<t_correct, insideLimit>(&coord[0], cellId, correctCellCoord);
855 }

◆ propagateDistance()

template<MInt nDim>
void CartesianGrid< nDim >::propagateDistance ( std::vector< MInt > &  list,
MIntScratchSpace distMem,
MInt  dist 
)
Author
Thomas Schilden
Date
18.10.2016

The algorithm does the following:

  1. propagates locally from the local cells in the list in parameter
  2. exchanges the distance and repeats the propagation on the halo cells
Parameters
[in]arrayof cells to propagate from
[in]numberof cells to propagate from
[in]arrayto store the distance
[in]finaldistance

Definition at line 11210 of file cartesiangrid.cpp.

11210 {
11211 TRACE();
11212
11213 m_log << "running distance propagation for distance " << dist << endl;
11214
11215 for(const auto gridCellId : list)
11216 propagationStep(gridCellId, 0, distMem.data(), dist);
11217
11218 if(noNeighborDomains() > 0) {
11219 MIntScratchSpace recvMemOffset(noNeighborDomains() + 1, AT_, "recvMemOffset");
11220 recvMemOffset.fill(0);
11221 MInt allRecv = 0;
11222 for(MInt dom = 0; dom < noNeighborDomains(); dom++) {
11223 allRecv += (signed)m_haloCells[dom].size();
11224 recvMemOffset[dom + 1] = allRecv;
11225 }
11226 MIntScratchSpace recvMem(allRecv, AT_, "recvMem");
11227 MInt checkHalos = 1;
11228 MInt nmbrComm = 0;
11229 m_log << "checking halos" << endl;
11230 while(checkHalos) {
11231 checkHalos = 0;
11232 // exchange distance
11233 exchangeNotInPlace(distMem.data(), recvMem.data());
11234 // update halo cells and propagate
11235 for(MInt dom = 0; dom < noNeighborDomains(); dom++) {
11236 for(MInt cell = 0; cell < (signed)m_haloCells[dom].size(); cell++) {
11237 MInt windowDist = recvMem[recvMemOffset[dom] + cell];
11238 MInt haloDist = distMem[m_haloCells[dom][cell]];
11239 if(windowDist < haloDist) {
11240 propagationStep(m_haloCells[dom][cell], windowDist, distMem.data(), dist);
11241 checkHalos = 1;
11242 }
11243 }
11244 }
11245 MPI_Allreduce(MPI_IN_PLACE, &checkHalos, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "checkHalos");
11246 if(checkHalos) {
11247 nmbrComm++;
11248 m_log << "checking halos again " << nmbrComm << endl;
11249 }
11250 }
11251 }
11252}
void exchangeNotInPlace(DATATYPE *exchangeVar, DATATYPE *recvMem)
communicates a variable from windows to halos but does not overwrite halo values. Window values are s...
void propagationStep(MInt cellId, MInt dist, MInt *distMem, MInt endDist)
starts the propagation on a cell and continues calling the function for the neighbours
pointer data()
Definition: scratch.h:289

◆ propagationStep()

template<MInt nDim>
void CartesianGrid< nDim >::propagationStep ( MInt  cellId,
MInt  dist,
MInt distMem,
MInt  endDist 
)
Author
Thomas Schilden
Date
18.10.2016
Parameters
[in]cellId
[in]currentdistance
[in]arrayto store the distance
[in]finaldistance

Definition at line 11267 of file cartesiangrid.cpp.

11267 {
11268 TRACE();
11269 if(dist < distMem[cellId]) {
11270 distMem[cellId] = dist;
11271 if(dist < endDist) {
11272 for(MInt i = 0; i < 2 * nDim; i++) {
11273 const MInt nghbrId = a_neighborId(cellId, i);
11274 if(nghbrId > -1) propagationStep(nghbrId, dist + 1, distMem, endDist);
11275 }
11276 }
11277 }
11278}

◆ reduceToLevel()

template<MInt nDim>
template<class F >
MInt CartesianGrid< nDim >::reduceToLevel ( const MInt  reductionLevel,
interpolateToParentCells 
)
Author
Andreas Lintermann
Date
26.08.2012

The current grid is reduced by calling interpolateToParentCells.

Requires rewriting of certain arrays for the execution of the other subroutines:

  1. Save the globalIds of the window/halocells for later identification
  2. Reallocate m_windowCells and m_haloCells (saveGridDomain requires the arrays to be of size m_noDomains, currenty has size noNeighborDomains())
  3. Delete all cells above a certain level provided by m_reductionLevel, uses deleteCell from CartesianGrid
  4. Update the m_windowCell and m_haloCell arrays, therefore also reallocate these arrays (required by saveGridDomainPar)
  5. Update m_domainOffsets since the sizes of the Collectors for each process has changed, this requires global communication (this is required by the IO routine of the solver)

Definition at line 1091 of file cartesiangrid.h.

1091 {
1092 TRACE();
1093 // 1. before we delete, generate a copy of the global ids for the domains so
1094 // that we can identify them later (as the global id will not be updated
1095 // during delete cell)
1096 std::vector<std::vector<MInt>> old_globalhaloCells, old_globalwindowCells;
1097
1098 for(MInt i = 0; i < noNeighborDomains(); i++) {
1099 std::vector<MInt> tmp_halo;
1100 std::vector<MInt> tmp_window;
1101 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
1102 tmp_halo.push_back(a_globalId(m_haloCells[i][j]));
1103 }
1104 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
1105 tmp_window.push_back(a_globalId(m_windowCells[i][j]));
1106 }
1107 old_globalhaloCells.push_back(tmp_halo);
1108 old_globalwindowCells.push_back(tmp_window);
1109 }
1110
1111 // 2. we need to realloc m_haloCells and m_windowCells so that we
1112 // suit the requirements of saveGridDomainPar
1113 m_haloCells.clear();
1114 m_windowCells.clear();
1115 m_haloCells.resize(noDomains());
1116 m_windowCells.resize(noDomains());
1117
1118 // 3. Delete all cells that are above a certain level, interpolate all
1119 // finer cells to coarser cells
1120 for(MInt level = m_maxLevel; level > reductionLevel; level--) {
1121 interpolateToParentCells(level - 1);
1122 for(MInt c = m_tree.size() - 1; c >= 0; c--) {
1123 if(a_level(c) == level) {
1124 deleteCell(c);
1125 }
1126 }
1127 }
1129
1130 // 4. Update window and halo cell arrays
1131
1132 for(MInt c = 0; c < m_tree.size(); c++) {
1133 if(a_hasProperty(c, Cell::IsHalo)) {
1134 MInt nghr = -1;
1135 for(MInt i = 0; i < noNeighborDomains(); i++) {
1136 for(std::size_t j = 0; j < old_globalhaloCells[i].size(); j++)
1137 if(a_globalId(c) == old_globalhaloCells[i][j]) {
1138 nghr = i;
1139 break;
1140 }
1141 if(nghr != -1) {
1142 break;
1143 }
1144 }
1145 m_haloCells[m_nghbrDomains[nghr]].push_back(c);
1146
1147 } else if(a_hasProperty(c, Cell::IsWindow)) {
1148 MInt nghr = -1;
1149 std::vector<MInt> t;
1150 for(MInt i = 0; i < noNeighborDomains(); i++) {
1151 for(std::size_t j = 0; j < old_globalwindowCells[i].size(); j++)
1152 if(a_globalId(c) == old_globalwindowCells[i][j]) {
1153 nghr = i;
1154 t.push_back(i);
1155 break;
1156 }
1157 if(nghr != -1) {
1158 continue;
1159 }
1160 }
1161 for(MInt& i : t) {
1162 m_windowCells[m_nghbrDomains[i]].push_back(c);
1163 }
1164 }
1165 }
1166
1167
1168 // Update the number of internal cells
1169 for(MInt i = 0; i < noDomains(); i++) {
1170 m_noInternalCells -= (signed)m_haloCells[i].size();
1171 }
1172
1173 // 5. Update m_domainOffsets
1174 MIntScratchSpace rcvBufRed(noDomains(), AT_, "rcvBufRed");
1175
1176 // fill buffer and exchange
1177 MPI_Allgather(&(m_noInternalCells), 1, MPI_INT, rcvBufRed.begin(), 1, MPI_INT, mpiComm(), AT_, "(m_noInternalCells)",
1178 "rcvBufRed.begin()");
1179
1180 // put the result into the array
1181 MInt offset = 0;
1182 for(MInt i = 0; i < noDomains(); i++) {
1183 m_domainOffsets[i] = offset;
1184 offset += rcvBufRed[i];
1185 }
1186 // the last element holds the total number
1187 m_domainOffsets[noDomains()] = offset;
1188
1189 return rcvBufRed[domainId()];
1190}

◆ reductionFactor()

template<MInt nDim>
MFloat CartesianGrid< nDim >::reductionFactor ( ) const
inline

Definition at line 545 of file cartesiangrid.h.

545{ return m_reductionFactor; }

◆ refineCell()

template<MInt nDim>
void CartesianGrid< nDim >::refineCell ( const MInt  cellId,
const MLong *const  refineChildIds = nullptr,
const MBool  mayHaveChildren = false,
const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &  cellOutsideSolver = std::vector<std::function<MInt(const MFloat*, const MInt, const MInt)>>(),
const std::bitset< maia::grid::tree::Tree< nDim >::maxNoSolvers()>  refineFlag = std::bitset<maia::grid::tree::Tree<nDim>::maxNoSolvers()>(1ul) 
)
private

Refine the cells with the given ids.

Author
Lennart Schneiders
Date
12.12.2012

This function only creates the geometrical data for new cells, the initialization of flow variables must be dealt with by the corresponding solver classes.

Definition at line 5822 of file cartesiangrid.cpp.

5825 {
5826 static constexpr MInt noInternalConnections = (nDim == 2) ? 4 : 12;
5827 static constexpr MInt connectionDirs[12] = {1, 1, 3, 3, 1, 1, 3, 3, 5, 5, 5, 5};
5828 static constexpr MInt childs0[12] = {0, 2, 0, 1, 4, 6, 4, 5, 0, 1, 2, 3};
5829 static constexpr MInt childs1[12] = {1, 3, 2, 3, 5, 7, 6, 7, 4, 5, 6, 7};
5830 static constexpr MInt dirStencil[3][8] = {
5831 {0, 1, 0, 1, 0, 1, 0, 1}, {2, 2, 3, 3, 2, 2, 3, 3}, {4, 4, 4, 4, 5, 5, 5, 5}};
5832 static constexpr MInt sideIds[3][8] = {{0, 1, 0, 1, 0, 1, 0, 1}, {0, 0, 1, 1, 0, 0, 1, 1}, {0, 0, 0, 0, 1, 1, 1, 1}};
5833 static constexpr MInt revDir[6] = {1, 0, 3, 2, 5, 4};
5834 static constexpr MInt otherSide[2] = {1, 0};
5835 static constexpr MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
5836 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
5837
5838 ASSERT(m_maxRfnmntLvl >= m_maxLevel, "");
5839 if(a_level(cellId) >= m_maxRfnmntLvl) return;
5840
5841 const MInt childLevel = a_level(cellId) + 1;
5842 const MFloat childCellLength = cellLengthAtLevel(childLevel);
5843
5844 MInt noOutsideChilds = 0;
5845 for(MInt c = 0; c < m_maxNoChilds; c++) {
5847 std::fill_n(isOutside, maia::grid::tree::Tree<nDim>::maxNoSolvers(), -1);
5848
5849 if(!mayHaveChildren && a_childId(cellId, c) > -1) {
5850 // mTerm(1, AT_, "Not supposed to happen." );
5851 }
5852
5853 if(a_childId(cellId, c) > -1) continue;
5854
5855 if(refineChildIds != nullptr && refineChildIds[c] < 0) {
5856 a_childId(cellId, c) = -1;
5857 continue;
5858 }
5859
5860 MFloat coords[nDim];
5861 for(MInt i = 0; i < nDim; i++) {
5862 coords[i] = a_coordinate(cellId, i) + F1B2 * signStencil[c][i] * childCellLength;
5863 }
5864 MInt allOutside = 0;
5865 if(!cellOutsideSolver.empty()) {
5866 allOutside = 1;
5867 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
5868 if(refineFlag[solver]) {
5869 isOutside[solver] = cellOutsideSolver[solver](coords, childLevel, cellId);
5870 } else {
5871 isOutside[solver] = 1;
5872 }
5873 allOutside = mMin(allOutside, isOutside[solver]); // call cellOutsideSolver() function in each solver
5874 }
5875 }
5876 if(allOutside > 0) {
5877 noOutsideChilds++;
5878 a_childId(cellId, c) = -1;
5879 continue;
5880 }
5881
5882 MInt childId;
5883 if(m_freeIndices.size() > 0) {
5884 auto it = m_freeIndices.begin();
5885 childId = *(it);
5886 m_freeIndices.erase(it);
5887 ASSERT(childId > -1 && childId < m_tree.size(), "");
5888 } else {
5889 childId = m_tree.size();
5890 m_tree.append();
5891 }
5892
5893 for(MInt i = 0; i < nDim; i++) {
5894 a_coordinate(childId, i) = coords[i];
5895 }
5896
5897 if(refineChildIds != nullptr) {
5898 a_globalId(childId) = refineChildIds[c];
5899 } else {
5900 a_globalId(childId) = -1;
5901 }
5902
5903 treeb().resetSolver(childId);
5904 MBool any = false;
5905 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
5906 if(refineFlag[solver] && isOutside[solver] < 1) treeb().solver(childId, solver) = true;
5907 any = any || m_tree.solver(childId, solver);
5908 }
5909 ASSERT(any, "");
5910
5911 a_level(childId) = childLevel;
5912
5913 a_childId(cellId, c) = childId;
5914 a_parentId(childId) = cellId;
5915 a_isToDelete(childId) = false;
5916 a_resetProperties(childId);
5917 a_hasProperty(childId, Cell::IsHalo) = (refineChildIds != nullptr);
5918 // a_hasProperty( cellId, Cell::IsHalo);
5919 // a_hasProperty( childId, Cell::IsPeriodic) = a_hasProperty( cellId, Cell::IsPeriodic);
5920
5921 for(MInt k = 0; k < m_maxNoChilds; k++)
5922 a_childId(childId, k) = -1;
5923 for(MInt d = 0; d < 2 * nDim; d++) {
5924 a_neighborId(childId, d) = -1;
5925 }
5926
5927 if(treeb().noSolvers() == 1) {
5928 treeb().solver(childId, 0) = true; // remove if multisolver info set correctly!!!
5929 }
5930
5931 treeb().resetIsLeafCell(childId);
5932
5933 MInt nodeId[3];
5934 MInt revNodeId[3];
5935 for(MInt i = 0; i < nDim; i++) {
5936 nodeId[i] = sideIds[i][c] * IPOW2(i);
5937 revNodeId[i] = otherSide[sideIds[i][c]] * IPOW2(i);
5938 }
5939 for(MInt d = 0; d < nDim; d++) {
5940 const MInt dir = dirStencil[d][c];
5941 if(a_hasNeighbor(cellId, dir) == 0) {
5942 a_neighborId(childId, dir) = -1;
5943 } else if(a_noChildren(a_neighborId(cellId, dir)) == 0) {
5944 a_neighborId(childId, dir) = -1;
5945 } else {
5946 const MInt childNode = c - nodeId[d] + revNodeId[d];
5947 const MInt nghbrId = a_childId(a_neighborId(cellId, dir), childNode);
5948 if(nghbrId < 0) {
5949 a_neighborId(childId, dir) = -1;
5950 continue;
5951 }
5952 a_neighborId(childId, dir) = nghbrId;
5953 a_neighborId(nghbrId, revDir[dir]) = childId;
5954 }
5955 }
5956 a_hasProperty(childId, Cell::WasNewlyCreated) = true;
5957
5958 // Set a default weight and the number of offspring
5959 a_weight(childId) = 1.0;
5960 a_noOffsprings(childId) = 1;
5961 }
5962
5963 if(noOutsideChilds == m_maxNoChilds) {
5964 // all childs are outside!
5965 // NOTE: this occours when there is a difference in the geometry used in the grid-generation
5966 // geometryroot.cpp-isPointInsideNode and
5967 // geometry.cpp-pointIsInside of the geometry during the solver run!
5968 // FIX: call again but this time without the solver-Outside check,
5969 // meaning that all cells will be refined instead!
5970 // NOTE: How is that a fix?
5971 const std::vector<std::function<MInt(const MFloat*, const MInt, const MInt)>> cellOutsideEmpty;
5972 refineCell(cellId, nullptr, false, cellOutsideEmpty, refineFlag);
5973 return;
5974 }
5975
5976
5977 ASSERT(noOutsideChilds < m_maxNoChilds,
5978 to_string(noOutsideChilds) + "Check your geometry: all childs are outside or should not be refined! ");
5979 ASSERT(a_noChildren(cellId) > 0, "");
5980 treeb().resetIsLeafCell(cellId);
5981
5982 for(MInt c = 0; c < noInternalConnections; c++) {
5983 const MInt dir = connectionDirs[c];
5984 const MInt child0 = a_childId(cellId, childs0[c]);
5985 const MInt child1 = a_childId(cellId, childs1[c]);
5986 if(child0 > -1 && child1 > -1) {
5987 a_neighborId(child0, dir) = child1;
5988 a_neighborId(child1, revDir[dir]) = child0;
5989 }
5990 }
5991
5992 a_hasProperty(cellId, Cell::WasRefined) = true;
5993}
Class that represents grid tree and contains all relevant per-node data.
static constexpr MInt maxNoSolvers()
Return maximum number of supported solvers.
void resetSolver(const MInt id)
Reset all solver use.

◆ refineCheck()

template<MInt nDim>
MBool CartesianGrid< nDim >::refineCheck ( const MInt  cellId,
const MInt  solver,
const std::vector< std::function< MInt(const MFloat *, const MInt, const MInt)> > &  cellOutsideSolver 
)
private
Author
Lennart Schneiders

Definition at line 8815 of file cartesiangrid.cpp.

8817 {
8818 // Enable grid checks for LB (refinement)
8819 MBool restrictDiagonalLevelJumps = m_lbGridChecks;
8820 MBool extendCheckTo2ndNeighbor = m_lbGridChecks;
8821
8822 ASSERT(m_tree.solver(cellId, solver), "");
8823 for(MInt dir = 0; dir < m_noDirs; dir++) {
8824 if(a_hasNeighbor(cellId, dir, solver)) {
8825 if(restrictDiagonalLevelJumps) {
8826 MInt d0 = dir / 2;
8827 MInt d1 = (d0 + 1) % nDim;
8828 for(MInt p = 0; p < 2; p++) {
8829 MInt dir1 = 2 * d1 + p;
8830 if(a_hasNeighbor(a_neighborId(cellId, dir, solver), dir1, solver) == 0) {
8831 return false;
8832 }
8833
8834 // Ensure two diagonal neigbors to avoid double interpolation in LB
8835 // For readability introduce names of cells
8836 MInt firstDiagNghbor;
8837 if(extendCheckTo2ndNeighbor) {
8838 firstDiagNghbor = a_neighborId(a_neighborId(cellId, dir, solver), dir1, solver);
8839 if(a_hasNeighbor(firstDiagNghbor, dir, solver)) {
8840 if(a_hasNeighbor(a_neighborId(firstDiagNghbor, dir, solver), dir1, solver) == 0) {
8841 return false;
8842 }
8843 } else {
8844 return false;
8845 }
8846 }
8847
8848 // From last merge: else if. But this crashes 3D case. Thus change to if
8849 IF_CONSTEXPR(nDim == 3) {
8850 MInt d2 = (d1 + 1) % nDim;
8851 for(MInt q = 0; q < 2; q++) {
8852 MInt dir2 = 2 * d2 + q;
8853 if(a_hasNeighbor(a_neighborId(a_neighborId(cellId, dir, solver), dir1, solver), dir2, solver) == 0) {
8854 return false;
8855 }
8856
8857 // Ensure two diagonal neigbors (corner) to avoid double interpolation in LB
8858 // The step-wise procedure is necessary to ensure "filling" between neighbors
8859 MInt firstCornerNeighbor =
8860 a_neighborId(a_neighborId(a_neighborId(cellId, dir, solver), dir1, solver), dir2, solver);
8861 if(extendCheckTo2ndNeighbor) {
8862 if(a_hasNeighbor(firstCornerNeighbor, dir, solver)) {
8863 if(a_hasNeighbor(a_neighborId(firstCornerNeighbor, dir, solver), dir1, solver)) {
8864 if(a_hasNeighbor(a_neighborId(a_neighborId(firstCornerNeighbor, dir, solver), dir1, solver), dir2,
8865 solver)
8866 == 0) {
8867 return false;
8868 }
8869 } else {
8870 return false;
8871 }
8872 } else {
8873 return false;
8874 }
8875 }
8876 }
8877 }
8878 }
8879 }
8880 } else if(m_allowInterfaceRefinement && hasCutOff()) {
8881 // continue;
8882 // check if the cell is a cutOff cell
8883 // meaning that the largest parent doesn't have a neighbor in that direction!
8884
8885 MInt parentId = a_parentId(cellId, solver);
8886 if(parentId > -1 && !a_hasNeighbor(parentId, dir, solver)) {
8887 continue;
8888 } else if(parentId > -1) {
8889 return false;
8890 }
8891
8892 } else if(m_allowInterfaceRefinement) {
8893 MFloat coords[nDim];
8894 for(MInt k = 0; k < nDim; k++) {
8895 coords[k] = a_coordinate(cellId, k);
8896 }
8897 coords[dir / 2] += ((dir % 2 == 0) ? -F1 : F1) * cellLengthAtCell(cellId);
8898 MInt isOutside = cellOutsideSolver[solver](coords, a_level(cellId), cellId);
8899 if(isOutside == 0) {
8900 return false;
8901 } else if(isOutside == -1) {
8902 MInt parentId = a_parentId(cellId, solver);
8903 while(parentId > -1) {
8904 if(a_hasNeighbor(parentId, dir, solver)) {
8905 return false;
8906 }
8907 parentId = a_parentId(parentId, solver);
8908 }
8909 }
8910 } else {
8911 return false;
8912 }
8913 }
8914 return true;
8915}
MBool hasCutOff() const
Returns weather the grid has a cutOff.
Definition: cartesiangrid.h:83

◆ removeCell()

template<MInt nDim>
template<MBool removeChilds_>
void CartesianGrid< nDim >::removeCell ( const MInt  cellId)
private
Author
Lennart Schneiders

Definition at line 6031 of file cartesiangrid.cpp.

6031 {
6032 static constexpr MInt revDir[6] = {1, 0, 3, 2, 5, 4};
6033
6034 ASSERT(cellId > -1 && cellId < treeb().size(), "");
6035 ASSERT(a_noChildren(cellId) == 0, "No children expected for child. ");
6036 ASSERT(!a_hasProperty(cellId, Cell::IsPartitionCell) || a_hasProperty(cellId, Cell::IsHalo),
6037 "Error: cannot remove non-halo partition cell");
6038
6039 for(MInt dir = 0; dir < m_noDirs; dir++) {
6040 if(a_hasNeighbor(cellId, dir) > 0) {
6041 MInt nghbrId = a_neighborId(cellId, dir);
6042 if((nghbrId < 0) || (nghbrId >= treeb().size())) {
6043 mTerm(1, AT_,
6044 "Unexpected situation 2 in CartesianGrid::removeChildIds() >> " + to_string(cellId) + " " + to_string(dir)
6045 + " " + to_string(nghbrId) + " " + to_string(treeb().size()));
6046 }
6047 a_neighborId(nghbrId, revDir[dir]) = -1;
6048 a_neighborId(cellId, dir) = -1;
6049 } else {
6050 a_neighborId(cellId, dir) = -1;
6051 }
6052 }
6053 const MInt parentId = a_parentId(cellId);
6054 a_parentId(cellId) = -1;
6055 a_globalId(cellId) = -1;
6056 treeb().resetSolver(cellId);
6057
6058 a_resetProperties(cellId);
6059
6060 a_isToDelete(cellId) = true;
6061
6062 a_level(cellId) = -1;
6063 treeb().resetIsLeafCell(cellId);
6064
6065 if(cellId == (treeb().size() - 1)) {
6066 treeb().size(treeb().size() - 1);
6067 } else {
6068 m_freeIndices.insert(cellId);
6069 }
6070
6071 // return early if called from inside removeChilds
6072 if(removeChilds_ || parentId == -1) return;
6073
6074 ASSERT(parentId < treeb().size(), "");
6075
6076 //
6077 for(MInt i = 0; i < m_maxNoChilds; i++) {
6078 if(a_childId(parentId, i) == cellId) {
6079 a_childId(parentId, i) = -1;
6080 break;
6081 }
6082 }
6083
6084 //
6085 treeb().resetIsLeafCell(parentId);
6086 for(MInt solverId = 0; solverId < m_tree.noSolvers(); solverId++) {
6087 if(m_tree.solver(parentId, solverId)) {
6088 a_isLeafCell(parentId, solverId) =
6089 !a_hasChildren(parentId, solverId) && !a_hasProperty(parentId, Cell::IsPartLvlAncestor);
6090 }
6091 }
6092}

◆ removeChilds()

template<MInt nDim>
void CartesianGrid< nDim >::removeChilds ( const MInt  cellId)
private
Author
Lennart Schneiders

Definition at line 6004 of file cartesiangrid.cpp.

6004 {
6005 TRACE();
6006
6007 if(a_noChildren(cellId) <= 0) {
6008 mTerm(1, AT_, "Unexpected situation 1 in CartesianGrid::removeChilds(MInt childId)");
6009 }
6010 for(MInt i = 0; i < m_maxNoChilds; i++) {
6011 const MInt childId = a_childId(cellId, i);
6012
6013 if(childId > -1) {
6014 removeCell<true>(childId);
6015 a_childId(cellId, i) = -1;
6016 }
6017
6018 treeb().resetIsLeafCell(cellId);
6019 }
6020
6021 a_hasProperty(cellId, Cell::WasCoarsened) = true;
6022}

◆ resetCell()

template<MInt nDim>
void CartesianGrid< nDim >::resetCell ( const MInt cellId)
inlineprivate
Author
Lennart Schneiders

Definition at line 9148 of file cartesiangrid.cpp.

9148 {
9149 a_resetProperties(cellId);
9150 m_tree.resetSolver(cellId);
9151 m_tree.resetIsLeafCell(cellId);
9152 a_parentId(cellId) = -1;
9153 a_globalId(cellId) = -1;
9154 a_level(cellId) = -1;
9155 a_noOffsprings(cellId) = 0;
9156 a_weight(cellId) = F1;
9157 a_workload(cellId) = F0;
9158 fill(&a_childId(cellId, 0), &a_childId(cellId, 0) + m_maxNoChilds, -1);
9159 fill(&a_neighborId(cellId, 0), &a_neighborId(cellId, 0) + m_maxNoNghbrs, -1);
9160}
const MInt m_maxNoNghbrs

◆ restorePeriodicConnection()

template<MInt nDim>
void CartesianGrid< nDim >::restorePeriodicConnection
Author
Tim Wegmann

Definition at line 10670 of file cartesiangrid.cpp.

10670 {
10671 TRACE();
10672
10673 for(MUint i = 0; i < m_neighborBackup.size(); i++) {
10674 MInt cellId = get<0>(m_neighborBackup[i]);
10675 MInt nghbrId = get<1>(m_neighborBackup[i]);
10676 MInt dir = get<2>(m_neighborBackup[i]);
10677 a_neighborId(cellId, dir) = nghbrId;
10678 a_neighborId(nghbrId, m_revDir[dir]) = cellId;
10679 }
10680 m_neighborBackup.clear();
10681}

◆ rotateCartesianCoordinates()

template<MInt nDim>
void CartesianGrid< nDim >::rotateCartesianCoordinates ( MFloat coords,
MFloat  angle 
)
Author
Thomas Hoesgen
Date
November 2020

Definition at line 13748 of file cartesiangrid.cpp.

13748 {
13749 TRACE();
13750
13751 MFloat tmpCoords[nDim];
13752
13753 for(MInt d = 0; d < nDim; d++) {
13754 tmpCoords[d] = coords[d] - m_azimuthalPerCenter[d];
13755 }
13756
13757 coords[m_azimuthalPeriodicDir[0]] =
13758 tmpCoords[m_azimuthalPeriodicDir[0]] * cos(angle) - tmpCoords[m_azimuthalPeriodicDir[1]] * sin(angle);
13759 coords[m_azimuthalPeriodicDir[1]] =
13760 tmpCoords[m_azimuthalPeriodicDir[0]] * sin(angle) + tmpCoords[m_azimuthalPeriodicDir[1]] * cos(angle);
13761
13762 for(MInt d = 0; d < nDim; d++) {
13763 coords[d] += m_azimuthalPerCenter[d];
13764 }
13765}
T cos(const T a, const T b, const T x)
Cosine slope filter.
Definition: filter.h:125

◆ saveDonorGridPartition()

template<MInt nDim>
void CartesianGrid< nDim >::saveDonorGridPartition ( const MString gridMapFileName,
const MString gridPartitionFileName 
)
private
Author
Michael Schlottke-Lakemper (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-07-07
Parameters
[in]gridMapFileNameName of the grid map that was already generated.
[in]gridPartitionFileNameName of the partition file to use.

Store the grid partition information for a given donor grid and for the current number of MPI ranks. Works by finding the global cell id of the first mapped cell in the grid map file.

Definition at line 9747 of file cartesiangrid.cpp.

9747 {
9748 TRACE();
9749
9750 using namespace maia::parallel_io;
9751
9752 // Open grid map file and read mapping information
9753 ParallelIo gridMapFile(gridMapFileName, PIO_READ, mpiComm());
9754 MString donorGridFileName;
9755 gridMapFile.getAttribute(&donorGridFileName, "donorGridFileName");
9756 gridMapFile.setOffset(m_noInternalCells, m_domainOffsets[domainId()]);
9757 MIntScratchSpace gridMap(m_noInternalCells, AT_, "gridMap");
9758 gridMapFile.readArray(&gridMap[0], "cellIds");
9759
9760 m_log << "Saving grid partition for donor grid " << donorGridFileName << " and writing the results to "
9761 << gridPartitionFileName << "..." << endl;
9762
9763 // Determine global cell id of first mapped cell on this domain
9764 auto c = find_if(gridMap.begin(), gridMap.end(), [](const MInt a) { return a != -1; });
9765 const MInt cellId = (c == end(gridMap)) ? -1 : *c;
9766
9767 // Open grid partition file and write to it
9768 ParallelIo file(gridPartitionFileName, PIO_REPLACE, mpiComm());
9769 file.setAttribute(m_gridInputFileName, "targetGridFileName");
9770 file.setAttribute(donorGridFileName, "gridFile");
9771 file.defineArray(PIO_INT, "firstCellIds", noDomains());
9772 file.setOffset(1, domainId());
9773 file.writeArray(&cellId, "firstCellIds");
9774
9775 m_log << "Saved grid partition file." << endl;
9776}

◆ saveGrid() [1/2]

template<MInt nDim>
void CartesianGrid< nDim >::saveGrid ( const MChar fileName,
const std::vector< std::vector< MInt > > &  haloCells,
const std::vector< std::vector< MInt > > &  windowCells,
const std::vector< std::vector< MInt > > &  azimuthalHaloCells,
const std::vector< MInt > &  azimuthalUnmappedHaloCells,
const std::vector< std::vector< MInt > > &  azimuthalWindowCells,
MInt recalcIdTree = nullptr 
)

Definition at line 9005 of file cartesiangrid.cpp.

9009 {
9010 TRACE();
9011 maia::grid::IO<CartesianGrid<nDim>>::save(*this, fileName, static_cast<Collector<void>*>(nullptr), haloCells,
9012 windowCells, azimuthalHaloCells, azimuthalUnmappedHaloCells,
9013 azimuthalWindowCells, recalcIdTree);
9014}
const std::vector< std::vector< MInt > > & azimuthalWindowCells() const
const std::vector< std::vector< MInt > > & azimuthalHaloCells() const

◆ saveGrid() [2/2]

template<MInt nDim>
void CartesianGrid< nDim >::saveGrid ( const MChar fileName,
MInt recalcIdTree 
)

Definition at line 9017 of file cartesiangrid.cpp.

9017 {
9018 TRACE();
9019
9020 if(m_newMinLevel < 0) {
9021 maia::grid::IO<CartesianGrid<nDim>>::save(*this, fileName, static_cast<Collector<void>*>(nullptr), m_haloCells,
9023 m_azimuthalWindowCells, recalcIdTree);
9024
9025 } else { // if possible Increase MinLevel when writing the restart-File!
9026 // if the m_targetGridMinLevel has already been updated, the new grid restartFile
9027 // is forced without a backup and further check!
9028
9030 maia::grid::IO<CartesianGrid<nDim>>::save(*this, fileName, static_cast<Collector<void>*>(nullptr), m_haloCells,
9032 m_azimuthalWindowCells, recalcIdTree);
9033 } else if(noDomains() > 1) {
9034 MInt backup = m_newMinLevel;
9035 m_newMinLevel = -1;
9036 maia::grid::IO<CartesianGrid<nDim>>::save(*this, fileName, static_cast<Collector<void>*>(nullptr), m_haloCells,
9038 m_azimuthalWindowCells, recalcIdTree);
9039 m_newMinLevel = backup;
9040
9041 } else {
9042 // check that all minLevels are refined
9043 MInt noUnrefinedMinCells = 0;
9044 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
9045 if(a_isHalo(cellId)) continue;
9046 if(a_level(cellId) < m_newMinLevel) {
9047 if(a_noChildren(cellId) < 1) noUnrefinedMinCells++;
9048 }
9049 }
9050
9051 MPI_Allreduce(MPI_IN_PLACE, &noUnrefinedMinCells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
9052 "noUnrefinedMinCells");
9053
9054 // if the minLevel cells are not sufficiently refiened a reguar output is wirtten
9055 if(noUnrefinedMinCells > 0) {
9056 MInt backup = m_newMinLevel;
9057 if(domainId() == 0) {
9058 cerr << "Mincells not yet sufficiently refined for minLevel increase from " << m_minLevel << " to "
9059 << m_newMinLevel << "!" << endl;
9060 }
9061 m_newMinLevel = -1;
9062 maia::grid::IO<CartesianGrid<nDim>>::save(*this, fileName, static_cast<Collector<void>*>(nullptr), m_haloCells,
9064 m_azimuthalWindowCells, recalcIdTree);
9065 m_newMinLevel = backup;
9066
9067 } else { // writing the restartGrid with increased minLevel!
9068
9069 // write the original grid as backup
9070 MInt backupMinLevel = m_newMinLevel;
9071 m_newMinLevel = -1;
9073 std::stringstream s;
9074 s << "restartGrid_backup_" << globalTimeStep << ParallelIo::fileExt();
9075 MString newGridFileName = s.str();
9076
9078 *this, (m_outputDir + newGridFileName).c_str(), static_cast<Collector<void>*>(nullptr), m_haloCells,
9080
9081 m_newMinLevel = backupMinLevel;
9083
9084 if(domainId() == 0) {
9085 cerr << "Increasing minLevel from " << m_minLevel << " to " << m_newMinLevel << endl;
9086 }
9087
9088 MInt backupUniform = m_maxUniformRefinementLevel;
9090 if(domainId() == 0) {
9091 cerr << "Increasing maxUniformRefinementLevel from " << m_maxUniformRefinementLevel << " to "
9092 << m_newMinLevel << endl;
9093 }
9095 }
9096 // writing the new grid
9097 maia::grid::IO<CartesianGrid<nDim>>::save(*this, fileName, static_cast<Collector<void>*>(nullptr), m_haloCells,
9099 m_azimuthalWindowCells, recalcIdTree);
9100
9101 m_maxUniformRefinementLevel = backupUniform;
9102 }
9103 }
9104 }
9105}
MInt globalTimeStep

◆ savePartitionCellWorkloadsGridFile()

template<MInt nDim>
void CartesianGrid< nDim >::savePartitionCellWorkloadsGridFile

Definition at line 12824 of file cartesiangrid.cpp.

12824 {
12825 TRACE();
12826 using namespace parallel_io;
12827
12828 ParallelIo parallelIo(m_restartDir + gridInputFileName(), PIO_APPEND, mpiComm());
12829
12830 // Set offset and total size for partition-cell workloads
12831 const MInt noLocalPartitionCells = m_noPartitionCells;
12832 parallelIo.setOffset(noLocalPartitionCells, m_localPartitionCellOffsets[0]);
12833
12834 // Write new partition-cell workloads to grid file
12835 ScratchSpace<MFloat> partitionCellsWorkload(noLocalPartitionCells, AT_, "partitionCellsWorkload");
12836 MFloat totalWorkload = 0.0;
12837 for(MInt i = 0; i < noLocalPartitionCells; i++) {
12838 const MInt partitionCellId = m_localPartitionCellLocalIds[i];
12839 partitionCellsWorkload[i] = a_workload(partitionCellId);
12840 totalWorkload += a_workload(partitionCellId);
12841 }
12842
12843 MPI_Allreduce(MPI_IN_PLACE, &totalWorkload, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "totalWorkload");
12844 // TODO labels:GRID,IO @ansgar set other attributes as well, e.g. partitionCellMaxWorkload, ...
12845 parallelIo.setAttributes(&totalWorkload, "totalWorkload", 1);
12846 parallelIo.writeArray(&partitionCellsWorkload[0], "partitionCellsWorkload");
12847}
MString gridInputFileName() const
Return grid file name.

◆ savePartitionFile() [1/2]

template<MInt nDim>
void CartesianGrid< nDim >::savePartitionFile
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de

Definition at line 12782 of file cartesiangrid.cpp.

12782 {
12783 TRACE();
12784
12785 stringstream fileName;
12786 fileName << "partition_n" << noDomains() << "_" << globalTimeStep;
12787
12789}
void savePartitionFile()
Save current grid partitioning to file.

◆ savePartitionFile() [2/2]

template<MInt nDim>
void CartesianGrid< nDim >::savePartitionFile ( const MString partitionFileNameBase,
const MLong  partitionCellOffset 
)
private
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Parameters
[in]partitionFileNameBaseOutput base file name.
[in]partitionCellOffsetLocal partition-cell offset.

Definition at line 12756 of file cartesiangrid.cpp.

12756 {
12757 TRACE();
12758
12759 using namespace maia::parallel_io;
12760
12761 stringstream partitionFileName;
12762 partitionFileName << m_outputDir << partitionFileNameBase << ParallelIo::fileExt();
12763
12764 // Open grid partition file and write to it
12765 ParallelIo file(partitionFileName.str(), PIO_REPLACE, mpiComm());
12766
12768 file.setAttributes(&noPartitionCells, "noPartitionCells", 1);
12769
12770 file.defineArray(PIO_LONG, "partitionCellOffset", noDomains());
12771 file.setOffset(1, domainId());
12772 file.writeArray(&partitionCellOffset, "partitionCellOffset");
12773
12774 m_log << "Saved partition to file '" << partitionFileName.str() << "'." << endl;
12775}

◆ setAzimuthalNeighborDomainIndex() [1/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::setAzimuthalNeighborDomainIndex ( const MInt  ndom,
std::vector< std::vector< MInt > > &  vecA,
std::vector< std::vector< MInt > > &  vecB 
)
private
Author
Thomas Hoesgen
Date
March 2021

Definition at line 964 of file cartesiangrid.cpp.

965 {
966 ASSERT(ndom > -1, "");
967 if(m_azimuthalNghbrDomainIndex[ndom] < 0) {
968 vecA.emplace_back();
969 vecB.emplace_back();
972 m_azimuthalNghbrDomains.push_back(ndom);
973 }
974 return m_azimuthalNghbrDomainIndex[ndom];
975}
std::vector< MInt > m_azimuthalNghbrDomainIndex

◆ setAzimuthalNeighborDomainIndex() [2/2]

template<MInt nDim>
MInt CartesianGrid< nDim >::setAzimuthalNeighborDomainIndex ( const MInt  ndom,
std::vector< std::vector< MInt > > &  vecA,
std::vector< std::vector< MLong > > &  vecB 
)
private
Author
Thomas Hoesgen
Date
March 2021

Definition at line 982 of file cartesiangrid.cpp.

983 {
984 ASSERT(ndom > -1, "");
985 if(m_azimuthalNghbrDomainIndex[ndom] < 0) {
986 vecA.emplace_back();
987 vecB.emplace_back();
990 m_azimuthalNghbrDomains.push_back(ndom);
991 }
992 return m_azimuthalNghbrDomainIndex[ndom];
993}

◆ setChildSolverFlag()

template<MInt nDim>
void CartesianGrid< nDim >::setChildSolverFlag ( const MInt  cellId,
const MInt  solver,
const std::function< MInt(const MFloat *, const MInt, const MInt)> &  cellOutsideSolver 
)
private

Definition at line 13682 of file cartesiangrid.cpp.

13684 {
13685 TRACE();
13686
13687 static constexpr MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
13688 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
13689
13690 const MInt childLevel = a_level(cellId) + 1;
13691 const MFloat childCellLength = cellLengthAtLevel(childLevel);
13692
13693 for(MInt c = 0; c < m_maxNoChilds; c++) {
13694 MInt childId = a_childId(cellId, c);
13695
13696 if(childId < 0) continue;
13697 if(treeb().solver(childId, solver)) continue;
13698
13699 MFloat coords[nDim];
13700 for(MInt i = 0; i < nDim; i++) {
13701 coords[i] = a_coordinate(cellId, i) + F1B2 * signStencil[c][i] * childCellLength;
13702 }
13703 MInt isOutside = cellOutsideSolver(coords, childLevel, cellId);
13704
13705 if(isOutside < 1) {
13706 treeb().solver(childId, solver) = true;
13707 }
13708 }
13709}

◆ setGridInputFilename()

template<MInt nDim>
void CartesianGrid< nDim >::setGridInputFilename ( MBool  forceRestart = false)
private
Author
Lennart Schneiders

Definition at line 716 of file cartesiangrid.cpp.

716 {
717 TRACE();
718
719 stringstream s;
720 MString name;
721 MBool tmpFalse = false;
722
723 const MBool restart = forceRestart || m_restart;
724
725 const MBool useNonSpecifiedRestartFile =
726 restart ? Context::getBasicProperty<MBool>("useNonSpecifiedRestartFile", AT_, &tmpFalse) : true;
727
728 const MInt restartTimeStep = useNonSpecifiedRestartFile ? 0 : Context::getBasicProperty<MInt>("restartTimeStep", AT_);
729 MBool multilevel = false;
730 m_zonal = false;
731 multilevel = Context::getBasicProperty<MBool>("multilevel", AT_, &multilevel);
732 m_zonal = Context::getBasicProperty<MBool>("zonal", AT_, &m_zonal);
733
734 // NOTE: gridSolverId is the reference solverId used by the grid to read the gridFileName from the
735 // correcponding restartVariables file!
736 const MInt gridSolverId = 0;
737
738 MString solverType = Context::getSolverProperty<MString>("solvertype", gridSolverId, AT_);
739
740
741 if(solverType == "MAIA_LS_SOLVER" || solverType == "MAIA_MULTI_LS") {
742 // the ls solver needs special treatment right now since cartesian grid is expected but it can also have its own
743 // grid here the cartesian grid file name is required... ls solver right now has to have a cartesian grid file name
744 // 'grid.Netcdf' this will be adjusted in the near future
745 if(domainId() == 0) {
746 cerr << "cartesian grid file name has to be 'grid.Netcdf'" << endl;
747 }
748 m_gridInputFileName = "grid.Netcdf";
749 MBool m_adaptation = Context::getBasicProperty<MBool>("adaptation", AT_, &m_adaptation);
750 if(m_adaptation && m_restart) {
751 MInt restartTime = Context::getBasicProperty<MInt>("restartTimeStep", AT_);
752
753 stringstream reinitFile;
754 reinitFile << "restartGrid_00" << restartTime << ".Netcdf";
755
756 m_gridInputFileName = reinitFile.str();
757 cerr << "grid file name changed to : " << m_gridInputFileName << endl;
758 }
759
760 } else {
761 if(restart) {
762 stringstream varFileName;
763 if(solverType == "MAIA_LATTICE_BOLTZMANN") {
764 // Get restart filename for LB
765 varFileName << m_restartDir;
766 varFileName << "restart_" << restartTimeStep << ParallelIo::fileExt();
767 } else if(solverType == "MAIA_DISCONTINUOUS_GALERKIN") {
768 // Get restart filename for DG
769 if(useNonSpecifiedRestartFile) {
770 varFileName << m_restartDir << "restart" << ParallelIo::fileExt();
771 } else if(g_multiSolverGrid) {
772 varFileName << m_restartDir << "restart_b" << gridSolverId << "_" << setw(8) << setfill('0')
773 << restartTimeStep << ParallelIo::fileExt();
774 } else {
775 varFileName << m_restartDir << "restart_" << setw(8) << setfill('0') << restartTimeStep
776 << ParallelIo::fileExt();
777 }
778 } else if(solverType == "MAIA_DG_MULTISOLVER") {
779 // Get restart filename for DG
780 if(useNonSpecifiedRestartFile) {
781 varFileName << m_restartDir << "restart_b0" << ParallelIo::fileExt();
782 } else {
783 varFileName << m_restartDir << "restart_b0_" << setw(8) << setfill('0') << restartTimeStep
784 << ParallelIo::fileExt();
785 }
786 } else if(solverType == "MAIA_LEVELSET_SOLVER") {
787 varFileName << m_restartDir << "restartLSCG";
788 if(treeb().noSolvers() > 1) varFileName << "_" << gridSolverId;
789 if(!useNonSpecifiedRestartFile) varFileName << "_" << restartTimeStep;
790 varFileName << ParallelIo::fileExt();
791 } else {
792 // Get restart filename for FV
793 if(!multilevel) {
794 if(m_zonal) {
795 varFileName << m_restartDir << "restartVariables" << gridSolverId;
796 } else {
797 varFileName << m_restartDir << "restartVariables";
798 }
799 if(!useNonSpecifiedRestartFile) varFileName << "_" << restartTimeStep;
800 varFileName << ParallelIo::fileExt();
801 } else {
802 // For multilevel, use solver-specific file name for restart files
803 const MInt maxLength = 256;
804 array<MChar, maxLength> buffer{};
805 snprintf(buffer.data(), maxLength, "restart_b00_t%08d", restartTimeStep);
806 varFileName << m_restartDir << MString(buffer.data()) << ParallelIo::fileExt();
807 }
808 }
809 const MString fileName = varFileName.str();
810 m_log << "Trying to read grid input file name from restart file " << fileName << endl;
811 if(fileExists(fileName.c_str())) {
812 ParallelIo parallelIo(fileName.c_str(), maia::parallel_io::PIO_READ, mpiComm());
813 parallelIo.getAttribute(&name, "gridFile");
814 s << name;
815 } else {
816 MString tmp = Context::getBasicProperty<MString>("gridInputFileName", AT_);
817 s << tmp;
818 }
819 } else {
820 MString tmp = Context::getBasicProperty<MString>("gridInputFileName", AT_);
821 s << tmp;
822 }
823 m_gridInputFileName = s.str();
824 struct stat buffer {};
825 if(restart && stat((m_restartDir + m_gridInputFileName).c_str(), &buffer) != 0) {
826 mTerm(1, AT_, "Grid input file " + m_restartDir + m_gridInputFileName + " does not exist.");
827 }
828 m_log << "Cartesian Grid input file name is " << m_gridInputFileName
829 << " (full path: " << m_restartDir + m_gridInputFileName << ")." << endl;
830 }
831}
MBool fileExists(const MString &fileName)
Returns true if the file fileName exists, false otherwise.
Definition: functions.cpp:73
const MInt PIO_READ
Definition: parallelio.h:40

◆ setLevel()

template<MInt nDim>
void CartesianGrid< nDim >::setLevel
private

This function must be called after a dummy cell is appended otherwise the loop must be changed to size().

Definition at line 8927 of file cartesiangrid.cpp.

8927 {
8928 TRACE();
8929 m_maxLevel = -1;
8930
8931 for(MInt i = 0; i < m_tree.size(); i++) { // m_noRegularCells
8932 if(a_isToDelete(i)) continue;
8933 if(a_hasProperty(i, Cell::IsHalo)) continue;
8935 }
8936
8937 MPI_Allreduce(MPI_IN_PLACE, &m_maxLevel, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "m_maxLevel");
8938
8939 if(m_minLevel < 0 || m_maxLevel < m_minLevel || m_maxLevel > 31 || m_minLevel > m_maxLevel) {
8940 mTerm(1, AT_, "Inconsistent min/max levels: " + to_string(m_minLevel) + "/" + to_string(m_maxLevel));
8941 }
8942}

◆ setNeighborDomainIndex() [1/2]

template<MInt nDim>
template<typename TA , typename TB >
MInt CartesianGrid< nDim >::setNeighborDomainIndex ( const MInt  ndom,
std::vector< TA > &  vecA,
std::vector< TB > &  vecB 
)
private
Author
Lennart Schneiders
Date
October 2017

Definition at line 948 of file cartesiangrid.cpp.

948 {
949 ASSERT(ndom > -1, "");
950 if(m_nghbrDomainIndex[ndom] < 0) {
951 vecA.emplace_back();
952 vecB.emplace_back();
953 m_nghbrDomainIndex[ndom] = (signed)m_nghbrDomains.size();
954 m_nghbrDomains.push_back(ndom);
955 }
956 return m_nghbrDomainIndex[ndom];
957}

◆ setNeighborDomainIndex() [2/2]

template<MInt nDim>
template<typename TA , typename TB , typename TC >
MInt CartesianGrid< nDim >::setNeighborDomainIndex ( const MInt  ndom,
std::vector< TA > &  vecA,
std::vector< TB > &  vecB,
std::vector< TC > &  vecC 
)
private
Author
Lennart Schneiders
Date
October 2017

Definition at line 929 of file cartesiangrid.cpp.

930 {
931 ASSERT(ndom > -1, "");
932 if(m_nghbrDomainIndex[ndom] < 0) {
933 vecA.emplace_back();
934 vecB.emplace_back();
935 vecC.emplace_back();
936 m_nghbrDomainIndex[ndom] = (signed)m_nghbrDomains.size();
937 m_nghbrDomains.push_back(ndom);
938 }
939 return m_nghbrDomainIndex[ndom];
940}

◆ setSolver()

template<MInt nDim>
void CartesianGrid< nDim >::setSolver ( const MInt  cellId,
const MInt  solverId,
MBool  flag 
)
inline

Definition at line 256 of file cartesiangrid.h.

256{ m_tree.solver(cellId, solverId) = flag; }

◆ setUpdatedPartitionCells()

template<MInt nDim>
void CartesianGrid< nDim >::setUpdatedPartitionCells ( const MBool  flag)
inline

Definition at line 587 of file cartesiangrid.h.

587{ m_updatedPartitionCells = flag; }

◆ setupWindowHaloCellConnectivity()

template<MInt nDim>
void CartesianGrid< nDim >::setupWindowHaloCellConnectivity
private
Author
Lennart Schneiders
Date
October 2017

Definition at line 1003 of file cartesiangrid.cpp.

1003 {
1004 TRACE();
1005
1006 auto logDuration = [this](const MFloat timeStart, const MString comment) {
1007 logDuration_(timeStart, "WINDOW/HALO", comment, mpiComm(), domainId(), noDomains());
1008 };
1009 const MFloat winHaloTimeStart = wallTime();
1010
1011 std::vector<MInt>().swap(m_nghbrDomains);
1012 std::vector<MInt>().swap(m_nghbrDomainIndex);
1013 std::vector<std::vector<MInt>>().swap(m_haloCells);
1014 std::vector<std::vector<MInt>>().swap(m_windowCells);
1015 std::vector<std::unordered_map<MInt, M32X4bit<true>>>().swap(m_windowLayer_);
1016
1017 cerr0 << "Establish window/halo connectivity..." << endl;
1018
1019 /* if( Context::propertyExists("targetGridFileName") ) { */
1020 /* TERMM(1, "deprecated"); */
1021 /* MString targetGridFileName = Context::getBasicProperty<MString>("targetGridFileName",
1022 * AT_, &targetGridFileName); */
1023
1024 std::vector<MInt>().swap(m_nghbrDomains);
1025 m_nghbrDomainIndex.resize(noDomains());
1026 std::fill_n(m_nghbrDomainIndex.begin(), noDomains(), -1);
1027
1028 if(m_azimuthalPer) {
1031 std::fill_n(m_azimuthalNghbrDomainIndex.begin(), noDomains(), -1);
1032
1033 m_azimuthalHaloCells.clear();
1035 m_azimuthalWindowCells.clear();
1036 }
1037
1038 // 1. create window-halo-connectivity on m_minLevel
1039 const MFloat minExchangeTimeStart = wallTime();
1041 logDuration(minExchangeTimeStart, "Create min level exchange cells");
1042
1043 // 2. iteratively create window-halo-connectivity on m_minLevel+1...m_maxLevel
1044 const MFloat higherExchangeTimeStart = wallTime();
1045 if(m_maxLevel > m_minLevel) {
1046 // WH_old
1047 if(m_haloMode > 0)
1049 else
1051 }
1052 logDuration(higherExchangeTimeStart, "Create higher level exchange cells");
1053
1054#ifdef MAIA_GRID_SANITY_CHECKS
1056#endif
1057
1058 // exchange cell properties
1060
1061 // create communication data
1063
1064 // WH_old
1065 // Exchange solver info
1066 if(m_haloMode > 0)
1068 else
1070 m_tree.size());
1071
1072 if(m_azimuthalPer) {
1073 if(noAzimuthalNeighborDomains() > 0) {
1075 &m_tree.solverBits(0), m_tree.size());
1076 }
1077 // Set unmapped halos as true for each solver
1078 // Solver bit is updated in proxy
1079 for(MInt i = 0; i < noAzimuthalUnmappedHaloCells(); i++) {
1081 for(MInt solver = 0; solver < treeb().noSolvers(); solver++) {
1082 m_tree.solver(cellId, solver) = true;
1083 }
1084 }
1085 // To ensure that azimuthal halo cells are fully refined (have all children)
1086 // or are not refined at all, solver Bits need to be checked!
1088 }
1089
1091
1093
1094 for(MInt i = 0; i < noNeighborDomains(); i++) {
1095 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
1096 a_hasProperty(m_haloCells[i][j], Cell::IsHalo) = true;
1097 a_hasProperty(m_haloCells[i][j], Cell::IsWindow) = false;
1098 }
1099 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
1100 a_hasProperty(m_windowCells[i][j], Cell::IsHalo) = false;
1101 a_hasProperty(m_windowCells[i][j], Cell::IsWindow) = true;
1102 }
1103 }
1104 if(m_azimuthalPer) {
1105 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
1106 for(MInt j = 0; j < (signed)m_azimuthalHaloCells[i].size(); j++) {
1107 a_hasProperty(m_azimuthalHaloCells[i][j], Cell::IsHalo) = true;
1108 a_hasProperty(m_azimuthalHaloCells[i][j], Cell::IsWindow) = false;
1109 }
1110 for(MInt j = 0; j < (signed)m_azimuthalWindowCells[i].size(); j++) {
1111 a_hasProperty(m_azimuthalWindowCells[i][j], Cell::IsHalo) = false;
1112 a_hasProperty(m_azimuthalWindowCells[i][j], Cell::IsWindow) = true;
1113 }
1114 }
1115 for(MInt j = 0; j < noAzimuthalUnmappedHaloCells(); j++) {
1116 a_hasProperty(m_azimuthalUnmappedHaloCells[j], Cell::IsHalo) = true;
1117 }
1118 }
1119
1121
1122 MFloat cellCnt[4] = {F0, F0, F0, F0};
1123 for(MInt i = 0; i < noNeighborDomains(); i++) {
1124 cellCnt[0] += (MFloat)m_haloCells[i].size();
1125 cellCnt[1] += (MFloat)m_windowCells[i].size();
1126 }
1127 cellCnt[2] = (MFloat)m_tree.size();
1128 cellCnt[3] = (MFloat)noNeighborDomains();
1129 m_log << "Grid local halo/window cell ratio: " << cellCnt[0] << " " << cellCnt[1] << endl;
1130 m_log << "Grid local halo/window cell ratio: " << cellCnt[0] << "; relative " << cellCnt[0] / cellCnt[2] << "; "
1131 << cellCnt[1] << "; relative " << cellCnt[1] / cellCnt[2] << endl;
1132#ifndef NDEBUG
1133 MFloat maxHaloCellRatio = cellCnt[0] / cellCnt[2];
1134 MPI_Allreduce(MPI_IN_PLACE, &maxHaloCellRatio, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
1135 "maxHaloCellRatio");
1136 m_log << "Grid maximum halo cell ratio: " << maxHaloCellRatio << endl;
1137
1138 MFloat maxWindowCellRatio = cellCnt[1] / cellCnt[2];
1139 MPI_Allreduce(MPI_IN_PLACE, &maxWindowCellRatio, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
1140 "maxWindowCellRatio");
1141 m_log << "Grid maximum window cell ratio: " << maxWindowCellRatio << endl;
1142
1143 MPI_Allreduce(MPI_IN_PLACE, cellCnt, 4, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "cellCnt");
1144 cellCnt[0] /= cellCnt[2];
1145 cellCnt[1] /= cellCnt[2];
1146 cellCnt[3] /= (MFloat)noDomains();
1147 m_log << "Grid global halo/window cell ratio: " << cellCnt[0] << " " << cellCnt[1] << endl;
1148 MInt maxNoNeighborDomains = noNeighborDomains();
1149 MPI_Allreduce(MPI_IN_PLACE, &maxNoNeighborDomains, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
1150 "maxNoNeighborDomains");
1151 m_log << "Grid maximum number of neighbor domains: " << maxNoNeighborDomains << ", average: " << cellCnt[3] << endl;
1152#endif
1153
1154 cerr0 << "done." << endl;
1155 logDuration(winHaloTimeStart, "Window/halo total");
1156}
void createMinLevelExchangeCells()
Create window-halo-connectivity based on hilbertIndex matching for regular and periodic exchange cell...

◆ storeMinLevelCells()

template<MInt nDim>
void CartesianGrid< nDim >::storeMinLevelCells ( const MBool  updateMinlevel = false)
Author
Lennart Schneiders

Definition at line 10229 of file cartesiangrid.cpp.

10229 {
10230 // Create map from hilbert id to all internal min cells
10231 m_minLevelCells.clear();
10232 map<MLong, MInt> minLevelCells;
10233 const MInt minLevel = updateMinlevel ? m_newMinLevel : m_minLevel;
10234 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
10235 if(a_hasProperty(cellId, Cell::IsHalo)) continue; // min-level halo partition level ancestor handled below
10236 if(a_isToDelete(cellId)) continue;
10237 if(a_level(cellId) == minLevel) {
10238 const MLong hilbertId =
10240 TERMM_IF_COND(minLevelCells.count(hilbertId), "Error: duplicate hilbertId.");
10241 minLevelCells.insert(pair<MLong, MInt>(hilbertId, cellId));
10242 }
10243 }
10244
10245 MBool found = false;
10246 MInt minLvlHaloPartLvlAncestor = -1;
10247 for(auto& i : m_partitionLevelAncestorIds) {
10248 TERMM_IF_NOT_COND(a_hasProperty(i, Cell::IsPartLvlAncestor),
10249 "cell is not a partition level ancestor: " + std::to_string(i));
10250 TERMM_IF_COND(a_isToDelete(i), "Error: partition level ancestor marked for deletion.");
10251 // If there is a min-level halo partition level ancestor this is the min-level cell for the
10252 // first partition cell on this domain, it will be stored in m_minLevelCells as first entry
10253 // (lowest hilbert id)!
10254 if(a_level(i) == minLevel && a_hasProperty(i, Cell::IsHalo)) {
10255 TERMM_IF_COND(found, "there should only be a single min-level halo partition level ancestor "
10256 "in the list of partitionLevelAncestorIds! Other halo cells with "
10257 "these properties shouldnt be in that list!");
10258 const MInt hilbertId = updateMinlevel ? generateHilbertIndex(i, m_newMinLevel) : generateHilbertIndex(i);
10259 TERMM_IF_COND(minLevelCells.count(hilbertId), "duplicate hilbertId.");
10260 minLevelCells.insert(pair<MInt, MInt>(hilbertId, i));
10261 minLvlHaloPartLvlAncestor = i;
10262 found = true;
10263
10264 // DEBUG
10265 /* m_log << "found a min-level halo partition level ancestor: " << i << " " << hilbertId */
10266 /* << std::endl; */
10267 }
10268 }
10269
10270 for(auto& minLevelCell : minLevelCells) {
10271 m_minLevelCells.push_back(minLevelCell.second);
10272 }
10273
10274 // add halo min level cells to the back
10275 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
10276 // Skip the min-level halo partition level ancestor which was already added as a first entry to
10277 // m_minLevelCells above
10278 if(found && cellId == minLvlHaloPartLvlAncestor) continue;
10279
10280 if(a_level(cellId) == minLevel && a_hasProperty(cellId, Cell::IsHalo)) {
10281 TERMM_IF_COND(a_isToDelete(cellId), "Error: min-level halo marked for deletion.");
10282 m_minLevelCells.push_back(cellId);
10283 }
10284 }
10285}
MLong generateHilbertIndex(const MInt cellId, const MInt targetMinLevel)

◆ swapCells()

template<MInt nDim>
void CartesianGrid< nDim >::swapCells ( const MInt  cellId0,
const MInt  cellId1 
)
private
Author
Lennart Schneiders

Definition at line 8559 of file cartesiangrid.cpp.

8559 {
8560 static constexpr MInt revDir[6] = {1, 0, 3, 2, 5, 4};
8561 if(cellId1 == cellId0) return;
8562 ASSERT(cellId1 > -1 && cellId0 > -1 && cellId1 < treeb().size() && cellId0 < treeb().size(),
8563 "Invalid cell range " << cellId1 << " " << cellId0 << " " << treeb().size());
8564
8565 // TODO labels:GRID use swap() of grid tree class instead?
8566 // swap parent-child links, the sequence is important in case cellId0 and cellId1 are in parent-child relation!
8567 MInt parentId0 = a_parentId(cellId0);
8568 MInt parentId1 = a_parentId(cellId1);
8569 MInt child0 = -1;
8570 MInt child1 = -1;
8571 if(parentId0 > -1) {
8572 for(MInt k = 0; k < m_maxNoChilds; k++) {
8573 if(a_childId(parentId0, k) == cellId0) {
8574 child0 = k;
8575 break;
8576 }
8577 }
8578 }
8579 if(parentId1 > -1) {
8580 for(MInt k = 0; k < m_maxNoChilds; k++) {
8581 if(a_childId(parentId1, k) == cellId1) {
8582 child1 = k;
8583 break;
8584 }
8585 }
8586 }
8587 for(MInt k = 0; k < m_maxNoChilds; k++) {
8588 if(a_childId(cellId0, k) > -1) {
8589 ASSERT(a_parentId(a_childId(cellId0, k)) == cellId0, "Wrong parent!");
8590 a_parentId(a_childId(cellId0, k)) = cellId1;
8591 }
8592 }
8593 for(MInt k = 0; k < m_maxNoChilds; k++) {
8594 if(a_childId(cellId1, k) > -1) {
8595 ASSERT(a_parentId(a_childId(cellId1, k)) == cellId1, "Wrong parent!");
8596 a_parentId(a_childId(cellId1, k)) = cellId0;
8597 }
8598 }
8599 if(child0 > -1) a_childId(parentId0, child0) = cellId1;
8600 if(child1 > -1) a_childId(parentId1, child1) = cellId0;
8601
8602 for(MInt k = 0; k < m_maxNoChilds; k++) {
8603 std::swap(a_childId(cellId1, k), a_childId(cellId0, k));
8604 }
8605 std::swap(a_parentId(cellId0), a_parentId(cellId1));
8606
8607 // swap forward/reverse neighbor links (in opposite directions, otherwise not working when cellId0 and cellId1 are
8608 // neighbors)
8609 for(MInt dir = 0; dir < m_noDirs; dir++) {
8610 MInt nghbrId0 = a_neighborId(cellId0, dir);
8611 MInt nghbrId1 = a_neighborId(cellId1, revDir[dir]);
8612 if(nghbrId0 > -1) {
8613 ASSERT(a_neighborId(nghbrId0, revDir[dir]) == cellId0, "Reverse link dead");
8614 a_neighborId(nghbrId0, revDir[dir]) = cellId1;
8615 }
8616 if(nghbrId1 > -1) {
8617 ASSERT(a_neighborId(nghbrId1, dir) == cellId1, "Reverse link dead");
8618 a_neighborId(nghbrId1, dir) = cellId0;
8619 }
8620 }
8621 for(MInt dir = 0; dir < m_noDirs; dir++) {
8622 std::swap(a_neighborId(cellId1, dir), a_neighborId(cellId0, dir));
8623 }
8624
8625
8626 // swap other data
8627 std::swap(a_level(cellId1), a_level(cellId0));
8628 std::swap(m_tree.properties(cellId0), m_tree.properties(cellId1));
8629 std::swap(m_tree.solverBits(cellId0), m_tree.solverBits(cellId1));
8630 std::swap(a_globalId(cellId1), a_globalId(cellId0));
8631 std::swap(m_tree.leafCellBits(cellId1), m_tree.leafCellBits(cellId0));
8632 std::swap(a_weight(cellId1), a_weight(cellId0));
8633 std::swap(a_workload(cellId1), a_workload(cellId0));
8634 std::swap(a_noOffsprings(cellId1), a_noOffsprings(cellId0));
8635 for(MInt i = 0; i < nDim; i++) {
8636 std::swap(a_coordinate(cellId1, i), a_coordinate(cellId0, i));
8637 }
8638}

◆ tagActiveWindows()

template<MInt nDim>
void CartesianGrid< nDim >::tagActiveWindows ( std::vector< MLong > &  refineChildIds,
MInt  level 
)
private
Author
Lennart Schneiders
Date
October 2017

Definition at line 4302 of file cartesiangrid.cpp.

4302 {
4303 constexpr MInt maxNghbrDoms = 1024;
4304 MIntScratchSpace nghbrList(27 * m_maxNoChilds, AT_, "nghbrList");
4305 vector<std::bitset<maxNghbrDoms>> nghrDomFlag(m_tree.size());
4306 vector<std::bitset<maxNghbrDoms>> nghrDomFlagBak;
4307 vector<std::bitset<maxNghbrDoms>> nghrDomFlagBak2;
4308 set<MInt> exchangeCellList;
4309 if(noNeighborDomains() > maxNghbrDoms) {
4310 mTerm(1, AT_, "Too many neighbor domains(" + std::to_string(noNeighborDomains()) + "). Increase bitset size.");
4311 }
4312 // temporary solution for partitionLevelShifts, might produce a lot of halo cells, more clever way to flag active
4313 // windows should be found
4314 // TODO labels:GRID @ansgar_pls_adapt fix this!
4315 constexpr MBool testingFix_partitionLevelShift = true; // false;
4316
4317 // TODO labels:GRID @timw_multiSolverHalos remove old version!
4318 constexpr MBool multiSolverHaloLayer = true; // should be true
4319
4320 MInt windowCnt = 0;
4321 for(MInt i = 0; i < noNeighborDomains(); i++)
4322 windowCnt += m_windowCells[i].size();
4323 refineChildIds.resize(windowCnt * m_maxNoChilds);
4324 fill(refineChildIds.begin(), refineChildIds.end(), -1);
4325
4326
4327 // identify window cells on the next higher level, or coarser leaf window cells if not existing
4328 for(MInt i = 0; i < noNeighborDomains(); i++) {
4329 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
4330 const MInt cellId = m_windowCells[i][j];
4331
4332 // if ( a_level( cellId ) != level ) continue; //however, such cells should not exist, yet
4333 if(a_noChildren(cellId) > 0) {
4334 if(a_level(cellId) == level) {
4335 for(MInt child = 0; child < m_maxNoChilds; child++) {
4336 MInt childId = a_childId(cellId, child);
4337 if(childId < 0) continue;
4338
4339 // fix for unconsistent window tags with double window cells (domain interface and periodic)
4340 // const MBool doubleWindow = exchangeCellList.find(cellId) != exchangeCellList.end();
4341 // if(!doubleWindow){
4342 exchangeCellList.insert(childId);
4343 //}
4344 }
4345 }
4346 } else {
4347 exchangeCellList.insert(cellId);
4348 }
4349 }
4350 }
4351
4352 // add halo cells
4353 // NOTE: the loop below or similar assumptions that
4354 // internal/halo cells are sorted are wrong during adaptation
4355 // for (MInt cellId = m_noInternalCells; cellId < m_tree.size(); cellId++) {
4356 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
4357 if(a_isHalo(cellId)) {
4358 exchangeCellList.insert(cellId);
4359 }
4360 }
4361
4362 // exchangeCellList conaints all window and halo-Cells,
4363 // and additionally all children of all windowCells
4364
4365 if(m_maxPartitionLevelShift > 0) {
4366 // exchange some window cell data
4367 ScratchSpace<MInt> bprops(m_tree.size(), 2, AT_, "bprops");
4368 bprops.fill(-1);
4369 // Note: changed loop to iterate over whole tree, internal and halo cells not sorted!
4370 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
4371 if(a_isHalo(cellId) || a_isToDelete(cellId)) {
4372 continue;
4373 }
4374 bprops(cellId, 0) = (MInt)a_hasProperty(cellId, Cell::IsPartLvlAncestor);
4375 bprops(cellId, 1) = a_noOffsprings(cellId);
4376
4377 ASSERT(bprops(cellId, 0) > -1 && bprops(cellId, 1) > 0,
4378 std::to_string(cellId) + " " + std::to_string(bprops(cellId, 0)) + " "
4379 + std::to_string(bprops(cellId, 1)));
4380 }
4382
4383 // Note: loop only over the current haloCells since only for these data is exchanged, this does
4384 // not work properly if in case of a partition level shift some halo cell is not part of
4385 // m_haloCells yet such that its property IsPartLvlAncestor is reset!
4386 for(MInt i = 0; i < noNeighborDomains(); i++) {
4387 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
4388 const MInt cellId = m_haloCells[i][j];
4389 ASSERT(!a_isToDelete(cellId), "");
4390 ASSERT(bprops(cellId, 0) > -1 && bprops(cellId, 1) > 0,
4391 std::to_string(cellId) + " " + std::to_string(bprops(cellId, 0)) + " "
4392 + std::to_string(bprops(cellId, 1)));
4393 a_hasProperty(cellId, Cell::IsPartLvlAncestor) = (MBool)bprops(cellId, 0);
4394 a_noOffsprings(cellId) = bprops(cellId, 1);
4395 }
4396 }
4397 }
4398
4399 for(MInt i = m_tree.size(); i--;) {
4400 for(MInt j = 0; j < maxNghbrDoms; j++) {
4401 ASSERT(!nghrDomFlag[i][j], "");
4402 }
4403 }
4404
4405 // mark all halo cells as nghbrdomain
4406 for(MInt i = 0; i < noNeighborDomains(); i++) {
4407 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
4408 const MInt cellId = m_haloCells[i][j];
4409
4410 nghrDomFlag[cellId][i] = true;
4411
4412 if(m_maxPartitionLevelShift > 0) {
4413 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor)) {
4414 MInt minNghbrDomId = findNeighborDomainId(a_globalId(cellId));
4415 MInt maxNghbrDomId =
4417 for(MInt k = 0; k < noNeighborDomains(); k++) {
4418 if(m_nghbrDomains[k] >= minNghbrDomId && m_nghbrDomains[k] <= maxNghbrDomId) {
4419 nghrDomFlag[cellId][k] = true;
4420 for(MInt child = 0; child < m_maxNoChilds; child++) {
4421 MInt childId = a_childId(cellId, child);
4422 if(childId > -1) {
4423 nghrDomFlag[childId][k] = true;
4424 }
4425 }
4426 }
4427 }
4428 }
4429 }
4430 }
4431 }
4432
4433 map<MInt, MInt> solverCellsAdded;
4434 solverCellsAdded.clear();
4435
4436 // extend halo cells by the defined number of halo layers
4437 // NOTE: m_noHaloLayers corresponds to the number of halo-Layers of the grid
4438 // for multiSolver applications some solvers may have a lower number of halo-Layers!
4439 for(MInt layer = 0; layer < m_noHaloLayers; layer++) {
4440 nghrDomFlagBak.assign(nghrDomFlag.begin(), nghrDomFlag.end());
4441
4442 for(MInt cellId : exchangeCellList) {
4443 if(a_level(cellId) > (level + 1)) continue;
4444 if(a_level(cellId) < (level + 1) && a_noChildren(cellId) > 0) continue;
4445 const MInt counter = getAdjacentGridCells(cellId, nghbrList, level);
4446 // check diffs when called instead!!!!
4447 for(MInt n = 0; n < counter; n++) {
4448 MInt nghbrId = nghbrList[n];
4449 if(nghbrId < 0) continue;
4450
4451 // if the neighbor doesn't belong to all solvers
4452 // an additional layer needs to be added to the layer is below the noHaloLayers
4453 // for the solver, which does not have the neighbor!
4454 // to ensure that this each solver has at least the number of halo layers required!
4455 if(g_multiSolverGrid && multiSolverHaloLayer && !m_paraViewPlugin) {
4456 for(MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
4457 if(!treeb().solver(nghbrId, solverId) && layer < m_noSolverHaloLayers[solverId] /*&& layer > 0*/) {
4458 solverCellsAdded.insert(make_pair(nghbrId, solverId));
4459 }
4460 }
4461 }
4462
4463 for(MInt i = 0; i < noNeighborDomains(); i++) {
4464 if(nghrDomFlagBak[nghbrId][i]) {
4465 nghrDomFlag[cellId][i] = true;
4466 }
4467 }
4468
4469 // fix for unconsistent window tags with double window cells (domain interface and periodic)
4470 // MBool tagWindow = false;
4471 // for ( MInt i = 0; i < noNeighborDomains(); i++ ) {
4472
4473 // if(nghrDomFlagBak[ nghbrId ][ i ]){
4474 // //nghrDomFlag[ cellId ][ i ] = true;
4475 // tagWindow = true;
4476 // break;
4477 // }
4478 // }
4479 // if(tagWindow){
4480 // for ( MInt i = 0; i < noNeighborDomains(); i++ ) {
4481 // nghrDomFlag[ cellId ][ i ] = true;
4482 // }
4483 // }
4484
4485
4486 if(m_maxPartitionLevelShift > 0) {
4487 MInt rootId = a_parentId(cellId) > -1 ? a_parentId(cellId) : cellId;
4488 if(a_hasProperty(rootId, Cell::IsPartLvlAncestor)) {
4489 MInt minNghbrDomId = findNeighborDomainId(a_globalId(rootId));
4490 MInt maxNghbrDomId =
4492 for(MInt k = 0; k < noNeighborDomains(); k++) {
4493 if(m_nghbrDomains[k] >= minNghbrDomId && m_nghbrDomains[k] <= maxNghbrDomId) {
4494 nghrDomFlag[cellId][k] = true;
4495 }
4496 }
4497 }
4498 }
4499 }
4500 }
4501
4502 // now extend one additional layer around cells which might be missing the layer
4503 if(!solverCellsAdded.empty()) {
4504 nghrDomFlagBak2.assign(nghrDomFlag.begin(), nghrDomFlag.end());
4505
4506 for(map<MInt, MInt>::iterator it = solverCellsAdded.begin(); it != solverCellsAdded.end(); it++) {
4507 const MInt cellId = it->first;
4508 const MInt solverId = it->second;
4509
4510 // get additional cells
4511 // NOTE: diagonal neighbors are necessary as well, however checkNoHaloLayers
4512 // only checks for direct neighbors!
4513 const MInt counter = getAdjacentGridCells(cellId, nghbrList, level, true);
4514
4515 MBool anyNeighbor = false;
4516 const MInt size = noNeighborDomains();
4517 MBoolScratchSpace addedCell(size, AT_, "addedCell");
4518 fill(addedCell.begin(), addedCell.end(), false);
4519 for(MInt n = 0; n < counter; n++) {
4520 const MInt nghbrId = nghbrList[n];
4521 if(nghbrId < 0) continue;
4522 MInt parentId = a_parentId(cellId);
4523 if(parentId > -1) {
4524 if(!treeb().solver(parentId, solverId)) continue;
4525 }
4526 // labels:GRID testcase hack
4527 if(m_zonal) {
4528 MBool checkParentChilds = false;
4529 for(MInt child = 0; child < m_maxNoChilds; child++) {
4530 MInt childId = a_childId(cellId, child);
4531 if(childId > -1) {
4532 if(!treeb().solver(childId, solverId)) {
4533 checkParentChilds = true;
4534 break;
4535 }
4536 }
4537 }
4538 if(checkParentChilds) continue;
4539 }
4540 if(treeb().solver(nghbrId, solverId)) anyNeighbor = true;
4541 // if( !treeb().solver( nghbrId, solverId ) &&
4542 // a_level(nghbrId) == a_level(cellId)) continue;
4543 for(MInt i = 0; i < noNeighborDomains(); i++) {
4544 if(nghrDomFlagBak2[nghbrId][i]) {
4545 if(!nghrDomFlag[cellId][i]) {
4546 addedCell[i] = true;
4547 }
4548 nghrDomFlag[cellId][i] = true;
4549 }
4550 }
4551 }
4552 // remove the cell from the list again if:
4553 // no neighbors for the cell and intended solver could be found!
4554 // Meaning that the solver has a lower max-level or different boundingBox!
4555 if(!anyNeighbor) {
4556 // for ( MInt n = 0; n < counter; n++ ) {
4557 // const MInt nghbrId = nghbrList[ n ];
4558 for(MInt i = 0; i < noNeighborDomains(); i++) {
4559 if(addedCell[i]) {
4560 nghrDomFlag[cellId][i] = false;
4561 }
4562 }
4563 //}
4564 }
4565 }
4566 solverCellsAdded.clear();
4567 nghrDomFlagBak2.clear();
4568 }
4569 }
4570
4571 // not openmp compatible
4572 MInt cnt = 0;
4573 for(MInt i = 0; i < noNeighborDomains(); i++) {
4574 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
4575 MInt cellId = m_windowCells[i][j];
4576 if(a_level(cellId) == level) {
4577 for(MInt child = 0; child < m_maxNoChilds; child++) {
4578 MInt childId = a_childId(cellId, child);
4579 if(childId > -1) {
4580 if(nghrDomFlag[childId][i]) {
4581 refineChildIds[m_maxNoChilds * cnt + child] = 1;
4582 } else if(testingFix_partitionLevelShift && a_level(cellId) < m_minLevel + m_maxPartitionLevelShift) {
4583 refineChildIds[m_maxNoChilds * cnt + child] = 1;
4584 }
4585 }
4586 }
4587 }
4588 cnt++;
4589 }
4590 }
4591}
MInt getAdjacentGridCells(MInt, MIntScratchSpace &, MInt, MBool diagonalNeighbors=true)
Retrieves all direct and diagonal neighboring cells of the given cell on the child level if available...

◆ tagActiveWindows2_()

template<MInt nDim>
void CartesianGrid< nDim >::tagActiveWindows2_ ( std::vector< MLong > &  refineChildIds,
const MInt  level 
)
private
Date
June 2021

Definition at line 4601 of file cartesiangrid.cpp.

4601 {
4602
4603 MIntScratchSpace nghbrList(27 * m_maxNoChilds, AT_, "nghbrList");
4604
4605 // We rely on the fact, that exchangeCellList is sorted by the tuple's first element, then by its 2nd element etc.
4606 std::set<std::tuple<MInt/*layer*/,MInt/*cellId*/, MInt/*nghbrIdx*/,MInt/*solverId*/>> exchangeCellList;
4607 // partLvlShift
4608 auto newNghbrDomainsIndex = m_nghbrDomainIndex;
4609 auto newNghbrDomains = m_nghbrDomains;
4610
4611#ifndef NDEBUG
4612 std::set<MInt> allWindows;
4613#endif
4614
4615 // The algorithm for m_maxPartitionLevelShift>0 requires a_hasProperty(cellId, Cell::IsPartLvlAncestor) &
4616 // a_noOffsprings(cellId) of the halo cells to be set. This should be the case at this place.
4617
4618 // Get halo candidates
4619 for(MInt i = 0; i < noNeighborDomains(); i++) {
4620 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
4621 const MInt cellId = m_haloCells[i][j];
4622 // If this is called during meshAdaptation and grid has partLvlShift, then we might have halo cells for which
4623 // a_level(cellId)>level
4624 ASSERT(a_level(cellId)<=level || m_maxPartitionLevelShift>0, "");
4625 if (a_level(cellId)>level) continue;
4626
4627 // Note: currently we add all halos as candidates. A more sophisticated choice would be to add only those
4628 // who are adajcent to cells, which are not halos of same neighbor (the neighbor can still be a halo)
4629
4630 //TODO_SS labels:GRID what about the case a_noChildren(cellId)<IPOW2(nDim)
4631 if (a_level(cellId)==level || (a_noChildren(cellId)==0 && a_level(cellId)<level)) {
4632 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
4633 // For the following to work we need to exchange the solverBits before tagActiveWindowsAtMinLevel is
4634 // called (see comments in tagActiveWindowsAtMinLevel)
4635 // if (treeb().solver(cellId, solverId) || treeb().noSolvers()==1)
4636 if (treeb().solver(cellId, solverId)) {
4637 exchangeCellList.insert({std::make_tuple(0, cellId, i, solverId)});
4638 }
4639 }
4640 }
4641
4642 // Before we do the following we need to exchange the property IsPartLvlAncesotr and a_noOffsping (see above)
4643 if (a_hasProperty(cellId, Cell::IsPartLvlAncestor)) {
4644 if (a_level(cellId)==level || (a_noChildren(cellId)==0 && a_level(cellId)<level)) {
4645
4646 // TODO_SS labels:GRID what about the case a_noChildren(cellId)<IPOW2(nDim)
4647 const MInt minNghbrDomId = findNeighborDomainId(a_globalId(cellId));
4648 const MInt maxNghbrDomId =
4650
4651 for (MInt nghbrDom = minNghbrDomId; nghbrDom <= maxNghbrDomId; ++nghbrDom) {
4652 MInt k = newNghbrDomainsIndex[nghbrDom];
4653 if (nghbrDom==domainId()) continue; //TODO_SS labels:GRID not sure if this is correct
4654 //if (k<0 && nghbrDom==domainId()) continue; // periodic???
4655 if (k<0) {
4656 // We have a new neighbor
4657 k = newNghbrDomains.size();
4658 newNghbrDomainsIndex[nghbrDom] = k;
4659 newNghbrDomains.push_back(nghbrDom);
4660 }
4661 //if (i==k) continue;
4662// if(m_nghbrDomains[k] >= minNghbrDomId && m_nghbrDomains[k] <= maxNghbrDomId) { }
4663 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
4664 // For the following to work we need to exchange the solverBits before tagActiveWindowsAtMinLevel is
4665 // called (see comments in tagActiveWindowsAtMinLevel)
4666 // if (treeb().solver(cellId, solverId) || treeb().noSolvers()==1)
4667 if (treeb().solver(cellId, solverId)) {
4668 exchangeCellList.insert({std::make_tuple(0, cellId, k, solverId)});
4669
4670 for(MInt child = 0; child < m_maxNoChilds; child++) {
4671 const MInt childId = a_childId(cellId, child);
4672 if(childId > -1) {
4673
4674 //TODO_SS labels:GRID exchange noOffspring of halo cells (check if it is already done, especially those halo
4675 // cells which are not yet in m_haloCells, but are created because of partLvlShift)
4676 const MInt minNghbrDomId2 = findNeighborDomainId(a_globalId(childId));
4677 const MInt maxNghbrDomId2 =
4679 MInt lay = (newNghbrDomains[k] >= minNghbrDomId2 && newNghbrDomains[k] <= maxNghbrDomId2) ? 0 : 1;
4680 // TODO_SS labels:GRID since halo data are not exchanged yet, safety approach
4681 if (a_isHalo(childId)) lay = 0;
4682
4683 exchangeCellList.insert({std::make_tuple(lay, childId, k, solverId)});
4684 if (!a_isHalo(childId)) {
4685 if (treeb().solver(childId, solverId)) {
4686 //TODO_SS labels:GRID,totest following assert fails in periodic case when nghbrDom==domainId() --> check
4687 //TERMM_IF_COND(lay==0 && !a_hasProperty(childId, Cell::IsPartLvlAncestor), to_string(minNghbrDomId2) + " " + to_string(maxNghbrDomId2));
4688 //TODO_SS labels:GRID can we ensure that the newly found domain will also find current domain?
4689 m_windowLayer_[setNeighborDomainIndex(nghbrDom, m_haloCells, m_windowCells, m_windowLayer_)][childId].set(solverId, lay);
4690 }
4691 }
4692 }
4693 }
4694 }
4695 }
4696 }
4697 }
4698 }
4699 }
4700 }
4701
4702// vector<std::set<MInt>> windCellSet(noNeighborDomains());
4703// for(MInt i = 0; i < noNeighborDomains(); i++) {
4704// windCellSet[i].insert(m_windowCells[i].begin(), m_windowCells[i].end());
4705// }
4706
4707 // Get window candidates on lower level
4708 for(MInt i = 0; i < noNeighborDomains(); i++) {
4709 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
4710 const MInt cellId = m_windowCells[i][j];
4711#ifndef NDEBUG
4712 allWindows.insert(cellId);
4713 TERMM_IF_COND(m_windowLayer_[i].find(cellId)==m_windowLayer_[i].end(), std::to_string(m_maxPartitionLevelShift));
4714 TERMM_IF_COND(m_windowLayer_[i].at(cellId).all(), "");
4715#endif
4716
4717 if (a_level(cellId)==level) {
4718 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
4719 const MInt windowLayer = m_windowLayer_[i].at(cellId).get(solverId);
4720 // TODO_SS labels:GRID what about the case that a_noChildren<IPOW2(nDim)
4721 if (!a_hasChildren(cellId, solverId) && windowLayer<m_noSolverHaloLayers[solverId]) {
4722 // labels:GRID,DLB With DLB the following check fails: Bug?!
4723// if (windowLayer<1 && !a_hasProperty(cellId, Cell::IsPartLvlAncestor))
4724// TERMM(1, "");
4725 exchangeCellList.insert({std::make_tuple(windowLayer, cellId, i, solverId)});
4726 }
4727 }
4728 }
4729
4730 // 1) window cell (a_level(cellId)==level) with IPOW2(nDim) number of window children
4731 // 2) window cell (a_level(cellId)==level) with <IPOW2(nDim) number of window children
4732 if (a_hasProperty(cellId, Cell::IsPartLvlAncestor) && a_level(cellId)==level) {
4733 ASSERT(a_noChildren(cellId)>0, "");
4734 ASSERT(!a_isHalo(cellId), "");
4735
4736 MInt minNghbrDomId = findNeighborDomainId(a_globalId(cellId));
4737 MInt maxNghbrDomId =
4739#ifndef NDEBUG
4740 // All neighbor domains, who have children above this current window cell, should already be contained in
4741 // m_nghbrDomains
4742 for (MInt nD = minNghbrDomId; nD<=maxNghbrDomId; ++nD) {
4743 if (nD==domainId()) continue;
4744 MBool found = false;
4745 for (MInt ii = 0; ii < noNeighborDomains(); ii++) {
4746 if (m_nghbrDomains[ii]== nD) {
4747 found = true;
4748 break;
4749 }
4750 }
4751 TERMM_IF_NOT_COND(found, to_string(a_isHalo(cellId)) + " " + to_string(a_noOffsprings(cellId)));
4752 }
4753#endif
4754 if(m_nghbrDomains[i] >= minNghbrDomId && m_nghbrDomains[i] <= maxNghbrDomId) {
4755
4756 //TODO_SS labels:GRID do we need to put cellId into exchangeCellList in case a_noChildren(cellId)<IPOW2(nDim)
4757 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
4758 if (treeb().solver(cellId, solverId)) {
4759 exchangeCellList.insert({std::make_tuple(0, cellId, i, solverId)});
4760 }
4761 }
4762
4763// if (a_noChildren(cellId)==IPOW2(nDim)) {
4764 for(MInt child = 0; child < m_maxNoChilds; child++) {
4765 const MInt childId = a_childId(cellId, child);
4766 // Note: Due to cutOff we might have less then IPOW[nDim] children
4767 if (childId<0) continue;
4768 //TODO_SS labels:GRID,totest check the following assert: I guess during meshAdaptation is might fail
4769 //TERMM_IF_NOT_COND(!a_isHalo(childId), "");
4770
4771 minNghbrDomId = findNeighborDomainId(a_globalId(childId));
4772 maxNghbrDomId =
4774 // for(MInt k = 0; k < noNeighborDomains(); k++) { }
4775 //if (domainId()==m_nghbrDomains[k]) continue; // check if this makes sense
4776 //if(m_nghbrDomains[k] >= minNghbrDomId && m_nghbrDomains[k] <= maxNghbrDomId) { }
4777 MInt lay = (m_nghbrDomains[i] >= minNghbrDomId && m_nghbrDomains[i] <= maxNghbrDomId) ? 0 : 1;
4778 // TODO_SS labels:GRID since halo data are not exchanged yet, safety approach
4779 if (a_isHalo(childId)) lay = 0;
4780
4781 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
4782 //TODO_SS labels:GRID,totest maybe we could directly check solverBits of children, but first check
4783 // if solverBits of halo children are already set
4784 if (treeb().solver(cellId, solverId)) {
4785 exchangeCellList.insert({std::make_tuple(lay, childId, i, solverId)});
4786 if (!a_isHalo(childId)) {
4787 if (treeb().solver(childId, solverId)) {
4788// TERMM_IF_COND(lay==0 && !a_hasProperty(childId, Cell::IsPartLvlAncestor), to_string(domainId()) + " " + to_string(m_nghbrDomains[i]) + " " + to_string(minNghbrDomId) + " " + to_string(maxNghbrDomId));
4789 m_windowLayer_[i][childId].set(solverId, lay);
4790 }
4791 }
4792 }
4793 }
4794 }
4795 }
4796 }
4797 }
4798 }
4799
4800
4801 //
4802 std::vector<std::unordered_map<MInt, M32X4bit<true>>> haloLayer_(newNghbrDomains.size());
4803 for(MInt layer = 0; layer < m_noHaloLayers; layer++) {
4804
4805 const auto it_begin = exchangeCellList.lower_bound(std::make_tuple(layer,std::numeric_limits<MInt>::min(),
4806 std::numeric_limits<MInt>::min(),std::numeric_limits<MInt>::min()));
4807 const auto it_end = exchangeCellList.upper_bound(std::make_tuple(layer,std::numeric_limits<MInt>::max(),
4808 std::numeric_limits<MInt>::max(),std::numeric_limits<MInt>::max()));
4809 const MInt noCandidates = std::distance(it_begin, it_end);
4810
4811 MInt cnt = 0;
4812 for (auto it = it_begin; it!=it_end;) {
4813 const MInt cellId = get<1>(*it);
4814 TERMM_IF_NOT_COND(cellId > -1 && cellId < m_tree.size(), "");
4815 const MBool isHaloCellId = a_isHalo(cellId);
4816
4817 // 1) If cellId is on level 'level+1' it must be a window cell, and we are only looking for neighbors on same level
4818 // 2) If cellId is window cell, but not on 'level+1' we are only interested in neighbors on 'level+1', since we
4819 // should already have tagged windows on 'level' (and those windows on 'level' without children are put into
4820 // exchangeCellList above)
4821 // 3) If cellId is halo cell, it must be on level<='level': we allow both searching on lower and upper level
4822#ifndef NDEBUG
4823 TERMM_IF_COND(a_level(cellId)==level+1 && allWindows.find(a_parentId(cellId))==allWindows.end()
4824 && !a_hasProperty(a_parentId(cellId), Cell::IsPartLvlAncestor), "");
4825
4826 // The following check fails when this function is called during meshAdaptation
4827 //TERMM_IF_COND(a_isHalo(cellId) && a_level(cellId)>level && !a_hasProperty(cellId, Cell::IsPartLvlAncestor)/*&& m_maxPartitionLevelShift==0*/, "");
4828#endif
4829
4830 const MInt counter = a_level(cellId)==level+1 ? getAdjacentGridCells5<false,false>(cellId, nghbrList.data())
4831 : (isHaloCellId ? getAdjacentGridCells5<true,true>(cellId, nghbrList.data())
4832 : getAdjacentGridCells5<true,false>(cellId, nghbrList.data(), level+1));
4833
4834 // It can happen that we reached noCandidates, but by coincidence the next cellId is the same, but on layer+1
4835 //while (cellId==it->first.second && cnt<noCandidates) {
4836 while (cnt<noCandidates && cellId==get<1>(*it)) {
4837 ASSERT(get<0>(*it)==layer, "Send a bug report to the C++ vendor!");
4838 const MInt nghbrDomIdx = get<2>(*it);
4839 const MInt solverId = get<3>(*it);
4840
4841 for(MInt n = 0; n < counter; n++) {
4842 const MInt nghbrId = nghbrList[n];
4843 ASSERT(nghbrId > -1 && nghbrId < m_tree.size(), to_string(nghbrId) + "|" + to_string(m_tree.size()));
4844 ASSERT(a_level(nghbrId)<=level+1, to_string(a_level(nghbrId)) + "|" + to_string(level+1));
4845
4846 // At this place the solver tags of halo cells should already be set, i.e. solverBits are already exchanged.
4847 if (!treeb().solver(nghbrId, solverId)) continue;
4848
4849 // nghbrId is either
4850 // 1) a halo cell
4851 // 2) itself a window cell with no parent or its parent is a window cell or a window cell on level+1,
4852 // which not yet in allWindows
4853 const MBool isHalo = a_isHalo(nghbrId);
4854#ifndef NDEBUG
4855 if (m_maxPartitionLevelShift==0) {
4856 TERMM_IF_COND(isHalo && (allWindows.find(a_parentId(nghbrId))!=allWindows.end()
4857 || allWindows.find(nghbrId)!=allWindows.end()), "");
4858 }
4859#endif
4860
4861 //TODO_SS labels:GRID,totest check the last condition, if testcases fail and if it speeds up
4862 if (!isHalo && a_level(nghbrId)<level+1) continue;
4863
4864 // If parent is window, it must be in isSolverWindowCell(nghbrDomIdx, a_parentId(nghbrId), solverId)
4865 if (a_level(nghbrId)==level+1 && !a_isHalo(a_parentId(nghbrId)) && !isSolverWindowCell(nghbrDomIdx, a_parentId(nghbrId), solverId))
4866 continue;
4867
4868 // Sanity check that cell is in m_windowCells, in case it's not a halo
4869#ifndef NDEBUG
4870 TERMM_IF_COND(!isHalo
4871 && allWindows.find(a_parentId(nghbrId))==allWindows.end()
4872 && allWindows.find(nghbrId)!=allWindows.end()
4873 && !a_hasProperty(a_parentId(nghbrId), Cell::IsPartLvlAncestor), "");
4874
4875 // Check in case of no partition level shift
4876 if (m_maxPartitionLevelShift==0) {
4877 TERMM_IF_COND(a_level(nghbrId)==level+1 && allWindows.find(a_parentId(nghbrId))==allWindows.end(), "");
4878 } else {
4879 /* Actually I would expect for a_level(nghbrId)==level+1 the following possible situations:
4880 * 1) allWindows.find(a_parentId(nghbrId))!=allWindows.end() && !a_hasProperty(a_parentId(nghbrId), Cell::IsPartLvlAncestor)
4881 * 2) allWindows.find(a_parentId(nghbrId))!=allWindows.end() && a_hasProperty(a_parentId(nghbrId), Cell::IsPartLvlAncestor)
4882 * 3) allWindows.find(a_parentId(nghbrId))==allWindows.end() && a_hasProperty(a_parentId(nghbrId), Cell::IsPartLvlAncestor) && a_isHalo(a_parentId(nghbrId))
4883 * But since we are tagging currently way too many cells, we can have:
4884 * allWindows.find(a_parentId(nghbrId))==allWindows.end() && !a_hasProperty(a_parentId(nghbrId), Cell::IsPartLvlAncestor)
4885 */
4886 }
4887#endif
4888
4889 /* Currently nghbrId could be also a halo cell, e.g. if domain c has halo cells on domain a, we have to go
4890 * over the halos of domain b
4891 *
4892 * ------- -------
4893 * | |
4894 * a | b | c
4895 * | |
4896 */
4897 MInt nghbrDomIdx2 = nghbrDomIdx;
4899 if (!isHalo) {
4900 const MInt ndom = newNghbrDomains[nghbrDomIdx];
4901 //TODO_SS labels:GRID can we ensure that the newly found domain will also find current domain?
4903 }
4904 }
4905 const MInt windowLayer = isHalo ? haloLayer_[nghbrDomIdx][nghbrId].get(solverId)
4906 : m_windowLayer_[nghbrDomIdx2][nghbrId].get(solverId);
4907
4908 if (windowLayer>layer+1) {
4909
4910 isHalo ? haloLayer_[nghbrDomIdx][nghbrId].set(solverId, layer+1)
4911 : m_windowLayer_[nghbrDomIdx2].at(nghbrId).set(solverId, layer+1);
4912 ASSERT((isHalo && haloLayer_[nghbrDomIdx][nghbrId].get(solverId)==layer+1)
4913 || (!isHalo && m_windowLayer_[nghbrDomIdx2].at(nghbrId).get(solverId)==layer+1), "");
4914
4915 if (layer+1<m_noSolverHaloLayers[solverId])
4916 exchangeCellList.insert({std::make_tuple(layer+1, nghbrId, nghbrDomIdx, solverId)});
4917 }
4918 //}
4919 }
4920 ++cnt;
4921 ++it;
4922 }
4923 if (cnt==noCandidates) break;
4924 }
4925 } //loop over layers
4926
4927
4928 MInt cnt = 0;
4929 for(MInt i = 0; i < noNeighborDomains(); i++) {
4930 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
4931 MInt cellId = m_windowCells[i][j];
4932 if(a_level(cellId) == level) {
4933 for(MInt child = 0; child < m_maxNoChilds; child++) {
4934 const MInt childId = a_childId(cellId, child);
4935 if(childId > -1) {
4936 if (m_windowLayer_[i].find(childId)!=m_windowLayer_[i].end()) {
4937 ASSERT(!m_windowLayer_[i].at(childId).all(), "");
4938 refineChildIds[m_maxNoChilds * cnt + child] = 1;
4939 }
4940 }
4941 }
4942 }
4943 cnt++;
4944 }
4945 }
4946
4947 // DEBUG output
4948}
MInt getAdjacentGridCells5(const MInt, MInt *const, const MInt level=-1, const MBool diagonalNeighbors=true)

◆ tagActiveWindowsAtMinLevel()

template<MInt nDim>
void CartesianGrid< nDim >::tagActiveWindowsAtMinLevel ( const MInt  level)
private
Date
June 2021

Definition at line 5411 of file cartesiangrid.cpp.

5411 {
5412 TRACE();
5413
5414 MIntScratchSpace nghbrList(27 * m_maxNoChilds, AT_, "nghbrList");
5415
5416 // We rely on the fact, that exchangeCellList is sorted by the tuple's first element, then by its 2nd element etc.
5417 std::set<std::tuple<MInt/*layer*/,MInt/*cellId*/, MInt/*nghbrIdx*/,MInt/*solverId*/>> exchangeCellList;
5418 std::vector<std::unordered_map<MInt, M32X4bit<true>>> haloLayer_(noNeighborDomains());
5419
5420 ASSERT(m_windowLayer_.empty(), "");
5422
5423 if(m_maxPartitionLevelShift > 0) {
5424 // exchange some window cell data
5425 ScratchSpace<MInt> bprops(m_tree.size(), 2, AT_, "bprops");
5426 bprops.fill(-1);
5427 // Note: changed loop to iterate over whole tree, internal and halo cells not sorted!
5428 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
5429 if(a_isHalo(cellId) || a_isToDelete(cellId)) {
5430 continue;
5431 }
5432 bprops(cellId, 0) = (MInt)a_hasProperty(cellId, Cell::IsPartLvlAncestor);
5433 bprops(cellId, 1) = a_noOffsprings(cellId);
5434
5435 ASSERT(bprops(cellId, 0) > -1 && bprops(cellId, 1) > 0,
5436 std::to_string(cellId) + " " + std::to_string(bprops(cellId, 0)) + " "
5437 + std::to_string(bprops(cellId, 1)));
5438 }
5440
5441 // Note: loop only over the current haloCells since only for these data is exchanged, this does
5442 // not work properly if in case of a partition level shift some halo cell is not part of
5443 // m_haloCells yet such that its property IsPartLvlAncestor is reset!
5444 for(MInt i = 0; i < noNeighborDomains(); i++) {
5445 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
5446 const MInt cellId = m_haloCells[i][j];
5447 ASSERT(!a_isToDelete(cellId), "");
5448 ASSERT(bprops(cellId, 0) > -1 && bprops(cellId, 1) > 0,
5449 std::to_string(cellId) + " " + std::to_string(bprops(cellId, 0)) + " "
5450 + std::to_string(bprops(cellId, 1)));
5451 a_hasProperty(cellId, Cell::IsPartLvlAncestor) = (MBool)bprops(cellId, 0);
5452 a_noOffsprings(cellId) = bprops(cellId, 1);
5453 }
5454 }
5455 }
5456
5457 // Get halo candidates
5458 for(MInt i = 0; i < noNeighborDomains(); i++) {
5459 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
5460 const MInt cellId = m_haloCells[i][j];
5461 ASSERT(a_level(cellId)==level, "We expect all halo cells at this point to be on minLevel");
5462
5463 // Note: currently we add all halos as candidates. A more sophisticated choice would be to add only those
5464 // who are adajcent to cells, which are not halos of same neighbor (the neighbor can still be a halo)
5465 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5466 // For the following to work we need to first exchange the solverBits; Check if it speeds up the whole stuff.
5467 // if (treeb().solver(cellId, solverId) || treeb().noSolvers()==1)
5468 exchangeCellList.insert({std::make_tuple(0, cellId, i, solverId)});
5469 }
5470
5471 if(m_maxPartitionLevelShift > 0) {
5472 if(a_hasProperty(cellId, Cell::IsPartLvlAncestor)) {
5473 const MInt minNghbrDomId = findNeighborDomainId(a_globalId(cellId));
5474 const MInt maxNghbrDomId =
5476 for(MInt k = 0; k < noNeighborDomains(); k++) {
5477 if(m_nghbrDomains[k] >= minNghbrDomId && m_nghbrDomains[k] <= maxNghbrDomId) {
5478 // Note: currently we add all halos as candidates. A more sophisticated choice would be to add only those
5479 // who are adajcent to cells, which are not halos of same neighbor (the neighbor can still be a halo)
5480 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5481 // For the following to work we need to first exchange the solverBits; Check if it speeds up the whole stuff.
5482 // if (treeb().solver(cellId, solverId) || treeb().noSolvers()==1)
5483 exchangeCellList.insert({std::make_tuple(0, cellId, k, solverId)});
5484 }
5485 }
5486 }
5487 }
5488 }
5489
5490 }
5491 }
5492
5493 vector<std::set<MInt>> windCellSet(noNeighborDomains());
5494 for(MInt i = 0; i < noNeighborDomains(); i++) {
5495 windCellSet[i].insert(m_windowCells[i].begin(), m_windowCells[i].end());
5496 }
5497 //
5498 for(MInt i = 0; i < noNeighborDomains(); i++) {
5499 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
5500 const MInt cellId = m_windowCells[i][j];
5501
5502 if (a_hasProperty(cellId, Cell::IsPartLvlAncestor)) {
5503 const MInt minNghbrDomId = findNeighborDomainId(a_globalId(cellId));
5504 const MInt maxNghbrDomId =
5506#ifndef NDEBUG
5507 for (MInt nD = minNghbrDomId; nD<=maxNghbrDomId; ++nD) {
5508 if (nD==domainId()) continue;
5509 MBool found = false;
5510 for (MInt ii = 0; ii < noNeighborDomains(); ii++) {
5511 if (m_nghbrDomains[ii]== nD) {
5512 found = true;
5513 break;
5514 }
5515 }
5516 TERMM_IF_NOT_COND(found, to_string(a_isHalo(cellId)) + " " + to_string(a_noOffsprings(cellId)));
5517 }
5518#endif
5519 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5520 if (treeb().solver(cellId, solverId)) {
5521// for(MInt k = 0; k < noNeighborDomains(); k++) {
5522 //if (domainId()==m_nghbrDomains[k]) continue; // check if this makes sense
5523 if(m_nghbrDomains[i/*k*/] >= minNghbrDomId && m_nghbrDomains[i/*k*/] <= maxNghbrDomId) {
5524 TERMM_IF_NOT_COND(windCellSet[i].find(cellId)!=windCellSet[i].end(), "");
5525 m_windowLayer_[i/*k*/][cellId].set(solverId, 0);
5526 exchangeCellList.insert({std::make_tuple(0, cellId, i/*k*/, solverId)});
5527 }
5528// }
5529 }
5530 }
5531 }
5532 }
5533 }
5534
5535
5536
5537 //
5538 for(MInt layer = 0; layer < m_noHaloLayers; layer++) {
5539
5540 const auto it_begin = exchangeCellList.lower_bound(std::make_tuple(layer,std::numeric_limits<MInt>::min(),
5541 std::numeric_limits<MInt>::min(), std::numeric_limits<MInt>::min()));
5542 const auto it_end = exchangeCellList.upper_bound(std::make_tuple(layer+1,std::numeric_limits<MInt>::min(),
5543 std::numeric_limits<MInt>::min(), std::numeric_limits<MInt>::min()));
5544 const MInt noCandidates = std::distance(it_begin, it_end);
5545
5546 MInt cnt = 0;
5547 for (auto it = it_begin; it!=it_end;) {
5548 ASSERT(get<0>(*it)==layer, "Send a bug report to the C++ vendor!");
5549 const MInt cellId = get<1>(*it);
5550
5551 // Only look for nghbrs on same level
5552 const MInt counter = getAdjacentGridCells5<false,false>(cellId, nghbrList.data());
5553
5554 while (cnt<noCandidates && cellId==get<1>(*it)) {
5555 ASSERT(get<0>(*it)==layer, "Send a bug report to the C++ vendor!");
5556 const MInt nghbrDomIdx = get<2>(*it);
5557 ASSERT((signed)m_windowLayer_.size()>nghbrDomIdx, "");
5558 const MInt solverId = get<3>(*it);
5559
5560 for(MInt n = 0; n < counter; n++) {
5561 const MInt nghbrId = nghbrList[n];
5562 ASSERT(a_level(nghbrId)==level, "Nghbr expected to be on same level");
5563
5564 // if 'treeb().solver(nghbrId, solverId)' is run before the bitsets are exhchanged, it will always result
5565 // in false for halo cells.
5566 // nghbrId must be either haloCell or window cell (at least for m_maxPartitionLevelShift==0).
5567 // Since solverBits haven't yet been exchanged, we cannot check solver affiliation of halo cells
5568 const MBool isHalo = a_isHalo(nghbrId);
5569 if (!isHalo && !treeb().solver(nghbrId, solverId)) continue;
5570
5571 // Sanity check that cell is in m_windowCells (with partLvlShift this check doesn't work always)
5572 if (!isHalo && windCellSet[nghbrDomIdx].find(nghbrId)==windCellSet[nghbrDomIdx].end() && m_maxPartitionLevelShift>0) continue;
5573#ifndef NDEBUG
5574 TERMM_IF_COND(!isHalo && windCellSet[nghbrDomIdx].find(nghbrId)==windCellSet[nghbrDomIdx].end(), "This must be a window cell!");
5575#endif
5576
5577 MInt windowLayer = isHalo ? haloLayer_[nghbrDomIdx][nghbrId].get(solverId)
5578 : m_windowLayer_[nghbrDomIdx][nghbrId].get(solverId);
5579 if (windowLayer>layer+1) {
5580
5581 isHalo ? haloLayer_[nghbrDomIdx][nghbrId].set(solverId, layer+1)
5582 : m_windowLayer_[nghbrDomIdx].at(nghbrId).set(solverId, layer+1);
5583 ASSERT((isHalo && haloLayer_[nghbrDomIdx][nghbrId].get(solverId)==layer+1)
5584 || (!isHalo && m_windowLayer_[nghbrDomIdx].at(nghbrId).get(solverId)==layer+1), "");
5585
5586 if (layer+1<m_noSolverHaloLayers[solverId])
5587 exchangeCellList.insert({std::make_tuple(layer+1, nghbrId, nghbrDomIdx, solverId)});
5588 }
5589 }
5590 ++cnt;
5591 ++it;
5592 }
5593 if (cnt==noCandidates) break;
5594 }
5595 } //loop over layers
5596
5597 // All cells which are in m_windowCells but still not in m_windowLayer_ are appended to the latter (I don't know if
5598 // it's necessary or clever to do it)
5599 for (MInt i = 0; i < noNeighborDomains(); ++i) {
5600 for(MInt j = 0; j < (signed)m_windowCells[i].size(); j++) {
5601 const MInt cellId = m_windowCells[i][j];
5602 ASSERT(!a_isHalo(cellId), "");
5603 if (m_windowLayer_[i].find(cellId)==m_windowLayer_[i].end()) {
5604 for (MInt solverId = 0; solverId < treeb().noSolvers(); ++solverId)
5605 if (m_tree.solver(cellId, solverId)) {
5606 // My guess: actually it should be sufficient to have m_noHaloLayers+1, but since the respective halos are
5607 // already created, we need to accept all cells in m_windowCells, which are not yet in m_windowLayer_,
5608 // to have matching buffer sizes in MPI communications
5609 m_windowLayer_[i][cellId].set(solverId, a_hasProperty(cellId, Cell::IsPartLvlAncestor) ? 1 : (m_haloMode==2) ? m_noHaloLayers+1 : m_noSolverHaloLayers[solverId]);
5610 }
5611 }
5612 }
5613 }
5614
5615 // DEBUG output
5616}

◆ tagActiveWindowsOnLeafLvl3()

template<MInt nDim>
void CartesianGrid< nDim >::tagActiveWindowsOnLeafLvl3 ( const MInt  maxLevel,
const MBool  duringMeshAdaptation,
const std::vector< std::function< void(const MInt)> > &  removeCellSolver = std::vector<std::function<void(const MInt)>>() 
)
private
Date
June 2021

Definition at line 4958 of file cartesiangrid.cpp.

4959 {
4960
4961 MIntScratchSpace nghbrList(27 * m_maxNoChilds, AT_, "nghbrList");
4962
4963 // We don't need to exchange a_hasProperty(cellId, Cell::IsPartLvlAncestor) and a_noOffsprings(cellId)
4964 // here, because the halo cells on level=maxLevel are never partLvlAnc and have always
4965 // a_noOffsprings(cellId)==1.
4966
4967#ifndef NDEBUG
4968 set<MInt> halos;
4969 // Get halo candidates
4970 for(MInt i = 0; i < noNeighborDomains(); i++) {
4971 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
4972 const MInt cellId = m_haloCells[i][j];
4973 halos.insert(cellId);
4974 }
4975 }
4976#endif
4977
4978 std::unordered_map<MInt, M32X4bit<true>> haloLayers;
4979
4980 // Note: when this is called during meshAdaptation, then changes will only occur above m_maxUniformRefinementLevel
4981 for (MInt level = m_minLevel; level <= maxLevel; level++) {
4982 std::set<std::tuple<MInt/*halolayer*/,MInt/*cellId*/,MInt/*solverId*/>> exchangeCellList;
4983
4984 // Find first layer window cells
4985 for (MInt i = 0; i < noNeighborDomains(); i++) {
4986 for (auto& item : m_windowLayer_[i]) {
4987 const MInt cellId = item.first;
4988
4989 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
4990 // TODO_SS labels:GRID what about a_hasChildren(cellId, solverId)<IPOW2(nDim)
4991 if (a_level(cellId)==level || (a_level(cellId)==level-1 && !a_hasChildren(cellId, solverId))) {
4992 if (item.second.get(solverId)<=1) {
4993 ASSERT(m_tree.solver(cellId, solverId), "Cell was identifed to be a valid windowCell for"
4994 " solver=" + to_string(solverId) + ", but does not belong to that solver");
4995 exchangeCellList.insert({std::make_tuple(0, cellId, solverId)});
4996 }
4997 }
4998 }
4999 }
5000
5001 // Find halo cells on level-1 with no children
5002 for (const auto& item : haloLayers) {
5003 const MInt cellId = item.first;
5004 if (a_level(cellId)==level-1) {
5005 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5006 const MInt haloLayer = item.second.get(solverId);
5007 if (!a_hasChildren(cellId, solverId) && haloLayer<m_noSolverHaloLayers[solverId]) {
5008 exchangeCellList.insert({std::make_tuple(haloLayer, cellId, solverId)});
5009 // TODO_SS labels:GRID what about a_hasChildren(cellId, solverId)<IPOW2(nDim)
5010 } /*else if (a_noChildren(cellId)<IPOW2(nDim) && haloLayer<=m_noSolverHaloLayers[solverId]) {
5011 for(MInt child = 0; child < m_maxNoChilds; child++) {
5012 MInt childId = a_childId(cellId, child);
5013 if(childId < 0) continue;
5014 if (treeb().solver(childId, solverId)) {
5015 haloLayers[childId].set(solverId, haloLayer);
5016 if (haloLayer<m_noSolverHaloLayers[solverId]) {
5017 exchangeCellList.insert({std::make_pair(haloLayer, childId), solverId});
5018 }
5019 }
5020 }
5021 }*/
5022 }
5023 }
5024 }
5025
5026 // In the following halo cells with children on current domain are also identified as 1st layer 'window' cells
5028 for(MInt j = 0; j < (signed)m_haloCells[i].size(); j++) {
5029 const MInt cellId = m_haloCells[i][j];
5030 if (a_hasProperty(cellId, Cell::IsPartLvlAncestor)) {
5031 const MInt minNghbrDomId = findNeighborDomainId(a_globalId(cellId));
5032 const MInt maxNghbrDomId =
5034 if (domainId()<minNghbrDomId || domainId()>maxNghbrDomId) continue;
5035 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5036 if (m_tree.solver(cellId, solverId) && a_hasChildren(cellId, solverId)) {
5037 // Guess: The folowing assert fails e.g. if partitionCellMaxNoOffspring==1 and one solver is at least one
5038 // level coarser then the other one.
5039// TERMM_IF_NOT_COND(a_hasChildren(cellId, solverId), "");
5040 //TODO_SS labels:GRID what about noChildren<IPOW2(nDim)
5041 if (a_level(cellId)==level || (a_level(cellId)==level-1 && !a_hasChildren(cellId, solverId))) {
5042 exchangeCellList.insert({std::make_tuple(0, cellId, solverId)});
5043 // It may happen that one domain has no window cell at this level at all so we add this cell to
5044 // haloLayers with layer==0
5045 haloLayers[cellId].set(solverId,0);
5046 }
5047 }
5048 }
5049 }
5050 }
5051 }
5052 }
5053
5054
5055 // In the following no distinction is made regarding the neighbor. The current domain is extended by the
5056 // required number of halo layers, and halo cells required by current domain are inserted in haloLayers.
5057 for(MInt layer = 0; layer < m_noHaloLayers; layer++) {
5058
5059 const auto it_begin = exchangeCellList.lower_bound(std::make_tuple(layer,std::numeric_limits<MInt>::min(),
5060 std::numeric_limits<MInt>::min()));
5061 const auto it_end = exchangeCellList.upper_bound(std::make_tuple(layer,std::numeric_limits<MInt>::max(),
5062 std::numeric_limits<MInt>::min()));
5063 const MInt noCandidates = std::distance(it_begin, it_end);
5064
5065 MInt cnt = 0;
5066 for (auto it = it_begin; it!=it_end;) {
5067 const MInt cellId = get<1>(*it);
5068 ASSERT(cellId > -1 && cellId < m_tree.size(), "");
5069
5070 const MInt counter = a_level(cellId)==level ? getAdjacentGridCells5<false,false>(cellId, nghbrList.data())
5071 : getAdjacentGridCells5<true,false>(cellId, nghbrList.data(), level);
5072 // TEST1
5073// const MInt counter = a_level(cellId)==level ? getAdjacentGridCells5<false,true>(cellId, nghbrList.data())
5074// : getAdjacentGridCells5<true,false>(cellId, nghbrList.data());
5075
5076
5077 while (cnt<noCandidates && cellId==get<1>(*it)) {
5078 ASSERT(get<0>(*it)==layer, "Send a bug report to the C++ vendor!");
5079 const MInt solverId = get<2>(*it);
5080
5081 //TODO_SS labels:GRID the case hat one of the neighbors has a_noChildren<IPOW2(nDim)
5082 for(MInt n = 0; n < counter; n++) {
5083 const MInt nghbrId = nghbrList[n];
5084 ASSERT(nghbrId > -1 && nghbrId < m_tree.size(), "");
5085
5086 //TEST1
5087/* TERMM_IF_NOT_COND(a_level(nghbrId)==level || a_level(nghbrId)==level-1, "");
5088 if (!a_isHalo(nghbrId) || !treeb().solver(nghbrId, solverId))
5089 continue;
5090 if (a_level(nghbrId)==level-1 && !a_hasChildren(nghbrId,solverId)) continue;
5091 if (a_level(nghbrId)==level-1) {
5092 TERMM_IF_NOT_COND(a_noChildren(nghbrId)<IPOW2(nDim) || a_noChildren(nghbrId)==0, "");
5093 for(MInt child = 0; child < m_maxNoChilds; child++) {
5094 MInt childId = a_childId(nghbrId, child);
5095 if(childId < 0) continue;
5096
5097 TERMM_IF_NOT_COND(treeb().solver(childId,solverId) && a_isHalo(childId), "");
5098 const MInt haloLayer = haloLayers[childId].get(solverId);
5099
5100 if (haloLayer>layer+1) {
5101
5102 haloLayers[childId].set(solverId, layer+1);
5103
5104 if (layer+1<m_noSolverHaloLayers[solverId])
5105 exchangeCellList.insert({std::make_pair(layer+1, childId), solverId});
5106 }
5107 }
5108 continue;
5109 }*/
5110
5111#ifndef NDEBUG
5112 // Sanity checks
5113 TERMM_IF_NOT_COND(a_level(nghbrId)==level, "");
5114 // It might happen that a cell is disabled, but the isHalo flag is still set, that' why the a_isHalo test is not reliable
5115 TERMM_IF_NOT_COND(((halos.find(nghbrId)!=halos.end())==(findNeighborDomainId(a_globalId(nghbrId))!=domainId()))
5116 || a_hasProperty(nghbrId, Cell::IsPeriodic) || !treeb().solver(nghbrId, solverId), "");
5117#endif
5118
5119 // Skip if cell is not halo
5120 if (!a_isHalo(nghbrId) || !treeb().solver(nghbrId, solverId)/* || a_hasProperty(nghbrId, Cell::IsPartLvlAncestor)*/)
5121 continue;
5122
5123 const MInt haloLayer = haloLayers[nghbrId].get(solverId);
5124
5125 if (haloLayer>layer+1) {
5126
5127 haloLayers[nghbrId].set(solverId, layer+1);
5128 ASSERT(haloLayers[nghbrId].get(solverId)==layer+1, "");
5129
5130 if (layer+1<m_noSolverHaloLayers[solverId])
5131 exchangeCellList.insert({std::make_tuple(layer+1, nghbrId, solverId)});
5132 }
5133 }
5134 ++cnt;
5135 ++it;
5136 }
5137 if (cnt==noCandidates)
5138 break;
5139 }
5140 } //loop over layers
5141 }
5142
5143
5144 // Traverse through the tree to mark all required halos on all levels
5145 std::unordered_map<MInt,M8X1bit<false>> validHalos;
5146 for (auto it = haloLayers.cbegin(); it!=haloLayers.cend(); ++it) {
5147 const MInt cellId = it->first;
5148 ASSERT(validHalos.find(cellId)==validHalos.end(), "Duplicate halo cells!");
5149 auto& flag = validHalos[cellId];
5150 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5151 if (it->second.get(solverId)<=m_noSolverHaloLayers[solverId]) {
5152 ASSERT(m_tree.solver(cellId,solverId), "");
5153 flag.set(solverId,1);
5154 }
5155 }
5156 }
5157
5158//#ifndef NDEBUG
5159 // Sanity check that all parents of valid halo cells are also marked as valid
5160 for (const auto& item : validHalos) {
5161 MInt parentId = item.first;
5162 while (a_parentId(parentId)>-1) {
5163 parentId = a_parentId(parentId);
5164 const auto it = validHalos.find(parentId);
5165
5166 // Case 1: noPartLvlShift, then parent must be halo, but it can reside on current domain in periodic case
5167 // Case 2: partLvlShift, then parent can be window
5168 TERMM_IF_NOT_COND(m_maxPartitionLevelShift>0 || (a_isHalo(parentId) && it!=validHalos.end()), "");
5169 TERMM_IF_NOT_COND(m_maxPartitionLevelShift>0 || a_hasProperty(parentId, Cell::IsPeriodic) || findNeighborDomainId(a_globalId(parentId))!=domainId(), "");
5170 TERMM_IF_NOT_COND(it!=validHalos.end() || (a_hasProperty(parentId, Cell::IsPartLvlAncestor) && !a_isHalo(parentId)), "");
5171
5172 if (it==validHalos.end()) break;
5173
5174 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5175 TERMM_IF_COND(item.second.get(solverId) && !it->second.get(solverId), " solverId=" + to_string(solverId) +
5176 ": Parent of valid halo cell is no halo!");
5177 }
5178 }
5179 }
5180//#endif
5181
5182 // ---Disable all halos not required & communicate with respective windows --- //
5183
5184 // Receive information from halo cells, whether the respective window cell is required
5185 ScratchSpace<MPI_Request> recvRequests(max(1, noNeighborDomains()), AT_, "recvRequests");
5186 fill(recvRequests.begin(), recvRequests.end(), MPI_REQUEST_NULL);
5187 MInt receiveCount = 0;
5188 for (const auto& vecWindow : m_windowCells) receiveCount+=vecWindow.size();
5189 ScratchSpace<M8X1bit<>::type> windowBuffer(max(1, receiveCount), AT_, "windowBuffer");
5190 for (MInt i = 0, offset = 0; i < noNeighborDomains(); i++) {
5191 const MInt noWindowCells = m_windowCells[i].size();
5192 if (noWindowCells<1) continue;
5193
5194 MPI_Irecv(&windowBuffer[offset], noWindowCells, type_traits<M8X1bit<>::type>::mpiType(), m_nghbrDomains[i],
5195 m_nghbrDomains[i], mpiComm(), &recvRequests[i], AT_, "windowBuffer[offset]");
5196
5197 offset += noWindowCells;
5198 }
5199
5200 // The meshAdaptation forces us to keep children of pla's
5201// const MBool hasPartLvlShift = (m_maxPartitionLevelShift > 0);
5202 const MInt tmpScratchSize = m_tree.size();//(hasPartLvlShift) ? m_tree.size() : 1;
5203 ScratchSpace<MBool> isHaloPartLvlAncestor(tmpScratchSize, AT_, "isHaloPartLvlAncestor");
5204 isHaloPartLvlAncestor.fill(false);
5205
5206 // Determine relevant halo partition level ancestor window/halo cells that need to be preserved
5207 if(m_maxPartitionLevelShift > 0) {
5208 for(auto& i : m_partitionLevelAncestorIds) {
5209 ASSERT(a_hasProperty(i, Cell::IsPartLvlAncestor),
5210 "cell is not a partition level ancestor: " + std::to_string(i));
5211 // Mark halo partition level ancestors (which are part of the missing subtree of the grid)
5212 if(a_hasProperty(i, Cell::IsHalo)) {
5213 isHaloPartLvlAncestor[i] = true;
5214 }
5215 // Mark all halo childs of partition level ancestors (required for exchange of e.g. global
5216 // ids!)
5217 for(MInt child = 0; child < m_maxNoChilds; child++) {
5218 const MInt childId = a_childId(i, child);
5219 if(childId > -1 && a_isHalo(childId)) {
5220 isHaloPartLvlAncestor[childId] = true;
5221 }
5222 }
5223 }
5224 }
5225 // Should we keep all isHaloPartLvlAncestor cells, because they are kept in meshAdaptation?!
5226
5227 struct comp {
5228 MBool operator()(const std::pair<MInt, MInt>& m1, const std::pair<MInt, MInt>& m2) const {
5229 if(m1.first < m2.first) {
5230 return true;
5231 } else if (m1.first==m2.first) {
5232 if(m1.second < m2.second) {
5233 return true;
5234 } else {
5235 return false;
5236 }
5237 } else {
5238 return false;
5239 }
5240 }
5241 };
5242
5243 const MInt threesholdLvl = !duringMeshAdaptation ? 0/*m_minLevel*/ : m_maxUniformRefinementLevel;
5244 ScratchSpace<MPI_Request> sendRequests(max(1, noNeighborDomains()), AT_, "sendRequests");
5245 fill(sendRequests.begin(), sendRequests.end(), MPI_REQUEST_NULL);
5246 MInt sendCount = 0;
5247 for (const auto& vecHalo : m_haloCells) sendCount+=vecHalo.size();
5248 ScratchSpace<M8X1bit<>::type> tmp_data(sendCount, AT_, "tmp_data");
5249 std::map<std::pair<MInt/*level*/,MInt/*cellId*/>,M8X1bit<false>,comp> toDelete;
5250 for (MInt i = 0, idx = 0; i < noNeighborDomains(); i++) {
5251 if (m_maxPartitionLevelShift==0) toDelete.clear();
5252 const MInt offset = idx;
5253 const MInt noHaloCells = m_haloCells[i].size();
5254 if (noHaloCells<1) continue;
5255 std::vector<MInt> haloCells;
5256 haloCells.reserve(noHaloCells);
5257
5258 // Temporary fix: In case two halos are mapped to same window cell, keep them (occurs in periodic case)
5259 ScratchSpace<MBool> isDuplicateHalo(m_noPeriodicCartesianDirs>0 ? m_tree.size() : 1, AT_, "isDuplicateHalo");
5260 isDuplicateHalo.fill(false);
5262 std::map<MLong,MInt> haloGlobalIds;
5263 for (const auto cellId : m_haloCells[i]) {
5264 const MLong globalId = a_globalId(cellId);
5265 if (haloGlobalIds.find(globalId)!=haloGlobalIds.end()) {
5266 isDuplicateHalo[haloGlobalIds[globalId]] = true;
5267 isDuplicateHalo[cellId] = true;
5268 } else
5269 haloGlobalIds.insert({std::make_pair(globalId, cellId)});
5270 }
5271 }
5272
5273 for (const auto cellId : m_haloCells[i]) {
5274 const MBool isValidHalo = validHalos.find(cellId)!=validHalos.end();
5275
5276#ifndef NDEBUG
5277 // Check that partLvlAnc halo cell, with children on current domain is identified as validHalo
5278 const MInt minNghbrDomId1 = findNeighborDomainId(a_globalId(cellId));
5279 const MInt maxNghbrDomId1 =
5281 if (domainId()>=minNghbrDomId1 && domainId()<=maxNghbrDomId1 && !a_hasProperty(cellId, Cell::IsPeriodic))
5282 TERMM_IF_NOT_COND(!a_hasProperty(cellId, Cell::IsPartLvlAncestor) || isValidHalo, "Cell is partLvlAncestor, but not found as valid halo!");
5283#endif
5284
5285 // TODO_SS labels:GRID,toenhance do it more efficiently
5286 // Don't delete anything on minLevel
5287 const M8X1bit<> solver = (a_level(cellId)<=threesholdLvl
5288 || isHaloPartLvlAncestor[cellId]
5289 || (m_noPeriodicCartesianDirs>0 && isDuplicateHalo[cellId]))
5290 ? M8X1bit<false>{M8X1bit<true>{}.data()} : (isValidHalo ? validHalos[cellId] : M8X1bit<false>{});
5291
5292 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5293 if (m_tree.solver(cellId,solverId) && !solver.get(solverId)) {
5294 auto key = std::make_pair(-a_level(cellId),cellId);
5295 toDelete[key].set(solverId,true);
5296 }
5297 if (a_level(cellId)>threesholdLvl && !isHaloPartLvlAncestor[cellId] && m_tree.solver(cellId,solverId))
5298 m_tree.solver(cellId,solverId) = solver.get(solverId);
5299 }
5300 tmp_data[idx++] = solver.data();
5301 if (m_tree.solverBits(cellId).any() || isHaloPartLvlAncestor[cellId]) {
5302 haloCells.push_back(cellId);
5303 } else {
5304// a_hasProperty(cellId, Cell::IsHalo) = false;
5305// a_isToDelete(cellId)=true;
5306// m_freeIndices.insert(cellId);
5307// removeCell<false>(cellId);
5308// ASSERT(toDelete.find(std::make_pair(-a_level(cellId),cellId))!=toDelete.end(), "");
5309 //TODO_SS labels:GRID,toenhance Check if it might make sense, to set M8X1bit<false>(M8X1bit<true>.data()), to force
5310 // the solvers to delete the cells, if they exist in the solvers.
5311 // We need the following because, we might have partLvlAnc cell belonging to a solver,
5312 // but one of its children does not. So if we just propagate the informations from parent cell
5313 // we might have created halo cells, which are not used by any solver. We need to delete them.
5314 toDelete.insert({std::make_pair(-a_level(cellId),cellId), M8X1bit<false>()});
5315 }
5316 }
5318 if (m_maxPartitionLevelShift==0) {
5319 // In case of partLvlShift we need to first loop over all neigbhors, because a cell marked for deletion
5320 // might still have children, which belong to a different neighbor and are therefore not deleted yet
5321 for (const auto& item : toDelete) {
5322 const MInt cellId = item.first.second;
5323 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5324 if (!removeCellSolver.empty() && item.second.get(solverId)) {
5325 removeCellSolver[solverId](cellId);
5326 }
5327 }
5328 if (m_tree.solverBits(cellId).none()) {
5329 ASSERT(!isHaloPartLvlAncestor[cellId], "");
5330 removeCell<false>(cellId);
5331
5332 }
5333 }
5334 }
5335
5336 ASSERT(idx-offset==noHaloCells, "");
5337
5338 MPI_Isend(&tmp_data[offset], noHaloCells, type_traits<M8X1bit<>::type>::mpiType(), m_nghbrDomains[i], domainId(),
5339 mpiComm(), &sendRequests[i], AT_, "tmp_data");
5340 }
5342 for (const auto& item : toDelete) {
5343 const MInt cellId = item.first.second;
5344 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5345 if (!removeCellSolver.empty() && item.second.get(solverId)) {
5346 removeCellSolver[solverId](cellId);
5347 }
5348 }
5349 if (m_tree.solverBits(cellId).none()) {
5350 removeCell<false>(cellId);
5351 }
5352 }
5353 }
5354
5355 // Finish MPI communication
5356 MPI_Waitall(noNeighborDomains(), &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
5357 MPI_Waitall(noNeighborDomains(), &sendRequests[0], MPI_STATUSES_IGNORE, AT_);
5358
5359 for (MInt i = 0, idx = 0; i < noNeighborDomains(); i++) {
5360 // In periodic cases some window cells may appear twice; we have ensured above that those cells are always kept
5361 std::vector<MInt> windowCells;
5362 windowCells.reserve(m_windowCells[i].size());
5363 for (const auto cellId : m_windowCells[i]) {
5364 ASSERT(m_windowLayer_[i].find(cellId)!=m_windowLayer_[i].end(), "");
5365 M8X1bit<> solver(windowBuffer[idx++]);
5366 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5367 if (!solver.get(solverId) && isSolverWindowCell(i,cellId,solverId))
5368 m_windowLayer_[i].at(cellId).set(solverId, m_noHaloLayers+1);
5369 }
5370 MBool validWindow = false;
5371 for (MInt solverId = 0; solverId < treeb().noSolvers(); solverId++) {
5372 if (isSolverWindowCell(i,cellId,solverId)) {
5373 windowCells.push_back(cellId);
5374 validWindow=true;
5375 break;
5376 }
5377 }
5378 ASSERT(solver.any()==validWindow, "");
5379 // If a window cell was already checked and not deleted, we are not allowed to delete it now
5380 if (!validWindow) {
5381 //TODO_SS labels:GRID periodic cases
5382 const MBool ok = m_windowLayer_[i].erase(cellId);
5383 ASSERT(ok, "");
5384 MBool isWindow = false;
5385 for (const auto& w : m_windowLayer_) {
5386 if (w.find(cellId)!=w.end()) {
5387 isWindow = true;
5388 break;
5389 }
5390 }
5391 if (!isWindow)
5392 a_hasProperty(cellId, Cell::IsWindow) = false;
5393 }
5394 }
5396 }
5397
5398 if (!duringMeshAdaptation)
5399 compactCells();
5400
5401 // DEBUG output
5402}
MInt get(const MInt index) const
Definition: maiatypes.h:91
MBool any() const
Definition: maiatypes.h:95
T type
Definition: maiatypes.h:82
T data() const
Definition: maiatypes.h:105

◆ tagAzimuthalHigherLevelExchangeCells()

template<MInt nDim>
void CartesianGrid< nDim >::tagAzimuthalHigherLevelExchangeCells ( std::vector< MLong > &  refineChildIds,
std::vector< MLong > &  recvChildIds,
MInt  level 
)
Author
Thomas Hoesgen
Date
November 2020

Definition at line 13773 of file cartesiangrid.cpp.

13775 {
13776 TRACE();
13777
13778 if(noAzimuthalNeighborDomains() == 0) return;
13779
13780 static constexpr MFloat cornerStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
13781 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
13782 MIntScratchSpace nghbrList(200, AT_, "nghbrList");
13783 MFloat childCoords[3] = {F0, F0, F0};
13784 MFloat coordsCyl[3] = {F0, F0, F0};
13785 MFloat dxCyl = m_azimuthalAngle;
13786
13787 MInt noCells = treeb().size();
13788 MBoolScratchSpace gridBndryCells(noCells, AT_, "gridBndryCells");
13789 gridBndryCells.fill(false);
13790 for(auto it = m_gridBndryCells.begin(); it != m_gridBndryCells.end(); it++) {
13791 MInt cellId = *it;
13792 gridBndryCells[cellId] = true;
13793 }
13794
13795 MInt windowCnt = 0;
13796 MInt haloCnt = 0;
13797 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
13798 windowCnt += m_azimuthalWindowCells[i].size();
13799 haloCnt += m_azimuthalHaloCells[i].size();
13800 }
13801
13802 refineChildIds.resize(windowCnt * m_maxNoChilds);
13803 recvChildIds.resize(haloCnt * m_maxNoChilds);
13804
13805 MIntScratchSpace refinedWindows(windowCnt, AT_, "refinedWindows");
13806 refinedWindows.fill(0);
13807 MIntScratchSpace refineCandidates(haloCnt, AT_, "refineCandidates");
13808 refineCandidates.fill(0);
13809
13810 // Check which azimuthal window allows possible halo refinement
13811 // Only halo cells for which the corresponding internal cell is refined
13812 // are allowed to be refined
13813 MInt cnt = 0;
13814 MIntScratchSpace windowRefineCnt(noAzimuthalNeighborDomains(), AT_, "windowRefineCnt");
13815 windowRefineCnt.fill(0);
13816 MInt windowRefineCntTotal = 0;
13817 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
13818 for(MInt j = 0; j < noAzimuthalWindowCells(i); j++) {
13820
13821 MBool refine = false;
13822 if(a_level(cellId) == level) {
13823 if(a_noChildren(cellId) > 0) {
13824 refine = true;
13825 }
13826 }
13827
13828 if(refine) {
13829 refinedWindows[cnt] = 1;
13830 windowRefineCnt[i]++;
13831 windowRefineCntTotal++;
13832 }
13833 cnt++;
13834 }
13835 }
13836
13837 MIntScratchSpace windowMap(windowRefineCntTotal, AT_, "windowMap");
13838 cnt = 0;
13839 windowRefineCntTotal = 0;
13840 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
13841 for(MInt j = 0; j < noAzimuthalWindowCells(i); j++) {
13842 if(refinedWindows[cnt] > 0) {
13844 windowMap[windowRefineCntTotal] = cellId;
13845 windowRefineCntTotal++;
13846 }
13847 cnt++;
13848 }
13849 }
13850
13852 refinedWindows.getPointer(), refineCandidates.getPointer());
13853
13854 // Compute hilbertIds of refineCandidates childs
13855 cnt = 0;
13856 MInt haloRefineCntTotal = 0;
13857 MIntScratchSpace haloRefineCnt(noAzimuthalNeighborDomains(), AT_, "haloRefineCnt");
13858 haloRefineCnt.fill(0);
13859 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
13860 for(MInt j = 0; j < noAzimuthalHaloCells(i); j++) {
13861 if(refineCandidates[cnt] > 0) {
13862 haloRefineCnt[i]++;
13863 haloRefineCntTotal++;
13864 }
13865 cnt++;
13866 }
13867 }
13868
13869 MIntScratchSpace haloMap(haloRefineCntTotal, AT_, "haloMap");
13870 MIntScratchSpace refineHalo(noCells, AT_, "refineHalo");
13871 cnt = 0;
13872 haloRefineCntTotal = 0;
13873 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
13874 for(MInt j = 0; j < noAzimuthalHaloCells(i); j++) {
13876 refineHalo[cellId] = refineCandidates[cnt];
13877 if(refineCandidates[cnt] > 0) {
13878 haloMap[haloRefineCntTotal] = cellId;
13879 haloRefineCntTotal++;
13880 }
13881 cnt++;
13882 }
13883 }
13884
13885 MIntScratchSpace layerId(noCells, AT_, "layerId");
13886 layerId.fill(-1);
13887 for(MInt cellId = 0; cellId < noCells; cellId++) {
13888 if(a_isHalo(cellId)) {
13889 continue;
13890 }
13891 if(a_level(cellId) != level) {
13892 continue;
13893 }
13894 for(MInt d = 0; d < m_noDirs; d++) {
13895 MInt nghbrId = a_neighborId(cellId, d);
13896 if(nghbrId <= -1) {
13897 continue;
13898 }
13899 if(!a_isHalo(nghbrId)) {
13900 continue;
13901 }
13902 layerId[nghbrId] = 1;
13903
13904 MInt addLayer = true;
13905 if(!a_hasProperty(nghbrId, Cell::IsPeriodic)) {
13906 if(a_noChildren(nghbrId) != 0) {
13907 addLayer = false;
13908 }
13909 } else {
13910 if(refineHalo[nghbrId] > 0) {
13911 addLayer = false;
13912 }
13913 }
13914
13915 for(MInt d2 = 0; d2 < m_noDirs; d2++) {
13916 if(!addLayer && d == d2) {
13917 continue;
13918 }
13919 MInt nghbrId2 = a_neighborId(nghbrId, d2);
13920 if(nghbrId2 <= -1) {
13921 continue;
13922 }
13923 if(a_isHalo(nghbrId2) && layerId[nghbrId2] <= -1) {
13924 layerId[nghbrId2] = 2;
13925 }
13926 for(MInt d3 = 0; d3 < m_noDirs; d3++) {
13927 if(d3 == d || d3 == d2) {
13928 continue;
13929 }
13930 MInt nghbrId3 = a_neighborId(nghbrId2, d3);
13931 if(nghbrId3 <= -1) {
13932 continue;
13933 }
13934 if(a_isHalo(nghbrId3) && layerId[nghbrId3] <= -1) {
13935 layerId[nghbrId3] = 3;
13936 }
13937 }
13938 }
13939 }
13940 }
13941
13942 MLongScratchSpace haloChildIds(2 * haloRefineCntTotal * m_maxNoChilds, AT_, "haloChildIds");
13943 cnt = 0;
13944 ASSERT(m_noHaloLayers == 2, ""); // If m_noHaloLayers != 2 everything will break!
13945 for(MInt i = 0; i < haloRefineCntTotal; i++) {
13946 MInt cellId = haloMap[i];
13947
13948 MBool refine = false;
13949
13950 // Only refine halo cells which has a refined internal cell in its vicinity.
13951 if(a_level(cellId) == level) {
13952 if(layerId[cellId] > 0) {
13953 refine = true;
13954 }
13955 }
13956
13957 if(!refine) {
13958 fill(&haloChildIds[i * 2 * m_maxNoChilds], &haloChildIds[i * 2 * m_maxNoChilds] + (2 * m_maxNoChilds), -2);
13959 continue;
13960 }
13961
13962 MInt parentId = cellId;
13963 for(MInt lvl = level; lvl > m_minLevel; lvl--) {
13964 parentId = a_parentId(parentId);
13965 }
13966
13967 cartesianToCylindric(&a_coordinate(parentId, 0), coordsCyl);
13968 MInt side = m_azimuthalBbox.azimuthalSide(coordsCyl[1]);
13969
13970 // If cell is supposed to be refined. Calculate hilbertIds of the rotated coordinate of possible childs
13971 MFloat hLength = F1B2 * cellLengthAtLevel(a_level(cellId));
13972 for(MInt child = 0; child < m_maxNoChilds; child++) {
13973 for(MInt d = 0; d < nDim; d++) {
13974 childCoords[d] = a_coordinate(cellId, d) + cornerStencil[child][d] * F1B2 * hLength;
13975 }
13976 rotateCartesianCoordinates(childCoords, side * dxCyl);
13977
13978 MLong hilbertId =
13980 haloChildIds[i * 2 * m_maxNoChilds + 2 * child] = hilbertId;
13981 hilbertId = hilbertIndexGeneric(&childCoords[0], m_targetGridCenterOfGravity, m_targetGridLengthLevel0, level);
13982 haloChildIds[i * 2 * m_maxNoChilds + 2 * child + 1] = hilbertId;
13983 }
13984 }
13985
13986 ScratchSpace<MPI_Request> mpi_send_req(noAzimuthalNeighborDomains(), AT_, "mpi_send_req");
13987 ScratchSpace<MPI_Request> mpi_recv_req(noAzimuthalNeighborDomains(), AT_, "mpi_recv_req");
13988 mpi_send_req.fill(MPI_REQUEST_NULL);
13989 mpi_recv_req.fill(MPI_REQUEST_NULL);
13990
13991 MLongScratchSpace windowChildIds(2 * windowRefineCntTotal * m_maxNoChilds, AT_, "windowChildIds");
13992 cnt = 0;
13993 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
13994 if(windowRefineCnt[i] > 0) {
13995 MInt bufSize = 2 * m_maxNoChilds * windowRefineCnt[i];
13996 MPI_Irecv(&windowChildIds[cnt], bufSize, MPI_LONG, m_azimuthalNghbrDomains[i], 2, mpiComm(), &mpi_recv_req[i],
13997 AT_, "windowChildIds[cnt]");
13998 cnt += bufSize;
13999 }
14000 }
14001
14002 cnt = 0;
14003 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
14004 if(haloRefineCnt[i] > 0) {
14005 MInt bufSize = 2 * m_maxNoChilds * haloRefineCnt[i];
14006 MPI_Isend(&haloChildIds[cnt], bufSize, MPI_LONG, m_azimuthalNghbrDomains[i], 2, mpiComm(), &mpi_send_req[i], AT_,
14007 "haloChildIds[cnt]");
14008 cnt += bufSize;
14009 }
14010 }
14011
14012 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
14013 if(windowRefineCnt[i] > 0) MPI_Wait(&mpi_recv_req[i], MPI_STATUSES_IGNORE, AT_);
14014 if(haloRefineCnt[i] > 0) MPI_Wait(&mpi_send_req[i], MPI_STATUSES_IGNORE, AT_);
14015 }
14016
14017 // Now an internal cell is searched with the same hilbertId as the rotate halo child coordinate
14018 for(MInt i = 0; i < windowRefineCntTotal; i++) {
14019 MInt cellId = windowMap[i];
14020
14021 MBool gridBndry = gridBndryCells[cellId];
14022 MBool noRefine = false;
14023
14024 for(MInt child = 0; child < m_maxNoChilds; child++) {
14025 MLong haloHilbertId_L1 = windowChildIds[i * 2 * m_maxNoChilds + 2 * child];
14026 MLong haloHilbertId_L0 = windowChildIds[i * 2 * m_maxNoChilds + 2 * child + 1];
14027 windowChildIds[i * 2 * m_maxNoChilds + 2 * child] = -2;
14028 windowChildIds[i * 2 * m_maxNoChilds + 2 * child + 1] = -2;
14029
14030 if(haloHilbertId_L1 < -1) {
14031 windowChildIds[i * m_maxNoChilds + child] = -2;
14032 continue;
14033 }
14034
14035 MBool found = false;
14036 // First check in the childs of the parent window cell
14037 for(MInt child2 = 0; child2 < m_maxNoChilds; child2++) {
14038 MInt childId = a_childId(cellId, child2);
14039 if(childId < 0) continue;
14040
14042 m_targetGridLengthLevel0, level + 1);
14043
14044 if(hilbertId == haloHilbertId_L1) {
14045 windowChildIds[i * m_maxNoChilds + child] = a_globalId(childId);
14046
14047 found = true;
14048 break;
14049 }
14050 }
14051 if(found) continue;
14052
14053 // Now the neighboring cells of the internal cell are searched
14054 // They can either be on the child level or the current level
14055 // An azimuthal periodic connection between to cells, which are not on the same grid level
14056 // is possible!
14057 const MInt counter = getAdjacentGridCells(cellId, nghbrList, level);
14058 for(MInt n = 0; n < counter; n++) {
14059 MInt nghbrId = nghbrList[n];
14060 if(nghbrId < 0) continue;
14061 if(a_level(nghbrId) == level + 1) {
14063 m_targetGridLengthLevel0, level + 1);
14064 if(hilbertId == haloHilbertId_L1) {
14065 windowChildIds[i * m_maxNoChilds + child] = a_globalId(nghbrId);
14066
14067 found = true;
14068 break;
14069 }
14070 } else if(a_level(nghbrId) == level) {
14073
14074 if(hilbertId == haloHilbertId_L0) {
14075 windowChildIds[i * m_maxNoChilds + child] = a_globalId(nghbrId);
14076 found = true;
14077 break;
14078 }
14079 }
14080 }
14081 // If no adequate internal cellis found for on of the possible halo childs.
14082 // the halo cell will not be refined at all, alas it is a gridBndryCell, meaing
14083 // the rotated coordinate of the possible halo cell child could lie outside the
14084 // cartesian grid. In this case this cells becomes an unmapped halo cell and requires
14085 // special treatment
14086 if(!found) {
14087 if(gridBndry) {
14088 windowChildIds[i * m_maxNoChilds + child] = -1;
14089 } else {
14090 noRefine = true;
14091 break;
14092 }
14093 }
14094 }
14095 if(noRefine) {
14096 for(MInt child = 0; child < m_maxNoChilds; child++) {
14097 windowChildIds[i * m_maxNoChilds + child] = -2;
14098 }
14099 }
14100 }
14101
14102 cnt = 0;
14103 windowRefineCntTotal = 0;
14104 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
14105 for(MInt j = 0; j < noAzimuthalWindowCells(i); j++) {
14106 if(refinedWindows[cnt] > 0) {
14107 for(MInt child = 0; child < m_maxNoChilds; child++) {
14108 refineChildIds[cnt * m_maxNoChilds + child] = windowChildIds[windowRefineCntTotal * m_maxNoChilds + child];
14109 }
14110 windowRefineCntTotal++;
14111 } else {
14112 auto it = refineChildIds.begin() + (cnt * m_maxNoChilds);
14113 fill(it, it + m_maxNoChilds, -1);
14114 }
14115 cnt++;
14116 }
14117 }
14118
14119 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
14120 mpi_send_req[i] = MPI_REQUEST_NULL;
14121 mpi_recv_req[i] = MPI_REQUEST_NULL;
14122 }
14123
14124
14125 cnt = 0;
14126 haloChildIds.fill(-2);
14127 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
14128 if(haloRefineCnt[i] > 0) {
14129 MInt bufSize = m_maxNoChilds * haloRefineCnt[i];
14130 MPI_Irecv(&haloChildIds[cnt], bufSize, MPI_DOUBLE, m_azimuthalNghbrDomains[i], 2, mpiComm(), &mpi_recv_req[i],
14131 AT_, "haloChildIds[cnt]");
14132 cnt += bufSize;
14133 }
14134 }
14135
14136 cnt = 0;
14137 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
14138 if(windowRefineCnt[i] > 0) {
14139 MInt bufSize = m_maxNoChilds * windowRefineCnt[i];
14140 MPI_Isend(&windowChildIds[cnt], bufSize, MPI_DOUBLE, m_azimuthalNghbrDomains[i], 2, mpiComm(), &mpi_send_req[i],
14141 AT_, "windowChildIds[cnt]");
14142 cnt += bufSize;
14143 }
14144 }
14145
14146 MPI_Waitall(noAzimuthalNeighborDomains(), &mpi_recv_req[0], MPI_STATUSES_IGNORE, AT_);
14147 MPI_Waitall(noAzimuthalNeighborDomains(), &mpi_send_req[0], MPI_STATUSES_IGNORE, AT_);
14148
14149 // GlobalIds of internal cells are send to halo rank.
14150 cnt = 0;
14151 haloRefineCntTotal = 0;
14152 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
14153 for(MInt j = 0; j < noAzimuthalHaloCells(i); j++) {
14154 if(refineCandidates[cnt] > 0) {
14155 for(MInt child = 0; child < m_maxNoChilds; child++) {
14156 recvChildIds[cnt * m_maxNoChilds + child] = haloChildIds[haloRefineCntTotal * m_maxNoChilds + child];
14157 }
14158 haloRefineCntTotal++;
14159 } else {
14160 auto it = recvChildIds.begin() + (cnt * m_maxNoChilds);
14161 fill(it, it + m_maxNoChilds, -2);
14162 }
14163 cnt++;
14164 }
14165 }
14166}
MInt azimuthalSide(const MFloat phi)

◆ tagAzimuthalUnmappedHaloCells()

template<MInt nDim>
void CartesianGrid< nDim >::tagAzimuthalUnmappedHaloCells ( std::vector< std::vector< MLong > > &  shiftWindows,
std::vector< MLong > &  haloChildIds,
std::vector< MInt > &  haloDomainIds,
MInt  level 
)
Author
Thomas Hoesgen
Date
November 2020

Definition at line 14358 of file cartesiangrid.cpp.

14361 {
14362 TRACE();
14363
14364 static constexpr MFloat cornerStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
14365 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
14366 MFloat childCoords[3] = {F0, F0, F0};
14367 MFloat coordsCyl[3] = {F0, F0, F0};
14368 MFloat dxCyl = m_azimuthalAngle;
14369
14370 MInt cellCnt = 0;
14371 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
14372 if(a_level(cellId) != level + 1) continue;
14373 if(a_isHalo(cellId)) continue;
14374 cellCnt++;
14375 }
14376
14377 unordered_multimap<MLong, MInt> hilbertToLocal;
14378 hilbertToLocal.reserve(cellCnt * 1.5);
14379 ScratchSpace<MLong> hilbertOffsets(noDomains() + 1, AT_, "hilbertOffsets");
14380 MLong minHilbertIndex = std::numeric_limits<MLong>::max();
14381 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
14382 if(a_isHalo(cellId)) continue;
14385 minHilbertIndex = mMin(minHilbertIndex, hilbertId);
14386 if(a_level(cellId) != level + 1) continue;
14387 hilbertId =
14389 hilbertToLocal.insert(make_pair(hilbertId, cellId));
14390 }
14391 MPI_Allgather(&minHilbertIndex, 1, MPI_LONG, &hilbertOffsets[0], 1, MPI_LONG, mpiComm(), AT_, "minHilbertIndex",
14392 "hilbertOffsets[0]");
14393 hilbertOffsets[0] = 0;
14394 hilbertOffsets[noDomains()] = std::numeric_limits<MLong>::max();
14395
14396 if(m_noHaloLayers != 2) mTerm(1, AT_, "Only working with noHaloLayers=2");
14397
14398 MIntScratchSpace noSndHilberts(noDomains(), AT_, "noSndHilberts");
14399 noSndHilberts.fill(0);
14400
14401 shiftWindows.resize(noDomains());
14402
14403 haloDomainIds.resize(m_maxNoChilds * noAzimuthalUnmappedHaloCells());
14404 fill(haloDomainIds.begin(), haloDomainIds.end(), -1);
14405 haloChildIds.resize(m_maxNoChilds * noAzimuthalUnmappedHaloCells());
14406 fill(haloChildIds.begin(), haloChildIds.end(), -1);
14407
14408 MIntScratchSpace candidateMap(noAzimuthalUnmappedHaloCells(), AT_, "candidateMap");
14409 candidateMap.fill(-1);
14410 MLongScratchSpace candidateHilbertIds(m_maxNoChilds * noAzimuthalUnmappedHaloCells(), AT_, "candidateHilbertIds");
14411 candidateHilbertIds.fill(-1);
14412 MInt noRefineCandidates = 0;
14413
14414 // Almost Always refine unmapped halo cells
14415 MIntScratchSpace nghbrList(200, AT_, "nghbrList");
14416 for(MInt i = 0; i < noAzimuthalUnmappedHaloCells(); i++) {
14418 if(a_level(cellId) != level) continue;
14419
14420 MBool refine = false;
14421 const MInt counter = getAdjacentGridCells(cellId, nghbrList, (level - 1), true);
14422 for(MInt n = 0; n < counter; n++) {
14423 MInt nghbrId = nghbrList[n];
14424 if(nghbrId < 0) continue;
14425 if(a_isHalo(nghbrId)) continue;
14426 if(a_noChildren(nghbrId) > 0) {
14427 refine = true;
14428 }
14429 }
14430
14431 // First the hilbertIds of the child cells are calculated.
14432 // The hilbertIds are communicated to the mpi rank which has the
14433 // respective hilbertIdRange.
14434 // Then, it is checked if an internal cell can be found with the same hilbertId
14435 // to create an azimuthal window halo mapping.
14436 if(refine) {
14437 candidateMap[noRefineCandidates] = i;
14438
14439 MInt parentId = cellId;
14440 for(MInt lvl = level; lvl > m_minLevel; lvl--) {
14441 parentId = a_parentId(parentId);
14442 }
14443
14444 // It is more robust to determine the side with the parent on the minLevel
14445 cartesianToCylindric(&a_coordinate(parentId, 0), coordsCyl);
14446 MInt side = m_azimuthalBbox.azimuthalSide(coordsCyl[1]);
14447
14448 MFloat hLength = F1B2 * cellLengthAtLevel(a_level(cellId));
14449 for(MInt child = 0; child < m_maxNoChilds; child++) {
14450 for(MInt d = 0; d < nDim; d++) {
14451 childCoords[d] = a_coordinate(cellId, d) + cornerStencil[child][d] * F1B2 * hLength;
14452 }
14453 rotateCartesianCoordinates(childCoords, side * dxCyl);
14454
14455 MLong hilbertId =
14457
14458 MInt dom = -1;
14459 for(MInt d = 0; d < noDomains(); d++) {
14460 if(hilbertOffsets[d + 1] > hilbertId) {
14461 dom = d;
14462 break;
14463 }
14464 }
14465
14466 hilbertId = hilbertIndexGeneric(childCoords, m_targetGridCenterOfGravity, m_targetGridLengthLevel0, level + 1);
14467
14468 haloDomainIds[i * m_maxNoChilds + child] = dom;
14469 candidateHilbertIds[noRefineCandidates * m_maxNoChilds + child] = hilbertId;
14470 noSndHilberts[dom]++;
14471 }
14472 noRefineCandidates++;
14473 } else {
14474 fill(&haloChildIds[i * m_maxNoChilds], &haloChildIds[i * m_maxNoChilds] + m_maxNoChilds, -2);
14475 }
14476 }
14477
14478
14479 // Now the hilbertIds are communicated
14480 MIntScratchSpace sndOffsets(noDomains() + 1, AT_, "sndOffsets");
14481 sndOffsets[0] = 0;
14482 for(MInt d = 0; d < noDomains(); d++) {
14483 sndOffsets[d + 1] = sndOffsets[d] + noSndHilberts[d];
14484 noSndHilberts[d] = 0;
14485 }
14486
14487 MLongScratchSpace sndHilbertIds(m_maxNoChilds * noRefineCandidates, AT_, "sndHilbertIds");
14488 for(MInt i = 0; i < noRefineCandidates; i++) {
14489 MInt candidateId = candidateMap[i];
14490 for(MInt child = 0; child < m_maxNoChilds; child++) {
14491 MInt dom = haloDomainIds[candidateId * m_maxNoChilds + child];
14492 sndHilbertIds[sndOffsets[dom] + noSndHilberts[dom]] = candidateHilbertIds[i * m_maxNoChilds + child];
14493 noSndHilberts[dom]++;
14494 }
14495 }
14496
14497
14498 MIntScratchSpace noRcvHilberts(noDomains(), AT_, "noRcvHilberts");
14499 MPI_Alltoall(&noSndHilberts[0], 1, MPI_INT, &noRcvHilberts[0], 1, MPI_INT, mpiComm(), AT_, "noSndHilberts[0]",
14500 "noRcvHilberts[0]");
14501
14502
14503 MInt rcvHilbertsTotal = 0;
14504 MIntScratchSpace rcvOffsets(noDomains() + 1, AT_, "rcvOffsets");
14505 rcvOffsets[0] = 0;
14506 for(MInt d = 0; d < noDomains(); d++) {
14507 rcvOffsets[d + 1] = rcvOffsets[d] + noRcvHilberts[d];
14508 rcvHilbertsTotal += noRcvHilberts[d];
14509 }
14510 MLongScratchSpace rcvHilbertIds(rcvHilbertsTotal, AT_, "rcvHilbertIds");
14511
14512
14513 ScratchSpace<MPI_Request> sendReq(noDomains(), AT_, "sendReq");
14514 sendReq.fill(MPI_REQUEST_NULL);
14515
14516 for(MInt i = 0; i < noDomains(); i++) {
14517 if(noSndHilberts[i] == 0) continue;
14518 MPI_Issend(&sndHilbertIds[sndOffsets[i]], noSndHilberts[i], type_traits<MLong>::mpiType(), i, 24, mpiComm(),
14519 &sendReq[i], AT_, "sndHilbertIds[sndOffsets[i]");
14520 }
14521
14522 for(MInt i = 0; i < noDomains(); i++) {
14523 if(noRcvHilberts[i] == 0) continue;
14524 MPI_Recv(&rcvHilbertIds[rcvOffsets[i]], noRcvHilberts[i], type_traits<MLong>::mpiType(), i, 24, mpiComm(),
14525 MPI_STATUS_IGNORE, AT_, "rcvHilbertIds[rcvOffsets[i]]");
14526 }
14527
14528 for(MInt i = 0; i < noDomains(); i++) {
14529 if(noSndHilberts[i] == 0) continue;
14530 MPI_Wait(&sendReq[i], MPI_STATUSES_IGNORE, AT_);
14531 }
14532
14533
14534 // Check if internal cell can be found which has same hilbertId
14535 for(MInt i = 0; i < noDomains(); i++) {
14536 for(MInt j = 0; j < noRcvHilberts[i]; j++) {
14537 MLong hilbertId = rcvHilbertIds[rcvOffsets[i] + j];
14538
14539 MInt windowId = -1;
14540 auto range = hilbertToLocal.equal_range(hilbertId);
14541 for(auto it = range.first; it != range.second; ++it) {
14542 if(!a_hasProperty(it->second, Cell::IsPeriodic) && !a_hasProperty(it->second, Cell::IsHalo)) {
14543 windowId = it->second;
14544 }
14545 }
14546 ASSERT(windowId > -2, to_string(windowId) + " " + to_string(m_noInternalCells));
14547
14548 if(windowId > -1) {
14549 rcvHilbertIds[rcvOffsets[i] + j] = a_globalId(windowId);
14550 shiftWindows[i].push_back(rcvHilbertIds[rcvOffsets[i] + j]);
14551 } else {
14552 rcvHilbertIds[rcvOffsets[i] + j] = -1;
14553 }
14554 }
14555 }
14556
14557 // Communicated globalIds of found internal cells back to halo rank
14558 sendReq.fill(MPI_REQUEST_NULL);
14559
14560 for(MInt i = 0; i < noDomains(); i++) {
14561 if(noRcvHilberts[i] == 0) continue;
14562 MPI_Issend(&rcvHilbertIds[rcvOffsets[i]], noRcvHilberts[i], type_traits<MLong>::mpiType(), i, 12, mpiComm(),
14563 &sendReq[i], AT_, "rcvHilbertIds[rcvOffsets[i]]");
14564 }
14565
14566 for(MInt i = 0; i < noDomains(); i++) {
14567 if(noSndHilberts[i] == 0) continue;
14568 MPI_Recv(&sndHilbertIds[sndOffsets[i]], noSndHilberts[i], type_traits<MLong>::mpiType(), i, 12, mpiComm(),
14569 MPI_STATUS_IGNORE, AT_, "sndHilbertIds[sndOffsets[i]");
14570 }
14571
14572 for(MInt i = 0; i < noDomains(); i++) {
14573 if(noRcvHilberts[i] == 0) continue;
14574 MPI_Wait(&sendReq[i], MPI_STATUSES_IGNORE, AT_);
14575 }
14576
14577 for(MInt d = 0; d < noDomains(); d++) {
14578 noSndHilberts[d] = 0;
14579 }
14580
14581 for(MInt i = 0; i < noRefineCandidates; i++) {
14582 MInt candidateId = candidateMap[i];
14583 for(MInt child = 0; child < m_maxNoChilds; child++) {
14584 MInt dom = haloDomainIds[candidateId * m_maxNoChilds + child];
14585 haloChildIds[candidateId * m_maxNoChilds + child] = sndHilbertIds[sndOffsets[dom] + noSndHilberts[dom]++];
14586 }
14587 }
14588}

◆ targetGridMinLevel()

template<MInt nDim>
MInt CartesianGrid< nDim >::targetGridMinLevel ( ) const
inline

Definition at line 792 of file cartesiangrid.h.

792{ return m_targetGridMinLevel; };

◆ treeb() [1/2]

template<MInt nDim>
Tree & CartesianGrid< nDim >::treeb ( )
inline

Definition at line 784 of file cartesiangrid.h.

784{ return m_tree; }

◆ treeb() [2/2]

template<MInt nDim>
const Tree & CartesianGrid< nDim >::treeb ( ) const
inline

Definition at line 785 of file cartesiangrid.h.

785{ return m_tree; }

◆ updatedPartitionCells()

template<MInt nDim>
MBool CartesianGrid< nDim >::updatedPartitionCells ( ) const
inline

Definition at line 586 of file cartesiangrid.h.

586{ return m_updatedPartitionCells; }

◆ updateHaloCellCollectors()

template<MInt nDim>
void CartesianGrid< nDim >::updateHaloCellCollectors
private
Author
Lennart Schneiders
Date
October 2017

Definition at line 4139 of file cartesiangrid.cpp.

4139 {
4140 TRACE();
4141 const auto noNghbrDomains0 = (signed)m_nghbrDomains.size();
4142 const auto noAzimuthalNghbrDomains0 = (signed)m_azimuthalNghbrDomains.size();
4143 if(noNghbrDomains0 == 0 && noAzimuthalNghbrDomains0 == 0) {
4144 // serial computations can have neighbor domains, for example, when using
4145 // periodic boundaries, and that requires halo cells.
4146 //
4147 // That is, if there aren't any neighbor domains, halo cells are not required.
4148 return;
4149 }
4150
4151 ScratchSpace<MInt> domMap(noNghbrDomains0, AT_, "domMap");
4152
4153 vector<pair<MInt, MInt>> tmpDoms;
4154 tmpDoms.reserve(noNghbrDomains0);
4155
4156 // sort neighbor domain ids to avoid send/recv deadlocks
4157 for(MInt i = 0; i < noNghbrDomains0; i++) {
4158 if(m_haloCells[i].size() > 0 || m_windowCells[i].size() > 0) {
4159 tmpDoms.push_back(make_pair(m_nghbrDomains[i], i));
4160 }
4161 }
4162 sort(tmpDoms.begin(), tmpDoms.end()); // sort by ascending neighbor domain id
4163
4164 std::vector<MInt>().swap(m_nghbrDomains);
4165 ASSERT(m_nghbrDomainIndex.size() >= static_cast<size_t>(noDomains()),
4166 "m_nghbrDomainIndex size is " + std::to_string(m_nghbrDomainIndex.size())
4167 + " which is smaller than noDomains() = " + std::to_string(noDomains()));
4168 std::fill_n(m_nghbrDomainIndex.begin(), noDomains(), -1);
4169 for(MInt i = 0; i < (signed)tmpDoms.size(); i++) {
4170 domMap[i] = tmpDoms[i].second;
4171 m_nghbrDomainIndex[tmpDoms[i].first] = m_nghbrDomains.size();
4172 m_nghbrDomains.push_back(tmpDoms[i].first);
4174 TERMM(1, "Not supposed to happen: connection to self without periodicity.");
4175 }
4176 if(m_nghbrDomains[i] == domainId()) m_log << domainId() << ": periodic connection to self." << endl;
4177 }
4178
4179
4180 // sort window and halo cells by globalId
4181 const MBool sortHaloWindowCells = false;
4182 if(sortHaloWindowCells) {
4183 for(MInt i = 0; i < noNghbrDomains0; i++) {
4184 sort(m_haloCells[i].begin(), m_haloCells[i].end(),
4185 [this](const MInt& a, const MInt& b) { return a_globalId(a) < a_globalId(b); });
4186 sort(m_windowCells[i].begin(), m_windowCells[i].end(),
4187 [this](const MInt& a, const MInt& b) { return a_globalId(a) < a_globalId(b); });
4188 }
4189 }
4190
4191
4192 // write window/halo cells
4193 vector<std::vector<MInt>> haloCellBak(m_haloCells);
4194 vector<std::vector<MInt>> windowCellBak(m_windowCells);
4197 for(MInt i = 0; i < noNeighborDomains(); i++) {
4198 m_haloCells[i].resize(haloCellBak[domMap[i]].size());
4199 m_windowCells[i].resize(windowCellBak[domMap[i]].size());
4200 ASSERT(m_haloCells[i].size() >= haloCellBak[domMap[i]].size(), "");
4201 ASSERT(m_windowCells[i].size() >= windowCellBak[domMap[i]].size(), "");
4202 copy(haloCellBak[domMap[i]].begin(), haloCellBak[domMap[i]].end(), m_haloCells[i].begin());
4203 copy(windowCellBak[domMap[i]].begin(), windowCellBak[domMap[i]].end(), m_windowCells[i].begin());
4204 }
4205
4206 // TODO_SS labels:GRID,toenhance use move operation
4207 if (m_windowLayer_.size()>0 && m_haloMode>0) { //WH_old
4208 ASSERT(noNeighborDomains()<=(signed)m_windowLayer_.size(), "");
4209 std::vector<std::unordered_map<MInt, M32X4bit<true>>> windowLayerBak(m_windowLayer_);
4211 for(MInt i = 0; i < noNeighborDomains(); i++) {
4212 m_windowLayer_[i] = windowLayerBak[domMap[i]];
4213 }
4214 }
4215
4216
4217 if(m_azimuthalPer) {
4218 ScratchSpace<MInt> domMapAzi(noAzimuthalNghbrDomains0, AT_, "domMapAzi");
4219 // sort neighbor domain ids to avoid send/recv deadlocks
4220 tmpDoms.clear();
4221 tmpDoms.reserve(noAzimuthalNghbrDomains0);
4222 for(MInt i = 0; i < noAzimuthalNghbrDomains0; i++) {
4223 if(m_azimuthalHaloCells[i].size() > 0 || m_azimuthalWindowCells[i].size() > 0) {
4224 tmpDoms.push_back(make_pair(m_azimuthalNghbrDomains[i], i));
4225 }
4226 }
4227 sort(tmpDoms.begin(), tmpDoms.end()); // sort by ascending neighbor domain id
4228
4230 ASSERT(m_azimuthalNghbrDomainIndex.size() >= static_cast<size_t>(noDomains()),
4231 "m_azimuthalNghbrDomainIndex size is " + std::to_string(m_azimuthalNghbrDomainIndex.size())
4232 + " which is smaller than noDomains() = " + std::to_string(noDomains()));
4233 std::fill_n(m_azimuthalNghbrDomainIndex.begin(), noDomains(), -1);
4234 for(MInt i = 0; i < (signed)tmpDoms.size(); i++) {
4235 domMapAzi[i] = tmpDoms[i].second;
4236 m_azimuthalNghbrDomainIndex[tmpDoms[i].first] = m_azimuthalNghbrDomains.size();
4237 m_azimuthalNghbrDomains.push_back(tmpDoms[i].first);
4238 if(m_azimuthalNghbrDomains[i] == domainId()) m_log << domainId() << ": periodic connection to self." << endl;
4239 }
4240
4241 // sort azimuthal window and halo cells by globalId
4242 if(sortHaloWindowCells) {
4243 vector<MInt> posMapAzi;
4244 for(MInt i = 0; i < noAzimuthalNghbrDomains0; i++) {
4245 sort(m_azimuthalHaloCells[i].begin(), m_azimuthalHaloCells[i].end(),
4246 [this](const MInt& a, const MInt& b) { return a_globalId(a) < a_globalId(b); });
4247
4248 vector<pair<MInt, MInt>> azimuthalWindowCells;
4249 for(MInt j = 0; j < (signed)m_azimuthalWindowCells[i].size(); j++) {
4250 azimuthalWindowCells.push_back(make_pair(m_azimuthalWindowCells[i][j], j));
4251 }
4252 m_azimuthalWindowCells[i].clear();
4253 sort(azimuthalWindowCells.begin(), azimuthalWindowCells.end(),
4254 [&](const auto& a, const auto& b) { return a_globalId(a.first) < a_globalId(b.first); });
4256 posMapAzi.resize(azimuthalWindowCells.size());
4257 for(MInt j = 0; j < (signed)azimuthalWindowCells.size(); j++) {
4259 posMapAzi[azimuthalWindowCells[j].second] = j;
4260 }
4261 vector<MInt> higherLevelConnectivityBak(m_azimuthalHigherLevelConnectivity[i]);
4262 m_azimuthalHigherLevelConnectivity[i].resize(higherLevelConnectivityBak.size());
4263 for(MInt c = 0; c < (signed)higherLevelConnectivityBak.size(); c++) {
4264 m_azimuthalHigherLevelConnectivity[i].push_back(posMapAzi[higherLevelConnectivityBak[c]]);
4265 }
4266 azimuthalWindowCells.clear();
4267 higherLevelConnectivityBak.clear();
4268 }
4269 }
4270
4271 // write window/halo cells
4272 haloCellBak.clear();
4273 windowCellBak.clear();
4274 haloCellBak = m_azimuthalHaloCells;
4275 windowCellBak = m_azimuthalWindowCells;
4276 vector<vector<MInt>> higherLevelConnectivityBak2(m_azimuthalHigherLevelConnectivity);
4280 for(MInt i = 0; i < noAzimuthalNeighborDomains(); i++) {
4281 m_azimuthalHaloCells[i].resize(haloCellBak[domMapAzi[i]].size());
4282 m_azimuthalWindowCells[i].resize(windowCellBak[domMapAzi[i]].size());
4283 m_azimuthalHigherLevelConnectivity[i].resize(higherLevelConnectivityBak2[domMapAzi[i]].size());
4284 ASSERT(m_azimuthalHaloCells[i].size() >= haloCellBak[domMapAzi[i]].size(), "");
4285 ASSERT(m_azimuthalWindowCells[i].size() >= windowCellBak[domMapAzi[i]].size(), "");
4286 copy(haloCellBak[domMapAzi[i]].begin(), haloCellBak[domMapAzi[i]].end(), m_azimuthalHaloCells[i].begin());
4287 copy(windowCellBak[domMapAzi[i]].begin(), windowCellBak[domMapAzi[i]].end(), m_azimuthalWindowCells[i].begin());
4288 copy(higherLevelConnectivityBak2[domMapAzi[i]].begin(), higherLevelConnectivityBak2[domMapAzi[i]].end(), m_azimuthalHigherLevelConnectivity[i].begin());
4289 }
4290 }
4291}

◆ updatePartitionCellInformation()

template<MInt nDim>
void CartesianGrid< nDim >::updatePartitionCellInformation
private

Definition at line 10122 of file cartesiangrid.cpp.

10122 {
10123 // update partition cell global ids
10124 MInt noLocalPartitionCells = 0;
10125 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
10126 if(a_isToDelete(cellId)) {
10127 continue;
10128 }
10129 if(a_hasProperty(cellId, Cell::IsHalo)) {
10130 continue;
10131 }
10132
10133 if(a_hasProperty(cellId, Cell::IsPartitionCell)) {
10134 m_localPartitionCellGlobalIds[noLocalPartitionCells] = a_globalId(cellId);
10135 noLocalPartitionCells++;
10136 }
10137 }
10138
10139 if(noLocalPartitionCells == 0 && !m_updatingPartitionCells) {
10140 TERMM(1, "noLocalPartitionCells == 0");
10141 return;
10142 }
10143
10144 if(noLocalPartitionCells != m_noPartitionCells) {
10145 TERMM(-1, "Mismatch in partitionCells " + to_string(m_noPartitionCells) + "/" + to_string(noLocalPartitionCells));
10146 }
10147
10148 // sort by globalIds
10149 sort(m_localPartitionCellGlobalIds, m_localPartitionCellGlobalIds + noLocalPartitionCells);
10150
10151 // determine offset within GLOBAL!!! partition cells
10152 MIntScratchSpace localPartitionCellCounts(noDomains(), AT_, "localPartitionCellCounts");
10153 MPI_Allgather(&noLocalPartitionCells, 1, MPI_INT, &localPartitionCellCounts[0], 1, MPI_INT, mpiComm(), AT_,
10154 "noLocalPartitionCells", "localPartitionCellCounts[0]");
10155
10156 // sum up all previous domains partition cells
10157 MInt offset = 0;
10158 for(MInt dId = 0; dId < domainId(); dId++) {
10159 offset += localPartitionCellCounts[dId];
10160 }
10161
10162 // Set local partition cell offset, the next offset and the number of global partition cells
10163 m_localPartitionCellOffsets[0] = offset;
10164 m_localPartitionCellOffsets[1] = m_localPartitionCellOffsets[0] + noLocalPartitionCells;
10166
10167 // Create list of partition cell local ids (also ordered by global id)
10168 for(MInt i = 0; i < m_noPartitionCells; i++) {
10170 }
10171}

◆ updatePartitionCells()

template<MInt nDim>
MBool CartesianGrid< nDim >::updatePartitionCells ( MInt  offspringThreshold,
MFloat  workloadThreshold 
)

Note: should only be called from gridcontroller::balance() which restores a consistent grid with e.g. all partition level ancestor information! Also updating the partition cells might lead to domains which temporarily dont have any partition cell anymore!

Definition at line 13447 of file cartesiangrid.cpp.

13447 {
13448 TRACE();
13449 m_log << "Update partition cells: offspringThreshold=" << offspringThreshold
13450 << "; workloadThreshold=" << workloadThreshold << std::endl;
13451
13452 MBool partitionCellChange = false;
13453
13454 // update noOffspring and workloads
13456
13457 // Determine new partition cells (similar to gridio::saveGrid())
13458 // 1. Start with collecting min-level cells
13459 std::vector<MInt> tmpMinLevelCells;
13460 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
13461 if(a_level(cellId) == m_minLevel && !a_hasProperty(cellId, Cell::IsPeriodic)) {
13462 ASSERT(a_parentId(cellId) == -1, "");
13463 tmpMinLevelCells.push_back(cellId);
13464 }
13465 }
13466
13467 std::vector<MInt> partitionCellsFiltered;
13468 while(true) { // Repeat partition cell filtering until enough partition cells are present
13469 partitionCellsFiltered.clear();
13470 std::vector<MInt> tmpPartitionCells(tmpMinLevelCells);
13471
13472 // Iterate over all cells to consider
13473 while(!tmpPartitionCells.empty()) {
13474 const MInt cellId = tmpPartitionCells.front();
13475 tmpPartitionCells.erase(tmpPartitionCells.begin());
13476
13477 // Multisolver: make sure that children of solver leaf-cells cannot become partition cells!
13478 MBool isSolverLeafCell = false;
13479 for(MInt b = 0; b < treeb().noSolvers(); b++) {
13480 if(a_isLeafCell(cellId, b)) {
13481 isSolverLeafCell = true;
13482 break;
13483 }
13484 }
13485
13486 // Check if cell has too many offspring or too high workload (and is not a leaf cell)
13487 if((a_noOffsprings(cellId) > offspringThreshold || a_workload(cellId) > workloadThreshold) && !isSolverLeafCell) {
13488 MInt cnt = 0;
13489 // Add child cells to list of cells to consider as partition cells
13490 for(MInt j = 0; j < IPOW2(nDim); ++j) {
13491 if(a_childId(cellId, j) > -1) {
13492 tmpPartitionCells.insert(tmpPartitionCells.begin() + cnt, a_childId(cellId, j));
13493 cnt++;
13494 }
13495 }
13496 } else if(!a_isHalo(cellId)) {
13497 // Add as partition cell
13498 partitionCellsFiltered.push_back(cellId);
13499 }
13500 }
13501
13502 MLong globalNoNewPartitionCells = partitionCellsFiltered.size();
13503 MPI_Allreduce(MPI_IN_PLACE, &globalNoNewPartitionCells, 1, type_traits<MLong>::mpiType(), MPI_SUM, mpiComm(), AT_,
13504 "MPI_IN_PLACE", "globalNoNewPartitionCells");
13505 cerr0 << "Found " << globalNoNewPartitionCells << " new partition cells." << std::endl;
13506 m_log << "Found " << globalNoNewPartitionCells << " new partition cells." << std::endl;
13507
13508 // Make sure that there are enough partition cells (at least one per domain)
13509 // TODO labels:GRID add a minimum allowed number of partition cells on average per domain
13510 if(globalNoNewPartitionCells < noDomains()) {
13511 offspringThreshold /= 2;
13512 workloadThreshold *= 0.5;
13513 cerr0 << "Error: too few partition cells; Repeating filtering of partition cells with "
13514 "lowered thresholds..."
13515 << std::endl;
13516 } else {
13517 break;
13518 }
13519 }
13520
13521 const MInt oldNoPartCells = m_noPartitionCells;
13522 const MInt newNoPartCells = partitionCellsFiltered.size();
13523
13524 sort(partitionCellsFiltered.begin(), partitionCellsFiltered.end());
13525
13526 if(oldNoPartCells != newNoPartCells) {
13527 // Number of partition cells changed
13528 partitionCellChange = true;
13529 } else {
13530 // Number of partition cells did not change, check the partition cells for any change
13531 for(MInt i = 0; i < newNoPartCells; i++) {
13532 const MInt newPartCellId = partitionCellsFiltered[i];
13533 if(!a_hasProperty(newPartCellId, Cell::IsPartitionCell)) {
13534 partitionCellChange = true;
13535 break;
13536 }
13537 }
13538 }
13539
13540 MInt globalPartitionCellChange = partitionCellChange;
13541 MPI_Allreduce(MPI_IN_PLACE, &globalPartitionCellChange, 1, type_traits<MInt>::mpiType(), MPI_MAX, mpiComm(), AT_,
13542 "MPI_IN_PLACE", "globalPartitionCellChange");
13543
13544 // If there is no change of any partition cell globally, nothing to do
13545 if(!globalPartitionCellChange) {
13546 cerr0 << "Partition cells did not change." << std::endl;
13547 m_log << "Partition cells did not change." << std::endl;
13548 return false;
13549 }
13550
13551 // Set 'updating partition cells'-flag (allow case with 0 partition cells in eg. computeGlobalIds)
13553
13554 // Store if the current first min-level cell is a halo partition level ancestor (i.e. is the
13555 // ancestor of the first local partition cell)
13556 const MInt firstMinLvlCell = m_minLevelCells[0];
13557 MInt minLvlHaloPartLvlAncestor = -1;
13558 if(a_hasProperty(firstMinLvlCell, Cell::IsPartLvlAncestor) && a_hasProperty(firstMinLvlCell, Cell::IsHalo)) {
13559 minLvlHaloPartLvlAncestor = firstMinLvlCell;
13560 }
13561
13562 // Reset cell flags
13563 for(MInt cellId = 0; cellId < m_tree.size(); cellId++) {
13564 a_hasProperty(cellId, Cell::IsPartitionCell) = false;
13565 a_hasProperty(cellId, Cell::IsPartLvlAncestor) = false;
13566 }
13567
13568 // Set new partition cell flags
13569 MInt maxLevelDiff = 0;
13570 for(MInt i = 0; i < newNoPartCells; i++) {
13571 const MInt newPartCellId = partitionCellsFiltered[i];
13572 a_hasProperty(newPartCellId, Cell::IsPartitionCell) = true;
13573
13574 maxLevelDiff = std::max(maxLevelDiff, a_level(newPartCellId) - m_minLevel);
13575 }
13576
13577 m_noPartitionCells = newNoPartCells;
13578
13580 MPI_Allreduce(MPI_IN_PLACE, &m_noPartitionCellsGlobal, 1, type_traits<MLong>::mpiType(), MPI_SUM, mpiComm(), AT_,
13581 "MPI_IN_PLACE", "m_noPartitionCellsGlobal");
13582
13583 MPI_Allreduce(MPI_IN_PLACE, &maxLevelDiff, 1, type_traits<MInt>::mpiType(), MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
13584 "maxLevelDiff");
13585 cerr0 << "New maximum partition level shift: " << maxLevelDiff << std::endl;
13586 m_log << "New maximum partition level shift: " << maxLevelDiff << std::endl;
13587 m_maxPartitionLevelShift = maxLevelDiff;
13588
13589 // Reallocate partition cell arrays with new size
13590 // Note: data is set in computeGlobalIds, should not be required before
13592 mAlloc(m_localPartitionCellGlobalIds, std::max(m_noPartitionCells, 1), "m_localPartitionCellGlobalIds",
13593 static_cast<MLong>(-1), AT_);
13595 mAlloc(m_localPartitionCellLocalIds, std::max(m_noPartitionCells, 1), "m_localPartitionCellLocalIds", -1, AT_);
13596
13597 MIntScratchSpace isPartitionLevelAncestor(m_noInternalCells, AT_, "isPartitionLevelAncestor");
13598 isPartitionLevelAncestor.fill(0);
13599
13600 MInt noPartitionLevelAncestorsLocal = 0;
13601 // Determine partition level ancestor cells and set the corresponding cell property
13602 for(MInt i = 0; i < newNoPartCells; i++) {
13603 const MInt cellId = partitionCellsFiltered[i];
13604 MInt parentId = a_parentId(cellId);
13605
13606 // Loop up the parent cells of all partition cells
13607 while(parentId > -1) {
13608 a_hasProperty(parentId, Cell::IsPartLvlAncestor) = true;
13609
13610 if(!a_isHalo(parentId)) {
13611 noPartitionLevelAncestorsLocal++;
13612 }
13613
13614 for(MInt b = 0; b < treeb().noSolvers(); b++) {
13615 TERMM_IF_COND(a_isLeafCell(parentId, b), "Error: partition level ancestor is the leaf cell of a solver.");
13616 }
13617
13618 parentId = a_parentId(parentId);
13619 }
13620 }
13621
13622 m_noPartitionLevelAncestors = noPartitionLevelAncestorsLocal;
13623 // Determine global number of partition level ancestor cells
13626 AT_, "MPI_IN_PLACE", "noPartitionLevelAncestorsGlobal");
13627
13628 std::vector<MInt>().swap(m_partitionLevelAncestorIds);
13629 std::vector<MLong>().swap(m_partitionLevelAncestorChildIds);
13630
13631 // Note: only the min-level halo partition level ancestor needs to be stored since it is required
13632 // for computeGlobalIds()
13633 if(minLvlHaloPartLvlAncestor > -1) {
13634 TERMM_IF_NOT_COND(a_isHalo(minLvlHaloPartLvlAncestor), "Error: not a halo cell.");
13635 a_hasProperty(minLvlHaloPartLvlAncestor, Cell::IsPartLvlAncestor) = true;
13636 m_partitionLevelAncestorIds.push_back(minLvlHaloPartLvlAncestor);
13637 }
13638
13639 // Update partition cell local/global ids and partition cell offsets
13641
13642 // exchange properties
13644
13646 // Set status, checked when writing a grid restart file to avoid a refiltering of partition cells
13648
13649 return true;
13650}
MLong m_noPartitionLevelAncestorsGlobal

◆ wasAdapted()

template<MInt nDim>
MBool CartesianGrid< nDim >::wasAdapted ( ) const
inline

Definition at line 260 of file cartesiangrid.h.

260{ return m_wasAdapted; }

◆ wasBalanced()

template<MInt nDim>
MBool CartesianGrid< nDim >::wasBalanced ( ) const
inline

Definition at line 261 of file cartesiangrid.h.

261{ return m_wasBalanced; }

◆ wasBalancedAtLeastOnce()

template<MInt nDim>
MBool CartesianGrid< nDim >::wasBalancedAtLeastOnce ( ) const
inline

Definition at line 262 of file cartesiangrid.h.

262{ return m_wasBalancedAtLeastOnce; }

◆ windowCell()

template<MInt nDim>
MInt CartesianGrid< nDim >::windowCell ( const MInt  domainId,
const MInt  cellId 
) const
inline

Definition at line 457 of file cartesiangrid.h.

457{ return m_windowCells[domainId][cellId]; }

◆ windowCells()

template<MInt nDim>
const std::vector< std::vector< MInt > > & CartesianGrid< nDim >::windowCells ( ) const
inline

Definition at line 460 of file cartesiangrid.h.

460{ return m_windowCells; };

◆ windowLayer()

template<MInt nDim>
MInt CartesianGrid< nDim >::windowLayer ( const MInt  domainId,
const MInt  cellId,
const MInt  solverId 
) const
inline

Definition at line 463 of file cartesiangrid.h.

463 {
464 return m_windowLayer_[domainId].at(cellId).get(solverId);
465 }

Friends And Related Function Documentation

◆ DgCartesianSolver

template<MInt nDim>
template<MInt nDim_, class SysEqn >
friend class DgCartesianSolver
friend

Definition at line 68 of file cartesiangrid.h.

◆ FvBndryCnd2D

template<MInt nDim>
template<MInt nDim_, class SysEqn >
friend class FvBndryCnd2D
friend

Definition at line 59 of file cartesiangrid.h.

◆ FvBndryCnd3D

template<MInt nDim>
template<MInt nDim_, class SysEqn >
friend class FvBndryCnd3D
friend

Definition at line 61 of file cartesiangrid.h.

◆ FvCartesianSolverXD [1/2]

template<MInt nDim>
template<MInt nDim_, class SysEqn >
friend class FvCartesianSolverXD
friend

[Splitt] The following is part of a first step to splitt CartesianGrid from the inheritance hierarchy:

Todo:
labels:GRID the following friend declarations will be removed in a future commit

Definition at line 53 of file cartesiangrid.h.

◆ FvCartesianSolverXD [2/2]

template<MInt nDim>
template<MInt nDim_, class SysEqn >
class FvCartesianSolverXD
friend

Definition at line 57 of file cartesiangrid.h.

◆ FvMbCartesianSolverXD

template<MInt nDim>
template<MInt nDim_, class SysEqn >
friend class FvMbCartesianSolverXD
friend

Definition at line 63 of file cartesiangrid.h.

◆ LbSolver

template<MInt nDim>
template<MInt nDim_>
friend class LbSolver
friend

Definition at line 65 of file cartesiangrid.h.

◆ LsCartesianSolver

template<MInt nDim>
template<MInt nDim_>
friend class LsCartesianSolver
friend

Definition at line 55 of file cartesiangrid.h.

◆ maia::grid::Controller< nDim >

template<MInt nDim>
friend class maia::grid::Controller< nDim >
friend

Definition at line 68 of file cartesiangrid.h.

◆ maia::grid::IO< CartesianGrid< nDim > >

template<MInt nDim>
friend class maia::grid::IO< CartesianGrid< nDim > >
friend

Definition at line 68 of file cartesiangrid.h.

Member Data Documentation

◆ m_32BitOffset

template<MInt nDim>
MLong CartesianGrid< nDim >::m_32BitOffset = 0
private

Definition at line 682 of file cartesiangrid.h.

◆ m_addSolverToGrid

template<MInt nDim>
MBool CartesianGrid< nDim >::m_addSolverToGrid = false
private

Definition at line 725 of file cartesiangrid.h.

◆ m_allowCoarsening

template<MInt nDim>
MBool CartesianGrid< nDim >::m_allowCoarsening = true

Definition at line 753 of file cartesiangrid.h.

◆ m_allowInterfaceRefinement

template<MInt nDim>
MBool CartesianGrid< nDim >::m_allowInterfaceRefinement = false

Definition at line 369 of file cartesiangrid.h.

◆ m_azimuthalAngle

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_azimuthalAngle = F0

Definition at line 275 of file cartesiangrid.h.

◆ m_azimuthalAxialDir

template<MInt nDim>
MInt CartesianGrid< nDim >::m_azimuthalAxialDir = -1

Definition at line 274 of file cartesiangrid.h.

◆ m_azimuthalBbox

template<MInt nDim>
azimuthalBbox CartesianGrid< nDim >::m_azimuthalBbox

Definition at line 351 of file cartesiangrid.h.

◆ m_azimuthalHaloCells

template<MInt nDim>
std::vector<std::vector<MInt> > CartesianGrid< nDim >::m_azimuthalHaloCells
private

Definition at line 650 of file cartesiangrid.h.

◆ m_azimuthalHigherLevelConnectivity

template<MInt nDim>
std::vector<std::vector<MInt> > CartesianGrid< nDim >::m_azimuthalHigherLevelConnectivity
private

Definition at line 648 of file cartesiangrid.h.

◆ m_azimuthalNghbrDomainIndex

template<MInt nDim>
std::vector<MInt> CartesianGrid< nDim >::m_azimuthalNghbrDomainIndex

Definition at line 761 of file cartesiangrid.h.

◆ m_azimuthalNghbrDomains

template<MInt nDim>
std::vector<MInt> CartesianGrid< nDim >::m_azimuthalNghbrDomains
private

Definition at line 625 of file cartesiangrid.h.

◆ m_azimuthalPer

template<MInt nDim>
MBool CartesianGrid< nDim >::m_azimuthalPer = false

Definition at line 271 of file cartesiangrid.h.

◆ m_azimuthalPerCenter

template<MInt nDim>
std::array<MFloat, 3> CartesianGrid< nDim >::m_azimuthalPerCenter {}

Definition at line 272 of file cartesiangrid.h.

◆ m_azimuthalPeriodicDir

template<MInt nDim>
std::array<MInt, 2> CartesianGrid< nDim >::m_azimuthalPeriodicDir {}

Definition at line 273 of file cartesiangrid.h.

◆ m_azimuthalUnmappedHaloCells

template<MInt nDim>
std::vector<MInt> CartesianGrid< nDim >::m_azimuthalUnmappedHaloCells
private

Definition at line 651 of file cartesiangrid.h.

◆ m_azimuthalUnmappedHaloDomains

template<MInt nDim>
std::vector<MInt> CartesianGrid< nDim >::m_azimuthalUnmappedHaloDomains
private

Definition at line 652 of file cartesiangrid.h.

◆ m_azimuthalWindowCells

template<MInt nDim>
std::vector<std::vector<MInt> > CartesianGrid< nDim >::m_azimuthalWindowCells
private

Definition at line 649 of file cartesiangrid.h.

◆ m_boundingBox

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_boundingBox[6] {}
private

Definition at line 592 of file cartesiangrid.h.

◆ m_boundingBoxBackup

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_boundingBoxBackup[6] {}
private

Definition at line 596 of file cartesiangrid.h.

◆ m_centerOfGravity

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_centerOfGravity[3] {}
private

Definition at line 591 of file cartesiangrid.h.

◆ m_checkRefinementHoles

template<MInt nDim>
MBool* CartesianGrid< nDim >::m_checkRefinementHoles = nullptr
private

Definition at line 691 of file cartesiangrid.h.

◆ m_coarseRatio

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_coarseRatio = 0.2

Definition at line 752 of file cartesiangrid.h.

◆ m_counter1D

template<MInt nDim>
MInt CartesianGrid< nDim >::m_counter1D {}

Definition at line 731 of file cartesiangrid.h.

◆ m_counter2D

template<MInt nDim>
MInt CartesianGrid< nDim >::m_counter2D {}

Definition at line 733 of file cartesiangrid.h.

◆ m_counter3D

template<MInt nDim>
MInt CartesianGrid< nDim >::m_counter3D {}

Definition at line 735 of file cartesiangrid.h.

◆ m_cutOff

template<MInt nDim>
MInt CartesianGrid< nDim >::m_cutOff = 0

Definition at line 370 of file cartesiangrid.h.

◆ m_decisiveDirection

template<MInt nDim>
MInt CartesianGrid< nDim >::m_decisiveDirection {}
private

Definition at line 714 of file cartesiangrid.h.

◆ m_diagSmoothing

template<MInt nDim>
MBool* CartesianGrid< nDim >::m_diagSmoothing = nullptr
private

Definition at line 692 of file cartesiangrid.h.

◆ m_domainId

template<MInt nDim>
MInt CartesianGrid< nDim >::m_domainId {}
private

Definition at line 1064 of file cartesiangrid.h.

◆ m_domainOffsets

template<MInt nDim>
MLong* CartesianGrid< nDim >::m_domainOffsets = nullptr
private

Definition at line 660 of file cartesiangrid.h.

◆ m_freeIndices

template<MInt nDim>
std::set<MInt> CartesianGrid< nDim >::m_freeIndices

Definition at line 755 of file cartesiangrid.h.

◆ m_globalToLocalId

template<MInt nDim>
std::map<MLong, MInt> CartesianGrid< nDim >::m_globalToLocalId {}

Definition at line 748 of file cartesiangrid.h.

◆ m_gridBndryCells

template<MInt nDim>
std::vector<MInt> CartesianGrid< nDim >::m_gridBndryCells
private

Definition at line 653 of file cartesiangrid.h.

◆ m_gridCellVolume

template<MInt nDim>
MFloat* CartesianGrid< nDim >::m_gridCellVolume = nullptr

Definition at line 374 of file cartesiangrid.h.

◆ m_gridInputFileName

template<MInt nDim>
MString CartesianGrid< nDim >::m_gridInputFileName = ""

Definition at line 377 of file cartesiangrid.h.

◆ m_haloCells

template<MInt nDim>
std::vector<std::vector<MInt> > CartesianGrid< nDim >::m_haloCells
private

Definition at line 636 of file cartesiangrid.h.

◆ m_haloMode

template<MInt nDim>
MInt CartesianGrid< nDim >::m_haloMode = -1
private

Definition at line 616 of file cartesiangrid.h.

◆ m_hasMultiSolverBoundingBox

template<MInt nDim>
MBool CartesianGrid< nDim >::m_hasMultiSolverBoundingBox = false
private

Definition at line 607 of file cartesiangrid.h.

◆ m_identicalSolverLvlJumps

template<MInt nDim>
MInt* CartesianGrid< nDim >::m_identicalSolverLvlJumps = nullptr
private

Definition at line 696 of file cartesiangrid.h.

◆ m_identicalSolverMaxLvl

template<MInt nDim>
MInt* CartesianGrid< nDim >::m_identicalSolverMaxLvl = nullptr
private

Definition at line 695 of file cartesiangrid.h.

◆ m_identicalSolvers

template<MInt nDim>
MInt* CartesianGrid< nDim >::m_identicalSolvers = nullptr
private

Definition at line 694 of file cartesiangrid.h.

◆ m_lbGridChecks

template<MInt nDim>
MBool CartesianGrid< nDim >::m_lbGridChecks

Definition at line 751 of file cartesiangrid.h.

◆ m_lengthLevel0

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_lengthLevel0 {}
private

Definition at line 610 of file cartesiangrid.h.

◆ m_loadGridPartition

template<MInt nDim>
MBool CartesianGrid< nDim >::m_loadGridPartition = false
private

Definition at line 719 of file cartesiangrid.h.

◆ m_loadPartition

template<MInt nDim>
MBool CartesianGrid< nDim >::m_loadPartition = false
private

Definition at line 721 of file cartesiangrid.h.

◆ m_localBoundingBox

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_localBoundingBox[6] {}
private

Definition at line 599 of file cartesiangrid.h.

◆ m_localBoundingBoxInit

template<MInt nDim>
MBool CartesianGrid< nDim >::m_localBoundingBoxInit = false
private

Definition at line 600 of file cartesiangrid.h.

◆ m_localPartitionCellGlobalIds

template<MInt nDim>
MLong* CartesianGrid< nDim >::m_localPartitionCellGlobalIds = nullptr
private

Definition at line 668 of file cartesiangrid.h.

◆ m_localPartitionCellLocalIds

template<MInt nDim>
MInt* CartesianGrid< nDim >::m_localPartitionCellLocalIds = nullptr
private

Definition at line 669 of file cartesiangrid.h.

◆ m_localPartitionCellLocalIdsRestart

template<MInt nDim>
MInt* CartesianGrid< nDim >::m_localPartitionCellLocalIdsRestart = nullptr

Definition at line 762 of file cartesiangrid.h.

◆ m_localPartitionCellOffsets

template<MInt nDim>
MLong CartesianGrid< nDim >::m_localPartitionCellOffsets[3] {static_cast<MLong>(-1), static_cast<MLong>(-1), static_cast<MLong>(-1)}
private

Definition at line 667 of file cartesiangrid.h.

◆ m_localPartitionCellOffsetsRestart

template<MInt nDim>
MLong CartesianGrid< nDim >::m_localPartitionCellOffsetsRestart[3] {static_cast<MLong>(-1), static_cast<MLong>(-1), static_cast<MLong>(-1)}

Definition at line 763 of file cartesiangrid.h.

◆ m_lowMemAdaptation

template<MInt nDim>
MBool CartesianGrid< nDim >::m_lowMemAdaptation = true

Definition at line 371 of file cartesiangrid.h.

◆ m_maxLevel

template<MInt nDim>
MInt CartesianGrid< nDim >::m_maxLevel = -1

Definition at line 363 of file cartesiangrid.h.

◆ m_maxNoCells

template<MInt nDim>
MInt CartesianGrid< nDim >::m_maxNoCells = -1
private

Definition at line 613 of file cartesiangrid.h.

◆ m_maxNoChilds

template<MInt nDim>
constexpr MInt CartesianGrid< nDim >::m_maxNoChilds = IPOW2(nDim)
staticconstexprprivate

Definition at line 773 of file cartesiangrid.h.

◆ m_maxNoNghbrs

template<MInt nDim>
const MInt CartesianGrid< nDim >::m_maxNoNghbrs
private

Definition at line 771 of file cartesiangrid.h.

◆ m_maxNoSensors

template<MInt nDim>
constexpr MInt CartesianGrid< nDim >::m_maxNoSensors = 64
staticconstexpr

Definition at line 787 of file cartesiangrid.h.

◆ m_maxPartitionLevelShift

template<MInt nDim>
MInt CartesianGrid< nDim >::m_maxPartitionLevelShift {}
private

Definition at line 689 of file cartesiangrid.h.

◆ m_maxRfnmntLvl

template<MInt nDim>
MInt CartesianGrid< nDim >::m_maxRfnmntLvl = -1

Definition at line 361 of file cartesiangrid.h.

◆ m_maxUniformRefinementLevel

template<MInt nDim>
MInt CartesianGrid< nDim >::m_maxUniformRefinementLevel = -1

Definition at line 360 of file cartesiangrid.h.

◆ m_minLevel

template<MInt nDim>
MInt CartesianGrid< nDim >::m_minLevel = -1

Definition at line 365 of file cartesiangrid.h.

◆ m_minLevelCells

template<MInt nDim>
std::vector<MInt> CartesianGrid< nDim >::m_minLevelCells {}
private

Definition at line 687 of file cartesiangrid.h.

◆ m_mpiComm

template<MInt nDim>
const MPI_Comm CartesianGrid< nDim >::m_mpiComm
private

Definition at line 767 of file cartesiangrid.h.

◆ m_neighborBackup

template<MInt nDim>
std::vector<std::tuple<MInt, MInt, MInt> > CartesianGrid< nDim >::m_neighborBackup
private

Definition at line 628 of file cartesiangrid.h.

◆ m_neighborCode

template<MInt nDim>
std::array<MInt, 11 + (nDim - 2) * 32> CartesianGrid< nDim >::m_neighborCode {}

Definition at line 745 of file cartesiangrid.h.

◆ m_neighborList

template<MInt nDim>
MInt** CartesianGrid< nDim >::m_neighborList = nullptr
private

Definition at line 711 of file cartesiangrid.h.

◆ m_newMinLevel

template<MInt nDim>
MInt CartesianGrid< nDim >::m_newMinLevel = -1

Definition at line 367 of file cartesiangrid.h.

◆ m_nghbrDomainIndex

template<MInt nDim>
std::vector<MInt> CartesianGrid< nDim >::m_nghbrDomainIndex

Definition at line 758 of file cartesiangrid.h.

◆ m_nghbrDomains

template<MInt nDim>
std::vector<MInt> CartesianGrid< nDim >::m_nghbrDomains
private

Definition at line 622 of file cartesiangrid.h.

◆ m_noCellsGlobal

template<MInt nDim>
MLong CartesianGrid< nDim >::m_noCellsGlobal {}

Definition at line 353 of file cartesiangrid.h.

◆ m_noDirs

template<MInt nDim>
constexpr MInt CartesianGrid< nDim >::m_noDirs = 2 * nDim
staticconstexprprivate

Definition at line 772 of file cartesiangrid.h.

◆ m_noDomains

template<MInt nDim>
MInt CartesianGrid< nDim >::m_noDomains {}

Definition at line 358 of file cartesiangrid.h.

◆ m_noHaloLayers

template<MInt nDim>
MInt CartesianGrid< nDim >::m_noHaloLayers = -1
private

Definition at line 617 of file cartesiangrid.h.

◆ m_noHaloPartitionLevelAncestors

template<MInt nDim>
MInt CartesianGrid< nDim >::m_noHaloPartitionLevelAncestors {}
private

Definition at line 666 of file cartesiangrid.h.

◆ m_noIdenticalSolvers

template<MInt nDim>
MInt CartesianGrid< nDim >::m_noIdenticalSolvers = 0
private

Definition at line 693 of file cartesiangrid.h.

◆ m_noInternalCells

template<MInt nDim>
MInt CartesianGrid< nDim >::m_noInternalCells {}

Definition at line 356 of file cartesiangrid.h.

◆ m_noMinLevelCellsGlobal

template<MInt nDim>
MInt CartesianGrid< nDim >::m_noMinLevelCellsGlobal {}
private

Definition at line 685 of file cartesiangrid.h.

◆ m_noPartitionCells

template<MInt nDim>
MInt CartesianGrid< nDim >::m_noPartitionCells {}
private

Definition at line 664 of file cartesiangrid.h.

◆ m_noPartitionCellsGlobal

template<MInt nDim>
MLong CartesianGrid< nDim >::m_noPartitionCellsGlobal {}
private

Definition at line 665 of file cartesiangrid.h.

◆ m_noPartitionLevelAncestors

template<MInt nDim>
MInt CartesianGrid< nDim >::m_noPartitionLevelAncestors {}
private

Definition at line 679 of file cartesiangrid.h.

◆ m_noPartitionLevelAncestorsGlobal

template<MInt nDim>
MLong CartesianGrid< nDim >::m_noPartitionLevelAncestorsGlobal {}
private

Definition at line 681 of file cartesiangrid.h.

◆ m_noPeriodicCartesianDirs

template<MInt nDim>
MInt CartesianGrid< nDim >::m_noPeriodicCartesianDirs = 0

Definition at line 268 of file cartesiangrid.h.

◆ m_noSolverHaloLayers

template<MInt nDim>
MInt* CartesianGrid< nDim >::m_noSolverHaloLayers = nullptr
private

Definition at line 619 of file cartesiangrid.h.

◆ m_outputDir

template<MInt nDim>
MString CartesianGrid< nDim >::m_outputDir = ""
private

Definition at line 716 of file cartesiangrid.h.

◆ m_paraViewPlugin

template<MInt nDim>
const MBool CartesianGrid< nDim >::m_paraViewPlugin
private

Definition at line 770 of file cartesiangrid.h.

◆ m_partitionCellOffspringThreshold

template<MInt nDim>
MInt CartesianGrid< nDim >::m_partitionCellOffspringThreshold
private

Definition at line 656 of file cartesiangrid.h.

◆ m_partitionCellWorkloadThreshold

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_partitionCellWorkloadThreshold
private

Definition at line 657 of file cartesiangrid.h.

◆ m_partitionLevelAncestorChildIds

template<MInt nDim>
std::vector<MLong> CartesianGrid< nDim >::m_partitionLevelAncestorChildIds {}
private

Definition at line 705 of file cartesiangrid.h.

◆ m_partitionLevelAncestorHaloCells

template<MInt nDim>
std::vector<std::vector<MInt> > CartesianGrid< nDim >::m_partitionLevelAncestorHaloCells {}
private

Definition at line 707 of file cartesiangrid.h.

◆ m_partitionLevelAncestorIds

template<MInt nDim>
std::vector<MInt> CartesianGrid< nDim >::m_partitionLevelAncestorIds {}
private

List of partition level ancestor cell ids (including halos of the missing subtree of the grid in case of a partition level shift)

Definition at line 703 of file cartesiangrid.h.

◆ m_partitionLevelAncestorNghbrDomains

template<MInt nDim>
std::vector<MInt> CartesianGrid< nDim >::m_partitionLevelAncestorNghbrDomains {}
private

Definition at line 706 of file cartesiangrid.h.

◆ m_partitionLevelAncestorWindowCells

template<MInt nDim>
std::vector<std::vector<MInt> > CartesianGrid< nDim >::m_partitionLevelAncestorWindowCells {}
private

Definition at line 708 of file cartesiangrid.h.

◆ m_partitionParallelSplit

template<MInt nDim>
MBool CartesianGrid< nDim >::m_partitionParallelSplit = false
private

Definition at line 723 of file cartesiangrid.h.

◆ m_paths1D

template<MInt nDim>
MInt* CartesianGrid< nDim >::m_paths1D = nullptr

Definition at line 738 of file cartesiangrid.h.

◆ m_paths2D

template<MInt nDim>
MInt** CartesianGrid< nDim >::m_paths2D = nullptr

Definition at line 740 of file cartesiangrid.h.

◆ m_paths3D

template<MInt nDim>
MInt** CartesianGrid< nDim >::m_paths3D = nullptr

Definition at line 742 of file cartesiangrid.h.

◆ m_periodicCartesianDir

template<MInt nDim>
std::array<MInt, 3> CartesianGrid< nDim >::m_periodicCartesianDir {}

Definition at line 269 of file cartesiangrid.h.

◆ m_periodicCartesianLength

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_periodicCartesianLength[3] {}

Definition at line 270 of file cartesiangrid.h.

◆ m_reductionFactor

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_reductionFactor {}
private

Definition at line 713 of file cartesiangrid.h.

◆ m_referenceSolver

template<MInt nDim>
MInt CartesianGrid< nDim >::m_referenceSolver = -1
private

Definition at line 726 of file cartesiangrid.h.

◆ m_restart

template<MInt nDim>
MBool CartesianGrid< nDim >::m_restart
private

Definition at line 683 of file cartesiangrid.h.

◆ m_restartDir

template<MInt nDim>
MString CartesianGrid< nDim >::m_restartDir = ""
private

Definition at line 717 of file cartesiangrid.h.

◆ m_revDir

template<MInt nDim>
const MInt CartesianGrid< nDim >::m_revDir[6] = {1, 0, 3, 2, 5, 4}
private

Definition at line 631 of file cartesiangrid.h.

◆ m_targetGridBoundingBox

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_targetGridBoundingBox[6] {}
private

Definition at line 603 of file cartesiangrid.h.

◆ m_targetGridCenterOfGravity

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_targetGridCenterOfGravity[3] {}
private

Definition at line 604 of file cartesiangrid.h.

◆ m_targetGridLengthLevel0

template<MInt nDim>
MFloat CartesianGrid< nDim >::m_targetGridLengthLevel0 = -1
private

Definition at line 605 of file cartesiangrid.h.

◆ m_targetGridMinLevel

template<MInt nDim>
MInt CartesianGrid< nDim >::m_targetGridMinLevel = -1
private

Definition at line 606 of file cartesiangrid.h.

◆ m_tree

template<MInt nDim>
Tree CartesianGrid< nDim >::m_tree
private

Definition at line 769 of file cartesiangrid.h.

◆ m_updatedPartitionCells

template<MInt nDim>
MBool CartesianGrid< nDim >::m_updatedPartitionCells = false
private

Definition at line 676 of file cartesiangrid.h.

◆ m_updatePartitionCellsOnRestart

template<MInt nDim>
MBool CartesianGrid< nDim >::m_updatePartitionCellsOnRestart = true
private

Definition at line 670 of file cartesiangrid.h.

◆ m_updatingPartitionCells

template<MInt nDim>
MBool CartesianGrid< nDim >::m_updatingPartitionCells = false
private

Definition at line 674 of file cartesiangrid.h.

◆ m_wasAdapted

template<MInt nDim>
MBool CartesianGrid< nDim >::m_wasAdapted = false

Definition at line 264 of file cartesiangrid.h.

◆ m_wasBalanced

template<MInt nDim>
MBool CartesianGrid< nDim >::m_wasBalanced = false

Definition at line 265 of file cartesiangrid.h.

◆ m_wasBalancedAtLeastOnce

template<MInt nDim>
MBool CartesianGrid< nDim >::m_wasBalancedAtLeastOnce = false

Definition at line 266 of file cartesiangrid.h.

◆ m_windowCells

template<MInt nDim>
std::vector<std::vector<MInt> > CartesianGrid< nDim >::m_windowCells
private

Definition at line 633 of file cartesiangrid.h.

◆ m_windowLayer_

template<MInt nDim>
std::vector<std::unordered_map<MInt, M32X4bit<true> > > CartesianGrid< nDim >::m_windowLayer_
private

Definition at line 644 of file cartesiangrid.h.

◆ m_zonal

template<MInt nDim>
MBool CartesianGrid< nDim >::m_zonal
private

Definition at line 775 of file cartesiangrid.h.

◆ WINDOWLAYER_MAX

template<MInt nDim>
constexpr const auto CartesianGrid< nDim >::WINDOWLAYER_MAX = decltype(m_windowLayer_)::value_type::mapped_type::MAX
staticconstexprprivate

Definition at line 645 of file cartesiangrid.h.


The documentation for this class was generated from the following files: