Esempio n. 1
0
        public AuxiliaryStatesTensors ComputeTensorsAt(CartesianPoint globalIntegrationPoint,
                                                       TipCoordinateSystem tipCoordinateSystem)
        {
            // Common calculations
            PolarPoint2D polarCoordinates =
                tipCoordinateSystem.TransformPointGlobalCartesianToLocalPolar(globalIntegrationPoint);
            var commonValues = new CommonValues(polarCoordinates.R, polarCoordinates.Theta);

            // Displacement field derivatives
            Matrix2by2   displacementGradientMode1, displacementGradientMode2;
            TipJacobians polarJacobians = tipCoordinateSystem.CalculateJacobiansAt(polarCoordinates);

            ComputeDisplacementDerivatives(polarJacobians, commonValues,
                                           out displacementGradientMode1, out displacementGradientMode2);

            // Strains
            Tensor2D strainTensorMode1 = ComputeStrainTensor(displacementGradientMode1);
            Tensor2D strainTensorMode2 = ComputeStrainTensor(displacementGradientMode2);

            // Stresses
            Tensor2D stressTensorMode1, stressTensorMode2;

            ComputeStressTensors(commonValues, out stressTensorMode1, out stressTensorMode2);

            return(new AuxiliaryStatesTensors(displacementGradientMode1, displacementGradientMode2,
                                              strainTensorMode1, strainTensorMode2, stressTensorMode1, stressTensorMode2));
        }
Esempio n. 2
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;
            }
        }
        /// <summary>
        /// See <see cref="IGaussPointExtrapolation2D.ExtrapolateTensorFromGaussPointsToNodes(
        /// IReadOnlyList{Tensor2D}, IIsoparametricInterpolation2D)"/>
        /// </summary>
        public IReadOnlyList <Tensor2D> ExtrapolateTensorFromGaussPointsToNodes(IReadOnlyList <Tensor2D> tensorsAtGaussPoints,
                                                                                IIsoparametricInterpolation2D interpolation)
        {
            var nodalTensors = new Tensor2D[interpolation.NumFunctions];

            for (int i = 0; i < nodalTensors.Length; ++i)
            {
                nodalTensors[i] = tensorsAtGaussPoints[0];
            }
            return(nodalTensors);
        }
Esempio n. 4
0
 public AuxiliaryStatesTensors(Matrix2by2 displacementGradientMode1, Matrix2by2 displacementGradientMode2,
                               Tensor2D strainTensorMode1, Tensor2D strainTensorMode2,
                               Tensor2D stressTensorMode1, Tensor2D stressTensorMode2)
 {
     this.DisplacementGradientMode1 = displacementGradientMode1;
     this.DisplacementGradientMode2 = displacementGradientMode2;
     this.StrainTensorMode1         = strainTensorMode1;
     this.StrainTensorMode2         = strainTensorMode2;
     this.StressTensorMode1         = stressTensorMode1;
     this.StressTensorMode2         = stressTensorMode2;
 }
Esempio n. 5
0
        private IReadOnlyList <Tensor2D> ComputeSmoothedNodalTensors(Vector solution, bool extrapolateFromGPs,
                                                                     IOutputField field)
        {
            var tensorsFromAllElements = new Dictionary <XNode, List <Tensor2D> >();

            foreach (var node in model.Nodes)
            {
                tensorsFromAllElements[node] = new List <Tensor2D>();
            }
            Vector constrainedDisplacements = model.CalculateConstrainedDisplacements(dofOrderer);

            foreach (var element in model.Elements)
            {
                IReadOnlyList <Tensor2D> elementTensors;
                if (extrapolateFromGPs)
                {
                    elementTensors =
                        ElementNodalTensorsExtrapolation(element, solution, constrainedDisplacements, field);
                }
                else
                {
                    elementTensors = ElementNodalTensorsDirectly(element, solution, constrainedDisplacements, field);
                }

                for (int nodeIdx = 0; nodeIdx < element.Nodes.Count; ++nodeIdx)
                {
                    tensorsFromAllElements[element.Nodes[nodeIdx]].Add(elementTensors[nodeIdx]);
                }
            }

            // Average with equal weights for all elements. TODO: perhaps vary the weights depending on the element type/area
            var nodalTensors = new Tensor2D[model.Nodes.Count];

            for (int i = 0; i < model.Nodes.Count; ++i)
            {
                XNode  node = model.Nodes[i];
                double tensorXX = 0.0, tensorYY = 0.0, tensorXY = 0.0;
                foreach (var tensor in tensorsFromAllElements[node])
                {
                    tensorXX += tensor.XX;
                    tensorYY += tensor.YY;
                    tensorXY += tensor.XY;
                }
                int contributingElementsCount = tensorsFromAllElements[node].Count;
                tensorXX       /= contributingElementsCount;
                tensorYY       /= contributingElementsCount;
                tensorXY       /= contributingElementsCount;
                nodalTensors[i] = new Tensor2D(tensorXX, tensorYY, tensorXY);
            }

            return(nodalTensors);
        }
