From 122912bc32b0b2d61eca493220cccd85edf99ef8 Mon Sep 17 00:00:00 2001 From: Knut Morten Okstad Date: Thu, 20 Sep 2018 17:43:26 +0200 Subject: [PATCH] Added: Overload the constrain methods for mixed to also allow specifying DOFs to constrain for all bases (when invoked with basis=0) --- src/ASM/ASMmxBase.C | 23 +++++- src/ASM/ASMmxBase.h | 12 ++- src/ASM/ASMs2Dmx.C | 26 ++++++ src/ASM/ASMs2Dmx.h | 43 +++++++--- src/ASM/ASMs3Dmx.C | 187 +++++++++++++++++++++++++----------------- src/ASM/ASMs3Dmx.h | 41 +++++++-- src/ASM/LR/ASMu2Dmx.C | 26 ++++++ src/ASM/LR/ASMu2Dmx.h | 15 ++++ src/ASM/LR/ASMu3Dmx.C | 41 +++++++++ src/ASM/LR/ASMu3Dmx.h | 27 ++++++ src/SIM/SIMinput.C | 2 +- 11 files changed, 345 insertions(+), 98 deletions(-) diff --git a/src/ASM/ASMmxBase.C b/src/ASM/ASMmxBase.C index 6c32ebb85..2020f729d 100644 --- a/src/ASM/ASMmxBase.C +++ b/src/ASM/ASMmxBase.C @@ -12,6 +12,7 @@ //============================================================================== #include "ASMmxBase.h" +#include "Utilities.h" #include "GoTools/geometry/SplineSurface.h" #include "GoTools/geometry/SurfaceInterpolator.h" #include "GoTools/trivariate/SplineVolume.h" @@ -250,8 +251,8 @@ ASMmxBase::SurfaceVec ASMmxBase::establishBases (Go::SplineSurface* surf, } -ASMmxBase::VolumeVec ASMmxBase::establishBases(Go::SplineVolume* svol, - MixedType type) +ASMmxBase::VolumeVec ASMmxBase::establishBases (Go::SplineVolume* svol, + MixedType type) { VolumeVec result(2); // With mixed methods we need two separate spline spaces @@ -500,3 +501,21 @@ Go::SplineVolume* ASMmxBase::raiseBasis (Go::SplineVolume* svol) // Project the coordinates onto the new basis (the 2nd XYZ is dummy here) return Go::VolumeInterpolator::regularInterpolation(basis[0],basis[1],basis[2],ug[0],ug[1],ug[2],XYZ,ndim,false,XYZ); } + + +int ASMmxBase::maskDOFs (int dofs, char basis) const +{ + unsigned char ofs = std::accumulate(nfx.begin(),nfx.begin()+basis-1,0u); + std::set allDofs = utl::getDigits(dofs); + dofs = 0; + + // Convert the DOF digits to local values of this basis, + // and mask off those not residing on this basis + for (int dof : allDofs) + { + dofs *= 10; + if (dof > ofs && dof <= ofs+nfx[basis-1]) + dofs += dof - ofs; + } + return dofs; +} diff --git a/src/ASM/ASMmxBase.h b/src/ASM/ASMmxBase.h index 771d99122..61a2df54a 100644 --- a/src/ASM/ASMmxBase.h +++ b/src/ASM/ASMmxBase.h @@ -76,8 +76,10 @@ class ASMmxBase static char geoBasis; //!< 1-based index of basis representing the geometry protected: - typedef std::vector> SurfaceVec; //!< Convenience type - typedef std::vector> VolumeVec; //!< Convenience type + typedef std::shared_ptr SurfacePtr; //!< Pointer to spline + typedef std::shared_ptr VolumePtr; //!< Pointer to spline + typedef std::vector SurfaceVec; //!< Convenience type + typedef std::vector VolumeVec; //!< Convenience type //! \brief Establish mixed bases in 2D. //! \param[in] surf The base basis to use @@ -96,6 +98,12 @@ class ASMmxBase //! \brief Returns a C^p-1 basis of one degree higher than \a *svol. static Go::SplineVolume* raiseBasis(Go::SplineVolume* svol); + //! \brief Mask off DOFs not residing on the specified basis + //! \param[in] dofs Encoded DOF indices (like 123456 meaning dofs 1 to 6) + //! \param[in] basis Which basis to return DOF indices for + //! \return Encoded DOF indices related to the specified basis only + int maskDOFs(int dofs, char basis) const; + private: std::vector MADOF; //!< Matrix of accumulated DOFs for this patch diff --git a/src/ASM/ASMs2Dmx.C b/src/ASM/ASMs2Dmx.C index 01903a0ac..1e4b9b682 100644 --- a/src/ASM/ASMs2Dmx.C +++ b/src/ASM/ASMs2Dmx.C @@ -341,6 +341,32 @@ bool ASMs2Dmx::generateFEMTopology () } +void ASMs2Dmx::constrainEdge (int dir, bool open, int dof, int code, char basis) +{ + if (basis > 0) + this->ASMs2D::constrainEdge(dir,open,dof,code,basis); + else for (basis = 1; basis <= (char)nfx.size(); basis++) + { + int basisDofs = this->maskDOFs(dof,basis); + if (basisDofs > 0) + this->ASMs2D::constrainEdge(dir,open,basisDofs,code,basis); + } +} + + +void ASMs2Dmx::constrainCorner (int I, int J, int dof, int code, char basis) +{ + if (basis > 0) + this->ASMs2D::constrainCorner(I,J,dof,code,basis); + else for (basis = 1; basis <= (char)nfx.size(); basis++) + { + int basisDofs = this->maskDOFs(dof,basis); + if (basisDofs > 0) + this->ASMs2D::constrainCorner(I,J,basisDofs,code,basis); + } +} + + bool ASMs2Dmx::connectPatch (int edge, ASM2D& neighbor, int nedge, bool revers, int basis, bool coordCheck, int thick) { diff --git a/src/ASM/ASMs2Dmx.h b/src/ASM/ASMs2Dmx.h index 71788c382..19b39b9fc 100644 --- a/src/ASM/ASMs2Dmx.h +++ b/src/ASM/ASMs2Dmx.h @@ -16,7 +16,6 @@ #include "ASMs2D.h" #include "ASMmxBase.h" -#include /*! @@ -35,7 +34,7 @@ class ASMs2Dmx : public ASMs2D, private ASMmxBase //! \brief The constructor initializes the dimension of each basis. ASMs2Dmx(unsigned char n_s, const CharVec& n_f); //! \brief Copy constructor. - ASMs2Dmx(const ASMs2Dmx& patch, const CharVec& n_f = CharVec(2,0)); + ASMs2Dmx(const ASMs2Dmx& patch, const CharVec& n_f); //! \brief Destructor. virtual ~ASMs2Dmx(); @@ -87,17 +86,25 @@ class ASMs2Dmx : public ASMs2D, private ASMmxBase //! \brief Returns the classification of a node. //! \param[in] inod 1-based node index local to current patch virtual char getNodeType(size_t inod) const; - //! \brief Returns the area in the parameter space for an element. - //! \param[in] iel Element index - virtual double getParametricArea(int iel) const; - //! \brief Returns boundary edge length in the parameter space for an element. - //! \param[in] iel Element index - //! \param[in] dir Local index of the boundary edge - double getParametricLength(int iel, int dir) const; //! \brief Initializes the patch level MADOF array for mixed problems. virtual void initMADOF(const int* sysMadof); + //! \brief Constrains all DOFs on a given boundary edge. + //! \param[in] dir Parameter direction defining the edge to constrain + //! \param[in] open If \e true, exclude the end points of the edge + //! \param[in] dof Which DOFs to constrain at each node along the edge + //! \param[in] code Inhomogeneous dirichlet condition code + //! \param[in] basis Which basis to constrain edge for (0 means check all) + virtual void constrainEdge(int dir, bool open, int dof, int code, char basis); + //! \brief Constrains a corner node identified by the two parameter indices. + //! \param[in] I Parameter index in u-direction + //! \param[in] J Parameter index in v-direction + //! \param[in] dof Which DOFs to constrain at the node + //! \param[in] code Inhomogeneous dirichlet condition code + //! \param[in] basis Which basis to constrain node for (0 means check all) + virtual void constrainCorner(int I, int J, int dof, int code, char basis); + //! \brief Connects all matching nodes on two adjacent boundary edges. //! \param[in] edge Local edge index of this patch, in range [1,4] //! \param neighbor The neighbor patch @@ -139,7 +146,8 @@ class ASMs2Dmx : public ASMs2D, private ASMmxBase //! \param[in] time Parameters for nonlinear/time-dependent simulations //! \param[in] iChk Object checking if an element interface has contributions virtual bool integrate(Integrand& integrand, GlobalIntegral& glbInt, - const TimeDomain& time, const ASM::InterfaceChecker& iChk); + const TimeDomain& time, + const ASM::InterfaceChecker& iChk); // Post-processing methods @@ -204,7 +212,7 @@ class ASMs2Dmx : public ASMs2D, private ASMmxBase virtual void extractNodeVec(const RealArray& globVec, RealArray& nodeVec, unsigned char, int basis) const; - //! \brief Inject nodal results for this patch into a global vector. + //! \brief Injects nodal results for this patch into a global vector. //! \param[in] nodeVec Nodal result vector for this patch //! \param[out] globVec Global solution vector in DOF-order //! \param[in] basis Which basis (or 0 for both) to extract nodal values for @@ -215,7 +223,7 @@ class ASMs2Dmx : public ASMs2D, private ASMmxBase //! \brief Generates element groups for multi-threading of interior integrals. //! \param[in] integrand Object with problem-specific data and methods //! \param[in] silence If \e true, suppress threading group outprint - //! \param[in] ignoreGlobalLM If \e true, ignore global multipliers in sanity check + //! \param[in] ignoreGlobalLM Sanity check option virtual void generateThreadGroups(const Integrand& integrand, bool silence, bool ignoreGlobalLM); @@ -226,6 +234,15 @@ class ASMs2Dmx : public ASMs2D, private ASMmxBase //! \param[in] basis Which basis to return size parameters for virtual bool getSize(int& n1, int& n2, int basis) const; +protected: + //! \brief Returns the area in the parameter space for an element. + //! \param[in] iel Element index + double getParametricArea(int iel) const; + //! \brief Returns boundary edge length in the parameter space for an element. + //! \param[in] iel Element index + //! \param[in] dir Local index of the boundary edge + double getParametricLength(int iel, int dir) const; + //! \brief Finds the global (or patch-local) node numbers on a patch boundary. //! \param[in] lIndex Local index of the boundary edge //! \param nodes Array of node numbers @@ -235,7 +252,7 @@ class ASMs2Dmx : public ASMs2D, private ASMmxBase virtual void getBoundaryNodes(int lIndex, IntVec& nodes, int basis, int thick, int, bool local) const; -protected: +private: std::vector> m_basis; //!< Vector of bases Go::SplineSurface* altProjBasis = nullptr; //!< Alternative projection basis }; diff --git a/src/ASM/ASMs3Dmx.C b/src/ASM/ASMs3Dmx.C index ade7392f9..bb83e7fed 100644 --- a/src/ASM/ASMs3Dmx.C +++ b/src/ASM/ASMs3Dmx.C @@ -355,6 +355,47 @@ bool ASMs3Dmx::generateFEMTopology () } +void ASMs3Dmx::constrainFace (int dir, bool open, int dof, int code, char basis) +{ + if (basis > 0) + this->ASMs3D::constrainFace(dir,open,dof,code,basis); + else for (basis = 1; basis <= (char)nfx.size(); basis++) + { + int basisDofs = this->maskDOFs(dof,basis); + if (basisDofs > 0) + this->ASMs3D::constrainFace(dir,open,basisDofs,code,basis); + } +} + + +void ASMs3Dmx::constrainEdge (int lEdge, bool open, int dof, + int code, char basis) +{ + if (basis > 0) + this->ASMs3D::constrainEdge(lEdge,open,dof,code,basis); + else for (basis = 1; basis <= (char)nfx.size(); basis++) + { + int basisDofs = this->maskDOFs(dof,basis); + if (basisDofs > 0) + this->ASMs3D::constrainEdge(lEdge,open,basisDofs,code,basis); + } +} + + +void ASMs3Dmx::constrainCorner (int I, int J, int K, int dof, + int code, char basis) +{ + if (basis > 0) + this->ASMs3D::constrainCorner(I,J,K,dof,code,basis); + else for (basis = 1; basis <= (char)nfx.size(); basis++) + { + int basisDofs = this->maskDOFs(dof,basis); + if (basisDofs > 0) + this->ASMs3D::constrainCorner(I,J,K,basisDofs,code,basis); + } +} + + bool ASMs3Dmx::connectPatch (int face, ASM3D& neighbor, int nface, int norient, int basis, bool coordCheck, int thick) { @@ -479,6 +520,79 @@ bool ASMs3Dmx::getSize (int& n1, int& n2, int& n3, int basis) const } +#define DERR -999.99 + +double ASMs3Dmx::getParametricVolume (int iel) const +{ +#ifdef INDEX_CHECK + if (iel < 1 || (size_t)iel > MNPC.size()) + { + std::cerr <<" *** ASMs3Dmx::getParametricVolume: Element index "<< iel + <<" out of range [1,"<< MNPC.size() <<"]."<< std::endl; + return DERR; + } +#endif + if (MNPC[iel-1].empty()) + return 0.0; + + int inod1 = MNPC[iel-1][std::accumulate(elem_size.begin(), + elem_size.begin()+geoBasis, -1)]; +#ifdef INDEX_CHECK + if (inod1 < 0 || (size_t)inod1 >= nnod) + { + std::cerr <<" *** ASMs3Dmx::getParametricVolume: Node index "<< inod1 + <<" out of range [0,"<< nnod <<">."<< std::endl; + return DERR; + } +#endif + + double du = svol->knotSpan(0,nodeInd[inod1].I); + double dv = svol->knotSpan(1,nodeInd[inod1].J); + double dw = svol->knotSpan(2,nodeInd[inod1].K); + return du*dv*dw; +} + + +double ASMs3Dmx::getParametricArea (int iel, int dir) const +{ +#ifdef INDEX_CHECK + if (iel < 1 || (size_t)iel > MNPC.size()) + { + std::cerr <<" *** ASMs3Dmx::getParametricArea: Element index "<< iel + <<" out of range [1,"<< MNPC.size() <<"]."<< std::endl; + return DERR; + } +#endif + if (MNPC[iel-1].empty()) + return 0.0; + + int inod1 = MNPC[iel-1][std::accumulate(elem_size.begin(), + elem_size.begin()+geoBasis, -1)]; +#ifdef INDEX_CHECK + if (inod1 < 0 || (size_t)inod1 >= nnod) + { + std::cerr <<" *** ASMs3Dmx::getParametricArea: Node index "<< inod1 + <<" out of range [0,"<< nnod <<">."<< std::endl; + return DERR; + } +#endif + + const int ni = nodeInd[inod1].I; + const int nj = nodeInd[inod1].J; + const int nk = nodeInd[inod1].K; + switch (dir) + { + case 1: return svol->knotSpan(1,nj)*svol->knotSpan(2,nk); + case 2: return svol->knotSpan(0,ni)*svol->knotSpan(2,nk); + case 3: return svol->knotSpan(0,ni)*svol->knotSpan(1,nj); + } + + std::cerr <<" *** ASMs3Dmx::getParametricArea: Invalid face direction " + << dir << std::endl; + return DERR; +} + + bool ASMs3Dmx::integrate (Integrand& integrand, GlobalIntegral& glInt, const TimeDomain& time) @@ -1270,79 +1384,6 @@ void ASMs3Dmx::generateThreadGroups (const Integrand& integrand, bool silence, } -#define DERR -999.99 - -double ASMs3Dmx::getParametricVolume (int iel) const -{ -#ifdef INDEX_CHECK - if (iel < 1 || (size_t)iel > MNPC.size()) - { - std::cerr <<" *** ASMs3Dmx::getParametricVolume: Element index "<< iel - <<" out of range [1,"<< MNPC.size() <<"]."<< std::endl; - return DERR; - } -#endif - if (MNPC[iel-1].empty()) - return 0.0; - - int inod1 = MNPC[iel-1][std::accumulate(elem_size.begin(), - elem_size.begin()+geoBasis, -1)]; -#ifdef INDEX_CHECK - if (inod1 < 0 || (size_t)inod1 >= nnod) - { - std::cerr <<" *** ASMs3Dmx::getParametricVolume: Node index "<< inod1 - <<" out of range [0,"<< nnod <<">."<< std::endl; - return DERR; - } -#endif - - double du = svol->knotSpan(0,nodeInd[inod1].I); - double dv = svol->knotSpan(1,nodeInd[inod1].J); - double dw = svol->knotSpan(2,nodeInd[inod1].K); - return du*dv*dw; -} - - -double ASMs3Dmx::getParametricArea (int iel, int dir) const -{ -#ifdef INDEX_CHECK - if (iel < 1 || (size_t)iel > MNPC.size()) - { - std::cerr <<" *** ASMs3Dmx::getParametricArea: Element index "<< iel - <<" out of range [1,"<< MNPC.size() <<"]."<< std::endl; - return DERR; - } -#endif - if (MNPC[iel-1].empty()) - return 0.0; - - int inod1 = MNPC[iel-1][std::accumulate(elem_size.begin(), - elem_size.begin()+geoBasis, -1)]; -#ifdef INDEX_CHECK - if (inod1 < 0 || (size_t)inod1 >= nnod) - { - std::cerr <<" *** ASMs3Dmx::getParametricArea: Node index "<< inod1 - <<" out of range [0,"<< nnod <<">."<< std::endl; - return DERR; - } -#endif - - const int ni = nodeInd[inod1].I; - const int nj = nodeInd[inod1].J; - const int nk = nodeInd[inod1].K; - switch (dir) - { - case 1: return svol->knotSpan(1,nj)*svol->knotSpan(2,nk); - case 2: return svol->knotSpan(0,ni)*svol->knotSpan(2,nk); - case 3: return svol->knotSpan(0,ni)*svol->knotSpan(1,nj); - } - - std::cerr <<" *** ASMs3Dmx::getParametricArea: Invalid face direction " - << dir << std::endl; - return DERR; -} - - void ASMs3Dmx::getBoundaryNodes (int lIndex, IntVec& nodes, int basis, int thick, int, bool local) const { diff --git a/src/ASM/ASMs3Dmx.h b/src/ASM/ASMs3Dmx.h index 95c6bdca9..786084f63 100644 --- a/src/ASM/ASMs3Dmx.h +++ b/src/ASM/ASMs3Dmx.h @@ -16,7 +16,6 @@ #include "ASMs3D.h" #include "ASMmxBase.h" -#include /*! @@ -35,7 +34,7 @@ class ASMs3Dmx : public ASMs3D, private ASMmxBase //! \brief The constructor initializes the dimension of each basis. explicit ASMs3Dmx(const CharVec& n_f); //! \brief Copy constructor. - ASMs3Dmx(const ASMs3Dmx& patch, const CharVec& n_f = CharVec(2,0)); + ASMs3Dmx(const ASMs3Dmx& patch, const CharVec& n_f); //! \brief Destructor. virtual ~ASMs3Dmx(); @@ -52,7 +51,7 @@ class ASMs3Dmx : public ASMs3D, private ASMmxBase //! \brief Generates the finite element topology data for the patch. //! \details The data generated are the element-to-node connectivity array, - //! the node-to-IJ-index array, as well as global node and element numbers. + //! the node-to-IJK-index array, as well as global node and element numbers. virtual bool generateFEMTopology(); //! \brief Clears the contents of the patch, making it empty. @@ -91,6 +90,32 @@ class ASMs3Dmx : public ASMs3D, private ASMmxBase //! \brief Initializes the patch level MADOF array for mixed problems. virtual void initMADOF(const int* sysMadof); + //! \brief Constrains all DOFs on a given boundary face. + //! \param[in] dir Parameter direction defining the face to constrain + //! \param[in] open If \e true, exclude all points along the face boundary + //! \param[in] dof Which DOFs to constrain at each node on the face + //! \param[in] code Inhomogeneous dirichlet condition code + //! \param[in] basis Which basis to constrain face for (0 means check all) + virtual void constrainFace(int dir, bool open, int dof, + int code, char basis); + //! \brief Constrains all DOFs on a given boundary edge. + //! \param[in] lEdge Local index [1,12] of the edge to constrain + //! \param[in] open If \e true, exclude the end points of the edge + //! \param[in] dof Which DOFs to constrain at each node along the edge + //! \param[in] code Inhomogeneous dirichlet condition code + //! \param[in] basis Which basis to constrain edge for (0 means check all) + virtual void constrainEdge(int lEdge, bool open, int dof, + int code, char basis); + //! \brief Constrains a corner node identified by the three parameter indices. + //! \param[in] I Parameter index in u-direction + //! \param[in] J Parameter index in v-direction + //! \param[in] K Parameter index in w-direction + //! \param[in] dof Which DOFs to constrain at the node + //! \param[in] code Inhomogeneous dirichlet condition code + //! \param[in] basis Which basis to constrain node for (0 means check all) + virtual void constrainCorner(int I, int J, int K, int dof, + int code, char basis); + //! \brief Connects all matching nodes on two adjacent boundary faces. //! \param[in] face Local face index of this patch, in range [1,6] //! \param neighbor The neighbor patch @@ -132,7 +157,9 @@ class ASMs3Dmx : public ASMs3D, private ASMmxBase //! \param[in] time Parameters for nonlinear/time-dependent simulations //! \param[in] iChk Object checking if an element interface has contributions virtual bool integrate(Integrand& integrand, GlobalIntegral& glbInt, - const TimeDomain& time, const ASM::InterfaceChecker& iChk); + const TimeDomain& time, + const ASM::InterfaceChecker& iChk); + // Post-processing methods // ======================= @@ -159,7 +186,7 @@ class ASMs3Dmx : public ASMs3D, private ASMmxBase //! \param[in] gpar Parameter values of the result sampling points //! \param[in] regular Flag indicating how the sampling points are defined //! \param[in] deriv Derivative order to return - //! \param[in] nf If non-zero evaluates nf fields on first basis + //! \param[in] nf If nonzero, evaluate nf fields on first basis //! //! \details When \a regular is \e true, it is assumed that the parameter //! value array \a gpar forms a regular tensor-product point grid of dimension @@ -206,7 +233,7 @@ class ASMs3Dmx : public ASMs3D, private ASMmxBase //! \brief Generates element groups for multi-threading of interior integrals. //! \param[in] integrand Object with problem-specific data and methods //! \param[in] silence If \e true, suppress threading group outprint - //! \param[in] ignoreGlobalLM If \e true ignore global multipliers in sanity check + //! \param[in] ignoreGlobalLM Sanity check option virtual void generateThreadGroups(const Integrand& integrand, bool silence, bool ignoreGlobalLM); @@ -223,7 +250,7 @@ class ASMs3Dmx : public ASMs3D, private ASMmxBase virtual double getParametricVolume(int iel) const; //! \brief Returns boundary face area in the parameter space for an element. //! \param[in] iel Element index - //! \param[in] dir Local face index of the boundary face + //! \param[in] dir Local index of the boundary face double getParametricArea(int iel, int dir) const; //! \brief Finds the global (or patch-local) node numbers on a patch boundary. diff --git a/src/ASM/LR/ASMu2Dmx.C b/src/ASM/LR/ASMu2Dmx.C index 4119aa032..540385d1f 100644 --- a/src/ASM/LR/ASMu2Dmx.C +++ b/src/ASM/LR/ASMu2Dmx.C @@ -312,6 +312,32 @@ bool ASMu2Dmx::generateFEMTopology () } +void ASMu2Dmx::constrainEdge (int dir, bool open, int dof, int code, char basis) +{ + if (basis > 0) + this->ASMu2D::constrainEdge(dir,open,dof,code,basis); + else for (basis = 1; basis <= (char)nfx.size(); basis++) + { + int basisDofs = this->maskDOFs(dof,basis); + if (basisDofs > 0) + this->ASMu2D::constrainEdge(dir,open,basisDofs,code,basis); + } +} + + +void ASMu2Dmx::constrainCorner (int I, int J, int dof, int code, char basis) +{ + if (basis > 0) + this->ASMu2D::constrainCorner(I,J,dof,code,basis); + else for (basis = 1; basis <= (char)nfx.size(); basis++) + { + int basisDofs = this->maskDOFs(dof,basis); + if (basisDofs > 0) + this->ASMu2D::constrainCorner(I,J,basisDofs,code,basis); + } +} + + bool ASMu2Dmx::integrate (Integrand& integrand, GlobalIntegral& glInt, const TimeDomain& time) diff --git a/src/ASM/LR/ASMu2Dmx.h b/src/ASM/LR/ASMu2Dmx.h index ad15939aa..dfcdfcaa6 100644 --- a/src/ASM/LR/ASMu2Dmx.h +++ b/src/ASM/LR/ASMu2Dmx.h @@ -81,6 +81,21 @@ class ASMu2Dmx : public ASMu2D, private ASMmxBase //! \brief Initializes the patch level MADOF array for mixed problems. virtual void initMADOF(const int* sysMadof); + //! \brief Constrains all DOFs on a given boundary edge. + //! \param[in] dir Parameter direction defining the edge to constrain + //! \param[in] open If \e true, exclude the end points of the edge + //! \param[in] dof Which DOFs to constrain at each node along the edge + //! \param[in] code Inhomogeneous dirichlet condition code + //! \param[in] basis Which basis to constrain edge for (0 means check all) + virtual void constrainEdge(int dir, bool open, int dof, int code, char basis); + //! \brief Constrains a corner node identified by the two parameter indices. + //! \param[in] I Parameter index in u-direction + //! \param[in] J Parameter index in v-direction + //! \param[in] dof Which DOFs to constrain at the node + //! \param[in] code Inhomogeneous dirichlet condition code + //! \param[in] basis Which basis to constrain node for (0 means check all) + virtual void constrainCorner(int I, int J, int dof, int code, char basis); + // Methods for integration of finite element quantities. // These are the main computational methods of the ASM class hierarchy. // ==================================================================== diff --git a/src/ASM/LR/ASMu3Dmx.C b/src/ASM/LR/ASMu3Dmx.C index 841efc0bf..a5c0dd704 100644 --- a/src/ASM/LR/ASMu3Dmx.C +++ b/src/ASM/LR/ASMu3Dmx.C @@ -315,6 +315,47 @@ bool ASMu3Dmx::generateFEMTopology () } +void ASMu3Dmx::constrainFace (int dir, bool open, int dof, int code, char basis) +{ + if (basis > 0) + this->ASMu3D::constrainFace(dir,open,dof,code,basis); + else for (basis = 1; basis <= (char)nfx.size(); basis++) + { + int basisDofs = this->maskDOFs(dof,basis); + if (basisDofs > 0) + this->ASMu3D::constrainFace(dir,open,basisDofs,code,basis); + } +} + + +void ASMu3Dmx::constrainEdge (int lEdge, bool open, int dof, + int code, char basis) +{ + if (basis > 0) + this->ASMu3D::constrainEdge(lEdge,open,dof,code,basis); + else for (basis = 1; basis <= (char)nfx.size(); basis++) + { + int basisDofs = this->maskDOFs(dof,basis); + if (basisDofs > 0) + this->ASMu3D::constrainEdge(lEdge,open,basisDofs,code,basis); + } +} + + +void ASMu3Dmx::constrainCorner (int I, int J, int K, int dof, + int code, char basis) +{ + if (basis > 0) + this->ASMu3D::constrainCorner(I,J,K,dof,code,basis); + else for (basis = 1; basis <= (char)nfx.size(); basis++) + { + int basisDofs = this->maskDOFs(dof,basis); + if (basisDofs > 0) + this->ASMu3D::constrainCorner(I,J,K,basisDofs,code,basis); + } +} + + bool ASMu3Dmx::integrate (Integrand& integrand, GlobalIntegral& glInt, const TimeDomain& time) diff --git a/src/ASM/LR/ASMu3Dmx.h b/src/ASM/LR/ASMu3Dmx.h index a5b14c12e..1fbd4de71 100644 --- a/src/ASM/LR/ASMu3Dmx.h +++ b/src/ASM/LR/ASMu3Dmx.h @@ -81,6 +81,33 @@ class ASMu3Dmx : public ASMu3D, private ASMmxBase //! \brief Initializes the patch level MADOF array for mixed problems. virtual void initMADOF(const int* sysMadof); + //! \brief Constrains all DOFs on a given boundary face. + //! \param[in] dir Parameter direction defining the face to constrain + //! \param[in] open If \e true, exclude all points along the face boundary + //! \param[in] dof Which DOFs to constrain at each node on the face + //! \param[in] code Inhomogeneous dirichlet condition code + //! \param[in] basis Which basis to constrain face for (0 means check all) + virtual void constrainFace(int dir, bool open, int dof, + int code, char basis); + //! \brief Constrains all DOFs on a given boundary edge. + //! \param[in] lEdge Local index [1,12] of the edge to constrain + //! \param[in] open If \e true, exclude the end points of the edge + //! \param[in] dof Which DOFs to constrain at each node along the edge + //! \param[in] code Inhomogeneous dirichlet condition code + //! \param[in] basis Which basis to constrain edge for (0 means check all) + virtual void constrainEdge(int lEdge, bool open, int dof, + int code, char basis); + //! \brief Constrains a corner node identified by the three parameter indices. + //! \param[in] I Parameter index in u-direction + //! \param[in] J Parameter index in v-direction + //! \param[in] K Parameter index in w-direction + //! \param[in] dof Which DOFs to constrain at the node + //! \param[in] code Inhomogeneous dirichlet condition code + //! \param[in] basis Which basis to constrain node for (0 means check all) + virtual void constrainCorner(int I, int J, int K, int dof, + int code, char basis); + + // Methods for integration of finite element quantities. // These are the main computational methods of the ASM class hierarchy. // ==================================================================== diff --git a/src/SIM/SIMinput.C b/src/SIM/SIMinput.C index 12a8d81a5..dfd083f0a 100644 --- a/src/SIM/SIMinput.C +++ b/src/SIM/SIMinput.C @@ -508,7 +508,7 @@ bool SIMinput::parseBCTag (const TiXmlElement* elem) else if (!strcasecmp(elem->Value(),"dirichlet") && !ignoreDirichlet) { const TiXmlNode* dval = nullptr; - int comp = 0, symm = 0, basis = 1; + int comp = 0, symm = 0, basis = 0; std::string set, type, axes; utl::getAttribute(elem,"set",set); utl::getAttribute(elem,"type",type,true);