/// <summary> /// Affine-linear flux function on a border edge; Boundary conditions /// are implemented here. An affine-linear flux must implemented as a /// matrix and an offset vector: The linear border flux, in a /// mathematical notation is defined as BorderFlux(U) = /// M_in*U + b, where U is a column vector containing function values /// of other fields. Which fields in which order is specified by /// <see cref="IEquationComponent.ArgumentOrdering" /> property. In /// this implementation, the resulting flux solely depends on the /// implementation of <see cref="INonlinearFlux.BorderEdgeFlux"/> that /// has been supplied to the constructor. /// </summary> /// <param name="inp"> /// A set of input parameters such as time, coordinate and values of /// parameters. Given as reference for performance reasons; DO NOT /// WRITE to this structure.</param> /// <param name="Uin"></param> protected override double BorderEdgeFlux(ref CommonParamsBnd inp, double[] Uin) { MultidimensionalArray refFlux = MultidimensionalArray.Create(1, 1); baseFlux.BorderEdgeFlux( 0.0, inp.iEdge, MultidimensionalArray.CreateWrapper(inp.X, 1, 1, inp.D), MultidimensionalArray.CreateWrapper(inp.Normal, 1, inp.D), false, new byte[] { inp.EdgeTag }, 0, inp.Parameters_IN.Select(p => MultidimensionalArray.CreateWrapper(new double[] { p }, 1, 1)).ToArray(), 0, 1, refFlux); double[] FunctionMatrix = new double[inp.Parameters_IN.Length]; for (int i = 0; i < inp.Parameters_IN.Length; i++) { double[] perturbedParameters = inp.Parameters_IN.CloneAs(); double stepSize = GetStepSize(perturbedParameters[i]); perturbedParameters[i] += stepSize; MultidimensionalArray perturbedFlux = MultidimensionalArray.Create(1, 1); baseFlux.BorderEdgeFlux( 0.0, inp.iEdge, MultidimensionalArray.CreateWrapper(inp.X, 1, 1, inp.D), MultidimensionalArray.CreateWrapper(inp.Normal, 1, inp.D), false, new byte[] { inp.EdgeTag }, 0, perturbedParameters.Select(p => MultidimensionalArray.CreateWrapper(new double[] { p }, 1, 1)).ToArray(), 0, 1, perturbedFlux); FunctionMatrix[i] = (perturbedFlux[0, 0] - refFlux[0, 0]) / stepSize; } double result = refFlux[0, 0]; for (int i = 0; i < inp.Parameters_IN.Length; i++) { result += FunctionMatrix[i] * (Uin[i] - inp.Parameters_IN[i]); } return(result); }
/// <summary> /// <see cref="INonlinearFlux.BorderEdgeFlux"/> /// </summary> public void BorderEdgeFlux(double time, Vector2D x, Vector2D n, double[] FunctionMatrix, out double AffineOffset) { Array.Clear(m_Arguments, 0, m_Arguments.Length); AffineOffset = 0.0; AffineOffset = m_Flux.BorderEdgeFlux(time, x, n, m_Arguments); for (int i = m_Arguments.Length - 1; i >= 0; i--) { m_Arguments[i] = 1; FunctionMatrix[i] = m_Flux.BorderEdgeFlux(time, x, n, m_Arguments); FunctionMatrix[i] -= AffineOffset; m_Arguments[i] = 0; } if ((!_Flux)) { Array.Clear(FunctionMatrix, 0, FunctionMatrix.Length); AffineOffset = 0.0; } }
/// <summary> /// Evaluates the integrand by applying <see cref="flux"/>. /// </summary> protected override void Evaluate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { NodeSet QuadNodes = QR.Nodes; int D = gridData.SpatialDimension; int noOfFields = evaluators.Length; int NoOfNodes = QuadNodes.NoOfNodes; MultidimensionalArray fluxValues = MultidimensionalArray.Create(Length, NoOfNodes); MultidimensionalArray[] fieldValues = new MultidimensionalArray[evaluators.Length]; for (int i = 0; i < evaluators.Length; i++) { fieldValues[i] = MultidimensionalArray.Create(Length, NoOfNodes); } MultidimensionalArray globalCoordinates = MultidimensionalArray.Create(Length, NoOfNodes, D); int noOfNodes = QR.NoOfNodes; //MultidimensionalArray normals = MultidimensionalArray.Create(Length, noOfNodes, D); //gridData.Edges.GetNormals(i0, Length, m_NodeSetFamily[0].NodeSet, normals); var Normals = gridData.iGeomEdges.NormalsCache.GetNormals_Edge(QR.Nodes, i0, Length); // Loop over edges for (int i = 0; i < Length; i++) { int cell = gridData.iGeomEdges.CellIndices[i + i0, 0]; int edge = gridData.iGeomEdges.FaceIndices[i + i0, 0]; int iTrf = gridData.iGeomEdges.Edge2CellTrafoIndex[i + i0, 0]; NodeSet CellNodes = QR.Nodes.GetVolumeNodeSet(base.GridDat, iTrf); // Evaluate all fields for (int j = 0; j < noOfFields; j++) { evaluators[j].Evaluate(cell, 1, CellNodes, fieldValues[j], i, 0.0); } // Compute global coordinates gridData.TransformLocal2Global(CellNodes, cell, 1, globalCoordinates, i); // Evaluate integrand flux.BorderEdgeFlux( 0.0, i0 + i, globalCoordinates, Normals, false, gridData.iGeomEdges.EdgeTags, i0 + i, fieldValues, i, 1, fluxValues); // Save results for (int j = 0; j < NoOfNodes; j++) { EvalResult[i, j, 0] = fluxValues[i, j]; } } }