private static Tensor2D ComputeStrainTensor(Matrix2by2 displacementGradient) { double exx = displacementGradient[0, 0]; double eyy = displacementGradient[1, 1]; double exy = 0.5 * (displacementGradient[0, 1] + displacementGradient[1, 0]); return(new Tensor2D(exx, eyy, exy)); }
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 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; }
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)); }
private void ComputeDisplacementDerivatives(TipJacobians polarJacobians, CommonValues val, out Matrix2by2 displacementGradientMode1, out Matrix2by2 displacementGradientMode2) { // Temporary values and derivatives of the differentiated quantities. See documentation for their derivation. double E = material.HomogeneousYoungModulus; double v = material.HomogeneousPoissonRatio; double vEq = material.HomogeneousEquivalentPoissonRatio; double k = (3.0 - vEq) / (1.0 + vEq); double a = (1.0 + v) / (E * Math.Sqrt(2.0 * Math.PI)); double b = val.sqrtR; double b_r = 0.5 / val.sqrtR; // Mode 1 { // Temporary values that differ between the 2 modes double c1 = val.cosThetaOver2 * (k - val.cosTheta); double c2 = val.sinThetaOver2 * (k - val.cosTheta); double c1_theta = -0.5 * c2 + val.cosThetaOver2 * val.sinTheta; double c2_theta = 0.5 * c1 + val.sinThetaOver2 * val.sinTheta; // The vector field derivatives w.r.t. to the local polar coordinates. // The vector components refer to the local cartesian system though. var polarGradient = Matrix2by2.CreateFromArray( new double[, ] { { a *b_r *c1, a *b *c1_theta }, { a *b_r *c2, a *b *c2_theta } }); // The vector field derivatives w.r.t. to the local cartesian coordinates. displacementGradientMode1 = polarJacobians.TransformVectorFieldDerivativesLocalPolarToLocalCartesian(polarGradient); } // Mode 2 { double paren1 = 2.0 + k + val.cosTheta; double paren2 = 2.0 - k - val.cosTheta; double c1 = val.sinThetaOver2 * paren1; double c2 = val.cosThetaOver2 * paren2; double c1_theta = 0.5 * val.cosThetaOver2 * paren1 - val.sinThetaOver2 * val.sinTheta; double c2_theta = -0.5 * val.sinThetaOver2 * paren2 + val.cosThetaOver2 * val.sinTheta; // The vector field derivatives w.r.t. to the local polar coordinates. // The vector components refer to the local cartesian system though. var polarGradient = Matrix2by2.CreateFromArray( new double[, ] { { a *b_r *c1, a *b *c1_theta }, { a *b_r *c2, a *b *c2_theta } }); // The vector field derivatives w.r.t. to the local cartesian coordinates. displacementGradientMode2 = polarJacobians.TransformVectorFieldDerivativesLocalPolarToLocalCartesian(polarGradient); } }
/// <summary> /// /// </summary> /// <param name="tipCoordinates">Coordinates of the crack tip in the global cartesian system.</param> /// <param name="tipRotationAngle">Counter-clockwise angle from the O-x axis of the global cartesian system to /// the T-x1 axis of the local corrdinate system of the tip (T being the tip point)</param> public TipCoordinateSystem(CartesianPoint tipCoordinates, double tipRotationAngle) { this.RotationAngle = tipRotationAngle; double cosa = Math.Cos(tipRotationAngle); double sina = Math.Sin(tipRotationAngle); RotationMatrixGlobalToLocal = Matrix2by2.CreateFromArray(new double[, ] { { cosa, sina }, { -sina, cosa } }); TransposeRotationMatrixGlobalToLocal = RotationMatrixGlobalToLocal.Transpose(); localCoordinatesOfGlobalOrigin = -1 * (RotationMatrixGlobalToLocal * Vector2.Create(tipCoordinates.X, tipCoordinates.Y)); DeterminantOfJacobianGlobalToLocalCartesian = 1.0; // det = (cosa)^2 +(sina)^2 = 1 }
public TipJacobians(TipCoordinateSystem tipSystem, PolarPoint2D polarCoordinates) { this.tipSystem = tipSystem; double r = polarCoordinates.R; double cosTheta = Math.Cos(polarCoordinates.Theta); double sinTheta = Math.Sin(polarCoordinates.Theta); inverseJacobianPolarToLocal = Matrix2by2.CreateFromArray(new double[, ] { { cosTheta, sinTheta }, { -sinTheta / r, cosTheta / r } }); inverseJacobianPolarToGlobal = inverseJacobianPolarToLocal * tipSystem.RotationMatrixGlobalToLocal; }
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]); }
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)); }
// 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); }
/// <summary> /// Attention: The input vector field is differentiated w.r.t. the polar cartesian system coordinates. /// The output vector field is differentiated w.r.t. the local cartesian system coordinates. However the /// representations of both vector fields (aka the coordinates of the vectors) are in the local cartesian /// coordinate system. /// </summary> /// <param name="gradient">A 2x2 matrix, for which: Row i is the gradient of the ith component of the vector /// field, thus: gradient = [Fr,r Fr,theta; Ftheta,r Ftheta,theta], /// where Fi,j is the derivative of component i w.r.t. coordinate j</param> /// <returns></returns> public Matrix2by2 TransformVectorFieldDerivativesLocalPolarToLocalCartesian(Matrix2by2 gradient) { return(gradient * inverseJacobianPolarToLocal); }
/// <summary> /// /// </summary> /// <param name="gradient">A 2x2 matrix, for which: Row i is the gradient of the ith component of the vector /// field, thus: gradient = [Fx,x Fx,y; Fy,x Fy,y], /// where Fi,j is the derivative of component i w.r.t. coordinate j</param> /// <returns></returns> public Matrix2by2 TransformVectorFieldDerivativesGlobalCartesianToLocalCartesian(Matrix2by2 gradient) { return(RotationMatrixGlobalToLocal * (gradient * TransposeRotationMatrixGlobalToLocal)); }