/// <summary> /// Find the cell which contains some point <paramref name="pt"/>; /// If <paramref name="pt"/> is not within any cell, the cell with its /// center nearest to <paramref name="pt"/> is returned and in this /// case, <paramref name="IsInside"/> is false. /// </summary> /// <param name="pt"></param> /// <param name="GlobalId"> /// the Global ID of the found cell; /// </param> /// <param name="GlobalIndex"> /// the Global index of the found cell; /// </param> /// <param name="IsInside"> /// true, if <paramref name="pt"/> is within the cell identified by /// <paramref name="GlobalId"/>; /// otherwise, false; /// </param> /// <param name="OnThisProcess"> /// If true, the cell <paramref name="GlobalId"/> is located on the current MPI process. /// </param> /// <param name="CM"> /// optional cell mask to restrict the search region /// </param> /// <remarks> /// This operation is relatively costly, as it needs to perform a sweep /// over all cells, it should not be used for performance-critical /// tasks.<br/> /// This operation is MPI-collective, the output-values are equal on /// all MPI-processors. /// </remarks> static public void LocatePoint(this IGridData gdat, double[] pt, out long GlobalId, out long GlobalIndex, out bool IsInside, out bool OnThisProcess, CellMask CM = null) { using (new FuncTrace()) { if (pt.Length != gdat.SpatialDimension) { throw new ArgumentException("length must be equal to spatial dimension", "pt"); } ilPSP.MPICollectiveWatchDog.Watch(MPI.Wrappers.csMPI.Raw._COMM.WORLD); int MpiRank = gdat.CellPartitioning.MpiRank; int MpiSize = gdat.CellPartitioning.MpiSize; int J = gdat.iLogicalCells.NoOfLocalUpdatedCells; int D = gdat.SpatialDimension; MultidimensionalArray center = MultidimensionalArray.Create(1, 1, D); // cell center in global coordinates MultidimensionalArray _pt = MultidimensionalArray.Create(1, D); // point to search for for (int d = 0; d < D; d++) { _pt[0, d] = pt[d]; } MultidimensionalArray _pt_local = MultidimensionalArray.Create(1, 1, D); // .. in cell-local coordinate double[] pt_local = new double[D]; // sweep over locally updated cells ... // ==================================== int jL_MinDistCel = 0; // logical cell with minimum distance int jG_MinDistCel = 0; // geometrical cell with minimum distance double MinDist = double.MaxValue; int j_Within = -1; if (CM == null) { CM = CellMask.GetFullMask(gdat); } foreach (int jL in CM.ItemEnum) { foreach (int j in gdat.GetGeometricCellIndices(jL)) { // compute distance // ================ { var smplx = gdat.iGeomCells.GetRefElement(j); gdat.TransformLocal2Global(smplx.Center, j, 1, center, 0); double dist = 0; for (int d = 0; d < D; d++) { double del = pt[d] - center[0, 0, d]; dist += del * del; } dist = Math.Sqrt(dist); if (dist < MinDist) { MinDist = dist; jL_MinDistCel = jL; jG_MinDistCel = j; } } // transform back into cell // ======================== { try { gdat.TransformGlobal2Local(_pt, _pt_local, j, 1, 0); for (int d = 0; d < D; d++) { pt_local[d] = _pt_local[0, 0, d]; } var smplx = gdat.iGeomCells.GetRefElement(j); if (smplx.IsWithin(pt_local)) { j_Within = j; } } catch (ArithmeticException) { // probably outside... } } } } // ======================================== // First case: point is inside of some cell // ======================================== int lowestWithinRank = j_Within >= 0 ? MpiRank : int.MaxValue; lowestWithinRank = lowestWithinRank.MPIMin(); // lowest rank which found a cell that contains the point: // this rank will be the official finder! if (lowestWithinRank < MpiSize) { LocatPointHelper(gdat, lowestWithinRank, j_Within, out GlobalId, out GlobalIndex, out OnThisProcess); IsInside = true; return; } // ======================================== // Second case: point is outside of all cells // ======================================== double MinDistGlobal = MinDist.MPIMin(); int lowestMinimumRank = MinDistGlobal == MinDist ? MpiRank : int.MaxValue; lowestMinimumRank = lowestMinimumRank.MPIMin(); // find minimum rank on which the global minimum was reached. if (lowestMinimumRank < 0 || lowestMinimumRank >= MpiSize) { throw new ApplicationException(); } LocatPointHelper(gdat, lowestMinimumRank, jL_MinDistCel, out GlobalId, out GlobalIndex, out OnThisProcess); IsInside = false; return; } }
/// <summary> /// computes a global time-step length ("delta t") according to the /// Courant-Friedrichs-Lax - criterion, based on a velocity /// vector (<paramref name="velvect"/>) and the cell size /// this.<see cref="Cells"/>.<see cref="CellData.h_min"/>; /// </summary> /// <param name="velvect"> /// components of a velocity vector /// </param> /// <param name="max"> /// an upper maximum for the return value; This is useful if the velocity /// defined by <paramref name="velvect"/> is 0 or very small everywhere; /// </param> /// <param name="cm"> /// optional restriction of domain. /// </param> /// <returns> /// the minimum (over all cells j in all processes) of <see cref="CellData.h_min"/>[j] /// over v, where v is the Euclidean norm of a vector build from /// <paramref name="velvect"/>; /// This vector is evaluated at cell center and all cell vertices. /// The return value is the same on all processes; /// </returns> static public double ComputeCFLTime <T>(this IGridData __gdat, IEnumerable <T> velvect, double max, CellMask cm = null) where T : DGField // { using (var tr = new FuncTrace()) { GridData gdat = (GridData)__gdat; ilPSP.MPICollectiveWatchDog.Watch(MPI.Wrappers.csMPI.Raw._COMM.WORLD); T[] _velvect = velvect.ToArray(); if (cm == null) { cm = CellMask.GetFullMask(gdat); } int D = gdat.SpatialDimension; var KrefS = gdat.Grid.RefElements; // find cfl number on this processor // --------------------------------- var m_CFL_EvalPoints = new NodeSet[KrefS.Length]; for (int i = 0; i < KrefS.Length; i++) { var Kref = KrefS[i]; int N = Kref.NoOfVertices + 1; MultidimensionalArray vert = MultidimensionalArray.Create(N, D); vert.SetSubArray(Kref.Vertices, new int[] { 0, 0 }, new int[] { N - 2, D - 1 }); m_CFL_EvalPoints[i] = new NodeSet(Kref, vert); } // evaluators an memory for result int VecMax = 1000; DGField[] evalers = new DGField[_velvect.Length]; MultidimensionalArray[] fieldValues = new MultidimensionalArray[_velvect.Length]; for (int i = 0; i < _velvect.Length; i++) { evalers[i] = _velvect[i]; fieldValues[i] = MultidimensionalArray.Create(VecMax, m_CFL_EvalPoints[0].NoOfNodes); } var h_min = gdat.Cells.h_min; int K = _velvect.Length; double cflhere = max; //for (int j = 0; j < J; j += VectorSize) { foreach (Chunk chk in cm) { int VectorSize = VecMax; for (int j = chk.i0; j < chk.JE; j += VectorSize) { if (j + VectorSize > chk.JE + 1) { VectorSize = chk.JE - j; } VectorSize = gdat.Cells.GetNoOfSimilarConsecutiveCells(CellInfo.RefElementIndex_Mask, j, VectorSize); int iKref = gdat.Cells.GetRefElementIndex(j); int N = m_CFL_EvalPoints[iKref].GetLength(0); if (fieldValues[0].GetLength(0) != VectorSize) { for (int i = 0; i < _velvect.Length; i++) { fieldValues[i].Allocate(VectorSize, N); } } for (int k = 0; k < K; k++) { evalers[k].Evaluate(j, VectorSize, m_CFL_EvalPoints[iKref], fieldValues[k], 0, 0.0); } // loop over cells ... for (int jj = j; jj < j + VectorSize; jj++) { // loop over nodes ... for (int n = 0; n < N; n++) { double velabs = 0; // loop over velocity components ... for (int k = 0; k < K; k++) { double v = fieldValues[k][jj - j, n]; velabs += v * v; } velabs = Math.Sqrt(velabs); double cfl = h_min[jj] / velabs; cflhere = Math.Min(cfl, cflhere); } } } } // find the minimum over all processes via MPI and return // ------------------------------------------------------ double cfltotal; unsafe { csMPI.Raw.Allreduce((IntPtr)(&cflhere), (IntPtr)(&cfltotal), 1, csMPI.Raw._DATATYPE.DOUBLE, csMPI.Raw._OP.MIN, csMPI.Raw._COMM.WORLD); } tr.Info("computed CFL timestep: " + cfltotal); return(cfltotal); } }