Exemple #1
0
        public Dictionary <int, int> MatchElementToSubdomainEnrichedDofs(XContinuumElement2D element)
        {
            var element2Subdomain = new Dictionary <int, int>();
            int elementDof        = 0;

            foreach (XNode node in element.Nodes)
            {
                bool isSingularityNode = SingularHeavisideEnrichments.TryGetValue(node,
                                                                                  out HashSet <IEnrichmentItem2D> singularEnrichments);

                // TODO: Perhaps the nodal dof types should be decided by the element type (structural, continuum)
                // and drawn from XXContinuumElement2D instead of from enrichment items
                foreach (IEnrichmentItem2D enrichment in node.EnrichmentItems.Keys)
                {
                    if (isSingularityNode && singularEnrichments.Contains(enrichment))
                    {
                        ++elementDof;
                        continue;
                    }

                    // TODO: Perhaps I could iterate directly on the dofs, ignoring dof types for performance, if the order is guarranteed
                    foreach (EnrichedDof dofType in enrichment.Dofs)
                    {
                        element2Subdomain[elementDof++] = this.subdomainEnrichedDofs[node, dofType];
                    }
                }
            }
            return(element2Subdomain);
        }
Exemple #2
0
        public SortedSet <CartesianPoint> FindTriangleVertices(XContinuumElement2D element)
        {
            var polygon          = ConvexPolygon2D.CreateUnsafe(element.Nodes);
            var triangleVertices = new SortedSet <CartesianPoint>(element.Nodes, pointComparer);
            int nodesCount       = element.Nodes.Count;

            foreach (var vertex in Vertices)
            {
                PolygonPointPosition position = polygon.FindRelativePositionOfPoint(vertex);
                if (position == PolygonPointPosition.Inside || position == PolygonPointPosition.OnEdge ||
                    position == PolygonPointPosition.OnVertex)
                {
                    triangleVertices.Add(vertex);
                }
            }

            foreach (var crackSegment in Segments)
            {
                var segment = new LineSegment2D(crackSegment.Start, crackSegment.End);
                IReadOnlyList <CartesianPoint> intersections = segment.IntersectionWith(polygon);
                foreach (var point in intersections)
                {
                    triangleVertices.Add(point);
                }
            }

            return(triangleVertices);
        }
Exemple #3
0
        /// <summary>
        /// If a fixed enrichment area is applied, all nodes inside a circle around the tip are enriched with tip
        /// functions. They can still be enriched with Heaviside functions, if they do not belong to the tip
        /// element(s).
        /// </summary>
        /// <param name="tipNodes"></param>
        /// <param name="tipElement"></param>
        private void ApplyFixedEnrichmentArea(CartesianPoint crackTip, XContinuumElement2D tipElement,
                                              HashSet <XNode> tipNodes, IEnrichmentItem2D tipEnrichments)
        {
            if (enrichmentRadiusOverElementSize > 0)
            {
                var    outline        = ConvexPolygon2D.CreateUnsafe(tipElement.Nodes);
                double elementArea    = outline.ComputeArea();
                double radius         = enrichmentRadiusOverElementSize * Math.Sqrt(elementArea);
                var    enrichmentArea = new Circle2D(crackTip, radius);

                foreach (var element in Mesh.FindElementsInsideCircle(enrichmentArea, tipElement))
                {
                    bool completelyInside = true;
                    foreach (var node in element.Nodes)
                    {
                        CirclePointPosition position = enrichmentArea.FindRelativePositionOfPoint(node);
                        if ((position == CirclePointPosition.Inside) || (position == CirclePointPosition.On))
                        {
                            tipNodes.Add(node);
                        }
                        else
                        {
                            completelyInside = false;
                        }
                    }

                    if (completelyInside)
                    {
                        element.EnrichmentItems.Add(tipEnrichments);
                    }
                }
            }
        }
Exemple #4
0
        private void ReportTriangulation(XContinuumElement2D element, SortedSet <CartesianPoint> triangleVertices,
                                         IReadOnlyList <Triangle2D <CartesianPoint> > triangles)
        {
            if (!reports)
            {
                return;
            }
            Console.WriteLine("------ DEBUG: TRIANGULATION/ ------");
            Console.WriteLine("Element with nodes: ");
            foreach (var node in element.Nodes)
            {
                Console.Write(node);
                Console.Write(' ');
            }

            Console.WriteLine("\nVertices of triangular mesh: ");
            foreach (var vertex in triangleVertices)
            {
                Console.Write(vertex);
                Console.Write(' ');
            }

            Console.WriteLine("\nTriangles: ");
            foreach (var triangle in triangles)
            {
                Console.WriteLine(triangle);
            }

            Console.WriteLine("------ /DEBUG: TRIANGULATION ------");
        }
