Changed: Simplified the boundary nodes extraction a bit.
Always use getBoundaryNodes method and made getEdgeNodes private. Think there were some small undetected errors also (local vs. global node numbers).
This commit is contained in:
@@ -21,193 +21,178 @@
|
||||
#endif
|
||||
|
||||
|
||||
//! \brief Helper for applying operation to different ASM types
|
||||
//! \brief Base class for helpers applying nodal constraints.
|
||||
class NodalConstraintASMHelper {
|
||||
public:
|
||||
//! \brief Constructor
|
||||
//! \param pch The associated ASM class
|
||||
//! \brief The constructor initializes the patch pointer.
|
||||
explicit NodalConstraintASMHelper(ASMbase* pch) : bpch(pch) {}
|
||||
|
||||
//! \brief Empty destructor
|
||||
//! \brief Empty destructor.
|
||||
virtual ~NodalConstraintASMHelper() {}
|
||||
|
||||
//! \brief Obtain the global node number of a given corner node on patch.
|
||||
//! \param vertex Vertex to obtain
|
||||
//! \param basis Basis for vertex
|
||||
virtual int getCorner(int vertex, int basis) = 0;
|
||||
//! \brief Returns the local node number of a given corner of the patch.
|
||||
//! \param[in] vertex Vertex index to return the node number for
|
||||
//! \param[in] basis Basis for vertex
|
||||
virtual int getCorner(int vertex, int basis) const = 0;
|
||||
|
||||
//! \brief Constrain a given edge to a given node.
|
||||
//! \param item Edge index on patch
|
||||
//! \param comp Component to constrain
|
||||
//! \param basis Basis to constrain edge for
|
||||
//! \param idx Global node to constrain edge to.
|
||||
virtual void constrainEdge(int item, int comp, int basis, int idx) = 0;
|
||||
//! \brief Constrains a given edge to a given node.
|
||||
//! \param[in] item Edge index on patch
|
||||
//! \param[in] comp Component to constrain
|
||||
//! \param[in] basis Basis to constrain edge for
|
||||
//! \param[in] idx Global node to constrain edge to
|
||||
virtual void constrainEdge(int item, int comp, int basis, int idx) {}
|
||||
|
||||
//! \brief Constrain a given vertex to a given node.
|
||||
//! \param item item Vertex index on patch.
|
||||
//! \param comp Component to constrain
|
||||
//! \param basis Basis to constrain vertex for.
|
||||
//! \param idx Global node to constrain edge to.
|
||||
//! \brief Constrains a given face to a given node.
|
||||
//! \param[in] item Face index on patch
|
||||
//! \param[in] comp Component to constrain
|
||||
//! \param[in] basis Basis to constrain face for
|
||||
//! \param[in] idx Global node to constrain face to
|
||||
virtual void constrainFace(int item, int comp, int basis, int idx) {}
|
||||
|
||||
//! \brief Constrains a given vertex to a given node.
|
||||
//! \param[in] item Vertex index on patch
|
||||
//! \param[in] comp Component to constrain
|
||||
//! \param[in] basis Basis to constrain vertex for
|
||||
//! \param[in] idx Global node to constrain edge to
|
||||
void constrainVertex(int item, int comp, int basis, int idx)
|
||||
{
|
||||
int gn = bpch->getNodeID(getCorner(item, basis));
|
||||
if (gn != idx)
|
||||
bpch->add2PC(gn, comp, idx);
|
||||
this->constrainNode(this->getCorner(item,basis),comp,idx);
|
||||
}
|
||||
|
||||
//! \brief Constrain the patch to a given node.
|
||||
//! \brief Constrains the whole patch to a given node.
|
||||
//! \param[in] comp Component to constrain
|
||||
//! \param[in] basis Basis to constrain vertex for.
|
||||
//! \param[in] idx Global node to constrain patch to.
|
||||
//! \param[in] basis Basis to constrain patch for
|
||||
//! \param[in] idx Global node to constrain patch to
|
||||
void constrainPatch(int comp, int basis, int idx)
|
||||
{
|
||||
size_t ofs = getStartNode(basis);
|
||||
for (size_t i = 1; i <= bpch->getNoNodes(basis); ++i) {
|
||||
int gn = bpch->getNodeID(ofs+i);
|
||||
if (gn != idx)
|
||||
bpch->add2PC(bpch->getNodeID(ofs+i), comp, idx);
|
||||
}
|
||||
int nnod = bpch->getNoNodes(basis);
|
||||
int node = this->getStartNode(basis);
|
||||
for (int i = 0; i < nnod; i++)
|
||||
this->constrainNode(++node,comp,idx);
|
||||
}
|
||||
|
||||
//! \brief Obtain the starting node for a given basis.
|
||||
//! \param[in] basis Basis to obtain the starting node for
|
||||
size_t getStartNode(size_t basis)
|
||||
protected:
|
||||
//! \brief Constrains a given node to another node.
|
||||
//! \param[in] item Local index of node to constrain
|
||||
//! \param[in] comp Component to constrain
|
||||
//! \param[in] idx Global index of the node to constrain to
|
||||
void constrainNode(int item, int comp, int idx)
|
||||
{
|
||||
size_t ofs = 0;
|
||||
for (size_t i=1;i<basis;++i)
|
||||
ofs += bpch->getNoNodes(i);
|
||||
int node = bpch->getNodeID(item);
|
||||
if (node != idx)
|
||||
bpch->add2PC(node,comp,idx);
|
||||
}
|
||||
|
||||
//! \brief Returns the starting node for the given \a basis.
|
||||
int getStartNode(int basis) const
|
||||
{
|
||||
int ofs = 0;
|
||||
for (int i = 1; i < basis; i++)
|
||||
ofs += bpch->getNoNodes(i);
|
||||
return ofs;
|
||||
}
|
||||
|
||||
protected:
|
||||
ASMbase* bpch; //!< ASMbase pointer to associated patch
|
||||
ASMbase* bpch; //!< Pointer to the associated patch
|
||||
};
|
||||
|
||||
|
||||
//! \brief Helper for apply constraints to a structured 1D model.
|
||||
class NodalConstraintASMs1DHelper : public NodalConstraintASMHelper {
|
||||
public:
|
||||
//! \brief Constructor
|
||||
//! \param spch The associated ASM class
|
||||
explicit NodalConstraintASMs1DHelper(ASMs1D* spch) :
|
||||
NodalConstraintASMHelper(spch), pch(spch) {}
|
||||
//! \brief The constructor forwards to the parent class constructor.
|
||||
explicit NodalConstraintASMs1DHelper(ASMs1D* pch)
|
||||
: NodalConstraintASMHelper(pch) {}
|
||||
|
||||
//! \brief Obtain the global node number of a given corner node on patch.
|
||||
//! \param vertex Vertex to obtain
|
||||
//! \param basis Basis for vertex
|
||||
int getCorner(int vertex, int basis)
|
||||
//! \copydoc NodalConstraintASMHelper::getCorner
|
||||
virtual int getCorner(int vertex, int basis) const
|
||||
{
|
||||
size_t ofs = getStartNode(basis);
|
||||
return pch->getNodeID(ofs+(vertex==1?1:pch->getSize(basis)));
|
||||
int n1 = static_cast<ASMs1D*>(bpch)->getSize(basis);
|
||||
int ofs = this->getStartNode(basis);
|
||||
return bpch->getNodeID(ofs + (vertex == 1 ? 1 : n1));
|
||||
}
|
||||
|
||||
//! \brief Constrain a given edge to a given node.
|
||||
//! \param item Edge index on patch
|
||||
//! \param comp Component to constrain
|
||||
//! \param basis Basis to constrain edge for
|
||||
//! \param idx Global node to constrain edge to.
|
||||
void constrainEdge(int item, int comp, int basis, int idx) {}
|
||||
protected:
|
||||
ASMs1D* pch; //!< The associated patch.
|
||||
};
|
||||
|
||||
|
||||
//! \brief Helper for apply constraints to a structured 2D model.
|
||||
class NodalConstraintASMs2DHelper : public NodalConstraintASMHelper {
|
||||
public:
|
||||
//! \brief Constructor
|
||||
//! \param spch The associated ASM class
|
||||
explicit NodalConstraintASMs2DHelper(ASMs2D* spch) :
|
||||
NodalConstraintASMHelper(spch), pch(spch) {}
|
||||
//! \brief The constructor forwards to the parent class constructor.
|
||||
explicit NodalConstraintASMs2DHelper(ASMs2D* pch)
|
||||
: NodalConstraintASMHelper(pch) {}
|
||||
|
||||
//! \copydoc NodalConstraintASMHelper::getCorner
|
||||
int getCorner(int vertex, int basis)
|
||||
virtual int getCorner(int vertex, int basis) const
|
||||
{
|
||||
int n1, n2;
|
||||
pch->getSize(n1, n2, basis);
|
||||
size_t ofs = getStartNode(basis);
|
||||
const std::vector<int> idxs = {1, n1, n1*(n2-1)+1, n1*n2};
|
||||
return pch->getNodeID(idxs[vertex-1]+ofs);
|
||||
int n1, n2, ofs = this->getStartNode(basis);
|
||||
static_cast<ASMs2D*>(bpch)->getSize(n1,n2,basis);
|
||||
const IntVec idxs = { 1, n1, n1*(n2-1)+1, n1*n2 };
|
||||
return bpch->getNodeID(idxs[vertex-1]+ofs);
|
||||
}
|
||||
|
||||
//! \copydoc NodalConstraintASMHelper::constrainEdge
|
||||
void constrainEdge(int item, int comp, int basis, int idx)
|
||||
virtual void constrainEdge(int item, int comp, int basis, int idx)
|
||||
{
|
||||
size_t ofs = getStartNode(basis);
|
||||
|
||||
int n1, n2, node = 1;
|
||||
pch->getSize(n1,n2,basis);
|
||||
int n1, n2, node = 1 + this->getStartNode(basis);
|
||||
static_cast<ASMs2D*>(bpch)->getSize(n1,n2,basis);
|
||||
|
||||
switch (item) {
|
||||
case 2: // Right edge (positive I-direction)
|
||||
node += n1-1;
|
||||
case 1: // Left edge (negative I-direction)
|
||||
for (int i2 = 1; i2 <= n2; i2++, node += n1) {
|
||||
int gn = pch->getNodeID(ofs+node);
|
||||
if (gn != idx)
|
||||
pch->add2PC(pch->getNodeID(ofs+node), comp, idx);
|
||||
}
|
||||
for (int i2 = 1; i2 <= n2; i2++, node += n1)
|
||||
this->constrainNode(node,comp,idx);
|
||||
break;
|
||||
|
||||
case 4: // Back edge (positive J-direction)
|
||||
node += n1*(n2-1);
|
||||
case 3: // Front edge (negative J-direction)
|
||||
for (int i1 = 1; i1 <= n1; i1++, node++) {
|
||||
int gn = pch->getNodeID(ofs+node);
|
||||
if (gn != idx)
|
||||
pch->add2PC(gn, comp, idx);
|
||||
}
|
||||
for (int i1 = 1; i1 <= n1; i1++, node++)
|
||||
this->constrainNode(node,comp,idx);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
ASMs2D* pch; //!< The associated patch.
|
||||
};
|
||||
|
||||
|
||||
//! \brief Helper for apply constraints to a structured 3D model.
|
||||
class NodalConstraintASMs3DHelper : public NodalConstraintASMHelper {
|
||||
public:
|
||||
//! \brief Constructor
|
||||
//! \param spch The associated patch
|
||||
explicit NodalConstraintASMs3DHelper(ASMs3D* spch) :
|
||||
NodalConstraintASMHelper(spch), pch(spch) {}
|
||||
//! \brief The constructor forwards to the parent class constructor.
|
||||
explicit NodalConstraintASMs3DHelper(ASMs3D* pch)
|
||||
: NodalConstraintASMHelper(pch) {}
|
||||
|
||||
//! \copydoc NodalConstraintASMHelper::getCorner
|
||||
int getCorner(int vertex, int basis)
|
||||
virtual int getCorner(int vertex, int basis) const
|
||||
{
|
||||
size_t ofs = getStartNode(basis);
|
||||
int n1, n2, n3;
|
||||
pch->getSize(n1, n2, n3, basis);
|
||||
int n1, n2, n3, ofs = this->getStartNode(basis);
|
||||
static_cast<ASMs3D*>(bpch)->getSize(n1,n2,n3,basis);
|
||||
int ofs_j = n1*(n2-1);
|
||||
int ofs_k = n1*n2*(n3-1);
|
||||
const std::vector<int> idxs = { 1, n1,
|
||||
ofs_j+1, ofs_j+n1,
|
||||
ofs_k+1, ofs_k+n1,
|
||||
ofs_k+ofs_j+1, ofs_k+ofs_j+n1};
|
||||
return pch->getNodeID(idxs[vertex-1]+ofs);
|
||||
|
||||
const IntVec idxs = { 1, n1,
|
||||
ofs_j+1, ofs_j+n1,
|
||||
ofs_k+1, ofs_k+n1,
|
||||
ofs_k+ofs_j+1, ofs_k+ofs_j+n1};
|
||||
return bpch->getNodeID(idxs[vertex-1]+ofs);
|
||||
}
|
||||
|
||||
//! \copydoc NodalConstraintASMHelper::constrainEdge
|
||||
void constrainEdge(int item, int comp, int basis, int idx)
|
||||
virtual void constrainEdge(int item, int comp, int basis, int idx)
|
||||
{
|
||||
size_t node = getStartNode(basis)+1;
|
||||
int n1, n2, n3, node = 1 + this->getStartNode(basis);
|
||||
static_cast<ASMs3D*>(bpch)->getSize(n1,n2,n3,basis);
|
||||
|
||||
int n1, n2, n3;
|
||||
pch->getSize(n1,n2,n3,basis);
|
||||
|
||||
size_t inc = 1;
|
||||
int n;
|
||||
int inc = 1;
|
||||
int n = n1;
|
||||
if (item > 8) {
|
||||
inc = n1*n2;
|
||||
n = n3;
|
||||
} else if (item > 4) {
|
||||
inc = n1;
|
||||
n = n2;
|
||||
} else
|
||||
n = n1;
|
||||
}
|
||||
|
||||
switch (item)
|
||||
{
|
||||
@@ -234,23 +219,15 @@ public:
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 1; i <= n; i++, node += inc) {
|
||||
int gn = pch->getNodeID(node);
|
||||
if (gn != idx)
|
||||
pch->add2PC(gn, comp, idx);
|
||||
}
|
||||
for (int i = 1; i <= n; i++, node += inc)
|
||||
this->constrainNode(node,comp,idx);
|
||||
}
|
||||
|
||||
//! \brief Constrain a given face to a given node.
|
||||
//! \param item Face index on patch
|
||||
//! \param comp Component to constrain
|
||||
//! \param basis Basis to constrain edge for
|
||||
//! \param idx Global node to constrain edge to.
|
||||
void constrainFace(int item, int comp, int basis, int idx)
|
||||
//! \copydoc NodalConstraintASMHelper::constrainFace
|
||||
virtual void constrainFace(int item, int comp, int basis, int idx)
|
||||
{
|
||||
int node = getStartNode(basis)+1;
|
||||
int n1, n2, n3;
|
||||
pch->getSize(n1,n2,n3,basis);
|
||||
int n1, n2, n3, node = 1 + this->getStartNode(basis);
|
||||
static_cast<ASMs3D*>(bpch)->getSize(n1,n2,n3,basis);
|
||||
|
||||
const std::vector<int> faceDir = {-1, 1, -2, 2, -3, 3};
|
||||
switch (faceDir[item-1])
|
||||
@@ -259,93 +236,60 @@ public:
|
||||
node += n1-1;
|
||||
case -1: // Left face (negative I-direction)
|
||||
for (int i3 = 1; i3 <= n3; i3++)
|
||||
for (int i2 = 1; i2 <= n2; i2++, node += n1) {
|
||||
int gn = pch->getNodeID(node);
|
||||
if (gn != idx)
|
||||
pch->add2PC(gn, comp, idx);
|
||||
}
|
||||
for (int i2 = 1; i2 <= n2; i2++, node += n1)
|
||||
this->constrainNode(node,comp,idx);
|
||||
break;
|
||||
|
||||
case 2: // Back face (positive J-direction)
|
||||
node += n1*(n2-1);
|
||||
case -2: // Front face (negative J-direction)
|
||||
for (int i3 = 1; i3 <= n3; i3++, node += n1*(n2-1))
|
||||
for (int i1 = 1; i1 <= n1; i1++, node++) {
|
||||
int gn = pch->getNodeID(node);
|
||||
if (gn != idx)
|
||||
pch->add2PC(gn, comp, idx);
|
||||
}
|
||||
for (int i1 = 1; i1 <= n1; i1++, node++)
|
||||
this->constrainNode(node,comp,idx);
|
||||
break;
|
||||
|
||||
case 3: // Top face (positive K-direction)
|
||||
node += n1*n2*(n3-1);
|
||||
case -3: // Bottom face (negative K-direction)
|
||||
for (int i2 = 1; i2 <= n2; i2++)
|
||||
for (int i1 = 1; i1 <= n1; i1++, node++) {
|
||||
int gn = pch->getNodeID(node);
|
||||
if (gn != idx)
|
||||
pch->add2PC(gn, comp, idx);
|
||||
}
|
||||
for (int i1 = 1; i1 <= n1; i1++, node++)
|
||||
this->constrainNode(node,comp,idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
ASMs3D* pch; //!< The associated patch.
|
||||
};
|
||||
|
||||
|
||||
#ifdef HAS_LRSPLINE
|
||||
//! \brief Helper for apply constraints to an unstructured 2D model.
|
||||
class NodalConstraintASMu2DHelper : public NodalConstraintASMHelper {
|
||||
public:
|
||||
//! \brief Constructor
|
||||
//! \param upch Associated patch
|
||||
explicit NodalConstraintASMu2DHelper(ASMu2D* upch) :
|
||||
NodalConstraintASMHelper(upch), pch(upch) {}
|
||||
explicit NodalConstraintASMu2DHelper(ASMu2D* pch)
|
||||
: NodalConstraintASMHelper(pch) {}
|
||||
|
||||
//! \copydoc NodalConstraintASM2DHelper::getCorner
|
||||
int getCorner(int vertex, int basis)
|
||||
//! \copydoc NodalConstraintASMHelper::getCorner
|
||||
virtual int getCorner(int vertex, int basis) const
|
||||
{
|
||||
static const int indices[4][2] = {{-1,-1}, {1, -1}, {-1, 1}, {1,1}};
|
||||
return pch->getCorner(indices[vertex-1][0], indices[vertex-1][1], basis);
|
||||
static const int indices[4][2] = {{-1,-1}, {1,-1}, {-1,1}, {1,1}};
|
||||
return static_cast<ASMu2D*>(bpch)->getCorner(indices[vertex-1][0],
|
||||
indices[vertex-1][1],
|
||||
basis);
|
||||
}
|
||||
|
||||
//! \copydoc NodalConstraintASM2DHelper::constrainEdge
|
||||
void constrainEdge(int item, int comp, int basis, int idx)
|
||||
//! \copydoc NodalConstraintASMHelper::constrainEdge
|
||||
virtual void constrainEdge(int item, int comp, int basis, int idx)
|
||||
{
|
||||
std::vector<int> map = { LR::WEST, LR::EAST, LR::SOUTH, LR::NORTH };
|
||||
std::vector<int> nodes = pch->getEdgeNodes(map[item-1], basis, 0);
|
||||
for (auto& it : nodes) {
|
||||
int gn = pch->getNodeID(it);
|
||||
if (gn != idx)
|
||||
pch->add2PC(gn, comp, idx);
|
||||
}
|
||||
IntVec nodes;
|
||||
bpch->getBoundaryNodes(item,nodes,basis,1,0,true);
|
||||
for (int node : nodes)
|
||||
this->constrainNode(node,comp,idx);
|
||||
}
|
||||
protected:
|
||||
ASMu2D* pch; //!< The associated patch.
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
\brief Helper function to create a NodalConstraintASMHelper instance.
|
||||
*/
|
||||
|
||||
static NodalConstraintASMHelper* get2DHelper(ASMbase* pch)
|
||||
{
|
||||
ASMs2D* spch = dynamic_cast<ASMs2D*>(pch);
|
||||
if (spch)
|
||||
return new NodalConstraintASMs2DHelper(spch);
|
||||
|
||||
#ifdef HAS_LRSPLINE
|
||||
ASMu2D* upch = dynamic_cast<ASMu2D*>(pch);
|
||||
if (upch)
|
||||
return new NodalConstraintASMu2DHelper(upch);
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
//! \brief Template specialization for 1D.
|
||||
template<> bool SIMNodalConstraint<SIM1D>::applyConstraint()
|
||||
{
|
||||
@@ -376,13 +320,26 @@ template<> bool SIMNodalConstraint<SIM1D>::applyConstraint()
|
||||
//! \brief Template specialization for 2D.
|
||||
template<> bool SIMNodalConstraint<SIM2D>::applyConstraint()
|
||||
{
|
||||
// Lambda function to create the right NodalConstraintASMHelper instance
|
||||
auto&& getHelper = [this](int pidx) -> NodalConstraintASMHelper*
|
||||
{
|
||||
ASMbase* pch = this->getPatch(pidx);
|
||||
ASMs2D* spch = dynamic_cast<ASMs2D*>(pch);
|
||||
if (spch) return new NodalConstraintASMs2DHelper(spch);
|
||||
#ifdef HAS_LRSPLINE
|
||||
ASMu2D* upch = dynamic_cast<ASMu2D*>(pch);
|
||||
if (upch) return new NodalConstraintASMu2DHelper(upch);
|
||||
#endif
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
for (const auto& it3 : vertConstraints) {
|
||||
TopologySet::const_iterator it = SIM2D::myEntitys.find(it3.topset);
|
||||
if (it != SIM2D::myEntitys.end()) {
|
||||
std::unique_ptr<NodalConstraintASMHelper> helper(get2DHelper(this->getPatch(it3.patch)));
|
||||
std::unique_ptr<NodalConstraintASMHelper> helper(getHelper(it3.patch));
|
||||
int idx = helper->getCorner(it3.vertex, it3.basis);
|
||||
for (const auto& it2 : it->second) {
|
||||
std::unique_ptr<NodalConstraintASMHelper> helper2(get2DHelper(this->getPatch(it2.patch)));
|
||||
std::unique_ptr<NodalConstraintASMHelper> helper2(getHelper(it2.patch));
|
||||
if (it2.idim == 2)
|
||||
helper2->constrainPatch(it3.comp, it3.basis, idx);
|
||||
else if (it2.idim == 1) // Edge constraints
|
||||
|
||||
@@ -202,9 +202,8 @@ TEST_P(TestSIMNodalConstraint, Edge2DLR)
|
||||
s.preprocess();
|
||||
|
||||
const ASMu2D& pch = static_cast<const ASMu2D&>(*s.getPatch(1));
|
||||
static const std::vector<LR::parameterEdge> E
|
||||
{LR::WEST, LR::EAST, LR::SOUTH, LR::NORTH};
|
||||
auto nodes = pch.getEdgeNodes(E[GetParam()-1], 1, 0);
|
||||
IntVec nodes;
|
||||
pch.getBoundaryNodes(GetParam(),nodes,1);
|
||||
for (size_t i=1; i <= pch.getNoNodes(); ++i) {
|
||||
if (std::find(nodes.begin(), nodes.end(), i) != nodes.end() &&
|
||||
i != (size_t)pch.getCorner(1,-1,1) && GetParam() == 1)
|
||||
@@ -235,9 +234,8 @@ TEST_P(TestSIMNodalConstraint, Edge2DLRmx)
|
||||
s.preprocess();
|
||||
|
||||
const ASMu2D& pch = static_cast<const ASMu2D&>(*s.getPatch(1));
|
||||
static const std::vector<LR::parameterEdge> E
|
||||
{LR::WEST, LR::EAST, LR::SOUTH, LR::NORTH};
|
||||
auto nodes = pch.getEdgeNodes(E[GetParam()-1], 2, 0);
|
||||
IntVec nodes;
|
||||
pch.getBoundaryNodes(GetParam(),nodes,2);
|
||||
size_t ofs = pch.getNoNodes(1);
|
||||
for (size_t i=1; i <= pch.getNoNodes(1); ++i) {
|
||||
ASSERT_TRUE(pch.findMPC(i, 1) == nullptr);
|
||||
|
||||
@@ -684,27 +684,6 @@ bool ASMu2D::connectBasis (int edge, ASMu2D& neighbor, int nedge, bool revers,
|
||||
}
|
||||
|
||||
|
||||
IntVec ASMu2D::getEdgeNodes (int edge, int basis, int orient) const
|
||||
{
|
||||
size_t ofs = 1;
|
||||
for (int i = 1; i < basis; i++)
|
||||
ofs += this->getNoNodes(i);
|
||||
|
||||
std::vector<LR::Basisfunction*> edgeFunctions;
|
||||
this->getBasis(basis)->getEdgeFunctions(edgeFunctions,
|
||||
static_cast<LR::parameterEdge>(edge));
|
||||
|
||||
int v = (edge == 1 || edge == 2) ? 0 : 1;
|
||||
int u = 1-v;
|
||||
ASMLRSpline::Sort(u, v, orient, edgeFunctions);
|
||||
IntVec result(edgeFunctions.size());
|
||||
std::transform(edgeFunctions.begin(), edgeFunctions.end(), result.begin(),
|
||||
[ofs](LR::Basisfunction* a) { return a->getId()+ofs; });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ASMu2D::DirichletEdge::DirichletEdge (LR::LRSplineSurface* sf,
|
||||
int dir, int d, int c, int offset)
|
||||
: lr(sf), edg(LR::NONE), dof(d), code(c)
|
||||
@@ -2127,30 +2106,42 @@ bool ASMu2D::evalSolution (Matrix& sField, const IntegrandBase& integrand,
|
||||
}
|
||||
|
||||
|
||||
void ASMu2D::getEdgeNodes (IntVec& nodes, int edge, int basis,
|
||||
int orient, bool local) const
|
||||
{
|
||||
const LR::LRSplineSurface* srf = this->getBasis(basis);
|
||||
if (!srf) return; // silently ignore empty patches
|
||||
|
||||
size_t ofs = 1;
|
||||
for (int i = 1; i < basis; i++)
|
||||
ofs += this->getNoNodes(i);
|
||||
|
||||
std::vector<LR::Basisfunction*> edgeFunctions;
|
||||
srf->getEdgeFunctions(edgeFunctions,static_cast<LR::parameterEdge>(edge));
|
||||
if (orient >= 0) {
|
||||
int u = (edge == 1 || edge == 2) ? 1 : 0;
|
||||
ASMLRSpline::Sort(u, 1-u, orient, edgeFunctions);
|
||||
}
|
||||
|
||||
for (LR::Basisfunction* b : edgeFunctions)
|
||||
nodes.push_back(local ? b->getId()+ofs : this->getNodeID(b->getId()+ofs));
|
||||
}
|
||||
|
||||
|
||||
void ASMu2D::getBoundaryNodes (int lIndex, IntVec& nodes, int basis,
|
||||
int, int orient, bool local) const
|
||||
{
|
||||
if (basis == 0)
|
||||
basis = 1;
|
||||
|
||||
if (!this->getBasis(basis)) return; // silently ignore empty patches
|
||||
|
||||
LR::parameterEdge edge;
|
||||
switch (lIndex) {
|
||||
case 1: edge = LR::WEST; break;
|
||||
case 2: edge = LR::EAST; break;
|
||||
case 3: edge = LR::SOUTH; break;
|
||||
case 4: edge = LR::NORTH; break;
|
||||
case 1: this->getEdgeNodes(nodes,LR::WEST ,basis,orient,local); break;
|
||||
case 2: this->getEdgeNodes(nodes,LR::EAST ,basis,orient,local); break;
|
||||
case 3: this->getEdgeNodes(nodes,LR::SOUTH,basis,orient,local); break;
|
||||
case 4: this->getEdgeNodes(nodes,LR::NORTH,basis,orient,local); break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
if (nodes.empty())
|
||||
nodes = this->getEdgeNodes(edge, basis, 0);
|
||||
else {
|
||||
IntVec nodes2 = this->getEdgeNodes(edge, basis, 0);
|
||||
nodes.insert(nodes.end(), nodes2.begin(), nodes2.end());
|
||||
}
|
||||
|
||||
#if SP_DEBUG > 1
|
||||
std::cout <<"Boundary nodes in patch "<< idx+1 <<" edge "<< lIndex <<":";
|
||||
for (int n : nodes) std::cout <<" "<< n;
|
||||
|
||||
@@ -136,8 +136,8 @@ public:
|
||||
//! \param[in] basis Which basis to grab nodes for (0 for all)
|
||||
//! \param[in] orient Orientation of boundary (used for sorting)
|
||||
//! \param[in] local If \e true, return patch-local node numbers
|
||||
virtual void getBoundaryNodes(int lIndex, IntVec& nodes, int basis,
|
||||
int, int orient, bool local = false) const;
|
||||
virtual void getBoundaryNodes(int lIndex, IntVec& nodes, int basis, int = 1,
|
||||
int orient = 0, bool local = false) const;
|
||||
|
||||
//! \brief Returns the polynomial order in each parameter direction.
|
||||
//! \param[out] p1 Order in first (u) direction
|
||||
@@ -310,9 +310,6 @@ public:
|
||||
//! \param[in] basis which basis to consider (for mixed methods)
|
||||
virtual int getCorner(int I, int J, int basis) const;
|
||||
|
||||
//! \brief Returns the node indices for a given edge.
|
||||
IntVec getEdgeNodes(int edge, int basis, int orient) const;
|
||||
|
||||
protected:
|
||||
//! \brief Evaluates an integral over the interior patch domain.
|
||||
//! \param integrand Object with problem-specific data and methods
|
||||
@@ -553,6 +550,15 @@ protected:
|
||||
//! \return Characteristic element size
|
||||
double getElementCorners(int iel, std::vector<Vec3>& XC) const;
|
||||
|
||||
//! \brief Returns the node indices for a given edge.
|
||||
//! \param nodes Array of node numbers
|
||||
//! \param[in] edge Local index of the boundary edge
|
||||
//! \param[in] basis Which basis to grab nodes for
|
||||
//! \param[in] orient Orientation of boundary (used for sorting)
|
||||
//! \param[in] local If \e true, return patch-local node numbers
|
||||
void getEdgeNodes(IntVec& nodes, int edge, int basis,
|
||||
int orient, bool local) const;
|
||||
|
||||
//! \brief Evaluates the basis functions and derivatives of an element.
|
||||
//! \param[in] iel 0-based element index
|
||||
//! \param fe Integration point data for current element
|
||||
|
||||
@@ -34,44 +34,55 @@ class TestASMu2D : public testing::Test,
|
||||
};
|
||||
|
||||
|
||||
static ASMu2D* getPatch (SIMinput& sim)
|
||||
class TestSIM2D : public SIM2D
|
||||
{
|
||||
sim.opt.discretization = ASM::LRSpline;
|
||||
EXPECT_TRUE(sim.read("src/ASM/LR/Test/refdata/boundary_nodes.xinp"));
|
||||
EXPECT_TRUE(sim.createFEMmodel());
|
||||
return static_cast<ASMu2D*>(sim.getPatch(1));
|
||||
}
|
||||
public:
|
||||
TestSIM2D() : SIM2D(1)
|
||||
{
|
||||
opt.discretization = ASM::LRSpline;
|
||||
EXPECT_TRUE(this->read("src/ASM/LR/Test/refdata/boundary_nodes.xinp"));
|
||||
EXPECT_TRUE(this->createFEMmodel());
|
||||
}
|
||||
virtual ~TestSIM2D() {}
|
||||
};
|
||||
|
||||
|
||||
TEST_P(TestASMu2D, ConstrainEdge)
|
||||
{
|
||||
SIM2D sim(1);
|
||||
ASMu2D* pch = getPatch(sim);
|
||||
TestSIM2D sim;
|
||||
ASMu2D* pch = static_cast<ASMu2D*>(sim.getPatch(1));
|
||||
ASSERT_TRUE(pch != nullptr);
|
||||
|
||||
pch->constrainEdge(GetParam().edgeIdx, false, 1, 1, 1);
|
||||
|
||||
std::vector<int> glbNodes;
|
||||
pch->getBoundaryNodes(GetParam().edge, glbNodes, 1, 1, 0);
|
||||
for (int& it : glbNodes)
|
||||
ASSERT_TRUE(pch->findMPC(it, 1) != nullptr);
|
||||
pch->getBoundaryNodes(GetParam().edge, glbNodes, 1);
|
||||
|
||||
for (int node : glbNodes)
|
||||
EXPECT_TRUE(pch->findMPC(node,1) != nullptr);
|
||||
}
|
||||
|
||||
|
||||
TEST_P(TestASMu2D, ConstrainEdgeOpen)
|
||||
{
|
||||
SIM2D sim(1);
|
||||
ASMu2D* pch = getPatch(sim);
|
||||
TestSIM2D sim;
|
||||
ASMu2D* pch = static_cast<ASMu2D*>(sim.getPatch(1));
|
||||
ASSERT_TRUE(pch != nullptr);
|
||||
|
||||
pch->constrainEdge(GetParam().edgeIdx, true, 1, 1, 1);
|
||||
|
||||
std::vector<int> glbNodes;
|
||||
pch->getBoundaryNodes(GetParam().edge, glbNodes, 1, 1, 0);
|
||||
pch->getBoundaryNodes(GetParam().edge, glbNodes, 1);
|
||||
|
||||
int crn = pch->getCorner(GetParam().c1[0], GetParam().c1[1], 1);
|
||||
ASSERT_TRUE(pch->findMPC(crn, 1) == nullptr);
|
||||
EXPECT_TRUE(pch->findMPC(crn,1) == nullptr);
|
||||
glbNodes.erase(std::find(glbNodes.begin(), glbNodes.end(), crn));
|
||||
crn = pch->getCorner(GetParam().c2[0], GetParam().c2[1], 1);
|
||||
ASSERT_TRUE(pch->findMPC(crn, 1) == nullptr);
|
||||
EXPECT_TRUE(pch->findMPC(crn,1) == nullptr);
|
||||
glbNodes.erase(std::find(glbNodes.begin(), glbNodes.end(), crn));
|
||||
for (int& it : glbNodes)
|
||||
ASSERT_TRUE(pch->findMPC(it, 1) != nullptr);
|
||||
|
||||
for (int node : glbNodes)
|
||||
EXPECT_TRUE(pch->findMPC(node,1) != nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user