void AZ_matvec_mult(double *val, int *indx, int *bindx, int *rpntr, int *cpntr,
                    int *bpntr, double *b, register double *c,
                    int exchange_flag, int *data_org)

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

  c = Ab:
  Sparse (square) overlapped matrix-vector multiply, using the distributed
  variable block row (DVBR) data structure (A = val).

  Author:          Scott A. Hutchinson, SNL, 1421
  =======

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

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

  m:               Number of (block) rows in A.

  val:             Array containing the entries of the matrix. The matrix is
                   stored block-row-by-block-row. Each block entry is dense and
                   stored by columns (VBR).

  indx:            The ith element of indx points to the location in val of the
                   (0,0) entry of the ith block entry. The last element is the
                   number of nonzero entries of matrix A plus one.

  bindx:           Contains the block column indices of the non-zero block
                   entries.

  rpntr:           The ith element of rpntr indicates the first point row in
                   the i'th block row. The last element is the number of block
                   rows plus one.

  cpntr:           The jth element of cpntr indicates the first point column in
                   the jth block column. The last element is the number of
  bpntr:           The ith element of bpntr points to the first block entry of
                   the ith row in bindx. The last element is the number of
                   nonzero blocks of matrix A plus one.

  b:               Contains the vector b.

  c:               Contains the result vector c.

  exchange_flag:   Flag which controls call to exchange_bdry.

  data_org:        Array containing information on the distribution of the
                   matrix to this processor as well as communication parameters
                   (see Aztec User's Guide).

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

{

  /* local variables */

   AZ_MATRIX Amat;
   int proc_config[AZ_PROC_SIZE];
   static int first_time = 1;

   if (exchange_flag != 1) {
      printf("Warning: exchange_flag is no longer used in AZ_matvec_mult().\n");
      printf("         Set to '1' to avoid this message.\n");
   }
   Amat.rpntr      = rpntr;   Amat.cpntr    = cpntr;
   Amat.bpntr      = bpntr;   Amat.bindx    = bindx;
   Amat.indx       = indx;    Amat.val      = val;
   Amat.data_org   = data_org;
   Amat.aux_ival   = NULL;
   Amat.aux_dval   = NULL;
   Amat.aux_matrix = NULL;
   Amat.matrix_type = data_org[AZ_matrix_type];
#ifdef AZTEC_MPI
   AZ_set_comm(proc_config, MPI_COMM_WORLD);
   if (first_time == 1) {
      AZ_set_proc_config(proc_config, MPI_COMM_WORLD);
#else
   if (first_time == 1) {
      AZ_set_proc_config(proc_config, AZ_NOT_MPI);
#endif
      if (proc_config[AZ_node] == 0) {
          printf("Warning: AZ_matvec_mult() should be replaced with either\n");
          printf("          AZ_MSR_matvec_mult or AZ_VBR_matvec_mult()\n");
      }
   }
   first_time = 0;

   if      (Amat.matrix_type == AZ_MSR_MATRIX) Amat.matvec = AZ_MSR_matvec_mult;
   else if (Amat.matrix_type == AZ_VBR_MATRIX) Amat.matvec = AZ_VBR_matvec_mult;

   Amat.matvec(b, c, &Amat, proc_config);
}
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;
       }
   }
      
}
Exemple #3
0
int test_azoo_conv_with_scaling(int conv_option, int scaling_option,
                                const Epetra_Comm& comm, bool verbose)
{
  int localN = 20;
  int numprocs = comm.NumProc();
  int globalN = numprocs*localN;
 
  Epetra_Map emap(globalN, 0, comm);
  Epetra_CrsMatrix* Acrs = create_and_fill_crs_matrix(emap);

  Epetra_Vector x_crs(emap), b_crs(emap);
  x_crs.PutScalar(1.0);

  Acrs->Multiply(false, x_crs, b_crs);
  x_crs.PutScalar(0.0);

  AztecOO azoo(Acrs, &x_crs, &b_crs);
  azoo.SetAztecOption(AZ_conv, conv_option);
  azoo.SetAztecOption(AZ_solver, AZ_cg);
  azoo.SetAztecOption(AZ_scaling, scaling_option);

  azoo.Iterate(100, 1.e-9);

  //now, do the same thing with 'old-fashioned Aztec', and compare
  //the solutions.

    int* proc_config = new int[AZ_PROC_SIZE];

#ifdef EPETRA_MPI
  AZ_set_proc_config(proc_config, MPI_COMM_WORLD);
  AZ_set_comm(proc_config, MPI_COMM_WORLD);
#else
  AZ_set_proc_config(proc_config, 0);
#endif

  int *external, *update_index, *external_index;
  int *external2, *update_index2, *external_index2;
  AZ_MATRIX* Amsr = NULL;
  AZ_MATRIX* Avbr = NULL;
  int err = create_and_transform_simple_matrix(AZ_MSR_MATRIX, localN, 4.0,
                                               proc_config, Amsr,
                                               external, update_index,
                                               external_index);

  int N_update = localN+Amsr->data_org[AZ_N_border];
  double* x_msr = new double[N_update];
  double* b_msr = new double[N_update*2];
  double* b_msr_u = b_msr+N_update;
  double* x_vbr = new double[N_update];
  double* b_vbr = new double[N_update*2];
  double* b_vbr_u = b_vbr+N_update;

  err = create_and_transform_simple_matrix(AZ_VBR_MATRIX, localN, 4.0,
                                           proc_config, Avbr,
                                           external2, update_index2,
                                           external_index2);
  for(int i=0; i<N_update; ++i) {
    x_msr[i] = 1.0;
    b_msr[i] = 0.0;
    b_msr_u[i] = 0.0;
    x_vbr[i] = 1.0;
    b_vbr[i] = 0.0;
    b_vbr_u[i] = 0.0;
  }

  Amsr->matvec(x_msr, b_msr, Amsr, proc_config);
  Avbr->matvec(x_vbr, b_vbr, Avbr, proc_config);

  for(int i=0; i<N_update; ++i) {
    x_msr[i] = 0.0;
    x_vbr[i] = 0.0;
  }

  //check that the rhs's are the same.
  double max_rhs_diff1 = 0.0;
  double max_rhs_diff2 = 0.0;
  double* bptr_crs = b_crs.Values();

  AZ_invorder_vec(b_msr, Amsr->data_org, update_index, NULL, b_msr_u);
  AZ_invorder_vec(b_vbr, Avbr->data_org, update_index2, Avbr->rpntr, b_vbr_u);
  for(int i=0; i<localN; ++i) {
    if (std::abs(bptr_crs[i] - b_msr_u[i]) > max_rhs_diff1) {
      max_rhs_diff1 = std::abs(bptr_crs[i] - b_msr_u[i]);
    }
    if (std::abs(bptr_crs[i] - b_vbr_u[i]) > max_rhs_diff2) {
      max_rhs_diff2 = std::abs(bptr_crs[i] - b_vbr_u[i]);
    }
  }

  if (max_rhs_diff1> 1.e-12) {
    cout << "AztecOO rhs not equal to Aztec msr rhs "<<max_rhs_diff1<<endl;
    return(-1);
  }

  if (max_rhs_diff2> 1.e-12) {
    cout << "AztecOO rhs not equal to Aztec vbr rhs "<<max_rhs_diff2<<endl;
    return(-1);
  }

  int* az_options = new int[AZ_OPTIONS_SIZE];
  double* params = new double[AZ_PARAMS_SIZE];
  double* status = new double[AZ_STATUS_SIZE];
  AZ_defaults(az_options, params);
  az_options[AZ_solver] = AZ_cg;
  az_options[AZ_conv] = conv_option;
  az_options[AZ_scaling] = scaling_option;

  az_options[AZ_max_iter] = 100;
  params[AZ_tol] = 1.e-9;

  AZ_iterate(x_msr, b_msr, az_options, params, status, proc_config,
             Amsr, NULL, NULL);
  AZ_iterate(x_vbr, b_vbr, az_options, params, status, proc_config,
             Avbr, NULL, NULL);

  AZ_invorder_vec(x_msr, Amsr->data_org, update_index, NULL, b_msr_u);
  AZ_invorder_vec(x_vbr, Avbr->data_org, update_index2, Avbr->rpntr, b_vbr_u);

  double max_diff1 = 0.0;
  double max_diff2 = 0.0;
  double* xptr_crs = x_crs.Values();

  for(int i=0; i<localN; ++i) {
    if (std::abs(xptr_crs[i] - b_msr_u[i]) > max_diff1) {
      max_diff1 = std::abs(xptr_crs[i] - b_msr_u[i]);
    }
    if (std::abs(xptr_crs[i] - b_vbr_u[i]) > max_diff2) {
      max_diff2 = std::abs(xptr_crs[i] - b_vbr_u[i]);
    }
  }

  if (max_diff1 > 1.e-7) {
    cout << "AztecOO failed to match Aztec msr with scaling and Anorm conv."
      << endl;
    return(-1);
  }

  if (max_diff2 > 1.e-7) {
    cout << "AztecOO failed to match Aztec vbr with scaling and Anorm conv."
      << endl;
    return(-1);
  }

  delete Acrs;
  delete [] x_msr;
  delete [] b_msr;
  delete [] x_vbr;
  delete [] b_vbr;
  destroy_matrix(Amsr);
  destroy_matrix(Avbr);
  delete [] proc_config;
  free(update_index);
  free(external);
  free(external_index);
  free(update_index2);
  free(external2);
  free(external_index2);
  delete [] az_options;
  delete [] params;
  delete [] status;

  return(0);
}
Exemple #4
0
int test_AZ_iterate_AZ_pre_calc_AZ_reuse(Epetra_Comm& Comm,
                                         int* options,
                                         bool verbose)
{
  (void)Comm;
  if (verbose) {
    cout << "testing AZ_keep_info/AZ_reuse with 'old' Aztec (solver "
         <<options[AZ_solver] <<", precond "<<options[AZ_precond]<<"/"
         << options[AZ_subdomain_solve]<<")"<<endl;
  }

  int* proc_config = new int[AZ_PROC_SIZE];

#ifdef EPETRA_MPI
  AZ_set_proc_config(proc_config, MPI_COMM_WORLD);
  AZ_set_comm(proc_config, MPI_COMM_WORLD);
#else
  AZ_set_proc_config(proc_config, 0);
#endif

  //We're going to create 2 Aztec matrices, one MSR and one VBR. We're going
  //to do 2 solves with each, reusing the preconditioner for the second solve.

  int *external, *update_index, *external_index;
  int *external2, *update_index2, *external_index2;

  int i, N = 5;
  AZ_MATRIX* Amsr = NULL;
  AZ_MATRIX* Avbr = NULL;
  int err = create_and_transform_simple_matrix(AZ_MSR_MATRIX, N, 3.0,
                                               proc_config, Amsr,
                                               external, update_index,
                                               external_index);

  err += create_and_transform_simple_matrix(AZ_VBR_MATRIX, N, 3.0,
                                            proc_config, Avbr,
                                            external2, update_index2,
                                            external_index2);


  int* az_options = new int[AZ_OPTIONS_SIZE];
  double* params = new double[AZ_PARAMS_SIZE];
  double* status = new double[AZ_STATUS_SIZE];
  AZ_defaults(az_options, params);
  az_options[AZ_solver] = options[AZ_solver];
  az_options[AZ_precond] = options[AZ_precond];
  az_options[AZ_subdomain_solve] = options[AZ_subdomain_solve];
  az_options[AZ_scaling] = AZ_sym_diag;
  if (verbose) {
    az_options[AZ_output] = AZ_warnings;
  }
  else {
    az_options[AZ_output] = 0;
  }

  int N_update = N+Amsr->data_org[AZ_N_border];
  double* x = new double[N_update];
  double* b = new double[N_update];

  for(i=0; i<N_update; ++i) {
    x[i] = 0.0;
    b[i] = 1.0;
  }

  AZ_PRECOND* Pmsr = AZ_precond_create(Amsr, AZ_precondition, NULL);
  AZ_SCALING* Smsr = AZ_scaling_create();
  AZ_PRECOND* Pvbr = AZ_precond_create(Avbr, AZ_precondition, NULL);
  AZ_SCALING* Svbr = AZ_scaling_create();

 // Amsr->data_org[AZ_name] = 1;
 // Avbr->data_org[AZ_name] = 2;

  //First solve with the first matrix (Amsr).
  if (verbose)
    cout << "solve Amsr, name: "<<Amsr->data_org[AZ_name]<<endl;

  call_AZ_iterate(Amsr, Pmsr, Smsr, x, b, az_options, params, status,
                  proc_config, 1, AZ_calc, verbose);

  //First solve with the second matrix (Avbr).
  if (verbose)
    cout << "solve Avbr, name: " <<Avbr->data_org[AZ_name]<<endl;

  call_AZ_iterate(Avbr, Pvbr, Svbr, x, b, az_options, params, status,
                  proc_config, 0, AZ_calc, verbose);

  //Second solve with Amsr, reusing preconditioner
  if (verbose)
    cout << "solve Amsr (first reuse)"<<endl;

  call_AZ_iterate(Amsr, Pmsr, Smsr, x, b, az_options, params, status,
                  proc_config, 1, AZ_reuse, verbose);

  //Second solve with Avbr, not reusing preconditioner
  if (verbose)
    cout << "solve Avbr (keepinfo==0), name: " <<Avbr->data_org[AZ_name]<<endl;

  call_AZ_iterate(Avbr, Pvbr, Svbr, x, b, az_options, params, status,
                  proc_config, 0, AZ_calc, verbose);

  if (verbose)
    std::cout << "calling AZ_free_memory..."<<std::endl;

  AZ_free_memory(Amsr->data_org[AZ_name]);
  AZ_free_memory(Avbr->data_org[AZ_name]);

  //solve with Amsr again, not reusing preconditioner
  if (verbose)
    cout << "solve Amsr (keepinfo==0)"<<endl;

  call_AZ_iterate(Amsr, Pmsr, Smsr, x, b, az_options, params, status,
                  proc_config, 0, AZ_calc, verbose);

  //Second solve with Avbr, this time with keepinfo==1
  if (verbose)
    cout << "solve Avbr (keepinfo==1), name: " <<Avbr->data_org[AZ_name]<<endl;

  call_AZ_iterate(Avbr, Pvbr, Svbr, x, b, az_options, params, status,
                  proc_config, 1, AZ_calc, verbose);

  //Second solve with Amsr, not reusing preconditioner
  if (verbose)
    cout << "solve Amsr (keepinfo==0, calc)"<<endl;

  call_AZ_iterate(Amsr, Pmsr, Smsr, x, b, az_options, params, status,
                  proc_config, 0, AZ_calc, verbose);

  //Second solve with Avbr, not reusing preconditioner
  if (verbose)
    cout << "solve Avbr (keepinfo==1, reuse), name: "<<Avbr->data_org[AZ_name]<<endl;

  call_AZ_iterate(Avbr, Pvbr, Svbr, x, b, az_options, params, status,
                  proc_config, 1, AZ_reuse, verbose);

  AZ_free_memory(Amsr->data_org[AZ_name]);
  AZ_free_memory(Avbr->data_org[AZ_name]);

  AZ_scaling_destroy(&Smsr);
  AZ_precond_destroy(&Pmsr);
  AZ_scaling_destroy(&Svbr);
  AZ_precond_destroy(&Pvbr);
  destroy_matrix(Amsr);
  destroy_matrix(Avbr);

  delete [] x;
  delete [] b;

  delete [] az_options;
  delete [] params;
  delete [] status;
  delete [] proc_config;
  free(update_index);
  free(external);
  free(external_index);
  free(update_index2);
  free(external2);
  free(external_index2);

  return(0);
}
Exemple #5
0
int test_AZ_iterate_then_AZ_scale_f(Epetra_Comm& Comm, bool verbose)
{
  (void)Comm;
  if (verbose) {
    cout << "testing AZ_iterate/AZ_scale_f with 'old' Aztec"<<endl;
  }

  int* proc_config = new int[AZ_PROC_SIZE];

#ifdef EPETRA_MPI
  AZ_set_proc_config(proc_config, MPI_COMM_WORLD);
  AZ_set_comm(proc_config, MPI_COMM_WORLD);
#else
  AZ_set_proc_config(proc_config, 0);
#endif

  int *external, *update_index, *external_index;

  int i, N = 5;
  AZ_MATRIX* Amat = NULL;
  int err = create_and_transform_simple_matrix(AZ_MSR_MATRIX, N, 3.0,
                                               proc_config, Amat,
                                                 external, update_index,
                                                 external_index);
  if (err != 0) {
    return(err);
  }
 
  int* options = new int[AZ_OPTIONS_SIZE];
  double* params = new double[AZ_PARAMS_SIZE];
  double* status = new double[AZ_STATUS_SIZE];
  AZ_defaults(options, params);
  options[AZ_scaling] = AZ_sym_diag;
  if (verbose) {
    options[AZ_output] = AZ_warnings;
  }
  else {
    options[AZ_output] = 0;
  }
  
  int N_update = N+Amat->data_org[AZ_N_border];
  double* x = new double[N_update];
  double* b = new double[N_update];

  for(i=0; i<N_update; ++i) {
    x[i] = 0.0;
    b[i] = 1.0;
  }

  AZ_PRECOND* Pmat = AZ_precond_create(Amat, AZ_precondition, NULL);
  AZ_SCALING* Scal = AZ_scaling_create();

  options[AZ_keep_info] = 1;

  AZ_iterate(x, b, options, params, status, proc_config,
             Amat, Pmat, Scal);

  //now set options[AZ_pre_calc] = AZ_reuse and try to call AZ_scale_f.
  options[AZ_pre_calc] = AZ_reuse;

  AZ_scale_f(AZ_SCALE_MAT_RHS_SOL, Amat, options, b, x, proc_config, Scal);

  AZ_scaling_destroy(&Scal);
  AZ_precond_destroy(&Pmat);
  destroy_matrix(Amat);

  delete [] x;
  delete [] b;

  delete [] options;
  delete [] params;
  delete [] status;
  delete [] proc_config;
  free(update_index);
  free(external);
  free(external_index);

  return(0);
}