Exemple #5
0
        private bool IsCutElement(XContinuumElement2D element)
        {
            var polygon = ConvexPolygon2D.CreateUnsafe(element.Nodes);

            // Look at each segment
            foreach (var crackSegment in Segments)
            {
                var            segment = new LineSegment2D(crackSegment.Start, crackSegment.End);
                CartesianPoint intersectionPoint;
                foreach (var edge in polygon.Edges)
                {
                    LineSegment2D.SegmentSegmentPosition position = segment.IntersectionWith(edge, out intersectionPoint);
                    if (position == LineSegment2D.SegmentSegmentPosition.Intersecting)
                    {
                        // TODO: Perhaps the element should not be flagged as a Heaviside element, if the segment passes
                        // through 1 node only. To detect this, check if the intersection point coincides with an element
                        // node. If it does store it and go to the next edge. If a second intersection point (that does
                        // not coincide with the stored one) is found then it is a Heaviside element.
                        return(true);
                    }
                    else if (position == LineSegment2D.SegmentSegmentPosition.Overlapping)
                    {
                        return(true);
                    }
                }
            }

            // Look at the vertices
            // (if a segment is entirely inside an element, it will not be caught by checking the segment itself)
            bool previousVertexOnEdge = false;
            LinkedListNode <CartesianPoint> currentNode = Vertices.First.Next;
            LinkedListNode <CartesianPoint> lastNode    = Vertices.Last;

            while (currentNode != lastNode)
            {
                PolygonPointPosition position = polygon.FindRelativePositionOfPoint(currentNode.Value);
                if (position == PolygonPointPosition.Inside)
                {
                    return(true);
                }
                else if (position == PolygonPointPosition.OnEdge || position == PolygonPointPosition.OnVertex)
                {
                    if (previousVertexOnEdge)
                    {
                        return(true);
                    }
                    else
                    {
                        previousVertexOnEdge = true;
                    }
                }
                else
                {
                    previousVertexOnEdge = false;
                }
                currentNode = currentNode.Next;
            }

            return(false);
        }
Exemple #6
0
        public List <int> GetSubdomainEnrichedDofsOf(XContinuumElement2D element)
        {
            var dofs = new List <int>();

            foreach (XNode node in element.Nodes)
            {
                bool isSingularityNode = SingularHeavisideEnrichments.TryGetValue(node,
                                                                                  out HashSet <IEnrichmentItem2D> singularEnrichments);

                // TODO: Perhaps the nodal dof types should be decided by the element type (structural, continuum)
                // and drawn from XXContinuumElement2D instead of from enrichment items
                foreach (IEnrichmentItem2D enrichment in node.EnrichmentItems.Keys)
                {
                    if (isSingularityNode && singularEnrichments.Contains(enrichment))
                    {
                        continue;
                    }

                    foreach (EnrichedDof dofType in enrichment.Dofs)
                    {
                        dofs.Add(this.subdomainEnrichedDofs[node, dofType]);
                    }
                }
            }
            return(dofs);
        }
 //TODO: I tried an alternative approach, ie elements access their enrichments from their nodes.
 //      My original thought that this approach (storing enrichments in elements, unless they are standard /
 //      blending) wouldn't work for blending elements, was incorrect, as elements with 0 enrichments
 //      were then examined and separated into standard / blending.
 public void EnrichElement(XContinuumElement2D element)
 {
     if (!affectedElements.Contains(element))
     {
         affectedElements.Add(element);
         element.EnrichmentItems.Add(this);
     }
 }
Exemple #8
0
        public EvaluatedFunction2D[] EvaluateAllAt(NaturalPoint point, XContinuumElement2D element,
                                                   EvalInterpolation2D interpolation)
        {
            CartesianPoint cartesianPoint = interpolation.TransformPointNaturalToGlobalCartesian();
            double         signedDistance = crackDescription.SignedDistanceOf(point, element, interpolation);

            return(new EvaluatedFunction2D[] { enrichmentFunction.EvaluateAllAt(signedDistance) });
        }
Exemple #9
0
 public void AddElement(XContinuumElement2D element)
 {
     if (elements.Contains(element))
     {
         throw new ArgumentException("This element is already inserted");
     }
     elements.Add(element);
 }
Exemple #10
0
        public override EvaluatedFunction2D[] EvaluateAllAt(NaturalPoint point, XContinuumElement2D element,
                                                            EvalInterpolation2D interpolation)
        {
            CartesianPoint cartesianPoint = interpolation.TransformPointNaturalToGlobalCartesian();
            double         signedDistance = Discontinuity.SignedDistanceOf(cartesianPoint);
            Vector2        normalVector   = Discontinuity.NormalVectorThrough(cartesianPoint);

            return(new EvaluatedFunction2D[] { enrichmentFunction.EvaluateAllAt(signedDistance, normalVector) });
        }
