SIRIUS 7.5.0
Electronic structure library and applications
communicator.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2022 Anton Kozhevnikov, Thomas Schulthess
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
5// the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
8// following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
10// and the following disclaimer in the documentation and/or other materials provided with the distribution.
11//
12// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
13// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
15// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
18// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
20/** \file communicator.hpp
21 *
22 * \brief Contains declaration and implementation of mpi::Communicator class.
23 */
24
25#ifndef __COMMUNICATOR_HPP__
26#define __COMMUNICATOR_HPP__
27
28#include <mpi.h>
29#include <cassert>
30#include <vector>
31#include <complex>
32#include <cstdarg>
33#include <functional>
34#include <memory>
35#include <algorithm>
36#include <cstring>
37#include <cstdio>
38#include <map>
39
40namespace sirius {
41
42/// MPI related functions and classes.
43namespace mpi {
44
45/// Get number of ranks per node.
47
48/// Get GPU device id associated with the current rank.
49int get_device_id(int num_devices__);
50
51#define CALL_MPI(func__, args__) \
52{ \
53 if (func__ args__ != MPI_SUCCESS) { \
54 std::printf("error in %s at line %i of file %s\n", #func__, __LINE__, __FILE__); \
55 MPI_Abort(MPI_COMM_WORLD, -1); \
56 } \
57}
58
59/// Tyoe of MPI reduction.
60enum class op_t
61{
62 sum,
63 max,
64 min,
65 land
66};
67
68template <op_t op>
70
71template <>
72struct op_wrapper<op_t::sum>
73{
74 operator MPI_Op() const noexcept {return MPI_SUM;}
75};
76
77template <>
78struct op_wrapper<op_t::max>
79{
80 operator MPI_Op() const noexcept {return MPI_MAX;}
81};
82
83template <>
84struct op_wrapper<op_t::min>
85{
86 operator MPI_Op() const noexcept {return MPI_MIN;}
87};
88
89template <>
90struct op_wrapper<op_t::land>
91{
92 operator MPI_Op() const noexcept {return MPI_LAND;}
93};
94
95template <typename T>
97
98template <>
99struct type_wrapper<float>
100{
101 operator MPI_Datatype() const noexcept {return MPI_FLOAT;}
102};
103
104template <>
105struct type_wrapper<std::complex<float>>
106{
107 operator MPI_Datatype() const noexcept {return MPI_C_FLOAT_COMPLEX;}
108};
109
110template <>
111struct type_wrapper<double>
112{
113 operator MPI_Datatype() const noexcept {return MPI_DOUBLE;}
114};
115
116template <>
117struct type_wrapper<std::complex<double>>
118{
119 operator MPI_Datatype() const noexcept {return MPI_C_DOUBLE_COMPLEX;}
120};
121
122template <>
123struct type_wrapper<long double>
124{
125 operator MPI_Datatype() const noexcept {return MPI_LONG_DOUBLE;}
126};
127
128template <>
129struct type_wrapper<int>
130{
131 operator MPI_Datatype() const noexcept {return MPI_INT;}
132};
133
134template <>
135struct type_wrapper<int16_t>
136{
137 operator MPI_Datatype() const noexcept {return MPI_SHORT;}
138};
139
140template <>
141struct type_wrapper<char>
142{
143 operator MPI_Datatype() const noexcept {return MPI_CHAR;}
144};
145
146template <>
147struct type_wrapper<unsigned char>
148{
149 operator MPI_Datatype() const noexcept {return MPI_UNSIGNED_CHAR;}
150};
151
152template <>
153struct type_wrapper<unsigned long long>
154{
155 operator MPI_Datatype() const noexcept {return MPI_UNSIGNED_LONG_LONG;}
156};
157
158template <>
159struct type_wrapper<unsigned long>
160{
161 operator MPI_Datatype() const noexcept {return MPI_UNSIGNED_LONG;}
162};
163
164template <>
165struct type_wrapper<bool>
166{
167 operator MPI_Datatype() const noexcept {return MPI_C_BOOL;}
168};
169
170template <>
171struct type_wrapper<uint32_t>
172{
173 operator MPI_Datatype() const noexcept {return MPI_UINT32_T;}
174};
175
177{
178 int num_ranks{-1};
179 std::vector<int> counts;
180 std::vector<int> offsets;
181
183 {
184 }
185
186 block_data_descriptor(int num_ranks__)
187 : num_ranks(num_ranks__)
188 {
189 counts = std::vector<int>(num_ranks, 0);
190 offsets = std::vector<int>(num_ranks, 0);
191 }
192
193 void calc_offsets()
194 {
195 for (int i = 1; i < num_ranks; i++) {
196 offsets[i] = offsets[i - 1] + counts[i - 1];
197 }
198 }
199
200 inline int size() const
201 {
202 return counts.back() + offsets.back();
203 }
204};
205
207{
208 private:
209 MPI_Request handler_;
210 public:
211 ~Request()
212 {
213 //CALL_MPI(MPI_Request_free, (&handler_));
214 }
215 void wait()
216 {
217 CALL_MPI(MPI_Wait, (&handler_, MPI_STATUS_IGNORE));
218 }
219
220 MPI_Request& handler()
221 {
222 return handler_;
223 }
224};
225
227{
228 void operator()(MPI_Comm* comm__) const
229 {
230 int mpi_finalized_flag;
231 MPI_Finalized(&mpi_finalized_flag);
232 if (!mpi_finalized_flag) {
233 CALL_MPI(MPI_Comm_free, (comm__));
234 }
235 delete comm__;
236 }
237};
238
239/// MPI communicator wrapper.
241{
242 private:
243 /// Raw MPI communicator.
244 MPI_Comm mpi_comm_raw_{MPI_COMM_NULL};
245 /// Smart pointer to allocated MPI communicator.
246 std::shared_ptr<MPI_Comm> mpi_comm_;
247 /// Store communicator's rank.
248 int rank_{-1};
249 /// Store communicator's size.
250 int size_{-1};
251
252 void init()
253 {
254 assert(mpi_comm_raw_ != MPI_COMM_NULL);
255 CALL_MPI(MPI_Comm_rank, (mpi_comm_raw_, &rank_));
256 CALL_MPI(MPI_Comm_size, (mpi_comm_raw_, &size_));
257 }
258
259 public:
260 /// Default constructor.
262 {
263 }
264
265 /// Constructor for existing communicator.
266 explicit Communicator(MPI_Comm mpi_comm__)
267 : mpi_comm_raw_(mpi_comm__)
268 {
269 init();
270 }
271
272 /// Constructor for new communicator.
273 explicit Communicator(std::shared_ptr<MPI_Comm> comm__)
274 : mpi_comm_raw_(*comm__)
275 , mpi_comm_(comm__)
276 {
277 init();
278 }
279
280 /// MPI initialization.
281 static void initialize(int required__)
282 {
283 int provided;
284
285 MPI_Init_thread(NULL, NULL, required__, &provided);
286
287 MPI_Query_thread(&provided);
288 if ((provided < required__) && (Communicator::world().rank() == 0)) {
289 std::printf("Warning! Required level of thread support is not provided.\n");
290 std::printf("provided: %d \nrequired: %d\n", provided, required__);
291 }
292 }
293
294 /// MPI shut down.
295 static void finalize()
296 {
297 MPI_Finalize();
298 }
299
300 static bool is_finalized()
301 {
302 int mpi_finalized_flag;
303 MPI_Finalized(&mpi_finalized_flag);
304 return mpi_finalized_flag == true;
305 }
306
307 static Communicator const& self()
308 {
309 static Communicator comm(MPI_COMM_SELF);
310 return comm;
311 }
312
313 static Communicator const& world()
314 {
315 static Communicator comm(MPI_COMM_WORLD);
316 return comm;
317 }
318
319 static Communicator const& null()
320 {
321 static Communicator comm(MPI_COMM_NULL);
322 return comm;
323 }
324
325 void abort(int errcode__) const
326 {
327 CALL_MPI(MPI_Abort, (this->native(), errcode__));
328 }
329
330 inline Communicator cart_create(int ndims__, int const* dims__, int const* periods__) const
331 {
332 auto comm_sptr = std::shared_ptr<MPI_Comm>(new MPI_Comm, mpi_comm_deleter());
333 CALL_MPI(MPI_Cart_create, (this->native(), ndims__, dims__, periods__, 0, comm_sptr.get()));
334 return Communicator(comm_sptr);
335 }
336
337 inline Communicator cart_sub(int const* remain_dims__) const
338 {
339 auto comm_sptr = std::shared_ptr<MPI_Comm>(new MPI_Comm, mpi_comm_deleter());
340 CALL_MPI(MPI_Cart_sub, (this->native(), remain_dims__, comm_sptr.get()));
341 return Communicator(comm_sptr);
342 }
343
344 inline Communicator split(int color__) const
345 {
346 auto comm_sptr = std::shared_ptr<MPI_Comm>(new MPI_Comm, mpi_comm_deleter());
347 CALL_MPI(MPI_Comm_split, (this->native(), color__, rank(), comm_sptr.get()));
348 return Communicator(comm_sptr);
349 }
350
351 inline Communicator duplicate() const
352 {
353 auto comm_sptr = std::shared_ptr<MPI_Comm>(new MPI_Comm, mpi_comm_deleter());
354 CALL_MPI(MPI_Comm_dup, (this->native(), comm_sptr.get()));
355 return Communicator(comm_sptr);
356 }
357
358 /// Mapping between Fortran and SIRIUS MPI communicators.
359 static Communicator const& map_fcomm(int fcomm__)
360 {
361 static std::map<int, Communicator> fcomm_map;
362 if (!fcomm_map.count(fcomm__)) {
363 fcomm_map[fcomm__] = Communicator(MPI_Comm_f2c(fcomm__));
364 }
365
366 auto& comm = fcomm_map[fcomm__];
367 return comm;
368 }
369
370 /// Return the native raw MPI communicator handler.
371 inline MPI_Comm native() const
372 {
373 return mpi_comm_raw_;
374 }
375
376 static int get_tag(int i__, int j__)
377 {
378 if (i__ > j__) {
379 std::swap(i__, j__);
380 }
381 return (j__ * (j__ + 1) / 2 + i__ + 1) << 6;
382 }
383
384 static std::string processor_name()
385 {
386 char name[MPI_MAX_PROCESSOR_NAME];
387 int len;
388 CALL_MPI(MPI_Get_processor_name, (name, &len));
389 return std::string(name, len);
390 }
391
392 /// Rank of MPI process inside communicator.
393 inline int rank() const
394 {
395 return rank_;
396 }
397
398 /// Size of the communicator (number of ranks).
399 inline int size() const
400 {
401 return size_;
402 }
403
404 /// Rank of MPI process inside communicator with associated Cartesian partitioning.
405 inline int cart_rank(std::vector<int> const& coords__) const
406 {
407 if (this->native() == MPI_COMM_SELF) {
408 return 0;
409 }
410
411 int r;
412 CALL_MPI(MPI_Cart_rank, (this->native(), &coords__[0], &r));
413 return r;
414 }
415
416 inline bool is_null() const
417 {
418 return (mpi_comm_raw_ == MPI_COMM_NULL);
419 }
420
421 inline void barrier() const
422 {
423#if defined(__PROFILE_MPI)
424 PROFILE("MPI_Barrier");
425#endif
426 assert(this->native() != MPI_COMM_NULL);
427 CALL_MPI(MPI_Barrier, (this->native()));
428 }
429
430 template <typename T, op_t mpi_op__ = op_t::sum>
431 inline void reduce(T* buffer__, int count__, int root__) const
432 {
433 if (root__ == rank()) {
434 CALL_MPI(MPI_Reduce, (MPI_IN_PLACE, buffer__, count__, type_wrapper<T>(),
435 op_wrapper<mpi_op__>(), root__, this->native()));
436 } else {
437 CALL_MPI(MPI_Reduce, (buffer__, NULL, count__, type_wrapper<T>(),
438 op_wrapper<mpi_op__>(), root__, this->native()));
439 }
440 }
441
442 template <typename T, op_t mpi_op__ = op_t::sum>
443 inline void reduce(T* buffer__, int count__, int root__, MPI_Request* req__) const
444 {
445 if (root__ == rank()) {
446 CALL_MPI(MPI_Ireduce, (MPI_IN_PLACE, buffer__, count__, type_wrapper<T>(),
447 op_wrapper<mpi_op__>(), root__, this->native(), req__));
448 } else {
449 CALL_MPI(MPI_Ireduce, (buffer__, NULL, count__, type_wrapper<T>(),
450 op_wrapper<mpi_op__>(), root__, this->native(), req__));
451 }
452 }
453
454 template <typename T, op_t mpi_op__ = op_t::sum>
455 void reduce(T const* sendbuf__, T* recvbuf__, int count__, int root__) const
456 {
457 CALL_MPI(MPI_Reduce, (sendbuf__, recvbuf__, count__, type_wrapper<T>(),
458 op_wrapper<mpi_op__>(), root__, this->native()));
459 }
460
461 template <typename T, op_t mpi_op__ = op_t::sum>
462 void reduce(T const* sendbuf__, T* recvbuf__, int count__, int root__, MPI_Request* req__) const
463 {
464 CALL_MPI(MPI_Ireduce, (sendbuf__, recvbuf__, count__, type_wrapper<T>(),
465 op_wrapper<mpi_op__>(), root__, this->native(), req__));
466 }
467
468 /// Perform the in-place (the output buffer is used as the input buffer) all-to-all reduction.
469 template <typename T, op_t mpi_op__ = op_t::sum>
470 inline void allreduce(T* buffer__, int count__) const
471 {
472 CALL_MPI(MPI_Allreduce, (MPI_IN_PLACE, buffer__, count__, type_wrapper<T>(),
473 op_wrapper<mpi_op__>(), this->native()));
474 }
475
476 /// Perform the in-place (the output buffer is used as the input buffer) all-to-all reduction.
477 template <typename T, op_t op__ = op_t::sum>
478 inline void allreduce(std::vector<T>& buffer__) const
479 {
480 allreduce<T, op__>(buffer__.data(), static_cast<int>(buffer__.size()));
481 }
482
483 template <typename T, op_t mpi_op__ = op_t::sum>
484 inline void iallreduce(T* buffer__, int count__, MPI_Request* req__) const
485 {
486#if defined(__PROFILE_MPI)
487 PROFILE("MPI_Iallreduce");
488#endif
489 CALL_MPI(MPI_Iallreduce, (MPI_IN_PLACE, buffer__, count__, type_wrapper<T>(),
490 op_wrapper<mpi_op__>(), this->native(), req__));
491 }
492
493 /// Perform buffer broadcast.
494 template <typename T>
495 inline void bcast(T* buffer__, int count__, int root__) const
496 {
497#if defined(__PROFILE_MPI)
498 PROFILE("MPI_Bcast");
499#endif
500 CALL_MPI(MPI_Bcast, (buffer__, count__, type_wrapper<T>(), root__, this->native()));
501 }
502
503 inline void bcast(std::string& str__, int root__) const
504 {
505 int sz;
506 if (rank() == root__) {
507 sz = static_cast<int>(str__.size());
508 }
509 bcast(&sz, 1, root__);
510 char* buf = new char[sz + 1];
511 if (rank() == root__) {
512 std::copy(str__.c_str(), str__.c_str() + sz + 1, buf);
513 }
514 bcast(buf, sz + 1, root__);
515 str__ = std::string(buf);
516 delete[] buf;
517 }
518
519 /// In-place MPI_Allgatherv.
520 template <typename T>
521 void
522 allgather(T* buffer__, int const* recvcounts__, int const* displs__) const
523 {
524#if defined(__PROFILE_MPI)
525 PROFILE("MPI_Allgatherv");
526#endif
527 CALL_MPI(MPI_Allgatherv, (MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, buffer__, recvcounts__, displs__,
528 type_wrapper<T>(), this->native()));
529 }
530
531 /// Out-of-place MPI_Allgatherv.
532 template <typename T>
533 void
534 allgather(T const* sendbuf__, int sendcount__, T* recvbuf__, int const* recvcounts__, int const* displs__) const
535 {
536#if defined(__PROFILE_MPI)
537 PROFILE("MPI_Allgatherv");
538#endif
539 CALL_MPI(MPI_Allgatherv, (sendbuf__, sendcount__, type_wrapper<T>(), recvbuf__, recvcounts__,
540 displs__, type_wrapper<T>(), this->native()));
541 }
542
543 template <typename T>
544 void
545 allgather(T const* sendbuf__, T* recvbuf__, int count__, int displs__) const
546 {
547 std::vector<int> v(size() * 2);
548 v[2 * rank()] = count__;
549 v[2 * rank() + 1] = displs__;
550
551 CALL_MPI(MPI_Allgather,
552 (MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, v.data(), 2, type_wrapper<int>(), this->native()));
553
554 std::vector<int> counts(size());
555 std::vector<int> displs(size());
556
557 for (int i = 0; i < size(); i++) {
558 counts[i] = v[2 * i];
559 displs[i] = v[2 * i + 1];
560 }
561
562 CALL_MPI(MPI_Allgatherv, (sendbuf__, count__, type_wrapper<T>(), recvbuf__, counts.data(),
563 displs.data(), type_wrapper<T>(), this->native()));
564 }
565
566 /// In-place MPI_Allgatherv.
567 template <typename T>
568 void
569 allgather(T* buffer__, int count__, int displs__) const
570 {
571 std::vector<int> v(size() * 2);
572 v[2 * rank()] = count__;
573 v[2 * rank() + 1] = displs__;
574
575 CALL_MPI(MPI_Allgather,
576 (MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, v.data(), 2, type_wrapper<int>(), this->native()));
577
578 std::vector<int> counts(size());
579 std::vector<int> displs(size());
580
581 for (int i = 0; i < size(); i++) {
582 counts[i] = v[2 * i];
583 displs[i] = v[2 * i + 1];
584 }
585 allgather(buffer__, counts.data(), displs.data());
586 }
587
588 template <typename T>
589 void send(T const* buffer__, int count__, int dest__, int tag__) const
590 {
591#if defined(__PROFILE_MPI)
592 PROFILE("MPI_Send");
593#endif
594 CALL_MPI(MPI_Send, (buffer__, count__, type_wrapper<T>(), dest__, tag__, this->native()));
595 }
596
597 template <typename T>
598 Request isend(T const* buffer__, int count__, int dest__, int tag__) const
599 {
600 Request req;
601#if defined(__PROFILE_MPI)
602 PROFILE("MPI_Isend");
603#endif
604 CALL_MPI(MPI_Isend, (buffer__, count__, type_wrapper<T>(), dest__, tag__, this->native(), &req.handler()));
605 return req;
606 }
607
608 template <typename T>
609 void recv(T* buffer__, int count__, int source__, int tag__) const
610 {
611#if defined(__PROFILE_MPI)
612 PROFILE("MPI_Recv");
613#endif
614 CALL_MPI(MPI_Recv,
615 (buffer__, count__, type_wrapper<T>(), source__, tag__, this->native(), MPI_STATUS_IGNORE));
616 }
617
618 template <typename T>
619 Request irecv(T* buffer__, int count__, int source__, int tag__) const
620 {
621 Request req;
622#if defined(__PROFILE_MPI)
623 PROFILE("MPI_Irecv");
624#endif
625 CALL_MPI(MPI_Irecv, (buffer__, count__, type_wrapper<T>(), source__, tag__, this->native(), &req.handler()));
626 return req;
627 }
628
629 template <typename T>
630 void gather(T const* sendbuf__, T* recvbuf__, int const* recvcounts__, int const* displs__, int root__) const
631 {
632 int sendcount = recvcounts__[rank()];
633
634#if defined(__PROFILE_MPI)
635 PROFILE("MPI_Gatherv");
636#endif
637 CALL_MPI(MPI_Gatherv, (sendbuf__, sendcount, type_wrapper<T>(), recvbuf__, recvcounts__, displs__,
638 type_wrapper<T>(), root__, this->native()));
639 }
640
641 /// Gather data on a given rank.
642 template <typename T>
643 void gather(T const* sendbuf__, T* recvbuf__, int offset__, int count__, int root__) const
644 {
645
646#if defined(__PROFILE_MPI)
647 PROFILE("MPI_Gatherv");
648#endif
649 std::vector<int> v(size() * 2);
650 v[2 * rank()] = count__;
651 v[2 * rank() + 1] = offset__;
652
653 CALL_MPI(MPI_Allgather,
654 (MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, v.data(), 2, type_wrapper<int>(), this->native()));
655
656 std::vector<int> counts(size());
657 std::vector<int> offsets(size());
658
659 for (int i = 0; i < size(); i++) {
660 counts[i] = v[2 * i];
661 offsets[i] = v[2 * i + 1];
662 }
663 CALL_MPI(MPI_Gatherv, (sendbuf__, count__, type_wrapper<T>(), recvbuf__, counts.data(),
664 offsets.data(), type_wrapper<T>(), root__, this->native()));
665 }
666
667 template <typename T>
668 void scatter(T const* sendbuf__, T* recvbuf__, int const* sendcounts__, int const* displs__, int root__) const
669 {
670#if defined(__PROFILE_MPI)
671 PROFILE("MPI_Scatterv");
672#endif
673 int recvcount = sendcounts__[rank()];
674 CALL_MPI(MPI_Scatterv, (sendbuf__, sendcounts__, displs__, type_wrapper<T>(), recvbuf__, recvcount,
675 type_wrapper<T>(), root__, this->native()));
676 }
677
678 template <typename T>
679 void alltoall(T const* sendbuf__, int sendcounts__, T* recvbuf__, int recvcounts__) const
680 {
681#if defined(__PROFILE_MPI)
682 PROFILE("MPI_Alltoall");
683#endif
684 CALL_MPI(MPI_Alltoall, (sendbuf__, sendcounts__, type_wrapper<T>(), recvbuf__, recvcounts__,
685 type_wrapper<T>(), this->native()));
686 }
687
688 template <typename T>
689 void alltoall(T const* sendbuf__, int const* sendcounts__, int const* sdispls__, T* recvbuf__,
690 int const* recvcounts__, int const* rdispls__) const
691 {
692#if defined(__PROFILE_MPI)
693 PROFILE("MPI_Alltoallv");
694#endif
695 CALL_MPI(MPI_Alltoallv, (sendbuf__, sendcounts__, sdispls__, type_wrapper<T>(), recvbuf__,
696 recvcounts__, rdispls__, type_wrapper<T>(), this->native()));
697 }
698};
699
700} // namespace mpi
701
702} // namespace sirius
703
704#endif // __COMMUNICATOR_HPP__
MPI communicator wrapper.
void bcast(T *buffer__, int count__, int root__) const
Perform buffer broadcast.
void allgather(T *buffer__, int const *recvcounts__, int const *displs__) const
In-place MPI_Allgatherv.
static void initialize(int required__)
MPI initialization.
void allreduce(std::vector< T > &buffer__) const
Perform the in-place (the output buffer is used as the input buffer) all-to-all reduction.
void allgather(T const *sendbuf__, int sendcount__, T *recvbuf__, int const *recvcounts__, int const *displs__) const
Out-of-place MPI_Allgatherv.
void gather(T const *sendbuf__, T *recvbuf__, int offset__, int count__, int root__) const
Gather data on a given rank.
MPI_Comm mpi_comm_raw_
Raw MPI communicator.
int rank_
Store communicator's rank.
void allgather(T *buffer__, int count__, int displs__) const
In-place MPI_Allgatherv.
int size_
Store communicator's size.
MPI_Comm native() const
Return the native raw MPI communicator handler.
int size() const
Size of the communicator (number of ranks).
Communicator()
Default constructor.
int cart_rank(std::vector< int > const &coords__) const
Rank of MPI process inside communicator with associated Cartesian partitioning.
void allreduce(T *buffer__, int count__) const
Perform the in-place (the output buffer is used as the input buffer) all-to-all reduction.
static Communicator const & map_fcomm(int fcomm__)
Mapping between Fortran and SIRIUS MPI communicators.
int rank() const
Rank of MPI process inside communicator.
static void finalize()
MPI shut down.
std::shared_ptr< MPI_Comm > mpi_comm_
Smart pointer to allocated MPI communicator.
Communicator(MPI_Comm mpi_comm__)
Constructor for existing communicator.
Communicator(std::shared_ptr< MPI_Comm > comm__)
Constructor for new communicator.
void copy(T *target__, T const *source__, size_t n__)
Copy memory inside a device.
Definition: acc.hpp:320
int get_device_id(int num_devices__)
Get GPU device id associated with the current rank.
op_t
Tyoe of MPI reduction.
int num_ranks_per_node()
Get number of ranks per node.
Namespace of the SIRIUS library.
Definition: sirius.f90:5