public Matrix BuildLumpedMassMatrix() { int numDofs = 2 * Nodes.Count; var lumpedMass = Matrix.CreateZero(numDofs, numDofs); IReadOnlyList <Matrix> shapeGradientsNatural = Interpolation.EvaluateNaturalGradientsAtGaussPoints(QuadratureForConsistentMass); // Contribution of each Gauss point to the element's area //TODO: Perhaps I could calculate the volume of the element without going through each Gauss point. Probably the // nodes are needed instead of the GPs. For linear elements I can find the area geometrically (as polygons). //TODO: this should have been cached when integrating other quantities (e.g. stiffness) double area = 0; for (int gp = 0; gp < QuadratureForConsistentMass.IntegrationPoints.Count; ++gp) { var jacobian = new IsoparametricJacobian2D(Nodes, shapeGradientsNatural[gp]); area += jacobian.DirectDeterminant * QuadratureForConsistentMass.IntegrationPoints[gp].Weight; } // Divide the total mass uniformly for each node double nodalMass = Thickness * area * dynamicProperties.Density / Nodes.Count; for (int i = 0; i < numDofs; ++i) { lumpedMass[i, i] = nodalMass; } return(lumpedMass); }
public Matrix BuildDiffusionConductivityMatrix() { int numDofs = Nodes.Count; var conductivity = Matrix.CreateZero(numDofs, numDofs); IReadOnlyList <Matrix> shapeGradientsNatural = Interpolation.EvaluateNaturalGradientsAtGaussPoints(QuadratureForStiffness); for (int gp = 0; gp < QuadratureForStiffness.IntegrationPoints.Count; ++gp) { // Calculate the necessary quantities for the integration //Matrix constitutive = (Matrix)(materialsAtGaussPoints[gp].ConstitutiveMatrix); // ugly cast will be removed along with the legacy Matrix classes var jacobian = new IsoparametricJacobian2D(Nodes, shapeGradientsNatural[gp]); Matrix shapeGradientsCartesian = jacobian.TransformNaturalDerivativesToCartesian(shapeGradientsNatural[gp]); Matrix deformation = BuildDeformationMatrix(shapeGradientsCartesian); // Contribution of this gauss point to the element stiffness matrix Matrix partialK = deformation.Transpose() * deformation; //Matrix partialΚ = deformation.Transpose() * (constitutive * deformation); //partialK.Scale(materialsAtGaussPoints[gaussPoint].ThermalConductivity); double dA = jacobian.DirectDeterminant * QuadratureForStiffness.IntegrationPoints[gp].Weight; //TODO: this is used by all methods that integrate. I should cache it. conductivity.AxpyIntoThis(partialK, dA * material.ThermalConductivity); } conductivity.ScaleIntoThis(Thickness); return(conductivity); }
public Matrix BuildStabilizingConductivityMatrix() { int numDofs = Nodes.Count; var convection = Matrix.CreateZero(numDofs, numDofs); IReadOnlyList <double[]> shapeFunctions = Interpolation.EvaluateFunctionsAtGaussPoints(QuadratureForConsistentMass); IReadOnlyList <Matrix> shapeGradientsNatural = Interpolation.EvaluateNaturalGradientsAtGaussPoints(QuadratureForConsistentMass); for (int gp = 0; gp < QuadratureForConsistentMass.IntegrationPoints.Count; ++gp) { Vector shapeFunctionMatrix = BuildShapeFunctionMatrix(shapeFunctions[gp]); var jacobian = new IsoparametricJacobian2D(Nodes, shapeGradientsNatural[gp]); Matrix shapeGradientsCartesian = jacobian.TransformNaturalDerivativesToCartesian(shapeGradientsNatural[gp]); Matrix deformation = BuildDeformationMatrix(shapeGradientsCartesian); Vector deformationX = deformation.GetRow(0); Vector deformationY = deformation.GetRow(1); //Matrix partial = shapeFunctionMatrix.TensorProduct(shapeFunctionMatrix); Matrix partial = deformationX.TensorProduct(deformationY); double dA = jacobian.DirectDeterminant * QuadratureForConsistentMass.IntegrationPoints[gp].Weight; convection.AxpyIntoThis(partial, dA); } //WARNING: the following needs to change for non uniform density. Perhaps the integration order too. convection.ScaleIntoThis(-Math.Pow(material.ThermalConvection, 2)); return(convection); }
public double CalculateArea() { //TODO: Linear elements can use the more efficient rules for volume of polygons. Therefore this method should be // delegated to the interpolation. //TODO: A different integration rule should be used for integrating constant functions. For linear elements there // is only 1 Gauss point (most probably), therefore the computational cost could be the same as using the // polygonal formulas. double area = 0.0; IReadOnlyList <Matrix> shapeGradientsNatural = Interpolation.EvaluateNaturalGradientsAtGaussPoints(QuadratureForStiffness); for (int gp = 0; gp < QuadratureForStiffness.IntegrationPoints.Count; ++gp) { var jacobian = new IsoparametricJacobian2D(Nodes, shapeGradientsNatural[gp]); area += jacobian.DirectDeterminant * QuadratureForStiffness.IntegrationPoints[gp].Weight; //TODO: this is used by all methods that integrate. I should cache it. } return(area); }
public EvalInterpolation2D(IReadOnlyList <Node> elementNodes, double[] shapeFunctions, Matrix shapeGradientsNatural, IsoparametricJacobian2D jacobian) { int numNodes = elementNodes.Count; #if DEBUG if ((shapeFunctions.Length != numNodes) || (shapeGradientsNatural.NumRows != numNodes)) { throw new ArgumentException($"There are {numNodes} nodes, but {ShapeFunctions.Length} shape functions" + $" and {shapeGradientsNatural.NumRows} natural shape derivatives."); } #endif this.elementNodes = elementNodes; this.ShapeFunctions = shapeFunctions; this.ShapeGradientsNatural = shapeGradientsNatural; this.Jacobian = jacobian; this.ShapeGradientsCartesian = jacobian.TransformNaturalDerivativesToCartesian(shapeGradientsNatural); }
public Matrix BuildCapacityMatrix() { int numDofs = Nodes.Count; var capacity = Matrix.CreateZero(numDofs, numDofs); IReadOnlyList <double[]> shapeFunctions = Interpolation.EvaluateFunctionsAtGaussPoints(QuadratureForConsistentMass); IReadOnlyList <Matrix> shapeGradientsNatural = Interpolation.EvaluateNaturalGradientsAtGaussPoints(QuadratureForConsistentMass); for (int gp = 0; gp < QuadratureForConsistentMass.IntegrationPoints.Count; ++gp) { Vector shapeFunctionMatrix = BuildShapeFunctionMatrix(shapeFunctions[gp]); Matrix partial = shapeFunctionMatrix.TensorProduct(shapeFunctionMatrix); var jacobian = new IsoparametricJacobian2D(Nodes, shapeGradientsNatural[gp]); double dA = jacobian.DirectDeterminant * QuadratureForConsistentMass.IntegrationPoints[gp].Weight; capacity.AxpyIntoThis(partial, dA); } //WARNING: the following needs to change for non uniform density. Perhaps the integration order too. capacity.ScaleIntoThis(Thickness * material.Density * material.SpecialHeatCoeff); return(capacity); }
/// <summary> /// Calculate strains (exx, eyy, 2exy) and stresses (sxx, syy, sxy) at integration points, store them in the materials /// and return them (e.g. for postprocessing). The order of the tensors is the same as the order of the integration /// points defined by <see cref="QuadratureForStiffness"/>. /// </summary> /// <param name="localDisplacements"></param> /// <returns></returns> public (IReadOnlyList <double[]> strains, IReadOnlyList <double[]> stresses) UpdateStrainsStressesAtGaussPoints( double[] localDisplacements) { int numGPs = QuadratureForStiffness.IntegrationPoints.Count; var strains = new double[numGPs][]; var stresses = new double[numGPs][]; IReadOnlyList <Matrix> shapeGradientsNatural = Interpolation.EvaluateNaturalGradientsAtGaussPoints(QuadratureForStiffness); for (int gp = 0; gp < numGPs; ++gp) { IMatrixView constitutive = materialsAtGaussPoints[gp].ConstitutiveMatrix; var jacobian = new IsoparametricJacobian2D(Nodes, shapeGradientsNatural[gp]); Matrix shapeGrandientsCartesian = jacobian.TransformNaturalDerivativesToCartesian(shapeGradientsNatural[gp]); Matrix deformation = BuildDeformationMatrix(shapeGrandientsCartesian); strains[gp] = deformation.Multiply(localDisplacements); stresses[gp] = constitutive.Multiply(strains[gp]); } return(strains, stresses); }
public Matrix BuildConsistentMassMatrix() { int numDofs = 2 * Nodes.Count; var mass = Matrix.CreateZero(numDofs, numDofs); IReadOnlyList <double[]> shapeFunctions = Interpolation.EvaluateFunctionsAtGaussPoints(QuadratureForConsistentMass); IReadOnlyList <Matrix> shapeGradientsNatural = Interpolation.EvaluateNaturalGradientsAtGaussPoints(QuadratureForConsistentMass); for (int gp = 0; gp < QuadratureForConsistentMass.IntegrationPoints.Count; ++gp) { Matrix shapeFunctionMatrix = BuildShapeFunctionMatrix(shapeFunctions[gp]); //Matrix partial = shapeFunctionMatrix.Transpose() * shapeFunctionMatrix; Matrix partial = shapeFunctionMatrix.MultiplyRight(shapeFunctionMatrix, true, false); var jacobian = new IsoparametricJacobian2D(Nodes, shapeGradientsNatural[gp]); double dA = jacobian.DirectDeterminant * QuadratureForConsistentMass.IntegrationPoints[gp].Weight; mass.AxpyIntoThis(partial, dA); } //WARNING: the following needs to change for non uniform density. Perhaps the integration order too. mass.ScaleIntoThis(Thickness * dynamicProperties.Density); return(mass); }
public Matrix BuildStiffnessMatrix() { int numDofs = 2 * Nodes.Count; var stiffness = Matrix.CreateZero(numDofs, numDofs); IReadOnlyList <Matrix> shapeGradientsNatural = Interpolation.EvaluateNaturalGradientsAtGaussPoints(QuadratureForStiffness); for (int gp = 0; gp < QuadratureForStiffness.IntegrationPoints.Count; ++gp) { // Calculate the necessary quantities for the integration IMatrixView constitutive = materialsAtGaussPoints[gp].ConstitutiveMatrix; var jacobian = new IsoparametricJacobian2D(Nodes, shapeGradientsNatural[gp]); Matrix shapeGradientsCartesian = jacobian.TransformNaturalDerivativesToCartesian(shapeGradientsNatural[gp]); Matrix deformation = BuildDeformationMatrix(shapeGradientsCartesian); // Contribution of this gauss point to the element stiffness matrix Matrix partial = deformation.ThisTransposeTimesOtherTimesThis(constitutive); double dA = jacobian.DirectDeterminant * QuadratureForStiffness.IntegrationPoints[gp].Weight; //TODO: this is used by all methods that integrate. I should cache it. stiffness.AxpyIntoThis(partial, dA); } stiffness.ScaleIntoThis(Thickness); return(stiffness); }