public SurfaceLoadElement(ISurfaceLoad surfaceLoad, IIsoparametricInterpolation2D isoparametricInterpolation2D, IQuadrature2D quadrature2D, IReadOnlyList <Node> nodes) { this.surfaceLoad = surfaceLoad; this.isoparametricInterpolation2D = isoparametricInterpolation2D; this.quadrature2D = quadrature2D; this.nodes = nodes; }
/// <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); }
/// <summary> /// See <see cref="IGaussPointExtrapolation2D.ExtrapolateScalarFromGaussPointsToNodes( /// IReadOnlyList{double}, IIsoparametricInterpolation2D)"/> /// </summary> public IReadOnlyList <double> ExtrapolateScalarFromGaussPointsToNodes(IReadOnlyList <double> scalarsAtGaussPoints, IIsoparametricInterpolation2D interpolation) { var nodalScalars = new double[interpolation.NumFunctions]; for (int i = 0; i < nodalScalars.Length; ++i) { nodalScalars[i] = scalarsAtGaussPoints[0]; } return(nodalScalars); }
private static void TestPartitionOfUnity(IIsoparametricInterpolation2D interpolation) { double tolerance = 1e-10; NaturalPoint[] points = pointGenerators[interpolation](); for (int p = 0; p < points.Length; ++p) { double[] shapeFuncs = interpolation.EvaluateFunctionsAt(points[p]); double sum = 0.0; for (int f = 0; f < interpolation.NumFunctions; ++f) { sum += shapeFuncs[f]; } Assert.True(Utilities.AreValuesEqual(1.0, sum, tolerance)); } }
private double[][] EvaluateExtrapolationFunctionsAtNodes(IIsoparametricInterpolation2D interpolation) { bool isCached = cachedExtrapolationFunctionsAtNodes.TryGetValue(interpolation, out double[][] nodalExtrapolationFunctions); if (!isCached) { IReadOnlyList <NaturalPoint> nodes = interpolation.NodalNaturalCoordinates; nodalExtrapolationFunctions = new double[nodes.Count][]; for (int i = 0; i < nodes.Count; ++i) { nodalExtrapolationFunctions[i] = EvaluateExtrapolationFunctionsAt(nodes[i]); } cachedExtrapolationFunctionsAtNodes.Add(interpolation, nodalExtrapolationFunctions); } return(nodalExtrapolationFunctions); }
/// <summary> /// See <see cref="IGaussPointExtrapolation2D.ExtrapolateScalarFromGaussPointsToNodes( /// IReadOnlyList{double}, IIsoparametricInterpolation2D)"/> /// </summary> public IReadOnlyList <double> ExtrapolateScalarFromGaussPointsToNodes(IReadOnlyList <double> scalarsAtGaussPoints, IIsoparametricInterpolation2D interpolation) { double[][] nodalExtrapolationFunctions = EvaluateExtrapolationFunctionsAtNodes(interpolation); IReadOnlyList <NaturalPoint> nodes = interpolation.NodalNaturalCoordinates; var nodalScalars = new double[nodes.Count]; for (int i = 0; i < nodes.Count; ++i) { //nodalScalars[i] = ExtrapolateScalarFromGaussPoints(scalarsAtGaussPoints, nodes[i]); // for debugging double scalar = 0; for (int gp = 0; gp < Quadrature.IntegrationPoints.Count; ++gp) { scalar += nodalExtrapolationFunctions[i][gp] * scalarsAtGaussPoints[gp]; } nodalScalars[i] = scalar; } return(nodalScalars); }
public ContinuumElement2D(double thickness, IReadOnlyList <Node> nodes, IIsoparametricInterpolation2D interpolation, IQuadrature2D quadratureForStiffness, IQuadrature2D quadratureForConsistentMass, IGaussPointExtrapolation2D gaussPointExtrapolation, IReadOnlyList <ElasticMaterial2D> materialsAtGaussPoints, DynamicMaterial dynamicProperties) { this.dynamicProperties = dynamicProperties; this.materialsAtGaussPoints = materialsAtGaussPoints; this.GaussPointExtrapolation = gaussPointExtrapolation; this.Nodes = nodes; this.Interpolation = interpolation; this.QuadratureForConsistentMass = quadratureForConsistentMass; this.QuadratureForStiffness = quadratureForStiffness; this.Thickness = thickness; dofTypes = new IDofType[nodes.Count][]; for (int i = 0; i < nodes.Count; ++i) { dofTypes[i] = new IDofType[] { StructuralDof.TranslationX, StructuralDof.TranslationY }; } }
private static void TestValuesAtNodes(IIsoparametricInterpolation2D interpolation) { double tolerance = 1e-10; for (int n = 0; n < interpolation.NodalNaturalCoordinates.Count; ++n) { double[] shapeFuncs = interpolation.EvaluateFunctionsAt(interpolation.NodalNaturalCoordinates[n]); for (int f = 0; f < interpolation.NumFunctions; ++f) { if (f == n) { Assert.True(Utilities.AreValuesEqual(1.0, shapeFuncs[f], tolerance)); } else { Assert.True(Utilities.AreValuesEqual(0.0, shapeFuncs[f], tolerance)); } } } }
//private readonly Dictionary<GaussPoint, ThermalMaterial> materialsAtGaussPoints; public ThermalElement2D(double thickness, IReadOnlyList <Node> nodes, IIsoparametricInterpolation2D interpolation, IQuadrature2D quadratureForStiffness, IQuadrature2D quadratureForConsistentMass, IGaussPointExtrapolation2D gaussPointExtrapolation, ThermalMaterial material) { this.material = material; this.GaussPointExtrapolation = gaussPointExtrapolation; this.Nodes = nodes; this.Interpolation = interpolation; this.QuadratureForConsistentMass = quadratureForConsistentMass; this.QuadratureForStiffness = quadratureForStiffness; this.Thickness = thickness; dofTypes = new IDofType[nodes.Count][]; for (int i = 0; i < interpolation.NumFunctions; ++i) { dofTypes[i] = new IDofType[] { ThermalDof.Temperature } } ; }
/// <summary> /// See <see cref="IGaussPointExtrapolation2D.ExtrapolateVectorFromGaussPointsToNodes( /// IReadOnlyList{double[]}, IIsoparametricInterpolation2D)"/> /// </summary> public IReadOnlyList <double[]> ExtrapolateVectorFromGaussPointsToNodes(IReadOnlyList <double[]> vectorsAtGaussPoints, IIsoparametricInterpolation2D interpolation) { double[][] nodalExtrapolationFunctions = EvaluateExtrapolationFunctionsAtNodes(interpolation); IReadOnlyList <NaturalPoint> nodes = interpolation.NodalNaturalCoordinates; var nodalVectors = new double[nodes.Count][]; for (int i = 0; i < nodes.Count; ++i) { //nodalVectors[i] = ExtrapolateVectorFromGaussPoints(tensorsAtGaussPoints, nodes[i]); // for debugging var vector = new double[2]; for (int gp = 0; gp < Quadrature.IntegrationPoints.Count; ++gp) { vector[0] += nodalExtrapolationFunctions[i][gp] * vectorsAtGaussPoints[gp][0]; vector[1] += nodalExtrapolationFunctions[i][gp] * vectorsAtGaussPoints[gp][1]; } nodalVectors[i] = vector; } return(nodalVectors); }
public Table <INode, IDofType, double> CalculateSurfaceLoad(IIsoparametricInterpolation2D interpolation, IQuadrature2D integration, IReadOnlyList <Node> nodes) { int numDofs = nodes.Count; var stiffness = Vector.CreateZero(numDofs); IReadOnlyList <double[]> shapeFunctions = interpolation.EvaluateFunctionsAtGaussPoints(integration); IReadOnlyList <Matrix> shapeGradientsNatural = interpolation.EvaluateNaturalGradientsAtGaussPoints(integration); for (int gp = 0; gp < integration.IntegrationPoints.Count; ++gp) { Vector shapeFunctionVector = Vector.CreateFromArray(shapeFunctions[gp]); Matrix jacobianMatrix = Matrix.CreateZero(2, 3); for (int k = 0; k < nodes.Count; k++) { jacobianMatrix[0, 0] += shapeGradientsNatural[gp][k, 0] * nodes[k].X; jacobianMatrix[0, 1] += shapeGradientsNatural[gp][k, 0] * nodes[k].Y; jacobianMatrix[0, 2] += shapeGradientsNatural[gp][k, 0] * nodes[k].Z; jacobianMatrix[1, 0] += shapeGradientsNatural[gp][k, 1] * nodes[k].X; jacobianMatrix[1, 1] += shapeGradientsNatural[gp][k, 1] * nodes[k].Y; jacobianMatrix[1, 2] += shapeGradientsNatural[gp][k, 1] * nodes[k].Z; } Vector tangentVector1 = jacobianMatrix.GetRow(0); Vector tangentVector2 = jacobianMatrix.GetRow(1); Vector normalVector = tangentVector1.CrossProduct(tangentVector2); var jacdet = normalVector.Norm2(); double dA = jacdet * integration.IntegrationPoints[gp].Weight; stiffness.AxpyIntoThis(shapeFunctionVector, dA); } var appliedDisplacements = Vector.CreateWithValue(nodes.Count, _flux); var fluxLoad = stiffness.DoEntrywise(appliedDisplacements, (stiffi, appi) => stiffi * appi); var table = new Table <INode, IDofType, double>(); for (int i = 0; i < nodes.Count; i++) { table.TryAdd(nodes[i], ThermalDof.Temperature, fluxLoad[i]); } return(table); }
/// <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); }
private readonly IDofType[][] standardDofTypes; //TODO: this should not be stored for each element. Instead store it once for each Quad4, Tri3, etc. Otherwise create it on the fly. public XContinuumElement2D(int id, IReadOnlyList <XNode> nodes, IIsoparametricInterpolation2D interpolation, IGaussPointExtrapolation2D gaussPointExtrapolation, IQuadrature2D standardQuadrature, IIntegrationStrategy2D <XContinuumElement2D> integrationStrategy, IIntegrationStrategy2D <XContinuumElement2D> jIntegralStrategy, IMaterialField2D material) { this.id = id; this.Nodes = nodes; this.Interpolation = interpolation; this.GaussPointExtrapolation = gaussPointExtrapolation; this.StandardQuadrature = standardQuadrature; this.IntegrationStrategy = integrationStrategy; this.JintegralStrategy = jIntegralStrategy; this.Material = material; this.NumStandardDofs = 2 * nodes.Count; standardDofTypes = new IDofType[nodes.Count][]; for (int i = 0; i < nodes.Count; ++i) { standardDofTypes[i] = new IDofType[] { StructuralDof.TranslationX, StructuralDof.TranslationY }; } //OBSOLETE: Elements access their enrichments from nodes now. //this.EnrichmentItems = new List<IEnrichmentItem2D>(); }
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 Table <INode, IDofType, double> CalculateSurfaceLoad(IIsoparametricInterpolation2D interpolation, IQuadrature2D integration, IReadOnlyList <Node> nodes) { //nodes[0].ElementsDictionary.Values.ToList<> int numDofs = nodes.Count; double kappaCoef; if (numDofs == 4) { kappaCoef = 100; } else { kappaCoef = 1; } var stiffness = Matrix.CreateZero(numDofs, numDofs); IReadOnlyList <double[]> shapeFunctions = interpolation.EvaluateFunctionsAtGaussPoints(integration); IReadOnlyList <Matrix> shapeGradientsNatural = interpolation.EvaluateNaturalGradientsAtGaussPoints(integration); double[] dist = new double[nodes.Count]; List <INode> neighborNodes = new List <INode>(); for (int i = 0; i < nodes.Count; i++) { neighborNodes.Clear(); foreach (var element in nodes[i].ElementsDictionary.Values) { neighborNodes.AddRange(element.Nodes); } neighborNodes = neighborNodes.Distinct().ToList(); neighborNodes.Remove(nodes[i]); var minDist = neighborNodes.Select(x => Math.Sqrt( Math.Pow(nodes[i].X - x.X, 2) + Math.Pow(nodes[i].Y - x.Y, 2) + Math.Pow(nodes[i].Z - x.Z, 2))).Min(); dist[i] = minDist; } //double kappa = kappaCoef * _diffusionCoeff / dist.Min(); //double[] kappa = new double[nodes.Count]; for (int gp = 0; gp < integration.IntegrationPoints.Count; ++gp) { //var jacobian = new IsoparametricJacobian3D(Nodes, shapeGradientsNatural[gp]); var shapeFunctionMatrix = Vector.CreateFromArray(shapeFunctions[gp]); Matrix jacobianMatrix = Matrix.CreateZero(2, 3); for (int k = 0; k < nodes.Count; k++) { //xGaussPoint += shapeFunctionMatrix[gp, k] * this.Nodes[k].X; //yGaussPoint += shapeFunctionMatrix[gp, k] * this.Nodes[k].Y; //zGaussPoint += shapeFunctionMatrix[gp, k] * this.Nodes[k].Z; jacobianMatrix[0, 0] += shapeGradientsNatural[gp][k, 0] * nodes[k].X; jacobianMatrix[0, 1] += shapeGradientsNatural[gp][k, 0] * nodes[k].Y; jacobianMatrix[0, 2] += shapeGradientsNatural[gp][k, 0] * nodes[k].Z; jacobianMatrix[1, 0] += shapeGradientsNatural[gp][k, 1] * nodes[k].X; jacobianMatrix[1, 1] += shapeGradientsNatural[gp][k, 1] * nodes[k].Y; jacobianMatrix[1, 2] += shapeGradientsNatural[gp][k, 1] * nodes[k].Z; //kappa[k] = _diffusionCoeff / .05 / dist[k]; } Vector tangentVector1 = jacobianMatrix.GetRow(0); Vector tangentVector2 = jacobianMatrix.GetRow(1); Vector normalVector = tangentVector1.CrossProduct(tangentVector2); var jacdet = normalVector.Norm2(); normalVector.ScaleIntoThis(1 / jacdet); Matrix jacobianMatrixLeftInverse = jacobianMatrix.Transpose() * (jacobianMatrix * jacobianMatrix.Transpose()).Invert(); Matrix shapeGradientsCartesian = (shapeGradientsNatural[gp]) * jacobianMatrixLeftInverse.Transpose(); Matrix deformation = shapeGradientsCartesian.Transpose(); Vector deformationNormal = normalVector * deformation; //Vector deformationX = deformation.GetRow(0); //Vector deformationY = deformation.GetRow(1); //Vector deformationZ = deformation.GetRow(2); //Matrix partial = kappa * shapeFunctionMatrix.TensorProduct(shapeFunctionMatrix) // -_diffusionCoeff * deformationNormal.TensorProduct(shapeFunctionMatrix); double kappa = _diffusionCoeff / .05; Matrix partial = kappa * shapeFunctionMatrix.TensorProduct(shapeFunctionMatrix); //Vector surfaceBasisVector1 = Vector.CreateZero(3); //surfaceBasisVector1[0] = jacobianMatrix[0, 0]; //surfaceBasisVector1[1] = jacobianMatrix[0, 1]; //surfaceBasisVector1[2] = jacobianMatrix[0, 2]; //Vector surfaceBasisVector2 = Vector.CreateZero(3); //surfaceBasisVector2[0] = jacobianMatrix[1, 0]; //surfaceBasisVector2[1] = jacobianMatrix[1, 1]; //surfaceBasisVector2[2] = jacobianMatrix[1, 2]; //Vector surfaceBasisVector3 = surfaceBasisVector1.CrossProduct(surfaceBasisVector2); //var jacdet = surfaceBasisVector3.Norm2(); double dA = jacdet * integration.IntegrationPoints[gp].Weight; stiffness.AxpyIntoThis(partial, dA); } //var appliedDisplacements=Vector.CreateWithValue(nodes.Count, _magnitude); var appliedDisplacements = _distribution(nodes); var weakDirichletForces = stiffness * appliedDisplacements; var table = new Table <INode, IDofType, double>(); for (int i = 0; i < nodes.Count; i++) { table.TryAdd(nodes[i], ThermalDof.Temperature, weakDirichletForces[i]); } return(table); }
public Table <INode, IDofType, double> CalculateSurfaceLoad(IIsoparametricInterpolation2D interpolation, IQuadrature2D integration, IReadOnlyList <Node> nodes) { var loadTable = new Table <INode, IDofType, double>(); IReadOnlyList <Matrix> shapeGradientsNatural = interpolation.EvaluateNaturalGradientsAtGaussPoints(integration); IReadOnlyList <double[]> shapeFunctionNatural = interpolation.EvaluateFunctionsAtGaussPoints(integration); for (int gp = 0; gp < integration.IntegrationPoints.Count; gp++) { var jacobianMatrix = Matrix.CreateZero(2, 3); for (int indexNode = 0; indexNode < nodes.Count; indexNode++) { jacobianMatrix[0, 0] += shapeGradientsNatural[gp][indexNode, 0] * nodes[indexNode].X; jacobianMatrix[0, 1] += shapeGradientsNatural[gp][indexNode, 0] * nodes[indexNode].Y; jacobianMatrix[0, 2] += shapeGradientsNatural[gp][indexNode, 0] * nodes[indexNode].Z; jacobianMatrix[1, 0] += shapeGradientsNatural[gp][indexNode, 1] * nodes[indexNode].X; jacobianMatrix[1, 1] += shapeGradientsNatural[gp][indexNode, 1] * nodes[indexNode].Y; jacobianMatrix[1, 2] += shapeGradientsNatural[gp][indexNode, 1] * nodes[indexNode].Z; } var tangentVector1 = jacobianMatrix.GetRow(0); var tangentVector2 = jacobianMatrix.GetRow(1); var normalVector = tangentVector1.CrossProduct(tangentVector2); Vector surfaceBasisVector1 = Vector.CreateZero(3); surfaceBasisVector1[0] = jacobianMatrix[0, 0]; surfaceBasisVector1[1] = jacobianMatrix[0, 1]; surfaceBasisVector1[2] = jacobianMatrix[0, 2]; Vector surfaceBasisVector2 = Vector.CreateZero(3); surfaceBasisVector2[0] = jacobianMatrix[1, 0]; surfaceBasisVector2[1] = jacobianMatrix[1, 1]; surfaceBasisVector2[2] = jacobianMatrix[1, 2]; Vector surfaceBasisVector3 = surfaceBasisVector1.CrossProduct(surfaceBasisVector2); var jacdet = surfaceBasisVector3.Norm2(); var weightFactor = integration.IntegrationPoints[gp].Weight; for (int indexNode = 0; indexNode < nodes.Count; indexNode++) { var node = nodes[indexNode]; var valueX = _loadX * shapeFunctionNatural[gp][indexNode] * jacdet * weightFactor; var valueY = _loadY * shapeFunctionNatural[gp][indexNode] * jacdet * weightFactor; var valueZ = _loadZ * shapeFunctionNatural[gp][indexNode] * jacdet * weightFactor; if (loadTable.Contains(node, StructuralDof.TranslationX)) { loadTable[node, StructuralDof.TranslationX] += valueX; } else { loadTable.TryAdd(node, StructuralDof.TranslationX, valueX); } if (loadTable.Contains(node, StructuralDof.TranslationY)) { loadTable[node, StructuralDof.TranslationY] += valueY; } else { loadTable.TryAdd(node, StructuralDof.TranslationY, valueY); } if (loadTable.Contains(node, StructuralDof.TranslationZ)) { loadTable[node, StructuralDof.TranslationZ] += valueZ; } else { loadTable.TryAdd(node, StructuralDof.TranslationZ, valueZ); } } } return(loadTable); }