Exemple #11
0
        private void ComputeInteractionIntegrals(XContinuumElement2D element, Vector standardNodalDisplacements,
                                                 Vector enrichedNodalDisplacements, double[] nodalWeights, TipCoordinateSystem tipSystem,
                                                 out double integralMode1, out double integralMode2)
        {
            integralMode1 = 0.0;
            integralMode2 = 0.0;
            foreach (GaussPoint naturalGP in element.JintegralStrategy.GenerateIntegrationPoints(element))
            {
                // Nomenclature: global = global cartesian system, natural = element natural system,
                // local = tip local cartesian system

                EvalInterpolation2D evaluatedInterpolation =
                    element.Interpolation.EvaluateAllAt(element.Nodes, naturalGP);
                CartesianPoint globalGP     = evaluatedInterpolation.TransformPointNaturalToGlobalCartesian();
                Matrix         constitutive =
                    element.Material.CalculateConstitutiveMatrixAt(naturalGP, evaluatedInterpolation);

                // State 1
                Matrix2by2 globalDisplacementGradState1 = element.CalculateDisplacementFieldGradient(
                    naturalGP, evaluatedInterpolation, standardNodalDisplacements, enrichedNodalDisplacements);
                Tensor2D   globalStressState1          = element.CalculateStressTensor(globalDisplacementGradState1, constitutive);
                Matrix2by2 localDisplacementGradState1 = tipSystem.
                                                         TransformVectorFieldDerivativesGlobalCartesianToLocalCartesian(globalDisplacementGradState1);
                Tensor2D localStressTensorState1 = tipSystem.
                                                   TransformTensorGlobalCartesianToLocalCartesian(globalStressState1);

                // Weight Function
                // TODO: There should be a method InterpolateScalarGradient(double[] nodalValues) in EvaluatedInterpolation
                // TODO: Rewrite this as a shapeGradients (matrix) * nodalWeights (vector) operation.
                var globalWeightGradient = Vector2.CreateZero();
                for (int nodeIdx = 0; nodeIdx < element.Nodes.Count; ++nodeIdx)
                {
                    globalWeightGradient.AxpyIntoThis(
                        evaluatedInterpolation.ShapeGradientsCartesian.GetRow(nodeIdx), // Previously: GetGlobalCartesianDerivativesOf(element.Nodes[nodeIdx])
                        nodalWeights[nodeIdx]);
                }
                Vector2 localWeightGradient = tipSystem.
                                              TransformScalarFieldDerivativesGlobalCartesianToLocalCartesian(globalWeightGradient);

                // State 2
                // TODO: XContinuumElement shouldn't have to pass tipCoordinate system to auxiliaryStates.
                // It would be better to have CrackTip handle this and the coordinate transformations. That would also
                // obey LoD, but a lot of wrapper methods would be required.
                AuxiliaryStatesTensors auxiliary = auxiliaryStatesStrategy.ComputeTensorsAt(globalGP, tipSystem);

                // Interaction integrals
                double integrandMode1 = ComputeJIntegrand(localWeightGradient, localDisplacementGradState1,
                                                          localStressTensorState1, auxiliary.DisplacementGradientMode1,
                                                          auxiliary.StrainTensorMode1, auxiliary.StressTensorMode1);
                double integrandMode2 = ComputeJIntegrand(localWeightGradient, localDisplacementGradState1,
                                                          localStressTensorState1, auxiliary.DisplacementGradientMode2,
                                                          auxiliary.StrainTensorMode2, auxiliary.StressTensorMode2);

                integralMode1 += integrandMode1 * evaluatedInterpolation.Jacobian.DirectDeterminant * naturalGP.Weight;
                integralMode2 += integrandMode2 * evaluatedInterpolation.Jacobian.DirectDeterminant * naturalGP.Weight;
            }
        }
Exemple #12
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);
            }
        }
Exemple #13
0
        public List <int> GetEnrichedDofsOf(XContinuumElement2D element)
        {
            var globalDofs = new List <int>();

            foreach (var nodeDofLocal in element.GetEnrichedDofs())
            {
                globalDofs.Add(enrichedDofs[nodeDofLocal.row, nodeDofLocal.col]); // It must be included.
            }
            return(globalDofs);
        }
