public void WriteMesh() { if (writeFieldsNext) { throw new InvalidOperationException("A mesh has already been written."); } // Nodes writer.WriteLine("DATASET UNSTRUCTURED_GRID"); writer.WriteLine(String.Format("POINTS {0} double", mesh.VtkPoints.Count)); for (int i = 0; i < mesh.VtkPoints.Count; ++i) // Their indices in Model.Nodes are equal to their IDs { VtkPoint point = mesh.VtkPoints[i]; writer.Write(String.Format("{0} {1} 0.0\n", point.X, point.Y)); } // Element connectivity int elementDataCount = 0; foreach (VtkCell cell in mesh.VtkCells) { elementDataCount += 1 + cell.Vertices.Count; } writer.WriteLine(String.Format("\nCELLS {0} {1}", mesh.VtkCells.Count, elementDataCount)); foreach (VtkCell cell in mesh.VtkCells) { writer.Write(cell.Vertices.Count); foreach (VtkPoint point in cell.Vertices) { writer.Write(' '); writer.Write(point.ID); } writer.WriteLine(); } // Element types writer.WriteLine("\nCELL_TYPES " + mesh.VtkCells.Count); foreach (VtkCell cell in mesh.VtkCells) { writer.WriteLine(cell.Code); } }
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); } }