32 #ifndef VSMC_MPI_BACKEND_MPI_HPP
33 #define VSMC_MPI_BACKEND_MPI_HPP
41 #define VSMC_RUNTIME_ASSERT_MPI_BACKEND_MPI_COPY_SIZE_MISMATCH \
42 VSMC_RUNTIME_ASSERT((N == global_size_), \
43 ("**StateMPI::copy** SIZE MISMATCH"))
49 template <
typename WeightSetBase,
typename ID>
54 typedef typename WeightSetBase::size_type
size_type;
59 ::
boost::mpi::comm_duplicate), resample_size_(0)
61 ::boost::mpi::all_reduce(world_, N, resample_size_,
62 std::plus<size_type>());
63 this->set_ess(static_cast<double>(resample_size_));
70 gather_resample_weight();
71 if (world_.rank() == 0) {
72 const std::size_t
S =
static_cast<std::size_t
>(world_.size());
73 for (std::size_t r = 0; r != S; ++r) {
74 first = std::copy(weight_all_[r].begin(), weight_all_[r].end(),
82 resample_weight_.resize(resample_size_);
85 return world_.rank() == 0 ? &resample_weight_[0] :
VSMC_NULLPTR;
89 const ::boost::mpi::communicator &
world ()
const {
return world_;}
95 const size_type N =
static_cast<size_type
>(this->size());
96 double *
const lwptr = this->mutable_log_weight_data();
98 double lmax_weight = lwptr[0];
99 for (size_type i = 0; i != N; ++i)
100 if (lmax_weight < lwptr[i])
101 lmax_weight = lwptr[i];
102 double gmax_weight = 0;
103 ::boost::mpi::all_reduce(world_, lmax_weight, gmax_weight,
104 ::boost::mpi::maximum<double>());
105 for (size_type i = 0; i != N; ++i)
106 lwptr[i] -= gmax_weight;
111 const size_type N =
static_cast<size_type
>(this->size());
112 double *
const wptr = this->mutable_weight_data();
115 for (size_type i = 0; i != N; ++i)
118 ::boost::mpi::all_reduce(world_, lcoeff, gcoeff, std::plus<double>());
120 for (size_type i = 0; i != N; ++i)
124 for (size_type i = 0; i != N; ++i)
125 less += wptr[i] * wptr[i];
127 ::boost::mpi::all_reduce(world_, less, gess, std::plus<double>());
136 const size_type N =
static_cast<size_type
>(this->size());
137 std::vector<double, AlignedAllocator<double> > buffer(N);
138 double *
const bptr = &buffer[0];
141 const double *
const lwptr = this->log_weight_data();
142 for (size_type i = 0; i != N; ++i)
143 bptr[i] = lwptr[i] + first[i];
144 double lmax_weight = bptr[0];
145 for (size_type i = 0; i != N; ++i)
146 if (lmax_weight < bptr[i])
147 lmax_weight = bptr[i];
148 double gmax_weight = 0;
149 ::boost::mpi::all_reduce(world_, lmax_weight, gmax_weight,
150 ::boost::mpi::maximum<double>());
151 for (size_type i = 0; i != N; ++i)
152 bptr[i] -= gmax_weight;
153 for (size_type i = 0; i != N; ++i)
154 bptr[i] = exp(bptr[i]);
156 const double *
const wptr = this->weight_data();
157 for (size_type i = 0; i != N; ++i)
158 bptr[i] = wptr[i] * first[i];
162 for (size_type i = 0; i != N; ++i)
165 ::boost::mpi::all_reduce(world_, lcoeff, gcoeff, std::plus<double>());
167 for (size_type i = 0; i != N; ++i)
171 for (size_type i = 0; i != N; ++i)
172 less += bptr[i] * bptr[i];
174 ::boost::mpi::all_reduce(world_, less, gess, std::plus<double>());
183 const size_type N =
static_cast<size_type
>(this->size());
184 const double *bptr = first;
185 const double *
const wptr = this->weight_data();
186 std::vector<double, AlignedAllocator<double> > buffer;
189 double *
const cptr = &buffer[0];
190 for (size_type i = 0; i != N; ++i)
191 cptr[i] = exp(first[i]);
197 for (size_type i = 0; i != N; ++i) {
198 double wb = wptr[i] * bptr[i];
200 lbelow += wb * bptr[i];
204 ::boost::mpi::all_reduce(world_, labove, gabove, std::plus<double>());
205 ::boost::mpi::all_reduce(world_, lbelow, gbelow, std::plus<double>());
207 return gabove * gabove / gbelow;
212 ::boost::mpi::communicator world_;
213 size_type resample_size_;
214 mutable std::vector<double> resample_weight_;
215 mutable std::vector<double> weight_;
216 mutable std::vector<std::vector<double> > weight_all_;
218 void gather_resample_weight ()
const
220 weight_.resize(this->size());
221 this->read_weight(&weight_[0]);
222 if (world_.rank() == 0)
223 ::boost::mpi::gather(world_, weight_, weight_all_, 0);
225 ::boost::mpi::gather(world_, weight_, 0);
231 template <
typename BaseState,
typename ID>
243 ::
boost::mpi::comm_duplicate),
244 offset_(0), global_size_(0), size_equal_(true),
245 copy_tag_(::
boost::mpi::environment::max_tag())
247 ::boost::mpi::all_gather(world_, N, size_all_);
248 const std::size_t R =
static_cast<std::size_t
>(world_.rank());
249 const std::size_t
S =
static_cast<std::size_t
>(world_.size());
250 for (std::size_t i = 0; i != R; ++i) {
251 offset_ += size_all_[i];
252 global_size_ += size_all_[i];
253 size_equal_ = size_equal_ && N == size_all_[i];
255 for (std::size_t i = R; i != S; ++i) {
256 global_size_ += size_all_[i];
257 size_equal_ = size_equal_ && N == size_all_[i];
319 template <
typename IntType>
320 void copy (size_type N,
const IntType *copy_from)
324 copy_pre_processor_dispatch(has_copy_pre_processor_<BaseState>());
325 copy_from_.resize(N);
326 if (world_.rank() == 0)
327 std::copy(copy_from, copy_from + N, copy_from_.begin());
328 ::boost::mpi::broadcast(world_, copy_from_, 0);
331 copy_post_processor_dispatch(has_copy_post_processor_<BaseState>());
335 const ::boost::mpi::communicator &
world ()
const {
return world_;}
342 size_type
offset ()
const {
return offset_;}
349 return static_cast<int>(global_id / this->size());
352 size_type g = size_all_[0];
353 while (g <= global_id) {
358 return static_cast<int>(r);
363 {
return global_id >= offset_ && global_id < this->size() + offset_;}
371 this->size() *
static_cast<size_type
>(
rank(global_id));
375 size_type g = size_all_[0];
376 while (g <= global_id) {
382 return global_id - g;
418 std::vector<std::pair<int, size_type> > ©_recv,
419 std::vector<std::pair<int, size_type> > ©_send)
423 const int rank_this = world_.rank();
425 copy_from_this_.resize(this->size());
426 const size_type *first = copy_from + offset_;
427 for (size_type to = 0; to != this->size(); ++to, ++first) {
428 size_type from = *first;
429 copy_from_this_[to] =
432 BaseState::copy(this->size(), ©_from_this_[0]);
436 for (size_type to = 0; to != N; ++to, ++copy_from) {
437 size_type from = *copy_from;
438 int rank_recv =
rank(to);
439 int rank_send =
rank(from);
442 if (rank_this == rank_recv && rank_this == rank_send) {
444 }
else if (rank_this == rank_recv) {
445 copy_recv.push_back(std::make_pair(rank_send, id_recv));
446 }
else if (rank_this == rank_send) {
447 copy_send.push_back(std::make_pair(rank_recv, id_send));
457 const std::vector<std::pair<int, size_type> > ©_recv,
458 const std::vector<std::pair<int, size_type> > ©_send)
460 const int rank_this = world_.rank();
461 for (
int r = 0; r != world_.size(); ++r) {
462 if (rank_this == r) {
463 for (std::size_t i = 0; i != copy_recv.size(); ++i) {
464 world_.recv(copy_recv[i].first, copy_tag_, pack_recv_);
465 #if VSMC_HAS_CXX11_RVALUE_REFERENCES
466 this->state_unpack(copy_recv[i].second,
469 this->state_unpack(copy_recv[i].second,
474 for (std::size_t i = 0; i != copy_send.size(); ++i) {
475 if (copy_send[i].first == r) {
476 pack_send_ = this->state_pack(copy_send[i].second);
477 world_.send(copy_send[i].first, copy_tag_, pack_send_);
486 ::boost::mpi::communicator world_;
488 size_type global_size_;
490 std::vector<size_type> size_all_;
492 std::vector<size_type> copy_from_;
493 std::vector<size_type> copy_from_this_;
494 std::vector<std::pair<int, size_type> > copy_recv_;
495 std::vector<std::pair<int, size_type> > copy_send_;
496 typename BaseState::state_pack_type pack_recv_;
497 typename BaseState::state_pack_type pack_send_;
502 void copy_pre_processor_dispatch (cxx11::
true_type)
503 {BaseState::copy_pre_processor();}
508 {BaseState::copy_post_processor();}
515 #endif // VSMC_MPI_BACKEND_MPI_HPP
double compute_cess(const double *first, bool use_log) const
WeightSetBase::size_type size_type
#define VSMC_RUNTIME_ASSERT_MPI_BACKEND_MPI_COPY_SIZE_MISMATCH
bool is_local(size_type global_id) const
Given a global particle id check if it is on this node
size_type offset() const
The number of particles on nodes with ranks less than the rank of this node.
void copy(size_type N, const IntType *copy_from)
Copy particles.
#define VSMC_DEFINE_METHOD_CHECKER(name, RT, Args)
size_type resample_size() const
integral_constant< bool, false > false_type
WeightSetMPI(size_type N)
T & get(Array< T, N > &ary)
Array ADL of get.
remove_reference< T >::type && move(T &&t) noexcept
WeightSetMPI< typename traits::WeightSetTypeTrait< BaseState >::type, ID > weight_set_type
const ::boost::mpi::communicator & world() const
A duplicated MPI communicator for this weight set object.
size_type global_id(size_type local_id) const
Transfer a local particle id on this node into a global particle id.
#define VSMC_NULLPTR
nullptr
Particle::weight_set_type subtype using MPI.
integral_constant< bool, true > true_type
void copy_this_node(size_type N, const size_type *copy_from, std::vector< std::pair< int, size_type > > ©_recv, std::vector< std::pair< int, size_type > > ©_send)
Perform local copy.
const ::boost::mpi::communicator & world() const
A duplicated MPI communicator for this state value object.
internal::SizeTypeDispatch< T, value >::type type
int rank(size_type global_id) const
Given a global particle id return the rank of the node it belongs.
size_type global_size() const
The number of particles on all nodes.
int copy_tag() const
The MPI recv/send tag used by copy_inter_node
void copy_inter_node(const std::vector< std::pair< int, size_type > > ©_recv, const std::vector< std::pair< int, size_type > > ©_send)
Perform global copy.
double compute_ess(const double *first, bool use_log) const
traits::SizeTypeTrait< BaseState >::type size_type
void normalize_log_weight()
size_type local_id(size_type global_id) const
Transfer a global particle id into a local particle id (possibly not on this node, use rank to get the rank of its node)
const double * resample_weight_data() const
void read_resample_weight(double *first) const