void CSRMatrix::create(CSRMatrix::ValueType type, unsigned m, const CSRMap & elms) { m_valType = type; m_dimension = m; unsigned nnz = elms.size(); m_numNonZero = nnz; if(type > tIndexOnly) m_value->create(nnz * type); m_rowPtr->create((m+1) * 4); m_colInd->create(nnz * 4); unsigned * I = rowPtr(); unsigned * J = colInd(); unsigned lastRow = m+2; unsigned row, col; unsigned ielm = 0; CSRMap::const_iterator it = elms.begin(); for(; it !=elms.end(); ++it) { row = it->first/m; col = it->first%m; if(row != lastRow) { I[row] = ielm; lastRow = row; } J[it->second] = col; ielm++; } I[m] = ielm; }
void CudaCSRMatrix::initOnDevice() { m_deviceValue->create(numNonZero() * valueType()); m_deviceRowPtr->create((dimension() + 1) * 4); m_deviceColInd->create(numNonZero() * 4); m_deviceRowPtr->hostToDevice(rowPtr()); m_deviceColInd->hostToDevice(colInd()); }
GraphType* FinleyDomain::createTrilinosGraph(bool reducedOrder) const { index_t myNumTargets; index_t numTargets; const index_t* target; const_TrilinosMap_ptr rowMap; const_TrilinosMap_ptr colMap; if (reducedOrder) { myNumTargets = m_nodes->getNumReducedDegreesOfFreedom(); numTargets = m_nodes->getNumReducedDegreesOfFreedomTargets(); target = m_nodes->borrowTargetReducedDegreesOfFreedom(); rowMap = m_nodes->trilinosReducedRowMap; colMap = m_nodes->trilinosReducedColMap; } else { myNumTargets = m_nodes->getNumDegreesOfFreedom(); numTargets = m_nodes->getNumDegreesOfFreedomTargets(); target = m_nodes->borrowTargetDegreesOfFreedom(); rowMap = m_nodes->trilinosRowMap; colMap = m_nodes->trilinosColMap; } boost::scoped_array<IndexList> indexList(new IndexList[numTargets]); #pragma omp parallel { // insert contributions from element matrices into columns in // index list IndexList_insertElements(indexList.get(), m_elements, reducedOrder, target, reducedOrder, target); IndexList_insertElements(indexList.get(), m_faceElements, reducedOrder, target, reducedOrder, target); IndexList_insertElements(indexList.get(), m_contactElements, reducedOrder, target, reducedOrder, target); IndexList_insertElements(indexList.get(), m_points, reducedOrder, target, reducedOrder, target); } Teuchos::ArrayRCP<size_t> rowPtr(myNumTargets + 1); for (size_t i = 0; i < myNumTargets; i++) { rowPtr[i+1] = rowPtr[i] + indexList[i].count(0, numTargets); } Teuchos::ArrayRCP<LO> colInd(rowPtr[myNumTargets]); #pragma omp parallel for for (index_t i = 0; i < myNumTargets; i++) { indexList[i].toArray(&colInd[rowPtr[i]], 0, numTargets, 0); std::sort(&colInd[rowPtr[i]], &colInd[rowPtr[i+1]]); } GraphType* graph = new GraphType(rowMap, colMap, rowPtr, colInd); Teuchos::RCP<Teuchos::ParameterList> params = Teuchos::parameterList(); params->set("Optimize Storage", true); graph->fillComplete(rowMap, rowMap, params); return graph; }
void CSRMatrix::verbose() { unsigned lastRow = m_dimension + 2; unsigned i, j; unsigned * row = rowPtr(); j = 0; for(i=0; i< m_numNonZero; i++) { if(i == *row) { std::cout<<"\n row"<<j<<" ("<<*row<<") "; j++; row++; } std::cout<<" "<<colInd()[i]; } std::cout<<"\nn non-zero "<<*row<<"\n"; std::cout<<"dimension "<<m_dimension<<"\n"; std::cout<<"value size "<<m_valType<<"\n"; }
double Ifpack_FrobeniusNorm(const Epetra_RowMatrix& A) { double MyNorm = 0.0, GlobalNorm; std::vector<int> colInd(A.MaxNumEntries()); std::vector<double> colVal(A.MaxNumEntries()); for (int i = 0 ; i < A.NumMyRows() ; ++i) { int Nnz; IFPACK_CHK_ERR(A.ExtractMyRowCopy(i,A.MaxNumEntries(),Nnz, &colVal[0],&colInd[0])); for (int j = 0 ; j < Nnz ; ++j) { MyNorm += colVal[j] * colVal[j]; } } A.Comm().SumAll(&MyNorm,&GlobalNorm,1); return(sqrt(GlobalNorm)); }
// ============================================================================ int ML_Epetra::MultiLevelPreconditioner:: CreateAuxiliaryMatrixCrs(Epetra_FECrsMatrix* &FakeMatrix) { int NumMyRows = RowMatrix_->NumMyRows(); const Epetra_Map& RowMap = RowMatrix_->RowMatrixRowMap(); const Epetra_Map& ColMap = RowMatrix_->RowMatrixColMap(); FakeMatrix = new Epetra_FECrsMatrix(Copy,RowMap, 2*RowMatrix_->MaxNumEntries()); if (FakeMatrix == 0) ML_CHK_ERR(-1); // something went wrong int NumDimensions = 0; double* x_coord = List_.get("x-coordinates", (double *)0); if (x_coord != 0) ++NumDimensions; // at least x-coordinates must be not null if( NumDimensions == 0 ) { std::cerr << ErrorMsg_ << "Option `aggregation: use auxiliary matrix' == true" << std::endl << ErrorMsg_ << "requires x-, y-, or z-coordinates." << std::endl << ErrorMsg_ << "You must specify them using options" << std::endl << ErrorMsg_ << "`x-coordinates' (and equivalently for" << std::endl << ErrorMsg_ << "y- and z-." << std::endl; ML_CHK_ERR(-2); // wrong parameters } double* y_coord = List_.get("y-coordinates", (double *)0); if (y_coord != 0) ++NumDimensions; double* z_coord = List_.get("z-coordinates", (double *)0); if (z_coord != 0) ++NumDimensions; // small check to avoid strange behavior if( z_coord != 0 && y_coord == 0 ) { std::cerr << ErrorMsg_ << "Something wrong: `y-coordinates'" << std::endl << ErrorMsg_ << "is null, while `z-coordinates' is null" << std::endl; ML_CHK_ERR(-3); // something went wrong } double theta = List_.get("aggregation: theta",0.0); bool SymmetricPattern = List_.get("aggregation: use symmetric pattern",false); // usual crap to clutter the output if( verbose_ ) { std::cout << std::endl; std::cout << PrintMsg_ << "*** Using auxiliary matrix to create the aggregates" << std::endl << PrintMsg_ << "*** Number of dimensions = " << NumDimensions << std::endl << PrintMsg_ << "*** theta = " << theta; if( SymmetricPattern ) std::cout << ", using symmetric pattern" << std::endl; else std::cout << ", using original pattern" << std::endl; std::cout << std::endl; } // create vectors containing coordinates, replicated for all unknonws // FIXME: I don't really need Z in all cases // for west // I am over-allocating, for large number of equations per node // this is not optimal. However, it is a only-once importing // of some more data. It should harm too much... // // The following will work for constant number of equations per // node only. The fix should be easy, though. Epetra_Vector RowX(RowMap); RowX.PutScalar(0.0); Epetra_Vector RowY(RowMap); RowY.PutScalar(0.0); Epetra_Vector RowZ(RowMap); RowZ.PutScalar(0.0); for (int i = 0 ; i < NumMyRows ; i += NumPDEEqns_) { RowX[i] = x_coord[i / NumPDEEqns_]; if (NumDimensions > 1) RowY[i] = y_coord[i / NumPDEEqns_]; if (NumDimensions > 2) RowZ[i] = z_coord[i / NumPDEEqns_]; } // create vectors containing coordinates for columns // (this is useful only if MIS/ParMETIS are used) Epetra_Vector ColX(ColMap); ColX.PutScalar(0.0); Epetra_Vector ColY(ColMap); ColY.PutScalar(0.0); Epetra_Vector ColZ(ColMap); ColZ.PutScalar(0.0); // get coordinates for non-local nodes (in column map) Epetra_Import Importer(ColMap,RowMap); ColX.Import(RowX,Importer,Insert); if (NumDimensions > 1) ColY.Import(RowY,Importer,Insert); if (NumDimensions > 2) ColZ.Import(RowZ,Importer,Insert); // global row and column numbering int* MyGlobalRowElements = RowMap.MyGlobalElements(); int* MyGlobalColElements = ColMap.MyGlobalElements(); // room for getrow() int MaxNnz = RowMatrix_->MaxNumEntries(); std::vector<int> colInd(MaxNnz); std::vector<double> colVal(MaxNnz); std::vector<double> coord_i(3); std::vector<double> coord_j(3); // =================== // // cycle over all rows // // =================== // for (int i = 0; i < NumMyRows ; i += NumPDEEqns_) { int GlobalRow = MyGlobalRowElements[i]; if( i%NumPDEEqns_ == 0 ) { // do it just once for each block row switch( NumDimensions ) { case 3: coord_i[2] = RowZ[i]; case 2: coord_i[1] = RowY[i]; case 1: coord_i[0] = RowX[i]; } int NumEntries; ML_CHK_ERR(RowMatrix_->ExtractMyRowCopy(i,MaxNnz,NumEntries, &colVal[0],&colInd[0])); // NOTE: for VBR matrices, the "real" value that will be used in // the subsequent part of the code is only the one for the first // equations. For each block, I replace values with the sum of // the std::abs of each block entry. for (int j = 0 ; j < NumEntries ; j += NumPDEEqns_) { colVal[j] = std::fabs(colVal[j]); for (int k = 1 ; k < NumPDEEqns_ ; ++k) { colVal[j] += std::fabs(colVal[j+k]); } } // work only on the first equations. Theta will blend the // coordinate part with the sub of std::abs of row elements. int GlobalCol; double total = 0.0; for (int j = 0 ; j < NumEntries ; j += NumPDEEqns_) { if (colInd[j] >= NumMyRows) continue; if (colInd[j]%NumPDEEqns_ == 0) { // insert diagonal later if (colInd[j] != i) { // get coordinates of this node switch (NumDimensions) { case 3: coord_j[2] = ColZ[colInd[j]]; case 2: coord_j[1] = ColY[colInd[j]]; case 1: coord_j[0] = ColX[colInd[j]]; } // d2 is the square of the distance between node `i' and // node `j' double d2 = (coord_i[0] - coord_j[0]) * (coord_i[0] - coord_j[0]) + (coord_i[1] - coord_j[1]) * (coord_i[1] - coord_j[1]) + (coord_i[2] - coord_j[2]) * (coord_i[2] - coord_j[2]); if (d2 == 0.0) { std::cerr << std::endl; std::cerr << ErrorMsg_ << "distance between node " << i/NumPDEEqns_ << " and node " << colInd[j]/NumPDEEqns_ << std::endl << ErrorMsg_ << "is zero. Coordinates of these nodes are" << std::endl << ErrorMsg_ << "x_i = " << coord_i[0] << ", x_j = " << coord_j[0] << std::endl << ErrorMsg_ << "y_i = " << coord_i[1] << ", y_j = " << coord_j[1] << std::endl << ErrorMsg_ << "z_i = " << coord_i[2] << ", z_j = " << coord_j[2] << std::endl << ErrorMsg_ << "Now proceeding with distance = 1.0" << std::endl; std::cerr << std::endl; d2 = 1.0; } // blend d2 with the actual values of the matrix // FIXME: am I useful? double val = -(1.0 - theta) * (1.0 / d2) + theta * (colVal[j]); GlobalCol = MyGlobalColElements[colInd[j]]; // insert this value on all rows for (int k = 0 ; k < NumPDEEqns_ ; ++k) { int row = GlobalRow + k; int col = GlobalCol + k; if (FakeMatrix->SumIntoGlobalValues(1,&row,1,&col,&val) != 0) { ML_CHK_ERR(FakeMatrix->InsertGlobalValues(1,&row,1,&col,&val)); } } total -= val; // put (j,i) element as well, only for in-process stuff. // I have some problems with off-processor elements. // It is here that I need the FE matrix. if (SymmetricPattern == true && colInd[j] < NumMyRows ) { for( int k=0 ; k<NumPDEEqns_ ; ++k ) { int row = GlobalCol+k; int col = GlobalRow+k; if( FakeMatrix->SumIntoGlobalValues(1,&row,1,&col,&val) != 0 ) { ML_CHK_ERR(FakeMatrix->InsertGlobalValues(1,&row,1,&col,&val)); } } total -= val; } } } } // create lines with zero-row sum for (int k = 0 ; k < NumPDEEqns_ ; ++k) { int row = GlobalRow + k; if (FakeMatrix->SumIntoGlobalValues(1,&row,1,&row,&total) != 0) { if (FakeMatrix->InsertGlobalValues(1,&row,1,&row,&total) != 0) ML_CHK_ERR(-9); // something went wrong } } } } if (FakeMatrix->FillComplete()) ML_CHK_ERR(-5); // something went wrong // stick pointer in Amat for level 0 (finest level) ml_->Amat[LevelID_[0]].data = (void *)FakeMatrix; // tell ML to keep the tentative prolongator ML_Aggregate_Set_Reuse(agg_); // pray that no bugs will tease us return(0); }
// ============================================================================ int ML_Epetra::MultiLevelPreconditioner:: CreateAuxiliaryMatrixVbr(Epetra_VbrMatrix* &FakeMatrix) { // FakeMatrix has already been created before if (FakeMatrix == 0) ML_CHK_ERR(-1); // something went wrong int NumDimensions = 0; double* x_coord = List_.get("x-coordinates", (double *)0); if (x_coord != 0) ++NumDimensions; // at least x-coordinates must be not null if( NumDimensions == 0 ) { std::cerr << ErrorMsg_ << "Option `aggregation: use auxiliary matrix' == true" << std::endl << ErrorMsg_ << "requires x-, y-, or z-coordinates." << std::endl << ErrorMsg_ << "You must specify them using options" << std::endl << ErrorMsg_ << "`x-coordinates' (and equivalently for" << std::endl << ErrorMsg_ << "y- and z-)." << std::endl; ML_CHK_ERR(-2); // wrong parameters } double* y_coord = List_.get("y-coordinates", (double *)0); if (y_coord != 0) ++NumDimensions; double* z_coord = List_.get("z-coordinates", (double *)0); if (z_coord != 0) ++NumDimensions; // small check to avoid strange behavior if( z_coord != 0 && y_coord == 0 ) { std::cerr << ErrorMsg_ << "Something wrong: `y-coordinates'" << std::endl << ErrorMsg_ << "is null, while `z-coordinates' is not null" << std::endl; ML_CHK_ERR(-3); // something went wrong } // usual crap to clutter the output if( verbose_ ) { std::cout << std::endl; std::cout << PrintMsg_ << "*** Using auxiliary matrix to create the aggregates" << std::endl << PrintMsg_ << "*** Number of dimensions = " << NumDimensions << std::endl << PrintMsg_ << "*** (the version for Epetra_VbrMatrix is currently used)" << std::endl; std::cout << std::endl; } const Epetra_BlockMap& RowMap = FakeMatrix->RowMap(); const Epetra_BlockMap& ColMap = FakeMatrix->ColMap(); int NumMyRowElements = RowMap.NumMyElements(); int NumMyColElements = ColMap.NumMyElements(); int* MyGlobalRowElements = RowMap.MyGlobalElements(); int* MyGlobalColElements = ColMap.MyGlobalElements(); // use point map to exchange coordinates Epetra_Map PointRowMap(-1,NumMyRowElements,MyGlobalRowElements,0,Comm()); Epetra_Map PointColMap(-1,NumMyColElements,MyGlobalColElements,0,Comm()); Epetra_Vector RowX(PointRowMap); Epetra_Vector RowY(PointRowMap); Epetra_Vector RowZ(PointRowMap); for (int i = 0 ; i < NumMyRowElements ; ++i) { RowX[i] = x_coord[i]; if (NumDimensions > 1) RowY[i] = y_coord[i]; if (NumDimensions > 2) RowZ[i] = z_coord[i]; } // create vectors containing coordinates for columns // (this is useful only if MIS/ParMETIS are used) Epetra_Vector ColX(PointColMap); Epetra_Vector ColY(PointColMap); Epetra_Vector ColZ(PointColMap); // get coordinates for non-local nodes (in column map) Epetra_Import Importer(PointColMap,PointRowMap); ColX.Import(RowX,Importer,Insert); if (NumDimensions > 1) ColY.Import(RowY,Importer,Insert); if (NumDimensions > 2) ColZ.Import(RowZ,Importer,Insert); // room for getrow() int MaxNnz = FakeMatrix->MaxNumEntries(); std::vector<int> colInd(MaxNnz); std::vector<double> colVal(MaxNnz); std::vector<double> coord_i(3); std::vector<double> coord_j(3); // change the entries of FakeMatrix so that it corresponds to a discrete // Laplacian. Note: This is not exactly the same as in the Crs case. FakeMatrix->PutScalar(0.0); for (int LocalRow = 0; LocalRow < NumMyRowElements ; ++LocalRow) { int RowDim, NumBlockEntries; int* BlockIndices; Epetra_SerialDenseMatrix** RowValues; switch (NumDimensions) { case 3: coord_i[2] = RowZ[LocalRow]; case 2: coord_i[1] = RowY[LocalRow]; case 1: coord_i[0] = RowX[LocalRow]; } FakeMatrix->ExtractMyBlockRowView(LocalRow,RowDim,NumBlockEntries, BlockIndices,RowValues); // accumulator for zero row-sum double total = 0.0; for (int j = 0 ; j < NumBlockEntries ; ++j) { int LocalCol = BlockIndices[j]; // insert diagonal later if (LocalCol != LocalRow) { // get coordinates of this node switch (NumDimensions) { case 3: coord_j[2] = ColZ[LocalCol]; case 2: coord_j[1] = ColY[LocalCol]; case 1: coord_j[0] = ColX[LocalCol]; } // d2 is the square of the distance between node `i' and // node `j' double d2 = (coord_i[0] - coord_j[0]) * (coord_i[0] - coord_j[0]) + (coord_i[1] - coord_j[1]) * (coord_i[1] - coord_j[1]) + (coord_i[2] - coord_j[2]) * (coord_i[2] - coord_j[2]); if (d2 == 0.0) { std::cerr << std::endl; std::cerr << ErrorMsg_ << "distance between node " << LocalRow << " and node " << LocalCol << std::endl << ErrorMsg_ << "is zero. Coordinates of these nodes are" << std::endl << ErrorMsg_ << "x_i = " << coord_i[0] << ", x_j = " << coord_j[0] << std::endl << ErrorMsg_ << "y_i = " << coord_i[1] << ", y_j = " << coord_j[1] << std::endl << ErrorMsg_ << "z_i = " << coord_i[2] << ", z_j = " << coord_j[2] << std::endl << ErrorMsg_ << "Now proceeding with distance = 1.0" << std::endl; std::cerr << std::endl; d2 = 1.0; } for (int k = 0 ; k < RowValues[j]->M() ; ++k) { for (int h = 0 ; h < RowValues[j]->N() ; ++h) { if (k == h) (*RowValues[j])(k,h) = - 1.0 / d2; } } total += 1.0 /d2; } } // check that the diagonal block exists bool ok = false; int DiagonalBlock = 0; for (int j = 0 ; j < NumBlockEntries ; ++j) { if (BlockIndices[j] == LocalRow) { DiagonalBlock = j; ok = true; break; } } assert (ok == true); for (int k = 0 ; k < RowValues[DiagonalBlock]->N() ; ++k) { (*RowValues[DiagonalBlock])(k,k) = total; } } // tell ML to keep the tentative prolongator ML_Aggregate_Set_Reuse(agg_); // pray that no bugs will tease us return(0); }
int Ifpack_AnalyzeMatrixElements(const Epetra_RowMatrix& A, const bool abs, const int steps) { bool verbose = (A.Comm().MyPID() == 0); double min_val = DBL_MAX; double max_val = -DBL_MAX; std::vector<int> colInd(A.MaxNumEntries()); std::vector<double> colVal(A.MaxNumEntries()); for (int i = 0 ; i < A.NumMyRows() ; ++i) { int Nnz; IFPACK_CHK_ERR(A.ExtractMyRowCopy(i,A.MaxNumEntries(),Nnz, &colVal[0],&colInd[0])); for (int j = 0 ; j < Nnz ; ++j) { double v = colVal[j]; if (abs) if (v < 0) v = -v; if (v < min_val) min_val = v; if (v > max_val) max_val = v; } } if (verbose) { cout << endl; Ifpack_PrintLine(); cout << "Label of matrix = " << A.Label() << endl; cout << endl; } double delta = (max_val - min_val) / steps; for (int k = 0 ; k < steps ; ++k) { double below = delta * k + min_val; double above = below + delta; int MyBelow = 0, GlobalBelow; for (int i = 0 ; i < A.NumMyRows() ; ++i) { int Nnz; IFPACK_CHK_ERR(A.ExtractMyRowCopy(i,A.MaxNumEntries(),Nnz, &colVal[0],&colInd[0])); for (int j = 0 ; j < Nnz ; ++j) { double v = colVal[j]; if (abs) if (v < 0) v = -v; if (v >= below && v < above) MyBelow++; } } A.Comm().SumAll(&MyBelow, &GlobalBelow, 1); if (verbose) { printf("Elements in [%+7e, %+7e) = %10d ( = %5.2f %%)\n", below, above, GlobalBelow, 100.0 * GlobalBelow / A.NumGlobalNonzeros64()); } } if (verbose) { Ifpack_PrintLine(); cout << endl; } return(0); }
int Ifpack_Analyze(const Epetra_RowMatrix& A, const bool Cheap, const int NumPDEEqns) { int NumMyRows = A.NumMyRows(); long long NumGlobalRows = A.NumGlobalRows64(); long long NumGlobalCols = A.NumGlobalCols64(); long long MyBandwidth = 0, GlobalBandwidth; long long MyLowerNonzeros = 0, MyUpperNonzeros = 0; long long GlobalLowerNonzeros, GlobalUpperNonzeros; long long MyDiagonallyDominant = 0, GlobalDiagonallyDominant; long long MyWeaklyDiagonallyDominant = 0, GlobalWeaklyDiagonallyDominant; double MyMin, MyAvg, MyMax; double GlobalMin, GlobalAvg, GlobalMax; long long GlobalStorage; bool verbose = (A.Comm().MyPID() == 0); GlobalStorage = sizeof(int*) * NumGlobalRows + sizeof(int) * A.NumGlobalNonzeros64() + sizeof(double) * A.NumGlobalNonzeros64(); if (verbose) { print(); Ifpack_PrintLine(); print<const char*>("Label", A.Label()); print<long long>("Global rows", NumGlobalRows); print<long long>("Global columns", NumGlobalCols); print<long long>("Stored nonzeros", A.NumGlobalNonzeros64()); print<long long>("Nonzeros / row", A.NumGlobalNonzeros64() / NumGlobalRows); print<double>("Estimated storage (Mbytes)", 1.0e-6 * GlobalStorage); } long long NumMyActualNonzeros = 0, NumGlobalActualNonzeros; long long NumMyEmptyRows = 0, NumGlobalEmptyRows; long long NumMyDirichletRows = 0, NumGlobalDirichletRows; std::vector<int> colInd(A.MaxNumEntries()); std::vector<double> colVal(A.MaxNumEntries()); Epetra_Vector Diag(A.RowMatrixRowMap()); Epetra_Vector RowSum(A.RowMatrixRowMap()); Diag.PutScalar(0.0); RowSum.PutScalar(0.0); for (int i = 0 ; i < NumMyRows ; ++i) { long long GRID = A.RowMatrixRowMap().GID64(i); int Nnz; IFPACK_CHK_ERR(A.ExtractMyRowCopy(i,A.MaxNumEntries(),Nnz, &colVal[0],&colInd[0])); if (Nnz == 0) NumMyEmptyRows++; if (Nnz == 1) NumMyDirichletRows++; for (int j = 0 ; j < Nnz ; ++j) { double v = colVal[j]; if (v < 0) v = -v; if (colVal[j] != 0.0) NumMyActualNonzeros++; long long GCID = A.RowMatrixColMap().GID64(colInd[j]); if (GCID != GRID) RowSum[i] += v; else Diag[i] = v; if (GCID < GRID) MyLowerNonzeros++; else if (GCID > GRID) MyUpperNonzeros++; long long b = GCID - GRID; if (b < 0) b = -b; if (b > MyBandwidth) MyBandwidth = b; } if (Diag[i] > RowSum[i]) MyDiagonallyDominant++; if (Diag[i] >= RowSum[i]) MyWeaklyDiagonallyDominant++; RowSum[i] += Diag[i]; } // ======================== // // summing up global values // // ======================== // A.Comm().SumAll(&MyDiagonallyDominant,&GlobalDiagonallyDominant,1); A.Comm().SumAll(&MyWeaklyDiagonallyDominant,&GlobalWeaklyDiagonallyDominant,1); A.Comm().SumAll(&NumMyActualNonzeros, &NumGlobalActualNonzeros, 1); A.Comm().SumAll(&NumMyEmptyRows, &NumGlobalEmptyRows, 1); A.Comm().SumAll(&NumMyDirichletRows, &NumGlobalDirichletRows, 1); A.Comm().SumAll(&MyBandwidth, &GlobalBandwidth, 1); A.Comm().SumAll(&MyLowerNonzeros, &GlobalLowerNonzeros, 1); A.Comm().SumAll(&MyUpperNonzeros, &GlobalUpperNonzeros, 1); A.Comm().SumAll(&MyDiagonallyDominant, &GlobalDiagonallyDominant, 1); A.Comm().SumAll(&MyWeaklyDiagonallyDominant, &GlobalWeaklyDiagonallyDominant, 1); double NormOne = A.NormOne(); double NormInf = A.NormInf(); double NormF = Ifpack_FrobeniusNorm(A); if (verbose) { print(); print<long long>("Actual nonzeros", NumGlobalActualNonzeros); print<long long>("Nonzeros in strict lower part", GlobalLowerNonzeros); print<long long>("Nonzeros in strict upper part", GlobalUpperNonzeros); print(); print<long long>("Empty rows", NumGlobalEmptyRows, 100.0 * NumGlobalEmptyRows / NumGlobalRows); print<long long>("Dirichlet rows", NumGlobalDirichletRows, 100.0 * NumGlobalDirichletRows / NumGlobalRows); print<long long>("Diagonally dominant rows", GlobalDiagonallyDominant, 100.0 * GlobalDiagonallyDominant / NumGlobalRows); print<long long>("Weakly diag. dominant rows", GlobalWeaklyDiagonallyDominant, 100.0 * GlobalWeaklyDiagonallyDominant / NumGlobalRows); print(); print<long long>("Maximum bandwidth", GlobalBandwidth); print(); print("", "one-norm", "inf-norm", "Frobenius", false); print("", "========", "========", "=========", false); print(); print<double>("A", NormOne, NormInf, NormF); } if (Cheap == false) { // create A + A^T and A - A^T Epetra_FECrsMatrix AplusAT(Copy, A.RowMatrixRowMap(), 0); Epetra_FECrsMatrix AminusAT(Copy, A.RowMatrixRowMap(), 0); #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES if(A.RowMatrixRowMap().GlobalIndicesInt()) { for (int i = 0 ; i < NumMyRows ; ++i) { int GRID = A.RowMatrixRowMap().GID(i); assert (GRID != -1); int Nnz; IFPACK_CHK_ERR(A.ExtractMyRowCopy(i,A.MaxNumEntries(),Nnz, &colVal[0],&colInd[0])); for (int j = 0 ; j < Nnz ; ++j) { int GCID = A.RowMatrixColMap().GID(colInd[j]); assert (GCID != -1); double plus_val = colVal[j]; double minus_val = -colVal[j]; if (AplusAT.SumIntoGlobalValues(1,&GRID,1,&GCID,&plus_val) != 0) { IFPACK_CHK_ERR(AplusAT.InsertGlobalValues(1,&GRID,1,&GCID,&plus_val)); } if (AplusAT.SumIntoGlobalValues(1,&GCID,1,&GRID,&plus_val) != 0) { IFPACK_CHK_ERR(AplusAT.InsertGlobalValues(1,&GCID,1,&GRID,&plus_val)); } if (AminusAT.SumIntoGlobalValues(1,&GRID,1,&GCID,&plus_val) != 0) { IFPACK_CHK_ERR(AminusAT.InsertGlobalValues(1,&GRID,1,&GCID,&plus_val)); } if (AminusAT.SumIntoGlobalValues(1,&GCID,1,&GRID,&minus_val) != 0) { IFPACK_CHK_ERR(AminusAT.InsertGlobalValues(1,&GCID,1,&GRID,&minus_val)); } } } } else #endif #ifndef EPETRA_NO_64BIT_GLOBAL_INDICES if(A.RowMatrixRowMap().GlobalIndicesLongLong()) { for (int i = 0 ; i < NumMyRows ; ++i) { long long GRID = A.RowMatrixRowMap().GID64(i); assert (GRID != -1); int Nnz; IFPACK_CHK_ERR(A.ExtractMyRowCopy(i,A.MaxNumEntries(),Nnz, &colVal[0],&colInd[0])); for (int j = 0 ; j < Nnz ; ++j) { long long GCID = A.RowMatrixColMap().GID64(colInd[j]); assert (GCID != -1); double plus_val = colVal[j]; double minus_val = -colVal[j]; if (AplusAT.SumIntoGlobalValues(1,&GRID,1,&GCID,&plus_val) != 0) { IFPACK_CHK_ERR(AplusAT.InsertGlobalValues(1,&GRID,1,&GCID,&plus_val)); } if (AplusAT.SumIntoGlobalValues(1,&GCID,1,&GRID,&plus_val) != 0) { IFPACK_CHK_ERR(AplusAT.InsertGlobalValues(1,&GCID,1,&GRID,&plus_val)); } if (AminusAT.SumIntoGlobalValues(1,&GRID,1,&GCID,&plus_val) != 0) { IFPACK_CHK_ERR(AminusAT.InsertGlobalValues(1,&GRID,1,&GCID,&plus_val)); } if (AminusAT.SumIntoGlobalValues(1,&GCID,1,&GRID,&minus_val) != 0) { IFPACK_CHK_ERR(AminusAT.InsertGlobalValues(1,&GCID,1,&GRID,&minus_val)); } } } } else #endif throw "Ifpack_Analyze: GlobalIndices type unknown"; AplusAT.FillComplete(); AminusAT.FillComplete(); AplusAT.Scale(0.5); AminusAT.Scale(0.5); NormOne = AplusAT.NormOne(); NormInf = AplusAT.NormInf(); NormF = Ifpack_FrobeniusNorm(AplusAT); if (verbose) { print<double>("A + A^T", NormOne, NormInf, NormF); } NormOne = AminusAT.NormOne(); NormInf = AminusAT.NormInf(); NormF = Ifpack_FrobeniusNorm(AminusAT); if (verbose) { print<double>("A - A^T", NormOne, NormInf, NormF); } } if (verbose) { print(); print<const char*>("", "min", "avg", "max", false); print<const char*>("", "===", "===", "===", false); } MyMax = -DBL_MAX; MyMin = DBL_MAX; MyAvg = 0.0; for (int i = 0 ; i < NumMyRows ; ++i) { int Nnz; IFPACK_CHK_ERR(A.ExtractMyRowCopy(i,A.MaxNumEntries(),Nnz, &colVal[0],&colInd[0])); for (int j = 0 ; j < Nnz ; ++j) { MyAvg += colVal[j]; if (colVal[j] > MyMax) MyMax = colVal[j]; if (colVal[j] < MyMin) MyMin = colVal[j]; } } A.Comm().MaxAll(&MyMax, &GlobalMax, 1); A.Comm().MinAll(&MyMin, &GlobalMin, 1); A.Comm().SumAll(&MyAvg, &GlobalAvg, 1); GlobalAvg /= A.NumGlobalNonzeros64(); if (verbose) { print(); print<double>(" A(i,j)", GlobalMin, GlobalAvg, GlobalMax); } MyMax = 0.0; MyMin = DBL_MAX; MyAvg = 0.0; for (int i = 0 ; i < NumMyRows ; ++i) { int Nnz; IFPACK_CHK_ERR(A.ExtractMyRowCopy(i,A.MaxNumEntries(),Nnz, &colVal[0],&colInd[0])); for (int j = 0 ; j < Nnz ; ++j) { double v = colVal[j]; if (v < 0) v = -v; MyAvg += v; if (colVal[j] > MyMax) MyMax = v; if (colVal[j] < MyMin) MyMin = v; } } A.Comm().MaxAll(&MyMax, &GlobalMax, 1); A.Comm().MinAll(&MyMin, &GlobalMin, 1); A.Comm().SumAll(&MyAvg, &GlobalAvg, 1); GlobalAvg /= A.NumGlobalNonzeros64(); if (verbose) { print<double>("|A(i,j)|", GlobalMin, GlobalAvg, GlobalMax); } // ================= // // diagonal elements // // ================= // Diag.MinValue(&GlobalMin); Diag.MaxValue(&GlobalMax); Diag.MeanValue(&GlobalAvg); if (verbose) { print(); print<double>(" A(k,k)", GlobalMin, GlobalAvg, GlobalMax); } Diag.Abs(Diag); Diag.MinValue(&GlobalMin); Diag.MaxValue(&GlobalMax); Diag.MeanValue(&GlobalAvg); if (verbose) { print<double>("|A(k,k)|", GlobalMin, GlobalAvg, GlobalMax); } // ============================================== // // cycle over all equations for diagonal elements // // ============================================== // if (NumPDEEqns > 1 ) { if (verbose) print(); for (int ie = 0 ; ie < NumPDEEqns ; ie++) { MyMin = DBL_MAX; MyMax = -DBL_MAX; MyAvg = 0.0; for (int i = ie ; i < Diag.MyLength() ; i += NumPDEEqns) { double d = Diag[i]; MyAvg += d; if (d < MyMin) MyMin = d; if (d > MyMax) MyMax = d; } A.Comm().MinAll(&MyMin, &GlobalMin, 1); A.Comm().MaxAll(&MyMax, &GlobalMax, 1); A.Comm().SumAll(&MyAvg, &GlobalAvg, 1); // does not really work fine if the number of global // elements is not a multiple of NumPDEEqns GlobalAvg /= (Diag.GlobalLength64() / NumPDEEqns); if (verbose) { char str[80]; sprintf(str, " A(k,k), eq %d", ie); print<double>(str, GlobalMin, GlobalAvg, GlobalMax); } } } // ======== // // row sums // // ======== // RowSum.MinValue(&GlobalMin); RowSum.MaxValue(&GlobalMax); RowSum.MeanValue(&GlobalAvg); if (verbose) { print(); print<double>(" sum_j A(k,j)", GlobalMin, GlobalAvg, GlobalMax); } // ===================================== // // cycle over all equations for row sums // // ===================================== // if (NumPDEEqns > 1 ) { if (verbose) print(); for (int ie = 0 ; ie < NumPDEEqns ; ie++) { MyMin = DBL_MAX; MyMax = -DBL_MAX; MyAvg = 0.0; for (int i = ie ; i < Diag.MyLength() ; i += NumPDEEqns) { double d = RowSum[i]; MyAvg += d; if (d < MyMin) MyMin = d; if (d > MyMax) MyMax = d; } A.Comm().MinAll(&MyMin, &GlobalMin, 1); A.Comm().MaxAll(&MyMax, &GlobalMax, 1); A.Comm().SumAll(&MyAvg, &GlobalAvg, 1); // does not really work fine if the number of global // elements is not a multiple of NumPDEEqns GlobalAvg /= (Diag.GlobalLength64() / NumPDEEqns); if (verbose) { char str[80]; sprintf(str, " sum_j A(k,j), eq %d", ie); print<double>(str, GlobalMin, GlobalAvg, GlobalMax); } } } if (verbose) Ifpack_PrintLine(); return(0); }