xref: /petsc/src/ksp/pc/impls/ml/ml.c (revision 6cd78baa48aed50e262496b9c21bb15a766f90bf)
1 
2 /*
3    Provides an interface to the ML smoothed Aggregation
4    Note: Something non-obvious breaks -pc_mg_type ADDITIVE for parallel runs
5                                     Jed Brown, see [PETSC #18321, #18449].
6 */
7 #include <petsc-private/pcimpl.h>   /*I "petscpc.h" I*/
8 #include <../src/ksp/pc/impls/mg/mgimpl.h>                    /*I "petscpcmg.h" I*/
9 #include <../src/mat/impls/aij/seq/aij.h>
10 #include <../src/mat/impls/aij/mpi/mpiaij.h>
11 
12 #include <math.h>
13 EXTERN_C_BEGIN
14 /* HAVE_CONFIG_H flag is required by ML include files */
15 #if !defined(HAVE_CONFIG_H)
16 #define HAVE_CONFIG_H
17 #endif
18 #include <ml_include.h>
19 EXTERN_C_END
20 
21 typedef enum {PCML_NULLSPACE_AUTO,PCML_NULLSPACE_USER,PCML_NULLSPACE_BLOCK,PCML_NULLSPACE_SCALAR} PCMLNullSpaceType;
22 static const char *const PCMLNullSpaceTypes[] = {"AUTO","USER","BLOCK","SCALAR","PCMLNullSpaceType","PCML_NULLSPACE_",0};
23 
24 /* The context (data structure) at each grid level */
25 typedef struct {
26   Vec        x,b,r;           /* global vectors */
27   Mat        A,P,R;
28   KSP        ksp;
29 } GridCtx;
30 
31 /* The context used to input PETSc matrix into ML at fine grid */
32 typedef struct {
33   Mat          A;      /* Petsc matrix in aij format */
34   Mat          Aloc;   /* local portion of A to be used by ML */
35   Vec          x,y;
36   ML_Operator  *mlmat;
37   PetscScalar  *pwork; /* tmp array used by PetscML_comm() */
38 } FineGridCtx;
39 
40 /* The context associates a ML matrix with a PETSc shell matrix */
41 typedef struct {
42   Mat          A;       /* PETSc shell matrix associated with mlmat */
43   ML_Operator  *mlmat;  /* ML matrix assorciated with A */
44   Vec          y, work;
45 } Mat_MLShell;
46 
47 /* Private context for the ML preconditioner */
48 typedef struct {
49   ML                *ml_object;
50   ML_Aggregate      *agg_object;
51   GridCtx           *gridctx;
52   FineGridCtx       *PetscMLdata;
53   PetscInt          Nlevels,MaxNlevels,MaxCoarseSize,CoarsenScheme,EnergyMinimization;
54   PetscReal         Threshold,DampingFactor,EnergyMinimizationDropTol;
55   PetscBool         SpectralNormScheme_Anorm,BlockScaling,EnergyMinimizationCheap,Symmetrize,OldHierarchy,KeepAggInfo,Reusable;
56   PetscBool         reuse_interpolation;
57   PCMLNullSpaceType nulltype;
58   PetscMPIInt       size; /* size of communicator for pc->pmat */
59 } PC_ML;
60 
61 #undef __FUNCT__
62 #define __FUNCT__ "PetscML_getrow"
63 static int PetscML_getrow(ML_Operator *ML_data, int N_requested_rows, int requested_rows[],int allocated_space, int columns[], double values[], int row_lengths[])
64 {
65   PetscErrorCode ierr;
66   PetscInt       m,i,j,k=0,row,*aj;
67   PetscScalar    *aa;
68   FineGridCtx    *ml=(FineGridCtx*)ML_Get_MyGetrowData(ML_data);
69   Mat_SeqAIJ     *a = (Mat_SeqAIJ*)ml->Aloc->data;
70 
71   ierr = MatGetSize(ml->Aloc,&m,PETSC_NULL); if (ierr) return(0);
72   for (i = 0; i<N_requested_rows; i++) {
73     row   = requested_rows[i];
74     row_lengths[i] = a->ilen[row];
75     if (allocated_space < k+row_lengths[i]) return(0);
76     if ( (row >= 0) || (row <= (m-1)) ) {
77       aj = a->j + a->i[row];
78       aa = a->a + a->i[row];
79       for (j=0; j<row_lengths[i]; j++){
80         columns[k]  = aj[j];
81         values[k++] = aa[j];
82       }
83     }
84   }
85   return(1);
86 }
87 
88 #undef __FUNCT__
89 #define __FUNCT__ "PetscML_comm"
90 static PetscErrorCode PetscML_comm(double p[],void *ML_data)
91 {
92   PetscErrorCode ierr;
93   FineGridCtx    *ml=(FineGridCtx*)ML_data;
94   Mat            A=ml->A;
95   Mat_MPIAIJ     *a = (Mat_MPIAIJ*)A->data;
96   PetscMPIInt    size;
97   PetscInt       i,in_length=A->rmap->n,out_length=ml->Aloc->cmap->n;
98   PetscScalar    *array;
99 
100   PetscFunctionBegin;
101   ierr = MPI_Comm_size(((PetscObject)A)->comm,&size);CHKERRQ(ierr);
102   if (size == 1) return 0;
103 
104   ierr = VecPlaceArray(ml->y,p);CHKERRQ(ierr);
105   ierr = VecScatterBegin(a->Mvctx,ml->y,a->lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
106   ierr = VecScatterEnd(a->Mvctx,ml->y,a->lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
107   ierr = VecResetArray(ml->y);CHKERRQ(ierr);
108   ierr = VecGetArray(a->lvec,&array);CHKERRQ(ierr);
109   for (i=in_length; i<out_length; i++){
110     p[i] = array[i-in_length];
111   }
112   ierr = VecRestoreArray(a->lvec,&array);CHKERRQ(ierr);
113   PetscFunctionReturn(0);
114 }
115 
116 #undef __FUNCT__
117 #define __FUNCT__ "PetscML_matvec"
118 static int PetscML_matvec(ML_Operator *ML_data,int in_length,double p[],int out_length,double ap[])
119 {
120   PetscErrorCode ierr;
121   FineGridCtx    *ml=(FineGridCtx*)ML_Get_MyMatvecData(ML_data);
122   Mat            A=ml->A, Aloc=ml->Aloc;
123   PetscMPIInt    size;
124   PetscScalar    *pwork=ml->pwork;
125   PetscInt       i;
126 
127   PetscFunctionBegin;
128   ierr = MPI_Comm_size(((PetscObject)A)->comm,&size);CHKERRQ(ierr);
129   if (size == 1){
130     ierr = VecPlaceArray(ml->x,p);CHKERRQ(ierr);
131   } else {
132     for (i=0; i<in_length; i++) pwork[i] = p[i];
133     PetscML_comm(pwork,ml);
134     ierr = VecPlaceArray(ml->x,pwork);CHKERRQ(ierr);
135   }
136   ierr = VecPlaceArray(ml->y,ap);CHKERRQ(ierr);
137   ierr = MatMult(Aloc,ml->x,ml->y);CHKERRQ(ierr);
138   ierr = VecResetArray(ml->x);CHKERRQ(ierr);
139   ierr = VecResetArray(ml->y);CHKERRQ(ierr);
140   PetscFunctionReturn(0);
141 }
142 
143 #undef __FUNCT__
144 #define __FUNCT__ "MatMult_ML"
145 static PetscErrorCode MatMult_ML(Mat A,Vec x,Vec y)
146 {
147   PetscErrorCode   ierr;
148   Mat_MLShell      *shell;
149   PetscScalar      *xarray,*yarray;
150   PetscInt         x_length,y_length;
151 
152   PetscFunctionBegin;
153   ierr = MatShellGetContext(A,(void **)&shell);CHKERRQ(ierr);
154   ierr = VecGetArray(x,&xarray);CHKERRQ(ierr);
155   ierr = VecGetArray(y,&yarray);CHKERRQ(ierr);
156   x_length = shell->mlmat->invec_leng;
157   y_length = shell->mlmat->outvec_leng;
158   ML_Operator_Apply(shell->mlmat,x_length,xarray,y_length,yarray);
159   ierr = VecRestoreArray(x,&xarray);CHKERRQ(ierr);
160   ierr = VecRestoreArray(y,&yarray);CHKERRQ(ierr);
161   PetscFunctionReturn(0);
162 }
163 
164 #undef __FUNCT__
165 #define __FUNCT__ "MatMultAdd_ML"
166 /* Computes y = w + A * x
167    It is possible that w == y, but not x == y
168 */
169 static PetscErrorCode MatMultAdd_ML(Mat A,Vec x,Vec w,Vec y)
170 {
171   Mat_MLShell   *shell;
172   PetscScalar   *xarray,*yarray;
173   PetscInt       x_length,y_length;
174   PetscErrorCode ierr;
175 
176   PetscFunctionBegin;
177   ierr = MatShellGetContext(A, (void **) &shell);CHKERRQ(ierr);
178   if (y == w) {
179     if (!shell->work) {
180       ierr = VecDuplicate(y, &shell->work);CHKERRQ(ierr);
181     }
182     ierr = VecGetArray(x,           &xarray);CHKERRQ(ierr);
183     ierr = VecGetArray(shell->work, &yarray);CHKERRQ(ierr);
184     x_length = shell->mlmat->invec_leng;
185     y_length = shell->mlmat->outvec_leng;
186     ML_Operator_Apply(shell->mlmat, x_length, xarray, y_length, yarray);
187     ierr = VecRestoreArray(x,           &xarray);CHKERRQ(ierr);
188     ierr = VecRestoreArray(shell->work, &yarray);CHKERRQ(ierr);
189     ierr = VecAXPY(y, 1.0, shell->work);CHKERRQ(ierr);
190   } else {
191     ierr = VecGetArray(x, &xarray);CHKERRQ(ierr);
192     ierr = VecGetArray(y, &yarray);CHKERRQ(ierr);
193     x_length = shell->mlmat->invec_leng;
194     y_length = shell->mlmat->outvec_leng;
195     ML_Operator_Apply(shell->mlmat, x_length, xarray, y_length, yarray);
196     ierr = VecRestoreArray(x, &xarray);CHKERRQ(ierr);
197     ierr = VecRestoreArray(y, &yarray);CHKERRQ(ierr);
198     ierr = VecAXPY(y, 1.0, w);CHKERRQ(ierr);
199   }
200   PetscFunctionReturn(0);
201 }
202 
203 /* newtype is ignored since only handles one case */
204 #undef __FUNCT__
205 #define __FUNCT__ "MatConvert_MPIAIJ_ML"
206 static PetscErrorCode MatConvert_MPIAIJ_ML(Mat A,MatType newtype,MatReuse scall,Mat *Aloc)
207 {
208   PetscErrorCode  ierr;
209   Mat_MPIAIJ      *mpimat=(Mat_MPIAIJ*)A->data;
210   Mat_SeqAIJ      *mat,*a=(Mat_SeqAIJ*)(mpimat->A)->data,*b=(Mat_SeqAIJ*)(mpimat->B)->data;
211   PetscInt        *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j;
212   PetscScalar     *aa=a->a,*ba=b->a,*ca;
213   PetscInt        am=A->rmap->n,an=A->cmap->n,i,j,k;
214   PetscInt        *ci,*cj,ncols;
215 
216   PetscFunctionBegin;
217   if (am != an) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"A must have a square diagonal portion, am: %d != an: %d",am,an);
218 
219   if (scall == MAT_INITIAL_MATRIX){
220     ierr = PetscMalloc((1+am)*sizeof(PetscInt),&ci);CHKERRQ(ierr);
221     ci[0] = 0;
222     for (i=0; i<am; i++){
223       ci[i+1] = ci[i] + (ai[i+1] - ai[i]) + (bi[i+1] - bi[i]);
224     }
225     ierr = PetscMalloc((1+ci[am])*sizeof(PetscInt),&cj);CHKERRQ(ierr);
226     ierr = PetscMalloc((1+ci[am])*sizeof(PetscScalar),&ca);CHKERRQ(ierr);
227 
228     k = 0;
229     for (i=0; i<am; i++){
230       /* diagonal portion of A */
231       ncols = ai[i+1] - ai[i];
232       for (j=0; j<ncols; j++) {
233         cj[k]   = *aj++;
234         ca[k++] = *aa++;
235       }
236       /* off-diagonal portion of A */
237       ncols = bi[i+1] - bi[i];
238       for (j=0; j<ncols; j++) {
239         cj[k]   = an + (*bj); bj++;
240         ca[k++] = *ba++;
241       }
242     }
243     if (k != ci[am]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"k: %d != ci[am]: %d",k,ci[am]);
244 
245     /* put together the new matrix */
246     an = mpimat->A->cmap->n+mpimat->B->cmap->n;
247     ierr = MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,am,an,ci,cj,ca,Aloc);CHKERRQ(ierr);
248 
249     /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */
250     /* Since these are PETSc arrays, change flags to free them as necessary. */
251     mat = (Mat_SeqAIJ*)(*Aloc)->data;
252     mat->free_a       = PETSC_TRUE;
253     mat->free_ij      = PETSC_TRUE;
254 
255     mat->nonew    = 0;
256   } else if (scall == MAT_REUSE_MATRIX){
257     mat=(Mat_SeqAIJ*)(*Aloc)->data;
258     ci = mat->i; cj = mat->j; ca = mat->a;
259     for (i=0; i<am; i++) {
260       /* diagonal portion of A */
261       ncols = ai[i+1] - ai[i];
262       for (j=0; j<ncols; j++) *ca++ = *aa++;
263       /* off-diagonal portion of A */
264       ncols = bi[i+1] - bi[i];
265       for (j=0; j<ncols; j++) *ca++ = *ba++;
266     }
267   } else SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"Invalid MatReuse %d",(int)scall);
268   PetscFunctionReturn(0);
269 }
270 
271 extern PetscErrorCode MatDestroy_Shell(Mat);
272 #undef __FUNCT__
273 #define __FUNCT__ "MatDestroy_ML"
274 static PetscErrorCode MatDestroy_ML(Mat A)
275 {
276   PetscErrorCode ierr;
277   Mat_MLShell    *shell;
278 
279   PetscFunctionBegin;
280   ierr = MatShellGetContext(A,(void **)&shell);CHKERRQ(ierr);
281   ierr = VecDestroy(&shell->y);CHKERRQ(ierr);
282   if (shell->work) {ierr = VecDestroy(&shell->work);CHKERRQ(ierr);}
283   ierr = PetscFree(shell);CHKERRQ(ierr);
284   ierr = MatDestroy_Shell(A);CHKERRQ(ierr);
285   ierr = PetscObjectChangeTypeName((PetscObject)A,0);CHKERRQ(ierr);
286   PetscFunctionReturn(0);
287 }
288 
289 #undef __FUNCT__
290 #define __FUNCT__ "MatWrapML_SeqAIJ"
291 static PetscErrorCode MatWrapML_SeqAIJ(ML_Operator *mlmat,MatReuse reuse,Mat *newmat)
292 {
293   struct ML_CSR_MSRdata *matdata = (struct ML_CSR_MSRdata *)mlmat->data;
294   PetscErrorCode        ierr;
295   PetscInt              m=mlmat->outvec_leng,n=mlmat->invec_leng,*nnz = PETSC_NULL,nz_max;
296   PetscInt              *ml_cols=matdata->columns,*ml_rowptr=matdata->rowptr,*aj,i,j,k;
297   PetscScalar           *ml_vals=matdata->values,*aa;
298 
299   PetscFunctionBegin;
300   if (!mlmat->getrow) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"mlmat->getrow = NULL");
301   if (m != n){ /* ML Pmat and Rmat are in CSR format. Pass array pointers into SeqAIJ matrix */
302     if (reuse){
303       Mat_SeqAIJ  *aij= (Mat_SeqAIJ*)(*newmat)->data;
304       aij->i = ml_rowptr;
305       aij->j = ml_cols;
306       aij->a = ml_vals;
307     } else {
308       /* sort ml_cols and ml_vals */
309       ierr = PetscMalloc((m+1)*sizeof(PetscInt),&nnz);
310       for (i=0; i<m; i++) {
311         nnz[i] = ml_rowptr[i+1] - ml_rowptr[i];
312       }
313       aj = ml_cols; aa = ml_vals;
314       for (i=0; i<m; i++){
315         ierr = PetscSortIntWithScalarArray(nnz[i],aj,aa);CHKERRQ(ierr);
316         aj += nnz[i]; aa += nnz[i];
317       }
318       ierr = MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,m,n,ml_rowptr,ml_cols,ml_vals,newmat);CHKERRQ(ierr);
319       ierr = PetscFree(nnz);CHKERRQ(ierr);
320     }
321     PetscFunctionReturn(0);
322   }
323 
324   /* ML Amat is in MSR format. Copy its data into SeqAIJ matrix */
325   if (reuse) {
326     for (nz_max=0,i=0; i<m; i++) nz_max = PetscMax(nz_max,ml_cols[i+1] - ml_cols[i] + 1);
327   } else {
328     ierr = MatCreate(PETSC_COMM_SELF,newmat);CHKERRQ(ierr);
329     ierr = MatSetSizes(*newmat,m,n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
330     ierr = MatSetType(*newmat,MATSEQAIJ);CHKERRQ(ierr);
331 
332     ierr = PetscMalloc((m+1)*sizeof(PetscInt),&nnz);
333     nz_max = 1;
334     for (i=0; i<m; i++) {
335       nnz[i] = ml_cols[i+1] - ml_cols[i] + 1;
336       if (nnz[i] > nz_max) nz_max = nnz[i];
337     }
338     ierr = MatSeqAIJSetPreallocation(*newmat,0,nnz);CHKERRQ(ierr);
339   }
340   ierr = PetscMalloc2(nz_max,PetscScalar,&aa,nz_max,PetscInt,&aj);CHKERRQ(ierr);
341   for (i=0; i<m; i++) {
342     PetscInt ncols;
343     k = 0;
344     /* diagonal entry */
345     aj[k] = i; aa[k++] = ml_vals[i];
346     /* off diagonal entries */
347     for (j=ml_cols[i]; j<ml_cols[i+1]; j++){
348       aj[k] = ml_cols[j]; aa[k++] = ml_vals[j];
349     }
350     ncols = ml_cols[i+1] - ml_cols[i] + 1;
351     /* sort aj and aa */
352     ierr = PetscSortIntWithScalarArray(ncols,aj,aa);CHKERRQ(ierr);
353     ierr = MatSetValues(*newmat,1,&i,ncols,aj,aa,INSERT_VALUES);CHKERRQ(ierr);
354   }
355   ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
356   ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
357 
358   ierr = PetscFree2(aa,aj);CHKERRQ(ierr);
359   ierr = PetscFree(nnz);CHKERRQ(ierr);
360   PetscFunctionReturn(0);
361 }
362 
363 #undef __FUNCT__
364 #define __FUNCT__ "MatWrapML_SHELL"
365 static PetscErrorCode MatWrapML_SHELL(ML_Operator *mlmat,MatReuse reuse,Mat *newmat)
366 {
367   PetscErrorCode ierr;
368   PetscInt       m,n;
369   ML_Comm        *MLcomm;
370   Mat_MLShell    *shellctx;
371 
372   PetscFunctionBegin;
373   m = mlmat->outvec_leng;
374   n = mlmat->invec_leng;
375 
376   if (reuse){
377     ierr = MatShellGetContext(*newmat,(void **)&shellctx);CHKERRQ(ierr);
378     shellctx->mlmat = mlmat;
379     PetscFunctionReturn(0);
380   }
381 
382   MLcomm = mlmat->comm;
383   ierr = PetscNew(Mat_MLShell,&shellctx);CHKERRQ(ierr);
384   ierr = MatCreateShell(MLcomm->USR_comm,m,n,PETSC_DETERMINE,PETSC_DETERMINE,shellctx,newmat);CHKERRQ(ierr);
385   ierr = MatShellSetOperation(*newmat,MATOP_MULT,(void(*)(void))MatMult_ML);CHKERRQ(ierr);
386   ierr = MatShellSetOperation(*newmat,MATOP_MULT_ADD,(void(*)(void))MatMultAdd_ML);CHKERRQ(ierr);
387   shellctx->A         = *newmat;
388   shellctx->mlmat     = mlmat;
389   shellctx->work      = PETSC_NULL;
390   ierr = VecCreate(MLcomm->USR_comm,&shellctx->y);CHKERRQ(ierr);
391   ierr = VecSetSizes(shellctx->y,m,PETSC_DECIDE);CHKERRQ(ierr);
392   ierr = VecSetFromOptions(shellctx->y);CHKERRQ(ierr);
393   (*newmat)->ops->destroy = MatDestroy_ML;
394   PetscFunctionReturn(0);
395 }
396 
397 #undef __FUNCT__
398 #define __FUNCT__ "MatWrapML_MPIAIJ"
399 static PetscErrorCode MatWrapML_MPIAIJ(ML_Operator *mlmat,MatReuse reuse,Mat *newmat)
400 {
401   struct ML_CSR_MSRdata *matdata = (struct ML_CSR_MSRdata *)mlmat->data;
402   PetscInt              *ml_cols=matdata->columns,*aj;
403   PetscScalar           *ml_vals=matdata->values,*aa;
404   PetscErrorCode        ierr;
405   PetscInt              i,j,k,*gordering;
406   PetscInt              m=mlmat->outvec_leng,n,nz_max,row;
407   Mat                   A;
408 
409   PetscFunctionBegin;
410   if (!mlmat->getrow) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"mlmat->getrow = NULL");
411   n = mlmat->invec_leng;
412   if (m != n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"m %d must equal to n %d",m,n);
413 
414   if (reuse) {
415     A = *newmat;
416     for (nz_max=0,i=0; i<m; i++) nz_max = PetscMax(nz_max,ml_cols[i+1] - ml_cols[i] + 1);
417   } else {
418     PetscInt *nnzA,*nnzB,*nnz;
419     ierr = MatCreate(mlmat->comm->USR_comm,&A);CHKERRQ(ierr);
420     ierr = MatSetSizes(A,m,n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
421     ierr = MatSetType(A,MATMPIAIJ);CHKERRQ(ierr);
422     ierr = PetscMalloc3(m,PetscInt,&nnzA,m,PetscInt,&nnzB,m,PetscInt,&nnz);CHKERRQ(ierr);
423 
424     nz_max = 0;
425     for (i=0; i<m; i++){
426       nnz[i] = ml_cols[i+1] - ml_cols[i] + 1;
427       if (nz_max < nnz[i]) nz_max = nnz[i];
428       nnzA[i] = 1; /* diag */
429       for (j=ml_cols[i]; j<ml_cols[i+1]; j++){
430         if (ml_cols[j] < m) nnzA[i]++;
431       }
432       nnzB[i] = nnz[i] - nnzA[i];
433     }
434     ierr = MatMPIAIJSetPreallocation(A,0,nnzA,0,nnzB);CHKERRQ(ierr);
435     ierr = PetscFree3(nnzA,nnzB,nnz);
436   }
437 
438   /* insert mat values -- remap row and column indices */
439   nz_max++;
440   ierr = PetscMalloc2(nz_max,PetscScalar,&aa,nz_max,PetscInt,&aj);CHKERRQ(ierr);
441   /* create global row numbering for a ML_Operator */
442   ML_build_global_numbering(mlmat,&gordering,"rows");
443   for (i=0; i<m; i++) {
444     PetscInt ncols;
445     row = gordering[i];
446     k = 0;
447     /* diagonal entry */
448     aj[k] = row; aa[k++] = ml_vals[i];
449     /* off diagonal entries */
450     for (j=ml_cols[i]; j<ml_cols[i+1]; j++){
451       aj[k] = gordering[ml_cols[j]]; aa[k++] = ml_vals[j];
452     }
453     ncols = ml_cols[i+1] - ml_cols[i] + 1;
454     ierr = MatSetValues(A,1,&row,ncols,aj,aa,INSERT_VALUES);CHKERRQ(ierr);
455   }
456   ML_free(gordering);
457   ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
458   ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
459   *newmat = A;
460 
461   ierr = PetscFree2(aa,aj);CHKERRQ(ierr);
462   PetscFunctionReturn(0);
463 }
464 
465 /* -----------------------------------------------------------------------------*/
466 #undef __FUNCT__
467 #define __FUNCT__ "PCReset_ML"
468 PetscErrorCode PCReset_ML(PC pc)
469 {
470   PetscErrorCode  ierr;
471   PC_MG           *mg = (PC_MG*)pc->data;
472   PC_ML           *pc_ml = (PC_ML*)mg->innerctx;
473   PetscInt        level,fine_level=pc_ml->Nlevels-1;
474 
475   PetscFunctionBegin;
476   ML_Aggregate_Destroy(&pc_ml->agg_object);
477   ML_Destroy(&pc_ml->ml_object);
478 
479   if (pc_ml->PetscMLdata) {
480     ierr = PetscFree(pc_ml->PetscMLdata->pwork);CHKERRQ(ierr);
481     ierr = MatDestroy(&pc_ml->PetscMLdata->Aloc);CHKERRQ(ierr);
482     ierr = VecDestroy(&pc_ml->PetscMLdata->x);CHKERRQ(ierr);
483     ierr = VecDestroy(&pc_ml->PetscMLdata->y);CHKERRQ(ierr);
484   }
485   ierr = PetscFree(pc_ml->PetscMLdata);CHKERRQ(ierr);
486 
487   if (pc_ml->gridctx) {
488     for (level=0; level<fine_level; level++){
489       if (pc_ml->gridctx[level].A){ierr = MatDestroy(&pc_ml->gridctx[level].A);CHKERRQ(ierr);}
490       if (pc_ml->gridctx[level].P){ierr = MatDestroy(&pc_ml->gridctx[level].P);CHKERRQ(ierr);}
491       if (pc_ml->gridctx[level].R){ierr = MatDestroy(&pc_ml->gridctx[level].R);CHKERRQ(ierr);}
492       if (pc_ml->gridctx[level].x){ierr = VecDestroy(&pc_ml->gridctx[level].x);CHKERRQ(ierr);}
493       if (pc_ml->gridctx[level].b){ierr = VecDestroy(&pc_ml->gridctx[level].b);CHKERRQ(ierr);}
494       if (pc_ml->gridctx[level+1].r){ierr = VecDestroy(&pc_ml->gridctx[level+1].r);CHKERRQ(ierr);}
495     }
496   }
497   ierr = PetscFree(pc_ml->gridctx);CHKERRQ(ierr);
498   PetscFunctionReturn(0);
499 }
500 /* -------------------------------------------------------------------------- */
501 /*
502    PCSetUp_ML - Prepares for the use of the ML preconditioner
503                     by setting data structures and options.
504 
505    Input Parameter:
506 .  pc - the preconditioner context
507 
508    Application Interface Routine: PCSetUp()
509 
510    Notes:
511    The interface routine PCSetUp() is not usually called directly by
512    the user, but instead is called by PCApply() if necessary.
513 */
514 extern PetscErrorCode PCSetFromOptions_MG(PC);
515 extern PetscErrorCode PCReset_MG(PC);
516 
517 #undef __FUNCT__
518 #define __FUNCT__ "PCSetUp_ML"
519 PetscErrorCode PCSetUp_ML(PC pc)
520 {
521   PetscErrorCode  ierr;
522   PetscMPIInt     size;
523   FineGridCtx     *PetscMLdata;
524   ML              *ml_object;
525   ML_Aggregate    *agg_object;
526   ML_Operator     *mlmat;
527   PetscInt        nlocal_allcols,Nlevels,mllevel,level,level1,m,fine_level,bs;
528   Mat             A,Aloc;
529   GridCtx         *gridctx;
530   PC_MG           *mg = (PC_MG*)pc->data;
531   PC_ML           *pc_ml = (PC_ML*)mg->innerctx;
532   PetscBool       isSeq, isMPI;
533   KSP             smoother;
534   PC              subpc;
535   PetscInt        mesh_level, old_mesh_level;
536 
537   PetscFunctionBegin;
538   A = pc->pmat;
539   ierr = MPI_Comm_size(((PetscObject)A)->comm,&size);CHKERRQ(ierr);
540 
541   if (pc->setupcalled) {
542     if (pc->flag == SAME_NONZERO_PATTERN && pc_ml->reuse_interpolation) {
543       /*
544        Reuse interpolaton instead of recomputing aggregates and updating the whole hierarchy. This is less expensive for
545        multiple solves in which the matrix is not changing too quickly.
546        */
547       ml_object = pc_ml->ml_object;
548       gridctx = pc_ml->gridctx;
549       Nlevels = pc_ml->Nlevels;
550       fine_level = Nlevels - 1;
551       gridctx[fine_level].A = A;
552 
553       ierr = PetscObjectTypeCompare((PetscObject) A, MATSEQAIJ, &isSeq);CHKERRQ(ierr);
554       ierr = PetscObjectTypeCompare((PetscObject) A, MATMPIAIJ, &isMPI);CHKERRQ(ierr);
555       if (isMPI){
556         ierr = MatConvert_MPIAIJ_ML(A,PETSC_NULL,MAT_INITIAL_MATRIX,&Aloc);CHKERRQ(ierr);
557       } else if (isSeq) {
558         Aloc = A;
559         ierr = PetscObjectReference((PetscObject)Aloc);CHKERRQ(ierr);
560       } else SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG, "Matrix type '%s' cannot be used with ML. ML can only handle AIJ matrices.",((PetscObject)A)->type_name);
561 
562       ierr = MatGetSize(Aloc,&m,&nlocal_allcols);CHKERRQ(ierr);
563       PetscMLdata = pc_ml->PetscMLdata;
564       ierr = MatDestroy(&PetscMLdata->Aloc);CHKERRQ(ierr);
565       PetscMLdata->A    = A;
566       PetscMLdata->Aloc = Aloc;
567       ML_Init_Amatrix(ml_object,0,m,m,PetscMLdata);
568       ML_Set_Amatrix_Matvec(ml_object,0,PetscML_matvec);
569 
570       mesh_level = ml_object->ML_finest_level;
571       while (ml_object->SingleLevel[mesh_level].Rmat->to) {
572         old_mesh_level = mesh_level;
573         mesh_level = ml_object->SingleLevel[mesh_level].Rmat->to->levelnum;
574 
575         /* clean and regenerate A */
576         mlmat = &(ml_object->Amat[mesh_level]);
577         ML_Operator_Clean(mlmat);
578         ML_Operator_Init(mlmat,ml_object->comm);
579         ML_Gen_AmatrixRAP(ml_object, old_mesh_level, mesh_level);
580       }
581 
582       level = fine_level - 1;
583       if (size == 1) { /* convert ML P, R and A into seqaij format */
584         for (mllevel=1; mllevel<Nlevels; mllevel++){
585           mlmat = &(ml_object->Amat[mllevel]);
586           ierr = MatWrapML_SeqAIJ(mlmat,MAT_REUSE_MATRIX,&gridctx[level].A);CHKERRQ(ierr);
587           level--;
588         }
589       } else { /* convert ML P and R into shell format, ML A into mpiaij format */
590         for (mllevel=1; mllevel<Nlevels; mllevel++){
591           mlmat  = &(ml_object->Amat[mllevel]);
592           ierr = MatWrapML_MPIAIJ(mlmat,MAT_REUSE_MATRIX,&gridctx[level].A);CHKERRQ(ierr);
593           level--;
594         }
595       }
596 
597       for (level=0; level<fine_level; level++) {
598         if (level > 0){
599           ierr = PCMGSetResidual(pc,level,PCMGDefaultResidual,gridctx[level].A);CHKERRQ(ierr);
600         }
601         ierr = KSPSetOperators(gridctx[level].ksp,gridctx[level].A,gridctx[level].A,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
602       }
603       ierr = PCMGSetResidual(pc,fine_level,PCMGDefaultResidual,gridctx[fine_level].A);CHKERRQ(ierr);
604       ierr = KSPSetOperators(gridctx[fine_level].ksp,gridctx[level].A,gridctx[fine_level].A,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
605 
606       ierr = PCSetUp_MG(pc);CHKERRQ(ierr);
607       PetscFunctionReturn(0);
608     } else {
609       /* since ML can change the size of vectors/matrices at any level we must destroy everything */
610       ierr = PCReset_ML(pc);CHKERRQ(ierr);
611       ierr = PCReset_MG(pc);CHKERRQ(ierr);
612     }
613   }
614 
615   /* setup special features of PCML */
616   /*--------------------------------*/
617   /* covert A to Aloc to be used by ML at fine grid */
618   pc_ml->size = size;
619   ierr = PetscObjectTypeCompare((PetscObject) A, MATSEQAIJ, &isSeq);CHKERRQ(ierr);
620   ierr = PetscObjectTypeCompare((PetscObject) A, MATMPIAIJ, &isMPI);CHKERRQ(ierr);
621   if (isMPI){
622     ierr = MatConvert_MPIAIJ_ML(A,PETSC_NULL,MAT_INITIAL_MATRIX,&Aloc);CHKERRQ(ierr);
623   } else if (isSeq) {
624     Aloc = A;
625     ierr = PetscObjectReference((PetscObject)Aloc);CHKERRQ(ierr);
626   } else SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG, "Matrix type '%s' cannot be used with ML. ML can only handle AIJ matrices.",((PetscObject)A)->type_name);
627 
628   /* create and initialize struct 'PetscMLdata' */
629   ierr = PetscNewLog(pc,FineGridCtx,&PetscMLdata);CHKERRQ(ierr);
630   pc_ml->PetscMLdata = PetscMLdata;
631   ierr = PetscMalloc((Aloc->cmap->n+1)*sizeof(PetscScalar),&PetscMLdata->pwork);CHKERRQ(ierr);
632 
633   ierr = VecCreate(PETSC_COMM_SELF,&PetscMLdata->x);CHKERRQ(ierr);
634   ierr = VecSetSizes(PetscMLdata->x,Aloc->cmap->n,Aloc->cmap->n);CHKERRQ(ierr);
635   ierr = VecSetType(PetscMLdata->x,VECSEQ);CHKERRQ(ierr);
636 
637   ierr = VecCreate(PETSC_COMM_SELF,&PetscMLdata->y);CHKERRQ(ierr);
638   ierr = VecSetSizes(PetscMLdata->y,A->rmap->n,PETSC_DECIDE);CHKERRQ(ierr);
639   ierr = VecSetType(PetscMLdata->y,VECSEQ);CHKERRQ(ierr);
640   PetscMLdata->A    = A;
641   PetscMLdata->Aloc = Aloc;
642 
643   /* create ML discretization matrix at fine grid */
644   /* ML requires input of fine-grid matrix. It determines nlevels. */
645   ierr = MatGetSize(Aloc,&m,&nlocal_allcols);CHKERRQ(ierr);
646   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
647   ML_Create(&ml_object,pc_ml->MaxNlevels);
648   ML_Comm_Set_UsrComm(ml_object->comm,((PetscObject)A)->comm);
649   pc_ml->ml_object = ml_object;
650   ML_Init_Amatrix(ml_object,0,m,m,PetscMLdata);
651   ML_Set_Amatrix_Getrow(ml_object,0,PetscML_getrow,PetscML_comm,nlocal_allcols);
652   ML_Set_Amatrix_Matvec(ml_object,0,PetscML_matvec);
653 
654   ML_Set_Symmetrize(ml_object,pc_ml->Symmetrize ? ML_YES : ML_NO);
655 
656   /* aggregation */
657   ML_Aggregate_Create(&agg_object);
658   pc_ml->agg_object = agg_object;
659 
660   {
661     MatNullSpace mnull;
662     ierr = MatGetNearNullSpace(A,&mnull);CHKERRQ(ierr);
663     if (pc_ml->nulltype == PCML_NULLSPACE_AUTO) {
664       if (mnull) pc_ml->nulltype = PCML_NULLSPACE_USER;
665       else if (bs > 1) pc_ml->nulltype = PCML_NULLSPACE_BLOCK;
666       else pc_ml->nulltype = PCML_NULLSPACE_SCALAR;
667     }
668     switch (pc_ml->nulltype) {
669     case PCML_NULLSPACE_USER: {
670       PetscScalar *nullvec;
671       const PetscScalar *v;
672       PetscBool has_const;
673       PetscInt i,j,mlocal,nvec,M;
674       const Vec *vecs;
675       if (!mnull) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_USER,"Must provide explicit null space using MatSetNearNullSpace() to use user-specified null space");
676       ierr = MatGetSize(A,&M,PETSC_NULL);CHKERRQ(ierr);
677       ierr = MatGetLocalSize(Aloc,&mlocal,PETSC_NULL);CHKERRQ(ierr);
678       ierr = MatNullSpaceGetVecs(mnull,&has_const,&nvec,&vecs);CHKERRQ(ierr);
679       ierr = PetscMalloc((nvec+!!has_const)*mlocal*sizeof *nullvec,&nullvec);CHKERRQ(ierr);
680       if (has_const) for (i=0; i<mlocal; i++) nullvec[i] = 1.0/M;
681       for (i=0; i<nvec; i++) {
682         ierr = VecGetArrayRead(vecs[i],&v);CHKERRQ(ierr);
683         for (j=0; j<mlocal; j++) nullvec[(i+!!has_const)*mlocal + j] = v[j];
684         ierr = VecRestoreArrayRead(vecs[i],&v);CHKERRQ(ierr);
685       }
686       ierr = ML_Aggregate_Set_NullSpace(agg_object,bs,nvec+!!has_const,nullvec,mlocal);CHKERRQ(ierr);
687       ierr = PetscFree(nullvec);CHKERRQ(ierr);
688     } break;
689     case PCML_NULLSPACE_BLOCK:
690       ierr = ML_Aggregate_Set_NullSpace(agg_object,bs,bs,0,0);CHKERRQ(ierr);
691       break;
692     case PCML_NULLSPACE_SCALAR:
693       break;
694     default: SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Unknown null space type");
695     }
696   }
697   ML_Aggregate_Set_MaxCoarseSize(agg_object,pc_ml->MaxCoarseSize);
698   /* set options */
699   switch (pc_ml->CoarsenScheme) {
700   case 1:
701     ML_Aggregate_Set_CoarsenScheme_Coupled(agg_object);break;
702   case 2:
703     ML_Aggregate_Set_CoarsenScheme_MIS(agg_object);break;
704   case 3:
705     ML_Aggregate_Set_CoarsenScheme_METIS(agg_object);break;
706   }
707   ML_Aggregate_Set_Threshold(agg_object,pc_ml->Threshold);
708   ML_Aggregate_Set_DampingFactor(agg_object,pc_ml->DampingFactor);
709   if (pc_ml->SpectralNormScheme_Anorm){
710     ML_Set_SpectralNormScheme_Anorm(ml_object);
711   }
712   agg_object->keep_agg_information      = (int)pc_ml->KeepAggInfo;
713   agg_object->keep_P_tentative          = (int)pc_ml->Reusable;
714   agg_object->block_scaled_SA           = (int)pc_ml->BlockScaling;
715   agg_object->minimizing_energy         = (int)pc_ml->EnergyMinimization;
716   agg_object->minimizing_energy_droptol = (double)pc_ml->EnergyMinimizationDropTol;
717   agg_object->cheap_minimizing_energy   = (int)pc_ml->EnergyMinimizationCheap;
718 
719   if (pc_ml->OldHierarchy) {
720     Nlevels = ML_Gen_MGHierarchy_UsingAggregation(ml_object,0,ML_INCREASING,agg_object);
721   } else {
722     Nlevels = ML_Gen_MultiLevelHierarchy_UsingAggregation(ml_object,0,ML_INCREASING,agg_object);
723   }
724   if (Nlevels<=0) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Nlevels %d must > 0",Nlevels);
725   pc_ml->Nlevels = Nlevels;
726   fine_level = Nlevels - 1;
727 
728   ierr = PCMGSetLevels(pc,Nlevels,PETSC_NULL);CHKERRQ(ierr);
729   /* set default smoothers */
730   for (level=1; level<=fine_level; level++){
731     if (size == 1){
732       ierr = PCMGGetSmoother(pc,level,&smoother);CHKERRQ(ierr);
733       ierr = KSPSetType(smoother,KSPRICHARDSON);CHKERRQ(ierr);
734       ierr = KSPGetPC(smoother,&subpc);CHKERRQ(ierr);
735       ierr = PCSetType(subpc,PCSOR);CHKERRQ(ierr);
736     } else {
737       ierr = PCMGGetSmoother(pc,level,&smoother);CHKERRQ(ierr);
738       ierr = KSPSetType(smoother,KSPRICHARDSON);CHKERRQ(ierr);
739       ierr = KSPGetPC(smoother,&subpc);CHKERRQ(ierr);
740       ierr = PCSetType(subpc,PCSOR);CHKERRQ(ierr);
741     }
742   }
743   ierr = PCSetFromOptions_MG(pc);CHKERRQ(ierr); /* should be called in PCSetFromOptions_ML(), but cannot be called prior to PCMGSetLevels() */
744 
745   ierr = PetscMalloc(Nlevels*sizeof(GridCtx),&gridctx);CHKERRQ(ierr);
746   pc_ml->gridctx = gridctx;
747 
748   /* wrap ML matrices by PETSc shell matrices at coarsened grids.
749      Level 0 is the finest grid for ML, but coarsest for PETSc! */
750   gridctx[fine_level].A = A;
751 
752   level = fine_level - 1;
753   if (size == 1){ /* convert ML P, R and A into seqaij format */
754     for (mllevel=1; mllevel<Nlevels; mllevel++){
755       mlmat = &(ml_object->Pmat[mllevel]);
756       ierr  = MatWrapML_SeqAIJ(mlmat,MAT_INITIAL_MATRIX,&gridctx[level].P);CHKERRQ(ierr);
757       mlmat = &(ml_object->Rmat[mllevel-1]);
758       ierr  = MatWrapML_SeqAIJ(mlmat,MAT_INITIAL_MATRIX,&gridctx[level].R);CHKERRQ(ierr);
759 
760       mlmat = &(ml_object->Amat[mllevel]);
761       ierr  = MatWrapML_SeqAIJ(mlmat,MAT_INITIAL_MATRIX,&gridctx[level].A);CHKERRQ(ierr);
762       level--;
763     }
764   } else { /* convert ML P and R into shell format, ML A into mpiaij format */
765     for (mllevel=1; mllevel<Nlevels; mllevel++){
766       mlmat  = &(ml_object->Pmat[mllevel]);
767       ierr = MatWrapML_SHELL(mlmat,MAT_INITIAL_MATRIX,&gridctx[level].P);CHKERRQ(ierr);
768       mlmat  = &(ml_object->Rmat[mllevel-1]);
769       ierr = MatWrapML_SHELL(mlmat,MAT_INITIAL_MATRIX,&gridctx[level].R);CHKERRQ(ierr);
770 
771       mlmat  = &(ml_object->Amat[mllevel]);
772       ierr = MatWrapML_MPIAIJ(mlmat,MAT_INITIAL_MATRIX,&gridctx[level].A);CHKERRQ(ierr);
773       level--;
774     }
775   }
776 
777   /* create vectors and ksp at all levels */
778   for (level=0; level<fine_level; level++){
779     level1 = level + 1;
780     ierr = VecCreate(((PetscObject)gridctx[level].A)->comm,&gridctx[level].x);CHKERRQ(ierr);
781     ierr = VecSetSizes(gridctx[level].x,gridctx[level].A->cmap->n,PETSC_DECIDE);CHKERRQ(ierr);
782     ierr = VecSetType(gridctx[level].x,VECMPI);CHKERRQ(ierr);
783     ierr = PCMGSetX(pc,level,gridctx[level].x);CHKERRQ(ierr);
784 
785     ierr = VecCreate(((PetscObject)gridctx[level].A)->comm,&gridctx[level].b);CHKERRQ(ierr);
786     ierr = VecSetSizes(gridctx[level].b,gridctx[level].A->rmap->n,PETSC_DECIDE);CHKERRQ(ierr);
787     ierr = VecSetType(gridctx[level].b,VECMPI);CHKERRQ(ierr);
788     ierr = PCMGSetRhs(pc,level,gridctx[level].b);CHKERRQ(ierr);
789 
790     ierr = VecCreate(((PetscObject)gridctx[level1].A)->comm,&gridctx[level1].r);CHKERRQ(ierr);
791     ierr = VecSetSizes(gridctx[level1].r,gridctx[level1].A->rmap->n,PETSC_DECIDE);CHKERRQ(ierr);
792     ierr = VecSetType(gridctx[level1].r,VECMPI);CHKERRQ(ierr);
793     ierr = PCMGSetR(pc,level1,gridctx[level1].r);CHKERRQ(ierr);
794 
795     if (level == 0){
796       ierr = PCMGGetCoarseSolve(pc,&gridctx[level].ksp);CHKERRQ(ierr);
797     } else {
798       ierr = PCMGGetSmoother(pc,level,&gridctx[level].ksp);CHKERRQ(ierr);
799     }
800   }
801   ierr = PCMGGetSmoother(pc,fine_level,&gridctx[fine_level].ksp);CHKERRQ(ierr);
802 
803   /* create coarse level and the interpolation between the levels */
804   for (level=0; level<fine_level; level++){
805     level1 = level + 1;
806     ierr = PCMGSetInterpolation(pc,level1,gridctx[level].P);CHKERRQ(ierr);
807     ierr = PCMGSetRestriction(pc,level1,gridctx[level].R);CHKERRQ(ierr);
808     if (level > 0){
809       ierr = PCMGSetResidual(pc,level,PCMGDefaultResidual,gridctx[level].A);CHKERRQ(ierr);
810     }
811     ierr = KSPSetOperators(gridctx[level].ksp,gridctx[level].A,gridctx[level].A,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
812   }
813   ierr = PCMGSetResidual(pc,fine_level,PCMGDefaultResidual,gridctx[fine_level].A);CHKERRQ(ierr);
814   ierr = KSPSetOperators(gridctx[fine_level].ksp,gridctx[level].A,gridctx[fine_level].A,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
815 
816   /* setupcalled is set to 0 so that MG is setup from scratch */
817   pc->setupcalled = 0;
818   ierr = PCSetUp_MG(pc);CHKERRQ(ierr);
819   PetscFunctionReturn(0);
820 }
821 
822 /* -------------------------------------------------------------------------- */
823 /*
824    PCDestroy_ML - Destroys the private context for the ML preconditioner
825    that was created with PCCreate_ML().
826 
827    Input Parameter:
828 .  pc - the preconditioner context
829 
830    Application Interface Routine: PCDestroy()
831 */
832 #undef __FUNCT__
833 #define __FUNCT__ "PCDestroy_ML"
834 PetscErrorCode PCDestroy_ML(PC pc)
835 {
836   PetscErrorCode  ierr;
837   PC_MG           *mg = (PC_MG*)pc->data;
838   PC_ML           *pc_ml= (PC_ML*)mg->innerctx;
839 
840   PetscFunctionBegin;
841   ierr = PCReset_ML(pc);CHKERRQ(ierr);
842   ierr = PetscFree(pc_ml);CHKERRQ(ierr);
843   ierr = PCDestroy_MG(pc);CHKERRQ(ierr);
844   PetscFunctionReturn(0);
845 }
846 
847 #undef __FUNCT__
848 #define __FUNCT__ "PCSetFromOptions_ML"
849 PetscErrorCode PCSetFromOptions_ML(PC pc)
850 {
851   PetscErrorCode  ierr;
852   PetscInt        indx,PrintLevel;
853   const char      *scheme[] = {"Uncoupled","Coupled","MIS","METIS"};
854   PC_MG           *mg = (PC_MG*)pc->data;
855   PC_ML           *pc_ml = (PC_ML*)mg->innerctx;
856   PetscMPIInt     size;
857   MPI_Comm        comm = ((PetscObject)pc)->comm;
858 
859   PetscFunctionBegin;
860   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
861   ierr = PetscOptionsHead("ML options");CHKERRQ(ierr);
862   PrintLevel    = 0;
863   indx          = 0;
864   ierr = PetscOptionsInt("-pc_ml_PrintLevel","Print level","ML_Set_PrintLevel",PrintLevel,&PrintLevel,PETSC_NULL);CHKERRQ(ierr);
865   ML_Set_PrintLevel(PrintLevel);
866   ierr = PetscOptionsInt("-pc_ml_maxNlevels","Maximum number of levels","None",pc_ml->MaxNlevels,&pc_ml->MaxNlevels,PETSC_NULL);CHKERRQ(ierr);
867   ierr = PetscOptionsInt("-pc_ml_maxCoarseSize","Maximum coarsest mesh size","ML_Aggregate_Set_MaxCoarseSize",pc_ml->MaxCoarseSize,&pc_ml->MaxCoarseSize,PETSC_NULL);CHKERRQ(ierr);
868   ierr = PetscOptionsEList("-pc_ml_CoarsenScheme","Aggregate Coarsen Scheme","ML_Aggregate_Set_CoarsenScheme_*",scheme,4,scheme[0],&indx,PETSC_NULL);CHKERRQ(ierr);
869   pc_ml->CoarsenScheme = indx;
870   ierr = PetscOptionsReal("-pc_ml_DampingFactor","P damping factor","ML_Aggregate_Set_DampingFactor",pc_ml->DampingFactor,&pc_ml->DampingFactor,PETSC_NULL);CHKERRQ(ierr);
871   ierr = PetscOptionsReal("-pc_ml_Threshold","Smoother drop tol","ML_Aggregate_Set_Threshold",pc_ml->Threshold,&pc_ml->Threshold,PETSC_NULL);CHKERRQ(ierr);
872   ierr = PetscOptionsBool("-pc_ml_SpectralNormScheme_Anorm","Method used for estimating spectral radius","ML_Set_SpectralNormScheme_Anorm",pc_ml->SpectralNormScheme_Anorm,&pc_ml->SpectralNormScheme_Anorm,PETSC_NULL);CHKERRQ(ierr);
873   ierr = PetscOptionsBool("-pc_ml_Symmetrize","Symmetrize aggregation","ML_Set_Symmetrize",pc_ml->Symmetrize,&pc_ml->Symmetrize,PETSC_NULL);CHKERRQ(ierr);
874   ierr = PetscOptionsBool("-pc_ml_BlockScaling","Scale all dofs at each node together","None",pc_ml->BlockScaling,&pc_ml->BlockScaling,PETSC_NULL);CHKERRQ(ierr);
875   ierr = PetscOptionsEnum("-pc_ml_nullspace","Which type of null space information to use","None",PCMLNullSpaceTypes,(PetscEnum)pc_ml->nulltype,(PetscEnum*)&pc_ml->nulltype,PETSC_NULL);CHKERRQ(ierr);
876   ierr = PetscOptionsInt("-pc_ml_EnergyMinimization","Energy minimization norm type (0=no minimization; see ML manual for 1,2,3; -1 and 4 undocumented)","None",pc_ml->EnergyMinimization,&pc_ml->EnergyMinimization,PETSC_NULL);CHKERRQ(ierr);
877   ierr = PetscOptionsBool("-pc_ml_reuse_interpolation","Reuse the interpolation operators when possible (cheaper, weaker when matrix entries change a lot)","None",pc_ml->reuse_interpolation,&pc_ml->reuse_interpolation,PETSC_NULL);CHKERRQ(ierr);
878   /*
879     The following checks a number of conditions.  If we let this stuff slip by, then ML's error handling will take over.
880     This is suboptimal because it amounts to calling exit(1) so we check for the most common conditions.
881 
882     We also try to set some sane defaults when energy minimization is activated, otherwise it's hard to find a working
883     combination of options and ML's exit(1) explanations don't help matters.
884   */
885   if (pc_ml->EnergyMinimization < -1 || pc_ml->EnergyMinimization > 4) SETERRQ(comm,PETSC_ERR_ARG_OUTOFRANGE,"EnergyMinimization must be in range -1..4");
886   if (pc_ml->EnergyMinimization == 4 && size > 1) SETERRQ(comm,PETSC_ERR_SUP,"Energy minimization type 4 does not work in parallel");
887   if (pc_ml->EnergyMinimization == 4) {ierr = PetscInfo(pc,"Mandel's energy minimization scheme is experimental and broken in ML-6.2");CHKERRQ(ierr);}
888   if (pc_ml->EnergyMinimization) {
889     ierr = PetscOptionsReal("-pc_ml_EnergyMinimizationDropTol","Energy minimization drop tolerance","None",pc_ml->EnergyMinimizationDropTol,&pc_ml->EnergyMinimizationDropTol,PETSC_NULL);CHKERRQ(ierr);
890   }
891   if (pc_ml->EnergyMinimization == 2) {
892     /* According to ml_MultiLevelPreconditioner.cpp, this option is only meaningful for norm type (2) */
893     ierr = PetscOptionsBool("-pc_ml_EnergyMinimizationCheap","Use cheaper variant of norm type 2","None",pc_ml->EnergyMinimizationCheap,&pc_ml->EnergyMinimizationCheap,PETSC_NULL);CHKERRQ(ierr);
894   }
895   /* energy minimization sometimes breaks if this is turned off, the more classical stuff should be okay without it */
896   if (pc_ml->EnergyMinimization) pc_ml->KeepAggInfo = PETSC_TRUE;
897   ierr = PetscOptionsBool("-pc_ml_KeepAggInfo","Allows the preconditioner to be reused, or auxilliary matrices to be generated","None",pc_ml->KeepAggInfo,&pc_ml->KeepAggInfo,PETSC_NULL);CHKERRQ(ierr);
898   /* Option (-1) doesn't work at all (calls exit(1)) if the tentative restriction operator isn't stored. */
899   if (pc_ml->EnergyMinimization == -1) pc_ml->Reusable = PETSC_TRUE;
900   ierr = PetscOptionsBool("-pc_ml_Reusable","Store intermedaiate data structures so that the multilevel hierarchy is reusable","None",pc_ml->Reusable,&pc_ml->Reusable,PETSC_NULL);CHKERRQ(ierr);
901   /*
902     ML's C API is severely underdocumented and lacks significant functionality.  The C++ API calls
903     ML_Gen_MultiLevelHierarchy_UsingAggregation() which is a modified copy (!?) of the documented function
904     ML_Gen_MGHierarchy_UsingAggregation().  This modification, however, does not provide a strict superset of the
905     functionality in the old function, so some users may still want to use it.  Note that many options are ignored in
906     this context, but ML doesn't provide a way to find out which ones.
907    */
908   ierr = PetscOptionsBool("-pc_ml_OldHierarchy","Use old routine to generate hierarchy","None",pc_ml->OldHierarchy,&pc_ml->OldHierarchy,PETSC_NULL);CHKERRQ(ierr);
909   ierr = PetscOptionsTail();CHKERRQ(ierr);
910   PetscFunctionReturn(0);
911 }
912 
913 /* -------------------------------------------------------------------------- */
914 /*
915    PCCreate_ML - Creates a ML preconditioner context, PC_ML,
916    and sets this as the private data within the generic preconditioning
917    context, PC, that was created within PCCreate().
918 
919    Input Parameter:
920 .  pc - the preconditioner context
921 
922    Application Interface Routine: PCCreate()
923 */
924 
925 /*MC
926      PCML - Use algebraic multigrid preconditioning. This preconditioner requires you provide
927        fine grid discretization matrix. The coarser grid matrices and restriction/interpolation
928        operators are computed by ML, with the matrices coverted to PETSc matrices in aij format
929        and the restriction/interpolation operators wrapped as PETSc shell matrices.
930 
931    Options Database Key:
932    Multigrid options(inherited)
933 +  -pc_mg_cycles <1>: 1 for V cycle, 2 for W-cycle (MGSetCycles)
934 .  -pc_mg_smoothup <1>: Number of post-smoothing steps (MGSetNumberSmoothUp)
935 .  -pc_mg_smoothdown <1>: Number of pre-smoothing steps (MGSetNumberSmoothDown)
936    -pc_mg_type <multiplicative>: (one of) additive multiplicative full cascade kascade
937    ML options:
938 .  -pc_ml_PrintLevel <0>: Print level (ML_Set_PrintLevel)
939 .  -pc_ml_maxNlevels <10>: Maximum number of levels (None)
940 .  -pc_ml_maxCoarseSize <1>: Maximum coarsest mesh size (ML_Aggregate_Set_MaxCoarseSize)
941 .  -pc_ml_CoarsenScheme <Uncoupled>: (one of) Uncoupled Coupled MIS METIS
942 .  -pc_ml_DampingFactor <1.33333>: P damping factor (ML_Aggregate_Set_DampingFactor)
943 .  -pc_ml_Threshold <0>: Smoother drop tol (ML_Aggregate_Set_Threshold)
944 -  -pc_ml_SpectralNormScheme_Anorm <false>: Method used for estimating spectral radius (ML_Set_SpectralNormScheme_Anorm)
945 
946    Level: intermediate
947 
948   Concepts: multigrid
949 
950 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType,
951            PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), MPSetCycles(), PCMGSetNumberSmoothDown(),
952            PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(),
953            PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(),
954            PCMGSetCyclesOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR()
955 M*/
956 
957 EXTERN_C_BEGIN
958 #undef __FUNCT__
959 #define __FUNCT__ "PCCreate_ML"
960 PetscErrorCode  PCCreate_ML(PC pc)
961 {
962   PetscErrorCode  ierr;
963   PC_ML           *pc_ml;
964   PC_MG           *mg;
965 
966   PetscFunctionBegin;
967   /* PCML is an inherited class of PCMG. Initialize pc as PCMG */
968   ierr = PCSetType(pc,PCMG);CHKERRQ(ierr); /* calls PCCreate_MG() and MGCreate_Private() */
969   ierr = PetscObjectChangeTypeName((PetscObject)pc,PCML);CHKERRQ(ierr);
970   /* Since PCMG tries to use DM assocated with PC must delete it */
971   ierr = DMDestroy(&pc->dm);CHKERRQ(ierr);
972   mg = (PC_MG*)pc->data;
973   mg->galerkin = 2;             /* Use Galerkin, but it is computed externally */
974 
975   /* create a supporting struct and attach it to pc */
976   ierr = PetscNewLog(pc,PC_ML,&pc_ml);CHKERRQ(ierr);
977   mg->innerctx = pc_ml;
978 
979   pc_ml->ml_object     = 0;
980   pc_ml->agg_object    = 0;
981   pc_ml->gridctx       = 0;
982   pc_ml->PetscMLdata   = 0;
983   pc_ml->Nlevels       = -1;
984   pc_ml->MaxNlevels    = 10;
985   pc_ml->MaxCoarseSize = 1;
986   pc_ml->CoarsenScheme = 1;
987   pc_ml->Threshold     = 0.0;
988   pc_ml->DampingFactor = 4.0/3.0;
989   pc_ml->SpectralNormScheme_Anorm = PETSC_FALSE;
990   pc_ml->size          = 0;
991 
992   /* overwrite the pointers of PCMG by the functions of PCML */
993   pc->ops->setfromoptions = PCSetFromOptions_ML;
994   pc->ops->setup          = PCSetUp_ML;
995   pc->ops->reset          = PCReset_ML;
996   pc->ops->destroy        = PCDestroy_ML;
997   PetscFunctionReturn(0);
998 }
999 EXTERN_C_END
1000