Exemple #14
0
 public XSubdomain2D_old FindSubdomainOfElement(XContinuumElement2D element)
 {
     foreach (var subdomain in subdomains)
     {
         if (subdomain.Elements.Contains(element))
         {
             return(subdomain);
         }
     }
     throw new KeyNotFoundException("This element does not belong to any subdomain.");
 }
        /// <summary>
        /// Warning: with narrow band this should throw an exception if the element/nodes are not tracked.
        /// </summary>
        /// <param name="point"></param>
        /// <param name="elementNodes"></param>
        /// <param name="interpolation"></param>
        /// <returns></returns>
        public double SignedDistanceOf(NaturalPoint point, XContinuumElement2D element,
                                       EvalInterpolation2D interpolation)
        {
            double signedDistance = 0.0;

            for (int nodeIdx = 0; nodeIdx < element.Nodes.Count; ++nodeIdx)
            {
                signedDistance += interpolation.ShapeFunctions[nodeIdx] * levelSetsBody[element.Nodes[nodeIdx]];
            }
            return(signedDistance);
        }
        public Tensor2D EvaluateAt(XContinuumElement2D element, NaturalPoint point,
                                   Vector standardDisplacements, Vector enrichedDisplacements)
        {
            EvalInterpolation2D evaluatedInterpolation = element.Interpolation.EvaluateAllAt(element.Nodes, point);
            Matrix2by2          displacementGradient   = element.CalculateDisplacementFieldGradient(
                point, evaluatedInterpolation, standardDisplacements, enrichedDisplacements);
            Matrix constitutive =
                element.Material.CalculateConstitutiveMatrixAt(point, evaluatedInterpolation);

            return(element.CalculateStressTensor(displacementGradient, constitutive));
        }
