From e675c398197432b3aa05bd3e58f3dc4dfacf96e2 Mon Sep 17 00:00:00 2001 From: Christoph Lehmann <christoph.lehmann@ufz.de> Date: Wed, 9 Feb 2022 10:46:07 +0100 Subject: [PATCH] [NL] Added an integration method registry --- .../Integration/IntegrationMethodRegistry.cpp | 209 ++++++++++++++++++ .../Integration/IntegrationMethodRegistry.h | 32 +++ 2 files changed, 241 insertions(+) create mode 100644 NumLib/Fem/Integration/IntegrationMethodRegistry.cpp create mode 100644 NumLib/Fem/Integration/IntegrationMethodRegistry.h diff --git a/NumLib/Fem/Integration/IntegrationMethodRegistry.cpp b/NumLib/Fem/Integration/IntegrationMethodRegistry.cpp new file mode 100644 index 00000000000..b11841e5163 --- /dev/null +++ b/NumLib/Fem/Integration/IntegrationMethodRegistry.cpp @@ -0,0 +1,209 @@ +/** + * \file + * \copyright + * Copyright (c) 2012-2022, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + */ + +#include "IntegrationMethodRegistry.h" + +#include <unordered_map> + +#include "BaseLib/Error.h" +#include "GaussLegendreIntegrationPolicy.h" +#include "MeshLib/Elements/Elements.h" + +static constexpr unsigned MAX_ORDER_REGULAR = 4u; + +template <typename MeshElement> +using IntegrationPolicy = NumLib::GaussLegendreIntegrationPolicy<MeshElement>; + +template <typename IntegrationPolicy_> +static NumLib::GenericIntegrationMethod createGenericIntegrationMethod( + unsigned const order) +{ + typename IntegrationPolicy_::IntegrationMethod meth{order}; + unsigned const np = meth.getNumberOfPoints(); + + std::vector<MathLib::WeightedPoint> wps; + wps.reserve(np); + + for (unsigned ip = 0; ip < np; ++ip) + { + wps.emplace_back(meth.getWeightedPoint(ip)); + + if (wps.back() != meth.getWeightedPoint(ip)) + { + throw std::runtime_error( + "createGenericIntegrationMethod mismatch for ip=" + + std::to_string(ip) + ", order=" + std::to_string(order) + + ", method=" + typeid(decltype(meth)).name()); + } + } + + return NumLib::GenericIntegrationMethod{order, std::move(wps)}; +} + +template <typename MeshElement> +static void putIntegrationMethodsFor( + std::unordered_map<std::type_index, + std::vector<NumLib::GenericIntegrationMethod>>& + integration_methods_by_mesh_element_type, + unsigned max_order) +{ + std::vector<NumLib::GenericIntegrationMethod> integration_methods; + integration_methods.reserve(max_order + 1); + + // order 0 -> no valid weighted points + NumLib::GenericIntegrationMethod invalidMethod{0, {}}; + integration_methods.push_back(std::move(invalidMethod)); + + for (unsigned order = 1; order <= max_order; ++order) + { + integration_methods.push_back( + createGenericIntegrationMethod<IntegrationPolicy<MeshElement>>( + order)); + } + + integration_methods_by_mesh_element_type.emplace( + std::type_index(typeid(MeshElement)), std::move(integration_methods)); +} + +static void putIntegrationMethodsForDim0( + std::unordered_map<std::type_index, + std::vector<NumLib::GenericIntegrationMethod>>& + integration_methods_by_mesh_element_type) +{ + putIntegrationMethodsFor<MeshLib::Point>( + integration_methods_by_mesh_element_type, + MAX_ORDER_REGULAR /* arbitrary cutoff */); +} + +static void putIntegrationMethodsForDim1( + std::unordered_map<std::type_index, + std::vector<NumLib::GenericIntegrationMethod>>& + integration_methods_by_mesh_element_type) +{ + putIntegrationMethodsFor<MeshLib::Line>( + integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR); + + putIntegrationMethodsFor<MeshLib::Line3>( + integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR); +} + +static void putIntegrationMethodsForDim2( + std::unordered_map<std::type_index, + std::vector<NumLib::GenericIntegrationMethod>>& + integration_methods_by_mesh_element_type) +{ + putIntegrationMethodsFor<MeshLib::Quad>( + integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR); + + putIntegrationMethodsFor<MeshLib::Quad8>( + integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR); + + putIntegrationMethodsFor<MeshLib::Quad9>( + integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR); + + putIntegrationMethodsFor<MeshLib::Tri>( + integration_methods_by_mesh_element_type, 4); + + putIntegrationMethodsFor<MeshLib::Tri6>( + integration_methods_by_mesh_element_type, 4); +} + +static void putIntegrationMethodsForDim3( + std::unordered_map<std::type_index, + std::vector<NumLib::GenericIntegrationMethod>>& + integration_methods_by_mesh_element_type) +{ + putIntegrationMethodsFor<MeshLib::Hex>( + integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR); + + putIntegrationMethodsFor<MeshLib::Hex20>( + integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR); + + putIntegrationMethodsFor<MeshLib::Tet>( + integration_methods_by_mesh_element_type, 4); + + putIntegrationMethodsFor<MeshLib::Tet10>( + integration_methods_by_mesh_element_type, 4); + + // TODO max order 2? cf. IntegrationGaussLegendrePrism::getNumberOfPoints + // (only order 2) + putIntegrationMethodsFor<MeshLib::Prism>( + integration_methods_by_mesh_element_type, 2); + + putIntegrationMethodsFor<MeshLib::Prism15>( + integration_methods_by_mesh_element_type, 2); + + putIntegrationMethodsFor<MeshLib::Pyramid>( + integration_methods_by_mesh_element_type, 3); + + putIntegrationMethodsFor<MeshLib::Pyramid13>( + integration_methods_by_mesh_element_type, 3); +} + +static std::unordered_map<std::type_index, + std::vector<NumLib::GenericIntegrationMethod>> +initIntegrationMethods() +{ + std::unordered_map<std::type_index, + std::vector<NumLib::GenericIntegrationMethod>> + integration_methods_by_mesh_element_type; + + putIntegrationMethodsForDim0(integration_methods_by_mesh_element_type); + putIntegrationMethodsForDim1(integration_methods_by_mesh_element_type); + putIntegrationMethodsForDim2(integration_methods_by_mesh_element_type); + putIntegrationMethodsForDim3(integration_methods_by_mesh_element_type); + + return integration_methods_by_mesh_element_type; +} + +//! The actual integration method registry. +//! +//! A mapping \code [mesh element type] -> [list of integration +//! methods]\endcode, where each entry in the list corresponds to integration +//! order 0, 1, 2, ... +static const std::unordered_map<std::type_index, + std::vector<NumLib::GenericIntegrationMethod>> + integration_methods_by_mesh_element_type = initIntegrationMethods(); + +namespace NumLib::IntegrationMethodRegistry +{ +GenericIntegrationMethod const& getIntegrationMethod( + std::type_index const mesh_element_type, unsigned const order) +{ + if (order == 0) + { + // For 0D elements (points) the order does not matter, still we don't + // want order zero there. For all other element types integration order + // does matter. + OGS_FATAL("An integration order of 0 is not supported."); + } + + if (auto it = + integration_methods_by_mesh_element_type.find(mesh_element_type); + it != integration_methods_by_mesh_element_type.end()) + { + auto& integration_methods = it->second; + + if (order >= integration_methods.size()) + { + OGS_FATAL( + "Integration order {} is not supported for mesh elements of " + "type {}", + order, + mesh_element_type.name()); + } + + return integration_methods[order]; + } + + OGS_FATAL( + "No integration methods are available for mesh elements of type {}", + mesh_element_type.name()); +} +} // namespace NumLib diff --git a/NumLib/Fem/Integration/IntegrationMethodRegistry.h b/NumLib/Fem/Integration/IntegrationMethodRegistry.h new file mode 100644 index 00000000000..c9c551e28de --- /dev/null +++ b/NumLib/Fem/Integration/IntegrationMethodRegistry.h @@ -0,0 +1,32 @@ +/** + * \file + * \copyright + * Copyright (c) 2012-2022, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + */ + +#pragma once + +#include <typeindex> + +#include "GenericIntegrationMethod.h" + +namespace NumLib +{ +namespace IntegrationMethodRegistry +{ +//! Provides the default integration method for a given mesh element type and a +//! given integration order. +GenericIntegrationMethod const& getIntegrationMethod( + std::type_index const mesh_element_type, unsigned const order); + +//! Templated version of above method. Provided for convenience. +template <typename MeshElement> +GenericIntegrationMethod const& getIntegrationMethod(unsigned order) +{ + return getIntegrationMethod(std::type_index(typeid(MeshElement)), order); +} +} // namespace IntegrationMethodRegistry +} // namespace NumLib -- GitLab