static void PrlgAndRestMtxTestRec(int p, MultigridMapping[] MgMapSeq) { var currentLevelMap = MgMapSeq.First(); var AggBasis = currentLevelMap.AggBasis[0]; // extract Restriciton and Prolongation Operators BlockMsrMatrix RestOp = new BlockMsrMatrix(MgMapSeq.First(), MgMapSeq.First().ProblemMapping); AggBasis.GetRestrictionMatrix(RestOp, MgMapSeq.First(), 0); BlockMsrMatrix PrlgOp = RestOp.Transpose(); // restriction onto level itself BlockMsrMatrix ShldBeEye = BlockMsrMatrix.Multiply(RestOp, PrlgOp); ShldBeEye.AccEyeSp(-1.0); double ErrNorm = ShldBeEye.InfNorm(); Console.WriteLine("Id norm {0} \t (level {1})", ErrNorm, currentLevelMap.AggGrid.MgLevel); Assert.Less(ErrNorm, 1.0e-8); if (MgMapSeq.Length > 1) { PrlgAndRestMtxTestRec(p, MgMapSeq.Skip(1).ToArray()); } }
/// <summary> /// Reload of some operator after before grid-redistribution. /// </summary> /// <param name="Mtx_new"> /// Output, matrix which should be restored. /// </param> /// <param name="Reference"> /// Unique string reference under which data has been stored before grid-redistribution. /// </param> /// <param name="RowMapping"> /// Coordinate mapping to correlate the matrix rows with cells of the computational grid. /// </param> /// <param name="ColMapping"> /// Coordinate mapping to correlate the matrix columns with cells of the computational grid. /// </param> public void RestoreMatrix(BlockMsrMatrix Mtx_new, string Reference, UnsetteledCoordinateMapping RowMapping, UnsetteledCoordinateMapping ColMapping) { int J = m_NewGrid.iLogicalCells.NoOfLocalUpdatedCells; CheckMatrix(Mtx_new, RowMapping, ColMapping, J); BlockMsrMatrix Mtx_old = m_Matrices[Reference].Item3; int[] RowHash = GetDGBasisHash(RowMapping.BasisS); int[] ColHash = GetDGBasisHash(ColMapping.BasisS); if (!ArrayTools.AreEqual(RowHash, m_Matrices[Reference].Item1)) { throw new ApplicationException(); } if (!ArrayTools.AreEqual(ColHash, m_Matrices[Reference].Item2)) { throw new ApplicationException(); } BlockMsrMatrix P_Row = GetRowPermutationMatrix(Mtx_new, Mtx_old, RowHash); BlockMsrMatrix P_Col = GetColPermutationMatrix(Mtx_new, Mtx_old, ColHash); Debug.Assert(Mtx_new._RowPartitioning.LocalNoOfBlocks == m_newJ); Debug.Assert(Mtx_new._ColPartitioning.LocalNoOfBlocks == m_newJ); Debug.Assert(Mtx_old._RowPartitioning.LocalNoOfBlocks == m_oldJ); Debug.Assert(Mtx_old._ColPartitioning.LocalNoOfBlocks == m_oldJ); Debug.Assert(P_Row._RowPartitioning.LocalNoOfBlocks == m_newJ); Debug.Assert(P_Row._ColPartitioning.LocalNoOfBlocks == m_oldJ); Debug.Assert(P_Col._RowPartitioning.LocalNoOfBlocks == m_oldJ); Debug.Assert(P_Col._ColPartitioning.LocalNoOfBlocks == m_newJ); BlockMsrMatrix.Multiply(Mtx_new, BlockMsrMatrix.Multiply(P_Row, Mtx_old), P_Col); }
/// <summary> /// returns all external rows of <paramref name="M"/> /// corresponding to ghost cells of <paramref name="map"/>, /// which are located on other Mpi-ranks. /// </summary> /// <param name="map">Multigrid mapping</param> /// <param name="M">matrix distributed according to <paramref name="map"/></param> /// <returns></returns> public static BlockMsrMatrix GetAllExternalRows(MultigridMapping map, BlockMsrMatrix M) { var extcells = map.AggGrid.iLogicalCells.NoOfExternalCells.ForLoop(i => i + map.LocalNoOfBlocks); var SBS = new SubBlockSelector(map); SBS.CellSelector(extcells, false); var AllExtMask = new BlockMaskExt(SBS, 0); var ExternalRows_BlockI0 = AllExtMask.GetAllSubMatrixCellOffsets(); var ExternalRows_BlockN = AllExtMask.GetAllSubMatrixCellLength(); var ExternalRowsIndices = AllExtMask.m_GlobalMask; BlockPartitioning PermRow = new BlockPartitioning(ExternalRowsIndices.Count, ExternalRows_BlockI0, ExternalRows_BlockN, M.MPI_Comm, i0isLocal: true); BlockMsrMatrix Perm = new BlockMsrMatrix(PermRow, M._RowPartitioning); for (int iRow = 0; iRow < ExternalRowsIndices.Count; iRow++) { Debug.Assert(M._RowPartitioning.IsInLocalRange(ExternalRowsIndices[iRow]) == false); Perm[iRow + PermRow.i0, ExternalRowsIndices[iRow]] = 1; } #if TEST Perm.SaveToTextFileSparseDebug("Perm"); #endif return(BlockMsrMatrix.Multiply(Perm, M)); }
static void RestictionMatrixTestRec(int p, IEnumerable <MultigridMapping> MgMapSeq) { var currentLevelMap = MgMapSeq.First(); AggregationGridBasis AggBasis = currentLevelMap.AggBasis[0]; var map = new UnsetteledCoordinateMapping(new Basis(grid, p)); Random rnd = new Random(); double[] OrigVec = map.LocalLength.ForLoop(i => rnd.NextDouble()); double[] RestVec = new double[AggBasis.LocalDim]; double[] PrlgVec = new double[OrigVec.Length]; double[] RestVec2 = new double[RestVec.Length]; double[] PrlgVec2 = new double[OrigVec.Length]; AggBasis.RestictFromFullGrid(OrigVec, RestVec); AggBasis.ProlongateToFullGrid(PrlgVec, RestVec); BlockMsrMatrix RestOp = new BlockMsrMatrix(MgMapSeq.First(), MgMapSeq.First().ProblemMapping); AggBasis.GetRestrictionMatrix(RestOp, MgMapSeq.First(), 0); RestOp.SpMV(1.0, OrigVec, 0.0, RestVec2); BlockMsrMatrix PrlgOp = RestOp.Transpose(); PrlgOp.SpMV(1.0, RestVec2, 0.0, PrlgVec2); double RestErrNorm = GenericBlas.L2Dist(RestVec2, RestVec); double PrlgErrNorm = GenericBlas.L2Dist(PrlgVec2, PrlgVec); double LostInfNorm = GenericBlas.L2Dist(OrigVec, PrlgVec2); //Console.WriteLine("Rest. matrix test: {0}, Prolong. matrix test {1}, Lost info {2}", RestErrNorm, PrlgErrNorm, LostInfNorm); Assert.IsTrue(RestErrNorm < 1.0e-10); Assert.IsTrue(PrlgErrNorm < 1.0e-10); // restriction onto level itself BlockMsrMatrix RestMtx = currentLevelMap.FromOtherLevelMatrix(currentLevelMap); BlockMsrMatrix ShldBeEye = BlockMsrMatrix.Multiply(RestMtx, RestMtx.Transpose()); ShldBeEye.AccEyeSp(-1.0); double errNorm = ShldBeEye.InfNorm(); Console.WriteLine("Id norm {0} \t (level {1})", errNorm, currentLevelMap.AggGrid.MgLevel); Assert.IsTrue(errNorm < 1.0e-8); // recursion if (MgMapSeq.Count() > 1) { RestictionMatrixTestRec(p, MgMapSeq.Skip(1)); } }
/// <summary> /// Prolongation or Restriction from *any* other level to this level. /// </summary> /// <param name="otherLevel"> /// Other level, from which one wants to prolongate/restrict. /// </param> /// <returns> /// A matrix, where /// - row correspond to this mapping /// - columns correspond to <paramref name="otherLevel"/> /// If the other level is coarser, this is a prolongation; if the other level is finer, it is the restriction in the L2-sense, /// for standard DG; for XDG, in some other norm determined by the cut-cell shape. /// </returns> public BlockMsrMatrix FromOtherLevelMatrix(MultigridMapping otherLevel) { using (new FuncTrace()) { BlockMsrMatrix PrlgMtx; { PrlgMtx = new BlockMsrMatrix(otherLevel, otherLevel.ProblemMapping); for (int ifld = 0; ifld < otherLevel.AggBasis.Length; ifld++) { otherLevel.AggBasis[ifld].GetRestrictionMatrix(PrlgMtx, otherLevel, ifld); // prolongate from the other level to the full grid } PrlgMtx = PrlgMtx.Transpose(); } BlockMsrMatrix RestMtx; { RestMtx = new BlockMsrMatrix(this, this.ProblemMapping); for (int ifld = 0; ifld < this.AggBasis.Length; ifld++) { this.AggBasis[ifld].GetRestrictionMatrix(RestMtx, this, ifld); // ... and restrict to this level } } var result = BlockMsrMatrix.Multiply(RestMtx, PrlgMtx); #if DEBUG { var resultT = result.Transpose(); BlockMsrMatrix ShoudBeId; if (result.RowPartitioning.TotalLength < result.ColPartition.TotalLength) { ShoudBeId = BlockMsrMatrix.Multiply(result, resultT); } else { ShoudBeId = BlockMsrMatrix.Multiply(resultT, result); } ShoudBeId.AccEyeSp(-1.0); double ShouldBeID_Norm = ShoudBeId.InfNorm(); Debug.Assert(ShouldBeID_Norm < 1.0e-8); //Console.WriteLine("Id norm {0} \t (level {1})", ShouldBeID_Norm, this.AggGrid.MgLevel); } #endif return(result); } }
public void Init(MultigridOperator op) { using (new FuncTrace()) { if (m_MgOp != null) { // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // someone is trying to re-use this solver: see if the settings permit that // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if (op.LevelIndex != m_MgOp.LevelIndex) { throw new ArgumentException("Re-use on different level not possible."); } if (!this.MtxFull._RowPartitioning.EqualsPartition(op.OperatorMatrix._RowPartitioning)) { throw new ArgumentException("Matrix has changed, unable to re-use"); } if (!this.MtxFull._ColPartitioning.EqualsPartition(op.OperatorMatrix._ColPartitioning)) { throw new ArgumentException("Matrix has changed, unable to re-use"); } #if DEBUG if (!object.ReferenceEquals(this.MtxFull, op.OperatorMatrix)) { BlockMsrMatrix Check = this.MtxFull.CloneAs(); Check.Acc(-1.0, op.OperatorMatrix); if (Check.InfNorm() != 0.0) { throw new ArgumentException("Matrix has changed, unable to re-use"); } } #endif if (this.m_BlockingStrategy.GetNoOfBlocks(op) != this.blockSolvers.Count()) { throw new ArgumentException("Blocking, unable to re-use"); } return; } var Mop = op.OperatorMatrix; var MgMap = op.Mapping; this.m_MgOp = op; int myMpiRank = MgMap.MpiRank; int myMpisize = MgMap.MpiSize; if (!Mop.RowPartitioning.EqualsPartition(MgMap.Partitioning)) { throw new ArgumentException("Row partitioning mismatch."); } if (!Mop.ColPartition.EqualsPartition(MgMap.Partitioning)) { throw new ArgumentException("Column partitioning mismatch."); } var ag = MgMap.AggGrid; int JComp = ag.iLogicalCells.NoOfLocalUpdatedCells; int JGhost = ag.iLogicalCells.NoOfExternalCells; #if DEBUG ilPSP.Connectors.Matlab.BatchmodeConnector matlab; if (m_MatlabParalellizationCheck) { matlab = new ilPSP.Connectors.Matlab.BatchmodeConnector(); } else { matlab = null; } #endif //Mop.Clear(); //for(int i = Mop.RowPartitioning.i0; i < Mop.RowPartitioning.iE; i++) { // Mop[i, i] = i + 1; //} // get cell blocks // =============== var _Blocks = this.m_BlockingStrategy.GetBlocking(op); int NoOfSchwzBlocks = _Blocks.Count(); // test cell blocks // ================ #if DEBUG { // ensure that each cell is used exactly once, among all blocks bool[] test = new bool[ag.iLogicalCells.NoOfLocalUpdatedCells]; foreach (var bi in _Blocks) { foreach (int j in bi) { Debug.Assert(test[j] == false); test[j] = true; } ; } for (int i = 0; i < test.Length; i++) { Debug.Assert(test[i] == true); } } #endif // extend blocks according to desired overlap // ========================================== { BitArray marker = new BitArray(JComp + JGhost); if (Overlap < 0) { throw new ArgumentException(); } if (Overlap > 0) { if (Overlap > 1 && Mop.RowPartitioning.MpiSize > 1) { throw new NotSupportedException("In MPI parallel runs, the maximum supported overlap for the Schwarz preconditioner is 1."); } foreach (List <int> bi in _Blocks) // loop over blocks... { marker.SetAll(false); // marks all cells which are members of the block foreach (int jcomp in bi) { marker[jcomp] = true; } // determine overlap regions for (int k = 0; k < Overlap; k++) { int Jblock = bi.Count; for (int j = 0; j < Jblock; j++) { int jCell = bi[j]; int[] Neighs = ag.iLogicalCells.CellNeighbours[jCell]; foreach (int jNeigh in Neighs) { if (marker[jNeigh] == false) { // neighbor cell is not already a member of the block // => add it. bi.Add(jNeigh); marker[jNeigh] = true; } } } } bi.Sort(); } } BlockCells = _Blocks.Select(list => list.ToArray()).ToArray(); } // convert cell blocks to DOF blocks // ================================= List <int>[] BlkIdx_gI_lR; // for each Schwarz block, (global) indices in the local range List <int>[] BlkIdx_gI_eR; // for each Schwarz block, (global) indices of external rows and columns List <int>[] TempRowIdx_gI; // for each Schwarz block, (global) indices into the temporary matrix List <int>[] BlkIdx_lI_eR; // for each Schwarz block, (local) indices of external rows and columns List <int>[] LocalBlocks_i0, LocalBlocks_N; // blocking of the Schwarz-Blocks. // for matrix 'ExternalRowsTemp': which rows of 'Mop' are required locally List <int> ExternalRowsIndices, ExternalRows_BlockI0, ExternalRows_BlockN; { int Jup = MgMap.AggGrid.iLogicalCells.NoOfLocalUpdatedCells; int Jgh = MgMap.AggGrid.iLogicalCells.NoOfExternalCells; int LocalizedBlockCounter = 0; BlkIdx_gI_lR = NoOfSchwzBlocks.ForLoop(iPart => new List <int>(BlockCells[iPart].Length * MgMap.MaximalLength)); BlkIdx_gI_eR = NoOfSchwzBlocks.ForLoop(iPart => new List <int>()); LocalBlocks_i0 = NoOfSchwzBlocks.ForLoop(iPart => new List <int>()); LocalBlocks_N = NoOfSchwzBlocks.ForLoop(iPart => new List <int>()); TempRowIdx_gI = NoOfSchwzBlocks.ForLoop(iPart => new List <int>()); BlkIdx_lI_eR = NoOfSchwzBlocks.ForLoop(iPart => new List <int>()); ExternalRowsIndices = new List <int>(); ExternalRows_BlockI0 = new List <int>(); ExternalRows_BlockN = new List <int>(); for (int iPart = 0; iPart < NoOfSchwzBlocks; iPart++) // loop over parts... { int[] bc = BlockCells[iPart]; var biI = BlkIdx_gI_lR[iPart]; var biE = BlkIdx_gI_eR[iPart]; var l1 = TempRowIdx_gI[iPart]; var l2 = BlkIdx_lI_eR[iPart]; var LBBi0 = LocalBlocks_i0[iPart]; var LBBN = LocalBlocks_N[iPart]; int Jblock = bc.Length; int anotherCounter = 0; for (int jblk = 0; jblk < Jblock; jblk++) // loop over cells in blocks... { int j = bc[jblk]; int N = MgMap.GetLength(j); if (j < Jup) { // locally updated cell int i0 = MgMap.GlobalUniqueIndex(0, j, 0); for (int n = 0; n < N; n++) { biI.Add(i0 + n); } } else { // external cell int i0E = MgMap.GlobalUniqueIndex(0, j, 0); // int i0L = MgMap.LocalUniqueIndex(0, j, 0); // ExternalRows_BlockI0.Add(LocalizedBlockCounter); ExternalRows_BlockN.Add(N); //LEBi0.Add(LocalizedBlockCounter); //LEBn.Add(N); for (int n = 0; n < N; n++) { biE.Add(i0E + n); ExternalRowsIndices.Add(i0E + n); l1.Add(LocalizedBlockCounter + n); l2.Add(i0L + n); Debug.Assert(Mop._RowPartitioning.FindProcess(i0E + n) != myMpiRank); } LocalizedBlockCounter += N; } LBBi0.Add(anotherCounter); LBBN.Add(N); anotherCounter += N; } } //this.BlockIndices = _LocallyStoredBlockIndices.Select(bi => bi.ToArray()).ToArray(); } // get rows for blocks that use external cells // =========================================== #if DEBUG { if (Overlap == 0) { Debug.Assert(ExternalRowsIndices.Count == 0); Debug.Assert(ExternalRows_BlockI0.Count == 0); Debug.Assert(ExternalRows_BlockN.Count == 0); } foreach (var bi in BlkIdx_gI_lR) { foreach (int idx in bi) { Debug.Assert(idx >= m_MgOp.Mapping.i0); Debug.Assert(idx < m_MgOp.Mapping.iE); } } foreach (var ei in BlkIdx_gI_eR) { foreach (int idx in ei) { Debug.Assert(idx < m_MgOp.Mapping.i0 || idx >= m_MgOp.Mapping.iE); } } int LL = m_MgOp.Mapping.LocalLength; int jMax = m_MgOp.Mapping.AggGrid.iLogicalCells.NoOfCells - 1; int LE = m_MgOp.Mapping.LocalUniqueIndex(0, jMax, 0) + m_MgOp.Mapping.GetLength(jMax); foreach (var ci in BlkIdx_lI_eR) { foreach (int idx in ci) { Debug.Assert(idx >= LL); Debug.Assert(idx < LE); } } if (m_MatlabParalellizationCheck) { int globalBlockCounter = 0; for (int rankCounter = 0; rankCounter < myMpisize; rankCounter++) { int rank_NoBlks = NoOfSchwzBlocks.MPIBroadcast(rankCounter); if (rankCounter == myMpiRank) { Debug.Assert(rank_NoBlks == NoOfSchwzBlocks); } for (int iBlock = 0; iBlock < rank_NoBlks; iBlock++) { double[] vec; if (rankCounter == myMpiRank) { vec = ArrayTools.Cat(BlkIdx_gI_lR[iBlock], BlkIdx_gI_eR[iBlock]).Select(ii => ((double)(ii + 1))).ToArray(); } else { vec = new double[0]; } matlab.PutVector(vec, string.Format("BlockIdx{0}", globalBlockCounter)); globalBlockCounter++; csMPI.Raw.Barrier(csMPI.Raw._COMM.WORLD); } } } } #endif BlockMsrMatrix ExternalRowsTemp; if (myMpisize > 1 && Overlap > 0) { //int NoOfLocalRows = _ExternalBlockIndices.Sum(L => L.Count); BlockPartitioning PermRow = new BlockPartitioning(ExternalRowsIndices.Count, ExternalRows_BlockI0, ExternalRows_BlockN, Mop.MPI_Comm, i0isLocal: true); // Remark: we use a permutation matrix for MPI-exchange of rows BlockMsrMatrix Perm = new BlockMsrMatrix(PermRow, Mop._RowPartitioning); for (int iRow = 0; iRow < ExternalRowsIndices.Count; iRow++) { Debug.Assert(Mop._RowPartitioning.IsInLocalRange(ExternalRowsIndices[iRow]) == false); Perm[iRow + PermRow.i0, ExternalRowsIndices[iRow]] = 1; } ExternalRowsTemp = BlockMsrMatrix.Multiply(Perm, Mop); #if DEBUG if (m_MatlabParalellizationCheck) { matlab.PutSparseMatrix(Perm, "Perm"); matlab.PutSparseMatrix(ExternalRowsTemp, "ExternalRowsTemp"); } #endif } else { ExternalRowsTemp = null; } ExternalRowsIndices = null; ExternalRows_BlockI0 = null; ExternalRows_BlockN = null; // create solvers // ============== { blockSolvers = new ISparseSolver[NoOfSchwzBlocks]; #if DEBUG List <BlockMsrMatrix> Blocks = new List <BlockMsrMatrix>(); #endif for (int iPart = 0; iPart < NoOfSchwzBlocks; iPart++) { var bi = BlkIdx_gI_lR[iPart]; int Bsz; if (MgMap.MinimalLength == MgMap.MaximalLength) { Bsz = MgMap.MaximalLength; } else { Bsz = 1; } var l1 = TempRowIdx_gI[iPart]; //if (M.RowPartitioning.MpiSize > 1) { // int i0Proc = M.RowPartitioning.i0; // bi = bi.CloneAs(); // for (int i = 0; i < bi.Length; i++) { // bi[i] += i0Proc; // } //} BlockPartitioning localBlocking = new BlockPartitioning(bi.Count + l1.Count, LocalBlocks_i0[iPart], LocalBlocks_N[iPart], csMPI.Raw._COMM.SELF); if (l1.Count > 0) { // convert the indices into 'ExternalRowsTemp' to global indices int l1L = l1.Count; int offset = ExternalRowsTemp._RowPartitioning.i0; for (int i = 0; i < l1L; i++) { l1[i] += offset; } } BlockMsrMatrix Block = new BlockMsrMatrix(localBlocking, localBlocking);// bi.Length, bi.Length, Bsz, Bsz); Mop.WriteSubMatrixTo(Block, bi, default(int[]), bi, default(int[])); if (l1.Count > 0) { int offset = bi.Count; int[] targRows = l1.Count.ForLoop(i => i + offset); var biE = BlkIdx_gI_eR[iPart]; int[] extTargCols = biE.Count.ForLoop(i => i + offset); Mop.AccSubMatrixTo(1.0, Block, bi, default(int[]), new int[0], default(int[]), biE, extTargCols); ExternalRowsTemp.AccSubMatrixTo(1.0, Block, l1, targRows, bi, default(int[]), biE, extTargCols); } #if DEBUG if (m_MatlabParalellizationCheck) { Blocks.Add(Block); } #endif blockSolvers[iPart] = new PARDISOSolver() { CacheFactorization = true, UseDoublePrecision = false }; //blockSolvers[iPart] = new FullDirectSolver(); //blockSolvers[iPart] = new ilPSP.LinSolvers.MUMPS.MUMPSSolver(); blockSolvers[iPart].DefineMatrix(Block); } #if DEBUG if (m_MatlabParalellizationCheck) { int globalBlockCounter = 0; for (int rankCounter = 0; rankCounter < myMpisize; rankCounter++) { int rank_NoBlks = NoOfSchwzBlocks.MPIBroadcast(rankCounter); for (int iBlock = 0; iBlock < rank_NoBlks; iBlock++) { BlockMsrMatrix Block; if (rankCounter == myMpiRank) { Block = Blocks[iBlock]; } else { Block = null; } matlab.PutSparseMatrix(Block, string.Format("Block{0}", globalBlockCounter)); globalBlockCounter++; csMPI.Raw.Barrier(csMPI.Raw._COMM.WORLD); } } } #endif } // Record required indices // ======================= { this.BlockIndices_Local = new int[NoOfSchwzBlocks][]; this.BlockIndices_External = new int[NoOfSchwzBlocks][]; int LocalI0 = MgMap.i0; int LocalLength = MgMap.LocalLength; for (int iBlock = 0; iBlock < NoOfSchwzBlocks; iBlock++) { var _bi = BlkIdx_gI_lR[iBlock]; int L = _bi.Count; int[] bil = new int[L]; this.BlockIndices_Local[iBlock] = bil; for (int l = 0; l < L; l++) { bil[l] = _bi[l] - LocalI0; Debug.Assert(bil[l] >= 0); Debug.Assert(bil[l] < MgMap.LocalLength); } var _biE = BlkIdx_lI_eR[iBlock]; if (_biE.Count > 0) { this.BlockIndices_External[iBlock] = _biE.ToArray(); } } } this.MtxFull = Mop; if (CoarseSolver != null) { CoarseSolver.Init(op.CoarserLevel); } // Debug & Test-Code // ================= #if DEBUG if (m_MatlabParalellizationCheck) { Console.WriteLine("Matlab dir: " + matlab.WorkingDirectory); matlab.PutSparseMatrix(Mop, "Full"); int GlobalNoOfBlocks = NoOfSchwzBlocks.MPISum(); for (int iGlbBlock = 0; iGlbBlock < GlobalNoOfBlocks; iGlbBlock++) { matlab.Cmd("BlockErr({0} + 1, 1) = norm( Block{0} - Full( BlockIdx{0}, BlockIdx{0} ), inf );", iGlbBlock); } Random rnd = new Random(myMpiRank); double[] testRHS = new double[MgMap.LocalLength]; for (int i = 0; i < testRHS.Length; i++) { testRHS[i] = rnd.NextDouble(); } matlab.PutVector(testRHS, "testRHS"); MPIexchange <double[]> ResExchange = new MPIexchange <double[]>(MgMap, testRHS); ResExchange.TransceiveStartImReturn(); ResExchange.TransceiveFinish(0.0); int offset = MgMap.LocalLength; int g = 0; for (int rankCounter = 0; rankCounter < myMpisize; rankCounter++) { int rank_NoBlks = NoOfSchwzBlocks.MPIBroadcast(rankCounter); for (int iBlock = 0; iBlock < rank_NoBlks; iBlock++) { double[] SubVec; if (rankCounter == myMpiRank) { int LL = this.BlockIndices_Local[iBlock].Length; int LE; if (this.BlockIndices_External[iBlock] != null) { LE = this.BlockIndices_External[iBlock].Length; } else { LE = 0; } int L = LL + LE; SubVec = new double[L]; for (int i = 0; i < LL; i++) { SubVec[i] = testRHS[this.BlockIndices_Local[iBlock][i]]; } if (LE > 0) { for (int i = 0; i < LE; i++) { SubVec[i + LL] = ResExchange.Vector_Ext[this.BlockIndices_External[iBlock][i] - offset]; } } } else { SubVec = new double[0]; } matlab.PutVector(SubVec, "SubVec" + g); g++; } } for (int iGlbBlock = 0; iGlbBlock < GlobalNoOfBlocks; iGlbBlock++) { matlab.Cmd("RhsErr({0} + 1, 1) = norm( SubVec{0} - testRHS( BlockIdx{0} ), inf );", iGlbBlock); } double[] testX = new double[testRHS.Length]; MPIexchangeInverse <double[]> XExchange = new MPIexchangeInverse <double[]>(MgMap, testX); g = 0; for (int rankCounter = 0; rankCounter < myMpisize; rankCounter++) { int rank_NoBlks = NoOfSchwzBlocks.MPIBroadcast(rankCounter); for (int iBlock = 0; iBlock < rank_NoBlks; iBlock++) { if (rankCounter == myMpiRank) { int LL = this.BlockIndices_Local[iBlock].Length; int LE; if (this.BlockIndices_External[iBlock] != null) { LE = this.BlockIndices_External[iBlock].Length; } else { LE = 0; } int L = LL + LE; for (int i = 0; i < LL; i++) { testX[this.BlockIndices_Local[iBlock][i]] += (g + 1); } if (LE > 0) { for (int i = 0; i < LE; i++) { XExchange.Vector_Ext[this.BlockIndices_External[iBlock][i] - offset] += (g + 1); } } } else { //nop } g++; } } XExchange.TransceiveStartImReturn(); XExchange.TransceiveFinish(1.0); matlab.Cmd("testXref = zeros({0},1);", MgMap.TotalLength); for (int iGlbBlock = 0; iGlbBlock < GlobalNoOfBlocks; iGlbBlock++) { matlab.Cmd("testXref(BlockIdx{0},1) = testXref(BlockIdx{0},1) + ({0} + 1);", iGlbBlock); } matlab.PutVector(testX, "testX"); matlab.Cmd("testXErr = norm(testX - testXref, inf);"); MultidimensionalArray BlockErr = MultidimensionalArray.Create(GlobalNoOfBlocks, 1); MultidimensionalArray RhsErr = MultidimensionalArray.Create(GlobalNoOfBlocks, 1); MultidimensionalArray testXErr = MultidimensionalArray.Create(1, 1); matlab.GetMatrix(BlockErr, "BlockErr"); matlab.GetMatrix(RhsErr, "RhsErr"); matlab.GetMatrix(testXErr, "testXErr"); matlab.Execute(); for (int iGlbBlock = 0; iGlbBlock < GlobalNoOfBlocks; iGlbBlock++) { Console.WriteLine("Block #{0} Error (external? ) " + BlockErr[iGlbBlock, 0], iGlbBlock); Console.WriteLine("RHS #{0} Error " + RhsErr[iGlbBlock, 0], iGlbBlock); Debug.Assert(BlockErr[iGlbBlock, 0] == 0); Debug.Assert(RhsErr[iGlbBlock, 0] == 0); } Console.WriteLine("X Error " + testXErr[0, 0]); Debug.Assert(testXErr[0, 0] == 0.0); matlab.Dispose(); } #endif } }
public static void MultiplyTest( [Values(XDGusage.none, XDGusage.mixed1, XDGusage.mixed2, XDGusage.all)] XDGusage UseXdg, [Values(1, 3)] int DGOrder, [Values(false, true)] bool compressL1, [Values(false, true)] bool compressL2) { unsafe { int[] Params = new int[8], ParamsGlob = new int[8]; fixed(int *pParams = Params, pParamsGlob = ParamsGlob) { pParams[0] = (int)UseXdg; pParams[1] = DGOrder; pParams[2] = compressL1 ? 1 : 0; pParams[3] = compressL2 ? 1 : 0; pParams[4] = -pParams[0]; pParams[5] = -pParams[1]; pParams[6] = -pParams[2]; pParams[7] = -pParams[3]; csMPI.Raw.Allreduce((IntPtr)pParams, (IntPtr)pParamsGlob, 8, csMPI.Raw._DATATYPE.INT, csMPI.Raw._OP.MIN, csMPI.Raw._COMM.WORLD); } int[] ParamsMin = ParamsGlob.GetSubVector(0, 4); int[] ParamsMax = ParamsGlob.GetSubVector(4, 4); for (int i = 0; i < 4; i++) { if (Params[i] != ParamsMin[i]) { throw new ApplicationException(); } if (Params[i] != -ParamsMax[i]) { throw new ApplicationException(); } } Console.WriteLine("MultiplyTest({0},{1},{2},{3})", UseXdg, DGOrder, compressL1, compressL2); } using (var solver = new Matrix_MPItestMain() { m_UseXdg = UseXdg, m_DGorder = DGOrder }) { // create the test data // ==================== BoSSS.Solution.Application.CommandLineOptions opts = null; //opts = new BoSSS.Solution.Application.CommandLineOptions(); solver.Init(null, opts); solver.RunSolverMode(); Stopwatch stw = new Stopwatch(); stw.Reset(); stw.Start(); BlockMsrMatrix M = solver.OperatorMatrix; int[] Ilist1 = solver.ProblemMapping.GetSubvectorIndices(false, 0); int[] Ilist2 = solver.ProblemMapping.GetSubvectorIndices(false, 1); foreach (int i in Ilist1) { Assert.IsTrue(solver.ProblemMapping.IsInLocalRange(i)); } foreach (int i in Ilist2) { Assert.IsTrue(solver.ProblemMapping.IsInLocalRange(i)); } var Blk1 = solver.ProblemMapping.GetSubBlocking(Ilist1, csMPI.Raw._COMM.WORLD, compressL1 ? -1 : 0); var Blk2 = solver.ProblemMapping.GetSubBlocking(Ilist2, csMPI.Raw._COMM.WORLD, compressL2 ? -1 : 0); int[] Tlist1 = compressL1 ? default(int[]) : Blk1.GetOccupiedIndicesList(); int[] Tlist2 = compressL2 ? default(int[]) : Blk2.GetOccupiedIndicesList(); if (Tlist1 != null) { Assert.AreEqual(Tlist1.Length, Ilist1.Length); foreach (int i in Tlist1) { Assert.IsTrue(Blk1.IsInLocalRange(i)); } } if (Tlist2 != null) { Assert.AreEqual(Tlist2.Length, Ilist2.Length); foreach (int i in Tlist2) { Assert.IsTrue(Blk2.IsInLocalRange(i)); } } BlockMsrMatrix M11 = new BlockMsrMatrix(Blk1, Blk1); BlockMsrMatrix M12 = new BlockMsrMatrix(Blk1, Blk2); BlockMsrMatrix M21 = new BlockMsrMatrix(Blk2, Blk1); BlockMsrMatrix M22 = new BlockMsrMatrix(Blk2, Blk2); M.AccSubMatrixTo(1.0, M11, Ilist1, Tlist1, Ilist1, Tlist1); M.AccSubMatrixTo(1.0, M12, Ilist1, Tlist1, Ilist2, Tlist2); M.AccSubMatrixTo(1.0, M21, Ilist2, Tlist2, Ilist1, Tlist1); M.AccSubMatrixTo(1.0, M22, Ilist2, Tlist2, Ilist2, Tlist2); /* * MultidimensionalArray CheckRes2 = MultidimensionalArray.Create(1, 4); * using (var MatlabRef = new BatchmodeConnector()) { * * MatlabRef.PutVector(Ilist1.Select(i => (double)i + 1.0).ToArray(), "Ilist1"); * MatlabRef.PutVector(Ilist2.Select(i => (double)i + 1.0).ToArray(), "Ilist2"); * MatlabRef.PutVector(Tlist1 == null ? Ilist1.Length.ForLoop(i => (double)i + 1.0 + Blk1.i0) : Tlist1.Select(i => (double)i + 1.0).ToArray(), "Tlist1"); * MatlabRef.PutVector(Tlist2 == null ? Ilist2.Length.ForLoop(i => (double)i + 1.0 + Blk2.i0) : Tlist2.Select(i => (double)i + 1.0).ToArray(), "Tlist2"); * * MatlabRef.PutSparseMatrix(solver.AltOperatorMatrix, "M"); * * * MatlabRef.Cmd("L1 = {0};", Blk1.TotalLength); * MatlabRef.Cmd("L2 = {0};", Blk2.TotalLength); * //MatlabRef.Cmd("refM11 = sparse(L1, L1);"); * //MatlabRef.Cmd("refM12 = sparse(L1, L2);"); * MatlabRef.Cmd("refM21 = sparse(L2, L1);"); * //MatlabRef.Cmd("refM22 = sparse(L2, L2);"); * * //MatlabRef.Cmd("refM11(Tlist1, Tlist1) = M(Ilist1, Ilist1);"); * //MatlabRef.Cmd("refM12(Tlist1, Tlist2) = M(Ilist1, Ilist2);"); * MatlabRef.Cmd("refM21(Tlist2, Tlist1) = M(Ilist2, Ilist1);"); * //MatlabRef.Cmd("refM22(Tlist2, Tlist2) = M(Ilist2, Ilist2);"); * * //MatlabRef.Cmd("err11 = norm(refM11 - M11, inf);"); * //MatlabRef.Cmd("err12 = norm(refM12 - M12, inf);"); * //MatlabRef.Cmd("err21 = norm(refM21 - M21, inf);"); * //MatlabRef.Cmd("err22 = norm(refM22 - M22, inf);"); * * MatlabRef.Cmd("CheckRes = [refM21(1339, 1321), 0.0, 1.567, 0 ];"); * MatlabRef.GetMatrix(CheckRes2, "CheckRes"); * * MatlabRef.Execute(); * } */ // test multipliation (later verified by matlab) BlockMsrMatrix M11xM12 = new BlockMsrMatrix(M11._RowPartitioning, M12._ColPartitioning); M11xM12.Acc(1.0, M12); BlockMsrMatrix.Multiply(M11xM12, M11, M12); BlockMsrMatrix M22xM21 = new BlockMsrMatrix(M22._RowPartitioning, M21._ColPartitioning); BlockMsrMatrix.Multiply(M22xM21, M22, M21); double ProdNorm = M22xM21.InfNorm(); stw.Stop(); //M.SaveToTextFileSparse(@"C:\tmp\M.txt"); //M11.SaveToTextFileSparse(@"C:\tmp\M11.txt"); //M12.SaveToTextFileSparse(@"C:\tmp\M12.txt"); //M21.SaveToTextFileSparse(@"C:\tmp\M21.txt"); //M22.SaveToTextFileSparse(@"C:\tmp\M22.txt"); //M22xM21.SaveToTextFileSparse(@"C:\tmp\M22xM21.txt"); using (var MatlabRef = new BatchmodeConnector()) { MultidimensionalArray CheckRes = MultidimensionalArray.Create(1, 4); MatlabRef.PutSparseMatrix(M11, "M11"); MatlabRef.PutSparseMatrix(M12, "M12"); MatlabRef.PutSparseMatrix(M21, "M21"); MatlabRef.PutSparseMatrix(M22, "M22"); MatlabRef.PutSparseMatrix(M11xM12, "M11xM12"); MatlabRef.PutSparseMatrix(M22xM21, "M22xM21"); MatlabRef.Cmd("refM11xM12 = M12 + M11*M12;"); MatlabRef.Cmd("refM22xM21 = M22*M21;"); MatlabRef.Cmd("err1112 = norm(refM11xM12 - M11xM12, inf);"); MatlabRef.Cmd("err2221 = norm(refM22xM21 - M22xM21, inf);"); MatlabRef.Cmd("CheckRes = [err1112, err2221, 0, 0];"); MatlabRef.GetMatrix(CheckRes, "CheckRes"); MatlabRef.Execute(); Console.WriteLine("Matlab check M11*M12: " + CheckRes[0, 0]); Console.WriteLine("Matlab check M22*M21: " + CheckRes[0, 1]); Assert.IsTrue(CheckRes[0, 0] == 0.0); Assert.IsTrue(CheckRes[0, 1] < 1.0e-10 * ProdNorm); //Assert.IsTrue(CheckRes[0, 2] == 0.0); //Assert.IsTrue(CheckRes[0, 3] == 0.0); } Console.WriteLine("Time spend in matrix operations: " + stw.Elapsed.TotalSeconds + " sec."); TotTime_MatrixOp += stw.Elapsed; } }
void Setup() { using (new FuncTrace()) { if (setupdone) { return; } setupdone = true; if (this.FinerLevel != null) { this.FinerLevel.Setup(); } // Construct intermediate 'raw' restriction and prolongation operators // =================================================================== BlockMsrMatrix RawRestriction, RawProlongation; if (this.FinerLevel == null) { RawRestriction = null; RawProlongation = null; } else { //#if DEBUG // var __PrlgOperator_Check = this.FinerLevel.Mapping.FromOtherLevelMatrix(this.Mapping); //#endif var __PrlgOperator = this.Mapping.GetProlongationOperator(this.FinerLevel.Mapping); //var __PrlgOperator = this.FinerLevel.Mapping.FromOtherLevelMatrix(this.Mapping); Debug.Assert(__PrlgOperator.RowPartitioning.LocalLength == this.FinerLevel.Mapping.LocalLength); Debug.Assert(__PrlgOperator.ColPartition.LocalLength == this.Mapping.LocalLength); //#if DEBUG // var __Err = __PrlgOperator_Check.CloneAs(); // __Err.Acc(-1.0, __PrlgOperator); // double ErrNorm = __Err.InfNorm(); // Console.WriteLine("Error norm: " + ErrNorm); // double Ref = Math.Max(__PrlgOperator.InfNorm(), __PrlgOperator_Check.InfNorm()); // //Debug.Assert(ErrNorm < Ref*1.0e-8); //#endif if (this.FinerLevel.RightChangeOfBasis_Inverse != null) { RawProlongation = BlockMsrMatrix.Multiply(this.FinerLevel.RightChangeOfBasis_Inverse, __PrlgOperator); } else { RawProlongation = __PrlgOperator; } RawRestriction = RawProlongation.Transpose(); } this.m_PrologateOperator = RawProlongation; this.m_RestrictionOperator = RawRestriction; // Construct intermediate 'raw' operator and mass matrix (before change of basis) // ============================================================================== // operator matrix before change of basis BlockMsrMatrix RawOpMatrix; if (this.FinerLevel == null) { RawOpMatrix = this.m_RawOperatorMatrix; this.m_RawOperatorMatrix = null; } else { BlockMsrMatrix Op = FinerLevel.OperatorMatrix; RawOpMatrix = BlockMsrMatrix.Multiply(RawRestriction, BlockMsrMatrix.Multiply(Op, RawProlongation)); } // mass matrix before change of basis BlockMsrMatrix RawMassMatrix; if (this.FinerLevel == null) { RawMassMatrix = this.m_RawMassMatrix; this.m_RawMassMatrix = null; } else { BlockMsrMatrix MM = FinerLevel.MassMatrix; RawMassMatrix = BlockMsrMatrix.Multiply(RawRestriction, BlockMsrMatrix.Multiply(MM, RawProlongation)); } Debug.Assert(RawOpMatrix.RowPartitioning.LocalLength == this.Mapping.LocalLength); // compute change of basis // ======================= int[] IndefRows = this.ComputeChangeOfBasis(RawOpMatrix, RawMassMatrix, out m_LeftChangeOfBasis, out m_RightChangeOfBasis, out m_LeftChangeOfBasis_Inverse, out m_RightChangeOfBasis_Inverse); // apply change of basis to operator matrix // ======================================== { var Lpc = this.m_LeftChangeOfBasis; var Rpc = this.m_RightChangeOfBasis; BlockMsrMatrix O1; if (Lpc != null) { O1 = BlockMsrMatrix.Multiply(Lpc, RawOpMatrix); } else { O1 = RawOpMatrix; } if (Rpc != null) { this.m_OperatorMatrix = BlockMsrMatrix.Multiply(O1, Rpc); } else { this.m_OperatorMatrix = O1; } // fix zero rows // (possible result from the Mode.IdMass_DropIndefinite or Mode.SymPart_DiagBlockEquilib_DropIndefinite -- option) foreach (int _iRow in IndefRows) { int iRow = Math.Abs(_iRow); Debug.Assert(this.m_OperatorMatrix.GetNoOfNonZerosPerRow(iRow) == 0); this.m_OperatorMatrix[iRow, iRow] = 1.0; } #if DEBUG for (int iRow = this.m_OperatorMatrix.RowPartitioning.i0; iRow < this.m_OperatorMatrix.RowPartitioning.iE; iRow++) { Debug.Assert(this.m_OperatorMatrix.GetNoOfNonZerosPerRow(iRow) > 0); } #endif } // apply change of basis to mass matrix // ==================================== { var Lpc = this.m_LeftChangeOfBasis; var Rpc = this.m_RightChangeOfBasis; if (RawMassMatrix != null) { BlockMsrMatrix O1; if (Lpc != null) { O1 = BlockMsrMatrix.Multiply(Lpc, RawMassMatrix); } else { O1 = RawMassMatrix; } if (Rpc != null) { this.m_MassMatrix = BlockMsrMatrix.Multiply(O1, Rpc); } else { this.m_MassMatrix = O1; } } else { if (Lpc != null && Rpc != null) { this.m_MassMatrix = BlockMsrMatrix.Multiply(Lpc, Rpc); } else if (Lpc != null) { Debug.Assert(Rpc == null); this.m_MassMatrix = Lpc; } else if (Rpc != null) { Debug.Assert(Lpc == null); this.m_MassMatrix = Rpc; } else { Debug.Assert(Lpc == null); Debug.Assert(Rpc == null); this.m_MassMatrix = null; } } //{ // var eyeTest = this.m_MassMatrix.CloneAs(); // eyeTest.AccEyeSp(-1.0); // double infnrm = eyeTest.InfNorm(); // Console.WriteLine("Mass matrix level {0} is id {1} ", this.Mapping.LevelIndex, infnrm); //} } } }
public void Init(MultigridOperator op) { int D = op.GridData.SpatialDimension; CodName = (new string[] { "mom0", "mom1" }); Params = ArrayTools.Cat( VariableNames.Velocity0Vector(D)); DomName = ArrayTools.Cat(VariableNames.VelocityVector(D)); LocalOp = new SpatialOperator(DomName, Params, CodName, (A, B, C) => 4); for (int d = 0; d < D; d++) { LocalOp.EquationComponents["mom" + d].Add(new LocalDiffusiveFlux() { m_component = d, dt = m_dt, muA = m_muA }); } LocalOp.Commit(); //LocalMatrix = op.MassMatrix.CloneAs().ToMsrMatrix(); //LocalMatrix.Clear(); //var U0 = new VectorField<SinglePhaseField>(op.BaseGridProblemMapping Take(D).Select(F => (SinglePhaseField)F).ToArray()); UnsetteledCoordinateMapping test = new UnsetteledCoordinateMapping(op.BaseGridProblemMapping.BasisS.GetSubVector(0, D)); var U0 = ((BoSSS.Foundation.CoordinateMapping)op.Mapping.ProblemMapping).Fields.GetSubVector(0, 2); var empty = new SinglePhaseField[D]; LocalMatrix = LocalOp.ComputeMatrix(test, empty, test, time: m_dt); Uidx = op.Mapping.ProblemMapping.GetSubvectorIndices(true, D.ForLoop(i => i)); Pidx = op.Mapping.ProblemMapping.GetSubvectorIndices(true, D); int Upart = Uidx.Length; int Ppart = Pidx.Length; ConvDiff = null; // new BlockMsrMatrix(Upart, Upart, 1, 1); pGrad = null; // new BlockMsrMatrix(Upart, Ppart, 1, 1); divVel = null; // new BlockMsrMatrix(Ppart, Upart, 1, 1); BlockMsrMatrix VelocityMass = null; // new BlockMsrMatrix(Upart, Upart, 1, 1); BlockMsrMatrix leftChangeBasesVel = null; // new BlockMsrMatrix(Upart, Upart, 1, 1); BlockMsrMatrix rightChangeBasesVel = null; // new BlockMsrMatrix(Upart, Upart, 1, 1); op.MassMatrix.AccSubMatrixTo(1.0, VelocityMass, Uidx, default(int[]), Uidx, default(int[]), default(int[]), default(int[])); op.LeftChangeOfBasis.AccSubMatrixTo(1.0, leftChangeBasesVel, Uidx, default(int[]), Uidx, default(int[]), default(int[]), default(int[])); op.RightChangeOfBasis.AccSubMatrixTo(1.0, rightChangeBasesVel, Uidx, default(int[]), Uidx, default(int[]), default(int[]), default(int[])); var temp = BlockMsrMatrix.Multiply(leftChangeBasesVel, LocalMatrix); LocalMatrix = BlockMsrMatrix.Multiply(temp, rightChangeBasesVel); var M = op.OperatorMatrix; M.AccSubMatrixTo(1.0, ConvDiff, Uidx, default(int[]), Uidx, default(int[]), default(int[]), default(int[])); M.AccSubMatrixTo(1.0, pGrad, Uidx, default(int[]), Pidx, default(int[]), default(int[]), default(int[])); M.AccSubMatrixTo(1.0, divVel, Pidx, default(int[]), Uidx, default(int[]), default(int[]), default(int[])); //LocalMatrix.SaveToTextFileSparse("LocalConvDiffMatrix"); //ConvDiff.SaveToTextFileSparse("ConvDiff"); //op.MassMatrix.SaveToTextFileSparse("MassMatrix"); //VelocityMass.SaveToTextFileSparse("VelocityMass"); }
// // /// <summary> /// applies the agglomeration on a general matrix /// </summary> /// <param name="Matrix">the matrix that should be manipulated.</param> /// <param name="Rhs">the right-hand-side that should be manipulated</param> /// <param name="ColMap"></param> /// <param name="ColMapAggSw">Turns column agglomeration on/off fore each variable individually; default == null is on. </param> /// <param name="RowMap"></param> /// <param name="RowMapAggSw">The same shit as for <paramref name="ColMapAggSw"/>, just for rows.</param> public void ManipulateMatrixAndRHS<M, T>(M Matrix, T Rhs, UnsetteledCoordinateMapping RowMap, UnsetteledCoordinateMapping ColMap, bool[] RowMapAggSw = null, bool[] ColMapAggSw = null) where M : IMutableMatrixEx where T : IList<double> { MPICollectiveWatchDog.Watch(); //var mtxS = GetFrameMatrices(Matrix, RowMap, ColMap); if (Matrix == null && Rhs == null) // nothing to do return; if (TotalNumberOfAgglomerations <= 0) // nothing to do return; if (RowMapAggSw != null) throw new NotImplementedException(); // generate agglomeration sparse matrices // ====================================== int RequireRight; if (Matrix == null) { // we don't need multiplication-from-the-right at all RequireRight = 0; } else { if (RowMap.EqualsUnsetteled(ColMap) && ArrayTools.ListEquals(ColMapAggSw, RowMapAggSw)) { // we can use the same matrix for right and left multiplication RequireRight = 1; } else { // separate matrix for the multiplication-from-the-right is required RequireRight = 2; } } BlockMsrMatrix LeftMul = null, RightMul = null; { foreach (var kv in DictAgglomeration) { var Species = kv.Key; var m_Agglomerator = kv.Value; if (m_Agglomerator != null) { CellMask spcMask = this.Tracker.Regions.GetSpeciesMask(Species); MiniMapping rowMini = new MiniMapping(RowMap, Species, this.Tracker.Regions); BlockMsrMatrix LeftMul_Species = m_Agglomerator.GetRowManipulationMatrix(RowMap, rowMini.MaxDeg, rowMini.NoOfVars, rowMini.i0Func, rowMini.NFunc, false, spcMask); if (LeftMul == null) { LeftMul = LeftMul_Species; } else { LeftMul.Acc(1.0, LeftMul_Species); } if (!object.ReferenceEquals(LeftMul, RightMul) && RightMul != null) { MiniMapping colMini = new MiniMapping(ColMap, Species, this.Tracker.Regions); BlockMsrMatrix RightMul_Species = m_Agglomerator.GetRowManipulationMatrix(ColMap, colMini.MaxDeg, colMini.NoOfVars, colMini.i0Func, colMini.NFunc, false, spcMask); if (RightMul == null) { RightMul = RightMul_Species; } else { RightMul.Acc(1.0, RightMul_Species); } } else if (RequireRight == 1) { RightMul = LeftMul; } else { RightMul = null; } } } } // apply the agglomeration to the matrix // ===================================== if (Matrix != null) { BlockMsrMatrix RightMulTr = RightMul.Transpose(); BlockMsrMatrix _Matrix; if (Matrix is BlockMsrMatrix) { _Matrix = (BlockMsrMatrix)((object)Matrix); } else { _Matrix = Matrix.ToBlockMsrMatrix(RowMap, ColMap); } var AggMatrix = BlockMsrMatrix.Multiply(LeftMul, BlockMsrMatrix.Multiply(_Matrix, RightMulTr)); if (object.ReferenceEquals(_Matrix, Matrix)) { _Matrix.Clear(); _Matrix.Acc(1.0, AggMatrix); } else { Matrix.Acc(-1.0, _Matrix); // das ist so Matrix.Acc(1.0, AggMatrix); // meagaschlecht !!!!!! } } // apply the agglomeration to the Rhs // ================================== if (Rhs != null) { double[] tmp = Rhs.ToArray(); if (object.ReferenceEquals(tmp, Rhs)) throw new ApplicationException("Flache kopie sollte eigentlich ausgeschlossen sein!?"); LeftMul.SpMV(1.0, tmp, 0.0, Rhs); } }