/// <summary> /// Concatenates grids into one data structure an makes use of <see cref="MergeLogically(GridCommons, GridCommons)"/> /// </summary> /// <param name="grids">list of different grids</param> public static GridCommons MergeLogically(params GridCommons[] grids) { GridCommons ret = grids.First(); for (int i = 1; i < grids.Length; i++) { ret = MergeLogically(ret, grids[i]); } return(ret); }
static bool AreBasicPropertiesEqual(GridCommons A, GridCommons B) { if (object.ReferenceEquals(A, B)) { return(true); } if ((A == null) != (B == null)) { return(false); } ilPSP.MPICollectiveWatchDog.Watch(MPI.Wrappers.csMPI.Raw._COMM.WORLD); int glbNoOfCells_A = A.NumberOfCells; int glbNoOfCells_B = B.NumberOfCells; int glbNoOfBcCells_A = A.NumberOfBcCells; int glbNoOfBcCells_B = B.NumberOfBcCells; if (glbNoOfCells_A != glbNoOfCells_B) { return(false); } if (glbNoOfBcCells_A != glbNoOfBcCells_B) { return(false); } if (!ArrayTools.ListEquals(A.RefElements, B.RefElements, (a, b) => object.ReferenceEquals(a, b))) { return(false); } if (!ArrayTools.ListEquals(A.EdgeRefElements, B.EdgeRefElements, (a, b) => object.ReferenceEquals(a, b))) { return(false); } if (!A.EdgeTagNames.Keys.SetEquals(B.EdgeTagNames.Keys)) { return(false); } foreach (var nmn in A.EdgeTagNames.Keys) { if (A.EdgeTagNames[nmn] != B.EdgeTagNames[nmn]) { return(false); } } if (!ArrayTools.ListEquals(A.PeriodicTrafo, B.PeriodicTrafo, (a, b) => a.ApproximateEquals(b))) { return(false); } return(true); }
static bool AreReferencesEqual(GridCommons A, GridCommons B) { if (object.ReferenceEquals(A, B)) { return(true); } if ((A == null) != (B == null)) { return(false); } ilPSP.MPICollectiveWatchDog.Watch(MPI.Wrappers.csMPI.Raw._COMM.WORLD); int glbNoOfCells_A = A.NumberOfCells; int glbNoOfCells_B = B.NumberOfCells; int glbNoOfBcCells_A = A.NumberOfBcCells; int glbNoOfBcCells_B = B.NumberOfBcCells; if (glbNoOfCells_A != glbNoOfCells_B) { return(false); } if (glbNoOfBcCells_A != glbNoOfBcCells_B) { return(false); } if (!ArrayTools.ListEquals(A.RefElements, B.RefElements, (a, b) => object.ReferenceEquals(a, b))) { return(false); } if (!ArrayTools.ListEquals(A.EdgeRefElements, B.EdgeRefElements, (a, b) => object.ReferenceEquals(a, b))) { return(false); } if (!ArrayTools.ListEquals(A.EdgeTagNames, B.EdgeTagNames, (a, b) => (a.Key == b.Key && a.Value.Equals(b.Value)))) { return(false); } if (!ArrayTools.ListEquals(A.PeriodicTrafo, B.PeriodicTrafo, (a, b) => a.ApproximateEquals(b))) { return(false); } return(true); }
/// <summary> /// Copies this info object for usage in another database. /// </summary> /// <param name="targetDatabase">The target database.</param> /// <returns> /// A copy of the original info object for usage in the target database. /// </returns> public IGridInfo CopyFor(IDatabaseInfo targetDatabase) { GridCommons copy = new GridCommons(m_RefElements, m_EdgeRefElements); Type type = this.GetType(); // Cycle to get all the fields from the parent classes as well. while (type != null) { // Copy all the field values foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { field.SetValue(copy, field.GetValue(this)); } type = type.BaseType; } copy.m_Database = targetDatabase; return(copy); }
static bool AreCellsEqual(GridCommons A, GridCommons B) { if (object.ReferenceEquals(A, B)) { return(true); } if ((A == null) != (B == null)) { return(false); } if (A.Cells == null) { throw new ArgumentException(); } int A_NumberOfBcCells = A.NumberOfBcCells; int match = 1; { // load cells of grid B, if required // --------------------------------- Cell[] B_Cells; if (B.Cells == null) { throw new Exception("Cells are not initialized"); } else { B_Cells = B.Cells; } if (A.Cells.Length != B_Cells.Length) { throw new ApplicationException(); } // put the cells of B into the same order as those of A // ---------------------------------------------------- { // tau is the GlobalID-permutation that we have for the loaded vector // sigma is the current GlobalID-permutation of the grid var sigma = new Permutation(A.Cells.Select(cell => cell.GlobalID).ToArray(), csMPI.Raw._COMM.WORLD); var tau = new Permutation(B_Cells.Select(cell => cell.GlobalID).ToArray(), csMPI.Raw._COMM.WORLD); if (sigma.TotalLength != tau.TotalLength) { // should have been checked already throw new ArgumentException(); } // compute resorting permutation Permutation invSigma = sigma.Invert(); Permutation Resorting = invSigma * tau; tau = null; // Werfen wir sie dem GC zum Fraße vor! invSigma = null; // put dg coordinates into right order Resorting.ApplyToVector(B_Cells.CloneAs(), B_Cells); } // compare cells // ------------- for (int j = 0; j < A.Cells.Length; j++) { Cell Ca = A.Cells[j]; Cell Cb = B_Cells[j]; Debug.Assert(Ca.GlobalID == Cb.GlobalID); if (!ArrayTools.ListEquals(Ca.NodeIndices, Cb.NodeIndices, (ia, ib) => ia == ib)) { match = 0; break; } if (Ca.Type != Cb.Type) { match = 0; break; } if (Ca.CellFaceTags != null || Cb.CellFaceTags != null) { CellFaceTag[] CFTA = Ca.CellFaceTags != null ? Ca.CellFaceTags : new CellFaceTag[0]; CellFaceTag[] CFTB = Cb.CellFaceTags != null ? Cb.CellFaceTags : new CellFaceTag[0]; if (CFTA.Length != CFTB.Length) { match = 0; break; } bool setMatch = true; for (int i1 = 0; i1 < CFTA.Length; i1++) { bool b = false; for (int j1 = 0; j1 < CFTB.Length; j1++) { if (CFTA[i1].Equals(CFTB[j1])) { b = true; break; } } if (b == false) { setMatch = false; break; } } if (!setMatch) { match = 0; break; } } double h = Math.Min(Ca.TransformationParams.MindistBetweenRows(), Cb.TransformationParams.MindistBetweenRows()); double L2Dist = Ca.TransformationParams.L2Dist(Cb.TransformationParams); if (L2Dist > h * 1.0e-9) { match = 0; break; } } } if (A_NumberOfBcCells > 0) { BCElement[] B_BcCells; if (B.BcCells == null && !B.BcCellsStorageGuid.Equals(Guid.Empty)) { throw new Exception("Bc Cells are not initialized"); } else { B_BcCells = B.BcCells; } if (A.BcCells.Length != B_BcCells.Length) { throw new ApplicationException("Internal error."); } // put the cells of B into the same order as those of A // ---------------------------------------------------- { long Offset = A.NumberOfCells_l; // tau is the GlobalID-permutation that we have for the loaded vector // sigma is the current GlobalID-permutation of the grid var sigma = new Permutation(A.BcCells.Select(cell => cell.GlobalID - Offset).ToArray(), csMPI.Raw._COMM.WORLD); var tau = new Permutation(B_BcCells.Select(cell => cell.GlobalID - Offset).ToArray(), csMPI.Raw._COMM.WORLD); if (sigma.TotalLength != tau.TotalLength) { // should have been checked already throw new ArgumentException(); } // compute resorting permutation Permutation invSigma = sigma.Invert(); Permutation Resorting = invSigma * tau; tau = null; // Werfen wir sie dem GC zum Fraße vor! invSigma = null; // put dg coordinates into right order Resorting.ApplyToVector(B_BcCells.CloneAs(), B_BcCells); } // compare cells // ------------- for (int j = 0; j < A.BcCells.Length; j++) { BCElement Ca = A.BcCells[j]; BCElement Cb = B_BcCells[j]; Debug.Assert(Ca.GlobalID == Cb.GlobalID); if (!ArrayTools.ListEquals(Ca.NodeIndices, Cb.NodeIndices, (ia, ib) => ia == ib)) { match = 0; break; } if (Ca.Type != Cb.Type) { match = 0; break; } if (Ca.Conformal != Cb.Conformal) { match = 0; break; } if (Ca.EdgeTag != Cb.EdgeTag) { match = 0; break; } if (Ca.NeighCell_GlobalIDs != null || Cb.NeighCell_GlobalIDs != null) { long[] NgA = Ca.NeighCell_GlobalIDs != null ? Ca.NeighCell_GlobalIDs : new long[0]; long[] NgB = Cb.NeighCell_GlobalIDs != null ? Cb.NeighCell_GlobalIDs : new long[0]; if (NgA.Length != NgB.Length) { match = 0; break; } bool setMatch = true; for (int i1 = 0; i1 < NgA.Length; i1++) { bool b = false; for (int j1 = 0; j1 < NgB.Length; j1++) { if (NgA[i1] == NgB[j1]) { b = true; break; } } if (b == false) { setMatch = false; break; } } if (!setMatch) { match = 0; break; } } double h = Math.Min(Ca.TransformationParams.MindistBetweenRows(), Cb.TransformationParams.MindistBetweenRows()); double L2Dist = Ca.TransformationParams.L2Dist(Cb.TransformationParams); if (L2Dist > h * 1.0e-9) { match = 0; break; } } } match = match.MPIMin(); return(match > 0); }
/// <summary> /// Creates a new grid, which is an adaptive refinement (cell by cell) of this grid. /// </summary> public GridCommons Adapt(IEnumerable <int> CellsToRefine, IEnumerable <int[]> CellsToCoarsen, out GridCorrelation Old2New) { using (new FuncTrace()) { GridCommons oldGrid = this.m_Grid; GridCommons newGrid = new GridCommons(oldGrid.RefElements, oldGrid.EdgeRefElements); Old2New = new GridCorrelation(); int J = this.Cells.NoOfLocalUpdatedCells; BitArray CellsToRefineBitmask = new BitArray(J); BitArray CellsToCoarseBitmask = new BitArray(J); BitArray AdaptNeighborsBitmask = new BitArray(J); // templates for subdivision // ========================= RefElement[] KrefS = oldGrid.RefElements; // all ref elements used RefElement.SubdivisionTreeNode[] KrefS_SubDiv = new RefElement.SubdivisionTreeNode[KrefS.Length]; // subdivision tree for each ref element RefElement.SubdivisionTreeNode[][] KrefS_SubdivLeaves = new RefElement.SubdivisionTreeNode[KrefS.Length][]; // actual subdivision elements Tuple <int, int>[][,] KrefS_SubdivConnections = new Tuple <int, int> [KrefS.Length][, ]; // connections between elements; 1st idx: ref elem; 2nd idx: subdiv elm; 3rd idx: face of subdiv elm; content: [idx of subdiv elm,idx of face] int[][][] KrefS_Faces2Subdiv = new int[KrefS.Length][][]; // mapping: [ref elm, face of ref elm] -> Subdivision elements which bound to this face. Old2New.GeometricMapping = new AffineTrafo[KrefS.Length][]; //List<AffineTrafo> InterCellTrafos = new List<AffineTrafo>(); //int[][] RefinementIctIdx = new int[KrefS.Length][]; //int[][] CoarseningIctIdx = new int[KrefS.Length][]; for (int iKref = 0; iKref < KrefS.Length; iKref++) { RefElement Kref = KrefS[iKref]; KrefS_SubDiv[iKref] = Kref.GetSubdivisionTree(1); KrefS_SubdivLeaves[iKref] = KrefS_SubDiv[0].GetLeaves(); Debug.Assert(ArrayTools.ListEquals(KrefS_SubdivLeaves[iKref], KrefS_SubDiv[iKref].Children[0].GetLevel(), (a, b) => object.ReferenceEquals(a, b))); KrefS_Faces2Subdiv[iKref] = new int[Kref.NoOfFaces][]; KrefS_SubdivConnections[iKref] = new Tuple <int, int> [KrefS_SubdivLeaves[iKref].Length, KrefS[iKref].NoOfFaces]; for (int iSubdiv = 0; iSubdiv < KrefS_SubdivConnections[iKref].GetLength(0); iSubdiv++) // loop over subdivision elements { for (int iFace = 0; iFace < KrefS_SubdivConnections[iKref].GetLength(1); iFace++) // loop over faces of subdivision elements { var t = KrefS_SubdivLeaves[iKref][iSubdiv].GetNeighbor(iFace); if (t.Item1 < 0) { // at the boundary of the subdivision ArrayTools.AddToArray(iSubdiv, ref KrefS_Faces2Subdiv[iKref][t.Item2]); } KrefS_SubdivConnections[iKref][iSubdiv, iFace] = t; } } //RefinementIctIdx[iKref] = new int[KrefS_SubdivLeaves[iKref].Length]; //CoarseningIctIdx[iKref] = new int[KrefS_SubdivLeaves[iKref].Length]; Old2New.GeometricMapping[iKref] = new AffineTrafo[KrefS_SubdivLeaves[iKref].Length]; for (int iSubDiv = 0; iSubDiv < KrefS_SubdivLeaves[iKref].Length; iSubDiv++) { Old2New.GeometricMapping[iKref][iSubDiv] = KrefS_SubdivLeaves[iKref][iSubDiv].TrafoFromRoot; //InterCellTrafos.Add(KrefS_SubdivLeaves[iKref][iSubDiv].TrafoFromRoot); //RefinementIctIdx[iKref][iSubDiv] = InterCellTrafos.Count - 1; //InterCellTrafos.Add(KrefS_SubdivLeaves[iKref][iSubDiv].Trafo2Root); //CoarseningIctIdx[iKref][iSubDiv] = InterCellTrafos.Count - 1; } } Old2New.KrefS_SubdivLeaves = KrefS_SubdivLeaves; // Check Input, set Bitmasks // ========================= if (CellsToRefine != null) { foreach (int jCell in CellsToRefine) { if (CellsToRefineBitmask[jCell] == true) { throw new ArgumentException("Double entry.", "CellsToRefine"); } CellsToRefineBitmask[jCell] = true; int[] Neighs, dummy; this.GetCellNeighbours(jCell, GetCellNeighbours_Mode.ViaEdges, out Neighs, out dummy); foreach (int jNeigh in Neighs) { AdaptNeighborsBitmask[jNeigh] = true; } } } if (CellsToCoarsen != null) { foreach (int[] jCellS in CellsToCoarsen) // loop over all coarsening clusters... // cluster of cells to coarsen { Cell[] CellS = jCellS.Select(j => this.Cells.GetCell(j)).ToArray(); int CoarseningClusterID = CellS[0].CoarseningClusterID; int iKref = this.Cells.GetRefElementIndex(jCellS[0]); int RefinementLevel = CellS[0].RefinementLevel; if (jCellS.Length != KrefS_SubdivLeaves[iKref].Length) { throw new ArgumentException("Number of elements in coarsening cluster does not match refinement template for respective element type."); } if (RefinementLevel <= 0 || CoarseningClusterID <= 0) { throw new ArgumentException("Coarsening not available for respective cell."); } if (CellS.Where(cl => cl.ParentCell != null).Count() != 1) { throw new ArgumentException("Coarsening cluster seems wrong, or internal data may be corrupted."); } for (int z = 0; z < CellS.Length; z++) { int j = jCellS[z]; if (CellsToRefineBitmask[j] == true) { throw new ArgumentException("Cannot refine and coarsen the same cell."); } if (CellsToCoarseBitmask[j] == true) { throw new ArgumentException("Double entry.", "CellsToCoarsen"); } CellsToCoarseBitmask[j] = true; Cell Cj = this.Cells.GetCell(j); //if(Cj.CoarseningPeers == null) // throw new ArgumentException("Coarsening not available for respective cell."); //if(Cj.CoarseningPeers.Length != jCellS.Length - 1) // throw new ArgumentException("Coarsening cluster seems incomplete."); //if(Cj.CoarseningPeers.Length != jCellS.Length - 1) // throw new ArgumentException("Coarsening cluster seems incomplete."); //foreach(long gid in jCellS) { // if(CellS.Where(cl => cl.GlobalID == gid).Count() != 1) // throw new ArgumentException("Coarsening cluster seems incomplete."); //} if (CoarseningClusterID != Cj.CoarseningClusterID) { throw new ArgumentException("Mismatch of 'CoarseningClusterID' within cluster."); } int[] Neighs, dummy; this.GetCellNeighbours(j, GetCellNeighbours_Mode.ViaVertices, out Neighs, out dummy); foreach (int jNeigh in Neighs) { if (Array.IndexOf(jCellS, jNeigh) < 0) { AdaptNeighborsBitmask[jNeigh] = true; } } } } } int InsertCounter = J; // create new cells // ================ Debug.Assert(this.MpiSize == 1, "still need to adjust the following lines."); long GlobalIdCounter = oldGrid.NumberOfCells_l; //int PtrNewCells = oldGrid.NoOfUpdateCells; //newGrid.Cells = new Cell[NewNoOfCells]; List <Cell> newCells = new List <Cell>(); int newVertexCounter = oldGrid.Cells.Max(cl => cl.NodeIndices.Max()) + 1; Cell[][] adaptedCells = new Cell[J][]; Old2New.OldGlobalId = this.CurrentGlobalIdPermutation.Values.CloneAs(); Old2New.MappingIndex = new int[J][]; Old2New.DestGlobalId = new long[J][]; // clone neighbors of refined/coarsened cells // ------------------------------------------ for (int j = 0; j < J; j++) { Debug.Assert(Old2New.OldGlobalId[j] == this.Cells.GetCell(j).GlobalID); Debug.Assert(Old2New.OldGlobalId[j] == oldGrid.Cells[j].GlobalID); Debug.Assert(object.ReferenceEquals(this.Cells.GetCell(j), oldGrid.Cells[j])); Debug.Assert((CellsToRefineBitmask[j] && CellsToCoarseBitmask[j]) == false, "Cannot refine and coarsen the same cell."); if ((CellsToRefineBitmask[j] || CellsToCoarseBitmask[j]) == false) { if (AdaptNeighborsBitmask[j]) { // neighbor information needs to be updated var oldCell = oldGrid.Cells[j]; var newCell = oldCell.CloneAs(); // data newCells.Add(newCell); adaptedCells[j] = new Cell[] { newCell }; // remove out-dated neighborship info if (newCell.CellFaceTags != null && newCell.CellFaceTags.Length > 0) { int[] oldNeighs = this.Cells.CellNeighbours[j]; foreach (int jNeigh in oldNeighs) { if (CellsToRefineBitmask[jNeigh] || CellsToCoarseBitmask[jNeigh]) { // one of the neighbors has changed, so _potentially_ the cell face tags have to be updated long gId_Neigh = this.Cells.GetGlobalID(jNeigh); for (int i = 0; i < newCell.CellFaceTags.Length; i++) { if (newCell.CellFaceTags[i].NeighCell_GlobalID == gId_Neigh) { Debug.Assert(newCell.CellFaceTags[i].EdgeTag == 0 || newCell.CellFaceTags[i].EdgeTag >= GridCommons.FIRST_PERIODIC_BC_TAG); ArrayTools.RemoveAt(ref newCell.CellFaceTags, i); i--; } } } } } } else { // cell and neighbors remain unchanged newCells.Add(oldGrid.Cells[j]); } Debug.Assert(Old2New.MappingIndex[j] == null); Debug.Assert(Old2New.DestGlobalId[j] == null); Old2New.MappingIndex[j] = null; Old2New.DestGlobalId[j] = new long[] { newCells[newCells.Count - 1].GlobalID }; } else { Debug.Assert(CellsToRefineBitmask[j] || CellsToCoarseBitmask[j]); } } // coarsening // ---------- int bCoarsened = 0; if (CellsToCoarsen != null) { foreach (int[] jCellS in CellsToCoarsen) { bCoarsened = 0xFFFF; // cluster of cells to coarsen Cell[] CellS = jCellS.Select(j => this.Cells.GetCell(j)).ToArray(); Debug.Assert(jCellS.Length == CellS.Length); int RefinementLevel = CellS[0].RefinementLevel - 1; if (RefinementLevel < 0) { throw new ArgumentException("Refinement level out of range - corrupted data structure."); } foreach (var cl in CellS) { if (cl.RefinementLevel != RefinementLevel + 1) { throw new ArgumentException("Refinement varies within refinement cluster - corrupted data structure."); } } Cell Cell0 = CellS.Single(cl => cl.ParentCell != null); Cell Mother = Cell0.ParentCell; //Debug.Assert(CellS.Where(cl => cl.GlobalID == Mother.GlobalID).Count() == 1); Debug.Assert(Mother.RefinementLevel == RefinementLevel); Cell restoredCell = new Cell(); restoredCell.Type = Mother.Type; Debug.Assert(Mother.Type == Cell0.Type); restoredCell.NodeIndices = Mother.NodeIndices; restoredCell.CoarseningClusterID = Mother.CoarseningClusterID; restoredCell.ParentCell = Mother.ParentCell; restoredCell.GlobalID = Cell0.GlobalID; restoredCell.TransformationParams = Mother.TransformationParams; restoredCell.RefinementLevel = RefinementLevel; restoredCell.CoarseningClusterSize = Mother.CoarseningClusterSize; restoredCell.CoarseningLeafIndex = Mother.CoarseningLeafIndex; // boundary conditions by cell face tags if (Mother.CellFaceTags != null) { restoredCell.CellFaceTags = Mother.CellFaceTags.Where(cftag => cftag.EdgeTag > 0 && cftag.EdgeTag < GridCommons.FIRST_PERIODIC_BC_TAG).ToArray(); } for (int iSubDiv = 0; iSubDiv < jCellS.Length; iSubDiv++) { int j = jCellS[iSubDiv]; Cell Cj = CellS[iSubDiv]; Debug.Assert(adaptedCells[j] == null); adaptedCells[j] = new[] { restoredCell }; Debug.Assert(Old2New.MappingIndex[j] == null); Debug.Assert(Old2New.DestGlobalId[j] == null); Old2New.MappingIndex[j] = new int[] { Cj.CoarseningLeafIndex }; Old2New.DestGlobalId[j] = new long[] { restoredCell.GlobalID }; } newCells.Add(restoredCell); } } // refinement // ---------- if (CellsToRefine != null) { int NewCoarseningClusterId; { int[] locData = new int[] { (this.m_Grid.Cells.Max(cl => cl.CoarseningClusterID)), (CellsToRefine.Count() + 1) }; int[] glbData = locData.MPIMax(); NewCoarseningClusterId = glbData[0] + 1 + glbData[1] * this.MpiRank; } foreach (int j in CellsToRefine) { var oldCell = oldGrid.Cells[j]; int iKref = this.Cells.GetRefElementIndex(j); var Kref = KrefS[iKref]; var Leaves = KrefS_SubdivLeaves[iKref]; Tuple <int, int>[,] Connections = KrefS_SubdivConnections[iKref]; NodeSet RefNodes = Kref.GetInterpolationNodes(oldCell.Type); Debug.Assert(adaptedCells[j] == null); Cell[] refinedCells = new Cell[Leaves.Length]; adaptedCells[j] = refinedCells; Debug.Assert(Old2New.MappingIndex[j] == null); Old2New.MappingIndex[j] = new int[Leaves.Length]; for (int iSubDiv = 0; iSubDiv < Leaves.Length; iSubDiv++) // pass 1: create new cells // create new cell { Cell newCell = new Cell(); newCell.Type = oldCell.Type; if (iSubDiv == 0) { newCell.GlobalID = oldCell.GlobalID; newCell.ParentCell = oldCell.CloneAs(); } else { newCell.GlobalID = GlobalIdCounter; GlobalIdCounter++; } newCell.RefinementLevel = oldCell.RefinementLevel + 1; newCell.CoarseningClusterSize = Leaves.Length; newCell.CoarseningClusterID = NewCoarseningClusterId; newCell.CoarseningLeafIndex = iSubDiv; refinedCells[iSubDiv] = newCell; // Vertices var RefNodesRoot = Leaves[iSubDiv].Trafo2Root.Transform(RefNodes); newCell.TransformationParams = MultidimensionalArray.Create(RefNodes.Lengths); this.TransformLocal2Global(RefNodesRoot, newCell.TransformationParams, j); // node indices newCell.NodeIndices = new int[Kref.NoOfVertices]; for (int i = 0; i < Kref.NoOfVertices; i++) { newCell.NodeIndices[i] = newVertexCounter; newVertexCounter++; } // correlation Old2New.MappingIndex[j][iSubDiv] = iSubDiv; } NewCoarseningClusterId++; for (int iSubDiv = 0; iSubDiv < Leaves.Length; iSubDiv++) // pass 2: do other things //// record information for (later) coarsening //refinedCells[iSubDiv].CoarseningPeers = refinedCells // .Where(cell => cell.GlobalID != refinedCells[iSubDiv].GlobalID) // .Select(cell => cell.GlobalID) // .ToArray(); // neighbors within { for (int iFace = 0; iFace < Kref.NoOfFaces; iFace++) { int iSubDiv_Neigh = Connections[iSubDiv, iFace].Item1; if (iSubDiv_Neigh >= 0) { ArrayTools.AddToArray(new CellFaceTag() { ConformalNeighborship = true, NeighCell_GlobalID = refinedCells[Connections[iSubDiv, iFace].Item1].GlobalID, FaceIndex = iFace }, ref refinedCells[iSubDiv].CellFaceTags); } } } newCells.AddRange(refinedCells); Debug.Assert(Old2New.DestGlobalId[j] == null); Old2New.DestGlobalId[j] = refinedCells.Select(Cl => Cl.GlobalID).ToArray(); } } newGrid.Cells = newCells.ToArray(); // fix neighborship // ================ byte[,] Edge2Face = this.Edges.FaceIndices; //int[][] Cells2Edges = this.Cells.Cells2Edges; int[,] Edge2Cell = this.Edges.CellIndices; //byte[] EdgeTags = this.Edges.EdgeTags; MultidimensionalArray[] VerticesFor_KrefEdge = this.Edges.EdgeRefElements.Select(KrefEdge => KrefEdge.Vertices).ToArray(); int[] ONE_NULL = new int[] { 0 }; int NoOfEdges = this.Edges.Count; Debug.Assert(Edge2Face.GetLength(0) == NoOfEdges); Debug.Assert(Edge2Cell.GetLength(0) == NoOfEdges); for (int iEdge = 0; iEdge < NoOfEdges; iEdge++) { int jCell1 = Edge2Cell[iEdge, 0]; int jCell2 = Edge2Cell[iEdge, 1]; if (jCell2 < 0) { continue; } Debug.Assert((CellsToRefineBitmask[jCell1] && CellsToCoarseBitmask[jCell1]) == false); Debug.Assert((CellsToRefineBitmask[jCell2] && CellsToCoarseBitmask[jCell2]) == false); bool C1changed = CellsToRefineBitmask[jCell1] || CellsToCoarseBitmask[jCell1]; bool C2changed = CellsToRefineBitmask[jCell2] || CellsToCoarseBitmask[jCell2]; if ((C1changed || C2changed) == false) { // edge between two un-changed cells -- this neighborship remains the same. continue; } Cell[] adaptedCells1 = adaptedCells[jCell1]; Cell[] adaptedCells2 = adaptedCells[jCell2]; if (CellsToCoarseBitmask[jCell1] && CellsToCoarseBitmask[jCell2]) { Debug.Assert(adaptedCells1.Length == 1); Debug.Assert(adaptedCells2.Length == 1); if (adaptedCells1[0].GlobalID == adaptedCells2[0].GlobalID) { // these two cells will be joint into one cell -> no new neighborship Debug.Assert(ReferenceEquals(adaptedCells1[0], adaptedCells2[0])); continue; } } Debug.Assert(adaptedCells1 != null); Debug.Assert(adaptedCells2 != null); int iFace1 = Edge2Face[iEdge, 0]; int iFace2 = Edge2Face[iEdge, 1]; Debug.Assert((adaptedCells1.Length > 1) == (CellsToRefineBitmask[jCell1])); Debug.Assert((adaptedCells2.Length > 1) == (CellsToRefineBitmask[jCell2])); int iKref1 = this.Cells.GetRefElementIndex(jCell1); int iKref2 = this.Cells.GetRefElementIndex(jCell2); var Kref1 = this.Cells.GetRefElement(jCell1); var Kref2 = this.Cells.GetRefElement(jCell2); int[] idx1, idx2; if (CellsToRefineBitmask[jCell1]) { idx1 = KrefS_Faces2Subdiv[iKref1][iFace1]; } else { Debug.Assert(adaptedCells1.Length == 1); idx1 = ONE_NULL; } if (CellsToRefineBitmask[jCell2]) { idx2 = KrefS_Faces2Subdiv[iKref2][iFace2]; } else { Debug.Assert(adaptedCells2.Length == 1); idx2 = ONE_NULL; } foreach (int i1 in idx1) { MultidimensionalArray VtxFace1; if (CellsToRefineBitmask[jCell1]) { VtxFace1 = KrefS_SubdivLeaves[iKref1][i1].GetFaceVertices(iFace1); } else { VtxFace1 = Kref1.GetFaceVertices(iFace1); } Cell Cl1 = adaptedCells1[i1]; foreach (int i2 in idx2) { Cell Cl2 = adaptedCells2[i2]; Debug.Assert(Cl1.GlobalID != Cl2.GlobalID); int conCount1; if (Cl1.CellFaceTags == null) { conCount1 = 0; } else { conCount1 = Cl1.CellFaceTags.Where(cfTag => cfTag.NeighCell_GlobalID == Cl2.GlobalID).Count(); } Debug.Assert(conCount1 <= 1); #if DEBUG int conCount2; if (Cl2.CellFaceTags == null) { conCount2 = 0; } else { conCount2 = Cl2.CellFaceTags.Where(cfTag => cfTag.NeighCell_GlobalID == Cl1.GlobalID).Count(); } Debug.Assert(conCount1 == conCount2); #endif if (conCount1 > 0) { continue; } MultidimensionalArray VtxFace2; { MultidimensionalArray VtxFace2_L; if (CellsToRefineBitmask[jCell2]) { VtxFace2_L = KrefS_SubdivLeaves[iKref2][i2].GetFaceVertices(iFace2); } else { VtxFace2_L = Kref2.GetFaceVertices(iFace2); } MultidimensionalArray VtxFace2_G = MultidimensionalArray.Create(VtxFace2_L.GetLength(0), VtxFace2_L.GetLength(1)); VtxFace2 = MultidimensionalArray.Create(VtxFace2_L.GetLength(0), VtxFace2_L.GetLength(1)); this.TransformLocal2Global(VtxFace2_L, VtxFace2_G, jCell2); bool[] Converged = new bool[VtxFace2_L.NoOfRows]; this.TransformGlobal2Local(VtxFace2_G, VtxFace2, jCell1, Converged); if (Converged.Any(t => t == false)) { throw new ArithmeticException("Newton divergence"); } } bool bIntersect = GridData.EdgeData.FaceIntersect(VtxFace1, VtxFace2, Kref1.GetFaceTrafo(iFace1), Kref1.GetInverseFaceTrafo(iFace1), VerticesFor_KrefEdge, out bool conformal1, out bool conformal2, out AffineTrafo newTrafo, out int Edg_idx); if (bIntersect) { ArrayTools.AddToArray(new CellFaceTag() { ConformalNeighborship = false, NeighCell_GlobalID = Cl2.GlobalID, FaceIndex = iFace1 }, ref Cl1.CellFaceTags); ArrayTools.AddToArray(new CellFaceTag() { ConformalNeighborship = false, NeighCell_GlobalID = Cl1.GlobalID, FaceIndex = iFace2 }, ref Cl2.CellFaceTags); } } } } // finalize // ======== int bCoarsenedGlobal = bCoarsened.MPIMax(); if (bCoarsenedGlobal > 0) { #if DEBUG if (this.MpiSize == 1) { List <int> allgids = new List <int>(); foreach (var cl in newGrid.Cells) { allgids.Add((int)(cl.GlobalID)); } bool[] markers = new bool[allgids.Max() + 1]; for (int i = 0; i < allgids.Count; i++) { long gid = allgids[i]; Debug.Assert(markers[gid] == false, "Some GlobalID is used twice."); markers[gid] = true; } foreach (var cl in newGrid.Cells) { if (cl.CellFaceTags != null) { for (int i = 0; i < cl.CellFaceTags.Length; i++) { long ngid = cl.CellFaceTags[i].NeighCell_GlobalID; if (ngid >= 0) { Debug.Assert(markers[ngid] == true); } } } } } #endif List <long> old2NewGid = new List <long>(); Debug.Assert(Old2New.DestGlobalId.Length == J); for (int j = 0; j < J; j++) { old2NewGid.AddRange(Old2New.DestGlobalId[j]); } newGrid.CompressGlobalID(old2NewGid); int c2 = 0; for (int j = 0; j < J; j++) { long[] o2nj = Old2New.DestGlobalId[j]; int K = o2nj.Length; for (int k = 0; k < K; k++) { o2nj[k] = old2NewGid[c2]; c2++; } } Debug.Assert(c2 == old2NewGid.Count); } return(newGrid); } }
public GridCommonsDatabaseMethods(GridCommons grid) { this.grid = grid; }
/// <summary> /// Concatenates grids <paramref name="A"/> and <paramref name="B"/> into one data structure. /// </summary> public static GridCommons MergeLogically(GridCommons A, GridCommons B) { GridCommons R = new GridCommons(); R.m_GridGuid = Guid.NewGuid(); //R.BcCellPartitioning; R.m_BcCellPartitioning //R.BcCells; //R.BcCellsStorageGuid; //R.CellPartitioning; //R.Cells; //R.Description; //R.EdgeRefElements; //R.EdgeTagNames; //R.GridGuid; == R.ID; //R.InversePeriodicTrafo on-demand //R.m_ClassNameOfEdgeRefElement //R.m_RefElements; //R.m_EdgeRefElements; ///////////////////////// // merge ref elements ///////////////////////// { R.m_RefElements = A.m_RefElements.CloneAs(); int[] BrefElm = new int[B.m_RefElements.Length]; for (int iKrefB = 0; iKrefB < BrefElm.Length; iKrefB++) { RefElement Kref = B.m_RefElements[iKrefB]; int iKrefBNew = R.m_RefElements.IndexOf(Kref, (a, b) => a.Equals(b)); if (iKrefBNew < 0) { ArrayTools.AddToArray(Kref, ref R.m_RefElements); iKrefBNew = B.m_RefElements.Length - 1; } BrefElm[iKrefB] = iKrefBNew; } R.m_EdgeRefElements = A.m_EdgeRefElements.CloneAs(); int[] BEdgeRefElm = new int[B.m_EdgeRefElements.Length]; for (int iEdgeKrefB = 0; iEdgeKrefB < BEdgeRefElm.Length; iEdgeKrefB++) { RefElement Kref = B.m_EdgeRefElements[iEdgeKrefB]; int iEdgeKrefBNew = R.m_EdgeRefElements.IndexOf(Kref, (a, b) => a.Equals(b)); if (iEdgeKrefBNew < 0) { ArrayTools.AddToArray(Kref, ref R.m_EdgeRefElements); iEdgeKrefBNew = B.m_EdgeRefElements.Length - 1; } BEdgeRefElm[iEdgeKrefB] = iEdgeKrefBNew; } } ////////////////////////////////////////// // merge edge tags & periodic transformations ////////////////////////////////////////// byte[] BNewEdgeTag = new byte[0xff]; // mapping: old edge tag in B (index) => edge tag in R (content) { R.m_PeriodicTrafo.AddRange(A.m_PeriodicTrafo.Select(at => at.CloneAs()).ToArray()); R.m_EdgeTagNames.AddRange(A.m_EdgeTagNames); foreach (var kv in B.m_EdgeTagNames) { byte _EdgeTagB = kv.Key, _NewEdgeTagB; string NameB = kv.Value; if (R.m_EdgeTagNames.ContainsValue(NameB)) { _NewEdgeTagB = R.m_EdgeTagNames.First(kv2 => kv2.Value.Equals(NameB)).Key; } else { _NewEdgeTagB = R.m_EdgeTagNames.Keys.Where(et => et < FIRST_PERIODIC_BC_TAG).Max(); } BNewEdgeTag[_EdgeTagB] = _NewEdgeTagB; } AffineTrafo[] BperiodicTrafo = B.m_PeriodicTrafo.Select(at => at.CloneAs()).ToArray(); for (int i = 0; i < BperiodicTrafo.Length; i++) { var Tr = BperiodicTrafo[i]; int _BEdgeTag = i + FIRST_PERIODIC_BC_TAG; int _BNewEdgeTag; int idxTr = R.m_PeriodicTrafo.IndexOf(Tr, (TrA, TrB) => TrA.ApproximateEquals(TrB)); if (idxTr < 0) { R.m_PeriodicTrafo.Add(Tr); _BNewEdgeTag = R.m_PeriodicTrafo.Count + FIRST_PERIODIC_BC_TAG - 1; R.m_EdgeTagNames.Add((byte)_BNewEdgeTag, B.m_EdgeTagNames[(byte)_BEdgeTag]); } else { _BNewEdgeTag = idxTr + FIRST_PERIODIC_BC_TAG; } BNewEdgeTag[_BEdgeTag] = (byte)_BNewEdgeTag; } } ////////////////////////// // merge cells (logically) ////////////////////////// { int NodeOffset = A.NodePartitioning.TotalLength; long JAglb = A.NumberOfCells_l; long JBglb = B.NumberOfCells_l; long KAglb = A.NoOfBcCells.MPISum(); long KBglb = B.NoOfBcCells.MPISum(); int JA = A.Cells.Length; int JB = B.Cells.Length; R.Cells = new Cell[JA + JB]; int KA = A.NoOfBcCells; int KB = B.NoOfBcCells; R.BcCells = new BCElement[KA + KB]; // check GlobalIds of cells for (int ja = 0; ja < JA; ja++) { Cell CA = A.Cells[ja]; if (CA.GlobalID < 0 || CA.GlobalID >= JAglb) { throw new ArgumentException("Illegal GlobalId in grid A.", "A"); } } for (int jb = 0; jb < JB; jb++) { Cell CB = B.Cells[jb]; if (CB.GlobalID < 0 || CB.GlobalID >= JBglb) { throw new ArgumentException("Illegal GlobalId in grid B.", "B"); } } // check globalIDs of boundary elements for (int ka = 0; ka < KA; ka++) { BCElement BcA = A.BcCells[ka]; if (BcA.GlobalID < JAglb || BcA.GlobalID >= JAglb + KAglb) { throw new ArgumentException("Illegal GlobalId for boundary element in grid A.", "A"); } } for (int kb = 0; kb < KB; kb++) { BCElement BcB = B.BcCells[kb]; if (BcB.GlobalID < JB || BcB.GlobalID >= JBglb + KBglb) { throw new ArgumentException("Illegal GlobalId for boundary element in grid B.", "B"); } } // cells of A: // ----------- for (int ja = 0; ja < JA; ja++) { Cell CA = A.Cells[ja]; R.Cells[ja] = new Cell() { GlobalID = CA.GlobalID, NodeIndices = CA.NodeIndices == null ? null : CA.NodeIndices.CloneAs(), Type = CA.Type, TransformationParams = CA.TransformationParams.CloneAs(), CellFaceTags = CA.CellFaceTags == null ? null : CA.CellFaceTags.Select(tag => new CellFaceTag() { EdgeTag = tag.EdgeTag, FaceIndex = tag.FaceIndex, ConformalNeighborship = tag.ConformalNeighborship, NeighCell_GlobalID = tag.NeighCell_GlobalID < JAglb ? tag.NeighCell_GlobalID : // normal cell tag.NeighCell_GlobalID + JBglb, // boundary element PeriodicInverse = tag.PeriodicInverse }).ToArray() }; Debug.Assert(R.Cells[ja].GlobalID >= 0 && R.Cells[ja].GlobalID < JAglb); if (CA.CellFaceTags != null) { for (int i = 0; i < CA.CellFaceTags.Length; i++) { var cft = R.Cells[ja].CellFaceTags[i]; var orgCft = CA.CellFaceTags[i]; Debug.Assert( (orgCft.NeighCell_GlobalID < JAglb && cft.NeighCell_GlobalID >= 0 && cft.NeighCell_GlobalID < JAglb) || // normall cell (orgCft.NeighCell_GlobalID >= JAglb && cft.NeighCell_GlobalID >= JAglb + JBglb && cft.NeighCell_GlobalID < JAglb + JBglb + KAglb)); // boundary element } } } // cells of B: // ----------- for (int jb = 0; jb < JB; jb++) { Cell CB = B.Cells[jb]; R.Cells[jb + JA] = new Cell() { GlobalID = CB.GlobalID + JAglb, NodeIndices = CB.NodeIndices == null ? null : CB.NodeIndices.Select(idx => idx + NodeOffset).ToArray(), Type = CB.Type, TransformationParams = CB.TransformationParams.CloneAs(), CellFaceTags = CB.CellFaceTags == null ? null : CB.CellFaceTags.Select(tag => new CellFaceTag() { EdgeTag = BNewEdgeTag[tag.EdgeTag], FaceIndex = tag.FaceIndex, ConformalNeighborship = tag.ConformalNeighborship, NeighCell_GlobalID = tag.NeighCell_GlobalID + JAglb, // correct for normal cell and boundary element PeriodicInverse = tag.PeriodicInverse }).ToArray() }; Debug.Assert(R.Cells[jb + JA].GlobalID >= JAglb && R.Cells[jb + JA].GlobalID < JAglb + JBglb); if (CB.CellFaceTags != null) { for (int i = 0; i < CB.CellFaceTags.Length; i++) { var cft = R.Cells[jb + JA].CellFaceTags[i]; var orgCft = CB.CellFaceTags[i]; Debug.Assert( (orgCft.NeighCell_GlobalID < JBglb && cft.NeighCell_GlobalID >= JAglb && cft.NeighCell_GlobalID < JAglb + JBglb) || // normall cell (orgCft.NeighCell_GlobalID >= JBglb && cft.NeighCell_GlobalID >= JAglb + JBglb + KAglb && cft.NeighCell_GlobalID < JAglb + JBglb + KAglb + KBglb)); // boundary element } } } // boundary elements of A: // ----------------------- for (int ka = 0; ka < KA; ka++) { BCElement BcA = A.BcCells[ka]; R.BcCells[ka] = new BCElement() { Conformal = BcA.Conformal, GlobalID = BcA.GlobalID + JBglb, NeighCell_GlobalIDs = BcA.NeighCell_GlobalIDs == null ? null : BcA.NeighCell_GlobalIDs.Select( gidN => gidN < JAglb ? gidN : gidN + JBglb).ToArray(), EdgeTag = BcA.EdgeTag, NodeIndices = BcA.NodeIndices == null ? null : BcA.NodeIndices.CloneAs(), TransformationParams = BcA.TransformationParams.CloneAs(), Type = BcA.Type }; Debug.Assert(R.BcCells[ka].GlobalID >= JAglb + JBglb && R.BcCells[ka].GlobalID < JAglb + JBglb + KAglb); if (BcA.NeighCell_GlobalIDs != null) { for (int i = 0; i < BcA.NeighCell_GlobalIDs.Length; i++) { long Ngid = R.BcCells[ka].NeighCell_GlobalIDs[i]; long orgNgid = BcA.NeighCell_GlobalIDs[i]; Debug.Assert((orgNgid < JAglb && Ngid >= 0 && Ngid < JAglb) || // normall cell (orgNgid >= JAglb && Ngid >= JAglb + JBglb && Ngid < JAglb + JBglb + KAglb)); // boundary element } } } // boundary elements of B: // ----------------------- for (int kb = 0; kb < KB; kb++) { BCElement BcB = A.BcCells[kb]; R.BcCells[kb + KA] = new BCElement() { Conformal = BcB.Conformal, GlobalID = BcB.GlobalID + JAglb, NeighCell_GlobalIDs = BcB.NeighCell_GlobalIDs == null ? null : BcB.NeighCell_GlobalIDs.Select( gidN => gidN < JBglb ? gidN + JAglb : gidN + JAglb).ToArray(), EdgeTag = BNewEdgeTag[BcB.EdgeTag], NodeIndices = BcB.NodeIndices == null ? null : BcB.NodeIndices.Select(idx => idx + NodeOffset).ToArray(), TransformationParams = BcB.TransformationParams.CloneAs(), Type = BcB.Type }; Debug.Assert(R.BcCells[kb].GlobalID >= JAglb + JBglb + KAglb && R.BcCells[kb].GlobalID < JAglb + JBglb + KAglb + KBglb); if (BcB.NeighCell_GlobalIDs != null) { for (int i = 0; i < BcB.NeighCell_GlobalIDs.Length; i++) { long Ngid = R.BcCells[kb + KA].NeighCell_GlobalIDs[i]; long orgNgid = BcB.NeighCell_GlobalIDs[i]; Debug.Assert((orgNgid < JBglb && Ngid >= JAglb && Ngid < JAglb + JBglb) || // normall cell (orgNgid >= JBglb && Ngid >= JAglb + JBglb + KAglb && Ngid < JAglb + JBglb + KAglb + KBglb)); // boundary element } } } } return(R); }
/// <summary> /// Usually used after <see cref="MergeLogically(GridCommons, GridCommons)"/>; this method finds element boundaries /// which intersect geometrically, but not logically and inserts a <see cref="CellFaceTag"/> which connects those cells. /// </summary> /// <param name="g"></param> /// <param name="upsampling"></param> /// <returns></returns> public static GridCommons Seal(GridCommons g, int upsampling = 4) { GridCommons R = g.CloneAs(); g = null; GridData gdat = new GridData(R); int D = gdat.SpatialDimension; int J = gdat.Cells.NoOfLocalUpdatedCells; if (R.CellPartitioning.MpiSize > 1) { throw new NotSupportedException("Not supported in MPI-parallel mode."); } //NodeSet[] TestNodes = gdat.Edges.EdgeRefElements.Select(KrefEdge => KrefEdge.GetSubdivisionTree(upsampling).GlobalVertice).ToArray(); NodeSet[] TestNodes = gdat.Edges.EdgeRefElements.Select(KrefEdge => KrefEdge.GetBruteForceQuadRule(upsampling, 1).Nodes).ToArray(); // Its better to use vertices in the interior of the element; if we use vertices at the corners, we might get // intersection of edges that just share one point. // Define all edges that will be tested (set to boundary edges) // ============================================================ int[] UnknownEdges = gdat.BoundaryEdges.ItemEnum.ToArray(); int L = UnknownEdges.Sum(iEdg => TestNodes[gdat.Edges.GetRefElementIndex(iEdg)].NoOfNodes); // Transform nodes on edges (that should be tested) to global coordinates // ====================================================================== MultidimensionalArray TestNodesGlobal = MultidimensionalArray.Create(L, D); MultidimensionalArray NormalsGlobal = MultidimensionalArray.Create(L, D); int[] NodeToEdge = new int[L]; // pointer l -> Edge index, where l is the first index into 'TestNodesGlobal' & 'NormalsGlobal' int[,] E2C = gdat.Edges.CellIndices; int cnt = 0; foreach (int iEdg in UnknownEdges) { int iKref = gdat.Edges.GetRefElementIndex(iEdg); NodeSet Ns = TestNodes[iKref]; int K = Ns.NoOfNodes; int[] I0 = new int[] { cnt, 0 }; int[] IE = new int[] { cnt + K - 1, D - 1 }; MultidimensionalArray TN = gdat.GlobalNodes.GetValue_EdgeSV(Ns, iEdg, 1); TestNodesGlobal.SetSubArray(TN.ExtractSubArrayShallow(0, -1, -1), I0, IE); MultidimensionalArray N1 = gdat.Edges.NormalsCache.GetNormals_Edge(Ns, iEdg, 1); NormalsGlobal.SetSubArray(N1.ExtractSubArrayShallow(0, -1, -1), I0, IE); for (int i = cnt; i < cnt + K; i++) { NodeToEdge[i] = iEdg; } cnt += K; } // binary tree to speed up point localization int[] pl_Permutation = new int[L]; PointLocalization pl = new PointLocalization(TestNodesGlobal, 0.01, pl_Permutation); Debug.Assert(!object.ReferenceEquals(pl.Points, TestNodesGlobal)); // compare search edges to all other nodes // ======================================= // mapping: cell --> Neighbour cell index, face index // 1st index: Cell index; // 2nd index: enumeration List <Tuple <int, int> >[] FoundPairings = new List <Tuple <int, int> > [gdat.Cells.NoOfCells]; int[][] C2E = gdat.Cells.Cells2Edges; byte[,] E2F = gdat.Edges.FaceIndices; int cnt2 = 0; for (int iEdgC = 0; iEdgC < UnknownEdges.Length; iEdgC++) // loop over edges that may get sealed { int iEdg = UnknownEdges[iEdgC]; int iKref = gdat.Edges.GetRefElementIndex(iEdg); NodeSet Ns = TestNodes[iKref]; int K = Ns.NoOfNodes; int jCell1 = E2C[iEdg, 0]; Debug.Assert(E2C[iEdg, 1] < 0); int iFace1 = E2F[iEdg, 0]; Debug.Assert(E2F[iEdg, 1] == byte.MaxValue); int[] I0 = new int[] { cnt2, 0 }; int[] IE = new int[] { cnt2 + K - 1, D - 1 }; MultidimensionalArray TN = TestNodesGlobal.ExtractSubArrayShallow(I0, IE); //MultidimensionalArray N1 = NormalsGlobal.ExtractSubArrayShallow(I0, IE); // find bounding box for edge BoundingBox bbEdge = new BoundingBox(TN); if (bbEdge.h_min / bbEdge.h_max < 1.0e-5) { // very thin bounding box, thicken slightly double delta = bbEdge.h_max * 1.0e-5; for (int d = 0; d < D; d++) { bbEdge.Min[d] -= delta; bbEdge.Max[d] += delta; } } bbEdge.ExtendByFactor(0.01); // determine binary code for bounding box int bbEdgeSigBits; GeomBinTreeBranchCode bbEdgeCode = GeomBinTreeBranchCode.Combine( GeomBinTreeBranchCode.CreateFormPoint(pl.PointsBB, bbEdge.Min), GeomBinTreeBranchCode.CreateFormPoint(pl.PointsBB, bbEdge.Max), out bbEdgeSigBits); // determine all points in bounding box int iP0, Len; pl.GetPointsInBranch(bbEdgeCode, bbEdgeSigBits, out iP0, out Len); // determine all edged which potentially overlap with edge 'iEdg' HashSet <int> PotOvrlap = new HashSet <int>(); // a set of edge indices for (int n = 0; n < Len; n++) { int l = iP0 + n; int iPt = pl_Permutation[l]; Debug.Assert(GenericBlas.L2DistPow2(pl.Points.GetRow(l), TestNodesGlobal.GetRow(iPt)) <= 0); int iOvlpEdge = NodeToEdge[iPt]; if (iOvlpEdge != iEdg) { PotOvrlap.Add(iOvlpEdge); } } //int[] PotOvrlap = UnknownEdges.CloneAs(); // determine actually overlapping boundary edges: foreach (int iOvrlapEdge in PotOvrlap) { int jCell2 = E2C[iOvrlapEdge, 0]; Debug.Assert(E2C[iOvrlapEdge, 1] < 0); if (jCell2 == jCell1) { continue; } int iFace2 = E2F[iOvrlapEdge, 0]; Debug.Assert(E2F[iOvrlapEdge, 1] == byte.MaxValue); int AllreadyFound = FoundPairings[jCell1] == null ? 0 : FoundPairings[jCell1].Where(tp => tp.Item1 == jCell2 && tp.Item2 == iFace1).Count(); if (AllreadyFound > 1) { throw new ApplicationException("Error in algorithmus."); } if (AllreadyFound > 0) { continue; } var Kref_j2 = gdat.Cells.GetRefElement(jCell2); double h = Kref_j2.GetMaxDiameter(); MultidimensionalArray LocVtx_j2 = MultidimensionalArray.Create(K, D); bool[] NewtonConvervence = new bool[K]; gdat.TransformGlobal2Local(TN, LocVtx_j2, jCell2, NewtonConvervence); for (int k = 0; k < K; k++) // loop over all transformed points { if (!NewtonConvervence[k]) { continue; } double[] pt = LocVtx_j2.GetRow(k); double[] ptClose = new double[D]; double dist = Kref_j2.ClosestPoint(pt, ptClose); if (dist > h * 1.0e-8) { continue; } AffineManifold Face = Kref_j2.GetFacePlane(iFace2); double FaceDist = Face.PointDistance(pt); if (FaceDist.Abs() > 1.0e-8 * h) { continue; } NodeSet Ns2 = new NodeSet(Kref_j2, pt); MultidimensionalArray Normals2 = MultidimensionalArray.Create(1, D); gdat.Edges.GetNormalsForCell(Ns2, jCell2, iFace2, Normals2); double[] N1d = NormalsGlobal.GetRow(cnt2 + k); double[] N2d = Normals2.GetRow(0); //Check if face normals points exactly in the opposite direction, 2 ways: // 1) calculate angle between both normals -> bad choice because of Math.Acos // 2) inner product of two opposite vectors is -1 //if (Math.Abs(Math.Abs(Math.Acos(GenericBlas.InnerProd(N1d, N2d))) - Math.PI) > 1.0e-8) if (Math.Abs(GenericBlas.InnerProd(N1d, N2d) + 1.0) > 1.0e-8) { continue; } // if we reach this point, jCell1 should match with jCell2/iFace2 if (FoundPairings[jCell1] == null) { FoundPairings[jCell1] = new List <Tuple <int, int> >(); } if (FoundPairings[jCell2] == null) { FoundPairings[jCell2] = new List <Tuple <int, int> >(); } FoundPairings[jCell1].Add(new Tuple <int, int>(jCell2, iFace1)); FoundPairings[jCell2].Add(new Tuple <int, int>(jCell1, iFace2)); break; // no need to test jCell1 vs. jCell2 anymore } } cnt2 += K; } // add the newly found pairings to the grid for (int j = 0; j < J; j++) { var fp = FoundPairings[j]; if (fp != null) { foreach (var t in fp) { ArrayTools.AddToArray(new CellFaceTag() { EdgeTag = 0, FaceIndex = t.Item2, ConformalNeighborship = false, NeighCell_GlobalID = gdat.CurrentGlobalIdPermutation.Values[t.Item1] }, ref R.Cells[j].CellFaceTags); } } } return(R); }