xref: /petsc/src/ksp/pc/impls/gamg/geo.c (revision 2e68589b902172b31894c5911c32a0b8b89b52fd)
1*2e68589bSMark F. Adams /*
2*2e68589bSMark F. Adams  GAMG geometric-algebric multiogrid PC - Mark Adams 2011
3*2e68589bSMark F. Adams  */
4*2e68589bSMark F. Adams 
5*2e68589bSMark F. Adams #include <../src/ksp/pc/impls/gamg/gamg.h>        /*I "petscpc.h" I*/
6*2e68589bSMark F. Adams #include <private/kspimpl.h>
7*2e68589bSMark F. Adams 
8*2e68589bSMark F. Adams #if defined(PETSC_HAVE_TRIANGLE)
9*2e68589bSMark F. Adams #define REAL PetscReal
10*2e68589bSMark F. Adams #include <triangle.h>
11*2e68589bSMark F. Adams #endif
12*2e68589bSMark F. Adams 
13*2e68589bSMark F. Adams #include <assert.h>
14*2e68589bSMark F. Adams #include <petscblaslapack.h>
15*2e68589bSMark F. Adams 
16*2e68589bSMark F. Adams /* -------------------------------------------------------------------------- */
17*2e68589bSMark F. Adams /*
18*2e68589bSMark F. Adams    PCSetCoordinates_GEO
19*2e68589bSMark F. Adams 
20*2e68589bSMark F. Adams    Input Parameter:
21*2e68589bSMark F. Adams    .  pc - the preconditioner context
22*2e68589bSMark F. Adams */
23*2e68589bSMark F. Adams EXTERN_C_BEGIN
24*2e68589bSMark F. Adams #undef __FUNCT__
25*2e68589bSMark F. Adams #define __FUNCT__ "PCSetCoordinates_GEO"
26*2e68589bSMark F. Adams PetscErrorCode PCSetCoordinates_GEO( PC pc, PetscInt ndm, PetscReal *coords )
27*2e68589bSMark F. Adams {
28*2e68589bSMark F. Adams   PC_MG          *mg = (PC_MG*)pc->data;
29*2e68589bSMark F. Adams   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;
30*2e68589bSMark F. Adams   PetscErrorCode ierr;
31*2e68589bSMark F. Adams   PetscInt       arrsz,bs,my0,kk,ii,nloc,Iend;
32*2e68589bSMark F. Adams   Mat            Amat = pc->pmat;
33*2e68589bSMark F. Adams 
34*2e68589bSMark F. Adams   PetscFunctionBegin;
35*2e68589bSMark F. Adams   PetscValidHeaderSpecific( Amat, MAT_CLASSID, 1 );
36*2e68589bSMark F. Adams   ierr  = MatGetBlockSize( Amat, &bs );               CHKERRQ( ierr );
37*2e68589bSMark F. Adams   ierr  = MatGetOwnershipRange( Amat, &my0, &Iend ); CHKERRQ(ierr);
38*2e68589bSMark F. Adams   nloc = (Iend-my0)/bs;
39*2e68589bSMark F. Adams   if((Iend-my0)%bs!=0) SETERRQ1(((PetscObject)Amat)->comm,PETSC_ERR_ARG_WRONG, "Bad local size %d.",nloc);
40*2e68589bSMark F. Adams 
41*2e68589bSMark F. Adams   pc_gamg->data_rows = 1;
42*2e68589bSMark F. Adams   if( coords==0 && nloc > 0 ) {
43*2e68589bSMark F. Adams     SETERRQ(((PetscObject)Amat)->comm,PETSC_ERR_ARG_WRONG, "Need coordinates for pc_gamg_type 'geo'.");
44*2e68589bSMark F. Adams   }
45*2e68589bSMark F. Adams   pc_gamg->data_cols = ndm; /* coordinates */
46*2e68589bSMark F. Adams 
47*2e68589bSMark F. Adams   arrsz = nloc*pc_gamg->data_rows*pc_gamg->data_cols;
48*2e68589bSMark F. Adams 
49*2e68589bSMark F. Adams   /* create data - syntactic sugar that should be refactored at some point */
50*2e68589bSMark F. Adams   if (pc_gamg->data==0 || (pc_gamg->data_sz != arrsz)) {
51*2e68589bSMark F. Adams     ierr = PetscFree( pc_gamg->data );  CHKERRQ(ierr);
52*2e68589bSMark F. Adams     ierr = PetscMalloc((arrsz+1)*sizeof(PetscReal), &pc_gamg->data ); CHKERRQ(ierr);
53*2e68589bSMark F. Adams   }
54*2e68589bSMark F. Adams   for(kk=0;kk<arrsz;kk++)pc_gamg->data[kk] = -999.;
55*2e68589bSMark F. Adams   pc_gamg->data[arrsz] = -99.;
56*2e68589bSMark F. Adams   /* copy data in - column oriented */
57*2e68589bSMark F. Adams   for( kk = 0 ; kk < nloc ; kk++ ){
58*2e68589bSMark F. Adams     for( ii = 0 ; ii < ndm ; ii++ ) {
59*2e68589bSMark F. Adams       pc_gamg->data[ii*nloc + kk] =  coords[kk*ndm + ii];
60*2e68589bSMark F. Adams     }
61*2e68589bSMark F. Adams   }
62*2e68589bSMark F. Adams   assert(pc_gamg->data[arrsz] == -99.);
63*2e68589bSMark F. Adams 
64*2e68589bSMark F. Adams   pc_gamg->data_sz = arrsz;
65*2e68589bSMark F. Adams 
66*2e68589bSMark F. Adams   PetscFunctionReturn(0);
67*2e68589bSMark F. Adams }
68*2e68589bSMark F. Adams EXTERN_C_END
69*2e68589bSMark F. Adams 
70*2e68589bSMark F. Adams /* -------------------------------------------------------------------------- */
71*2e68589bSMark F. Adams /*
72*2e68589bSMark F. Adams    PCSetData_GEO
73*2e68589bSMark F. Adams 
74*2e68589bSMark F. Adams   Input Parameter:
75*2e68589bSMark F. Adams    . pc -
76*2e68589bSMark F. Adams */
77*2e68589bSMark F. Adams #undef __FUNCT__
78*2e68589bSMark F. Adams #define __FUNCT__ "PCSetData_GEO"
79*2e68589bSMark F. Adams PetscErrorCode PCSetData_GEO( PC pc )
80*2e68589bSMark F. Adams {
81*2e68589bSMark F. Adams   PetscFunctionBegin;
82*2e68589bSMark F. Adams   SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_LIB,"GEO MG needs coordinates");
83*2e68589bSMark F. Adams }
84*2e68589bSMark F. Adams 
85*2e68589bSMark F. Adams /* -------------------------------------------------------------------------- */
86*2e68589bSMark F. Adams /*
87*2e68589bSMark F. Adams    PCSetFromOptions_GEO
88*2e68589bSMark F. Adams 
89*2e68589bSMark F. Adams   Input Parameter:
90*2e68589bSMark F. Adams    . pc -
91*2e68589bSMark F. Adams */
92*2e68589bSMark F. Adams #undef __FUNCT__
93*2e68589bSMark F. Adams #define __FUNCT__ "PCSetFromOptions_GEO"
94*2e68589bSMark F. Adams PetscErrorCode PCSetFromOptions_GEO( PC pc )
95*2e68589bSMark F. Adams {
96*2e68589bSMark F. Adams   PetscErrorCode  ierr;
97*2e68589bSMark F. Adams   PC_MG           *mg = (PC_MG*)pc->data;
98*2e68589bSMark F. Adams   PC_GAMG         *pc_gamg = (PC_GAMG*)mg->innerctx;
99*2e68589bSMark F. Adams 
100*2e68589bSMark F. Adams   PetscFunctionBegin;
101*2e68589bSMark F. Adams   ierr = PetscOptionsHead("GAMG-GEO options"); CHKERRQ(ierr);
102*2e68589bSMark F. Adams   {
103*2e68589bSMark F. Adams     /* -pc_gamg_sa_nsmooths */
104*2e68589bSMark F. Adams     /* pc_gamg_sa->smooths = 0; */
105*2e68589bSMark F. Adams     /* ierr = PetscOptionsInt("-pc_gamg_agg_nsmooths", */
106*2e68589bSMark F. Adams     /*                        "smoothing steps for smoothed aggregation, usually 1 (0)", */
107*2e68589bSMark F. Adams     /*                        "PCGAMGSetNSmooths_AGG", */
108*2e68589bSMark F. Adams     /*                        pc_gamg_sa->smooths, */
109*2e68589bSMark F. Adams     /*                        &pc_gamg_sa->smooths, */
110*2e68589bSMark F. Adams     /*                        &flag);  */
111*2e68589bSMark F. Adams     /* CHKERRQ(ierr); */
112*2e68589bSMark F. Adams   }
113*2e68589bSMark F. Adams   ierr = PetscOptionsTail();CHKERRQ(ierr);
114*2e68589bSMark F. Adams 
115*2e68589bSMark F. Adams   /* call base class */
116*2e68589bSMark F. Adams   ierr = PCSetFromOptions_GAMG( pc ); CHKERRQ(ierr);
117*2e68589bSMark F. Adams 
118*2e68589bSMark F. Adams   if( pc_gamg->verbose ) {
119*2e68589bSMark F. Adams     PetscPrintf(PETSC_COMM_WORLD,"[%d]%s done\n",0,__FUNCT__);
120*2e68589bSMark F. Adams   }
121*2e68589bSMark F. Adams 
122*2e68589bSMark F. Adams   PetscFunctionReturn(0);
123*2e68589bSMark F. Adams }
124*2e68589bSMark F. Adams 
125*2e68589bSMark F. Adams /* -------------------------------------------------------------------------- */
126*2e68589bSMark F. Adams /*
127*2e68589bSMark F. Adams  PCCreateGAMG_GEO - nothing to do here now
128*2e68589bSMark F. Adams 
129*2e68589bSMark F. Adams   Input Parameter:
130*2e68589bSMark F. Adams    . pc -
131*2e68589bSMark F. Adams */
132*2e68589bSMark F. Adams #undef __FUNCT__
133*2e68589bSMark F. Adams #define __FUNCT__ "PCCreateGAMG_GEO"
134*2e68589bSMark F. Adams PetscErrorCode  PCCreateGAMG_GEO( PC pc )
135*2e68589bSMark F. Adams {
136*2e68589bSMark F. Adams   PetscErrorCode  ierr;
137*2e68589bSMark F. Adams   PC_MG           *mg = (PC_MG*)pc->data;
138*2e68589bSMark F. Adams   PC_GAMG         *pc_gamg = (PC_GAMG*)mg->innerctx;
139*2e68589bSMark F. Adams 
140*2e68589bSMark F. Adams   PetscFunctionBegin;
141*2e68589bSMark F. Adams   pc->ops->setfromoptions = PCSetFromOptions_GEO;
142*2e68589bSMark F. Adams   /* pc->ops->destroy        = PCDestroy_GEO; */
143*2e68589bSMark F. Adams   /* reset does not do anything; setup not virtual */
144*2e68589bSMark F. Adams 
145*2e68589bSMark F. Adams   /* set internal function pointers */
146*2e68589bSMark F. Adams   pc_gamg->createprolongator = PCGAMGcreateProl_GEO;
147*2e68589bSMark F. Adams   pc_gamg->createdefaultdata = PCSetData_GEO;
148*2e68589bSMark F. Adams 
149*2e68589bSMark F. Adams   ierr = PetscObjectComposeFunctionDynamic( (PetscObject)pc,
150*2e68589bSMark F. Adams                                             "PCSetCoordinates_C",
151*2e68589bSMark F. Adams                                             "PCSetCoordinates_GEO",
152*2e68589bSMark F. Adams                                             PCSetCoordinates_GEO);CHKERRQ(ierr);
153*2e68589bSMark F. Adams 
154*2e68589bSMark F. Adams   PetscFunctionReturn(0);
155*2e68589bSMark F. Adams }
156*2e68589bSMark F. Adams 
157*2e68589bSMark F. Adams /* -------------------------------------------------------------------------- */
158*2e68589bSMark F. Adams /*
159*2e68589bSMark F. Adams  triangulateAndFormProl
160*2e68589bSMark F. Adams 
161*2e68589bSMark F. Adams    Input Parameter:
162*2e68589bSMark F. Adams    . selected_2 - list of selected local ID, includes selected ghosts
163*2e68589bSMark F. Adams    . nnodes -
164*2e68589bSMark F. Adams    . coords[2*nnodes] - column vector of local coordinates w/ ghosts
165*2e68589bSMark F. Adams    . selected_1 - selected IDs that go with base (1) graph
166*2e68589bSMark F. Adams    . locals_llist - linked list with (some) locality info of base graph
167*2e68589bSMark F. Adams    . crsGID[selected.size()] - global index for prolongation operator
168*2e68589bSMark F. Adams    . bs - block size
169*2e68589bSMark F. Adams   Output Parameter:
170*2e68589bSMark F. Adams    . a_Prol - prolongation operator
171*2e68589bSMark F. Adams    . a_worst_best - measure of worst missed fine vertex, 0 is no misses
172*2e68589bSMark F. Adams */
173*2e68589bSMark F. Adams #undef __FUNCT__
174*2e68589bSMark F. Adams #define __FUNCT__ "triangulateAndFormProl"
175*2e68589bSMark F. Adams PetscErrorCode triangulateAndFormProl( IS  selected_2, /* list of selected local ID, includes selected ghosts */
176*2e68589bSMark F. Adams 				       const PetscInt nnodes,
177*2e68589bSMark F. Adams                                        const PetscReal coords[], /* column vector of local coordinates w/ ghosts */
178*2e68589bSMark F. Adams                                        IS  selected_1, /* list of selected local ID, includes selected ghosts */
179*2e68589bSMark F. Adams                                        IS  locals_llist, /* linked list from selected vertices of aggregate unselected vertices */
180*2e68589bSMark F. Adams 				       const PetscInt crsGID[],
181*2e68589bSMark F. Adams                                        const PetscInt bs,
182*2e68589bSMark F. Adams                                        Mat a_Prol, /* prolongation operator (output) */
183*2e68589bSMark F. Adams                                        PetscReal *a_worst_best /* measure of worst missed fine vertex, 0 is no misses */
184*2e68589bSMark F. Adams                                        )
185*2e68589bSMark F. Adams {
186*2e68589bSMark F. Adams #if defined(PETSC_HAVE_TRIANGLE)
187*2e68589bSMark F. Adams   PetscErrorCode       ierr;
188*2e68589bSMark F. Adams   PetscInt             jj,tid,tt,idx,nselected_1,nselected_2;
189*2e68589bSMark F. Adams   struct triangulateio in,mid;
190*2e68589bSMark F. Adams   const PetscInt      *selected_idx_1,*selected_idx_2,*llist_idx;
191*2e68589bSMark F. Adams   PetscMPIInt          mype,npe;
192*2e68589bSMark F. Adams   PetscInt             Istart,Iend,nFineLoc,myFine0;
193*2e68589bSMark F. Adams   int kk,nPlotPts,sid;
194*2e68589bSMark F. Adams 
195*2e68589bSMark F. Adams   PetscFunctionBegin;
196*2e68589bSMark F. Adams   *a_worst_best = 0.0;
197*2e68589bSMark F. Adams   ierr = MPI_Comm_rank(((PetscObject)a_Prol)->comm,&mype);    CHKERRQ(ierr);
198*2e68589bSMark F. Adams   ierr = MPI_Comm_size(((PetscObject)a_Prol)->comm,&npe);     CHKERRQ(ierr);
199*2e68589bSMark F. Adams   ierr = ISGetLocalSize( selected_1, &nselected_1 );        CHKERRQ(ierr);
200*2e68589bSMark F. Adams   ierr = ISGetLocalSize( selected_2, &nselected_2 );        CHKERRQ(ierr);
201*2e68589bSMark F. Adams   if(nselected_2 == 1 || nselected_2 == 2 ){ /* 0 happens on idle processors */
202*2e68589bSMark F. Adams     /* SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Not enough points - error in stopping logic",nselected_2); */
203*2e68589bSMark F. Adams     *a_worst_best = 100.0; /* this will cause a stop, but not globalized (should not happen) */
204*2e68589bSMark F. Adams #ifdef VERBOSE
205*2e68589bSMark F. Adams     PetscPrintf(PETSC_COMM_SELF,"[%d]%s %d selected point - bailing out\n",mype,__FUNCT__,nselected_2);
206*2e68589bSMark F. Adams #endif
207*2e68589bSMark F. Adams     PetscFunctionReturn(0);
208*2e68589bSMark F. Adams   }
209*2e68589bSMark F. Adams   ierr = MatGetOwnershipRange( a_Prol, &Istart, &Iend );  CHKERRQ(ierr);
210*2e68589bSMark F. Adams   nFineLoc = (Iend-Istart)/bs; myFine0 = Istart/bs;
211*2e68589bSMark F. Adams   nPlotPts = nFineLoc; /* locals */
212*2e68589bSMark F. Adams   /* traingle */
213*2e68589bSMark F. Adams   /* Define input points - in*/
214*2e68589bSMark F. Adams   in.numberofpoints = nselected_2;
215*2e68589bSMark F. Adams   in.numberofpointattributes = 0;
216*2e68589bSMark F. Adams   /* get nselected points */
217*2e68589bSMark F. Adams   ierr = PetscMalloc( 2*(nselected_2)*sizeof(REAL), &in.pointlist ); CHKERRQ(ierr);
218*2e68589bSMark F. Adams   ierr = ISGetIndices( selected_2, &selected_idx_2 );     CHKERRQ(ierr);
219*2e68589bSMark F. Adams 
220*2e68589bSMark F. Adams   for(kk=0,sid=0;kk<nselected_2;kk++,sid += 2){
221*2e68589bSMark F. Adams     PetscInt lid = selected_idx_2[kk];
222*2e68589bSMark F. Adams     in.pointlist[sid] = coords[lid];
223*2e68589bSMark F. Adams     in.pointlist[sid+1] = coords[nnodes + lid];
224*2e68589bSMark F. Adams     if(lid>=nFineLoc) nPlotPts++;
225*2e68589bSMark F. Adams   }
226*2e68589bSMark F. Adams   assert(sid==2*nselected_2);
227*2e68589bSMark F. Adams 
228*2e68589bSMark F. Adams   in.numberofsegments = 0;
229*2e68589bSMark F. Adams   in.numberofedges = 0;
230*2e68589bSMark F. Adams   in.numberofholes = 0;
231*2e68589bSMark F. Adams   in.numberofregions = 0;
232*2e68589bSMark F. Adams   in.trianglelist = 0;
233*2e68589bSMark F. Adams   in.segmentmarkerlist = 0;
234*2e68589bSMark F. Adams   in.pointattributelist = 0;
235*2e68589bSMark F. Adams   in.pointmarkerlist = 0;
236*2e68589bSMark F. Adams   in.triangleattributelist = 0;
237*2e68589bSMark F. Adams   in.trianglearealist = 0;
238*2e68589bSMark F. Adams   in.segmentlist = 0;
239*2e68589bSMark F. Adams   in.holelist = 0;
240*2e68589bSMark F. Adams   in.regionlist = 0;
241*2e68589bSMark F. Adams   in.edgelist = 0;
242*2e68589bSMark F. Adams   in.edgemarkerlist = 0;
243*2e68589bSMark F. Adams   in.normlist = 0;
244*2e68589bSMark F. Adams   /* triangulate */
245*2e68589bSMark F. Adams   mid.pointlist = 0;            /* Not needed if -N switch used. */
246*2e68589bSMark F. Adams   /* Not needed if -N switch used or number of point attributes is zero: */
247*2e68589bSMark F. Adams   mid.pointattributelist = 0;
248*2e68589bSMark F. Adams   mid.pointmarkerlist = 0; /* Not needed if -N or -B switch used. */
249*2e68589bSMark F. Adams   mid.trianglelist = 0;          /* Not needed if -E switch used. */
250*2e68589bSMark F. Adams   /* Not needed if -E switch used or number of triangle attributes is zero: */
251*2e68589bSMark F. Adams   mid.triangleattributelist = 0;
252*2e68589bSMark F. Adams   mid.neighborlist = 0;         /* Needed only if -n switch used. */
253*2e68589bSMark F. Adams   /* Needed only if segments are output (-p or -c) and -P not used: */
254*2e68589bSMark F. Adams   mid.segmentlist = 0;
255*2e68589bSMark F. Adams   /* Needed only if segments are output (-p or -c) and -P and -B not used: */
256*2e68589bSMark F. Adams   mid.segmentmarkerlist = 0;
257*2e68589bSMark F. Adams   mid.edgelist = 0;             /* Needed only if -e switch used. */
258*2e68589bSMark F. Adams   mid.edgemarkerlist = 0;   /* Needed if -e used and -B not used. */
259*2e68589bSMark F. Adams   mid.numberoftriangles = 0;
260*2e68589bSMark F. Adams 
261*2e68589bSMark F. Adams   /* Triangulate the points.  Switches are chosen to read and write a  */
262*2e68589bSMark F. Adams   /*   PSLG (p), preserve the convex hull (c), number everything from  */
263*2e68589bSMark F. Adams   /*   zero (z), assign a regional attribute to each element (A), and  */
264*2e68589bSMark F. Adams   /*   produce an edge list (e), a Voronoi diagram (v), and a triangle */
265*2e68589bSMark F. Adams   /*   neighbor list (n).                                            */
266*2e68589bSMark F. Adams   if(nselected_2 != 0){ /* inactive processor */
267*2e68589bSMark F. Adams     char args[] = "npczQ"; /* c is needed ? */
268*2e68589bSMark F. Adams     triangulate(args, &in, &mid, (struct triangulateio *) NULL );
269*2e68589bSMark F. Adams     /* output .poly files for 'showme' */
270*2e68589bSMark F. Adams     if( !PETSC_TRUE ) {
271*2e68589bSMark F. Adams       static int level = 1;
272*2e68589bSMark F. Adams       FILE *file; char fname[32];
273*2e68589bSMark F. Adams 
274*2e68589bSMark F. Adams       sprintf(fname,"C%d_%d.poly",level,mype); file = fopen(fname, "w");
275*2e68589bSMark F. Adams       /*First line: <# of vertices> <dimension (must be 2)> <# of attributes> <# of boundary markers (0 or 1)>*/
276*2e68589bSMark F. Adams       fprintf(file, "%d  %d  %d  %d\n",in.numberofpoints,2,0,0);
277*2e68589bSMark F. Adams       /*Following lines: <vertex #> <x> <y> */
278*2e68589bSMark F. Adams       for(kk=0,sid=0;kk<in.numberofpoints;kk++,sid += 2){
279*2e68589bSMark F. Adams         fprintf(file, "%d %e %e\n",kk,in.pointlist[sid],in.pointlist[sid+1]);
280*2e68589bSMark F. Adams       }
281*2e68589bSMark F. Adams       /*One line: <# of segments> <# of boundary markers (0 or 1)> */
282*2e68589bSMark F. Adams       fprintf(file, "%d  %d\n",0,0);
283*2e68589bSMark F. Adams       /*Following lines: <segment #> <endpoint> <endpoint> [boundary marker] */
284*2e68589bSMark F. Adams       /* One line: <# of holes> */
285*2e68589bSMark F. Adams       fprintf(file, "%d\n",0);
286*2e68589bSMark F. Adams       /* Following lines: <hole #> <x> <y> */
287*2e68589bSMark F. Adams       /* Optional line: <# of regional attributes and/or area constraints> */
288*2e68589bSMark F. Adams       /* Optional following lines: <region #> <x> <y> <attribute> <maximum area> */
289*2e68589bSMark F. Adams       fclose(file);
290*2e68589bSMark F. Adams 
291*2e68589bSMark F. Adams       /* elems */
292*2e68589bSMark F. Adams       sprintf(fname,"C%d_%d.ele",level,mype); file = fopen(fname, "w");
293*2e68589bSMark F. Adams       /* First line: <# of triangles> <nodes per triangle> <# of attributes> */
294*2e68589bSMark F. Adams       fprintf(file, "%d %d %d\n",mid.numberoftriangles,3,0);
295*2e68589bSMark F. Adams       /* Remaining lines: <triangle #> <node> <node> <node> ... [attributes] */
296*2e68589bSMark F. Adams       for(kk=0,sid=0;kk<mid.numberoftriangles;kk++,sid += 3){
297*2e68589bSMark F. Adams         fprintf(file, "%d %d %d %d\n",kk,mid.trianglelist[sid],mid.trianglelist[sid+1],mid.trianglelist[sid+2]);
298*2e68589bSMark F. Adams       }
299*2e68589bSMark F. Adams       fclose(file);
300*2e68589bSMark F. Adams 
301*2e68589bSMark F. Adams       sprintf(fname,"C%d_%d.node",level,mype); file = fopen(fname, "w");
302*2e68589bSMark F. Adams       /* First line: <# of vertices> <dimension (must be 2)> <# of attributes> <# of boundary markers (0 or 1)> */
303*2e68589bSMark F. Adams       /* fprintf(file, "%d  %d  %d  %d\n",in.numberofpoints,2,0,0); */
304*2e68589bSMark F. Adams       fprintf(file, "%d  %d  %d  %d\n",nPlotPts,2,0,0);
305*2e68589bSMark F. Adams       /*Following lines: <vertex #> <x> <y> */
306*2e68589bSMark F. Adams       for(kk=0,sid=0;kk<in.numberofpoints;kk++,sid+=2){
307*2e68589bSMark F. Adams         fprintf(file, "%d %e %e\n",kk,in.pointlist[sid],in.pointlist[sid+1]);
308*2e68589bSMark F. Adams       }
309*2e68589bSMark F. Adams 
310*2e68589bSMark F. Adams       sid /= 2;
311*2e68589bSMark F. Adams       for(jj=0;jj<nFineLoc;jj++){
312*2e68589bSMark F. Adams         PetscBool sel = PETSC_TRUE;
313*2e68589bSMark F. Adams         for( kk=0 ; kk<nselected_2 && sel ; kk++ ){
314*2e68589bSMark F. Adams           PetscInt lid = selected_idx_2[kk];
315*2e68589bSMark F. Adams           if( lid == jj ) sel = PETSC_FALSE;
316*2e68589bSMark F. Adams         }
317*2e68589bSMark F. Adams         if( sel ) {
318*2e68589bSMark F. Adams           fprintf(file, "%d %e %e\n",sid++,coords[jj],coords[nnodes + jj]);
319*2e68589bSMark F. Adams         }
320*2e68589bSMark F. Adams       }
321*2e68589bSMark F. Adams       fclose(file);
322*2e68589bSMark F. Adams       assert(sid==nPlotPts);
323*2e68589bSMark F. Adams       level++;
324*2e68589bSMark F. Adams     }
325*2e68589bSMark F. Adams   }
326*2e68589bSMark F. Adams #if defined PETSC_USE_LOG
327*2e68589bSMark F. Adams   ierr = PetscLogEventBegin(gamg_setup_events[FIND_V],0,0,0,0);CHKERRQ(ierr);
328*2e68589bSMark F. Adams #endif
329*2e68589bSMark F. Adams   { /* form P - setup some maps */
330*2e68589bSMark F. Adams     PetscInt clid_iterator;
331*2e68589bSMark F. Adams     PetscInt *nTri, *node_tri;
332*2e68589bSMark F. Adams 
333*2e68589bSMark F. Adams     ierr = PetscMalloc( nselected_2*sizeof(PetscInt), &node_tri ); CHKERRQ(ierr);
334*2e68589bSMark F. Adams     ierr = PetscMalloc( nselected_2*sizeof(PetscInt), &nTri ); CHKERRQ(ierr);
335*2e68589bSMark F. Adams 
336*2e68589bSMark F. Adams     /* need list of triangles on node */
337*2e68589bSMark F. Adams     for(kk=0;kk<nselected_2;kk++) nTri[kk] = 0;
338*2e68589bSMark F. Adams     for(tid=0,kk=0;tid<mid.numberoftriangles;tid++){
339*2e68589bSMark F. Adams       for(jj=0;jj<3;jj++) {
340*2e68589bSMark F. Adams         PetscInt cid = mid.trianglelist[kk++];
341*2e68589bSMark F. Adams         if( nTri[cid] == 0 ) node_tri[cid] = tid;
342*2e68589bSMark F. Adams         nTri[cid]++;
343*2e68589bSMark F. Adams       }
344*2e68589bSMark F. Adams     }
345*2e68589bSMark F. Adams #define EPS 1.e-12
346*2e68589bSMark F. Adams     /* find points and set prolongation */
347*2e68589bSMark F. Adams     ierr = ISGetIndices( selected_1, &selected_idx_1 );     CHKERRQ(ierr);
348*2e68589bSMark F. Adams     ierr = ISGetIndices( locals_llist, &llist_idx );     CHKERRQ(ierr);
349*2e68589bSMark F. Adams     for( clid_iterator = 0 ; clid_iterator < nselected_1 ; clid_iterator++ ){
350*2e68589bSMark F. Adams       PetscInt flid = selected_idx_1[clid_iterator]; assert(flid != -1);
351*2e68589bSMark F. Adams       PetscScalar AA[3][3];
352*2e68589bSMark F. Adams       PetscBLASInt N=3,NRHS=1,LDA=3,IPIV[3],LDB=3,INFO;
353*2e68589bSMark F. Adams       do{
354*2e68589bSMark F. Adams         if( flid < nFineLoc ) {  /* could be a ghost */
355*2e68589bSMark F. Adams           PetscInt bestTID = -1; PetscReal best_alpha = 1.e10;
356*2e68589bSMark F. Adams           const PetscInt fgid = flid + myFine0;
357*2e68589bSMark F. Adams           /* compute shape function for gid */
358*2e68589bSMark F. Adams           const PetscReal fcoord[3] = { coords[flid], coords[nnodes + flid], 1.0 };
359*2e68589bSMark F. Adams           PetscBool haveit = PETSC_FALSE; PetscScalar alpha[3]; PetscInt clids[3];
360*2e68589bSMark F. Adams           /* look for it */
361*2e68589bSMark F. Adams           for( tid = node_tri[clid_iterator], jj=0;
362*2e68589bSMark F. Adams                jj < 5 && !haveit && tid != -1;
363*2e68589bSMark F. Adams                jj++ ){
364*2e68589bSMark F. Adams             for(tt=0;tt<3;tt++){
365*2e68589bSMark F. Adams               PetscInt cid2 = mid.trianglelist[3*tid + tt];
366*2e68589bSMark F. Adams               PetscInt lid2 = selected_idx_2[cid2];
367*2e68589bSMark F. Adams               AA[tt][0] = coords[lid2]; AA[tt][1] = coords[nnodes + lid2]; AA[tt][2] = 1.0;
368*2e68589bSMark F. Adams               clids[tt] = cid2; /* store for interp */
369*2e68589bSMark F. Adams             }
370*2e68589bSMark F. Adams 
371*2e68589bSMark F. Adams             for(tt=0;tt<3;tt++) alpha[tt] = (PetscScalar)fcoord[tt];
372*2e68589bSMark F. Adams 
373*2e68589bSMark F. Adams             /* SUBROUTINE DGESV( N, NRHS, A, LDA, IPIV, B, LDB, INFO ) */
374*2e68589bSMark F. Adams             LAPACKgesv_(&N, &NRHS, (PetscScalar*)AA, &LDA, IPIV, alpha, &LDB, &INFO);
375*2e68589bSMark F. Adams             {
376*2e68589bSMark F. Adams               PetscBool have=PETSC_TRUE;  PetscReal lowest=1.e10;
377*2e68589bSMark F. Adams               for( tt = 0, idx = 0 ; tt < 3 ; tt++ ) {
378*2e68589bSMark F. Adams                 if( PetscRealPart(alpha[tt]) > (1.0+EPS) || PetscRealPart(alpha[tt]) < -EPS ) have = PETSC_FALSE;
379*2e68589bSMark F. Adams                 if( PetscRealPart(alpha[tt]) < lowest ){
380*2e68589bSMark F. Adams                   lowest = PetscRealPart(alpha[tt]);
381*2e68589bSMark F. Adams                   idx = tt;
382*2e68589bSMark F. Adams                 }
383*2e68589bSMark F. Adams               }
384*2e68589bSMark F. Adams               haveit = have;
385*2e68589bSMark F. Adams             }
386*2e68589bSMark F. Adams             tid = mid.neighborlist[3*tid + idx];
387*2e68589bSMark F. Adams           }
388*2e68589bSMark F. Adams 
389*2e68589bSMark F. Adams           if( !haveit ) {
390*2e68589bSMark F. Adams             /* brute force */
391*2e68589bSMark F. Adams             for(tid=0 ; tid<mid.numberoftriangles && !haveit ; tid++ ){
392*2e68589bSMark F. Adams               for(tt=0;tt<3;tt++){
393*2e68589bSMark F. Adams                 PetscInt cid2 = mid.trianglelist[3*tid + tt];
394*2e68589bSMark F. Adams                 PetscInt lid2 = selected_idx_2[cid2];
395*2e68589bSMark F. Adams                 AA[tt][0] = coords[lid2]; AA[tt][1] = coords[nnodes + lid2]; AA[tt][2] = 1.0;
396*2e68589bSMark F. Adams                 clids[tt] = cid2; /* store for interp */
397*2e68589bSMark F. Adams               }
398*2e68589bSMark F. Adams               for(tt=0;tt<3;tt++) alpha[tt] = fcoord[tt];
399*2e68589bSMark F. Adams               /* SUBROUTINE DGESV( N, NRHS, A, LDA, IPIV, B, LDB, INFO ) */
400*2e68589bSMark F. Adams               LAPACKgesv_(&N, &NRHS, (PetscScalar*)AA, &LDA, IPIV, alpha, &LDB, &INFO);
401*2e68589bSMark F. Adams               {
402*2e68589bSMark F. Adams                 PetscBool have=PETSC_TRUE;  PetscReal worst=0.0, v;
403*2e68589bSMark F. Adams                 for(tt=0; tt<3 && have ;tt++) {
404*2e68589bSMark F. Adams                   if( PetscRealPart(alpha[tt]) > 1.0+EPS || PetscRealPart(alpha[tt]) < -EPS ) have=PETSC_FALSE;
405*2e68589bSMark F. Adams                   if( (v=PetscAbs(PetscRealPart(alpha[tt])-0.5)) > worst ) worst = v;
406*2e68589bSMark F. Adams                 }
407*2e68589bSMark F. Adams                 if( worst < best_alpha ) {
408*2e68589bSMark F. Adams                   best_alpha = worst; bestTID = tid;
409*2e68589bSMark F. Adams                 }
410*2e68589bSMark F. Adams                 haveit = have;
411*2e68589bSMark F. Adams               }
412*2e68589bSMark F. Adams             }
413*2e68589bSMark F. Adams           }
414*2e68589bSMark F. Adams           if( !haveit ) {
415*2e68589bSMark F. Adams             if( best_alpha > *a_worst_best ) *a_worst_best = best_alpha;
416*2e68589bSMark F. Adams             /* use best one */
417*2e68589bSMark F. Adams             for(tt=0;tt<3;tt++){
418*2e68589bSMark F. Adams               PetscInt cid2 = mid.trianglelist[3*bestTID + tt];
419*2e68589bSMark F. Adams               PetscInt lid2 = selected_idx_2[cid2];
420*2e68589bSMark F. Adams               AA[tt][0] = coords[lid2]; AA[tt][1] = coords[nnodes + lid2]; AA[tt][2] = 1.0;
421*2e68589bSMark F. Adams               clids[tt] = cid2; /* store for interp */
422*2e68589bSMark F. Adams             }
423*2e68589bSMark F. Adams             for(tt=0;tt<3;tt++) alpha[tt] = fcoord[tt];
424*2e68589bSMark F. Adams             /* SUBROUTINE DGESV( N, NRHS, A, LDA, IPIV, B, LDB, INFO ) */
425*2e68589bSMark F. Adams             LAPACKgesv_(&N, &NRHS, (PetscScalar*)AA, &LDA, IPIV, alpha, &LDB, &INFO);
426*2e68589bSMark F. Adams           }
427*2e68589bSMark F. Adams 
428*2e68589bSMark F. Adams           /* put in row of P */
429*2e68589bSMark F. Adams           for(idx=0;idx<3;idx++){
430*2e68589bSMark F. Adams             PetscScalar shp = alpha[idx];
431*2e68589bSMark F. Adams             if( PetscAbs(PetscRealPart(shp)) > 1.e-6 ) {
432*2e68589bSMark F. Adams               PetscInt cgid = crsGID[clids[idx]];
433*2e68589bSMark F. Adams               PetscInt jj = cgid*bs, ii = fgid*bs; /* need to gloalize */
434*2e68589bSMark F. Adams               for(tt=0 ; tt < bs ; tt++, ii++, jj++ ){
435*2e68589bSMark F. Adams                 ierr = MatSetValues(a_Prol,1,&ii,1,&jj,&shp,INSERT_VALUES); CHKERRQ(ierr);
436*2e68589bSMark F. Adams               }
437*2e68589bSMark F. Adams             }
438*2e68589bSMark F. Adams           }
439*2e68589bSMark F. Adams         } /* local vertex test */
440*2e68589bSMark F. Adams       } while( (flid=llist_idx[flid]) != -1 );
441*2e68589bSMark F. Adams     }
442*2e68589bSMark F. Adams     ierr = ISRestoreIndices( selected_2, &selected_idx_2 );     CHKERRQ(ierr);
443*2e68589bSMark F. Adams     ierr = ISRestoreIndices( selected_1, &selected_idx_1 );     CHKERRQ(ierr);
444*2e68589bSMark F. Adams     ierr = ISRestoreIndices( locals_llist, &llist_idx );     CHKERRQ(ierr);
445*2e68589bSMark F. Adams     ierr = MatAssemblyBegin(a_Prol,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
446*2e68589bSMark F. Adams     ierr = MatAssemblyEnd(a_Prol,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
447*2e68589bSMark F. Adams 
448*2e68589bSMark F. Adams     ierr = PetscFree( node_tri );  CHKERRQ(ierr);
449*2e68589bSMark F. Adams     ierr = PetscFree( nTri );  CHKERRQ(ierr);
450*2e68589bSMark F. Adams   }
451*2e68589bSMark F. Adams #if defined PETSC_USE_LOG
452*2e68589bSMark F. Adams   ierr = PetscLogEventEnd(gamg_setup_events[FIND_V],0,0,0,0);CHKERRQ(ierr);
453*2e68589bSMark F. Adams #endif
454*2e68589bSMark F. Adams   free( mid.trianglelist );
455*2e68589bSMark F. Adams   free( mid.neighborlist );
456*2e68589bSMark F. Adams   ierr = PetscFree( in.pointlist );  CHKERRQ(ierr);
457*2e68589bSMark F. Adams 
458*2e68589bSMark F. Adams   PetscFunctionReturn(0);
459*2e68589bSMark F. Adams #else
460*2e68589bSMark F. Adams     SETERRQ(((PetscObject)a_Prol)->comm,PETSC_ERR_LIB,"configure with TRIANGLE to use geometric MG");
461*2e68589bSMark F. Adams #endif
462*2e68589bSMark F. Adams }
463*2e68589bSMark F. Adams /* -------------------------------------------------------------------------- */
464*2e68589bSMark F. Adams /*
465*2e68589bSMark F. Adams    getGIDsOnSquareGraph - square graph, get
466*2e68589bSMark F. Adams 
467*2e68589bSMark F. Adams    Input Parameter:
468*2e68589bSMark F. Adams    . selected_1 - selected local indices (includes ghosts in input Gmat_1)
469*2e68589bSMark F. Adams    . Gmat1 - graph that goes with 'selected_1'
470*2e68589bSMark F. Adams    Output Parameter:
471*2e68589bSMark F. Adams    . a_selected_2 - selected local indices (includes ghosts in output a_Gmat_2)
472*2e68589bSMark F. Adams    . a_Gmat_2 - graph that is squared of 'Gmat_1'
473*2e68589bSMark F. Adams    . a_crsGID[a_selected_2.size()] - map of global IDs of coarse grid nodes
474*2e68589bSMark F. Adams */
475*2e68589bSMark F. Adams #undef __FUNCT__
476*2e68589bSMark F. Adams #define __FUNCT__ "getGIDsOnSquareGraph"
477*2e68589bSMark F. Adams PetscErrorCode getGIDsOnSquareGraph( const IS selected_1,
478*2e68589bSMark F. Adams                                      const Mat Gmat1,
479*2e68589bSMark F. Adams                                      IS *a_selected_2,
480*2e68589bSMark F. Adams                                      Mat *a_Gmat_2,
481*2e68589bSMark F. Adams                                      PetscInt **a_crsGID
482*2e68589bSMark F. Adams                                      )
483*2e68589bSMark F. Adams {
484*2e68589bSMark F. Adams   PetscErrorCode ierr;
485*2e68589bSMark F. Adams   PetscMPIInt    mype,npe;
486*2e68589bSMark F. Adams   PetscInt       *crsGID, kk,my0,Iend,nloc,nSelected_1;
487*2e68589bSMark F. Adams   const PetscInt *selected_idx;
488*2e68589bSMark F. Adams   MPI_Comm       wcomm = ((PetscObject)Gmat1)->comm;
489*2e68589bSMark F. Adams 
490*2e68589bSMark F. Adams   PetscFunctionBegin;
491*2e68589bSMark F. Adams   ierr = MPI_Comm_rank(wcomm,&mype);CHKERRQ(ierr);
492*2e68589bSMark F. Adams   ierr = MPI_Comm_size(wcomm,&npe);CHKERRQ(ierr);
493*2e68589bSMark F. Adams   ierr = MatGetOwnershipRange(Gmat1,&my0,&Iend); CHKERRQ(ierr); /* AIJ */
494*2e68589bSMark F. Adams   nloc = Iend - my0; /* this does not change */
495*2e68589bSMark F. Adams   ierr = ISGetLocalSize( selected_1, &nSelected_1 );        CHKERRQ(ierr);
496*2e68589bSMark F. Adams 
497*2e68589bSMark F. Adams   if (npe == 1) { /* not much to do in serial */
498*2e68589bSMark F. Adams     ierr = PetscMalloc( nSelected_1*sizeof(PetscInt), &crsGID ); CHKERRQ(ierr);
499*2e68589bSMark F. Adams     for(kk=0;kk<nSelected_1;kk++) crsGID[kk] = kk;
500*2e68589bSMark F. Adams     *a_Gmat_2 = 0;
501*2e68589bSMark F. Adams     *a_selected_2 = selected_1; /* needed? */
502*2e68589bSMark F. Adams   }
503*2e68589bSMark F. Adams   else {
504*2e68589bSMark F. Adams     PetscInt      idx,num_fine_ghosts,num_crs_ghost,nLocalSelected,myCrs0;
505*2e68589bSMark F. Adams     Mat_MPIAIJ   *mpimat2;
506*2e68589bSMark F. Adams     Mat           Gmat2;
507*2e68589bSMark F. Adams     Vec           locState;
508*2e68589bSMark F. Adams     PetscScalar   *cpcol_state;
509*2e68589bSMark F. Adams 
510*2e68589bSMark F. Adams     /* get 'nLocalSelected' */
511*2e68589bSMark F. Adams     ierr = ISGetIndices( selected_1, &selected_idx );     CHKERRQ(ierr);
512*2e68589bSMark F. Adams     for(kk=0,nLocalSelected=0;kk<nSelected_1;kk++){
513*2e68589bSMark F. Adams       PetscInt lid = selected_idx[kk];
514*2e68589bSMark F. Adams       if(lid<nloc) nLocalSelected++;
515*2e68589bSMark F. Adams     }
516*2e68589bSMark F. Adams     ierr = ISRestoreIndices( selected_1, &selected_idx );     CHKERRQ(ierr);
517*2e68589bSMark F. Adams     /* scan my coarse zero gid, set 'lid_state' with coarse GID */
518*2e68589bSMark F. Adams     MPI_Scan( &nLocalSelected, &myCrs0, 1, MPIU_INT, MPIU_SUM, wcomm );
519*2e68589bSMark F. Adams     myCrs0 -= nLocalSelected;
520*2e68589bSMark F. Adams 
521*2e68589bSMark F. Adams     if( a_Gmat_2 != 0 ) { /* output */
522*2e68589bSMark F. Adams       /* grow graph to get wider set of selected vertices to cover fine grid, invalidates 'llist' */
523*2e68589bSMark F. Adams       ierr = MatTransposeMatMult(Gmat1, Gmat1, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &Gmat2 );   CHKERRQ(ierr);
524*2e68589bSMark F. Adams       *a_Gmat_2 = Gmat2; /* output */
525*2e68589bSMark F. Adams     }
526*2e68589bSMark F. Adams     else Gmat2 = Gmat1;  /* use local to get crsGIDs at least */
527*2e68589bSMark F. Adams     /* get coarse grid GIDS for selected (locals and ghosts) */
528*2e68589bSMark F. Adams     mpimat2 = (Mat_MPIAIJ*)Gmat2->data;
529*2e68589bSMark F. Adams     ierr = MatGetVecs( Gmat2, &locState, 0 );         CHKERRQ(ierr);
530*2e68589bSMark F. Adams     ierr = VecSet( locState, (PetscScalar)(PetscReal)(-1) );  CHKERRQ(ierr); /* set with UNKNOWN state */
531*2e68589bSMark F. Adams     ierr = ISGetIndices( selected_1, &selected_idx );     CHKERRQ(ierr);
532*2e68589bSMark F. Adams     for(kk=0;kk<nLocalSelected;kk++){
533*2e68589bSMark F. Adams       PetscInt fgid = selected_idx[kk] + my0;
534*2e68589bSMark F. Adams       PetscScalar v = (PetscScalar)(kk+myCrs0);
535*2e68589bSMark F. Adams       ierr = VecSetValues( locState, 1, &fgid, &v, INSERT_VALUES );  CHKERRQ(ierr); /* set with PID */
536*2e68589bSMark F. Adams     }
537*2e68589bSMark F. Adams     ierr = ISRestoreIndices( selected_1, &selected_idx );     CHKERRQ(ierr);
538*2e68589bSMark F. Adams     ierr = VecAssemblyBegin( locState ); CHKERRQ(ierr);
539*2e68589bSMark F. Adams     ierr = VecAssemblyEnd( locState ); CHKERRQ(ierr);
540*2e68589bSMark F. Adams     ierr = VecScatterBegin(mpimat2->Mvctx,locState,mpimat2->lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
541*2e68589bSMark F. Adams     ierr =   VecScatterEnd(mpimat2->Mvctx,locState,mpimat2->lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
542*2e68589bSMark F. Adams     ierr = VecGetLocalSize( mpimat2->lvec, &num_fine_ghosts ); CHKERRQ(ierr);
543*2e68589bSMark F. Adams     ierr = VecGetArray( mpimat2->lvec, &cpcol_state ); CHKERRQ(ierr);
544*2e68589bSMark F. Adams     for(kk=0,num_crs_ghost=0;kk<num_fine_ghosts;kk++){
545*2e68589bSMark F. Adams       if( (PetscInt)PetscRealPart(cpcol_state[kk]) != -1 ) num_crs_ghost++;
546*2e68589bSMark F. Adams     }
547*2e68589bSMark F. Adams     ierr = PetscMalloc( (nLocalSelected+num_crs_ghost)*sizeof(PetscInt), &crsGID ); CHKERRQ(ierr); /* output */
548*2e68589bSMark F. Adams     {
549*2e68589bSMark F. Adams       PetscInt *selected_set;
550*2e68589bSMark F. Adams       ierr = PetscMalloc( (nLocalSelected+num_crs_ghost)*sizeof(PetscInt), &selected_set ); CHKERRQ(ierr);
551*2e68589bSMark F. Adams       /* do ghost of 'crsGID' */
552*2e68589bSMark F. Adams       for(kk=0,idx=nLocalSelected;kk<num_fine_ghosts;kk++){
553*2e68589bSMark F. Adams         if( (PetscInt)PetscRealPart(cpcol_state[kk]) != -1 ){
554*2e68589bSMark F. Adams           PetscInt cgid = (PetscInt)PetscRealPart(cpcol_state[kk]);
555*2e68589bSMark F. Adams           selected_set[idx] = nloc + kk;
556*2e68589bSMark F. Adams           crsGID[idx++] = cgid;
557*2e68589bSMark F. Adams         }
558*2e68589bSMark F. Adams       }
559*2e68589bSMark F. Adams       assert(idx==(nLocalSelected+num_crs_ghost));
560*2e68589bSMark F. Adams       ierr = VecRestoreArray( mpimat2->lvec, &cpcol_state ); CHKERRQ(ierr);
561*2e68589bSMark F. Adams       /* do locals in 'crsGID' */
562*2e68589bSMark F. Adams       ierr = VecGetArray( locState, &cpcol_state ); CHKERRQ(ierr);
563*2e68589bSMark F. Adams       for(kk=0,idx=0;kk<nloc;kk++){
564*2e68589bSMark F. Adams         if( (PetscInt)PetscRealPart(cpcol_state[kk]) != -1 ){
565*2e68589bSMark F. Adams           PetscInt cgid = (PetscInt)PetscRealPart(cpcol_state[kk]);
566*2e68589bSMark F. Adams           selected_set[idx] = kk;
567*2e68589bSMark F. Adams           crsGID[idx++] = cgid;
568*2e68589bSMark F. Adams         }
569*2e68589bSMark F. Adams       }
570*2e68589bSMark F. Adams       assert(idx==nLocalSelected);
571*2e68589bSMark F. Adams       ierr = VecRestoreArray( locState, &cpcol_state ); CHKERRQ(ierr);
572*2e68589bSMark F. Adams 
573*2e68589bSMark F. Adams       if( a_selected_2 != 0 ) { /* output */
574*2e68589bSMark F. Adams         ierr = ISCreateGeneral(PETSC_COMM_SELF,(nLocalSelected+num_crs_ghost),selected_set,PETSC_COPY_VALUES,a_selected_2);
575*2e68589bSMark F. Adams         CHKERRQ(ierr);
576*2e68589bSMark F. Adams       }
577*2e68589bSMark F. Adams       ierr = PetscFree( selected_set );  CHKERRQ(ierr);
578*2e68589bSMark F. Adams     }
579*2e68589bSMark F. Adams     ierr = VecDestroy( &locState );                    CHKERRQ(ierr);
580*2e68589bSMark F. Adams   }
581*2e68589bSMark F. Adams   *a_crsGID = crsGID; /* output */
582*2e68589bSMark F. Adams 
583*2e68589bSMark F. Adams   PetscFunctionReturn(0);
584*2e68589bSMark F. Adams }
585*2e68589bSMark F. Adams 
586*2e68589bSMark F. Adams /* -------------------------------------------------------------------------- */
587*2e68589bSMark F. Adams /*
588*2e68589bSMark F. Adams    PCGAMGcreateProl_GEO
589*2e68589bSMark F. Adams 
590*2e68589bSMark F. Adams   Input Parameter:
591*2e68589bSMark F. Adams    . pc - this
592*2e68589bSMark F. Adams    . Amat - matrix on this fine level
593*2e68589bSMark F. Adams    . data[nloc*data_sz(in)]
594*2e68589bSMark F. Adams   Output Parameter:
595*2e68589bSMark F. Adams    . a_P_out - prolongation operator to the next level
596*2e68589bSMark F. Adams    . a_data_out - data of coarse grid points (num local columns in 'a_P_out')
597*2e68589bSMark F. Adams */
598*2e68589bSMark F. Adams #undef __FUNCT__
599*2e68589bSMark F. Adams #define __FUNCT__ "PCGAMGcreateProl_GEO"
600*2e68589bSMark F. Adams PetscErrorCode PCGAMGcreateProl_GEO( PC pc,
601*2e68589bSMark F. Adams                                      const Mat Amat,
602*2e68589bSMark F. Adams                                      const PetscReal data[],
603*2e68589bSMark F. Adams                                      Mat *a_P_out,
604*2e68589bSMark F. Adams                                      PetscReal **a_data_out
605*2e68589bSMark F. Adams                                      )
606*2e68589bSMark F. Adams {
607*2e68589bSMark F. Adams   PC_MG          *mg = (PC_MG*)pc->data;
608*2e68589bSMark F. Adams   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;
609*2e68589bSMark F. Adams   const PetscInt verbose = pc_gamg->verbose;
610*2e68589bSMark F. Adams   const PetscInt  dim = pc_gamg->data_cols, data_cols = pc_gamg->data_cols;
611*2e68589bSMark F. Adams   PetscErrorCode ierr;
612*2e68589bSMark F. Adams   PetscInt       Istart,Iend,nloc,jj,kk,my0,nLocalSelected,NN,MM,bs;
613*2e68589bSMark F. Adams   Mat            Prol, Gmat;
614*2e68589bSMark F. Adams   PetscMPIInt    mype, npe;
615*2e68589bSMark F. Adams   MPI_Comm       wcomm = ((PetscObject)Amat)->comm;
616*2e68589bSMark F. Adams   IS             permIS, llist_1, selected_1, selected_2;
617*2e68589bSMark F. Adams   const PetscInt *selected_idx;
618*2e68589bSMark F. Adams 
619*2e68589bSMark F. Adams   PetscFunctionBegin;
620*2e68589bSMark F. Adams   ierr = MPI_Comm_rank(wcomm,&mype);CHKERRQ(ierr);
621*2e68589bSMark F. Adams   ierr = MPI_Comm_size(wcomm,&npe);CHKERRQ(ierr);
622*2e68589bSMark F. Adams   ierr = MatGetOwnershipRange( Amat, &Istart, &Iend ); CHKERRQ(ierr);
623*2e68589bSMark F. Adams   ierr = MatGetSize( Amat, &MM, &NN ); CHKERRQ(ierr);
624*2e68589bSMark F. Adams   ierr  = MatGetBlockSize( Amat, &bs );               CHKERRQ( ierr );
625*2e68589bSMark F. Adams   nloc = (Iend-Istart)/bs; my0 = Istart/bs; assert((Iend-Istart)%bs==0);
626*2e68589bSMark F. Adams 
627*2e68589bSMark F. Adams   ierr = createGraph( pc, Amat, &Gmat, PETSC_NULL, &permIS ); CHKERRQ(ierr);
628*2e68589bSMark F. Adams 
629*2e68589bSMark F. Adams   /* SELECT COARSE POINTS */
630*2e68589bSMark F. Adams #if defined PETSC_USE_LOG
631*2e68589bSMark F. Adams   ierr = PetscLogEventBegin(gamg_setup_events[SET4],0,0,0,0);CHKERRQ(ierr);
632*2e68589bSMark F. Adams #endif
633*2e68589bSMark F. Adams 
634*2e68589bSMark F. Adams   ierr = maxIndSetAgg( permIS, Gmat, PETSC_NULL, PETSC_FALSE, &selected_1, &llist_1 );
635*2e68589bSMark F. Adams   CHKERRQ(ierr);
636*2e68589bSMark F. Adams #if defined PETSC_USE_LOG
637*2e68589bSMark F. Adams   ierr = PetscLogEventEnd(gamg_setup_events[SET4],0,0,0,0);CHKERRQ(ierr);
638*2e68589bSMark F. Adams #endif
639*2e68589bSMark F. Adams   ierr = ISDestroy(&permIS); CHKERRQ(ierr);
640*2e68589bSMark F. Adams 
641*2e68589bSMark F. Adams   /* get 'nLocalSelected' */
642*2e68589bSMark F. Adams   ierr = ISGetLocalSize( selected_1, &NN );        CHKERRQ(ierr);
643*2e68589bSMark F. Adams   ierr = ISGetIndices( selected_1, &selected_idx );     CHKERRQ(ierr);
644*2e68589bSMark F. Adams   for(kk=0,nLocalSelected=0;kk<NN;kk++){
645*2e68589bSMark F. Adams     PetscInt lid = selected_idx[kk];
646*2e68589bSMark F. Adams     if(lid<nloc) nLocalSelected++;
647*2e68589bSMark F. Adams   }
648*2e68589bSMark F. Adams   ierr = ISRestoreIndices( selected_1, &selected_idx );     CHKERRQ(ierr);
649*2e68589bSMark F. Adams 
650*2e68589bSMark F. Adams   /* create prolongator, create P matrix */
651*2e68589bSMark F. Adams   ierr = MatCreateMPIAIJ(wcomm,
652*2e68589bSMark F. Adams                          nloc*bs, nLocalSelected*bs,
653*2e68589bSMark F. Adams                          PETSC_DETERMINE, PETSC_DETERMINE,
654*2e68589bSMark F. Adams                          3*data_cols, PETSC_NULL, /* don't have a good way to set this!!! */
655*2e68589bSMark F. Adams                          3*data_cols, PETSC_NULL,
656*2e68589bSMark F. Adams                          &Prol );
657*2e68589bSMark F. Adams   CHKERRQ(ierr);
658*2e68589bSMark F. Adams 
659*2e68589bSMark F. Adams   /* can get all points "removed" */
660*2e68589bSMark F. Adams   ierr =  MatGetSize( Prol, &kk, &jj ); CHKERRQ(ierr);
661*2e68589bSMark F. Adams   if( jj==0 ) {
662*2e68589bSMark F. Adams     if( verbose ) {
663*2e68589bSMark F. Adams       PetscPrintf(PETSC_COMM_WORLD,"[%d]%s no selected points on coarse grid\n",mype,__FUNCT__);
664*2e68589bSMark F. Adams     }
665*2e68589bSMark F. Adams     ierr = MatDestroy( &Prol );  CHKERRQ(ierr);
666*2e68589bSMark F. Adams     ierr = ISDestroy( &llist_1 ); CHKERRQ(ierr);
667*2e68589bSMark F. Adams     ierr = ISDestroy( &selected_1 ); CHKERRQ(ierr);
668*2e68589bSMark F. Adams     ierr = MatDestroy( &Gmat );  CHKERRQ(ierr);
669*2e68589bSMark F. Adams     *a_P_out = PETSC_NULL;  /* out */
670*2e68589bSMark F. Adams     PetscFunctionReturn(0);
671*2e68589bSMark F. Adams   }
672*2e68589bSMark F. Adams 
673*2e68589bSMark F. Adams   {
674*2e68589bSMark F. Adams     PetscReal *coords;
675*2e68589bSMark F. Adams     PetscInt nnodes;
676*2e68589bSMark F. Adams     PetscInt  *crsGID;
677*2e68589bSMark F. Adams     Mat        Gmat2;
678*2e68589bSMark F. Adams 
679*2e68589bSMark F. Adams     assert(dim==data_cols);
680*2e68589bSMark F. Adams     /* grow ghost data for better coarse grid cover of fine grid */
681*2e68589bSMark F. Adams #if defined PETSC_USE_LOG
682*2e68589bSMark F. Adams     ierr = PetscLogEventBegin(gamg_setup_events[SET5],0,0,0,0);CHKERRQ(ierr);
683*2e68589bSMark F. Adams #endif
684*2e68589bSMark F. Adams     ierr = getGIDsOnSquareGraph( selected_1, Gmat, &selected_2, &Gmat2, &crsGID );
685*2e68589bSMark F. Adams     CHKERRQ(ierr);
686*2e68589bSMark F. Adams     ierr = MatDestroy( &Gmat );  CHKERRQ(ierr);
687*2e68589bSMark F. Adams     /* llist is now not valid wrt squared graph, but will work as iterator in 'triangulateAndFormProl' */
688*2e68589bSMark F. Adams #if defined PETSC_USE_LOG
689*2e68589bSMark F. Adams     ierr = PetscLogEventEnd(gamg_setup_events[SET5],0,0,0,0);CHKERRQ(ierr);
690*2e68589bSMark F. Adams #endif
691*2e68589bSMark F. Adams     /* create global vector of coorindates in 'coords' */
692*2e68589bSMark F. Adams     if (npe > 1) {
693*2e68589bSMark F. Adams       ierr = getDataWithGhosts( Gmat2, dim, data, &nnodes, &coords );
694*2e68589bSMark F. Adams       CHKERRQ(ierr);
695*2e68589bSMark F. Adams     }
696*2e68589bSMark F. Adams     else {
697*2e68589bSMark F. Adams       coords = (PetscReal*)data;
698*2e68589bSMark F. Adams       nnodes = nloc;
699*2e68589bSMark F. Adams     }
700*2e68589bSMark F. Adams     ierr = MatDestroy( &Gmat2 );  CHKERRQ(ierr);
701*2e68589bSMark F. Adams 
702*2e68589bSMark F. Adams     /* triangulate */
703*2e68589bSMark F. Adams     if( dim == 2 ) {
704*2e68589bSMark F. Adams       PetscReal metric=0.0;
705*2e68589bSMark F. Adams #if defined PETSC_USE_LOG
706*2e68589bSMark F. Adams       ierr = PetscLogEventBegin(gamg_setup_events[SET6],0,0,0,0);CHKERRQ(ierr);
707*2e68589bSMark F. Adams #endif
708*2e68589bSMark F. Adams       ierr = triangulateAndFormProl( selected_2, nnodes, coords,
709*2e68589bSMark F. Adams                                      selected_1, llist_1, crsGID, bs, Prol, &metric );
710*2e68589bSMark F. Adams       CHKERRQ(ierr);
711*2e68589bSMark F. Adams #if defined PETSC_USE_LOG
712*2e68589bSMark F. Adams       ierr = PetscLogEventEnd(gamg_setup_events[SET6],0,0,0,0); CHKERRQ(ierr);
713*2e68589bSMark F. Adams #endif
714*2e68589bSMark F. Adams       ierr = PetscFree( crsGID );  CHKERRQ(ierr);
715*2e68589bSMark F. Adams 
716*2e68589bSMark F. Adams       /* clean up and create coordinates for coarse grid (output) */
717*2e68589bSMark F. Adams       if (npe > 1) ierr = PetscFree( coords ); CHKERRQ(ierr);
718*2e68589bSMark F. Adams 
719*2e68589bSMark F. Adams       if( metric > 1. ) { /* needs to be globalized - should not happen */
720*2e68589bSMark F. Adams         if( verbose ) {
721*2e68589bSMark F. Adams           PetscPrintf(PETSC_COMM_SELF,"[%d]%s failed metric for coarse grid %e\n",mype,__FUNCT__,metric);
722*2e68589bSMark F. Adams         }
723*2e68589bSMark F. Adams         ierr = MatDestroy( &Prol );  CHKERRQ(ierr);
724*2e68589bSMark F. Adams         Prol = PETSC_NULL;
725*2e68589bSMark F. Adams       }
726*2e68589bSMark F. Adams       else if( metric > .0 ) {
727*2e68589bSMark F. Adams         if( verbose ) {
728*2e68589bSMark F. Adams           PetscPrintf(PETSC_COMM_SELF,"[%d]%s metric for coarse grid = %e\n",mype,__FUNCT__,metric);
729*2e68589bSMark F. Adams         }
730*2e68589bSMark F. Adams       }
731*2e68589bSMark F. Adams     } else {
732*2e68589bSMark F. Adams       SETERRQ(wcomm,PETSC_ERR_LIB,"3D not implemented for 'geo' AMG");
733*2e68589bSMark F. Adams     }
734*2e68589bSMark F. Adams     { /* create next coords - output */
735*2e68589bSMark F. Adams       PetscReal *crs_crds;
736*2e68589bSMark F. Adams       ierr = PetscMalloc( dim*nLocalSelected*sizeof(PetscReal), &crs_crds );
737*2e68589bSMark F. Adams       CHKERRQ(ierr);
738*2e68589bSMark F. Adams       ierr = ISGetIndices( selected_1, &selected_idx );     CHKERRQ(ierr);
739*2e68589bSMark F. Adams       for(kk=0;kk<nLocalSelected;kk++){/* grab local select nodes to promote - output */
740*2e68589bSMark F. Adams         PetscInt lid = selected_idx[kk];
741*2e68589bSMark F. Adams         for(jj=0;jj<dim;jj++) crs_crds[jj*nLocalSelected + kk] = data[jj*nloc + lid];
742*2e68589bSMark F. Adams       }
743*2e68589bSMark F. Adams       ierr = ISRestoreIndices( selected_1, &selected_idx );     CHKERRQ(ierr);
744*2e68589bSMark F. Adams       *a_data_out = crs_crds; /* out */
745*2e68589bSMark F. Adams     }
746*2e68589bSMark F. Adams     if (npe > 1) {
747*2e68589bSMark F. Adams       ierr = ISDestroy( &selected_2 ); CHKERRQ(ierr); /* this is selected_1 in serial */
748*2e68589bSMark F. Adams     }
749*2e68589bSMark F. Adams   }
750*2e68589bSMark F. Adams   *a_P_out = Prol;  /* out */
751*2e68589bSMark F. Adams 
752*2e68589bSMark F. Adams   ierr = ISDestroy( &llist_1 ); CHKERRQ(ierr);
753*2e68589bSMark F. Adams   ierr = ISDestroy( &selected_1 ); CHKERRQ(ierr);
754*2e68589bSMark F. Adams 
755*2e68589bSMark F. Adams   PetscFunctionReturn(0);
756*2e68589bSMark F. Adams }
757