Thank you Daniel for your response.
I took a while since I was trying to implement something that was similar
to the post you pointed to by Philip Wardlaw, but was as requested by
Wolfgang's response a little more general. I looked on git but did not know
how to search to find what he may or may not have posted by him.
I have minimally modified four files that are attached (data_out.h,
data_postprocessor.h, data_out.cc and data_postprocessor.cc). The
modifications start and end with "//#### Start" or "//#### End". Their is
an addition of an enum in data_out.h. The same could be done for the other
places build_patches() is used like data_out_faces() etc. but I am not sure
whether would be useful since I am not familiar with them.
typedef enum
{
no_data,
material_id_data,
user_index_data,
pointer_data, // not implemented
} ExtraDataOut;
The value of the enum is passed from user code to build_patches () as an
unsigned int. I guess ideally it would be an DataOut<dim>::ExtraDataOut but
my C++ was not good enough to have the enum known to
DataPostprocessor<dim>. The new call to build_patches() would be:
for HP code:
data_out.build_patches (ndiv, DataOut<dim>::user_index_data); // not yet
mapping_collection
or NON-HP code:
data_out.build_patches (mapping, ndiv, DataOut<dim>::curved_inner_cells,
DataOut<dim>::user_index_data);
In both cases the final new parameter defalts to DataOut<dim>::no_data. I
created two new functions:
compute_derived_quantities_scalar_with_data ()
compute_derived_quantities_vector_with_data ()
with the data item returned as an unsigned long long int to accomadate a 64
bit pointer and kept the original ones as is:
compute_derived_quantities_scalar ()
compute_derived_quantities_vector ()
When attempting to have just one I got the warning related to "hidden
funtion" that I was not able to get rid of so I created another name for
the new one which for me worked fine.
I have "make clean debug" and "make release run" the following steps:
step-18, 17, 8, 27, 30, 6 and 51 and my extended step-8 with HP, NON-HP
and MPI/PETSc using the original compute_derived_quantities_vector() and
new compute_derived_quantities_vector_with_data() without issues. All
extended step-8 gave the same numerical results, considering HP/NON-HP.
I hope this will be useful to others.
Pete Griffin
On Saturday, August 6, 2016 at 4:29:46 PM UTC-4, Daniel Arndt wrote:
>
> Pete,
>
> I remember someone having something like this in mind. This is the link to
> that discussion:
> https://groups.google.com/forum/#!topic/dealii/QKuDndKojug
>
> A different way would be to derive from DataOut and overwrite
> DataOut::first_cell and DataOut::next_cell by skipping all the cells that
> don't have a specific material_id.
> If you do this for each material_id, you could create an output file for
> each material_id and join them afterwards. This would be similar to how you
> combine output from different MPI processes using a pvtu file (step-40).
>
> Best,
> Daniel
>
--
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see
https://groups.google.com/d/forum/dealii?hl=en
---
You received this message because you are subscribed to the Google Groups
"deal.II User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
// ---------------------------------------------------------------------
//
// Copyright (C) 1999 - 2015 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------
#include <deal.II/base/work_stream.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/grid/tria.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/hp/dof_handler.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/fe/fe.h>
#include <deal.II/fe/fe_dgq.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/hp/fe_values.h>
#include <deal.II/fe/mapping_q1.h>
#include <sstream>
DEAL_II_NAMESPACE_OPEN
namespace internal
{
namespace DataOut
{
template <int dim, int spacedim>
ParallelData<dim,spacedim>::
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_cxx11::shared_ptr<dealii::hp::FECollection<dim,spacedim> > > &finite_elements,
const UpdateFlags update_flags,
const std::vector<std::vector<unsigned int> > &cell_to_patch_index_map)
:
ParallelDataBase<dim,spacedim> (n_datasets,
n_subdivisions,
n_postprocessor_outputs,
mapping,
finite_elements,
update_flags,
false),
cell_to_patch_index_map (&cell_to_patch_index_map)
{}
}
}
template <int dim, typename DoFHandlerType>
void
DataOut<dim,DoFHandlerType>::
build_one_patch
(const std::pair<cell_iterator, unsigned int> *cell_and_index,
internal::DataOut::ParallelData<DoFHandlerType::dimension, DoFHandlerType::space_dimension> &scratch_data,
const unsigned int n_subdivisions,
const CurvedCellRegion curved_cell_region,
//#### in data_out.cc
//#### Start New/Modified
std::vector<DataOutBase::Patch<DoFHandlerType::dimension, DoFHandlerType::space_dimension> > &patches,
unsigned int iDataTypeWanted)
//#### End New/Modified
{
// first create the output object that we will write into
::dealii::DataOutBase::Patch<DoFHandlerType::dimension, DoFHandlerType::space_dimension> patch;
patch.n_subdivisions = n_subdivisions;
// use ucd_to_deal map as patch vertices are in the old, unnatural
// ordering. if the mapping does not preserve locations
// (e.g. MappingQEulerian), we need to compute the offset of the vertex for
// the graphical output. Otherwise, we can just use the vertex info.
for (unsigned int vertex=0; vertex<GeometryInfo<DoFHandlerType::dimension>::vertices_per_cell; ++vertex)
if (scratch_data.mapping_collection[0].preserves_vertex_locations())
patch.vertices[vertex] = cell_and_index->first->vertex(vertex);
else
patch.vertices[vertex] = scratch_data.mapping_collection[0].transform_unit_to_real_cell
(cell_and_index->first,
GeometryInfo<DoFHandlerType::dimension>::unit_cell_vertex (vertex));
if (scratch_data.n_datasets > 0)
{
// create DoFHandlerType::active_cell_iterator and initialize FEValues
scratch_data.reinit_all_fe_values(this->dof_data, cell_and_index->first);
const FEValuesBase<DoFHandlerType::dimension,DoFHandlerType::space_dimension> &fe_patch_values
= scratch_data.get_present_fe_values (0);
const unsigned int n_q_points = fe_patch_values.n_quadrature_points;
// depending on the requested output of curved cells, if necessary
// append the quadrature points to the last rows of the patch.data
// member. This is the case if we want to produce curved cells at the
// boundary and this cell actually is at the boundary, or else if we
// want to produce curved cells everywhere
//
// note: a cell is *always* at the boundary if dim<spacedim
if (curved_cell_region==curved_inner_cells
||
(curved_cell_region==curved_boundary
&&
(cell_and_index->first->at_boundary()
||
(DoFHandlerType::dimension != DoFHandlerType::space_dimension))))
{
Assert(patch.space_dim==DoFHandlerType::space_dimension, ExcInternalError());
const std::vector<Point<DoFHandlerType::space_dimension> > &q_points=fe_patch_values.get_quadrature_points();
// resize the patch.data member in order to have enough memory for
// the quadrature points as well
patch.data.reinit (scratch_data.n_datasets+DoFHandlerType::space_dimension, n_q_points);
// set the flag indicating that for this cell the points are
// explicitly given
patch.points_are_available=true;
// copy points to patch.data
for (unsigned int i=0; i<DoFHandlerType::space_dimension; ++i)
for (unsigned int q=0; q<n_q_points; ++q)
patch.data(patch.data.size(0)-DoFHandlerType::space_dimension+i,q)=q_points[q][i];
}
else
{
patch.data.reinit(scratch_data.n_datasets, n_q_points);
patch.points_are_available = false;
}
unsigned long long int cell_out_data;
if (iDataTypeWanted == material_id_data) cell_out_data = cell_and_index->first->material_id();
else if (iDataTypeWanted == user_index_data) cell_out_data = cell_and_index->first->user_index();
else if (iDataTypeWanted == no_data) cell_out_data = 0;
else Assert (false, ExcNotImplemented());
// counter for data records
unsigned int offset=0;
// first fill dof_data
for (unsigned int dataset=0; dataset<this->dof_data.size(); ++dataset)
{
const FEValuesBase<DoFHandlerType::dimension,DoFHandlerType::space_dimension> &this_fe_patch_values
= scratch_data.get_present_fe_values (dataset);
const unsigned int n_components =
this_fe_patch_values.get_fe().n_components();
const DataPostprocessor<DoFHandlerType::space_dimension> *postprocessor=this->dof_data[dataset]->postprocessor;
if (postprocessor != 0)
{
// we have to postprocess the data, so determine, which fields
// have to be updated
const UpdateFlags update_flags=postprocessor->get_needed_update_flags();
if (n_components == 1)
{
// at each point there is only one component of value,
// gradient etc.
if (update_flags & update_values)
this->dof_data[dataset]->get_function_values (this_fe_patch_values,
scratch_data.patch_values);
if (update_flags & update_gradients)
this->dof_data[dataset]->get_function_gradients (this_fe_patch_values,
scratch_data.patch_gradients);
if (update_flags & update_hessians)
this->dof_data[dataset]->get_function_hessians (this_fe_patch_values,
scratch_data.patch_hessians);
if (update_flags & update_quadrature_points)
scratch_data.patch_evaluation_points = this_fe_patch_values.get_quadrature_points();
std::vector<Point<DoFHandlerType::space_dimension> > dummy_normals;
//#### Start New/Modified
if (iDataTypeWanted == no_data)
postprocessor->
compute_derived_quantities_scalar(
scratch_data.patch_values,
scratch_data.patch_gradients,
scratch_data.patch_hessians,
dummy_normals,
scratch_data.patch_evaluation_points,
scratch_data.postprocessed_values[dataset]);
else
postprocessor->
compute_derived_quantities_scalar_with_data(
scratch_data.patch_values,
scratch_data.patch_gradients,
scratch_data.patch_hessians,
dummy_normals,
scratch_data.patch_evaluation_points,
scratch_data.postprocessed_values[dataset],
cell_out_data);
//#### End New/Modified
}
else
{
scratch_data.resize_system_vectors (n_components);
// at each point there is a vector valued function and its
// derivative...
if (update_flags & update_values)
this->dof_data[dataset]->get_function_values (this_fe_patch_values,
scratch_data.patch_values_system);
if (update_flags & update_gradients)
this->dof_data[dataset]->get_function_gradients (this_fe_patch_values,
scratch_data.patch_gradients_system);
if (update_flags & update_hessians)
this->dof_data[dataset]->get_function_hessians (this_fe_patch_values,
scratch_data.patch_hessians_system);
if (update_flags & update_quadrature_points)
scratch_data.patch_evaluation_points = this_fe_patch_values.get_quadrature_points();
std::vector<Point<DoFHandlerType::space_dimension> > dummy_normals;
//#### Start New/Modified
if (iDataTypeWanted == no_data)
postprocessor->
compute_derived_quantities_vector(
scratch_data.patch_values_system,
scratch_data.patch_gradients_system,
scratch_data.patch_hessians_system,
dummy_normals,
scratch_data.patch_evaluation_points,
scratch_data.postprocessed_values[dataset]);
else
postprocessor->
compute_derived_quantities_vector_with_data(
scratch_data.patch_values_system,
scratch_data.patch_gradients_system,
scratch_data.patch_hessians_system,
dummy_normals,
scratch_data.patch_evaluation_points,
scratch_data.postprocessed_values[dataset],
cell_out_data);
//#### End New/Modified
}
for (unsigned int q=0; q<n_q_points; ++q)
for (unsigned int component=0;
component<this->dof_data[dataset]->n_output_variables;
++component)
patch.data(offset+component,q)
= scratch_data.postprocessed_values[dataset][q](component);
}
else
// now we use the given data vector without modifications. again,
// we treat single component functions separately for efficiency
// reasons.
if (n_components == 1)
{
this->dof_data[dataset]->get_function_values (this_fe_patch_values,
scratch_data.patch_values);
for (unsigned int q=0; q<n_q_points; ++q)
patch.data(offset,q) = scratch_data.patch_values[q];
}
else
{
scratch_data.resize_system_vectors(n_components);
this->dof_data[dataset]->get_function_values (this_fe_patch_values,
scratch_data.patch_values_system);
for (unsigned int component=0; component<n_components;
++component)
for (unsigned int q=0; q<n_q_points; ++q)
patch.data(offset+component,q) =
scratch_data.patch_values_system[q](component);
}
// increment the counter for the actual data record
offset+=this->dof_data[dataset]->n_output_variables;
}
// then do the cell data. only compute the number of a cell if needed;
// also make sure that we only access cell data if the
// first_cell/next_cell functions only return active cells
if (this->cell_data.size() != 0)
{
Assert (!cell_and_index->first->has_children(), ExcNotImplemented());
for (unsigned int dataset=0; dataset<this->cell_data.size(); ++dataset)
{
const double value
= this->cell_data[dataset]->get_cell_data_value (cell_and_index->second);
for (unsigned int q=0; q<n_q_points; ++q)
patch.data(offset+dataset,q) = value;
}
}
}
for (unsigned int f=0; f<GeometryInfo<DoFHandlerType::dimension>::faces_per_cell; ++f)
{
// let's look up whether the neighbor behind that face is noted in the
// table of cells which we treat. this can only happen if the neighbor
// exists, and is on the same level as this cell, but it may also happen
// that the neighbor is not a member of the range of cells over which we
// loop, in which case the respective entry in the
// cell_to_patch_index_map will have the value no_neighbor. (note that
// since we allocated only as much space in this array as the maximum
// index of the cells we loop over, not every neighbor may have its
// space in it, so we have to assume that it is extended by values
// no_neighbor)
if (cell_and_index->first->at_boundary(f)
||
(cell_and_index->first->neighbor(f)->level() != cell_and_index->first->level()))
{
patch.neighbors[f] = numbers::invalid_unsigned_int;
continue;
}
const cell_iterator neighbor = cell_and_index->first->neighbor(f);
Assert (static_cast<unsigned int>(neighbor->level()) <
scratch_data.cell_to_patch_index_map->size(),
ExcInternalError());
if ((static_cast<unsigned int>(neighbor->index()) >=
(*scratch_data.cell_to_patch_index_map)[neighbor->level()].size())
||
((*scratch_data.cell_to_patch_index_map)[neighbor->level()][neighbor->index()]
==
dealii::DataOutBase::Patch<DoFHandlerType::dimension>::no_neighbor))
{
patch.neighbors[f] = numbers::invalid_unsigned_int;
continue;
}
// now, there is a neighbor, so get its patch number and set it for the
// neighbor index
patch.neighbors[f]
= (*scratch_data.cell_to_patch_index_map)[neighbor->level()][neighbor->index()];
}
const unsigned int patch_idx =
(*scratch_data.cell_to_patch_index_map)[cell_and_index->first->level()][cell_and_index->first->index()];
// did we mess up the indices?
Assert(patch_idx < patches.size(), ExcInternalError());
patch.patch_index = patch_idx;
// Put the patch into the patches vector. instead of copying the data,
// simply swap the contents to avoid the penalty of writing into another
// processor's memory
patches[patch_idx].swap (patch);
}
//#### Start New/Modified
template <int dim, typename DoFHandlerType>
void DataOut<dim,DoFHandlerType>::build_patches (const unsigned int n_subdivisions, const unsigned int iDataTypeWanted)
{
build_patches (StaticMappingQ1<DoFHandlerType::dimension,DoFHandlerType::space_dimension>::mapping,
n_subdivisions, no_curved_cells, iDataTypeWanted);
}
//#### End New/Modified
//#### New/Modified function
template <int dim, typename DoFHandlerType>
void DataOut<dim,DoFHandlerType>::build_patches
(const Mapping<DoFHandlerType::dimension,DoFHandlerType::space_dimension> &mapping,
const unsigned int n_subdivisions_,
//#### Start New/Modified
const CurvedCellRegion curved_region,
unsigned int iDataTypeWanted)
//#### End New/Modified
{
// Check consistency of redundant template parameter
Assert (dim==DoFHandlerType::dimension, ExcDimensionMismatch(dim, DoFHandlerType::dimension));
Assert (this->triangulation != 0,
Exceptions::DataOut::ExcNoTriangulationSelected());
const unsigned int n_subdivisions = (n_subdivisions_ != 0)
? n_subdivisions_
: this->default_subdivisions;
Assert (n_subdivisions >= 1,
Exceptions::DataOut::ExcInvalidNumberOfSubdivisions(n_subdivisions));
// First count the cells we want to create patches of. Also fill the object
// that maps the cell indices to the patch numbers, as this will be needed
// for generation of neighborship information.
// Note, there is a confusing mess of different indices here at play:
// patch_index - the index of a patch in all_cells
// cell->index - only unique on each level, used in cell_to_patch_index_map
// active_index - index for a cell when counting from begin_active() using ++cell
// cell_index - unique index of a cell counted using next_locally_owned_cell()
// starting from first_locally_owned_cell()
//
// It turns out that we create one patch for each selected cell, so patch_index==cell_index.
//
// will be cell_to_patch_index_map[cell->level][cell->index] = patch_index
std::vector<std::vector<unsigned int> > cell_to_patch_index_map;
cell_to_patch_index_map.resize (this->triangulation->n_levels());
for (unsigned int l=0; l<this->triangulation->n_levels(); ++l)
{
// max_index is the largest cell->index on level l
unsigned int max_index = 0;
for (cell_iterator cell=first_locally_owned_cell(); cell != this->triangulation->end();
cell = next_locally_owned_cell(cell))
if (static_cast<unsigned int>(cell->level()) == l)
max_index = std::max (max_index,
static_cast<unsigned int>(cell->index()));
cell_to_patch_index_map[l].resize (max_index+1,
dealii::DataOutBase::Patch<DoFHandlerType::dimension,
DoFHandlerType::space_dimension>::no_neighbor);
}
// will be all_cells[patch_index] = pair(cell, active_index)
std::vector<std::pair<cell_iterator, unsigned int> > all_cells;
{
// important: we need to compute the active_index of the cell in the range
// 0..n_active_cells() because this is where we need to look up cell
// data from (cell data vectors do not have the length distance computed by
// first_locally_owned_cell/next_locally_owned_cell because this might skip
// some values (FilteredIterator).
active_cell_iterator active_cell = this->triangulation->begin_active();
unsigned int active_index = 0;
cell_iterator cell = first_locally_owned_cell();
for (; cell != this->triangulation->end();
cell = next_locally_owned_cell(cell))
{
// move forward until active_cell points at the cell (cell) we are looking
// at to compute the current active_index
while (active_cell!=this->triangulation->end()
&& cell->active()
&& active_cell_iterator(cell) != active_cell)
{
++active_cell;
++active_index;
}
Assert (static_cast<unsigned int>(cell->level()) <
cell_to_patch_index_map.size(),
ExcInternalError());
Assert (static_cast<unsigned int>(cell->index()) <
cell_to_patch_index_map[cell->level()].size(),
ExcInternalError());
Assert (active_index < this->triangulation->n_active_cells(),
ExcInternalError());
cell_to_patch_index_map[cell->level()][cell->index()] = all_cells.size();
all_cells.push_back (std::make_pair(cell, active_index));
}
}
this->patches.clear ();
this->patches.resize(all_cells.size());
// now create a default object for the WorkStream object to work with
unsigned int n_datasets=this->cell_data.size();
for (unsigned int i=0; i<this->dof_data.size(); ++i)
n_datasets += this->dof_data[i]->n_output_variables;
std::vector<unsigned int> n_postprocessor_outputs (this->dof_data.size());
for (unsigned int dataset=0; dataset<this->dof_data.size(); ++dataset)
if (this->dof_data[dataset]->postprocessor)
n_postprocessor_outputs[dataset] = this->dof_data[dataset]->n_output_variables;
else
n_postprocessor_outputs[dataset] = 0;
const CurvedCellRegion curved_cell_region
= (n_subdivisions<2 ? no_curved_cells : curved_region);
UpdateFlags update_flags = update_values;
if (curved_cell_region != no_curved_cells)
update_flags |= update_quadrature_points;
for (unsigned int i=0; i<this->dof_data.size(); ++i)
if (this->dof_data[i]->postprocessor)
update_flags |= this->dof_data[i]->postprocessor->get_needed_update_flags();
// perhaps update_normal_vectors is present, which would only be useful on
// faces, but we may not use it here.
Assert (!(update_flags & update_normal_vectors),
ExcMessage("The update of normal vectors may not be requested for evaluation of "
"data on cells via DataPostprocessor."));
internal::DataOut::ParallelData<DoFHandlerType::dimension, DoFHandlerType::space_dimension>
thread_data (n_datasets, n_subdivisions,
n_postprocessor_outputs,
mapping,
this->get_finite_elements(),
update_flags,
cell_to_patch_index_map);
// now build the patches in parallel
if (all_cells.size() > 0)
WorkStream::run (&all_cells[0],
&all_cells[0]+all_cells.size(),
std_cxx11::bind(&DataOut<dim,DoFHandlerType>::build_one_patch,
this,
std_cxx11::_1,
std_cxx11::_2,
/* no std_cxx11::_3, since this function doesn't actually need a
copy data object -- it just writes everything right into the
output array */
n_subdivisions,
curved_cell_region,
//#### Start New/Modified
std_cxx11::ref(this->patches),
iDataTypeWanted),
//#### End New/Modified
// no copy-local-to-global function needed here
std_cxx11::function<void (const int &)>(),
thread_data,
/* dummy CopyData object = */ 0,
// experimenting shows that we can make things run a bit
// faster if we increase the number of cells we work on
// per item (i.e., WorkStream's chunk_size argument,
// about 10% improvement) and the items in flight at any
// given time (another 5% on the testcase discussed in
// @ref workstream_paper, on 32 cores) and if
8*MultithreadInfo::n_threads(),
64);
}
template <int dim, typename DoFHandlerType>
typename DataOut<dim,DoFHandlerType>::cell_iterator
DataOut<dim,DoFHandlerType>::first_cell ()
{
return this->triangulation->begin_active ();
}
template <int dim, typename DoFHandlerType>
typename DataOut<dim,DoFHandlerType>::cell_iterator
DataOut<dim,DoFHandlerType>::next_cell
(const typename DataOut<dim,DoFHandlerType>::cell_iterator &cell)
{
// convert the iterator to an active_iterator and advance this to the next
// active cell
typename Triangulation<DoFHandlerType::dimension,DoFHandlerType::space_dimension>::
active_cell_iterator active_cell = cell;
++active_cell;
return active_cell;
}
template <int dim, typename DoFHandlerType>
typename DataOut<dim,DoFHandlerType>::cell_iterator
DataOut<dim,DoFHandlerType>::first_locally_owned_cell ()
{
typename DataOut<dim,DoFHandlerType>::cell_iterator
cell = first_cell();
// skip cells if the current one has no children (is active) and is a ghost
// or artificial cell
while ((cell != this->triangulation->end()) &&
(cell->has_children() == false) &&
!cell->is_locally_owned())
cell = next_cell(cell);
return cell;
}
template <int dim, typename DoFHandlerType>
typename DataOut<dim,DoFHandlerType>::cell_iterator
DataOut<dim,DoFHandlerType>::next_locally_owned_cell
(const typename DataOut<dim,DoFHandlerType>::cell_iterator &old_cell)
{
typename DataOut<dim,DoFHandlerType>::cell_iterator
cell = next_cell(old_cell);
while ((cell != this->triangulation->end()) &&
(cell->has_children() == false) &&
!cell->is_locally_owned())
cell = next_cell(cell);
return cell;
}
// explicit instantiations
#include "data_out.inst"
DEAL_II_NAMESPACE_CLOSE
// ---------------------------------------------------------------------
//
// Copyright (C) 1999 - 2016 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------
#ifndef dealii__data_out_h
#define dealii__data_out_h
#include <deal.II/base/config.h>
#include <deal.II/numerics/data_out_dof_data.h>
#include <deal.II/base/std_cxx11/shared_ptr.h>
DEAL_II_NAMESPACE_OPEN
template <int, int> class FEValuesBase;
namespace internal
{
namespace DataOut
{
/**
* A derived class for use in the DataOut class. This is a class for the
* AdditionalData kind of data structure discussed in the documentation of
* the WorkStream context.
*/
template <int dim, int spacedim>
struct ParallelData : public ParallelDataBase<dim,spacedim>
{
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_cxx11::shared_ptr<dealii::hp::FECollection<dim,spacedim> > > &finite_elements,
const UpdateFlags update_flags,
const std::vector<std::vector<unsigned int> > &cell_to_patch_index_map);
std::vector<Point<spacedim> > patch_evaluation_points;
const std::vector<std::vector<unsigned int> > *cell_to_patch_index_map;
};
}
}
/**
* This class is the main class to provide output of data described by finite
* element fields defined on a collection of cells.
*
* This class is an actual implementation of the functionality proposed by the
* DataOut_DoFData class. It offers a function build_patches() that generates
* the data to be written in some graphics format. Most of the interface and
* an example of its use is described in the documentation of this base class.
*
* The only thing this class offers is the function build_patches() which
* loops over all cells of the triangulation stored by the
* attach_dof_handler() function of the base class (with the exception of
* cells of parallel::distributed::Triangulation objects that are not owned by
* the current processor) and converts the data on these to actual patches
* which are the objects that are later output by the functions of the base
* classes. You can give a parameter to the function which determines how many
* subdivisions in each coordinate direction are to be performed, i.e. of how
* many subcells each patch shall consist. Default is one, but you may want to
* choose a higher number for higher order elements, for example two for
* quadratic elements, three for cubic elements three, and so on. The purpose
* of this parameter is because most graphics programs do not allow to specify
* higher order polynomial functions in the file formats: only data at
* vertices can be plotted and is then shown as a bilinear interpolation
* within the interior of cells. This may be insufficient if you have higher
* order finite elements, and the only way to achieve better output is to
* subdivide each cell of the mesh into several cells for graphical output. Of
* course, what you get to see is still a bilinear interpolation on each cell
* of the output (where these cells are not subdivisions of the cells of the
* triangulation in use) due to the same limitations in output formats, but at
* least a bilinear interpolation of a higher order polynomial on a finer
* mesh.
*
* Note that after having called build_patches() once, you can call one or
* more of the write() functions of DataOutInterface. You can therefore output
* the same data in more than one format without having to rebuild the
* patches.
*
*
* <h3>User interface information</h3>
*
* The base classes of this class, DataOutBase, DataOutInterface and
* DataOut_DoFData offer several interfaces of their own. Refer to the
* DataOutBase class's documentation for a discussion of the different output
* formats presently supported, DataOutInterface for ways of selecting which
* format to use upon output at run-time and without the need to adapt your
* program when new formats become available, as well as for flags to
* determine aspects of output. The DataOut_DoFData() class's documentation
* has an example of using nodal data to generate output.
*
*
* <h3>Extensions</h3>
*
* By default, this class produces patches for all active cells. Sometimes,
* this is not what you want, maybe because they are simply too many (and too
* small to be seen individually) or because you only want to see a certain
* region of the domain (for example in parallel programs such as the step-18
* example program), or for some other reason.
*
* For this, internally build_patches() does not generate the sequence of
* cells to be converted into patches itself, but relies on the two functions
* first_cell() and next_cell(). By default, they return the first active
* cell, and the next active cell, respectively. Since they are @p virtual
* functions, you can write your own class derived from DataOut in which you
* overload these two functions to select other cells for output. This may,
* for example, include only cells that are in parts of a domain (e.g., if you
* don't care about the solution elsewhere, think for example a buffer region
* in which you attenuate outgoing waves in the Perfectly Matched Layer
* method) or if you don't want output to be generated at all levels of an
* adaptively refined mesh because this creates too much data (in this case,
* the set of cells returned by your implementations of first_cell() and
* next_cell() will include non-active cells, and DataOut::build_patches()
* will simply take interpolated values of the solution instead of the exact
* values on these cells children for output). Once you derive your own class,
* you would just create an object of this type instead of an object of type
* DataOut, and everything else will remain the same.
*
* The two functions are not constant, so you may store information within
* your derived class about the last accessed cell. This is useful if the
* information of the last cell which was accessed is not sufficient to
* determine the next one.
*
* There is one caveat, however: if you have cell data (in contrast to nodal,
* or dof, data) such as error indicators, then you must make sure that
* first_cell() and next_cell() only walk over active cells, since cell data
* cannot be interpolated to a coarser cell. If you do have cell data and use
* this pair of functions and they return a non-active cell, then an exception
* will be thrown.
*
* @pre This class only makes sense if the first template argument,
* <code>dim</code> equals the dimension of the DoFHandler type given as the
* second template argument, i.e., if <code>dim ==
* DoFHandlerType::dimension</code>. This redundancy is a historical relic
* from the time where the library had only a single DoFHandler class and this
* class consequently only a single template argument.
*
* @ingroup output
* @author Wolfgang Bangerth, 1999
*/
template <int dim, typename DoFHandlerType=DoFHandler<dim> >
class DataOut : public DataOut_DoFData<DoFHandlerType, DoFHandlerType::dimension, DoFHandlerType::space_dimension>
{
public:
/**
* Typedef to the iterator type of the dof handler class under
* consideration.
*/
typedef typename DataOut_DoFData<DoFHandlerType, DoFHandlerType::dimension, DoFHandlerType::space_dimension>::cell_iterator
cell_iterator;
typedef typename DataOut_DoFData<DoFHandlerType, DoFHandlerType::dimension, DoFHandlerType::space_dimension>::active_cell_iterator
active_cell_iterator;
/**
* Enumeration describing the region of the domain in which curved cells
* shall be created.
*/
enum CurvedCellRegion
{
no_curved_cells,
curved_boundary,
curved_inner_cells
};
//#### in data_out.h
//#### Start New
/**
* Enumeration from build_patches to relay as unsigned int to
* build_one_patch what data in data_postprocessor to
* return through compute_derived_quantities_with_data().
*/
typedef enum
{
no_data,
material_id_data,
user_index_data,
pointer_data,
} ExtraDataOut;
//#### End New
/**
* This is the central function of this class since it builds the list of
* patches to be written by the low-level functions of the base class. A
* patch is, in essence, some intermediate representation of the data on
* each cell of a triangulation and DoFHandler object that can then be used
* to write files in some format that is readable by visualization programs.
*
* You can find an overview of the use of this function in the general
* documentation of this class. An example is also provided in the
* documentation of this class's base class DataOut_DoFData.
*
* @param n_subdivisions A parameter that determines how many "patches" this
* function will build out of every cell. If you do not specify this value
* in calling, or provide the default value zero, then this is interpreted
* as DataOutInterface::default_subdivisions which most of the time will be
* equal to one (unless you have set it to something else). The purpose of
* this parameter is to subdivide each cell of the mesh into $2\times 2,
* 3\times 3, \ldots$ "patches" in 2d, and $2\times 2\times 2, 3\times
* 3\times 3, \ldots$ (if passed the value 2, 3, etc) where each patch
* represents the data from a regular subdivision of the cell into equal
* parts. Most of the times, this is not necessary and outputting one patch
* per cell is exactly what you want to plot the solution. That said, the
* data we write into files for visualization can only represent (bi-,
* tri)linear data on each cell, and most visualization programs can in fact
* only visualize this kind of data. That's good enough if you work with
* (bi-, tri)linear finite elements, in which case what you get to see is
* exactly what has been computed. On the other hand, if you work with (bi-,
* tri)quadratic elements, then what is written into the output file is just
* a (bi-, tri)linear interpolation onto the current mesh, i.e., only the
* values at the vertices. If this is not good enough, you can, for example,
* specify @p n_subdivisions equal to 2 to plot the solution on a once-
* refined mesh, or if set to 3, on a mesh where each cell is represented by
* 3-by-3 patches. On each of these smaller patches, given the limitations
* of output formats, the data is still linearly interpolated, but a linear
* interpolation of quadratic data on a finer mesh is still a better
* representation of the actual quadratic surface than on the original mesh.
* In other words, using this parameter can not help you plot the solution
* exactly, but it can get you closer if you use finite elements of higher
* polynomial degree.
*/
//#### Start New/Modified, userdata is a new parameter
virtual void build_patches (const unsigned int n_subdivisions = 0,
const unsigned int iDataTypeWanted = no_data);
//#### End New/Modified
/**
* Same as above, except that the additional first parameter defines a
* mapping that is to be used in the generation of output. If
* <tt>n_subdivisions>1</tt>, the points interior of subdivided patches
* which originate from cells at the boundary of the domain can be computed
* using the mapping, i.e. a higher order mapping leads to a representation
* of a curved boundary by using more subdivisions. Some mappings like
* MappingQEulerian result in curved cells in the interior of the domain.
* However, there is nor easy way to get this information from the Mapping.
* Thus the last argument @p curved_region take one of three values
* resulting in no curved cells at all, curved cells at the boundary
* (default) or curved cells in the whole domain.
*
* Even for non-curved cells the mapping argument can be used for the
* Eulerian mappings (see class MappingQ1Eulerian) where a mapping is used
* not only to determine the position of points interior to a cell, but also
* of the vertices. It offers an opportunity to watch the solution on a
* deformed triangulation on which the computation was actually carried out,
* even if the mesh is internally stored in its undeformed configuration and
* the deformation is only tracked by an additional vector that holds the
* deformation of each vertex.
*
* @todo The @p mapping argument should be replaced by a
* hp::MappingCollection in case of a hp::DoFHandler.
*/
virtual void build_patches (const Mapping<DoFHandlerType::dimension,
DoFHandlerType::space_dimension> &mapping,
const unsigned int n_subdivisions = 0,
//#### Start New/Modified, userdata is a new parameter
const CurvedCellRegion curved_region = curved_boundary,
const unsigned int iDataTypeWanted = no_data);
//#### End New/Modified
/**
* Return the first cell which we want output for. The default
* implementation returns the first active cell, but you might want to
* return other cells in a derived class.
*/
virtual cell_iterator first_cell ();
/**
* Return the next cell after @p cell which we want output for. If there
* are no more cells, <tt>#dofs->end()</tt> shall be returned.
*
* The default implementation returns the next active cell, but you might
* want to return other cells in a derived class. Note that the default
* implementation assumes that the given @p cell is active, which is
* guaranteed as long as first_cell() is also used from the default
* implementation. Overloading only one of the two functions might not be a
* good idea.
*/
virtual cell_iterator next_cell (const cell_iterator &cell);
private:
/**
* Return the first cell produced by the first_cell()/next_cell() function
* pair that is locally owned. If this object operates on a non-distributed
* triangulation, the result equals what first_cell() returns.
*/
virtual cell_iterator first_locally_owned_cell ();
/**
* Return the next cell produced by the next_cell() function that is locally
* owned. If this object operates on a non-distributed triangulation, the
* result equals what first_cell() returns.
*/
virtual cell_iterator next_locally_owned_cell (const cell_iterator &cell);
/**
* Build one patch. This function is called in a WorkStream context.
*
* The first argument here is the iterator, the second the scratch data
* object. All following are tied to particular values when calling
* WorkStream::run(). The function does not take a CopyData object but
* rather allocates one on its own stack for memory access efficiency
* reasons.
*/
void build_one_patch
(const std::pair<cell_iterator, unsigned int> *cell_and_index,
internal::DataOut::ParallelData<DoFHandlerType::dimension, DoFHandlerType::space_dimension> &scratch_data,
const unsigned int n_subdivisions,
const CurvedCellRegion curved_cell_region,
//#### Start New/Modified, userdata is a new parameter
std::vector<DataOutBase::Patch<DoFHandlerType::dimension, DoFHandlerType::space_dimension> > &patches,
unsigned int iDataTypeWanted);
//#### End New/Modified
};
DEAL_II_NAMESPACE_CLOSE
#endif
// ---------------------------------------------------------------------
//
// Copyright (C) 2007 - 2015 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------
#include <deal.II/numerics/data_postprocessor.h>
DEAL_II_NAMESPACE_OPEN
// -------------------------- DataPostprocessor ---------------------------
template <int dim>
DataPostprocessor<dim>::~DataPostprocessor()
{}
//#### in data_postProcessor.cc
//#### Start New
template <int dim>
void
DataPostprocessor<dim>::
compute_derived_quantities_scalar_with_data (
const std::vector<double> &/*uh*/,
const std::vector<Tensor<1,dim> > &/*duh*/,
const std::vector<Tensor<2,dim> > &/*dduh*/,
const std::vector<Point<dim> > &/*normals*/,
const std::vector<Point<dim> > &/*evaluation_points*/,
std::vector<Vector<double> > &computed_quantities,
const unsigned long long int & /*cell_out_data*/) const
{
computed_quantities.clear();
//#### Start New
std::cerr << "\nIs the parameter DataOut<dim>::ExtraDataOut of build_patches() correct?\n";
//#### End New
AssertThrow(false,ExcPureFunctionCalled());
}
template <int dim>
void
DataPostprocessor<dim>::
compute_derived_quantities_vector_with_data (
const std::vector<Vector<double> > &/*uh*/,
const std::vector<std::vector<Tensor<1,dim> > > &/*duh*/,
const std::vector<std::vector<Tensor<2,dim> > > &/*dduh*/,
const std::vector<Point<dim> > &/*normals*/,
const std::vector<Point<dim> > &/*evaluation_points*/,
std::vector<Vector<double> > &computed_quantities,
const unsigned long long int & /*cell_out_data*/) const
{
computed_quantities.clear();
//#### Start New
std::cerr << "\nIs the parameter DataOut<dim>::ExtraDataOut of build_patches() correct?\n";
//#### End New
AssertThrow(false,ExcPureFunctionCalled());
}
//#### End New
template <int dim>
void
DataPostprocessor<dim>::
compute_derived_quantities_scalar (
const std::vector<double> &/*uh*/,
const std::vector<Tensor<1,dim> > &/*duh*/,
const std::vector<Tensor<2,dim> > &/*dduh*/,
const std::vector<Point<dim> > &/*normals*/,
const std::vector<Point<dim> > &/*evaluation_points*/,
std::vector<Vector<double> > &computed_quantities) const
{
computed_quantities.clear();
//#### Start New/Modified
std::cerr << "\nIs the parameter DataOut<dim>::ExtraDataOut of build_patches() correct?\n";
//#### End New/Modified
AssertThrow(false,ExcPureFunctionCalled());
}
template <int dim>
void
DataPostprocessor<dim>::
compute_derived_quantities_vector (
const std::vector<Vector<double> > &/*uh*/,
const std::vector<std::vector<Tensor<1,dim> > > &/*duh*/,
const std::vector<std::vector<Tensor<2,dim> > > &/*dduh*/,
const std::vector<Point<dim> > &/*normals*/,
const std::vector<Point<dim> > &/*evaluation_points*/,
std::vector<Vector<double> > &computed_quantities) const
{
computed_quantities.clear();
//#### Start New/Modified
std::cerr << "\nIs the parameter DataOut<dim>::ExtraDataOut of build_patches() correct?\n";
//#### End New/Modified
AssertThrow(false,ExcPureFunctionCalled());
}
template <int dim>
std::vector<DataComponentInterpretation::DataComponentInterpretation>
DataPostprocessor<dim>::get_data_component_interpretation () const
{
// default implementation assumes that all
// components are independent scalars
return
std::vector<DataComponentInterpretation::DataComponentInterpretation>
(get_names().size(),
DataComponentInterpretation::component_is_scalar);
}
// -------------------------- DataPostprocessorScalar ---------------------------
template <int dim>
DataPostprocessorScalar<dim>::
DataPostprocessorScalar (const std::string &name,
const UpdateFlags update_flags)
:
name (name),
update_flags (update_flags)
{}
template <int dim>
std::vector<std::string>
DataPostprocessorScalar<dim>::
get_names () const
{
return std::vector<std::string> (1, name);
}
template <int dim>
std::vector<DataComponentInterpretation::DataComponentInterpretation>
DataPostprocessorScalar<dim>::
get_data_component_interpretation () const
{
return
std::vector<DataComponentInterpretation::DataComponentInterpretation>
(1, DataComponentInterpretation::component_is_scalar);
}
template <int dim>
UpdateFlags
DataPostprocessorScalar<dim>::
get_needed_update_flags () const
{
return update_flags;
}
// -------------------------- DataPostprocessorVector ---------------------------
template <int dim>
DataPostprocessorVector<dim>::
DataPostprocessorVector (const std::string &name,
const UpdateFlags update_flags)
:
name (name),
update_flags (update_flags)
{}
template <int dim>
std::vector<std::string>
DataPostprocessorVector<dim>::
get_names () const
{
return std::vector<std::string> (dim, name);
}
template <int dim>
std::vector<DataComponentInterpretation::DataComponentInterpretation>
DataPostprocessorVector<dim>::
get_data_component_interpretation () const
{
return
std::vector<DataComponentInterpretation::DataComponentInterpretation>
(dim, DataComponentInterpretation::component_is_part_of_vector);
}
template <int dim>
UpdateFlags
DataPostprocessorVector<dim>::
get_needed_update_flags () const
{
return update_flags;
}
// explicit instantiation
#include "data_postprocessor.inst"
DEAL_II_NAMESPACE_CLOSE
// ---------------------------------------------------------------------
//
// Copyright (C) 2007 - 2015 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------
#ifndef dealii__data_postprocessor_h
#define dealii__data_postprocessor_h
#include <deal.II/base/subscriptor.h>
#include <deal.II/base/tensor.h>
#include <deal.II/base/point.h>
#include <deal.II/lac/vector.h>
#include <deal.II/fe/fe_update_flags.h>
#include <deal.II/numerics/data_component_interpretation.h>
#include <vector>
#include <string>
DEAL_II_NAMESPACE_OPEN
/**
* This class provides an interface to compute derived quantities from a
* solution that can then be output in graphical formats for visualization,
* using facilities such as the DataOut class.
*
* For the (graphical) output of a FE solution one frequently wants to include
* derived quantities, which are calculated from the values of the solution
* and possibly the first and second derivatives of the solution. Examples are
* the calculation of Mach numbers from velocity and density in supersonic
* flow computations, or the computation of the magnitude of a complex-valued
* solution as demonstrated in step-29. Other uses are shown in step-32 and
* step-33. This class offers the interface to perform such postprocessing.
* Given the values and derivatives of the solution at those points where we
* want to generated output, the functions of this class can be overloaded to
* compute new quantities.
*
* A data vector and an object of a class derived from the current one can be
* given to the DataOut::add_data_vector() function (and similarly for
* DataOutRotation and DataOutFaces). This will cause DataOut::build_patches()
* to compute the derived quantities instead of using the data provided by the
* data vector (typically the solution vector). Note that the
* DataPostprocessor object (i.e., in reality the object of your derived
* class) has to live until the DataOut object is destroyed as the latter
* keeps a pointer to the former and will complain if the object pointed to is
* destroyed while the latter still has a pointer to it. If both the data
* postprocessor and DataOut objects are local variables of a function (as
* they are, for example, in step-29), then you can avoid this error by
* declaring the data postprocessor variable before the DataOut variable as
* objects are destroyed in reverse order of declaration.
*
* In order not to perform needless calculations, DataPostprocessor has to
* provide information which input data is needed for the calculation of the
* derived quantities, i.e. whether it needs the values, the first derivative
* and/or the second derivative of the provided data. DataPostprocessor
* objects which are used in combination with a DataOutFaces object can also
* ask for the normal vectors at each point. The information which data is
* needed has to be provided via the UpdateFlags returned by the virtual
* function get_needed_update_flags(). It is your responsibility to use only
* those values which were updated in the calculation of derived quantities.
* The DataOut object will provide references to the requested data in the
* call to compute_derived_quantities_scalar() or
* compute_derived_quantities_vector() (DataOut decides which of the two
* functions to call depending on whether the finite element in use has only a
* single, or multiple vector components; note that this is only determined by
* the number of components in the finite element in use, and not by whether
* the data computed by a class derived from the current one is scalar or
* vector valued).
*
* Furthermore, derived classes have to implement the get_names() function,
* where the number of output variables returned by the latter function has to
* match the size of the vector returned by the former. Furthermore, this
* number has to match the number of computed quantities, of course.
*
*
* <h3>Use in simpler cases</h3>
*
* Deriving from the current class allows to implement very general
* postprocessors. For example, in the step-32 program, we implement a
* postprocessor that takes a solution that consists of velocity, pressure and
* temperature (dim+2 components) and computes a variety of output quantities,
* some of which are vector valued and some of which are scalar. On the other
* hand, in step-29 we implement a postprocessor that only computes the
* magnitude of a complex number given by a two-component finite element. It
* seems silly to have to implement four virtual functions for this
* (compute_derived_quantities_scalar() or
* compute_derived_quantities_vector(), get_names(), get_update_flags() and
* get_data_component_interpretation()).
*
* To this end there are two classes DataPostprocessorScalar and
* DataPostprocessorVector that are meant to be used if the output quantity is
* either a single scalar or a single vector (here used meaning to have
* exactly dim components). When using these classes, one only has to write a
* constructor that passes the name of the output variable and the update
* flags to the constructor of the base class and overload the function that
* actually computes the results.
*
* @ingroup output
* @author Tobias Leicht, 2007
*/
template <int dim>
class DataPostprocessor: public Subscriptor
{
public:
/**
* Destructor. This function doesn't actually do anything but is marked as
* virtual to ensure that data postprocessors can be destroyed through
* pointers to the base class.
*/
virtual ~DataPostprocessor ();
/**
* This is the main function which actually performs the postprocessing. The
* last argument is a reference to the postprocessed data which has correct
* size already and must be filled by this function. @p uh is a reference to
* a vector of data values at all points, @p duh the same for gradients, @p
* dduh for second derivatives and @p normals is a reference to the normal
* vectors. Note, that the last four references will only contain valid
* data, if the respective flags are returned by @p get_needed_update_flags,
* otherwise those vectors will be in an unspecified state. @p normals will
* always be an empty vector when working on cells, not on faces.
*
* This function is called when the original data vector represents scalar
* data, i.e. the finite element in use has only a single vector component.
*/
//#### in data_postprocessor.h
//#### Start New
virtual
void
compute_derived_quantities_scalar_with_data (
const std::vector<double> &uh,
const std::vector<Tensor<1,dim> > &duh,
const std::vector<Tensor<2,dim> > &dduh,
const std::vector<Point<dim> > &normals,
const std::vector<Point<dim> > &evaluation_points,
std::vector<Vector<double> > &computed_quantities,
const unsigned long long int &cell_out_data) const;
virtual
void
compute_derived_quantities_vector_with_data (
const std::vector<Vector<double> > &uh,
const std::vector<std::vector<Tensor<1,dim> > > &duh,
const std::vector<std::vector<Tensor<2,dim> > > &dduh,
const std::vector<Point<dim> > &normals,
const std::vector<Point<dim> > &evaluation_points,
std::vector<Vector<double> > &computed_quantities,
const unsigned long long int &cell_out_data) const;
//#### End New
virtual
void
compute_derived_quantities_scalar (
const std::vector<double> &uh,
const std::vector<Tensor<1,dim> > &duh,
const std::vector<Tensor<2,dim> > &dduh,
const std::vector<Point<dim> > &normals,
const std::vector<Point<dim> > &evaluation_points,
std::vector<Vector<double> > &computed_quantities) const;
virtual
void
compute_derived_quantities_vector (
const std::vector<Vector<double> > &uh,
const std::vector<std::vector<Tensor<1,dim> > > &duh,
const std::vector<std::vector<Tensor<2,dim> > > &dduh,
const std::vector<Point<dim> > &normals,
const std::vector<Point<dim> > &evaluation_points,
std::vector<Vector<double> > &computed_quantities) const;
virtual std::vector<std::string> get_names () const = 0;
/**
* This functions returns information about how the individual components of
* output files that consist of more than one data set are to be
* interpreted.
*
* For example, if one has a finite element for the Stokes equations in 2d,
* representing components (u,v,p), one would like to indicate that the
* first two, u and v, represent a logical vector so that later on when we
* generate graphical output we can hand them off to a visualization program
* that will automatically know to render them as a vector field, rather
* than as two separate and independent scalar fields.
*
* The default implementation of this function returns a vector of values
* DataComponentInterpretation::component_is_scalar, indicating that all
* output components are independent scalar fields. However, if a derived
* class produces data that represents vectors, it may return a vector that
* contains values DataComponentInterpretation::component_is_part_of_vector.
* In the example above, one would return a vector with components
* (DataComponentInterpretation::component_is_part_of_vector,
* DataComponentInterpretation::component_is_part_of_vector,
* DataComponentInterpretation::component_is_scalar) for (u,v,p).
*/
virtual
std::vector<DataComponentInterpretation::DataComponentInterpretation>
get_data_component_interpretation () const;
/**
* Return, which data has to be provided to compute the derived quantities.
* This has to be a combination of @p update_values, @p update_gradients and
* @p update_hessians. If the DataPostprocessor is to be used in combination
* with DataOutFaces, you may also ask for a update of normals via the @p
* update_normal_vectors flag.
*/
virtual UpdateFlags get_needed_update_flags () const = 0;
private:
};
/**
* This class provides a simpler interface to the functionality offered by the
* DataPostprocessor class in case one wants to compute only a single scalar
* quantity from the finite element field passed to the DataOut class. For
* this particular case, it is clear what the returned value of
* DataPostprocessor::get_data_component_interpretation() should be and we
* pass the values returned by get_names() and get_needed_update_flags() to
* the constructor so that derived classes do not have to implement these
* functions by hand.
*
* All derived classes have to do is implement a constructor and overload
* either DataPostprocessor::compute_derived_quantities_scalar() or
* DataPostprocessor::compute_derived_quantities_vector().
*
* An example of how this class can be used can be found in step-29.
*
* @ingroup output
* @author Wolfgang Bangerth, 2011
*/
template <int dim>
class DataPostprocessorScalar : public DataPostprocessor<dim>
{
public:
/**
* Constructor. Take the name of the single scalar variable computed by
* classes derived from the current one, as well as the update flags
* necessary to compute this quantity.
*
* @param name The name by which the scalar variable computed by this class
* should be made available in graphical output files.
* @param update_flags This has to be a combination of @p update_values, @p
* update_gradients and @p update_hessians. If the DataPostprocessor is to
* be used in combination with DataOutFaces, you may also ask for a update
* of normals via the @p update_normal_vectors flag.
*/
DataPostprocessorScalar (const std::string &name,
const UpdateFlags update_flags);
/**
* Return the vector of strings describing the names of the computed
* quantities. Given the purpose of this class, this is a vector with a
* single entry equal to the name given to the constructor.
*/
virtual std::vector<std::string> get_names () const;
/**
* This functions returns information about how the individual components of
* output files that consist of more than one data set are to be
* interpreted. Since the current class is meant to be used for a single
* scalar result variable, the returned value is obviously
* DataComponentInterpretation::component_is_scalar.
*/
virtual
std::vector<DataComponentInterpretation::DataComponentInterpretation>
get_data_component_interpretation () const;
/**
* Return, which data has to be provided to compute the derived quantities.
* The flags returned here are the ones passed to the constructor of this
* class.
*/
virtual UpdateFlags get_needed_update_flags () const;
private:
/**
* Copies of the two arguments given to the constructor of this class.
*/
const std::string name;
const UpdateFlags update_flags;
};
/**
* This class provides a simpler interface to the functionality offered by the
* DataPostprocessor class in case one wants to compute only a single vector
* quantity (defined as having exactly dim components) from the finite element
* field passed to the DataOut class. For this particular case, it is clear
* what the returned value of
* DataPostprocessor::get_data_component_interpretation() should be and we
* pass the values returned by get_names() and get_needed_update_flags() to
* the constructor so that derived classes do not have to implement these
* functions by hand.
*
* All derived classes have to do is implement a constructor and overload
* either DataPostprocessor::compute_derived_quantities_scalar() or
* DataPostprocessor::compute_derived_quantities_vector().
*
* An example of how the closely related class DataPostprocessorScalar is used
* can be found in step-29.
*
* @ingroup output
* @author Wolfgang Bangerth, 2011
*/
template <int dim>
class DataPostprocessorVector : public DataPostprocessor<dim>
{
public:
/**
* Constructor. Take the name of the single vector variable computed by
* classes derived from the current one, as well as the update flags
* necessary to compute this quantity.
*
* @param name The name by which the vector variable computed by this class
* should be made available in graphical output files.
* @param update_flags This has to be a combination of @p update_values, @p
* update_gradients and @p update_hessians. If the DataPostprocessor is to
* be used in combination with DataOutFaces, you may also ask for a update
* of normals via the @p update_normal_vectors flag.
*/
DataPostprocessorVector (const std::string &name,
const UpdateFlags update_flags);
/**
* Return the vector of strings describing the names of the computed
* quantities. Given the purpose of this class, this is a vector with dim
* entries all equal to the name given to the constructor.
*/
virtual std::vector<std::string> get_names () const;
/**
* This functions returns information about how the individual components of
* output files that consist of more than one data set are to be
* interpreted. Since the current class is meant to be used for a single
* vector result variable, the returned value is obviously
* DataComponentInterpretation::component_is_part repeated dim times.
*/
virtual
std::vector<DataComponentInterpretation::DataComponentInterpretation>
get_data_component_interpretation () const;
/**
* Return which data has to be provided to compute the derived quantities.
* The flags returned here are the ones passed to the constructor of this
* class.
*/
virtual UpdateFlags get_needed_update_flags () const;
private:
/**
* Copies of the two arguments given to the constructor of this class.
*/
const std::string name;
const UpdateFlags update_flags;
};
DEAL_II_NAMESPACE_CLOSE
#endif