Esempio n. 6
0
        private static double ComputeJIntegrand(Vector2 weightGrad, Matrix2by2 displGrad1, Tensor2D stress1,
                                                Matrix2by2 displGrad2, Tensor2D strain2, Tensor2D stress2)
        {
            // Unrolled to greatly reduce mistakes. Alternatively Einstein notation products could be implementated
            // in Tensor2D (like the tensor-tensor multiplication is), but still some parts would have to be unrolled.
            // Perhaps vector (and scalar) gradients should also be accessed by component and derivative variable.

            double strainEnergy = stress1.MultiplyColon(strain2);
            double parenthesis0 = stress1.XX * displGrad2[0, 0] + stress1.XY * displGrad2[1, 0]
                                  + stress2.XX * displGrad1[0, 0] + stress2.XY * displGrad1[1, 0] - strainEnergy;
            double parenthesis1 = stress1.XY * displGrad2[0, 0] + stress1.YY * displGrad2[1, 0]
                                  + stress2.XY * displGrad1[0, 0] + stress2.YY * displGrad1[1, 0];

            return(parenthesis0 * weightGrad[0] + parenthesis1 * weightGrad[1]);
        }
Esempio n. 7
0
        private static void ComputeStressTensors(CommonValues val,
                                                 out Tensor2D stressTensorMode1, out Tensor2D stressTensorMode2)
        {
            double coeff = 1.0 / (Math.Sqrt(2.0 * Math.PI) * val.sqrtR);

            double sxxMode1 = coeff * val.cosThetaOver2 * (1.0 - val.sinThetaOver2 * val.sin3ThetaOver2);
            double syyMode1 = coeff * val.cosThetaOver2 * (1.0 + val.sinThetaOver2 * val.sin3ThetaOver2);
            double sxyMode1 = coeff * val.sinThetaOver2 * val.cosThetaOver2 * val.cos3ThetaOver2;

            double sxxMode2 = -coeff * val.sinThetaOver2 * (2.0 + val.cosThetaOver2 * val.cos3ThetaOver2);
            double syyMode2 = sxyMode1;
            double sxyMode2 = sxxMode1;

            stressTensorMode1 = new Tensor2D(sxxMode1, syyMode1, sxyMode1);
            stressTensorMode2 = new Tensor2D(sxxMode2, syyMode2, sxyMode2);
        }
Esempio n. 8
0
        //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));
        }
Esempio n. 9
0
        // 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);
        }
