Files
IFEM/Apps/Common/SIMNodalConstraint.C
Knut Morten Okstad 3c9529c072 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).
2019-04-02 09:26:55 +02:00

385 lines
12 KiB
C

// $Id$
//==============================================================================
//!
//! \file SIMNodalConstraint.C
//!
//! \date Nov 4 2015
//!
//! \author Arne Morten Kvarving / SINTEF
//!
//! \brief Base class for simulators constraining a topologyset to a given node.
//!
//==============================================================================
#include "SIMNodalConstraint.h"
#include "ASMs1D.h"
#include "ASMs2D.h"
#include "ASMs3D.h"
#ifdef HAS_LRSPLINE
#include "ASMu2D.h"
#include "LRSpline/LRSpline.h"
#endif
//! \brief Base class for helpers applying nodal constraints.
class NodalConstraintASMHelper {
public:
//! \brief The constructor initializes the patch pointer.
explicit NodalConstraintASMHelper(ASMbase* pch) : bpch(pch) {}
//! \brief Empty destructor.
virtual ~NodalConstraintASMHelper() {}
//! \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 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 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)
{
this->constrainNode(this->getCorner(item,basis),comp,idx);
}
//! \brief Constrains the whole patch to a given node.
//! \param[in] comp Component to constrain
//! \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)
{
int nnod = bpch->getNoNodes(basis);
int node = this->getStartNode(basis);
for (int i = 0; i < nnod; i++)
this->constrainNode(++node,comp,idx);
}
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)
{
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; //!< Pointer to the associated patch
};
//! \brief Helper for apply constraints to a structured 1D model.
class NodalConstraintASMs1DHelper : public NodalConstraintASMHelper {
public:
//! \brief The constructor forwards to the parent class constructor.
explicit NodalConstraintASMs1DHelper(ASMs1D* pch)
: NodalConstraintASMHelper(pch) {}
//! \copydoc NodalConstraintASMHelper::getCorner
virtual int getCorner(int vertex, int basis) const
{
int n1 = static_cast<ASMs1D*>(bpch)->getSize(basis);
int ofs = this->getStartNode(basis);
return bpch->getNodeID(ofs + (vertex == 1 ? 1 : n1));
}
};
//! \brief Helper for apply constraints to a structured 2D model.
class NodalConstraintASMs2DHelper : public NodalConstraintASMHelper {
public:
//! \brief The constructor forwards to the parent class constructor.
explicit NodalConstraintASMs2DHelper(ASMs2D* pch)
: NodalConstraintASMHelper(pch) {}
//! \copydoc NodalConstraintASMHelper::getCorner
virtual int getCorner(int vertex, int basis) const
{
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
virtual void constrainEdge(int item, int comp, int basis, int idx)
{
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)
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++)
this->constrainNode(node,comp,idx);
default:
break;
}
}
};
//! \brief Helper for apply constraints to a structured 3D model.
class NodalConstraintASMs3DHelper : public NodalConstraintASMHelper {
public:
//! \brief The constructor forwards to the parent class constructor.
explicit NodalConstraintASMs3DHelper(ASMs3D* pch)
: NodalConstraintASMHelper(pch) {}
//! \copydoc NodalConstraintASMHelper::getCorner
virtual int getCorner(int vertex, int basis) const
{
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 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
virtual void constrainEdge(int item, int comp, int basis, int idx)
{
int n1, n2, n3, node = 1 + this->getStartNode(basis);
static_cast<ASMs3D*>(bpch)->getSize(n1,n2,n3,basis);
int inc = 1;
int n = n1;
if (item > 8) {
inc = n1*n2;
n = n3;
} else if (item > 4) {
inc = n1;
n = n2;
}
switch (item)
{
case 6:
case 10:
node += n1 - 1;
break;
case 2:
case 11:
node += n1*(n2-1);
break;
case 12:
node += n1*n2 - 1;
break;
case 3:
case 7:
node += n1*n2*(n3-1);
break;
case 8:
node += n1*(n2*(n3-1) + 1) - 1;
break;
case 4:
node += n1*(n2*n3-1);
break;
}
for (int i = 1; i <= n; i++, node += inc)
this->constrainNode(node,comp,idx);
}
//! \copydoc NodalConstraintASMHelper::constrainFace
virtual void constrainFace(int item, int comp, int basis, int idx)
{
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])
{
case 1: // Right face (positive I-direction)
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)
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++)
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++)
this->constrainNode(node,comp,idx);
break;
}
}
};
#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* pch)
: NodalConstraintASMHelper(pch) {}
//! \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 static_cast<ASMu2D*>(bpch)->getCorner(indices[vertex-1][0],
indices[vertex-1][1],
basis);
}
//! \copydoc NodalConstraintASMHelper::constrainEdge
virtual void constrainEdge(int item, int comp, int basis, int idx)
{
IntVec nodes;
bpch->getBoundaryNodes(item,nodes,basis,1,0,true);
for (int node : nodes)
this->constrainNode(node,comp,idx);
}
};
#endif
//! \brief Template specialization for 1D.
template<> bool SIMNodalConstraint<SIM1D>::applyConstraint()
{
for (const auto& it3 : vertConstraints) {
TopologySet::const_iterator it = SIM1D::myEntitys.find(it3.topset);
if (it != SIM1D::myEntitys.end()) {
ASMs1D* pch = static_cast<ASMs1D*>(this->getPatch(it3.patch));
if (!pch)
continue;
NodalConstraintASMs1DHelper helper(pch);
int idx = pch->getNodeID(helper.getCorner(it3.vertex, it3.basis));
for (const auto& it2 : it->second) {
ASMs1D* pch2 = static_cast<ASMs1D*>(this->getPatch(it2.patch));
if (!pch2)
continue;
NodalConstraintASMs1DHelper helper2(pch2);
if (it2.idim == 1)
helper2.constrainPatch(it3.comp, it3.basis, idx);
else if (it2.idim == 0) // vertex constraints
helper.constrainVertex(it2.item, it3.comp, it3.basis, idx);
}
}
}
return true;
}
//! \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(getHelper(it3.patch));
int idx = helper->getCorner(it3.vertex, it3.basis);
for (const auto& it2 : it->second) {
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
helper2->constrainEdge(it2.item, it3.comp, it3.basis, idx);
else if (it2.idim == 0) // Vertex constraint
helper2->constrainVertex(it2.item, it3.comp, it3.basis, idx);
}
}
}
return true;
}
//! \brief Template specialization for 3D.
template<> bool SIMNodalConstraint<SIM3D>::applyConstraint()
{
for (const auto& it3 : vertConstraints) {
TopologySet::const_iterator it = SIM3D::myEntitys.find(it3.topset);
if (it != SIM3D::myEntitys.end()) {
ASMs3D* pch = static_cast<ASMs3D*>(this->getPatch(it3.patch));
if (!pch)
continue;
NodalConstraintASMs3DHelper helper(pch);
int idx = helper.getCorner(it3.vertex, it3.basis);
for (const auto& it2 : it->second) {
ASMs3D* pch2 = static_cast<ASMs3D*>(this->getPatch(it2.patch));
if (!pch2)
continue;
NodalConstraintASMs3DHelper helper2(pch2);
if (it2.idim == 3)
helper2.constrainPatch(it3.comp, it3.basis, idx);
else if (it2.idim == 2) // Face constraints
helper2.constrainFace(it2.item, it3.comp, it3.basis, idx);
else if (it2.idim == 1) // Edge constraints
helper2.constrainEdge(it2.item, it3.comp, it3.basis, idx);
else if (it2.idim == 0) // Vertex constraint
helper2.constrainVertex(it2.item, it3.comp, it3.basis, idx);
}
}
}
return true;
}