public Matrix CalculateConstitutiveMatrixAt(NaturalPoint point, EvalInterpolation2D interpolation) { double eqE, eqV; if (IsMaterial1(point, interpolation)) { eqE = EquivalentYoungModulus1; eqV = EquivalentPoissonRatio1; } else { eqE = EquivalentYoungModulus2; eqV = EquivalentPoissonRatio2; } double scalar = eqE / (1 - eqV * eqV); var matrix = Matrix.CreateZero(3, 3); matrix[0, 0] = scalar; matrix[0, 1] = scalar * eqV; matrix[1, 0] = scalar * eqV; matrix[1, 1] = scalar; matrix[2, 2] = 0.5 * eqE / (1 + eqV); return(matrix); }
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) }); }
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; } }
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) }); }
/// <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)); }
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)); }
public Matrix CalculateConstitutiveMatrixAt(NaturalPoint point, EvalInterpolation2D interpolation) { var matrix = Matrix.CreateZero(3, 3); double eqE = HomogeneousEquivalentYoungModulus; double eqV = HomogeneousEquivalentPoissonRatio; double scalar = eqE / (1 - eqV * eqV); matrix[0, 0] = scalar; matrix[0, 1] = scalar * eqV; matrix[1, 0] = scalar * eqV; matrix[1, 1] = scalar; matrix[2, 2] = 0.5 * eqE / (1 + eqV); return(matrix); }
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); }
private (Tensor2D strain, Tensor2D stress) ComputeStrainStress(XContinuumElement2D element, NaturalPoint gaussPoint, EvalInterpolation2D evaluatedInterpolation, Vector standardNodalDisplacements, Vector enrichedNodalDisplacements) { Matrix constitutive = element.Material.CalculateConstitutiveMatrixAt(gaussPoint, evaluatedInterpolation); Matrix2by2 displacementGradient = element.CalculateDisplacementFieldGradient(gaussPoint, evaluatedInterpolation, standardNodalDisplacements, enrichedNodalDisplacements); double strainXX = displacementGradient[0, 0]; double strainYY = displacementGradient[1, 1]; double strainXYtimes2 = displacementGradient[0, 1] + displacementGradient[1, 0]; double stressXX = constitutive[0, 0] * strainXX + constitutive[0, 1] * strainYY; double stressYY = constitutive[1, 0] * strainXX + constitutive[1, 1] * strainYY; double stressXY = constitutive[2, 2] * strainXYtimes2; return(new Tensor2D(strainXX, strainYY, 0.5 * strainXYtimes2), new Tensor2D(stressXX, stressYY, stressXY)); }
} // Do nothing for elastic properties. private bool IsMaterial1(NaturalPoint point, EvalInterpolation2D interpolation) { //TODO: This should be done with the natural points and LSM. CartesianPoint cartesianPoint = interpolation.TransformPointNaturalToGlobalCartesian(); MaterialInterface2D.Subdomain subdomain = bimaterialInterface.LocatePoint(cartesianPoint); if (subdomain == MaterialInterface2D.Subdomain.Positive) { return(true); } else if (subdomain == MaterialInterface2D.Subdomain.Negative) { return(false); } else { throw new ArgumentException("The point (xi, eta) = " + point + " - (x, y) = " + cartesianPoint + ", lies on the bi-material interface"); } }
// 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); }
public Tuple <double, double> SignedDistanceGradientThrough(NaturalPoint point, IReadOnlyList <XNode> elementNodes, EvalInterpolation2D interpolation) { double gradientX = 0.0; double gradientY = 0.0; for (int nodeIdx = 0; nodeIdx < elementNodes.Count; ++nodeIdx) { double dNdx = interpolation.ShapeGradientsCartesian[nodeIdx, 0]; double dNdy = interpolation.ShapeGradientsCartesian[nodeIdx, 1]; double levelSet = levelSetsBody[elementNodes[nodeIdx]]; gradientX += dNdx * levelSet; gradientY += dNdy * levelSet; } return(new Tuple <double, double>(gradientX, gradientY)); }
// TODO: I should really cache these somehow, so that they can be accessible from the crack object. They are used at various points. private (double positiveArea, double negativeArea) FindSignedAreasOfElement(ISingleCrack crack, XContinuumElement2D element) { SortedSet <CartesianPoint> triangleVertices = crack.FindTriangleVertices(element); IReadOnlyList <Triangle2D <CartesianPoint> > triangles = triangulator.CreateMesh(triangleVertices); double positiveArea = 0.0; double 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 body level set != 0 int sign = 0; foreach (var vertex in triangle.Vertices) { XNode vertexAsNode = null; foreach (var node in element.Nodes) // TODO: find a faster way to do this { if ((vertex.X == node.X) && (vertex.Y == node.Y)) { vertexAsNode = node; break; } } if (vertexAsNode != null) { double distance = crack.SignedDistanceOf(vertexAsNode); if (Math.Abs(distance) <= zeroDistanceTolerance) { sign = 0; } else { sign = Math.Sign(distance); } if (sign != 0) { break; } } } // If no node with non-zero body level set is found, then find the body level set of its centroid if (sign == 0) { // Report this instance in DEBUG messages. It should not happen with linear level sets and only 1 crack. //if (reports) //{ // Console.WriteLine("--- DEBUG: Triangulation resulted in a triangle where no vertex is an element node. ---"); //} var centroid = new CartesianPoint((v0.X + v1.X + v2.X) / 3.0, (v0.Y + v1.Y + v2.Y) / 3.0); NaturalPoint centroidNatural = element.Interpolation. CreateInverseMappingFor(element.Nodes).TransformPointCartesianToNatural(centroid); EvalInterpolation2D centroidInterpolation = element.Interpolation.EvaluateAllAt(element.Nodes, centroidNatural); sign = Math.Sign(crack.SignedDistanceOf(centroidNatural, element, centroidInterpolation)); } 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"); } } return(positiveArea, negativeArea); }
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 double GetThicknessAt(NaturalPoint point, EvalInterpolation2D interpolation) => HomogeneousThickness;
public double GetThicknessAt(NaturalPoint point, EvalInterpolation2D interpolation) => IsMaterial1(point, interpolation) ? Thickness1 : Thickness2;
public double GetEquivalentPoissonRatioAt(NaturalPoint point, EvalInterpolation2D interpolation) => IsMaterial1(point, interpolation) ? EquivalentPoissonRatio1 : EquivalentPoissonRatio2;
private void FindSignedAreasOfElement(XContinuumElement2D element, out double positiveArea, out double negativeArea) { SortedSet <CartesianPoint> triangleVertices = FindTriangleVertices(element); IReadOnlyList <Triangle2D <CartesianPoint> > triangles = triangulator.CreateMesh(triangleVertices); 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 body level set != 0 int sign = 0; foreach (var vertex in triangle.Vertices) { if (vertex is XNode) { sign = Math.Sign(levelSetsBody[(XNode)vertex]); if (sign != 0) { break; } } } // If no node with non-zero body level set is found, then find the body level set of its centroid if (sign == 0) { // Report this instance in DEBUG messages. It should not happen with linear level sets and only 1 crack. if (reports) { Console.WriteLine("--- DEBUG: Triangulation resulted in a triangle where no vertex is an element node. ---"); } var centroid = new CartesianPoint((v0.X + v1.X + v2.X) / 3.0, (v0.Y + v1.Y + v2.Y) / 3.0); NaturalPoint centroidNatural = element.Interpolation. CreateInverseMappingFor(element.Nodes).TransformPointCartesianToNatural(centroid); EvalInterpolation2D centroidInterpolation = element.Interpolation.EvaluateAllAt(element.Nodes, centroidNatural); sign = Math.Sign(SignedDistanceOf(centroidNatural, element, centroidInterpolation)); } 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"); } } }
public abstract EvaluatedFunction2D[] EvaluateAllAt(NaturalPoint point, XContinuumElement2D element, EvalInterpolation2D interpolation);
public double GetEquivalentPoissonRatioAt(NaturalPoint point, EvalInterpolation2D interpolation) => HomogeneousEquivalentPoissonRatio;
public double SignedDistanceOf(NaturalPoint point, XContinuumElement2D element, EvalInterpolation2D interpolation) { return(SignedDistanceOfPoint(interpolation.TransformPointNaturalToGlobalCartesian())); }
public double GetEquivalentYoungModulusAt(NaturalPoint point, EvalInterpolation2D interpolation) => IsMaterial1(point, interpolation) ? EquivalentYoungModulus1 : EquivalentYoungModulus2;
public double GetEquivalentYoungModulusAt(NaturalPoint point, EvalInterpolation2D interpolation) => HomogeneousEquivalentYoungModulus;