void Stokhos::AdaptivityManager:: sumInOperator(Epetra_CrsMatrix & A,const Stokhos::AdaptivityManager::Sparse3TensorHash & Cijk,int k,const Epetra_CrsMatrix & J_k) const { TEUCHOS_ASSERT(J_k.NumMyRows() == int(sg_basis_row_dof_.size())); TEUCHOS_ASSERT(J_k.NumMyCols() == int(sg_basis_col_dof_.size())); const Teuchos::Array<double> & normValues = sg_master_basis_->norm_squared(); // loop over deterministic rows for(int localM=0;localM<J_k.NumMyRows();localM++) { int m = J_k.GRID(localM); // grab row basis Teuchos::RCP<const Stokhos::ProductBasis<int,double> > rowStochBasis = sg_basis_row_dof_[localM]; // grab row from deterministic system int d_numEntries; int * d_Indices; double * d_Values; J_k.ExtractMyRowView(localM,d_numEntries,d_Values,d_Indices); // loop over stochastic degrees of freedom of this row for(int rb_i=0;rb_i<rowStochBasis->size();rb_i++) { int i = sg_master_basis_->index(rowStochBasis->term(rb_i)); double normValue = normValues[i]; // sg_master_basis->norm_squared(i); int sg_m = getGlobalRowId(localM,rb_i); // we wipe out old values, capacity should gurantee // we don't allocate more often than neccessary! std::vector<int> sg_indices; std::vector<double> sg_values; // sg_indices.resize(0); // sg_values.resize(0); // loop over each column for(int colInd=0;colInd<d_numEntries;colInd++) { int localN = d_Indices[colInd]; // grab local deterministic column id // grab row basis Teuchos::RCP<const Stokhos::ProductBasis<int,double> > colStochBasis = sg_basis_col_dof_[localN]; // build values array for(int cb_j=0;cb_j<colStochBasis->size();cb_j++) { int j = sg_master_basis_->index(colStochBasis->term(cb_j)); int sg_n = getGlobalColId(localN,cb_j); double cijk = Cijk.getValue(i,j,k); // no reason to work it in! if(cijk==0) continue; if(scaleOp_) cijk = cijk/normValue; sg_indices.push_back(sg_n); sg_values.push_back(cijk*d_Values[colInd]); } } // add in matrix values A.SumIntoGlobalValues(sg_m,sg_indices.size(),&sg_values[0],&sg_indices[0]); } } }
// rebuild a single subblock Epetra_CrsMatrix void rebuildSubBlock(int i,int j,const Epetra_CrsMatrix & A,const std::vector<std::pair<int,RCP<Epetra_Map> > > & subMaps,Epetra_CrsMatrix & mat) { // get the number of variables families int numVarFamily = subMaps.size(); TEUCHOS_ASSERT(i>=0 && i<numVarFamily); TEUCHOS_ASSERT(j>=0 && j<numVarFamily); TEUCHOS_ASSERT(mat.Filled()); const Epetra_Map & gRowMap = *subMaps[i].second; const Epetra_Map & rowMap = *Teuchos::get_extra_data<RCP<Epetra_Map> >(subMaps[i].second,"contigMap"); int colFamilyCnt = subMaps[j].first; // compute the number of global variables // and the row and column block offset int numGlobalVars = 0; int rowBlockOffset = 0; int colBlockOffset = 0; for(int k=0;k<numVarFamily;k++) { numGlobalVars += subMaps[k].first; // compute block offsets if(k<i) rowBlockOffset += subMaps[k].first; if(k<j) colBlockOffset += subMaps[k].first; } // copy all global rows to here Epetra_Import import(gRowMap,A.RowMap()); Epetra_CrsMatrix localA(Copy,gRowMap,0); localA.Import(A,import,Insert); // clear out the old matrix mat.PutScalar(0.0); // get entry information int numMyRows = rowMap.NumMyElements(); int maxNumEntries = A.GlobalMaxNumEntries(); // for extraction std::vector<int> indices(maxNumEntries); std::vector<double> values(maxNumEntries); // for insertion std::vector<int> colIndices(maxNumEntries); std::vector<double> colValues(maxNumEntries); // insert each row into subblock // let FillComplete handle column distribution for(int localRow=0;localRow<numMyRows;localRow++) { int numEntries = -1; int globalRow = gRowMap.GID(localRow); int contigRow = rowMap.GID(localRow); TEUCHOS_ASSERT(globalRow>=0); TEUCHOS_ASSERT(contigRow>=0); // extract a global row copy int err = localA.ExtractGlobalRowCopy(globalRow, maxNumEntries, numEntries, &values[0], &indices[0]); TEUCHOS_ASSERT(err==0); int numOwnedCols = 0; for(int localCol=0;localCol<numEntries;localCol++) { int globalCol = indices[localCol]; // determinate which block this column ID is in int block = globalCol / numGlobalVars; bool inFamily = true; // test the beginning of the block inFamily &= (block*numGlobalVars+colBlockOffset <= globalCol); inFamily &= ((block*numGlobalVars+colBlockOffset+colFamilyCnt) > globalCol); // is this column in the variable family if(inFamily) { int familyOffset = globalCol-(block*numGlobalVars+colBlockOffset); colIndices[numOwnedCols] = block*colFamilyCnt + familyOffset; colValues[numOwnedCols] = values[localCol]; numOwnedCols++; } } // insert it into the new matrix mat.SumIntoGlobalValues(contigRow,numOwnedCols,&colValues[0],&colIndices[0]); } }
int main(int argc, char *argv[]) { #ifdef EPETRA_MPI MPI_Init(&argc,&argv); Epetra_MpiComm Comm(MPI_COMM_WORLD); #else Epetra_SerialComm Comm; #endif Epetra_Time Time(Comm); // Create the linear problem using the class `Trilinos_Util::CrsMatrixGallery.' // Various matrix examples are supported; please refer to the // Trilinos tutorial for more details. // create Aztec stuff int proc_config[AZ_PROC_SIZE], options[AZ_OPTIONS_SIZE]; #ifdef ML_MPI /* get number of processors and the name of this processor */ AZ_set_proc_config(proc_config, MPI_COMM_WORLD); int proc = proc_config[AZ_node]; int nprocs = proc_config[AZ_N_procs]; #else AZ_set_proc_config(proc_config, AZ_NOT_MPI); int proc = 0; int nprocs = 1; #endif // read in the matrix size FILE *fp = fopen("ExampleMatrices/cantilever2D/data_matrix.txt","r"); int leng; fscanf(fp,"%d",&leng); int num_PDE_eqns=2; int N_grid_pts = leng/num_PDE_eqns; // make a linear distribution of the matrix respecting the blocks size int leng1 = leng/nprocs; int leng2 = leng-leng1*nprocs; if (proc >= leng2) { leng2 += (proc*leng1); } else { leng1++; leng2 = proc*leng1; } int N_update = leng1; int* update = new int[N_update+1]; int i; double *val=NULL; int *bindx=NULL; for (i=0; i<N_update; i++) update[i] = i+leng2; // create the Epetra_CrSMatrix Epetra_Map* StandardMap = new Epetra_Map(leng,N_update,update,0,Comm); Epetra_CrsMatrix* A = new Epetra_CrsMatrix(Copy,*StandardMap,1); AZ_input_msr_matrix("ExampleMatrices/cantilever2D/data_matrix.txt", update, &val, &bindx, N_update, proc_config); for (i=0; i<leng; i++) { int row = update[i]; A->SumIntoGlobalValues(row,1,&(val[i]),&row); A->SumIntoGlobalValues(row,bindx[i+1]-bindx[i],&(val[bindx[i]]),&(bindx[bindx[i]])); } A->TransformToLocal(); // create solution and right-hand side (MultiVectors are fine as well) Epetra_Vector* LHS = new Epetra_Vector(A->OperatorDomainMap()); Epetra_Vector* RHS = new Epetra_Vector(A->OperatorRangeMap()); LHS->Random(); RHS->Random(); // build the epetra linear problem Epetra_LinearProblem Problem(A, LHS, RHS); // Construct a solver object for this problem AztecOO solver(Problem); // =========================== begin of ML part =========================== // create a parameter list for ML options ParameterList MLList; // set defaults for classic smoothed aggregation ML_Epetra::SetDefaults("SA",MLList); MLList.set("aggregation: damping factor", 0.0); // number of relaxation sweeps MLList.set("adaptive: max sweeps", 10); // number of additional null space vectors to compute MLList.set("adaptive: num vectors",2); #if 1 ML_Epetra::MultiLevelPreconditioner* MLPrec = new ML_Epetra::MultiLevelPreconditioner(dynamic_cast<Epetra_RowMatrix&>(*A), MLList, false); // need to allocate and fill the null space (also the // default one, as in this case). This vector is no longer // needed after a call to ComputeAdaptivePreconditioner(). int NullSpaceSize = 2; vector<double> NullSpace((NullSpaceSize*A->NumMyRows())); for (i = 0 ; i < A->NumMyRows() ; ++i) { NullSpace[i] = 1.0; ++i; NullSpace[i] = 0.0; } for (i = A->NumMyRows() ; i < 2*A->NumMyRows() ; ++i) { NullSpace[i] = 0.0; ++i; NullSpace[i] = 1.0; } MLPrec->ComputeAdaptivePreconditioner(NullSpaceSize,&NullSpace[0]); #else ML_Epetra::MultiLevelPreconditioner* MLPrec = new ML_Epetra::MultiLevelPreconditioner(dynamic_cast<Epetra_RowMatrix&>(*A), MLList); #endif // tell AztecOO to use this preconditioner, then solve solver.SetPrecOperator(MLPrec); // =========================== end of ML part ============================= solver.SetAztecOption(AZ_solver, AZ_gmres); solver.SetAztecOption(AZ_output, 32); // solve with 500 iterations and 1e-12 tolerance solver.Iterate(1550, 1e-5); delete MLPrec; // compute the real residual double residual, diff; if( Comm.MyPID()==0 ) { cout << "||b-Ax||_2 = " << residual << endl; cout << "||x_exact - x||_2 = " << diff << endl; cout << "Total Time = " << Time.ElapsedTime() << endl; } #ifdef EPETRA_MPI MPI_Finalize(); #endif return(0); }