Skip to content

Commit

Permalink
Support MappingCartesian in FEPointEvaluation
Browse files Browse the repository at this point in the history
  • Loading branch information
gassmoeller committed Sep 23, 2021
1 parent 5a2787e commit 523833d
Show file tree
Hide file tree
Showing 5 changed files with 481 additions and 10 deletions.
32 changes: 31 additions & 1 deletion include/deal.II/fe/mapping_cartesian.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,31 @@ class MappingCartesian : public Mapping<dim, spacedim>
* @}
*/

/**
* As opposed to the other fill_fe_values() and fill_fe_face_values()
* functions that rely on pre-computed information of InternalDataBase, this
* function chooses the flexible evaluation path on the cell and points
* passed in to the current function.
*
* @param[in] cell The cell where to evaluate the mapping
*
* @param[in] unit_points The points in reference coordinates where the
* transformation (Jacobians, positions) should be computed.
*
* @param[in] update_flags The kind of information that should be computed.
*
* @param[out] output_data A struct containing the evaluated quantities such
* as the Jacobian resulting from application of the mapping on the given
* cell with its underlying manifolds.
*/
void
fill_mapping_data_for_generic_points(
const typename Triangulation<dim, spacedim>::cell_iterator &cell,
const ArrayView<const Point<dim>> & unit_points,
const UpdateFlags update_flags,
dealii::internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
&output_data) const;


private:
/**
Expand All @@ -178,7 +203,12 @@ class MappingCartesian : public Mapping<dim, spacedim>
{
public:
/**
* Constructor.
* Default constructor.
*/
InternalData() = default;

/**
* Constructor that initializes the object with a quadrature.
*/
InternalData(const Quadrature<dim> &quadrature);

Expand Down
59 changes: 50 additions & 9 deletions include/deal.II/matrix_free/fe_point_evaluation.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <deal.II/base/vectorization.h>

#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/mapping_cartesian.h>
#include <deal.II/fe/mapping_q.h>

#include <deal.II/matrix_free/evaluation_flags.h>
Expand Down Expand Up @@ -578,10 +579,16 @@ class FEPointEvaluation
SmartPointer<const Mapping<dim, spacedim>> mapping;

/**
* Pointer to MappingQ class that enables the fast path of this
* class.
* Pointer to the function of the mapping that computes the necessary
* mapping quantities like quadrature points and Jacobians.
*/
const MappingQ<dim, spacedim> *mapping_q;
std::function<void(
const typename Triangulation<dim, spacedim>::cell_iterator & /*cell*/,
const ArrayView<const Point<dim>> & /*unit_points*/,
const UpdateFlags /*update_flags*/,
dealii::internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
& /*output_data*/)>
fill_mapping_data_for_generic_points;

