Example #1
0
        /// <summary>
        /// WARNING: This doesn't work if a node is enriched with more than 1 Heaviside functions from different cracks.
        /// </summary>
        /// <param name="subdomain"></param>
        /// <returns></returns>
        private static Dictionary <XNode, HashSet <IEnrichmentItem2D> > FindBoundaryNodesWithSingularHeaviside(
            ICrackDescription crack, XSubdomain2D_old subdomain)
        {
            var singularNodeEnrichments = new Dictionary <XNode, HashSet <IEnrichmentItem2D> >();

            foreach (ISingleCrack singleCrack in crack.SingleCracks)
            {
                // Build nodal supports of boundary Heaviside nodes.
                // TODO: if the same node is enriched with more than one cracks, then avoid redoing the following for each crack
                var boundaryHeavisideNodes = new List <XNode>();
                var nodalSupports          = new List <ISet <XContinuumElement2D> >();
                foreach (var node in subdomain.BoundaryNodes)
                {
                    // Only process Heaviside nodes
                    bool isHeaviside = false;
                    foreach (var enrichment in node.EnrichmentItems.Keys)
                    {
                        if (enrichment == singleCrack.CrackBodyEnrichment)
                        {
                            boundaryHeavisideNodes.Add(node);
                            isHeaviside = true;
                            break;
                        }
                    }
                    if (isHeaviside)
                    {
                        // Intersection of nodal support and subdomain
                        var support = new HashSet <XContinuumElement2D>();
                        foreach (var element in singleCrack.Mesh.FindElementsWithNode(node))
                        {
                            if (subdomain.Elements.Contains(element))
                            {
                                support.Add(element);
                            }
                        }
                        nodalSupports.Add(support);
                    }
                }

                // Find problematic nodes
                ISet <XNode> singularNodes = singleCrack.SingularityResolver.
                                             FindHeavisideNodesToRemove(singleCrack, boundaryHeavisideNodes, nodalSupports);

                // Register the problematic nodes
                foreach (var node in singularNodes)
                {
                    bool nodeExists = singularNodeEnrichments.TryGetValue(node, out HashSet <IEnrichmentItem2D> enrichmentsOnly);
                    if (!nodeExists)
                    {
                        enrichmentsOnly = new HashSet <IEnrichmentItem2D>();
                        singularNodeEnrichments.Add(node, enrichmentsOnly);
                    }
                    enrichmentsOnly.Add(singleCrack.CrackBodyEnrichment);
                }
            }

            return(singularNodeEnrichments);
        }
Example #2
0
        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);
            }
        }
Example #3
0
        public static XSubdomainDofOrderer CreateNodeMajor(ICrackDescription crack, XSubdomain2D_old subdomain) //TODO: also add AMD reordering
        {
            // Handle nodes with singular Heaviside enrichment
            Dictionary <XNode, HashSet <IEnrichmentItem2D> > singularityHeavisideEnrichments =
                FindBoundaryNodesWithSingularHeaviside(crack, subdomain);

            if (singularityHeavisideEnrichments.Count > 0)
            {
                Console.Write($"WARNING: Subdomain {subdomain.ID} has boundary nodes that are enriched with Heaviside,");
                Console.Write(" but that would lead to singular matrices, since the nodal support in this subdomain only");
                Console.Write(" contains Gauss points with the same sign. It would be better to use another domain");
                Console.Write(" decomposition. The nodes in question are: ");
                foreach (var node in singularityHeavisideEnrichments.Keys)
                {
                    Console.Write(node + " ");
                }
                Console.WriteLine();
            }

            var subdomainEnrichedDofs = new DofTable <EnrichedDof>();
            var boundaryDofs          = new Dictionary <XNode, ISet <EnrichedDof> >();
            int dofCounter            = 0;

            foreach (XNode node in subdomain.AllNodes)
            {
                bool isboundaryNode = subdomain.BoundaryNodes.Contains(node);
                if (isboundaryNode && node.IsEnriched)
                {
                    boundaryDofs.Add(node, new HashSet <EnrichedDof>());
                }
                bool isSingularityNode = singularityHeavisideEnrichments.TryGetValue(node,
                                                                                     out HashSet <IEnrichmentItem2D> singularEnrichments);

                foreach (IEnrichmentItem2D enrichment in node.EnrichmentItems.Keys)
                {
                    if (isSingularityNode && singularEnrichments.Contains(enrichment))
                    {
                        continue;
                    }
                    foreach (EnrichedDof dof in enrichment.Dofs)
                    {
                        if (isboundaryNode)
                        {
                            boundaryDofs[node].Add(dof);
                        }
                        subdomainEnrichedDofs[node, dof] = dofCounter;
                        ++dofCounter;
                    }
                }
            }
            return(new XSubdomainDofOrderer(dofCounter, subdomainEnrichedDofs, singularityHeavisideEnrichments, boundaryDofs));
        }
        private XSubdomain2D_old[] AssignNodesToSubdomains(IReadOnlyList <XNode> nodes, IReadOnlyList <IRegion2D> regions)
        {
            var subdomains = new XSubdomain2D_old[regions.Count];

            for (int s = 0; s < regions.Count; ++s)
            {
                subdomains[s] = new XSubdomain2D_old(s);
            }

            foreach (var node in nodes)
            {
                int multiplicity = 0;
                for (int s = 0; s < regions.Count; ++s)
                {
                    NodePosition pos = regions[s].FindRelativePosition(node);
                    if (pos == NodePosition.Internal)
                    {
                        if (multiplicity > 0)
                        {
                            throw new ArgumentException(
                                      $"The regions overlap, as {node} is internal to region {s} and boundary to an earlier one.");
                        }
                        subdomains[s].AddInternalNode(node);
                        ++multiplicity;
                        break; // It cannot belong to other regions. TODO: perhaps this should be checked
                    }
                    else if (pos == NodePosition.Boundary)
                    {
                        ++multiplicity;
                        subdomains[s].AddBoundaryNode(node);
                        // It can also belong to other regions.
                    }
                }
                if (multiplicity == 0)
                {
                    throw new IncorrectDecompositionException(
                              $"{node} did not belong to any of the regions provided");
                }
            }

            return(subdomains);
        }
        /// <summary>
        /// Index i = element local dof. Dictionary[i] = global dof.
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public IReadOnlyDictionary <int, int> MatchElementToGlobalEnrichedDofsOf(XContinuumElement2D element) //TODO: this can be an array.
        {
            XSubdomain2D_old subdomain = cluster.FindSubdomainOfElement(element);

            return(subdomain.DofOrderer.MatchElementToGlobalEnrichedDofs(element));
        }
        /// <summary>
        /// </summary>
        /// <param name="element"></param>
        /// <param name="globalFreeVector">Both the free standard and enriched dofs.</param>
        /// <returns></returns>
        public Vector ExtractEnrichedDisplacementsOfElementFromGlobal(XContinuumElement2D element, Vector globalFreeVector)
        {
            XSubdomain2D_old subdomain = cluster.FindSubdomainOfElement(element);

            return(subdomain.DofOrderer.ExtractEnrichedDisplacementsOfElementFromGlobal(cluster, element, globalFreeVector));
        }