Beispiel #1
0
        /// <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);
        }
Beispiel #2
0
        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);
        }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
        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);
        }
Beispiel #6
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;
 }
Beispiel #8
0
        /// <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);
        }
Beispiel #9
0
        /// <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);
        }