/**
* Pointer to the FiniteElement object passed to the constructor.
Expand Down Expand Up @@ -691,14 +698,48 @@ FEPointEvaluation<n_components, dim, spacedim, Number>::FEPointEvaluation(
const UpdateFlags update_flags,
const unsigned int first_selected_component)
: mapping(&mapping)
, mapping_q(dynamic_cast<const MappingQ<dim, spacedim> *>(&mapping))
, fe(&fe)
, update_flags(update_flags)
, update_flags_mapping(update_default)
{
AssertIndexRange(first_selected_component + n_components,
fe.n_components() + 1);

if (const MappingQ<dim, spacedim> *mapping_q =
dynamic_cast<const MappingQ<dim, spacedim> *>(&mapping))
{
fill_mapping_data_for_generic_points =
[mapping_q](
const typename Triangulation<dim, spacedim>::cell_iterator &cell,
const ArrayView<const Point<dim>> &unit_points,
const UpdateFlags update_flags,
dealii::internal::FEValuesImplementation::MappingRelatedData<dim,
spacedim>
&output_data) -> void {
mapping_q->fill_mapping_data_for_generic_points(cell,
unit_points,
update_flags,
output_data);
};
}
else if (const MappingCartesian<dim, spacedim> *mapping_cartesian =
dynamic_cast<const MappingCartesian<dim, spacedim> *>(&mapping))
{
fill_mapping_data_for_generic_points =
[mapping_cartesian](
const typename Triangulation<dim, spacedim>::cell_iterator &cell,
const ArrayView<const Point<dim>> &unit_points,
const UpdateFlags update_flags,
dealii::internal::FEValuesImplementation::MappingRelatedData<dim,
spacedim>
&output_data) -> void {
mapping_cartesian->fill_mapping_data_for_generic_points(cell,
unit_points,
update_flags,
output_data);
};
}

bool same_base_element = true;
unsigned int base_element_number = 0;
unsigned int component = 0;
Expand All @@ -713,7 +754,7 @@ FEPointEvaluation<n_components, dim, spacedim, Number>::FEPointEvaluation(
}
else
component += fe.element_multiplicity(base_element_number);
if (mapping_q != nullptr &&
if (fill_mapping_data_for_generic_points &&
internal::FEPointEvaluation::is_fast_path_supported(
fe, base_element_number) &&
same_base_element)
Expand Down Expand Up @@ -772,10 +813,10 @@ FEPointEvaluation<n_components, dim, spacedim, Number>::reinit(
std::copy(unit_points.begin(), unit_points.end(), this->unit_points.begin());

if (!poly.empty())
mapping_q->fill_mapping_data_for_generic_points(cell,
unit_points,
update_flags_mapping,
mapping_data);
fill_mapping_data_for_generic_points(cell,
unit_points,
update_flags_mapping,
mapping_data);
else
{
fe_values = std::make_shared<FEValues<dim, spacedim>>(
Expand Down
51 changes: 51 additions & 0 deletions source/fe/mapping_cartesian.cc
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,57 @@ MappingCartesian<dim, spacedim>::fill_fe_values(



template <int dim, int spacedim>
void
MappingCartesian<dim, spacedim>::fill_mapping_data_for_generic_points(
const typename Triangulation<dim, spacedim>::cell_iterator &cell,
const ArrayView<const Point<dim>> & unit_points,
const UpdateFlags update_flags,
dealii::internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
&output_data) const
{
if (update_flags == update_default)
return;

Assert(update_flags & update_inverse_jacobians ||
update_flags & update_jacobians ||
update_flags & update_quadrature_points,
ExcNotImplemented());

output_data.initialize(unit_points.size(), update_flags);
const unsigned int n_points = unit_points.size();

InternalData data;
data.update_each = update_flags;
data.quadrature_points =
std::vector<Point<dim>>(unit_points.begin(), unit_points.end());

update_cell_extents(cell, CellSimilarity::none, data);

maybe_update_cell_quadrature_points(cell,
data,
output_data.quadrature_points);

for (unsigned int i = 0; i < n_points; ++i)
{
if (update_flags & update_jacobians)
{
output_data.jacobians[i] = DerivativeForm<1, dim, spacedim>();
for (unsigned int j = 0; j < dim; ++j)
output_data.jacobians[i][j][j] = data.cell_extents[j];
}

if (update_flags & update_inverse_jacobians)
{
output_data.inverse_jacobians[i] = DerivativeForm<1, dim, spacedim>();
for (unsigned int j = 0; j < dim; ++j)
output_data.inverse_jacobians[i][j][j] = 1. / data.cell_extents[j];
}
}
}



template <int dim, int spacedim>
void
MappingCartesian<dim, spacedim>::fill_fe_face_values(
Expand Down
154 changes: 154 additions & 0 deletions tests/matrix_free/point_evaluation_13.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// ---------------------------------------------------------------------
//
// Copyright (C) 2021 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.md at
// the top level directory of deal.II.
//
// ---------------------------------------------------------------------


// Check FEPointEvaluation for vector-valued FE_Q and MappingCartesian by
// comparing to the output of FEValues with the same settings.
// This is a modified version of point_evaluation_03.cc.

#include <deal.II/base/function_lib.h>

#include <deal.II/dofs/dof_handler.h>

#include <deal.II/fe/fe_q.h>
#include <deal.II/fe/fe_system.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/mapping_cartesian.h>

#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/tria.h>

#include <deal.II/lac/vector.h>

#include <deal.II/matrix_free/fe_point_evaluation.h>

#include <deal.II/numerics/vector_tools.h>

#include <iostream>

#include "../tests.h"



template <int dim>
class MyFunction : public Function<dim>
{
public:
MyFunction()
: Function<dim>(dim)
{}

double
value(const Point<dim> &p, const unsigned int component) const override
{
return component + p[component];
}
};



template <int dim>
void
test()
{
using namespace dealii;
Triangulation<dim> tria;

GridGenerator::subdivided_hyper_cube(tria, 2, 0, 1);

MappingCartesian<dim> mapping;
deallog << "Cartesian linear mapping" << std::endl;

std::vector<Point<dim>> unit_points;
for (unsigned int i = 0; i < 13; ++i)
{
Point<dim> p;
for (unsigned int d = 0; d < dim; ++d)
p[d] = static_cast<double>(i) / 17. + 0.015625 * d;
unit_points.push_back(p);
}

FESystem<dim> fe(FE_Q<dim>(2), dim);
FEValues<dim> fe_values(mapping,
fe,
Quadrature<dim>(unit_points),
update_values | update_gradients);

DoFHandler<dim> dof_handler(tria);
dof_handler.distribute_dofs(fe);
Vector<double> vector(dof_handler.n_dofs());

FEPointEvaluation<dim, dim> evaluator(mapping,
fe,
update_values | update_gradients);

VectorTools::interpolate(mapping, dof_handler, MyFunction<dim>(), vector);

std::vector<double> solution_values(fe.dofs_per_cell);
std::vector<Tensor<1, dim>> function_values(unit_points.size());
std::vector<Tensor<2, dim>> function_gradients(unit_points.size());

FEValuesExtractors::Vector extractor(0);

for (const auto &cell : dof_handler.active_cell_iterators())
{
fe_values.reinit(cell);
fe_values[extractor].get_function_values(vector, function_values);
fe_values[extractor].get_function_gradients(vector, function_gradients);

cell->get_dof_values(vector,
solution_values.begin(),
solution_values.end());

evaluator.reinit(cell, unit_points);
evaluator.evaluate(solution_values,
EvaluationFlags::values | EvaluationFlags::gradients);

deallog << "Cell with center " << cell->center(true) << std::endl;
for (unsigned int i = 0; i < function_values.size(); ++i)
deallog << mapping.transform_unit_to_real_cell(cell, unit_points[i])
<< ": " << evaluator.get_value(i) << " error value "
<< (function_values[i] - evaluator.get_value(i)).norm()
<< " error grad "
<< (evaluator.get_gradient(i) - function_gradients[i]).norm()
<< std::endl;
deallog << std::endl;

for (unsigned int i = 0; i < unit_points.size(); ++i)
{
evaluator.submit_value(evaluator.get_value(i), i);
evaluator.submit_gradient(evaluator.get_gradient(i), i);
}

evaluator.integrate(solution_values,
EvaluationFlags::values | EvaluationFlags::gradients);

for (const auto i : solution_values)
deallog << i << " ";
deallog << std::endl;
}
}



int
main()
{
initlog();
deallog << std::setprecision(10);

test<2>();
test<3>();
}
Loading

0 comments on commit 523833d

Please sign in to comment.