/// <summary> /// Tools for updating operator matrices under level-set movement, when ordering of DOFs (the mapping) changes. /// </summary> public static void OperatorLevelSetUpdate(LevelSetTracker LsTrk, BlockMsrMatrix[] OpMtx, UnsetteledCoordinateMapping RowMap, UnsetteledCoordinateMapping ColMap) { using (new FuncTrace()) { BoSSS.Foundation.Grid.IGridData GridData = LsTrk.GridDat; int JE = GridData.iLogicalCells.NoOfCells; int Jup = GridData.iLogicalCells.NoOfLocalUpdatedCells; int cell_j0 = GridData.CellPartitioning.i0; // build index mappings // ==================== int[,] _old2NewRows, _old2NewCols; { List <Tuple <int, int> > old2NewRows = new List <Tuple <int, int> >(); List <Tuple <int, int> > old2NewCols = new List <Tuple <int, int> >(); List <Tuple <int, int> > old2NewColsExt = new List <Tuple <int, int> >(); // loop over cells for (int j = 0; j < JE; j++) { int[] RowIdxUpdate; if (j < Jup) { RowIdxUpdate = MappingUpdate(LsTrk, j, RowMap, false); } else { RowIdxUpdate = null; } int[] ColIdxUpdate = MappingUpdate(LsTrk, j, ColMap, false); Debug.Assert((j >= Jup) || ((RowIdxUpdate != null) == (ColIdxUpdate != null))); if (RowIdxUpdate != null) { //Debug.Assert(RowMap.GetBlockLen(cell_j0 + j) == RowMap.MaxTotalNoOfCoordinatesPerCell); //Debug.Assert(RowIdxUpdate.Length == RowMap.GetBlockLen(cell_j0 + j)); int i0 = RowMap.GetBlockI0(cell_j0 + j); int II = RowIdxUpdate.Length; for (int ii = 0; ii < II; ii++) { int iOld = ii + i0; int iNew = RowIdxUpdate[ii] + i0; if (RowIdxUpdate[ii] >= 0) { Debug.Assert(old2NewRows.Count == 0 || old2NewRows[old2NewRows.Count - 1].Item1 < iOld); old2NewRows.Add(new Tuple <int, int>(iOld, iNew)); } } } if (ColIdxUpdate != null) { //Debug.Assert(ColMap.MinTotalNoOfCoordinatesPerCell == ColMap.MaxTotalNoOfCoordinatesPerCell); //Debug.Assert(ColMap.GetBlockLen(cell_j0 + j) == ColMap.MaxTotalNoOfCoordinatesPerCell); //Debug.Assert(ColIdxUpdate.Length == ColMap.GetBlockLen(cell_j0 + j)); // mapping is old-->new, i.e. new[IdxUpdate[k]] = old[k] for all k //int i0 = ColMap.GetBlockI0(cell_j0 + j); //int jLoc; //if (j < Jup) // jLoc = j; //else // jLoc = LsTrk.GridDat.iParallel.Global2LocalIdx[cell_j0 + j]; int i0 = ColMap.GlobalUniqueCoordinateIndex(0, j, 0); //Debug.Assert() int II = ColIdxUpdate.Length; for (int ii = 0; ii < II; ii++) { int iOld = ii + i0; int iNew = ColIdxUpdate[ii] + i0; if (ColIdxUpdate[ii] >= 0) { if (j < Jup) { Debug.Assert(old2NewCols.Count == 0 || old2NewCols[old2NewCols.Count - 1].Item1 < iOld); old2NewCols.Add(new Tuple <int, int>(iOld, iNew)); } else { old2NewColsExt.Add(new Tuple <int, int>(iOld, iNew)); } } } } } // data conversion int I = old2NewRows.Count; _old2NewRows = new int[I, 2]; for (int i = 0; i < I; i++) { var t = old2NewRows[i]; _old2NewRows[i, 0] = t.Item1; _old2NewRows[i, 1] = t.Item2; } int J = old2NewCols.Count + old2NewColsExt.Count; old2NewColsExt.Sort((a, b) => a.Item1 - b.Item1); _old2NewCols = new int[J, 2]; int ja = 0, jb = 0; for (int j = 0; j < J; j++) { Tuple <int, int> t; if (ja < old2NewCols.Count && jb < old2NewColsExt.Count) { Tuple <int, int> t1, t2; t1 = old2NewCols[ja]; t2 = old2NewColsExt[jb]; Debug.Assert(t1.Item1 != t2.Item1); if (t1.Item1 < t2.Item1) { t = t1; ja++; } else { t = t2; jb++; } } else if (ja < old2NewCols.Count) { t = old2NewCols[ja]; ja++; } else { Debug.Assert(jb < old2NewColsExt.Count); Debug.Assert(ja >= old2NewCols.Count); t = old2NewColsExt[jb]; jb++; } _old2NewCols[j, 0] = t.Item1; _old2NewCols[j, 1] = t.Item2; Debug.Assert(j == 0 || _old2NewCols[j - 1, 0] < _old2NewCols[j, 0]); } Debug.Assert(ja == old2NewCols.Count); Debug.Assert(jb == old2NewColsExt.Count); } // update matrices // =============== for (int iMtx = 0; iMtx < OpMtx.Length; iMtx++) { if (OpMtx[iMtx] != null) { OpMtx[iMtx] = OpMtx[iMtx].RecyclePermute(RowMap, ColMap, _old2NewRows, _old2NewCols); } } } }