//==============================================================================
Epetra_MsrMatrix::Epetra_MsrMatrix(int * proc_config, AZ_MATRIX * a_mat)
  : Epetra_Object("Epetra::MsrMatrix"),
    Amat_(a_mat),
    proc_config_(proc_config),
    Values_(0),
    Indices_(0),
    MaxNumEntries_(-1),
    ImportVector_(0),
    NormInf_(-1.0),
    NormOne_(-1.0)
{
#ifdef AZTEC_MPI
  MPI_Comm * mpicomm = (MPI_Comm * ) AZ_get_comm(proc_config);
  Comm_ = new Epetra_MpiComm(*mpicomm);
#else
  Comm_ = new Epetra_SerialComm();
#endif  
  if (a_mat->data_org[AZ_matrix_type]!=AZ_MSR_MATRIX)
    throw Comm_->ReportError("AZ_matrix_type must be AZ_MSR_MATRIX", -1);
  int * bindx = a_mat->bindx;
  NumMyRows_ = a_mat->data_org[AZ_N_internal] + a_mat->data_org[AZ_N_border];
  int NumExternal = a_mat->data_org[AZ_N_external];
  NumMyCols_ = NumMyRows_ + NumExternal;
  NumMyNonzeros_ = bindx[NumMyRows_] - bindx[0] + NumMyRows_;
  //Comm_->SumAll(&NumMyNonzeros_, &NumGlobalNonzeros_, 1);
  long long NumMyNonzerosLL_ = (long long) NumMyNonzeros_;
  Comm_->SumAll(&NumMyNonzerosLL_, &NumGlobalNonzeros_, 1);

  int * MyGlobalElements = a_mat->update;
  if (MyGlobalElements==0) 
    throw Comm_->ReportError("Aztec matrix has no update list: Check if AZ_Transform was called.", -2);

  DomainMap_ = new Epetra_Map(-1, NumMyRows_, MyGlobalElements, 0, *Comm_);

  double * dbleColGIDs = new double[NumMyCols_];
  int * ColGIDs = new int[NumMyCols_];
  for (int i=0; i<NumMyRows_; i++) dbleColGIDs[i] = (double) MyGlobalElements[i];
  AZ_exchange_bdry(dbleColGIDs, a_mat->data_org, proc_config);
  {for (int i=0; i<NumMyCols_; i++) ColGIDs[i] = (int) dbleColGIDs[i];}

  ColMap_ = new Epetra_Map(-1, NumMyCols_, ColGIDs, 0, *Comm_);

  Importer_ = new Epetra_Import(*ColMap_, *DomainMap_);
  
  delete [] dbleColGIDs;
  delete [] ColGIDs;
}
void AZ_solve_subdomain(double x[],int N, struct context *context)
{
/****************************************************************************
  Given a vector 'x' representing the right hand side, solve the system
  using whatever subdomain solver is indicated by 'context->which'
  and whatever factorization information has already been computed.

  Author:          Ray Tuminaro, SNL, 9222 (3/98)

  Return code:     void
  ============

  Parameter list:
  ===============

  x                On input, the right hand side of the subdomain system that
                   is to be solved. 
                   On output, the solution of the subdomain system.

  N                On input, the size of the linear system to be solved.

  bindx2,val2      On input, matrix or factorization information to be used 
                   by the solver. For most schemes, this information is in
                   MSR format. However, the lu and bilu scheme would have
                   this information in another format.
                   Note: additional array information can be passed through
                   context.

  context          On input, the various fields are set to solver specific
                   information corresponding to algorithm parameters as
                   well as a previously done factorization.

*******************************************************************************/

double *val2;
int    *bindx2;
int N_blk_rows;
#ifdef HAVE_AZLU
int ifail;
#endif
int *sub_options, sub_proc_config[AZ_PROC_SIZE], *hold_data_org, *new_data_org;
double *sub_params, *sub_status;
AZ_MATRIX *sub_matrix;
AZ_PRECOND *sub_precond;
struct AZ_SCALING *sub_scaling;
#ifdef AZTEC_MPI
MPI_AZComm  *tptr;
#endif
double *y;
char label[80];
int  t1, t2, t3, i, t4, t5 = 0;

/* Begin Aztec 2.1 mheroux mod */
#ifdef IFPACK
  int ione = 1;
  void *precon;
#endif
/* End Aztec 2.1 mheroux mod */

   val2   = context->A_overlapped->val;
   bindx2 = context->A_overlapped->bindx;

   switch(context->aztec_choices->options[AZ_subdomain_solve]) {

/* Begin Aztec 2.1 mheroux mod */

   case AZ_bilu_ifp:
#ifdef IFPACK
     y = (double *) malloc (N * sizeof(double));
     DCOPY_F77(&N, x, &ione, y, &ione);
     precon = context->precon;
     ifp_apply(precon, N, 1, y, N, x, N);
     free((void *) y);
#endif
     break;

/* End Aztec 2.1 mheroux mod */

   case AZ_bilu:
      N_blk_rows = context->N_blk_rows;

      AZ_lower_triang_vbr_solve(N_blk_rows, context->A_overlapped->cpntr, 
                                context->A_overlapped->bpntr, 
				context->A_overlapped->indx,
                                bindx2, val2, x);

      AZ_upper_triang_vbr_solve(N_blk_rows, context->A_overlapped->cpntr,
                                context->A_overlapped->bpntr, 
				context->A_overlapped->indx, bindx2,
                                val2, x, context->ipvt, context->dblock);
      break;
   case AZ_ilut:
   case AZ_rilu:
   case AZ_ilu:
      AZ_lower_tsolve(x,N, val2, bindx2, context->iu, x ); 
      AZ_upper_tsolve( x, N, val2, bindx2, context->iu);
      break;
   case AZ_icc:
      AZ_lower_icc(bindx2,val2,N,x);
      AZ_upper_icc(bindx2,val2,N,x);
      break;
   case AZ_lu:
#ifdef HAVE_AZLU
      if (N == 0) return;
      else if (N== 1) {
         x[0] *= val2[0];
         ifail = 0;
      }
      else AZ_backsolve(val2, context->pivot,x, bindx2, 
	              context->ha, context->iflag, 
                      &ifail, &(context->N_nz_factors),
		      &N, &N);
#else
    AZ_printf_err("AZ_lu unavailable: configure with --enable-aztecoo-azlu to make available\n");
    exit(1);
#endif
      break;
   default: 
      if (context->aztec_choices->options[AZ_subdomain_solve]
                  >= AZ_SOLVER_PARAMS) {
         AZ_printf_out("ERROR: Unknown subdomain solver %d\n",
                context->aztec_choices->options[AZ_subdomain_solve]);
         exit(1);
       }
       else {
          /* better to put most of this in the factorization */

          AZ_recover_sol_params(context->aztec_choices->options[
			        AZ_subdomain_solve], &sub_options, 
				&sub_params, &sub_status, &sub_matrix, 
			        &sub_precond, &sub_scaling);
          t1 = sub_options[AZ_recursion_level];
          sub_options[AZ_recursion_level]++;

          t2 = sub_options[AZ_output];
          if (context->proc_config[AZ_node] != 0 ) 
             sub_options[AZ_output] = AZ_none;

          t3 = context->proc_config[AZ_MPI_Tag];

          /* fix data_org */

          hold_data_org = context->A_overlapped->data_org;
          new_data_org = (int *) AZ_allocate( sizeof(int) * AZ_send_list );
          if (new_data_org == NULL) {
             AZ_printf_out("Error: Not enough space for subdomain matrix\n");
             exit(1);
          }
          context->A_overlapped->data_org = new_data_org;
          context->A_overlapped->matvec = AZ_MSR_matvec_mult;
          new_data_org[AZ_matrix_type] = AZ_MSR_MATRIX;
          new_data_org[AZ_N_internal]  = N;
          new_data_org[AZ_N_border  ]  = 0;
          new_data_org[AZ_N_external]  = 0;
          new_data_org[AZ_N_int_blk ]  = N;
          new_data_org[AZ_N_bord_blk]  = 0;
          new_data_org[AZ_N_ext_blk ]  = 0;
          new_data_org[AZ_N_neigh   ]  = 0;
          new_data_org[AZ_total_send]  = 0;
          new_data_org[AZ_name      ]  = hold_data_org[AZ_name];
          new_data_org[AZ_internal_use]= 0;
          new_data_org[AZ_N_rows      ]= N;
          sub_precond->Pmat = context->A_overlapped;
          sub_precond->prec_function = AZ_precondition;
       
          sub_proc_config[AZ_node] = 0;
          sub_proc_config[AZ_N_procs] = 1;
#ifdef AZTEC_MPI
          tptr = AZ_get_comm(context->proc_config);
          AZ_set_comm(sub_proc_config, *tptr);
#endif

          sprintf(label,"y in ssolve%d", sub_options[AZ_recursion_level]);
          y = AZ_manage_memory((N+1)*sizeof(double),
                             AZ_ALLOC, AZ_SYS+az_iterate_id, label, &i);

          for (i = 0 ; i < N ; i++ ) y[i] = x[i];
          for (i = 0 ; i < N ; i++ ) x[i] = 0.0;

          t4 = sub_options[AZ_keep_info];
          sub_options[AZ_keep_info] = 1;

          if (context->aztec_choices->options[AZ_pre_calc] >= AZ_reuse) {
             t5 = sub_options[AZ_pre_calc];
             sub_options[AZ_pre_calc] = AZ_sys_reuse;
          }

          AZ_oldsolve(x, y,sub_options,sub_params, sub_status, sub_proc_config,
                       context->A_overlapped, sub_precond, sub_scaling);

          sub_options[AZ_keep_info] = t4;
          if (context->aztec_choices->options[AZ_pre_calc] == AZ_sys_reuse) 
             sub_options[AZ_pre_calc]  = t5;

          sub_options[AZ_recursion_level] = t1;
          sub_options[AZ_output] = t2;
          context->A_overlapped->data_org = hold_data_org;
          AZ_free(new_data_org);
          context->proc_config[AZ_MPI_Tag] = t3;
       }
   }
      
}
Beispiel #3
0
int Aztec2Petra(int * proc_config,
		AZ_MATRIX * Amat, double * az_x, double * az_b,
		Epetra_Comm * & comm,
		Epetra_BlockMap * & map,
		Epetra_RowMatrix * &A,
		Epetra_Vector * & x,
		Epetra_Vector * & b,
		int ** global_indices) {

  bool do_throw = false;

#ifdef EPETRA_NO_32BIT_GLOBAL_INDICES
  do_throw = true;
#else
  do_throw =
    map->GlobalIndicesLongLong() ||
    A->RowMatrixRowMap().GlobalIndicesLongLong();
#endif

  if(do_throw) {
    // We throw rather than let the compiler error out so that the
    // rest of the library is available and all possible tests can run.

    const char* error = "Aztec2Petra: Not available for 64-bit Maps.";
    std::cerr << error << std::endl;
    throw error;
  }

#ifndef EPETRA_NO_32BIT_GLOBAL_INDICES // REMOVE BEGIN
  // If no 32 bit indices, remove the code below using the preprocessor
  // otherwise VbrMatrix functions cause linker issues.

  // Build Epetra_Comm object

#ifdef AZTEC_MPI
    MPI_Comm * mpicomm = (MPI_Comm * ) AZ_get_comm(proc_config);
    comm = (Epetra_Comm *) new Epetra_MpiComm(*mpicomm);
#else
    comm = (Epetra_Comm *) new Epetra_SerialComm();
#endif  

  int * MyGlobalElements, *global_bindx, *update;
  
  if (!Amat->has_global_indices) {
    //create a global bindx
    AZ_revert_to_global(proc_config, Amat, &global_bindx, &update);
    MyGlobalElements = update;
  }
  else // Already have global ordering
    {
      global_bindx = Amat->bindx;
      MyGlobalElements = Amat->update;
      if (MyGlobalElements==0) EPETRA_CHK_ERR(-1);
    }

  // Get matrix information
  int NumMyElements = 0;
  if (Amat->data_org[AZ_matrix_type] == AZ_VBR_MATRIX)
    NumMyElements = Amat->data_org[AZ_N_int_blk] + Amat->data_org[AZ_N_bord_blk];
  else
    NumMyElements = Amat->data_org[AZ_N_internal] + Amat->data_org[AZ_N_border];
  // int NumMyElements = Amat->N_update; // Note: This "official" way does not always work
  int * bpntr = Amat->bpntr;
  int * rpntr = Amat->rpntr;
  int * indx = Amat->indx;
  double * val = Amat->val;

  int NumGlobalElements;
  comm->SumAll(&NumMyElements, &NumGlobalElements, 1);


  // Make ElementSizeList (if VBR) - number of block entries in each block row

  int * ElementSizeList = 0;

  if (Amat->data_org[AZ_matrix_type] == AZ_VBR_MATRIX) {
  
    ElementSizeList = new int[NumMyElements];
    if (ElementSizeList==0) EPETRA_CHK_ERR(-1); // Ran out of memory
    
    for (int i=0; i<NumMyElements; i++) ElementSizeList[i] = rpntr[i+1] - rpntr[i];

#ifdef EPETRA_NO_32BIT_GLOBAL_INDICES
    map = 0;
#else
    map = new Epetra_BlockMap(NumGlobalElements, NumMyElements, MyGlobalElements, 
			     ElementSizeList, 0, *comm);
#endif

    if (map==0) EPETRA_CHK_ERR(-2); // Ran out of memory

    delete [] ElementSizeList;
 
    Epetra_VbrMatrix * AA = new Epetra_VbrMatrix(View, *map, 0);
  
    if (AA==0) EPETRA_CHK_ERR(-3); // Ran out of memory

    /* Add block rows one-at-a-time */
    {for (int i=0; i<NumMyElements; i++) {
      int BlockRow = MyGlobalElements[i];
      int NumBlockEntries = bpntr[i+1] - bpntr[i];
      int *BlockIndices = global_bindx + bpntr[i];
      int ierr = AA->BeginInsertGlobalValues(BlockRow, NumBlockEntries, BlockIndices);
      if (ierr!=0) {
	cerr << "Error in BeginInsertGlobalValues(GlobalBlockRow = " << BlockRow 
	     << ") = " << ierr << endl; 
	EPETRA_CHK_ERR(ierr);
      }
      int LDA = rpntr[i+1] - rpntr[i];
      int NumRows = LDA;
      for (int j=bpntr[i]; j<bpntr[i+1]; j++) {
	int NumCols = (indx[j+1] - indx[j])/LDA;
	double * Values = val + indx[j];
	ierr = AA->SubmitBlockEntry(Values, LDA, NumRows, NumCols);
	if (ierr!=0) {
	  cerr << "Error in SubmitBlockEntry, GlobalBlockRow = " << BlockRow 
	       << "GlobalBlockCol = " << BlockIndices[j] << "Error = " << ierr << endl; 
	  EPETRA_CHK_ERR(ierr);
	}
      }
      ierr = AA->EndSubmitEntries();
      if (ierr!=0) {
	cerr << "Error in EndSubmitEntries(GlobalBlockRow = " << BlockRow 
	     << ") = " << ierr << endl; 
	EPETRA_CHK_ERR(ierr);
      }
    }}  
    int ierr=AA->FillComplete();    
    if (ierr!=0) {
      cerr <<"Error in Epetra_VbrMatrix FillComplete" << ierr << endl;
      EPETRA_CHK_ERR(ierr);
    }
    
    A = dynamic_cast<Epetra_RowMatrix *> (AA); // cast VBR pointer to RowMatrix pointer
  }
  else if  (Amat->data_org[AZ_matrix_type] == AZ_MSR_MATRIX) {
  
    /* Make numNzBlks - number of block entries in each block row */

    int * numNz = new int[NumMyElements];
    for (int i=0; i<NumMyElements; i++) numNz[i] = global_bindx[i+1] - global_bindx[i] + 1;

#ifdef EPETRA_NO_32BIT_GLOBAL_INDICES
    Epetra_Map * map1 = 0;
#else
    Epetra_Map * map1 = new Epetra_Map(NumGlobalElements, NumMyElements,
				     MyGlobalElements, 0, *comm);
#endif

    Epetra_CrsMatrix * AA = new Epetra_CrsMatrix(Copy, *map1, numNz);

    map = (Epetra_BlockMap *) map1; // cast Epetra_Map to Epetra_BlockMap

    /* Add  rows one-at-a-time */

    for (int row=0; row<NumMyElements; row++) {
      double * row_vals = val + global_bindx[row];
      int * col_inds = global_bindx + global_bindx[row];
      int numEntries = global_bindx[row+1] - global_bindx[row];
#ifdef EPETRA_NO_32BIT_GLOBAL_INDICES
      int ierr = 1;
#else
      int ierr = AA->InsertGlobalValues(MyGlobalElements[row], numEntries, row_vals, col_inds);
#endif
      if (ierr!=0) {
	cerr << "Error puting row " << MyGlobalElements[row] << endl;
	EPETRA_CHK_ERR(ierr);
      }
#ifdef EPETRA_NO_32BIT_GLOBAL_INDICES
      ierr = 1;
#else
      ierr = AA->InsertGlobalValues(MyGlobalElements[row], 1, val+row, MyGlobalElements+row);
#endif
      if (ierr!=0) {
	cerr << "Error putting  diagonal" << endl;
	EPETRA_CHK_ERR(ierr);
      }
    }

    int ierr=AA->FillComplete();
    if (ierr!=0) {
      cerr << "Error in Epetra_CrsMatrix_FillComplete" << endl;
      EPETRA_CHK_ERR(ierr);
    }
    A = dynamic_cast<Epetra_RowMatrix *> (AA); // cast CRS pointer to RowMatrix pointer
  }
  else cerr << "Not a supported AZ_MATRIX data type" << endl;


  // Create x vector
  x = new Epetra_Vector(View, *map,az_x);

  
  // RPP: Can not use the OperatorRangeMap in the ctor of the "b" vector 
  // below.  In MPSalsa, we delete the VbrMatrix yet still use the vector "b".
  // Deleting the matrix deletes the OperatorRangeMap that the b vector is 
  // based on.  Losing the map means "b" and all vectors that are created 
  // with the copy constructor of "b" break.  Mike has suggested 
  // using reference counting (Boost smart pointers) so the map is not 
  // deleted.  For now we will use the "map" variable as the base map for "b". 
  //b = new Epetra_Vector (View, A->OperatorRangeMap(), az_b);
  b = new Epetra_Vector (View, *map, az_b);

  *global_indices = 0; // Assume return array will be empty
  if (!Amat->has_global_indices) {
   AZ_free((void *) update);
   if (Amat->data_org[AZ_matrix_type] != AZ_VBR_MATRIX)
     AZ_free((void *) global_bindx);
   else
     global_indices = &global_bindx;
   }
#endif // EPETRA_NO_32BIT_GLOBAL_INDICES REMOVE END

  return 0;
}
Beispiel #4
0
//==============================================================================
Epetra_MsrMatrix::Epetra_MsrMatrix(int * proc_config, AZ_MATRIX * a_mat)
  : Epetra_Object("Epetra::MsrMatrix"),
    Amat_(a_mat),
    proc_config_(proc_config),
    Values_(0),
    Indices_(0),
    MaxNumEntries_(-1),
    ImportVector_(0),
    NormInf_(-1.0),
    NormOne_(-1.0)
{
#ifdef EPETRA_NO_32BIT_GLOBAL_INDICES
  // We throw rather than let the compiler error out so that the
  // rest of the library is available and all possible tests can run.
  const char* error = "Epetra_MsrMatrix::Epetra_MsrMatrix: Not available for 64-bit Maps.";
  std::cerr << error << std::endl;
  throw Comm_->ReportError(error, -2);
#endif

#ifdef AZTEC_MPI
  MPI_Comm * mpicomm = (MPI_Comm * ) AZ_get_comm(proc_config);
  Comm_ = new Epetra_MpiComm(*mpicomm);
#else
  Comm_ = new Epetra_SerialComm();
#endif  
  if (a_mat->data_org[AZ_matrix_type]!=AZ_MSR_MATRIX)
    throw Comm_->ReportError("AZ_matrix_type must be AZ_MSR_MATRIX", -1);
  int * bindx = a_mat->bindx;
  NumMyRows_ = a_mat->data_org[AZ_N_internal] + a_mat->data_org[AZ_N_border];
  int NumExternal = a_mat->data_org[AZ_N_external];
  NumMyCols_ = NumMyRows_ + NumExternal;
  NumMyNonzeros_ = bindx[NumMyRows_] - bindx[0] + NumMyRows_;

#ifndef EPETRA_NO_64BIT_GLOBAL_INDICES
  long long tmp_NumMyNonzeros = NumMyNonzeros_;
  Comm_->SumAll(&tmp_NumMyNonzeros, &NumGlobalNonzeros_, 1);
#else
    int tmp_NumGlobalNonzeros = 0;
    Comm_->SumAll(&NumMyNonzeros_, &tmp_NumGlobalNonzeros, 1);
	NumGlobalNonzeros_ = tmp_NumGlobalNonzeros;
#endif

  int * MyGlobalElements = a_mat->update;
  if (MyGlobalElements==0) 
    throw Comm_->ReportError("Aztec matrix has no update list: Check if AZ_Transform was called.", -2);

#ifdef EPETRA_NO_32BIT_GLOBAL_INDICES
  DomainMap_ = 0;
#else
  DomainMap_ = new Epetra_Map(-1, NumMyRows_, MyGlobalElements, 0, *Comm_);
#endif

  double * dbleColGIDs = new double[NumMyCols_];
  int * ColGIDs = new int[NumMyCols_];
  for (int i=0; i<NumMyRows_; i++) dbleColGIDs[i] = (double) MyGlobalElements[i];
  AZ_exchange_bdry(dbleColGIDs, a_mat->data_org, proc_config);
  {for (int i=0; i<NumMyCols_; i++) ColGIDs[i] = (int) dbleColGIDs[i];}

#ifdef EPETRA_NO_32BIT_GLOBAL_INDICES
  ColMap_ = 0;
#else
  ColMap_ = new Epetra_Map(-1, NumMyCols_, ColGIDs, 0, *Comm_);
#endif

  Importer_ = new Epetra_Import(*ColMap_, *DomainMap_);
  
  delete [] dbleColGIDs;
  delete [] ColGIDs;
}