KratosMultiphysics
KRATOS Multiphysics (Kratos) is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, and high performance. Kratos is written in C++, and counts with an extensive Python interface.
pointer_map_communicator.h
Go to the documentation of this file.
1 // | / |
2 // ' / __| _` | __| _ \ __|
3 // . \ | ( | | ( |\__ `
4 // _|\_\_| \__,_|\__|\___/ ____/
5 // Multi-Physics
6 //
7 // License: BSD License
8 // Kratos default license: kratos/license.txt
9 //
10 // Main authors: Riccardo Rossi
11 // Suneth Warnakulasuriya
12 //
13 
14 #if !defined(KRATOS_POINTER_MAP_COMMUNICATOR_H_INCLUDED )
15 #define KRATOS_POINTER_MAP_COMMUNICATOR_H_INCLUDED
16 
17 
18 // System includes
19 #include <string>
20 #include <vector>
21 #include <unordered_map>
22 #include <utility>
23 
24 // External includes
25 #include "concurrentqueue/concurrentqueue.h"
26 
27 // Project includes
31 #include "includes/define.h"
35 #include "utilities/openmp_utils.h"
36 
37 namespace Kratos
38 {
41 
44 
45 template <class TPointerDataType, class TValueDataType>
46 class GlobalPointerMapCommunicator;
47 
90 template<class TPointerDataType, class TValueDataType, class TApplyFunctor>
92 {
93 public:
96 
98 
100 
102 
103  using DataVectorType = std::vector<TValueDataType>;
104 
108 
116  const TApplyFunctor& rApplyFunctor,
117  TGPMapCommunicator& rPointerCommunicator)
118  : mCurrentRank(rPointerCommunicator.GetMyPID()),
119  mrApplyFunctor(rApplyFunctor),
120  mrPointerCommunicator(rPointerCommunicator)
121  {
122  KRATOS_TRY
123 
124  if (rPointerCommunicator.IsDistributed()) {
125 
127  << "Constructing a proxy in a parallel "
128  "region is not allowed.\n";
129 
130  this->mUpdateMethod = &ProxyType::AssignLocalAndRemoteData;
131  } else {
132  this->mUpdateMethod = &ProxyType::AssignLocalData;
133  }
134 
135  KRATOS_CATCH("");
136  }
137 
141 
164  void Assign(
165  GlobalPointerType& rGlobalPointer,
166  const TValueDataType& rValue)
167  {
168  (this->*(this->mUpdateMethod))(rGlobalPointer, rValue);
169  }
170 
182  {
183  mrPointerCommunicator.SendAndApplyRemotely(*this);
184  }
185 
187 
188 private:
191 
192  const int mCurrentRank;
193  const TApplyFunctor& mrApplyFunctor;
194 
195  void (ProxyType::*mUpdateMethod)(GlobalPointerType&, const TValueDataType&);
196 
197  moodycamel::ConcurrentQueue<std::pair<GlobalPointerType, TValueDataType>> mNonLocalGlobalPointerValueConcurrentQueue;
198 
199  TGPMapCommunicator& mrPointerCommunicator;
200 
204 
215  void AssignLocalData(
216  GlobalPointerType& rGlobalPointer,
217  const TValueDataType& rValue)
218  {
219  mrApplyFunctor(*rGlobalPointer, rValue);
220  }
221 
222 
233  void AssignLocalAndRemoteData(
234  GlobalPointerType& rGlobalPointer,
235  const TValueDataType& rValue)
236  {
237  const int data_rank = rGlobalPointer.GetRank();
238 
239  if (data_rank == mCurrentRank) {
240  mrApplyFunctor(*rGlobalPointer, rValue);
241  } else {
242  mNonLocalGlobalPointerValueConcurrentQueue.enqueue(
243  std::make_pair(std::move(rGlobalPointer), rValue));
244  }
245  }
246 
250 
251  friend class GlobalPointerMapCommunicator<TPointerDataType, TValueDataType>;
252 
254 
255 };
256 
258 
260 template <class TPointerDataType, class TValueDataType>
262 {
263 public:
266 
267  using IndexType = std::size_t;
268 
270 
271  using DataVectorType = std::vector<TValueDataType>;
272 
273  using GlobalPointerValueVectorPair = std::pair<GlobalPointerType, DataVectorType>;
274 
275  template<class TApplyFunctor>
277 
280 
284 
293  const DataCommunicator& rDataCommunicator)
294  : mrDataCommunicator(rDataCommunicator),
295  mCurrentRank(rDataCommunicator.Rank())
296  {
297  }
298 
300  virtual ~GlobalPointerMapCommunicator() = default;
301 
304 
307 
311 
323  template <class TApplyFunctor>
325  {
326  KRATOS_TRY
327 
328  if (IsDistributed()) {
329 
331  << "Calling SendAndApplyRemotely in a parallel region is not "
332  "allowed.\n";
333 
334  // get the final map for communications
335  // constructing an rank based GlobalPointersUnorderedMap will make unique keys list in GlobalPointersUnorderedMap
336  // which will result in lower communication for keys. These unique keys can be easily OMP parallelized
337  std::unordered_map<int, GlobalPointersUnorderedMap<TPointerDataType, DataVectorType>> non_local_map;
338 
339  bool found_gp_value = true;
340  while (found_gp_value) {
341  std::pair<GlobalPointerType, TValueDataType> item_pair;
342  found_gp_value =
343  rApplyProxy.mNonLocalGlobalPointerValueConcurrentQueue.try_dequeue(item_pair);
344  if (found_gp_value) {
345  auto& r_gp = item_pair.first;
346  non_local_map[r_gp.GetRank()][r_gp].push_back(
347  std::move(item_pair.second));
348  }
349  }
350 
351  // compute the communication plan
352  const auto& colors = ComputeCommunicationPlan(non_local_map);
353 
354  // perform send and receives to get and send remote data
355  for (const auto color : colors) {
356  if (color >= 0) {
357  // In here
358  // 1. We can do communication twice using default serializer for two map vectors.
359  // First map: (rank, gp)
360  // Second map: (rank, data_value)
361  // 2. We can combine non_local_gp_map and non_local_data_map to one map, and do communication once
362  // after serializing the custom map.
363  // Current implementation
364  //
365  // Pros and Cons of 1:
366  // default serialization is used -> Pro
367  // OMP parallel loops cannot be used because received_gps_vector may not be unique -> Con
368  // This will be a performance hit if the lambda proxy is computationally expensive
369  // Communication need to be done twice once for gps, once for values -> Con
370  // Pros and Const of 2:
371  // custom serialization will be used -> Con
372  // OMP parallel loops can be used in applying the proxy because the gps will be unique in the map -> Pro
373  // communication need to be done only once -> Pro
374  //
375  // I think the 2nd options outweighs the first one, so I implemented the second one. Suggestions are
376  // greately appreciated.
377 
378  const auto& received_gp_map = mrDataCommunicator.SendRecv(non_local_map[color], color, color);
379 
380  // create list for OMP parallel looping
381  // using move semantics to move data of GP and std::vector<TValueDataType>
382  // objects in received_gp_map
383  std::vector<GlobalPointerValueVectorPair> gp_value_pair_list;
384  gp_value_pair_list.resize(received_gp_map.size());
385  for (const auto& r_pair : received_gp_map) {
386  gp_value_pair_list.push_back(std::move(r_pair));
387  }
388 
389  // running this in parallel assuming rApplyProxy.mrApplyFunctor is thread safe
390  block_for_each(gp_value_pair_list, [&](GlobalPointerValueVectorPair& rItem) {
391  auto& r_pointer_data_type_entity = *(rItem.first);
392  for (IndexType i = 0; i < rItem.second.size(); ++i) {
393  // it is safer to call the serial update method here
394  // because we should only get process's local gps when communication is done
395  rApplyProxy.mrApplyFunctor(r_pointer_data_type_entity, rItem.second[i]);
396  }
397  });
398  }
399  }
400 
401  // Clearing of the concurrent queue is not required here because, when dequeueing, it will make an
402  // empty concurrent queue.
403  }
404 
405  KRATOS_CATCH("");
406  }
407 
419  template <class TApplyFunctor>
420  ProxyType<TApplyFunctor> GetApplyProxy(TApplyFunctor&& rApplyFunctor)
421  {
422  return ProxyType<TApplyFunctor>(std::forward<TApplyFunctor>(rApplyFunctor), *this);
423  }
424 
429  bool IsDistributed() const
430  {
432  }
433 
438  int GetMyPID() const
439  {
440  return mCurrentRank;
441  }
442 
446 
448  virtual std::string Info() const
449  {
450  std::stringstream buffer;
451  buffer << "GlobalPointerMapCommunicator" ;
452  return buffer.str();
453  }
454 
456  virtual void PrintInfo(std::ostream& rOStream) const
457  {
458  rOStream << "GlobalPointerMapCommunicator";
459  }
460 
462  virtual void PrintData(std::ostream& rOStream) const {}
463 
465 
466 protected:
469 
471  const int mCurrentRank;
472 
476 
477  template<class... TArgs>
478  std::vector<int> ComputeCommunicationPlan(const std::unordered_map<int, TArgs...>& rNonLocalGlobalPointerMap)
479  {
480  std::vector<int> send_list;
481  send_list.reserve(rNonLocalGlobalPointerMap.size());
482  for (const auto& r_pair : rNonLocalGlobalPointerMap) {
483  send_list.push_back(r_pair.first);
484  }
485  std::sort(send_list.begin(), send_list.end());
486 
488  send_list, mrDataCommunicator);
489  }
490 
492 
493 }; // Class GlobalPointerMapCommunicator
494 
498 
499 
501 template <class TPointerDataType, class TDataType>
502 inline std::istream& operator>>(
503  std::istream& rIStream,
505 {
506  return rIStream;
507 }
508 
510 template <class TPointerDataType, class TDataType>
511 inline std::ostream& operator<<(
512  std::ostream& rOStream,
514 {
515  rThis.PrintInfo(rOStream);
516  rOStream << std::endl;
517  rThis.PrintData(rOStream);
518 
519  return rOStream;
520 }
522 
524 
525 } // namespace Kratos.
526 
527 #endif // KRATOS_POINTER_MAP_COMMUNICATOR_H_INCLUDED defined
528 
529 
Proxy class to update local and non-local data.
Definition: pointer_map_communicator.h:92
std::vector< TValueDataType > DataVectorType
Definition: pointer_map_communicator.h:103
GlobalPointerMapCommunicator< TPointerDataType, TValueDataType > TGPMapCommunicator
Definition: pointer_map_communicator.h:99
GlobalPointer< TPointerDataType > GlobalPointerType
Definition: pointer_map_communicator.h:101
ApplyProxy(const TApplyFunctor &rApplyFunctor, TGPMapCommunicator &rPointerCommunicator)
Construct a new Apply Proxy object.
Definition: pointer_map_communicator.h:115
ApplyProxy< TPointerDataType, TValueDataType, TApplyFunctor > ProxyType
Definition: pointer_map_communicator.h:97
void SendAndApplyRemotely()
This method does all the communication.
Definition: pointer_map_communicator.h:181
void Assign(GlobalPointerType &rGlobalPointer, const TValueDataType &rValue)
Assigns value of the GlobalPointer.
Definition: pointer_map_communicator.h:164
Serial (do-nothing) version of a wrapper class for MPI communication.
Definition: data_communicator.h:318
TObject SendRecv(const TObject &rSendObject, const int SendDestination, const int SendTag, const int RecvSource, const int RecvTag) const
Exchange data with other ranks.
Definition: data_communicator.h:492
virtual bool IsDistributed() const
Check whether this DataCommunicator is aware of parallelism.
Definition: data_communicator.h:606
This class is a wrapper for a pointer to a data that is located in a different rank.
Definition: global_pointer.h:44
Short class definition.
Definition: pointer_map_communicator.h:262
void SendAndApplyRemotely(ProxyType< TApplyFunctor > &rApplyProxy)
Sends and applies remote Gp values.
Definition: pointer_map_communicator.h:324
GlobalPointerMapCommunicator(const DataCommunicator &rDataCommunicator)
Construct a new Global Pointer Map Communicator object.
Definition: pointer_map_communicator.h:292
GlobalPointerMapCommunicator(GlobalPointerMapCommunicator const &rOther)=delete
Copy constructor.
std::vector< TValueDataType > DataVectorType
Definition: pointer_map_communicator.h:271
std::vector< int > ComputeCommunicationPlan(const std::unordered_map< int, TArgs... > &rNonLocalGlobalPointerMap)
Definition: pointer_map_communicator.h:478
std::pair< GlobalPointerType, DataVectorType > GlobalPointerValueVectorPair
Definition: pointer_map_communicator.h:273
bool IsDistributed() const
Returns jobs parallel status.
Definition: pointer_map_communicator.h:429
ProxyType< TApplyFunctor > GetApplyProxy(TApplyFunctor &&rApplyFunctor)
Get the Apply Proxy object.
Definition: pointer_map_communicator.h:420
const int mCurrentRank
Definition: pointer_map_communicator.h:471
std::size_t IndexType
Definition: pointer_map_communicator.h:267
GlobalPointerMapCommunicator & operator=(GlobalPointerMapCommunicator const &rOther)=delete
Assignment constructor.
virtual void PrintInfo(std::ostream &rOStream) const
Print information about this object.
Definition: pointer_map_communicator.h:456
KRATOS_CLASS_POINTER_DEFINITION(GlobalPointerMapCommunicator)
Pointer definition of GlobalPointerMapCommunicator.
virtual void PrintData(std::ostream &rOStream) const
Print object's data.
Definition: pointer_map_communicator.h:462
virtual std::string Info() const
Turn back information as a string.
Definition: pointer_map_communicator.h:448
const DataCommunicator & mrDataCommunicator
Definition: pointer_map_communicator.h:470
int GetMyPID() const
Get the current rank.
Definition: pointer_map_communicator.h:438
virtual ~GlobalPointerMapCommunicator()=default
Destructor.
static std::vector< int > ComputeCommunicationScheduling(const std::vector< int > &rLocalDestinationIds, const DataCommunicator &rComm)
Definition: communication_coloring_utilities.cpp:56
static int IsInParallel()
Wrapper for omp_in_parallel().
Definition: openmp_utils.h:122
#define KRATOS_CATCH(MoreInfo)
Definition: define.h:110
#define KRATOS_TRY
Definition: define.h:109
int GetRank() const
Returns the rank of the global pointer.
Definition: global_pointer.h:262
#define KRATOS_DEBUG_ERROR_IF(conditional)
Definition: exception.h:171
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
void block_for_each(TIterator itBegin, TIterator itEnd, TFunction &&rFunction)
Execute a functor on all items of a range in parallel.
Definition: parallel_utilities.h:299
std::istream & operator>>(std::istream &rIStream, LinearMasterSlaveConstraint &rThis)
input stream function
std::ostream & operator<<(std::ostream &rOStream, const LinearMasterSlaveConstraint &rThis)
output stream function
Definition: linear_master_slave_constraint.h:432
color
Definition: all_t_win_vs_m_fixed_error.py:230
Definition: colors.py:1
integer i
Definition: TensorModule.f:17