Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reintroduce old VectorTools::interpolate as fallback #5334

Merged
merged 2 commits into from Oct 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
236 changes: 236 additions & 0 deletions include/deal.II/numerics/vector_tools.templates.h
Expand Up @@ -247,11 +247,232 @@ namespace VectorTools
}


/**
* Older version of the function directly below that does the same thing. This
* version also works for FESystems that contain non-interpolatory elements
* (as long as their components are not selected in the component mask).
* TODO: Remove this function when the other function is fixed to also work
* for the mentioned case.
*/
template <int dim, int spacedim, typename VectorType,
template <int, int> class DoFHandlerType, typename T>
void interpolate_selected_components (const Mapping<dim,spacedim> &mapping,
const DoFHandlerType<dim,spacedim> &dof,
const T &function,
VectorType &vec,
const ComponentMask &component_mask)
{
typedef typename VectorType::value_type number;
Assert (component_mask.represents_n_components(dof.get_fe(0).n_components()),
ExcMessage("The number of components in the mask has to be either "
"zero or equal to the number of components in the finite "
"element.") );

Assert (vec.size() == dof.n_dofs(),
ExcDimensionMismatch (vec.size(), dof.n_dofs()));
Assert (component_mask.n_selected_components(dof.get_fe(0).n_components()) > 0,
ComponentMask::ExcNoComponentSelected());

const hp::FECollection<dim,spacedim> &fe = dof.get_fe_collection();
const unsigned int n_components = fe.n_components();
const bool fe_is_system = (n_components != 1);

typename DoFHandlerType<dim,spacedim>::active_cell_iterator
cell = dof.begin_active(),
endc = dof.end();

// For FESystems many of the
// unit_support_points will appear
// multiple times, as a point may be
// unit_support_point for several of the
// components of the system. The following
// is rather complicated, but at least
// attempts to avoid evaluating the
// vectorfunction multiple times at the
// same point on a cell.
//
// First check that the desired components are interpolating.
for (unsigned int fe_index=0; fe_index<fe.size(); ++fe_index)
{
for (unsigned int component_index = 0; component_index < n_components; ++component_index)
{
if (component_mask[component_index] == true)
{
Assert ((fe[fe_index].base_element(fe[fe_index].component_to_base_index
(component_index).first).has_support_points()) ||
(fe[fe_index].base_element(fe[fe_index].component_to_base_index
(component_index).first).dofs_per_cell == 0),
ExcNonInterpolatingFE());
}
}
}

// Find the support points on a cell that are mentioned multiple times, and
// only add each once. Each multiple point gets to know the dof index of
// its representative point by the dof_to_rep_dof_table.

// the following vector collects all unit support points p[i],
// 0<=i<fe.dofs_per_cell, for which unit_support_point(i) is unique
// (representative). The position of a support point within this vector is
// called the rep index.
std::vector<std::vector<Point<dim> > > rep_unit_support_points (fe.size());
// the following table converts a dof i
// to the rep index.
std::vector<std::vector<types::global_dof_index> > dof_to_rep_index_table(fe.size());

std::vector<unsigned int> n_rep_points (fe.size(), 0);

for (unsigned int fe_index=0; fe_index<fe.size(); ++fe_index)
{
for (unsigned int i=0; i<fe[fe_index].dofs_per_cell; ++i)
{
const unsigned int component
= fe[fe_index].system_to_component_index(i).first;
if (component_mask[component] == true)
{
const Point<dim> dof_support_point = fe[fe_index].unit_support_point(i);

bool representative=true;
// the following loop is looped
// the other way round to get
// the minimal effort of
// O(fe.dofs_per_cell) for multiple
// support points that are placed
// one after the other.
for (unsigned int j=rep_unit_support_points[fe_index].size(); j>0; --j)
if (dof_support_point
== rep_unit_support_points[fe_index][j-1])
{
dof_to_rep_index_table[fe_index].push_back(j-1);
representative=false;
break;
}

if (representative)
{
dof_to_rep_index_table[fe_index].push_back
(rep_unit_support_points[fe_index].size());
rep_unit_support_points[fe_index].push_back(dof_support_point);
++n_rep_points[fe_index];
}
}
else
{
// If correct component not to be interpolated, append invalid index to in table
dof_to_rep_index_table[fe_index].push_back(numbers::invalid_dof_index);
}
}

Assert(rep_unit_support_points[fe_index].size()==n_rep_points[fe_index],
ExcInternalError());
Assert(dof_to_rep_index_table[fe_index].size()==fe[fe_index].dofs_per_cell,
ExcInternalError());
}

std::vector<types::global_dof_index> dofs_on_cell (fe.max_dofs_per_cell());

// get space for the values of the
// function at the rep support points.
//
// have two versions, one for system fe
// and one for scalar ones, to take the
// more efficient one respectively
std::vector<std::vector<number> > function_values_scalar(fe.size());
std::vector<std::vector<Vector<number> > > function_values_system(fe.size());

// Make a quadrature rule from support points
// to feed it into FEValues
hp::QCollection<dim> support_quadrature;
for (unsigned int fe_index=0; fe_index<fe.size(); ++fe_index)
support_quadrature.push_back (Quadrature<dim>(rep_unit_support_points[fe_index]));

// Transformed support points are computed by
// FEValues
hp::MappingCollection<dim,spacedim> mapping_collection (mapping);

hp::FEValues<dim,spacedim> fe_values (mapping_collection,
fe, support_quadrature, update_quadrature_points);

for (; cell!=endc; ++cell)
if (cell->is_locally_owned())
{
const unsigned int fe_index = cell->active_fe_index();
if (fe[fe_index].dofs_per_cell != 0)
{
// for each cell:
// get location of finite element
// support_points
fe_values.reinit(cell);
const std::vector<Point<spacedim> > &rep_support_points =
fe_values.get_present_fe_values().get_quadrature_points();

// get indices of the dofs on this cell
dofs_on_cell.resize (fe[fe_index].dofs_per_cell);
cell->get_dof_indices (dofs_on_cell);


if (fe_is_system)
{
// get function values at
// these points. Here: get
// all components
function_values_system[fe_index]
.resize (n_rep_points[fe_index],
Vector<number> (fe[fe_index].n_components()));

Assert (dof.get_fe(fe_index).n_components() == function(cell)->n_components,
ExcDimensionMismatch(dof.get_fe(0).n_components(),
function(cell)->n_components));

function(cell)->vector_value_list (rep_support_points,
function_values_system[fe_index]);
// distribute the function
// values to the global
// vector
for (unsigned int i=0; i<fe[fe_index].dofs_per_cell; ++i)
{
const unsigned int component
= fe[fe_index].system_to_component_index(i).first;
if (component_mask[component] == true)
{
const unsigned int rep_dof=dof_to_rep_index_table[fe_index][i];
::dealii::internal::ElementAccess<VectorType>::set(
function_values_system[fe_index][rep_dof](component),
dofs_on_cell[i], vec);
}
}
}
else
{
// get first component only,
// which is the only component
// in the function anyway
function_values_scalar[fe_index].resize (n_rep_points[fe_index]);
function(cell)->value_list (rep_support_points,
function_values_scalar[fe_index],
0);
// distribute the function
// values to the global
// vector
for (unsigned int i=0; i<fe[fe_index].dofs_per_cell; ++i)
::dealii::internal::ElementAccess<VectorType>::set(
function_values_scalar[fe_index][dof_to_rep_index_table[fe_index][i]],
dofs_on_cell[i], vec);
}
}
}
vec.compress(VectorOperation::insert);
}


// Internal implementation of interpolate that takes a generic functor
// function such that function(cell) is of type
// Function<spacedim, typename VectorType::value_type>*
//
// A given cell is skipped if function(cell) == nullptr
// TODO: Make this function also work for FESystems that
// contain elements without generalized support points, as
// long as their components are not selected for interpolation.
template <int dim,
int spacedim,
typename VectorType,
Expand Down Expand Up @@ -312,6 +533,21 @@ namespace VectorTools

const hp::FECollection<dim, spacedim> &fe(dof_handler.get_fe_collection());

// Check if the element has generalized support points
bool has_generalized_support_points = true;
for (unsigned int fe_index=0; fe_index<fe.size(); ++fe_index)
{
has_generalized_support_points = has_generalized_support_points && fe[fe_index].has_generalized_support_points();
}

// If the element has no generalized support points the algorithm in this
// function does not work. Fall back to an earlier version.
if (!has_generalized_support_points)
{
interpolate_selected_components(mapping,dof_handler,function,vec,component_mask);
return;
}

std::vector<types::global_dof_index> dofs_on_cell(fe.max_dofs_per_cell());

// Temporary storage for cell-wise interpolation operation. We store a
Expand Down