private static void CalculateNeumannLoad2D(Element element, NeumannBoundaryCondition neumann, Dictionary <int, double> neumannLoad, Nurbs2D nurbs, int j, double jacdet, IList <GaussLegendrePoint3D> gaussPoints, double xGaussPoint, double yGaussPoint, double zGaussPoint, Vector surfaceBasisVector3) { var elementControlPoints = element.ControlPoints.ToArray(); for (int k = 0; k < elementControlPoints.Length; k++) { int dofIDX = element.Model.GlobalDofOrdering.GlobalFreeDofs[elementControlPoints[k], StructuralDof.TranslationX]; int dofIDY = element.Model.GlobalDofOrdering.GlobalFreeDofs[elementControlPoints[k], StructuralDof.TranslationY]; int dofIDZ = element.Model.GlobalDofOrdering.GlobalFreeDofs[elementControlPoints[k], StructuralDof.TranslationZ]; if (neumannLoad.ContainsKey(dofIDX)) { neumannLoad[dofIDX] += nurbs.NurbsValues[k, j] * jacdet * gaussPoints[j].WeightFactor * neumann.Value(xGaussPoint, yGaussPoint, zGaussPoint)[0] * surfaceBasisVector3[0]; } else { neumannLoad.Add( dofIDX, nurbs.NurbsValues[k, j] * jacdet * gaussPoints[j].WeightFactor * neumann.Value(xGaussPoint, yGaussPoint, zGaussPoint)[0] * surfaceBasisVector3[0]); } if (neumannLoad.ContainsKey(dofIDY)) { neumannLoad[dofIDY] += nurbs.NurbsValues[k, j] * jacdet * gaussPoints[j].WeightFactor * neumann.Value(xGaussPoint, yGaussPoint, zGaussPoint)[1] * surfaceBasisVector3[1]; } else { neumannLoad.Add( dofIDY, nurbs.NurbsValues[k, j] * jacdet * gaussPoints[j].WeightFactor * neumann.Value(xGaussPoint, yGaussPoint, zGaussPoint)[1] * surfaceBasisVector3[1]); } if (neumannLoad.ContainsKey(dofIDZ)) { neumannLoad[dofIDZ] += nurbs.NurbsValues[k, j] * jacdet * gaussPoints[j].WeightFactor * neumann.Value(xGaussPoint, yGaussPoint, zGaussPoint)[2] * surfaceBasisVector3[2]; } else { neumannLoad.Add(dofIDZ, nurbs.NurbsValues[k, j] * jacdet * gaussPoints[j].WeightFactor * neumann.Value(xGaussPoint, yGaussPoint, zGaussPoint)[2] * surfaceBasisVector3[2]); } } }
private void CalculateNeumann(LoadProvider provider, NeumannBoundaryCondition condition, Dictionary <int, double> load) { foreach (var element in ElementsDictionary.Values) { var loadNeumann = provider.LoadNeumann(element, this, condition); foreach (int dof in loadNeumann.Keys) { if (load.ContainsKey(dof)) { load[dof] += loadNeumann[dof]; } else { load.Add(dof, loadNeumann[dof]); } } } }
/// <summary> /// This method cannot be used, combined with <see cref="NurbsElement3D"/> as it refers to two-dimensional loads. /// </summary> /// <param name="element">An <see cref="Element"/> of type <see cref="NurbsElement3D"/>.</param> /// <param name="face">The <see cref="Face"/> that the <see cref="NeumannBoundaryCondition"/> was applied to.</param> /// <param name="neumann">The <see cref="NeumannBoundaryCondition"/>.</param> /// <returns>A <see cref="Dictionary{TKey,TValue}"/> whose keys are the numbering of the degree of freedom and values are the magnitude of the load due to the <see cref="NeumannBoundaryCondition"/>.</returns> public Dictionary <int, double> CalculateLoadingCondition(Element element, Face face, NeumannBoundaryCondition neumann) => throw new NotSupportedException();
/// <summary> /// This method cannot be used, combined with <see cref="TSplineKirchhoffLoveShellElementMaterial"/> as it refers to one-dimensional loads. /// </summary> /// <param name="element">An element of type <see cref="TSplineKirchhoffLoveShellElementMaterial"/>.</param> /// <param name="edge">An one dimensional boundary entity. For more info see <see cref="Edge"/>.</param> /// <param name="neumann"><inheritdoc cref="NeumannBoundaryCondition"/></param> /// <returns>A <see cref="Dictionary{TKey,TValue}"/> where integer values denote the degree of freedom that has a value double load value due to the enforcement of the <see cref="NeumannBoundaryCondition"/>.</returns> public Dictionary <int, double> CalculateLoadingCondition(Element element, Edge edge, NeumannBoundaryCondition neumann) => throw new NotImplementedException();
/// <summary> /// This method calculates the Neumann boundary condition when applied to a two-dimensional NURBS element. /// </summary> /// <param name="element">An element of type <see cref="NurbsElement2D"/></param> /// <param name="face">An two dimensional boundary entity. For more info see <see cref="Face"/>.</param> /// <param name="neumann"><inheritdoc cref="NeumannBoundaryCondition"/>.</param> /// <returns>A <see cref="Dictionary{TKey,TValue}"/> where integer values denote the degree of freedom that has a value double load value due to the enforcement of the <see cref="NeumannBoundaryCondition"/>.</returns> public Dictionary <int, double> CalculateLoadingCondition(Element element, Face face, NeumannBoundaryCondition neumann) { Contract.Requires(element != null, "The element cannot be null"); Contract.Requires(face != null, "The face cannot be null"); Contract.Requires(neumann != null, "The Neumann Boundary condition cannot be null"); IList <GaussLegendrePoint3D> gaussPoints = CreateElementGaussPoints(element, face.Degrees[0], face.Degrees[1]); Dictionary <int, double> neumannLoad = new Dictionary <int, double>(); var elementControlPoints = element.ControlPoints.ToArray(); Nurbs2D nurbs = new Nurbs2D(element, elementControlPoints, face); for (int j = 0; j < gaussPoints.Count; j++) { var jacobianMatrix = JacobianMatrixForLoadCalculation(element, nurbs, j, out var xGaussPoint, out var yGaussPoint, out var zGaussPoint); 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); double jacdet = jacobianMatrix[0, 0] * jacobianMatrix[1, 1] - jacobianMatrix[1, 0] * jacobianMatrix[0, 1]; CalculateNeumannLoad2D(element, neumann, neumannLoad, nurbs, j, jacdet, gaussPoints, xGaussPoint, yGaussPoint, zGaussPoint, surfaceBasisVector3); } return(neumannLoad); }
private static void CalculatePressure1D( Element element, Edge edge, NeumannBoundaryCondition neumann, IList <ControlPoint> controlPoints, IList <GaussLegendrePoint3D> gaussPoints, IDictionary <int, double> neumannLoad) { var nurbs = new Nurbs1D(element, controlPoints, edge); for (int j = 0; j < gaussPoints.Count; j++) { double xGaussPoint = 0; double yGaussPoint = 0; double zGaussPoint = 0; double jacobian1 = 0.0; double jacobian2 = 0.0; var elementControlPoints = element.ControlPointsDictionary.Values.ToArray(); for (int k = 0; k < elementControlPoints.Length; k++) { xGaussPoint += nurbs.NurbsValues[k, j] * elementControlPoints[k].X; yGaussPoint += nurbs.NurbsValues[k, j] * elementControlPoints[k].Y; zGaussPoint += nurbs.NurbsValues[k, j] * elementControlPoints[k].Z; jacobian1 += nurbs.NurbsDerivativeValuesKsi[k, j] * elementControlPoints[k].X; jacobian2 += nurbs.NurbsDerivativeValuesKsi[k, j] * elementControlPoints[k].Y; } double jacdet = Math.Sqrt(Math.Pow(jacobian1, 2) + Math.Pow(jacobian2, 2)); var loadGaussPoint = neumann.Value(xGaussPoint, yGaussPoint, zGaussPoint); for (int k = 0; k < element.ControlPointsDictionary.Count; k++) { if (element.Model.GlobalDofOrdering.GlobalFreeDofs.Contains(elementControlPoints[k], StructuralDof.TranslationX)) { int dofIDX = element.Model.GlobalDofOrdering.GlobalFreeDofs[elementControlPoints[k], StructuralDof.TranslationX]; if (neumannLoad.ContainsKey(dofIDX)) { neumannLoad[dofIDX] += jacdet * gaussPoints[j].WeightFactor * nurbs.NurbsValues[k, j] * loadGaussPoint[0]; } else { neumannLoad.Add( dofIDX, jacdet * gaussPoints[j].WeightFactor * nurbs.NurbsValues[k, j] * loadGaussPoint[0]); } } if (!element.Model.GlobalDofOrdering.GlobalFreeDofs.Contains( elementControlPoints[k], StructuralDof.TranslationY)) { continue; } var dofIDY = element.Model.GlobalDofOrdering.GlobalFreeDofs[ elementControlPoints[k], StructuralDof.TranslationY]; if (neumannLoad.ContainsKey(dofIDY)) { neumannLoad[dofIDY] += jacdet * gaussPoints[j].WeightFactor * nurbs.NurbsValues[k, j] * loadGaussPoint[1]; } else { neumannLoad.Add(dofIDY, jacdet * gaussPoints[j].WeightFactor * nurbs.NurbsValues[k, j] * loadGaussPoint[1]); } } } }
/// <summary> /// This method calculates the Neumann boundary condition when applied to a one dimensional NURBS element. /// </summary> /// <param name="element">An element of type <see cref="NurbsElement1D"/>.</param> /// <param name="edge">An one dimensional boundary entity. For more info see <see cref="Edge"/>.</param> /// <param name="neumann"><inheritdoc cref="NeumannBoundaryCondition"/></param> /// <returns>A <see cref="Dictionary{TKey,TValue}"/> where integer values denote the degree of freedom that has a value double load value due to the enforcement of the <see cref="NeumannBoundaryCondition"/>.</returns> public Dictionary <int, double> CalculateLoadingCondition(Element element, Edge edge, NeumannBoundaryCondition neumann) { IList <GaussLegendrePoint3D> gaussPoints = CreateElementGaussPoints(element); Dictionary <int, double> neumannLoad = new Dictionary <int, double>(); IList <ControlPoint> controlPoints = new List <ControlPoint>(); CalculateEdgeControlPoints(element, edge, controlPoints); CalculatePressure1D(element, edge, neumann, controlPoints, gaussPoints, neumannLoad); return(neumannLoad); }
/// <summary> /// Solve the PDE backwards from the end. /// Each step t, solve Ax=b, where A is constructed from pu, pm, and pd, and b is calculated from t+dt /// </summary> public double[][] Solve(double[] t, double[] xGrid, double[] x, Func <double, double> payOff) { var value = new double[t.Length][]; for (var i = 0; i < t.Length; ++i) { value[i] = new double[x.Length]; } for (var j = 0; j < x.Length; ++j) { value[t.Length - 1][j] = payOff(x[j]); } var boundaryConditions = new NeumannBoundaryCondition[2]; boundaryConditions[0] = new NeumannBoundaryCondition(Boundary.Upper, payOff(x[x.Length - 1]) - payOff(x[x.Length - 2])); boundaryConditions[1] = new NeumannBoundaryCondition(Boundary.Lower, payOff(x[1]) - payOff(x[0])); var dt = t[1] - t[0]; var dx = xGrid[1] - xGrid[0]; var nu = _alpha(0.0, 0.0, dt); var beta = _beta(0.0, 0.0); var rf = _r(0.0); var pu = -nu * dt / (4 * dx) - beta * dt / (2 * dx * dx); var pd = nu * dt / (4 * dx) - beta * dt / (2 * dx * dx); var pm = 1 + rf * dt / 2 + beta * dt / (dx * dx); var steps = t.Length; var gridPoints = xGrid.Length; var diagonal = new List <double>(); var upperDiagonal = new List <double>(); var lowerDiagonal = new List <double>(); diagonal.Add(1); upperDiagonal.Add(-1); lowerDiagonal.Add(0); for (var i = 1; i < gridPoints - 1; ++i) { lowerDiagonal.Add(pd); diagonal.Add(pm); upperDiagonal.Add(pu); } diagonal.Add(-1); lowerDiagonal.Add(1); upperDiagonal.Add(0); var aTridiagonal = new TridiagonalMatrix(gridPoints, diagonal.ToArray(), upperDiagonal.ToArray(), lowerDiagonal.ToArray()); var b = new double[gridPoints]; for (var i = steps - 2; i >= 0; --i) { for (var j = 1; j < gridPoints - 1; ++j) { b[j] = -pu * value[i + 1][j + 1] - pd * value[i + 1][j - 1] - (pm - 2) * value[i + 1][j]; } Array.ForEach(boundaryConditions, boundary => { b = boundary.Apply(b); }); var solution = aTridiagonal.SolveFor(b); for (var k = 0; k < solution.Length; ++k) { value[i][k] = Math.Max(solution[k], payOff(x[k])); } } return(value); }