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