protected override SayeQuadRule BuildQuadRule(MultidimensionalArray X, double X_weight, int heightDirection, double length) { QuadRule gaussRule_1D = Line.Instance.GetQuadratureRule(order); double[,] nodesArr = new double[gaussRule_1D.NoOfNodes, 2]; for (int i = 0; i < gaussRule_1D.NoOfNodes; ++i) { for (int j = 0; j < 2; ++j) { nodesArr[i, j] = X[0, j]; if (j == heightDirection) { nodesArr[i, j] += length / 2 * gaussRule_1D.Nodes[i, 0]; } } } MultidimensionalArray weights = gaussRule_1D.Weights.CloneAs(); weights.Scale(length / 2); weights.Scale(X_weight); MultidimensionalArray nodes = new MultidimensionalArray(2); nodes.InitializeFrom(nodesArr); SayeQuadRule transformed_GaussRule_1D = new SayeQuadRule(nodes, weights); return(transformed_GaussRule_1D); }
/// <summary> /// Computes the residual of the Eikonal equation. /// </summary> protected override void Evaluate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { NodeSet QuadNodes = QR.Nodes; var gradPhi = m_gradPhi; int D = m_phi.GridDat.SpatialDimension; int NoOfNodes = QuadNodes.NoOfNodes; m_phi.EvaluateGradient(i0, Length, QuadNodes, m_gradPhi); for (int i = 0; i < Length; i++) { for (int n = 0; n < NoOfNodes; n++) { // compute the residual of the Eikonal equation: double acc = 0; for (int d = 0; d < D; d++) { double dPhi_dxd = gradPhi[i, n, d]; acc += dPhi_dxd * dPhi_dxd; } acc = Math.Sqrt(acc); acc -= 1; // L2-Norm of the residual: EvalResult[i, n, 0] = acc * acc; } } }
protected override SayeQuadRule SetGaussQuadratureNodes(SayeSquare arg) { //Aquire needed data //------------------------------------------------------------------------------------------------------------ QuadRule gaussRule_2D = Square.Instance.GetQuadratureRule(order); MultidimensionalArray nodes_GaussRule_2D = ((MultidimensionalArray)gaussRule_2D.Nodes).CloneAs(); MultidimensionalArray weights_GaussRule_2D = gaussRule_2D.Weights.CloneAs(); double[] diameters = arg.Diameters; MultidimensionalArray centerArr = arg.GetCellCenter().ExtractSubArrayShallow(new int[] { 0, -1 }); double jacobian = diameters[0] * diameters[1]; //AffineTransformation of nodes, scale weights //------------------------------------------------------------------------------------------------------------ //Scale Nodes for (int i = 0; i < 2; ++i) { nodes_GaussRule_2D.ColScale(i, diameters[i]); } //Scale Weights weights_GaussRule_2D.Scale(jacobian); //Move Nodes int[] index = new int[] { 0, -1 }; for (int i = 0; i < gaussRule_2D.NoOfNodes; ++i) { index[0] = i; nodes_GaussRule_2D.AccSubArray(1, centerArr, index); } //Set return data //------------------------------------------------------------------------------------------------------------ SayeQuadRule transformed_GaussRule_2D = new SayeQuadRule(nodes_GaussRule_2D, weights_GaussRule_2D); return(transformed_GaussRule_2D); }
/// <summary> /// For each cell \f$ K\f$ in the given /// range and for each \f$ \vec{\Lambda}\f$ /// in <see cref="LevelSetVolumeQuadRuleFactory.lambdaBasis"/>: /// Computes /// \f$ /// \int \limits_{\{\vec{x}; \varphi(\vec{x}) = 0 \} \cap K} \vec{\Lambda} \cdot \vec{n}_I \;ds, /// \f$ /// where \f$ \varphi\f$ is the level set /// function and \f$ \vec{n}_I\f$ denotes the /// unit normal vector on \f$ \varphi\f$ /// </summary> protected override void Evaluate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { NodeSet QuadNodes = QR.Nodes; int D = gridData.SpatialDimension; int NoOfNodes = QuadNodes.NoOfNodes; MultidimensionalArray levelSetNormals = owner.LevelSetData.GetLevelSetReferenceNormals(QuadNodes, i0, Length); MultidimensionalArray metrics = owner.LevelSetData.GetLevelSetNormalReferenceToPhysicalMetrics( QuadNodes, i0, Length); for (int i = 0; i < Length; i++) { MultidimensionalArray lambdaValues = owner.EvaluateLambdas(i0 + i, QuadNodes); for (int j = 0; j < NoOfNodes; j++) { for (int k = 0; k < m_TotalNoOfIntegralsPerItem; k++) { for (int d = 0; d < D; d++) { EvalResult[i, j, k] += lambdaValues[j, k, d] * levelSetNormals[i, j, d]; } EvalResult[i, j, k] *= metrics[i, j]; } } } }
public QuadRule Evaluate(int Cell, T arg) { //Setup algorithm //---------------------------------------------------------------------- cell = Cell; TreeNode <T> recursionTree = new TreeNode <T>(); TreeNode <T> fullSpace = recursionTree.AddChild(arg); //Build Integrand //---------------------------------------------------------------------- SayeRecursion(fullSpace); //Evaluate Integrand //---------------------------------------------------------------------- //Fill nodesAndWeights recursionTree.UnrollFunc(IntegrandEvaluation); //ConvertToQuadRule QuadRule toRuleThemAll = fullSpace.Value.NodesAndWeights.GetQuadRule(); //Handle empty QuadRule if (toRuleThemAll.NoOfNodes == 0) { Debug.WriteLine("Evaluation of cell {0} returned empty Quadrule", cell); toRuleThemAll = CreateZeroQuadrule(); } return(toRuleThemAll); }
/// <summary> /// Constructor /// </summary> /// <param name="lsData"></param> /// <param name="rootFindingAlgorithm"> /// One-dimensional root-finding algorithm for determining roots of the /// level set function on edges of the edges of the volume simplex. /// Default is <see cref="LineSegment.DefaultRootFindingAlgorithm"/> /// </param> /// <param name="jumpType"> /// Determines the level set region to be integrated over (negative /// level set values, positive level set values, or both) /// </param> public LevelSetEdgeVolumeQuadRuleFactory( LevelSetTracker.LevelSetData lsData, LineSegment.IRootFindingAlgorithm rootFindingAlgorithm = null, JumpTypes jumpType = JumpTypes.Heaviside) { if (lsData.GridDat.Cells.RefElements.Length > 1) { throw new NotImplementedException( "Multiple reference elements currently not supported"); } this.LevelSetData = lsData; this.jumpType = jumpType; this.levelSetIndex = lsData.LevelSetIndex; CoFaceQuadRuleFactory = new CutLineOnEdgeQuadRuleFactory(lsData, rootFindingAlgorithm, jumpType); edgeSurfaceRuleFactory = new LevelSetEdgeSurfaceQuadRuleFactory(lsData, CoFaceQuadRuleFactory, jumpType); // Use vertices; Since it is only used on edges that are considered // uncut, they _should_ all have the same sign RefElement simplex = LevelSetData.GridDat.Grid.RefElements[0]; RefElement edgeSimplex = simplex.FaceRefElement; QuadRule signEdgeRule = new QuadRule() { Nodes = edgeSimplex.Vertices, Weights = MultidimensionalArray.Create(edgeSimplex.NoOfVertices) }; signTestRule = new CellBoundaryFromEdgeRuleFactory <CellBoundaryQuadRule>( LevelSetData.GridDat, simplex, new FixedRuleFactory <QuadRule>(signEdgeRule)). GetQuadRuleSet(new CellMask(LevelSetData.GridDat, Chunk.GetSingleElementChunk(0)), -1). First().Rule; }
protected override QuadRule CreateZeroQuadrule() { QuadRule zeroRule = QuadRule.CreateEmpty(RefElement, 1, RefElement.SpatialDimension); zeroRule.Nodes.LockForever(); return(zeroRule); }
protected override void Evaluate(int i0, int Length, QuadRule rule, MultidimensionalArray EvalResult) { NodeSet Nodes = rule.Nodes; int F = m_fields.Length; int D = GridDat.SpatialDimension; for (int f = 0; f < F; f++) { m_fields[f].Evaluate(i0, Length, Nodes, evalRes[f]); } GridDat.TransformLocal2Global(Nodes, i0, Length, X, 0); int NoOfNodes = Nodes.NoOfNodes; double[] _x = new double[D]; double[] args = new double[F]; for (int i = 0; i < Length; i++) { for (int n = 0; n < NoOfNodes; n++) { for (int f = 0; f < F; f++) { args[f] = evalRes[f][i, n]; } for (int d = 0; d < D; d++) { _x[d] = X[i, n, d]; } EvalResult[i, n, 0] = m_f(_x, args, i + i0); } } }
private double SetUpConfiguration() { testCase.UpdateLevelSet(levelSet); levelSetTracker.UpdateTracker(__NearRegionWith: 0, incremental: false, __LevSetAllowedMovement: 2); XDGField.Clear(); XDGField.GetSpeciesShadowField("A").ProjectField( 1.0, testCase.JumpingFieldSpeciesAInitialValue, default(CellQuadratureScheme)); XDGField.GetSpeciesShadowField("B").ProjectField( 1.0, testCase.JumpingFieldSpeciesBInitialValue, default(CellQuadratureScheme)); SinglePhaseField.Clear(); SinglePhaseField.ProjectField(testCase.ContinuousFieldInitialValue); double referenceValue = testCase.Solution; if (testCase is IVolumeTestCase) { QuadRule standardRule = Grid.RefElements[0].GetQuadratureRule(2 * XDGField.Basis.Degree + 1); ScalarFieldQuadrature uncutQuadrature = new ScalarFieldQuadrature( GridData, XDGField, new CellQuadratureScheme( new FixedRuleFactory <QuadRule>(standardRule), levelSetTracker.Regions.GetCutCellSubGrid().Complement().VolumeMask), standardRule.OrderOfPrecision); uncutQuadrature.Execute(); referenceValue -= uncutQuadrature.Result; } return(referenceValue); }
private void WriteVolumeNodes(StreamWriter log, IQuadRuleFactory <QuadRule> ruleFactory, int order, SubGrid subGrid, ITestCase testCase, int selectedCell = -1) { foreach (var chunkRulePair in ruleFactory.GetQuadRuleSet(subGrid.VolumeMask, order)) { foreach (int cell in chunkRulePair.Chunk.Elements) { QuadRule rule = chunkRulePair.Rule; MultidimensionalArray globalVertices = MultidimensionalArray.Create( 1, rule.NoOfNodes, Grid.SpatialDimension); MultidimensionalArray metrics = levelSetTracker.DataHistories[0].Current.GetLevelSetNormalReferenceToPhysicalMetrics( rule.Nodes, cell, 1); GridData.TransformLocal2Global(rule.Nodes, cell, 1, globalVertices, 0); if (selectedCell >= 0 && cell != selectedCell) { continue; } for (int k = 0; k < rule.NoOfNodes; k++) { double weight = rule.Weights[k]; if (testCase is ISurfaceTestCase) { // Use to get correct HMF weights in reference coordinate // system (surface weights are already divided by $metrics // to save this step in actual quadrature) //weight *= metrics[0, k]; } if (Grid.SpatialDimension == 2) { log.WriteLine( "{0}\t{1}\t{2}\t{3}\t{4}", cell, k, globalVertices[0, k, 0].ToString(formatInfo), globalVertices[0, k, 1].ToString(formatInfo), Math.Round(weight, 2).ToString(formatInfo)); } else { log.WriteLine( "{0}\t{1}\t{2}\t{3}\t{4}\t{5}", cell, k, globalVertices[0, k, 0].ToString(formatInfo), globalVertices[0, k, 1].ToString(formatInfo), globalVertices[0, k, 2].ToString(formatInfo), weight.ToString(formatInfo)); } } } } }
/// <summary> /// Sums up all weights associated with a quadrature rule and reports /// an error if the sum is not equal to the volume /// (<see cref="RefElement.Volume"/>) of the simplex. /// </summary> /// <param name="order">The <b>requested</b> order</param> /// <param name="rule">The quadrature rule</param> private void TestSumOfWeights(int order, QuadRule rule) { double error = Math.Abs(rule.Weights.Sum() - GetSimplex().Volume); // This error should be much smaller (and was much smaller on the // old master branch); Should be investigated. Assert.That( error <= 1e-9, "Sum of weights != Simplex volume (Deviance: " + String.Format("{0:e}", error) + ")"); }
/// <summary> /// Computes the matrix matrix /// V_ij = sum_k{p_i(nodes(k) * p_j(nodes(k)) * weights(k)} /// for a given quadrature rule (where p_i and p_j are the orthonormal /// polynomials supplied by the quadrature rule) and reports an error /// if this matrix differs from the identity matrix /// </summary> /// <param name="order">The <b>requested</b> order</param> /// <param name="rule">The quadrature rule</param> /// <param name="polynomials">The orthonormal polynomials</param> private void TestMassMatrix(int order, QuadRule rule, PolynomialList polynomials) { MultidimensionalArray[] values = new MultidimensionalArray[polynomials.Count]; for (int i = 0; i < polynomials.Count; i++) { values[i] = MultidimensionalArray.Create(rule.NoOfNodes); polynomials[i].Evaluate(values[i], rule.Nodes); } //For every exactly integrable polynomial i for (int i = 0; i < polynomials.Count; i++) { // Check if quadrature rule is suitable if (polynomials[i].AbsoluteDegree > order) { continue; } //For every exactly integrable co-polynomial j for (int j = 0; j <= i; j++) { // Check if quadrature rule is suitable if (polynomials[i].AbsoluteDegree + polynomials[j].AbsoluteDegree > order) { continue; } double result = 0; for (int k = 0; k < rule.NoOfNodes; k++) { result += values[i][k] * values[j][k] * rule.Weights[k]; } //Elements should be zero except of diagonal elements double expectedResult = 0.0; if (i == j) { expectedResult = 1.0; } //Store maximum absolute error for the report we want to create double error = Math.Abs(result - expectedResult); //Console.WriteLine("MassMatrixError: {0}", error); Assert.That( error <= 1e-9, String.Format( "MassMatrix[" + i + "," + j + "] should be {0} but is off by {1:e} for order {2}", expectedResult, error, order)); } } }
private void WriteSurfaceNodes(StreamWriter log, IQuadRuleFactory <QuadRule> ruleFactory, int order, SubGrid subGrid) { var edgeRules = ruleFactory.GetQuadRuleSet( levelSetTracker.Regions.GetCutCellSubGrid().AllEdgesMask, order); foreach (var chunkRulePair in edgeRules) { foreach (int edge in chunkRulePair.Chunk.Elements) { QuadRule rule = chunkRulePair.Rule; int cell = GridData.iGeomEdges.CellIndices[edge, 0]; NodeSet volumeVertices = new NodeSet( GridData.iGeomCells.GetRefElement(cell), rule.NoOfNodes, Grid.SpatialDimension); Grid.RefElements[0].TransformFaceCoordinates( GridData.iGeomEdges.FaceIndices[edge, 0], rule.Nodes, volumeVertices); volumeVertices.LockForever(); MultidimensionalArray globalVertices = MultidimensionalArray.Create( 1, rule.NoOfNodes, Grid.SpatialDimension); GridData.TransformLocal2Global(volumeVertices, cell, 1, globalVertices, 0); for (int k = 0; k < rule.NoOfNodes; k++) { if (Grid.SpatialDimension == 2) { log.WriteLine( "{0}\t{1}\t{2}\t{3}\t{4}", cell, k, globalVertices[0, k, 0].ToString(formatInfo), globalVertices[0, k, 1].ToString(formatInfo), rule.Weights[k].ToString(formatInfo)); } else { log.WriteLine( "{0}\t{1}\t{2}\t{3}\t{4}\t{5}", cell, k, globalVertices[0, k, 0].ToString(formatInfo), globalVertices[0, k, 1].ToString(formatInfo), globalVertices[0, k, 2].ToString(formatInfo), rule.Weights[k].ToString(formatInfo)); } } } } }
public void TestNominalOrder() { var simplex = GetSimplex(); int highestKnownOrder = simplex.HighestKnownOrder; for (int i = 0; i <= highestKnownOrder; i++) { QuadRule rule = simplex.GetQuadratureRule(i); int realOrder = rule.OrderOfPrecision; Assert.IsTrue( realOrder >= i, "Requested order < real order (" + realOrder + ")"); } }
/// <summary> /// Projects every basis polynomial for the quadrature rule of the /// given order onto a single cell grid supplied by the sub-class and /// approximates the LInfinity error of the projection. /// </summary> /// <remarks> /// The DG projection uses a quadrature rule of 2*n+1 for a basis of /// order n. Thus, make sure <paramref name="order"/> that a quadrature /// rule of order 2*order+1 exists before calling this method</remarks> /// <param name="order">The <b>requested</b> order</param> /// <param name="polynomials">The orthonormal polynomials</param> /// <param name="rule">The tested quadrature rule</param> private void TestProjectionError(int order, PolynomialList polynomials, QuadRule rule) { Basis basis = new Basis(context, order); for (int i = 0; i < polynomials.Count; i++) { if (2 * polynomials[i].AbsoluteDegree + 1 > order) { // Not integrable _exactly_ with this rule continue; } DGField field = new SinglePhaseField(basis); ScalarFunction function = delegate(MultidimensionalArray input, MultidimensionalArray output) { polynomials[i].Evaluate(output, new NodeSet(rule.RefElement, input)); }; field.ProjectField(function); double LInfError = 0; for (int j = 0; j < rule.NoOfNodes; j++) { MultidimensionalArray result = MultidimensionalArray.Create(1, 1); NodeSet point = new NodeSet(context.iGeomCells.GetRefElement(0), 1, rule.SpatialDim); for (int k = 0; k < rule.SpatialDim; k++) { point[0, k] = rule.Nodes[j, k]; } point.LockForever(); //Evaluate pointwise because we don't want the accumulated //result field.Evaluate(0, 1, point, result, 0.0); MultidimensionalArray exactResult = MultidimensionalArray.Create(1); polynomials[i].Evaluate(exactResult, point); LInfError = Math.Max(Math.Abs(result[0, 0] - exactResult[0]), LInfError); } //Console.WriteLine("ProjectionError: {0}", LInfError); Assert.IsTrue( LInfError <= 1e-13, String.Format( "Projection error too high for polynomial {0}. Error: {1:e}", i, LInfError)); } }
protected override void Evaluate(int i0, int Length, QuadRule qr, MultidimensionalArray EvalResult) { if (field is XDGField) { SpeciesId speciesB = new SpeciesId() { cntnt = 11112 }; MultidimensionalArray result = EvalResult.ExtractSubArrayShallow(-1, -1, 0); ((XDGField)field).GetSpeciesShadowField(speciesB).Evaluate(i0, Length, qr.Nodes, result, 0, 0.0); } else { field.Evaluate(i0, Length, qr.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); } }
public void TestProjectionError() { var simplex = GetSimplex(); int maxOrder = Math.Min( simplex.HighestKnownOrder, simplex.HighestSupportedPolynomialDegree); //In a field of order i, the a field automatically uses a //quadrature rule of order 2i+1 to compute the DG projection. //Thus, we can only (and need only to) orders i for which it is //guaranteed that a rule of order 2i-1 exists, too for (int i = 0; 2 * i + 1 <= maxOrder; i++) { QuadRule rule = simplex.GetQuadratureRule(i); TestProjectionError(i, simplex.GetOrthonormalPolynomials(maxOrder), rule); } }
/// <summary> /// quadrature for a point is trivial - it's just evaluation a the point, /// so there is only one quadrature rule with one node that is valid for any order; /// </summary> /// <param name="DesiredOrder"> /// any positive integer value; /// </param> /// <returns> /// An exact quad. rule for arbitrary functions in zero dimensions !!! /// </returns> public override QuadRule GetQuadratureRule(int DesiredOrder) { if (DesiredOrder < 0) { throw new ArgumentOutOfRangeException("negative polynomial degree."); } QuadRule qr = new QuadRule(); qr.OrderOfPrecision = int.MaxValue; qr.Nodes = new NodeSet(this, 1, 1); qr.Nodes[0, 0] = 0.0; qr.Nodes.LockForever(); qr.Weights = MultidimensionalArray.Create(1); qr.Weights[0] = 1.0; return(qr); }
/// <summary> /// Modulates the result of /// <see cref="EvaluateDivergenceOfIntegrand"/> by the weights /// given by <see cref="EvaluateWeightFunction"/>. /// </summary> protected override void Evaluate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { NodeSet QuadNodes = QR.Nodes; int NoOfNodes = QuadNodes.NoOfNodes; m_Owner.EvaluateDivergenceOfIntegrand(QuadNodes, i0, Length, EvalResult); m_Owner.EvaluateWeightFunction(QuadNodes, i0, Length, m_WeightBuffer); for (int i = 0; i < Length; i++) { for (int j = 0; j < NoOfNodes; j++) { double gamma = m_WeightBuffer[i, j]; for (int k = 0; k < m_Owner.m_NoOfIntegrands; k++) { EvalResult[i, j, k] *= gamma; } } } }
/// <summary> /// Returns surface and volume quadrature nodes, respectively. /// </summary> /// <param name="Cell"></param> /// <param name="arg"></param> /// <returns></returns> public QuadRule[] ComboEvaluate(int Cell, T arg) { //Setup algorithm //---------------------------------------------------------------------- arg.Surface = false; cell = Cell; TreeNode <T> recursionTree = new TreeNode <T>(); TreeNode <T> fullSpace = recursionTree.AddChild(arg); //Build Integrand //---------------------------------------------------------------------- SayeRecursion(fullSpace); //Evaluate Integrand //---------------------------------------------------------------------- //Fill nodesAndWeights SurfRule = GetEmptySurfaceRule(); recursionTree.UnrollFunc(ComboIntegrandEvaluation); //Convert data to QuadRule. The volume rule is saved in SayeArgument as in the single algorithm. //The surface rule is saved SurfRule. QuadRule[] rulezOfKrom = new QuadRule[2]; rulezOfKrom[0] = fullSpace.Value.NodesAndWeights.GetQuadRule(); //Volume rule rulezOfKrom[1] = SurfRule.GetQuadRule(); //Surface rule //Handle empty QuadRule if (rulezOfKrom[0].NoOfNodes == 0) { Debug.WriteLine("Evaluation of cell {0} returned empty volume quadrule", cell); rulezOfKrom[0] = CreateZeroQuadrule(); } if (rulezOfKrom[1].NoOfNodes == 0) { Debug.WriteLine("Evaluation of cell {0} returned empty surface quadrule", cell); rulezOfKrom[1] = CreateZeroQuadrule(); } return(rulezOfKrom); }
public void TestSumOfWeights() { var simplex = GetSimplex(); int highestKnownOrder = simplex.HighestKnownOrder; QuadRule lastQuadRule = null; for (int i = 0; i <= highestKnownOrder; i++) { QuadRule rule = simplex.GetQuadratureRule(i); if (lastQuadRule == rule) { // Same rule, nothing new to test continue; } TestSumOfWeights(i, rule); lastQuadRule = rule; } }
protected override void Evaluate(int i0, int Length, QuadRule rule, MultidimensionalArray EvalResult) { NodeSet NodesUntransformed = rule.Nodes; int M = NodesUntransformed.GetLength(0); //int D = NodesUntransformed.GetLength(1); MultidimensionalArray fieldvalsA = EvalResult.ResizeShallow(new int[] { Length, NodesUntransformed.GetLength(0) }); fieldvalsA.Clear(); m_FieldA.Evaluate(i0, Length, NodesUntransformed, fieldvalsA, 1.0); fieldvalsB.Clear(); m_FieldB.Evaluate(i0, Length, NodesUntransformed, fieldvalsB, 1.0); for (int j = 0; j < Length; j++) { for (int m = 0; m < M; m++) { EvalResult[j, m, 0] = fieldvalsA[j, m] * fieldvalsB[j, m]; } } }
protected override void Evaluate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { int N = m_Basis.MaximalLength; int NoOfNodes = QR.Nodes.NoOfNodes; if (((GridData)gridData).Cells.ContainsNonlinearCell()) { throw new NotImplementedException(); } MultidimensionalArray scaling = base.gridData.iGeomCells.JacobiDet; for (int i = 0; i < m_Fields.Length; i++) { m_Fields[i].Evaluate(i0, Length, QR.Nodes, FieldVals[i], 0, 0.0); } for (int j = 0; j < Length; j++) { int jCell = j + i0; double sc = 1.0 / scaling[jCell]; for (int node = 0; node < NoOfNodes; node++) { for (int BlkRowLoc = 0; BlkRowLoc < N; BlkRowLoc++) { for (int BlkColLoc = 0; BlkColLoc < N; BlkColLoc++) { double[] _FieldVals = new double[FieldVals.Length]; for (int i = 0; i < FieldVals.Length; i++) { _FieldVals[i] = FieldVals[i][j, node]; } double FieldFuncValue = FieldFunc(_FieldVals); EvalResult[j, node, BlkRowLoc *N + BlkColLoc] = BasisValues[node, BlkRowLoc] * BasisValues[node, BlkColLoc] * sc * FieldFuncValue; } } } } }
public void Evaluate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { // Del_Evaluate // ~~~~~~~~~~~~~ NodeSet NS = QR.Nodes; int NoOfNodes = NS.NoOfNodes; var BasisVal = b.CellEval(NS, i0, Length); EvalResult.ExtractSubArrayShallow(new int[] { 0, 0, 0, 0 }, new int[] { Length - 1, NoOfNodes - 1, Nnx - 1, Nnx - 1 }) .Multiply(1.0, BasisVal, BasisVal, 0.0, "ikmn", "ikm", "ikn"); if (UevalBuf == null) { UevalBuf = MultidimensionalArray.Create(Length, NoOfNodes); } if (UevalBuf.GetLength(0) < Length || UevalBuf.GetLength(1) != NoOfNodes) { UevalBuf.Allocate(Length, NoOfNodes); } MultidimensionalArray _UevalBuf; if (UevalBuf.GetLength(0) > Length) { _UevalBuf = UevalBuf.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { Length - 1, NoOfNodes - 1 }); } else { Debug.Assert(UevalBuf.GetLength(0) == Length); _UevalBuf = UevalBuf; } for (int d = 0; d < D; d++) { _UevalBuf.Clear(); Uin[d].Evaluate(i0, Length, NS, _UevalBuf); EvalResult.ExtractSubArrayShallow(new int[] { 0, 0, Nnx + d, 0 }, new int[] { Length - 1, NoOfNodes - 1, Nnx + d - 1, Nnx - 1 }) .Multiply(1.0, BasisVal, _UevalBuf, 0.0, "ikm", "ikm", "ik"); } }
public void TestMassMatrix() { var simplex = GetSimplex(); // Limit order for run-time reasons int highestKnownOrder = Math.Min(simplex.HighestKnownOrder, 21); QuadRule lastQuadRule = null; for (int i = 0; i <= highestKnownOrder; i++) { QuadRule rule = simplex.GetQuadratureRule(i); if (lastQuadRule == rule) { // Same rule, nothing new to test continue; } TestMassMatrix(i, rule, simplex.GetOrthonormalPolynomials(Math.Min(highestKnownOrder, simplex.HighestSupportedPolynomialDegree))); lastQuadRule = rule; } }
/// <summary> /// Updates <see cref="lambdaBasis"/>, <see cref="baseRule"/> and /// <see cref="basisValuesEdge"/> every time a different order is /// requested in <see cref="GetQuadRuleSet"/> /// </summary> /// <param name="order"> /// The new order of the moment-fitting basis /// </param> private void SwitchOrder(int order) { int iKref = this.LevelSetData.GridDat.Cells.RefElements.IndexOf(this.RefElement, (A, B) => object.ReferenceEquals(A, B)); int noOfFaces = LevelSetData.GridDat.Grid.RefElements[iKref].NoOfFaces; int D = RefElement.FaceRefElement.SpatialDimension; Polynomial[] basePolynomials = RefElement.FaceRefElement.GetOrthonormalPolynomials(order).ToArray(); Polynomial[] antiderivativePolynomials = new Polynomial[basePolynomials.Length * D]; for (int i = 0; i < basePolynomials.Length; i++) { Polynomial p = basePolynomials[i]; for (int d = 0; d < D; d++) { Polynomial pNew = p.CloneAs(); for (int j = 0; j < p.Coeff.Length; j++) { pNew.Exponents[j, d]++; pNew.Coeff[j] /= pNew.Exponents[j, d]; // Make sure divergence is Phi again pNew.Coeff[j] /= D; } antiderivativePolynomials[i * D + d] = pNew; } } lambdaBasis = new PolynomialList(antiderivativePolynomials); int minNoOfPoints = GetNumberOfLambdas(); int minOrder = 1; double safetyFactor = 1.6; while (RefElement.FaceRefElement.GetQuadratureRule(minOrder).NoOfNodes < safetyFactor * minNoOfPoints) { minOrder += 1; } QuadRule singleEdgeRule = RefElement.FaceRefElement.GetQuadratureRule(minOrder); baseRule = new CellBoundaryFromEdgeRuleFactory <CellBoundaryQuadRule>( LevelSetData.GridDat, LevelSetData.GridDat.Grid.RefElements[0], new FixedRuleFactory <QuadRule>(singleEdgeRule)). GetQuadRuleSet(new CellMask(LevelSetData.GridDat, Chunk.GetSingleElementChunk(0)), -1). First().Rule; //Basis singleEdgeBasis = new Basis(tracker.GridDat, order, RefElement.FaceRefElement); PolynomialList singleEdgeBasis = new PolynomialList(RefElement.FaceRefElement.GetOrthonormalPolynomials(order)); //MultidimensionalArray edgeNodes = singleEdgeRule.Nodes.CloneAs(); //basisValuesEdge = MultidimensionalArray.Create( // singleEdgeRule.NoOfNodes, singleEdgeBasis.Count); //MultidimensionalArray monomials = Polynomial.GetMonomials( // edgeNodes, RefElement.FaceRefElement.SpatialDimension, singleEdgeBasis.Degree); //for (int j = 0; j < singleEdgeBasis.MinimalLength; j++) { // singleEdgeBasis.Polynomials[iKref, j].Evaluate( // basisValuesEdge.ExtractSubArrayShallow(-1, j), // edgeNodes, // monomials); //} this.basisValuesEdge = singleEdgeBasis.Values.GetValues(singleEdgeRule.Nodes); }
void GetQuadRuleSet_Internal(int order) { using (new FuncTrace()) { int original_order = order; stpwGetQuadRuleSet.Start(); order = Math.Max(order, 2); // Ansatz won't work below 2! int D = this.tracker.GridDat.SpatialDimension;; // check arguments, init // ===================== CellMask _mask = this.MaxGrid; // subgrid on which the volume rule should be constructed // ====================================================== CellBoundaryQuadratureScheme cellBndSchme = new CellBoundaryQuadratureScheme(this.cellFaceFactory, _mask); CellBoundaryQuadratureScheme cellBndLineSchme = null; if (this.UseStokes) { cellBndLineSchme = new CellBoundaryQuadratureScheme(this.LevelSetBoundaryLineFactory, _mask); } // set up // ====== int NoOfEqTotal, NoOfStokesEq, NoOfGaußEq; DivergenceFreeBasis DivFreeBasis = this.UseGauß ? new DivergenceFreeBasis(tracker.GridDat, this.Kref, order + 1) : null; Basis ScalarBasis = this.UseStokes ? new Basis(this.tracker.GridDat, order + 1) : null; // we loose a order of 1 for the volume rule due to the divergence operator NoOfGaußEq = DivFreeBasis != null ? (DivFreeBasis.Count / D) : 0; NoOfStokesEq = (ScalarBasis != null ? ScalarBasis.Length : 0) * D; NoOfEqTotal = NoOfGaußEq + NoOfStokesEq; // define Nodes // ============ NodeSet NodeSet = null; { if (this.Kref.GetType() == typeof(Square)) { int K = (int)Math.Ceiling(Math.Sqrt(NoOfEqTotal * 1.7)) + 1; var Nodes1D = GenericBlas.Linspace(-1, 1, K); var _NodeSet = MultidimensionalArray.Create(K * K, 2); int n = 0; for (int i = 0; i < K /*&& n <= NoOfEq*1.1*/; i++) { for (int j = 0; j < K /*&& n <= NoOfEq*1.1*/; j++) { _NodeSet[n, 0] = Nodes1D[i]; _NodeSet[n, 1] = Nodes1D[j]; n++; } } NodeSet = new NodeSet(this.Kref, _NodeSet); } else { for (int o = 1; o < 1000000; o++) { var qr = Kref.GetBruteForceQuadRule(o, 0); if (qr.NoOfNodes >= (NoOfEqTotal * 1.1)) { NodeSet = qr.Nodes; break; } } } } int NoOfNodes = NodeSet.GetLength(0); // find RHS integrals // ================== MultidimensionalArray RHS_Gauß = null; if (this.UseGauß) { stpwGetQuadRuleSet_GaussRHS.Start(); RHS_Gauß = this.GaußAnsatzRHS(DivFreeBasis, cellBndSchme, _mask, order); stpwGetQuadRuleSet_GaussRHS.Stop(); Debug.Assert(RHS_Gauß.Dimension == 2); Debug.Assert(RHS_Gauß.GetLength(0) == NoOfGaußEq); Debug.Assert(RHS_Gauß.GetLength(1) == _mask.NoOfItemsLocally); } MultidimensionalArray RHS_Stokes = null; if (this.UseStokes) { stpwGetQuadRuleSet_StokesRHS.Start(); RHS_Stokes = this.StokesAnsatzRHS(ScalarBasis, cellBndLineSchme, _mask, order); stpwGetQuadRuleSet_StokesRHS.Stop(); Debug.Assert(RHS_Stokes.Dimension == 2); Debug.Assert(RHS_Stokes.GetLength(0) == NoOfStokesEq); Debug.Assert(RHS_Stokes.GetLength(1) == _mask.NoOfItemsLocally); } // construct da rule! // ================== ChunkRulePair <QuadRule>[] SurfaceRule; { SurfaceRule = new ChunkRulePair <QuadRule> [_mask.NoOfItemsLocally]; var grddat = this.tracker.GridDat; // loop over cells in subgrid... int jSub = 0; foreach (int jCell in _mask.ItemEnum) // loop over cells in the mask // setup System // ============ { NodeSet surfNodes; if (this.SurfaceNodesOnZeroLevset) { surfNodes = ProjectOntoLevset(jCell, NodeSet); } else { surfNodes = NodeSet; } MultidimensionalArray metrics; { int iKref = grddat.Cells.GetRefElementIndex(jCell); metrics = LevelSetData.GetLevelSetNormalReferenceToPhysicalMetrics(surfNodes, jCell, 1); } MultidimensionalArray Mtx_Gauss = null; if (this.UseGauß) { Mtx_Gauss = GaußAnsatzMatrix(DivFreeBasis, surfNodes, jCell); Debug.Assert(Mtx_Gauss.Dimension == 2); Debug.Assert(Mtx_Gauss.GetLength(0) == NoOfGaußEq); Debug.Assert(Mtx_Gauss.GetLength(1) == NoOfNodes); } MultidimensionalArray Mtx_Stokes = null; if (this.UseStokes) { Mtx_Stokes = this.StokesAnsatzMatrix(ScalarBasis, surfNodes, jCell); Debug.Assert(Mtx_Stokes.Dimension == 2); Debug.Assert(Mtx_Stokes.GetLength(0) == NoOfStokesEq); Debug.Assert(Mtx_Stokes.GetLength(1) == NoOfNodes); for (int i = 0; i < NoOfStokesEq; i++) { for (int j = 0; j < NoOfNodes; j++) { Mtx_Stokes[i, j] /= metrics[0, j]; } } } stpwGetQuadRuleSet_SolveRHS.Start(); // convert to FORTRAN order MultidimensionalArray _Mtx = MultidimensionalArray.Create(NoOfEqTotal, NoOfNodes); if (this.UseGauß) { _Mtx.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { NoOfGaußEq - 1, NoOfNodes - 1 }).Set(Mtx_Gauss); } if (this.UseStokes) { _Mtx.ExtractSubArrayShallow(new int[] { NoOfGaußEq, 0 }, new int[] { NoOfStokesEq + NoOfGaußEq - 1, NoOfNodes - 1 }).Set(Mtx_Stokes); } // convert to FORTRAN order Debug.Assert(NoOfNodes >= NoOfEqTotal); MultidimensionalArray _RHS = MultidimensionalArray.Create(NoOfNodes, 1); // this is also output, so it must be larger! { for (int i = 0; i < NoOfGaußEq; i++) { _RHS[i, 0] = RHS_Gauß[i, jSub]; } for (int i = 0; i < NoOfStokesEq; i++) { _RHS[i + NoOfGaußEq, 0] = RHS_Stokes[i, jSub]; } } MultidimensionalArray __RHS = null, __Mtx = null; if (this.Docheck) { // values used for testing: __RHS = MultidimensionalArray.Create(NoOfEqTotal); for (int i = 0; i < NoOfEqTotal; i++) { __RHS[i] = _RHS[i, 0]; } __Mtx = MultidimensionalArray.Create(_Mtx.NoOfRows, _Mtx.NoOfCols); __Mtx.SetMatrix(_Mtx); } // solve system // ============ //int M = _Mtx.NoOfRows; //int N = _Mtx.NoOfCols; //LAPACK.F77_LAPACK.DGELSY(M, N, _Mtx.Entries, _RHS.Entries, 1, 1.0e-14); _Mtx.LeastSquareSolve(_RHS); if (this.Docheck) { // Probe: MultidimensionalArray X = MultidimensionalArray.Create(NoOfNodes); // weights X.ResizeShallow(NoOfNodes, 1).SetMatrix(_RHS); __RHS.Multiply(-1.0, __Mtx, X, 1.0, "j", "jk", "k"); double L2_ERR = __RHS.L2Norm(); if (L2_ERR > 1.0e-7) { throw new ApplicationException("Quadrature rule in cell " + jCell + " seems to be not very precise: L2_ERR = " + L2_ERR); } //Debug.Assert(L2_ERR < 1.0e-8, "Quadrature rule in cell " + jCell + " seems to be not very precise: L2_ERR = " + L2_ERR); //if (L2_ERR > 1.0e-9) // Console.WriteLine("Warning: Quadrature rule in cell " + jCell + ": L2_ERR = " + L2_ERR); } stpwGetQuadRuleSet_SolveRHS.Stop(); // return da rule! // =============== { { // the surface rule // ---------------- QuadRule qr_l = new QuadRule() { OrderOfPrecision = order, Weights = MultidimensionalArray.Create(NoOfNodes), Nodes = surfNodes }; for (int k = 0; k < NoOfNodes; k++) { qr_l.Weights[k] = _RHS[k, 0] / metrics[0, k]; } SurfaceRule[jSub] = new ChunkRulePair <QuadRule>(Chunk.GetSingleElementChunk(jCell), qr_l); } } jSub++; } } stpwGetQuadRuleSet.Stop(); if (!this.m_SurfaceRules.ContainsKey(original_order)) { this.m_SurfaceRules.Add(original_order, SurfaceRule); } } }
/// <summary> /// Returns a <see cref="CellBoundaryQuadRule"/> for each cell in the /// given <paramref name="mask"/>. This rule consists of Gaussian /// quadrature rules on each continuous line segment on the edges of a /// given cell (where continuous means 'not intersected by the zero /// level set' /// </summary> /// <param name="mask"></param> /// <param name="order"></param> /// <returns></returns> public IEnumerable <IChunkRulePair <CellBoundaryQuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (!(mask is CellMask)) { throw new ArgumentException("This works on cell basis, so a volume mask is required."); } //Console.WriteLine("boundary order: " + order); if (mask == null) { mask = CellMask.GetFullMask(levelSetData.GridDat); } if (order != lastOrder) { cache.Clear(); } double[] EdgeToVolumeTransformationDeterminants = this.RefElement.FaceTrafoGramianSqrt; QuadRule baseRule = lineSimplex.GetQuadratureRule(order); int D = levelSetData.GridDat.SpatialDimension; var _Cells = levelSetData.GridDat.Cells; var result = new List <ChunkRulePair <CellBoundaryQuadRule> >(mask.NoOfItemsLocally); foreach (Chunk chunk in mask) { for (int i = 0; i < chunk.Len; i++) { int cell = i + chunk.i0; if (cache.ContainsKey(cell)) { Debug.Assert(cache[cell].Nodes.IsLocked, "Quadrule with non-locked nodes in cache."); result.Add(new ChunkRulePair <CellBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), cache[cell])); continue; } List <double[]> nodes = new List <double[]>(); List <double> weights = new List <double>(); int[] noOfNodesPerEdge = new int[referenceLineSegments.Length]; for (int e = 0; e < referenceLineSegments.Length; e++) { LineSegment referenceSegment = referenceLineSegments[e]; int iKref = _Cells.GetRefElementIndex(cell); double[] roots = referenceSegment.GetRoots(levelSetData.LevelSet, cell, iKref); double edgeDet = EdgeToVolumeTransformationDeterminants[e]; LineSegment[] subSegments = referenceSegment.Split(roots); for (int k = 0; k < subSegments.Length; k++) { // Evaluate sub segment at center to determine sign NodeSet _point = new NodeSet(this.RefElement, subSegments[k].GetPointOnSegment(0.0)); double weightFactor = subSegments[k].Length / referenceSegment.Length; if (weightFactor < 1.0e-14) { // segment has a length of approximately 0.0 => no need to care about it. continue; } weightFactor *= edgeDet; if (jumpType != JumpTypes.Implicit) { //using (tracker.GridDat.NSC.CreateLock(MultidimensionalArray.CreateWrapper(point, 1, D), this.iKref, -1.0)) { MultidimensionalArray levelSetValue = this.levelSetData.GetLevSetValues(_point, cell, 1); switch (jumpType) { case JumpTypes.Heaviside: if (levelSetValue[0, 0] <= -Tolerance) { continue; } break; case JumpTypes.OneMinusHeaviside: if (levelSetValue[0, 0] >= Tolerance) { continue; } break; case JumpTypes.Sign: weightFactor *= levelSetValue[0, 0].Sign(); break; default: throw new NotImplementedException(); } //} } for (int m = 0; m < baseRule.NoOfNodes; m++) { // Base rule _always_ is a line rule, thus Nodes[*, _0_] double[] point = subSegments[k].GetPointOnSegment(baseRule.Nodes[m, 0]); weights.Add(weightFactor * baseRule.Weights[m]); nodes.Add(point); noOfNodesPerEdge[e]++; } } } if (weights.Count == 0) { result.Add(new ChunkRulePair <CellBoundaryQuadRule>(Chunk.GetSingleElementChunk(cell), emptyrule)); continue; } NodeSet localNodes = new NodeSet(this.RefElement, nodes.Count, D); for (int j = 0; j < nodes.Count; j++) { for (int d = 0; d < D; d++) { localNodes[j, d] = nodes[j][d]; } } localNodes.LockForever(); CellBoundaryQuadRule subdividedRule = new CellBoundaryQuadRule() { OrderOfPrecision = order, Weights = MultidimensionalArray.Create(weights.Count), Nodes = localNodes, NumbersOfNodesPerFace = noOfNodesPerEdge }; subdividedRule.Weights.SetSubVector(weights, -1); cache.Add(cell, subdividedRule); result.Add(new ChunkRulePair <CellBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), subdividedRule)); } } return(result); }
/// <summary> /// Integrand evaluation. /// </summary> protected override void Evaluate(int i0, int Length, QuadRule rule, MultidimensionalArray EvalResult) { NodeSet NodesUntransformed = rule.Nodes; int M = NodesUntransformed.GetLength(0); int D = NodesUntransformed.GetLength(1); // evaluate scalar function ans store result in 'EvalResult' // ========================================================= Debug.Assert(!((m_func != null) && (m_funcEx != null))); if (m_func != null || m_Map != null) { GridDat.TransformLocal2Global(NodesUntransformed, i0, Length, m_NodesTransformed, 0); } if (m_func != null) { MultidimensionalArray inp = m_NodesTransformed.ResizeShallow(new int[] { Length *M, D }); MultidimensionalArray outp = EvalResult.ResizeShallow(new int[] { Length *M }); m_func(inp, outp); Debug.Assert(m_funcEx == null); } if (m_funcEx != null) { m_funcEx(i0, Length, NodesUntransformed, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); Debug.Assert(m_func == null); } if (m_Map == null) { // L2 error branch // +++++++++++++++ MultidimensionalArray fieldvals = EvalResult.ResizeShallow(new int[] { Length, NodesUntransformed.GetLength(0) }); m_Owner.Evaluate(i0, Length, NodesUntransformed, fieldvals, -1.0); for (int j = 0; j < Length; j++) { for (int m = 0; m < M; m++) { double e; e = EvalResult[j, m, 0]; EvalResult[j, m, 0] = e * e; } } } else { // arbitrary mapping branch // ++++++++++++++++++++++++ MultidimensionalArray fieldvals = MultidimensionalArray.Create(new int[] { Length, NodesUntransformed.GetLength(0) }); m_Owner.Evaluate(i0, Length, NodesUntransformed, fieldvals, -1.0); double[] X = new double[D]; for (int j = 0; j < Length; j++) { for (int m = 0; m < M; m++) { double e; e = EvalResult[j, m, 0]; for (int d = 0; d < D; d++) { X[d] = m_NodesTransformed[j, m, d]; } EvalResult[j, m, 0] = this.m_Map(X, fieldvals[j, m], e); } } } }
/// <summary> /// /// </summary> protected void EvaluateEx(int i0, int Length, QuadRule QR, MultidimensionalArray QuadResult) { NodeSet NodesUntransformed = QR.Nodes; IGridData grid = this.GridDat; int D = grid.SpatialDimension; int NoOfEquations = m_CodomainBasisS.Length; int NoOfNodes = NodesUntransformed.NoOfNodes; bool isAffine = grid.iGeomCells.IsCellAffineLinear(i0); int[] geom2log = grid.iGeomCells.GeomCell2LogicalCell; #if DEBUG for (int i = 1; i < Length; i++) { Debug.Assert(grid.iGeomCells.IsCellAffineLinear(i + i0) == isAffine); if (geom2log == null) { for (int e = 0; e < base.m_CodomainBasisS.Length; e++) { Debug.Assert(base.m_CodomainBasisS[e].GetLength(i + i0) == base.m_CodomainBasisS[e].GetLength(i0)); } } else { for (int e = 0; e < base.m_CodomainBasisS.Length; e++) { Debug.Assert(base.m_CodomainBasisS[e].GetLength(geom2log[i + i0]) == base.m_CodomainBasisS[e].GetLength(geom2log[i0])); } } } #endif // this is an EvaluateEx: we are also responsible for multiplying with quadrature weights and summing up! Debug.Assert(QuadResult.Dimension == 2); Debug.Assert(QuadResult.GetLength(0) == Length); Debug.Assert(QuadResult.GetLength(1) == base.m_CodomainMapping.BasisS.Sum(basis => basis.Length)); // =================== // Evaluate all fields // =================== this.Field_Eval.Start(); for (int f = 0; f < m_DomainFields.Length; f++) { if (m_ValueRequired[f]) { Debug.Assert(m_FieldValues[f] != null); if (m_DomainFields[f] != null) { m_DomainFields[f].Evaluate(i0, Length, NodesUntransformed, m_FieldValues[f]); } else { // field is null => set to 0.0 m_FieldValues[f].Clear(); } } } for (int f = 0; f < m_GradientRequired.Length; f++) { if (m_GradientRequired[f]) { Debug.Assert(m_FieldGradients[f] != null); if (m_DomainFields[f] != null) { m_DomainFields[f].EvaluateGradient(i0, Length, NodesUntransformed, m_FieldGradients[f]); } else { // field is null => set to 0.0 m_FieldValues[f].Clear(); } } } this.Field_Eval.Stop(); // ===================================== // Transform Nodes to global coordinates // ===================================== this.ParametersAndNormals.Start(); var NodesGlobalCoords = grid.GlobalNodes.GetValue_Cell(NodesUntransformed, i0, Length); //var NodesGlobalCoords = MultidimensionalArray.Create(Length, NoOfNodes, D); this.ParametersAndNormals.Stop(); // ======================= // Evaluate Flux functions // ======================= bool[] RequireTestFunctionGradient = new bool[NoOfEquations]; bool[] Cleared_m_FluxValues = new bool[NoOfEquations]; this.Flux_Eval.Start(); // loop over all equations ... for (int e = 0; e < NoOfEquations; e++) { // Field fld = m_CodomainFields[e]; if (m_NonlinFluxes[e].m_AllComponentsOfMyType.Length + m_NonlinFluxesEx[e].m_AllComponentsOfMyType.Length > 0) { m_FluxValues[e].Clear(); Cleared_m_FluxValues[e] = true; RequireTestFunctionGradient[e] = true; // sum up all INonlinearFlux - objects int jjj = 0; foreach (INonlinearFlux nonlinFlx in m_NonlinFluxes[e].m_AllComponentsOfMyType) { m_NonlinFluxesWatches[e][jjj].Start(); nonlinFlx.Flux(m_Time, NodesGlobalCoords, m_NonlinFluxes[e].MapArguments(m_FieldValues, nonlinFlx), 0, Length, m_FluxValues[e]); m_NonlinFluxesWatches[e][jjj].Stop(); jjj++; } // sum up all INonlinearFluxEx - objects jjj = 0; foreach (INonlinearFluxEx nonlinFlxEx in m_NonlinFluxesEx[e].m_AllComponentsOfMyType) { m_NonlinFluxesExWatches[e][jjj].Start(); nonlinFlxEx.Flux(m_Time, NodesGlobalCoords, m_NonlinFluxesEx[e].MapArguments(m_FieldValues, nonlinFlxEx), 0, Length, m_FluxValues[e], i0); m_NonlinFluxesExWatches[e][jjj].Stop(); jjj++; } m_FluxValues[e].Scale(-1.0); } } // ========================= // Evaluate Source functions // ========================= bool[] RequireTestfunction = new bool[NoOfEquations]; bool[] Cleared_m_SourceValues = new bool[NoOfEquations]; for (int e = 0; e < NoOfEquations; e++) { // Equation eq = m_Equations[e]; // Field fld = eq.MyField; if (m_NonlinSources[e].m_AllComponentsOfMyType.Length > 0) { m_SourceValues[e].Clear(); Cleared_m_SourceValues[e] = true; RequireTestfunction[e] = true; // sum up all sources int jjj = 0; foreach (INonlinearSource nonlinSrc in m_NonlinSources[e].m_AllComponentsOfMyType) { m_NonlinSources_watch[e][jjj].Start(); nonlinSrc.Source(m_Time, NodesGlobalCoords, m_NonlinSources[e].MapArguments(m_FieldValues, nonlinSrc), 0, i0, Length, m_SourceValues[e]); m_NonlinSources_watch[e][jjj].Stop(); jjj++; } } } // ============== // Evaluate Forms // ============== for (int e = 0; e < NoOfEquations; e++) { if (m_NonlinFormV[e].m_AllComponentsOfMyType.Length > 0) { for (int icomp = 0; icomp < m_NonlinFormV[e].m_AllComponentsOfMyType.Length; icomp++) { INonlinVolumeForm_V nonlinform = m_NonlinFormV[e].m_AllComponentsOfMyType[icomp]; if ((nonlinform.VolTerms & (TermActivationFlags.UxV | TermActivationFlags.V | TermActivationFlags.GradUxV)) == 0) { continue; } else { m_NonlinFormV_watch[e][icomp].Start(); RequireTestfunction[e] = true; if (!Cleared_m_SourceValues[e]) { m_SourceValues[e].Clear(); Cleared_m_SourceValues[e] = true; } VolumFormParams vfp; vfp.GridDat = base.GridDat; vfp.j0 = i0; vfp.Len = Length; vfp.Xglobal = NodesGlobalCoords; vfp.time = this.m_Time; int NoArgs = m_NonlinFormV[e].NoOfArguments[icomp]; int NoParams = m_NonlinFormV[e].NoOfParameters[icomp]; var MappedArgsAndParams = m_NonlinFormV[e].MapArguments(this.m_FieldValues, nonlinform); vfp.ParameterVars = MappedArgsAndParams.GetSubVector(NoArgs, NoParams); var MappedArgs = MappedArgsAndParams.GetSubVector(0, NoArgs); var MappedGradients = m_NonlinFormV[e].MapArguments(this.m_FieldGradients, nonlinform, true); nonlinform.Form(ref vfp, MappedArgs, MappedGradients, this.m_SourceValues[e]); m_NonlinFormV_watch[e][icomp].Stop(); } } } } for (int e = 0; e < NoOfEquations; e++) { if (m_NonlinFormGradV[e].m_AllComponentsOfMyType.Length > 0) { for (int icomp = 0; icomp < m_NonlinFormGradV[e].m_AllComponentsOfMyType.Length; icomp++) { INonlinVolumeForm_GradV nonlinform = m_NonlinFormGradV[e].m_AllComponentsOfMyType[icomp]; if ((nonlinform.VolTerms & (TermActivationFlags.GradUxGradV | TermActivationFlags.UxGradV | TermActivationFlags.GradV)) == 0) { continue; } else { m_NonlinFormGradV_watch[e][icomp].Start(); RequireTestFunctionGradient[e] = true; if (!Cleared_m_FluxValues[e]) { this.m_FluxValues[e].Clear(); Cleared_m_FluxValues[e] = true; } VolumFormParams vfp; vfp.GridDat = base.GridDat; vfp.j0 = i0; vfp.Len = Length; vfp.Xglobal = NodesGlobalCoords; vfp.time = this.m_Time; int NoArgs = m_NonlinFormGradV[e].NoOfArguments[icomp]; int NoParams = m_NonlinFormGradV[e].NoOfParameters[icomp]; var MappedArgsAndParams = m_NonlinFormGradV[e].MapArguments(this.m_FieldValues, nonlinform); vfp.ParameterVars = MappedArgsAndParams.GetSubVector(NoArgs, NoParams); var MappedArgs = MappedArgsAndParams.GetSubVector(0, NoArgs); var MappedGradients = m_NonlinFormGradV[e].MapArguments(this.m_FieldGradients, nonlinform, true); nonlinform.Form(ref vfp, MappedArgs, MappedGradients, this.m_FluxValues[e]); m_NonlinFormGradV_watch[e][icomp].Stop(); } } } } this.Flux_Eval.Stop(); // ================ // Transform fluxes // ================ // its less work to multiply the fluxes by the inverse Jacobi, // than each test function gradient by inverse Jacobi. // Could be interpreted as transforming fluxes to Refelem, i think.... this.Flux_Trafo.Start(); MultidimensionalArray InverseJacobi = null, JacobiDet = null; for (int e = 0; e < NoOfEquations; e++) { Debug.Assert((m_FluxValues[e] != null) == (m_FluxValuesTrf[e] != null)); if (m_FluxValues[e] != null) { if (InverseJacobi == null) { if (isAffine) { InverseJacobi = grid.iGeomCells.InverseTransformation.ExtractSubArrayShallow(new int[] { i0, 0, 0 }, new int[] { i0 + Length - 1, D - 1, D - 1 }); } else { InverseJacobi = grid.InverseJacobian.GetValue_Cell(QR.Nodes, i0, Length); //InverseJacobi = MultidimensionalArray.Create(Length, NoOfNodes, D, D); } } if (JacobiDet == null && !isAffine) { JacobiDet = grid.JacobianDeterminat.GetValue_Cell(QR.Nodes, i0, Length); } if (isAffine) { m_FluxValuesTrf[e].Multiply(1.0, m_FluxValues[e], InverseJacobi, 0.0, "jke", "jkd", "jed"); // for affine-linear cells the multiplication with Jacobi determinant is done AFTER quadrature, since it is constant per cell. } else { m_FluxValuesTrf[e].Multiply(1.0, m_FluxValues[e], InverseJacobi, 0.0, "jke", "jkd", "jked"); m_FluxValuesTrf[e].Multiply(1.0, m_FluxValuesTrf[e], JacobiDet, 0.0, "jke", "jke", "jk"); // apply scaling with Jacobi determinant, for integral transformation } } if (m_SourceValues[e] != null) { if (JacobiDet == null && !isAffine) { JacobiDet = grid.JacobianDeterminat.GetValue_Cell(QR.Nodes, i0, Length); } //JacobiDet = MultidimensionalArray.Create(Length, NoOfNodes); // apply scaling with Jacobi determinant, for integral transformation if (isAffine) { // nop: for affine-linear cells the multiplication with Jacobi determinant is done AFTER quadrature, since it is constant per cell. } else { m_SourceValues[e].Multiply(1.0, m_SourceValues[e], JacobiDet, 0.0, "jk", "jk", "jk"); } } } this.Flux_Trafo.Stop(); // ======================= // evaluate test functions // ======================= this.Basis_Eval.Start(); if (this.m_MaxCodBasis != null && QR.NoOfNodes != this.m_TestFuncWeighted.GetLength(0)) { this.m_TestFuncWeighted.Allocate(QR.NoOfNodes, m_MaxCodBasis.GetLength(i0)); } if (this.m_MaxCodBasis_Gradient != null && QR.NoOfNodes != this.m_TestFuncGradWeighted.GetLength(0)) { this.m_TestFuncGradWeighted.Allocate(QR.NoOfNodes, m_MaxCodBasis_Gradient.GetLength(i0), D); } if (m_MaxCodBasis != null) { var testFunc = m_MaxCodBasis.Evaluate(QR.Nodes); m_TestFuncWeighted.Multiply(1.0, QR.Weights, testFunc, 0.0, "kn", "k", "kn"); } if (m_MaxCodBasis_Gradient != null) { var testFuncGrad = m_MaxCodBasis_Gradient.EvaluateGradient(QR.Nodes); m_TestFuncGradWeighted.Multiply(1.0, QR.Weights, testFuncGrad, 0.0, "knd", "k", "knd"); } this.Basis_Eval.Stop(); // ========================================== // multiply with test functions / save result // ========================================== MultidimensionalArray OrthoTrf = null; // to transform back to ONB on physical space... int iBufOrthoTrf; if (isAffine) { OrthoTrf = TempBuffer.GetTempMultidimensionalarray(out iBufOrthoTrf, Length); OrthoTrf.Multiply(1.0, grid.iGeomCells.JacobiDet.ExtractSubArrayShallow(new int[] { i0 }, new int[] { i0 + Length - 1 }), grid.ChefBasis.Scaling.ExtractSubArrayShallow(new int[] { i0 }, new int[] { i0 + Length - 1 }), 0.0, "j", "j", "j"); } else { int MaxDegree = Math.Max(this.m_MaxCodBasis != null ? m_MaxCodBasis.Degree : 0, this.m_MaxCodBasis_Gradient != null ? m_MaxCodBasis_Gradient.Degree : 0); OrthoTrf = grid.ChefBasis.OrthonormalizationTrafo.GetValue_Cell(i0, Length, MaxDegree); iBufOrthoTrf = int.MinValue; } this.Loops.Start(); int N0, N; N0 = 0; for (int e = 0; e < NoOfEquations; e++) // loop over equations... { if (geom2log != null) { N = m_CodomainBasisS[e].GetLength(geom2log[i0]); } else { N = m_CodomainBasisS[e].GetLength(i0); } int iBuf; MultidimensionalArray QuadResult_e = TempBuffer.GetTempMultidimensionalarray(out iBuf, Length, N); // fluxes // ------ if (RequireTestFunctionGradient[e]) { MultidimensionalArray Fluxes_e = m_FluxValuesTrf[e], testFuncGrad_e = null; if (m_TestFuncGradWeighted.GetLength(1) == N) { testFuncGrad_e = m_TestFuncGradWeighted; } else { testFuncGrad_e = m_TestFuncGradWeighted.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { NoOfNodes - 1, N - 1, D - 1 }); } QuadResult_e.Multiply(1.0, Fluxes_e, testFuncGrad_e, 0.0, "jn", "jke", "kne"); } // sources // ------- if (RequireTestfunction[e]) { MultidimensionalArray SourceValues_e = m_SourceValues[e], testFunc_e = null; if (m_TestFuncWeighted.GetLength(1) == N) { testFunc_e = m_TestFuncWeighted; } else { testFunc_e = m_TestFuncWeighted.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { NoOfNodes - 1, N - 1 }); } QuadResult_e.Multiply(1.0, SourceValues_e, testFunc_e, 1.0, "jn", "jk", "kn"); } // final transformations // --------------------- MultidimensionalArray trfQuadResult_e = QuadResult.ExtractSubArrayShallow(new int[] { 0, N0 }, new int[] { Length - 1, N0 + N - 1 }); if (isAffine) { trfQuadResult_e.Multiply(1.0, OrthoTrf, QuadResult_e, 0.0, "jn", "j", "jn"); } else { MultidimensionalArray _OrthoTrf; if (OrthoTrf.GetLength(1) == N) { _OrthoTrf = OrthoTrf; } else { _OrthoTrf = OrthoTrf.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { Length - 1, N - 1, N - 1 }); } trfQuadResult_e.Multiply(1.0, _OrthoTrf, QuadResult_e, 0.0, "jn", "jmn", "jm"); } // next // ---- TempBuffer.FreeTempBuffer(iBuf); N0 += N; } if (isAffine) { TempBuffer.FreeTempBuffer(iBufOrthoTrf); } this.Loops.Stop(); #if DEBUG QuadResult.CheckForNanOrInf(true, true, true); #endif }