Reference documentation for deal.II version Git 7026f387cc 2019-10-15 14:19:01 -0400
\(\newcommand{\dealcoloneq}{\mathrel{\vcenter{:}}=}\)
number_cache.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/memory_consumption.h>
17 #include <deal.II/base/mpi.h>
18 
19 #include <deal.II/dofs/number_cache.h>
20 
21 #include <numeric>
22 
23 
24 DEAL_II_NAMESPACE_OPEN
25 
26 namespace internal
27 {
28  namespace DoFHandlerImplementation
29  {
31  : n_global_dofs(0)
32  , n_locally_owned_dofs(0)
33  {}
34 
35 
36 
38  : n_global_dofs(n_global_dofs)
39  , n_locally_owned_dofs(n_global_dofs)
40  , locally_owned_dofs(complete_index_set(n_global_dofs))
41  , n_locally_owned_dofs_per_processor(1, n_global_dofs)
42  , locally_owned_dofs_per_processor(1, complete_index_set(n_global_dofs))
43  {}
44 
45 
46 
48  const std::vector<IndexSet> &locally_owned_dofs_per_processor,
49  const unsigned int my_rank)
50  : locally_owned_dofs_per_processor(locally_owned_dofs_per_processor)
51  {
52  const unsigned int n_procs = locally_owned_dofs_per_processor.size();
53 
54  // compress IndexSet representation before using it for anything else
55  for (unsigned int p = 0; p < n_procs; ++p)
56  locally_owned_dofs_per_processor[p].compress();
57 
58  n_locally_owned_dofs_per_processor.resize(n_procs);
59  for (unsigned int p = 0; p < n_procs; ++p)
61  locally_owned_dofs_per_processor[p].n_elements();
63  locally_owned_dofs = locally_owned_dofs_per_processor[my_rank];
64 
65 
67  std::accumulate(n_locally_owned_dofs_per_processor.begin(),
70  }
71 
72 
73 
74  void
76  {
77  n_global_dofs = 0;
82  }
83 
84 
85 
86  std::vector<types::global_dof_index>
88  const MPI_Comm mpi_communicator) const
89  {
90  const unsigned int n_procs =
92  Utilities::MPI::n_mpi_processes(mpi_communicator) :
93  1;
94  if (n_global_dofs == 0)
95  return std::vector<types::global_dof_index>();
96  else if (n_locally_owned_dofs_per_processor.empty() == false)
97  {
100  }
101  else
102  {
103  std::vector<types::global_dof_index> result(n_procs,
105 #ifdef DEAL_II_WITH_MPI
106  if (n_procs > 1)
107  MPI_Allgather(DEAL_II_MPI_CONST_CAST(&n_locally_owned_dofs),
108  1,
109  DEAL_II_DOF_INDEX_MPI_TYPE,
110  result.data(),
111  1,
112  DEAL_II_DOF_INDEX_MPI_TYPE,
113  mpi_communicator);
114 #endif
115  return result;
116  }
117  }
118 
119 
120 
121  std::vector<IndexSet>
123  const MPI_Comm mpi_communicator) const
124  {
126  const unsigned int n_procs =
128  Utilities::MPI::n_mpi_processes(mpi_communicator) :
129  1;
130  if (n_global_dofs == 0)
131  return std::vector<IndexSet>();
132  else if (locally_owned_dofs_per_processor.empty() == false)
133  {
136  }
137  else
138  {
139  std::vector<IndexSet> locally_owned_dofs_per_processor(
140  n_procs, locally_owned_dofs);
141 
142 #ifdef DEAL_II_WITH_MPI
143  if (n_procs > 1)
144  {
145  // this step is substantially more complicated because indices
146  // might be distributed arbitrarily among the processors. Here we
147  // have to serialize the IndexSet objects and shop them across the
148  // network.
149  std::vector<char> my_data;
150  {
151 # ifdef DEAL_II_WITH_ZLIB
152 
153  boost::iostreams::filtering_ostream out;
154  out.push(boost::iostreams::gzip_compressor(
155  boost::iostreams::gzip_params(
156  boost::iostreams::gzip::best_speed)));
157  out.push(boost::iostreams::back_inserter(my_data));
158 
159  boost::archive::binary_oarchive archive(out);
160 
161  archive << locally_owned_dofs;
162  out.flush();
163 # else
164  std::ostringstream out;
165  boost::archive::binary_oarchive archive(out);
166  archive << locally_owned_dofs;
167  const std::string &s = out.str();
168  my_data.reserve(s.size());
169  my_data.assign(s.begin(), s.end());
170 # endif
171  }
172 
173  // determine maximum size of IndexSet
174  const unsigned int max_size =
175  Utilities::MPI::max(my_data.size(), mpi_communicator);
176 
177  // as the MPI_Allgather call will be reading max_size elements,
178  // and as this may be past the end of my_data, we need to increase
179  // the size of the local buffer. This is filled with zeros.
180  my_data.resize(max_size);
181 
182  std::vector<char> buffer(max_size * n_procs);
183  const int ierr = MPI_Allgather(my_data.data(),
184  max_size,
185  MPI_BYTE,
186  buffer.data(),
187  max_size,
188  MPI_BYTE,
189  mpi_communicator);
190  AssertThrowMPI(ierr);
191 
192  for (unsigned int i = 0; i < n_procs; ++i)
193  if (i == Utilities::MPI::this_mpi_process(mpi_communicator))
194  locally_owned_dofs_per_processor[i] = locally_owned_dofs;
195  else
196  {
197  // copy the data previously received into a stringstream
198  // object and then read the IndexSet from it
199  std::string decompressed_buffer;
200 
201  // first decompress the buffer
202  {
203 # ifdef DEAL_II_WITH_ZLIB
204 
205  boost::iostreams::filtering_ostream decompressing_stream;
206  decompressing_stream.push(
207  boost::iostreams::gzip_decompressor());
208  decompressing_stream.push(
209  boost::iostreams::back_inserter(decompressed_buffer));
210 
211  decompressing_stream.write(&buffer[i * max_size],
212  max_size);
213 # else
214  decompressed_buffer.assign(&buffer[i * max_size],
215  max_size);
216 # endif
217  }
218 
219  // then restore the object from the buffer
220  std::istringstream in(decompressed_buffer);
221  boost::archive::binary_iarchive archive(in);
222 
223  archive >> locally_owned_dofs_per_processor[i];
224  }
225  }
226 #endif
228  }
229  }
230 
231 
232  std::size_t
234  {
242  }
243  } // namespace DoFHandlerImplementation
244 } // namespace internal
245 
246 DEAL_II_NAMESPACE_CLOSE
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1567
size_type size() const
Definition: index_set.h:1600
void clear()
Definition: index_set.h:1576
std::vector< types::global_dof_index > get_n_locally_owned_dofs_per_processor(const MPI_Comm mpi_communicator) const
Definition: number_cache.cc:87
std::vector< types::global_dof_index > n_locally_owned_dofs_per_processor
Definition: number_cache.h:169
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:74
std::vector< IndexSet > get_locally_owned_dofs_per_processor(const MPI_Comm mpi_communicator) const
unsigned int global_dof_index
Definition: types.h:89
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1695
std::vector< IndexSet > locally_owned_dofs_per_processor
Definition: number_cache.h:180
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:85
void write(std::ostream &out) const
Definition: index_set.cc:405
bool job_supports_mpi()
Definition: mpi.cc:810
T max(const T &t, const MPI_Comm &mpi_communicator)
std::enable_if< std::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)