// 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);
        }
        public IReadOnlyDictionary <XContinuumElement2D, IReadOnlyList <Vector2> > FindElementWiseDisplacements(
            Vector solution)
        {
            Vector constrainedDisplacements = model.CalculateConstrainedDisplacements(dofOrderer);
            var    allDisplacements         = new Dictionary <XContinuumElement2D, IReadOnlyList <Vector2> >();

            foreach (var element in model.Elements)
            {
                Vector displacementsUnrolled = dofOrderer.ExtractDisplacementVectorOfElementFromGlobal(
                    element, solution, constrainedDisplacements);
                var displacementsAsVectors = new Vector2[element.Nodes.Count];
                for (int i = 0; i < element.Nodes.Count; ++i) // This only works for continuum elements though.
                {
                    displacementsAsVectors[i] = Vector2.Create(displacementsUnrolled[2 * i], displacementsUnrolled[2 * i + 1]);
                }
                allDisplacements[element] = displacementsAsVectors;
            }
            return(allDisplacements);
        }
        // Computes stresses directly at the nodes. The other approach is to compute them at Gauss points and then extrapolate
        private IReadOnlyDictionary <XNode, Tensor2D> ComputeNodalStressesOfElement(XContinuumElement2D element,
                                                                                    Vector freeDisplacements, Vector constrainedDisplacements)
        {
            Vector standardDisplacements = dofOrderer.ExtractDisplacementVectorOfElementFromGlobal(element,
                                                                                                   freeDisplacements, constrainedDisplacements);
            Vector enrichedDisplacements =
                dofOrderer.ExtractEnrichedDisplacementsOfElementFromGlobal(element, freeDisplacements);

            IReadOnlyList <NaturalPoint> naturalNodes = element.Interpolation.NodalNaturalCoordinates;
            var nodalStresses = new Dictionary <XNode, Tensor2D>();

            for (int i = 0; i < element.Nodes.Count; ++i)
            {
                EvalInterpolation2D evaluatedInterpolation =
                    element.Interpolation.EvaluateAllAt(element.Nodes, naturalNodes[i]);
                Matrix2by2 displacementGradient = element.CalculateDisplacementFieldGradient(
                    naturalNodes[i], evaluatedInterpolation, standardDisplacements, enrichedDisplacements);
                Matrix constitutive =
                    element.Material.CalculateConstitutiveMatrixAt(naturalNodes[i], evaluatedInterpolation);
                nodalStresses[element.Nodes[i]] = element.CalculateStressTensor(displacementGradient, constitutive);
            }

            return(nodalStresses);
        }
