public XCluster2D CreateSubdomains() { XCluster2D cluster = initialDecomposer.CreateSubdomains(); initialDecomposer = null; // no longer needed and it might take up significant memory for large meshes. return(cluster); }
/// <summary> /// Only standard free and standard constrained dofs. /// </summary> /// <param name="model"></param> /// <param name="cluster"></param> /// <returns></returns> public static XClusterDofOrderer CreateNodeMajor(Model2D_old model, XCluster2D cluster) { (int numConstrainedDofs, DofTable <StructuralDof> constrainedDofs) = OrderConstrainedDofs(model.Constraints); (int numStandardDofs, DofTable <StructuralDof> standardDofs) = OrderStandardDofs(model); return(new XClusterDofOrderer(cluster, numConstrainedDofs, constrainedDofs, numStandardDofs, standardDofs)); }
private XSubdomain2D_old FindSubdomainWhereNodeEnrichmentIsNotSingular(XCluster2D cluster, XNode node, IEnrichmentItem2D enrichment) { foreach (XSubdomain2D_old subdomain in cluster.Subdomains) { if (subdomain.BoundaryNodes.Contains(node)) { bool isSingularityNode = subdomain.DofOrderer.SingularHeavisideEnrichments.TryGetValue(node, out HashSet <IEnrichmentItem2D> singularEnrichments); if (!isSingularityNode) { return(subdomain); } else if (!singularEnrichments.Contains(enrichment)) { return(subdomain); } } } // This point should not be reached under normal circumstances if (SingularHeavisideEnrichments.ContainsKey(node)) { throw new IncorrectDecompositionException( $"Heaviside dofs of {node} are singular in all subdomains. Investigate further"); } else { throw new ArgumentException( $"In this subdomain, {node} is not a boundary node with singular Heaviside enrichment"); } }
private XClusterDofOrderer(XCluster2D cluster, int numConstrainedDofs, DofTable <StructuralDof> constrainedDofs, int numStandardDofs, DofTable <StructuralDof> standardDofs) { this.cluster = cluster; this.NumConstrainedDofs = numConstrainedDofs; this.constrainedDofs = constrainedDofs; this.NumStandardDofs = numStandardDofs; this.standardDofs = standardDofs; }
public XCluster2D CreateSubdomains() { XSubdomain2D_old[] subdomains = AssignNodesToSubdomains(nodes, regions); AddElementsToSubdomains(elements, subdomains); var cluster = new XCluster2D(); cluster.AddSubdomains(subdomains); return(cluster); }
public void UpdateSubdomains(XCluster2D cluster) { //TODO: this can be done without accessing the single crack. We just need to access the same tip element and nodes foreach (ISingleCrack singleCrack in crack.SingleCracks) { // Find the subdomain that contains the crack tip CartesianPoint tip = singleCrack.CrackTips[0]; XContinuumElement2D tipElement = singleCrack.CrackTipElements[tip][0]; // If there are more neighboring ones, we don't need them XSubdomain2D_old tipSubdomain = cluster.FindSubdomainOfElement(tipElement); // Find all elements that have at least one tip enriched node //TODO: this can be merged with the next subtask var tipEnrichedElements = new HashSet <XContinuumElement2D>(); ISet <XNode> tipNodes = singleCrack.CrackTipNodesNew[singleCrack.CrackTipEnrichments]; foreach (XNode node in tipNodes) { tipEnrichedElements.UnionWith(mesh.FindElementsWithNode(node)); } // Find which of these elements must be removed and from which subdomains var removedElements = new Dictionary <XContinuumElement2D, XSubdomain2D_old>(); foreach (var element in tipEnrichedElements) { if (!tipSubdomain.Elements.Contains(element)) { XSubdomain2D_old previousSubdomain = cluster.FindSubdomainOfElement(element); removedElements.Add(element, previousSubdomain); } } if (removedElements.Count == 0) { continue; } // Find the old subdomains of the nodes of the elements to be removed, before moving the elements Dictionary <XNode, HashSet <XSubdomain2D_old> > oldNodeMembership = FindOldNodeMembership(cluster, removedElements); // Move these elements to the subdomain that contains the crack tip //var modifiedSubdomains = new HashSet<XSubdomain2D>(); foreach (var elementSubdomainPair in removedElements) { XContinuumElement2D element = elementSubdomainPair.Key; XSubdomain2D_old oldSubdomain = elementSubdomainPair.Value; oldSubdomain.Elements.Remove(element); tipSubdomain.Elements.Add(element); //modifiedSubdomains.Add(previousSubdomain); //modifiedSubdomains.Add(tipSubdomain); //TODO: this only needs to be added once } // Move their nodes to their new subdomains, which also updates the boundaries. RemoveNodesFromSubdomains(oldNodeMembership); Dictionary <XNode, HashSet <XSubdomain2D_old> > newNodeMembership = FindNewNodeMembership(cluster, oldNodeMembership.Keys); AddNodesToSubdomains(newNodeMembership); } }
public XCluster2D CreateSubdomains() { HashSet <XNode>[] internalNodes, boundaryNodes; (internalNodes, boundaryNodes) = PartitionNodes(); HashSet <XContinuumElement2D>[] subdomains = PartitionElements(internalNodes, boundaryNodes); (internalNodes, boundaryNodes) = RepartitionNodes(subdomains); var cluster = new XCluster2D(); for (int i = 0; i < numRegions; ++i) { cluster.AddSubdomain(new XSubdomain2D_old(i, subdomains[i], internalNodes[i], boundaryNodes[i])); } return(cluster); }
/// <summary> /// </summary> /// <param name="element"></param> /// <param name="globalFreeVector">Both the free standard and enriched dofs.</param> /// <returns></returns> public Vector ExtractEnrichedDisplacementsOfElementFromGlobal(XCluster2D cluster, XContinuumElement2D element, Vector globalFreeVector) { // While Heaviside dofs on boundary nodes that would cause singular stiffness matrices are generally avoided, // the returned vector of this method must include them. Since H(x)-H(xNode)=0, it wouldn't be wrong to exclude // them in theory. However it would cause indexing problems if they are missing, since other XFEM classes (such as // XContinuumElement) have no concept of a node being enriched only for some elements. DofTable <EnrichedDof> elementDofs = element.GetEnrichedDofs(); double[] elementVector = new double[elementDofs.EntryCount]; foreach (XNode node in element.Nodes) { bool isSingularityNode = SingularHeavisideEnrichments.TryGetValue(node, out HashSet <IEnrichmentItem2D> singularEnrichments); foreach (IEnrichmentItem2D enrichment in node.EnrichmentItems.Keys) { XSubdomainDofOrderer correctOrderer = this; if (isSingularityNode && singularEnrichments.Contains(enrichment)) { // Find global dof index from other subdomain, sine it is not stored here correctOrderer = FindSubdomainWhereNodeEnrichmentIsNotSingular(cluster, node, enrichment).DofOrderer; } foreach (var dofType in enrichment.Dofs) { int elementDofIdx = elementDofs[node, dofType]; int globalDofIdx = correctOrderer.FirstGlobalDofIndex + correctOrderer.subdomainEnrichedDofs[node, dofType]; elementVector[elementDofIdx] = globalFreeVector[globalDofIdx]; } } } //foreach (Tuple<XNode2D, EnrichedDof, int> entry in elementDofs) //{ // int globalEnrichedDof = globalEnrichedDofs[entry.Item1, entry.Item2]; // elementVector[entry.Item3] = globalFreeVector[globalEnrichedDof]; //} return(Vector.CreateFromArray(elementVector)); }
public void UpdateSubdomains(XCluster2D cluster) { // Do nothing }
private Dictionary <XNode, HashSet <XSubdomain2D_old> > FindNewNodeMembership(XCluster2D cluster, IEnumerable <XNode> nodes) { var nodeMembership = new Dictionary <XNode, HashSet <XSubdomain2D_old> >(); var elementMembership = new Dictionary <XContinuumElement2D, XSubdomain2D_old>(); // cache each element for all its nodes foreach (var node in nodes) { var nodeSubdomains = new HashSet <XSubdomain2D_old>(); foreach (var element in mesh.FindElementsWithNode(node)) { // Find the subdomain of this element efficiently bool isProccessed = elementMembership.TryGetValue(element, out XSubdomain2D_old subdomain); if (!isProccessed) { subdomain = cluster.FindSubdomainOfElement(element); elementMembership.Add(element, subdomain); } nodeSubdomains.Add(subdomain); } nodeMembership.Add(node, nodeSubdomains); } return(nodeMembership); }
//TODO: perhaps the node membership should be stored in Cluster for all nodes of the model and updated whenever sth changes private Dictionary <XNode, HashSet <XSubdomain2D_old> > FindOldNodeMembership(XCluster2D cluster, Dictionary <XContinuumElement2D, XSubdomain2D_old> removedElements) { var nodeMembership = new Dictionary <XNode, HashSet <XSubdomain2D_old> >(); foreach (var elementSubdomainPair in removedElements) { foreach (var node in elementSubdomainPair.Key.Nodes) { if (nodeMembership.ContainsKey(node)) { continue; // Avoid nodes that were processed in previous elements } var nodeSubdomains = new HashSet <XSubdomain2D_old>(); foreach (var nodeElement in mesh.FindElementsWithNode(node)) { // Find the subdomain of this element efficiently //TODO: cache the searched elements for other nodes bool isRemoved = removedElements.TryGetValue(nodeElement, out XSubdomain2D_old previousSubdomain); if (isRemoved) { nodeSubdomains.Add(previousSubdomain); } else { nodeSubdomains.Add(cluster.FindSubdomainOfElement(nodeElement)); } } nodeMembership.Add(node, nodeSubdomains); } } return(nodeMembership); }