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