diff --git a/CMakeLists.txt b/CMakeLists.txt index bb8832a50565bde6f37ab589737a15e08f116030..46126f9121cfafeb028c9d6f32a2ddf826c9fcf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,10 @@ cmake_minimum_required (VERSION 3.19) # CMake utils list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +set(CMAKE_INSTALL_LIBDIR "lib") +set(CMAKE_INSTALL_INCLUDEDIR "include") +set(CMAKE_INSTALL_BINDIR "bin") + # Forbids in-source builds include(CheckNotInSources) diff --git a/src/geometry/SquareTransformation.hpp b/src/geometry/SquareTransformation.hpp index d6474f33e4ecbaa4bcfba525dadc9fd38e95962d..b0e970c6eda673b48c5cf5c0d0a1ad7e73f8ef74 100644 --- a/src/geometry/SquareTransformation.hpp +++ b/src/geometry/SquareTransformation.hpp @@ -84,6 +84,25 @@ class SquareTransformation return m_coefficients * X + m_shift; } + PUGS_INLINE + TinyVector<Dimension> + areaVariation(const TinyVector<2>& X) const + { + const auto& T = m_coefficients; + const double& x = X[0]; + const double& y = X[1]; + + const TinyVector<Dimension> dxT{T(0, 0) + T(0, 2) * y, // + T(1, 0) + T(1, 2) * y, // + T(2, 0) + T(2, 2) * y}; + + const TinyVector<Dimension> dyT{T(0, 1) + T(0, 2) * x, // + T(1, 1) + T(1, 2) * x, // + T(2, 1) + T(2, 2) * x}; + + return crossProduct(dxT, dyT); + } + PUGS_INLINE double areaVariationNorm(const TinyVector<2>& X) const { diff --git a/src/geometry/TriangleTransformation.hpp b/src/geometry/TriangleTransformation.hpp index df8444d894a7ed56c0fe3825ffbf1cc14a742531..c49db368684d8c96aeb5061041828799e8509fac 100644 --- a/src/geometry/TriangleTransformation.hpp +++ b/src/geometry/TriangleTransformation.hpp @@ -66,6 +66,7 @@ class TriangleTransformation private: TinyMatrix<Dimension, 2> m_jacobian; TinyVector<Dimension> m_shift; + TinyVector<Dimension> m_area_variation; double m_area_variation_norm; public: @@ -76,6 +77,21 @@ class TriangleTransformation return m_jacobian * x + m_shift; } + PUGS_INLINE + TinyVector<Dimension> + areaVariation() const + { + return m_area_variation; + } + + PUGS_INLINE + TinyVector<Dimension> + areaVariation(const TinyVector<2>&) const + { + return m_area_variation; + } + + PUGS_INLINE double areaVariationNorm() const { @@ -92,7 +108,8 @@ class TriangleTransformation m_shift = a; - m_area_variation_norm = l2Norm(crossProduct(b - a, c - a)); + m_area_variation = crossProduct(b - a, c - a); + m_area_variation_norm = l2Norm(m_area_variation); } ~TriangleTransformation() = default; diff --git a/src/scheme/PolynomialReconstruction.cpp b/src/scheme/PolynomialReconstruction.cpp index c646dc4fbec060bf5983a24ec33ca8bdb2718725..923458cde39814ef9c1a841cf0cb30cf5eacbbb7 100644 --- a/src/scheme/PolynomialReconstruction.cpp +++ b/src/scheme/PolynomialReconstruction.cpp @@ -824,11 +824,7 @@ PolynomialReconstruction::_build( return this->_build<CellCenterReconstructionMatrixBuilder<MeshType>>(p_mesh, discrete_function_variant_list); } case IntegrationMethodType::boundary: { - if constexpr (MeshType::Dimension == 2) { - return this->_build<BoundaryIntegralReconstructionMatrixBuilder<MeshType>>(p_mesh, - discrete_function_variant_list); - } - [[fallthrough]]; + return this->_build<BoundaryIntegralReconstructionMatrixBuilder<MeshType>>(p_mesh, discrete_function_variant_list); } case IntegrationMethodType::element: { return this->_build<ElementIntegralReconstructionMatrixBuilder<MeshType>>(p_mesh, discrete_function_variant_list); diff --git a/src/scheme/reconstruction_utils/BoundaryIntegralReconstructionMatrixBuilder.cpp b/src/scheme/reconstruction_utils/BoundaryIntegralReconstructionMatrixBuilder.cpp index d030ac6d51d22d70eb209fa437a8684064d57529..7a9f7eded202a3cb98b74769cf4d23930a32c60f 100644 --- a/src/scheme/reconstruction_utils/BoundaryIntegralReconstructionMatrixBuilder.cpp +++ b/src/scheme/reconstruction_utils/BoundaryIntegralReconstructionMatrixBuilder.cpp @@ -1,20 +1,183 @@ #include <scheme/reconstruction_utils/BoundaryIntegralReconstructionMatrixBuilder.hpp> #include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureFormula.hpp> #include <analysis/QuadratureManager.hpp> #include <geometry/LineCubicTransformation.hpp> #include <geometry/LineParabolicTransformation.hpp> +#include <geometry/LineTransformation.hpp> +#include <geometry/SquareTransformation.hpp> #include <geometry/SymmetryUtils.hpp> -#include <mesh/Connectivity.hpp> +#include <geometry/TriangleTransformation.hpp> #include <mesh/Mesh.hpp> #include <mesh/MeshDataManager.hpp> #include <mesh/PolynomialMesh.hpp> #include <scheme/DiscreteFunctionDPk.hpp> template <MeshConcept MeshTypeT> +class PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<MeshTypeT>::SpecificDimensionalData +{ + private: + const ItemToItemMatrix<ItemType::cell, ItemType::face> m_cell_to_face_matrix; + const ItemToItemMatrix<ItemType::face, ItemType::node> m_face_to_node_matrix; + const FaceValuePerCell<const bool> m_cell_face_is_reversed; + + public: + PUGS_INLINE const auto& + cellToFaceMatrix() const noexcept + { + return m_cell_to_face_matrix; + } + + PUGS_INLINE + const auto& + faceToNodeMatrix() const noexcept + { + return m_face_to_node_matrix; + } + + PUGS_INLINE + const auto& + cellFaceIsReversed() const noexcept + { + return m_cell_face_is_reversed; + } + + SpecificDimensionalData(const Connectivity<MeshType::Dimension>& connectivity) + : m_cell_to_face_matrix{connectivity.cellToFaceMatrix()}, + m_face_to_node_matrix{connectivity.faceToNodeMatrix()}, + m_cell_face_is_reversed{connectivity.cellFaceIsReversed()} + {} + + ~SpecificDimensionalData() = default; +}; + +template <> +class PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<Mesh<1>>::SpecificDimensionalData +{ + private: + const ItemToItemMatrix<ItemType::cell, ItemType::node> m_cell_to_node_matrix; + + public: + PUGS_INLINE + const auto& + cellToNodeMatrix() const noexcept + { + return m_cell_to_node_matrix; + } + + SpecificDimensionalData(const Connectivity<1>& connectivity) : m_cell_to_node_matrix{connectivity.cellToNodeMatrix()} + {} + + ~SpecificDimensionalData() = default; +}; + +template <> +template <typename ConformTransformationT> +void +PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<Mesh<3>>::_computeEjkBoundaryMean( + const QuadratureFormula<MeshType::Dimension - 1>& quadrature, + const ConformTransformationT& T, + const Rd& Xj, + const double inv_Vi, + SmallArray<double>& mean_of_ejk) +{ + for (size_t i_q = 0; i_q < quadrature.numberOfPoints(); ++i_q) { + const double wq = quadrature.weight(i_q); + const TinyVector<2> xi_q = quadrature.point(i_q); + + const double area_variation_e1 = T.areaVariation(xi_q)[0] * inv_Vi; + + const Rd X_Xj = T(xi_q) - Xj; + + const double x_xj = X_Xj[0]; + const double y_yj = X_Xj[1]; + const double z_zj = X_Xj[2]; + + { + size_t k = 0; + m_tmp_array[k++] = x_xj * wq * area_variation_e1; + for (; k <= m_polynomial_degree; ++k) { + m_tmp_array[k] // + = x_xj * m_tmp_array[k - 1] * m_antiderivative_correction_coef[k]; // ((1. * k) / (k + 1)); + } + + for (size_t i_y = 1; i_y <= m_polynomial_degree; ++i_y) { + const size_t begin_i_y_1 = m_yz_row_index[i_y - 1]; + const size_t nb_monoms = m_yz_row_size[i_y]; + for (size_t l = 0; l < nb_monoms; ++l, ++k) { + m_tmp_array[k] = y_yj * m_tmp_array[begin_i_y_1 + l]; + } + } + + for (size_t i_z = 1; i_z <= m_polynomial_degree; ++i_z) { + const size_t nb_y = m_yz_row_size[m_z_triangle_index[i_z]]; + const size_t index_z = m_z_triangle_index[i_z]; + const size_t index_z_1 = m_z_triangle_index[i_z - 1]; + for (size_t i_y = 0; i_y < nb_y; ++i_y) { + const size_t begin_i_yz_1 = m_yz_row_index[index_z_1 + i_y]; + const size_t nb_monoms = m_yz_row_size[index_z + i_y]; + for (size_t l = 0; l < nb_monoms; ++l, ++k) { + m_tmp_array[k] = z_zj * m_tmp_array[begin_i_yz_1 + l]; + } + } + } + } + + for (size_t k = 1; k < m_basis_dimension; ++k) { + mean_of_ejk[k - 1] += m_tmp_array[k]; + } + } +} + +template <> template <typename ConformTransformationT> void -PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<MeshTypeT>::_computeEjkBoundaryMean( +PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<Mesh<2>>::_computeEjkBoundaryMean( + const QuadratureFormula<MeshType::Dimension - 1>& quadrature, + const ConformTransformationT& T, + const Rd& Xj, + const double inv_Vi, + SmallArray<double>& mean_of_ejk) +{ + const double velocity_perp_e1 = T.velocity()[1] * inv_Vi; + + for (size_t i_q = 0; i_q < quadrature.numberOfPoints(); ++i_q) { + const double wq = quadrature.weight(i_q); + const TinyVector<1> xi_q = quadrature.point(i_q); + + const Rd X_Xj = T(xi_q) - Xj; + + const double x_xj = X_Xj[0]; + const double y_yj = X_Xj[1]; + + { + size_t k = 0; + m_tmp_array[k++] = x_xj * wq * velocity_perp_e1; + for (; k <= m_polynomial_degree; ++k) { + m_tmp_array[k] // + = x_xj * m_tmp_array[k - 1] * m_antiderivative_correction_coef[k]; // ((1. * k) / (k + 1)); + } + + for (size_t i_y = 1; i_y <= m_polynomial_degree; ++i_y) { + const size_t begin_i_y_1 = m_y_row_index[i_y - 1]; + for (size_t l = 0; l <= m_polynomial_degree - i_y; ++l) { + m_tmp_array[k++] = y_yj * m_tmp_array[begin_i_y_1 + l]; + } + } + } + + for (size_t k = 1; k < m_basis_dimension; ++k) { + mean_of_ejk[k - 1] += m_tmp_array[k]; + } + } +} + +template <> +template <typename ConformTransformationT> +void +PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<PolynomialMesh<2>>::_computeEjkBoundaryMean( const QuadratureFormula<MeshType::Dimension - 1>& quadrature, const ConformTransformationT& T, const Rd& Xj, @@ -34,25 +197,26 @@ PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<MeshTypeT> const double y_yj = X_Xj[1]; { - size_t k = 0; - m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[k++] = x_xj * wq * velocity_perp_e1; + size_t k = 0; + m_tmp_array[k++] = x_xj * wq * velocity_perp_e1; for (; k <= m_polynomial_degree; ++k) { - m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[k] = - x_xj * m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[k - 1] * m_antiderivative_coef[k]; + m_tmp_array[k] // + = x_xj * m_tmp_array[k - 1] * m_antiderivative_correction_coef[k]; // ((1. * k) / (k + 1)); } for (size_t i_y = 1; i_y <= m_polynomial_degree; ++i_y) { - const size_t begin_i_y_1 = ((i_y - 1) * (2 * m_polynomial_degree - i_y + 4)) / 2; + const size_t begin_i_y_1 = m_y_row_index[i_y - 1]; for (size_t l = 0; l <= m_polynomial_degree - i_y; ++l) { - m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[k++] = y_yj * m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[begin_i_y_1 + l]; + m_tmp_array[k++] = y_yj * m_tmp_array[begin_i_y_1 + l]; } } } for (size_t k = 1; k < m_basis_dimension; ++k) { - mean_of_ejk[k - 1] += m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[k]; + mean_of_ejk[k - 1] += m_tmp_array[k]; } } + } else { for (size_t i_q = 0; i_q < quadrature.numberOfPoints(); ++i_q) { const double wq = quadrature.weight(i_q); @@ -66,23 +230,22 @@ PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<MeshTypeT> const double y_yj = X_Xj[1]; { - size_t k = 0; - m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[k++] = x_xj * wq * velocity_perp_e1; + size_t k = 0; + m_tmp_array[k++] = x_xj * wq * velocity_perp_e1; for (; k <= m_polynomial_degree; ++k) { - m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[k] = - x_xj * m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[k - 1] * m_antiderivative_coef[k]; + m_tmp_array[k] = x_xj * m_tmp_array[k - 1] * m_antiderivative_correction_coef[k]; } for (size_t i_y = 1; i_y <= m_polynomial_degree; ++i_y) { const size_t begin_i_y_1 = ((i_y - 1) * (2 * m_polynomial_degree - i_y + 4)) / 2; for (size_t l = 0; l <= m_polynomial_degree - i_y; ++l) { - m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[k++] = y_yj * m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[begin_i_y_1 + l]; + m_tmp_array[k++] = y_yj * m_tmp_array[begin_i_y_1 + l]; } } } for (size_t k = 1; k < m_basis_dimension; ++k) { - mean_of_ejk[k - 1] += m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek[k]; + mean_of_ejk[k - 1] += m_tmp_array[k]; } } } @@ -96,24 +259,69 @@ PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<MeshTypeT> SmallArray<double>& mean_of_ejk) { if constexpr (is_polygonal_mesh_v<MeshType>) { - const auto& quadrature = - QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(m_polynomial_degree + 1)); - const double inv_Vi = 1. / m_Vj[cell_id]; + const auto& face_is_reversed = m_dimensional_data_ptr->cellFaceIsReversed()[cell_id]; + const auto& cell_face_list = m_dimensional_data_ptr->cellToFaceMatrix()[cell_id]; + const auto& face_to_node_matrix = m_dimensional_data_ptr->faceToNodeMatrix(); + mean_of_ejk.fill(0); - auto cell_face_list = m_cell_to_face_matrix[cell_id]; - for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { - bool is_reversed = m_cell_face_is_reversed[cell_id][i_face]; - const FaceId face_id = cell_face_list[i_face]; - auto face_node_list = m_face_to_node_matrix[face_id]; - if (is_reversed) { - const LineTransformation<2> T{m_xr[face_node_list[1]], m_xr[face_node_list[0]]}; - _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); - } else { - const LineTransformation<2> T{m_xr[face_node_list[0]], m_xr[face_node_list[1]]}; - _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); + if constexpr (MeshType::Dimension == 2) { + const auto& quadrature = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(m_polynomial_degree + 1)); + + for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { + const FaceId face_id = cell_face_list[i_face]; + auto face_node_list = face_to_node_matrix[face_id]; + if (face_is_reversed[i_face]) { + const LineTransformation<2> T{m_xr[face_node_list[1]], m_xr[face_node_list[0]]}; + _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); + } else { + const LineTransformation<2> T{m_xr[face_node_list[0]], m_xr[face_node_list[1]]}; + _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); + } + } + } else { + static_assert(MeshType::Dimension == 3); + + const auto& triangle_quadrature = + QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(m_polynomial_degree + 1)); + const auto& square_quadrature = + QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(m_polynomial_degree + 1)); + + for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { + const FaceId face_id = cell_face_list[i_face]; + auto face_node_list = face_to_node_matrix[face_id]; + switch (face_node_list.size()) { + case 3: { + if (face_is_reversed[i_face]) { + const TriangleTransformation<3> T{m_xr[face_node_list[2]], m_xr[face_node_list[1]], + m_xr[face_node_list[0]]}; + _computeEjkBoundaryMean(triangle_quadrature, T, Xj, inv_Vi, mean_of_ejk); + } else { + const TriangleTransformation<3> T{m_xr[face_node_list[0]], m_xr[face_node_list[1]], + m_xr[face_node_list[2]]}; + _computeEjkBoundaryMean(triangle_quadrature, T, Xj, inv_Vi, mean_of_ejk); + } + break; + } + case 4: { + if (face_is_reversed[i_face]) { + const SquareTransformation<3> T{m_xr[face_node_list[3]], m_xr[face_node_list[2]], m_xr[face_node_list[1]], + m_xr[face_node_list[0]]}; + _computeEjkBoundaryMean(square_quadrature, T, Xj, inv_Vi, mean_of_ejk); + } else { + const SquareTransformation<3> T{m_xr[face_node_list[0]], m_xr[face_node_list[1]], m_xr[face_node_list[2]], + m_xr[face_node_list[3]]}; + _computeEjkBoundaryMean(square_quadrature, T, Xj, inv_Vi, mean_of_ejk); + } + break; + } + default: { + throw NotImplementedError("invalid face type"); + } + } } } } else { @@ -126,17 +334,31 @@ PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<MeshTypeT> const double inv_Vi = 1. / m_Vj[cell_id]; + const auto& face_is_reversed = m_dimensional_data_ptr->cellFaceIsReversed()[cell_id]; + const auto& cell_face_list = m_dimensional_data_ptr->cellToFaceMatrix()[cell_id]; + const auto& face_to_node_matrix = m_dimensional_data_ptr->faceToNodeMatrix(); + auto xr = m_mesh.xr(); auto xl = m_mesh.xl(); mean_of_ejk.fill(0); - auto cell_face_list = m_cell_to_face_matrix[cell_id]; + for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { - bool is_reversed = m_cell_face_is_reversed[cell_id][i_face]; + bool is_reversed = face_is_reversed[i_face]; const FaceId face_id = cell_face_list[i_face]; - auto face_node_list = m_face_to_node_matrix[face_id]; -#warning rework + auto face_node_list = face_to_node_matrix[face_id]; + switch (m_mesh.degree()) { + case 1: { + if (is_reversed) { + const LineTransformation<2> T{xr[face_node_list[1]], xr[face_node_list[0]]}; + _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); + } else { + const LineTransformation<2> T{xr[face_node_list[0]], xr[face_node_list[1]]}; + _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); + } + break; + } case 2: { if (is_reversed) { const LineParabolicTransformation<2> T{xr[face_node_list[1]], xl[face_id][0], xr[face_node_list[0]]}; @@ -178,29 +400,79 @@ PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder< const CellId& cell_id, SmallArray<double>& mean_of_ejk) { - if constexpr (is_polygonal_mesh_v<MeshType>) { - const auto& quadrature = - QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(m_polynomial_degree + 1)); + const double inv_Vi = 1. / m_Vj[cell_id]; - const double inv_Vi = 1. / m_Vj[cell_id]; + const auto& face_is_reversed = m_dimensional_data_ptr->cellFaceIsReversed()[cell_id]; + const auto& cell_face_list = m_dimensional_data_ptr->cellToFaceMatrix()[cell_id]; + const auto& face_to_node_matrix = m_dimensional_data_ptr->faceToNodeMatrix(); - mean_of_ejk.fill(0); - auto cell_face_list = m_cell_to_face_matrix[cell_id]; - for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { - bool is_reversed = m_cell_face_is_reversed[cell_id][i_face]; + mean_of_ejk.fill(0); - const FaceId face_id = cell_face_list[i_face]; - auto face_node_list = m_face_to_node_matrix[face_id]; + if constexpr (is_polygonal_mesh_v<MeshType>) { + if constexpr (MeshType::Dimension == 2) { + const auto& quadrature = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(m_polynomial_degree + 1)); + + for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { + const FaceId face_id = cell_face_list[i_face]; + auto face_node_list = face_to_node_matrix[face_id]; - const auto x0 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[1]]); - const auto x1 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[0]]); + const auto x0 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[1]]); + const auto x1 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[0]]); - if (is_reversed) { - const LineTransformation<2> T{x1, x0}; - _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); - } else { - const LineTransformation<2> T{x0, x1}; - _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); + if (face_is_reversed[i_face]) { + const LineTransformation<2> T{x1, x0}; + _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); + } else { + const LineTransformation<2> T{x0, x1}; + _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); + } + } + } else { + static_assert(MeshType::Dimension == 3); + + const auto& triangle_quadrature = + QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(m_polynomial_degree + 1)); + const auto& square_quadrature = + QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(m_polynomial_degree + 1)); + + for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { + const FaceId face_id = cell_face_list[i_face]; + auto face_node_list = face_to_node_matrix[face_id]; + switch (face_node_list.size()) { + case 3: { + const auto x0 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[2]]); + const auto x1 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[1]]); + const auto x2 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[0]]); + + if (face_is_reversed[i_face]) { + const TriangleTransformation<3> T{x2, x1, x0}; + _computeEjkBoundaryMean(triangle_quadrature, T, Xj, inv_Vi, mean_of_ejk); + } else { + const TriangleTransformation<3> T{x0, x1, x2}; + _computeEjkBoundaryMean(triangle_quadrature, T, Xj, inv_Vi, mean_of_ejk); + } + break; + } + case 4: { + const auto x0 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[3]]); + const auto x1 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[2]]); + const auto x2 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[1]]); + const auto x3 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[0]]); + + if (face_is_reversed[i_face]) { + const SquareTransformation<3> T{x3, x2, x1, x0}; + _computeEjkBoundaryMean(square_quadrature, T, Xj, inv_Vi, mean_of_ejk); + } else { + const SquareTransformation<3> T{x0, x1, x2, x3}; + _computeEjkBoundaryMean(square_quadrature, T, Xj, inv_Vi, mean_of_ejk); + } + break; + } + default: { + throw NotImplementedError("invalid face type"); + } + } } } } else { @@ -211,19 +483,28 @@ PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder< const auto& quadrature = QuadratureManager::instance().getLineFormula( GaussLegendreQuadratureDescriptor((m_polynomial_degree + 1) * m_mesh.degree() + (m_mesh.degree() - 1))); - const double inv_Vi = 1. / m_Vj[cell_id]; - auto xl = m_mesh.xl(); - mean_of_ejk.fill(0); - auto cell_face_list = m_cell_to_face_matrix[cell_id]; for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { - bool is_reversed = m_cell_face_is_reversed[cell_id][i_face]; + bool is_reversed = face_is_reversed[i_face]; const FaceId face_id = cell_face_list[i_face]; - auto face_node_list = m_face_to_node_matrix[face_id]; + auto face_node_list = face_to_node_matrix[face_id]; switch (m_mesh.degree()) { + case 1: { + const auto x0 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[1]]); + const auto x2 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[0]]); + + if (is_reversed) { + const LineTransformation<2> T{x2, x0}; + _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); + } else { + const LineTransformation<2> T{x0, x2}; + _computeEjkBoundaryMean(quadrature, T, Xj, inv_Vi, mean_of_ejk); + } + break; + } case 2: { const auto x0 = symmetrize_coordinates(origin, normal, m_xr[face_node_list[1]]); const auto x1 = symmetrize_coordinates(origin, normal, xl[face_id][0]); @@ -263,13 +544,87 @@ PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder< } } +template <> +void +PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<Mesh<1>>::_computeEjkMeanByBoundary( + const Rd& Xj, + const CellId& cell_id, + SmallArray<double>& mean_of_ejk) +{ + const double inv_Vi = 1. / m_Vj[cell_id]; + + const auto& cell_node_list = m_dimensional_data_ptr->cellToNodeMatrix()[cell_id]; + + const double xr1_xj = (m_xr[cell_node_list[1]] - Xj)[0]; + + m_tmp_array[0] = xr1_xj * inv_Vi; + for (size_t k = 1; k <= m_polynomial_degree; ++k) { + m_tmp_array[k] // + = xr1_xj * m_tmp_array[k - 1] * m_antiderivative_correction_coef[k]; // ((1. * k) / (k + 1)); + } + + for (size_t k = 1; k < m_basis_dimension; ++k) { + mean_of_ejk[k - 1] = m_tmp_array[k]; + } + + const double xr0_xj = (m_xr[cell_node_list[0]] - Xj)[0]; + + m_tmp_array[0] = xr0_xj * inv_Vi; + for (size_t k = 1; k <= m_polynomial_degree; ++k) { + m_tmp_array[k] // + = xr0_xj * m_tmp_array[k - 1] * m_antiderivative_correction_coef[k]; // ((1. * k) / (k + 1)); + } + + for (size_t k = 1; k < m_basis_dimension; ++k) { + mean_of_ejk[k - 1] -= m_tmp_array[k]; + } +} + +template <> +void +PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder< + Mesh<1>>::_computeEjkMeanByBoundaryInSymmetricCell(const Rd& origin, + const Rd& normal, + const Rd& Xj, + const CellId& cell_id, + SmallArray<double>& mean_of_ejk) +{ + const double inv_Vi = 1. / m_Vj[cell_id]; + + const auto& cell_node_list = m_dimensional_data_ptr->cellToNodeMatrix()[cell_id]; + + const double xr1_xj = (symmetrize_coordinates(origin, normal, m_xr[cell_node_list[0]]) - Xj)[0]; + + m_tmp_array[0] = xr1_xj * inv_Vi; + for (size_t k = 1; k <= m_polynomial_degree; ++k) { + m_tmp_array[k] // + = xr1_xj * m_tmp_array[k - 1] * m_antiderivative_correction_coef[k]; // ((1. * k) / (k + 1)); + } + + for (size_t k = 1; k < m_basis_dimension; ++k) { + mean_of_ejk[k - 1] = m_tmp_array[k]; + } + + const double xr0_xj = (symmetrize_coordinates(origin, normal, m_xr[cell_node_list[1]]) - Xj)[0]; + + m_tmp_array[0] = xr0_xj * inv_Vi; + for (size_t k = 1; k <= m_polynomial_degree; ++k) { + m_tmp_array[k] // + = xr0_xj * m_tmp_array[k - 1] * m_antiderivative_correction_coef[k]; // ((1. * k) / (k + 1)); + } + + for (size_t k = 1; k < m_basis_dimension; ++k) { + mean_of_ejk[k - 1] -= m_tmp_array[k]; + } +} + template <MeshConcept MeshTypeT> void PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<MeshTypeT>::build( const CellId cell_j_id, ShrinkMatrixView<SmallMatrix<double>>& A) { - if constexpr (MeshType::Dimension == 2) { + if constexpr (MeshType::Dimension <= 3) { const auto& stencil_cell_list = m_stencil_array[cell_j_id]; const Rd& Xj = m_xj[cell_j_id]; @@ -319,12 +674,12 @@ PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder< m_basis_dimension{ DiscreteFunctionDPk<MeshType::Dimension, double>::BasisViewType::dimensionFromDegree(polynomial_degree)}, m_polynomial_degree{polynomial_degree}, - m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek{m_basis_dimension}, + m_tmp_array{m_basis_dimension}, m_mean_j_of_ejk{m_basis_dimension - 1}, m_mean_i_of_ejk{m_basis_dimension - 1}, - m_cell_to_face_matrix{mesh.connectivity().cellToFaceMatrix()}, - m_face_to_node_matrix{mesh.connectivity().faceToNodeMatrix()}, - m_cell_face_is_reversed{mesh.connectivity().cellFaceIsReversed()}, + + m_dimensional_data_ptr{std::make_shared<SpecificDimensionalData>(mesh.connectivity())}, + m_stencil_array{stencil_array}, m_symmetry_origin_list{symmetry_origin_list}, m_symmetry_normal_list{symmetry_normal_list}, @@ -332,16 +687,59 @@ PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder< m_xj{MeshDataManager::instance().getMeshData(mesh).xj()}, m_xr{mesh.xr()} { + SmallArray<double> antiderivative_correction_coef(m_polynomial_degree + 1); + for (size_t k = 0; k < antiderivative_correction_coef.size(); ++k) { + // The antiderivative of x^k is k/(k+1) times the antiderivative of x^(k-1) + antiderivative_correction_coef[k] = ((1. * k) / (k + 1)); + } + + m_antiderivative_correction_coef = antiderivative_correction_coef; + if constexpr (MeshType::Dimension == 2) { - SmallArray<double> antiderivative_coef(m_polynomial_degree + 1); - for (size_t k = 0; k < antiderivative_coef.size(); ++k) { - antiderivative_coef[k] = ((1. * k) / (k + 1)); + SmallArray<size_t> y_row_index(m_polynomial_degree + 1); + + size_t i_y = 0; + + y_row_index[i_y++] = 0; + for (ssize_t n = m_polynomial_degree + 1; n > 1; --n, ++i_y) { + y_row_index[i_y] = y_row_index[i_y - 1] + n; } - m_antiderivative_coef = antiderivative_coef; + m_y_row_index = y_row_index; + + } else if constexpr (MeshType::Dimension == 3) { + SmallArray<size_t> yz_row_index((m_polynomial_degree + 2) * (m_polynomial_degree + 1) / 2 + 1); + SmallArray<size_t> z_triangle_index(m_polynomial_degree + 1); + + { + size_t i_z = 0; + size_t i_yz = 0; + + yz_row_index[i_yz++] = 0; + for (ssize_t n = m_polynomial_degree + 1; n >= 1; --n) { + z_triangle_index[i_z++] = i_yz - 1; + for (ssize_t i = n; i >= 1; --i) { + yz_row_index[i_yz] = yz_row_index[i_yz - 1] + i; + ++i_yz; + } + } + } + + SmallArray<size_t> yz_row_size{yz_row_index.size() - 1}; + for (size_t i = 0; i < yz_row_size.size(); ++i) { + yz_row_size[i] = yz_row_index[i + 1] - yz_row_index[i]; + } + + m_yz_row_index = yz_row_index; + m_z_triangle_index = z_triangle_index; + m_yz_row_size = yz_row_size; } } +template void PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<Mesh<1>>::build( + const CellId, + ShrinkMatrixView<SmallMatrix<double>>&); + template void PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<Mesh<2>>::build( const CellId, ShrinkMatrixView<SmallMatrix<double>>&); @@ -350,6 +748,17 @@ template void PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuil const CellId, ShrinkMatrixView<SmallMatrix<double>>&); +template void PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder<Mesh<3>>::build( + const CellId, + ShrinkMatrixView<SmallMatrix<double>>&); + +template PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder< + Mesh<1>>::BoundaryIntegralReconstructionMatrixBuilder(const MeshType&, + const size_t, + const SmallArray<const Rd>&, + const SmallArray<const Rd>&, + const CellToCellStencilArray&); + template PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder< Mesh<2>>::BoundaryIntegralReconstructionMatrixBuilder(const MeshType&, const size_t, @@ -363,3 +772,9 @@ template PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder< const SmallArray<const Rd>&, const SmallArray<const Rd>&, const CellToCellStencilArray&); +template PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder< + Mesh<3>>::BoundaryIntegralReconstructionMatrixBuilder(const MeshType&, + const size_t, + const SmallArray<const Rd>&, + const SmallArray<const Rd>&, + const CellToCellStencilArray&); diff --git a/src/scheme/reconstruction_utils/BoundaryIntegralReconstructionMatrixBuilder.hpp b/src/scheme/reconstruction_utils/BoundaryIntegralReconstructionMatrixBuilder.hpp index df24d76a73097d13f6379681780d90aed6f49e1d..60707189b909e9d5f17ae2852be655cbfb877351 100644 --- a/src/scheme/reconstruction_utils/BoundaryIntegralReconstructionMatrixBuilder.hpp +++ b/src/scheme/reconstruction_utils/BoundaryIntegralReconstructionMatrixBuilder.hpp @@ -3,14 +3,14 @@ #include <algebra/ShrinkMatrixView.hpp> #include <algebra/SmallMatrix.hpp> -#include <analysis/QuadratureFormula.hpp> -#include <geometry/LineTransformation.hpp> #include <mesh/ItemValue.hpp> #include <mesh/StencilArray.hpp> -#include <mesh/SubItemValuePerItem.hpp> #include <scheme/PolynomialReconstruction.hpp> #include <utils/SmallArray.hpp> +template <size_t Dimension> +class QuadratureFormula; + template <MeshConcept MeshTypeT> class PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder { @@ -26,13 +26,12 @@ class PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder const size_t m_basis_dimension; const size_t m_polynomial_degree; - const SmallArray<double> m_inv_Vj_alpha_p_1_wq_X_prime_orth_ek; + const SmallArray<double> m_tmp_array; SmallArray<double> m_mean_j_of_ejk; SmallArray<double> m_mean_i_of_ejk; - const ItemToItemMatrix<ItemType::cell, ItemType::face> m_cell_to_face_matrix; - const ItemToItemMatrix<ItemType::face, ItemType::node> m_face_to_node_matrix; - const FaceValuePerCell<const bool> m_cell_face_is_reversed; + class SpecificDimensionalData; + std::shared_ptr<SpecificDimensionalData> m_dimensional_data_ptr; const CellToCellStencilArray& m_stencil_array; @@ -43,7 +42,15 @@ class PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder const CellValue<const Rd> m_xj; const NodeValue<const Rd> m_xr; - SmallArray<const double> m_antiderivative_coef; + // 2D + SmallArray<const size_t> m_y_row_index; + + // 3D + SmallArray<const size_t> m_yz_row_index; + SmallArray<const size_t> m_z_triangle_index; + SmallArray<const size_t> m_yz_row_size; + + SmallArray<const double> m_antiderivative_correction_coef; template <typename ConformTransformationT> void _computeEjkBoundaryMean(const QuadratureFormula<MeshType::Dimension - 1>& quadrature, @@ -76,7 +83,6 @@ class PolynomialReconstruction::BoundaryIntegralReconstructionMatrixBuilder const SmallArray<const Rd>& symmetry_normal_list, const CellToCellStencilArray& stencil_array); - BoundaryIntegralReconstructionMatrixBuilder() = default; ~BoundaryIntegralReconstructionMatrixBuilder() = default; }; diff --git a/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.cpp b/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.cpp index 198dba9afe1faf1c324a8c03ae68376dc27ac799..24579e0594276b7a1a992aa3d2e8bd09375e333a 100644 --- a/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.cpp +++ b/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.cpp @@ -2,6 +2,8 @@ #include <analysis/GaussLegendreQuadratureDescriptor.hpp> #include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureFormula.hpp> +#include <analysis/QuadratureManager.hpp> #include <geometry/CubeTransformation.hpp> #include <geometry/LineTransformation.hpp> #include <geometry/PrismTransformation.hpp> @@ -76,13 +78,7 @@ PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder<MeshTypeT>: } else if constexpr (MeshType::Dimension == 3) { static_assert(MeshType::Dimension == 3); - const double detT = [&] { - if constexpr (std::is_same_v<TetrahedronTransformation, std::decay_t<decltype(T)>>) { - return T.jacobianDeterminant(); - } else { - return T.jacobianDeterminant(xi_q); - } - }(); + const double detT = T.jacobianDeterminant(xi_q); const double x_xj = X_Xj[0]; const double y_yj = X_Xj[1]; diff --git a/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.hpp b/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.hpp index 1f4573438260e321dbd1461d2566f854236b25f4..7a3e8f7fc04d6d4ba21d4a36ed02ba24dd0d67d0 100644 --- a/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.hpp +++ b/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.hpp @@ -3,14 +3,15 @@ #include <algebra/ShrinkMatrixView.hpp> #include <algebra/SmallMatrix.hpp> -#include <analysis/QuadratureFormula.hpp> -#include <analysis/QuadratureManager.hpp> #include <mesh/CellType.hpp> #include <mesh/ItemValue.hpp> #include <mesh/StencilArray.hpp> #include <scheme/PolynomialReconstruction.hpp> #include <utils/SmallArray.hpp> +template <size_t Dimension> +class QuadratureFormula; + template <MeshConcept MeshTypeT> class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder { diff --git a/src/utils/SignalManager.cpp b/src/utils/SignalManager.cpp index 4b2046a98796fc72cef406f77e7498930089f533..5054622c0d9959c089ddfa3f3a323820614c5806 100644 --- a/src/utils/SignalManager.cpp +++ b/src/utils/SignalManager.cpp @@ -52,17 +52,27 @@ SignalManager::signalName(int signal) void SignalManager::pauseForDebug(int signal) { - if (std::string(PUGS_BUILD_TYPE) != "Release") { - if (s_pause_on_error) { - // Each failing process must write - std::cerr.clear(); + if (s_pause_on_error) { + // Each failing process must write + std::cerr.clear(); + if (std::string(PUGS_BUILD_TYPE) != "Release") { + char hostname[HOST_NAME_MAX + 1]; + gethostname(hostname, HOST_NAME_MAX + 1); std::cerr << "\n======================================\n" - << rang::style::reset << rang::fg::reset << rang::style::bold << "to attach gdb to this process run\n" + << rang::style::reset << rang::fg::reset << rang::style::bold << "Process paused on host \"" + << rang::fg::yellow << hostname << rang::fg::reset << "\"\n" + << "to attach gdb to this process run\n" << "\tgdb -pid " << rang::fg::red << getpid() << rang::fg::reset << '\n' << "else press Control-C to exit\n" << rang::style::reset << "======================================\n" << std::flush; pause(); + } else { + std::cerr << '\n' + << rang::style::bold + << "Pausing is useless for Release version.\n" + "To attach debugger use Debug built type." + << rang::style::reset << '\n'; } } std::exit(signal); @@ -73,56 +83,52 @@ SignalManager::handler(int signal) { static std::mutex mutex; - if (mutex.try_lock()) { - std::signal(SIGTERM, SIG_DFL); - std::signal(SIGINT, SIG_DFL); - std::signal(SIGABRT, SIG_DFL); - - // Each failing process must write - std::cerr.clear(); + std::lock_guard<std::mutex> lock(mutex); - std::cerr << BacktraceManager{} << '\n'; + std::signal(SIGINT, SIG_BLOCK); - std::cerr << "\n *** " << rang::style::reset << rang::fg::reset << rang::style::bold << "Signal " << rang::fgB::red - << signalName(signal) << rang::fg::reset << " caught" << rang::style::reset << " ***\n\n"; + // Each failing process must write + std::cerr.clear(); - std::exception_ptr eptr = std::current_exception(); - try { - if (eptr) { - std::rethrow_exception(eptr); - } else { - std::ostringstream error_msg; - error_msg << "received " << signalName(signal); - std::cerr << ASTExecutionStack::getInstance().errorMessageAt(error_msg.str()) << '\n'; - } - } - catch (const IBacktraceError& backtrace_error) { - auto source_location = backtrace_error.sourceLocation(); - std::cerr << rang::fgB::cyan << source_location.file_name() << ':' << source_location.line() << ':' - << source_location.column() << ':' << rang::fg::reset << rang::fgB::yellow - << " threw the following exception" << rang::fg::reset << "\n\n"; - std::cerr << ASTExecutionStack::getInstance().errorMessageAt(backtrace_error.what()) << '\n'; - } - catch (const ParseError& parse_error) { - auto p = parse_error.positions().front(); - std::cerr << rang::style::bold << p.source << ':' << p.line << ':' << p.column << ':' << rang::style::reset - << rang::fgB::red << " error: " << rang::fg::reset << rang::style::bold << parse_error.what() - << rang::style::reset << '\n'; - } - catch (const IExitError& exit_error) { - std::cerr << ASTExecutionStack::getInstance().errorMessageAt(exit_error.what()) << '\n'; - } - catch (const AssertError& assert_error) { - std::cerr << assert_error << '\n'; - } - catch (...) { - std::cerr << "Unknown exception!\n"; - } + std::cerr << BacktraceManager{} << '\n'; - SignalManager::pauseForDebug(signal); + std::cerr << "\n *** " << rang::style::reset << rang::fg::reset << rang::style::bold << "Signal " << rang::fgB::red + << signalName(signal) << rang::fg::reset << " caught" << rang::style::reset << " ***\n\n"; - mutex.unlock(); + std::exception_ptr eptr = std::current_exception(); + try { + if (eptr) { + std::rethrow_exception(eptr); + } else { + std::ostringstream error_msg; + error_msg << "received " << signalName(signal); + std::cerr << ASTExecutionStack::getInstance().errorMessageAt(error_msg.str()) << '\n'; + } + } + catch (const IBacktraceError& backtrace_error) { + auto source_location = backtrace_error.sourceLocation(); + std::cerr << rang::fgB::cyan << source_location.file_name() << ':' << source_location.line() << ':' + << source_location.column() << ':' << rang::fg::reset << rang::fgB::yellow + << " threw the following exception" << rang::fg::reset << "\n\n"; + std::cerr << ASTExecutionStack::getInstance().errorMessageAt(backtrace_error.what()) << '\n'; } + catch (const ParseError& parse_error) { + auto p = parse_error.positions().front(); + std::cerr << rang::style::bold << p.source << ':' << p.line << ':' << p.column << ':' << rang::style::reset + << rang::fgB::red << " error: " << rang::fg::reset << rang::style::bold << parse_error.what() + << rang::style::reset << '\n'; + } + catch (const IExitError& exit_error) { + std::cerr << ASTExecutionStack::getInstance().errorMessageAt(exit_error.what()) << '\n'; + } + catch (const AssertError& assert_error) { + std::cerr << assert_error << '\n'; + } + catch (...) { + std::cerr << "Unknown exception!\n"; + } + + SignalManager::pauseForDebug(signal); } void diff --git a/tests/test_LinearSolver.cpp b/tests/test_LinearSolver.cpp index 76ef6aa2bb75c3ea94fcf392f59ddb74350dc50a..286fe11ed4040486a4387105065adb955077baf8 100644 --- a/tests/test_LinearSolver.cpp +++ b/tests/test_LinearSolver.cpp @@ -837,77 +837,52 @@ TEST_CASE("LinearSolver", "[algebra]") SECTION("Dense Matrices") { - SECTION("check linear solvers") + SECTION("SmallMatrix") { - SECTION("symmetric system") + SECTION("check linear solvers") { - SmallMatrix<double> A{5}; - A = zero; - - A(0, 0) = 2; - A(0, 1) = -1; - - A(1, 0) = -1; - A(1, 1) = 2; - A(1, 2) = -1; - - A(2, 1) = -1; - A(2, 2) = 2; - A(2, 3) = -1; - - A(3, 2) = -1; - A(3, 3) = 2; - A(3, 4) = -1; - - A(4, 3) = -1; - A(4, 4) = 2; + SECTION("symmetric system") + { + SmallMatrix<double> A{5}; + A = zero; - SmallVector<const double> x_exact = [] { - SmallVector<double> y{5}; - y[0] = 1; - y[1] = 3; - y[2] = 2; - y[3] = 4; - y[4] = 5; - return y; - }(); + A(0, 0) = 2; + A(0, 1) = -1; - SmallVector<double> b = A * x_exact; + A(1, 0) = -1; + A(1, 1) = 2; + A(1, 2) = -1; - SECTION("builtin") - { - SECTION("CG no preconditioner") - { - LinearSolverOptions options; - options.library() = LSLibrary::builtin; - options.method() = LSMethod::cg; - options.precond() = LSPrecond::none; + A(2, 1) = -1; + A(2, 2) = 2; + A(2, 3) = -1; - SmallVector<double> x{5}; - x = zero; + A(3, 2) = -1; + A(3, 3) = 2; + A(3, 4) = -1; - LinearSolver solver{options}; + A(4, 3) = -1; + A(4, 4) = 2; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); - } - } + SmallVector<const double> x_exact = [] { + SmallVector<double> y{5}; + y[0] = 1; + y[1] = 3; + y[2] = 2; + y[3] = 4; + y[4] = 5; + return y; + }(); - SECTION("Eigen3") - { -#ifdef PUGS_HAS_EIGEN3 + SmallVector<double> b = A * x_exact; - SECTION("CG") + SECTION("builtin") { - LinearSolverOptions options; - options.library() = LSLibrary::eigen3; - options.method() = LSMethod::cg; - options.precond() = LSPrecond::none; - options.verbose() = true; - SECTION("CG no preconditioner") { + LinearSolverOptions options; + options.library() = LSLibrary::builtin; + options.method() = LSMethod::cg; options.precond() = LSPrecond::none; SmallVector<double> x{5}; @@ -919,89 +894,176 @@ TEST_CASE("LinearSolver", "[algebra]") SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } + } - SECTION("CG Diagonal") + SECTION("Eigen3") + { +#ifdef PUGS_HAS_EIGEN3 + + SECTION("CG") { - options.precond() = LSPrecond::diagonal; + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::cg; + options.precond() = LSPrecond::none; + options.verbose() = true; - SmallVector<double> x{5}; - x = zero; + SECTION("CG no preconditioner") + { + options.precond() = LSPrecond::none; - LinearSolver solver{options}; + SmallVector<double> x{5}; + x = zero; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("CG Diagonal") + { + options.precond() = LSPrecond::diagonal; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("CG ICholesky") + { + options.precond() = LSPrecond::incomplete_cholesky; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b), + "error: incomplete cholesky is not available for dense matrices in Eigen3"); + } + + SECTION("CG AMG") + { + options.precond() = LSPrecond::amg; + + SmallVector<double> x{5}; + x = zero; + + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: AMG is not an Eigen3 preconditioner!"); + } } - SECTION("CG ICholesky") + SECTION("Cholesky") { - options.precond() = LSPrecond::incomplete_cholesky; + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::cholesky; + options.precond() = LSPrecond::none; SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; - REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b), - "error: incomplete cholesky is not available for dense matrices in Eigen3"); + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } - SECTION("CG AMG") +#else // PUGS_HAS_EIGEN3 + SECTION("Eigen3 not linked") { - options.precond() = LSPrecond::amg; - - SmallVector<double> x{5}; - x = zero; + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::cg; + options.precond() = LSPrecond::none; - REQUIRE_THROWS_WITH(LinearSolver{options}, "error: AMG is not an Eigen3 preconditioner!"); + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Eigen3 is not linked to pugs. Cannot use it!"); } +#endif // PUGS_HAS_EIGEN3 } - SECTION("Cholesky") + SECTION("PETSc") { - LinearSolverOptions options; - options.library() = LSLibrary::eigen3; - options.method() = LSMethod::cholesky; - options.precond() = LSPrecond::none; +#ifdef PUGS_HAS_PETSC - SmallVector<double> x{5}; - x = zero; + SECTION("CG") + { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::cg; + options.precond() = LSPrecond::none; + options.verbose() = true; - LinearSolver solver{options}; + SECTION("CG no preconditioner") + { + options.precond() = LSPrecond::none; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); - } + SmallVector<double> x{5}; + x = zero; -#else // PUGS_HAS_EIGEN3 - SECTION("Eigen3 not linked") - { - LinearSolverOptions options; - options.library() = LSLibrary::eigen3; - options.method() = LSMethod::cg; - options.precond() = LSPrecond::none; + LinearSolver solver{options}; - REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Eigen3 is not linked to pugs. Cannot use it!"); - } -#endif // PUGS_HAS_EIGEN3 - } + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } - SECTION("PETSc") - { -#ifdef PUGS_HAS_PETSC + SECTION("CG Diagonal") + { + options.precond() = LSPrecond::diagonal; - SECTION("CG") - { - LinearSolverOptions options; - options.library() = LSLibrary::petsc; - options.method() = LSMethod::cg; - options.precond() = LSPrecond::none; - options.verbose() = true; + SmallVector<double> x{5}; + x = zero; - SECTION("CG no preconditioner") + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("CG ICholesky") + { + options.precond() = LSPrecond::incomplete_cholesky; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("CG AMG") + { + options.precond() = LSPrecond::amg; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + } + + SECTION("Cholesky") { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::cholesky; options.precond() = LSPrecond::none; SmallVector<double> x{5}; @@ -1014,133 +1076,448 @@ TEST_CASE("LinearSolver", "[algebra]") REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } - SECTION("CG Diagonal") +#else // PUGS_HAS_PETSC + SECTION("PETSc not linked") { - options.precond() = LSPrecond::diagonal; + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::cg; + options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: PETSc is not linked to pugs. Cannot use it!"); + } +#endif // PUGS_HAS_PETSC + } + } - LinearSolver solver{options}; + SECTION("none symmetric system") + { + SECTION("Dense matrix") + { + SmallMatrix<double> A{5}; + A = zero; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); - } + A(0, 0) = 2; + A(0, 1) = -1; - SECTION("CG ICholesky") + A(1, 0) = -0.2; + A(1, 1) = 2; + A(1, 2) = -1; + + A(2, 1) = -1; + A(2, 2) = 4; + A(2, 3) = -2; + + A(3, 2) = -1; + A(3, 3) = 2; + A(3, 4) = -0.1; + + A(4, 3) = 1; + A(4, 4) = 3; + + SmallVector<const double> x_exact = [] { + SmallVector<double> y{5}; + y[0] = 1; + y[1] = 3; + y[2] = 2; + y[3] = 4; + y[4] = 5; + return y; + }(); + + SmallVector<double> b = A * x_exact; + + SECTION("builtin") { - options.precond() = LSPrecond::incomplete_cholesky; + SECTION("BICGStab no preconditioner") + { + LinearSolverOptions options; + options.library() = LSLibrary::builtin; + options.method() = LSMethod::bicgstab; + options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + SmallVector<double> x{5}; + x = zero; - LinearSolver solver{options}; + LinearSolver solver{options}; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } } - SECTION("CG AMG") + SECTION("Eigen3") { - options.precond() = LSPrecond::amg; +#ifdef PUGS_HAS_EIGEN3 - SmallVector<double> x{5}; - x = zero; + SECTION("BICGStab") + { + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::bicgstab; + options.precond() = LSPrecond::none; + options.verbose() = true; - LinearSolver solver{options}; + SECTION("BICGStab no preconditioner") + { + options.precond() = LSPrecond::none; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("BICGStab Diagonal") + { + options.precond() = LSPrecond::diagonal; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("BICGStab ILU") + { + options.precond() = LSPrecond::incomplete_LU; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b), + "error: incomplete LU is not available for dense matrices in Eigen3"); + } + } + + SECTION("BICGStab2") + { + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::bicgstab2; + options.precond() = LSPrecond::none; + + SECTION("BICGStab2 no preconditioner") + { + options.precond() = LSPrecond::none; + + SmallVector<double> x{5}; + x = zero; + + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: BICGStab2 is not an Eigen3 linear solver!"); + } + } + + SECTION("GMRES") + { + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::gmres; + options.precond() = LSPrecond::none; + + SECTION("GMRES no preconditioner") + { + options.precond() = LSPrecond::none; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("GMRES Diagonal") + { + options.precond() = LSPrecond::diagonal; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("GMRES ILU") + { + options.precond() = LSPrecond::incomplete_LU; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b), + "error: incomplete LU is not available for dense matrices in Eigen3"); + } + } + + SECTION("LU") + { + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::lu; + options.precond() = LSPrecond::none; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + +#else // PUGS_HAS_EIGEN3 + SECTION("Eigen3 not linked") + { + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::cg; + options.precond() = LSPrecond::none; + + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Eigen3 is not linked to pugs. Cannot use it!"); + } +#endif // PUGS_HAS_EIGEN3 } - } - SECTION("Cholesky") - { - LinearSolverOptions options; - options.library() = LSLibrary::petsc; - options.method() = LSMethod::cholesky; - options.precond() = LSPrecond::none; + SECTION("PETSc") + { +#ifdef PUGS_HAS_PETSC - SmallVector<double> x{5}; - x = zero; + SECTION("BICGStab") + { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::bicgstab; + options.precond() = LSPrecond::none; + options.verbose() = true; - LinearSolver solver{options}; + SECTION("BICGStab no preconditioner") + { + options.precond() = LSPrecond::none; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); - } + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("BICGStab Diagonal") + { + options.precond() = LSPrecond::diagonal; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("BICGStab ILU") + { + options.precond() = LSPrecond::incomplete_LU; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + } + + SECTION("BICGStab2") + { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::bicgstab2; + options.precond() = LSPrecond::none; + + SECTION("BICGStab2 no preconditioner") + { + options.precond() = LSPrecond::none; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("BICGStab2 Diagonal") + { + options.precond() = LSPrecond::diagonal; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + } + + SECTION("GMRES") + { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::gmres; + options.precond() = LSPrecond::none; + + SECTION("GMRES no preconditioner") + { + options.precond() = LSPrecond::none; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("GMRES Diagonal") + { + options.precond() = LSPrecond::diagonal; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("GMRES ILU") + { + options.precond() = LSPrecond::incomplete_LU; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + } + + SECTION("LU") + { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::lu; + options.precond() = LSPrecond::none; + + SmallVector<double> x{5}; + x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + SmallVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } #else // PUGS_HAS_PETSC - SECTION("PETSc not linked") - { - LinearSolverOptions options; - options.library() = LSLibrary::petsc; - options.method() = LSMethod::cg; - options.precond() = LSPrecond::none; + SECTION("PETSc not linked") + { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::cg; + options.precond() = LSPrecond::none; - REQUIRE_THROWS_WITH(LinearSolver{options}, "error: PETSc is not linked to pugs. Cannot use it!"); - } + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: PETSc is not linked to pugs. Cannot use it!"); + } #endif // PUGS_HAS_PETSC + } + } } } + } - SECTION("none symmetric system") + SECTION("TinyMatrix") + { + SECTION("check linear solvers") { - SECTION("Dense matrix") + SECTION("symmetric system") { - SmallMatrix<double> A{5}; - A = zero; + TinyMatrix<5> A = zero; A(0, 0) = 2; A(0, 1) = -1; - A(1, 0) = -0.2; + A(1, 0) = -1; A(1, 1) = 2; A(1, 2) = -1; A(2, 1) = -1; - A(2, 2) = 4; - A(2, 3) = -2; + A(2, 2) = 2; + A(2, 3) = -1; A(3, 2) = -1; A(3, 3) = 2; - A(3, 4) = -0.1; + A(3, 4) = -1; - A(4, 3) = 1; - A(4, 4) = 3; + A(4, 3) = -1; + A(4, 4) = 2; - SmallVector<const double> x_exact = [] { - SmallVector<double> y{5}; - y[0] = 1; - y[1] = 3; - y[2] = 2; - y[3] = 4; - y[4] = 5; - return y; - }(); + TinyVector<5> x_exact{1, 3, 2, 4, 5}; - SmallVector<double> b = A * x_exact; + TinyVector b = A * x_exact; SECTION("builtin") { - SECTION("BICGStab no preconditioner") + SECTION("CG no preconditioner") { LinearSolverOptions options; options.library() = LSLibrary::builtin; - options.method() = LSMethod::bicgstab; + options.method() = LSMethod::cg; options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; + TinyVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } } @@ -1149,322 +1526,535 @@ TEST_CASE("LinearSolver", "[algebra]") { #ifdef PUGS_HAS_EIGEN3 - SECTION("BICGStab") + SECTION("CG") { LinearSolverOptions options; options.library() = LSLibrary::eigen3; - options.method() = LSMethod::bicgstab; + options.method() = LSMethod::cg; options.precond() = LSPrecond::none; options.verbose() = true; - SECTION("BICGStab no preconditioner") + SECTION("CG no preconditioner") { options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; + TinyVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } - SECTION("BICGStab Diagonal") + SECTION("CG Diagonal") { options.precond() = LSPrecond::diagonal; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; + TinyVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } - SECTION("BICGStab ILU") + SECTION("CG ICholesky") { - options.precond() = LSPrecond::incomplete_LU; + options.precond() = LSPrecond::incomplete_cholesky; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; LinearSolver solver{options}; REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b), - "error: incomplete LU is not available for dense matrices in Eigen3"); + "error: incomplete cholesky is not available for dense matrices in Eigen3"); + } + + SECTION("CG AMG") + { + options.precond() = LSPrecond::amg; + + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: AMG is not an Eigen3 preconditioner!"); } } - SECTION("BICGStab2") + SECTION("Cholesky") { LinearSolverOptions options; options.library() = LSLibrary::eigen3; - options.method() = LSMethod::bicgstab2; + options.method() = LSMethod::cholesky; options.precond() = LSPrecond::none; - SECTION("BICGStab2 no preconditioner") - { - options.precond() = LSPrecond::none; + TinyVector<5> x = zero; - SmallVector<double> x{5}; - x = zero; + LinearSolver solver{options}; - REQUIRE_THROWS_WITH(LinearSolver{options}, "error: BICGStab2 is not an Eigen3 linear solver!"); - } + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } - SECTION("GMRES") +#else // PUGS_HAS_EIGEN3 + SECTION("Eigen3 not linked") { LinearSolverOptions options; options.library() = LSLibrary::eigen3; - options.method() = LSMethod::gmres; + options.method() = LSMethod::cg; + options.precond() = LSPrecond::none; + + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Eigen3 is not linked to pugs. Cannot use it!"); + } +#endif // PUGS_HAS_EIGEN3 + } + + SECTION("PETSc") + { +#ifdef PUGS_HAS_PETSC + + SECTION("CG") + { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::cg; options.precond() = LSPrecond::none; + options.verbose() = true; - SECTION("GMRES no preconditioner") + SECTION("CG no preconditioner") { options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; + TinyVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } - SECTION("GMRES Diagonal") + SECTION("CG Diagonal") { options.precond() = LSPrecond::diagonal; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; + TinyVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } - SECTION("GMRES ILU") + SECTION("CG ICholesky") { - options.precond() = LSPrecond::incomplete_LU; + options.precond() = LSPrecond::incomplete_cholesky; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; LinearSolver solver{options}; - REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b), - "error: incomplete LU is not available for dense matrices in Eigen3"); + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("CG AMG") + { + options.precond() = LSPrecond::amg; + + TinyVector<5> x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } } - SECTION("LU") + SECTION("Cholesky") { LinearSolverOptions options; - options.library() = LSLibrary::eigen3; - options.method() = LSMethod::lu; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::cholesky; options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; + TinyVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } -#else // PUGS_HAS_EIGEN3 - SECTION("Eigen3 not linked") +#else // PUGS_HAS_PETSC + SECTION("PETSc not linked") { LinearSolverOptions options; - options.library() = LSLibrary::eigen3; + options.library() = LSLibrary::petsc; options.method() = LSMethod::cg; options.precond() = LSPrecond::none; - REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Eigen3 is not linked to pugs. Cannot use it!"); + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: PETSc is not linked to pugs. Cannot use it!"); } -#endif // PUGS_HAS_EIGEN3 +#endif // PUGS_HAS_PETSC } + } - SECTION("PETSc") + SECTION("none symmetric system") + { + SECTION("Dense matrix") { -#ifdef PUGS_HAS_PETSC + TinyMatrix<5> A = zero; - SECTION("BICGStab") - { - LinearSolverOptions options; - options.library() = LSLibrary::petsc; - options.method() = LSMethod::bicgstab; - options.precond() = LSPrecond::none; - options.verbose() = true; + A(0, 0) = 2; + A(0, 1) = -1; + + A(1, 0) = -0.2; + A(1, 1) = 2; + A(1, 2) = -1; + + A(2, 1) = -1; + A(2, 2) = 4; + A(2, 3) = -2; + + A(3, 2) = -1; + A(3, 3) = 2; + A(3, 4) = -0.1; + + A(4, 3) = 1; + A(4, 4) = 3; + + const TinyVector<5> x_exact{1, 3, 2, 4, 5 + + }; + + const TinyVector b = A * x_exact; + SECTION("builtin") + { SECTION("BICGStab no preconditioner") { + LinearSolverOptions options; + options.library() = LSLibrary::builtin; + options.method() = LSMethod::bicgstab; options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; + TinyVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } + } + + SECTION("Eigen3") + { +#ifdef PUGS_HAS_EIGEN3 - SECTION("BICGStab Diagonal") + SECTION("BICGStab") { - options.precond() = LSPrecond::diagonal; + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::bicgstab; + options.precond() = LSPrecond::none; + options.verbose() = true; - SmallVector<double> x{5}; - x = zero; + SECTION("BICGStab no preconditioner") + { + options.precond() = LSPrecond::none; - LinearSolver solver{options}; + TinyVector<5> x = zero; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); - } + LinearSolver solver{options}; - SECTION("BICGStab ILU") - { - options.precond() = LSPrecond::incomplete_LU; + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } - SmallVector<double> x{5}; - x = zero; + SECTION("BICGStab Diagonal") + { + options.precond() = LSPrecond::diagonal; - LinearSolver solver{options}; + TinyVector<5> x = zero; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("BICGStab ILU") + { + options.precond() = LSPrecond::incomplete_LU; + + TinyVector<5> x = zero; + + LinearSolver solver{options}; + + REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b), + "error: incomplete LU is not available for dense matrices in Eigen3"); + } } - } - SECTION("BICGStab2") - { - LinearSolverOptions options; - options.library() = LSLibrary::petsc; - options.method() = LSMethod::bicgstab2; - options.precond() = LSPrecond::none; + SECTION("BICGStab2") + { + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::bicgstab2; + options.precond() = LSPrecond::none; - SECTION("BICGStab2 no preconditioner") + SECTION("BICGStab2 no preconditioner") + { + options.precond() = LSPrecond::none; + + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: BICGStab2 is not an Eigen3 linear solver!"); + } + } + + SECTION("GMRES") { + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::gmres; options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + SECTION("GMRES no preconditioner") + { + options.precond() = LSPrecond::none; - LinearSolver solver{options}; + TinyVector<5> x = zero; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("GMRES Diagonal") + { + options.precond() = LSPrecond::diagonal; + + TinyVector<5> x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("GMRES ILU") + { + options.precond() = LSPrecond::incomplete_LU; + + TinyVector<5> x = zero; + + LinearSolver solver{options}; + + REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b), + "error: incomplete LU is not available for dense matrices in Eigen3"); + } } - SECTION("BICGStab2 Diagonal") + SECTION("LU") { - options.precond() = LSPrecond::diagonal; + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::lu; + options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; + TinyVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } + +#else // PUGS_HAS_EIGEN3 + SECTION("Eigen3 not linked") + { + LinearSolverOptions options; + options.library() = LSLibrary::eigen3; + options.method() = LSMethod::cg; + options.precond() = LSPrecond::none; + + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Eigen3 is not linked to pugs. Cannot use it!"); + } +#endif // PUGS_HAS_EIGEN3 } - SECTION("GMRES") + SECTION("PETSc") { - LinearSolverOptions options; - options.library() = LSLibrary::petsc; - options.method() = LSMethod::gmres; - options.precond() = LSPrecond::none; +#ifdef PUGS_HAS_PETSC - SECTION("GMRES no preconditioner") + SECTION("BICGStab") { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::bicgstab; options.precond() = LSPrecond::none; + options.verbose() = true; - SmallVector<double> x{5}; - x = zero; + SECTION("BICGStab no preconditioner") + { + options.precond() = LSPrecond::none; - LinearSolver solver{options}; + TinyVector<5> x = zero; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("BICGStab Diagonal") + { + options.precond() = LSPrecond::diagonal; + + TinyVector<5> x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("BICGStab ILU") + { + options.precond() = LSPrecond::incomplete_LU; + + TinyVector<5> x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } } - SECTION("GMRES Diagonal") + SECTION("BICGStab2") { - options.precond() = LSPrecond::diagonal; + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::bicgstab2; + options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + SECTION("BICGStab2 no preconditioner") + { + options.precond() = LSPrecond::none; - LinearSolver solver{options}; + TinyVector<5> x = zero; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("BICGStab2 Diagonal") + { + options.precond() = LSPrecond::diagonal; + + TinyVector<5> x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } } - SECTION("GMRES ILU") + SECTION("GMRES") { - options.precond() = LSPrecond::incomplete_LU; + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::gmres; + options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + SECTION("GMRES no preconditioner") + { + options.precond() = LSPrecond::none; - LinearSolver solver{options}; + TinyVector<5> x = zero; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("GMRES Diagonal") + { + options.precond() = LSPrecond::diagonal; + + TinyVector<5> x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } + + SECTION("GMRES ILU") + { + options.precond() = LSPrecond::incomplete_LU; + + TinyVector<5> x = zero; + + LinearSolver solver{options}; + + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } } - } - SECTION("LU") - { - LinearSolverOptions options; - options.library() = LSLibrary::petsc; - options.method() = LSMethod::lu; - options.precond() = LSPrecond::none; + SECTION("LU") + { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::lu; + options.precond() = LSPrecond::none; - SmallVector<double> x{5}; - x = zero; + TinyVector<5> x = zero; - LinearSolver solver{options}; + LinearSolver solver{options}; - solver.solveLocalSystem(A, x, b); - SmallVector error = x - x_exact; - REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); - } + solver.solveLocalSystem(A, x, b); + TinyVector error = x - x_exact; + REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); + } #else // PUGS_HAS_PETSC - SECTION("PETSc not linked") - { - LinearSolverOptions options; - options.library() = LSLibrary::petsc; - options.method() = LSMethod::cg; - options.precond() = LSPrecond::none; + SECTION("PETSc not linked") + { + LinearSolverOptions options; + options.library() = LSLibrary::petsc; + options.method() = LSMethod::cg; + options.precond() = LSPrecond::none; - REQUIRE_THROWS_WITH(LinearSolver{options}, "error: PETSc is not linked to pugs. Cannot use it!"); - } + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: PETSc is not linked to pugs. Cannot use it!"); + } #endif // PUGS_HAS_PETSC + } } } } diff --git a/tests/test_PolynomialReconstruction_degree_2.cpp b/tests/test_PolynomialReconstruction_degree_2.cpp index a1c5c058975c17f9a5ec7e40c41f28b9abb18a66..db13612c1d8c5efad94a6f890251e366826d014b 100644 --- a/tests/test_PolynomialReconstruction_degree_2.cpp +++ b/tests/test_PolynomialReconstruction_degree_2.cpp @@ -118,7 +118,7 @@ TEST_CASE("PolynomialReconstruction_degree_2", "[scheme]") auto dpk_Ah = reconstructions[0]->get<DiscreteFunctionDPk<1, const R3x3>>(); double max_error = test_only::max_reconstruction_error(mesh, dpk_Ah, std::function(R3x3_exact)); - REQUIRE(parallel::allReduceMax(max_error) == Catch::Approx(0).margin(1E-14)); + REQUIRE(parallel::allReduceMax(max_error) == Catch::Approx(0).margin(1E-12)); } } } @@ -139,7 +139,7 @@ TEST_CASE("PolynomialReconstruction_degree_2", "[scheme]") auto dpk_Vh = reconstructions[0]->get<DiscreteFunctionDPkVector<1, const double>>(); double max_error = test_only::max_reconstruction_error(mesh, dpk_Vh, vector_exact); - REQUIRE(parallel::allReduceMax(max_error) == Catch::Approx(0).margin(1E-14)); + REQUIRE(parallel::allReduceMax(max_error) == Catch::Approx(0).margin(1E-12)); } } } @@ -172,7 +172,7 @@ TEST_CASE("PolynomialReconstruction_degree_2", "[scheme]") auto dpk_Vh = reconstructions[0]->get<DiscreteFunctionDPkVector<1, const R3>>(); double max_error = test_only::max_reconstruction_error(mesh, dpk_Vh, vector_exact); - REQUIRE(parallel::allReduceMax(max_error) == Catch::Approx(0).margin(1E-14)); + REQUIRE(parallel::allReduceMax(max_error) == Catch::Approx(0).margin(1E-12)); } } } @@ -219,7 +219,7 @@ TEST_CASE("PolynomialReconstruction_degree_2", "[scheme]") { auto dpk_uh = reconstructions[1]->get<DiscreteFunctionDPk<1, const R3>>(); double max_error = test_only::max_reconstruction_error(mesh, dpk_uh, std::function(R3_exact)); - REQUIRE(parallel::allReduceMax(max_error) == Catch::Approx(0).margin(1E-14)); + REQUIRE(parallel::allReduceMax(max_error) == Catch::Approx(0).margin(1E-12)); } { @@ -231,7 +231,7 @@ TEST_CASE("PolynomialReconstruction_degree_2", "[scheme]") { auto dpk_Vh = reconstructions[3]->get<DiscreteFunctionDPkVector<1, const double>>(); double max_error = test_only::max_reconstruction_error(mesh, dpk_Vh, vector_exact); - REQUIRE(parallel::allReduceMax(max_error) == Catch::Approx(0).margin(1E-14)); + REQUIRE(parallel::allReduceMax(max_error) == Catch::Approx(0).margin(1E-12)); } } } diff --git a/tools/plugin-template/CMakeLists.txt-template b/tools/plugin-template/CMakeLists.txt-template index 9c6478b0711cbbd5e38a41f3eaa6c4736a300e67..369887ba7ffd5dfeb9b3593157c51d7a1beefd2f 100644 --- a/tools/plugin-template/CMakeLists.txt-template +++ b/tools/plugin-template/CMakeLists.txt-template @@ -23,14 +23,21 @@ find_package(Pugs REQUIRED) list(APPEND CMAKE_MODULE_PATH "${PUGS_PREFIX_PATH}/lib/cmake/Kokkos") include(KokkosConfig) -set(HDF5_PREFER_PARALLEL TRUE) -list(APPEND CMAKE_MODULE_PATH "${PUGS_PREFIX_PATH}/lib/cmake/HighFive") -include(HighFiveConfig) - list(APPEND CMAKE_MODULE_PATH "${PUGS_PREFIX_PATH}/lib/cmake/pugs") -include(PugsTargets) include(PugsCompileFlags) +if (${PUGS_HAS_MPI}) + set(HDF5_PREFER_PARALLEL TRUE) + list(APPEND CMAKE_MODULE_PATH "${PUGS_PREFIX_PATH}/lib/cmake/HighFive") + + include(HighFiveConfig) + if (TARGET HighFive) + set(HIGHFIVE_TARGET HighFive::HighFive) + endif() +endif() + +include(PugsTargets) + #------------------------------------------------------ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PUGS_CMAKE_CXX_FLAGS}") @@ -77,16 +84,11 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}") include_directories(SYSTEM "${PUGS_PREFIX_PATH}/include") include_directories(SYSTEM "${PUGS_PREFIX_PATH}/include/kokkos") include_directories(SYSTEM "${PUGS_PREFIX_PATH}/include/tao/") +if (${PUGS_HAS_MPI}) include_directories(SYSTEM "${MPI_CXX_INCLUDE_DIRS}") +endif() -get_target_property(_prop Pugs::PugsAlgebra INTERFACE_INCLUDE_DIRECTORIES) -set(PUGS_INC_DIR "${PUGS_INC_DIR};${_prop}") -get_target_property(_prop Pugs::PugsUtils INTERFACE_INCLUDE_DIRECTORIES) -set(PUGS_INC_DIR "${PUGS_INC_DIR};${_prop}") -get_target_property(_prop Pugs::pugs INTERFACE_INCLUDE_DIRECTORIES) -set(PUGS_INC_DIR "${PUGS_INC_DIR};${_prop}") - -include_directories(SYSTEM ${PUGS_INC_DIR}) +include_directories(SYSTEM "${PUGS_PREFIX_PATH}/include") link_directories(${PUGS_PREFIX_PATH}/lib) #------------------------------------------------------ @@ -143,6 +145,10 @@ add_library(_PLUGIN_NAME_ # add cpp sources files here ) +target_link_libraries(_PLUGIN_NAME_ + ${HIGHFIVE_TARGET} +) + #------------------------------------------------------ add_subdirectory(tests)