/NumLib/Fem/Integration/IntegrationMethodRegistry.cpp

https://github.com/ufz/ogs · C++ · 214 lines · 152 code · 39 blank · 23 comment · 9 complexity · be4231f3d88166ea2e546c3edabe2272 MD5 · raw file

  1. /**
  2. * \file
  3. * \copyright
  4. * Copyright (c) 2012-2022, OpenGeoSys Community (http://www.opengeosys.org)
  5. * Distributed under a Modified BSD License.
  6. * See accompanying file LICENSE.txt or
  7. * http://www.opengeosys.org/project/license
  8. */
  9. #include "IntegrationMethodRegistry.h"
  10. #include <unordered_map>
  11. #include "BaseLib/Error.h"
  12. #include "GaussLegendreIntegrationPolicy.h"
  13. #include "MeshLib/Elements/Elements.h"
  14. static constexpr unsigned MAX_ORDER_REGULAR = 4u;
  15. template <typename MeshElement>
  16. using IntegrationPolicy = NumLib::GaussLegendreIntegrationPolicy<MeshElement>;
  17. template <typename IntegrationPolicy_>
  18. static NumLib::GenericIntegrationMethod createGenericIntegrationMethod(
  19. unsigned const order)
  20. {
  21. typename IntegrationPolicy_::IntegrationMethod meth{order};
  22. unsigned const np = meth.getNumberOfPoints();
  23. std::vector<MathLib::WeightedPoint> wps;
  24. wps.reserve(np);
  25. for (unsigned ip = 0; ip < np; ++ip)
  26. {
  27. wps.emplace_back(meth.getWeightedPoint(ip));
  28. if (wps.back() != meth.getWeightedPoint(ip))
  29. {
  30. throw std::runtime_error(
  31. "createGenericIntegrationMethod mismatch for ip=" +
  32. std::to_string(ip) + ", order=" + std::to_string(order) +
  33. ", method=" + typeid(decltype(meth)).name());
  34. }
  35. }
  36. return NumLib::GenericIntegrationMethod{order, std::move(wps)};
  37. }
  38. template <typename MeshElement>
  39. static void putIntegrationMethodsFor(
  40. std::unordered_map<std::type_index,
  41. std::vector<NumLib::GenericIntegrationMethod>>&
  42. integration_methods_by_mesh_element_type,
  43. unsigned max_order)
  44. {
  45. std::vector<NumLib::GenericIntegrationMethod> integration_methods;
  46. integration_methods.reserve(max_order + 1);
  47. // order 0 -> no valid weighted points
  48. NumLib::GenericIntegrationMethod invalidMethod{0, {}};
  49. integration_methods.push_back(std::move(invalidMethod));
  50. for (unsigned order = 1; order <= max_order; ++order)
  51. {
  52. integration_methods.push_back(
  53. createGenericIntegrationMethod<IntegrationPolicy<MeshElement>>(
  54. order));
  55. }
  56. integration_methods_by_mesh_element_type.emplace(
  57. std::type_index(typeid(MeshElement)), std::move(integration_methods));
  58. }
  59. static void putIntegrationMethodsForDim0(
  60. std::unordered_map<std::type_index,
  61. std::vector<NumLib::GenericIntegrationMethod>>&
  62. integration_methods_by_mesh_element_type)
  63. {
  64. putIntegrationMethodsFor<MeshLib::Point>(
  65. integration_methods_by_mesh_element_type,
  66. MAX_ORDER_REGULAR /* arbitrary cutoff */);
  67. }
  68. static void putIntegrationMethodsForDim1(
  69. std::unordered_map<std::type_index,
  70. std::vector<NumLib::GenericIntegrationMethod>>&
  71. integration_methods_by_mesh_element_type)
  72. {
  73. putIntegrationMethodsFor<MeshLib::Line>(
  74. integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR);
  75. putIntegrationMethodsFor<MeshLib::Line3>(
  76. integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR);
  77. }
  78. static void putIntegrationMethodsForDim2(
  79. std::unordered_map<std::type_index,
  80. std::vector<NumLib::GenericIntegrationMethod>>&
  81. integration_methods_by_mesh_element_type)
  82. {
  83. putIntegrationMethodsFor<MeshLib::Quad>(
  84. integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR);
  85. putIntegrationMethodsFor<MeshLib::Quad8>(
  86. integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR);
  87. putIntegrationMethodsFor<MeshLib::Quad9>(
  88. integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR);
  89. putIntegrationMethodsFor<MeshLib::Tri>(
  90. integration_methods_by_mesh_element_type, 4);
  91. putIntegrationMethodsFor<MeshLib::Tri6>(
  92. integration_methods_by_mesh_element_type, 4);
  93. }
  94. static void putIntegrationMethodsForDim3(
  95. std::unordered_map<std::type_index,
  96. std::vector<NumLib::GenericIntegrationMethod>>&
  97. integration_methods_by_mesh_element_type)
  98. {
  99. putIntegrationMethodsFor<MeshLib::Hex>(
  100. integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR);
  101. putIntegrationMethodsFor<MeshLib::Hex20>(
  102. integration_methods_by_mesh_element_type, MAX_ORDER_REGULAR);
  103. putIntegrationMethodsFor<MeshLib::Tet>(
  104. integration_methods_by_mesh_element_type, 4);
  105. putIntegrationMethodsFor<MeshLib::Tet10>(
  106. integration_methods_by_mesh_element_type, 4);
  107. putIntegrationMethodsFor<MeshLib::Prism>(
  108. integration_methods_by_mesh_element_type, 4);
  109. putIntegrationMethodsFor<MeshLib::Prism15>(
  110. integration_methods_by_mesh_element_type, 4);
  111. putIntegrationMethodsFor<MeshLib::Pyramid>(
  112. integration_methods_by_mesh_element_type, 3);
  113. putIntegrationMethodsFor<MeshLib::Pyramid13>(
  114. integration_methods_by_mesh_element_type, 3);
  115. }
  116. static std::unordered_map<std::type_index,
  117. std::vector<NumLib::GenericIntegrationMethod>>
  118. initIntegrationMethods()
  119. {
  120. std::unordered_map<std::type_index,
  121. std::vector<NumLib::GenericIntegrationMethod>>
  122. integration_methods_by_mesh_element_type;
  123. putIntegrationMethodsForDim0(integration_methods_by_mesh_element_type);
  124. putIntegrationMethodsForDim1(integration_methods_by_mesh_element_type);
  125. putIntegrationMethodsForDim2(integration_methods_by_mesh_element_type);
  126. putIntegrationMethodsForDim3(integration_methods_by_mesh_element_type);
  127. return integration_methods_by_mesh_element_type;
  128. }
  129. namespace NumLib::IntegrationMethodRegistry
  130. {
  131. GenericIntegrationMethod const& getIntegrationMethod(
  132. std::type_index const mesh_element_type, unsigned const order)
  133. {
  134. if (order == 0)
  135. {
  136. // For 0D elements (points) the order does not matter, still we don't
  137. // want order zero there. For all other element types integration order
  138. // does matter.
  139. OGS_FATAL("An integration order of 0 is not supported.");
  140. }
  141. // The actual integration method registry.
  142. //
  143. // A mapping \code [mesh element type] -> [list of integration
  144. // methods]\endcode, where each entry in the list corresponds to integration
  145. // order 0, 1, 2, ...
  146. //
  147. // Having this as a static __local__ variable circumvents the static
  148. // initialization order fiasco we would have if this was a static __global__
  149. // variable. The fiasco arises, because this registry uses static global
  150. // data from MathLib. Currently (Feb 2022) we cannot circumvent the problem
  151. // with constinit due to lack of compiler support.
  152. static const std::unordered_map<
  153. std::type_index,
  154. std::vector<NumLib::GenericIntegrationMethod>>
  155. integration_methods_by_mesh_element_type = initIntegrationMethods();
  156. if (auto it =
  157. integration_methods_by_mesh_element_type.find(mesh_element_type);
  158. it != integration_methods_by_mesh_element_type.end())
  159. {
  160. auto& integration_methods = it->second;
  161. if (order >= integration_methods.size())
  162. {
  163. OGS_FATAL(
  164. "Integration order {} is not supported for mesh elements of "
  165. "type {}",
  166. order,
  167. mesh_element_type.name());
  168. }
  169. return integration_methods[order];
  170. }
  171. OGS_FATAL(
  172. "No integration methods are available for mesh elements of type {}",
  173. mesh_element_type.name());
  174. }
  175. } // namespace NumLib::IntegrationMethodRegistry