Exemple #4
0
        public void WriteOutputData(IDofOrderer dofOrderer, Vector freeDisplacements, Vector constrainedDisplacements, int step)
        {
            // TODO: guess initial capacities from previous steps or from the model
            var allPoints     = new List <VtkPoint>();
            var allCells      = new List <VtkCell>();
            var displacements = new List <double[]>();
            var strains       = new List <Tensor2D>();
            var stresses      = new List <Tensor2D>();
            int pointCounter  = 0;

            foreach (XContinuumElement2D element in model.Elements)
            {
                Vector standardDisplacements = dofOrderer.ExtractDisplacementVectorOfElementFromGlobal(element,
                                                                                                       freeDisplacements, constrainedDisplacements);
                Vector enrichedDisplacements =
                    dofOrderer.ExtractEnrichedDisplacementsOfElementFromGlobal(element, freeDisplacements);
                bool mustTriangulate = MustBeTriangulated(element, out ISingleCrack intersectingCrack);

                if (!mustTriangulate)
                {
                    // Mesh
                    var cellPoints = new VtkPoint[element.Nodes.Count];
                    for (int p = 0; p < cellPoints.Length; ++p)
                    {
                        cellPoints[p] = new VtkPoint(pointCounter++, element.Nodes[p]);
                        allPoints.Add(cellPoints[p]);
                    }
                    allCells.Add(new VtkCell(element.CellType, cellPoints));

                    // Displacements
                    for (int p = 0; p < cellPoints.Length; ++p)
                    {
                        displacements.Add(new double[] { standardDisplacements[2 * p], standardDisplacements[2 * p + 1] });
                    }

                    // Strains and stresses at Gauss points of element
                    // WARNING: do not use the quadrature object, since GPs are sorted differently.
                    IReadOnlyList <GaussPoint> gaussPoints = element.GaussPointExtrapolation.Quadrature.IntegrationPoints;
                    var strainsAtGPs  = new Tensor2D[gaussPoints.Count];
                    var stressesAtGPs = new Tensor2D[gaussPoints.Count];
                    for (int gp = 0; gp < gaussPoints.Count; ++gp)
                    {
                        EvalInterpolation2D evalInterpol =
                            element.Interpolation.EvaluateAllAt(element.Nodes, gaussPoints[gp]);
                        (Tensor2D strain, Tensor2D stress) = ComputeStrainStress(element, gaussPoints[gp],
                                                                                 evalInterpol, standardDisplacements, enrichedDisplacements);
                        strainsAtGPs[gp]  = strain;
                        stressesAtGPs[gp] = stress;
                    }

                    // Extrapolate strains and stresses to element nodes. This is exact, since the element is not enriched
                    IReadOnlyList <Tensor2D> strainsAtNodes = element.GaussPointExtrapolation.
                                                              ExtrapolateTensorFromGaussPointsToNodes(strainsAtGPs, element.Interpolation);
                    IReadOnlyList <Tensor2D> stressesAtNodes = element.GaussPointExtrapolation.
                                                               ExtrapolateTensorFromGaussPointsToNodes(stressesAtGPs, element.Interpolation);
                    for (int p = 0; p < cellPoints.Length; ++p)
                    {
                        strains.Add(strainsAtNodes[p]);
                        stresses.Add(stressesAtNodes[p]);
                    }
                }
                else
                {
                    // Triangulate and then operate on each triangle
                    SortedSet <CartesianPoint> triangleVertices            = intersectingCrack.FindTriangleVertices(element);
                    IReadOnlyList <Triangle2D <CartesianPoint> > triangles = triangulator.CreateMesh(triangleVertices);

                    foreach (Triangle2D <CartesianPoint> triangle in triangles)
                    {
                        // Mesh
                        int numTriangleNodes = 3;
                        var cellPoints       = new VtkPoint[numTriangleNodes];
                        for (int p = 0; p < numTriangleNodes; ++p)
                        {
                            CartesianPoint point = triangle.Vertices[p];
                            cellPoints[p] = new VtkPoint(pointCounter++, point.X, point.Y, point.Z);
                            allPoints.Add(cellPoints[p]);
                        }
                        allCells.Add(new VtkCell(CellType.Tri3, cellPoints));

                        // Displacements, strains and stresses are not defined on the crack, thus they must be evaluated at GPs
                        // and extrapolated to each point of interest. However how should I choose the Gauss points? Here I take
                        // the Gauss points of the subtriangles.
                        IGaussPointExtrapolation2D    extrapolation = ExtrapolationGaussTriangular3Points.UniqueInstance;
                        IIsoparametricInterpolation2D interpolation = InterpolationTri3.UniqueInstance;

                        // Find the Gauss points of the triangle in the natural system of the element
                        IInverseInterpolation2D inverseMapping = element.Interpolation.CreateInverseMappingFor(element.Nodes);
                        var triangleNodesNatural = new NaturalPoint[numTriangleNodes];
                        for (int p = 0; p < numTriangleNodes; ++p)
                        {
                            triangleNodesNatural[p] = inverseMapping.TransformPointCartesianToNatural(cellPoints[p]);
                        }
                        NaturalPoint[] triangleGPsNatural =
                            FindTriangleGPsNatural(triangleNodesNatural, extrapolation.Quadrature.IntegrationPoints);

                        // Find the field values at the Gauss points of the triangle (their coordinates are in the natural
                        // system of the element)
                        var displacementsAtGPs = new double[triangleGPsNatural.Length][];
                        var strainsAtGPs       = new Tensor2D[triangleGPsNatural.Length];
                        var stressesAtGPs      = new Tensor2D[triangleGPsNatural.Length];
                        for (int gp = 0; gp < triangleGPsNatural.Length; ++gp)
                        {
                            EvalInterpolation2D evalInterpol =
                                element.Interpolation.EvaluateAllAt(element.Nodes, triangleGPsNatural[gp]);
                            displacementsAtGPs[gp] = element.CalculateDisplacementField(triangleGPsNatural[gp],
                                                                                        evalInterpol, standardDisplacements, enrichedDisplacements).CopyToArray();
                            (Tensor2D strain, Tensor2D stress) = ComputeStrainStress(element, triangleGPsNatural[gp],
                                                                                     evalInterpol, standardDisplacements, enrichedDisplacements);
                            strainsAtGPs[gp]  = strain;
                            stressesAtGPs[gp] = stress;
                        }

                        // Extrapolate the field values to the triangle nodes. We need their coordinates in the auxiliary
                        // system of the triangle. We could use the inverse interpolation of the triangle to map the natural
                        // (element local) coordinates of the nodes to the auxiliary system of the triangle. Fortunately they
                        // can be accessed by the extrapolation object directly.
                        IReadOnlyList <double[]> displacementsAtTriangleNodes =
                            extrapolation.ExtrapolateVectorFromGaussPointsToNodes(displacementsAtGPs, interpolation);
                        IReadOnlyList <Tensor2D> strainsAtTriangleNodes =
                            extrapolation.ExtrapolateTensorFromGaussPointsToNodes(strainsAtGPs, interpolation);
                        IReadOnlyList <Tensor2D> stressesAtTriangleNodes =
                            extrapolation.ExtrapolateTensorFromGaussPointsToNodes(stressesAtGPs, interpolation);
                        for (int p = 0; p < numTriangleNodes; ++p)
                        {
                            displacements.Add(displacementsAtTriangleNodes[p]);
                            strains.Add(strainsAtTriangleNodes[p]);
                            stresses.Add(stressesAtTriangleNodes[p]);
                        }
                    }
                }
            }

            using (var writer = new VtkFileWriter($"{pathNoExtension}_{step}.vtk"))
            {
                writer.WriteMesh(allPoints, allCells);
                writer.WriteVector2DField("displacement", displacements);
                writer.WriteTensor2DField("strain", strains);
                writer.WriteTensor2DField("stress", stresses);
            }
        }