Actual source code: classical.c
petsc-dev 2014-02-02
1: #include <../src/ksp/pc/impls/gamg/gamg.h> /*I "petscpc.h" I*/
2: #include <petsc-private/kspimpl.h>
4: PetscFunctionList PCGAMGClassicalProlongatorList = NULL;
5: PetscBool PCGAMGClassicalPackageInitialized = PETSC_FALSE;
7: typedef struct {
8: PetscReal interp_threshold; /* interpolation threshold */
9: char prolongtype[256];
10: PetscInt nsmooths; /* number of jacobi smoothings on the prolongator */
11: } PC_GAMG_Classical;
15: /*@C
16: PCGAMGClassicalSetType - Sets the type of classical interpolation to use
18: Collective on PC
20: Input Parameters:
21: . pc - the preconditioner context
23: Options Database Key:
24: . -pc_gamg_classical_type
26: Level: intermediate
28: .seealso: ()
29: @*/
30: PetscErrorCode PCGAMGClassicalSetType(PC pc, PCGAMGClassicalType type)
31: {
36: PetscTryMethod(pc,"PCGAMGClassicalSetType_C",(PC,PCGAMGType),(pc,type));
37: return(0);
38: }
42: static PetscErrorCode PCGAMGClassicalSetType_GAMG(PC pc, PCGAMGClassicalType type)
43: {
44: PetscErrorCode ierr;
45: PC_MG *mg = (PC_MG*)pc->data;
46: PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;
47: PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx;
50: PetscStrcpy(cls->prolongtype,type);
51: return(0);
52: }
56: PetscErrorCode PCGAMGClassicalCreateGhostVector_Private(Mat G,Vec *gvec,PetscInt **global)
57: {
58: Mat_MPIAIJ *aij = (Mat_MPIAIJ*)G->data;
60: PetscBool isMPIAIJ;
63: PetscObjectTypeCompare((PetscObject)G, MATMPIAIJ, &isMPIAIJ);
64: if (isMPIAIJ) {
65: if (gvec)VecDuplicate(aij->lvec,gvec);
66: if (global)*global = aij->garray;
67: } else {
68: /* no off-processor nodes */
69: if (gvec)*gvec = NULL;
70: if (global)*global = NULL;
71: }
72: return(0);
73: }
77: /*
78: Split the relevant graph into diagonal and off-diagonal parts in local numbering; for now this
79: a roundabout private interface to the mats' internal diag and offdiag mats.
80: */
81: PetscErrorCode PCGAMGClassicalGraphSplitting_Private(Mat G,Mat *Gd, Mat *Go)
82: {
83: Mat_MPIAIJ *aij = (Mat_MPIAIJ*)G->data;
85: PetscBool isMPIAIJ;
87: PetscObjectTypeCompare((PetscObject)G, MATMPIAIJ, &isMPIAIJ );
88: if (isMPIAIJ) {
89: *Gd = aij->A;
90: *Go = aij->B;
91: } else {
92: *Gd = G;
93: *Go = NULL;
94: }
95: return(0);
96: }
100: PetscErrorCode PCGAMGGraph_Classical(PC pc,const Mat A,Mat *G)
101: {
102: PetscInt s,f,n,idx,lidx,gidx;
103: PetscInt r,c,ncols;
104: const PetscInt *rcol;
105: const PetscScalar *rval;
106: PetscInt *gcol;
107: PetscScalar *gval;
108: PetscReal rmax;
109: PetscInt cmax = 0;
110: PC_MG *mg;
111: PC_GAMG *gamg;
112: PetscErrorCode ierr;
113: PetscInt *gsparse,*lsparse;
114: PetscScalar *Amax;
115: MatType mtype;
118: mg = (PC_MG *)pc->data;
119: gamg = (PC_GAMG *)mg->innerctx;
121: MatGetOwnershipRange(A,&s,&f);
122: n=f-s;
123: PetscMalloc(sizeof(PetscInt)*n,&lsparse);
124: PetscMalloc(sizeof(PetscInt)*n,&gsparse);
125: PetscMalloc(sizeof(PetscScalar)*n,&Amax);
127: for (r = 0;r < n;r++) {
128: lsparse[r] = 0;
129: gsparse[r] = 0;
130: }
132: for (r = s;r < f;r++) {
133: /* determine the maximum off-diagonal in each row */
134: rmax = 0.;
135: MatGetRow(A,r,&ncols,&rcol,&rval);
136: for (c = 0; c < ncols; c++) {
137: if (PetscRealPart(-rval[c]) > rmax && rcol[c] != r) {
138: rmax = PetscRealPart(-rval[c]);
139: }
140: }
141: Amax[r-s] = rmax;
142: if (ncols > cmax) cmax = ncols;
143: lidx = 0;
144: gidx = 0;
145: /* create the local and global sparsity patterns */
146: for (c = 0; c < ncols; c++) {
147: if (PetscRealPart(-rval[c]) > gamg->threshold*PetscRealPart(Amax[r-s]) || rcol[c] == r) {
148: if (rcol[c] < f && rcol[c] >= s) {
149: lidx++;
150: } else {
151: gidx++;
152: }
153: }
154: }
155: MatRestoreRow(A,r,&ncols,&rcol,&rval);
156: lsparse[r-s] = lidx;
157: gsparse[r-s] = gidx;
158: }
159: PetscMalloc(sizeof(PetscScalar)*cmax,&gval);
160: PetscMalloc(sizeof(PetscInt)*cmax,&gcol);
162: MatCreate(PetscObjectComm((PetscObject)A),G);
163: MatGetType(A,&mtype);
164: MatSetType(*G,mtype);
165: MatSetSizes(*G,n,n,PETSC_DETERMINE,PETSC_DETERMINE);
166: MatMPIAIJSetPreallocation(*G,0,lsparse,0,gsparse);
167: MatSeqAIJSetPreallocation(*G,0,lsparse);
168: for (r = s;r < f;r++) {
169: MatGetRow(A,r,&ncols,&rcol,&rval);
170: idx = 0;
171: for (c = 0; c < ncols; c++) {
172: /* classical strength of connection */
173: if (PetscRealPart(-rval[c]) > gamg->threshold*PetscRealPart(Amax[r-s]) || rcol[c] == r) {
174: gcol[idx] = rcol[c];
175: gval[idx] = rval[c];
176: idx++;
177: }
178: }
179: MatSetValues(*G,1,&r,idx,gcol,gval,INSERT_VALUES);
180: MatRestoreRow(A,r,&ncols,&rcol,&rval);
181: }
182: MatAssemblyBegin(*G, MAT_FINAL_ASSEMBLY);
183: MatAssemblyEnd(*G, MAT_FINAL_ASSEMBLY);
185: PetscFree(gval);
186: PetscFree(gcol);
187: PetscFree(lsparse);
188: PetscFree(gsparse);
189: PetscFree(Amax);
190: return(0);
191: }
196: PetscErrorCode PCGAMGCoarsen_Classical(PC pc,Mat *G,PetscCoarsenData **agg_lists)
197: {
198: PetscErrorCode ierr;
199: MatCoarsen crs;
200: MPI_Comm fcomm = ((PetscObject)pc)->comm;
205: /* construct the graph if necessary */
206: if (!G) {
207: SETERRQ(fcomm,PETSC_ERR_ARG_WRONGSTATE,"Must set Graph in PC in PCGAMG before coarsening");
208: }
210: MatCoarsenCreate(fcomm,&crs);
211: MatCoarsenSetFromOptions(crs);
212: MatCoarsenSetAdjacency(crs,*G);
213: MatCoarsenSetStrictAggs(crs,PETSC_TRUE);
214: MatCoarsenApply(crs);
215: MatCoarsenGetData(crs,agg_lists);
216: MatCoarsenDestroy(&crs);
218: return(0);
219: }
223: /*
224: Find all ghost nodes that are coarse and output the fine/coarse splitting for those as well
226: Input:
227: G - graph;
228: gvec - Global Vector
229: avec - Local part of the scattered vec
230: bvec - Global part of the scattered vec
232: Output:
233: findx - indirection t
235: */
236: PetscErrorCode PCGAMGClassicalGhost_Private(Mat G,Vec v,Vec gv)
237: {
239: Mat_MPIAIJ *aij = (Mat_MPIAIJ*)G->data;
240: PetscBool isMPIAIJ;
243: PetscObjectTypeCompare((PetscObject)G, MATMPIAIJ, &isMPIAIJ );
244: if (isMPIAIJ) {
245: VecScatterBegin(aij->Mvctx,v,gv,INSERT_VALUES,SCATTER_FORWARD);
246: VecScatterEnd(aij->Mvctx,v,gv,INSERT_VALUES,SCATTER_FORWARD);
247: }
248: return(0);
249: }
253: PetscErrorCode PCGAMGProlongator_Classical_Direct(PC pc, const Mat A, const Mat G, PetscCoarsenData *agg_lists,Mat *P)
254: {
255: PetscErrorCode ierr;
256: MPI_Comm comm;
257: PetscReal *Amax_pos,*Amax_neg;
258: Mat lA,gA; /* on and off diagonal matrices */
259: PetscInt fn; /* fine local blocked sizes */
260: PetscInt cn; /* coarse local blocked sizes */
261: PetscInt gn; /* size of the off-diagonal fine vector */
262: PetscInt fs,fe; /* fine (row) ownership range*/
263: PetscInt cs,ce; /* coarse (column) ownership range */
264: PetscInt i,j; /* indices! */
265: PetscBool iscoarse; /* flag for determining if a node is coarse */
266: PetscInt *lcid,*gcid; /* on and off-processor coarse unknown IDs */
267: PetscInt *lsparse,*gsparse; /* on and off-processor sparsity patterns for prolongator */
268: PetscScalar pij;
269: const PetscScalar *rval;
270: const PetscInt *rcol;
271: PetscScalar g_pos,g_neg,a_pos,a_neg,diag,invdiag,alpha,beta;
272: Vec F; /* vec of coarse size */
273: Vec C; /* vec of fine size */
274: Vec gF; /* vec of off-diagonal fine size */
275: MatType mtype;
276: PetscInt c_indx;
277: PetscScalar c_scalar;
278: PetscInt ncols,col;
279: PetscInt row_f,row_c;
280: PetscInt cmax=0,idx;
281: PetscScalar *pvals;
282: PetscInt *pcols;
283: PC_MG *mg = (PC_MG*)pc->data;
284: PC_GAMG *gamg = (PC_GAMG*)mg->innerctx;
287: comm = ((PetscObject)pc)->comm;
288: MatGetOwnershipRange(A,&fs,&fe);
289: fn = (fe - fs);
291: MatGetVecs(A,&F,NULL);
293: /* get the number of local unknowns and the indices of the local unknowns */
295: PetscMalloc(sizeof(PetscInt)*fn,&lsparse);
296: PetscMalloc(sizeof(PetscInt)*fn,&gsparse);
297: PetscMalloc(sizeof(PetscInt)*fn,&lcid);
298: PetscMalloc(sizeof(PetscReal)*fn,&Amax_pos);
299: PetscMalloc(sizeof(PetscReal)*fn,&Amax_neg);
301: /* count the number of coarse unknowns */
302: cn = 0;
303: for (i=0;i<fn;i++) {
304: /* filter out singletons */
305: PetscCDEmptyAt(agg_lists,i,&iscoarse);
306: lcid[i] = -1;
307: if (!iscoarse) {
308: cn++;
309: }
310: }
312: /* create the coarse vector */
313: VecCreateMPI(comm,cn,PETSC_DECIDE,&C);
314: VecGetOwnershipRange(C,&cs,&ce);
316: /* construct a global vector indicating the global indices of the coarse unknowns */
317: cn = 0;
318: for (i=0;i<fn;i++) {
319: PetscCDEmptyAt(agg_lists,i,&iscoarse);
320: if (!iscoarse) {
321: lcid[i] = cs+cn;
322: cn++;
323: } else {
324: lcid[i] = -1;
325: }
326: *((PetscInt *)&c_scalar) = lcid[i];
327: c_indx = fs+i;
328: VecSetValues(F,1,&c_indx,&c_scalar,INSERT_VALUES);
329: }
331: VecAssemblyBegin(F);
332: VecAssemblyEnd(F);
334: /* determine the biggest off-diagonal entries in each row */
335: for (i=fs;i<fe;i++) {
336: Amax_pos[i-fs] = 0.;
337: Amax_neg[i-fs] = 0.;
338: MatGetRow(A,i,&ncols,&rcol,&rval);
339: for(j=0;j<ncols;j++){
340: if ((PetscRealPart(-rval[j]) > Amax_neg[i-fs]) && i != rcol[j]) Amax_neg[i-fs] = PetscAbsScalar(rval[j]);
341: if ((PetscRealPart(rval[j]) > Amax_pos[i-fs]) && i != rcol[j]) Amax_pos[i-fs] = PetscAbsScalar(rval[j]);
342: }
343: if (ncols > cmax) cmax = ncols;
344: MatRestoreRow(A,i,&ncols,&rcol,&rval);
345: }
346: PetscMalloc(sizeof(PetscInt)*cmax,&pcols);
347: PetscMalloc(sizeof(PetscScalar)*cmax,&pvals);
349: /* split the operator into two */
350: PCGAMGClassicalGraphSplitting_Private(A,&lA,&gA);
352: /* scatter to the ghost vector */
353: PCGAMGClassicalCreateGhostVector_Private(A,&gF,NULL);
354: PCGAMGClassicalGhost_Private(A,F,gF);
356: if (gA) {
357: VecGetSize(gF,&gn);
358: PetscMalloc(sizeof(PetscInt)*gn,&gcid);
359: for (i=0;i<gn;i++) {
360: VecGetValues(gF,1,&i,&c_scalar);
361: gcid[i] = *((PetscInt *)&c_scalar);
362: }
363: }
365: VecDestroy(&F);
366: VecDestroy(&gF);
367: VecDestroy(&C);
369: /* count the on and off processor sparsity patterns for the prolongator */
370: for (i=0;i<fn;i++) {
371: /* on */
372: lsparse[i] = 0;
373: gsparse[i] = 0;
374: if (lcid[i] >= 0) {
375: lsparse[i] = 1;
376: gsparse[i] = 0;
377: } else {
378: MatGetRow(lA,i,&ncols,&rcol,&rval);
379: for (j = 0;j < ncols;j++) {
380: col = rcol[j];
381: if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
382: lsparse[i] += 1;
383: }
384: }
385: MatRestoreRow(lA,i,&ncols,&rcol,&rval);
386: /* off */
387: if (gA) {
388: MatGetRow(gA,i,&ncols,&rcol,&rval);
389: for (j = 0; j < ncols; j++) {
390: col = rcol[j];
391: if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
392: gsparse[i] += 1;
393: }
394: }
395: MatRestoreRow(gA,i,&ncols,&rcol,&rval);
396: }
397: }
398: }
400: /* preallocate and create the prolongator */
401: MatCreate(comm,P);
402: MatGetType(G,&mtype);
403: MatSetType(*P,mtype);
405: MatSetSizes(*P,fn,cn,PETSC_DETERMINE,PETSC_DETERMINE);
406: MatMPIAIJSetPreallocation(*P,0,lsparse,0,gsparse);
407: MatSeqAIJSetPreallocation(*P,0,lsparse);
409: /* loop over local fine nodes -- get the diagonal, the sum of positive and negative strong and weak weights, and set up the row */
410: for (i = 0;i < fn;i++) {
411: /* determine on or off */
412: row_f = i + fs;
413: row_c = lcid[i];
414: if (row_c >= 0) {
415: pij = 1.;
416: MatSetValues(*P,1,&row_f,1,&row_c,&pij,INSERT_VALUES);
417: } else {
418: g_pos = 0.;
419: g_neg = 0.;
420: a_pos = 0.;
421: a_neg = 0.;
422: diag = 0.;
424: /* local connections */
425: MatGetRow(lA,i,&ncols,&rcol,&rval);
426: for (j = 0; j < ncols; j++) {
427: col = rcol[j];
428: if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
429: if (PetscRealPart(rval[j]) > 0.) {
430: g_pos += rval[j];
431: } else {
432: g_neg += rval[j];
433: }
434: }
435: if (col != i) {
436: if (PetscRealPart(rval[j]) > 0.) {
437: a_pos += rval[j];
438: } else {
439: a_neg += rval[j];
440: }
441: } else {
442: diag = rval[j];
443: }
444: }
445: MatRestoreRow(lA,i,&ncols,&rcol,&rval);
447: /* ghosted connections */
448: if (gA) {
449: MatGetRow(gA,i,&ncols,&rcol,&rval);
450: for (j = 0; j < ncols; j++) {
451: col = rcol[j];
452: if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
453: if (PetscRealPart(rval[j]) > 0.) {
454: g_pos += rval[j];
455: } else {
456: g_neg += rval[j];
457: }
458: }
459: if (PetscRealPart(rval[j]) > 0.) {
460: a_pos += rval[j];
461: } else {
462: a_neg += rval[j];
463: }
464: }
465: MatRestoreRow(gA,i,&ncols,&rcol,&rval);
466: }
468: if (g_neg == 0.) {
469: alpha = 0.;
470: } else {
471: alpha = -a_neg/g_neg;
472: }
474: if (g_pos == 0.) {
475: diag += a_pos;
476: beta = 0.;
477: } else {
478: beta = -a_pos/g_pos;
479: }
480: if (diag == 0.) {
481: invdiag = 0.;
482: } else invdiag = 1. / diag;
483: /* on */
484: MatGetRow(lA,i,&ncols,&rcol,&rval);
485: idx = 0;
486: for (j = 0;j < ncols;j++) {
487: col = rcol[j];
488: if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
489: row_f = i + fs;
490: row_c = lcid[col];
491: /* set the values for on-processor ones */
492: if (PetscRealPart(rval[j]) < 0.) {
493: pij = rval[j]*alpha*invdiag;
494: } else {
495: pij = rval[j]*beta*invdiag;
496: }
497: if (PetscAbsScalar(pij) != 0.) {
498: pvals[idx] = pij;
499: pcols[idx] = row_c;
500: idx++;
501: }
502: }
503: }
504: MatRestoreRow(lA,i,&ncols,&rcol,&rval);
505: /* off */
506: if (gA) {
507: MatGetRow(gA,i,&ncols,&rcol,&rval);
508: for (j = 0; j < ncols; j++) {
509: col = rcol[j];
510: if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
511: row_f = i + fs;
512: row_c = gcid[col];
513: /* set the values for on-processor ones */
514: if (PetscRealPart(rval[j]) < 0.) {
515: pij = rval[j]*alpha*invdiag;
516: } else {
517: pij = rval[j]*beta*invdiag;
518: }
519: if (PetscAbsScalar(pij) != 0.) {
520: pvals[idx] = pij;
521: pcols[idx] = row_c;
522: idx++;
523: }
524: }
525: }
526: MatRestoreRow(gA,i,&ncols,&rcol,&rval);
527: }
528: MatSetValues(*P,1,&row_f,idx,pcols,pvals,INSERT_VALUES);
529: }
530: }
532: MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY);
533: MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY);
535: PetscFree(lsparse);
536: PetscFree(gsparse);
537: PetscFree(pcols);
538: PetscFree(pvals);
539: PetscFree(Amax_pos);
540: PetscFree(Amax_neg);
541: PetscFree(lcid);
542: if (gA) {PetscFree(gcid);}
544: return(0);
545: }
549: PetscErrorCode PCGAMGTruncateProlongator_Private(PC pc,Mat *P)
550: {
551: PetscInt j,i,ps,pf,pn,pcs,pcf,pcn,idx,cmax;
552: PetscErrorCode ierr;
553: const PetscScalar *pval;
554: const PetscInt *pcol;
555: PetscScalar *pnval;
556: PetscInt *pncol;
557: PetscInt ncols;
558: Mat Pnew;
559: PetscInt *lsparse,*gsparse;
560: PetscReal pmax_pos,pmax_neg,ptot_pos,ptot_neg,pthresh_pos,pthresh_neg;
561: PC_MG *mg = (PC_MG*)pc->data;
562: PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;
563: PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx;
566: /* trim and rescale with reallocation */
567: MatGetOwnershipRange(*P,&ps,&pf);
568: MatGetOwnershipRangeColumn(*P,&pcs,&pcf);
569: pn = pf-ps;
570: pcn = pcf-pcs;
571: PetscMalloc(sizeof(PetscInt)*pn,&lsparse);
572: PetscMalloc(sizeof(PetscInt)*pn,&gsparse);
573: /* allocate */
574: cmax = 0;
575: for (i=ps;i<pf;i++) {
576: lsparse[i-ps] = 0;
577: gsparse[i-ps] = 0;
578: MatGetRow(*P,i,&ncols,&pcol,&pval);
579: if (ncols > cmax) {
580: cmax = ncols;
581: }
582: pmax_pos = 0.;
583: pmax_neg = 0.;
584: for (j=0;j<ncols;j++) {
585: if (PetscRealPart(pval[j]) > pmax_pos) {
586: pmax_pos = PetscRealPart(pval[j]);
587: } else if (PetscRealPart(pval[j]) < pmax_neg) {
588: pmax_neg = PetscRealPart(pval[j]);
589: }
590: }
591: for (j=0;j<ncols;j++) {
592: if (PetscRealPart(pval[j]) >= pmax_pos*cls->interp_threshold || PetscRealPart(pval[j]) <= pmax_neg*cls->interp_threshold) {
593: if (pcol[j] >= pcs && pcol[j] < pcf) {
594: lsparse[i-ps]++;
595: } else {
596: gsparse[i-ps]++;
597: }
598: }
599: }
600: MatRestoreRow(*P,i,&ncols,&pcol,&pval);
601: }
603: PetscMalloc(sizeof(PetscScalar)*cmax,&pnval);
604: PetscMalloc(sizeof(PetscInt)*cmax,&pncol);
606: MatCreate(PetscObjectComm((PetscObject)*P),&Pnew);
607: MatSetType(Pnew, MATAIJ);
608: MatSetSizes(Pnew,pn,pcn,PETSC_DETERMINE,PETSC_DETERMINE);
609: MatSeqAIJSetPreallocation(Pnew,0,lsparse);
610: MatMPIAIJSetPreallocation(Pnew,0,lsparse,0,gsparse);
612: for (i=ps;i<pf;i++) {
613: MatGetRow(*P,i,&ncols,&pcol,&pval);
614: pmax_pos = 0.;
615: pmax_neg = 0.;
616: for (j=0;j<ncols;j++) {
617: if (PetscRealPart(pval[j]) > pmax_pos) {
618: pmax_pos = PetscRealPart(pval[j]);
619: } else if (PetscRealPart(pval[j]) < pmax_neg) {
620: pmax_neg = PetscRealPart(pval[j]);
621: }
622: }
623: pthresh_pos = 0.;
624: pthresh_neg = 0.;
625: ptot_pos = 0.;
626: ptot_neg = 0.;
627: for (j=0;j<ncols;j++) {
628: if (PetscRealPart(pval[j]) >= cls->interp_threshold*pmax_pos) {
629: pthresh_pos += PetscRealPart(pval[j]);
630: } else if (PetscRealPart(pval[j]) <= cls->interp_threshold*pmax_neg) {
631: pthresh_neg += PetscRealPart(pval[j]);
632: }
633: if (PetscRealPart(pval[j]) > 0.) {
634: ptot_pos += PetscRealPart(pval[j]);
635: } else {
636: ptot_neg += PetscRealPart(pval[j]);
637: }
638: }
639: if (PetscAbsReal(pthresh_pos) > 0.) ptot_pos /= pthresh_pos;
640: if (PetscAbsReal(pthresh_neg) > 0.) ptot_neg /= pthresh_neg;
641: idx=0;
642: for (j=0;j<ncols;j++) {
643: if (PetscRealPart(pval[j]) >= pmax_pos*cls->interp_threshold) {
644: pnval[idx] = ptot_pos*pval[j];
645: pncol[idx] = pcol[j];
646: idx++;
647: } else if (PetscRealPart(pval[j]) <= pmax_neg*cls->interp_threshold) {
648: pnval[idx] = ptot_neg*pval[j];
649: pncol[idx] = pcol[j];
650: idx++;
651: }
652: }
653: MatRestoreRow(*P,i,&ncols,&pcol,&pval);
654: MatSetValues(Pnew,1,&i,idx,pncol,pnval,INSERT_VALUES);
655: }
657: MatAssemblyBegin(Pnew, MAT_FINAL_ASSEMBLY);
658: MatAssemblyEnd(Pnew, MAT_FINAL_ASSEMBLY);
659: MatDestroy(P);
661: *P = Pnew;
662: PetscFree(lsparse);
663: PetscFree(gsparse);
664: PetscFree(pncol);
665: PetscFree(pnval);
666: return(0);
667: }
671: PetscErrorCode PCGAMGProlongator_Classical_Standard(PC pc, const Mat A, const Mat G, PetscCoarsenData *agg_lists,Mat *P)
672: {
673: PetscErrorCode ierr;
674: Mat *lA;
675: Vec lv,v,cv;
676: PetscScalar *lcid;
677: IS lis;
678: PetscInt fs,fe,cs,ce,nl,i,j,k,li,lni,ci;
679: VecScatter lscat;
680: PetscInt fn,cn,cid,c_indx;
681: PetscBool iscoarse;
682: PetscScalar c_scalar;
683: const PetscScalar *vcol;
684: const PetscInt *icol;
685: const PetscInt *gidx;
686: PetscInt ncols;
687: PetscInt *lsparse,*gsparse;
688: MatType mtype;
689: PetscInt maxcols;
690: PetscReal diag,jdiag,jwttotal;
691: PetscScalar *pvcol,vi;
692: PetscInt *picol;
693: PetscInt pncols;
694: PetscScalar *pcontrib,pentry,pjentry;
695: /* PC_MG *mg = (PC_MG*)pc->data; */
696: /* PC_GAMG *gamg = (PC_GAMG*)mg->innerctx; */
700: MatGetOwnershipRange(A,&fs,&fe);
701: fn = fe-fs;
702: MatGetVecs(A,NULL,&v);
703: ISCreateStride(PETSC_COMM_SELF,fe-fs,fs,1,&lis);
704: /* increase the overlap by two to get neighbors of neighbors */
705: MatIncreaseOverlap(A,1,&lis,2);
706: ISSort(lis);
707: /* get the local part of A */
708: MatGetSubMatrices(A,1,&lis,&lis,MAT_INITIAL_MATRIX,&lA);
709: /* build the scatter out of it */
710: ISGetLocalSize(lis,&nl);
711: VecCreateSeq(PETSC_COMM_SELF,nl,&lv);
712: VecScatterCreate(v,lis,lv,NULL,&lscat);
714: PetscMalloc(sizeof(PetscInt)*fn,&lsparse);
715: PetscMalloc(sizeof(PetscInt)*fn,&gsparse);
716: PetscMalloc(sizeof(PetscScalar)*nl,&pcontrib);
718: /* create coarse vector */
719: cn = 0;
720: for (i=0;i<fn;i++) {
721: PetscCDEmptyAt(agg_lists,i,&iscoarse);
722: if (!iscoarse) {
723: cn++;
724: }
725: }
726: VecCreateMPI(PetscObjectComm((PetscObject)A),cn,PETSC_DECIDE,&cv);
727: VecGetOwnershipRange(cv,&cs,&ce);
728: cn = 0;
729: for (i=0;i<fn;i++) {
730: PetscCDEmptyAt(agg_lists,i,&iscoarse);
731: if (!iscoarse) {
732: cid = cs+cn;
733: cn++;
734: } else {
735: cid = -1;
736: }
737: *(PetscInt*)&c_scalar = cid;
738: c_indx = fs+i;
739: VecSetValues(v,1,&c_indx,&c_scalar,INSERT_VALUES);
740: }
741: VecScatterBegin(lscat,v,lv,INSERT_VALUES,SCATTER_FORWARD);
742: VecScatterEnd(lscat,v,lv,INSERT_VALUES,SCATTER_FORWARD);
743: /* count to preallocate the prolongator */
744: ISGetIndices(lis,&gidx);
745: VecGetArray(lv,&lcid);
746: maxcols = 0;
747: /* count the number of unique contributing coarse cells for each fine */
748: for (i=0;i<nl;i++) {
749: pcontrib[i] = 0.;
750: MatGetRow(lA[0],i,&ncols,&icol,NULL);
751: if (gidx[i] >= fs && gidx[i] < fe) {
752: li = gidx[i] - fs;
753: lsparse[li] = 0;
754: gsparse[li] = 0;
755: cid = *(PetscInt*)&(lcid[i]);
756: if (cid >= 0) {
757: lsparse[li] = 1;
758: } else {
759: for (j=0;j<ncols;j++) {
760: if (*(PetscInt*)&(lcid[icol[j]]) >= 0) {
761: pcontrib[icol[j]] = 1.;
762: } else {
763: ci = icol[j];
764: MatRestoreRow(lA[0],i,&ncols,&icol,NULL);
765: MatGetRow(lA[0],ci,&ncols,&icol,NULL);
766: for (k=0;k<ncols;k++) {
767: if (*(PetscInt*)&(lcid[icol[k]]) >= 0) {
768: pcontrib[icol[k]] = 1.;
769: }
770: }
771: MatRestoreRow(lA[0],ci,&ncols,&icol,NULL);
772: MatGetRow(lA[0],i,&ncols,&icol,NULL);
773: }
774: }
775: for (j=0;j<ncols;j++) {
776: if (*(PetscInt*)&(lcid[icol[j]]) >= 0 && pcontrib[icol[j]] != 0.) {
777: lni = *(PetscInt*)&(lcid[icol[j]]);
778: if (lni >= cs && lni < ce) {
779: lsparse[li]++;
780: } else {
781: gsparse[li]++;
782: }
783: pcontrib[icol[j]] = 0.;
784: } else {
785: ci = icol[j];
786: MatRestoreRow(lA[0],i,&ncols,&icol,NULL);
787: MatGetRow(lA[0],ci,&ncols,&icol,NULL);
788: for (k=0;k<ncols;k++) {
789: if (*(PetscInt*)&(lcid[icol[k]]) >= 0 && pcontrib[icol[k]] != 0.) {
790: lni = *(PetscInt*)&(lcid[icol[k]]);
791: if (lni >= cs && lni < ce) {
792: lsparse[li]++;
793: } else {
794: gsparse[li]++;
795: }
796: pcontrib[icol[k]] = 0.;
797: }
798: }
799: MatRestoreRow(lA[0],ci,&ncols,&icol,NULL);
800: MatGetRow(lA[0],i,&ncols,&icol,NULL);
801: }
802: }
803: }
804: if (lsparse[li] + gsparse[li] > maxcols) maxcols = lsparse[li]+gsparse[li];
805: }
806: MatRestoreRow(lA[0],i,&ncols,&icol,&vcol);
807: }
808: PetscMalloc(sizeof(PetscInt)*maxcols,&picol);
809: PetscMalloc(sizeof(PetscScalar)*maxcols,&pvcol);
810: MatCreate(PetscObjectComm((PetscObject)A),P);
811: MatGetType(A,&mtype);
812: MatSetType(*P,mtype);
813: MatSetSizes(*P,fn,cn,PETSC_DETERMINE,PETSC_DETERMINE);
814: MatMPIAIJSetPreallocation(*P,0,lsparse,0,gsparse);
815: MatSeqAIJSetPreallocation(*P,0,lsparse);
816: for (i=0;i<nl;i++) {
817: diag = 0.;
818: if (gidx[i] >= fs && gidx[i] < fe) {
819: li = gidx[i] - fs;
820: pncols=0;
821: cid = *(PetscInt*)&(lcid[i]);
822: if (cid >= 0) {
823: pncols = 1;
824: picol[0] = cid;
825: pvcol[0] = 1.;
826: } else {
827: MatGetRow(lA[0],i,&ncols,&icol,&vcol);
828: for (j=0;j<ncols;j++) {
829: pentry = vcol[j];
830: if (*(PetscInt*)&(lcid[icol[j]]) >= 0) {
831: /* coarse neighbor */
832: pcontrib[icol[j]] += pentry;
833: } else if (icol[j] != i) {
834: /* the neighbor is a strongly connected fine node */
835: ci = icol[j];
836: vi = vcol[j];
837: MatRestoreRow(lA[0],i,&ncols,&icol,&vcol);
838: MatGetRow(lA[0],ci,&ncols,&icol,&vcol);
839: jwttotal=0.;
840: jdiag = 0.;
841: for (k=0;k<ncols;k++) {
842: if (ci == icol[k]) {
843: jdiag = PetscRealPart(vcol[k]);
844: }
845: }
846: for (k=0;k<ncols;k++) {
847: if (*(PetscInt*)&(lcid[icol[k]]) >= 0 && jdiag*PetscRealPart(vcol[k]) < 0.) {
848: pjentry = vcol[k];
849: jwttotal += PetscRealPart(pjentry);
850: }
851: }
852: if (jwttotal != 0.) {
853: jwttotal = PetscRealPart(vi)/jwttotal;
854: for (k=0;k<ncols;k++) {
855: if (*(PetscInt*)&(lcid[icol[k]]) >= 0 && jdiag*PetscRealPart(vcol[k]) < 0.) {
856: pjentry = vcol[k]*jwttotal;
857: pcontrib[icol[k]] += pjentry;
858: }
859: }
860: } else {
861: diag += PetscRealPart(vi);
862: }
863: MatRestoreRow(lA[0],ci,&ncols,&icol,&vcol);
864: MatGetRow(lA[0],i,&ncols,&icol,&vcol);
865: } else {
866: diag += PetscRealPart(vcol[j]);
867: }
868: }
869: if (diag != 0.) {
870: diag = 1./diag;
871: for (j=0;j<ncols;j++) {
872: if (*(PetscInt*)&(lcid[icol[j]]) >= 0 && pcontrib[icol[j]] != 0.) {
873: /* the neighbor is a coarse node */
874: if (PetscAbsScalar(pcontrib[icol[j]]) > 0.0) {
875: lni = *(PetscInt*)&(lcid[icol[j]]);
876: pvcol[pncols] = -pcontrib[icol[j]]*diag;
877: picol[pncols] = lni;
878: pncols++;
879: }
880: pcontrib[icol[j]] = 0.;
881: } else {
882: /* the neighbor is a strongly connected fine node */
883: ci = icol[j];
884: MatRestoreRow(lA[0],i,&ncols,&icol,&vcol);
885: MatGetRow(lA[0],ci,&ncols,&icol,&vcol);
886: for (k=0;k<ncols;k++) {
887: if (*(PetscInt*)&(lcid[icol[k]]) >= 0 && pcontrib[icol[k]] != 0.) {
888: if (PetscAbsScalar(pcontrib[icol[k]]) > 0.0) {
889: lni = *(PetscInt*)&(lcid[icol[k]]);
890: pvcol[pncols] = -pcontrib[icol[k]]*diag;
891: picol[pncols] = lni;
892: pncols++;
893: }
894: pcontrib[icol[k]] = 0.;
895: }
896: }
897: MatRestoreRow(lA[0],ci,&ncols,&icol,&vcol);
898: MatGetRow(lA[0],i,&ncols,&icol,&vcol);
899: }
900: pcontrib[icol[j]] = 0.;
901: }
902: MatRestoreRow(lA[0],i,&ncols,&icol,&vcol);
903: }
904: }
905: ci = gidx[i];
906: li = gidx[i] - fs;
907: if (pncols > 0) {
908: MatSetValues(*P,1,&ci,pncols,picol,pvcol,INSERT_VALUES);
909: }
910: }
911: }
912: ISRestoreIndices(lis,&gidx);
913: VecRestoreArray(lv,&lcid);
915: PetscFree(pcontrib);
916: PetscFree(picol);
917: PetscFree(pvcol);
918: PetscFree(lsparse);
919: PetscFree(gsparse);
920: ISDestroy(&lis);
921: MatDestroyMatrices(1,&lA);
922: VecDestroy(&lv);
923: VecDestroy(&cv);
924: VecDestroy(&v);
925: VecScatterDestroy(&lscat);
927: MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY);
928: MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY);
930: /*
931: Mat Pold;
932: PCGAMGProlongator_Classical(pc,A,G,agg_lists,&Pold);
933: MatView(Pold,PETSC_VIEWER_STDOUT_WORLD);
934: MatView(*P,PETSC_VIEWER_STDOUT_WORLD);
935: MatDestroy(&Pold);
936: */
937: return(0);
938: }
942: PetscErrorCode PCGAMGOptProl_Classical_Jacobi(PC pc,const Mat A,Mat *P)
943: {
945: PetscErrorCode ierr;
946: PetscInt f,s,n,cf,cs,i,idx;
947: PetscInt *coarserows;
948: PetscInt ncols;
949: const PetscInt *pcols;
950: const PetscScalar *pvals;
951: Mat Pnew;
952: Vec diag;
953: PC_MG *mg = (PC_MG*)pc->data;
954: PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;
955: PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx;
958: if (cls->nsmooths == 0) {
959: PCGAMGTruncateProlongator_Private(pc,P);
960: return(0);
961: }
962: MatGetOwnershipRange(*P,&s,&f);
963: n = f-s;
964: MatGetOwnershipRangeColumn(*P,&cs,&cf);
965: PetscMalloc(sizeof(PetscInt)*n,&coarserows);
966: /* identify the rows corresponding to coarse unknowns */
967: idx = 0;
968: for (i=s;i<f;i++) {
969: MatGetRow(*P,i,&ncols,&pcols,&pvals);
970: /* assume, for now, that it's a coarse unknown if it has a single unit entry */
971: if (ncols == 1) {
972: if (pvals[0] == 1.) {
973: coarserows[idx] = i;
974: idx++;
975: }
976: }
977: MatRestoreRow(*P,i,&ncols,&pcols,&pvals);
978: }
979: MatGetVecs(A,&diag,0);
980: MatGetDiagonal(A,diag);
981: VecReciprocal(diag);
982: for (i=0;i<cls->nsmooths;i++) {
983: MatMatMult(A,*P,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&Pnew);
984: MatZeroRows(Pnew,idx,coarserows,0.,NULL,NULL);
985: MatDiagonalScale(Pnew,diag,0);
986: MatAYPX(Pnew,-1.0,*P,DIFFERENT_NONZERO_PATTERN);
987: MatDestroy(P);
988: *P = Pnew;
989: Pnew = NULL;
990: }
991: VecDestroy(&diag);
992: PetscFree(coarserows);
993: PCGAMGTruncateProlongator_Private(pc,P);
994: return(0);
995: }
999: PetscErrorCode PCGAMGProlongator_Classical(PC pc, const Mat A, const Mat G, PetscCoarsenData *agg_lists,Mat *P)
1000: {
1001: PetscErrorCode ierr;
1002: PetscErrorCode (*f)(PC,Mat,Mat,PetscCoarsenData*,Mat*);
1003: PC_MG *mg = (PC_MG*)pc->data;
1004: PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;
1005: PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx;
1008: PetscFunctionListFind(PCGAMGClassicalProlongatorList,cls->prolongtype,&f);
1009: if (!f)SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Cannot find PCGAMG Classical prolongator type");
1010: (*f)(pc,A,G,agg_lists,P);
1011: return(0);
1012: }
1016: PetscErrorCode PCGAMGDestroy_Classical(PC pc)
1017: {
1019: PC_MG *mg = (PC_MG*)pc->data;
1020: PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;
1023: PetscFree(pc_gamg->subctx);
1024: PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalSetType_C",NULL);
1025: return(0);
1026: }
1030: PetscErrorCode PCGAMGSetFromOptions_Classical(PC pc)
1031: {
1032: PC_MG *mg = (PC_MG*)pc->data;
1033: PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;
1034: PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx;
1035: char tname[256];
1036: PetscErrorCode ierr;
1037: PetscBool flg;
1040: PetscOptionsHead("GAMG-Classical options");
1041: PetscOptionsFList("-pc_gamg_classical_type","Type of Classical AMG prolongation",
1042: "PCGAMGClassicalSetType",PCGAMGClassicalProlongatorList,cls->prolongtype, tname, sizeof(tname), &flg);
1043: if (flg) {
1044: PCGAMGClassicalSetType(pc,tname);
1045: }
1046: PetscOptionsReal("-pc_gamg_classical_interp_threshold","Threshold for classical interpolator entries","",cls->interp_threshold,&cls->interp_threshold,NULL);
1047: PetscOptionsInt("-pc_gamg_classical_nsmooths","Threshold for classical interpolator entries","",cls->nsmooths,&cls->nsmooths,NULL);
1048: PetscOptionsTail();
1049: return(0);
1050: }
1054: PetscErrorCode PCGAMGSetData_Classical(PC pc, Mat A)
1055: {
1056: PC_MG *mg = (PC_MG*)pc->data;
1057: PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;
1060: /* no data for classical AMG */
1061: pc_gamg->data = NULL;
1062: pc_gamg->data_cell_cols = 0;
1063: pc_gamg->data_cell_rows = 0;
1064: pc_gamg->data_sz = 0;
1065: return(0);
1066: }
1071: PetscErrorCode PCGAMGClassicalFinalizePackage(void)
1072: {
1076: PCGAMGClassicalPackageInitialized = PETSC_FALSE;
1077: PetscFunctionListDestroy(&PCGAMGClassicalProlongatorList);
1078: return(0);
1079: }
1083: PetscErrorCode PCGAMGClassicalInitializePackage(void)
1084: {
1088: if (PCGAMGClassicalPackageInitialized) return(0);
1089: PetscFunctionListAdd(&PCGAMGClassicalProlongatorList,PCGAMGCLASSICALDIRECT,PCGAMGProlongator_Classical_Direct);
1090: PetscFunctionListAdd(&PCGAMGClassicalProlongatorList,PCGAMGCLASSICALSTANDARD,PCGAMGProlongator_Classical_Standard);
1091: PetscRegisterFinalize(PCGAMGClassicalFinalizePackage);
1092: return(0);
1093: }
1095: /* -------------------------------------------------------------------------- */
1096: /*
1097: PCCreateGAMG_Classical
1099: */
1102: PetscErrorCode PCCreateGAMG_Classical(PC pc)
1103: {
1105: PC_MG *mg = (PC_MG*)pc->data;
1106: PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;
1107: PC_GAMG_Classical *pc_gamg_classical;
1110: PCGAMGClassicalInitializePackage();
1111: if (pc_gamg->subctx) {
1112: /* call base class */
1113: PCDestroy_GAMG(pc);
1114: }
1116: /* create sub context for SA */
1117: PetscNewLog(pc,&pc_gamg_classical);
1118: pc_gamg->subctx = pc_gamg_classical;
1119: pc->ops->setfromoptions = PCGAMGSetFromOptions_Classical;
1120: /* reset does not do anything; setup not virtual */
1122: /* set internal function pointers */
1123: pc_gamg->ops->destroy = PCGAMGDestroy_Classical;
1124: pc_gamg->ops->graph = PCGAMGGraph_Classical;
1125: pc_gamg->ops->coarsen = PCGAMGCoarsen_Classical;
1126: pc_gamg->ops->prolongator = PCGAMGProlongator_Classical;
1127: pc_gamg->ops->optprol = PCGAMGOptProl_Classical_Jacobi;
1128: pc_gamg->ops->setfromoptions = PCGAMGSetFromOptions_Classical;
1130: pc_gamg->ops->createdefaultdata = PCGAMGSetData_Classical;
1131: pc_gamg_classical->interp_threshold = 0.2;
1132: pc_gamg_classical->nsmooths = 0;
1133: PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalSetType_C",PCGAMGClassicalSetType_GAMG);
1134: PCGAMGClassicalSetType(pc,PCGAMGCLASSICALSTANDARD);
1135: return(0);
1136: }