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> /// Creates a new composite quadrature rules of minimal order /// <paramref name="order"/> from a single quadrature rule factory and /// an associated domain of integration. /// </summary> /// <typeparam name="TDomain"> /// The type of the domain to be integrated over. /// </typeparam> /// <param name="ruleFactory"> /// The quadrature rule factory to be used to create the quadrature /// rules for the given domain. /// </param> /// <param name="order"> /// The minimal order of the quadrature rules to be used. See /// <see cref="IQuadRuleFactory{T}.GetQuadRuleSet"/>. /// </param> /// <param name="domain"> /// The domain to be integrated over. /// </param> /// <returns> /// A composite rule containing the quadrature rules associated with /// all elements of the given domain. /// </returns> /// <remarks> /// The main specialty about the resulting composite rule is that the /// implementation guarantees that the sets of nodes and weights /// associated to the respective quadrature rules share the <b>same</b> /// objects of their contents are equal. This is allows for the /// optimization of the execution of the quadrature itself. /// </remarks> public static CompositeQuadRule <TQuadRule> Create <TDomain>( IQuadRuleFactory <TQuadRule> ruleFactory, int order, TDomain domain) where TDomain : ExecutionMask { CompositeQuadRule <TQuadRule> compositeRule = new CompositeQuadRule <TQuadRule>(); // BEWARE: This check may cause nasty trouble in parallel runs // where a domain is only present on some domains and has thus been // removed by Björn //if (domain.NoOfItemsLocally == 0) { // return compositeRule; //} var ruleSet = ruleFactory.GetQuadRuleSet(domain, order); var nodes = new List <NodeSet>(); var nodesMap = new Dictionary <MultidimensionalArray, int>(); var weights = new List <MultidimensionalArray>(); var weightsMap = new Dictionary <MultidimensionalArray, int>(); foreach (var chunkRulePair in ruleSet) { Chunk chunk = chunkRulePair.Chunk; TQuadRule rule = chunkRulePair.Rule; Debug.Assert(rule.Nodes.IsLocked, "Error in quadrature rule creation: factory delivered some rule non-locked node set."); int iNode; if (!nodesMap.TryGetValue(rule.Nodes, out iNode)) { // nodes must be added nodes.Add(rule.Nodes); iNode = nodes.Count - 1; nodesMap.Add(rule.Nodes, iNode); } int iWeight; if (!weightsMap.TryGetValue(rule.Weights, out iWeight)) { // weights must be added weights.Add(rule.Weights); iWeight = weights.Count - 1; weightsMap.Add(rule.Weights, iWeight); } // Make sure arrays are not only equal but identical (i.e., // reference equals) rule.Nodes = nodes[iNode]; rule.Weights = weights[iWeight]; compositeRule.chunkRulePairs.Add( new ChunkRulePair <TQuadRule>(chunk, rule)); } return(compositeRule); }
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 IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } var baseSet = baseFactory.GetQuadRuleSet(mask, order); var result = new List <ChunkRulePair <QuadRule> >(); foreach (var chunkRulePair in baseSet) { MultidimensionalArray levelSetValues = tracker.DataHistories[levSetIndex].Current.GetLevSetValues( chunkRulePair.Rule.Nodes, chunkRulePair.Chunk.i0, chunkRulePair.Chunk.Len); MultidimensionalArray gradientValues = tracker.DataHistories[levSetIndex].Current.GetLevelSetGradients( chunkRulePair.Rule.Nodes, chunkRulePair.Chunk.i0, chunkRulePair.Chunk.Len); foreach (int cell in chunkRulePair.Chunk.Elements) { QuadRule rule = chunkRulePair.Rule.CloneAs(); for (int i = 0; i < rule.NoOfNodes; i++) { rule.Weights[i] *= polynomial.Evaluate(levelSetValues[cell - chunkRulePair.Chunk.i0, i], width); // Scale by the norm of the gradient in order to be on // the safe side with non-signed-distance functions double norm = 0.0; for (int j = 0; j < RefElement.SpatialDimension; j++) { int index = cell - chunkRulePair.Chunk.i0; norm += gradientValues[index, i, j] * gradientValues[index, i, j]; } rule.Weights[i] *= Math.Sqrt(norm); } result.Add(new ChunkRulePair <QuadRule>( Chunk.GetSingleElementChunk(cell), rule)); } } return(result); }
public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } QuadRule fullRule = RefElement.GetQuadratureRule(order); int L1 = fullRule.NoOfNodes; int D = fullRule.SpatialDim; var otherRule = m_orgrule.GetQuadRuleSet(mask, order); var ret = new List <IChunkRulePair <QuadRule> >(otherRule.Count()); foreach (var x in otherRule) { Chunk chk = x.Chunk; QuadRule qr = x.Rule; int L2 = qr.NoOfNodes; Debug.Assert(qr.SpatialDim == fullRule.SpatialDim); QuadRule compQr = new QuadRule(); compQr.OrderOfPrecision = qr.OrderOfPrecision; compQr.Nodes = new NodeSet(this.RefElement, L1 + L2, D); compQr.Weights = MultidimensionalArray.Create(L1 + L2); compQr.Nodes.SetSubArray(fullRule.Nodes, new int[] { 0, 0 }, new int[] { L1 - 1, D - 1 }); compQr.Weights.SetSubArray(fullRule.Weights, new int[] { 0 }, new int[] { L1 - 1 }); compQr.Nodes.SetSubArray(qr.Nodes, new int[] { L1, 0 }, new int[] { L1 + L2 - 1, D - 1 }); compQr.Weights.AccSubArray(-1, qr.Weights, new int[] { L1 }, new int[] { L1 + L2 - 1 }); compQr.Nodes.LockForever(); ret.Add(new ChunkRulePair <QuadRule>(chk, compQr)); } return(ret); }
/// <summary> /// Uses the given edge rule factory to create quadrature rules for /// the boundaries of all cells in <paramref name="mask"/>. /// </summary> /// <param name="mask"> /// A <b><see cref="CellMask"/></b> containing all cells to be /// integrated over. /// </param> /// <param name="order"> /// <see cref="IQuadRuleFactory{T}.GetQuadRuleSet"/> /// </param> /// <returns> /// Quadrature rules for the boundary of all cells in /// <paramref name="mask"/> in the volume coordinate system. /// </returns> public IEnumerable <IChunkRulePair <T> > GetQuadRuleSet(ExecutionMask mask, int order) { if (!(mask is CellMask)) { throw new ArgumentException("Expecting a cell/volume mask."); } if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } if (!object.ReferenceEquals(this.context, mask.GridData)) { throw new ArgumentException(); } // helper vars int D = this.context.SpatialDimension; var CellToEdge = this.context.iLogicalCells.Cells2Edges; var EdgeToCell = this.context.iLogicalEdges.CellIndices; var FaceIndices = this.context.iGeomEdges.FaceIndices; var TrafoIdx = this.context.iGeomEdges.Edge2CellTrafoIndex; var EdgeToCellTrafos = this.context.iGeomEdges.Edge2CellTrafos; int NoOfFaces = RefElement.NoOfFaces; var Scalings = context.iGeomEdges.Edge2CellTrafos_SqrtGramian; int J = this.context.iLogicalCells.NoOfLocalUpdatedCells; // output data structure, temporary Dictionary <int, T> cellBndRuleMap = new Dictionary <int, T>(); // Get edge quad rules BitArray edgeBitMask = new BitArray(context.iGeomEdges.Count); foreach (Chunk chunk in mask) { foreach (int cell in chunk.Elements) { var LocalCellIndexToEdges_cell = CellToEdge[cell]; for (int e = LocalCellIndexToEdges_cell.Length - 1; e >= 0; e--) { int edge = Math.Abs(LocalCellIndexToEdges_cell[e]) - 1; edgeBitMask[edge] = true; } cellBndRuleMap.Add(cell, new T() { NumbersOfNodesPerFace = new int[NoOfFaces] }); } } IEnumerable <IChunkRulePair <QuadRule> > edgeRuleMap = edgeRuleFactory.GetQuadRuleSet( new EdgeMask(context, edgeBitMask, MaskType.Geometrical), order); // build cell boundary rule var CellBitMask = mask.GetBitMask(); foreach (var edgeRule in edgeRuleMap) { QuadRule rule = edgeRule.Rule; Debug.Assert(rule.Nodes.GetLength(1) == Math.Max(D - 1, 1)); int iEdge0 = edgeRule.Chunk.i0; int iEdgeE = edgeRule.Chunk.JE; for (int iEdge = iEdge0; iEdge < iEdgeE; iEdge++) { for (int kk = 0; kk < 2; kk++) // loop over in and out { int jCell = EdgeToCell[iEdge, kk]; if (jCell < 0 || jCell >= J) { continue; } if (!CellBitMask[jCell]) { continue; } int iTrafo = TrafoIdx[iEdge, kk]; var trafo = EdgeToCellTrafos[iTrafo]; int iFace = FaceIndices[iEdge, kk]; double scl = Scalings[iTrafo]; NodeSet VolumeNodes = new NodeSet(this.RefElement, rule.NoOfNodes, D); trafo.Transform(rule.Nodes, VolumeNodes); VolumeNodes.LockForever(); var cellBndRule = cellBndRuleMap[jCell]; AddToCellBoundaryRule(cellBndRule, VolumeNodes, rule.Weights, iFace, scl); } } } // return // ====== { int[] Cells = cellBndRuleMap.Keys.ToArray(); Array.Sort(Cells); ChunkRulePair <T>[] R = new ChunkRulePair <T> [Cells.Length]; for (int i = 0; i < R.Length; i++) { int jCell = Cells[i]; cellBndRuleMap[jCell].Nodes.LockForever(); R[i] = new ChunkRulePair <T>(Chunk.GetSingleElementChunk(jCell), cellBndRuleMap[jCell]); } return(R); } }
public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } QuadRule baseRule = Line.Instance.GetQuadratureRule(order); var pointRules = rootFactory.GetQuadRuleSet(mask, order); var result = new List <ChunkRulePair <QuadRule> >(); foreach (Chunk chunk in mask) { foreach (int cell in chunk.Elements) { var pointRule = pointRules.Single(pair => pair.Chunk.i0 <= cell && pair.Chunk.JE > cell).Rule; QuadRule reconstructedRule; switch (pointRule.NoOfNodes) { case 0: case 1: // Cell not really cut reconstructedRule = QuadRule.CreateEmpty(RefElement, 1, 2); break; case 2: { LineSegment linearReconstruction = new LineSegment( RefElement.SpatialDimension, RefElement, pointRule.Nodes.GetRow(0), pointRule.Nodes.GetRow(1)); reconstructedRule = QuadRule.CreateEmpty( RefElement, baseRule.NoOfNodes, RefElement.SpatialDimension); for (int i = 0; i < baseRule.NoOfNodes; i++) { reconstructedRule.Weights[i] = baseRule.Weights[i] * linearReconstruction.Length / Line.Instance.Volume; double[] point = linearReconstruction.GetPointOnSegment(baseRule.Nodes[i, 0]); for (int d = 0; d < RefElement.SpatialDimension; d++) { reconstructedRule.Nodes[i, d] = point[d]; } } } break; case 4: { // Assume only single interface double[] xCoords = pointRule.Nodes.GetColumn(0); double maxXDist = xCoords.Max() - xCoords.Min(); double[] yCoords = pointRule.Nodes.GetColumn(1); double maxYDist = yCoords.Max() - yCoords.Min(); int orderingDirection; if (maxXDist > maxYDist) { orderingDirection = 0; } else { orderingDirection = 1; } double[][] roots = new double[pointRule.NoOfNodes][]; for (int i = 0; i < roots.Length; i++) { roots[i] = new double[] { pointRule.Nodes[i, 0], pointRule.Nodes[i, 1] }; } var orderedRoots = roots.OrderBy(t => t[orderingDirection]).ToArray(); // Now, construct two separate rules LineSegment linearReconstruction1 = new LineSegment( RefElement.SpatialDimension, RefElement, orderedRoots[0], orderedRoots[1]); LineSegment linearReconstruction2 = new LineSegment( RefElement.SpatialDimension, RefElement, orderedRoots[2], orderedRoots[3]); reconstructedRule = QuadRule.CreateEmpty( RefElement, 2 * baseRule.NoOfNodes, RefElement.SpatialDimension); for (int i = 0; i < baseRule.NoOfNodes; i++) { reconstructedRule.Weights[i] = baseRule.Weights[i] * linearReconstruction1.Length / Line.Instance.Volume; double[] point = linearReconstruction1.GetPointOnSegment(baseRule.Nodes[i, 0]); for (int d = 0; d < RefElement.SpatialDimension; d++) { reconstructedRule.Nodes[i, d] = point[d]; } int offset = baseRule.NoOfNodes; reconstructedRule.Weights[offset + i] = baseRule.Weights[i] * linearReconstruction2.Length / Line.Instance.Volume; point = linearReconstruction2.GetPointOnSegment(baseRule.Nodes[i, 0]); for (int d = 0; d < RefElement.SpatialDimension; d++) { reconstructedRule.Nodes[offset + i, d] = point[d]; } } } break; default: throw new NotImplementedException(); } reconstructedRule.Nodes.LockForever(); MultidimensionalArray metrics = tracker.DataHistories[0].Current.GetLevelSetNormalReferenceToPhysicalMetrics(reconstructedRule.Nodes, cell, 1); for (int i = 0; i < reconstructedRule.NoOfNodes; i++) { reconstructedRule.Weights[i] /= metrics[0, i]; } result.Add(new ChunkRulePair <QuadRule>( Chunk.GetSingleElementChunk(cell), reconstructedRule)); } } return(result); }
public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } var standardVolumeRules = baseFactory.GetQuadRuleSet(mask, order); var pointRules = rootFactory.GetQuadRuleSet(mask, order); var result = new List <ChunkRulePair <QuadRule> >(); foreach (var chunkRulePair in standardVolumeRules) { foreach (int cell in chunkRulePair.Chunk.Elements) { QuadRule standardRule = chunkRulePair.Rule; var pointRule = pointRules.Single(pair => pair.Chunk.i0 <= cell && pair.Chunk.JE > cell).Rule; MultidimensionalArray gradientsAtRoots = tracker.DataHistories[0].Current.GetLevelSetGradients(pointRule.Nodes, cell, 1); QuadRule modifiedRule; switch (pointRule.NoOfNodes) { case 0: case 1: { // Cell not really cut MultidimensionalArray levelSetValue = tracker.DataHistories[0].Current.GetLevSetValues( new NodeSet(RefElement, new double[2]), cell, 1); if (Math.Sign(levelSetValue.Storage[0]) < 0) { // Cell is completely void QuadRule emptyRule = QuadRule.CreateEmpty(RefElement, 1, 2); emptyRule.Nodes.LockForever(); modifiedRule = emptyRule; } else { // Cell is completely non-void modifiedRule = standardRule; } } break; case 2: { double a, b, c; GetLevelSetApproximationCofficients(cell, pointRule.Nodes.GetRow(0), pointRule.Nodes.GetRow(1), out a, out b, out c); double[] eqcv = Heqpol_coefficients(a, b, c); modifiedRule = standardRule.CloneAs(); for (int i = 0; i < modifiedRule.NoOfNodes; i++) { double x = modifiedRule.Nodes[i, 0]; double y = modifiedRule.Nodes[i, 1]; // double[] v = new double[] { // 1.0, x, x * x, y, x * y, y * y }; double v = eqcv[0] + eqcv[1] * x + eqcv[2] * x * x + eqcv[3] * y + eqcv[4] * x * y + eqcv[5] * y * y; modifiedRule.Weights[i] *= v; } modifiedRule.Nodes.LockForever(); } break; case 4: { // Assume only single interface double[] xCoords = pointRule.Nodes.GetColumn(0); double maxXDist = xCoords.Max() - xCoords.Min(); double[] yCoords = pointRule.Nodes.GetColumn(1); double maxYDist = yCoords.Max() - yCoords.Min(); int orderingDirection; if (maxXDist > maxYDist) { orderingDirection = 0; } else { orderingDirection = 1; } double[][] roots = new double[pointRule.NoOfNodes][]; for (int i = 0; i < roots.Length; i++) { roots[i] = new double[] { pointRule.Nodes[i, 0], pointRule.Nodes[i, 1] }; } var orderedRoots = roots.OrderBy(t => t[orderingDirection]).ToArray(); // Now, do the equivalent polynomial thing double a, b, c; GetLevelSetApproximationCofficients(cell, orderedRoots[0], orderedRoots[1], out a, out b, out c); double[] eqcv1 = Heqpol_coefficients(a, b, c); GetLevelSetApproximationCofficients(cell, orderedRoots[2], orderedRoots[3], out a, out b, out c); double[] eqcv2 = Heqpol_coefficients(a, b, c); modifiedRule = standardRule.CloneAs(); for (int i = 0; i < modifiedRule.NoOfNodes; i++) { double x = modifiedRule.Nodes[i, 0]; double y = modifiedRule.Nodes[i, 1]; // double[] v = new double[] { // 1.0, x, x * x, y, x * y, y * y }; double v1 = eqcv1[0] + eqcv1[1] * x + eqcv1[2] * x * x + eqcv1[3] * y + eqcv1[4] * x * y + eqcv1[5] * y * y; double v2 = eqcv2[0] + eqcv2[1] * x + eqcv2[2] * x * x + eqcv2[3] * y + eqcv2[4] * x * y + eqcv2[5] * y * y; modifiedRule.Weights[i] *= v1 * v2; } } break; default: throw new NotImplementedException(); } result.Add(new ChunkRulePair <QuadRule>( Chunk.GetSingleElementChunk(cell), modifiedRule)); } } return(result); }
/// <summary> /// produces an edge quadrature rule /// </summary> /// <param name="mask">an edge mask</param> /// <param name="order">desired order</param> /// <returns></returns> public IEnumerable <IChunkRulePair <DoubleEdgeQuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (!(mask is EdgeMask)) { throw new ArgumentException(); } EdgeMask edgMask = mask as EdgeMask; var ret = new Dictionary <Chunk, DoubleEdgeQuadRule>(mask.NoOfItemsLocally); #if DEBUG var EdgesOfInterest = edgMask.GetBitMask(); var EdgeTouched = (BitArray)EdgesOfInterest.Clone(); #endif WeightInbalance = 0.0; // find all cells that are 'touched' by the edge mask // -------------------------------------------------- int J = grd.NoOfLocalUpdatedCells; BitArray TouchedCells = new BitArray(J, false); var Edg2Cell = grd.Edges; int chunkCnt = 0; foreach (var chnk in mask) { int EE = chnk.JE; for (int e = chnk.i0; e < EE; e++) { int j1 = Edg2Cell[e, 0], j2 = Edg2Cell[e, 1]; TouchedCells[j1] = true; if (j2 >= 0) { TouchedCells[j2] = true; } Chunk singleEdgeChunk; singleEdgeChunk.i0 = e; singleEdgeChunk.Len = 1; ret.Add(singleEdgeChunk, null); } chunkCnt++; } CellMask celMask = (new CellMask(grd, TouchedCells)); // create cell boundary rule! IEnumerable <IChunkRulePair <CellBoundaryQuadRule> > cellBndRule = m_cellBndQF.GetQuadRuleSet(celMask, order); // do MPI communication (get rules for external cells) { int size, rank; csMPI.Raw.Comm_Rank(csMPI.Raw._COMM.WORLD, out rank); csMPI.Raw.Comm_Size(csMPI.Raw._COMM.WORLD, out size); if (size > 1) { throw new NotSupportedException("currently no MPI support"); } } // assign the cell boundary rule to edges // -------------------------------------- var volSplx = m_cellBndQF.Simplex; int NoOfFaces = volSplx.NoOfEdges; var Cells2Edge = grd.LocalCellIndexToEdges; foreach (var kv in cellBndRule) // loop over cell chunks (in the cell boundary rule)... { Chunk chk = kv.Chunk; CellBoundaryQuadRule qr = kv.Rule; int JE = chk.JE; for (int j = chk.i0; j < JE; j++) // loop over all cells in chunk... { Debug.Assert(qr.NumbersOfNodesPerEdge.Length == NoOfFaces); for (int e = 0; e < NoOfFaces; e++) // loop over faces of cell... //if (qr.NumbersOfNodesPerEdge[e] <= 0) // // no contribution from this edge // continue; { int iEdge = Math.Abs(Cells2Edge[j, e]) - 1; Chunk singleEdgeChunk = Chunk.GetSingleElementChunk(iEdge); DoubleEdgeQuadRule qrEdge; if (ret.TryGetValue(singleEdgeChunk, out qrEdge)) { // we are interested in this edge! #if DEBUG Debug.Assert(EdgesOfInterest[iEdge] == true); EdgeTouched[iEdge] = false; var vtx = this.Simplex.Vertices; MultidimensionalArray _vtx = MultidimensionalArray.Create(vtx.GetLength(0), vtx.GetLength(1)); _vtx.SetA2d(vtx); var VolSimplex = m_cellBndQF.Simplex; var RefCoord = MultidimensionalArray.Create(vtx.GetLength(0), vtx.GetLength(1) + 1); var PhysCoord = MultidimensionalArray.Create(1, vtx.GetLength(0), vtx.GetLength(1) + 1); VolSimplex.EdgeToVolumeCoordinates(e, _vtx, RefCoord); grd.TransformLocal2Global(RefCoord, PhysCoord, j, 1, 0); #endif qrEdge = CombineQr(qrEdge, qr, e, j); Debug.Assert(qrEdge != null); ret[singleEdgeChunk] = qrEdge; } else { // nop: the edge is not in the 'edgMask'! continue; } } } } #if DEBUG for (int i = EdgeTouched.Length - 1; i >= 0; i--) { Debug.Assert(EdgeTouched[i] == false); } #endif return(ret.Select(p => new ChunkRulePair <DoubleEdgeQuadRule>(p.Key, p.Value))); }