diff --git a/UnitTest_PZ/TestDeRham/TestDeRham.cpp b/UnitTest_PZ/TestDeRham/TestDeRham.cpp index c21f6ddae..2d449cbd3 100644 --- a/UnitTest_PZ/TestDeRham/TestDeRham.cpp +++ b/UnitTest_PZ/TestDeRham/TestDeRham.cpp @@ -21,13 +21,24 @@ #include "TPZElementMatrixT.h" #include "MMeshType.h" #include "pzintel.h" - +#include "TPZMultiphysicsCompMesh.h" +#include "pzshapetetra.h" +#include "pzshapecube.h" +#include "TPZShapeHDivConstant.h" #include #include #include +#include -enum class ESpace{H1,HCurl,HDiv,HDivConst,L2}; +enum class ESpace +{ + H1, + HCurl, + HDiv, + HDivConst, + L2 +}; static const std::map names({{ESpace::H1, "H1"}, {ESpace::HCurl, "HCurl"}, @@ -35,7 +46,6 @@ static const std::map names({{ESpace::H1, "H1"}, {ESpace::HDivConst, "HDivConst"}, {ESpace::L2, "L2"}}); - /** @brief Compares the dimensions of the span of the differential operator associated with the left space against the kernel of the right space. Let us call the operator op (h1-> grad, hcurl -> curl, hdiv -> div, l2 -> id). @@ -43,9 +53,10 @@ static const std::map names({{ESpace::H1, "H1"}, rank(M_left) = ker(M_right). @note For L2, the comparison is rank(M_left) = rank(M_right), and the operator associated with the L2 approximation space is the identity (op(phi_i) = phi_i). - @param [in] kRight polynomial order of the rightmost approximation space*/ + @param [in] kRight polynomial order of the rightmost approximation space (except for HDiv and HDivConst)*/ template void CheckRankKerDim(int kRight); + /** @brief Checks if the range of the differential operator of the left approximation space is contained in the functions of the approximation space on the right. Let us call the operator op (h1-> grad, hcurl -> curl, hdiv -> div, l2 -> id). Denoting by @@ -62,10 +73,10 @@ template void CheckInclusion(int kRight); TEMPLATE_TEST_CASE("Dimension Compatibility", "[derham_tests]", - (typename std::integral_constant), - (typename std::integral_constant)) + (typename std::integral_constant), + (typename std::integral_constant)) { - //SVD requires LAPACK + // SVD requires LAPACK #ifndef PZ_USING_LAPACK return; #endif @@ -75,45 +86,53 @@ TEMPLATE_TEST_CASE("Dimension Compatibility", "[derham_tests]", ESpace::HCurl, ESpace::HDiv, ESpace::HDivConst); - int k = GENERATE(1,2,3); - SECTION(names.at(leftSpace)) { - switch (leftSpace) { - case ESpace::H1: - CheckRankKerDim(k); - //TODOFIX - // if constexpr (dim == 2){ - // CheckRankKerDim(k); - // } - break; - case ESpace::HCurl: - if constexpr (dim == 2){ - CheckRankKerDim(k); + + SECTION(names.at(leftSpace)) + { + int k = GENERATE(1, 2, 3); + SECTION(std::to_string(k)) + { + switch (leftSpace) + { + case ESpace::H1: + { + CheckRankKerDim(k); + break; } - else{ - CheckRankKerDim(k); + case ESpace::HCurl: + { + if constexpr (dim == 2) + { + CheckRankKerDim(k); + } + else + { + CheckRankKerDim(k); + } + break; } - break; - case ESpace::HDiv: - CheckRankKerDim(k); - break; - case ESpace::HDivConst: - //HdivConstant should only be called with k = 0. The if statement is only to ensure it is called once. If we generate k=0 it fails for other approximation spaces - //Any better solutions? - if (k == 1) { - CheckRankKerDim(0); + case ESpace::HDiv: + { + CheckRankKerDim(k); + break; + } + case ESpace::HDivConst: + { + CheckRankKerDim(k); + break; + } + case ESpace::L2: + break; } - break; - case ESpace::L2: - break; } } } TEMPLATE_TEST_CASE("Inclusion", "[derham_tests]", - (typename std::integral_constant), - (typename std::integral_constant)) + (typename std::integral_constant), + (typename std::integral_constant)) { - //SVD requires LAPACK + // SVD requires LAPACK #ifndef PZ_USING_LAPACK return; #endif @@ -123,34 +142,43 @@ TEMPLATE_TEST_CASE("Inclusion", "[derham_tests]", ESpace::HCurl, ESpace::HDiv, ESpace::HDivConst); - int k = GENERATE(1,2,3); - SECTION(names.at(leftSpace)) { - switch (leftSpace) { - case ESpace::H1: - CheckInclusion(k); - //TODOFIX - // if constexpr (dim == 2){ - // CheckInclusion(k); - // } - break; - case ESpace::HCurl: - CheckInclusion(k); - break; - case ESpace::HDiv: - CheckInclusion(k); - break; - case ESpace::HDivConst: - CheckInclusion(k); - break; - default: - break; + SECTION(names.at(leftSpace)) + { + int k = GENERATE(1, 2, 3); + SECTION(std::to_string(k)) + { + switch (leftSpace) + { + case ESpace::H1: + { + CheckInclusion(k); + break; + } + case ESpace::HCurl: + { + CheckInclusion(k); + break; + } + case ESpace::HDiv: + { + CheckInclusion(k); + break; + } + case ESpace::HDivConst: + { + CheckInclusion(k); + break; + } + default: + break; + } } } } /******************************************************************************* ***********************************AUX FUNCS*********************************** -*******************************************************************************/ + *******************************************************************************/ /** @brief Creates appropriate computational meshes to study De Rham compatibility of FEM approximation spaces. The mesh will consist of elements of type elType (inside the function, @@ -163,7 +191,7 @@ TEMPLATE_TEST_CASE("Inclusion", "[derham_tests]", @param [out] cmeshL computational mesh of leftmost approximaton space @param [out] cmeshR computational mesh of rightmost approximaton space*/ template -void CreateMeshes(int kRight, MMeshType elType, +void CreateMeshes(int &kRight, MMeshType elType, int &kLeft, TPZAutoPointer &gmesh, TPZAutoPointer &cmeshL, TPZAutoPointer &cmeshR); @@ -191,328 +219,422 @@ TPZAutoPointer CreateCMesh(TPZAutoPointer gMesh, @param [in] S matrix @param[in] tol arithmetic tolerance */ -int CalcRank(const TPZFMatrix & S, const STATE tol); +int CalcRank(const TPZFMatrix &S, const STATE tol); /******************************************************************************* ***********************************TEST FUNCS*********************************** *******************************************************************************/ - template -void CheckRankKerDim(int kRight) { +void CheckRankKerDim(int kRight) +{ /****************************************** CHECK FUNCTION DECLARATION FOR MORE DETAILS *******************************************/ - //select element type + // select element type auto elType = GENERATE(MMeshType::ETriangular, MMeshType::EQuadrilateral, MMeshType::ETetrahedral, MMeshType::EHexahedral, MMeshType::EPrismatic); - - const auto elDim = MMeshType_Dimension(elType); - if(elType == MMeshType::EPrismatic && leftSpace == ESpace::HCurl){ - return;//TODOFIX - } - //if dimension does not correspond, skip - if(elDim != dim) return; - - - int kLeft; - TPZAutoPointer gmesh{nullptr}; - TPZAutoPointer cmeshL{nullptr}, cmeshR{nullptr}; - //creates computational meshes - CreateMeshes(kRight, elType, - kLeft, gmesh, cmeshL, cmeshR); - - //for debuggin - const auto nameLeft = names.at(leftSpace); - const auto nameRight = names.at(rightSpace); - const auto elName = MMeshType_Name(elType); - CAPTURE(nameLeft,nameRight,elName); - - //stores the matrices - TPZAutoPointer> matPtrL = nullptr; - TPZAutoPointer> matPtrR = nullptr; + SECTION(MMeshType_Name(elType)) { - - constexpr int nThreads{0}; - TPZLinearAnalysis anL(cmeshL,RenumType::ENone); - TPZLinearAnalysis anR(cmeshR, RenumType::ENone); - - TPZFStructMatrix strmtrxL(cmeshL); - strmtrxL.SetNumThreads(nThreads); - anL.SetStructuralMatrix(strmtrxL); - - TPZFStructMatrix strmtrxR(cmeshR); - strmtrxR.SetNumThreads(nThreads); - anR.SetStructuralMatrix(strmtrxR); - - TPZStepSolver step; - step.SetDirect(ELU); + if (elType == MMeshType::EPrismatic && leftSpace == ESpace::HDivConst) + { + return; // TODOFIX + } + const auto elDim = MMeshType_Dimension(elType); + if (elType == MMeshType::EPrismatic && leftSpace == ESpace::HCurl) + { + return; // TODOFIX + } - anL.SetSolver(step); - anR.SetSolver(step); - - anL.Assemble(); - anR.Assemble(); + // if dimension does not correspond, skip + if (elDim != dim) + return; - matPtrL = anL.MatrixSolver().Matrix(); - matPtrR = anR.MatrixSolver().Matrix(); + int kLeft; + TPZAutoPointer gmesh{nullptr}; + TPZAutoPointer cmeshL{nullptr}, cmeshR{nullptr}; + // creates computational meshes + CreateMeshes(kRight, elType, + kLeft, gmesh, cmeshL, cmeshR); - } - - TPZFMatrix matL(*matPtrL); - TPZFMatrix matR(*matPtrR); - - const int dimL = matL.Rows(); - const int dimR = matR.Rows(); - - TPZFMatrix SL, SR; - - { - TPZFMatrix Udummy, VTdummy; - matL.SVD(Udummy, SL, VTdummy, 'N', 'N'); - matR.SVD(Udummy, SR, VTdummy, 'N', 'N'); - } - static constexpr auto tol = std::numeric_limits::epsilon()*100000; - - //rank of op(phi_i,phi_j) of left space - const int rankL = CalcRank(SL,tol); - const int rankR = CalcRank(SR,tol); - //dimension of the nullspace of op(phi_i,phi_j) of right space - const int kerR = dimR-rankR; - - CAPTURE(kLeft,kRight,dimL,rankL,dimR,kerR,rankR); - CAPTURE(SL,SR); - if constexpr (rightSpace==ESpace::L2){//for L2 the operator is -> 0 - REQUIRE(rankL == rankR); - } - else{ - REQUIRE(rankL == kerR); + // for debuggin + const auto nameLeft = names.at(leftSpace); + const auto nameRight = names.at(rightSpace); + const auto elName = MMeshType_Name(elType); + CAPTURE(nameLeft, nameRight, elName); + + // stores the matrices + TPZAutoPointer> matPtrL = nullptr; + TPZAutoPointer> matPtrR = nullptr; + + { + constexpr int nThreads{4}; + TPZLinearAnalysis anL(cmeshL, RenumType::ENone); + TPZLinearAnalysis anR(cmeshR, RenumType::ENone); + + TPZFStructMatrix strmtrxL(cmeshL); + strmtrxL.SetNumThreads(nThreads); + anL.SetStructuralMatrix(strmtrxL); + + TPZFStructMatrix strmtrxR(cmeshR); + strmtrxR.SetNumThreads(nThreads); + anR.SetStructuralMatrix(strmtrxR); + + TPZStepSolver step; + step.SetDirect(ELU); + + anL.SetSolver(step); + anR.SetSolver(step); + + anL.Assemble(); + anR.Assemble(); + + matPtrL = anL.MatrixSolver().Matrix(); + matPtrR = anR.MatrixSolver().Matrix(); + } + + TPZFMatrix matL(*matPtrL); + TPZFMatrix matR(*matPtrR); + + const int dimL = matL.Rows(); + const int dimR = matR.Rows(); + + TPZFMatrix SL, SR; + + { + TPZFMatrix Udummy, VTdummy; + matL.SVD(Udummy, SL, VTdummy, 'N', 'N'); + matR.SVD(Udummy, SR, VTdummy, 'N', 'N'); + } + static constexpr auto tol = std::numeric_limits::epsilon() * 100000; + + TPZManVector connectorderL(cmeshL->NConnects(), 0), connectorderR(cmeshR->NConnects(), 0); + for (int i = 0; i < cmeshL->NConnects(); i++) + { + connectorderL[i] = cmeshL->ConnectVec()[i].Order(); + } + for (int i = 0; i < cmeshR->NConnects(); i++) + { + connectorderR[i] = cmeshR->ConnectVec()[i].Order(); + } + TPZManVector nshapeL(cmeshL->NConnects(), 0), nshapeR(cmeshR->NConnects(), 0); + for (int i = 0; i < cmeshL->NConnects(); i++) + { + nshapeL[i] = cmeshL->ConnectVec()[i].NShape(); + } + for (int i = 0; i < cmeshR->NConnects(); i++) + { + nshapeR[i] = cmeshR->ConnectVec()[i].NShape(); + } + + // rank of op(phi_i,phi_j) of left space + const int rankL = CalcRank(SL, tol); + const int rankR = CalcRank(SR, tol); + // dimension of the nullspace of op(phi_i,phi_j) of right space + const int kerR = dimR - rankR; + + CAPTURE(kLeft, kRight, dimL, rankL, dimR, kerR, rankR); + CAPTURE(connectorderL, connectorderR); + CAPTURE(nshapeL, nshapeR); + // CAPTURE(SL, SR); + if constexpr (rightSpace == ESpace::L2) + { // for L2 the operator is -> 0 + REQUIRE(rankL == rankR); + } + else + { + REQUIRE(rankL == kerR); + } } } template -void CheckInclusion(int kRight) { +void CheckInclusion(int kRight) +{ /****************************************** CHECK FUNCTION DECLARATION FOR MORE DETAILS *******************************************/ - + constexpr int matId = 1; - //select element type + // select element type auto elType = GENERATE(MMeshType::ETriangular, MMeshType::EQuadrilateral, MMeshType::ETetrahedral, MMeshType::EHexahedral, MMeshType::EPrismatic); - const auto elDim = MMeshType_Dimension(elType); + SECTION(MMeshType_Name(elType)) + { + const auto elDim = MMeshType_Dimension(elType); - if(elType == MMeshType::EPrismatic && leftSpace == ESpace::HCurl){ - return;//TODOFIX - } - //skips if dimension is not compatible - if (elDim != dim) return; - - int kLeft; - TPZAutoPointer gmesh{nullptr}; - TPZAutoPointer cmeshL{nullptr}, cmeshR{nullptr}; - //for debugging - const auto nameLeft = names.at(leftSpace); - const auto nameRight = names.at(rightSpace); - const auto elName = MMeshType_Name(elType); - CAPTURE(nameLeft,nameRight,elName); - - //creates computational meshes - CreateMeshes(kRight, elType, kLeft, - gmesh, cmeshL, cmeshR); - - //creates multiphysics mesh - TPZAutoPointer cmeshMF = new TPZCompMesh(gmesh); - - - /* - Now, the appropriate material will be selected given their - combination of left and right approximation spaces. - This material will be responsible for creating the matrix M - */ - auto *matMF = []() -> TPZMaterial * { - if constexpr (rightSpace == ESpace::H1) { - return nullptr; - } else if constexpr (rightSpace == ESpace::HCurl) { - return new TPZMatDeRhamH1HCurl(matId, dim); - } else if constexpr (rightSpace == ESpace::HDiv) { - if constexpr (dim == 3){ - return new TPZMatDeRhamHCurlHDiv(matId,dim); - } - return nullptr; - } else if constexpr (rightSpace == ESpace::L2) { - return new TPZMatDeRhamHDivL2(matId, dim); + if (elType == MMeshType::EPrismatic && leftSpace == ESpace::HDivConst) + { + return; // TODOFIX } - }(); - if (!matMF) - return; - - cmeshMF->InsertMaterialObject(matMF); - cmeshMF->SetDimModel(dim); - - cmeshMF->SetAllCreateFunctionsMultiphysicElem(); - - cmeshMF->AutoBuild(); - cmeshMF->CleanUpUnconnectedNodes(); - - TPZManVector meshVecIn = {cmeshL.operator->(), - cmeshR.operator->()}; - - TPZBuildMultiphysicsMesh::AddElements(meshVecIn, cmeshMF.operator->()); - TPZBuildMultiphysicsMesh::AddConnects(meshVecIn, cmeshMF.operator->()); - TPZBuildMultiphysicsMesh::TransferFromMeshes(meshVecIn, - cmeshMF.operator->()); - - cmeshMF->ExpandSolution(); - cmeshMF->ComputeNodElCon(); - cmeshMF->CleanUpUnconnectedNodes(); - TPZLinearAnalysis analysis(cmeshMF, RenumType::ENone); - TPZFStructMatrix strmtrx(cmeshMF); - analysis.SetStructuralMatrix(strmtrx); - TPZStepSolver step; - step.SetDirect(ELU); - analysis.SetSolver(step); - - analysis.Assemble(); - //it is a full matrix - auto mfMatrix = - dynamic_cast&> ( - analysis.MatrixSolver().Matrix().operator*()); - - const int rLeftEqs = cmeshR->NEquations(); - const int lLeftEqs = cmeshL->NEquations(); - TPZFMatrix rightMatrix(rLeftEqs,rLeftEqs); - - //rightMatrix is the matrix phi_i phi_j for the approx. space on the right - mfMatrix.GetSub(lLeftEqs, lLeftEqs, rLeftEqs, rLeftEqs, rightMatrix); - - - TPZFMatrix Sfull, Sright; - - { - TPZFMatrix Udummy, VTdummy; - mfMatrix.SVD(Udummy, Sfull, VTdummy, 'N', 'N'); - rightMatrix.SVD(Udummy, Sright, VTdummy, 'N', 'N'); - } + if (elType == MMeshType::EPrismatic && leftSpace == ESpace::HCurl) + { + return; // TODOFIX + } + // skips if dimension is not compatible + if (elDim != dim) + return; + + int kLeft; + TPZAutoPointer gmesh{nullptr}; + TPZAutoPointer cmeshL{nullptr}, cmeshR{nullptr}; + // for debugging + const auto nameLeft = names.at(leftSpace); + const auto nameRight = names.at(rightSpace); + const auto elName = MMeshType_Name(elType); + CAPTURE(nameLeft, nameRight, elName); + + // creates computational meshes + CreateMeshes(kRight, elType, kLeft, + gmesh, cmeshL, cmeshR); + + // creates multiphysics mesh + TPZMultiphysicsCompMesh *cmeshMF = new TPZMultiphysicsCompMesh(gmesh); + + /* + Now, the appropriate material will be selected given their + combination of left and right approximation spaces. + This material will be responsible for creating the matrix M + */ + auto *matMF = []() -> TPZMaterial * + { + if constexpr (rightSpace == ESpace::H1) + { + return nullptr; + } + else if constexpr (rightSpace == ESpace::HCurl) + { + return new TPZMatDeRhamH1HCurl(matId, dim); + } + else if constexpr (rightSpace == ESpace::HDiv) + { + if constexpr (dim == 3) + { + return new TPZMatDeRhamHCurlHDiv(matId, dim); + } + return nullptr; + } + else if constexpr (rightSpace == ESpace::L2) + { + return new TPZMatDeRhamHDivL2(matId, dim); + } + }(); + + if (!matMF) + return; - /** - We want to compare if rank(rightMatrix) == rank(mfMatrix). - This will ensure us that op(phi_i).op(phi_j) of the left space - are contained in the functions of the approximation space on the right. - */ - static constexpr auto tol = std::numeric_limits::epsilon()*10000; - auto fullDim = Sfull.Rows(); - auto fullRank = CalcRank(Sfull,tol); - auto rightDim = Sright.Rows(); - auto rightRank = CalcRank(Sright,tol); + cmeshMF->InsertMaterialObject(matMF); + cmeshMF->SetDimModel(dim); + cmeshMF->SetAllCreateFunctionsMultiphysicElem(); - CAPTURE(kLeft,kRight,fullDim, fullRank,rightDim, rightRank); - REQUIRE(fullRank == rightRank); -} + TPZManVector active_approx_spaces(2, 1); + TPZManVector meshVec(2); + meshVec[0] = cmeshL.operator->(); + meshVec[1] = cmeshR.operator->(); + cmeshMF->BuildMultiphysicsSpace(active_approx_spaces, meshVec); + cmeshMF->CleanUpUnconnectedNodes(); + cmeshMF->LoadReferences(); + + TPZLinearAnalysis analysis(cmeshMF, RenumType::ENone); + TPZFStructMatrix strmtrx(cmeshMF); + analysis.SetStructuralMatrix(strmtrx); + TPZStepSolver step; + step.SetDirect(ELU); + analysis.SetSolver(step); + + analysis.Assemble(); + // it is a full matrix + auto mfMatrix = + dynamic_cast &>( + analysis.MatrixSolver().Matrix().operator*()); + + const int rLeftEqs = cmeshR->NEquations(); + const int lLeftEqs = cmeshL->NEquations(); + TPZFMatrix rightMatrix(rLeftEqs, rLeftEqs); + + // rightMatrix is the matrix phi_i phi_j for the approx. space on the right + mfMatrix.GetSub(lLeftEqs, lLeftEqs, rLeftEqs, rLeftEqs, rightMatrix); + + TPZFMatrix Sfull, Sright; + + { + TPZFMatrix Udummy, VTdummy; + mfMatrix.SVD(Udummy, Sfull, VTdummy, 'N', 'N'); + rightMatrix.SVD(Udummy, Sright, VTdummy, 'N', 'N'); + } + + /** + We want to compare if rank(rightMatrix) == rank(mfMatrix). + This will ensure us that op(phi_i).op(phi_j) of the left space + are contained in the functions of the approximation space on the right. + */ + static constexpr auto tol = std::numeric_limits::epsilon() * 10000; + auto fullDim = Sfull.Rows(); + auto fullRank = CalcRank(Sfull, tol); + auto rightDim = Sright.Rows(); + auto rightRank = CalcRank(Sright, tol); + + CAPTURE(kLeft, kRight, fullDim, fullRank, rightDim, rightRank); + REQUIRE(fullRank == rightRank); + } +} /******************************************************************************* ***********************************AUX FUNCS*********************************** -*******************************************************************************/ + *******************************************************************************/ template -void CreateMeshes(int kRight, MMeshType elType, +void CreateMeshes(int &kRight, MMeshType elType, int &kLeft, TPZAutoPointer &gmesh, TPZAutoPointer &cmeshL, - TPZAutoPointer &cmeshR){ + TPZAutoPointer &cmeshR) +{ + constexpr int matId = 1; - - + const auto elDim = MMeshType_Dimension(elType); // for CheckInclusion test, the following materials will be ignored - auto *matLeft = [&kLeft,kRight,elType]() - -> TPZMaterial* { - if constexpr (leftSpace == ESpace::H1) { + auto *matLeft = [&kLeft, &kRight, elType]() + -> TPZMaterial * + { + if constexpr (leftSpace == ESpace::H1) + { kLeft = kRight + 1; return new TPZMatDeRhamH1(matId, dim); - } else if constexpr (leftSpace == ESpace::HCurl) { - if(elType == MMeshType::EQuadrilateral || elType == MMeshType::EHexahedral){ + } + else if constexpr (leftSpace == ESpace::HCurl) + { + if (elType == MMeshType::EQuadrilateral || elType == MMeshType::EHexahedral) + { kLeft = kRight; - }else{ + } + else + { kLeft = kRight + 1; } - return new TPZMatDeRhamHCurl(matId,dim); - } else if constexpr (leftSpace == ESpace::HDiv) { + return new TPZMatDeRhamHCurl(matId, dim); + } + else if constexpr (leftSpace == ESpace::HDiv) + { kLeft = kRight; - return new TPZMatDeRhamHDiv(matId,dim); - } else if constexpr (leftSpace == ESpace::HDivConst) { + return new TPZMatDeRhamHDiv(matId, dim); + } + else if constexpr (leftSpace == ESpace::HDivConst) + { kLeft = kRight; - return new TPZMatDeRhamHDiv(matId,dim); - } else if constexpr (leftSpace == ESpace::L2) { + kRight = 0; + return new TPZMatDeRhamHDiv(matId, dim); + } + else if constexpr (leftSpace == ESpace::L2) + { return nullptr; } }(); - + auto *matRight = []() - -> TPZMaterial * { - if constexpr (rightSpace == ESpace::H1) { + -> TPZMaterial * + { + if constexpr (rightSpace == ESpace::H1) + { return nullptr; - } else if constexpr (rightSpace == ESpace::HCurl) { - return new TPZMatDeRhamHCurl(matId,dim); - } else if constexpr (rightSpace == ESpace::HDiv) { - return new TPZMatDeRhamHDiv(matId,dim); - } else if constexpr (rightSpace == ESpace::HDivConst) { - return new TPZMatDeRhamHDiv(matId,dim); - } else if constexpr (rightSpace == ESpace::L2) { - return new TPZMatDeRhamL2(matId,dim); + } + else if constexpr (rightSpace == ESpace::HCurl) + { + return new TPZMatDeRhamHCurl(matId, dim); + } + else if constexpr (rightSpace == ESpace::HDiv) + { + return new TPZMatDeRhamHDiv(matId, dim); + } + else if constexpr (rightSpace == ESpace::HDivConst) + { + return new TPZMatDeRhamHDiv(matId, dim); + } + else if constexpr (rightSpace == ESpace::L2) + { + return new TPZMatDeRhamL2(matId, dim); } }(); REQUIRE((matLeft != nullptr && matRight != nullptr)); - //generates mesh with a single element + // generates mesh with a single element constexpr bool singleElement{true}; - if constexpr(singleElement){ + if constexpr (singleElement) + { constexpr bool createBoundEls{false}; gmesh = TPZGeoMeshTools::CreateGeoMeshSingleEl(elType, matId, createBoundEls); - }else{ - gmesh = CreateGMesh(dim,elType,matId); } - cmeshL = CreateCMesh(gmesh, matLeft, matId, kLeft, leftSpace); - cmeshR = CreateCMesh(gmesh, matRight, matId, kRight, rightSpace); - - - auto EnrichMesh = [](TPZAutoPointer cmesh, const int k){ + else + { + gmesh = CreateGMesh(dim, elType, matId); + } - for (auto cel : cmesh->ElementVec()){ - if(cel->Dimension() != dim) continue; + auto EnrichMesh = [](TPZAutoPointer cmesh, const int k) + { + for (auto cel : cmesh->ElementVec()) + { + if (cel->Dimension() != dim) + continue; auto intel = - dynamic_cast(cel); + dynamic_cast(cel); const auto nsides = intel->Reference()->NSides(); - intel->SetSideOrder(nsides-1, k+1); + intel->SetSideOrder(nsides - 1, k + 1); + intel->AdjustIntegrationRule(); } cmesh->ExpandSolution(); }; - if(elType == MMeshType::ETetrahedral){ - if constexpr (leftSpace == ESpace::HCurl){ + cmeshL = CreateCMesh(gmesh, matLeft, matId, kLeft, leftSpace); + + // Enriching the internal functions for Hdiv or HdivConst + if constexpr (leftSpace == ESpace::HDiv || leftSpace == ESpace::HDivConst) + { + int enrichLvl = GENERATE(-1, 0, 1); + // SECTION("Enrichment Level: " + std::to_string(enrichLvl+1)); + EnrichMesh(cmeshL, kLeft + enrichLvl); + if constexpr (leftSpace == ESpace::HDiv) + { // In this case, the L2 space order has to be equal to the Hdiv enriched space + kRight = kLeft + enrichLvl + 1; + cmeshR = CreateCMesh(gmesh, matRight, matId, kRight, rightSpace); + } + else + { + cmeshR = CreateCMesh(gmesh, matRight, matId, kRight, rightSpace); + } + } + else + { + cmeshR = CreateCMesh(gmesh, matRight, matId, kRight, rightSpace); + } + + if (elType == MMeshType::ETetrahedral) + { + if constexpr (leftSpace == ESpace::HCurl) + { EnrichMesh(cmeshL, kLeft); } - else if constexpr (rightSpace == ESpace::HCurl){ + else if constexpr (rightSpace == ESpace::HCurl) + { EnrichMesh(cmeshR, kRight); } - - if constexpr (leftSpace == ESpace::H1){ + + if constexpr (leftSpace == ESpace::H1) + { EnrichMesh(cmeshL, kLeft); } } - } - TPZAutoPointer CreateGMesh(const int dim, const MMeshType elType, const int matId) { @@ -538,7 +660,8 @@ TPZAutoPointer CreateCMesh(TPZAutoPointer gmesh, cmesh->SetDefaultOrder(k); cmesh->SetDimModel(gmesh->Dimension()); cmesh->InsertMaterialObject(mat); - switch (space) { + switch (space) + { case ESpace::H1: cmesh->SetAllCreateFunctionsContinuous(); break; @@ -565,12 +688,12 @@ TPZAutoPointer CreateCMesh(TPZAutoPointer gmesh, return cmesh; } - - -int CalcRank(const TPZFMatrix & S, const STATE tol){ +int CalcRank(const TPZFMatrix &S, const STATE tol) +{ int rank = 0; const int dimMat = S.Rows(); - for (int i = 0; i < dimMat; i++) { + for (int i = 0; i < dimMat; i++) + { rank += S.GetVal(i, 0) > tol ? 1 : 0; } return rank;