/// <summary> /// Run this /// </summary> /// <param name="mask"></param> /// <param name="order"></param> void CalculateComboQuadRuleSet(ExecutionMask mask, int order) { comboRule.order = order; rulez[0].Clear(); rulez[1].Clear(); //Find quadrature nodes and weights in each cell/chunk #if LOG_TIME Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); #endif foreach (Chunk chunk in mask) { foreach (int cell in chunk.Elements) { QuadRule[] sayeRule = comboRule.ComboEvaluate(cell); ChunkRulePair <QuadRule> sayePair_volume = new ChunkRulePair <QuadRule>(Chunk.GetSingleElementChunk(cell), sayeRule[0]); ChunkRulePair <QuadRule> sayePair_surface = new ChunkRulePair <QuadRule>(Chunk.GetSingleElementChunk(cell), sayeRule[1]); rulez[0].Add(sayePair_volume); rulez[1].Add(sayePair_surface); } } #if LOG_TIME stopWatch.Stop(); long ts = stopWatch.ElapsedMilliseconds; Console.WriteLine("Calculated combo cutcell rule : {0}ms", ts); #endif }
/* * /// <summary> * /// initialized by the constructor to avoid MPI-deadlocks; * /// </summary> * Dictionary<RefElement, EdgeMask> m_Subgrid4Kref_AllEdges = new Dictionary<RefElement, EdgeMask>(); */ //LevelSetTracker lsTrk { // get { // return XDGSpaceMetrics.Tracker; // } //} public EdgeQuadratureScheme Get_SurfaceElement_EdgeQuadScheme(SpeciesId sp) { if (!this.SpeciesList.Contains(sp)) { throw new ArgumentException("Given species (id = " + sp.cntnt + ") is not supported."); } //var allRelevantEdges = this.m_SpeciesSubgrid_InnerAndDomainEdges[sp].Intersect(this.m_CutCellSubgrid_InnerEdges); var innerCutCellEdges = this.XDGSpaceMetrics.LevelSetRegions.GetCutCellSubGrid().InnerEdgesMask; var boundaryCutCellEdges = ExecutionMask.Intersect(this.XDGSpaceMetrics.LevelSetRegions.GetCutCellSubGrid().BoundaryEdgesMask, this.XDGSpaceMetrics.GridDat.BoundaryEdges); var allRelevantEdges = this.m_SpeciesSubgrid_InnerAndDomainEdges[sp].Intersect(ExecutionMask.Union(innerCutCellEdges, boundaryCutCellEdges)); //EdgeMask AggEdges = this.CellAgglomeration != null ? this.CellAgglomeration.GetAgglomerator(sp).AggInfo.AgglomerationEdges : null; //if (AggEdges != null && AggEdges.NoOfItemsLocally > 0) // allRelevantEdges = allRelevantEdges.Except(AggEdges); var edgeQrIns = new EdgeQuadratureScheme(false, allRelevantEdges); foreach (var Kref in XDGSpaceMetrics.GridDat.Grid.RefElements) { for (int iLevSet = 0; iLevSet < XDGSpaceMetrics.NoOfLevelSets; iLevSet++) // loop over level sets... { EdgeMask cutEdges = this.GetCutEdges(Kref, iLevSet); var factory = this.XDGSpaceMetrics.XQuadFactoryHelper.GetSurfaceElement_BoundaryRuleFactory(iLevSet, Kref); edgeQrIns.AddFactory(factory, cutEdges); } } return(edgeQrIns); }
public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (!RuleStatus.initialized || order != RuleStatus.order) { #if LOG_ACTIONS Console.WriteLine("Initialize {0} \n", quadMode); #endif return(InitializeRule(mask, order)); } else { switch (RuleStatus.RecalculationMode) { case Mode.CalculateOnceAfterInstantiation: #if LOG_ACTIONS Console.WriteLine("Reusing {0} \n", quadMode); #endif return(UseExistingRule(mask)); //break; case Mode.RecalculateOnEveryVolumeCall: if (quadMode == QuadratureType.Volume) { #if LOG_ACTIONS Console.WriteLine("Recalcing {0} \n", quadMode); #endif return(InitializeRule(mask, order)); } else { #if LOG_ACTIONS Console.WriteLine("Reusing {0} \n", quadMode); #endif return(UseExistingRule(mask)); } //break; case Mode.RecalculateOnEverySurfaceCall: if (quadMode == QuadratureType.Surface) { #if LOG_ACTIONS Console.WriteLine("Recalcing {0} \n", quadMode); #endif return(InitializeRule(mask, order)); } else { #if LOG_ACTIONS Console.WriteLine("Reusing {0} \n", quadMode); #endif return(UseExistingRule(mask)); } //break; default: throw new NotImplementedException(); //break; } } }
IEnumerable <IChunkRulePair <QuadRule> > UseExistingRule(ExecutionMask subMask) { if (subMask.Equals(RuleStatus.initialMask)) { return(rule); } //If not, filter rules to fit subMask else { Debug.Assert(subMask.IsSubMaskOf(RuleStatus.initialMask)); List <IChunkRulePair <QuadRule> > subRulez = new List <IChunkRulePair <QuadRule> >(subMask.Count()); IEnumerator <int> initialMask_enum = RuleStatus.initialMask.GetItemEnumerator(); int i = 0; BitArray subMask_bitmask = subMask.GetBitMask(); while (initialMask_enum.MoveNext()) { if (subMask_bitmask[initialMask_enum.Current]) { subRulez.Add(rule.ElementAt(i)); } ++i; } return(subRulez); } }
public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { rule.order = order; var result = new List <ChunkRulePair <QuadRule> >(); #if LOG_TIME Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); #endif //Find quadrature nodes and weights in each cell/chunk foreach (Chunk chunk in mask) { foreach (int cell in chunk.Elements) { QuadRule sayeRule = rule.Evaluate(cell); ChunkRulePair <QuadRule> sayePair = new ChunkRulePair <QuadRule>(Chunk.GetSingleElementChunk(cell), sayeRule); result.Add(sayePair); } } #if LOG_TIME stopWatch.Stop(); long ts = stopWatch.ElapsedMilliseconds; Console.WriteLine("Calculated cutcell rule : {0}ms", ts); #endif return(result); }
/// <summary> /// Estimates the distance below which we consider an element (i.e., /// cell or edge) cut. This is important in the case of curved /// interfaces. /// </summary> /// <param name="element"> /// The element (edge or cell) in question. /// </param> /// <param name="mask"> /// The mask containing the given element <paramref name="element"/>. /// </param> /// <returns> /// The minimal distance below which consider element /// <paramref name="element"/> cut. /// </returns> /// <remarks> /// Uses different estimates depending on the element type. The case of /// edges is straightforward (since we don't have enough information to /// do something sophisticated). For cells, we use a modified version of /// a formular given by MinGibou2007: /// \f$ /// \max |\Phi(v)| \leq 0.5 * \mathrm{Lip}(\Phi) h_\mathrm{max}. /// \f$ /// In particular, we assume that the Lipschitz constant is close to 1 /// which is true if the level set is signed distance. A more /// sophisticated method would evaluate the gradients at the vertices /// in order to estimate the Lipschitz constant, but this would be less /// efficient. /// </remarks> private double EstimateMinDistance(int element, ExecutionMask mask) { double minDistance = double.NaN; if (mask is CellMask) { // Assume norm of gradient \approx 1 // -> Lipschitz constant is in the order of 1 double hMaxEdge = -1.0; int[] cells2Edges = gridData.Cells.Cells2Edges[element]; for (int e = 0; e < cells2Edges.Length; e++) { int edgeIndex = Math.Abs(cells2Edges[e]) - 1; hMaxEdge = Math.Max(gridData.Edges.h_max_Edge[edgeIndex], hMaxEdge); } minDistance = 0.5 * hMaxEdge; } else if (mask is EdgeMask) { //minDistance = 0.5 * gridData.Edges.h_max_Edge[element]; minDistance = 1.0 * gridData.Edges.h_max_Edge[element]; } else { throw new NotImplementedException("Unknown mask type"); } return(minDistance); }
/// <summary> /// construction of the quadrature rule. /// </summary> public IEnumerable <IChunkRulePair <DoubleEdgeQuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } var orgQr = this.RefElement.GetQuadratureRule(order); var dblQr = new DoubleEdgeQuadRule(); dblQr.OrderOfPrecision = orgQr.OrderOfPrecision; int L = orgQr.NoOfNodes; int D = orgQr.Nodes.GetLength(1); dblQr.Median = L; dblQr.Nodes = new NodeSet(this.RefElement, L * 2, D); dblQr.Weights = MultidimensionalArray.Create(L * 2); dblQr.Nodes.SetSubArray(orgQr.Nodes, new int[] { 0, 0 }, new int[] { L - 1, D - 1 }); dblQr.Nodes.SetSubArray(orgQr.Nodes, new int[] { L, 0 }, new int[] { 2 * L - 1, D - 1 }); dblQr.Weights.SetSubArray(orgQr.Weights, new int[] { 0 }, new int[] { L - 1 }); dblQr.Weights.SetSubArray(orgQr.Weights, new int[] { L }, new int[] { 2 * L - 1 }); dblQr.Nodes.LockForever(); return(mask.Select(chunk => new ChunkRulePair <DoubleEdgeQuadRule>(chunk, dblQr))); }
public IEnumerable <IChunkRulePair <CellBoundaryQuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { using (var tr = new FuncTrace()) { if (mask != null && mask is CellMask == false) { throw new ArgumentException("Cell mask required", "mask"); } if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } Stopwatch totalTimer = new Stopwatch(); Stopwatch projectionTimer = new Stopwatch(); Stopwatch optimizationTimer = new Stopwatch(); totalTimer.Start(); if (order != currentOrder) { cache.Clear(); SwitchOrder(order); } var result = new List <ChunkRulePair <CellBoundaryQuadRule> >(mask.NoOfItemsLocally); foreach (Chunk chunk in mask) { for (int i = 0; i < chunk.Len; i++) { int cell = chunk.i0 + i; if (cache.ContainsKey(cell)) { result.Add(new ChunkRulePair <CellBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), cache[cell])); continue; } optimizationTimer.Start(); CellBoundaryQuadRule optimizedRule = GetOptimizedRule(chunk.i0 + i, order); optimizationTimer.Stop(); cache.Add(cell, optimizedRule); result.Add(new ChunkRulePair <CellBoundaryQuadRule>( Chunk.GetSingleElementChunk(i + chunk.i0), optimizedRule)); } } totalTimer.Stop(); double totalTicks = (double)totalTimer.ElapsedTicks; double percentageProjection = Math.Round(projectionTimer.ElapsedTicks / totalTicks * 100, 2); double percentageOptimization = Math.Round(optimizationTimer.ElapsedTicks / totalTicks * 100, 2); tr.Info("Percentage spent on projection to surface: " + percentageProjection.ToString(NumberFormatInfo.InvariantInfo) + "%"); tr.Info("Percentage spent on optimization: " + percentageOptimization.ToString(NumberFormatInfo.InvariantInfo) + "%"); return(result); } }
IEnumerable <IChunkRulePair <QuadRule> > InitializeRule(ExecutionMask subMask, int Order) { ComboRuleEvaluator(subMask, Order); RuleStatus.order = Order; RuleStatus.initialMask = subMask; RuleStatus.initialized = true; return(rule); }
/// <summary> /// Constructs the quadrature rules all edges of all cells in /// <paramref name="mask"/>. For edges that are not intersected by the /// zero iso-contour, standard Gaussian quadrature rules of /// sufficiently high order will be used. /// </summary> /// <param name="mask"> /// Cells for which quadrature rules shall be created /// </param> /// <param name="order"> /// Desired order of the moment-fitting system. Assuming that /// <see cref="edgeSurfaceRuleFactory"/> integrates the basis /// polynomials exactly over the zero iso-contour (which it usually /// doesn't!), the resulting quadrature rules will be exact up to this /// order. /// </param> /// <returns>A set of quadrature rules</returns> /// <remarks> /// Since the selected level set is generally discontinuous across cell /// boundaries, this method does not make use of the fact that /// neighboring cells share edges. That is, the optimization will be /// performed twice for each inner edge in <paramref name="mask"/>. /// </remarks> public IEnumerable <IChunkRulePair <CellBoundaryQuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { using (var tr = new FuncTrace()) { if (!(mask is CellMask)) { throw new ArgumentException("CellMask required", "mask"); } if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } int noOfEdges = LevelSetData.GridDat.Grid.RefElements[0].NoOfFaces; CellMask tmpLogicalMask = new CellMask(mask.GridData, mask.GetBitMask(), MaskType.Logical); #if DEBUG CellMask differingCells = tmpLogicalMask.Except(this.LevelSetData.Region.GetCutCellMask4LevSet(this.levelSetIndex)); if (differingCells.NoOfItemsLocally > 0) { throw new ArgumentException("The provided mask has to be a sub-set of the cut cells. " + "Cells {0} are not in the CutCellMaks of this tracker.", differingCells.GetSummary()); } #endif subGrid = new SubGrid(tmpLogicalMask); localCellIndex2SubgridIndex = subGrid.LocalCellIndex2SubgridIndex; if (order != lastOrder) { cache.Clear(); SwitchOrder(order); } var result = new List <ChunkRulePair <CellBoundaryQuadRule> >(mask.NoOfItemsLocally); CellBoundaryQuadRule[] optimizedRules = GetOptimizedRules((CellMask)mask, order); int n = 0; foreach (Chunk chunk in mask) { foreach (int cell in chunk.Elements) { if (cache.ContainsKey(cell)) { result.Add(new ChunkRulePair <CellBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), cache[cell])); } else { cache.Add(cell, optimizedRules[n]); result.Add(new ChunkRulePair <CellBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), optimizedRules[n])); } n++; } } return(result); } }
/// <summary> /// Uses <see cref="Grid.RefElement.GetQuadratureRule"/> to create a quad rule /// (i.e., the quad rule is the same for all elements of /// <paramref name="mask"/>) /// </summary> /// <param name="mask"> /// <see cref="IQuadRuleFactory{QuadRule}.GetQuadRuleSet"/> /// </param> /// <param name="order"> /// <see cref="IQuadRuleFactory{QuadRule}.GetQuadRuleSet"/> /// </param> /// <returns> /// <see cref="Grid.RefElement.GetQuadratureRule"/> /// </returns> public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { QuadRule rule = RefElement.GetQuadratureRule(order); Debug.Assert(rule.Nodes.IsLocked, "Error: non-locked quad rule from reference element."); Debug.Assert(object.ReferenceEquals(rule.Nodes.RefElement, RefElement), "Error: quad rule from reference element has not the right reference elment assigned."); return(mask.Select(chunk => new ChunkRulePair <QuadRule>(chunk, rule))); }
public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (!(mask is CellMask)) { throw new ArgumentException("Expecting a cell mask."); } if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } #if DEBUG if (mask.Except(m_Owner.MaxGrid).NoOfItemsLocally > 0) { throw new NotSupportedException("'mask' must be a subset of the cut cells, for my reference element."); } #endif if (!Rules.ContainsKey(order)) { m_Owner.GetQuadRuleSet_Internal(order); } if (mask.NoOfItemsLocally == m_Owner.MaxGrid.NoOfItemsLocally) { // aggressive return(Rules[order]); } else { var Rule = Rules[order]; SubGrid S = new SubGrid((CellMask)mask); var jsub2jcell = S.SubgridIndex2LocalCellIndex; var Ret = new ChunkRulePair <QuadRule> [S.LocalNoOfCells_WithExternal]; int L = Ret.Length, H = Rule.Length; int h = 0; for (int jsub = 0; jsub < L; jsub++) { int jCell = jsub2jcell[jsub]; Debug.Assert(Rule[h].Chunk.Len == 1); while (jCell > Rule[h].Chunk.i0) { h++; } Debug.Assert(jCell == Rule[h].Chunk.i0); Ret[jsub] = Rule[h]; } return(Ret); } }
/// <summary> /// Returns the quad rule supplied to the constructor for every /// single chunk in <paramref name="mask"/>. /// </summary> /// <param name="mask"> /// <see cref="IQuadRuleFactory{QuadRule}.GetQuadRuleSet"/> /// </param> /// <param name="order"> /// <see cref="IQuadRuleFactory{QuadRule}.GetQuadRuleSet"/> /// </param> /// <returns> /// <see cref="IQuadRuleFactory{QuadRule}.GetQuadRuleSet"/> /// </returns> public IEnumerable <IChunkRulePair <T> > GetQuadRuleSet(ExecutionMask mask, int order) { var result = new List <IChunkRulePair <T> >(mask.Count()); var quadRule = m_qr; foreach (Chunk chunk in mask) { result.Add(new ChunkRulePair <T>(chunk, quadRule)); } return(result); }
public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (!ruleStatus.Initialized || order != ruleStatus.Order) { InitializeRule(order); return(UseExistingRule(mask)); } else { return(UseExistingRule(mask)); } }
/// <summary> /// Uses <see cref="Grid.RefElement.GetQuadratureRule"/> to create a quad rule /// (i.e., the quad rule is the same for all elements of /// <paramref name="mask"/>) /// </summary> /// <param name="mask"> /// <see cref="IQuadRuleFactory{QuadRule}.GetQuadRuleSet"/> /// </param> /// <param name="order"> /// <see cref="IQuadRuleFactory{QuadRule}.GetQuadRuleSet"/> /// </param> /// <returns> /// <see cref="Grid.RefElement.GetQuadratureRule"/> /// </returns> public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } QuadRule rule = RefElement.GetQuadratureRule(order); Debug.Assert(rule.Nodes.IsLocked, "Error: non-locked quad rule from reference element."); Debug.Assert(object.ReferenceEquals(rule.Nodes.RefElement, RefElement), "Error: quad rule from reference element has not the right reference elment assigned."); return(mask.Select(chunk => new ChunkRulePair <QuadRule>(chunk, rule))); }
/// <summary> /// Returns the quad rule supplied to the constructor for every /// single chunk in <paramref name="mask"/>. /// </summary> /// <param name="mask"> /// <see cref="IQuadRuleFactory{QuadRule}.GetQuadRuleSet"/> /// </param> /// <param name="order"> /// <see cref="IQuadRuleFactory{QuadRule}.GetQuadRuleSet"/> /// </param> /// <returns> /// <see cref="IQuadRuleFactory{QuadRule}.GetQuadRuleSet"/> /// </returns> public IEnumerable <IChunkRulePair <T> > GetQuadRuleSet(ExecutionMask mask, int order) { if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } var result = new List <IChunkRulePair <T> >(mask.Count()); var quadRule = m_qr; foreach (Chunk chunk in mask) { result.Add(new ChunkRulePair <T>(chunk, quadRule)); } return(result); }
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); }
/// <summary> /// Constructs the <see cref="ExecutionMask"/> of the appropriate type /// containing all cells/edges with reference element <paramref name="E"/> /// </summary> /// <param name="E"></param> /// <param name="g"></param> /// <returns></returns> TDomain GetDomainForRefElement(Grid.RefElements.RefElement E, IGridData g) { ExecutionMask em = null; if (typeof(TDomain) == typeof(EdgeMask) || typeof(TDomain).IsSubclassOf(typeof(EdgeMask))) { em = g.iLogicalEdges.GetEdges4RefElement(E); } else if (typeof(TDomain) == typeof(CellMask) || typeof(TDomain).IsSubclassOf(typeof(CellMask))) { em = g.iLogicalCells.GetCells4Refelement(E); } else { throw new NotImplementedException(); } return((TDomain)(em)); }
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> /// Constructs the <see cref="ExecutionMask"/> of the appropriate type /// containing all cells/edges with reference element <paramref name="E"/> /// </summary> /// <param name="E"></param> /// <param name="g"></param> /// <returns></returns> TDomain GetDomainForRefElement(RefElement E, IGridData g) { ExecutionMask em = null; if (typeof(TDomain) == typeof(EdgeMask) || typeof(TDomain).IsSubclassOf(typeof(EdgeMask))) { em = g.iGeomEdges.GetEdges4RefElement(E); } else if (typeof(TDomain) == typeof(CellMask) || typeof(TDomain).IsSubclassOf(typeof(CellMask))) { em = g.iGeomCells.GetCells4Refelement(E); } else { throw new NotImplementedException(); } if (em.MaskType != MaskType.Geometrical) { throw new ApplicationException(); } return((TDomain)(em)); }
IEnumerable <IChunkRulePair <QuadRule> > IQuadRuleFactory <QuadRule> .GetQuadRuleSet(ExecutionMask mask, int order) { if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } var ret = new List <IChunkRulePair <QuadRule> >(); double R = RADIUS[iLevSet]; foreach (var chunk in mask) { for (int jCell = chunk.i0; jCell < chunk.JE; jCell++) { double alpha_0, alpha_1; FindAngles(jCell, RADIUS[this.iLevSet], _Context, out alpha_0, out alpha_1); if (alpha_0 == alpha_1) { QuadRule emptyRule = new QuadRule(); emptyRule.Nodes = new NodeSet(this.RefElement, new double[1, 2]); emptyRule.Weights = MultidimensionalArray.Create(1); emptyRule.OrderOfPrecision = 123; ret.Add(new ChunkRulePair <QuadRule>(new Chunk() { i0 = jCell, Len = 1 }, emptyRule)); } else { var da1Drule = this.RefElement.FaceRefElement.GetBruteForceQuadRule(8, order); QuadRule Bogenrule = new QuadRule(); var GlobNodes = MultidimensionalArray.Create(da1Drule.NoOfNodes, 2); var LocNodes = MultidimensionalArray.Create(1, da1Drule.NoOfNodes, 2); Bogenrule.Nodes = new NodeSet(this.RefElement, da1Drule.NoOfNodes, 2); for (int k = 0; k < da1Drule.NoOfNodes; k++) { double beta = da1Drule.Nodes[k, 0]; double alpha = alpha_0 + (beta + 1) * 0.5 * (alpha_1 - alpha_0); GlobNodes[k, 0] = R * Math.Cos(alpha); GlobNodes[k, 1] = R * Math.Sin(alpha); if (Position != null) { GlobNodes[k, 0] += Position[0]; GlobNodes[k, 1] += Position[1]; } } _Context.TransformGlobal2Local(GlobNodes, LocNodes, jCell, 1, 0); Bogenrule.Nodes.Set(LocNodes.ExtractSubArrayShallow(0, -1, -1)); var GlobCenter = MultidimensionalArray.Create(1, 2); var LocCenter = MultidimensionalArray.Create(1, 1, 2); _Context.TransformGlobal2Local(GlobCenter, LocCenter, jCell, 1, 0); //double RR = Math.Sqrt((LocNodes[0, 0, 0] - LocCenter[0, 0, 0]).Pow2() + (LocNodes[0, 0, 1] - LocCenter[0, 0, 1]).Pow2()); //double metric = (R*(alpha_1 - alpha_0)/2.0)/_Context.ChefBasis.Scaling[jCell]; double metric = (R * (alpha_1 - alpha_0) / 2.0) / _Context.Cells.JacobiDet[jCell]; //double metric = R; Bogenrule.OrderOfPrecision = 123; Bogenrule.Weights = da1Drule.Weights.CloneAs(); Bogenrule.Weights.Scale(metric); Bogenrule.Nodes.LockForever(); ret.Add(new ChunkRulePair <QuadRule>(new Chunk() { i0 = jCell, Len = 1 }, Bogenrule)); //*/ /* * var da1Drule = this.RefElement.FaceRefElement.GetBruteForceQuadRule(8, order); * * QuadRule PswsLin = new QuadRule(); * * var GlobNodes = MultidimensionalArray.Create(da1Drule.NoOfNodes, 2); * var LocNodes = MultidimensionalArray.Create(1, da1Drule.NoOfNodes, 2); * PswsLin.Nodes = new NodeSet(this.RefElement, da1Drule.NoOfNodes, 2); * * double x0 = Math.Cos(alpha_0) * R; * double y0 = Math.Sin(alpha_0) * R; * double x1 = Math.Cos(alpha_1) * R; * double y1 = Math.Sin(alpha_1) * R; * double dist = Math.Sqrt((x1 - x0).Pow2() + (y1 - y0).Pow2()); * * for(int k = 0; k < da1Drule.NoOfNodes; k++) { * double beta = da1Drule.Nodes[k, 0]; * //double alpha = alpha_0 + (beta + 1) * 0.5 * (alpha_1 - alpha_0); * * //GlobNodes[k, 0] = R * Math.Cos(alpha); * //GlobNodes[k, 1] = R * Math.Sin(alpha); * * double a = 0.5*(beta + 1); * GlobNodes[k, 0] = x0*(1 - a) + x1*a; * GlobNodes[k, 1] = y0 * (1 - a) + y1 * a; * * } * _Context.TransformGlobal2Local(GlobNodes, LocNodes, jCell, 1, 0); * PswsLin.Nodes.Set(LocNodes.ExtractSubArrayShallow(0, -1, -1)); * * var GlobCenter = MultidimensionalArray.Create(1, 2); * var LocCenter = MultidimensionalArray.Create(1, 1, 2); * _Context.TransformGlobal2Local(GlobCenter, LocCenter, jCell, 1, 0); * * //double RR = Math.Sqrt((LocNodes[0, 0, 0] - LocCenter[0, 0, 0]).Pow2() + (LocNodes[0, 0, 1] - LocCenter[0, 0, 1]).Pow2()); * * * //double metric = (R*(alpha_1 - alpha_0)/2.0)/_Context.ChefBasis.Scaling[jCell]; * double metric = (dist / 2.0) / _Context.Cells.JacobiDet[jCell]; * //double metric = R; * PswsLin.OrderOfPrecision = 123; * PswsLin.Weights = da1Drule.Weights.CloneAs(); * PswsLin.Weights.Scale(metric); * PswsLin.Nodes.LockForever(); * * ret.Add(new ChunkRulePair<QuadRule>(new Chunk() { i0 = jCell, Len = 1 }, PswsLin)); */ } } } return(ret); }
/// <summary> /// Constructs the adapted subdivisions for all cells in /// <paramref name="mask"/>. The size of each chunk will be exactly one /// since, in general, we cannot expect subsequent cells to have the /// same subdivisions. /// </summary> /// <param name="mask"> /// <see cref="ISubdivisionStrategy.GetSubdivisionNodes"/> /// </param> /// <returns> /// The subdivisions for all elements in <paramref name="mask"/>, /// </returns> public IEnumerable <KeyValuePair <Chunk, IEnumerable <SubdivisionNode> > > GetSubdivisionNodes(ExecutionMask mask) { using (new FuncTrace()) { foreach (int iElement in mask.ItemEnum) // loop over all cells/edges in mask { this.subdivisionTree.ResetToSavePoint(); double minDistance = EstimateMinDistance(iElement, mask); NestedVertexSet currentSet = baseVertexSet; for (int i = 0; i < maxDivisions; i++) { if (currentSet.NumberOfLocalVertices == 0) { // No new vertices were added during last subdivision break; } int cell; NodeSet vertices = GetVertices(iElement, currentSet, mask, out cell); MultidimensionalArray levelSetValues = LevelSetData.GetLevSetValues(vertices, cell, 1); subdivisionTree.ReadDistances(levelSetValues.ExtractSubArrayShallow(0, -1)); currentSet = new NestedVertexSet(currentSet); subdivisionTree.Subdivide( currentSet, true, minDistance / Math.Pow(2.0, i)); } // Finally, read level set values in leaves (needed by IsCut) { int cell; NodeSet vertices = GetVertices(iElement, currentSet, mask, out cell); if (vertices != null) { MultidimensionalArray levelSetValues = LevelSetData.GetLevSetValues(vertices, cell, 1); subdivisionTree.ReadDistances(levelSetValues.ExtractSubArrayShallow(0, -1)); } } yield return(new KeyValuePair <Chunk, IEnumerable <SubdivisionNode> >( new Chunk() { i0 = iElement, Len = 1 }, subdivisionTree.Leaves)); } } }
/// <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 <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { // init & checks // ============= if (!(mask is EdgeMask)) { throw new ArgumentException("Expecting an edge mask."); } #if DEBUG var maskBitMask = mask.GetBitMask(); #endif var Edg2Cel = this.grd.iGeomEdges.CellIndices; var Edg2Fac = this.grd.iGeomEdges.FaceIndices; int J = this.grd.Cells.NoOfLocalUpdatedCells; QuadRule DefaultRule = this.RefElement.GetQuadratureRule(order);; int myIKrfeEdge = this.grd.Edges.EdgeRefElements.IndexOf(this.RefElement, (a, b) => object.ReferenceEquals(a, b)); if (myIKrfeEdge < 0) { throw new ApplicationException("fatal error"); } int[] EdgeIndices = mask.ItemEnum.ToArray(); int NoEdg = EdgeIndices.Length; // return value ChunkRulePair <QuadRule>[] Ret = new ChunkRulePair <QuadRule> [NoEdg]; // find cells // ========== BitArray CellBitMask = new BitArray(J); int[] Cells = new int[NoEdg]; // mapping: Edge Index --> Cell Index (both geometrical) int[] Faces = new int[NoEdg]; // mapping: Edge Index --> Face BitArray MaxDomainMask = m_maxDomain.GetBitMask(); { for (int i = 0; i < NoEdg; i++) { int iEdge = EdgeIndices[i]; if (this.grd.Edges.GetRefElementIndex(iEdge) != myIKrfeEdge) { throw new ArgumentException("illegal edge mask"); } if (!(grd.Edges.IsEdgeConformalWithCell1(iEdge) || grd.Edges.IsEdgeConformalWithCell2(iEdge))) { throw new NotSupportedException("For an edge that is not conformal with at least one cell, no edge rule can be created from a cell boundary rule."); } int jCell0 = Edg2Cel[iEdge, 0]; int jCell1 = Edg2Cel[iEdge, 1]; bool conf0 = grd.Edges.IsEdgeConformalWithCell1(iEdge); bool conf1 = grd.Edges.IsEdgeConformalWithCell2(iEdge); // this gives no errors for surface elements in 3D bool Allow0 = MaxDomainMask[jCell0]; bool Allow1 = (jCell1 >= 0 && jCell1 < J) ? MaxDomainMask[jCell1] : false; // //this is required for MPI parallel calculations //bool Allow0 = true;// AllowedCells[jCell0]; //bool Allow1 = (jCell1 >= 0 && jCell1 < J);// ? AllowedCells[jCell1] : false; if (!Allow0 && !Allow1) { // fallback onto default rule, if allowed //if (this.m_DefaultRuleFallbackAllowed) { // Cells[i] = -1; // by a negative index, we mark that we take the default rule // Faces[i] = -1; // Ret[i] = new ChunkRulePair<QuadRule>(Chunk.GetSingleElementChunk(EdgeIndices[i]), DefaultRule); //} else { throw new ArgumentException("unable to find a cell from which the edge rule can be taken."); //} } else { Debug.Assert(Allow0 || Allow1); if (conf0 && Allow0) { // cell 0 is allowed and conformal: // take this, it won't get better CellBitMask[jCell0] = true; Faces[i] = Edg2Fac[iEdge, 0]; Cells[i] = jCell0; } else if (conf1 && Allow1) { // cell 1 is allowed and conformal: // take this, it won't get better CellBitMask[jCell1] = true; Faces[i] = Edg2Fac[iEdge, 1]; Cells[i] = jCell1; } else if (Allow0) { // cell 0 is allowed, but NOT conformal CellBitMask[jCell0] = true; Faces[i] = -Edg2Fac[iEdge, 0]; // by a negative index, we mark a non-conformal edge Cells[i] = jCell0; } else if (Allow1) { // cell 1 is allowed, but NOT conformal CellBitMask[jCell1] = true; Faces[i] = -Edg2Fac[iEdge, 1]; // by a negative index, we mark a non-conformal edge Cells[i] = jCell1; } } } } // get cell boundary rule // ====================== var CellMask = new CellMask(this.grd, CellBitMask); IChunkRulePair <CellBoundaryQuadRule>[] cellBndRule = this.m_cellBndQF.GetQuadRuleSet(CellMask, order).ToArray(); int[] jCell2PairIdx = new int[J]; for (int i = 0; i < cellBndRule.Length; i++) { var chk = cellBndRule[i].Chunk; for (int jCell = chk.JE - 1; jCell >= chk.i0; jCell--) { jCell2PairIdx[jCell] = i + 555; } } int[] iChunk = new int[NoEdg]; // which chunk for which edge? for (int i = 0; i < NoEdg; i++) { if (Cells[i] >= 0) { iChunk[i] = jCell2PairIdx[Cells[i]] - 555; } else { iChunk[i] = int.MinValue; } } // build rule // ========== { for (int i = 0; i < NoEdg; i++) // loop over edges //if (MaxDomainMask[Cells[i]] == false) // Debugger.Break(); //if (Cells[i] >= 0) { { var CellBndR = cellBndRule[iChunk[i]].Rule; QuadRule qrEdge = null; if (Faces[i] >= 0) { qrEdge = this.CombineQr(null, CellBndR, Faces[i]); } else { throw new NotSupportedException("currently no support for non-conformal edges."); } qrEdge.Nodes.LockForever(); qrEdge.Weights.LockForever(); Ret[i] = new ChunkRulePair <QuadRule>(Chunk.GetSingleElementChunk(EdgeIndices[i]), qrEdge); //} else { // Debug.Assert(Ret[i] != null); //} } } // return // ====== #if DEBUG for (int i = 0; i < Ret.Length; i++) { Chunk c = Ret[i].Chunk; for (int e = c.i0; e < c.JE; e++) { Debug.Assert(maskBitMask[e] == true); } } #endif return(Ret); /* * * var EdgesThatConcernMe = grd.Edges.Edges4RefElement[m_cellBndQF.RefElement.FaceSimplex]; * EdgeMask edgMask = (mask as EdgeMask).Intersect(EdgesThatConcernMe); * * var ret = new Dictionary<Chunk, QuadRule>(mask.NoOfItemsLocally); #if DEBUG * var EdgesOfInterest = edgMask.GetBitMask(); * var EdgeTouched = (BitArray)EdgesOfInterest.Clone(); * * edgMask.ToTxtFile("Edges-" + grd.MyRank + ".csv", false); #endif * * * WeightInbalance = 0.0; * * // find all cells that are 'touched' by the edge mask * // -------------------------------------------------- * int J = grd.Cells.NoOfLocalUpdatedCells; * BitArray TouchedCells = new BitArray(J, false); * * var Edg2Cell = grd.Edges.CellIndices; * * int chunkCnt = 0; * foreach (var chnk in mask) { * int EE = chnk.JE; * for (int e = chnk.i0; e < EE; e++) { * if (!(grd.Edges.IsEdgeConformalwithCell1(e) || grd.Edges.IsEdgeConformalwithCell2(e))) { * throw new NotSupportedException("For an edge that is not conformal with at least one cell, no edge rule can be created from a cell boundary rule."); * } * * int j1 = Edg2Cell[e, 0], j2 = Edg2Cell[e, 1]; * TouchedCells[j1] = true; * if (j2 >= 0 && j2 < J) * TouchedCells[j2] = true; * * * Chunk singleEdgeChunk; * singleEdgeChunk.i0 = e; * singleEdgeChunk.Len = 1; * * ret.Add(singleEdgeChunk, null); * } * chunkCnt++; * } * * CellMask celMask = new CellMask(grd, TouchedCells); * celMask.ToTxtFile("CellsU-" + grd.MyRank + ".csv", false); * celMask = celMask.Intersect(m_maxDomain); * celMask.ToTxtFile("Cells-" + grd.MyRank + ".csv", false); * * // 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.RefElement; * int NoOfFaces = volSplx.NoOfFaces; * var Cells2Edge = grd.Cells.Cells2Edges; * var FaceIndices = grd.Edges.FaceIndices; * * int cnt = -1; * foreach (var kv in cellBndRule) { // loop over cell chunks (in the cell boundary rule)... * Chunk chk = kv.Chunk; * CellBoundaryQuadRule qr = kv.Rule; * cnt++; * * int JE = chk.JE; * for (int j = chk.i0; j < JE; j++) { // loop over all cells in chunk... * Debug.Assert(qr.NumbersOfNodesPerFace.Length == NoOfFaces); * var Cells2Edge_j = Cells2Edge[j]; * * for (int _e = Cells2Edge_j.Length - 1; _e >= 0; _e--) { // loop over all edges of cell... * * //if (qr.NumbersOfNodesPerEdge[e] <= 0) * // // no contribution from this edge * // continue; * * bool isInCell = Cells2Edge_j[_e] >= 0; * int iEdge = Math.Abs(Cells2Edge_j[_e]) - 1; * int iFace = FaceIndices[iEdge, isInCell ? 0 : 1]; * * if (isInCell) { * if (!grd.Edges.IsEdgeConformalwithCell1(iEdge)) * // we already tested that at least one cell is conformal with the edge, * // so it is safe to drop this face * continue; * } else { * if (!grd.Edges.IsEdgeConformalwithCell2(iEdge)) * // we already tested that at least one cell is conformal with the edge, * // so it is safe to drop this face * continue; * } * * * Chunk singleEdgeChunk = Chunk.GetSingleElementChunk(iEdge); * * QuadRule 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.RefElement.Vertices; * MultidimensionalArray _vtx = MultidimensionalArray.Create(vtx.GetLength(0), vtx.GetLength(1)); * _vtx.Set(vtx); * * var RefCoord = MultidimensionalArray.Create(vtx.GetLength(0), vtx.GetLength(1) + 1); * var PhysCoord = MultidimensionalArray.Create(1, vtx.GetLength(0), vtx.GetLength(1) + 1); * * volSplx.TransformFaceCoordinates(iFace, _vtx, RefCoord); * grd.TransformLocal2Global(RefCoord, PhysCoord, j, 1, 0); * #endif * * qrEdge = CombineQr(qrEdge, qr, iFace, j); * * Debug.Assert(qrEdge != null); * ret[singleEdgeChunk] = qrEdge; * } else { * // nop: the edge is not in the 'edgMask'! * continue; * } * } * * } * } * #if DEBUG * (new EdgeMask(this.grd, EdgeTouched)).ToTxtFile("failedEdges-" + grd.MyRank + ".csv", false); * * for (int i = EdgeTouched.Length - 1; i >= 0; i--) * Debug.Assert(EdgeTouched[i] == false); #endif * * return ret.Select(p => new ChunkRulePair<QuadRule>(p.Key, p.Value)); */ }
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> /// Uses <see cref="SubdivisionNode.NullSubdivisionNode"/> to create an /// identity transformation for the given simplex. The chunks of /// <paramref name="mask"/> are not altered. /// </summary> /// <param name="mask"> /// <see cref="ISubdivisionStrategy.GetSubdivisionNodes"/> /// </param> /// <returns> /// <see cref="ISubdivisionStrategy.GetSubdivisionNodes"/> /// </returns> public IEnumerable <KeyValuePair <Chunk, IEnumerable <SubdivisionNode> > > GetSubdivisionNodes(ExecutionMask mask) { foreach (Chunk chunk in mask) { yield return(new KeyValuePair <Chunk, IEnumerable <SubdivisionNode> >( chunk, new SubdivisionNode[] { SubdivisionNode.NullSubdivisionNode(simplex.SpatialDimension) })); } }
/// <summary> /// Uses <see cref="Grid.RefElement.SubdivisionTree"/> to create the brute /// force subdivision which is the same for all cells. As a result, the /// chunks of <paramref name="mask"/> are not altered. /// </summary> /// <param name="mask"> /// <see cref="ISubdivisionStrategy.GetSubdivisionNodes"/> /// </param> /// <returns> /// <see cref="ISubdivisionStrategy.GetSubdivisionNodes"/> /// </returns> /// <remarks> /// Currently, the nodes returned by /// <see cref="Grid.RefElement.SubdivisionTree"/> are unnecessarily /// boxed by this method. This should be changed by changing the return /// type of <see cref="Grid.RefElement.SubdivisionTree"/> at some /// point. /// </remarks> public IEnumerable <KeyValuePair <Chunk, IEnumerable <SubdivisionNode> > > GetSubdivisionNodes(ExecutionMask mask) { using (new FuncTrace()) { RefElement.SubdivisionTreeNode[] leaves = RefElement.GetSubdivisionTree(numberOfSubdivisions).GetLeaves(); foreach (Chunk chunk in mask) { yield return(new KeyValuePair <Chunk, IEnumerable <SubdivisionNode> >( chunk, leaves.Select((leave) => new SubdivisionNode(leave.TrafoFromRoot, true)))); } } }
/// <summary> /// Constructs suitable quadrature rules cells in /// <paramref name="mask"/>. /// </summary> /// <param name="mask"> /// Cells for which quadrature rules shall be created /// </param> /// <param name="order"> /// Desired order of the moment-fitting system. Assuming that /// <see cref="surfaceRuleFactory"/> integrates the basis polynomials /// exactly over the zero iso-contour (which it usually /// doesn't!), the resulting quadrature rules will be exact up to this /// order. /// </param> /// <returns>A set of quadrature rules</returns> /// <remarks> /// Since the selected level set is generally discontinuous across cell /// boundaries, this method does not make use of the fact that /// neighboring cells share edges. That is, the optimization will be /// performed twice for each inner edge in <paramref name="mask"/>. /// </remarks> public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { using (var tr = new FuncTrace()) { CellMask cellMask = mask as CellMask; if (cellMask == null) { throw new ArgumentException("Mask must be a volume mask", "mask"); } // Note: This is a parallel call, so do this early to avoid parallel confusion localCellIndex2SubgridIndex = new SubGrid(cellMask).LocalCellIndex2SubgridIndex; int maxLambdaDegree = order + 1; int noOfLambdas = GetNumberOfLambdas(maxLambdaDegree); int noOfEdges = LevelSetData.GridDat.Grid.RefElements[0].NoOfFaces; int D = RefElement.SpatialDimension; // Get the basis polynomials and integrate them analytically Polynomial[] basePolynomials = RefElement.GetOrthonormalPolynomials(order).ToArray(); Polynomial[] polynomials = 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]; pNew.Coeff[j] /= D; // Make sure divergence is Phi again } polynomials[i * D + d] = pNew; } } // basePolynomials[i] == div(polynomials[i*D], ... , polynomials[i*D + D - 1]) lambdaBasis = new PolynomialList(polynomials); if (RestrictNodes) { trafos = new AffineTrafo[mask.NoOfItemsLocally]; foreach (Chunk chunk in mask) { foreach (var cell in chunk.Elements.AsSmartEnumerable()) { CellMask singleElementMask = new CellMask( LevelSetData.GridDat, Chunk.GetSingleElementChunk(cell.Value)); LineAndPointQuadratureFactory.LineQRF lineFactory = this.edgeRuleFactory as LineAndPointQuadratureFactory.LineQRF; if (lineFactory == null) { throw new Exception(); } var lineRule = lineFactory.GetQuadRuleSet(singleElementMask, order).Single().Rule; var pointRule = lineFactory.m_Owner.GetPointFactory().GetQuadRuleSet(singleElementMask, order).Single().Rule; // Also add point rule points since line rule points // are constructed from Gauss rules that do not include // the end points BoundingBox box = new BoundingBox(lineRule.Nodes); box.AddPoints(pointRule.Nodes); int noOfRoots = pointRule.Nodes.GetLength(0); if (noOfRoots <= 1) { // Cell is considered cut because the level set // is very close, but actually isn't. Note that // we can NOT omit the cell (as in the surface // case) as it will be missing in the list of // uncut cells, i.e. this cell would be ignored // completely trafos[localCellIndex2SubgridIndex[cell.Value]] = AffineTrafo.Identity(RefElement.SpatialDimension); continue; } else if (noOfRoots == 2) { // Go a bit into the direction of the normal // from the center between the nodes in order // not to miss regions with strong curvature double[] center = box.Min.CloneAs(); center.AccV(1.0, box.Max); center.ScaleV(0.5); NodeSet centerNode = new NodeSet(RefElement, center); centerNode.LockForever(); MultidimensionalArray normal = LevelSetData.GetLevelSetReferenceNormals(centerNode, cell.Value, 1); MultidimensionalArray dist = LevelSetData.GetLevSetValues(centerNode, cell.Value, 1); double scaling = Math.Sqrt(LevelSetData.GridDat.Cells.JacobiDet[cell.Value]); double[] newPoint = new double[D]; for (int d = 0; d < D; d++) { newPoint[d] = center[d] - normal[0, 0, d] * dist[0, 0] / scaling; } box.AddPoint(newPoint); // Make sure points stay in box for (int d = 0; d < D; d++) { box.Min[d] = Math.Max(box.Min[d], -1); box.Max[d] = Math.Min(box.Max[d], 1); } } MultidimensionalArray preImage = RefElement.Vertices.ExtractSubArrayShallow( new int[] { 0, 0 }, new int[] { D, D - 1 }); MultidimensionalArray image = MultidimensionalArray.Create(D + 1, D); image[0, 0] = box.Min[0]; // Top left image[0, 1] = box.Max[1]; image[1, 0] = box.Max[0]; // Top right image[1, 1] = box.Max[1]; image[2, 0] = box.Min[0]; // Bottom left; image[2, 1] = box.Min[1]; AffineTrafo trafo = AffineTrafo.FromPoints(preImage, image); trafos[localCellIndex2SubgridIndex[cell.Value]] = trafo; } } } LambdaCellBoundaryQuadrature cellBoundaryQuadrature = new LambdaCellBoundaryQuadrature(this, edgeRuleFactory, cellMask); cellBoundaryQuadrature.Execute(); LambdaLevelSetSurfaceQuadrature surfaceQuadrature = new LambdaLevelSetSurfaceQuadrature(this, surfaceRuleFactory, cellMask); surfaceQuadrature.Execute(); // Must happen _after_ all parallel calls (e.g., definition of // the sub-grid or quadrature) in order to avoid problems in // parallel runs if (mask.NoOfItemsLocally == 0) { var empty = new ChunkRulePair <QuadRule> [0]; return(empty); } if (cachedRules.ContainsKey(order)) { order = cachedRules.Keys.Where(cachedOrder => cachedOrder >= order).Min(); CellMask cachedMask = new CellMask(mask.GridData, cachedRules[order].Select(p => p.Chunk).ToArray()); if (cachedMask.Equals(mask)) { return(cachedRules[order]); } else { throw new NotImplementedException( "Case not yet covered yet in combination with caching; deactivate caching to get rid of this message"); } } double[,] quadResults = cellBoundaryQuadrature.Results; foreach (Chunk chunk in mask) { for (int i = 0; i < chunk.Len; i++) { int iSubGrid = localCellIndex2SubgridIndex[chunk.i0 + i]; switch (jumpType) { case JumpTypes.Heaviside: for (int k = 0; k < noOfLambdas; k++) { quadResults[iSubGrid, k] -= surfaceQuadrature.Results[iSubGrid, k]; } break; case JumpTypes.OneMinusHeaviside: for (int k = 0; k < noOfLambdas; k++) { quadResults[iSubGrid, k] += surfaceQuadrature.Results[iSubGrid, k]; } break; case JumpTypes.Sign: for (int k = 0; k < noOfLambdas; k++) { quadResults[iSubGrid, k] -= 2.0 * surfaceQuadrature.Results[iSubGrid, k]; } break; default: throw new NotImplementedException(); } } } BitArray voidCellsArray = new BitArray(LevelSetData.GridDat.Cells.NoOfLocalUpdatedCells); BitArray fullCellsArray = new BitArray(LevelSetData.GridDat.Cells.NoOfLocalUpdatedCells); foreach (Chunk chunk in cellMask) { foreach (var cell in chunk.Elements) { double rhsL2Norm = 0.0; for (int k = 0; k < noOfLambdas; k++) { double entry = quadResults[localCellIndex2SubgridIndex[cell], k]; rhsL2Norm += entry * entry; } if (rhsL2Norm < 1e-14) { // All integrals are zero => cell not really cut // (level set is tangent) and fully in void region voidCellsArray[cell] = true; continue; } double l2NormFirstIntegral = quadResults[localCellIndex2SubgridIndex[cell], 0]; l2NormFirstIntegral *= l2NormFirstIntegral; double rhsL2NormWithoutFirst = rhsL2Norm - l2NormFirstIntegral; // Beware: This check is only sensible if basis is orthonormal on RefElement! if (rhsL2NormWithoutFirst < 1e-14 && Math.Abs(l2NormFirstIntegral - RefElement.Volume) < 1e-14) { // All integrals are zero except integral over first integrand // If basis is orthonormal, this implies that cell is uncut and // fully in non-void region since then // \int_K \Phi_i dV = \int_A \Phi_i dV = \delta_{0,i} // However, we have to compare RefElement.Volume since // integration is performed in reference coordinates! fullCellsArray[cell] = true; } } } var result = new List <ChunkRulePair <QuadRule> >(cellMask.NoOfItemsLocally); CellMask emptyCells = new CellMask(LevelSetData.GridDat, voidCellsArray); foreach (Chunk chunk in emptyCells) { foreach (int cell in chunk.Elements) { QuadRule emptyRule = QuadRule.CreateEmpty(RefElement, 1, RefElement.SpatialDimension); emptyRule.Nodes.LockForever(); result.Add(new ChunkRulePair <QuadRule>( Chunk.GetSingleElementChunk(cell), emptyRule)); } } CellMask fullCells = new CellMask(LevelSetData.GridDat, fullCellsArray); foreach (Chunk chunk in fullCells) { foreach (int cell in chunk.Elements) { QuadRule fullRule = RefElement.GetQuadratureRule(order); result.Add(new ChunkRulePair <QuadRule>( Chunk.GetSingleElementChunk(cell), fullRule)); } } CellMask realCutCells = cellMask.Except(emptyCells).Except(fullCells); if (RestrictNodes) { foreach (Chunk chunk in realCutCells) { foreach (int cell in chunk.Elements) { CellMask singleElementMask = new CellMask( LevelSetData.GridDat, Chunk.GetSingleElementChunk(cell)); AffineTrafo trafo = trafos[localCellIndex2SubgridIndex[cell]]; Debug.Assert(Math.Abs(trafo.Matrix.Determinant()) > 1e-10); NodeSet nodes = GetNodes(noOfLambdas).CloneAs(); NodeSet mappedNodes = new NodeSet(RefElement, trafo.Transform(nodes)); mappedNodes.LockForever(); // Remove nodes in negative part MultidimensionalArray levelSetValues = LevelSetData.GetLevSetValues(mappedNodes, cell, 1); List <int> nodesToBeCopied = new List <int>(mappedNodes.GetLength(0)); for (int n = 0; n < nodes.GetLength(0); n++) { if (levelSetValues[0, n] >= 0.0) { nodesToBeCopied.Add(n); } } NodeSet reducedNodes = new NodeSet( this.RefElement, nodesToBeCopied.Count, D); for (int n = 0; n < nodesToBeCopied.Count; n++) { for (int d = 0; d < D; d++) { reducedNodes[n, d] = mappedNodes[nodesToBeCopied[n], d]; } } reducedNodes.LockForever(); QuadRule optimizedRule = GetOptimizedRule( cell, trafo, reducedNodes, quadResults, order); result.Add(new ChunkRulePair <QuadRule>( singleElementMask.Single(), optimizedRule)); } } } else { // Use same nodes in all cells QuadRule[] optimizedRules = GetOptimizedRules( realCutCells, GetNodes(noOfLambdas), quadResults, order); int ruleIndex = 0; foreach (Chunk chunk in realCutCells) { foreach (var cell in chunk.Elements) { result.Add(new ChunkRulePair <QuadRule>( Chunk.GetSingleElementChunk(cell), optimizedRules[ruleIndex])); ruleIndex++; } } } cachedRules[order] = result.OrderBy(p => p.Chunk.i0).ToArray(); return(cachedRules[order]); } }
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); }
/// <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); } }