Exemple #17
0
        /// <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)
        {
            DofTable <EnrichedDof> elementDofs = element.GetEnrichedDofs();

            double[] elementVector = new double[elementDofs.EntryCount];
            foreach ((XNode node, EnrichedDof dofType, int dofIdx) in elementDofs)
            {
                int globalEnrichedDof = enrichedDofs[node, dofType];
                elementVector[dofIdx] = globalFreeVector[globalEnrichedDof];
            }
            return(Vector.CreateFromArray(elementVector));
        }
        public static void TestJointStiffnessMatrixOfCrackBodyElement()
        {
            double equalityTolerance          = 1E-13;
            Matrix expectedStiffnessNodeMajor = 1E6 * Matrix.CreateFromArray(new double[, ]
            {
                { 1.154, 0.481, 0.962, 0.240, -0.769, 0.096, 0.769, 0.144, -0.577, -0.481, 0.577, 0.433, 0.192, -0.096, 0.385, -0.048 },
                { 0.481, 1.154, 0.240, 0.481, -0.096, 0.192, 0.337, -0.192, -0.481, -0.577, 0.529, 0.577, 0.096, -0.769, 0.048, -0.096 },
                { 0.962, 0.240, 1.923, 0.481, -0.769, 0.337, 0.000, 0.000, -0.577, -0.529, 0.000, 0.000, 0.385, -0.048, 0.769, -0.096 },
                { 0.240, 0.481, 0.481, 0.962, 0.144, 0.192, 0.000, 0.000, -0.433, -0.577, 0.000, 0.000, 0.048, -0.096, 0.096, -0.192 },
                { -0.769, -0.096, -0.769, 0.144, 1.154, -0.481, -0.962, 0.240, 0.192, 0.096, -0.385, -0.048, -0.577, 0.481, -0.577, 0.433 },
                { 0.096, 0.192, 0.337, 0.192, -0.481, 1.154, 0.240, -0.481, -0.096, -0.769, 0.048, 0.096, 0.481, -0.577, 0.529, -0.577 },
                { 0.769, 0.337, 0.000, 0.000, -0.962, 0.240, 1.923, -0.481, -0.385, -0.048, 0.769, 0.096, 0.577, -0.529, 0.000, 0.000 },
                { 0.144, -0.192, 0.000, 0.000, 0.240, -0.481, -0.481, 0.962, 0.048, 0.096, -0.096, -0.192, -0.433, 0.577, 0.000, 0.000 },
                { -0.577, -0.481, -0.577, -0.433, 0.192, -0.096, -0.385, 0.048, 1.154, 0.481, -0.962, -0.240, -0.769, 0.096, -0.769, -0.144 },
                { -0.481, -0.577, -0.529, -0.577, 0.096, -0.769, -0.048, 0.096, 0.481, 1.154, -0.240, -0.481, -0.096, 0.192, -0.337, 0.192 },
                { 0.577, 0.529, 0.000, 0.000, -0.385, 0.048, 0.769, -0.096, -0.962, -0.240, 1.923, 0.481, 0.769, -0.337, 0.000, 0.000 },
                { 0.433, 0.577, 0.000, 0.000, -0.048, 0.096, 0.096, -0.192, -0.240, -0.481, 0.481, 0.962, -0.144, -0.192, 0.000, 0.000 },
                { 0.192, 0.096, 0.385, 0.048, -0.577, 0.481, 0.577, -0.433, -0.769, -0.096, 0.769, -0.144, 1.154, -0.481, 0.962, -0.240 },
                { -0.096, -0.769, -0.048, -0.096, 0.481, -0.577, -0.529, 0.577, 0.096, 0.192, -0.337, -0.192, -0.481, 1.154, -0.240, 0.481 },
                { 0.385, 0.048, 0.769, 0.096, -0.577, 0.529, 0.000, 0.000, -0.769, -0.337, 0.000, 0.000, 0.962, -0.240, 1.923, -0.481 },
                { -0.048, -0.096, -0.096, -0.192, 0.433, -0.577, 0.000, 0.000, -0.144, 0.192, 0.000, 0.000, -0.240, 0.481, -0.481, 0.962 }
            });

            Matrix expectedStiffnessStdFirst = 1E6 * Matrix.CreateFromArray(new double[, ]
            {
                { 1.154, 0.481, -0.769, 0.096, -0.577, -0.481, 0.192, -0.096, 0.962, 0.240, 0.769, 0.144, 0.577, 0.433, 0.385, -0.048 },
                { 0.481, 1.154, -0.096, 0.192, -0.481, -0.577, 0.096, -0.769, 0.240, 0.481, 0.337, -0.192, 0.529, 0.577, 0.048, -0.096 },
                { -0.769, -0.096, 1.154, -0.481, 0.192, 0.096, -0.577, 0.481, -0.769, 0.144, -0.962, 0.240, -0.385, -0.048, -0.577, 0.433 },
                { 0.096, 0.192, -0.481, 1.154, -0.096, -0.769, 0.481, -0.577, 0.337, 0.192, 0.240, -0.481, 0.048, 0.096, 0.529, -0.577 },
                { -0.577, -0.481, 0.192, -0.096, 1.154, 0.481, -0.769, 0.096, -0.577, -0.433, -0.385, 0.048, -0.962, -0.240, -0.769, -0.144 },
                { -0.481, -0.577, 0.096, -0.769, 0.481, 1.154, -0.096, 0.192, -0.529, -0.577, -0.048, 0.096, -0.240, -0.481, -0.337, 0.192 },
                { 0.192, 0.096, -0.577, 0.481, -0.769, -0.096, 1.154, -0.481, 0.385, 0.048, 0.577, -0.433, 0.769, -0.144, 0.962, -0.240 },
                { -0.096, -0.769, 0.481, -0.577, 0.096, 0.192, -0.481, 1.154, -0.048, -0.096, -0.529, 0.577, -0.337, -0.192, -0.240, 0.481 },
                { 0.962, 0.240, -0.769, 0.337, -0.577, -0.529, 0.385, -0.048, 1.923, 0.481, 0.000, 0.000, 0.000, 0.000, 0.769, -0.096 },
                { 0.240, 0.481, 0.144, 0.192, -0.433, -0.577, 0.048, -0.096, 0.481, 0.962, 0.000, 0.000, 0.000, 0.000, 0.096, -0.192 },
                { 0.769, 0.337, -0.962, 0.240, -0.385, -0.048, 0.577, -0.529, 0.000, 0.000, 1.923, -0.481, 0.769, 0.096, 0.000, 0.000 },
                { 0.144, -0.192, 0.240, -0.481, 0.048, 0.096, -0.433, 0.577, 0.000, 0.000, -0.481, 0.962, -0.096, -0.192, 0.000, 0.000 },
                { 0.577, 0.529, -0.385, 0.048, -0.962, -0.240, 0.769, -0.337, 0.000, 0.000, 0.769, -0.096, 1.923, 0.481, 0.000, 0.000 },
                { 0.433, 0.577, -0.048, 0.096, -0.240, -0.481, -0.144, -0.192, 0.000, 0.000, 0.096, -0.192, 0.481, 0.962, 0.000, 0.000 },
                { 0.385, 0.048, -0.577, 0.529, -0.769, -0.337, 0.962, -0.240, 0.769, 0.096, 0.000, 0.000, 0.000, 0.000, 1.923, -0.481 },
                { -0.048, -0.096, 0.433, -0.577, -0.144, 0.192, -0.240, 0.481, -0.096, -0.192, 0.000, 0.000, 0.000, 0.000, -0.481, 0.962 }
            });

            XContinuumElement2D element            = CreateCrackBodyElement();
            IMatrix             stiffnessNodeMajor = element.JoinStiffnessesNodeMajor();
            IMatrix             stiffnessStdFirst  = element.JoinStiffnessesStandardFirst();

            Assert.True(expectedStiffnessNodeMajor.Equals(
                            stiffnessNodeMajor.DoToAllEntries(round), equalityTolerance));
            Assert.True(expectedStiffnessStdFirst.Equals(
                            stiffnessStdFirst.DoToAllEntries(round), equalityTolerance));
        }
