xref: /petsc/src/ksp/pc/impls/ml/ml.c (revision 6ca4d86a4068a21a8631ad5a376173d6ae9260ac)
1dba47a55SKris Buschelman #define PETSCKSP_DLL
2ab718edeSHong Zhang 
35582bec1SHong Zhang /*
45582bec1SHong Zhang    Provides an interface to the ML 3.0 smoothed Aggregation
55582bec1SHong Zhang */
65582bec1SHong Zhang #include "src/ksp/pc/pcimpl.h"   /*I "petscpc.h" I*/
75582bec1SHong Zhang #include "src/ksp/pc/impls/mg/mgimpl.h"                    /*I "petscmg.h" I*/
85582bec1SHong Zhang #include "src/mat/impls/aij/seq/aij.h"
95582bec1SHong Zhang #include "src/mat/impls/aij/mpi/mpiaij.h"
10cb5d8e9eSHong Zhang 
115582bec1SHong Zhang EXTERN_C_BEGIN
125582bec1SHong Zhang #include <math.h>
135582bec1SHong Zhang #include "ml_include.h"
145582bec1SHong Zhang EXTERN_C_END
155582bec1SHong Zhang 
165582bec1SHong Zhang /* The context (data structure) at each grid level */
175582bec1SHong Zhang typedef struct {
185582bec1SHong Zhang   Vec        x,b,r;           /* global vectors */
195582bec1SHong Zhang   Mat        A,P,R;
205582bec1SHong Zhang   KSP        ksp;
215582bec1SHong Zhang } GridCtx;
225582bec1SHong Zhang 
235582bec1SHong Zhang /* The context used to input PETSc matrix into ML at fine grid */
245582bec1SHong Zhang typedef struct {
255582bec1SHong Zhang   Mat          A,Aloc;
2624a42b14SHong Zhang   Vec          x,y;
275582bec1SHong Zhang   ML_Operator  *mlmat;
285582bec1SHong Zhang   PetscScalar  *pwork; /* tmp array used by PetscML_comm() */
295582bec1SHong Zhang } FineGridCtx;
305582bec1SHong Zhang 
315582bec1SHong Zhang /* The context associates a ML matrix with a PETSc shell matrix */
325582bec1SHong Zhang typedef struct {
335582bec1SHong Zhang   Mat          A;       /* PETSc shell matrix associated with mlmat */
345582bec1SHong Zhang   ML_Operator  *mlmat;  /* ML matrix assorciated with A */
355582bec1SHong Zhang   Vec          y;
365582bec1SHong Zhang } Mat_MLShell;
375582bec1SHong Zhang 
385582bec1SHong Zhang /* Private context for the ML preconditioner */
395582bec1SHong Zhang typedef struct {
405582bec1SHong Zhang   ML           *ml_object;
415582bec1SHong Zhang   ML_Aggregate *agg_object;
425582bec1SHong Zhang   GridCtx      *gridctx;
435582bec1SHong Zhang   FineGridCtx  *PetscMLdata;
445582bec1SHong Zhang   PetscInt     fine_level,MaxNlevels,MaxCoarseSize,CoarsenScheme;
455582bec1SHong Zhang   PetscReal    Threshold,DampingFactor;
465582bec1SHong Zhang   PetscTruth   SpectralNormScheme_Anorm;
475582bec1SHong Zhang   PetscMPIInt  size;
485582bec1SHong Zhang   PetscErrorCode (*PCSetUp)(PC);
495582bec1SHong Zhang   PetscErrorCode (*PCDestroy)(PC);
505582bec1SHong Zhang } PC_ML;
515582bec1SHong Zhang extern int PetscML_getrow(void *ML_data,int N_requested_rows,int requested_rows[],
525582bec1SHong Zhang             int allocated_space,int columns[],double values[],int row_lengths[]);
535582bec1SHong Zhang extern int PetscML_matvec(void *ML_data, int in_length, double p[], int out_length,double ap[]);
545582bec1SHong Zhang extern int PetscML_comm(double x[], void *ML_data);
555582bec1SHong Zhang extern PetscErrorCode MatMult_ML(Mat,Vec,Vec);
565582bec1SHong Zhang extern PetscErrorCode MatMultAdd_ML(Mat,Vec,Vec,Vec);
57eef31507SHong Zhang extern PetscErrorCode MatConvert_MPIAIJ_ML(Mat,const MatType,MatReuse,Mat*);
585582bec1SHong Zhang extern PetscErrorCode MatDestroy_ML(Mat);
59eef31507SHong Zhang extern PetscErrorCode MatWrapML_SeqAIJ(ML_Operator*,Mat*);
60eef31507SHong Zhang extern PetscErrorCode MatWrapML_MPIAIJ(ML_Operator*,Mat*);
61eef31507SHong Zhang extern PetscErrorCode MatWrapML_SHELL(ML_Operator*,Mat*);
625582bec1SHong Zhang 
635582bec1SHong Zhang /* -------------------------------------------------------------------------- */
645582bec1SHong Zhang /*
655582bec1SHong Zhang    PCSetUp_ML - Prepares for the use of the ML preconditioner
665582bec1SHong Zhang                     by setting data structures and options.
675582bec1SHong Zhang 
685582bec1SHong Zhang    Input Parameter:
695582bec1SHong Zhang .  pc - the preconditioner context
705582bec1SHong Zhang 
715582bec1SHong Zhang    Application Interface Routine: PCSetUp()
725582bec1SHong Zhang 
735582bec1SHong Zhang    Notes:
745582bec1SHong Zhang    The interface routine PCSetUp() is not usually called directly by
755582bec1SHong Zhang    the user, but instead is called by PCApply() if necessary.
765582bec1SHong Zhang */
77*6ca4d86aSHong Zhang extern PetscErrorCode PCSetFromOptions_MG(PC);
785582bec1SHong Zhang #undef __FUNCT__
795582bec1SHong Zhang #define __FUNCT__ "PCSetUp_ML"
80*6ca4d86aSHong Zhang PetscErrorCode PCSetUp_ML(PC pc)
815582bec1SHong Zhang {
825582bec1SHong Zhang   PetscErrorCode       ierr;
83eef31507SHong Zhang   PetscMPIInt          size;
845582bec1SHong Zhang   FineGridCtx          *PetscMLdata;
855582bec1SHong Zhang   ML                   *ml_object;
865582bec1SHong Zhang   ML_Aggregate         *agg_object;
875582bec1SHong Zhang   ML_Operator          *mlmat;
885582bec1SHong Zhang   PetscInt             nlocal_allcols,Nlevels,mllevel,level,m,fine_level;
895582bec1SHong Zhang   Mat                  A,Aloc;
905582bec1SHong Zhang   GridCtx              *gridctx;
915582bec1SHong Zhang   PC_ML                *pc_ml=PETSC_NULL;
925582bec1SHong Zhang   PetscObjectContainer container;
935582bec1SHong Zhang 
945582bec1SHong Zhang   PetscFunctionBegin;
955582bec1SHong Zhang   ierr = PetscObjectQuery((PetscObject)pc,"PC_ML",(PetscObject *)&container);CHKERRQ(ierr);
965582bec1SHong Zhang   if (container) {
975582bec1SHong Zhang     ierr = PetscObjectContainerGetPointer(container,(void **)&pc_ml);CHKERRQ(ierr);
985582bec1SHong Zhang   } else {
995582bec1SHong Zhang     SETERRQ(PETSC_ERR_ARG_NULL,"Container does not exit");
1005582bec1SHong Zhang   }
1015582bec1SHong Zhang 
1025582bec1SHong Zhang   /* setup special features of PCML */
1035582bec1SHong Zhang   /*--------------------------------*/
1045582bec1SHong Zhang   /* covert A to Aloc to be used by ML at fine grid */
1055582bec1SHong Zhang   A = pc->pmat;
1065582bec1SHong Zhang   ierr = MPI_Comm_size(A->comm,&size);CHKERRQ(ierr);
1075582bec1SHong Zhang   pc_ml->size = size;
1085582bec1SHong Zhang   if (size > 1){
109eef31507SHong Zhang     ierr = MatConvert_MPIAIJ_ML(A,PETSC_NULL,MAT_INITIAL_MATRIX,&Aloc);CHKERRQ(ierr);
1105582bec1SHong Zhang   } else {
1115582bec1SHong Zhang     Aloc = A;
1125582bec1SHong Zhang   }
1135582bec1SHong Zhang 
1145582bec1SHong Zhang   /* create and initialize struct 'PetscMLdata' */
1155582bec1SHong Zhang   ierr = PetscNew(FineGridCtx,&PetscMLdata);CHKERRQ(ierr);
1165582bec1SHong Zhang   PetscMLdata->A    = A;
1175582bec1SHong Zhang   PetscMLdata->Aloc = Aloc;
1185582bec1SHong Zhang   ierr = PetscMalloc((Aloc->n+1)*sizeof(PetscScalar),&PetscMLdata->pwork);CHKERRQ(ierr);
1195582bec1SHong Zhang   pc_ml->PetscMLdata = PetscMLdata;
1205582bec1SHong Zhang 
12124a42b14SHong Zhang   ierr = VecCreate(PETSC_COMM_SELF,&PetscMLdata->x);CHKERRQ(ierr);
12224a42b14SHong Zhang   if (size == 1){
123*6ca4d86aSHong Zhang     ierr = VecSetSizes(PetscMLdata->x,A->n,A->n);CHKERRQ(ierr);
12424a42b14SHong Zhang   } else {
125*6ca4d86aSHong Zhang     ierr = VecSetSizes(PetscMLdata->x,Aloc->n,Aloc->n);CHKERRQ(ierr);
12624a42b14SHong Zhang   }
12724a42b14SHong Zhang   ierr = VecSetType(PetscMLdata->x,VECSEQ);CHKERRQ(ierr);
12824a42b14SHong Zhang 
12924a42b14SHong Zhang   ierr = VecCreate(PETSC_COMM_SELF,&PetscMLdata->y);CHKERRQ(ierr);
13024a42b14SHong Zhang   ierr = VecSetSizes(PetscMLdata->y,A->m,PETSC_DECIDE);CHKERRQ(ierr);
13124a42b14SHong Zhang   ierr = VecSetType(PetscMLdata->y,VECSEQ);CHKERRQ(ierr);
13224a42b14SHong Zhang 
1335582bec1SHong Zhang   /* create ML discretization matrix at fine grid */
1345582bec1SHong Zhang   ierr = MatGetSize(Aloc,&m,&nlocal_allcols);CHKERRQ(ierr);
1355582bec1SHong Zhang   ML_Create(&ml_object,pc_ml->MaxNlevels);
1365582bec1SHong Zhang   ML_Init_Amatrix(ml_object,0,m,m,PetscMLdata);
1375582bec1SHong Zhang   ML_Set_Amatrix_Getrow(ml_object,0,PetscML_getrow,PetscML_comm,nlocal_allcols);
1385582bec1SHong Zhang   ML_Set_Amatrix_Matvec(ml_object,0,PetscML_matvec);
1395582bec1SHong Zhang 
1405582bec1SHong Zhang   /* aggregation */
1415582bec1SHong Zhang   ML_Aggregate_Create(&agg_object);
1425582bec1SHong Zhang   ML_Aggregate_Set_MaxCoarseSize(agg_object,pc_ml->MaxCoarseSize);
1435582bec1SHong Zhang   /* set options */
1445582bec1SHong Zhang   switch (pc_ml->CoarsenScheme) {
1455582bec1SHong Zhang   case 1:
1465582bec1SHong Zhang     ML_Aggregate_Set_CoarsenScheme_Coupled(agg_object);break;
1475582bec1SHong Zhang   case 2:
1485582bec1SHong Zhang     ML_Aggregate_Set_CoarsenScheme_MIS(agg_object);break;
1495582bec1SHong Zhang   case 3:
1505582bec1SHong Zhang     ML_Aggregate_Set_CoarsenScheme_METIS(agg_object);break;
1515582bec1SHong Zhang   }
1525582bec1SHong Zhang   ML_Aggregate_Set_Threshold(agg_object,pc_ml->Threshold);
1535582bec1SHong Zhang   ML_Aggregate_Set_DampingFactor(agg_object,pc_ml->DampingFactor);
1545582bec1SHong Zhang   if (pc_ml->SpectralNormScheme_Anorm){
1555582bec1SHong Zhang     ML_Aggregate_Set_SpectralNormScheme_Anorm(agg_object);
1565582bec1SHong Zhang   }
1575582bec1SHong Zhang 
1585582bec1SHong Zhang   Nlevels = ML_Gen_MGHierarchy_UsingAggregation(ml_object,0,ML_INCREASING,agg_object);
1595582bec1SHong Zhang   if (Nlevels<=0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Nlevels %d must > 0",Nlevels);
1605582bec1SHong Zhang   ierr = MGSetLevels(pc,Nlevels,PETSC_NULL);CHKERRQ(ierr);
161*6ca4d86aSHong Zhang   ierr = PCSetFromOptions_MG(pc);CHKERRQ(ierr); /* should be called in PCSetFromOptions_ML(), but cannot be called prior to MGSetLevels() */
1625582bec1SHong Zhang   pc_ml->ml_object  = ml_object;
1635582bec1SHong Zhang   pc_ml->agg_object = agg_object;
1645582bec1SHong Zhang 
1655582bec1SHong Zhang   ierr = PetscMalloc(Nlevels*sizeof(GridCtx),&gridctx);CHKERRQ(ierr);
1665582bec1SHong Zhang   fine_level = Nlevels - 1;
1675582bec1SHong Zhang   pc_ml->gridctx = gridctx;
1685582bec1SHong Zhang   pc_ml->fine_level = fine_level;
1695582bec1SHong Zhang 
1705582bec1SHong Zhang   /* wrap ML matrices by PETSc shell matrices at coarsened grids.
1715582bec1SHong Zhang      Level 0 is the finest grid for ML, but coarsest for PETSc! */
172e14861a4SHong Zhang   gridctx[fine_level].A = A;
173e14861a4SHong Zhang   level = fine_level - 1;
174ab718edeSHong Zhang   if (size == 1){ /* convert ML P, R and A into seqaij format */
1755582bec1SHong Zhang     for (mllevel=1; mllevel<Nlevels; mllevel++){
176e14861a4SHong Zhang       mlmat  = &(ml_object->Pmat[mllevel]);
177eef31507SHong Zhang       ierr = MatWrapML_SeqAIJ(mlmat,&gridctx[level].P);CHKERRQ(ierr);
178e14861a4SHong Zhang       mlmat  = &(ml_object->Amat[mllevel]);
179eef31507SHong Zhang       ierr = MatWrapML_SeqAIJ(mlmat,&gridctx[level].A);CHKERRQ(ierr);
180e14861a4SHong Zhang       mlmat  = &(ml_object->Rmat[mllevel-1]);
181eef31507SHong Zhang       ierr = MatWrapML_SeqAIJ(mlmat,&gridctx[level].R);CHKERRQ(ierr);
1825582bec1SHong Zhang       level--;
1835582bec1SHong Zhang     }
184ab718edeSHong Zhang   } else { /* convert ML P and R into shell format, ML A into mpiaij format */
1855582bec1SHong Zhang     for (mllevel=1; mllevel<Nlevels; mllevel++){
1865582bec1SHong Zhang       mlmat  = &(ml_object->Pmat[mllevel]);
187eef31507SHong Zhang       ierr = MatWrapML_SHELL(mlmat,&gridctx[level].P);CHKERRQ(ierr);
188ab718edeSHong Zhang       mlmat  = &(ml_object->Rmat[mllevel-1]);
189eef31507SHong Zhang       ierr = MatWrapML_SHELL(mlmat,&gridctx[level].R);CHKERRQ(ierr);
1905582bec1SHong Zhang       mlmat  = &(ml_object->Amat[mllevel]);
191eef31507SHong Zhang       ierr = MatWrapML_MPIAIJ(mlmat,&gridctx[level].A);CHKERRQ(ierr);
1925582bec1SHong Zhang       level--;
1935582bec1SHong Zhang     }
1945582bec1SHong Zhang   }
1955582bec1SHong Zhang 
1965582bec1SHong Zhang   /* create coarse level and the interpolation between the levels */
1975582bec1SHong Zhang   level = fine_level;
1985582bec1SHong Zhang   while ( level >= 0 ){
1995582bec1SHong Zhang     if (level != fine_level){
2005582bec1SHong Zhang       ierr = VecCreate(gridctx[level].A->comm,&gridctx[level].x);CHKERRQ(ierr);
2015582bec1SHong Zhang       ierr = VecSetSizes(gridctx[level].x,gridctx[level].A->n,PETSC_DECIDE);CHKERRQ(ierr);
2025582bec1SHong Zhang       ierr = VecSetType(gridctx[level].x,VECMPI);CHKERRQ(ierr);
2035582bec1SHong Zhang       ierr = MGSetX(pc,level,gridctx[level].x);CHKERRQ(ierr);
2045582bec1SHong Zhang 
2055582bec1SHong Zhang       ierr = VecCreate(gridctx[level].A->comm,&gridctx[level].b);CHKERRQ(ierr);
2065582bec1SHong Zhang       ierr = VecSetSizes(gridctx[level].b,gridctx[level].A->m,PETSC_DECIDE);CHKERRQ(ierr);
2075582bec1SHong Zhang       ierr = VecSetType(gridctx[level].b,VECMPI);CHKERRQ(ierr);
2085582bec1SHong Zhang       ierr = MGSetRhs(pc,level,gridctx[level].b);CHKERRQ(ierr);
2095582bec1SHong Zhang     }
210*6ca4d86aSHong Zhang     if (level) {
2115582bec1SHong Zhang       ierr = VecCreate(gridctx[level].A->comm,&gridctx[level].r);CHKERRQ(ierr);
2125582bec1SHong Zhang       ierr = VecSetSizes(gridctx[level].r,gridctx[level].A->m,PETSC_DECIDE);CHKERRQ(ierr);
2135582bec1SHong Zhang       ierr = VecSetType(gridctx[level].r,VECMPI);CHKERRQ(ierr);
2145582bec1SHong Zhang       ierr = MGSetR(pc,level,gridctx[level].r);CHKERRQ(ierr);
215*6ca4d86aSHong Zhang     }
2165582bec1SHong Zhang 
2175582bec1SHong Zhang     if (level == 0){
2185582bec1SHong Zhang       ierr = MGGetCoarseSolve(pc,&gridctx[level].ksp);CHKERRQ(ierr);
2195582bec1SHong Zhang     } else {
2205582bec1SHong Zhang       ierr = MGGetSmoother(pc,level,&gridctx[level].ksp);CHKERRQ(ierr);
2215582bec1SHong Zhang       ierr = MGSetResidual(pc,level,MGDefaultResidual,gridctx[level].A);CHKERRQ(ierr);
2225582bec1SHong Zhang       if (level == fine_level){
2235582bec1SHong Zhang         ierr = KSPSetOptionsPrefix(gridctx[level].ksp,"mg_fine_");CHKERRQ(ierr);
2245582bec1SHong Zhang         ierr = MGSetR(pc,level,gridctx[level].r);CHKERRQ(ierr);
2255582bec1SHong Zhang       }
2265582bec1SHong Zhang     }
2275582bec1SHong Zhang     ierr = KSPSetOperators(gridctx[level].ksp,gridctx[level].A,gridctx[level].A,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
2285582bec1SHong Zhang 
2295582bec1SHong Zhang     if (level < fine_level){
2305582bec1SHong Zhang       ierr = MGSetInterpolate(pc,level+1,gridctx[level].P);CHKERRQ(ierr);
2315582bec1SHong Zhang       ierr = MGSetRestriction(pc,level+1,gridctx[level].R);CHKERRQ(ierr);
2325582bec1SHong Zhang     }
2335582bec1SHong Zhang     level--;
2345582bec1SHong Zhang   }
2355582bec1SHong Zhang 
2365582bec1SHong Zhang   /* now call PCSetUp_MG()         */
2375582bec1SHong Zhang   /*--------------------------------*/
2385582bec1SHong Zhang   ierr = (*pc_ml->PCSetUp)(pc);CHKERRQ(ierr);
2395582bec1SHong Zhang   PetscFunctionReturn(0);
2405582bec1SHong Zhang }
2415582bec1SHong Zhang 
2425582bec1SHong Zhang #undef __FUNCT__
2435582bec1SHong Zhang #define __FUNCT__ "PetscObjectContainerDestroy_PC_ML"
2445582bec1SHong Zhang PetscErrorCode PetscObjectContainerDestroy_PC_ML(void *ptr)
2455582bec1SHong Zhang {
2465582bec1SHong Zhang   PetscErrorCode       ierr;
2475582bec1SHong Zhang   PC_ML                *pc_ml = (PC_ML*)ptr;
2485582bec1SHong Zhang   PetscInt             level;
2495582bec1SHong Zhang 
2505582bec1SHong Zhang   PetscFunctionBegin;
2515582bec1SHong Zhang   if (pc_ml->size > 1){ierr = MatDestroy(pc_ml->PetscMLdata->Aloc);CHKERRQ(ierr);}
2525582bec1SHong Zhang   ML_Aggregate_Destroy(&pc_ml->agg_object);
2535582bec1SHong Zhang   ML_Destroy(&pc_ml->ml_object);
2545582bec1SHong Zhang 
2555582bec1SHong Zhang   ierr = PetscFree(pc_ml->PetscMLdata->pwork);CHKERRQ(ierr);
25624a42b14SHong Zhang   ierr = VecDestroy(pc_ml->PetscMLdata->x);CHKERRQ(ierr);
25724a42b14SHong Zhang   ierr = VecDestroy(pc_ml->PetscMLdata->y);CHKERRQ(ierr);
2585582bec1SHong Zhang   ierr = PetscFree(pc_ml->PetscMLdata);CHKERRQ(ierr);
2595582bec1SHong Zhang 
2605582bec1SHong Zhang   level = pc_ml->fine_level;
2615582bec1SHong Zhang   while ( level>= 0 ){
2625582bec1SHong Zhang     if (level != pc_ml->fine_level){
2635582bec1SHong Zhang       ierr = MatDestroy(pc_ml->gridctx[level].A);CHKERRQ(ierr);
2645582bec1SHong Zhang       ierr = MatDestroy(pc_ml->gridctx[level].P);CHKERRQ(ierr);
2655582bec1SHong Zhang       ierr = MatDestroy(pc_ml->gridctx[level].R);CHKERRQ(ierr);
2665582bec1SHong Zhang       ierr = VecDestroy(pc_ml->gridctx[level].x);CHKERRQ(ierr);
2675582bec1SHong Zhang       ierr = VecDestroy(pc_ml->gridctx[level].b);CHKERRQ(ierr);
2685582bec1SHong Zhang     }
269*6ca4d86aSHong Zhang     if (level){
2705582bec1SHong Zhang       ierr = VecDestroy(pc_ml->gridctx[level].r);CHKERRQ(ierr);
271*6ca4d86aSHong Zhang     }
2725582bec1SHong Zhang     level--;
2735582bec1SHong Zhang   }
2745582bec1SHong Zhang   ierr = PetscFree(pc_ml->gridctx);CHKERRQ(ierr);
2755582bec1SHong Zhang   ierr = PetscFree(pc_ml);CHKERRQ(ierr);
2765582bec1SHong Zhang   PetscFunctionReturn(0);
2775582bec1SHong Zhang }
2785582bec1SHong Zhang /* -------------------------------------------------------------------------- */
2795582bec1SHong Zhang /*
2805582bec1SHong Zhang    PCDestroy_ML - Destroys the private context for the ML preconditioner
2815582bec1SHong Zhang    that was created with PCCreate_ML().
2825582bec1SHong Zhang 
2835582bec1SHong Zhang    Input Parameter:
2845582bec1SHong Zhang .  pc - the preconditioner context
2855582bec1SHong Zhang 
2865582bec1SHong Zhang    Application Interface Routine: PCDestroy()
2875582bec1SHong Zhang */
2885582bec1SHong Zhang #undef __FUNCT__
2895582bec1SHong Zhang #define __FUNCT__ "PCDestroy_ML"
290*6ca4d86aSHong Zhang PetscErrorCode PCDestroy_ML(PC pc)
2915582bec1SHong Zhang {
2925582bec1SHong Zhang   PetscErrorCode       ierr;
2935582bec1SHong Zhang   PC_ML                *pc_ml=PETSC_NULL;
2945582bec1SHong Zhang   PetscObjectContainer container;
2955582bec1SHong Zhang 
2965582bec1SHong Zhang   PetscFunctionBegin;
2975582bec1SHong Zhang   ierr = PetscObjectQuery((PetscObject)pc,"PC_ML",(PetscObject *)&container);CHKERRQ(ierr);
2985582bec1SHong Zhang   if (container) {
2995582bec1SHong Zhang     ierr = PetscObjectContainerGetPointer(container,(void **)&pc_ml);CHKERRQ(ierr);
3005582bec1SHong Zhang     pc->ops->destroy = pc_ml->PCDestroy;
3015582bec1SHong Zhang   } else {
3025582bec1SHong Zhang     SETERRQ(PETSC_ERR_ARG_NULL,"Container does not exit");
3035582bec1SHong Zhang   }
3049cb0ec93SHong Zhang   /* detach pc and PC_ML and dereference container */
3055582bec1SHong Zhang   ierr = PetscObjectCompose((PetscObject)pc,"PC_ML",0);CHKERRQ(ierr);
3065582bec1SHong Zhang   ierr = (*pc->ops->destroy)(pc);CHKERRQ(ierr);
3075582bec1SHong Zhang 
3085582bec1SHong Zhang   ierr = PetscObjectContainerDestroy(container);CHKERRQ(ierr);
3095582bec1SHong Zhang   PetscFunctionReturn(0);
3105582bec1SHong Zhang }
3115582bec1SHong Zhang 
3125582bec1SHong Zhang #undef __FUNCT__
3135582bec1SHong Zhang #define __FUNCT__ "PCSetFromOptions_ML"
314*6ca4d86aSHong Zhang PetscErrorCode PCSetFromOptions_ML(PC pc)
3155582bec1SHong Zhang {
3165582bec1SHong Zhang   PetscErrorCode ierr;
3175582bec1SHong Zhang   PetscInt       indx,m,PrintLevel,MaxNlevels,MaxCoarseSize;
3185582bec1SHong Zhang   PetscReal      Threshold,DampingFactor;
3195582bec1SHong Zhang   PetscTruth     flg;
3205582bec1SHong Zhang   const char     *type[] = {"additive","multiplicative","full","cascade","kascade"};
3215582bec1SHong Zhang   const char     *scheme[] = {"Uncoupled","Coupled","MIS","METIS"};
3225582bec1SHong Zhang   PC_ML          *pc_ml=PETSC_NULL;
3235582bec1SHong Zhang   PetscObjectContainer container;
3245582bec1SHong Zhang 
3255582bec1SHong Zhang   PetscFunctionBegin;
3265582bec1SHong Zhang   ierr = PetscObjectQuery((PetscObject)pc,"PC_ML",(PetscObject *)&container);CHKERRQ(ierr);
3275582bec1SHong Zhang   if (container) {
3285582bec1SHong Zhang     ierr = PetscObjectContainerGetPointer(container,(void **)&pc_ml);CHKERRQ(ierr);
3295582bec1SHong Zhang   } else {
3305582bec1SHong Zhang     SETERRQ(PETSC_ERR_ARG_NULL,"Container does not exit");
3315582bec1SHong Zhang   }
332*6ca4d86aSHong Zhang 
3335582bec1SHong Zhang   /* inherited MG options */
334*6ca4d86aSHong Zhang   ierr = PetscOptionsHead("Multigrid options(inherited)");CHKERRQ(ierr);
3355582bec1SHong Zhang   ierr = PetscOptionsInt("-pc_mg_cycles","1 for V cycle, 2 for W-cycle","MGSetCycles",1,&m,&flg);CHKERRQ(ierr);
3365582bec1SHong Zhang   ierr = PetscOptionsInt("-pc_mg_smoothup","Number of post-smoothing steps","MGSetNumberSmoothUp",1,&m,&flg);CHKERRQ(ierr);
3375582bec1SHong Zhang   ierr = PetscOptionsInt("-pc_mg_smoothdown","Number of pre-smoothing steps","MGSetNumberSmoothDown",1,&m,&flg);CHKERRQ(ierr);
3385582bec1SHong Zhang   ierr = PetscOptionsEList("-pc_mg_type","Multigrid type","MGSetType",type,5,type[1],&indx,&flg);CHKERRQ(ierr);
3395582bec1SHong Zhang   ierr = PetscOptionsTail();CHKERRQ(ierr);
3405582bec1SHong Zhang 
3415582bec1SHong Zhang   /* ML options */
3425582bec1SHong Zhang   ierr = PetscOptionsHead("ML options");CHKERRQ(ierr);
3435582bec1SHong Zhang   /* set defaults */
3445582bec1SHong Zhang   PrintLevel    = 0;
3455582bec1SHong Zhang   MaxNlevels    = 10;
3465582bec1SHong Zhang   MaxCoarseSize = 1;
3475582bec1SHong Zhang   indx          = 0;
3485582bec1SHong Zhang   Threshold     = 0.0;
3495582bec1SHong Zhang   DampingFactor = 4.0/3.0;
3505582bec1SHong Zhang 
3515582bec1SHong Zhang   ierr = PetscOptionsInt("-pc_ml_PrintLevel","Print level","ML_Set_PrintLevel",PrintLevel,&PrintLevel,PETSC_NULL);CHKERRQ(ierr);
3525582bec1SHong Zhang   ML_Set_PrintLevel(PrintLevel);
3535582bec1SHong Zhang 
3545582bec1SHong Zhang   ierr = PetscOptionsInt("-pc_ml_maxNlevels","Maximum number of levels","None",MaxNlevels,&MaxNlevels,PETSC_NULL);CHKERRQ(ierr);
3555582bec1SHong Zhang   pc_ml->MaxNlevels = MaxNlevels;
3565582bec1SHong Zhang 
3575582bec1SHong Zhang   ierr = PetscOptionsInt("-pc_ml_maxCoarseSize","Maximum coarsest mesh size","ML_Aggregate_Set_MaxCoarseSize",MaxCoarseSize,&MaxCoarseSize,PETSC_NULL);CHKERRQ(ierr);
3585582bec1SHong Zhang   pc_ml->MaxCoarseSize = MaxCoarseSize;
3595582bec1SHong Zhang 
3605582bec1SHong Zhang   ierr = PetscOptionsEList("-pc_ml_CoarsenScheme","Aggregate Coarsen Scheme","ML_Aggregate_Set_CoarsenScheme_*",scheme,4,scheme[0],&indx,PETSC_NULL);CHKERRQ(ierr);
3615582bec1SHong Zhang   pc_ml->CoarsenScheme = indx;
3625582bec1SHong Zhang 
3635582bec1SHong Zhang   ierr = PetscOptionsReal("-pc_ml_DampingFactor","P damping factor","ML_Aggregate_Set_DampingFactor",DampingFactor,&DampingFactor,PETSC_NULL);CHKERRQ(ierr);
3645582bec1SHong Zhang   pc_ml->DampingFactor = DampingFactor;
3655582bec1SHong Zhang 
3665582bec1SHong Zhang   ierr = PetscOptionsReal("-pc_ml_Threshold","Smoother drop tol","ML_Aggregate_Set_Threshold",Threshold,&Threshold,PETSC_NULL);CHKERRQ(ierr);
3675582bec1SHong Zhang   pc_ml->Threshold = Threshold;
3685582bec1SHong Zhang 
3695582bec1SHong Zhang   ierr = PetscOptionsLogical("-pc_ml_SpectralNormScheme_Anorm","Method used for estimating spectral radius","ML_Aggregate_Set_SpectralNormScheme_Anorm",PETSC_FALSE,&pc_ml->SpectralNormScheme_Anorm,PETSC_FALSE);
3705582bec1SHong Zhang 
3715582bec1SHong Zhang   ierr = PetscOptionsTail();CHKERRQ(ierr);
3725582bec1SHong Zhang   PetscFunctionReturn(0);
3735582bec1SHong Zhang }
3745582bec1SHong Zhang 
3755582bec1SHong Zhang /* -------------------------------------------------------------------------- */
3765582bec1SHong Zhang /*
3775582bec1SHong Zhang    PCCreate_ML - Creates a ML preconditioner context, PC_ML,
3785582bec1SHong Zhang    and sets this as the private data within the generic preconditioning
3795582bec1SHong Zhang    context, PC, that was created within PCCreate().
3805582bec1SHong Zhang 
3815582bec1SHong Zhang    Input Parameter:
3825582bec1SHong Zhang .  pc - the preconditioner context
3835582bec1SHong Zhang 
3845582bec1SHong Zhang    Application Interface Routine: PCCreate()
3855582bec1SHong Zhang */
3865582bec1SHong Zhang 
3875582bec1SHong Zhang /*MC
3885582bec1SHong Zhang      PCML - Use geometric multigrid preconditioning. This preconditioner requires you provide
3895582bec1SHong Zhang        fine grid discretization matrix. The coarser grid matrices and restriction/interpolation
390*6ca4d86aSHong Zhang        operators are computed by ML, with the matrices coverted to PETSc matrices in aij format
391*6ca4d86aSHong Zhang        and the restriction/interpolation operators wrapped as PETSc shell matrices.
3925582bec1SHong Zhang 
393*6ca4d86aSHong Zhang    Options Database Key:
394*6ca4d86aSHong Zhang    Multigrid options(inherited)
395*6ca4d86aSHong Zhang +  -pc_mg_cycles <1>: 1 for V cycle, 2 for W-cycle (MGSetCycles)
396*6ca4d86aSHong Zhang .  -pc_mg_smoothup <1>: Number of post-smoothing steps (MGSetNumberSmoothUp)
397*6ca4d86aSHong Zhang .  -pc_mg_smoothdown <1>: Number of pre-smoothing steps (MGSetNumberSmoothDown)
398*6ca4d86aSHong Zhang -  -pc_mg_type <multiplicative> (one of) additive multiplicative full cascade kascade
399*6ca4d86aSHong Zhang 
400*6ca4d86aSHong Zhang    ML options
401*6ca4d86aSHong Zhang +  -pc_ml_PrintLevel <0>: Print level (ML_Set_PrintLevel)
402*6ca4d86aSHong Zhang .  -pc_ml_maxNlevels <10>: Maximum number of levels (None)
403*6ca4d86aSHong Zhang .  -pc_ml_maxCoarseSize <1>: Maximum coarsest mesh size (ML_Aggregate_Set_MaxCoarseSize)
404*6ca4d86aSHong Zhang .  -pc_ml_CoarsenScheme <Uncoupled> (one of) Uncoupled Coupled MIS METIS
405*6ca4d86aSHong Zhang .  -pc_ml_DampingFactor <1.33333>: P damping factor (ML_Aggregate_Set_DampingFactor)
406*6ca4d86aSHong Zhang .  -pc_ml_Threshold <0>: Smoother drop tol (ML_Aggregate_Set_Threshold)
407*6ca4d86aSHong Zhang -  -pc_ml_SpectralNormScheme_Anorm: <false> Method used for estimating spectral radius (ML_Aggregate_Set_SpectralNormScheme_Anorm)
4085582bec1SHong Zhang 
4095582bec1SHong Zhang    Level: intermediate
4105582bec1SHong Zhang 
4115582bec1SHong Zhang   Concepts: multigrid
4125582bec1SHong Zhang 
4135582bec1SHong Zhang .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType,
4145582bec1SHong Zhang            MGSetLevels(), MGGetLevels(), MGSetType(), MPSetCycles(), MGSetNumberSmoothDown(),
4155582bec1SHong Zhang            MGSetNumberSmoothUp(), MGGetCoarseSolve(), MGSetResidual(), MGSetInterpolation(),
4165582bec1SHong Zhang            MGSetRestriction(), MGGetSmoother(), MGGetSmootherUp(), MGGetSmootherDown(),
4175582bec1SHong Zhang            MGSetCyclesOnLevel(), MGSetRhs(), MGSetX(), MGSetR()
4185582bec1SHong Zhang M*/
4195582bec1SHong Zhang 
4205582bec1SHong Zhang EXTERN_C_BEGIN
4215582bec1SHong Zhang #undef __FUNCT__
4225582bec1SHong Zhang #define __FUNCT__ "PCCreate_ML"
423dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_ML(PC pc)
4245582bec1SHong Zhang {
4255582bec1SHong Zhang   PetscErrorCode       ierr;
4265582bec1SHong Zhang   PC_ML                *pc_ml;
4275582bec1SHong Zhang   PetscObjectContainer container;
4285582bec1SHong Zhang 
4295582bec1SHong Zhang   PetscFunctionBegin;
4305582bec1SHong Zhang   /* initialize pc as PCMG */
4315582bec1SHong Zhang   ierr = PCSetType(pc,PCMG);CHKERRQ(ierr); /* calls PCCreate_MG() and MGCreate_Private() */
4325582bec1SHong Zhang 
4335582bec1SHong Zhang   /* create a supporting struct and attach it to pc */
4345582bec1SHong Zhang   ierr = PetscNew(PC_ML,&pc_ml);CHKERRQ(ierr);
4355582bec1SHong Zhang   ierr = PetscObjectContainerCreate(PETSC_COMM_SELF,&container);CHKERRQ(ierr);
4365582bec1SHong Zhang   ierr = PetscObjectContainerSetPointer(container,pc_ml);CHKERRQ(ierr);
4379cb0ec93SHong Zhang   ierr = PetscObjectContainerSetUserDestroy(container,PetscObjectContainerDestroy_PC_ML);CHKERRQ(ierr);
4385582bec1SHong Zhang   ierr = PetscObjectCompose((PetscObject)pc,"PC_ML",(PetscObject)container);CHKERRQ(ierr);
4395582bec1SHong Zhang 
4405582bec1SHong Zhang   pc_ml->PCSetUp   = pc->ops->setup;
4415582bec1SHong Zhang   pc_ml->PCDestroy = pc->ops->destroy;
4425582bec1SHong Zhang 
4435582bec1SHong Zhang   /* overwrite the pointers of PCMG by the functions of PCML */
4445582bec1SHong Zhang   pc->ops->setfromoptions = PCSetFromOptions_ML;
4455582bec1SHong Zhang   pc->ops->setup          = PCSetUp_ML;
4465582bec1SHong Zhang   pc->ops->destroy        = PCDestroy_ML;
4475582bec1SHong Zhang   PetscFunctionReturn(0);
4485582bec1SHong Zhang }
4495582bec1SHong Zhang EXTERN_C_END
4505582bec1SHong Zhang 
4515582bec1SHong Zhang int PetscML_getrow(void *ML_data, int N_requested_rows, int requested_rows[],
4525582bec1SHong Zhang    int allocated_space, int columns[], double values[], int row_lengths[])
4535582bec1SHong Zhang {
4545582bec1SHong Zhang   PetscErrorCode ierr;
4555582bec1SHong Zhang   Mat            Aloc;
4565582bec1SHong Zhang   Mat_SeqAIJ     *a;
4575582bec1SHong Zhang   PetscInt       m,i,j,k=0,row,*aj;
4585582bec1SHong Zhang   PetscScalar    *aa;
4595582bec1SHong Zhang   FineGridCtx    *ml=(FineGridCtx*)ML_data;
4605582bec1SHong Zhang 
4615582bec1SHong Zhang   Aloc = ml->Aloc;
4625582bec1SHong Zhang   a    = (Mat_SeqAIJ*)Aloc->data;
4635582bec1SHong Zhang   ierr = MatGetSize(Aloc,&m,PETSC_NULL);CHKERRQ(ierr);
4645582bec1SHong Zhang 
4655582bec1SHong Zhang   for (i = 0; i<N_requested_rows; i++) {
4665582bec1SHong Zhang     row   = requested_rows[i];
4675582bec1SHong Zhang     row_lengths[i] = a->ilen[row];
4685582bec1SHong Zhang     if (allocated_space < k+row_lengths[i]) return(0);
4695582bec1SHong Zhang     if ( (row >= 0) || (row <= (m-1)) ) {
4705582bec1SHong Zhang       aj = a->j + a->i[row];
4715582bec1SHong Zhang       aa = a->a + a->i[row];
4725582bec1SHong Zhang       for (j=0; j<row_lengths[i]; j++){
4735582bec1SHong Zhang         columns[k]  = aj[j];
4745582bec1SHong Zhang         values[k++] = aa[j];
4755582bec1SHong Zhang       }
4765582bec1SHong Zhang     }
4775582bec1SHong Zhang   }
4785582bec1SHong Zhang   return(1);
4795582bec1SHong Zhang }
4805582bec1SHong Zhang 
4815582bec1SHong Zhang int PetscML_matvec(void *ML_data,int in_length,double p[],int out_length,double ap[])
4825582bec1SHong Zhang {
4835582bec1SHong Zhang   PetscErrorCode ierr;
4845582bec1SHong Zhang   FineGridCtx    *ml=(FineGridCtx*)ML_data;
4855582bec1SHong Zhang   Mat            A=ml->A, Aloc=ml->Aloc;
4865582bec1SHong Zhang   PetscMPIInt    size;
4875582bec1SHong Zhang   PetscScalar    *pwork=ml->pwork;
4885582bec1SHong Zhang   PetscInt       i;
4895582bec1SHong Zhang 
4905582bec1SHong Zhang   ierr = MPI_Comm_size(A->comm,&size);CHKERRQ(ierr);
4915582bec1SHong Zhang   if (size == 1){
49224a42b14SHong Zhang     ierr = VecPlaceArray(ml->x,p);CHKERRQ(ierr);
4935582bec1SHong Zhang   } else {
4945582bec1SHong Zhang     for (i=0; i<in_length; i++) pwork[i] = p[i];
4955582bec1SHong Zhang     PetscML_comm(pwork,ml);
49624a42b14SHong Zhang     ierr = VecPlaceArray(ml->x,pwork);CHKERRQ(ierr);
4975582bec1SHong Zhang   }
49824a42b14SHong Zhang   ierr = VecPlaceArray(ml->y,ap);CHKERRQ(ierr);
49924a42b14SHong Zhang   ierr = MatMult(Aloc,ml->x,ml->y);CHKERRQ(ierr);
5005582bec1SHong Zhang   return 0;
5015582bec1SHong Zhang }
5025582bec1SHong Zhang 
5035582bec1SHong Zhang int PetscML_comm(double p[],void *ML_data)
5045582bec1SHong Zhang {
5055582bec1SHong Zhang   PetscErrorCode ierr;
5065582bec1SHong Zhang   FineGridCtx    *ml=(FineGridCtx*)ML_data;
5075582bec1SHong Zhang   Mat            A=ml->A;
5085582bec1SHong Zhang   Mat_MPIAIJ     *a = (Mat_MPIAIJ*)A->data;
5095582bec1SHong Zhang   PetscMPIInt    size;
5105582bec1SHong Zhang   PetscInt       i,in_length=A->m,out_length=ml->Aloc->n;
5115582bec1SHong Zhang   PetscScalar    *array;
5125582bec1SHong Zhang 
5135582bec1SHong Zhang   ierr = MPI_Comm_size(A->comm,&size);CHKERRQ(ierr);
5145582bec1SHong Zhang   if (size == 1) return 0;
51524a42b14SHong Zhang 
51624a42b14SHong Zhang   ierr = VecPlaceArray(ml->y,p);CHKERRQ(ierr);
51724a42b14SHong Zhang   ierr = VecScatterBegin(ml->y,a->lvec,INSERT_VALUES,SCATTER_FORWARD,a->Mvctx);CHKERRQ(ierr);
51824a42b14SHong Zhang   ierr = VecScatterEnd(ml->y,a->lvec,INSERT_VALUES,SCATTER_FORWARD,a->Mvctx);CHKERRQ(ierr);
5195582bec1SHong Zhang   ierr = VecGetArray(a->lvec,&array);CHKERRQ(ierr);
5205582bec1SHong Zhang   for (i=in_length; i<out_length; i++){
5215582bec1SHong Zhang     p[i] = array[i-in_length];
5225582bec1SHong Zhang   }
5235582bec1SHong Zhang   return 0;
5245582bec1SHong Zhang }
5255582bec1SHong Zhang #undef __FUNCT__
5265582bec1SHong Zhang #define __FUNCT__ "MatMult_ML"
5275582bec1SHong Zhang PetscErrorCode MatMult_ML(Mat A,Vec x,Vec y)
5285582bec1SHong Zhang {
5295582bec1SHong Zhang   PetscErrorCode   ierr;
5305582bec1SHong Zhang   Mat_MLShell      *shell;
5315582bec1SHong Zhang   PetscScalar      *xarray,*yarray;
5325582bec1SHong Zhang   PetscInt         x_length,y_length;
5335582bec1SHong Zhang 
5345582bec1SHong Zhang   PetscFunctionBegin;
5355582bec1SHong Zhang   ierr = MatShellGetContext(A,(void *)&shell);CHKERRQ(ierr);
5365582bec1SHong Zhang   ierr = VecGetArray(x,&xarray);CHKERRQ(ierr);
5375582bec1SHong Zhang   ierr = VecGetArray(y,&yarray);CHKERRQ(ierr);
5385582bec1SHong Zhang   x_length = shell->mlmat->invec_leng;
5395582bec1SHong Zhang   y_length = shell->mlmat->outvec_leng;
5405582bec1SHong Zhang 
5415582bec1SHong Zhang   ML_Operator_Apply(shell->mlmat,x_length,xarray,y_length,yarray);
5425582bec1SHong Zhang 
5435582bec1SHong Zhang   ierr = VecRestoreArray(x,&xarray);CHKERRQ(ierr);
5445582bec1SHong Zhang   ierr = VecRestoreArray(y,&yarray);CHKERRQ(ierr);
5455582bec1SHong Zhang   PetscFunctionReturn(0);
5465582bec1SHong Zhang }
5475582bec1SHong Zhang /* MatMultAdd_ML -  Compute y = w + A*x */
5485582bec1SHong Zhang #undef __FUNCT__
5495582bec1SHong Zhang #define __FUNCT__ "MatMultAdd_ML"
5505582bec1SHong Zhang PetscErrorCode MatMultAdd_ML(Mat A,Vec x,Vec w,Vec y)
5515582bec1SHong Zhang {
5525582bec1SHong Zhang   PetscErrorCode    ierr;
5535582bec1SHong Zhang   Mat_MLShell       *shell;
5545582bec1SHong Zhang   PetscScalar       *xarray,*yarray;
5555582bec1SHong Zhang   const PetscScalar one=1.0;
5565582bec1SHong Zhang   PetscInt          x_length,y_length;
5575582bec1SHong Zhang 
5585582bec1SHong Zhang   PetscFunctionBegin;
5595582bec1SHong Zhang   ierr = MatShellGetContext(A,(void *)&shell);CHKERRQ(ierr);
5605582bec1SHong Zhang   ierr = VecGetArray(x,&xarray);CHKERRQ(ierr);
5615582bec1SHong Zhang   ierr = VecGetArray(y,&yarray);CHKERRQ(ierr);
5625582bec1SHong Zhang 
5635582bec1SHong Zhang   x_length = shell->mlmat->invec_leng;
5645582bec1SHong Zhang   y_length = shell->mlmat->outvec_leng;
5655582bec1SHong Zhang 
5665582bec1SHong Zhang   ML_Operator_Apply(shell->mlmat,x_length,xarray,y_length,yarray);
5675582bec1SHong Zhang 
5685582bec1SHong Zhang   ierr = VecRestoreArray(x,&xarray);CHKERRQ(ierr);
5695582bec1SHong Zhang   ierr = VecRestoreArray(y,&yarray);CHKERRQ(ierr);
5705582bec1SHong Zhang   ierr = VecAXPY(&one,w,y);CHKERRQ(ierr);
5715582bec1SHong Zhang 
5725582bec1SHong Zhang   PetscFunctionReturn(0);
5735582bec1SHong Zhang }
5745582bec1SHong Zhang 
5755582bec1SHong Zhang /* newtype is ignored because "ml" is not listed under Petsc MatType yet */
5765582bec1SHong Zhang #undef __FUNCT__
5775582bec1SHong Zhang #define __FUNCT__ "MatConvert_MPIAIJ_ML"
578eef31507SHong Zhang PetscErrorCode MatConvert_MPIAIJ_ML(Mat A,const MatType newtype,MatReuse scall,Mat *Aloc)
5795582bec1SHong Zhang {
5805582bec1SHong Zhang   PetscErrorCode  ierr;
5815582bec1SHong Zhang   Mat_MPIAIJ      *mpimat=(Mat_MPIAIJ*)A->data;
5825582bec1SHong Zhang   Mat_SeqAIJ      *mat,*a=(Mat_SeqAIJ*)(mpimat->A)->data,*b=(Mat_SeqAIJ*)(mpimat->B)->data;
5835582bec1SHong Zhang   PetscInt        *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j;
5845582bec1SHong Zhang   PetscScalar     *aa=a->a,*ba=b->a,*ca;
5855582bec1SHong Zhang   PetscInt        am=A->m,an=A->n,i,j,k;
5865582bec1SHong Zhang   PetscInt        *ci,*cj,ncols;
5875582bec1SHong Zhang 
5885582bec1SHong Zhang   PetscFunctionBegin;
5895582bec1SHong Zhang   if (am != an) SETERRQ2(PETSC_ERR_ARG_WRONG,"A must have a square diagonal portion, am: %d != an: %d",am,an);
5905582bec1SHong Zhang 
5915582bec1SHong Zhang   if (scall == MAT_INITIAL_MATRIX){
5925582bec1SHong Zhang     ierr = PetscMalloc((1+am)*sizeof(PetscInt),&ci);CHKERRQ(ierr);
5935582bec1SHong Zhang     ci[0] = 0;
5945582bec1SHong Zhang     for (i=0; i<am; i++){
5955582bec1SHong Zhang       ci[i+1] = ci[i] + (ai[i+1] - ai[i]) + (bi[i+1] - bi[i]);
5965582bec1SHong Zhang     }
5975582bec1SHong Zhang     ierr = PetscMalloc((1+ci[am])*sizeof(PetscInt),&cj);CHKERRQ(ierr);
5985582bec1SHong Zhang     ierr = PetscMalloc((1+ci[am])*sizeof(PetscScalar),&ca);CHKERRQ(ierr);
5995582bec1SHong Zhang 
6005582bec1SHong Zhang     k = 0;
6015582bec1SHong Zhang     for (i=0; i<am; i++){
6025582bec1SHong Zhang       /* diagonal portion of A */
6035582bec1SHong Zhang       ncols = ai[i+1] - ai[i];
6045582bec1SHong Zhang       for (j=0; j<ncols; j++) {
6055582bec1SHong Zhang         cj[k]   = *aj++;
6065582bec1SHong Zhang         ca[k++] = *aa++;
6075582bec1SHong Zhang       }
6085582bec1SHong Zhang       /* off-diagonal portion of A */
6095582bec1SHong Zhang       ncols = bi[i+1] - bi[i];
6105582bec1SHong Zhang       for (j=0; j<ncols; j++) {
6115582bec1SHong Zhang         cj[k]   = an + (*bj); bj++;
6125582bec1SHong Zhang         ca[k++] = *ba++;
6135582bec1SHong Zhang       }
6145582bec1SHong Zhang     }
6155582bec1SHong Zhang     if (k != ci[am]) SETERRQ2(PETSC_ERR_ARG_WRONG,"k: %d != ci[am]: %d",k,ci[am]);
6165582bec1SHong Zhang 
6175582bec1SHong Zhang     /* put together the new matrix */
6185582bec1SHong Zhang     an = mpimat->A->n+mpimat->B->n;
6195582bec1SHong Zhang     ierr = MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,am,an,ci,cj,ca,Aloc);CHKERRQ(ierr);
6205582bec1SHong Zhang 
6215582bec1SHong Zhang     /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */
6225582bec1SHong Zhang     /* Since these are PETSc arrays, change flags to free them as necessary. */
6235582bec1SHong Zhang     mat = (Mat_SeqAIJ*)(*Aloc)->data;
6245582bec1SHong Zhang     mat->freedata = PETSC_TRUE;
6255582bec1SHong Zhang     mat->nonew    = 0;
6265582bec1SHong Zhang   } else if (scall == MAT_REUSE_MATRIX){
6275582bec1SHong Zhang     mat=(Mat_SeqAIJ*)(*Aloc)->data;
6285582bec1SHong Zhang     ci = mat->i; cj = mat->j; ca = mat->a;
6295582bec1SHong Zhang     for (i=0; i<am; i++) {
6305582bec1SHong Zhang       /* diagonal portion of A */
6315582bec1SHong Zhang       ncols = ai[i+1] - ai[i];
6325582bec1SHong Zhang       for (j=0; j<ncols; j++) *ca++ = *aa++;
6335582bec1SHong Zhang       /* off-diagonal portion of A */
6345582bec1SHong Zhang       ncols = bi[i+1] - bi[i];
6355582bec1SHong Zhang       for (j=0; j<ncols; j++) *ca++ = *ba++;
6365582bec1SHong Zhang     }
6375582bec1SHong Zhang   } else {
6385582bec1SHong Zhang     SETERRQ1(PETSC_ERR_ARG_WRONG,"Invalid MatReuse %d",(int)scall);
6395582bec1SHong Zhang   }
6405582bec1SHong Zhang   PetscFunctionReturn(0);
6415582bec1SHong Zhang }
6425582bec1SHong Zhang extern PetscErrorCode MatDestroy_Shell(Mat);
6435582bec1SHong Zhang #undef __FUNCT__
6445582bec1SHong Zhang #define __FUNCT__ "MatDestroy_ML"
6455582bec1SHong Zhang PetscErrorCode MatDestroy_ML(Mat A)
6465582bec1SHong Zhang {
6475582bec1SHong Zhang   PetscErrorCode ierr;
6485582bec1SHong Zhang   Mat_MLShell    *shell;
6495582bec1SHong Zhang 
6505582bec1SHong Zhang   PetscFunctionBegin;
6515582bec1SHong Zhang   ierr = MatShellGetContext(A,(void *)&shell);CHKERRQ(ierr);
6525582bec1SHong Zhang   ierr = VecDestroy(shell->y);CHKERRQ(ierr);
6535582bec1SHong Zhang   ierr = PetscFree(shell);CHKERRQ(ierr);
6545582bec1SHong Zhang   ierr = MatDestroy_Shell(A);CHKERRQ(ierr);
6555582bec1SHong Zhang   PetscFunctionReturn(0);
6565582bec1SHong Zhang }
6575582bec1SHong Zhang 
6585582bec1SHong Zhang #undef __FUNCT__
659eef31507SHong Zhang #define __FUNCT__ "MatWrapML_SeqAIJ"
660eef31507SHong Zhang PetscErrorCode MatWrapML_SeqAIJ(ML_Operator *mlmat,Mat *newmat)
6615582bec1SHong Zhang {
662e14861a4SHong Zhang   struct ML_CSR_MSRdata *matdata = (struct ML_CSR_MSRdata *)mlmat->data;
6635582bec1SHong Zhang   PetscErrorCode  ierr;
664e14861a4SHong Zhang   PetscInt        m=mlmat->outvec_leng,n=mlmat->invec_leng,nnz[m],nz_max;
665e14861a4SHong Zhang   PetscInt        *ml_cols=matdata->columns,*aj,i,j,k;
666e14861a4SHong Zhang   PetscScalar     *ml_vals=matdata->values,*aa;
6675582bec1SHong Zhang 
6685582bec1SHong Zhang   PetscFunctionBegin;
669e14861a4SHong Zhang   if ( mlmat->getrow == NULL) SETERRQ(PETSC_ERR_ARG_NULL,"mlmat->getrow = NULL");
670ab718edeSHong Zhang   if (m != n){ /* ML Pmat and Rmat are in CSR format. Pass array pointers into SeqAIJ matrix */
671e14861a4SHong Zhang     ierr = MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,m,n,matdata->rowptr,ml_cols,ml_vals,newmat);CHKERRQ(ierr);
67224a42b14SHong Zhang     PetscFunctionReturn(0);
67324a42b14SHong Zhang   }
6745582bec1SHong Zhang 
675e14861a4SHong Zhang   /* ML Amat is in MSR format. Copy its data into SeqAIJ matrix */
6765582bec1SHong Zhang   ierr = MatCreate(PETSC_COMM_SELF,m,n,PETSC_DECIDE,PETSC_DECIDE,newmat);CHKERRQ(ierr);
6775582bec1SHong Zhang   ierr = MatSetType(*newmat,MATSEQAIJ);CHKERRQ(ierr);
678e14861a4SHong Zhang 
679e14861a4SHong Zhang   nz_max = 0;
6805582bec1SHong Zhang   for (i=0; i<m; i++) {
681e14861a4SHong Zhang     nnz[i] = ml_cols[i+1] - ml_cols[i] + 1;
682e14861a4SHong Zhang     if (nnz[i] > nz_max) nz_max = nnz[i];
6835582bec1SHong Zhang   }
6845582bec1SHong Zhang   ierr = MatSeqAIJSetPreallocation(*newmat,0,nnz);CHKERRQ(ierr);
685ab718edeSHong Zhang   ierr = MatSetOption(*newmat,MAT_COLUMNS_SORTED);CHKERRQ(ierr); /* check! */
6865582bec1SHong Zhang 
687e14861a4SHong Zhang   nz_max++;
688e14861a4SHong Zhang   ierr = PetscMalloc(nz_max*(sizeof(int)+sizeof(PetscScalar)),&aj);CHKERRQ(ierr);
689e14861a4SHong Zhang   aa = (PetscScalar*)(aj + nz_max);
69024a42b14SHong Zhang 
6915582bec1SHong Zhang   for (i=0; i<m; i++){
692e14861a4SHong Zhang     k = 0;
693e14861a4SHong Zhang     /* diagonal entry */
694e14861a4SHong Zhang     aj[k] = i; aa[k++] = ml_vals[i];
695e14861a4SHong Zhang     /* off diagonal entries */
696e14861a4SHong Zhang     for (j=ml_cols[i]; j<ml_cols[i+1]; j++){
697e14861a4SHong Zhang       aj[k] = ml_cols[j]; aa[k++] = ml_vals[j];
69824a42b14SHong Zhang     }
699ab718edeSHong Zhang     /* sort aj and aa */
700e14861a4SHong Zhang     ierr = PetscSortIntWithScalarArray(nnz[i],aj,aa);CHKERRQ(ierr);
701e14861a4SHong Zhang     ierr = MatSetValues(*newmat,1,&i,nnz[i],aj,aa,INSERT_VALUES);CHKERRQ(ierr);
7025582bec1SHong Zhang   }
7035582bec1SHong Zhang   ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
7045582bec1SHong Zhang   ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
705e14861a4SHong Zhang   ierr = PetscFree(aj);CHKERRQ(ierr);
7065582bec1SHong Zhang   PetscFunctionReturn(0);
7075582bec1SHong Zhang }
7085582bec1SHong Zhang 
7095582bec1SHong Zhang #undef __FUNCT__
710eef31507SHong Zhang #define __FUNCT__ "MatWrapML_SHELL"
711eef31507SHong Zhang PetscErrorCode MatWrapML_SHELL(ML_Operator *mlmat,Mat *newmat)
7125582bec1SHong Zhang {
7135582bec1SHong Zhang   PetscErrorCode ierr;
7145582bec1SHong Zhang   PetscInt       m,n;
7155582bec1SHong Zhang   ML_Comm        *MLcomm;
7165582bec1SHong Zhang   Mat_MLShell    *shellctx;
7175582bec1SHong Zhang 
7185582bec1SHong Zhang   PetscFunctionBegin;
7195582bec1SHong Zhang   m = mlmat->outvec_leng;
7205582bec1SHong Zhang   n = mlmat->invec_leng;
7215582bec1SHong Zhang   if (!m || !n){
7225582bec1SHong Zhang     newmat = PETSC_NULL;
7235582bec1SHong Zhang   } else {
7245582bec1SHong Zhang     MLcomm = mlmat->comm;
7255582bec1SHong Zhang     ierr = PetscNew(Mat_MLShell,&shellctx);CHKERRQ(ierr);
7265582bec1SHong Zhang     ierr = MatCreateShell(MLcomm->USR_comm,m,n,PETSC_DETERMINE,PETSC_DETERMINE,shellctx,newmat);CHKERRQ(ierr);
7275582bec1SHong Zhang     ierr = MatShellSetOperation(*newmat,MATOP_MULT,(void *)MatMult_ML);CHKERRQ(ierr);
7285582bec1SHong Zhang     ierr = MatShellSetOperation(*newmat,MATOP_MULT_ADD,(void *)MatMultAdd_ML);CHKERRQ(ierr);
7295582bec1SHong Zhang     shellctx->A         = *newmat;
7305582bec1SHong Zhang     shellctx->mlmat     = mlmat;
7315582bec1SHong Zhang     ierr = VecCreate(PETSC_COMM_WORLD,&shellctx->y);CHKERRQ(ierr);
7325582bec1SHong Zhang     ierr = VecSetSizes(shellctx->y,m,PETSC_DECIDE);CHKERRQ(ierr);
7335582bec1SHong Zhang     ierr = VecSetFromOptions(shellctx->y);CHKERRQ(ierr);
7345582bec1SHong Zhang     (*newmat)->ops->destroy = MatDestroy_ML;
7355582bec1SHong Zhang   }
7365582bec1SHong Zhang   PetscFunctionReturn(0);
7375582bec1SHong Zhang }
738e14861a4SHong Zhang 
739e14861a4SHong Zhang #undef __FUNCT__
740eef31507SHong Zhang #define __FUNCT__ "MatWrapML_MPIAIJ"
741eef31507SHong Zhang PetscErrorCode MatWrapML_MPIAIJ(ML_Operator *mlmat,Mat *newmat)
742e14861a4SHong Zhang {
743ab718edeSHong Zhang   struct ML_CSR_MSRdata *matdata = (struct ML_CSR_MSRdata *)mlmat->data;
744ab718edeSHong Zhang   PetscInt        *ml_cols=matdata->columns,*aj;
745ab718edeSHong Zhang   PetscScalar     *ml_vals=matdata->values,*aa;
746e14861a4SHong Zhang   PetscErrorCode  ierr;
747ab718edeSHong Zhang   PetscInt        i,j,k,*gordering;
748ab718edeSHong Zhang   PetscInt        m=mlmat->outvec_leng,n,nnzA[m],nnzB[m],nnz[m],nz_max,row;
749ab718edeSHong Zhang   Mat             A;
750e14861a4SHong Zhang 
751e14861a4SHong Zhang   PetscFunctionBegin;
752ab718edeSHong Zhang   if (mlmat->getrow == NULL) SETERRQ(PETSC_ERR_ARG_NULL,"mlmat->getrow = NULL");
753ab718edeSHong Zhang   n = mlmat->invec_leng;
754e14861a4SHong Zhang   if (m != n) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"m %d must equal to n %d",m,n);
755e14861a4SHong Zhang 
756ab718edeSHong Zhang   ierr = MatCreate(mlmat->comm->USR_comm,m,n,PETSC_DECIDE,PETSC_DECIDE,&A);CHKERRQ(ierr);
757ab718edeSHong Zhang   ierr = MatSetType(A,MATMPIAIJ);CHKERRQ(ierr);
758e14861a4SHong Zhang   nz_max = 0;
759e14861a4SHong Zhang   for (i=0; i<m; i++){
760ab718edeSHong Zhang     nnz[i] = ml_cols[i+1] - ml_cols[i] + 1;
761e14861a4SHong Zhang     if (nz_max < nnz[i]) nz_max = nnz[i];
762ab718edeSHong Zhang     nnzA[i] = 1; /* diag */
763ab718edeSHong Zhang     for (j=ml_cols[i]; j<ml_cols[i+1]; j++){
764ab718edeSHong Zhang       if (ml_cols[j] < m) nnzA[i]++;
765e14861a4SHong Zhang     }
766e14861a4SHong Zhang     nnzB[i] = nnz[i] - nnzA[i];
767e14861a4SHong Zhang   }
768ab718edeSHong Zhang   ierr = MatMPIAIJSetPreallocation(A,0,nnzA,0,nnzB);CHKERRQ(ierr);
769e14861a4SHong Zhang 
770ab718edeSHong Zhang   /* insert mat values -- remap row and column indices */
771ab718edeSHong Zhang   nz_max++;
772ab718edeSHong Zhang   ierr = PetscMalloc(nz_max*(sizeof(int)+sizeof(PetscScalar)),&aj);CHKERRQ(ierr);
773ab718edeSHong Zhang   aa = (PetscScalar*)(aj + nz_max);
774ab718edeSHong Zhang   ML_build_global_numbering(mlmat,mlmat->comm,&gordering);
775e14861a4SHong Zhang   for (i=0; i<m; i++){
776e14861a4SHong Zhang     row = gordering[i];
777ab718edeSHong Zhang     k = 0;
778ab718edeSHong Zhang     /* diagonal entry */
779ab718edeSHong Zhang     aj[k] = row; aa[k++] = ml_vals[i];
780ab718edeSHong Zhang     /* off diagonal entries */
781ab718edeSHong Zhang     for (j=ml_cols[i]; j<ml_cols[i+1]; j++){
782ab718edeSHong Zhang       aj[k] = gordering[ml_cols[j]]; aa[k++] = ml_vals[j];
783e14861a4SHong Zhang     }
784ab718edeSHong Zhang     ierr = MatSetValues(A,1,&row,nnz[i],aj,aa,INSERT_VALUES);CHKERRQ(ierr);
785e14861a4SHong Zhang   }
786ab718edeSHong Zhang   ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
787ab718edeSHong Zhang   ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
788ab718edeSHong Zhang   *newmat = A;
789e14861a4SHong Zhang 
790ab718edeSHong Zhang   ierr = PetscFree(aj);CHKERRQ(ierr);
791e14861a4SHong Zhang   PetscFunctionReturn(0);
792e14861a4SHong Zhang }
793