diff --git a/Mesh/TPZCompElHCurl.cpp b/Mesh/TPZCompElHCurl.cpp index d520a7e7e..49c787b12 100644 --- a/Mesh/TPZCompElHCurl.cpp +++ b/Mesh/TPZCompElHCurl.cpp @@ -618,7 +618,8 @@ void TPZCompElHCurl::CreateHCurlConnects(TPZCompMesh &mesh){ } template -void TPZCompElHCurl::RestrainSide(int side, TPZInterpolatedElement *large, int neighbourside) { +template +void TPZCompElHCurl::RestrainSideT(int side, TPZInterpolatedElement *large, int neighbourside) { const TPZCompElSide thisCompSide(this, side); const TPZCompElSide largeCompSide(large, neighbourside); TPZGeoElSide thisGeoSide(this->Reference(), side); @@ -727,6 +728,7 @@ void TPZCompElHCurl::RestrainSide(int side, TPZInterpolatedElement *larg MSolve.Solve(MSL, MSL); + const auto thisNumSideNodes = NSideConnects(side); const auto largeNumSideNodes = large->NSideConnects(neighbourside); TPZBlock MBlocksmall(0, thisNumSideNodes), MBlocklarge(0, largeNumSideNodes); @@ -782,13 +784,27 @@ void TPZCompElHCurl::RestrainSide(int side, TPZInterpolatedElement *larg DebugStop(); } #endif + TPZFNMatrix<1000, TVar> MSLdep; + if constexpr (std::is_same_v){ + MSLdep = MSL; + }else{ + const int nr = MSL.Rows(); + const int nc = MSL.Cols(); + MSLdep.Resize(nr,nc); + auto *my_ptr = MSLdep.Elem(); + auto *their_ptr = MSL.Elem(); + for(int i = 0; i < nr*nc;i++){ + *my_ptr++ = *their_ptr++; + } + } + for (auto jn = 0; jn < largeNumSideNodes; jn++) { if (MBlocksmall.Size(in) == 0 || MBlocklarge.Size(jn) == 0) { continue; } int64_t jnodindex = large->SideConnectIndex(jn, neighbourside); - TPZConnect::TPZDepend *depend = - inod.AddDependency(inodindex, jnodindex, MSL, + TPZConnect::TPZDepend *depend = + inod.AddDependency(inodindex, jnodindex, MSLdep, MBlocksmall.Position(in), MBlocklarge.Position(jn), MBlocksmall.Size(in), MBlocklarge.Size(jn)); if (blocknorm(in, jn) < 1.e-8) { @@ -801,7 +817,7 @@ void TPZCompElHCurl::RestrainSide(int side, TPZInterpolatedElement *larg for (auto jn = 0; jn < largeNumSideNodes; jn++) { int64_t jnodindex = large->SideConnectIndex(jn, neighbourside); if (MBlocklarge.Size(jn)) { - inod.AddDependency(inodindex, jnodindex, MSL, MBlocksmall.Position(in), MBlocklarge.Position(jn), + inod.AddDependency(inodindex, jnodindex, MSLdep, MBlocksmall.Position(in), MBlocklarge.Position(jn), MBlocksmall.Size(in), MBlocklarge.Size(jn)); } ndepend++; diff --git a/Mesh/TPZCompElHCurl.h b/Mesh/TPZCompElHCurl.h index 0c1d7c86a..9c0f6f80e 100644 --- a/Mesh/TPZCompElHCurl.h +++ b/Mesh/TPZCompElHCurl.h @@ -107,7 +107,14 @@ class TPZCompElHCurl : public TPZIntelGen { /** @brief Sets the interpolation order of side to order*/ void SetSideOrder(int side, int order) override; - void RestrainSide(int side, TPZInterpolatedElement *large, int neighbourside) override; + void RestrainSide(int side, TPZInterpolatedElement *large, int neighbourside) override + { + if(this->Mesh()->GetSolType() == EReal){ + RestrainSideT(side,large,neighbourside); + }else{ + RestrainSideT(side,large,neighbourside); + } + } /** @brief Initialize a material data and its attributes based on element dimension, number * of state variables and material definitions */ void InitMaterialData(TPZMaterialData &data) override; @@ -190,6 +197,8 @@ class TPZCompElHCurl : public TPZIntelGen { TPZSolVec &sol, TPZSolVec &curlsol); + template + void RestrainSideT(int side, TPZInterpolatedElement *large, int neighbourside); int MaxOrder() override; }; diff --git a/Mesh/pzconnect.cpp b/Mesh/pzconnect.cpp index 46b372c23..ef311ff3f 100644 --- a/Mesh/pzconnect.cpp +++ b/Mesh/pzconnect.cpp @@ -332,8 +332,19 @@ template TPZConnect::TPZDepend::TPZDepend(int64_t dependindex,TPZFMatrix &depmat,int64_t ipos,int64_t jpos, int isize, int jsize) : fDepMatrix(isize,jsize) { fDepConnectIndex = dependindex; - int i,j; - for(i=0; iIsLinearMapping(); + return fGeoEl->IsLinearMapping(fSide); } diff --git a/Mesh/pzintel.cpp b/Mesh/pzintel.cpp index 2ce43fc46..2ab50aa0f 100644 --- a/Mesh/pzintel.cpp +++ b/Mesh/pzintel.cpp @@ -844,7 +844,18 @@ int64_t TPZInterpolatedElement::CreateMidSideConnect(int side) { return newnodeindex; } -void TPZInterpolatedElement::RestrainSide(int side, TPZInterpolatedElement *large, int neighbourside) { +void TPZInterpolatedElement::RestrainSide(int side, TPZInterpolatedElement *large, + int neighbourside) +{ + if(this->Mesh()->GetSolType() == EReal){ + RestrainSideT(side,large,neighbourside); + }else{ + RestrainSideT(side,large,neighbourside); + } +} + +template +void TPZInterpolatedElement::RestrainSideT(int side, TPZInterpolatedElement *large, int neighbourside) { TPZCompElSide thisside(this, side); TPZGeoElSide thisgeoside = thisside.Reference(); TPZCompElSide largecompside(large, neighbourside); @@ -992,13 +1003,30 @@ void TPZInterpolatedElement::RestrainSide(int side, TPZInterpolatedElement *larg DebugStop(); } #endif + + TPZFNMatrix<1000, TVar> MSLdep; + if constexpr (std::is_same_v){ + MSLdep = MSL; + }else{ + const int nr = MSL.Rows(); + const int nc = MSL.Cols(); + MSLdep.Resize(nr,nc); + auto *my_ptr = MSLdep.Elem(); + auto *their_ptr = MSL.Elem(); + for(int i = 0; i < nr*nc;i++){ + *my_ptr++ = *their_ptr++; + } + } + for (jn = 0; jn < numsidenodes_large; jn++) { if (MBlocksmall.Size(in) == 0 || MBlocklarge.Size(jn) == 0) { continue; } int64_t jnodindex = large->SideConnectIndex(jn, neighbourside); - TPZConnect::TPZDepend *depend = inod.AddDependency(inodindex, jnodindex, MSL, MBlocksmall.Position(in), MBlocklarge.Position(jn), - MBlocksmall.Size(in), MBlocklarge.Size(jn)); + TPZConnect::TPZDepend *depend = + inod.AddDependency(inodindex, jnodindex, MSLdep, + MBlocksmall.Position(in), MBlocklarge.Position(jn), + MBlocksmall.Size(in), MBlocklarge.Size(jn)); if (blocknorm(in, jn) < 1.e-8) { depend->fDepMatrix.Zero(); } @@ -1010,7 +1038,7 @@ void TPZInterpolatedElement::RestrainSide(int side, TPZInterpolatedElement *larg for (jn = 0; jn < numsidenodes_large; jn++) { int64_t jnodindex = large->SideConnectIndex(jn, neighbourside); if (MBlocklarge.Size(jn)) { - inod.AddDependency(inodindex, jnodindex, MSL, MBlocksmall.Position(in), MBlocklarge.Position(jn), + inod.AddDependency(inodindex, jnodindex, MSLdep, MBlocksmall.Position(in), MBlocklarge.Position(jn), MBlocksmall.Size(in), MBlocklarge.Size(jn)); } ndepend++; diff --git a/Mesh/pzintel.h b/Mesh/pzintel.h index 9986e3b30..a8a6cc910 100644 --- a/Mesh/pzintel.h +++ b/Mesh/pzintel.h @@ -47,7 +47,8 @@ class TPZInterpolatedElement : public TPZInterpolationSpace { */ static int ComputeSideOrder(TPZVec &elementset); - + template + void RestrainSideT(int side, TPZInterpolatedElement *large, int neighbourside); public: /** * @brief Constructor with a mesh and geometric element as arguments diff --git a/Mesh/pzinterpolationspace.cpp b/Mesh/pzinterpolationspace.cpp index 9cb16f107..2cf78f09b 100644 --- a/Mesh/pzinterpolationspace.cpp +++ b/Mesh/pzinterpolationspace.cpp @@ -1121,11 +1121,19 @@ void TPZInterpolationSpace::RemoveInterface(int side) { } void TPZInterpolationSpace::EvaluateError(TPZVec &errors,bool store_error){ + if(this->Mesh()->GetSolType() == ESolType::EReal){ + EvaluateErrorT(errors,store_error); + }else{ + EvaluateErrorT(errors,store_error); + } +} + +template +void TPZInterpolationSpace::EvaluateErrorT(TPZVec &errors,bool store_error){ errors.Fill(0.); - //TODOCOMPLEX auto *material = this->Material(); auto* materror = - dynamic_cast *>(this->Material()); + dynamic_cast *>(this->Material()); //TPZMaterial * matptr = material.operator->(); if (!material) { PZError << __PRETTY_FUNCTION__; @@ -1180,7 +1188,7 @@ void TPZInterpolationSpace::EvaluateError(TPZVec &errors,bool store_error) TPZManVector intpoint(problemdimension), values(NErrors); REAL weight; - TPZMaterialDataT data; + TPZMaterialDataT data; this->InitMaterialData(data); const int nintpoints = intrule->NPoints(); @@ -1207,7 +1215,7 @@ void TPZInterpolationSpace::EvaluateError(TPZVec &errors,bool store_error) if(store_error) { int64_t index = Index(); - TPZFMatrix &elvals = Mesh()->ElementSolution(); + TPZFMatrix &elvals = Mesh()->ElementSolution(); if (elvals.Cols() < NErrors) { PZError<<__PRETTY_FUNCTION__; PZError << " The element solution of the mesh should be resized before EvaluateError\n"; diff --git a/Mesh/pzinterpolationspace.h b/Mesh/pzinterpolationspace.h index 1af73a963..89146a7eb 100644 --- a/Mesh/pzinterpolationspace.h +++ b/Mesh/pzinterpolationspace.h @@ -375,6 +375,8 @@ virtual int ClassId() const override; template void ComputeRequiredDataT(TPZMaterialDataT &data, TPZVec &qsi); + template + void EvaluateErrorT(TPZVec &errors, bool store_error ); template void SolutionInternal(TPZVec &qsi,int var,TPZVec &sol); /// Preferred polynomial order diff --git a/SpecialMaps/TPZCylinderMap.cpp b/SpecialMaps/TPZCylinderMap.cpp index be4f54474..a14afb339 100644 --- a/SpecialMaps/TPZCylinderMap.cpp +++ b/SpecialMaps/TPZCylinderMap.cpp @@ -47,13 +47,19 @@ namespace pzgeom { we need to normalise it*/ { REAL normorth1{0}; - for(auto &xx : orth1) {normorth1 += xx*xx;} + for(const auto &xx : orth1) {normorth1 += xx*xx;} normorth1 = sqrt(normorth1); for(auto &xx : orth1) {xx /= normorth1;} } TPZManVector orth2(3,0.); Cross(y,orth1,orth2); + { + REAL normorth2{0}; + for(const auto &xx : orth2) {normorth2 += xx*xx;} + normorth2 = sqrt(normorth2); + for(auto &xx : orth2) {xx /= normorth2;} + } for(int i = 0; i < 3; i++){ fRotation(i,0) = orth1[i]; fRotation(i,1) = orth2[i]; diff --git a/SpecialMaps/TPZCylinderMap.h b/SpecialMaps/TPZCylinderMap.h index 032125147..518f81e03 100644 --- a/SpecialMaps/TPZCylinderMap.h +++ b/SpecialMaps/TPZCylinderMap.h @@ -90,6 +90,19 @@ namespace pzgeom { /** @brief Sets axis of the cylinder and compute rotation matrix*/ void SetCylinderAxis(const TPZVec &axis); + + void GetCylinderAxis(TPZVec &axis) const + { +#ifdef PZDEBUG + if(axis.size()!=3){ + DebugStop(); + } +#endif + //axis is the last column of rotation matrix + axis[0] = fRotation.GetVal(0,2); + axis[1] = fRotation.GetVal(1,2); + axis[2] = fRotation.GetVal(2,2); + } /** @brief Sets the rotation matrix that converts from the reference cylinder to the cylinder in the xyz space. Reference cylinder has axis (0,0,1), therefore last column of rotation matrix diff --git a/SpecialMaps/tpzchangeel.cpp b/SpecialMaps/tpzchangeel.cpp index 026ea46cf..74a8a0f89 100644 --- a/SpecialMaps/tpzchangeel.cpp +++ b/SpecialMaps/tpzchangeel.cpp @@ -25,7 +25,7 @@ #include "pzgeoelside.h" #include "pzstack.h" #include "tpzgeoelrefpattern.h" - +#include "pzvec_extras.h" #include using namespace std; using namespace pzgeom; @@ -468,6 +468,21 @@ TPZGeoEl * TPZChangeEl::ChangeToArc3D(TPZGeoMesh *mesh, const int64_t ElemIndex, PZError << "Error at " << __PRETTY_FUNCTION__ << " geometric el is not 1d\n"; return NULL; } + + TPZManVector xnode(3,0); + for(int in = 0; in < 2; in++){ + old_el->NodePtr(in)->GetCoordinates(xnode); + const auto normdiff = fabs(Norm(xnode-xcenter)-radius); + if(normdiff > 1e-10){ + PZError<<__PRETTY_FUNCTION__ + <<"\nComputed radius: "<Id(); const int64_t oldMatId = old_el->MaterialId(); constexpr int nsides = 3; @@ -500,18 +515,19 @@ TPZGeoEl * TPZChangeEl::ChangeToArc3D(TPZGeoMesh *mesh, const int64_t ElemIndex, template TPZGeoEl * ChangeToCylinderT(TPZGeoMesh *mesh, const int64_t ElemIndex, const TPZVec &xcenter, - const T &axis - ) + const T &axis_or_mat, + const REAL radius) { - auto SetCylData = [xcenter,axis,mesh](auto &cyl){ + auto SetCylData = [xcenter,axis_or_mat,mesh](auto &cyl, TPZVec &axis){ cyl.SetOrigin(xcenter); if constexpr (std::is_same_v>){ - cyl.SetRotationMatrix(axis); + cyl.SetRotationMatrix(axis_or_mat); }else{ - cyl.SetCylinderAxis(axis); + cyl.SetCylinderAxis(axis_or_mat); } cyl.ComputeCornerCoordinates(*mesh); + cyl.GetCylinderAxis(axis); }; TPZGeoEl * old_el = mesh->ElementVec()[ElemIndex]; @@ -536,68 +552,93 @@ TPZGeoEl * ChangeToCylinderT(TPZGeoMesh *mesh, const int64_t ElemIndex, for(int in = 0; in < nnodes; in++){ nodeindexes[in] = old_el->NodeIndex(in); } + mesh->DeleteElement(old_el); TPZGeoEl *new_el{nullptr}; + TPZManVector axis(3,0.); if (oldType == EOned){ auto cyl = new TPZGeoElRefPattern>(nodeindexes, oldMatId, *mesh); - SetCylData(cyl->Geom()); + SetCylData(cyl->Geom(),axis); new_el = cyl; } else if(oldType == ETriangle){ auto cyl = new TPZGeoElRefPattern>(nodeindexes, oldMatId, *mesh); - SetCylData(cyl->Geom()); + SetCylData(cyl->Geom(),axis); new_el = cyl; }else if (oldType == EQuadrilateral){ auto cyl = new TPZGeoElRefPattern>(nodeindexes, oldMatId, *mesh); - SetCylData(cyl->Geom()); + SetCylData(cyl->Geom(),axis); new_el = cyl; }else if (oldType == ETetraedro){ auto cyl = new TPZGeoElRefPattern>(nodeindexes, oldMatId, *mesh); - SetCylData(cyl->Geom()); + SetCylData(cyl->Geom(),axis); new_el = cyl; }else if (oldType == ECube){ auto cyl = new TPZGeoElRefPattern>(nodeindexes, oldMatId, *mesh); - SetCylData(cyl->Geom()); + SetCylData(cyl->Geom(),axis); new_el = cyl; }else if (oldType == EPrisma){ auto cyl = new TPZGeoElRefPattern>(nodeindexes, oldMatId, *mesh); - SetCylData(cyl->Geom()); + SetCylData(cyl->Geom(),axis); new_el = cyl; } else if (oldType == EPiramide){ auto cyl = new TPZGeoElRefPattern>(nodeindexes, oldMatId, *mesh); - SetCylData(cyl->Geom()); + SetCylData(cyl->Geom(),axis); new_el = cyl; } else { DebugStop(); } + //for 2d elements we know it is a cylinder shell with constant radius + if(new_el->Dimension() ==2){ + TPZManVector xnode(3,0); + for(int in = 0; in < nnodes; in++){ + new_el->NodePtr(in)->GetCoordinates(xnode); + //component of xnode that is orthogonal to cyl axis + TPZManVector x_orth= xnode - xcenter; + const REAL dax = Dot(x_orth,axis); + for(int ix = 0; ix < 3; ix++){x_orth[ix]-=dax*axis[ix];} + const auto normdiff = fabs(Norm(x_orth)-radius); + if(normdiff > 1e-10){ + PZError<<__PRETTY_FUNCTION__ + <<"\nComputed radius: "< &xcenter, - const TPZFMatrix &rotmat + const TPZFMatrix &rotmat, + const REAL radius ){ - return ChangeToCylinderT(mesh,ElemIndex,xcenter,rotmat); + return ChangeToCylinderT(mesh,ElemIndex,xcenter,rotmat,radius); } TPZGeoEl * TPZChangeEl::ChangeToCylinder(TPZGeoMesh *mesh, const int64_t ElemIndex, const TPZVec &xcenter, - const TPZVec &axis + const TPZVec &axis, + const REAL radius ) { - return ChangeToCylinderT(mesh,ElemIndex,xcenter,axis); + return ChangeToCylinderT(mesh,ElemIndex,xcenter,axis,radius); } diff --git a/SpecialMaps/tpzchangeel.h b/SpecialMaps/tpzchangeel.h index 149aaa702..6fdc377e9 100644 --- a/SpecialMaps/tpzchangeel.h +++ b/SpecialMaps/tpzchangeel.h @@ -38,11 +38,13 @@ class TPZChangeEl { /** @brief Turns a regular 2D element into a TPZCylinderMap(using rotation matrix)*/ static TPZGeoEl * ChangeToCylinder(TPZGeoMesh *mesh, const int64_t ElemIndex, const TPZVec &xcenter, - const TPZFMatrix &rotmatrix); + const TPZFMatrix &rotmatrix, + const REAL radius); /** @brief Turns a regular 2D element into a TPZCylinderMap(using cylinder axis)*/ static TPZGeoEl * ChangeToCylinder(TPZGeoMesh *mesh, const int64_t ElemIndex, const TPZVec &xcenter, - const TPZVec &axis); + const TPZVec &axis, + const REAL radius); /** @brief Slide middle nodes of an quadratic geoelement to the quarterpoint with respect to a given side */ static TPZGeoEl * ChangeToQuarterPoint(TPZGeoMesh *Mesh, int64_t ElemIndex, int targetSide); diff --git a/UnitTest_PZ/TestGeometry/GeometryUnitTest.cpp b/UnitTest_PZ/TestGeometry/GeometryUnitTest.cpp index c1d61c6b2..22cc8a4fc 100644 --- a/UnitTest_PZ/TestGeometry/GeometryUnitTest.cpp +++ b/UnitTest_PZ/TestGeometry/GeometryUnitTest.cpp @@ -485,7 +485,7 @@ TEST_CASE("changeel_tests","[geometry_tests]") { TPZFNMatrix<9,REAL> ax(3,3); ax.Identity(); trig_el = TPZChangeEl::ChangeToCylinder(&gmesh, trig_el->Index(), - xc, ax); + xc, ax, radius); REQUIRE(trig_el); TestPts(trig_el); nodevec.Resize(4); @@ -495,7 +495,7 @@ TEST_CASE("changeel_tests","[geometry_tests]") { new TPZGeoElRefPattern(nodevec,trig_mat+1,gmesh); gmesh.BuildConnectivity(); quad_el = TPZChangeEl::ChangeToCylinder(&gmesh, quad_el->Index(), - xc, ax); + xc, ax, radius); REQUIRE(quad_el); TestPts(quad_el); diff --git a/Util/TPZParallelUtils.h b/Util/TPZParallelUtils.h index c786c854c..16e928a7d 100644 --- a/Util/TPZParallelUtils.h +++ b/Util/TPZParallelUtils.h @@ -28,28 +28,31 @@ as in It is the user responsability to use the necessary mutexes and locks. */ template -void ParallelFor( int ibeg, int iend, const TFunc & f ) +void ParallelFor( int ibeg, int iend, const TFunc & f ,const int nt=-1) { - const auto nthreads = std::thread::hardware_concurrency(); - std::vector threadvec; - const int sz = (iend-ibeg)/nthreads; - for (int i=0; i -1 ? nt : std::thread::hardware_concurrency(); + int sz{0}; + if(nthreads){ + std::vector threadvec; + sz = (iend-ibeg)/nthreads; + for (int i=0; i &one) { RType(T) res = 0.; int size = one.NElements(); if constexpr (is_complex::value){ + T cres{0}; for (int i = 0; i < size; i++) { - res += (RType(T)) one[i] * std::conj(one[i]); + cres += one[i] * std::conj(one[i]); } + res = cres.real(); }else{ for (int i = 0; i < size; i++) { res += one[i]*one[i];