deal.II version GIT relicensing-6842-g793a97d2aa 2026-10-02 14:00:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
data_out_stack.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 1999 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
15
18
19#include <deal.II/fe/fe.h>
21
23
25
27#include <deal.II/lac/vector.h>
28
30
31#include <sstream>
32
34
35
36template <int dim, int spacedim>
37std::size_t
43
44
45
46template <int dim, int spacedim>
47void
49 const double dp)
50{
51 parameter = p;
52 parameter_step = dp;
53
54 // check whether the user called finish_parameter_value() at the end of the
55 // previous parameter step
56 //
57 // this is to prevent serious waste of memory
58 for (typename std::vector<DataVector>::const_iterator i = dof_data.begin();
59 i != dof_data.end();
60 ++i)
61 Assert(i->data.empty(), ExcDataNotCleared());
62 for (typename std::vector<DataVector>::const_iterator i = cell_data.begin();
63 i != cell_data.end();
64 ++i)
65 Assert(i->data.empty(), ExcDataNotCleared());
66}
67
68
69template <int dim, int spacedim>
70void
76
77
78template <int dim, int spacedim>
79void
81 const VectorType vector_type)
82{
83 std::vector<std::string> names;
84 names.push_back(name);
85 declare_data_vector(names, vector_type);
86}
87
88
89template <int dim, int spacedim>
90void
92 const std::vector<std::string> &names,
93 const VectorType vector_type)
94{
95 if constexpr (running_in_debug_mode())
96 {
97 // make sure this function is
98 // not called after some parameter
99 // values have already been
100 // processed
102
103 // also make sure that no name is
104 // used twice
105 for (const auto &name : names)
106 {
107 for (const auto &data_set : dof_data)
108 for (const auto &data_set_name : data_set.names)
109 Assert(name != data_set_name, ExcNameAlreadyUsed(name));
110
111 for (const auto &data_set : cell_data)
112 for (const auto &data_set_name : data_set.names)
113 Assert(name != data_set_name, ExcNameAlreadyUsed(name));
114 }
115 }
116
117 switch (vector_type)
118 {
119 case dof_vector:
120 dof_data.emplace_back();
121 dof_data.back().names = names;
122 break;
123
124 case cell_vector:
125 cell_data.emplace_back();
126 cell_data.back().names = names;
127 break;
128 }
129}
130
131
132template <int dim, int spacedim>
133template <typename number>
134void
136 const std::string &name)
137{
138 const unsigned int n_components = dof_handler->get_fe(0).n_components();
139
140 std::vector<std::string> names;
141 // if only one component or vector
142 // is cell vector: we only need one
143 // name
144 if ((n_components == 1) ||
145 (vec.size() == dof_handler->get_triangulation().n_active_cells()))
146 {
147 names.resize(1, name);
148 }
149 else
150 // otherwise append _i to the
151 // given name
152 {
153 names.resize(n_components);
154 for (unsigned int i = 0; i < n_components; ++i)
155 {
156 std::ostringstream namebuf;
157 namebuf << '_' << i;
158 names[i] = name + namebuf.str();
159 }
160 }
161
162 add_data_vector(vec, names);
163}
164
165
166template <int dim, int spacedim>
167template <typename number>
168void
170 const Vector<number> &vec,
171 const std::vector<std::string> &names)
172{
173 Assert(dof_handler != nullptr,
175 // either cell data and one name,
176 // or dof data and n_components names
177 Assert(((vec.size() == dof_handler->get_triangulation().n_active_cells()) &&
178 (names.size() == 1)) ||
179 ((vec.size() == dof_handler->n_dofs()) &&
180 (names.size() == dof_handler->get_fe(0).n_components())),
182 names.size(), dof_handler->get_fe(0).n_components()));
183 for (const auto &name : names)
184 {
185 Assert(name.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
186 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
187 "0123456789_<>()") == std::string::npos,
189 name,
190 name.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
191 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
192 "0123456789_<>()")));
193 }
194
195 if (vec.size() == dof_handler->n_dofs())
196 {
197 typename std::vector<DataVector>::iterator data_vector = dof_data.begin();
198 for (; data_vector != dof_data.end(); ++data_vector)
199 if (data_vector->names == names)
200 {
201 data_vector->data.reinit(vec.size());
202 std::copy(vec.begin(), vec.end(), data_vector->data.begin());
203 return;
204 }
205
206 // ok. not found. there is a
207 // slight chance that
208 // n_dofs==n_cells, so only
209 // bomb out if the next if
210 // statement will not be run
211 if (dof_handler->n_dofs() !=
212 dof_handler->get_triangulation().n_active_cells())
213 Assert(false, ExcVectorNotDeclared(names[0]));
214 }
215
216 // search cell data
217 if ((vec.size() != dof_handler->n_dofs()) ||
218 (dof_handler->n_dofs() ==
219 dof_handler->get_triangulation().n_active_cells()))
220 {
221 typename std::vector<DataVector>::iterator data_vector =
222 cell_data.begin();
223 for (; data_vector != cell_data.end(); ++data_vector)
224 if (data_vector->names == names)
225 {
226 data_vector->data.reinit(vec.size());
227 std::copy(vec.begin(), vec.end(), data_vector->data.begin());
228 return;
229 }
230 Assert(false, ExcVectorNotDeclared(names[0]));
231 }
232
233 // we have either return or Assert
234 // statements above, so shouldn't
235 // get here!
237}
238
239
240template <int dim, int spacedim>
241void
242DataOutStack<dim, spacedim>::build_patches(const unsigned int nnnn_subdivisions)
243{
244 // this is mostly copied from the
245 // DataOut class
246 unsigned int n_subdivisions =
247 (nnnn_subdivisions != 0) ? nnnn_subdivisions : this->default_subdivisions;
248
249 Assert(n_subdivisions >= 1,
251 n_subdivisions));
252 Assert(dof_handler != nullptr,
254
256
257 const unsigned int n_components = dof_handler->get_fe(0).n_components();
258 const unsigned int n_datasets =
259 dof_data.size() * n_components + cell_data.size();
260
261 // first count the cells we want to
262 // create patches of and make sure
263 // there is enough memory for that
264 unsigned int n_patches = 0;
266 dof_handler->begin_active();
267 cell != dof_handler->end();
268 ++cell)
269 ++n_patches;
270
271
272 // before we start the loop:
273 // create a quadrature rule that
274 // actually has the points on this
275 // patch, and an object that
276 // extracts the data on each
277 // cell to these points
278 const QTrapezoid<1> q_trapez;
279 const QIterated<dim> patch_points(q_trapez, n_subdivisions);
280
281 // create collection objects from
282 // single quadratures,
283 // and finite elements. if we have
284 // an hp-DoFHandler,
285 // dof_handler.get_fe() returns a
286 // collection of which we do a
287 // shallow copy instead
288 const hp::QCollection<dim> q_collection(patch_points);
289 const hp::FECollection<dim> &fe_collection = dof_handler->get_fe_collection();
290
291 hp::FEValues<dim> x_fe_patch_values(fe_collection,
292 q_collection,
294
295 const unsigned int n_q_points = patch_points.size();
296 std::vector<double> patch_values(n_q_points);
297 std::vector<Vector<double>> patch_values_system(n_q_points,
298 Vector<double>(n_components));
299
300 // add the required number of
301 // patches. first initialize a template
302 // patch with n_q_points (in the plane
303 // of the cells) times n_subdivisions+1 (in
304 // the time direction) points
306 default_patch.n_subdivisions = n_subdivisions;
307 default_patch.reference_cell = ReferenceCells::get_hypercube<dim + 1>();
308 default_patch.data.reinit(n_datasets, n_q_points * (n_subdivisions + 1));
309 patches.insert(patches.end(), n_patches, default_patch);
310
311 // now loop over all cells and
312 // actually create the patches
313 typename std::vector<
315 patches.begin() + (patches.size() - n_patches);
316 unsigned int cell_number = 0;
318 dof_handler->begin_active();
319 cell != dof_handler->end();
320 ++cell, ++patch, ++cell_number)
321 {
322 Assert(cell->is_locally_owned(), ExcNotImplemented());
323
324 Assert(patch != patches.end(), ExcInternalError());
325
326 // first fill in the vertices of the patch
327
328 // Patches are organized such
329 // that the parameter direction
330 // is the last
331 // coordinate. Thus, vertices
332 // are two copies of the space
333 // patch, one at parameter-step
334 // and one at parameter.
335 switch (dim)
336 {
337 case 1:
338 patch->vertices[0] =
339 Point<dim + 1>(cell->vertex(0)[0], parameter - parameter_step);
340 patch->vertices[1] =
341 Point<dim + 1>(cell->vertex(1)[0], parameter - parameter_step);
342 patch->vertices[2] = Point<dim + 1>(cell->vertex(0)[0], parameter);
343 patch->vertices[3] = Point<dim + 1>(cell->vertex(1)[0], parameter);
344 break;
345
346 case 2:
347 patch->vertices[0] = Point<dim + 1>(cell->vertex(0)[0],
348 cell->vertex(0)[1],
350 patch->vertices[1] = Point<dim + 1>(cell->vertex(1)[0],
351 cell->vertex(1)[1],
353 patch->vertices[2] = Point<dim + 1>(cell->vertex(2)[0],
354 cell->vertex(2)[1],
356 patch->vertices[3] = Point<dim + 1>(cell->vertex(3)[0],
357 cell->vertex(3)[1],
359 patch->vertices[4] =
360 Point<dim + 1>(cell->vertex(0)[0], cell->vertex(0)[1], parameter);
361 patch->vertices[5] =
362 Point<dim + 1>(cell->vertex(1)[0], cell->vertex(1)[1], parameter);
363 patch->vertices[6] =
364 Point<dim + 1>(cell->vertex(2)[0], cell->vertex(2)[1], parameter);
365 patch->vertices[7] =
366 Point<dim + 1>(cell->vertex(3)[0], cell->vertex(3)[1], parameter);
367 break;
368
369 default:
371 }
372
373
374 // now fill in the data values.
375 // note that the required order is
376 // with highest coordinate running
377 // fastest, we need to enter each
378 // value (n_subdivisions+1) times
379 // in succession
380 if (n_datasets > 0)
381 {
382 x_fe_patch_values.reinit(cell);
383 const FEValues<dim> &fe_patch_values =
384 x_fe_patch_values.get_present_fe_values();
385
386 // first fill dof_data
387 for (unsigned int dataset = 0; dataset < dof_data.size(); ++dataset)
388 {
389 if (n_components == 1)
390 {
391 fe_patch_values.get_function_values(dof_data[dataset].data,
392 patch_values);
393 for (unsigned int i = 0; i < n_subdivisions + 1; ++i)
394 for (unsigned int q = 0; q < n_q_points; ++q)
395 patch->data(dataset, q + n_q_points * i) =
396 patch_values[q];
397 }
398 else
399 // system of components
400 {
401 fe_patch_values.get_function_values(dof_data[dataset].data,
402 patch_values_system);
403 for (unsigned int component = 0; component < n_components;
404 ++component)
405 for (unsigned int i = 0; i < n_subdivisions + 1; ++i)
406 for (unsigned int q = 0; q < n_q_points; ++q)
407 patch->data(dataset * n_components + component,
408 q + n_q_points * i) =
409 patch_values_system[q](component);
410 }
411 }
412
413 // then do the cell data
414 for (unsigned int dataset = 0; dataset < cell_data.size(); ++dataset)
415 {
416 const double value = cell_data[dataset].data(cell_number);
417 for (unsigned int q = 0; q < n_q_points; ++q)
418 for (unsigned int i = 0; i < n_subdivisions + 1; ++i)
419 patch->data(dataset + dof_data.size() * n_components,
420 q * (n_subdivisions + 1) + i) = value;
421 }
422 }
423 }
424}
425
426
427template <int dim, int spacedim>
428void
430{
431 // release lock on dof handler
432 dof_handler = nullptr;
433 for (typename std::vector<DataVector>::iterator i = dof_data.begin();
434 i != dof_data.end();
435 ++i)
436 i->data.reinit(0);
437
438 for (typename std::vector<DataVector>::iterator i = cell_data.begin();
439 i != cell_data.end();
440 ++i)
441 i->data.reinit(0);
442}
443
444
445
446template <int dim, int spacedim>
447std::size_t
458
459
460
461template <int dim, int spacedim>
462const std::vector<
469
470
471
472template <int dim, int spacedim>
473std::vector<std::string>
475{
476 std::vector<std::string> names;
477 for (typename std::vector<DataVector>::const_iterator dataset =
478 dof_data.begin();
479 dataset != dof_data.end();
480 ++dataset)
481 names.insert(names.end(), dataset->names.begin(), dataset->names.end());
482 for (typename std::vector<DataVector>::const_iterator dataset =
483 cell_data.begin();
484 dataset != cell_data.end();
485 ++dataset)
486 names.insert(names.end(), dataset->names.begin(), dataset->names.end());
487
488 return names;
489}
490
491
492
493// explicit instantiations
494#include "numerics/data_out_stack.inst"
495
496
unsigned int default_subdivisions
void validate_dataset_names() const
std::size_t memory_consumption() const
ObserverPointer< const DoFHandler< dim, spacedim >, DataOutStack< dim, spacedim > > dof_handler
void declare_data_vector(const std::string &name, const VectorType vector_type)
virtual std::vector< std::string > get_dataset_names() const override
std::vector< DataVector > cell_data
void new_parameter_value(const double parameter_value, const double parameter_step)
std::vector< DataVector > dof_data
void finish_parameter_value()
void attach_dof_handler(const DoFHandler< dim, spacedim > &dof_handler)
double parameter_step
void build_patches(const unsigned int n_subdivisions=0)
std::vector<::DataOutBase::Patch< patch_dim, patch_spacedim > > patches
virtual const std::vector< ::DataOutBase::Patch< DataOutStack< dim, spacedim >::patch_dim, DataOutStack< dim, spacedim >::patch_spacedim > > & get_patches() const override
void add_data_vector(const Vector< number > &vec, const std::string &name)
void get_function_values(const ReadVector< Number > &fe_function, std::vector< Number > &values) const
Definition point.h:111
virtual size_type size() const override
iterator end()
iterator begin()
const FEValuesType & get_present_fe_values() const
Definition fe_values.h:693
void reinit(const TriaIterator< DoFCellAccessor< dim, spacedim, lda > > &cell, const unsigned int q_index=numbers::invalid_unsigned_int, const unsigned int mapping_index=numbers::invalid_unsigned_int, const unsigned int fe_index=numbers::invalid_unsigned_int)
Definition fe_values.cc:294
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcInvalidNumberOfSubdivisions(int arg1)
static ::ExceptionBase & ExcDataNotCleared()
static ::ExceptionBase & ExcDataAlreadyAdded()
static ::ExceptionBase & ExcVectorNotDeclared(std::string arg1)
static ::ExceptionBase & ExcNotImplemented()
static ::ExceptionBase & ExcInvalidCharacter(std::string arg1, std::size_t arg2)
static ::ExceptionBase & ExcInvalidNumberOfNames(int arg1, int arg2)
#define Assert(cond, exc)
static ::ExceptionBase & ExcNoDoFHandlerSelected()
static ::ExceptionBase & ExcNameAlreadyUsed(std::string arg1)
static ::ExceptionBase & ExcInternalError()
typename ActiveSelector::active_cell_iterator active_cell_iterator
@ update_values
Shape function values.
std::vector< index_type > data
Definition mpi.cc:734
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
Table< 2, float > data
ReferenceCell< dim > reference_cell
unsigned int n_subdivisions
std::size_t memory_consumption() const
std::vector< std::string > names