https://mooseframework.inl.gov
StochasticToolsUtils.h
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #pragma once
11 
12 #include "MooseUtils.h"
13 #include "libmesh/communicator.h"
14 
15 namespace StochasticTools
16 {
17 
21 template <typename T>
23 {
24  static constexpr bool value = false;
25 };
26 template <typename T>
27 struct canDefaultGather<std::vector<T>>
28 {
29  static constexpr bool value = std::is_base_of<TIMPI::DataType, TIMPI::StandardType<T>>::value;
30 };
31 template <typename T>
33 {
34  static constexpr bool value = false;
35 };
36 template <typename T>
37 struct canStochasticGather<std::vector<T>>
38 {
39  static constexpr bool value = canStochasticGather<T>::value ||
40  std::is_base_of<TIMPI::DataType, TIMPI::StandardType<T>>::value ||
41  std::is_same<T, std::string>::value || std::is_same<T, bool>::value;
42 };
43 
44 /*
45  * Methods for gathering nested vectors
46  */
47 template <typename T>
48 void
50 {
51  ::mooseError("Cannot gather values of type ", MooseUtils::prettyCppType<T>());
52 }
53 template <typename T,
54  typename std::enable_if<canDefaultGather<std::vector<T>>::value, int>::type = 0>
55 void
57  processor_id_type root_id,
58  std::vector<T> & val)
59 {
60  comm.gather(root_id, val);
61 }
62 template <
63  typename T,
64  typename std::enable_if<canStochasticGather<std::vector<std::vector<T>>>::value, int>::type = 0>
65 void
67  processor_id_type root_id,
68  std::vector<std::vector<T>> & val)
69 {
70  // Get local vector sizes
71  std::size_t num_local_vecs = val.size();
72  std::vector<std::size_t> val_sizes;
73  val_sizes.reserve(num_local_vecs);
74  std::size_t num_local_vals = 0;
75  for (const auto & v : val)
76  {
77  val_sizes.push_back(v.size());
78  num_local_vals += v.size();
79  }
80 
81  // Flatten the local vector of vectors
82  std::vector<T> val_exp;
83  val_exp.reserve(num_local_vals);
84  for (auto & v : val)
85  std::copy(v.begin(), v.end(), std::back_inserter(val_exp));
86 
87  // Gather the vector sizes and the flattened vector
88  comm.gather(root_id, val_sizes);
89  stochasticGather(comm, root_id, val_exp);
90 
91  // Build the vector of vectors from the gathered flatten vector
92  if (comm.rank() == root_id)
93  {
94  val.resize(val_sizes.size());
95  std::size_t ind = num_local_vals;
96  for (std::size_t i = num_local_vecs; i < val_sizes.size(); ++i)
97  {
98  val[i].resize(val_sizes[i]);
99  std::move(val_exp.begin() + ind, val_exp.begin() + ind + val_sizes[i], val[i].begin());
100  ind += val_sizes[i];
101  }
102  }
103 }
104 // Gathering a vector of strings hasn't been implemented in libMesh, so just gonna do it the hard
105 // way
106 template <typename T>
107 void
109  processor_id_type root_id,
110  std::vector<std::basic_string<T>> & val)
111 {
112  std::vector<std::basic_string<T>> val_gath = val;
113  comm.allgather(val_gath);
114  if (comm.rank() == root_id)
115  val = std::move(val_gath);
116 }
117 // Gathering bool is weird
118 template <typename A>
119 void
121  processor_id_type root_id,
122  std::vector<bool, A> & val)
123 {
124  std::vector<unsigned short int> temp(val.size());
125  for (std::size_t i = 0; i < val.size(); ++i)
126  temp[i] = val[i] ? 1 : 0;
127  comm.gather(root_id, temp);
128  if (comm.rank() == root_id)
129  {
130  val.resize(temp.size());
131  for (std::size_t i = 0; i < temp.size(); ++i)
132  val[i] = temp[i] == 1;
133  }
134 }
135 
136 /*
137  * Methods for gathering nested vectors on all processors
138  */
139 template <typename T>
140 void
142 {
143  ::mooseError("Cannot gather values of type ", MooseUtils::prettyCppType<T>());
144 }
145 template <typename T,
146  typename std::enable_if<canDefaultGather<std::vector<T>>::value, int>::type = 0>
147 void
148 stochasticAllGather(const libMesh::Parallel::Communicator & comm, std::vector<T> & val)
149 {
150  comm.allgather(val);
151 }
152 template <
153  typename T,
154  typename std::enable_if<canStochasticGather<std::vector<std::vector<T>>>::value, int>::type = 0>
155 void
156 stochasticAllGather(const libMesh::Parallel::Communicator & comm, std::vector<std::vector<T>> & val)
157 {
158  // Get local vector sizes
159  std::size_t num_local_vecs = val.size();
160  std::vector<std::size_t> val_sizes;
161  val_sizes.reserve(num_local_vecs);
162  std::size_t num_local_vals = 0;
163  for (const auto & v : val)
164  {
165  val_sizes.push_back(v.size());
166  num_local_vals += v.size();
167  }
168 
169  // Flatten the local vector of vectors
170  std::vector<T> val_exp;
171  val_exp.reserve(num_local_vals);
172  for (auto & v : val)
173  std::copy(v.begin(), v.end(), std::back_inserter(val_exp));
174 
175  // Gather the vector sizes and the flattened vector
176  comm.allgather(val_sizes);
177  stochasticAllGather(comm, val_exp);
178 
179  // Build the vector of vectors from the gathered flatten vector
180  val.resize(val_sizes.size());
181  std::size_t ind = 0;
182  for (std::size_t i = 0; i < val_sizes.size(); ++i)
183  {
184  val[i].resize(val_sizes[i]);
185  std::move(val_exp.begin() + ind, val_exp.begin() + ind + val_sizes[i], val[i].begin());
186  ind += val_sizes[i];
187  }
188 }
189 // Gathering a vector of strings hasn't been implemented in libMesh, so just gonna do it the hard
190 // way
191 template <typename T>
192 void
194  std::vector<std::basic_string<T>> & val)
195 {
196  comm.allgather(val);
197 }
198 // Gathering bool is weird
199 template <typename A>
200 void
201 stochasticAllGather(const libMesh::Parallel::Communicator & comm, std::vector<bool, A> & val)
202 {
203  std::vector<unsigned short int> temp(val.size());
204  for (std::size_t i = 0; i < val.size(); ++i)
205  temp[i] = val[i] ? 1 : 0;
206  comm.allgather(temp);
207  val.resize(temp.size());
208  for (std::size_t i = 0; i < temp.size(); ++i)
209  val[i] = temp[i] == 1;
210 }
211 
212 /*
213  * Methods for sorting vectors of vectors with elements inplace. For example:
214  * {{7, 5, 2}, {3, 8, 6}, {9, 9, 1}} -> {{3, 5, 1}, {7, 8, 2}, {9, 9, 6}}
215  */
216 template <typename T>
217 void
218 inplaceSort(std::vector<T> & values)
219 {
220  std::sort(values.begin(), values.end());
221 }
222 template <typename T>
223 void
224 inplaceSort(std::vector<std::vector<T>> & values)
225 {
226  if (values.empty())
227  return;
228 
229  const std::size_t sz = values[0].size();
230  mooseAssert(std::find_if(values.begin(),
231  values.end(),
232  [&sz](const std::vector<T> & val)
233  { return val.size() != sz; }) == values.end(),
234  "All vectors must be same size to sort.");
235 
236  std::vector<T> vals(values.size());
237  for (const auto & i : make_range(sz))
238  {
239  for (const auto & k : index_range(values))
240  vals[k] = values[k][i];
241  inplaceSort(vals);
242  for (const auto & k : index_range(values))
243  values[k][i] = std::move(vals[k]);
244  }
245 }
246 
257 template <typename T>
258 std::vector<std::vector<T>>
259 reshapeVector(const std::vector<T> & vec, std::size_t n, bool row_major)
260 {
261  const auto nelem = vec.size();
262  const auto nrow = row_major ? nelem / n : n;
263  const auto ncol = row_major ? n : nelem / n;
264  if (nelem % n != 0)
265  ::mooseError(
266  "Reshaping dimensions (", nrow, ", ", ncol, ") does not match vector size (", nelem, ").");
267 
268  std::vector<std::vector<T>> mat(nrow, std::vector<T>(ncol));
269  for (const auto & i : make_range(nrow))
270  for (const auto & j : make_range(ncol))
271  {
272  const auto k = row_major ? (i * ncol + j) : (j * nrow + i);
273  mat[i][j] = vec[k];
274  }
275  return mat;
276 }
277 
278 } // StochasticTools namespace
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
std::vector< std::vector< T > > reshapeVector(const std::vector< T > &vec, std::size_t n, bool row_major)
Reshape a vector into matrix-like vector of vectors.
void gather(const unsigned int root_id, const T &send_data, std::vector< T, A > &recv) const
processor_id_type rank() const
uint8_t processor_id_type
Enum for batch type in stochastic tools MultiApp.
void stochasticGather(const libMesh::Parallel::Communicator &, processor_id_type, T &)
void inplaceSort(std::vector< T > &values)
Custom type trait that has a ::value of true for types that can be gathered.
static const std::string v
Definition: NS.h:84
IntRange< T > make_range(T beg, T end)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
void stochasticAllGather(const libMesh::Parallel::Communicator &, T &)
static const std::string k
Definition: NS.h:130
auto index_range(const T &sizable)