1 2 /* 3 This provides a simple shell for Fortran (and C programmers) to 4 create a very simple matrix class for use with KSP without coding 5 much of anything. 6 */ 7 8 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 9 #include <petsc/private/vecimpl.h> 10 11 struct _MatShellOps { 12 /* 3 */ PetscErrorCode (*mult)(Mat,Vec,Vec); 13 /* 5 */ PetscErrorCode (*multtranspose)(Mat,Vec,Vec); 14 /* 17 */ PetscErrorCode (*getdiagonal)(Mat,Vec); 15 /* 43 */ PetscErrorCode (*copy)(Mat,Mat,MatStructure); 16 /* 60 */ PetscErrorCode (*destroy)(Mat); 17 }; 18 19 typedef struct { 20 struct _MatShellOps ops[1]; 21 22 PetscScalar vscale,vshift; 23 Vec dshift; 24 Vec left,right; 25 Vec left_work,right_work; 26 Vec left_add_work,right_add_work; 27 Mat axpy; 28 PetscScalar axpy_vscale; 29 PetscBool managescalingshifts; /* The user will manage the scaling and shifts for the MATSHELL, not the default */ 30 /* support for ZeroRows/Columns operations */ 31 IS zrows; 32 IS zcols; 33 Vec zvals; 34 Vec zvals_w; 35 VecScatter zvals_sct_r; 36 VecScatter zvals_sct_c; 37 void *ctx; 38 } Mat_Shell; 39 40 41 /* 42 Store and scale values on zeroed rows 43 xx = [x_1, 0], 0 on zeroed columns 44 */ 45 static PetscErrorCode MatShellPreZeroRight(Mat A,Vec x,Vec *xx) 46 { 47 Mat_Shell *shell = (Mat_Shell*)A->data; 48 PetscErrorCode ierr; 49 50 PetscFunctionBegin; 51 *xx = x; 52 if (shell->zrows) { 53 ierr = VecSet(shell->zvals_w,0.0);CHKERRQ(ierr); 54 ierr = VecScatterBegin(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 55 ierr = VecScatterEnd(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 56 ierr = VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals);CHKERRQ(ierr); 57 } 58 if (shell->zcols) { 59 if (!shell->right_work) { 60 ierr = MatCreateVecs(A,&shell->right_work,NULL);CHKERRQ(ierr); 61 } 62 ierr = VecCopy(x,shell->right_work);CHKERRQ(ierr); 63 ierr = VecISSet(shell->right_work,shell->zcols,0.0);CHKERRQ(ierr); 64 *xx = shell->right_work; 65 } 66 PetscFunctionReturn(0); 67 } 68 69 /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */ 70 static PetscErrorCode MatShellPostZeroLeft(Mat A,Vec x) 71 { 72 Mat_Shell *shell = (Mat_Shell*)A->data; 73 PetscErrorCode ierr; 74 75 PetscFunctionBegin; 76 if (shell->zrows) { 77 ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 78 ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 79 } 80 PetscFunctionReturn(0); 81 } 82 83 /* 84 Store and scale values on zeroed rows 85 xx = [x_1, 0], 0 on zeroed rows 86 */ 87 static PetscErrorCode MatShellPreZeroLeft(Mat A,Vec x,Vec *xx) 88 { 89 Mat_Shell *shell = (Mat_Shell*)A->data; 90 PetscErrorCode ierr; 91 92 PetscFunctionBegin; 93 *xx = NULL; 94 if (!shell->zrows) { 95 *xx = x; 96 } else { 97 if (!shell->left_work) { 98 ierr = MatCreateVecs(A,NULL,&shell->left_work);CHKERRQ(ierr); 99 } 100 ierr = VecCopy(x,shell->left_work);CHKERRQ(ierr); 101 ierr = VecSet(shell->zvals_w,0.0);CHKERRQ(ierr); 102 ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 103 ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 104 ierr = VecScatterBegin(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 105 ierr = VecScatterEnd(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 106 ierr = VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals);CHKERRQ(ierr); 107 *xx = shell->left_work; 108 } 109 PetscFunctionReturn(0); 110 } 111 112 /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */ 113 static PetscErrorCode MatShellPostZeroRight(Mat A,Vec x) 114 { 115 Mat_Shell *shell = (Mat_Shell*)A->data; 116 PetscErrorCode ierr; 117 118 PetscFunctionBegin; 119 if (shell->zcols) { 120 ierr = VecISSet(x,shell->zcols,0.0);CHKERRQ(ierr); 121 } 122 if (shell->zrows) { 123 ierr = VecScatterBegin(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 124 ierr = VecScatterEnd(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 125 } 126 PetscFunctionReturn(0); 127 } 128 129 /* 130 xx = diag(left)*x 131 */ 132 static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx) 133 { 134 Mat_Shell *shell = (Mat_Shell*)A->data; 135 PetscErrorCode ierr; 136 137 PetscFunctionBegin; 138 *xx = NULL; 139 if (!shell->left) { 140 *xx = x; 141 } else { 142 if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);} 143 ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr); 144 *xx = shell->left_work; 145 } 146 PetscFunctionReturn(0); 147 } 148 149 /* 150 xx = diag(right)*x 151 */ 152 static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx) 153 { 154 Mat_Shell *shell = (Mat_Shell*)A->data; 155 PetscErrorCode ierr; 156 157 PetscFunctionBegin; 158 *xx = NULL; 159 if (!shell->right) { 160 *xx = x; 161 } else { 162 if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);} 163 ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr); 164 *xx = shell->right_work; 165 } 166 PetscFunctionReturn(0); 167 } 168 169 /* 170 x = diag(left)*x 171 */ 172 static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x) 173 { 174 Mat_Shell *shell = (Mat_Shell*)A->data; 175 PetscErrorCode ierr; 176 177 PetscFunctionBegin; 178 if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);} 179 PetscFunctionReturn(0); 180 } 181 182 /* 183 x = diag(right)*x 184 */ 185 static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x) 186 { 187 Mat_Shell *shell = (Mat_Shell*)A->data; 188 PetscErrorCode ierr; 189 190 PetscFunctionBegin; 191 if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);} 192 PetscFunctionReturn(0); 193 } 194 195 /* 196 Y = vscale*Y + diag(dshift)*X + vshift*X 197 198 On input Y already contains A*x 199 */ 200 static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y) 201 { 202 Mat_Shell *shell = (Mat_Shell*)A->data; 203 PetscErrorCode ierr; 204 205 PetscFunctionBegin; 206 if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */ 207 PetscInt i,m; 208 const PetscScalar *x,*d; 209 PetscScalar *y; 210 ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr); 211 ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr); 212 ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr); 213 ierr = VecGetArray(Y,&y);CHKERRQ(ierr); 214 for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i]; 215 ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr); 216 ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr); 217 ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr); 218 } else { 219 ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr); 220 } 221 if (shell->vshift != 0.0) {ierr = VecAXPY(Y,shell->vshift,X);CHKERRQ(ierr);} /* if test is for non-square matrices */ 222 PetscFunctionReturn(0); 223 } 224 225 /*@ 226 MatShellGetContext - Returns the user-provided context associated with a shell matrix. 227 228 Not Collective 229 230 Input Parameter: 231 . mat - the matrix, should have been created with MatCreateShell() 232 233 Output Parameter: 234 . ctx - the user provided context 235 236 Level: advanced 237 238 Fortran Notes: 239 To use this from Fortran you must write a Fortran interface definition for this 240 function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 241 242 .keywords: matrix, shell, get, context 243 244 .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext() 245 @*/ 246 PetscErrorCode MatShellGetContext(Mat mat,void *ctx) 247 { 248 PetscErrorCode ierr; 249 PetscBool flg; 250 251 PetscFunctionBegin; 252 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 253 PetscValidPointer(ctx,2); 254 ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 255 if (flg) *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx; 256 else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot get context from non-shell matrix"); 257 PetscFunctionReturn(0); 258 } 259 260 static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat,PetscInt nr,PetscInt rows[],PetscInt nc,PetscInt cols[],PetscScalar diag,PetscBool rc) 261 { 262 PetscErrorCode ierr; 263 Mat_Shell *shell = (Mat_Shell*)mat->data; 264 Vec x = NULL,b = NULL; 265 IS is1, is2; 266 const PetscInt *ridxs; 267 PetscInt *idxs,*gidxs; 268 PetscInt cum,rst,cst,i; 269 270 PetscFunctionBegin; 271 if (shell->axpy) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot diagonal scale MATSHELL after MatAXPY operation"); 272 if (!shell->zvals) { 273 ierr = MatCreateVecs(mat,NULL,&shell->zvals);CHKERRQ(ierr); 274 } 275 if (!shell->zvals_w) { 276 ierr = VecDuplicate(shell->zvals,&shell->zvals_w);CHKERRQ(ierr); 277 } 278 ierr = MatGetOwnershipRange(mat,&rst,NULL);CHKERRQ(ierr); 279 ierr = MatGetOwnershipRangeColumn(mat,&cst,NULL);CHKERRQ(ierr); 280 281 /* Expand/create index set of zeroed rows */ 282 ierr = PetscMalloc1(nr,&idxs);CHKERRQ(ierr); 283 for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst; 284 ierr = ISCreateGeneral(PETSC_COMM_SELF,nr,idxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr); 285 ierr = ISSort(is1);CHKERRQ(ierr); 286 ierr = VecISSet(shell->zvals,is1,diag);CHKERRQ(ierr); 287 if (shell->zrows) { 288 ierr = ISSum(shell->zrows,is1,&is2);CHKERRQ(ierr); 289 ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr); 290 ierr = ISDestroy(&is1);CHKERRQ(ierr); 291 shell->zrows = is2; 292 } else shell->zrows = is1; 293 294 /* Create scatters for diagonal values communications */ 295 ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr); 296 ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr); 297 298 /* row scatter: from/to left vector */ 299 ierr = MatCreateVecs(mat,&x,&b);CHKERRQ(ierr); 300 ierr = VecScatterCreate(b,shell->zrows,shell->zvals_w,shell->zrows,&shell->zvals_sct_r);CHKERRQ(ierr); 301 302 /* col scatter: from right vector to left vector */ 303 ierr = ISGetIndices(shell->zrows,&ridxs);CHKERRQ(ierr); 304 ierr = ISGetLocalSize(shell->zrows,&nr);CHKERRQ(ierr); 305 ierr = PetscMalloc1(nr,&gidxs);CHKERRQ(ierr); 306 for (i = 0, cum = 0; i < nr; i++) { 307 if (ridxs[i] >= mat->cmap->N) continue; 308 gidxs[cum] = ridxs[i]; 309 cum++; 310 } 311 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)mat),cum,gidxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr); 312 ierr = VecScatterCreate(x,is1,shell->zvals_w,is1,&shell->zvals_sct_c);CHKERRQ(ierr); 313 ierr = ISDestroy(&is1);CHKERRQ(ierr); 314 ierr = VecDestroy(&x);CHKERRQ(ierr); 315 ierr = VecDestroy(&b);CHKERRQ(ierr); 316 317 /* Expand/create index set of zeroed columns */ 318 if (rc) { 319 ierr = PetscMalloc1(nc,&idxs);CHKERRQ(ierr); 320 for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst; 321 ierr = ISCreateGeneral(PETSC_COMM_SELF,nc,idxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr); 322 ierr = ISSort(is1);CHKERRQ(ierr); 323 if (shell->zcols) { 324 ierr = ISSum(shell->zcols,is1,&is2);CHKERRQ(ierr); 325 ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr); 326 ierr = ISDestroy(&is1);CHKERRQ(ierr); 327 shell->zcols = is2; 328 } else shell->zcols = is1; 329 } 330 PetscFunctionReturn(0); 331 } 332 333 static PetscErrorCode MatZeroRows_Shell(Mat mat,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b) 334 { 335 PetscInt nr, *lrows; 336 PetscErrorCode ierr; 337 338 PetscFunctionBegin; 339 if (x && b) { 340 Vec xt; 341 PetscScalar *vals; 342 PetscInt *gcols,i,st,nl,nc; 343 344 ierr = PetscMalloc1(n,&gcols);CHKERRQ(ierr); 345 for (i = 0, nc = 0; i < n; i++) if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i]; 346 347 ierr = MatCreateVecs(mat,&xt,NULL);CHKERRQ(ierr); 348 ierr = VecCopy(x,xt);CHKERRQ(ierr); 349 ierr = PetscCalloc1(nc,&vals);CHKERRQ(ierr); 350 ierr = VecSetValues(xt,nc,gcols,vals,INSERT_VALUES);CHKERRQ(ierr); /* xt = [x1, 0] */ 351 ierr = PetscFree(vals);CHKERRQ(ierr); 352 ierr = VecAssemblyBegin(xt);CHKERRQ(ierr); 353 ierr = VecAssemblyEnd(xt);CHKERRQ(ierr); 354 ierr = VecAYPX(xt,-1.0,x);CHKERRQ(ierr); /* xt = [0, x2] */ 355 356 ierr = VecGetOwnershipRange(xt,&st,NULL);CHKERRQ(ierr); 357 ierr = VecGetLocalSize(xt,&nl);CHKERRQ(ierr); 358 ierr = VecGetArray(xt,&vals);CHKERRQ(ierr); 359 for (i = 0; i < nl; i++) { 360 PetscInt g = i + st; 361 if (g > mat->rmap->N) continue; 362 if (PetscAbsScalar(vals[i]) == 0.0) continue; 363 ierr = VecSetValue(b,g,diag*vals[i],INSERT_VALUES);CHKERRQ(ierr); 364 } 365 ierr = VecRestoreArray(xt,&vals);CHKERRQ(ierr); 366 ierr = VecAssemblyBegin(b);CHKERRQ(ierr); 367 ierr = VecAssemblyEnd(b);CHKERRQ(ierr); /* b = [b1, x2 * diag] */ 368 ierr = VecDestroy(&xt);CHKERRQ(ierr); 369 ierr = PetscFree(gcols);CHKERRQ(ierr); 370 } 371 ierr = PetscLayoutMapLocal(mat->rmap,n,rows,&nr,&lrows,NULL);CHKERRQ(ierr); 372 ierr = MatZeroRowsColumns_Local_Shell(mat,nr,lrows,0,NULL,diag,PETSC_FALSE);CHKERRQ(ierr); 373 ierr = PetscFree(lrows);CHKERRQ(ierr); 374 PetscFunctionReturn(0); 375 } 376 377 static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat,PetscInt n,const PetscInt rowscols[],PetscScalar diag,Vec x,Vec b) 378 { 379 PetscInt *lrows, *lcols; 380 PetscInt nr, nc; 381 PetscBool congruent; 382 PetscErrorCode ierr; 383 384 PetscFunctionBegin; 385 if (x && b) { 386 Vec xt, bt; 387 PetscScalar *vals; 388 PetscInt *grows,*gcols,i,st,nl; 389 390 ierr = PetscMalloc2(n,&grows,n,&gcols);CHKERRQ(ierr); 391 for (i = 0, nr = 0; i < n; i++) if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i]; 392 for (i = 0, nc = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i]; 393 ierr = PetscCalloc1(n,&vals);CHKERRQ(ierr); 394 395 ierr = MatCreateVecs(mat,&xt,&bt);CHKERRQ(ierr); 396 ierr = VecCopy(x,xt);CHKERRQ(ierr); 397 ierr = VecSetValues(xt,nc,gcols,vals,INSERT_VALUES);CHKERRQ(ierr); /* xt = [x1, 0] */ 398 ierr = VecAssemblyBegin(xt);CHKERRQ(ierr); 399 ierr = VecAssemblyEnd(xt);CHKERRQ(ierr); 400 ierr = VecAXPY(xt,-1.0,x);CHKERRQ(ierr); /* xt = [0, -x2] */ 401 ierr = MatMult(mat,xt,bt);CHKERRQ(ierr); /* bt = [-A12*x2,-A22*x2] */ 402 ierr = VecSetValues(bt,nr,grows,vals,INSERT_VALUES);CHKERRQ(ierr); /* bt = [-A12*x2,0] */ 403 ierr = VecAssemblyBegin(bt);CHKERRQ(ierr); 404 ierr = VecAssemblyEnd(bt);CHKERRQ(ierr); 405 ierr = VecAXPY(b,1.0,bt);CHKERRQ(ierr); /* b = [b1 - A12*x2, b2] */ 406 ierr = VecSetValues(bt,nr,grows,vals,INSERT_VALUES);CHKERRQ(ierr); /* b = [b1 - A12*x2, 0] */ 407 ierr = VecAssemblyBegin(bt);CHKERRQ(ierr); 408 ierr = VecAssemblyEnd(bt);CHKERRQ(ierr); 409 ierr = PetscFree(vals);CHKERRQ(ierr); 410 411 ierr = VecGetOwnershipRange(xt,&st,NULL);CHKERRQ(ierr); 412 ierr = VecGetLocalSize(xt,&nl);CHKERRQ(ierr); 413 ierr = VecGetArray(xt,&vals);CHKERRQ(ierr); 414 for (i = 0; i < nl; i++) { 415 PetscInt g = i + st; 416 if (g > mat->rmap->N) continue; 417 if (PetscAbsScalar(vals[i]) == 0.0) continue; 418 ierr = VecSetValue(b,g,-diag*vals[i],INSERT_VALUES);CHKERRQ(ierr); 419 } 420 ierr = VecRestoreArray(xt,&vals);CHKERRQ(ierr); 421 ierr = VecAssemblyBegin(b);CHKERRQ(ierr); 422 ierr = VecAssemblyEnd(b);CHKERRQ(ierr); /* b = [b1 - A12*x2, x2 * diag] */ 423 ierr = VecDestroy(&xt);CHKERRQ(ierr); 424 ierr = VecDestroy(&bt);CHKERRQ(ierr); 425 ierr = PetscFree2(grows,gcols);CHKERRQ(ierr); 426 } 427 ierr = PetscLayoutMapLocal(mat->rmap,n,rowscols,&nr,&lrows,NULL);CHKERRQ(ierr); 428 ierr = MatHasCongruentLayouts(mat,&congruent);CHKERRQ(ierr); 429 if (congruent) { 430 nc = nr; 431 lcols = lrows; 432 } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */ 433 PetscInt i,nt,*t; 434 435 ierr = PetscMalloc1(n,&t);CHKERRQ(ierr); 436 for (i = 0, nt = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i]; 437 ierr = PetscLayoutMapLocal(mat->cmap,nt,t,&nc,&lcols,NULL);CHKERRQ(ierr); 438 ierr = PetscFree(t);CHKERRQ(ierr); 439 } 440 ierr = MatZeroRowsColumns_Local_Shell(mat,nr,lrows,nc,lcols,diag,PETSC_TRUE);CHKERRQ(ierr); 441 if (!congruent) { 442 ierr = PetscFree(lcols);CHKERRQ(ierr); 443 } 444 ierr = PetscFree(lrows);CHKERRQ(ierr); 445 PetscFunctionReturn(0); 446 } 447 448 PetscErrorCode MatDestroy_Shell(Mat mat) 449 { 450 PetscErrorCode ierr; 451 Mat_Shell *shell = (Mat_Shell*)mat->data; 452 453 PetscFunctionBegin; 454 if (shell->ops->destroy) { 455 ierr = (*shell->ops->destroy)(mat);CHKERRQ(ierr); 456 } 457 ierr = VecDestroy(&shell->left);CHKERRQ(ierr); 458 ierr = VecDestroy(&shell->right);CHKERRQ(ierr); 459 ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr); 460 ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr); 461 ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr); 462 ierr = VecDestroy(&shell->left_add_work);CHKERRQ(ierr); 463 ierr = VecDestroy(&shell->right_add_work);CHKERRQ(ierr); 464 ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr); 465 ierr = VecDestroy(&shell->zvals_w);CHKERRQ(ierr); 466 ierr = VecDestroy(&shell->zvals);CHKERRQ(ierr); 467 ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr); 468 ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr); 469 ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr); 470 ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr); 471 ierr = PetscFree(mat->data);CHKERRQ(ierr); 472 PetscFunctionReturn(0); 473 } 474 475 PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str) 476 { 477 Mat_Shell *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data; 478 PetscErrorCode ierr; 479 PetscBool matflg; 480 481 PetscFunctionBegin; 482 ierr = PetscObjectTypeCompare((PetscObject)B,MATSHELL,&matflg);CHKERRQ(ierr); 483 if (!matflg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_NOTSAMETYPE,"Output matrix must be a MATSHELL"); 484 485 ierr = PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps));CHKERRQ(ierr); 486 ierr = PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr); 487 488 if (shellA->ops->copy) { 489 ierr = (*shellA->ops->copy)(A,B,str);CHKERRQ(ierr); 490 } 491 shellB->vscale = shellA->vscale; 492 shellB->vshift = shellA->vshift; 493 if (shellA->dshift) { 494 if (!shellB->dshift) { 495 ierr = VecDuplicate(shellA->dshift,&shellB->dshift);CHKERRQ(ierr); 496 } 497 ierr = VecCopy(shellA->dshift,shellB->dshift);CHKERRQ(ierr); 498 } else { 499 ierr = VecDestroy(&shellB->dshift);CHKERRQ(ierr); 500 } 501 if (shellA->left) { 502 if (!shellB->left) { 503 ierr = VecDuplicate(shellA->left,&shellB->left);CHKERRQ(ierr); 504 } 505 ierr = VecCopy(shellA->left,shellB->left);CHKERRQ(ierr); 506 } else { 507 ierr = VecDestroy(&shellB->left);CHKERRQ(ierr); 508 } 509 if (shellA->right) { 510 if (!shellB->right) { 511 ierr = VecDuplicate(shellA->right,&shellB->right);CHKERRQ(ierr); 512 } 513 ierr = VecCopy(shellA->right,shellB->right);CHKERRQ(ierr); 514 } else { 515 ierr = VecDestroy(&shellB->right);CHKERRQ(ierr); 516 } 517 ierr = MatDestroy(&shellB->axpy);CHKERRQ(ierr); 518 if (shellA->axpy) { 519 ierr = PetscObjectReference((PetscObject)shellA->axpy);CHKERRQ(ierr); 520 shellB->axpy = shellA->axpy; 521 shellB->axpy_vscale = shellA->axpy_vscale; 522 } 523 if (shellA->zrows) { 524 ierr = ISDuplicate(shellA->zrows,&shellB->zrows);CHKERRQ(ierr); 525 if (shellA->zcols) { 526 ierr = ISDuplicate(shellA->zcols,&shellB->zcols);CHKERRQ(ierr); 527 } 528 ierr = VecDuplicate(shellA->zvals,&shellB->zvals);CHKERRQ(ierr); 529 ierr = VecCopy(shellA->zvals,shellB->zvals);CHKERRQ(ierr); 530 ierr = VecDuplicate(shellA->zvals_w,&shellB->zvals_w);CHKERRQ(ierr); 531 ierr = PetscObjectReference((PetscObject)shellA->zvals_sct_r);CHKERRQ(ierr); 532 ierr = PetscObjectReference((PetscObject)shellA->zvals_sct_c);CHKERRQ(ierr); 533 shellB->zvals_sct_r = shellA->zvals_sct_r; 534 shellB->zvals_sct_c = shellA->zvals_sct_c; 535 } 536 PetscFunctionReturn(0); 537 } 538 539 PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M) 540 { 541 PetscErrorCode ierr; 542 void *ctx; 543 544 PetscFunctionBegin; 545 ierr = MatShellGetContext(mat,&ctx);CHKERRQ(ierr); 546 ierr = MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M);CHKERRQ(ierr); 547 if (op != MAT_DO_NOT_COPY_VALUES) { 548 ierr = MatCopy(mat,*M,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 549 } 550 PetscFunctionReturn(0); 551 } 552 553 PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y) 554 { 555 Mat_Shell *shell = (Mat_Shell*)A->data; 556 PetscErrorCode ierr; 557 Vec xx; 558 PetscObjectState instate,outstate; 559 560 PetscFunctionBegin; 561 if (!shell->ops->mult) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMult() for this MATSHELL"); 562 ierr = MatShellPreZeroRight(A,x,&xx);CHKERRQ(ierr); 563 ierr = MatShellPreScaleRight(A,xx,&xx);CHKERRQ(ierr); 564 ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr); 565 ierr = (*shell->ops->mult)(A,xx,y);CHKERRQ(ierr); 566 ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr); 567 if (instate == outstate) { 568 /* increase the state of the output vector since the user did not update its state themself as should have been done */ 569 ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr); 570 } 571 ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr); 572 ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr); 573 ierr = MatShellPostZeroLeft(A,y);CHKERRQ(ierr); 574 575 if (shell->axpy) { 576 if (!shell->left_work) {ierr = MatCreateVecs(A,&shell->left_work,NULL);CHKERRQ(ierr);} 577 ierr = MatMult(shell->axpy,x,shell->left_work);CHKERRQ(ierr); 578 ierr = VecAXPY(y,shell->axpy_vscale,shell->left_work);CHKERRQ(ierr); 579 } 580 PetscFunctionReturn(0); 581 } 582 583 PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z) 584 { 585 Mat_Shell *shell = (Mat_Shell*)A->data; 586 PetscErrorCode ierr; 587 588 PetscFunctionBegin; 589 if (y == z) { 590 if (!shell->right_add_work) {ierr = VecDuplicate(z,&shell->right_add_work);CHKERRQ(ierr);} 591 ierr = MatMult(A,x,shell->right_add_work);CHKERRQ(ierr); 592 ierr = VecAXPY(z,1.0,shell->right_add_work);CHKERRQ(ierr); 593 } else { 594 ierr = MatMult(A,x,z);CHKERRQ(ierr); 595 ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr); 596 } 597 PetscFunctionReturn(0); 598 } 599 600 PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y) 601 { 602 Mat_Shell *shell = (Mat_Shell*)A->data; 603 PetscErrorCode ierr; 604 Vec xx; 605 PetscObjectState instate,outstate; 606 607 PetscFunctionBegin; 608 ierr = MatShellPreZeroLeft(A,x,&xx);CHKERRQ(ierr); 609 ierr = MatShellPreScaleLeft(A,xx,&xx);CHKERRQ(ierr); 610 ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr); 611 if (!shell->ops->multtranspose) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMultTranspose() for this MATSHELL"); 612 ierr = (*shell->ops->multtranspose)(A,xx,y);CHKERRQ(ierr); 613 ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr); 614 if (instate == outstate) { 615 /* increase the state of the output vector since the user did not update its state themself as should have been done */ 616 ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr); 617 } 618 ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr); 619 ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr); 620 ierr = MatShellPostZeroRight(A,y);CHKERRQ(ierr); 621 622 if (shell->axpy) { 623 if (!shell->right_work) {ierr = MatCreateVecs(A,NULL,&shell->right_work);CHKERRQ(ierr);} 624 ierr = MatMultTranspose(shell->axpy,x,shell->right_work);CHKERRQ(ierr); 625 ierr = VecAXPY(y,shell->axpy_vscale,shell->right_work);CHKERRQ(ierr); 626 } 627 PetscFunctionReturn(0); 628 } 629 630 PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z) 631 { 632 Mat_Shell *shell = (Mat_Shell*)A->data; 633 PetscErrorCode ierr; 634 635 PetscFunctionBegin; 636 if (y == z) { 637 if (!shell->left_add_work) {ierr = VecDuplicate(z,&shell->left_add_work);CHKERRQ(ierr);} 638 ierr = MatMultTranspose(A,x,shell->left_add_work);CHKERRQ(ierr); 639 ierr = VecAXPY(z,1.0,shell->left_add_work);CHKERRQ(ierr); 640 } else { 641 ierr = MatMultTranspose(A,x,z);CHKERRQ(ierr); 642 ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr); 643 } 644 PetscFunctionReturn(0); 645 } 646 647 /* 648 diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 649 */ 650 PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v) 651 { 652 Mat_Shell *shell = (Mat_Shell*)A->data; 653 PetscErrorCode ierr; 654 655 PetscFunctionBegin; 656 if (shell->ops->getdiagonal) { 657 ierr = (*shell->ops->getdiagonal)(A,v);CHKERRQ(ierr); 658 } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Must provide shell matrix with routine to return diagonal using\nMatShellSetOperation(S,MATOP_GET_DIAGONAL,...)"); 659 ierr = VecScale(v,shell->vscale);CHKERRQ(ierr); 660 if (shell->dshift) { 661 ierr = VecAXPY(v,1.0,shell->dshift);CHKERRQ(ierr); 662 } 663 ierr = VecShift(v,shell->vshift);CHKERRQ(ierr); 664 if (shell->left) {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);} 665 if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);} 666 if (shell->zrows) { 667 ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 668 ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 669 } 670 if (shell->axpy) { 671 if (!shell->left_work) {ierr = VecDuplicate(v,&shell->left_work);CHKERRQ(ierr);} 672 ierr = MatGetDiagonal(shell->axpy,shell->left_work);CHKERRQ(ierr); 673 ierr = VecAXPY(v,shell->axpy_vscale,shell->left_work);CHKERRQ(ierr); 674 } 675 PetscFunctionReturn(0); 676 } 677 678 PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a) 679 { 680 Mat_Shell *shell = (Mat_Shell*)Y->data; 681 PetscErrorCode ierr; 682 683 PetscFunctionBegin; 684 if (shell->left || shell->right) { 685 if (!shell->dshift) { 686 ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift);CHKERRQ(ierr); 687 ierr = VecSet(shell->dshift,a);CHKERRQ(ierr); 688 } else { 689 if (shell->left) {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);} 690 if (shell->right) {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);} 691 ierr = VecShift(shell->dshift,a);CHKERRQ(ierr); 692 } 693 if (shell->left) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);} 694 if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);} 695 } else shell->vshift += a; 696 if (shell->zrows) { 697 ierr = VecShift(shell->zvals,a);CHKERRQ(ierr); 698 } 699 PetscFunctionReturn(0); 700 } 701 702 PetscErrorCode MatDiagonalSet_Shell_Private(Mat A,Vec D,PetscScalar s) 703 { 704 Mat_Shell *shell = (Mat_Shell*)A->data; 705 PetscErrorCode ierr; 706 707 PetscFunctionBegin; 708 if (!shell->dshift) {ierr = VecDuplicate(D,&shell->dshift);CHKERRQ(ierr);} 709 if (shell->left || shell->right) { 710 if (!shell->right_work) {ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work);CHKERRQ(ierr);} 711 if (shell->left && shell->right) { 712 ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr); 713 ierr = VecPointwiseDivide(shell->right_work,shell->right_work,shell->right);CHKERRQ(ierr); 714 } else if (shell->left) { 715 ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr); 716 } else { 717 ierr = VecPointwiseDivide(shell->right_work,D,shell->right);CHKERRQ(ierr); 718 } 719 ierr = VecAXPY(shell->dshift,s,shell->right_work);CHKERRQ(ierr); 720 } else { 721 ierr = VecAXPY(shell->dshift,s,D);CHKERRQ(ierr); 722 } 723 PetscFunctionReturn(0); 724 } 725 726 PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins) 727 { 728 Mat_Shell *shell = (Mat_Shell*)A->data; 729 Vec d; 730 PetscErrorCode ierr; 731 732 PetscFunctionBegin; 733 if (ins == INSERT_VALUES) { 734 if (!A->ops->getdiagonal) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Operation MATOP_GETDIAGONAL must be set first"); 735 ierr = VecDuplicate(D,&d);CHKERRQ(ierr); 736 ierr = MatGetDiagonal(A,d);CHKERRQ(ierr); 737 ierr = MatDiagonalSet_Shell_Private(A,d,-1.);CHKERRQ(ierr); 738 ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr); 739 ierr = VecDestroy(&d);CHKERRQ(ierr); 740 if (shell->zrows) { 741 ierr = VecCopy(D,shell->zvals);CHKERRQ(ierr); 742 } 743 } else { 744 ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr); 745 if (shell->zrows) { 746 ierr = VecAXPY(shell->zvals,1.0,D);CHKERRQ(ierr); 747 } 748 } 749 PetscFunctionReturn(0); 750 } 751 752 PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a) 753 { 754 Mat_Shell *shell = (Mat_Shell*)Y->data; 755 PetscErrorCode ierr; 756 757 PetscFunctionBegin; 758 shell->vscale *= a; 759 shell->vshift *= a; 760 if (shell->dshift) { 761 ierr = VecScale(shell->dshift,a);CHKERRQ(ierr); 762 } 763 shell->axpy_vscale *= a; 764 if (shell->zrows) { 765 ierr = VecScale(shell->zvals,a);CHKERRQ(ierr); 766 } 767 PetscFunctionReturn(0); 768 } 769 770 static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right) 771 { 772 Mat_Shell *shell = (Mat_Shell*)Y->data; 773 PetscErrorCode ierr; 774 775 PetscFunctionBegin; 776 if (shell->axpy) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot diagonal scale MATSHELL after MatAXPY operation"); 777 if (left) { 778 if (!shell->left) { 779 ierr = VecDuplicate(left,&shell->left);CHKERRQ(ierr); 780 ierr = VecCopy(left,shell->left);CHKERRQ(ierr); 781 } else { 782 ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr); 783 } 784 if (shell->zrows) { 785 ierr = VecPointwiseMult(shell->zvals,shell->zvals,left);CHKERRQ(ierr); 786 } 787 } 788 if (right) { 789 if (!shell->right) { 790 ierr = VecDuplicate(right,&shell->right);CHKERRQ(ierr); 791 ierr = VecCopy(right,shell->right);CHKERRQ(ierr); 792 } else { 793 ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr); 794 } 795 if (shell->zrows) { 796 if (!shell->left_work) { 797 ierr = MatCreateVecs(Y,NULL,&shell->left_work);CHKERRQ(ierr); 798 } 799 ierr = VecSet(shell->zvals_w,1.0);CHKERRQ(ierr); 800 ierr = VecScatterBegin(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 801 ierr = VecScatterEnd(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 802 ierr = VecPointwiseMult(shell->zvals,shell->zvals,shell->zvals_w);CHKERRQ(ierr); 803 } 804 } 805 PetscFunctionReturn(0); 806 } 807 808 PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t) 809 { 810 Mat_Shell *shell = (Mat_Shell*)Y->data; 811 PetscErrorCode ierr; 812 813 PetscFunctionBegin; 814 if (t == MAT_FINAL_ASSEMBLY) { 815 shell->vshift = 0.0; 816 shell->vscale = 1.0; 817 ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr); 818 ierr = VecDestroy(&shell->left);CHKERRQ(ierr); 819 ierr = VecDestroy(&shell->right);CHKERRQ(ierr); 820 ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr); 821 ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr); 822 ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr); 823 ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr); 824 ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr); 825 } 826 PetscFunctionReturn(0); 827 } 828 829 static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool *missing,PetscInt *d) 830 { 831 PetscFunctionBegin; 832 *missing = PETSC_FALSE; 833 PetscFunctionReturn(0); 834 } 835 836 PetscErrorCode MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str) 837 { 838 Mat_Shell *shell = (Mat_Shell*)Y->data; 839 PetscErrorCode ierr; 840 841 PetscFunctionBegin; 842 ierr = PetscObjectReference((PetscObject)X);CHKERRQ(ierr); 843 ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr); 844 shell->axpy = X; 845 shell->axpy_vscale = a; 846 PetscFunctionReturn(0); 847 } 848 849 static struct _MatOps MatOps_Values = {0, 850 0, 851 0, 852 0, 853 /* 4*/ MatMultAdd_Shell, 854 0, 855 MatMultTransposeAdd_Shell, 856 0, 857 0, 858 0, 859 /*10*/ 0, 860 0, 861 0, 862 0, 863 0, 864 /*15*/ 0, 865 0, 866 0, 867 MatDiagonalScale_Shell, 868 0, 869 /*20*/ 0, 870 MatAssemblyEnd_Shell, 871 0, 872 0, 873 /*24*/ MatZeroRows_Shell, 874 0, 875 0, 876 0, 877 0, 878 /*29*/ 0, 879 0, 880 0, 881 0, 882 0, 883 /*34*/ MatDuplicate_Shell, 884 0, 885 0, 886 0, 887 0, 888 /*39*/ MatAXPY_Shell, 889 0, 890 0, 891 0, 892 MatCopy_Shell, 893 /*44*/ 0, 894 MatScale_Shell, 895 MatShift_Shell, 896 MatDiagonalSet_Shell, 897 MatZeroRowsColumns_Shell, 898 /*49*/ 0, 899 0, 900 0, 901 0, 902 0, 903 /*54*/ 0, 904 0, 905 0, 906 0, 907 0, 908 /*59*/ 0, 909 MatDestroy_Shell, 910 0, 911 MatConvertFrom_Shell, 912 0, 913 /*64*/ 0, 914 0, 915 0, 916 0, 917 0, 918 /*69*/ 0, 919 0, 920 MatConvert_Shell, 921 0, 922 0, 923 /*74*/ 0, 924 0, 925 0, 926 0, 927 0, 928 /*79*/ 0, 929 0, 930 0, 931 0, 932 0, 933 /*84*/ 0, 934 0, 935 0, 936 0, 937 0, 938 /*89*/ 0, 939 0, 940 0, 941 0, 942 0, 943 /*94*/ 0, 944 0, 945 0, 946 0, 947 0, 948 /*99*/ 0, 949 0, 950 0, 951 0, 952 0, 953 /*104*/ 0, 954 0, 955 0, 956 0, 957 0, 958 /*109*/ 0, 959 0, 960 0, 961 0, 962 MatMissingDiagonal_Shell, 963 /*114*/ 0, 964 0, 965 0, 966 0, 967 0, 968 /*119*/ 0, 969 0, 970 0, 971 0, 972 0, 973 /*124*/ 0, 974 0, 975 0, 976 0, 977 0, 978 /*129*/ 0, 979 0, 980 0, 981 0, 982 0, 983 /*134*/ 0, 984 0, 985 0, 986 0, 987 0, 988 /*139*/ 0, 989 0, 990 0 991 }; 992 993 /*MC 994 MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free. 995 996 Level: advanced 997 998 .seealso: MatCreateShell() 999 M*/ 1000 1001 PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A) 1002 { 1003 Mat_Shell *b; 1004 PetscErrorCode ierr; 1005 1006 PetscFunctionBegin; 1007 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 1008 1009 ierr = PetscNewLog(A,&b);CHKERRQ(ierr); 1010 A->data = (void*)b; 1011 1012 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 1013 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 1014 1015 b->ctx = 0; 1016 b->vshift = 0.0; 1017 b->vscale = 1.0; 1018 b->managescalingshifts = PETSC_TRUE; 1019 A->assembled = PETSC_TRUE; 1020 A->preallocated = PETSC_FALSE; 1021 1022 ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr); 1023 PetscFunctionReturn(0); 1024 } 1025 1026 /*@C 1027 MatCreateShell - Creates a new matrix class for use with a user-defined 1028 private data storage format. 1029 1030 Collective on MPI_Comm 1031 1032 Input Parameters: 1033 + comm - MPI communicator 1034 . m - number of local rows (must be given) 1035 . n - number of local columns (must be given) 1036 . M - number of global rows (may be PETSC_DETERMINE) 1037 . N - number of global columns (may be PETSC_DETERMINE) 1038 - ctx - pointer to data needed by the shell matrix routines 1039 1040 Output Parameter: 1041 . A - the matrix 1042 1043 Level: advanced 1044 1045 Usage: 1046 $ extern int mult(Mat,Vec,Vec); 1047 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 1048 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 1049 $ [ Use matrix for operations that have been set ] 1050 $ MatDestroy(mat); 1051 1052 Notes: 1053 The shell matrix type is intended to provide a simple class to use 1054 with KSP (such as, for use with matrix-free methods). You should not 1055 use the shell type if you plan to define a complete matrix class. 1056 1057 Fortran Notes: 1058 To use this from Fortran with a ctx you must write an interface definition for this 1059 function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing 1060 in as the ctx argument. 1061 1062 PETSc requires that matrices and vectors being used for certain 1063 operations are partitioned accordingly. For example, when 1064 creating a shell matrix, A, that supports parallel matrix-vector 1065 products using MatMult(A,x,y) the user should set the number 1066 of local matrix rows to be the number of local elements of the 1067 corresponding result vector, y. Note that this is information is 1068 required for use of the matrix interface routines, even though 1069 the shell matrix may not actually be physically partitioned. 1070 For example, 1071 1072 $ 1073 $ Vec x, y 1074 $ extern int mult(Mat,Vec,Vec); 1075 $ Mat A 1076 $ 1077 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 1078 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 1079 $ VecGetLocalSize(y,&m); 1080 $ VecGetLocalSize(x,&n); 1081 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 1082 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 1083 $ MatMult(A,x,y); 1084 $ MatDestroy(&A); 1085 $ VecDestroy(&y); 1086 $ VecDestroy(&x); 1087 $ 1088 1089 1090 MATSHELL handles MatShift(), MatDiagonalSet(), MatDiagonalScale(), MatAXPY(), MatScale(), MatZeroRows() and MatZeroRowsColumns() internally, so these 1091 operations cannot be overwritten unless MatShellSetManageScalingShifts() is called. 1092 1093 1094 For rectangular matrices do all the scalings and shifts make sense? 1095 1096 Developers Notes: 1097 Regarding shifting and scaling. The general form is 1098 1099 diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 1100 1101 The order you apply the operations is important. For example if you have a dshift then 1102 apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift 1103 you get s*vscale*A + diag(shift) 1104 1105 A is the user provided function. 1106 1107 KSP/PC uses changes in the Mat's "state" to decide if preconditioners need to be rebuilt: PCSetUp() only calls the setup() for 1108 for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a MATSHELL to trigger 1109 an update in the preconditioner you must call MatAssemblyBegin()/MatAssemblyEnd() or PetscObjectStateIncrease((PetscObject)mat); 1110 each time the MATSHELL matrix has changed. 1111 1112 Calling MatAssemblyBegin()/MatAssemblyEnd() on a MATSHELL removes any previously supplied shift and scales that were provided 1113 with MatDiagonalSet(), MatShift(), MatScale(), or MatDiagonalScale(). 1114 1115 .keywords: matrix, shell, create 1116 1117 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext(), MATSHELL, MatShellSetManageScalingShifts() 1118 @*/ 1119 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) 1120 { 1121 PetscErrorCode ierr; 1122 1123 PetscFunctionBegin; 1124 ierr = MatCreate(comm,A);CHKERRQ(ierr); 1125 ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr); 1126 ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); 1127 ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); 1128 ierr = MatSetUp(*A);CHKERRQ(ierr); 1129 PetscFunctionReturn(0); 1130 } 1131 1132 /*@ 1133 MatShellSetContext - sets the context for a shell matrix 1134 1135 Logically Collective on Mat 1136 1137 Input Parameters: 1138 + mat - the shell matrix 1139 - ctx - the context 1140 1141 Level: advanced 1142 1143 Fortran Notes: 1144 To use this from Fortran you must write a Fortran interface definition for this 1145 function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 1146 1147 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 1148 @*/ 1149 PetscErrorCode MatShellSetContext(Mat mat,void *ctx) 1150 { 1151 Mat_Shell *shell = (Mat_Shell*)mat->data; 1152 PetscErrorCode ierr; 1153 PetscBool flg; 1154 1155 PetscFunctionBegin; 1156 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1157 ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 1158 if (flg) { 1159 shell->ctx = ctx; 1160 } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot attach context to non-shell matrix"); 1161 PetscFunctionReturn(0); 1162 } 1163 1164 /*@ 1165 MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the MATSHELL. Must be called immediately 1166 after MatCreateShell() 1167 1168 Logically Collective on Mat 1169 1170 Input Parameter: 1171 . mat - the shell matrix 1172 1173 Level: advanced 1174 1175 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatShellSetOperation() 1176 @*/ 1177 PetscErrorCode MatShellSetManageScalingShifts(Mat A) 1178 { 1179 PetscErrorCode ierr; 1180 Mat_Shell *shell; 1181 PetscBool flg; 1182 1183 PetscFunctionBegin; 1184 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1185 ierr = PetscObjectTypeCompare((PetscObject)A,MATSHELL,&flg);CHKERRQ(ierr); 1186 if (!flg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Can only use with MATSHELL matrices"); 1187 shell = (Mat_Shell*)A->data; 1188 shell->managescalingshifts = PETSC_FALSE; 1189 A->ops->diagonalset = NULL; 1190 A->ops->diagonalscale = NULL; 1191 A->ops->scale = NULL; 1192 A->ops->shift = NULL; 1193 A->ops->axpy = NULL; 1194 PetscFunctionReturn(0); 1195 } 1196 1197 /*@C 1198 MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function. 1199 1200 Logically Collective on Mat 1201 1202 Input Parameters: 1203 + mat - the shell matrix 1204 . f - the function 1205 . base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated 1206 - ctx - an optional context for the function 1207 1208 Output Parameter: 1209 . flg - PETSC_TRUE if the multiply is likely correct 1210 1211 Options Database: 1212 . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1213 1214 Level: advanced 1215 1216 Fortran Notes: 1217 Not supported from Fortran 1218 1219 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMultTranspose() 1220 @*/ 1221 PetscErrorCode MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg) 1222 { 1223 PetscErrorCode ierr; 1224 PetscInt m,n; 1225 Mat mf,Dmf,Dmat,Ddiff; 1226 PetscReal Diffnorm,Dmfnorm; 1227 PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1228 1229 PetscFunctionBegin; 1230 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1231 ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v);CHKERRQ(ierr); 1232 ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr); 1233 ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf);CHKERRQ(ierr); 1234 ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr); 1235 ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr); 1236 1237 ierr = MatComputeExplicitOperator(mf,&Dmf);CHKERRQ(ierr); 1238 ierr = MatComputeExplicitOperator(mat,&Dmat);CHKERRQ(ierr); 1239 1240 ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr); 1241 ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 1242 ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr); 1243 ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr); 1244 if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) { 1245 flag = PETSC_FALSE; 1246 if (v) { 1247 ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n",(double)(Diffnorm/Dmfnorm));CHKERRQ(ierr); 1248 ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr); 1249 ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr); 1250 ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr); 1251 } 1252 } else if (v) { 1253 ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr); 1254 } 1255 if (flg) *flg = flag; 1256 ierr = MatDestroy(&Ddiff);CHKERRQ(ierr); 1257 ierr = MatDestroy(&mf);CHKERRQ(ierr); 1258 ierr = MatDestroy(&Dmf);CHKERRQ(ierr); 1259 ierr = MatDestroy(&Dmat);CHKERRQ(ierr); 1260 PetscFunctionReturn(0); 1261 } 1262 1263 /*@C 1264 MatShellTestMultTranpose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function. 1265 1266 Logically Collective on Mat 1267 1268 Input Parameters: 1269 + mat - the shell matrix 1270 . f - the function 1271 . base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated 1272 - ctx - an optional context for the function 1273 1274 Output Parameter: 1275 . flg - PETSC_TRUE if the multiply is likely correct 1276 1277 Options Database: 1278 . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1279 1280 Level: advanced 1281 1282 Fortran Notes: 1283 Not supported from Fortran 1284 1285 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMult() 1286 @*/ 1287 PetscErrorCode MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg) 1288 { 1289 PetscErrorCode ierr; 1290 Vec x,y,z; 1291 PetscInt m,n,M,N; 1292 Mat mf,Dmf,Dmat,Ddiff; 1293 PetscReal Diffnorm,Dmfnorm; 1294 PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1295 1296 PetscFunctionBegin; 1297 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1298 ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v);CHKERRQ(ierr); 1299 ierr = MatCreateVecs(mat,&x,&y);CHKERRQ(ierr); 1300 ierr = VecDuplicate(y,&z);CHKERRQ(ierr); 1301 ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr); 1302 ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr); 1303 ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf);CHKERRQ(ierr); 1304 ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr); 1305 ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr); 1306 ierr = MatComputeExplicitOperator(mf,&Dmf);CHKERRQ(ierr); 1307 ierr = MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf);CHKERRQ(ierr); 1308 ierr = MatComputeExplicitOperatorTranspose(mat,&Dmat);CHKERRQ(ierr); 1309 1310 ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr); 1311 ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 1312 ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr); 1313 ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr); 1314 if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) { 1315 flag = PETSC_FALSE; 1316 if (v) { 1317 ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n",(double)(Diffnorm/Dmfnorm));CHKERRQ(ierr); 1318 ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr); 1319 ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr); 1320 ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr); 1321 } 1322 } else if (v) { 1323 ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr); 1324 } 1325 if (flg) *flg = flag; 1326 ierr = MatDestroy(&mf);CHKERRQ(ierr); 1327 ierr = MatDestroy(&Dmat);CHKERRQ(ierr); 1328 ierr = MatDestroy(&Ddiff);CHKERRQ(ierr); 1329 ierr = MatDestroy(&Dmf);CHKERRQ(ierr); 1330 ierr = VecDestroy(&x);CHKERRQ(ierr); 1331 ierr = VecDestroy(&y);CHKERRQ(ierr); 1332 ierr = VecDestroy(&z);CHKERRQ(ierr); 1333 PetscFunctionReturn(0); 1334 } 1335 1336 /*@C 1337 MatShellSetOperation - Allows user to set a matrix operation for a shell matrix. 1338 1339 Logically Collective on Mat 1340 1341 Input Parameters: 1342 + mat - the shell matrix 1343 . op - the name of the operation 1344 - f - the function that provides the operation. 1345 1346 Level: advanced 1347 1348 Usage: 1349 $ extern PetscErrorCode usermult(Mat,Vec,Vec); 1350 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 1351 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 1352 1353 Notes: 1354 See the file include/petscmat.h for a complete list of matrix 1355 operations, which all have the form MATOP_<OPERATION>, where 1356 <OPERATION> is the name (in all capital letters) of the 1357 user interface routine (e.g., MatMult() -> MATOP_MULT). 1358 1359 All user-provided functions (except for MATOP_DESTROY) should have the same calling 1360 sequence as the usual matrix interface routines, since they 1361 are intended to be accessed via the usual matrix interface 1362 routines, e.g., 1363 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 1364 1365 In particular each function MUST return an error code of 0 on success and 1366 nonzero on failure. 1367 1368 Within each user-defined routine, the user should call 1369 MatShellGetContext() to obtain the user-defined context that was 1370 set by MatCreateShell(). 1371 1372 Fortran Notes: 1373 For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not 1374 generate a matrix. See src/mat/examples/tests/ex120f.F 1375 1376 Use MatSetOperation() to set an operation for any matrix type 1377 1378 .keywords: matrix, shell, set, operation 1379 1380 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatShellSetManageScalingShifts() 1381 @*/ 1382 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void)) 1383 { 1384 PetscBool flg; 1385 Mat_Shell *shell; 1386 PetscErrorCode ierr; 1387 1388 PetscFunctionBegin; 1389 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1390 ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 1391 if (!flg) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Can only use with MATSHELL matrices"); 1392 shell = (Mat_Shell*)mat->data; 1393 1394 switch (op) { 1395 case MATOP_DESTROY: 1396 shell->ops->destroy = (PetscErrorCode (*)(Mat))f; 1397 break; 1398 case MATOP_VIEW: 1399 if (!mat->ops->viewnative) { 1400 mat->ops->viewnative = mat->ops->view; 1401 } 1402 mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f; 1403 break; 1404 case MATOP_COPY: 1405 shell->ops->copy = (PetscErrorCode (*)(Mat,Mat,MatStructure))f; 1406 break; 1407 case MATOP_DIAGONAL_SET: 1408 case MATOP_DIAGONAL_SCALE: 1409 case MATOP_SHIFT: 1410 case MATOP_SCALE: 1411 case MATOP_AXPY: 1412 case MATOP_ZERO_ROWS: 1413 case MATOP_ZERO_ROWS_COLUMNS: 1414 if (shell->managescalingshifts) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()"); 1415 (((void(**)(void))mat->ops)[op]) = f; 1416 break; 1417 case MATOP_GET_DIAGONAL: 1418 if (shell->managescalingshifts) { 1419 shell->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f; 1420 mat->ops->getdiagonal = MatGetDiagonal_Shell; 1421 } else { 1422 shell->ops->getdiagonal = NULL; 1423 mat->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f; 1424 } 1425 break; 1426 case MATOP_MULT: 1427 if (shell->managescalingshifts) { 1428 shell->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1429 mat->ops->mult = MatMult_Shell; 1430 } else { 1431 shell->ops->mult = NULL; 1432 mat->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1433 } 1434 break; 1435 case MATOP_MULT_TRANSPOSE: 1436 if (shell->managescalingshifts) { 1437 shell->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1438 mat->ops->multtranspose = MatMultTranspose_Shell; 1439 } else { 1440 shell->ops->multtranspose = NULL; 1441 mat->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1442 } 1443 break; 1444 default: 1445 (((void(**)(void))mat->ops)[op]) = f; 1446 break; 1447 } 1448 PetscFunctionReturn(0); 1449 } 1450 1451 /*@C 1452 MatShellGetOperation - Gets a matrix function for a shell matrix. 1453 1454 Not Collective 1455 1456 Input Parameters: 1457 + mat - the shell matrix 1458 - op - the name of the operation 1459 1460 Output Parameter: 1461 . f - the function that provides the operation. 1462 1463 Level: advanced 1464 1465 Notes: 1466 See the file include/petscmat.h for a complete list of matrix 1467 operations, which all have the form MATOP_<OPERATION>, where 1468 <OPERATION> is the name (in all capital letters) of the 1469 user interface routine (e.g., MatMult() -> MATOP_MULT). 1470 1471 All user-provided functions have the same calling 1472 sequence as the usual matrix interface routines, since they 1473 are intended to be accessed via the usual matrix interface 1474 routines, e.g., 1475 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 1476 1477 Within each user-defined routine, the user should call 1478 MatShellGetContext() to obtain the user-defined context that was 1479 set by MatCreateShell(). 1480 1481 .keywords: matrix, shell, set, operation 1482 1483 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext() 1484 @*/ 1485 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void)) 1486 { 1487 PetscBool flg; 1488 Mat_Shell *shell; 1489 PetscErrorCode ierr; 1490 1491 PetscFunctionBegin; 1492 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1493 ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 1494 if (!flg) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Can only use with MATSHELL matrices"); 1495 shell = (Mat_Shell*)mat->data; 1496 1497 switch (op) { 1498 case MATOP_DESTROY: 1499 *f = (void (*)(void))shell->ops->destroy; 1500 break; 1501 case MATOP_VIEW: 1502 *f = (void (*)(void))mat->ops->view; 1503 break; 1504 case MATOP_COPY: 1505 *f = (void (*)(void))shell->ops->copy; 1506 break; 1507 case MATOP_DIAGONAL_SET: 1508 case MATOP_DIAGONAL_SCALE: 1509 case MATOP_SHIFT: 1510 case MATOP_SCALE: 1511 case MATOP_AXPY: 1512 case MATOP_ZERO_ROWS: 1513 case MATOP_ZERO_ROWS_COLUMNS: 1514 *f = (((void (**)(void))mat->ops)[op]); 1515 break; 1516 case MATOP_GET_DIAGONAL: 1517 if (shell->ops->getdiagonal) 1518 *f = (void (*)(void))shell->ops->getdiagonal; 1519 else 1520 *f = (((void (**)(void))mat->ops)[op]); 1521 break; 1522 case MATOP_MULT: 1523 if (shell->ops->mult) 1524 *f = (void (*)(void))shell->ops->mult; 1525 else 1526 *f = (((void (**)(void))mat->ops)[op]); 1527 break; 1528 case MATOP_MULT_TRANSPOSE: 1529 if (shell->ops->multtranspose) 1530 *f = (void (*)(void))shell->ops->multtranspose; 1531 else 1532 *f = (((void (**)(void))mat->ops)[op]); 1533 break; 1534 default: 1535 *f = (((void (**)(void))mat->ops)[op]); 1536 } 1537 PetscFunctionReturn(0); 1538 } 1539