Exemple #19
0
        private void FindSignedAreasOfElement(XContinuumElement2D element,
                                              out double positiveArea, out double negativeArea)
        {
            SortedSet <CartesianPoint> triangleVertices            = FindTriangleVertices(element);
            IReadOnlyList <Triangle2D <CartesianPoint> > triangles = triangulator.CreateMesh(triangleVertices);

            ReportTriangulation(element, triangleVertices, triangles);

            positiveArea = 0.0;
            negativeArea = 0.0;
            foreach (var triangle in triangles)
            {
                CartesianPoint v0   = triangle.Vertices[0];
                CartesianPoint v1   = triangle.Vertices[1];
                CartesianPoint v2   = triangle.Vertices[2];
                double         area = 0.5 * Math.Abs(v0.X * (v1.Y - v2.Y) + v1.X * (v2.Y - v0.Y) + v2.X * (v0.Y - v1.Y));

                // The sign of the area can be derived from any node with signed distance != 0
                int sign = 0;
                foreach (var vertex in triangle.Vertices)
                {
                    sign = Math.Sign(SignedDistanceOfPoint(vertex));
                    if (sign != 0)
                    {
                        break;
                    }
                }

                // If no node with non-zero signed distance is found, then find the signed distance of its centroid
                if (sign == 0)
                {
                    // Report this instance in DEBUG messages. It should not happen.
                    Console.WriteLine("--- DEBUG: Triangulation resulted in a triangle where all vertices are on the crack. ---");
                    var centroid = new CartesianPoint((v0.X + v1.X + v2.X) / 3.0, (v0.Y + v1.Y + v2.Y) / 3.0);
                    sign = Math.Sign(SignedDistanceOfPoint(centroid));
                }

                if (sign > 0)
                {
                    positiveArea += area;
                }
                else if (sign < 0)
                {
                    negativeArea += area;
                }
                else
                {
                    throw new Exception(
                              "Even after finding the signed distance of its centroid, the sign of the area is unidentified");
                }
            }
        }
Exemple #20
0
 /// <summary>
 /// Checks if the element is internal to this subdomain. If it is, it is added and true is returned. Otherwise false is
 /// returned.
 /// </summary>
 /// <param name="element"></param>
 /// <returns></returns>
 public bool AddElementIfInternal(XContinuumElement2D element)
 {
     //TODO: check if one node is internal, while another is external.
     foreach (var node in element.Nodes)
     {
         if (!(internalNodes.Contains(node) || boundaryNodes.Contains(node)))
         {
             return(false);
         }
     }
     elements.Add(element);
     return(true);
 }
Exemple #21
0
        public Tensor2D EvaluateAt(XContinuumElement2D element, NaturalPoint point,
                                   Vector standardDisplacements, Vector enrichedDisplacements)
        {
            EvalInterpolation2D evaluatedInterpolation = element.Interpolation.EvaluateAllAt(element.Nodes, point);
            Matrix2by2          displacementGradient   = element.CalculateDisplacementFieldGradient(
                point, evaluatedInterpolation, standardDisplacements, enrichedDisplacements);

            double strainXX = displacementGradient[0, 0];
            double strainYY = displacementGradient[1, 1];
            double strainXY = 0.5 * (displacementGradient[0, 1] + displacementGradient[1, 0]);

            return(new Tensor2D(strainXX, strainYY, strainXY));
        }
Exemple #22
0
        public List <int> GetStandardDofsOf(XContinuumElement2D element)
        {
            var globalDofs = new List <int>(2 * element.Nodes.Count);

            foreach (var nodeDofLocal in element.GetStandardDofs())
            {
                bool isStandard = standardDofs.TryGetValue(nodeDofLocal.row, nodeDofLocal.col, out int globalDof);
                if (isStandard)
                {
                    globalDofs.Add(globalDof);
                }
            }
            return(globalDofs);
        }
Exemple #23
0
        public CrackElementPosition FindRelativePositionOf(XContinuumElement2D element)
        {
            CartesianPoint crackTip        = lsm.GetCrackTip(CrackTipPosition.Single);
            double         minBodyLevelSet = double.MaxValue;
            double         maxBodyLevelSet = double.MinValue;
            double         minTipLevelSet  = double.MaxValue;
            double         maxTipLevelSet  = double.MinValue;

            foreach (XNode node in element.Nodes)
            {
                double bodyLevelSet = lsm.LevelSetsBody[node];
                double tipLevelSet  = lsm.LevelSetsTip[node];
                if (bodyLevelSet < minBodyLevelSet)
                {
                    minBodyLevelSet = bodyLevelSet;
                }
                if (bodyLevelSet > maxBodyLevelSet)
                {
                    maxBodyLevelSet = bodyLevelSet;
                }
                if (tipLevelSet < minTipLevelSet)
                {
                    minTipLevelSet = tipLevelSet;
                }
                if (tipLevelSet > maxTipLevelSet)
                {
                    maxTipLevelSet = tipLevelSet;
                }
            }

            //Warning: this might actually be worse than Stolarska's criterion. At least that one enriched the dubious
            //intersected elements with tip enrichments. This one just ignores them.
            if (minBodyLevelSet * maxBodyLevelSet <= 0.0)
            {
                if (minTipLevelSet * maxTipLevelSet <= 0)
                {
                    var outline = ConvexPolygon2D.CreateUnsafe(element.Nodes);
                    if (outline.IsPointInsidePolygon(crackTip))
                    {
                        return(CrackElementPosition.ContainsTip);
                    }
                }
                else if (maxTipLevelSet < 0)
                {
                    return(CrackElementPosition.Intersected);
                }
            }
            return(CrackElementPosition.Irrelevant);
        }
        public EvaluatedFunction2D[] EvaluateAllAt(NaturalPoint point, XContinuumElement2D element,
                                                   EvalInterpolation2D interpolation)
        {
            PolarPoint2D polarPoint = TipSystem.TransformPointGlobalCartesianToLocalPolar(
                interpolation.TransformPointNaturalToGlobalCartesian());
            TipJacobians tipJacobians = TipSystem.CalculateJacobiansAt(polarPoint);

            var enrichments = new EvaluatedFunction2D[enrichmentFunctions.Count];

            for (int i = 0; i < enrichments.Length; ++i)
            {
                enrichments[i] = enrichmentFunctions[i].EvaluateAllAt(polarPoint, tipJacobians);
            }
            return(enrichments);
        }
