/home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/discretization/common/solution_view.hh Source File#

DiFfRG: /home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/discretization/common/solution_view.hh Source File
DiFfRG
Discretization Framework for functional Renormalization Group flows
solution_view.hh
Go to the documentation of this file.
1#pragma once
2
3// external libraries
4#include <deal.II/base/index_set.h>
5#include <deal.II/lac/vector.h>
6#ifdef DEAL_II_WITH_PETSC
7#include <deal.II/lac/petsc_vector.h>
8#endif
9
10// DiFfRG
12#include <DiFfRG/common/mpi.hh>
13
14// std
15#include <stdexcept>
16#include <vector>
17
18namespace DiFfRG
19{
47 template <typename VectorType> class SolutionView
48 {
49 public:
51 using size_type = dealii::types::global_dof_index;
52
53 SolutionView() = default;
54
58 void reinit(const dealii::IndexSet &, const dealii::IndexSet &, MPI_Comm) {}
59
63 void refresh(const VectorType &owned) { source = &owned; }
64
65 const VectorType &get() const
66 {
67 if (source == nullptr)
68 throw std::runtime_error("SolutionView::get() before refresh(): the view holds no solution.");
69 return *source;
70 }
71 operator const VectorType &() const { return get(); }
72
73 NumberType operator[](const size_type i) const { return get()[i]; }
74 size_type size() const { return get().size(); }
75
76 private:
77 const VectorType *source = nullptr;
78 };
79
80#ifdef DEAL_II_WITH_PETSC
105 template <> class SolutionView<dealii::PETScWrappers::MPI::Vector>
106 {
107 static_assert(std::is_same_v<PetscScalar, double>,
108 "SolutionView gathers with MPI_DOUBLE; PETSc must be built --with-scalar-type=real "
109 "and --with-precision=double, which is what the bundled recipe pins.");
110
111 public:
112 using VectorType = dealii::PETScWrappers::MPI::Vector;
113 using NumberType = VectorType::value_type;
114 using size_type = dealii::types::global_dof_index;
115
116 SolutionView() = default;
117
125 void reinit(const dealii::IndexSet &locally_owned, const dealii::IndexSet &ghost, MPI_Comm comm)
126 {
127 (void)ghost;
128 communicator = comm;
129 n_global = locally_owned.size();
130 const int n_ranks = static_cast<int>(MPI::size(comm));
131
132 counts.assign(n_ranks, 0);
133 displacements.assign(n_ranks, 0);
134 local_count = static_cast<int>(locally_owned.n_elements());
135
136 const int ierr = MPI_Allgather(&local_count, 1, MPI_INT, counts.data(), 1, MPI_INT, comm);
137 if (ierr != MPI_SUCCESS) throw std::runtime_error("SolutionView::reinit(): MPI_Allgather failed.");
138
139 std::size_t total = 0;
140 for (int r = 0; r < n_ranks; ++r) {
141 displacements[r] = static_cast<int>(total);
142 total += static_cast<std::size_t>(counts[r]);
143 }
144 // A PETSc MPI vector requires an ascending, one-to-one partition anyway (deal.II asserts it,
145 // and the assert is compiled out in Release), so the owned blocks are contiguous and in rank
146 // order -- which is exactly the Allgatherv layout. If that ever stops holding, the gather
147 // would silently permute the solution, so check it rather than trust it.
148 if (total != n_global)
149 throw std::runtime_error("SolutionView::reinit(): the locally owned sets do not partition "
150 "the index range exactly once; a gathered replica would be wrong.");
151
152 if (n_global > 0) replica.reinit(dealii::complete_index_set(n_global), MPI_COMM_SELF);
153 initialized = true;
154 is_empty = (n_global == 0);
155 }
156
163 void refresh(const VectorType &owned)
164 {
165 if (!initialized)
166 throw std::runtime_error("SolutionView::refresh() before reinit(): the gather plan is not known yet.");
167
168 // An unsized source is a legitimate "nothing to show" -- the residual is optional in the
169 // output path. Hold the empty vector separately instead of gathering it.
170 is_empty = (owned.size() == 0) || (n_global == 0);
171 if (is_empty) return;
172
173 if (owned.size() != n_global || static_cast<int>(owned.locally_owned_size()) != local_count)
174 throw std::runtime_error("SolutionView::refresh(): the vector does not match the layout "
175 "reinit() was given. Rebuild the view after a mesh change.");
176
177 const PetscScalar *src = nullptr;
178 PetscScalar *dst = nullptr;
179 Vec src_vec = static_cast<Vec>(owned);
180 Vec dst_vec = static_cast<Vec>(replica);
181
182 if (VecGetArrayRead(src_vec, &src) != 0) throw std::runtime_error("SolutionView::refresh(): VecGetArrayRead.");
183 if (VecGetArray(dst_vec, &dst) != 0) throw std::runtime_error("SolutionView::refresh(): VecGetArray.");
184
185 const int ierr = MPI_Allgatherv(src, local_count, MPI_DOUBLE, dst, counts.data(), displacements.data(),
186 MPI_DOUBLE, communicator);
187
188 VecRestoreArray(dst_vec, &dst);
189 VecRestoreArrayRead(src_vec, &src);
190
191 if (ierr != MPI_SUCCESS) throw std::runtime_error("SolutionView::refresh(): MPI_Allgatherv failed.");
192 }
193
194 const VectorType &get() const
195 {
196 if (!initialized) throw std::runtime_error("SolutionView::get() before reinit(): the view holds no solution.");
197 return is_empty ? empty : replica;
198 }
199 operator const VectorType &() const { return get(); }
200
201 NumberType operator[](const size_type i) const { return get()(i); }
202 size_type size() const { return get().size(); }
203
204 private:
205 VectorType replica;
206 VectorType empty;
207 MPI_Comm communicator = MPI_COMM_SELF;
208 std::vector<int> counts;
209 std::vector<int> displacements;
210 int local_count = 0;
211 size_type n_global = 0;
212 bool initialized = false;
213 bool is_empty = true;
214 };
215#endif
216} // namespace DiFfRG
A read-only, fully-replicated view of the solution.
Definition solution_view.hh:48
NumberType operator[](const size_type i) const
Definition solution_view.hh:73
const VectorType * source
Definition solution_view.hh:77
get_type::NumberType< VectorType > NumberType
Definition solution_view.hh:50
void refresh(const VectorType &owned)
Make the view reflect owned.
Definition solution_view.hh:63
dealii::types::global_dof_index size_type
Definition solution_view.hh:51
void reinit(const dealii::IndexSet &, const dealii::IndexSet &, MPI_Comm)
Establish the layout. No-op for the serial policy.
Definition solution_view.hh:58
size_type size() const
Definition solution_view.hh:74
const VectorType & get() const
Definition solution_view.hh:65
All compile-time knowledge about which linear algebra types DiFfRG uses.
uint size(MPI_Comm comm)
typename internal::_NumberType< VectorType >::value NumberType
Definition linear_algebra.hh:152
Definition complex_math.hh:10