// public static IEnumerable<Tuple<int, int>> FindAgglomeration(LevelSetTracker Tracker, SpeciesId spId, double AgglomerationThreshold, MultidimensionalArray CellVolumes, MultidimensionalArray edgeArea, bool AgglomerateNewborn, bool AgglomerateDeceased, bool ExceptionOnFailedAgglomeration, MultidimensionalArray[] oldCellVolumes, double[] oldTs__AgglomerationTreshold, double NewbornAndDecasedThreshold) { using (var tracer = new FuncTrace()) { MPICollectiveWatchDog.Watch(); // init // ======= GridData grdDat = Tracker.GridDat; int[,] Edge2Cell = grdDat.Edges.CellIndices; byte[] EdgeTags = grdDat.Edges.EdgeTags; var Cell2Edge = grdDat.Cells.Cells2Edges; int myMpiRank = Tracker.GridDat.MpiRank; int NoOfEdges = grdDat.Edges.Count; int Jup = grdDat.Cells.NoOfLocalUpdatedCells; int Jtot = grdDat.Cells.Count; Partitioning CellPart = Tracker.GridDat.CellPartitioning; int i0 = CellPart.i0; var GidxExt = Tracker.GridDat.Parallel.GlobalIndicesExternalCells; var GidxExt2Lidx = Tracker.GridDat.Parallel.Global2LocalIdx; //double[] RefVolumes = grdDat.Grid.RefElements.Select(Kref => Kref.Volume).ToArray(); if (CellVolumes.GetLength(0) != Jtot) throw new ArgumentException(); if (edgeArea.GetLength(0) != NoOfEdges) throw new ArgumentException(); double EmptyEdgeTreshold = 1.0e-10; // edges with a measure blow or equal to this threshold are // considered to be 'empty', therefore they should not be used for agglomeration; // there is, as always, an exception: if all inner edges which belong to a // cell that should be agglomerated, the criterion mentioned above must be ignored. // determine agglomeration cells // ================================ var _AccEdgesMask = new BitArray(NoOfEdges); var AgglomCellsBitmask = new BitArray(Jup); var _AgglomCellsEdges = new BitArray(NoOfEdges); //var _AllowedEdges = new BitArray(NoOfEdges); _AllowedEdges.SetAll(true); // AllowedEdges.GetBitMask(); var AgglomerationPairs = new List<CellAgglomerator.AgglomerationPair>(); { // mask for the cells in which we -- potentially -- want to do agglomeration var AggCandidates = Tracker.Regions.GetSpeciesMask(spId).GetBitMaskWithExternal().CloneAs(); // pass 1: determine agglomeration sources // --------------------------------------- List<int> AgglomCellsList = new List<int>(); { // for the present timestep // - - - - - - - - - - - - - CellMask suspectsForAgg = Tracker.Regions.GetCutCellMask().Intersect(Tracker.Regions.GetSpeciesMask(spId)); foreach (int jCell in suspectsForAgg.ItemEnum) { double totVol = grdDat.Cells.GetCellVolume(jCell); double spcVol = CellVolumes[jCell]; double alpha = AgglomerationThreshold; spcVol = Math.Max(spcVol, 0.0); double frac = spcVol / totVol; //if (!(frac >= 0.0 && frac <= 1.00000001)) // throw new Exception("Strange volume fraction: cell " + jCell + ", species" + spId.ToString() + ", volume fraction =" + frac + "."); frac = Math.Min(1.0, Math.Max(0.0, frac)); if (frac < alpha) { // cell 'jCell' should be agglomerated to some other cell AgglomCellsBitmask[jCell] = true; AgglomCellsList.Add(jCell); } } } int NoTimeLev = oldTs__AgglomerationTreshold != null ? oldTs__AgglomerationTreshold.Length : 0; if (NoTimeLev > 0) { // for the previous timestep // - - - - - - - - - - - - - //ushort[][] PrevRegions = new ushort[NoTimeLev][]; //CellMask suspectsForAgg = Tracker.PreviousRegions.GetSpeciesMask(spId); //CellMask[] suspectsForAgg = new CellMask[NoTimeLev]; //for(int itl = 0; itl < NoTimeLev; itl++) { // PrevRegions[itl] = Tracker.RegionsHistory[-itl].LevelSetRegionsCode; // suspectsForAgg[itl] = Tracker.RegionsHistory[-itl].GetSpeciesMask(spId); //} LevelSetSignCode[] signCodes = Tracker.GetLevelSetSignCodes(spId); int NoOfLevSets = Tracker.LevelSets.Count; for (int iTimeLev = 0; iTimeLev < NoTimeLev; iTimeLev++) { CellMask suspectsForAgg = Tracker.RegionsHistory[-iTimeLev].GetSpeciesMask(spId); foreach (int jCell in suspectsForAgg.ItemEnum) { double totVol = grdDat.Cells.GetCellVolume(jCell); double spcVol = oldCellVolumes[iTimeLev][jCell]; double alpha = oldTs__AgglomerationTreshold[iTimeLev]; spcVol = Math.Max(spcVol, 0.0); double frac = spcVol / totVol; frac = Math.Min(1.0, Math.Max(0.0, frac)); if (frac < alpha) { // cell 'jCell' should be agglomerated to some other cell if (!AgglomCellsBitmask[jCell]) { AgglomCellsBitmask[jCell] = true; AgglomCellsList.Add(jCell); } } } } } if (AgglomerateNewborn) { for (int j = 0; j < Jup; j++) { double vol = grdDat.Cells.GetCellVolume(j); double volNewFrac_j = Math.Max(CellVolumes[j], 0.0) / vol; volNewFrac_j = Math.Min(1.0, Math.Max(0.0, volNewFrac_j)); if (volNewFrac_j > NewbornAndDecasedThreshold) { for (int nTs = 0; nTs < oldCellVolumes.Length; nTs++) { double volOldFrac_j = Math.Max(oldCellVolumes[nTs][j], 0.0) / vol; volOldFrac_j = Math.Min(1.0, Math.Max(0.0, volOldFrac_j)); if (volOldFrac_j <= NewbornAndDecasedThreshold) { // cell exists at new time, but not at some old time -> newborn int jNewbornCell = j; AggCandidates[jNewbornCell] = false; if (!AgglomCellsBitmask[jNewbornCell]) { AgglomCellsList.Add(jNewbornCell); AgglomCellsBitmask[jNewbornCell] = true; } } } } } } if (AgglomerateDeceased) { for (int j = 0; j < Jup; j++) { double vol = grdDat.Cells.GetCellVolume(j); double volNewFrac_j = Math.Max(CellVolumes[j], 0.0) / vol; volNewFrac_j = Math.Min(1.0, Math.Max(0.0, volNewFrac_j)); if (volNewFrac_j <= NewbornAndDecasedThreshold) { for (int nTs = 0; nTs < oldCellVolumes.Length; nTs++) { double volOldFrac_j = Math.Max(oldCellVolumes[nTs][j], 0.0) / vol; volOldFrac_j = Math.Min(1.0, Math.Max(0.0, volOldFrac_j)); if (volOldFrac_j > NewbornAndDecasedThreshold) { // cell does not exist at new time, but at some old time -> decased int jNewbornCell = j; AggCandidates[jNewbornCell] = false; if (!AgglomCellsBitmask[jNewbornCell]) { AgglomCellsList.Add(jNewbornCell); AgglomCellsBitmask[jNewbornCell] = true; } } } } } } //*/ /* if (AgglomerateNewborn || AgglomerateDeceased) { //CellMask oldSpeciesCells = this.Tracker.LevelSetData.PreviousSubGrids[spId].VolumeMask; CellMask newSpeciesCells = Tracker.Regions.GetSpeciesMask(spId); // only accept cells with positive volume (new species cells) BitArray newSpeciesCellsBitmask = newSpeciesCells.GetBitMask().CloneAs(); Debug.Assert(newSpeciesCellsBitmask.Count == Jup); for (int j = 0; j < Jup; j++) { double vol = grdDat.Cells.GetCellVolume(j); double volFrac_j = Math.Max(CellVolumes[j], 0.0) / vol; volFrac_j = Math.Min(1.0, Math.Max(0.0, volFrac_j)); if (volFrac_j > NewbornAndDecasedThreshold) { Debug.Assert(newSpeciesCellsBitmask[j] == true); } else { newSpeciesCellsBitmask[j] = false; } } newSpeciesCells = new CellMask(grdDat, newSpeciesCellsBitmask); // only accept cells with positive volume (old species cells) BitArray oldSpeciesCellsBitmask = new BitArray(Jup); // oldSpeciesCells.GetBitMask().CloneAs(); //Debug.Assert(oldSpeciesCellsBitmask.Count == Jup); for (int nTs = 0; nTs < oldCellVolumes.Length; nTs++) { MultidimensionalArray _oldCellVolumes = oldCellVolumes[nTs]; for (int j = 0; j < Jup; j++) { double vol = grdDat.Cells.GetCellVolume(j); double volFrac_j = Math.Max(_oldCellVolumes[j],0.0) / vol; volFrac_j = Math.Min(1.0, Math.Max(0.0, volFrac_j)); if (volFrac_j > NewbornAndDecasedThreshold) { //Debug.Assert(oldSpeciesCellsBitmask[j] == true); oldSpeciesCellsBitmask[j] = true; } else { //oldSpeciesCellsBitmask[j] = false; } } } var oldSpeciesCells = new CellMask(grdDat, oldSpeciesCellsBitmask); // find newborn and decased CellMask newBorn = newSpeciesCells.Except(oldSpeciesCells); CellMask deceased = oldSpeciesCells.Except(newSpeciesCells); foreach (int jNewbornCell in newBorn.ItemEnum) { AggCandidates[jNewbornCell] = false; if (!AgglomCellsBitmask[jNewbornCell]) { AgglomCellsList.Add(jNewbornCell); AgglomCellsBitmask[jNewbornCell] = true; } //Console.WriteLine(" agglom newborn: " + jNewbornCell); } foreach (int jDeceasedCell in deceased.ItemEnum) { AggCandidates[jDeceasedCell] = false; if (!AgglomCellsBitmask[jDeceasedCell]) { AgglomCellsList.Add(jDeceasedCell); AgglomCellsBitmask[jDeceasedCell] = true; } //Console.WriteLine(" agglom deceased: " + jDeceasedCell); } } //*/ // pass 2: determine agglomeration targets // --------------------------------------- foreach (int jCell in AgglomCellsList) { var Cell2Edge_jCell = Cell2Edge[jCell]; // cell 'jCell' should be agglomerated to some other cell Debug.Assert(AgglomCellsBitmask[jCell] == true); double frac_neigh_max = -1.0; int e_max = -1; int jEdge_max = int.MinValue; int jCellNeigh_max = int.MinValue; int NoOfEdges_4_jCell = Cell2Edge_jCell.Length; // determine if there is a non-empty edge which connects cell 'jCell' // to some other cell bool NonEmptyEdgeAvailable = false; for (int e = 0; e < NoOfEdges_4_jCell; e++) { // loop over faces/neighbour cells... int iEdge = Cell2Edge_jCell[e]; int OtherCell; if (iEdge < 0) { // cell 'jCell' is the OUT-cell of edge 'iEdge' OtherCell = 0; iEdge *= -1; } else { OtherCell = 1; } iEdge--; int jCellNeigh = Edge2Cell[iEdge, OtherCell]; double EdgeArea_iEdge = edgeArea[iEdge]; if (jCellNeigh >= 0 && EdgeArea_iEdge > EmptyEdgeTreshold) NonEmptyEdgeAvailable = true; } for (int e = 0; e < NoOfEdges_4_jCell; e++) { // loop over faces/neighbour cells... int iEdge = Cell2Edge_jCell[e]; int OtherCell, ThisCell; if (iEdge < 0) { // cell 'jCell' is the OUT-cell of edge 'iEdge' OtherCell = 0; ThisCell = 1; iEdge *= -1; } else { OtherCell = 1; ThisCell = 0; } iEdge--; double EdgeArea_iEdge = edgeArea[iEdge]; _AgglomCellsEdges[iEdge] = true; Debug.Assert(Edge2Cell[iEdge, ThisCell] == jCell); int jCellNeigh = Edge2Cell[iEdge, OtherCell]; if (jCellNeigh < 0 || EdgeTags[iEdge] >= GridCommons.FIRST_PERIODIC_BC_TAG || (EdgeArea_iEdge <= EmptyEdgeTreshold && NonEmptyEdgeAvailable)) { // boundary edge, no neighbour for agglomeration Debug.Assert(Edge2Cell[iEdge, ThisCell] == jCell, "sollte aber so sein"); continue; } if (!AggCandidates[jCellNeigh]) // not suitable for agglomeration continue; // volume fraction of neighbour cell double spcVol_neigh = CellVolumes[jCellNeigh]; //double totVol_neigh = RefVolumes[grdDat.Cells.GetRefElementIndex(jCellNeigh)]; double totVol_neigh = grdDat.Cells.GetCellVolume(jCellNeigh); double frac_neigh = spcVol_neigh / totVol_neigh; // max? if (frac_neigh > frac_neigh_max) { frac_neigh_max = frac_neigh; e_max = e; jCellNeigh_max = jCellNeigh; jEdge_max = iEdge; } } if (jCellNeigh_max < 0) { string message = ("Agglomeration failed - no candidate for agglomeration found"); if (ExceptionOnFailedAgglomeration) throw new Exception(message); else Console.WriteLine(message); } else { _AccEdgesMask[jEdge_max] = true; int jCellNeighRank; if (jCellNeigh_max < Jup) { jCellNeighRank = myMpiRank; } else { jCellNeighRank = CellPart.FindProcess(GidxExt[jCellNeigh_max - Jup]); } AgglomerationPairs.Add(new CellAgglomerator.AgglomerationPair() { jCellTarget = jCellNeigh_max, jCellSource = jCell, OwnerRank4Target = jCellNeighRank, OwnerRank4Source = myMpiRank }); } } } // store & return // ================ return AgglomerationPairs.Select(pair => new Tuple<int, int>(pair.jCellSource, pair.jCellTarget)).ToArray(); } }
/// <summary> /// performs a parallel inversion of this permutation /// </summary> /// <returns></returns> public Permutation Invert() { using (new FuncTrace()) { Permutation inv = new Permutation(this); int localLength = m_Partition.LocalLength; //m_LocalLengths[m_Master.MyRank]; int size; MPI.Wrappers.csMPI.Raw.Comm_Size(m_Comm, out size); inv.m_Values = new long[localLength]; long myi0Offset = m_Partition.i0; //m_i0Offset[m_Master.MyRank]; Many2ManyMessenger <PermutationEntry> m2m = new Many2ManyMessenger <PermutationEntry>(m_Comm); int[] NoOfItemsToSent = new int[size]; // calc i0's for each process // ========================== long[] i0 = new long[size + 1]; for (int i = 1; i <= size; i++) { i0[i] = i0[i - 1] + m_Partition.GetLocalLength(i - 1);// m_LocalLengths[i - 1]; } // do local inversion and collect items // ==================================== List <PermutationEntry>[] itemsToSend = new List <PermutationEntry> [size]; for (int p = 0; p < size; p++) { itemsToSend[p] = new List <PermutationEntry>(); } for (int i = 0; i < localLength; i++) { // decide wether inversion of entry i is local or has to be transmitted ... if (m_Values[i] >= myi0Offset && m_Values[i] < (myi0Offset + localLength)) { // local inv.m_Values[this.m_Values[i] - myi0Offset] = i + myi0Offset; } else { // transmit // find target processor int targProc = m_Partition.FindProcess(m_Values[i]); NoOfItemsToSent[targProc]++; // collect item PermutationEntry pe; pe.Index = myi0Offset + i; pe.PermVal = m_Values[i]; itemsToSend[targProc].Add(pe); } } // setup messenger // =============== for (int i = 0; i < size; i++) { if (NoOfItemsToSent[i] > 0) { m2m.SetCommPath(i, NoOfItemsToSent[i]); } } m2m.CommitCommPaths(); // transmit data // ============= //csMPI.Raw.Barrier(csMPI.Raw.MPI_COMM_WORLD); //Console.WriteLine("one"); //csMPI.Raw.Barrier(csMPI.Raw.MPI_COMM_WORLD); //Console.WriteLine("two"); //csMPI.Raw.Barrier(csMPI.Raw.MPI_COMM_WORLD); //Console.WriteLine("three"); m2m.StartTransmission(1); for (int p = 0; p < size; p++) { if (NoOfItemsToSent[p] <= 0) { continue; } //Many2ManyMessenger.Buffer<PermEntry> sndbuf = new Many2ManyMessenger.Buffer<PermEntry>(m2m, false, p); PermutationEntry[] items = itemsToSend[p].ToArray(); m2m.SendBuffers(p).CopyFrom(items, 0); m2m.TransmittData(p); } m2m.FinishBlocking(); // invert received items // ===================== for (int p = 0; p < size; p++) { Many2ManyMessenger <PermutationEntry> .Buffer rcvbuf = m2m.ReceiveBuffers(p); if (rcvbuf == null) { continue; // no data from process no. p } int cnt = rcvbuf.Count; PermutationEntry[] items = new PermutationEntry[cnt]; rcvbuf.CopyTo(items, 0); for (int i = 0; i < cnt; i++) { inv.m_Values[items[i].PermVal - myi0Offset] = items[i].Index; } } // finalize // ======== m2m.Dispose(); return(inv); } }