Skip to content
Snippets Groups Projects
UniqueID.h 6.39 KiB
Newer Older
//======================================================================================================================
//
//  This file is part of waLBerla. waLBerla is free software: you can
//  redistribute it and/or modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation, either version 3 of
//  the License, or (at your option) any later version.
//
//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
//  for more details.
//
//  You should have received a copy of the GNU General Public License along
//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
//
//! \file UniqueID.h
//! \ingroup core
//! \author Klaus Iglberger
//! \author Sebastian Eibl <sebastian.eibl@fau.de>
//
//======================================================================================================================

#pragma once

//*************************************************************************************************
// Includes
//*************************************************************************************************

#include <stdexcept>
#include <core/mpi/MPIManager.h>
#include <core/debug/Debug.h>
#include <core/NonCreateable.h>
#include <core/DataTypes.h>


namespace walberla {

//=================================================================================================
//
//  CLASS DEFINITION
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Generation of unique IDs in MPI environments.
 * \ingroup core
 *
 * The UniqueID class is responsible for the generation of unique system IDs even during an MPI
 * parallel execution. The unqiue ID is composed from the number of locally generated objects
 * of type \a T and the rank of the local MPI process.
 */
template< typename T >
class UniqueID : private NonCreateable
{
public:
   //**Utility functions***************************************************************************
   /*!\name Utility functions */
   //@{
   static inline id_t create();
   static inline id_t createGlobal();
   static inline id_t invalidID();
   //@}
   //**********************************************************************************************
   
   static inline id_t count() { return counter_; }
   static inline id_t globalCount() { return globalCounter_; }

private:
   //**Member variables****************************************************************************
   /*!\name Member variables */
   //@{
   static id_t counter_;        //!< System ID counter.
   static id_t globalCounter_;  //!< Global system ID counter.
   //@}
   //**********************************************************************************************
};
//*************************************************************************************************




//=================================================================================================
//
//  DEFINITION AND INITIALIZATION OF THE STATIC MEMBER VARIABLES
//
//=================================================================================================

template< typename T >
id_t UniqueID<T>::counter_( 1 );

template< typename T >
id_t UniqueID<T>::globalCounter_( 1 );




//=================================================================================================
//
//  UTILITY FUNCTIONS
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Generates a unique ID.
 *
 * \return The newly generated unique ID.
 */
template< typename T >
inline id_t UniqueID<T>::create()
{
   id_t id( counter_++ );

   if( MPIManager::instance()->bitsNeededToRepresentRank() > 0 ) {
      const size_t shift( sizeof(id_t)*size_t(8) - MPIManager::instance()->bitsNeededToRepresentRank() );
      WALBERLA_ASSERT( shift < sizeof(id_t)*size_t(8), "Invalid shift detected" );

      const int rank ( MPIManager::instance()->worldRank() );
      WALBERLA_ASSERT( rank >= 0, "MPI system is not initialized" );

      if( counter_ >= ( id_t(1) << shift ) ) {
         // Revert overflow of counter
         --counter_;
         throw std::runtime_error( "Unable to create unique ID" );
      }

      id |= ( static_cast<id_t>( rank ) << shift );
   }
   else if( counter_ == size_t(0) ) {
      // Revert overflow of counter
      --counter_;
      throw std::runtime_error( "Unable to create unique ID" );
   }

   return id;
}
//*************************************************************************************************

//*************************************************************************************************
/*!\brief Generates an ID which is the same on all processes but unique on each process.
 *
 * \return The newly generated ID.
 */
template< typename T >
inline id_t UniqueID<T>::createGlobal()
{
   id_t id( globalCounter_++ );

   if( MPIManager::instance()->bitsNeededToRepresentRank() > 0 ) {
      const size_t shift( sizeof(id_t)*size_t(8) - MPIManager::instance()->bitsNeededToRepresentRank() );
      WALBERLA_ASSERT( shift < sizeof(id_t)*size_t(8), "Invalid shift detected" );

      const int size( MPIManager::instance()->numProcesses() );
      WALBERLA_ASSERT( size >= 0, "MPI system is not initialized" );

      if( globalCounter_ >= ( id_t(1) << shift ) ) {
         // Revert overflow of counter
         --globalCounter_;
         throw std::runtime_error( "Unable to create unique ID" );
      }

      id |= ( static_cast<id_t>( size ) << shift );
   }
   else if( globalCounter_ == size_t(0) ) {
      // Revert overflow of counter
      --globalCounter_;
      throw std::runtime_error( "Unable to create unique ID" );
   }

   return id;
}
//*************************************************************************************************

//*************************************************************************************************
/*!\brief Returns an invalid ID
 *
 * \return invalid ID.
 */
template< typename T >
inline id_t UniqueID<T>::invalidID()
{
   return 0;
}
//*************************************************************************************************

}