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; }
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); }