16#include <unordered_set>
66 #if !defined(UseSmartMPI)
70 _currentProgramStep==Terminate,
71 "forgot to terminate node properly through peano4::parallel::Node::getInstance().shutdown()"
78 _currentProgramStep = UndefProgramStep;
85 for (
int i=0; i<MaxSpacetreesPerRank; i++) {
94 case ExchangeMode::HorizontalData:
95 return "horizontal-data";
96 case ExchangeMode::VerticalData:
97 return "vertical-data";
115 return numberOfRanks * localTreeId + rank;
121 return id % numberOfRanks;
127 return treeId / numberOfRanks;
140 while (result==-1 and localThread<MaxSpacetreesPerRank) {
141 if ( _treeEntries.count( getId(rank,localThread) )==0 ) {
142 result = getId(rank,localThread);
145 logDebug(
"reserveId(int,int)",
"local tree " << localThread <<
" (global id=" << getId(rank,localThread) <<
") on rank " << rank <<
" is already in use" );
150 if (localThread==MaxSpacetreesPerRank-1) {
154 if (localThread<MaxSpacetreesPerRank) {
155 registerId( result, forTreeId );
166 assertion2( _treeEntries.count(
id)==0,
id, masterId );
169 assertion( isGlobalMaster(
id) or _treeEntries.count(masterId)==1 );
175 newEntry.
setId(
id );
178 _treeEntries.insert( std::pair<int,TreeEntry>(
id, newEntry) );
184 return _treeEntries.size();
192 _treeEntries.erase(
id);
194 logDebug(
"deregisterId(int)",
"removed tree " <<
id <<
" from list of trees" );
205 int outputStackMinusOtherStacks = outputStack - firstPeriodicBCStack;
207 return mirroredStack + firstPeriodicBCStack;
232 std::bitset<2*Dimensions> result;
234 for (
int d=0; d<2*Dimensions; d++) {
235 bool allFlagsSet =
true;
239 entry( d%Dimensions ) = d/Dimensions;
252 int normal = faceNumber % Dimensions;
253 bool lookRight = faceNumber < Dimensions;
254 neighbour(normal) += lookRight ? 1 : -1;
256 if (linearisedIndex>=
ThreePowerD/2) linearisedIndex--;
258 return baseIndex + linearisedIndex;
263 std::ostringstream msg;
266 bool firstEntry =
true;
267 for (
auto& p: data) {
274 msg <<
"(stack=" << p.first <<
",bnd=" << std::bitset<Dimensions>(p.second) <<
")";
283 std::bitset<2*Dimensions> boundaryNumbers = getPeriodicBoundaryNumber(flags);
286 std::unordered_set< std::bitset<2*Dimensions> > powerSet;
287 for (
int i=0; i<2*Dimensions; i++) {
288 if ( boundaryNumbers[i] ) {
289 std::bitset<2*Dimensions> newEntry(0);
291 powerSet.insert( newEntry );
293 for (
auto p: powerSet) {
296 powerSet.insert( newEntry );
301 std::set<peano4::parallel::Node::PeriodicBoundaryStackIdentifier> result;
302 int currentStackNumber = 0;
305 std::bitset<2*Dimensions> requiredEntryForThisDirection(0);
306 std::bitset<Dimensions> direction(0);
307 for (
int d=0; d<Dimensions; d++) {
308 if (neighbour(d)>1) {
309 requiredEntryForThisDirection[d] =
true;
312 if (neighbour(d)<1) {
313 requiredEntryForThisDirection[d+Dimensions] =
true;
317 if (powerSet.count(requiredEntryForThisDirection)>0) {
323 isPeriodicBoundaryExchangeOutputStackNumber(newEntry.first),
324 newEntry.first, newEntry.second, flags,
327 result.insert( newEntry );
329 currentStackNumber++;
350 logTraceOutWith2Arguments(
"getOutputStacksForPeriodicBoundaryExchange(...)", result.size(), (result.size()==1 ? std::to_string(result.begin()->first) :
"" ) );
357 assertion( isPeriodicBoundaryExchangeOutputStackNumber(outputStackNumber) );
367 assertion( isPeriodicBoundaryExchangeOutputStackNumber(outputStackIdentifier.first) );
371 result.second = outputStackIdentifier.second;
372 logTraceOutWith2Arguments(
"getPeriodicBoundaryExchangeInputStackNumberForOutputStack(int)", result.first, result.second );
381 return periodicBoundary;
389 return domainBoundary;
397 return domainBoundary;
425 logDebug(
"continueToRun()",
"send out " << message.
toString() <<
" to rank " << i);
437 return _currentProgramStep!=Terminate;
442 assertion1( number==Terminate or number>=0, number);
443 _currentProgramStep = number;
448 return _currentProgramStep;
466 for (
int i=0; i<MaxSpacetreesPerRank; i++) {
467 MPI_Comm_free(&(_dataExchangeCommunicators[i]));
480 assertion(sendingTreeId<MaxSpacetreesPerRank);
482 int tag = StacksPerCommunicationPartner/2 * getLocalTreeId(receivingTreeId);
484 case ExchangeMode::HorizontalData:
487 case ExchangeMode::VerticalData:
498 if (tag==getInstance()._rankOrchestrationTag) {
499 return "rank orchestration tag";
504 std::string result =
"data exchange tag for ";
506 switch ( tag % (StacksPerCommunicationPartner/2)) {
507 case 0: result +=
"horizontal data";
break;
508 case 1: result +=
"vertical data";
break;
#define assertion2(expr, param0, param1)
#define assertion1(expr, param)
#define assertionMsg(expr, message)
#define assertion5(expr, param0, param1, param2, param3, param4)
#define logDebug(methodName, logMacroMessageStream)
#define logTraceOutWith1Argument(methodName, argument0)
#define logTraceOut(methodName)
#define logWarning(methodName, logMacroMessageStream)
Wrapper macro around tarch::tarch::logging::Log to improve logging.
#define logTraceInWith4Arguments(methodName, argument0, argument1, argument2, argument3)
#define logTraceInWith5Arguments(methodName, argument0, argument1, argument2, argument3, argument4)
#define logTraceInWith3Arguments(methodName, argument0, argument1, argument2)
#define logTraceOutWith2Arguments(methodName, argument0, argument1)
#define logTraceIn(methodName)
#define logTraceInWith2Arguments(methodName, argument0, argument1)
#define dfor2(counter)
Shortcut For dfor(counter,2)
#define dfor3(counter)
Shortcut For dfor(counter,3)
#define enddforx
I prefer to use this macro for dforx instead of a closing bracket as many syntax parser fail otherwis...
static constexpr int MaxNumberOfCoreStacksPerSpacetreeInstance
Standard (serial) number of stacks required per spacetree.
static constexpr int NumberOfPeriodicBoundaryConditionStacks
In principle, there are Dimensions axes along which we can have periodic boundary conditions.
static constexpr int RankOfPeriodicBoundaryCondition
Periodic boundary conditions are technically realised as domain decomposition, i.e.
Node is Peano's abstraction for the hybrid of MPI/threads.
static void shutdownMPIDatatypes()
static std::bitset< 2 *Dimensions > getPeriodicBoundaryNumber(const tarch::la::Vector< TwoPowerD, int > &flags)
Analyse to which of the 2d faces it is adjacent.
static int getOutputStackForPeriodicBoundaryExchange(int faceNumber)
Identify output stack for periodic boundary data written by face.
Node()
The standard constructor assigns the attributes default values and checks whether the program is comp...
void shutdown()
The shutdown is invoked by peano4::shutdownSingletons()
static int getTreeNumberTiedToExchangeStackNumber(int number)
Gives you back the id of a communication partner, i.e.
static tarch::logging::Log _log
Logging device.
static bool isPeriodicBoundaryExchangeOutputStackNumber(int number)
bool continueToRun()
You should call this operation only on the ranks >0 to find out whether you should do more iteration/...
int reserveId(int rank, int forTreeId)
This operation is not const as it does some internal bookkeeping.
static bool isHorizontalDataExchangeInputStackNumber(int number)
static int getOutputStackNumberForHorizontalDataExchange(int id)
Hand in a spacetree id and get back the number that we should use to send something to this tree.
int getLocalTreeId(int treeId) const
static int mapPeriodicBoundaryExchangeOutputStackOntoInputStack(int outputStack)
int getRank(int treeId) const
You hand in a tree number and the node tells you on which rank such a tree is hosted.
static int getInputStackNumberForHorizontalDataExchange(int id)
Counterpart of getOutputStackNumberOfBoundaryExchange(int)
static constexpr int Terminate
int getCurrentProgramStep() const
void deregisterId(int id)
Only the SpacetreeSet should call this operation.
void registerId(int id, int masterId)
The operation is not thread-safe as we call it only internally, i.e.
static void initMPIDatatypes()
I originally wanted to embed these guys into the singleton's constructor.
std::pair< int, int > PeriodicBoundaryStackIdentifier
A periodic boundary stack is basically a stack (an integer), but I do augment it by a bitset which id...
int getGlobalTreeId(int treeId) const
static bool isVerticalDataExchangeOutputStackNumber(int number)
static bool isHorizontalDataExchangeOutputStackNumber(int number)
See getOutputStackNumberOfBoundaryExchange().
std::pair< int, MPI_Comm > GridDataExchangeMetaInformation
static std::string toString(const std::set< PeriodicBoundaryStackIdentifier > &data)
void setNextProgramStep(int number)
The user tells the set which program step to use, i.e.
static int getOutputStackNumberForVerticalDataExchange(int id)
int getNumberOfRegisteredTrees() const
virtual ~Node()
The standard destructor calls MPI_Finalize().
static std::set< PeriodicBoundaryStackIdentifier > getOutputStacksForPeriodicBoundaryExchange(const tarch::la::Vector< TwoPowerD, int > &flags)
You hand in a the flags of a vertex and you get the boundary stack identifiers including their direct...
static int getPeriodicBoundaryExchangeInputStackNumberForOutputStack(int outputStackNumber)
Hand in an output stack number of a face and you get back the input stack number.
static bool isVerticalDataExchangeInputStackNumber(int number)
static std::string getSemanticsForTag(int tag)
I use this for debugging.
static bool isGlobalMaster(int treeId)
Is this the global master?
static bool isStorageStackNumber(int number)
There are communication stacks and storage stacks.
GridDataExchangeMetaInformation getGridDataExchangeMetaInformation(int sendingTreeId, int receivingTreeId, ExchangeMode exchange) const
I use two tags per spacetree per rank: one for boundary data (horizontal) and one for up-down and syn...
static int getInputStackNumberForVerticalDataExchange(int id)
Get the input stack where a tree writes all of its vertical data to/from when it exchanges informatio...
int getId(int rank, int localTreeId) const
Peano maps grid instance threads + mpi ranks onto global IDs through this routine.
static Node & getInstance()
This operation returns the singleton instance.
static int getGlobalMasterRank()
Get the global master.
int getNumberOfRanks() const
static Rank & getInstance()
This operation returns the singleton instance.
int getRank() const
Return rank of this node.
void barrier(std::function< void()> waitor=[]() -> void {})
static int reserveFreeTag(const std::string &fullQualifiedMessageName, int numberOfTags=1)
Return a Free Tag.
Create a lock around a boolean semaphore region.
virtual void receiveDanglingMessages() override
Answer to MPI Messages.
static ServiceRepository & getInstance()
std::string toString(Filter filter)
CPUGPUMethod int dLinearised(const tarch::la::Vector< Dimensions, int > &counter, int max)
Map d-dimensional vector onto integer index.
static void shutdownDatatype()
static void initDatatype()
To be called prior to any MPI usage of this class.
static void shutdownDatatype()
Free the underlying MPI datatype.
static void initDatatype()
Wrapper around getDatatype() to trigger lazy evaluation if we use the lazy initialisation.
static void initDatatype()
Wrapper around getDatatype() to trigger lazy evaluation if we use the lazy initialisation.
static void shutdownDatatype()
Free the underlying MPI datatype.
static void shutdownDatatype()
Free the underlying MPI datatype.
static void initDatatype()
Wrapper around getDatatype() to trigger lazy evaluation if we use the lazy initialisation.
static void shutdownDatatype()
Free the underlying MPI datatype.
static void initDatatype()
Wrapper around getDatatype() to trigger lazy evaluation if we use the lazy initialisation.
static void receiveAndPollDanglingMessages(peano4::parallel::StartTraversalMessage &message, int source, int tag, MPI_Comm communicator=tarch::mpi::Rank::getInstance().getCommunicator())
static void sendAndPollDanglingMessages(const peano4::parallel::StartTraversalMessage &message, int destination, int tag, MPI_Comm communicator=tarch::mpi::Rank::getInstance().getCommunicator())
static void shutdownDatatype()
Free the underlying MPI datatype.
std::string toString() const
int getStepIdentifier() const
static void initDatatype()
Wrapper around getDatatype() to trigger lazy evaluation if we use the lazy initialisation.
void setStepIdentifier(int value)
void setMaster(int value)
static void shutdownDatatype()
Free the underlying MPI datatype.
static void initDatatype()
Wrapper around getDatatype() to trigger lazy evaluation if we use the lazy initialisation.