From 459463878aa5515c8f5b1426459f202b3d874f7c Mon Sep 17 00:00:00 2001 From: Arne Morten Kvarving Date: Wed, 27 Apr 2022 10:54:15 +0200 Subject: [PATCH] introduce support for an alternative projection basis --- src/ASM/ASMbase.h | 2 ++ src/ASM/ASMs2Dmx.C | 21 +++++++++++++++++++-- src/ASM/ASMs2Dmx.h | 16 ++++++++++------ src/ASM/ASMs3Dmx.C | 21 +++++++++++++++++++-- src/ASM/ASMs3Dmx.h | 17 +++++++++++------ src/ASM/LR/ASMu2Dmx.C | 16 ++++++++++++++++ src/ASM/LR/ASMu2Dmx.h | 5 +++++ src/ASM/LR/ASMu3Dmx.C | 20 ++++++++++++++++++++ src/ASM/LR/ASMu3Dmx.h | 5 +++++ 9 files changed, 107 insertions(+), 16 deletions(-) diff --git a/src/ASM/ASMbase.h b/src/ASM/ASMbase.h index 03efba45..b916ac06 100644 --- a/src/ASM/ASMbase.h +++ b/src/ASM/ASMbase.h @@ -682,6 +682,8 @@ public: virtual bool createProjectionBasis(bool) { return false; } //! \brief Checks if a separate projection basis is used for this patch. virtual bool separateProjectionBasis() const { return false; } + //! \brief Swap between main and alternative projection basis. + virtual void swapProjectionBasis() {} // Methods for result extraction diff --git a/src/ASM/ASMs2Dmx.C b/src/ASM/ASMs2Dmx.C index 2f1770bb..3e12400d 100644 --- a/src/ASM/ASMs2Dmx.C +++ b/src/ASM/ASMs2Dmx.C @@ -44,6 +44,12 @@ ASMs2Dmx::ASMs2Dmx (const ASMs2Dmx& patch, const CharVec& n_f) } +ASMs2Dmx::~ASMs2Dmx () +{ + delete altProjBasis; +} + + Go::SplineSurface* ASMs2Dmx::getBasis (int basis) const { if (basis < 1 || basis > (int)m_basis.size()) @@ -206,9 +212,10 @@ bool ASMs2Dmx::generateFEMTopology () ASMmxBase::Type == ASMmxBase::REDUCED_CONT_RAISE_BASIS2 || ASMmxBase::Type == ASMmxBase::DIV_COMPATIBLE) projB = proj = ASMmxBase::raiseBasis(surf); - else if (ASMmxBase::Type == ASMmxBase::SUBGRID) + else if (ASMmxBase::Type == ASMmxBase::SUBGRID) { projB = proj = m_basis.front()->clone(); - else + altProjBasis = ASMmxBase::raiseBasis(surf); + } else projB = proj = m_basis[2-ASMmxBase::geoBasis]->clone(); } delete surf; @@ -1237,3 +1244,13 @@ void ASMs2Dmx::getBoundaryNodes (int lIndex, IntVec& nodes, int basis, for (size_t b = 1; b <= m_basis.size(); b++) this->ASMs2D::getBoundaryNodes(lIndex, nodes, b, thick, 0, local); } + + +void ASMs2Dmx::swapProjectionBasis () +{ + if (altProjBasis) { + ASMmxBase::geoBasis = ASMmxBase::geoBasis == 1 ? 2 : 1; + std::swap(proj, altProjBasis); + surf = this->getBasis(ASMmxBase::geoBasis); + } +} diff --git a/src/ASM/ASMs2Dmx.h b/src/ASM/ASMs2Dmx.h index ca93504b..71788c38 100644 --- a/src/ASM/ASMs2Dmx.h +++ b/src/ASM/ASMs2Dmx.h @@ -36,8 +36,8 @@ public: ASMs2Dmx(unsigned char n_s, const CharVec& n_f); //! \brief Copy constructor. ASMs2Dmx(const ASMs2Dmx& patch, const CharVec& n_f = CharVec(2,0)); - //! \brief Empty destructor. - virtual ~ASMs2Dmx() {} + //! \brief Destructor. + virtual ~ASMs2Dmx(); //! \brief Returns the spline surface representing the basis of this patch. virtual Go::SplineSurface* getBasis(int basis = 1) const; @@ -123,7 +123,7 @@ public: //! \param glbInt The integrated quantity //! \param[in] time Parameters for nonlinear/time-dependent simulations virtual bool integrate(Integrand& integrand, - GlobalIntegral& glbInt, const TimeDomain& time); + GlobalIntegral& glbInt, const TimeDomain& time); //! \brief Evaluates a boundary integral over a patch edge. //! \param integrand Object with problem-specific data and methods @@ -131,7 +131,7 @@ public: //! \param glbInt The integrated quantity //! \param[in] time Parameters for nonlinear/time-dependent simulations virtual bool integrate(Integrand& integrand, int lIndex, - GlobalIntegral& glbInt, const TimeDomain& time); + GlobalIntegral& glbInt, const TimeDomain& time); //! \brief Evaluates an integral over element interfaces in the patch. //! \param integrand Object with problem-specific data and methods @@ -158,7 +158,7 @@ public: //! \param[in] locSol Solution vector local to current patch //! \param[in] nodes 1-based local node numbers to extract solution for virtual bool getSolution(Matrix& sField, const Vector& locSol, - const IntVec& nodes) const; + const IntVec& nodes) const; using ASMs2D::evalSolution; //! \brief Evaluates the primary solution field at the given points. @@ -192,7 +192,10 @@ public: //! Otherwise, we assume that it contains the \a u and \a v parameters //! directly for each sampling point. virtual bool evalSolution(Matrix& sField, const IntegrandBase& integrand, - const RealArray* gpar, bool regular) const; + const RealArray* gpar, bool regular) const; + + //! \brief Swap between main and alternative projection basis. + virtual void swapProjectionBasis(); //! \brief Extracts nodal results for this patch from the global vector. //! \param[in] globVec Global solution vector in DOF-order @@ -234,6 +237,7 @@ public: protected: std::vector> m_basis; //!< Vector of bases + Go::SplineSurface* altProjBasis = nullptr; //!< Alternative projection basis }; #endif diff --git a/src/ASM/ASMs3Dmx.C b/src/ASM/ASMs3Dmx.C index 2bcf5926..1bd6337d 100644 --- a/src/ASM/ASMs3Dmx.C +++ b/src/ASM/ASMs3Dmx.C @@ -50,6 +50,12 @@ ASMs3Dmx::ASMs3Dmx (const ASMs3Dmx& patch, const CharVec& n_f) } +ASMs3Dmx::~ASMs3Dmx () +{ + delete altProjBasis; +} + + Go::SplineVolume* ASMs3Dmx::getBasis (int basis) const { if (basis < 1 || basis > (int)m_basis.size()) @@ -207,9 +213,10 @@ bool ASMs3Dmx::generateFEMTopology () ASMmxBase::Type == ASMmxBase::REDUCED_CONT_RAISE_BASIS2 || ASMmxBase::Type == ASMmxBase::DIV_COMPATIBLE) projB = proj = ASMmxBase::raiseBasis(svol); - else if (ASMmxBase::Type == ASMmxBase::SUBGRID) + else if (ASMmxBase::Type == ASMmxBase::SUBGRID) { projB = proj = m_basis.front()->clone(); - else + altProjBasis = ASMmxBase::raiseBasis(svol); + } else projB = proj = m_basis[2-ASMmxBase::geoBasis]->clone(); } delete svol; @@ -1359,3 +1366,13 @@ void ASMs3Dmx::getBoundaryNodes (int lIndex, IntVec& nodes, int basis, for (size_t b = 1; b <= m_basis.size(); b++) this->ASMs3D::getBoundaryNodes(lIndex, nodes, b, thick, 0, local); } + + +void ASMs3Dmx::swapProjectionBasis () +{ + if (altProjBasis) { + ASMmxBase::geoBasis = ASMmxBase::geoBasis == 1 ? 2 : 1; + std::swap(proj, altProjBasis); + svol = this->getBasis(ASMmxBase::geoBasis); + } +} diff --git a/src/ASM/ASMs3Dmx.h b/src/ASM/ASMs3Dmx.h index 57957e82..95c6bdca 100644 --- a/src/ASM/ASMs3Dmx.h +++ b/src/ASM/ASMs3Dmx.h @@ -36,8 +36,8 @@ public: explicit ASMs3Dmx(const CharVec& n_f); //! \brief Copy constructor. ASMs3Dmx(const ASMs3Dmx& patch, const CharVec& n_f = CharVec(2,0)); - //! \brief Empty destructor. - virtual ~ASMs3Dmx() {} + //! \brief Destructor. + virtual ~ASMs3Dmx(); //! \brief Returns the spline surface representing the basis of this patch. virtual Go::SplineVolume* getBasis(int basis = 1) const; @@ -116,7 +116,7 @@ public: //! \param glbInt The integrated quantity //! \param[in] time Parameters for nonlinear/time-dependent simulations virtual bool integrate(Integrand& integrand, - GlobalIntegral& glbInt, const TimeDomain& time); + GlobalIntegral& glbInt, const TimeDomain& time); //! \brief Evaluates a boundary integral over a patch edge. //! \param integrand Object with problem-specific data and methods @@ -124,7 +124,7 @@ public: //! \param glbInt The integrated quantity //! \param[in] time Parameters for nonlinear/time-dependent simulations virtual bool integrate(Integrand& integrand, int lIndex, - GlobalIntegral& glbInt, const TimeDomain& time); + GlobalIntegral& glbInt, const TimeDomain& time); //! \brief Evaluates an integral over element interfaces in the patch. //! \param integrand Object with problem-specific data and methods @@ -150,7 +150,7 @@ public: //! \param[in] locSol Solution vector local to current patch //! \param[in] nodes 1-based local node numbers to extract solution for virtual bool getSolution(Matrix& sField, const Vector& locSol, - const IntVec& nodes) const; + const IntVec& nodes) const; using ASMs3D::evalSolution; //! \brief Evaluates the primary solution field at the given points. @@ -184,7 +184,10 @@ public: //! Otherwise, we assume that it contains the \a u, \a v and \a w parameters //! directly for each sampling point. virtual bool evalSolution(Matrix& sField, const IntegrandBase& integrand, - const RealArray* gpar, bool regular) const; + const RealArray* gpar, bool regular) const; + + //! \brief Swap between main and alternative projection basis. + virtual void swapProjectionBasis(); //! \brief Extracts nodal results for this patch from the global vector. //! \param[in] globVec Global solution vector in DOF-order @@ -213,6 +216,7 @@ public: //! \param[out] n3 Number of nodes in third (w) direction //! \param[in] basis Which basis to return size parameters for virtual bool getSize(int& n1, int& n2, int& n3, int basis) const; + protected: //! \brief Returns the volume in the parameter space for an element. //! \param[in] iel Element index @@ -232,6 +236,7 @@ protected: int thick, int, bool local) const; std::vector> m_basis; //!< Vector of bases + Go::SplineVolume* altProjBasis = nullptr; //!< Alternative projection basis }; #endif diff --git a/src/ASM/LR/ASMu2Dmx.C b/src/ASM/LR/ASMu2Dmx.C index 87ae4c61..416fd28f 100644 --- a/src/ASM/LR/ASMu2Dmx.C +++ b/src/ASM/LR/ASMu2Dmx.C @@ -227,6 +227,7 @@ bool ASMu2Dmx::generateFEMTopology () refBasis.reset(new LR::LRSplineSurface(otherBasis)); if (!projBasis) projBasis = m_basis.front(); + altProjBasis = refBasis; } else { if (!projBasis) @@ -1018,6 +1019,9 @@ bool ASMu2Dmx::refine (const LR::RefineData& prm, Vectors& sol) m_basis[0]->refineBasisFunction(elems); } + if (altProjBasis) + altProjBasis->generateIDs(); + size_t len = 0; for (size_t j = 0; j< m_basis.size(); ++j) { m_basis[j]->generateIDs(); @@ -1099,6 +1103,8 @@ void ASMu2Dmx::generateThreadGroups (const Integrand& integrand, bool silence, LR::generateThreadGroups(threadGroups,threadBasis,secConstraint); LR::generateThreadGroups(projThreadGroups,projBasis.get()); + if (altProjBasis) + LR::generateThreadGroups(altProjThreadGroups,altProjBasis.get()); std::vector bases; for (const std::shared_ptr& basis : m_basis) @@ -1223,3 +1229,13 @@ void ASMu2Dmx::copyRefinement (LR::LRSplineSurface* basis, line->start_, line->stop_, mult); } } + + +void ASMu2Dmx::swapProjectionBasis () +{ + if (altProjBasis) { + ASMmxBase::geoBasis = ASMmxBase::geoBasis == 1 ? 2 : 1; + std::swap(projBasis, altProjBasis); + std::swap(projThreadGroups, altProjThreadGroups); + } +} diff --git a/src/ASM/LR/ASMu2Dmx.h b/src/ASM/LR/ASMu2Dmx.h index 098eb3d5..94bb65ba 100644 --- a/src/ASM/LR/ASMu2Dmx.h +++ b/src/ASM/LR/ASMu2Dmx.h @@ -215,6 +215,9 @@ public: //! \param multiplicity Wanted multiplicity void copyRefinement(LR::LRSplineSurface* basis, int multiplicity) const; + //! \brief Swap between main and alternative projection basis. + virtual void swapProjectionBasis(); + protected: using ASMu2D::generateThreadGroups; //! \brief Generates element groups for multi-threading of interior integrals. @@ -228,6 +231,8 @@ private: std::vector> m_basis; //!< All bases LR::LRSplineSurface* threadBasis; //!< Basis for thread groups std::shared_ptr refBasis; //!< Basis to refine based on + std::shared_ptr altProjBasis; //!< Alternative projection basis + ThreadGroups altProjThreadGroups; //!< Element groups for multi-threaded assembly - alternative projection basis }; #endif diff --git a/src/ASM/LR/ASMu3Dmx.C b/src/ASM/LR/ASMu3Dmx.C index 4733a240..46f4f8b1 100644 --- a/src/ASM/LR/ASMu3Dmx.C +++ b/src/ASM/LR/ASMu3Dmx.C @@ -215,6 +215,7 @@ bool ASMu3Dmx::generateFEMTopology () refBasis.reset(new LR::LRSplineVolume(otherBasis.get())); projBasis = m_basis.front(); refBasis->generateIDs(); + altProjBasis = refBasis; } else { projBasis.reset(new LR::LRSplineVolume(otherBasis.get())); refBasis = projBasis; @@ -231,6 +232,10 @@ bool ASMu3Dmx::generateFEMTopology () lrspline = m_basis[geoBasis-1]; projBasis->generateIDs(); projBasis->getElementContaining(projBasis->getElement(0)->midpoint()); // to force cache generation + if (altProjBasis) { + altProjBasis->generateIDs(); + altProjBasis->getElementContaining(projBasis->getElement(0)->midpoint()); // to force cache generation + } myGeoBasis = ASMmxBase::geoBasis; nb.resize(m_basis.size()); @@ -977,6 +982,9 @@ bool ASMu3Dmx::refine (const LR::RefineData& prm, Vectors& sol) m_basis[0]->refineBasisFunction(elems); } + if (altProjBasis) + altProjBasis->generateIDs(); + size_t len = 0; for (size_t j = 0; j< m_basis.size(); ++j) { m_basis[j]->generateIDs(); @@ -1100,6 +1108,8 @@ void ASMu3Dmx::generateThreadGroups (const Integrand& integrand, bool silence, LR::generateThreadGroups(threadGroups,threadBasis,secConstraint); LR::generateThreadGroups(projThreadGroups,projBasis.get()); + if (altProjBasis) + LR::generateThreadGroups(altProjThreadGroups,altProjBasis.get()); std::vector bases; for (const std::shared_ptr& basis : m_basis) @@ -1119,3 +1129,13 @@ void ASMu3Dmx::generateThreadGroups (const Integrand& integrand, bool silence, this->analyzeThreadGroups(threadGroups[0]); #endif } + + +void ASMu3Dmx::swapProjectionBasis () +{ + if (altProjBasis) { + ASMmxBase::geoBasis = ASMmxBase::geoBasis == 1 ? 2 : 1; + std::swap(projBasis, altProjBasis); + std::swap(projThreadGroups, altProjThreadGroups); + } +} diff --git a/src/ASM/LR/ASMu3Dmx.h b/src/ASM/LR/ASMu3Dmx.h index 699075b7..2962ff43 100644 --- a/src/ASM/LR/ASMu3Dmx.h +++ b/src/ASM/LR/ASMu3Dmx.h @@ -181,6 +181,9 @@ public: //! \param multiplicity Wanted multiplicity void copyRefinement(LR::LRSplineVolume* basis, int multiplicity) const; + //! \brief Swap between main and alternative projection basis. + virtual void swapProjectionBasis(); + protected: //! \brief Generates element groups for multi-threading of interior integrals. //! \param[in] integrand Object with problem-specific data and methods @@ -192,9 +195,11 @@ protected: private: std::vector> m_basis; //!< Spline bases std::shared_ptr refBasis; //!< Basis to refine based on + std::shared_ptr altProjBasis; //!< Alternative projection basis LR::LRSplineVolume* threadBasis; //!< Basis for thread groups const std::vector& bezierExtractmx; //!< Bezier extraction matrices std::vector myBezierExtractmx; //!< Bezier extraction matrices + ThreadGroups altProjThreadGroups; //!< Element groups for multi-threaded assembly - alternative projection basis }; #endif