Example #1
0
        /// <summary>
        /// finds the smallest bounding box (in the geometric binary tree) which contains cell <paramref name="jCell"/>;
        /// </summary>
        /// <param name="jCell"></param>
        /// <return>
        /// the bounding box information (branch and significant bits) for the bounding box of cell <paramref name="jCell"/>;
        /// </return>
        public BoundingBoxCode GetCellBoundingBoxCode(int jCell)
        {
            BoundingBoxCode ret;
            int             sigbits;

            ret.Branch          = GeomBinTreeBranchCode.Combine(CellMinCode[jCell], CellMaxCode[jCell], out sigbits);
            ret.SignificantBits = (uint)sigbits;
            return(ret);
        }
Example #2
0
        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="grdDat"></param>
        public CellLocalization(GridData grdDat)
        {
            m_GrdDat = grdDat;

            int J = grdDat.Cells.NoOfLocalUpdatedCells;
            int D = grdDat.SpatialDimension;

            CellMinCode = new GeomBinTreeBranchCode[J];
            CellMaxCode = new GeomBinTreeBranchCode[J];

            // 1st pass: find bounding box of grid
            // ===================================
            GridBB = m_GrdDat.LocalBoundingBox;
            GridBB.ExtendByFactor(0.01);

            // 2nd pass: localize all cells
            // ============================
            CellMinCode = new GeomBinTreeBranchCode[J];
            CellMaxCode = new GeomBinTreeBranchCode[J];
            BoundingBox CellBB        = new BoundingBox(D);
            BoundingBox TreeBB        = new BoundingBox(D);
            var         CellBB_points = new double[][] { CellBB.Min, CellBB.Max };

            for (int j = 0; j < J; j++)
            {
                m_GrdDat.Cells.GetCellBoundingBox(j, CellBB);
                //grdDat.TransformLocal2Global(verticesLoc, vericesGlob, j, 1, 0);

                uint mincode = uint.MaxValue;
                uint maxcode = 0;
                foreach (var _pt in CellBB_points)
                {
                    GeomBinTreeBranchCode cd = GeomBinTreeBranchCode.CreateFormPoint(GridBB, _pt);
                    mincode = Math.Min(mincode, cd.Code);
                    maxcode = Math.Max(maxcode, cd.Code);
                }

                CellMinCode[j].Code = mincode;
                CellMaxCode[j].Code = maxcode;

                // test
                BoundingBoxCode currentlyGen = GetCellBoundingBoxCode(j);
                GridBB.SubBoxFromCode(TreeBB, currentlyGen);

                if (!TreeBB.Contains(CellBB))
                {
                    throw new ApplicationException("internal error - should not occur");
                }
            }
        }
Example #3
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);
        }