36#include <boost/math/special_functions/relative_difference.hpp>
37#include <boost/math/special_functions/sign.hpp>
38#include <boost/math/tools/roots.hpp>
49 namespace QuadratureGeneratorImplementation
62 ExcMessage(
"Interval start must be less than interval end."));
64 const double length = end - start;
106 const std::vector<std::reference_wrapper<
const Function<dim>>>
110 Assert(functions.size() > 0,
112 "The incoming vector must contain at least one function."));
115 boost::math::sign(functions[0].get().value(point));
120 for (
unsigned int j = 1;
j < functions.size(); ++
j)
122 const int sign = boost::math::sign(functions[
j].get().value(point));
155 for (
unsigned int i = 0; i <
cube.n_vertices(); ++i)
179 const std::vector<std::reference_wrapper<
const Function<dim>>>
189 FunctionTools::taylor_estimate_function_bounds<dim>(
190 function,
box, bounds.value, bounds.gradient);
200 std::pair<double, double>
205 std::pair<double, double>
extremes = bounds[0].value;
206 for (
unsigned int i = 1; i < bounds.size(); ++i)
257 ExcMessage(
"Function bounds reversed, max < min."));
274 std_cxx17::optional<HeightDirectionData>
291 for (
unsigned int d = 0; d < dim; ++d)
293 (*min_lower_abs_grad)[d] =
299 for (
unsigned int d = 0; d < dim; ++d)
301 (*min_lower_abs_grad)[d] =
323 return std_cxx17::optional<HeightDirectionData>();
373 quadrature.push_back(point, weight);
392 const std::vector<std::reference_wrapper<
const Function<dim>>>
395 const unsigned int direction,
403 const double bottom =
box.lower_bound(direction);
404 const double top =
box.upper_bound(direction);
406 for (
const auto &function : functions)
409 function, direction,
bottom));
411 function, direction,
top));
428 const std::vector<std::reference_wrapper<
const Function<dim>>>
431 const unsigned int open_direction,
438 for (
const auto &function : functions)
441 function, open_direction, point));
465 const std::vector<double> &roots,
469 const std::vector<std::reference_wrapper<
const Function<1>>>
478 for (
int i = -1; i <
n_roots; ++i)
481 const double start = i < 0 ? interval.lower_bound(0) : roots[i];
483 i + 1 <
n_roots ? roots[i + 1] : interval.upper_bound(0);
485 const double length = end - start;
499 q_partitioning.quadrature_by_definiteness(
definiteness);
515 const double tolerance,
516 const unsigned int max_recursion_depth,
517 const unsigned int max_iterations)
518 : tolerance(tolerance)
519 , max_recursion_depth(max_recursion_depth)
520 , max_iterations(max_iterations)
533 const std::vector<std::reference_wrapper<
const Function<1>>> &functions,
535 std::vector<double> & roots)
543 std::sort(roots.begin(), roots.end());
545 const auto roots_are_equal = [
this](
const double &a,
const double &b) {
558 std::vector<double> & roots)
561 const double left_value = function.value(interval.vertex(0));
562 const double right_value = function.value(interval.vertex(1));
567 const auto lambda = [&function](
const double x) {
579 boost::math::tools::toms748_solve(lambda,
580 interval.lower_bound(0),
581 interval.upper_bound(0),
588 roots.push_back(
root);
597 FunctionTools::taylor_estimate_function_bounds<1>(function,
650 this->quadrature_points.push_back(point);
651 this->weights.push_back(weight);
684 const unsigned int direction,
691 box.lower_bound(direction));
697 box.upper_bound(direction));
708 template <
int dim,
int spacedim>
712 : q_collection1D(&q_collection1D)
713 , additional_data(additional_data)
715 RootFinder::AdditionalData(additional_data.root_finder_tolerance,
716 additional_data.max_root_finder_splits))
723 template <
int dim,
int spacedim>
726 const std::vector<std::reference_wrapper<
const Function<dim>>>
745 const std::vector<std::reference_wrapper<const Function<1>>>
747 point_restrictions.end());
766 create_surface_point(point,
771 q_partitioning.surface);
774 point_restrictions.clear();
779 template <
int dim,
int spacedim>
784 const std::vector<std::reference_wrapper<
const Function<dim>>>
797 if (roots.size() == 1)
821 normal *= 1. / normal.norm();
826 weight * gradient.norm() /
833 template <
int dim,
int spacedim>
836 unsigned int q_index)
839 this->q_index = q_index;
844 template <
int dim,
int spacedim>
848 : additional_data(additional_data)
849 , q_collection1D(&q_collection1D)
856 template <
int dim,
int spacedim>
861 , low_dim_algorithm(q_collection1D, additional_data)
862 , up_through_dimension_creator(q_collection1D, additional_data)
870 template <
int dim,
int spacedim>
879 template <
int dim,
int spacedim>
883 return q_partitioning;
888 template <
int dim,
int spacedim>
891 const std::vector<std::reference_wrapper<
const Function<dim>>>
906 this->q_partitioning.positive);
909 -(
this->additional_data.limit_to_be_definite))
913 this->q_partitioning.negative);
919 this->q_partitioning.indefinite);
923 const std_cxx17::optional<HeightDirectionData> data =
928 if (data && data->min_abs_dfdx >
929 this->additional_data.lower_bound_implicit_function)
931 create_low_dim_quadratures(data->direction,
935 create_high_dim_quadratures(data->direction,
level_sets,
box);
958 std_cxx17::optional<unsigned int>
962 std::array<std::pair<double, unsigned int>, dim>
side_lengths;
963 for (
unsigned int i = 0; i < dim; ++i)
975 return std_cxx17::optional<unsigned int>();
999 const std_cxx17::optional<unsigned int> direction =
1028 corners.second[direction] -= .5 *
box.side_length(direction);
1047 corners.first[direction] += .5 *
box.side_length(direction);
1054 template <
int dim,
int spacedim>
1057 const std::vector<std::reference_wrapper<
const Function<dim>>>
1063 if (this->additional_data.split_in_half)
1065 const unsigned int direction =
1076 for (
unsigned int i = 0;
1087 template <
int dim,
int spacedim>
1104 const std::vector<std::reference_wrapper<
const Function<dim - 1>>>
1110 low_dim_algorithm.clear_quadratures();
1116 template <
int dim,
int spacedim>
1120 const std::vector<std::reference_wrapper<
const Function<dim>>>
1125 low_dim_algorithm.get_quadratures();
1128 (*this->q_collection1D)[this->q_index];
1135 this->q_partitioning.negative);
1142 this->q_partitioning.positive);
1144 up_through_dimension_creator.generate(
level_sets,
1148 this->q_partitioning);
1153 template <
int dim,
int spacedim>
1156 const std::vector<std::reference_wrapper<
const Function<dim>>>
1165 this->q_partitioning.quadrature_by_definiteness(
definiteness);
1172 template <
int dim,
int spacedim>
1178 this->q_index = q_index;
1179 low_dim_algorithm.set_1D_quadrature(q_index);
1180 up_through_dimension_creator.set_1D_quadrature(q_index);
1185 template <
int spacedim>
1191 RootFinder::AdditionalData(additional_data.root_finder_tolerance,
1192 additional_data.max_root_finder_splits))
1195 ExcMessage(
"Incoming quadrature collection is empty."));
1200 template <
int spacedim>
1203 const std::vector<std::reference_wrapper<
const Function<1>>>
1214 (*this->q_collection1D)[this->q_index];
1223 this->additional_data,
1224 this->q_partitioning);
1232 template <
int spacedim>
1235 const std::vector<std::reference_wrapper<
const Function<1>>>
1240 for (
const double root : roots)
1244 const double weight = 1;
1252 "The level set function has a gradient almost equal to 0."));
1255 this->q_partitioning.surface.push_back(point, weight, normal);
1261 template <
int spacedim>
1266 this->q_index = q_index;
1275 namespace DiscreteQuadratureGeneratorImplementation
1279 "The set_active_cell function has to be called before calling this function.");
1283 "The reference cell of the incoming cell must be a hypercube.");
1311 template <
int dim,
class VectorType = Vector<
double>>
1341 const unsigned int component = 0)
const override;
1352 const unsigned int component = 0)
const override;
1363 const unsigned int component = 0)
const override;
1405 std::vector<Polynomials::Polynomial<double>>
poly;
1420 template <
int dim,
class VectorType>
1424 : dof_handler(&dof_handler)
1433 template <
int dim,
class VectorType>
1439 &cell->get_triangulation() == &dof_handler->get_triangulation(),
1441 "The incoming cell must belong to the triangulation associated with "
1442 "the DoFHandler passed to the constructor."));
1445 &dof_handler->get_triangulation(),
1461 if (element->n_base_elements() == 1 &&
1472 element->base_element(0));
1474 polynomials_are_hat_functions =
1475 (poly.size() == 2 && poly[0].value(0.) == 1. &&
1476 poly[0].value(1.) == 0. && poly[1].value(0.) == 0. &&
1477 poly[1].value(1.) == 1.);
1483 local_dof_indices.resize(element->dofs_per_cell);
1486 local_dof_values.resize(element->dofs_per_cell);
1488 for (
unsigned int i = 0; i < local_dof_indices.size(); ++i)
1489 local_dof_values[i] =
1491 *global_dof_values, local_dof_indices[i]);
1496 template <
int dim,
class VectorType>
1502 return local_dof_values.size() > 0;
1507 template <
int dim,
class VectorType>
1511 const unsigned int component)
const
1516 if (!poly.empty() && component == 0)
1519 return ::internal::evaluate_tensor_product_value(
1523 polynomials_are_hat_functions,
1529 for (
unsigned int i = 0; i < local_dof_indices.size(); ++i)
1530 value += local_dof_values[i] *
1531 element->shape_value_component(i, point, component);
1539 template <
int dim,
class VectorType>
1543 const unsigned int component)
const
1548 if (!poly.empty() && component == 0)
1551 return ::internal::evaluate_tensor_product_value_and_gradient(
1555 polynomials_are_hat_functions,
1562 for (
unsigned int i = 0; i < local_dof_indices.size(); ++i)
1563 gradient += local_dof_values[i] *
1564 element->shape_grad_component(i, point, component);
1572 template <
int dim,
class VectorType>
1576 const unsigned int component)
const
1581 if (!poly.empty() && component == 0)
1584 return ::internal::evaluate_tensor_product_hessian(
1585 poly, local_dof_values, point, renumber);
1590 for (
unsigned int i = 0; i < local_dof_indices.size(); ++i)
1592 local_dof_values[i] *
1593 element->shape_grad_grad_component(i, point, component);
1604 const unsigned int max_box_splits,
1605 const double lower_bound_implicit_function,
1606 const double min_distance_between_roots,
1607 const double limit_to_be_definite,
1608 const double root_finder_tolerance,
1609 const unsigned int max_root_finder_splits,
1611 : max_box_splits(max_box_splits)
1612 , lower_bound_implicit_function(lower_bound_implicit_function)
1613 , min_distance_between_roots(min_distance_between_roots)
1614 , limit_to_be_definite(limit_to_be_definite)
1615 , root_finder_tolerance(root_finder_tolerance)
1616 , max_root_finder_splits(max_root_finder_splits)
1617 , split_in_half(split_in_half)
1626 : q_generator(q_collection, additional_data)
1629 ExcMessage(
"Incoming hp::QCollection<1> is empty."));
1639 Assert(level_set.n_components == 1,
1641 "The incoming function should be a scalar level set function,"
1642 " it should have one component."));
1645 q_generator.clear_quadratures();
1647 std::vector<std::reference_wrapper<const Function<dim>>>
level_sets;
1657 q_generator.get_quadratures().indefinite.size() == 0,
1659 "Generation of quadrature rules failed. This can mean that the level "
1660 "set function is degenerate in some way, e.g. oscillating extremely "
1670 return q_generator.get_quadratures().negative;
1679 return q_generator.get_quadratures().positive;
1688 return q_generator.get_quadratures().surface;
1696 q_generator.set_1D_quadrature(q_index);
1714 const unsigned int face_index)
1740 quadrature_generator.get_surface_quadrature();
1742 std::vector<Tensor<1, dim>> normals;
1752 normal /= normal.norm();
1753 normals.push_back(normal);
1767 quadrature_generator.set_1D_quadrature(q_index);
1776 return quadrature_generator.get_inside_quadrature();
1784 return quadrature_generator.get_outside_quadrature();
1793 return surface_quadrature;
1803 (void)additional_data;
1811 const unsigned int face_index)
1819 const unsigned int n_points = 1;
1820 const double weight = 1;
1821 const std::vector<Point<0>> points(n_points);
1822 const std::vector<double> weights(n_points, weight);
1855 return inside_quadrature;
1862 return outside_quadrature;
1870 return surface_quadrature;
1876 template <
class VectorType>
1880 const VectorType & level_set,
1883 , reference_space_level_set(
1884 std::make_unique<
internal::DiscreteQuadratureGeneratorImplementation::
1885 RefSpaceFEFieldFunction<dim, VectorType>>(
1897 Assert(cell->reference_cell().is_hyper_cube(),
1898 internal::DiscreteQuadratureGeneratorImplementation::
1899 ExcReferenceCellNotHypercube());
1901 reference_space_level_set->set_active_cell(cell);
1909 template <
class VectorType>
1913 const VectorType & level_set,
1916 , reference_space_level_set(
1917 std::make_unique<
internal::DiscreteQuadratureGeneratorImplementation::
1918 RefSpaceFEFieldFunction<dim, VectorType>>(
1929 const unsigned int face_index)
1931 Assert(cell->reference_cell().is_hyper_cube(),
1932 internal::DiscreteQuadratureGeneratorImplementation::
1933 ExcReferenceCellNotHypercube());
1935 reference_space_level_set->set_active_cell(cell);
1942#include "quadrature_generator.inst"
DiscreteFaceQuadratureGenerator(const hp::QCollection< 1 > &quadratures1D, const DoFHandler< dim > &dof_handler, const VectorType &level_set, const AdditionalData &additional_data=AdditionalData())
void generate(const typename Triangulation< dim >::active_cell_iterator &cell, const unsigned int face_index)
void generate(const typename Triangulation< dim >::active_cell_iterator &cell)
DiscreteQuadratureGenerator(const hp::QCollection< 1 > &quadratures1D, const DoFHandler< dim > &dof_handler, const VectorType &level_set, const AdditionalData &additional_data=AdditionalData())
const Quadrature< dim - 1 > & get_inside_quadrature() const
void generate(const Function< dim > &level_set, const BoundingBox< dim > &box, const unsigned int face_index)
void set_1D_quadrature(const unsigned int q_index)
FaceQuadratureGenerator(const hp::QCollection< 1 > &quadratures1D, const AdditionalData &additional_data=AdditionalData())
const ImmersedSurfaceQuadrature< dim - 1, dim > & get_surface_quadrature() const
const Quadrature< dim - 1 > & get_outside_quadrature() const
void set_1D_quadrature(const unsigned int q_index)
QuadratureGenerator(const hp::QCollection< 1 > &quadratures1D, const AdditionalData &additional_data=AdditionalData())
const Quadrature< dim > & get_inside_quadrature() const
const Quadrature< dim > & get_outside_quadrature() const
const ImmersedSurfaceQuadrature< dim > & get_surface_quadrature() const
void generate(const Function< dim > &level_set, const BoundingBox< dim > &box)
void set_active_cell(const typename Triangulation< dim >::active_cell_iterator &cell) override
Tensor< 1, dim > gradient(const Point< dim > &point, const unsigned int component=0) const override
double value(const Point< dim > &point, const unsigned int component=0) const override
std::vector< types::global_dof_index > local_dof_indices
bool polynomials_are_hat_functions
RefSpaceFEFieldFunction(const DoFHandler< dim > &dof_handler, const VectorType &dof_values)
const SmartPointer< const DoFHandler< dim > > dof_handler
std::vector< Polynomials::Polynomial< double > > poly
SymmetricTensor< 2, dim > hessian(const Point< dim > &point, const unsigned int component=0) const override
SmartPointer< const FiniteElement< dim > > element
std::vector< unsigned int > renumber
std::vector< typename VectorType::value_type > local_dof_values
const SmartPointer< const VectorType > global_dof_values
void push_back(const Point< dim > &point, const double weight)
ExtendableQuadrature()=default
const SmartPointer< const hp::QCollection< 1 > > q_collection1D
QGeneratorBase(const hp::QCollection< 1 > &q_collection1D, const AdditionalQGeneratorData &additional_data)
const QPartitioning< dim > & get_quadratures() const
QGenerator(const hp::QCollection< 1 > &q_collection1D, const AdditionalQGeneratorData &additional_data)
void set_1D_quadrature(const unsigned int q_index)
void create_high_dim_quadratures(const unsigned int height_function_direction, const std::vector< std::reference_wrapper< const Function< dim > > > &level_sets, const BoundingBox< dim > &box)
void generate(const std::vector< std::reference_wrapper< const Function< dim > > > &level_sets, const BoundingBox< dim > &box, const unsigned int n_box_splits)
hp::QCollection< dim > tensor_products
void use_midpoint_method(const std::vector< std::reference_wrapper< const Function< dim > > > &level_sets, const BoundingBox< dim > &box)
void split_box_and_recurse(const std::vector< std::reference_wrapper< const Function< dim > > > &level_sets, const BoundingBox< dim > &box, const std_cxx17::optional< HeightDirectionData > &direction_data, const unsigned int n_box_splits)
void create_low_dim_quadratures(const unsigned int height_function_direction, const std::vector< std::reference_wrapper< const Function< dim > > > &level_sets, const BoundingBox< dim > &box, const unsigned int n_box_splits)
ExtendableQuadrature< dim > & quadrature_by_definiteness(const Definiteness definiteness)
const AdditionalData additional_data
void find_roots(const std::vector< std::reference_wrapper< const Function< 1 > > > &functions, const BoundingBox< 1 > &interval, std::vector< double > &roots)
RootFinder(const AdditionalData &data=AdditionalData())
void generate(const std::vector< std::reference_wrapper< const Function< dim > > > &level_sets, const BoundingBox< dim > &box, const Quadrature< dim - 1 > &low_dim_quadrature, const unsigned int height_function_direction, QPartitioning< dim > &q_partitioning)
void set_1D_quadrature(const unsigned int q_index)
void create_surface_point(const Point< dim - 1 > &point, const double weight, const std::vector< std::reference_wrapper< const Function< dim > > > &level_sets, const BoundingBox< dim > &box, const unsigned int height_function_direction, ImmersedSurfaceQuadrature< dim > &surface_quadrature)
UpThroughDimensionCreator(const hp::QCollection< 1 > &q_collection1D, const AdditionalQGeneratorData &additional_data)
unsigned int size() const
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
#define Assert(cond, exc)
static ::ExceptionBase & ExcCellNotSet()
#define AssertIndexRange(index, range)
#define DeclExceptionMsg(Exception, defaulttext)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcReferenceCellNotHypercube()
static ::ExceptionBase & ExcMessage(std::string arg1)
typename ActiveSelector::active_cell_iterator active_cell_iterator
unsigned int compute_split_direction(const BoundingBox< dim > &box, const std_cxx17::optional< HeightDirectionData > &height_direction_data)
void distribute_points_between_roots(const Quadrature< 1 > &quadrature1D, const BoundingBox< 1 > &interval, const std::vector< double > &roots, const Point< dim - 1 > &point, const double weight, const unsigned int height_function_direction, const std::vector< std::reference_wrapper< const Function< 1 > > > &level_sets, const AdditionalQGeneratorData &additional_data, QPartitioning< dim > &q_partitioning)
double lower_bound_on_abs(const std::pair< double, double > &function_bounds)
void estimate_function_bounds(const std::vector< std::reference_wrapper< const Function< dim > > > &functions, const BoundingBox< dim > &box, std::vector< FunctionBounds< dim > > &all_function_bounds)
BoundingBox< dim > left_half(const BoundingBox< dim > &box, const unsigned int direction)
void add_tensor_product(const Quadrature< dim - 1 > &lower, const Quadrature< 1 > &quadrature1D, const double start, const double end, const unsigned int component_in_dim, ExtendableQuadrature< dim > &quadrature)
bool one_positive_one_negative_definite(const std::vector< FunctionBounds< dim > > &all_function_bounds)
std_cxx17::optional< HeightDirectionData > find_best_height_direction(const std::vector< FunctionBounds< dim > > &all_function_bounds)
void map_quadrature_to_box(const Quadrature< dim > &unit_quadrature, const BoundingBox< dim > &box, ExtendableQuadrature< dim > &quadrature)
std::pair< double, double > find_extreme_values(const std::vector< FunctionBounds< dim > > &all_function_bounds)
void tensor_point_with_1D_quadrature(const Point< dim - 1 > &point, const double weight, const Quadrature< 1 > &quadrature1D, const double start, const double end, const unsigned int component_in_dim, ExtendableQuadrature< dim > &quadrature)
void restrict_to_point(const std::vector< std::reference_wrapper< const Function< dim > > > &functions, const Point< dim - 1 > &point, const unsigned int open_direction, std::vector< Functions::PointRestriction< dim - 1 > > &restrictions)
std_cxx17::optional< unsigned int > direction_of_largest_extent(const BoundingBox< dim > &box)
BoundingBox< dim > right_half(const BoundingBox< dim > &box, const unsigned int direction)
bool is_indefinite(const std::pair< double, double > &function_bounds)
void take_min_max_at_vertices(const Function< dim > &function, const BoundingBox< dim > &box, std::pair< double, double > &value_bounds)
void restrict_to_top_and_bottom(const std::vector< std::reference_wrapper< const Function< dim > > > &functions, const BoundingBox< dim > &box, const unsigned int direction, std::vector< Functions::CoordinateRestriction< dim - 1 > > &restrictions)
Point< dim > face_projection_closest_zero_contour(const Point< dim - 1 > &point, const unsigned int direction, const BoundingBox< dim > &box, const Function< dim > &level_set)
Definiteness pointwise_definiteness(const std::vector< std::reference_wrapper< const Function< dim > > > &functions, const Point< dim > &point)
std::vector< Polynomials::Polynomial< double > > get_polynomial_space(const FiniteElement< dim, spacedim > &fe)
bool is_fast_path_supported(const FiniteElement< dim, spacedim > &fe, const unsigned int base_element_number)
Point< dim+1 > create_higher_dim_point(const Point< dim > &point, const unsigned int component_in_dim_plus_1, const double coordinate_value)
static const unsigned int invalid_unsigned_int
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
double min_distance_between_roots
AdditionalQGeneratorData(const unsigned int max_box_splits=4, const double lower_bound_implicit_function=1e-11, const double min_distance_between_roots=1e-12, const double limit_to_be_definite=1e-11, const double root_finder_tolerance=1e-12, const unsigned int max_root_finder_splits=2, bool split_in_half=true)
AdditionalData(const double tolerance=1e-12, const unsigned int max_recursion_depth=2, const unsigned int max_iterations=500)
void reinit(const Quadrature< dim_q > &quad, const FiniteElement< dim, spacedim > &fe_dim, const unsigned int base_element=0)
std::vector< unsigned int > lexicographic_numbering
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)