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_faces.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) 2000 - 2026 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#include <deal.II/fe/mapping.h>
22
23#include <deal.II/grid/tria.h>
25
27
29#include <deal.II/lac/vector.h>
30
32
34
35
36namespace internal
37{
38 namespace DataOutFacesImplementation
39 {
40 template <int dim, int spacedim>
42 const unsigned int n_datasets,
43 const unsigned int n_subdivisions,
44 const std::vector<unsigned int> &n_postprocessor_outputs,
45 const Mapping<dim, spacedim> &mapping,
46 const std::vector<
47 std::shared_ptr<::hp::FECollection<dim, spacedim>>>
48 &finite_elements,
49 const UpdateFlags update_flags)
50 : internal::DataOutImplementation::ParallelDataBase<dim, spacedim>(
51 n_datasets,
52 n_subdivisions,
53 n_postprocessor_outputs,
54 mapping,
55 finite_elements,
56 update_flags,
57 true)
58 {}
59
60
61
66 template <int dim, int spacedim>
67 void
71 &patch,
72 std::vector<
75 &patches)
76 {
77 patches.push_back(patch);
78 patches.back().patch_index = patches.size() - 1;
79 }
80 } // namespace DataOutFacesImplementation
81} // namespace internal
82
83
84
85template <int dim, int spacedim>
87 : surface_only(so)
88{}
89
90
91
92template <int dim, int spacedim>
93void
95 const FaceDescriptor *cell_and_face,
98{
99 const cell_iterator cell = cell_and_face->first;
100 const unsigned int face_number = cell_and_face->second;
101
102 Assert(cell->is_locally_owned(), ExcNotImplemented());
103
104 // First set the kind of object we are dealing with here in the 'patch'
105 // object.
106 patch.reference_cell = cell->face(face_number)->reference_cell();
107
108 // We use the mapping to transform the vertices. However, the mapping works
109 // on cells, not faces, so transform the face vertex to a cell vertex, that
110 // to a unit cell vertex and then, finally, that to the mapped vertex. In
111 // most cases this complicated procedure will be the identity.
112 for (const unsigned int vertex : cell->face(face_number)->vertex_indices())
113 {
114 const Point<dim> vertex_reference_coordinates =
115 cell->reference_cell().vertex(
116 cell->reference_cell().face_to_cell_vertices(
117 face_number, vertex, cell->combined_face_orientation(face_number)));
118
119 const Point<dim> vertex_real_coordinates =
120 data.mapping_collection[0].transform_unit_to_real_cell(
121 cell, vertex_reference_coordinates);
122
123 patch.vertices[vertex] = vertex_real_coordinates;
124 }
125
126
127 if (data.n_datasets > 0)
128 {
129 data.reinit_all_fe_values(this->dof_data, cell, face_number);
130 const FEValuesBase<dim> &fe_patch_values = data.get_present_fe_values(0);
131
132 const unsigned int n_q_points = fe_patch_values.n_quadrature_points;
133
134 // store the intermediate points
135 Assert(patch.space_dim == dim, ExcInternalError());
136 const std::vector<Point<dim>> &q_points =
137 fe_patch_values.get_quadrature_points();
138 // size the patch.data member in order to have enough memory for the
139 // quadrature points as well
140 patch.data.reinit(data.n_datasets + dim, q_points.size());
141 // set the flag indicating that for this cell the points are explicitly
142 // given
143 patch.points_are_available = true;
144 // copy points to patch.data
145 for (unsigned int i = 0; i < dim; ++i)
146 for (unsigned int q = 0; q < n_q_points; ++q)
147 patch.data(patch.data.size(0) - dim + i, q) = q_points[q][i];
148
149 // counter for data records
150 unsigned int offset = 0;
151
152 // first fill dof_data
153 for (unsigned int dataset = 0; dataset < this->dof_data.size(); ++dataset)
154 {
155 const FEValuesBase<dim> &this_fe_patch_values =
156 data.get_present_fe_values(dataset);
157 const unsigned int n_components =
158 this_fe_patch_values.get_fe().n_components();
159 const DataPostprocessor<dim> *postprocessor =
160 this->dof_data[dataset]->postprocessor;
161 if (postprocessor != nullptr)
162 {
163 // we have to postprocess the data, so determine, which fields
164 // have to be updated
165 const UpdateFlags update_flags =
166 postprocessor->get_needed_update_flags();
167
168 if (n_components == 1)
169 {
170 // at each point there is only one component of value,
171 // gradient etc.
172 if (update_flags & update_values)
173 this->dof_data[dataset]->get_function_values(
174 this_fe_patch_values,
176 real_part,
177 data.patch_values_scalar.solution_values);
178 if (update_flags & update_gradients)
179 this->dof_data[dataset]->get_function_gradients(
180 this_fe_patch_values,
182 real_part,
183 data.patch_values_scalar.solution_gradients);
184 if (update_flags & update_hessians)
185 this->dof_data[dataset]->get_function_hessians(
186 this_fe_patch_values,
188 real_part,
189 data.patch_values_scalar.solution_hessians);
190
191 if (update_flags & update_quadrature_points)
192 data.patch_values_scalar.evaluation_points =
193 this_fe_patch_values.get_quadrature_points();
194
195 if (update_flags & update_normal_vectors)
196 data.patch_values_scalar.normals =
197 this_fe_patch_values.get_normal_vectors();
198
200 dh_cell(&cell->get_triangulation(),
201 cell->level(),
202 cell->index(),
203 this->dof_data[dataset]->dof_handler);
204 data.patch_values_scalar.template set_cell_and_face<dim>(
205 dh_cell, face_number);
206
207 postprocessor->evaluate_scalar_field(
208 data.patch_values_scalar,
209 data.postprocessed_values[dataset]);
210 }
211 else
212 {
213 // at each point there is a vector valued function and its
214 // derivative...
215 data.resize_system_vectors(n_components);
216 if (update_flags & update_values)
217 this->dof_data[dataset]->get_function_values(
218 this_fe_patch_values,
220 real_part,
221 data.patch_values_system.solution_values);
222 if (update_flags & update_gradients)
223 this->dof_data[dataset]->get_function_gradients(
224 this_fe_patch_values,
226 real_part,
227 data.patch_values_system.solution_gradients);
228 if (update_flags & update_hessians)
229 this->dof_data[dataset]->get_function_hessians(
230 this_fe_patch_values,
232 real_part,
233 data.patch_values_system.solution_hessians);
234
235 if (update_flags & update_quadrature_points)
236 data.patch_values_system.evaluation_points =
237 this_fe_patch_values.get_quadrature_points();
238
239 if (update_flags & update_normal_vectors)
240 data.patch_values_system.normals =
241 this_fe_patch_values.get_normal_vectors();
242
244 dh_cell(&cell->get_triangulation(),
245 cell->level(),
246 cell->index(),
247 this->dof_data[dataset]->dof_handler);
248 data.patch_values_system.template set_cell_and_face<dim>(
249 dh_cell, face_number);
250
251 postprocessor->evaluate_vector_field(
252 data.patch_values_system,
253 data.postprocessed_values[dataset]);
254 }
255
256 for (unsigned int q = 0; q < n_q_points; ++q)
257 for (unsigned int component = 0;
258 component < this->dof_data[dataset]->n_output_variables;
259 ++component)
260 patch.data(offset + component, q) =
261 data.postprocessed_values[dataset][q](component);
262 }
263 else
264 // now we use the given data vector without modifications. again,
265 // we treat single component functions separately for efficiency
266 // reasons.
267 if (n_components == 1)
268 {
269 this->dof_data[dataset]->get_function_values(
270 this_fe_patch_values,
272 real_part,
273 data.patch_values_scalar.solution_values);
274 for (unsigned int q = 0; q < n_q_points; ++q)
275 patch.data(offset, q) =
276 data.patch_values_scalar.solution_values[q];
277 }
278 else
279 {
280 data.resize_system_vectors(n_components);
281 this->dof_data[dataset]->get_function_values(
282 this_fe_patch_values,
284 real_part,
285 data.patch_values_system.solution_values);
286 for (unsigned int component = 0; component < n_components;
287 ++component)
288 for (unsigned int q = 0; q < n_q_points; ++q)
289 patch.data(offset + component, q) =
290 data.patch_values_system.solution_values[q](component);
291 }
292 // increment the counter for the actual data record
293 offset += this->dof_data[dataset]->n_output_variables;
294 }
295
296 // then do the cell data
297 for (unsigned int dataset = 0; dataset < this->cell_data.size();
298 ++dataset)
299 {
300 // we need to get at the number of the cell to which this face
301 // belongs in order to access the cell data. this is not readily
302 // available, so choose the following rather inefficient way:
303 Assert(
304 cell->is_active(),
306 "The current function is trying to generate cell-data output "
307 "for a face that does not belong to an active cell. This is "
308 "not supported."));
309 const unsigned int cell_number = std::distance(
310 this->triangulation->begin_active(),
312
313 const double value = this->cell_data[dataset]->get_cell_data_value(
314 cell_number,
316 for (unsigned int q = 0; q < n_q_points; ++q)
317 patch.data(dataset + offset, q) = value;
318 }
319 }
320}
321
322
323
324template <int dim, int spacedim>
325void
326DataOutFaces<dim, spacedim>::build_patches(const unsigned int n_subdivisions)
327{
328 if (this->triangulation->get_reference_cells().size() == 1)
329 build_patches(this->triangulation->get_reference_cells()[0]
330 .template get_default_linear_mapping<spacedim>(),
331 n_subdivisions);
332 else
333 Assert(false,
334 ExcMessage("The DataOutFaces class can currently not be "
335 "used on meshes that do not have the same cell type "
336 "throughout."));
337}
338
339
340
341template <int dim, int spacedim>
342void
344 const Mapping<dim, spacedim> &mapping,
345 const unsigned int n_subdivisions_)
346{
347 const unsigned int n_subdivisions =
348 (n_subdivisions_ != 0) ? n_subdivisions_ : this->default_subdivisions;
349
350 Assert(n_subdivisions >= 1,
352 n_subdivisions));
353
354 Assert(this->triangulation != nullptr,
356
357 this->validate_dataset_names();
358
359 unsigned int n_datasets = this->cell_data.size();
360 for (unsigned int i = 0; i < this->dof_data.size(); ++i)
361 n_datasets += this->dof_data[i]->n_output_variables;
362
363 // first collect the cells we want to create patches of; we will
364 // then iterate over them. the end-condition of the loop needs to
365 // test that next_face() returns an end iterator, as well as for the
366 // case that first_face() returns an invalid FaceDescriptor object
367 std::vector<FaceDescriptor> all_faces;
368 for (FaceDescriptor face = first_face();
369 ((face.first != this->triangulation->end()) &&
370 (face != FaceDescriptor()));
371 face = next_face(face))
372 all_faces.push_back(face);
373
374 // clear the patches array and allocate the right number of elements
375 this->patches.clear();
376 this->patches.reserve(all_faces.size());
377 Assert(this->patches.empty(), ExcInternalError());
378
379
380 std::vector<unsigned int> n_postprocessor_outputs(this->dof_data.size());
381 for (unsigned int dataset = 0; dataset < this->dof_data.size(); ++dataset)
382 if (this->dof_data[dataset]->postprocessor)
383 n_postprocessor_outputs[dataset] =
384 this->dof_data[dataset]->n_output_variables;
385 else
386 n_postprocessor_outputs[dataset] = 0;
387
388 UpdateFlags update_flags = update_values;
389 for (unsigned int i = 0; i < this->dof_data.size(); ++i)
390 if (this->dof_data[i]->postprocessor)
391 update_flags |=
392 this->dof_data[i]->postprocessor->get_needed_update_flags();
393 update_flags |= update_quadrature_points;
394
396 n_datasets,
397 n_subdivisions,
398 n_postprocessor_outputs,
399 mapping,
400 this->get_fes(),
401 update_flags);
403 sample_patch.n_subdivisions = n_subdivisions;
404
405 // now build the patches in parallel
407 all_faces.data(),
408 all_faces.data() + all_faces.size(),
409 [this](
410 const FaceDescriptor *cell_and_face,
413 this->build_one_patch(cell_and_face, data, patch);
414 },
416 internal::DataOutFacesImplementation::append_patch_to_list<dim, spacedim>(
417 patch, this->patches);
418 },
419 thread_data,
420 sample_patch);
421}
422
423
424
425template <int dim, int spacedim>
428{
429 // simply find first active cell with a face on the boundary
430 for (const auto &cell : this->triangulation->active_cell_iterators())
431 if (cell->is_locally_owned())
432 for (const unsigned int f : cell->face_indices())
433 if ((surface_only == false) || cell->face(f)->at_boundary())
434 return FaceDescriptor(cell, f);
435
436 // just return an invalid descriptor if we haven't found a locally
437 // owned face. this can happen in parallel where all boundary
438 // faces are owned by other processors
439 return FaceDescriptor();
440}
441
442
443
444template <int dim, int spacedim>
447{
448 FaceDescriptor face = old_face;
449
450 // first check whether the present cell has more faces on the boundary. since
451 // we started with this face, its cell must clearly be locally owned
452 Assert(face.first->is_locally_owned(), ExcInternalError());
453 for (unsigned int f = face.second + 1; f < face.first->n_faces(); ++f)
454 if (!surface_only || face.first->face(f)->at_boundary())
455 // yup, that is so, so return it
456 {
457 face.second = f;
458 return face;
459 }
460
461 // otherwise find the next active cell that has a face on the boundary
462
463 // convert the iterator to an active_iterator and advance this to the next
464 // active cell
466 face.first;
467
468 // increase face pointer by one
469 ++active_cell;
470
471 // while there are active cells
472 while (active_cell != this->triangulation->end())
473 {
474 // check all the faces of this active cell. but skip it altogether
475 // if it isn't locally owned
476 if (active_cell->is_locally_owned())
477 for (const unsigned int f : face.first->face_indices())
478 if (!surface_only || active_cell->face(f)->at_boundary())
479 {
480 face.first = active_cell;
481 face.second = f;
482 return face;
483 }
484
485 // the present cell had no faces on the boundary (or was not locally
486 // owned), so check next cell
487 ++active_cell;
488 }
489
490 // we fell off the edge, so return with invalid pointer
491 face.first = this->triangulation->end();
492 face.second = 0;
493 return face;
494}
495
496
497
498// explicit instantiations
499#include "numerics/data_out_faces.inst"
500
void build_one_patch(const FaceDescriptor *cell_and_face, internal::DataOutFacesImplementation::ParallelData< dim, spacedim > &data, DataOutBase::Patch< patch_dim, patch_spacedim > &patch)
typename DataOut_DoFData< dim, patch_dim, spacedim, patch_spacedim >::cell_iterator cell_iterator
virtual FaceDescriptor next_face(const FaceDescriptor &face)
typename std::pair< cell_iterator, unsigned int > FaceDescriptor
virtual void build_patches(const unsigned int n_subdivisions=0)
DataOutFaces(const bool surface_only=true)
virtual FaceDescriptor first_face()
virtual UpdateFlags get_needed_update_flags() const =0
virtual void evaluate_vector_field(const DataPostprocessorInputs::Vector< dim > &input_data, std::vector< Vector< double > > &computed_quantities) const
virtual void evaluate_scalar_field(const DataPostprocessorInputs::Scalar< dim > &input_data, std::vector< Vector< double > > &computed_quantities) const
const std::vector< Point< spacedim > > & get_quadrature_points() const
const unsigned int n_quadrature_points
const std::vector< Tensor< 1, spacedim > > & get_normal_vectors() const
const FiniteElement< dim, spacedim > & get_fe() const
unsigned int n_components() const
Abstract base class for mapping classes.
Definition mapping.h:318
Definition point.h:111
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
static ::ExceptionBase & ExcInvalidNumberOfSubdivisions(int arg1)
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcNoTriangulationSelected()
static ::ExceptionBase & ExcMessage(std::string arg1)
typename ActiveSelector::active_cell_iterator active_cell_iterator
UpdateFlags
@ update_hessians
Second derivatives of shape functions.
@ update_values
Shape function values.
@ update_normal_vectors
Normal vectors.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
std::vector< index_type > data
Definition mpi.cc:734
void run(const std::vector< std::vector< Iterator > > &colored_iterators, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
void append_patch_to_list(const DataOutBase::Patch< DataOutFaces< dim, spacedim >::patch_dim, DataOutFaces< dim, spacedim >::patch_spacedim > &patch, std::vector< DataOutBase::Patch< DataOutFaces< dim, spacedim >::patch_dim, DataOutFaces< dim, spacedim >::patch_spacedim > > &patches)
Table< 2, float > data
ReferenceCell< dim > reference_cell
static const unsigned int space_dim
unsigned int n_subdivisions
std::array< Point< spacedim >, GeometryInfo< dim >::vertices_per_cell > vertices
ParallelData(const unsigned int n_datasets, const unsigned int n_subdivisions, const std::vector< unsigned int > &n_postprocessor_outputs, const Mapping< dim, spacedim > &mapping, const std::vector< std::shared_ptr<::hp::FECollection< dim, spacedim > > > &finite_elements, const UpdateFlags update_flags)