Exemple #25
0
 private int DecideElementRegion(XContinuumElement2D element, HashSet <XNode>[] internalNodes,
                                 HashSet <XNode>[] boundaryNodes)
 {
     foreach (var node in element.Nodes)
     {
         for (int i = 0; i < numRegions; ++i)
         {
             // The first region that contains part of the element is chosen.
             //TODO: a more sophisticated criterion, such as looking at the relative areas is needed.
             if (internalNodes[i].Contains(node))
             {
                 return(i);
             }
         }
     }
     throw new IncorrectDecompositionException("This element's nodes do not belong to any of the regions provided");
 }
Exemple #26
0
        //TODO: replace this with the Faster~() version
        public CrackElementPosition FindRelativePositionOf(XContinuumElement2D element)
        {
            CartesianPoint crackTip        = lsm.GetCrackTip(CrackTipPosition.Single);
            double         minBodyLevelSet = double.MaxValue;
            double         maxBodyLevelSet = double.MinValue;
            double         minTipLevelSet  = double.MaxValue;
            double         maxTipLevelSet  = double.MinValue;

            foreach (XNode node in element.Nodes)
            {
                double bodyLevelSet = lsm.LevelSetsBody[node];
                double tipLevelSet  = lsm.LevelSetsTip[node];
                if (bodyLevelSet < minBodyLevelSet)
                {
                    minBodyLevelSet = bodyLevelSet;
                }
                if (bodyLevelSet > maxBodyLevelSet)
                {
                    maxBodyLevelSet = bodyLevelSet;
                }
                if (tipLevelSet < minTipLevelSet)
                {
                    minTipLevelSet = tipLevelSet;
                }
                if (tipLevelSet > maxTipLevelSet)
                {
                    maxTipLevelSet = tipLevelSet;
                }
            }

            // Warning: This criterion might give false positives for tip elements (see Serafeim's thesis for details)
            if (minBodyLevelSet * maxBodyLevelSet <= 0.0)
            {
                var outline = ConvexPolygon2D.CreateUnsafe(element.Nodes);
                if (outline.IsPointInsidePolygon(crackTip))
                {
                    return(CrackElementPosition.ContainsTip);
                }
                else if (maxTipLevelSet < 0)
                {
                    return(CrackElementPosition.Intersected);
                }
            }
            return(CrackElementPosition.Irrelevant);
        }
        public SortedSet <CartesianPoint> FindTriangleVertices(XContinuumElement2D element)
        {
            var triangleVertices = new SortedSet <CartesianPoint>(element.Nodes, pointComparer);
            int nodesCount       = element.Nodes.Count;
            CrackElementPosition relativePosition = meshInteraction.FindRelativePositionOf(element);

            if (relativePosition != CrackElementPosition.Irrelevant)
            {
                // Find the intersections between element edges and the crack. TODO: See Serafeim's Msc Thesis for a correct procedure.
                for (int i = 0; i < nodesCount; ++i)
                {
                    XNode  node1     = element.Nodes[i];
                    XNode  node2     = element.Nodes[(i + 1) % nodesCount];
                    double levelSet1 = levelSetsBody[node1];
                    double levelSet2 = levelSetsBody[node2];

                    if (levelSet1 * levelSet2 < 0.0)
                    {
                        // The intersection point between these nodes can be found using the linear interpolation, see
                        // Sukumar 2001
                        double k = -levelSet1 / (levelSet2 - levelSet1);
                        double x = node1.X + k * (node2.X - node1.X);
                        double y = node1.Y + k * (node2.Y - node1.Y);

                        // TODO: For the tip element one intersection point is on the crack extension and does not
                        // need to be added. It is not wrong though.
                        triangleVertices.Add(new CartesianPoint(x, y));
                    }
                    else if (levelSet1 == 0.0)
                    {
                        triangleVertices.Add(node1);                        // TODO: perhaps some tolerance is needed.
                    }
                    else if (levelSet2 == 0.0)
                    {
                        triangleVertices.Add(node2);
                    }
                }

                if (relativePosition == CrackElementPosition.ContainsTip)
                {
                    triangleVertices.Add(crackTip);
                }
            }
            return(triangleVertices);
        }
        // Computes stresses directly at the nodes. The other approach is to compute them at Gauss points and then extrapolate
        private IReadOnlyList <Tensor2D> ElementNodalTensorsDirectly(XContinuumElement2D element,
                                                                     Vector freeDisplacements, Vector constrainedDisplacements, IOutputField field)
        {
            Vector standardDisplacements = dofOrderer.ExtractDisplacementVectorOfElementFromGlobal(element,
                                                                                                   freeDisplacements, constrainedDisplacements);
            Vector enrichedDisplacements =
                dofOrderer.ExtractEnrichedDisplacementsOfElementFromGlobal(element, freeDisplacements);

            IReadOnlyList <NaturalPoint> naturalNodes = element.Interpolation.NodalNaturalCoordinates;
            var nodalTensors = new Tensor2D[element.Nodes.Count];

            for (int i = 0; i < element.Nodes.Count; ++i)
            {
                nodalTensors[i] =
                    field.EvaluateAt(element, naturalNodes[i], standardDisplacements, enrichedDisplacements);
            }
            return(nodalTensors);
        }
        //TODO: Either work with Tensor class or double[]
        private IReadOnlyList <Tensor2D> ElementNodalTensorsExtrapolation(XContinuumElement2D element,
                                                                          Vector freeDisplacements, Vector constrainedDisplacements, IOutputField field)
        {
            Vector standardDisplacements = dofOrderer.ExtractDisplacementVectorOfElementFromGlobal(element,
                                                                                                   freeDisplacements, constrainedDisplacements);
            Vector enrichedDisplacements =
                dofOrderer.ExtractEnrichedDisplacementsOfElementFromGlobal(element, freeDisplacements);

            IReadOnlyList <NaturalPoint> gaussPoints = element.GaussPointExtrapolation.Quadrature.IntegrationPoints;
            var gpTensors = new Tensor2D[gaussPoints.Count];

            for (int i = 0; i < gaussPoints.Count; ++i)
            {
                gpTensors[i] =
                    field.EvaluateAt(element, gaussPoints[i], standardDisplacements, enrichedDisplacements);
            }
            return(element.GaussPointExtrapolation.ExtrapolateTensorFromGaussPointsToNodes(gpTensors, element.Interpolation));
        }
