//============================================================================== Ifpack_DiagonalFilter::Ifpack_DiagonalFilter(const Teuchos::RefCountPtr<Epetra_RowMatrix>& Matrix, double AbsoluteThreshold, double RelativeThreshold) : A_(Matrix), AbsoluteThreshold_(AbsoluteThreshold), RelativeThreshold_(RelativeThreshold) { Epetra_Time Time(Comm()); pos_.resize(NumMyRows()); val_.resize(NumMyRows()); std::vector<int> Indices(MaxNumEntries()); std::vector<double> Values(MaxNumEntries()); int NumEntries; for (int MyRow = 0 ; MyRow < NumMyRows() ; ++MyRow) { pos_[MyRow] = -1; val_[MyRow] = 0.0; int ierr = A_->ExtractMyRowCopy(MyRow, MaxNumEntries(), NumEntries, &Values[0], &Indices[0]); assert (ierr == 0); for (int i = 0 ; i < NumEntries ; ++i) { if (Indices[i] == MyRow) { pos_[MyRow] = i; val_[MyRow] = Values[i] * (RelativeThreshold_ - 1) + AbsoluteThreshold_ * EPETRA_SGN(Values[i]); } break; } } cout << "TIME = " << Time.ElapsedTime() << endl; }
//============================================================================== Ifpack2_AMDReordering:: Ifpack2_AMDReordering(const Ifpack2_AMDReordering& RHS) : NumMyRows_(RHS.NumMyRows()), IsComputed_(RHS.IsComputed()) { Reorder_.resize(NumMyRows()); InvReorder_.resize(NumMyRows()); for (int i = 0 ; i < NumMyRows() ; ++i) { Reorder_[i] = RHS.Reorder(i); InvReorder_[i] = RHS.InvReorder(i); } }
//============================================================================== int Ifpack2_LinearPartitioner::ComputePartitions() { int mod = NumMyRows() / NumLocalParts_; for (int i = 0 ; i < NumMyRows() ; ++i) { Partition_[i] = i / mod; if (Partition_[i] >= NumLocalParts_) Partition_[i] = NumLocalParts_ - 1; } return(0); }
// ============================================================================ inline void Ifpack_LinePartitioner::local_automatic_line_search(int NumEqns, int * blockIndices, int last, int next, int LineID, double tol, int *itemp, double * dtemp) const { double *xvals=xcoord_, *yvals=ycoord_, *zvals=zcoord_; int N = NumMyRows(); int allocated_space = MaxNumEntries(); int * cols = itemp; int * indices = &itemp[allocated_space]; double * dist = dtemp; while (blockIndices[next] == -1) { // Get the next row int n=0; int neighbors_in_line=0; Graph_->ExtractMyRowCopy(next,allocated_space,n,cols); double x0 = (xvals) ? xvals[next/NumEqns] : 0.0; double y0 = (yvals) ? yvals[next/NumEqns] : 0.0; double z0 = (zvals) ? zvals[next/NumEqns] : 0.0; // Calculate neighbor distances & sort int neighbor_len=0; for(int i=0; i<n; i+=NumEqns) { double mydist = 0.0; if(cols[i] >=N) continue; // Check for off-proc entries int nn = cols[i] / NumEqns; if(blockIndices[nn]==LineID) neighbors_in_line++; if(xvals) mydist += (x0 - xvals[nn]) * (x0 - xvals[nn]); if(yvals) mydist += (y0 - yvals[nn]) * (y0 - yvals[nn]); if(zvals) mydist += (z0 - zvals[nn]) * (z0 - zvals[nn]); dist[neighbor_len] = sqrt(mydist); indices[neighbor_len]=cols[i]; neighbor_len++; } // If more than one of my neighbors is already in this line. I // can't be because I'd create a cycle if(neighbors_in_line > 1) break; // Otherwise add me to the line for(int k=0; k<NumEqns; k++) blockIndices[next + k] = LineID; // Try to find the next guy in the line (only check the closest two that aren't element 0 (diagonal)) Epetra_Util::Sort(true,neighbor_len,dist,0,0,1,&indices,0,0); if(neighbor_len > 2 && indices[1] != last && blockIndices[indices[1]] == -1 && dist[1]/dist[neighbor_len-1] < tol) { last=next; next=indices[1]; } else if(neighbor_len > 3 && indices[2] != last && blockIndices[indices[2]] == -1 && dist[2]/dist[neighbor_len-1] < tol) { last=next; next=indices[2]; } else { // I have no further neighbors in this line break; } } }
//============================================================================== int Ifpack_UserPartitioner::ComputePartitions() { if (Map_ == 0) IFPACK_CHK_ERR(-1); // simply copy user's vector for (int i = 0 ; i < NumMyRows() ; ++i) { Partition_[i] = Map_[i]; } // put together all partitions composed by 1 one vertex // (if any) std::vector<int> singletons(NumLocalParts()); for (unsigned int i = 0 ; i < singletons.size() ; ++i) { singletons[i] = 0; } #if 0 // may want to uncomment the following to ensure that no // partitions are in fact singletons for (int i = 0 ; i < NumMyRows() ; ++i) { ++singletons[Partition_[i]]; } int count = 0; for (unsigned int i = 0 ; i < singletons.size() ; ++i) { if (singletons[i] == 1) ++count; } int index = -1; for (int i = 0 ; i < NumMyRows() ; ++i) { int j = Partition_[i]; if (singletons[j] == 1) { if (index == -1) index = j; else Partition_[i] = index; } } #endif return(0); }
//============================================================================== Ifpack2_AMDReordering& Ifpack2_AMDReordering:: operator=(const Ifpack2_AMDReordering& RHS) { if (this == &RHS) { return (*this); } NumMyRows_ = RHS.NumMyRows(); // set number of local rows IsComputed_ = RHS.IsComputed(); // resize vectors, and copy values from RHS Reorder_.resize(NumMyRows()); InvReorder_.resize(NumMyRows()); if (IsComputed()) { for (int i = 0 ; i < NumMyRows_ ; ++i) { Reorder_[i] = RHS.Reorder(i); InvReorder_[i] = RHS.InvReorder(i); } } return (*this); }
//============================================================================== int Ifpack_LinePartitioner::ComputePartitions() { // Sanity Checks if(mode_==COORDINATES && !xcoord_ && !ycoord_ && !zcoord_) IFPACK_CHK_ERR(-1); if((int)Partition_.size() != NumMyRows()) IFPACK_CHK_ERR(-2); // Short circuit if(Partition_.size() == 0) {NumLocalParts_ = 0; return 0;} // Set partitions to -1 to initialize algorithm for(int i=0; i<NumMyRows(); i++) Partition_[i] = -1; // Use the auto partitioner NumLocalParts_ = Compute_Blocks_AutoLine(&Partition_[0]); // Resize Parts_ Parts_.resize(NumLocalParts_); return(0); }
//============================================================================== int Ifpack_DiagonalFilter:: Multiply(bool TransA, const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { if (X.NumVectors() != Y.NumVectors()) IFPACK_CHK_ERR(-2); IFPACK_CHK_ERR(A_->Multiply(TransA, X, Y)); for (int v = 0 ; v < X.NumVectors() ; ++v) for (int i = 0 ; i < NumMyRows() ; ++i) Y[v][i] += val_[i] * X[v][i]; return(0); }
// ============================================================================ int Ifpack_LinePartitioner::Compute_Blocks_AutoLine(int * blockIndices) const { double *xvals=xcoord_, *yvals=ycoord_, *zvals=zcoord_; int NumEqns = NumEqns_; double tol = threshold_; int N = NumMyRows(); int allocated_space = MaxNumEntries(); int * cols = new int[2*allocated_space]; int * indices = &cols[allocated_space]; double * dist = new double[allocated_space]; int * itemp = new int[2*allocated_space]; double *dtemp = new double[allocated_space]; int num_lines = 0; for(int i=0; i<N; i+=NumEqns) { int nz=0; // Short circuit if I've already been blocked if(blockIndices[i] !=-1) continue; // Get neighbors and sort by distance Graph_->ExtractMyRowCopy(i,allocated_space,nz,cols); double x0 = (xvals) ? xvals[i/NumEqns] : 0.0; double y0 = (yvals) ? yvals[i/NumEqns] : 0.0; double z0 = (zvals) ? zvals[i/NumEqns] : 0.0; int neighbor_len=0; for(int j=0; j<nz; j+=NumEqns) { double mydist = 0.0; int nn = cols[j] / NumEqns; if(cols[j] >=N) continue; // Check for off-proc entries if(xvals) mydist += (x0 - xvals[nn]) * (x0 - xvals[nn]); if(yvals) mydist += (y0 - yvals[nn]) * (y0 - yvals[nn]); if(zvals) mydist += (z0 - zvals[nn]) * (z0 - zvals[nn]); dist[neighbor_len] = sqrt(mydist); indices[neighbor_len]=cols[j]; neighbor_len++; } Epetra_Util::Sort(true,neighbor_len,dist,0,0,1,&indices,0,0); // Number myself for(int k=0; k<NumEqns; k++) blockIndices[i + k] = num_lines; // Fire off a neighbor line search (nearest neighbor) if(neighbor_len > 2 && dist[1]/dist[neighbor_len-1] < tol) { local_automatic_line_search(NumEqns,blockIndices,i,indices[1],num_lines,tol,itemp,dtemp); } // Fire off a neighbor line search (second nearest neighbor) if(neighbor_len > 3 && dist[2]/dist[neighbor_len-1] < tol) { local_automatic_line_search(NumEqns,blockIndices,i,indices[2],num_lines,tol,itemp,dtemp); } num_lines++; } // Cleanup delete [] cols; delete [] dist; delete [] itemp; delete [] dtemp; return num_lines; }
//============================================================================== // NOTE: // - matrix is supposed to be localized, and passes through the // singleton filter. This means that I do not have to look // for Dirichlet nodes (singletons). Also, all rows and columns are // local. int Ifpack_METISPartitioner::ComputePartitions() { int ierr; #ifdef HAVE_IFPACK_METIS int nbytes = 0; int edgecut; #endif Teuchos::RefCountPtr<Epetra_CrsGraph> SymGraph ; Teuchos::RefCountPtr<Epetra_Map> SymMap; Teuchos::RefCountPtr<Ifpack_Graph_Epetra_CrsGraph> SymIFPACKGraph; Teuchos::RefCountPtr<Ifpack_Graph> IFPACKGraph = Teuchos::rcp( (Ifpack_Graph*)Graph_, false ); int Length = 2 * MaxNumEntries(); int NumIndices; std::vector<int> Indices; Indices.resize(Length); /* construct the CSR graph information of the LOCAL matrix using the get_row function */ std::vector<idxtype> wgtflag; wgtflag.resize(4); std::vector<int> options; options.resize(4); int numflag; if (UseSymmetricGraph_) { #if !defined(EPETRA_NO_32BIT_GLOBAL_INDICES) || !defined(EPETRA_NO_64BIT_GLOBAL_INDICES) // need to build a symmetric graph. // I do this in two stages: // 1.- construct an Epetra_CrsMatrix, symmetric // 2.- convert the Epetra_CrsMatrix into METIS format SymMap = Teuchos::rcp( new Epetra_Map(NumMyRows(),0,Graph_->Comm()) ); SymGraph = Teuchos::rcp( new Epetra_CrsGraph(Copy,*SymMap,0) ); #endif #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES if(SymGraph->RowMap().GlobalIndicesInt()) { for (int i = 0; i < NumMyRows() ; ++i) { ierr = Graph_->ExtractMyRowCopy(i, Length, NumIndices, &Indices[0]); IFPACK_CHK_ERR(ierr); for (int j = 0 ; j < NumIndices ; ++j) { int jj = Indices[j]; if (jj != i) { SymGraph->InsertGlobalIndices(i,1,&jj); SymGraph->InsertGlobalIndices(jj,1,&i); } } } } else #endif #ifndef EPETRA_NO_64BIT_GLOBAL_INDICES if(SymGraph->RowMap().GlobalIndicesLongLong()) { for (int i = 0; i < NumMyRows() ; ++i) { long long i_LL = i; ierr = Graph_->ExtractMyRowCopy(i, Length, NumIndices, &Indices[0]); IFPACK_CHK_ERR(ierr); for (int j = 0 ; j < NumIndices ; ++j) { long long jj = Indices[j]; if (jj != i_LL) { SymGraph->InsertGlobalIndices(i_LL,1,&jj); SymGraph->InsertGlobalIndices(jj,1,&i_LL); } } } } else #endif throw "Ifpack_METISPartitioner::ComputePartitions: GlobalIndices type unknown"; IFPACK_CHK_ERR(SymGraph->FillComplete()); SymIFPACKGraph = Teuchos::rcp( new Ifpack_Graph_Epetra_CrsGraph(SymGraph) ); IFPACKGraph = SymIFPACKGraph; } // now work on IFPACKGraph, that can be the symmetric or // the non-symmetric one /* set parameters */ wgtflag[0] = 0; /* no weights */ numflag = 0; /* C style */ options[0] = 0; /* default options */ std::vector<idxtype> xadj; xadj.resize(NumMyRows() + 1); std::vector<idxtype> adjncy; adjncy.resize(NumMyNonzeros()); int count = 0; int count2 = 0; xadj[0] = 0; for (int i = 0; i < NumMyRows() ; ++i) { xadj[count2+1] = xadj[count2]; /* nonzeros in row i-1 */ ierr = IFPACKGraph->ExtractMyRowCopy(i, Length, NumIndices, &Indices[0]); IFPACK_CHK_ERR(ierr); for (int j = 0 ; j < NumIndices ; ++j) { int jj = Indices[j]; if (jj != i) { adjncy[count++] = jj; xadj[count2+1]++; } } count2++; } std::vector<idxtype> NodesInSubgraph; NodesInSubgraph.resize(NumLocalParts_); // some cases can be handled separately int ok; if (NumLocalParts() == 1) { for (int i = 0 ; i < NumMyRows() ; ++i) Partition_[i] = 0; } else if (NumLocalParts() == NumMyRows()) { for (int i = 0 ; i < NumMyRows() ; ++i) Partition_[i] = i; } else { ok = 0; // sometimes METIS creates less partitions than specified. // ok will check this problem, and recall metis, asking // for NumLocalParts_/2 partitions while (ok == 0) { for (int i = 0 ; i < NumMyRows() ; ++i) Partition_[i] = -1; #ifdef HAVE_IFPACK_METIS int j = NumMyRows(); if (NumLocalParts_ < 8) { int i = 1; /* optype in the METIS manual */ numflag = 0; METIS_EstimateMemory(&j, &xadj[0], &adjncy[0], &numflag, &i, &nbytes ); METIS_PartGraphRecursive(&j, &xadj[0], &adjncy[0], NULL, NULL, &wgtflag[0], &numflag, &NumLocalParts_, &options[0], &edgecut, &Partition_[0]); } else { numflag = 0; METIS_PartGraphKway (&j, &xadj[0], &adjncy[0], NULL, NULL, &wgtflag[0], &numflag, &NumLocalParts_, &options[0], &edgecut, &Partition_[0]); } #else numflag = numflag * 2; // avoid warning for unused variable if (Graph_->Comm().MyPID() == 0) { cerr << "METIS was not linked; now I put all" << endl; cerr << "the local nodes in the same partition." << endl; } for (int i = 0 ; i < NumMyRows() ; ++i) Partition_[i] = 0; NumLocalParts_ = 1; #endif ok = 1; for (int i = 0 ; i < NumLocalParts() ; ++i) NodesInSubgraph[i] = 0; for (int i = 0 ; i < NumMyRows() ; ++i) { int j = Partition_[i]; if ((j < 0) || (j>= NumLocalParts())) { ok = 0; break; } else NodesInSubgraph[j]++; } for (int i = 0 ; i < NumLocalParts() ; ++i) { if( NodesInSubgraph[i] == 0 ) { ok = 0; break; } } if (ok == 0) { cerr << "Specified number of subgraphs (" << NumLocalParts_ << ") generates empty subgraphs." << endl; cerr << "Now I recall METIS with NumLocalParts_ = " << NumLocalParts_ / 2 << "..." << endl; NumLocalParts_ = NumLocalParts_/2; } if (NumLocalParts() == 0) { IFPACK_CHK_ERR(-10); // something went wrong } if (NumLocalParts() == 1) { for (int i = 0 ; i < NumMyRows() ; ++i) Partition_[i] = 0; ok = 1; } } /* while( ok == 0 ) */ } /* if( NumLocalParts_ == 1 ) */ return(0); }
//========================================================================== int Ifpack_CrsRiluk::Factor() { // if (!Allocated()) return(-1); // This test is not needed at this time. All constructors allocate. if (!ValuesInitialized()) return(-2); // Must have values initialized. if (Factored()) return(-3); // Can't have already computed factors. SetValuesInitialized(false); // MinMachNum should be officially defined, for now pick something a little // bigger than IEEE underflow value double MinDiagonalValue = Epetra_MinDouble; double MaxDiagonalValue = 1.0/MinDiagonalValue; int ierr = 0; int i, j, k; int * LI=0, * UI = 0; double * LV=0, * UV = 0; int NumIn, NumL, NumU; // Get Maximun Row length int MaxNumEntries = L_->MaxNumEntries() + U_->MaxNumEntries() + 1; vector<int> InI(MaxNumEntries); // Allocate temp space vector<double> InV(MaxNumEntries); vector<int> colflag(NumMyCols()); double *DV; ierr = D_->ExtractView(&DV); // Get view of diagonal #ifdef IFPACK_FLOPCOUNTERS int current_madds = 0; // We will count multiply-add as they happen #endif // Now start the factorization. // Need some integer workspace and pointers int NumUU; int * UUI; double * UUV; for (j=0; j<NumMyCols(); j++) colflag[j] = - 1; for(i=0; i<NumMyRows(); i++) { // Fill InV, InI with current row of L, D and U combined NumIn = MaxNumEntries; EPETRA_CHK_ERR(L_->ExtractMyRowCopy(i, NumIn, NumL, &InV[0], &InI[0])); LV = &InV[0]; LI = &InI[0]; InV[NumL] = DV[i]; // Put in diagonal InI[NumL] = i; EPETRA_CHK_ERR(U_->ExtractMyRowCopy(i, NumIn-NumL-1, NumU, &InV[NumL+1], &InI[NumL+1])); NumIn = NumL+NumU+1; UV = &InV[NumL+1]; UI = &InI[NumL+1]; // Set column flags for (j=0; j<NumIn; j++) colflag[InI[j]] = j; double diagmod = 0.0; // Off-diagonal accumulator for (int jj=0; jj<NumL; jj++) { j = InI[jj]; double multiplier = InV[jj]; // current_mults++; InV[jj] *= DV[j]; EPETRA_CHK_ERR(U_->ExtractMyRowView(j, NumUU, UUV, UUI)); // View of row above if (RelaxValue_==0.0) { for (k=0; k<NumUU; k++) { int kk = colflag[UUI[k]]; if (kk>-1) { InV[kk] -= multiplier*UUV[k]; #ifdef IFPACK_FLOPCOUNTERS current_madds++; #endif } } } else { for (k=0; k<NumUU; k++) { int kk = colflag[UUI[k]]; if (kk>-1) InV[kk] -= multiplier*UUV[k]; else diagmod -= multiplier*UUV[k]; #ifdef IFPACK_FLOPCOUNTERS current_madds++; #endif } } } if (NumL) { EPETRA_CHK_ERR(L_->ReplaceMyValues(i, NumL, LV, LI)); // Replace current row of L } DV[i] = InV[NumL]; // Extract Diagonal value if (RelaxValue_!=0.0) { DV[i] += RelaxValue_*diagmod; // Add off diagonal modifications // current_madds++; } if (fabs(DV[i]) > MaxDiagonalValue) { if (DV[i] < 0) DV[i] = - MinDiagonalValue; else DV[i] = MinDiagonalValue; } else DV[i] = 1.0/DV[i]; // Invert diagonal value for (j=0; j<NumU; j++) UV[j] *= DV[i]; // Scale U by inverse of diagonal if (NumU) { EPETRA_CHK_ERR(U_->ReplaceMyValues(i, NumU, UV, UI)); // Replace current row of L and U } // Reset column flags for (j=0; j<NumIn; j++) colflag[InI[j]] = -1; } // Validate that the L and U factors are actually lower and upper triangular if( !L_->LowerTriangular() ) EPETRA_CHK_ERR(-2); if( !U_->UpperTriangular() ) EPETRA_CHK_ERR(-3); #ifdef IFPACK_FLOPCOUNTERS // Add up flops double current_flops = 2 * current_madds; double total_flops = 0; EPETRA_CHK_ERR(Graph_.L_Graph().RowMap().Comm().SumAll(¤t_flops, &total_flops, 1)); // Get total madds across all PEs // Now count the rest total_flops += (double) L_->NumGlobalNonzeros(); // Accounts for multiplier above total_flops += (double) D_->GlobalLength(); // Accounts for reciprocal of diagonal if (RelaxValue_!=0.0) total_flops += 2 * (double)D_->GlobalLength(); // Accounts for relax update of diag UpdateFlops(total_flops); // Update flop count #endif SetFactored(true); return(ierr); }
// ============================================================================ // Visualize aggregates and (for XYZ or VTK format) also plot vectors // date: Aug-04 int ML_Epetra::MultiLevelPreconditioner:: Visualize(bool VizAggre, bool VizPreSmoother, bool VizPostSmoother, bool VizCycle, int NumApplPreSmoother, int NumApplPostSmoother, int NumCycleSmoother) { ML_Aggregate *aggregates = agg_; char filename[80] = ""; int NumDimensions = 0; ML_Aggregate_Viz_Stats *grid_info = (ML_Aggregate_Viz_Stats *) ml_->Grid[LevelID_[0]].Grid; double * x_coord = grid_info->x; double * y_coord = grid_info->y; double * z_coord = grid_info->z; if( x_coord ) NumDimensions++; if( y_coord ) NumDimensions++; if( z_coord ) NumDimensions++; assert( NumDimensions != 0 ); if (VizAggre == true) { // stats about level matrix sizes if( verbose_ ) std::cout << std::endl << "- number of rows for each level's matrix:" << std::endl << std::endl; for( int ilevel=0 ; ilevel < NumLevels_ ; ++ilevel ) { int imin, iavg, imax; int Nrows = ml_->Amat[LevelID_[ilevel]].outvec_leng/NumPDEEqns_; Comm().MinAll(&Nrows,&imin,1); Comm().MaxAll(&Nrows,&imax,1); Comm().SumAll(&Nrows,&iavg,1); iavg /= Comm().NumProc(); if( verbose_ ) { printf( "\t(level %d) rows per process (min) = %d\n", ilevel, imin); printf( "\t(level %d) rows per process (avg) = %d\n", ilevel, iavg); printf( "\t(level %d) rows per process (max) = %d\n", ilevel, imax); std::cout << std::endl; } } if( verbose_ ) std::cout << std::endl << "- analysis of the computational domain (finest level):" << std::endl << std::endl; ML_Aggregate_Stats_Analyze(ml_,aggregates); } // prepare output format. Now it can be: // - OpenDX (1D/2D/3D) // - XD3D (2D only) // - Paraview, or any other package that can read .vtk files (1D/2D/3D) int Format; std::string FileFormat = List_.get("viz: output format", "vtk"); // you are a cool guy if you plot with "xyz" if( FileFormat == "xyz" ) Format = 1; // you are a poor man if you need "dx". God bless you. else if( FileFormat == "dx" ) Format = 0; // you are a very cool guy if you plot with the "vtk" option (paraview) else if( FileFormat == "vtk" ) Format = 2; else { std::cerr << ErrorMsg_ << "Option `viz: output format' has an incorrect" << std::endl << ErrorMsg_ << "value (" << FileFormat << "). Possible values are" << std::endl << ErrorMsg_ << "<dx> / <xyz> / <vtk>" << std::endl; exit( EXIT_FAILURE ); } int ieqn = List_.get("viz: equation to plot", -1); if (AMGSolver_ == ML_MAXWELL) ieqn = -1; if( ieqn >= NumPDEEqns_ ) ieqn = 0; bool PrintStarting = List_.get("viz: print starting solution", false); ML_Smoother * ptr; double * tmp_rhs = new double[NumMyRows()]; double * tmp_sol = new double[NumMyRows()]; double * plot_me = new double[NumMyRows()/NumPDEEqns_]; // Note that this requires the new version of the // visualization routines. OpenDX cannot visualize vectors. if( ( VizPreSmoother || VizPostSmoother || VizCycle ) && ( Format == 0) ) { std::cerr << std::endl; std::cerr << ErrorMsg_ << "Option `viz: output format' == `dx' cannot be used" << std::endl << ErrorMsg_ << "to visualize the effect of smoothers and cycle." << std::endl; std::cerr << std::endl; VizPreSmoother = false; VizPostSmoother = false; VizCycle = false; } if( verbose_ ) std::cout << std::endl << "- visualization:" << std::endl << std::endl; // =============================================================== // // cycle over all levels. Note that almost the same thing // // is done for pre-smoothing, post-smoothing, and the effect // // of the cycle itself. For each of these, I plot on file // // the starting solution (before-), the final solution (after-), // // for each equation, and for each level (smoother only). // // All these junk works with XYZ only, and it should work in // // 3D too (although I never tested in 3D). // // // // JJH 3/11/2005 Paraview has been tested in 3D for .vtk output, // // and it works. // // =============================================================== // std::cout << "cycling thru levels 0 to " << NumLevels_ -1 << std::endl; for( int ilevel=0 ; ilevel<NumLevels_ ; ++ilevel ) { // =================== // // plot the aggregates // // =================== // if( VizAggre ) ML_Aggregate_Viz(ml_,aggregates,Format,NULL,NULL,LevelID_[ilevel]); // ============ // // pre-smoother // // ============ // ptr = ((ml_->SingleLevel[LevelID_[ilevel]]).pre_smoother); if( ptr != NULL && VizPreSmoother ) { RandomAndZero(tmp_sol,tmp_rhs,ml_->Amat[LevelID_[ilevel]].outvec_leng); // visualize starting vector if( PrintStarting ) { if( ieqn != -1 ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+ieqn]; sprintf(filename,"before-presmoother-eq%d", ieqn); printf("%s, numrows = %d\n",filename, NumMyRows()); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me, filename,LevelID_[ilevel]); } else { // by default, print out all equations for( int eq=0 ; eq<NumPDEEqns_ ; eq++ ) { sprintf(filename,"before-presmoother-eq%d", eq); printf("%s, numrows = %d\n",filename, NumMyRows()); for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) { plot_me[i/NumPDEEqns_] = tmp_sol[i+eq]; //FIXME JJH temporary print //printf("(eq %d, %d) %d: %lf\n",eq,LevelID_[ilevel],i,tmp_sol[i+eq]); } ML_Aggregate_Viz(ml_,aggregates,Format,plot_me, filename,LevelID_[ilevel]); } } } // increase the number of applications of the smoother // and run the smoother int old_ntimes = ptr->ntimes; ptr->ntimes = NumApplPreSmoother; ML_Smoother_Apply(ptr, ml_->Amat[LevelID_[ilevel]].outvec_leng, tmp_sol, ml_->Amat[LevelID_[ilevel]].outvec_leng, tmp_rhs, ML_NONZERO); ptr->ntimes = old_ntimes; // visualize // user may have required one specific equation only if( ieqn != -1 ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+ieqn]; sprintf(filename,"after-presmoother-eq%d", ieqn); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me, filename,LevelID_[ilevel]); } else { // by default, print out all equations for( int eq=0 ; eq<NumPDEEqns_ ; eq++ ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+eq]; sprintf(filename,"after-presmoother-eq%d", eq); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me, filename,LevelID_[ilevel]); } } } // VizPreSmoother // ============= // // post-smoother // // ============= // ptr = ((ml_->SingleLevel[LevelID_[ilevel]]).post_smoother); if( ptr != NULL && VizPostSmoother ) { // random solution and 0 rhs RandomAndZero(tmp_sol,tmp_rhs,ml_->Amat[LevelID_[ilevel]].outvec_leng); // visualize starting vector if( PrintStarting ) { if( ieqn != -1 ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+ieqn]; sprintf(filename,"before-postsmoother-eq%d", ieqn); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me, filename,LevelID_[ilevel]); } else { // by default, print out all equations for( int eq=0 ; eq<NumPDEEqns_ ; eq++ ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+eq]; sprintf(filename,"before-postsmoother-eq%d", eq); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me, filename,LevelID_[ilevel]); } } } // increase the number of applications of the smoother // and run the smoother int old_ntimes = ptr->ntimes; ptr->ntimes = NumApplPostSmoother; ML_Smoother_Apply(ptr, ml_->Amat[LevelID_[ilevel]].outvec_leng, tmp_sol, ml_->Amat[LevelID_[ilevel]].outvec_leng, tmp_rhs, ML_ZERO); ptr->ntimes = old_ntimes; // visualize // user may have required one specific equation only if( ieqn != -1 ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+ieqn]; printf(filename,"after-postsmoother-eq%d", ieqn); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me, filename,LevelID_[ilevel]); } else { // by default, print out all equations for( int eq=0 ; eq<NumPDEEqns_ ; eq++ ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+eq]; sprintf(filename,"after-postsmoother-eq%d", eq); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me, filename,LevelID_[ilevel]); } } } // VizPostSmoother } // for( ilevel ) // =============================== // // run ML cycle on a random vector // // =============================== // if( VizCycle ) { // random solution and zero rhs RandomAndZero(tmp_sol, tmp_rhs,ml_->Amat[LevelID_[0]].outvec_leng); // visualize starting vector if( PrintStarting ) { if( ieqn != -1 ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+ieqn]; sprintf(filename,"before-cycle-eq%d", ieqn); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me,filename,LevelID_[0]); } else { // by default, print out all equations for( int eq=0 ; eq<NumPDEEqns_ ; eq++ ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+eq]; sprintf(filename,"before-cycle-eq%d", eq); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me, filename,LevelID_[0]); } } } // run the cycle for( int i=0 ; i<NumCycleSmoother ; ++i ) ML_Cycle_MG(&(ml_->SingleLevel[ml_->ML_finest_level]), tmp_sol, tmp_rhs, ML_NONZERO, ml_->comm, ML_NO_RES_NORM, ml_); // visualize // user may have required one specific equation only if( ieqn != -1 ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+ieqn]; sprintf(filename,"after-cycle-eq%d", ieqn); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me,filename,LevelID_[0]); } else { // by default, print out all equations for( int eq=0 ; eq<NumPDEEqns_ ; eq++ ) { for( int i=0 ; i<NumMyRows() ; i+=NumPDEEqns_ ) plot_me[i/NumPDEEqns_] = tmp_sol[i+eq]; sprintf(filename,"after-cycle-eq%d", eq); ML_Aggregate_Viz(ml_,aggregates,Format,plot_me,filename,LevelID_[0]); } } } // VizCycle // =================== // // clean up and return // // =================== // delete [] tmp_sol; delete [] tmp_rhs; delete [] plot_me; return(0); }
//============================================================================= void Epetra_MsrMatrix::Print(ostream& os) const { int MyPID = RowMatrixRowMap().Comm().MyPID(); int NumProc = RowMatrixRowMap().Comm().NumProc(); for (int iproc=0; iproc < NumProc; iproc++) { if (MyPID==iproc) { /* const Epetra_fmtflags olda = os.setf(ios::right,ios::adjustfield); const Epetra_fmtflags oldf = os.setf(ios::scientific,ios::floatfield); const int oldp = os.precision(12); */ if (MyPID==0) { os << "\nNumber of Global Rows = "; os << NumGlobalRows(); os << endl; os << "Number of Global Cols = "; os << NumGlobalCols(); os << endl; os << "Number of Global Diagonals = "; os << NumGlobalDiagonals(); os << endl; os << "Number of Global Nonzeros = "; os << NumGlobalNonzeros(); os << endl; if (LowerTriangular()) os << " ** Matrix is Lower Triangular **"; os << endl; if (UpperTriangular()) os << " ** Matrix is Upper Triangular **"; os << endl; } os << "\nNumber of My Rows = "; os << NumMyRows(); os << endl; os << "Number of My Cols = "; os << NumMyCols(); os << endl; os << "Number of My Diagonals = "; os << NumMyDiagonals(); os << endl; os << "Number of My Nonzeros = "; os << NumMyNonzeros(); os << endl; os << endl; os << flush; // Reset os flags /* os.setf(olda,ios::adjustfield); os.setf(oldf,ios::floatfield); os.precision(oldp); */ } // Do a few global ops to give I/O a chance to complete Comm().Barrier(); Comm().Barrier(); Comm().Barrier(); } {for (int iproc=0; iproc < NumProc; iproc++) { if (MyPID==iproc) { int i, j; if (MyPID==0) { os.width(8); os << " Processor "; os.width(10); os << " Row Index "; os.width(10); os << " Col Index "; os.width(20); os << " Value "; os << endl; } for (i=0; i<NumMyRows_; i++) { int Row = RowMatrixRowMap().GID(i); // Get global row number int NumEntries = GetRow(i); // ith row is now in Values_ and Indices_ for (j = 0; j < NumEntries ; j++) { os.width(8); os << MyPID ; os << " "; os.width(10); os << Row ; os << " "; os.width(10); os << RowMatrixColMap().GID(Indices_[j]); os << " "; os.width(20); os << Values_[j]; os << " "; os << endl; } } os << flush; } // Do a few global ops to give I/O a chance to complete RowMatrixRowMap().Comm().Barrier(); RowMatrixRowMap().Comm().Barrier(); RowMatrixRowMap().Comm().Barrier(); }} return; }
int Ifpack_CrsRiluk::InitAllValues(const Epetra_RowMatrix & OverlapA, int MaxNumEntries) { int ierr = 0; int i, j; int NumIn, NumL, NumU; bool DiagFound; int NumNonzeroDiags = 0; vector<int> InI(MaxNumEntries); // Allocate temp space vector<int> LI(MaxNumEntries); vector<int> UI(MaxNumEntries); vector<double> InV(MaxNumEntries); vector<double> LV(MaxNumEntries); vector<double> UV(MaxNumEntries); bool ReplaceValues = (L_->StaticGraph() || L_->IndicesAreLocal()); // Check if values should be inserted or replaced if (ReplaceValues) { L_->PutScalar(0.0); // Zero out L and U matrices U_->PutScalar(0.0); } D_->PutScalar(0.0); // Set diagonal values to zero double *DV; EPETRA_CHK_ERR(D_->ExtractView(&DV)); // Get view of diagonal // First we copy the user's matrix into L and U, regardless of fill level for (i=0; i< NumMyRows(); i++) { EPETRA_CHK_ERR(OverlapA.ExtractMyRowCopy(i, MaxNumEntries, NumIn, &InV[0], &InI[0])); // Get Values and Indices // Split into L and U (we don't assume that indices are ordered). NumL = 0; NumU = 0; DiagFound = false; for (j=0; j< NumIn; j++) { int k = InI[j]; if (k==i) { DiagFound = true; DV[i] += Rthresh_ * InV[j] + EPETRA_SGN(InV[j]) * Athresh_; // Store perturbed diagonal in Epetra_Vector D_ } else if (k < 0) {EPETRA_CHK_ERR(-1);} // Out of range else if (k < i) { LI[NumL] = k; LV[NumL] = InV[j]; NumL++; } else if (k<NumMyRows()) { UI[NumU] = k; UV[NumU] = InV[j]; NumU++; } } // Check in things for this row of L and U if (DiagFound) NumNonzeroDiags++; else DV[i] = Athresh_; if (NumL) { if (ReplaceValues) { EPETRA_CHK_ERR(L_->ReplaceMyValues(i, NumL, &LV[0], &LI[0])); } else { EPETRA_CHK_ERR(L_->InsertMyValues(i, NumL, &LV[0], &LI[0])); } } if (NumU) { if (ReplaceValues) { EPETRA_CHK_ERR(U_->ReplaceMyValues(i, NumU, &UV[0], &UI[0])); } else { EPETRA_CHK_ERR(U_->InsertMyValues(i, NumU, &UV[0], &UI[0])); } } } if (!ReplaceValues) { // The domain of L and the range of U are exactly their own row maps (there is no communication). // The domain of U and the range of L must be the same as those of the original matrix, // However if the original matrix is a VbrMatrix, these two latter maps are translation from // a block map to a point map. EPETRA_CHK_ERR(L_->FillComplete(L_->RowMatrixColMap(), *L_RangeMap_)); EPETRA_CHK_ERR(U_->FillComplete(*U_DomainMap_, U_->RowMatrixRowMap())); } // At this point L and U have the values of A in the structure of L and U, and diagonal vector D SetValuesInitialized(true); SetFactored(false); int TotalNonzeroDiags = 0; EPETRA_CHK_ERR(Graph_.L_Graph().RowMap().Comm().SumAll(&NumNonzeroDiags, &TotalNonzeroDiags, 1)); NumMyDiagonals_ = NumNonzeroDiags; if (NumNonzeroDiags != NumMyRows()) ierr = 1; // Diagonals are not right, warn user return(ierr); }
//============================================================================== int Ifpack_GreedyPartitioner::ComputePartitions() { std::vector<int> ElementsPerPart(NumLocalParts()); std::vector<int> Count(NumLocalParts()); for (int i = 0 ; i < NumLocalParts() ; ++i) Count[i] = 0; // define how many nodes have to be put on each part int div = NumMyRows() / NumLocalParts(); int mod = NumMyRows() % NumLocalParts(); for (int i = 0 ; i < NumLocalParts() ; ++i) { Count[i] = 0; ElementsPerPart[i] = div; if (i < mod) ElementsPerPart[i]++; } for( int i=0 ; i<NumMyRows() ; ++i ) { Partition_[i] = -1; } int NumEntries; std::vector<int> Indices(MaxNumEntries()); // load root node for partition 0 int CurrentPartition = 0; int TotalCount = 0; // filter singletons and empty rows, put all of them in partition 0 for (int i = 0 ; i < NumMyRows() ; ++i) { NumEntries = 0; int ierr = Graph_->ExtractMyRowCopy(i, MaxNumEntries(), NumEntries, &Indices[0]); IFPACK_CHK_ERR(ierr); if (NumEntries <= 1) { Partition_[i] = 0; TotalCount++; } } if (TotalCount) CurrentPartition = 1; std::vector<int> ThisLevel(1); ThisLevel[0] = RootNode_; // be sure that RootNode is not a singleton or empty row if (Partition_[RootNode_] != -1) { // look for another RN for (int i = 0 ; i < NumMyRows() ; ++i) if (Partition_[i] == -1) { ThisLevel[0] = i; break; } } else { Partition_[RootNode_] = CurrentPartition; } // now aggregate the non-empty and non-singleton rows while (ThisLevel.size()) { std::vector<int> NextLevel; for (unsigned int i = 0 ; i < ThisLevel.size() ; ++i) { int CurrentNode = ThisLevel[i]; int ierr = Graph_->ExtractMyRowCopy(CurrentNode, MaxNumEntries(), NumEntries, &Indices[0]); IFPACK_CHK_ERR(ierr); if (NumEntries <= 1) continue; for (int j = 0 ; j < NumEntries ; ++j) { int NextNode = Indices[j]; if (NextNode >= NumMyRows()) continue; if (Partition_[NextNode] == -1) { // this is a free node NumLocalParts_ = CurrentPartition + 1; Partition_[NextNode] = CurrentPartition; ++Count[CurrentPartition]; ++TotalCount; NextLevel.push_back(NextNode); } } } // for (i) // check whether change partition or not if (Count[CurrentPartition] >= ElementsPerPart[CurrentPartition]) ++CurrentPartition; // swap next and this ThisLevel.resize(0); for (unsigned int i = 0 ; i < NextLevel.size() ; ++i) ThisLevel.push_back(NextLevel[i]); if (ThisLevel.size() == 0 && (TotalCount != NumMyRows())) { // need to look for new RootNode, do this in a simple way for (int i = 0 ; i < NumMyRows() ; i++) { if (Partition_[i] == -1) ThisLevel.push_back(i); break; } } } // while (ok) return(0); }
std::ostream& MLAPI::DistributedMatrix:: Print(std::ostream& os, const bool verbose) const { if (GetMyPID() == 0) { os << std::endl; os << "*** MLAPI::DistributedMatrix ***" << std::endl; os << "Label = " << GetLabel() << std::endl; os << "Number of rows = " << GetRangeSpace().GetNumGlobalElements() << std::endl; os << "Number of columns = " << GetDomainSpace().GetNumGlobalElements() << std::endl; os << std::endl; os.width(10); os << "row ID"; os.width(10); os << "col ID"; os.width(30); os << "value"; os << std::endl; os << std::endl; } for (int iproc = 0 ; iproc < GetNumProcs() ; ++iproc) { if (GetMyPID() == iproc) { if (IsFillCompleted()) { for (int i = 0 ; i < NumMyRows() ; ++i) { int GRID = RangeMap_->GID(i); double* Values; int* Indices; int NumEntries; Matrix_->ExtractMyRowView(i, NumEntries, Values, Indices); for (int j = 0 ; j < NumEntries ; ++j) { os.width(10); os << GRID; os.width(10); os << Matrix_->RowMatrixColMap().GID(Indices[j]); os.width(30); os << Values[j]; os << std::endl; } } } else { for (int i = 0 ; i < NumMyRows() ; ++i) { int GRID = RangeMap_->GID(i); double* Values; int* Indices; int NumEntries; Matrix_->ExtractGlobalRowView(GRID, NumEntries, Values, Indices); for (int j = 0 ; j < NumEntries ; ++j) { os.width(10); os << GRID; os.width(10); os << Indices[j]; os.width(30); os << Values[j]; os << std::endl; } } } } Barrier(); } if (GetMyPID() == 0) os << std::endl; Barrier(); return(os); }
// ================================================ ====== ==== ==== == = // the tentative null space is in input because the user // has to remember to allocate and fill it, and then to delete // it after calling this method. int ML_Epetra::MultiLevelPreconditioner:: ComputeAdaptivePreconditioner(int TentativeNullSpaceSize, double* TentativeNullSpace) { if ((TentativeNullSpaceSize == 0) || (TentativeNullSpace == 0)) ML_CHK_ERR(-1); // ================================== // // get parameters from the input list // // ================================== // // maximum number of relaxation sweeps int MaxSweeps = List_.get("adaptive: max sweeps", 10); // number of std::vector to be added to the tentative null space int NumAdaptiveVectors = List_.get("adaptive: num vectors", 1); if (verbose_) { std::cout << PrintMsg_ << "*** Adaptive Smoother Aggregation setup ***" << std::endl; std::cout << PrintMsg_ << " Maximum relaxation sweeps = " << MaxSweeps << std::endl; std::cout << PrintMsg_ << " Additional vectors to compute = " << NumAdaptiveVectors << std::endl; } // ==================================================== // // compute the preconditioner, set null space from user // // (who will have to delete std::vector TentativeNullSpace) // // ==================================================== // double* NewNullSpace = 0; double* OldNullSpace = TentativeNullSpace; int OldNullSpaceSize = TentativeNullSpaceSize; // need some work otherwise matvec() with Epetra_Vbr fails. // Also, don't differentiate between range and domain here // as ML will not work if range != domain const Epetra_VbrMatrix* VbrA = NULL; VbrA = dynamic_cast<const Epetra_VbrMatrix*>(RowMatrix_); Epetra_Vector* LHS = 0; Epetra_Vector* RHS = 0; if (VbrA != 0) { LHS = new Epetra_Vector(VbrA->DomainMap()); RHS = new Epetra_Vector(VbrA->DomainMap()); } else { LHS = new Epetra_Vector(RowMatrix_->OperatorDomainMap()); RHS = new Epetra_Vector(RowMatrix_->OperatorDomainMap()); } // destroy what we may already have if (IsComputePreconditionerOK_ == true) { DestroyPreconditioner(); } // build the preconditioner for the first time List_.set("null space: type", "pre-computed"); List_.set("null space: dimension", OldNullSpaceSize); List_.set("null space: vectors", OldNullSpace); ComputePreconditioner(); // ====================== // // add one std::vector at time // // ====================== // for (int istep = 0 ; istep < NumAdaptiveVectors ; ++istep) { if (verbose_) { std::cout << PrintMsg_ << "\tAdaptation step " << istep << std::endl; std::cout << PrintMsg_ << "\t---------------" << std::endl; } // ==================== // // look for "bad" modes // // ==================== // // note: should an error occur, ML_CHK_ERR will return, // and LHS and RHS will *not* be delete'd (--> memory leak). // Anyway, this means that something wrong happened in the code // and should be fixed by the user. LHS->Random(); double Norm2; for (int i = 0 ; i < MaxSweeps ; ++i) { // RHS = (I - ML^{-1} A) LHS ML_CHK_ERR(RowMatrix_->Multiply(false,*LHS,*RHS)); // FIXME: can do something slightly better here ML_CHK_ERR(ApplyInverse(*RHS,*RHS)); ML_CHK_ERR(LHS->Update(-1.0,*RHS,1.0)); LHS->Norm2(&Norm2); if (verbose_) { std::cout << PrintMsg_ << "\titer " << i << ", ||x||_2 = "; std::cout << Norm2 << std::endl; } } // scaling vectors double NormInf; LHS->NormInf(&NormInf); LHS->Scale(1.0 / NormInf); // ========================================================= // // copy tentative and computed null space into NewNullSpace, // // which now becomes the standard null space // // ========================================================= // int NewNullSpaceSize = OldNullSpaceSize + 1; NewNullSpace = new double[NumMyRows() * NewNullSpaceSize]; assert (NewNullSpace != 0); int itmp = OldNullSpaceSize * NumMyRows(); for (int i = 0 ; i < itmp ; ++i) { NewNullSpace[i] = OldNullSpace[i]; } for (int j = 0 ; j < NumMyRows() ; ++j) { NewNullSpace[itmp + j] = (*LHS)[j]; } // =============== // // visualize modes // // =============== // if (List_.get("adaptive: visualize", false)) { double* x_coord = List_.get("viz: x-coordinates", (double*)0); double* y_coord = List_.get("viz: y-coordinates", (double*)0); double* z_coord = List_.get("viz: z-coordinates", (double*)0); assert (x_coord != 0); std::vector<double> plot_me(NumMyRows()/NumPDEEqns_); ML_Aggregate_Viz_Stats info; info.Amatrix = &(ml_->Amat[LevelID_[0]]); info.x = x_coord; info.y = y_coord; info.z = z_coord; info.Nlocal = NumMyRows() / NumPDEEqns_; info.Naggregates = 1; ML_Operator_AmalgamateAndDropWeak(&(ml_->Amat[LevelID_[0]]), NumPDEEqns_, 0.0); for (int ieqn = 0 ; ieqn < NumPDEEqns_ ; ++ieqn) { for (int j = 0 ; j < NumMyRows() ; j+=NumPDEEqns_) { plot_me[j / NumPDEEqns_] = (*LHS)[j + ieqn]; } char FileName[80]; sprintf(FileName,"nullspace-mode%d-eq%d.xyz", istep, ieqn); if (verbose_) std::cout << PrintMsg_ << "writing file " << FileName << "..." << std::endl; ML_Aggregate_VisualizeXYZ(info,FileName, ml_->comm,&plot_me[0]); } ML_Operator_UnAmalgamateAndDropWeak(&(ml_->Amat[LevelID_[0]]), NumPDEEqns_, 0.0); } // Destroy the old preconditioner DestroyPreconditioner(); // ==================================================== // // build the new preconditioner with the new null space // // ==================================================== // List_.set("null space: type", "pre-computed"); List_.set("null space: dimension", NewNullSpaceSize); List_.set("null space: vectors", NewNullSpace); ML_CHK_ERR(ComputePreconditioner()); if (istep && (istep != NumAdaptiveVectors)) delete OldNullSpace; OldNullSpace = NewNullSpace; OldNullSpaceSize = NewNullSpaceSize; } // keep trace of this pointer, it will be delete'd later NullSpaceToFree_ = NewNullSpace; delete LHS; delete RHS; return(0); }
// ============================================================================ int Ifpack_LinePartitioner::Compute_Blocks_AutoLine(int * blockIndices) const { double *xvals=xcoord_, *yvals=ycoord_, *zvals=zcoord_; int NumEqns = NumEqns_; double tol = threshold_; int N = NumMyRows(); int allocated_space = MaxNumEntries(); int * cols = new int[2*allocated_space]; int * indices = &cols[allocated_space]; double * merit = new double[2*allocated_space]; double * vals = &merit[allocated_space]; int * itemp = new int[2*allocated_space]; double *dtemp = new double[2*allocated_space]; int num_lines = 0; for(int i=0; i<N; i+=NumEqns) { int nz=0; // Short circuit if I've already been blocked if(blockIndices[i] !=-1) continue; // Get neighbors and sort by distance if(mode_==MATRIX_ENTRIES) Matrix_->ExtractMyRowCopy(i,allocated_space,nz,vals,cols); else Graph_->ExtractMyRowCopy(i,allocated_space,nz,cols); double x0 = (xvals) ? xvals[i/NumEqns] : 0.0; double y0 = (yvals) ? yvals[i/NumEqns] : 0.0; double z0 = (zvals) ? zvals[i/NumEqns] : 0.0; int neighbor_len=0; for(int j=0; j<nz; j+=NumEqns) { int nn = cols[j] / NumEqns; if(cols[j] >=N) continue; // Check for off-proc entries if(mode_==COORDINATES) merit[neighbor_len] = compute_distance_coordinates(x0,y0,z0,nn,xvals,yvals,zvals); else { merit[neighbor_len] = - compute_distance_matrix_entries(vals,j,NumEqns); // Make this negative here, so we can use the same if tests at coordinates // Boost the diagonal here to ensure it goes first if(cols[j]==i) merit[neighbor_len] = -DBL_MAX; } indices[neighbor_len] = cols[j]; neighbor_len++; } Epetra_Util::Sort(true,neighbor_len,merit,0,0,1,&indices,0,0); // Number myself for(int k=0; k<NumEqns; k++) blockIndices[i + k] = num_lines; // Fire off a neighbor line search (nearest neighbor) if(neighbor_len > 2 && merit[1] < tol*merit[neighbor_len-1]) { local_automatic_line_search(NumEqns,blockIndices,i,indices[1],num_lines,tol,itemp,dtemp); } // Fire off a neighbor line search (second nearest neighbor) if(neighbor_len > 3 && merit[2] < tol*merit[neighbor_len-1]) { local_automatic_line_search(NumEqns,blockIndices,i,indices[2],num_lines,tol,itemp,dtemp); } num_lines++; } // Cleanup delete [] cols; delete [] merit; delete [] itemp; delete [] dtemp; return num_lines; }
// ============================================================================ inline void Ifpack_LinePartitioner::local_automatic_line_search(int NumEqns, int * blockIndices, int last, int next, int LineID, double tol, int *itemp, double * dtemp) const { double *xvals=xcoord_, *yvals=ycoord_, *zvals=zcoord_; int N = NumMyRows(); int allocated_space = MaxNumEntries(); int * cols = itemp; int * indices = &itemp[allocated_space]; double * merit= dtemp; double * vals = &dtemp[allocated_space]; while (blockIndices[next] == -1) { // Get the next row int n=0; int neighbors_in_line=0; if(mode_==MATRIX_ENTRIES) Matrix_->ExtractMyRowCopy(next,allocated_space,n,vals,cols); else Graph_->ExtractMyRowCopy(next,allocated_space,n,cols); // Coordinate distance info double x0 = (xvals) ? xvals[next/NumEqns] : 0.0; double y0 = (yvals) ? yvals[next/NumEqns] : 0.0; double z0 = (zvals) ? zvals[next/NumEqns] : 0.0; // Calculate neighbor distances & sort int neighbor_len=0; for(int i=0; i<n; i+=NumEqns) { if(cols[i] >=N) continue; // Check for off-proc entries int nn = cols[i] / NumEqns; if(blockIndices[nn]==LineID) neighbors_in_line++; if(mode_==COORDINATES) merit[neighbor_len] = compute_distance_coordinates(x0,y0,z0,nn,xvals,yvals,zvals); else { merit[neighbor_len] = - compute_distance_matrix_entries(vals,i,NumEqns); // Make this negative here, so we can use the same if tests at coordinates // Boost the diagonal here to ensure it goes first if(cols[i]==next) merit[neighbor_len] = -DBL_MAX; } indices[neighbor_len]=cols[i]; neighbor_len++; } // If more than one of my neighbors is already in this line. I // can't be because I'd create a cycle if(neighbors_in_line > 1) break; // Otherwise add me to the line for(int k=0; k<NumEqns; k++) blockIndices[next + k] = LineID; // Try to find the next guy in the line (only check the closest two that aren't element 0 (diagonal)) Epetra_Util::Sort(true,neighbor_len,merit,0,0,1,&indices,0,0); if(neighbor_len > 2 && indices[1] != last && blockIndices[indices[1]] == -1 && merit[1] < tol*merit[neighbor_len-1]) { last=next; next=indices[1]; } else if(neighbor_len > 3 && indices[2] != last && blockIndices[indices[2]] == -1 && merit[2] < tol*merit[neighbor_len-1]) { last=next; next=indices[2]; } else { // I have no further neighbors in this line break; } } }