예제 #1
0
int NuTo::Structure::BoundaryElementsCreate(int rElementGroupId, int rNodeGroupId, NodeBase* rControlNode)
{
    Timer timer(__FUNCTION__, GetShowTime(), GetLogger());

    // find groups
    boost::ptr_map<int, GroupBase>::iterator itGroupElements = mGroupMap.find(rElementGroupId);
    if (itGroupElements == mGroupMap.end())
        throw Exception(__PRETTY_FUNCTION__, "Group with the given identifier does not exist.");
    if (itGroupElements->second->GetType() != NuTo::eGroupId::Elements)
        throw Exception(__PRETTY_FUNCTION__, "Group is not an element group.");

    boost::ptr_map<int, GroupBase>::iterator itGroupBoundaryNodes = mGroupMap.find(rNodeGroupId);
    if (itGroupBoundaryNodes == mGroupMap.end())
        throw Exception(__PRETTY_FUNCTION__, "Group with the given identifier does not exist.");
    if (itGroupBoundaryNodes->second->GetType() != NuTo::eGroupId::Nodes)
        throw Exception(__PRETTY_FUNCTION__, "Group is not a node group.");

    Group<ElementBase>& elementGroup = *(itGroupElements->second->AsGroupElement());
    Group<NodeBase>& nodeGroup = *(itGroupBoundaryNodes->second->AsGroupNode());

    // since the search is done via the id's, the surface nodes are ptr, so make another set with the node ptrs
    std::set<const NodeBase*> nodePtrSet;
    for (auto itNode : nodeGroup)
    {
        nodePtrSet.insert(itNode.second);
    }

    std::vector<int> newBoundaryElementIds;

    // loop over all elements
    for (auto itElement : elementGroup)
    {
        ElementBase* elementPtr = itElement.second;
        const InterpolationType& interpolationType = elementPtr->GetInterpolationType();

        // std::cout << typeid(*elementPtr).name() << "\n";
        // std::cout << typeid(ContinuumElement<1>).name() << std::endl;
        if (typeid(*elementPtr) != typeid(ContinuumElement<1>) && typeid(*elementPtr) != typeid(ContinuumElement<2>) &&
            typeid(*elementPtr) != typeid(ContinuumElement<3>))
            throw Exception(__PRETTY_FUNCTION__, "Element is not a ContinuumElement.");

        // loop over all surfaces
        for (int iSurface = 0; iSurface < interpolationType.GetNumSurfaces(); ++iSurface)
        {
            bool elementSurfaceNodesMatchBoundaryNodes = true;
            Eigen::VectorXi surfaceNodeIndices = interpolationType.GetSurfaceNodeIndices(iSurface);

            int numSurfaceNodes = surfaceNodeIndices.rows();
            std::vector<const NodeBase*> surfaceNodes(numSurfaceNodes);

            for (int iSurfaceNode = 0; iSurfaceNode < numSurfaceNodes; ++iSurfaceNode)
            {
                surfaceNodes[iSurfaceNode] = elementPtr->GetNode(surfaceNodeIndices(iSurfaceNode, 0));
            }

            // check, if all surface nodes are in the node group
            for (auto& surfaceNode : surfaceNodes)
            {
                if (nodePtrSet.find(surfaceNode) == nodePtrSet.end())
                {
                    // this surface has at least one node that is not in the list, continue
                    elementSurfaceNodesMatchBoundaryNodes = false;
                    break;
                }
            }
            if (not elementSurfaceNodesMatchBoundaryNodes)
                continue;

            int surfaceId = iSurface;

            int elementId = GetUnusedId(mElementMap);

            ElementBase* boundaryElement = nullptr;
            ConstitutiveBase& constitutiveLaw = elementPtr->GetConstitutiveLaw(0);

            switch (elementPtr->GetLocalDimension())
            {
            case 1:
            {
                const auto& integrationType = *GetPtrIntegrationType(eIntegrationType::IntegrationType0DBoundary);
                auto& element = dynamic_cast<ContinuumElement<1>&>(*elementPtr);
                if (rControlNode == nullptr)
                    boundaryElement = new ContinuumBoundaryElement<1>(element, integrationType, surfaceId);
                else
                    boundaryElement = new ContinuumBoundaryElementConstrainedControlNode<1>(element, integrationType,
                                                                                            surfaceId, rControlNode);
                break;
            }
            case 2:
            {
                eIntegrationType integrationTypeEnum;
                // check for 2D types
                switch (interpolationType.GetStandardIntegrationType())
                {
                case eIntegrationType::IntegrationType2D3NGauss1Ip:
                case eIntegrationType::IntegrationType2D4NGauss1Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType1D2NGauss1Ip;
                    break;
                case eIntegrationType::IntegrationType2D3NGauss3Ip:
                case eIntegrationType::IntegrationType2D4NGauss4Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType1D2NGauss2Ip;
                    break;
                case eIntegrationType::IntegrationType2D3NGauss6Ip:
                case eIntegrationType::IntegrationType2D4NGauss9Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType1D2NGauss3Ip;
                    break;
                case eIntegrationType::IntegrationType2D3NGauss12Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType1D2NGauss5Ip;
                    break;

                case eIntegrationType::IntegrationType2D4NLobatto9Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType1D2NLobatto3Ip;
                    break;

                case eIntegrationType::IntegrationType2D4NLobatto16Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType1D2NLobatto4Ip;
                    break;

                case eIntegrationType::IntegrationType2D4NLobatto25Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType1D2NLobatto5Ip;
                    break;

                default:
                    throw Exception(__PRETTY_FUNCTION__,
                                    "Could not automatically determine integration type of the boundary element.");
                }
                const auto& integrationType = *GetPtrIntegrationType(integrationTypeEnum);
                auto& element = dynamic_cast<ContinuumElement<2>&>(*elementPtr);
                if (rControlNode == nullptr)
                    boundaryElement = new ContinuumBoundaryElement<2>(element, integrationType, surfaceId);
                else
                    boundaryElement = new ContinuumBoundaryElementConstrainedControlNode<2>(element, integrationType,
                                                                                            surfaceId, rControlNode);

                break;
            }
            case 3:
            {
                eIntegrationType integrationTypeEnum;
                // check for 3D types
                switch (interpolationType.GetStandardIntegrationType())
                {
                case eIntegrationType::IntegrationType3D4NGauss1Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType2D3NGauss1Ip;
                    break;

                case eIntegrationType::IntegrationType3D4NGauss4Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType2D3NGauss3Ip;
                    break;

                case eIntegrationType::IntegrationType3D8NGauss1Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType2D4NGauss1Ip;
                    break;

                case eIntegrationType::IntegrationType3D8NGauss2x2x2Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType2D4NGauss4Ip;
                    break;

                case eIntegrationType::IntegrationType3D8NLobatto3x3x3Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType2D4NLobatto9Ip;
                    break;

                case eIntegrationType::IntegrationType3D8NLobatto4x4x4Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType2D4NLobatto16Ip;
                    break;

                case eIntegrationType::IntegrationType3D8NLobatto5x5x5Ip:
                    integrationTypeEnum = eIntegrationType::IntegrationType2D4NLobatto16Ip;
                    break;

                default:
                    throw Exception(__PRETTY_FUNCTION__,
                                    "Could not automatically determine integration type of the boundary element.");
                }

                const auto& integrationType = *GetPtrIntegrationType(integrationTypeEnum);
                auto& element = dynamic_cast<ContinuumElement<3>&>(*elementPtr);
                if (rControlNode == nullptr)
                    boundaryElement = new ContinuumBoundaryElement<3>(element, integrationType, surfaceId);
                else
                    boundaryElement = new ContinuumBoundaryElementConstrainedControlNode<3>(element, integrationType,
                                                                                            surfaceId, rControlNode);
                break;
            }
            default:
                throw Exception(__PRETTY_FUNCTION__, "Boundary element for Continuum element with dimension " +
                                                             std::to_string(elementPtr->GetLocalDimension()) +
                                                             "not implemented");
            }

            mElementMap.insert(elementId, boundaryElement);
            newBoundaryElementIds.push_back(elementId);

            boundaryElement->SetConstitutiveLaw(constitutiveLaw);
        }
    }

    int boundaryElementGroup = GroupCreate(eGroupId::Elements);
    for (int boundaryElementId : newBoundaryElementIds)
        GroupAddElement(boundaryElementGroup, boundaryElementId);

    return boundaryElementGroup;
}
예제 #2
0
void NuTo::StructureBase::ConstraintLinearEquationNodeToElementCreate(int rNode, int rElementGroup, NuTo::Node::eDof,
                                                                      const double rTolerance,
                                                                      Eigen::Vector3d rNodeCoordOffset)
{
    const int dim = GetDimension();

    Eigen::VectorXd queryNodeCoords = NodeGetNodePtr(rNode)->Get(Node::eDof::COORDINATES);
    queryNodeCoords = queryNodeCoords + rNodeCoordOffset.head(dim);


    std::vector<int> elementGroupIds = GroupGetMemberIds(rElementGroup);

    ElementBase* elementPtr = nullptr;
    Eigen::VectorXd elementNaturalNodeCoords;
    bool nodeInElement = false;
    for (auto const& eleId : elementGroupIds)
    {
        elementPtr = ElementGetElementPtr(eleId);

        // Coordinate interpolation must be linear so the shape function derivatives are constant!
        assert(elementPtr->GetInterpolationType().Get(Node::eDof::COORDINATES).GetTypeOrder() ==
               Interpolation::eTypeOrder::EQUIDISTANT1);
        const Eigen::MatrixXd& derivativeShapeFunctionsGeometryNatural =
                elementPtr->GetInterpolationType()
                        .Get(Node::eDof::COORDINATES)
                        .DerivativeShapeFunctionsNatural(
                                Eigen::VectorXd::Zero(dim)); // just as _some_ point, as said, constant

        // real coordinates of every node in rElement
        Eigen::VectorXd elementNodeCoords = elementPtr->ExtractNodeValues(NuTo::Node::eDof::COORDINATES);

        switch (mDimension)
        {
        case 2:
        {
            Eigen::Matrix2d invJacobian =
                    dynamic_cast<ContinuumElement<2>*>(elementPtr)
                            ->CalculateJacobian(derivativeShapeFunctionsGeometryNatural, elementNodeCoords)
                            .inverse();

            elementNaturalNodeCoords = invJacobian * (queryNodeCoords - elementNodeCoords.head(2));
        }
        break;
        case 3:
        {
            Eigen::Matrix3d invJacobian =
                    dynamic_cast<ContinuumElement<3>*>(elementPtr)
                            ->CalculateJacobian(derivativeShapeFunctionsGeometryNatural, elementNodeCoords)
                            .inverse();

            elementNaturalNodeCoords = invJacobian * (queryNodeCoords - elementNodeCoords.head(3));
        }
        break;

        default:
            throw NuTo::Exception(std::string(__PRETTY_FUNCTION__) + ": \t Only implemented for 2D and 3D");
        }


        if ((elementNaturalNodeCoords.array() > -rTolerance).all() and
            elementNaturalNodeCoords.sum() <= 1. + rTolerance)
        {
            nodeInElement = true;
            break;
        }
    }

    if (not nodeInElement)
    {
        GetLogger() << "Natural node coordinates: \n" << elementNaturalNodeCoords << "\n";
        throw Exception(__PRETTY_FUNCTION__, "Node is not inside any element.");
    }

    auto shapeFunctions =
            elementPtr->GetInterpolationType().Get(Node::eDof::DISPLACEMENTS).ShapeFunctions(elementNaturalNodeCoords);

    std::vector<Constraint::Equation> equations(dim); // default construction of Equation with rhs = Constant = 0
    for (int iDim = 0; iDim < dim; ++iDim)
    {
        equations[iDim].AddTerm(Constraint::Term(*NodeGetNodePtr(rNode), iDim, 1.));
    }


    for (int iNode = 0; iNode < shapeFunctions.rows(); ++iNode)
    {
        int localNodeId = elementPtr->GetInterpolationType().Get(Node::eDof::DISPLACEMENTS).GetNodeIndex(iNode);
        auto globalNode = elementPtr->GetNode(localNodeId, Node::eDof::DISPLACEMENTS);
        //        std::cout << "globalNodeId \t" << globalNodeId << std::endl;
        double coefficient = -shapeFunctions(iNode, 0);

        for (int iDim = 0; iDim < dim; ++iDim)
            equations[iDim].AddTerm(Constraint::Term(*globalNode, iDim, coefficient));
    }
    Constraints().Add(Node::eDof::DISPLACEMENTS, equations);
}