Exemple #30
0
        private static (XModel model, IMesh2D <XNode, XContinuumElement2D> mesh) CreateModel(string meshPath)
        {
            // Mesh generation
            var reader = new GmshReader <XNode>(meshPath);

            (IReadOnlyList <XNode> nodes, IReadOnlyList <CellConnectivity <XNode> > elementConnectivities) = reader.CreateMesh(
                (id, x, y, z) => new XNode(id, x, y, z));

            // Nodes
            var model = new XModel();

            foreach (XNode node in nodes)
            {
                model.Nodes.Add(node);
            }

            // Integration rules
            var integration = new IntegrationForCrackPropagation2D(
                new RectangularSubgridIntegration2D <XContinuumElement2D>(8, GaussLegendre2D.GetQuadratureWithOrder(2, 2)),
                new RectangularSubgridIntegration2D <XContinuumElement2D>(8, GaussLegendre2D.GetQuadratureWithOrder(2, 2)));
            var jIntegration =
                new RectangularSubgridIntegration2D <XContinuumElement2D>(8, GaussLegendre2D.GetQuadratureWithOrder(4, 4));

            // Elements
            var material = HomogeneousElasticMaterial2D.CreateMaterialForPlaneStrain(2.1E7, 0.3);
            var factory  = new XContinuumElement2DFactory(integration, jIntegration, material);
            var cells    = new XContinuumElement2D[elementConnectivities.Count];

            for (int e = 0; e < cells.Length; ++e)
            {
                XContinuumElement2D element = factory.CreateElement(e, CellType.Quad4, elementConnectivities[e].Vertices);
                cells[e] = element;
                model.Elements.Add(element);
            }

            // Mesh usable for crack-mesh interaction
            //var boundary = new FilletBoundary();
            IDomain2DBoundary boundary = null;

            model.Boundary = boundary;
            var mesh = new BidirectionalMesh2D <XNode, XContinuumElement2D>(model.Nodes, cells, boundary);

            return(model, mesh);
        }