public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (mask == null) { mask = EdgeMask.GetFullMask(tracker.Ctx.GridDat); } if (mask is EdgeMask == false) { throw new Exception(); } QuadRule baseRule = lineSimplex.GetQuadratureRule(order); int D = tracker.Ctx.Grid.GridSimplex.SpatialDimension; var result = new List <ChunkRulePair <QuadRule> >(mask.NoOfItemsLocally); foreach (Chunk chunk in mask) { for (int i = 0; i < chunk.Len; i++) { List <double[]> nodes = new List <double[]>(); List <double> weights = new List <double>(); int[] noOfNodesPerEdge = new int[referenceLineSegments.Length]; int edge = i + chunk.i0; // Always choose 'left' edge int cell = tracker.Ctx.GridDat.Edges[edge, 0]; int localEdge = tracker.Ctx.GridDat.EdgeIndices[edge, 0]; LineSegment referenceSegment = referenceLineSegments[localEdge]; double[] roots = referenceSegment.GetRoots(tracker.LevelSets[levSetIndex], cell); LineSegment[] subSegments = referenceSegment.Split(roots); for (int k = 0; k < subSegments.Length; k++) { 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]); uint lh = tracker.Ctx.NSC.LockNodeSetFamily( tracker.Ctx.NSC.CreateContainer( MultidimensionalArray.CreateWrapper(point, 1, D), -1.0)); MultidimensionalArray levelSetValue = tracker.GetLevSetValues(levSetIndex, 0, cell, 1); tracker.Ctx.NSC.UnlockNodeSetFamily(lh); // Only positive volume if (levelSetValue[0, 0] <= 0.0) { continue; } weights.Add(baseRule.Weights[m] * subSegments[k].Length / referenceSegment.Length); nodes.Add(point); } } if (weights.Count == 0) { continue; } MultidimensionalArray localNodes = MultidimensionalArray.Create(nodes.Count, D); for (int j = 0; j < nodes.Count; j++) { for (int d = 0; d < D; d++) { localNodes[j, d] = nodes[j][d]; } } MultidimensionalArray localEdgeNodes = MultidimensionalArray.Create(nodes.Count, 1); tracker.Ctx.Grid.GridSimplex.VolumeToEdgeCoordinates(localEdge, localNodes, localEdgeNodes); QuadRule subdividedRule = new QuadRule() { OrderOfPrecision = order, Weights = MultidimensionalArray.Create(weights.Count), Nodes = localEdgeNodes.CloneAs() }; subdividedRule.Weights.SetV(weights, -1); result.Add(new ChunkRulePair <QuadRule>( Chunk.GetSingleElementChunk(edge), subdividedRule)); } } return(result); }
/// <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> /// Returns a set of <see cref="CellEdgeBoundaryQuadRule"/>s that /// enables the integration over sub-segments of the edges of the edges /// of a (three-dimensional) domain. This is obviously only useful if /// the integrand has a discontinuity that is aligned with the zero /// iso-contour of the level set function. /// </summary> /// <param name="mask"></param> /// <param name="order"></param> /// <returns></returns> public IEnumerable <IChunkRulePair <CellEdgeBoundaryQuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (mask == null) { mask = CellMask.GetFullMask(this.lsData.GridDat, MaskType.Geometrical); } if (mask is CellMask == false) { throw new ArgumentException("Edge mask required", "mask"); } if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } if (lastOrder != order) { cache.Clear(); } QuadRule baseRule = lineSimplex.GetQuadratureRule(order); int D = lsData.GridDat.SpatialDimension; int noOfEdges = lsData.GridDat.Grid.RefElements[0].NoOfFaces; int noOfEdgesOfEdge = RefElement.FaceRefElement.NoOfFaces; var result = new List <ChunkRulePair <CellEdgeBoundaryQuadRule> >(mask.NoOfItemsLocally); foreach (Chunk chunk in mask) { for (int i = 0; i < chunk.Len; i++) { int cell = i + chunk.i0; if (cache.ContainsKey(cell)) { result.Add(new ChunkRulePair <CellEdgeBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), cache[cell])); continue; } List <double[]> nodes = new List <double[]>(); List <double> weights = new List <double>(); if (lsData.GridDat.Cells.Cells2Edges[cell].Length != noOfEdges) { throw new NotImplementedException("Not implemented for hanging nodes"); } int[] noOfNodesPerEdge = new int[noOfEdges]; int[,] noOfNodesPerEdgeOfEdge = new int[noOfEdges, noOfEdgesOfEdge]; for (int e = 0; e < noOfEdges; e++) { int edge = Math.Abs(lsData.GridDat.Cells.Cells2Edges[cell][e]) - 1; double edgeDet = lsData.GridDat.Edges.SqrtGramian[edge]; for (int ee = 0; ee < noOfEdgesOfEdge; ee++) { LineSegment refSegment = referenceLineSegments[e, ee]; double edgeOfEdgeDet = RefElement.FaceRefElement.FaceTrafoGramianSqrt[ee]; double[] roots = refSegment.GetRoots(lsData.LevelSet, cell, 0); LineSegment[] subSegments = refSegment.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 scaling = edgeOfEdgeDet * subSegments[k].Length / refSegment.Length; if (jumpType != JumpTypes.Implicit) { //using (tracker.GridDat.NSC.CreateLock( // MultidimensionalArray.CreateWrapper(point, 1, D), 0, -1.0)) { MultidimensionalArray levelSetValue = lsData.GetLevSetValues(_point, cell, 1); switch (jumpType) { case JumpTypes.Heaviside: if (levelSetValue[0, 0] <= 0.0) { continue; } break; case JumpTypes.OneMinusHeaviside: if (levelSetValue[0, 0] > 0.0) { continue; } break; case JumpTypes.Sign: scaling *= 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(baseRule.Weights[m] * scaling); nodes.Add(point); noOfNodesPerEdge[e]++; noOfNodesPerEdgeOfEdge[e, ee]++; } } } } if (weights.Count == 0) { CellEdgeBoundaryQuadRule emptyRule = CellEdgeBoundaryQuadRule.CreateEmpty(1, RefElement); emptyRule.Nodes.LockForever(); cache.Add(cell, emptyRule); result.Add(new ChunkRulePair <CellEdgeBoundaryQuadRule>( 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(); CellEdgeBoundaryQuadRule subdividedRule = new CellEdgeBoundaryQuadRule() { OrderOfPrecision = order, Weights = MultidimensionalArray.Create(weights.Count), Nodes = localNodes, NumbersOfNodesPerFace = noOfNodesPerEdge, NumbersOfNodesPerFaceOfFace = noOfNodesPerEdgeOfEdge }; subdividedRule.Weights.SetSubVector(weights, -1); cache.Add(cell, subdividedRule); result.Add(new ChunkRulePair <CellEdgeBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), subdividedRule)); } } return(result); }