1 #include <../src/ksp/pc/impls/gamg/gamg.h> /*I "petscpc.h" I*/ 2 #include <petsc-private/kspimpl.h> 3 4 typedef struct { 5 PetscReal dummy; /* empty struct; save for later */ 6 } PC_GAMG_Classical; 7 8 9 #undef __FUNCT__ 10 #define __FUNCT__ "PCGAMGClassicalCreateGhostVector_Private" 11 PetscErrorCode PCGAMGClassicalCreateGhostVector_Private(Mat G,Vec *gvec,PetscInt **global) 12 { 13 Mat_MPIAIJ *aij = (Mat_MPIAIJ*)G->data; 14 PetscErrorCode ierr; 15 PetscBool isMPIAIJ; 16 17 PetscFunctionBegin; 18 ierr = PetscObjectTypeCompare((PetscObject)G, MATMPIAIJ, &isMPIAIJ); CHKERRQ(ierr); 19 if (isMPIAIJ) { 20 if (gvec)ierr = VecDuplicate(aij->lvec,gvec);CHKERRQ(ierr); 21 if (global)*global = aij->garray; 22 } else { 23 /* no off-processor nodes */ 24 if (gvec)*gvec = NULL; 25 if (global)*global = NULL; 26 } 27 PetscFunctionReturn(0); 28 } 29 30 #undef __FUNCT__ 31 #define __FUNCT__ "PCGAMGClassicalGraphSplitting_Private" 32 /* 33 Split the relevant graph into diagonal and off-diagonal parts in local numbering; for now this 34 a roundabout private interface to the mats' internal diag and offdiag mats. 35 */ 36 PetscErrorCode PCGAMGClassicalGraphSplitting_Private(Mat G,Mat *Gd, Mat *Go) 37 { 38 Mat_MPIAIJ *aij = (Mat_MPIAIJ*)G->data; 39 PetscErrorCode ierr; 40 PetscBool isMPIAIJ; 41 PetscFunctionBegin; 42 ierr = PetscObjectTypeCompare((PetscObject)G, MATMPIAIJ, &isMPIAIJ ); CHKERRQ(ierr); 43 if (isMPIAIJ) { 44 *Gd = aij->A; 45 *Go = aij->B; 46 } else { 47 *Gd = G; 48 *Go = NULL; 49 } 50 PetscFunctionReturn(0); 51 } 52 53 #undef __FUNCT__ 54 #define __FUNCT__ "PCGAMGGraph_Classical" 55 PetscErrorCode PCGAMGGraph_Classical(PC pc,const Mat A,Mat *G) 56 { 57 PetscInt s,f,idx; 58 PetscInt r,c,ncols; 59 const PetscInt *rcol; 60 const PetscScalar *rval; 61 PetscInt *gcol; 62 PetscScalar *gval; 63 PetscReal rmax; 64 PetscInt ncolstotal,cmax = 0; 65 PC_MG *mg; 66 PC_GAMG *gamg; 67 PetscErrorCode ierr; 68 PetscInt *gsparse,*lsparse; 69 PetscScalar *Amax; 70 Mat lA,gA; 71 MatType mtype; 72 73 PetscFunctionBegin; 74 mg = (PC_MG *)pc->data; 75 gamg = (PC_GAMG *)mg->innerctx; 76 77 ierr = MatGetOwnershipRange(A,&s,&f);CHKERRQ(ierr); 78 79 ierr = PCGAMGClassicalGraphSplitting_Private(A,&lA,&gA);CHKERRQ(ierr); 80 81 ierr = PetscMalloc(sizeof(PetscInt)*(f - s),&lsparse);CHKERRQ(ierr); 82 if (gA) {ierr = PetscMalloc(sizeof(PetscInt)*(f - s),&gsparse);CHKERRQ(ierr);} 83 else { 84 gsparse = NULL; 85 } 86 ierr = PetscMalloc(sizeof(PetscScalar)*(f - s),&Amax);CHKERRQ(ierr); 87 88 for (r = 0;r < f-s;r++) { 89 lsparse[r] = 0; 90 if (gsparse) gsparse[r] = 0; 91 } 92 93 for (r = 0;r < f-s;r++) { 94 /* determine the maximum off-diagonal in each row */ 95 rmax = 0.; 96 ierr = MatGetRow(lA,r,&ncols,&rcol,&rval);CHKERRQ(ierr); 97 ncolstotal = ncols; 98 for (c = 0; c < ncols; c++) { 99 if (PetscAbsScalar(rval[c]) > rmax && rcol[c] != r) { 100 rmax = PetscAbsScalar(rval[c]); 101 } 102 } 103 ierr = MatRestoreRow(lA,r,&ncols,&rcol,&rval);CHKERRQ(ierr); 104 105 if (gA) { 106 ierr = MatGetRow(gA,r,&ncols,&rcol,&rval);CHKERRQ(ierr); 107 ncolstotal += ncols; 108 for (c = 0; c < ncols; c++) { 109 if (PetscAbsScalar(rval[c]) > rmax) { 110 rmax = PetscAbsScalar(rval[c]); 111 } 112 } 113 ierr = MatRestoreRow(gA,r,&ncols,&rcol,&rval);CHKERRQ(ierr); 114 } 115 Amax[r] = rmax; 116 if (ncolstotal > cmax) cmax = ncolstotal; 117 118 ierr = MatGetRow(lA,r,&ncols,&rcol,&rval);CHKERRQ(ierr); 119 idx = 0; 120 121 /* create the local and global sparsity patterns */ 122 for (c = 0; c < ncols; c++) { 123 if (PetscAbsScalar(rval[c]) > gamg->threshold*PetscRealPart(Amax[r])) { 124 idx++; 125 } 126 } 127 ierr = MatRestoreRow(lA,r,&ncols,&rcol,&rval);CHKERRQ(ierr); 128 lsparse[r] = idx; 129 if (gA) { 130 idx = 0; 131 ierr = MatGetRow(gA,r,&ncols,&rcol,&rval);CHKERRQ(ierr); 132 for (c = 0; c < ncols; c++) { 133 if (PetscAbsScalar(rval[c]) > gamg->threshold*PetscRealPart(Amax[r])) { 134 idx++; 135 } 136 } 137 ierr = MatRestoreRow(gA,r,&ncols,&rcol,&rval);CHKERRQ(ierr); 138 gsparse[r] = idx; 139 } 140 } 141 ierr = PetscMalloc(sizeof(PetscScalar)*cmax,&gval);CHKERRQ(ierr); 142 ierr = PetscMalloc(sizeof(PetscInt)*cmax,&gcol);CHKERRQ(ierr); 143 144 ierr = MatCreate(PetscObjectComm((PetscObject)A),G); CHKERRQ(ierr); 145 ierr = MatGetType(A,&mtype);CHKERRQ(ierr); 146 ierr = MatSetType(*G,mtype);CHKERRQ(ierr); 147 ierr = MatSetSizes(*G,f-s,f-s,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr); 148 ierr = MatMPIAIJSetPreallocation(*G,0,lsparse,0,gsparse);CHKERRQ(ierr); 149 ierr = MatSeqAIJSetPreallocation(*G,0,lsparse);CHKERRQ(ierr); 150 for (r = s;r < f;r++) { 151 ierr = MatGetRow(A,r,&ncols,&rcol,&rval);CHKERRQ(ierr); 152 idx = 0; 153 for (c = 0; c < ncols; c++) { 154 /* classical strength of connection */ 155 if (PetscAbsScalar(rval[c]) > gamg->threshold*PetscRealPart(Amax[r-s])) { 156 gcol[idx] = rcol[c]; 157 gval[idx] = rval[c]; 158 idx++; 159 } 160 } 161 ierr = MatSetValues(*G,1,&r,idx,gcol,gval,INSERT_VALUES);CHKERRQ(ierr); 162 ierr = MatRestoreRow(A,r,&ncols,&rcol,&rval);CHKERRQ(ierr); 163 } 164 ierr = MatAssemblyBegin(*G, MAT_FINAL_ASSEMBLY); CHKERRQ(ierr); 165 ierr = MatAssemblyEnd(*G, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 166 167 ierr = PetscFree(gval);CHKERRQ(ierr); 168 ierr = PetscFree(gcol);CHKERRQ(ierr); 169 ierr = PetscFree(lsparse);CHKERRQ(ierr); 170 ierr = PetscFree(gsparse);CHKERRQ(ierr); 171 ierr = PetscFree(Amax);CHKERRQ(ierr); 172 PetscFunctionReturn(0); 173 } 174 175 176 #undef __FUNCT__ 177 #define __FUNCT__ "PCGAMGCoarsen_Classical" 178 PetscErrorCode PCGAMGCoarsen_Classical(PC pc,Mat *G,PetscCoarsenData **agg_lists) 179 { 180 PetscErrorCode ierr; 181 MatCoarsen crs; 182 MPI_Comm fcomm = ((PetscObject)pc)->comm; 183 184 PetscFunctionBegin; 185 186 187 /* construct the graph if necessary */ 188 if (!G) { 189 SETERRQ(fcomm,PETSC_ERR_ARG_WRONGSTATE,"Must set Graph in PC in PCGAMG before coarsening"); 190 } 191 192 ierr = MatCoarsenCreate(fcomm,&crs);CHKERRQ(ierr); 193 ierr = MatCoarsenSetFromOptions(crs);CHKERRQ(ierr); 194 ierr = MatCoarsenSetAdjacency(crs,*G);CHKERRQ(ierr); 195 ierr = MatCoarsenSetStrictAggs(crs,PETSC_TRUE);CHKERRQ(ierr); 196 ierr = MatCoarsenApply(crs);CHKERRQ(ierr); 197 ierr = MatCoarsenGetData(crs,agg_lists);CHKERRQ(ierr); 198 ierr = MatCoarsenDestroy(&crs);CHKERRQ(ierr); 199 200 PetscFunctionReturn(0); 201 } 202 203 #undef __FUNCT__ 204 #define __FUNCT__ "PCGAMGClassicalGhost_Private" 205 /* 206 Find all ghost nodes that are coarse and output the fine/coarse splitting for those as well 207 208 Input: 209 G - graph; 210 gvec - Global Vector 211 avec - Local part of the scattered vec 212 bvec - Global part of the scattered vec 213 214 Output: 215 findx - indirection t 216 217 */ 218 PetscErrorCode PCGAMGClassicalGhost_Private(Mat G,Vec v,Vec gv) 219 { 220 PetscErrorCode ierr; 221 Mat_MPIAIJ *aij = (Mat_MPIAIJ*)G->data; 222 PetscBool isMPIAIJ; 223 224 PetscFunctionBegin; 225 ierr = PetscObjectTypeCompare((PetscObject)G, MATMPIAIJ, &isMPIAIJ ); CHKERRQ(ierr); 226 if (isMPIAIJ) { 227 ierr = VecScatterBegin(aij->Mvctx,v,gv,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 228 ierr = VecScatterEnd(aij->Mvctx,v,gv,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 229 } 230 PetscFunctionReturn(0); 231 } 232 233 #undef __FUNCT__ 234 #define __FUNCT__ "PCGAMGProlongator_Classical" 235 PetscErrorCode PCGAMGProlongator_Classical(PC pc, const Mat A, const Mat G, PetscCoarsenData *agg_lists,Mat *P) 236 { 237 PetscErrorCode ierr; 238 MPI_Comm comm; 239 Mat lG,gG,lA,gA; /* on and off diagonal matrices */ 240 PetscInt fn; /* fine local blocked sizes */ 241 PetscInt cn; /* coarse local blocked sizes */ 242 PetscInt gn; /* size of the off-diagonal fine vector */ 243 PetscInt fs,fe; /* fine (row) ownership range*/ 244 PetscInt cs,ce; /* coarse (column) ownership range */ 245 PetscInt i,j,k; /* indices! */ 246 PetscBool iscoarse; /* flag for determining if a node is coarse */ 247 PetscInt *lcid,*gcid; /* on and off-processor coarse unknown IDs */ 248 PetscInt *lsparse,*gsparse; /* on and off-processor sparsity patterns for prolongator */ 249 PetscScalar pij; 250 const PetscScalar *rval; 251 const PetscInt *rcol; 252 PetscScalar g_pos,g_neg,a_pos,a_neg,diag,invdiag,alpha,beta; 253 Vec F; /* vec of coarse size */ 254 Vec C; /* vec of fine size */ 255 Vec gF; /* vec of off-diagonal fine size */ 256 MatType mtype; 257 PetscInt c_indx; 258 const PetscScalar *vcols; 259 const PetscInt *icols; 260 PetscScalar c_scalar; 261 PetscInt ncols,col; 262 PetscInt row_f,row_c; 263 PetscInt cmax=0,ncolstotal,idx; 264 PetscScalar *pvals; 265 PetscInt *pcols; 266 267 PetscFunctionBegin; 268 comm = ((PetscObject)pc)->comm; 269 ierr = MatGetOwnershipRange(A,&fs,&fe); CHKERRQ(ierr); 270 fn = (fe - fs); 271 272 ierr = MatGetVecs(A,&F,NULL);CHKERRQ(ierr); 273 274 /* get the number of local unknowns and the indices of the local unknowns */ 275 276 ierr = PetscMalloc(sizeof(PetscInt)*fn,&lsparse);CHKERRQ(ierr); 277 ierr = PetscMalloc(sizeof(PetscInt)*fn,&gsparse);CHKERRQ(ierr); 278 ierr = PetscMalloc(sizeof(PetscInt)*fn,&lcid);CHKERRQ(ierr); 279 280 /* count the number of coarse unknowns */ 281 cn = 0; 282 for (i=0;i<fn;i++) { 283 /* filter out singletons */ 284 ierr = PetscCDEmptyAt(agg_lists,i,&iscoarse); CHKERRQ(ierr); 285 lcid[i] = -1; 286 if (!iscoarse) { 287 cn++; 288 } 289 } 290 291 /* create the coarse vector */ 292 ierr = VecCreateMPI(comm,cn,PETSC_DECIDE,&C);CHKERRQ(ierr); 293 ierr = VecGetOwnershipRange(C,&cs,&ce);CHKERRQ(ierr); 294 295 /* construct a global vector indicating the global indices of the coarse unknowns */ 296 cn = 0; 297 for (i=0;i<fn;i++) { 298 ierr = PetscCDEmptyAt(agg_lists,i,&iscoarse); CHKERRQ(ierr); 299 if (!iscoarse) { 300 lcid[i] = cs+cn; 301 cn++; 302 } else { 303 lcid[i] = -1; 304 } 305 c_scalar = (PetscScalar)lcid[i]; 306 c_indx = fs+i; 307 ierr = VecSetValues(F,1,&c_indx,&c_scalar,INSERT_VALUES);CHKERRQ(ierr); 308 } 309 310 ierr = VecAssemblyBegin(F);CHKERRQ(ierr); 311 ierr = VecAssemblyEnd(F);CHKERRQ(ierr); 312 313 /* split the graph into two */ 314 ierr = PCGAMGClassicalGraphSplitting_Private(G,&lG,&gG);CHKERRQ(ierr); 315 ierr = PCGAMGClassicalGraphSplitting_Private(A,&lA,&gA);CHKERRQ(ierr); 316 317 /* scatter to the ghost vector */ 318 ierr = PCGAMGClassicalCreateGhostVector_Private(G,&gF,NULL);CHKERRQ(ierr); 319 ierr = PCGAMGClassicalGhost_Private(G,F,gF);CHKERRQ(ierr); 320 321 if (gG) { 322 ierr = VecGetSize(gF,&gn);CHKERRQ(ierr); 323 ierr = PetscMalloc(sizeof(PetscInt)*gn,&gcid);CHKERRQ(ierr); 324 for (i=0;i<gn;i++) { 325 ierr = VecGetValues(gF,1,&i,&c_scalar);CHKERRQ(ierr); 326 gcid[i] = (PetscInt)PetscRealPart(c_scalar); 327 } 328 } 329 330 ierr = VecDestroy(&F);CHKERRQ(ierr); 331 ierr = VecDestroy(&gF);CHKERRQ(ierr); 332 ierr = VecDestroy(&C);CHKERRQ(ierr); 333 334 /* count the on and off processor sparsity patterns for the prolongator */ 335 336 for (i=0;i<fn;i++) { 337 /* on */ 338 ierr = MatGetRow(lG,i,&ncols,&icols,&vcols);CHKERRQ(ierr); 339 ncolstotal = ncols; 340 lsparse[i] = 0; 341 gsparse[i] = 0; 342 if (lcid[i] >= 0) { 343 lsparse[i] = 1; 344 gsparse[i] = 0; 345 } else { 346 for (j = 0;j < ncols;j++) { 347 col = icols[j]; 348 if (lcid[col] >= 0 && vcols[j] != 0.) { 349 lsparse[i] += 1; 350 } 351 } 352 ierr = MatRestoreRow(lG,i,&ncols,&icols,&vcols);CHKERRQ(ierr); 353 ncolstotal += ncols; 354 /* off */ 355 if (gG) { 356 ierr = MatGetRow(gG,i,&ncols,&icols,&vcols);CHKERRQ(ierr); 357 for (j = 0; j < ncols; j++) { 358 col = icols[j]; 359 if (gcid[col] >= 0 && vcols[j] != 0.) { 360 gsparse[i] += 1; 361 } 362 } 363 ierr = MatRestoreRow(gG,i,&ncols,NULL,NULL);CHKERRQ(ierr); 364 } 365 if (ncolstotal > cmax) cmax = ncolstotal; 366 } 367 } 368 369 ierr = PetscMalloc(sizeof(PetscInt)*cmax,&pcols);CHKERRQ(ierr); 370 ierr = PetscMalloc(sizeof(PetscScalar)*cmax,&pvals);CHKERRQ(ierr); 371 372 /* preallocate and create the prolongator */ 373 ierr = MatCreate(comm,P); CHKERRQ(ierr); 374 ierr = MatGetType(G,&mtype);CHKERRQ(ierr); 375 ierr = MatSetType(*P,mtype);CHKERRQ(ierr); 376 377 ierr = MatSetSizes(*P,fn,cn,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr); 378 ierr = MatMPIAIJSetPreallocation(*P,0,lsparse,0,gsparse);CHKERRQ(ierr); 379 ierr = MatSeqAIJSetPreallocation(*P,0,lsparse);CHKERRQ(ierr); 380 381 /* loop over local fine nodes -- get the diagonal, the sum of positive and negative strong and weak weights, and set up the row */ 382 for (i = 0;i < fn;i++) { 383 /* determine on or off */ 384 row_f = i + fs; 385 row_c = lcid[i]; 386 if (row_c >= 0) { 387 pij = 1.; 388 ierr = MatSetValues(*P,1,&row_f,1,&row_c,&pij,INSERT_VALUES);CHKERRQ(ierr); 389 } else { 390 PetscInt nstrong=0,ntotal=0; 391 g_pos = 0.; 392 g_neg = 0.; 393 a_pos = 0.; 394 a_neg = 0.; 395 diag = 0.; 396 397 /* local strong connections */ 398 ierr = MatGetRow(lG,i,&ncols,&rcol,&rval);CHKERRQ(ierr); 399 for (k = 0; k < ncols; k++) { 400 if (lcid[rcol[k]] >= 0) { 401 if (PetscRealPart(rval[k]) > 0) { 402 g_pos += rval[k]; 403 } else { 404 g_neg += rval[k]; 405 } 406 nstrong++; 407 } 408 } 409 ierr = MatRestoreRow(lG,i,&ncols,&rcol,&rval);CHKERRQ(ierr); 410 411 /* ghosted strong connections */ 412 if (gG) { 413 ierr = MatGetRow(gG,i,&ncols,&rcol,&rval);CHKERRQ(ierr); 414 for (k = 0; k < ncols; k++) { 415 if (gcid[rcol[k]] >= 0) { 416 if (PetscRealPart(rval[k]) > 0.) { 417 g_pos += rval[k]; 418 } else { 419 g_neg += rval[k]; 420 } 421 nstrong++; 422 } 423 } 424 ierr = MatRestoreRow(gG,i,&ncols,&rcol,&rval);CHKERRQ(ierr); 425 } 426 427 /* local all connections */ 428 ierr = MatGetRow(lA,i,&ncols,&rcol,&rval);CHKERRQ(ierr); 429 for (k = 0; k < ncols; k++) { 430 if (rcol[k] != i) { 431 if (PetscRealPart(rval[k]) > 0) { 432 a_pos += rval[k]; 433 } else { 434 a_neg += rval[k]; 435 } 436 ntotal++; 437 } else diag = rval[k]; 438 } 439 ierr = MatRestoreRow(lA,i,&ncols,&rcol,&rval);CHKERRQ(ierr); 440 441 /* ghosted all connections */ 442 if (gA) { 443 ierr = MatGetRow(gA,i,&ncols,&rcol,&rval);CHKERRQ(ierr); 444 for (k = 0; k < ncols; k++) { 445 if (PetscRealPart(rval[k]) > 0.) { 446 a_pos += PetscRealPart(rval[k]); 447 } else { 448 a_neg += PetscRealPart(rval[k]); 449 } 450 ntotal++; 451 } 452 ierr = MatRestoreRow(gA,i,&ncols,&rcol,&rval);CHKERRQ(ierr); 453 } 454 455 if (g_neg == 0.) { 456 alpha = 0.; 457 } else { 458 alpha = -a_neg/g_neg; 459 } 460 461 if (g_pos == 0.) { 462 diag += a_pos; 463 beta = 0.; 464 } else { 465 beta = -a_pos/g_pos; 466 } 467 if (diag == 0.) { 468 invdiag = 0.; 469 } else invdiag = 1. / diag; 470 /* on */ 471 ierr = MatGetRow(lG,i,&ncols,&icols,&vcols);CHKERRQ(ierr); 472 idx = 0; 473 for (j = 0;j < ncols;j++) { 474 col = icols[j]; 475 if (lcid[col] >= 0 && vcols[j] != 0.) { 476 row_f = i + fs; 477 row_c = lcid[col]; 478 /* set the values for on-processor ones */ 479 if (PetscRealPart(vcols[j]) < 0.) { 480 pij = vcols[j]*alpha*invdiag; 481 } else { 482 pij = vcols[j]*beta*invdiag; 483 } 484 if (PetscAbsScalar(pij) != 0.) { 485 pvals[idx] = pij; 486 pcols[idx] = row_c; 487 idx++; 488 } 489 } 490 } 491 ierr = MatRestoreRow(lG,i,&ncols,&icols,&vcols);CHKERRQ(ierr); 492 /* off */ 493 if (gG) { 494 ierr = MatGetRow(gG,i,&ncols,&icols,&vcols);CHKERRQ(ierr); 495 for (j = 0; j < ncols; j++) { 496 col = icols[j]; 497 if (gcid[col] >= 0 && vcols[j] != 0.) { 498 row_f = i + fs; 499 row_c = gcid[col]; 500 /* set the values for on-processor ones */ 501 if (PetscRealPart(vcols[j]) < 0.) { 502 pij = vcols[j]*alpha*invdiag; 503 } else { 504 pij = vcols[j]*beta*invdiag; 505 } 506 if (PetscAbsScalar(pij) != 0.) { 507 pvals[idx] = pij; 508 pcols[idx] = row_c; 509 idx++; 510 } 511 } 512 } 513 ierr = MatRestoreRow(gG,i,&ncols,&icols,&vcols);CHKERRQ(ierr); 514 } 515 ierr = MatSetValues(*P,1,&row_f,idx,pcols,pvals,INSERT_VALUES);CHKERRQ(ierr); 516 } 517 } 518 519 ierr = MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 520 ierr = MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 521 522 ierr = PetscFree(lsparse);CHKERRQ(ierr); 523 ierr = PetscFree(gsparse);CHKERRQ(ierr); 524 ierr = PetscFree(pcols);CHKERRQ(ierr); 525 ierr = PetscFree(pvals);CHKERRQ(ierr); 526 ierr = PetscFree(lcid);CHKERRQ(ierr); 527 if (gG) {ierr = PetscFree(gcid);CHKERRQ(ierr);} 528 529 PetscFunctionReturn(0); 530 } 531 532 #undef __FUNCT__ 533 #define __FUNCT__ "PCGAMGDestroy_Classical" 534 PetscErrorCode PCGAMGDestroy_Classical(PC pc) 535 { 536 PetscErrorCode ierr; 537 PC_MG *mg = (PC_MG*)pc->data; 538 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 539 540 PetscFunctionBegin; 541 ierr = PetscFree(pc_gamg->subctx);CHKERRQ(ierr); 542 PetscFunctionReturn(0); 543 } 544 545 #undef __FUNCT__ 546 #define __FUNCT__ "PCGAMGSetFromOptions_Classical" 547 PetscErrorCode PCGAMGSetFromOptions_Classical(PC pc) 548 { 549 PetscFunctionBegin; 550 PetscFunctionReturn(0); 551 } 552 553 #undef __FUNCT__ 554 #define __FUNCT__ "PCGAMGSetData_Classical" 555 PetscErrorCode PCGAMGSetData_Classical(PC pc, Mat A) 556 { 557 PC_MG *mg = (PC_MG*)pc->data; 558 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 559 560 PetscFunctionBegin; 561 /* no data for classical AMG */ 562 pc_gamg->data = NULL; 563 pc_gamg->data_cell_cols = 1; 564 pc_gamg->data_cell_rows = 1; 565 pc_gamg->data_sz = 0; 566 PetscFunctionReturn(0); 567 } 568 569 /* -------------------------------------------------------------------------- */ 570 /* 571 PCCreateGAMG_Classical 572 573 */ 574 #undef __FUNCT__ 575 #define __FUNCT__ "PCCreateGAMG_Classical" 576 PetscErrorCode PCCreateGAMG_Classical(PC pc) 577 { 578 PetscErrorCode ierr; 579 PC_MG *mg = (PC_MG*)pc->data; 580 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 581 PC_GAMG_Classical *pc_gamg_classical; 582 583 PetscFunctionBegin; 584 if (pc_gamg->subctx) { 585 /* call base class */ 586 ierr = PCDestroy_GAMG(pc);CHKERRQ(ierr); 587 } 588 589 /* create sub context for SA */ 590 ierr = PetscNewLog(pc,&pc_gamg_classical);CHKERRQ(ierr); 591 pc_gamg->subctx = pc_gamg_classical; 592 pc->ops->setfromoptions = PCGAMGSetFromOptions_Classical; 593 /* reset does not do anything; setup not virtual */ 594 595 /* set internal function pointers */ 596 pc_gamg->ops->destroy = PCGAMGDestroy_Classical; 597 pc_gamg->ops->graph = PCGAMGGraph_Classical; 598 pc_gamg->ops->coarsen = PCGAMGCoarsen_Classical; 599 pc_gamg->ops->prolongator = PCGAMGProlongator_Classical; 600 pc_gamg->ops->optprol = NULL; 601 602 pc_gamg->ops->createdefaultdata = PCGAMGSetData_Classical; 603 PetscFunctionReturn(0); 604 } 605