Esempio n. 10
0
        public IReadOnlyList <Tensor2D> ComputeSmoothedNodalStresses(Vector solution)
        {
            var stressesFromAllElements = new Dictionary <XNode, List <Tensor2D> >();

            foreach (var node in model.Nodes)
            {
                stressesFromAllElements[node] = new List <Tensor2D>();
            }
            Vector constrainedDisplacements = model.CalculateConstrainedDisplacements(dofOrderer);

            foreach (var element in model.Elements)
            {
                IReadOnlyDictionary <XNode, Tensor2D> elementStresses =
                    ComputeNodalStressesOfElement(element, solution, constrainedDisplacements);
                foreach (var nodeStressPair in elementStresses)
                {
                    stressesFromAllElements[nodeStressPair.Key].Add(nodeStressPair.Value);
                }
            }

            // Average with equal weights for all elements. TODO: perhaps vary the weights depending on the element type/area
            var nodalStresses = new Tensor2D[model.Nodes.Count];

            for (int i = 0; i < model.Nodes.Count; ++i)
            {
                XNode  node = model.Nodes[i];
                double stressXX = 0.0, stressYY = 0.0, stressXY = 0.0;
                foreach (var tensor in stressesFromAllElements[node])
                {
                    stressXX += tensor.XX;
                    stressYY += tensor.YY;
                    stressXY += tensor.XY;
                }
                int contributingElementsCount = stressesFromAllElements[node].Count;
                stressXX        /= contributingElementsCount;
                stressYY        /= contributingElementsCount;
                stressXY        /= contributingElementsCount;
                nodalStresses[i] = new Tensor2D(stressXX, stressYY, stressXY);
            }

            return(nodalStresses);
        }
        /// <summary>
        /// See <see cref="IGaussPointExtrapolation2D.ExtrapolateTensorFromGaussPointsToNodes(
        /// IReadOnlyList{Tensor2D}, IIsoparametricInterpolation2D)"/>
        /// </summary>
        public IReadOnlyList <Tensor2D> ExtrapolateTensorFromGaussPointsToNodes(IReadOnlyList <Tensor2D> tensorsAtGaussPoints,
                                                                                IIsoparametricInterpolation2D interpolation)
        {
            double[][] nodalExtrapolationFunctions = EvaluateExtrapolationFunctionsAtNodes(interpolation);
            IReadOnlyList <NaturalPoint> nodes     = interpolation.NodalNaturalCoordinates;
            var nodalTensors = new Tensor2D[nodes.Count];

            for (int i = 0; i < nodes.Count; ++i)
            {
                //nodalTensors[i] = ExtrapolateVectorFromGaussPoints(tensorsAtGaussPoints, nodes[i]); // for debugging
                var tensor = new double[3];
                for (int gp = 0; gp < Quadrature.IntegrationPoints.Count; ++gp)
                {
                    tensor[0] += nodalExtrapolationFunctions[i][gp] * tensorsAtGaussPoints[gp].XX;
                    tensor[1] += nodalExtrapolationFunctions[i][gp] * tensorsAtGaussPoints[gp].YY;
                    tensor[2] += nodalExtrapolationFunctions[i][gp] * tensorsAtGaussPoints[gp].XY;
                }
                nodalTensors[i] = new Tensor2D(tensor[0], tensor[1], tensor[2]);
            }
            return(nodalTensors);
        }
Esempio n. 12
0
        public void WriteTensor2DField(string fieldName,
                                       IReadOnlyDictionary <ICell <TNode>, IReadOnlyList <Tensor2D> > tensorsAtElementNodes)
        {
            var nodalTensors = new Tensor2D[mesh.VtkPoints.Count];

            for (int e = 0; e < mesh.VtkCells.Count; ++e)
            {
                VtkCell cell = mesh.VtkCells[e];
                IReadOnlyList <Tensor2D> valuesAtCellVertices = tensorsAtElementNodes[mesh.OriginalElements[e]];
                for (int i = 0; i < cell.Vertices.Count; ++i)
                {
                    nodalTensors[cell.Vertices[i].ID] = valuesAtCellVertices[i];
                }
            }

            WriteFieldsHeader(nodalTensors.Length);
            writer.WriteLine(String.Format("TENSORS {0} double", fieldName));
            for (int i = 0; i < mesh.VtkPoints.Count; ++i)
            {
                writer.WriteLine(String.Format("{0} {1} {2} 0.0 0.0 0.0 0.0 0.0 0.0",
                                               nodalTensors[i].XX, nodalTensors[i].YY, nodalTensors[i].XY));
            }
            writer.WriteLine();
        }
Esempio n. 13
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);
            }
        }
 public Tensor2D TransformTensorGlobalCartesianToLocalCartesian(Tensor2D tensor)
 {
     return(tensor.Rotate(RotationAngle));
 }