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 struct _n_MatShellMatFunctionList { 20 PetscErrorCode (*symbolic)(Mat,Mat,Mat,void**); 21 PetscErrorCode (*numeric)(Mat,Mat,Mat,void*); 22 PetscErrorCode (*destroy)(void*); 23 MatProductType ptype; 24 char *composedname; /* string to identify routine with double dispatch */ 25 char *resultname; /* result matrix type */ 26 27 struct _n_MatShellMatFunctionList *next; 28 }; 29 typedef struct _n_MatShellMatFunctionList *MatShellMatFunctionList; 30 31 typedef struct { 32 struct _MatShellOps ops[1]; 33 34 /* The user will manage the scaling and shifts for the MATSHELL, not the default */ 35 PetscBool managescalingshifts; 36 37 /* support for MatScale, MatShift and MatMultAdd */ 38 PetscScalar vscale,vshift; 39 Vec dshift; 40 Vec left,right; 41 Vec left_work,right_work; 42 Vec left_add_work,right_add_work; 43 44 /* support for MatAXPY */ 45 Mat axpy; 46 PetscScalar axpy_vscale; 47 Vec axpy_left,axpy_right; 48 PetscObjectState axpy_state; 49 50 /* support for ZeroRows/Columns operations */ 51 IS zrows; 52 IS zcols; 53 Vec zvals; 54 Vec zvals_w; 55 VecScatter zvals_sct_r; 56 VecScatter zvals_sct_c; 57 58 /* MatMat operations */ 59 MatShellMatFunctionList matmat; 60 61 /* user defined context */ 62 void *ctx; 63 } Mat_Shell; 64 65 66 /* 67 Store and scale values on zeroed rows 68 xx = [x_1, 0], 0 on zeroed columns 69 */ 70 static PetscErrorCode MatShellPreZeroRight(Mat A,Vec x,Vec *xx) 71 { 72 Mat_Shell *shell = (Mat_Shell*)A->data; 73 PetscErrorCode ierr; 74 75 PetscFunctionBegin; 76 *xx = x; 77 if (shell->zrows) { 78 ierr = VecSet(shell->zvals_w,0.0);CHKERRQ(ierr); 79 ierr = VecScatterBegin(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 80 ierr = VecScatterEnd(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 81 ierr = VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals);CHKERRQ(ierr); 82 } 83 if (shell->zcols) { 84 if (!shell->right_work) { 85 ierr = MatCreateVecs(A,&shell->right_work,NULL);CHKERRQ(ierr); 86 } 87 ierr = VecCopy(x,shell->right_work);CHKERRQ(ierr); 88 ierr = VecISSet(shell->right_work,shell->zcols,0.0);CHKERRQ(ierr); 89 *xx = shell->right_work; 90 } 91 PetscFunctionReturn(0); 92 } 93 94 /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */ 95 static PetscErrorCode MatShellPostZeroLeft(Mat A,Vec x) 96 { 97 Mat_Shell *shell = (Mat_Shell*)A->data; 98 PetscErrorCode ierr; 99 100 PetscFunctionBegin; 101 if (shell->zrows) { 102 ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 103 ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 104 } 105 PetscFunctionReturn(0); 106 } 107 108 /* 109 Store and scale values on zeroed rows 110 xx = [x_1, 0], 0 on zeroed rows 111 */ 112 static PetscErrorCode MatShellPreZeroLeft(Mat A,Vec x,Vec *xx) 113 { 114 Mat_Shell *shell = (Mat_Shell*)A->data; 115 PetscErrorCode ierr; 116 117 PetscFunctionBegin; 118 *xx = NULL; 119 if (!shell->zrows) { 120 *xx = x; 121 } else { 122 if (!shell->left_work) { 123 ierr = MatCreateVecs(A,NULL,&shell->left_work);CHKERRQ(ierr); 124 } 125 ierr = VecCopy(x,shell->left_work);CHKERRQ(ierr); 126 ierr = VecSet(shell->zvals_w,0.0);CHKERRQ(ierr); 127 ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 128 ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 129 ierr = VecScatterBegin(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 130 ierr = VecScatterEnd(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 131 ierr = VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals);CHKERRQ(ierr); 132 *xx = shell->left_work; 133 } 134 PetscFunctionReturn(0); 135 } 136 137 /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */ 138 static PetscErrorCode MatShellPostZeroRight(Mat A,Vec x) 139 { 140 Mat_Shell *shell = (Mat_Shell*)A->data; 141 PetscErrorCode ierr; 142 143 PetscFunctionBegin; 144 if (shell->zcols) { 145 ierr = VecISSet(x,shell->zcols,0.0);CHKERRQ(ierr); 146 } 147 if (shell->zrows) { 148 ierr = VecScatterBegin(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 149 ierr = VecScatterEnd(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 150 } 151 PetscFunctionReturn(0); 152 } 153 154 /* 155 xx = diag(left)*x 156 */ 157 static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx) 158 { 159 Mat_Shell *shell = (Mat_Shell*)A->data; 160 PetscErrorCode ierr; 161 162 PetscFunctionBegin; 163 *xx = NULL; 164 if (!shell->left) { 165 *xx = x; 166 } else { 167 if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);} 168 ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr); 169 *xx = shell->left_work; 170 } 171 PetscFunctionReturn(0); 172 } 173 174 /* 175 xx = diag(right)*x 176 */ 177 static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx) 178 { 179 Mat_Shell *shell = (Mat_Shell*)A->data; 180 PetscErrorCode ierr; 181 182 PetscFunctionBegin; 183 *xx = NULL; 184 if (!shell->right) { 185 *xx = x; 186 } else { 187 if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);} 188 ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr); 189 *xx = shell->right_work; 190 } 191 PetscFunctionReturn(0); 192 } 193 194 /* 195 x = diag(left)*x 196 */ 197 static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x) 198 { 199 Mat_Shell *shell = (Mat_Shell*)A->data; 200 PetscErrorCode ierr; 201 202 PetscFunctionBegin; 203 if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);} 204 PetscFunctionReturn(0); 205 } 206 207 /* 208 x = diag(right)*x 209 */ 210 static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x) 211 { 212 Mat_Shell *shell = (Mat_Shell*)A->data; 213 PetscErrorCode ierr; 214 215 PetscFunctionBegin; 216 if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);} 217 PetscFunctionReturn(0); 218 } 219 220 /* 221 Y = vscale*Y + diag(dshift)*X + vshift*X 222 223 On input Y already contains A*x 224 */ 225 static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y) 226 { 227 Mat_Shell *shell = (Mat_Shell*)A->data; 228 PetscErrorCode ierr; 229 230 PetscFunctionBegin; 231 if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */ 232 PetscInt i,m; 233 const PetscScalar *x,*d; 234 PetscScalar *y; 235 ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr); 236 ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr); 237 ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr); 238 ierr = VecGetArray(Y,&y);CHKERRQ(ierr); 239 for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i]; 240 ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr); 241 ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr); 242 ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr); 243 } else { 244 ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr); 245 } 246 if (shell->vshift != 0.0) {ierr = VecAXPY(Y,shell->vshift,X);CHKERRQ(ierr);} /* if test is for non-square matrices */ 247 PetscFunctionReturn(0); 248 } 249 250 PetscErrorCode MatShellGetContext_Shell(Mat mat,void *ctx) 251 { 252 PetscFunctionBegin; 253 *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx; 254 PetscFunctionReturn(0); 255 } 256 257 /*@ 258 MatShellGetContext - Returns the user-provided context associated with a shell matrix. 259 260 Not Collective 261 262 Input Parameter: 263 . mat - the matrix, should have been created with MatCreateShell() 264 265 Output Parameter: 266 . ctx - the user provided context 267 268 Level: advanced 269 270 Fortran Notes: 271 To use this from Fortran you must write a Fortran interface definition for this 272 function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 273 274 .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext() 275 @*/ 276 PetscErrorCode MatShellGetContext(Mat mat,void *ctx) 277 { 278 PetscErrorCode ierr; 279 280 PetscFunctionBegin; 281 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 282 PetscValidPointer(ctx,2); 283 ierr = PetscUseMethod(mat,"MatShellGetContext_C",(Mat,void*),(mat,ctx));CHKERRQ(ierr); 284 PetscFunctionReturn(0); 285 } 286 287 static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat,PetscInt nr,PetscInt rows[],PetscInt nc,PetscInt cols[],PetscScalar diag,PetscBool rc) 288 { 289 PetscErrorCode ierr; 290 Mat_Shell *shell = (Mat_Shell*)mat->data; 291 Vec x = NULL,b = NULL; 292 IS is1, is2; 293 const PetscInt *ridxs; 294 PetscInt *idxs,*gidxs; 295 PetscInt cum,rst,cst,i; 296 297 PetscFunctionBegin; 298 if (!shell->zvals) { 299 ierr = MatCreateVecs(mat,NULL,&shell->zvals);CHKERRQ(ierr); 300 } 301 if (!shell->zvals_w) { 302 ierr = VecDuplicate(shell->zvals,&shell->zvals_w);CHKERRQ(ierr); 303 } 304 ierr = MatGetOwnershipRange(mat,&rst,NULL);CHKERRQ(ierr); 305 ierr = MatGetOwnershipRangeColumn(mat,&cst,NULL);CHKERRQ(ierr); 306 307 /* Expand/create index set of zeroed rows */ 308 ierr = PetscMalloc1(nr,&idxs);CHKERRQ(ierr); 309 for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst; 310 ierr = ISCreateGeneral(PETSC_COMM_SELF,nr,idxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr); 311 ierr = ISSort(is1);CHKERRQ(ierr); 312 ierr = VecISSet(shell->zvals,is1,diag);CHKERRQ(ierr); 313 if (shell->zrows) { 314 ierr = ISSum(shell->zrows,is1,&is2);CHKERRQ(ierr); 315 ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr); 316 ierr = ISDestroy(&is1);CHKERRQ(ierr); 317 shell->zrows = is2; 318 } else shell->zrows = is1; 319 320 /* Create scatters for diagonal values communications */ 321 ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr); 322 ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr); 323 324 /* row scatter: from/to left vector */ 325 ierr = MatCreateVecs(mat,&x,&b);CHKERRQ(ierr); 326 ierr = VecScatterCreate(b,shell->zrows,shell->zvals_w,shell->zrows,&shell->zvals_sct_r);CHKERRQ(ierr); 327 328 /* col scatter: from right vector to left vector */ 329 ierr = ISGetIndices(shell->zrows,&ridxs);CHKERRQ(ierr); 330 ierr = ISGetLocalSize(shell->zrows,&nr);CHKERRQ(ierr); 331 ierr = PetscMalloc1(nr,&gidxs);CHKERRQ(ierr); 332 for (i = 0, cum = 0; i < nr; i++) { 333 if (ridxs[i] >= mat->cmap->N) continue; 334 gidxs[cum] = ridxs[i]; 335 cum++; 336 } 337 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)mat),cum,gidxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr); 338 ierr = VecScatterCreate(x,is1,shell->zvals_w,is1,&shell->zvals_sct_c);CHKERRQ(ierr); 339 ierr = ISDestroy(&is1);CHKERRQ(ierr); 340 ierr = VecDestroy(&x);CHKERRQ(ierr); 341 ierr = VecDestroy(&b);CHKERRQ(ierr); 342 343 /* Expand/create index set of zeroed columns */ 344 if (rc) { 345 ierr = PetscMalloc1(nc,&idxs);CHKERRQ(ierr); 346 for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst; 347 ierr = ISCreateGeneral(PETSC_COMM_SELF,nc,idxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr); 348 ierr = ISSort(is1);CHKERRQ(ierr); 349 if (shell->zcols) { 350 ierr = ISSum(shell->zcols,is1,&is2);CHKERRQ(ierr); 351 ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr); 352 ierr = ISDestroy(&is1);CHKERRQ(ierr); 353 shell->zcols = is2; 354 } else shell->zcols = is1; 355 } 356 PetscFunctionReturn(0); 357 } 358 359 static PetscErrorCode MatZeroRows_Shell(Mat mat,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b) 360 { 361 Mat_Shell *shell = (Mat_Shell*)mat->data; 362 PetscInt nr, *lrows; 363 PetscErrorCode ierr; 364 365 PetscFunctionBegin; 366 if (x && b) { 367 Vec xt; 368 PetscScalar *vals; 369 PetscInt *gcols,i,st,nl,nc; 370 371 ierr = PetscMalloc1(n,&gcols);CHKERRQ(ierr); 372 for (i = 0, nc = 0; i < n; i++) if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i]; 373 374 ierr = MatCreateVecs(mat,&xt,NULL);CHKERRQ(ierr); 375 ierr = VecCopy(x,xt);CHKERRQ(ierr); 376 ierr = PetscCalloc1(nc,&vals);CHKERRQ(ierr); 377 ierr = VecSetValues(xt,nc,gcols,vals,INSERT_VALUES);CHKERRQ(ierr); /* xt = [x1, 0] */ 378 ierr = PetscFree(vals);CHKERRQ(ierr); 379 ierr = VecAssemblyBegin(xt);CHKERRQ(ierr); 380 ierr = VecAssemblyEnd(xt);CHKERRQ(ierr); 381 ierr = VecAYPX(xt,-1.0,x);CHKERRQ(ierr); /* xt = [0, x2] */ 382 383 ierr = VecGetOwnershipRange(xt,&st,NULL);CHKERRQ(ierr); 384 ierr = VecGetLocalSize(xt,&nl);CHKERRQ(ierr); 385 ierr = VecGetArray(xt,&vals);CHKERRQ(ierr); 386 for (i = 0; i < nl; i++) { 387 PetscInt g = i + st; 388 if (g > mat->rmap->N) continue; 389 if (PetscAbsScalar(vals[i]) == 0.0) continue; 390 ierr = VecSetValue(b,g,diag*vals[i],INSERT_VALUES);CHKERRQ(ierr); 391 } 392 ierr = VecRestoreArray(xt,&vals);CHKERRQ(ierr); 393 ierr = VecAssemblyBegin(b);CHKERRQ(ierr); 394 ierr = VecAssemblyEnd(b);CHKERRQ(ierr); /* b = [b1, x2 * diag] */ 395 ierr = VecDestroy(&xt);CHKERRQ(ierr); 396 ierr = PetscFree(gcols);CHKERRQ(ierr); 397 } 398 ierr = PetscLayoutMapLocal(mat->rmap,n,rows,&nr,&lrows,NULL);CHKERRQ(ierr); 399 ierr = MatZeroRowsColumns_Local_Shell(mat,nr,lrows,0,NULL,diag,PETSC_FALSE);CHKERRQ(ierr); 400 if (shell->axpy) { 401 ierr = MatZeroRows(shell->axpy,n,rows,0.0,NULL,NULL);CHKERRQ(ierr); 402 } 403 ierr = PetscFree(lrows);CHKERRQ(ierr); 404 PetscFunctionReturn(0); 405 } 406 407 static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat,PetscInt n,const PetscInt rowscols[],PetscScalar diag,Vec x,Vec b) 408 { 409 Mat_Shell *shell = (Mat_Shell*)mat->data; 410 PetscInt *lrows, *lcols; 411 PetscInt nr, nc; 412 PetscBool congruent; 413 PetscErrorCode ierr; 414 415 PetscFunctionBegin; 416 if (x && b) { 417 Vec xt, bt; 418 PetscScalar *vals; 419 PetscInt *grows,*gcols,i,st,nl; 420 421 ierr = PetscMalloc2(n,&grows,n,&gcols);CHKERRQ(ierr); 422 for (i = 0, nr = 0; i < n; i++) if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i]; 423 for (i = 0, nc = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i]; 424 ierr = PetscCalloc1(n,&vals);CHKERRQ(ierr); 425 426 ierr = MatCreateVecs(mat,&xt,&bt);CHKERRQ(ierr); 427 ierr = VecCopy(x,xt);CHKERRQ(ierr); 428 ierr = VecSetValues(xt,nc,gcols,vals,INSERT_VALUES);CHKERRQ(ierr); /* xt = [x1, 0] */ 429 ierr = VecAssemblyBegin(xt);CHKERRQ(ierr); 430 ierr = VecAssemblyEnd(xt);CHKERRQ(ierr); 431 ierr = VecAXPY(xt,-1.0,x);CHKERRQ(ierr); /* xt = [0, -x2] */ 432 ierr = MatMult(mat,xt,bt);CHKERRQ(ierr); /* bt = [-A12*x2,-A22*x2] */ 433 ierr = VecSetValues(bt,nr,grows,vals,INSERT_VALUES);CHKERRQ(ierr); /* bt = [-A12*x2,0] */ 434 ierr = VecAssemblyBegin(bt);CHKERRQ(ierr); 435 ierr = VecAssemblyEnd(bt);CHKERRQ(ierr); 436 ierr = VecAXPY(b,1.0,bt);CHKERRQ(ierr); /* b = [b1 - A12*x2, b2] */ 437 ierr = VecSetValues(bt,nr,grows,vals,INSERT_VALUES);CHKERRQ(ierr); /* b = [b1 - A12*x2, 0] */ 438 ierr = VecAssemblyBegin(bt);CHKERRQ(ierr); 439 ierr = VecAssemblyEnd(bt);CHKERRQ(ierr); 440 ierr = PetscFree(vals);CHKERRQ(ierr); 441 442 ierr = VecGetOwnershipRange(xt,&st,NULL);CHKERRQ(ierr); 443 ierr = VecGetLocalSize(xt,&nl);CHKERRQ(ierr); 444 ierr = VecGetArray(xt,&vals);CHKERRQ(ierr); 445 for (i = 0; i < nl; i++) { 446 PetscInt g = i + st; 447 if (g > mat->rmap->N) continue; 448 if (PetscAbsScalar(vals[i]) == 0.0) continue; 449 ierr = VecSetValue(b,g,-diag*vals[i],INSERT_VALUES);CHKERRQ(ierr); 450 } 451 ierr = VecRestoreArray(xt,&vals);CHKERRQ(ierr); 452 ierr = VecAssemblyBegin(b);CHKERRQ(ierr); 453 ierr = VecAssemblyEnd(b);CHKERRQ(ierr); /* b = [b1 - A12*x2, x2 * diag] */ 454 ierr = VecDestroy(&xt);CHKERRQ(ierr); 455 ierr = VecDestroy(&bt);CHKERRQ(ierr); 456 ierr = PetscFree2(grows,gcols);CHKERRQ(ierr); 457 } 458 ierr = PetscLayoutMapLocal(mat->rmap,n,rowscols,&nr,&lrows,NULL);CHKERRQ(ierr); 459 ierr = MatHasCongruentLayouts(mat,&congruent);CHKERRQ(ierr); 460 if (congruent) { 461 nc = nr; 462 lcols = lrows; 463 } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */ 464 PetscInt i,nt,*t; 465 466 ierr = PetscMalloc1(n,&t);CHKERRQ(ierr); 467 for (i = 0, nt = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i]; 468 ierr = PetscLayoutMapLocal(mat->cmap,nt,t,&nc,&lcols,NULL);CHKERRQ(ierr); 469 ierr = PetscFree(t);CHKERRQ(ierr); 470 } 471 ierr = MatZeroRowsColumns_Local_Shell(mat,nr,lrows,nc,lcols,diag,PETSC_TRUE);CHKERRQ(ierr); 472 if (!congruent) { 473 ierr = PetscFree(lcols);CHKERRQ(ierr); 474 } 475 ierr = PetscFree(lrows);CHKERRQ(ierr); 476 if (shell->axpy) { 477 ierr = MatZeroRowsColumns(shell->axpy,n,rowscols,0.0,NULL,NULL);CHKERRQ(ierr); 478 } 479 PetscFunctionReturn(0); 480 } 481 482 PetscErrorCode MatDestroy_Shell(Mat mat) 483 { 484 PetscErrorCode ierr; 485 Mat_Shell *shell = (Mat_Shell*)mat->data; 486 MatShellMatFunctionList matmat; 487 488 PetscFunctionBegin; 489 if (shell->ops->destroy) { 490 ierr = (*shell->ops->destroy)(mat);CHKERRQ(ierr); 491 } 492 ierr = PetscMemzero(shell->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr); 493 ierr = VecDestroy(&shell->left);CHKERRQ(ierr); 494 ierr = VecDestroy(&shell->right);CHKERRQ(ierr); 495 ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr); 496 ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr); 497 ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr); 498 ierr = VecDestroy(&shell->left_add_work);CHKERRQ(ierr); 499 ierr = VecDestroy(&shell->right_add_work);CHKERRQ(ierr); 500 ierr = VecDestroy(&shell->axpy_left);CHKERRQ(ierr); 501 ierr = VecDestroy(&shell->axpy_right);CHKERRQ(ierr); 502 ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr); 503 ierr = VecDestroy(&shell->zvals_w);CHKERRQ(ierr); 504 ierr = VecDestroy(&shell->zvals);CHKERRQ(ierr); 505 ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr); 506 ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr); 507 ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr); 508 ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr); 509 510 matmat = shell->matmat; 511 while (matmat) { 512 MatShellMatFunctionList next = matmat->next; 513 514 ierr = PetscObjectComposeFunction((PetscObject)mat,matmat->composedname,NULL);CHKERRQ(ierr); 515 ierr = PetscFree(matmat->composedname);CHKERRQ(ierr); 516 ierr = PetscFree(matmat->resultname);CHKERRQ(ierr); 517 ierr = PetscFree(matmat);CHKERRQ(ierr); 518 matmat = next; 519 } 520 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellGetContext_C",NULL);CHKERRQ(ierr); 521 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetContext_C",NULL);CHKERRQ(ierr); 522 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetVecType_C",NULL);CHKERRQ(ierr); 523 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetManageScalingShifts_C",NULL);CHKERRQ(ierr); 524 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetOperation_C",NULL);CHKERRQ(ierr); 525 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellGetOperation_C",NULL);CHKERRQ(ierr); 526 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetMatProductOperation_C",NULL);CHKERRQ(ierr); 527 ierr = PetscFree(mat->data);CHKERRQ(ierr); 528 PetscFunctionReturn(0); 529 } 530 531 typedef struct { 532 PetscErrorCode (*numeric)(Mat,Mat,Mat,void*); 533 PetscErrorCode (*destroy)(void*); 534 void *userdata; 535 Mat B; 536 Mat Bt; 537 Mat axpy; 538 } MatMatDataShell; 539 540 static PetscErrorCode DestroyMatMatDataShell(void *data) 541 { 542 MatMatDataShell *mmdata = (MatMatDataShell *)data; 543 PetscErrorCode ierr; 544 545 PetscFunctionBegin; 546 if (mmdata->destroy) { 547 ierr = (*mmdata->destroy)(mmdata->userdata);CHKERRQ(ierr); 548 } 549 ierr = MatDestroy(&mmdata->B);CHKERRQ(ierr); 550 ierr = MatDestroy(&mmdata->Bt);CHKERRQ(ierr); 551 ierr = MatDestroy(&mmdata->axpy);CHKERRQ(ierr); 552 ierr = PetscFree(mmdata);CHKERRQ(ierr); 553 PetscFunctionReturn(0); 554 } 555 556 static PetscErrorCode MatProductNumeric_Shell_X(Mat D) 557 { 558 PetscErrorCode ierr; 559 Mat_Product *product; 560 Mat A, B; 561 MatMatDataShell *mdata; 562 PetscScalar zero = 0.0; 563 564 PetscFunctionBegin; 565 MatCheckProduct(D,1); 566 product = D->product; 567 if (!product->data) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data empty"); 568 A = product->A; 569 B = product->B; 570 mdata = (MatMatDataShell*)product->data; 571 if (mdata->numeric) { 572 Mat_Shell *shell = (Mat_Shell*)A->data; 573 PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic; 574 PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric; 575 PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE; 576 577 if (shell->managescalingshifts) { 578 if (shell->zcols || shell->zrows) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProduct not supported with zeroed rows/columns"); 579 if (shell->right || shell->left) { 580 useBmdata = PETSC_TRUE; 581 if (!mdata->B) { 582 ierr = MatDuplicate(B,MAT_SHARE_NONZERO_PATTERN,&mdata->B);CHKERRQ(ierr); 583 } else { 584 newB = PETSC_FALSE; 585 } 586 ierr = MatCopy(B,mdata->B,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 587 } 588 switch (product->type) { 589 case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 590 if (shell->right) { 591 ierr = MatDiagonalScale(mdata->B,shell->right,NULL);CHKERRQ(ierr); 592 } 593 break; 594 case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 595 if (shell->left) { 596 ierr = MatDiagonalScale(mdata->B,shell->left,NULL);CHKERRQ(ierr); 597 } 598 break; 599 case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 600 if (shell->right) { 601 ierr = MatDiagonalScale(mdata->B,NULL,shell->right);CHKERRQ(ierr); 602 } 603 break; 604 case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 605 if (shell->right && shell->left) { 606 PetscBool flg; 607 608 ierr = VecEqual(shell->right,shell->left,&flg);CHKERRQ(ierr); 609 if (!flg) SETERRQ3(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices because left scaling != from right scaling",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name); 610 } 611 if (shell->right) { 612 ierr = MatDiagonalScale(mdata->B,NULL,shell->right);CHKERRQ(ierr); 613 } 614 break; 615 case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 616 if (shell->right && shell->left) { 617 PetscBool flg; 618 619 ierr = VecEqual(shell->right,shell->left,&flg);CHKERRQ(ierr); 620 if (!flg) SETERRQ3(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices because left scaling != from right scaling",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name); 621 } 622 if (shell->right) { 623 ierr = MatDiagonalScale(mdata->B,shell->right,NULL);CHKERRQ(ierr); 624 } 625 break; 626 default: SETERRQ3(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name); 627 } 628 } 629 /* allow the user to call MatMat operations on D */ 630 D->product = NULL; 631 D->ops->productsymbolic = NULL; 632 D->ops->productnumeric = NULL; 633 634 ierr = (*mdata->numeric)(A,useBmdata ? mdata->B : B,D,mdata->userdata);CHKERRQ(ierr); 635 636 /* clear any leftover user data and restore D pointers */ 637 ierr = MatProductClear(D);CHKERRQ(ierr); 638 D->ops->productsymbolic = stashsym; 639 D->ops->productnumeric = stashnum; 640 D->product = product; 641 642 if (shell->managescalingshifts) { 643 ierr = MatScale(D,shell->vscale);CHKERRQ(ierr); 644 switch (product->type) { 645 case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 646 case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 647 if (shell->left) { 648 ierr = MatDiagonalScale(D,shell->left,NULL);CHKERRQ(ierr); 649 if (shell->dshift || shell->vshift != zero) { 650 if (!shell->left_work) {ierr = MatCreateVecs(A,NULL,&shell->left_work);CHKERRQ(ierr);} 651 if (shell->dshift) { 652 ierr = VecCopy(shell->dshift,shell->left_work);CHKERRQ(ierr); 653 ierr = VecShift(shell->left_work,shell->vshift);CHKERRQ(ierr); 654 ierr = VecPointwiseMult(shell->left_work,shell->left_work,shell->left);CHKERRQ(ierr); 655 } else { 656 ierr = VecSet(shell->left_work,shell->vshift);CHKERRQ(ierr); 657 } 658 if (product->type == MATPRODUCT_ABt) { 659 MatReuse reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX; 660 MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN; 661 662 ierr = MatTranspose(mdata->B,reuse,&mdata->Bt);CHKERRQ(ierr); 663 ierr = MatDiagonalScale(mdata->Bt,shell->left_work,NULL);CHKERRQ(ierr); 664 ierr = MatAXPY(D,1.0,mdata->Bt,str);CHKERRQ(ierr); 665 } else { 666 MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 667 668 ierr = MatDiagonalScale(mdata->B,shell->left_work,NULL);CHKERRQ(ierr); 669 ierr = MatAXPY(D,1.0,mdata->B,str);CHKERRQ(ierr); 670 } 671 } 672 } 673 break; 674 case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 675 if (shell->right) { 676 ierr = MatDiagonalScale(D,shell->right,NULL);CHKERRQ(ierr); 677 if (shell->dshift || shell->vshift != zero) { 678 MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 679 680 if (!shell->right_work) {ierr = MatCreateVecs(A,&shell->right_work,NULL);CHKERRQ(ierr);} 681 if (shell->dshift) { 682 ierr = VecCopy(shell->dshift,shell->right_work);CHKERRQ(ierr); 683 ierr = VecShift(shell->right_work,shell->vshift);CHKERRQ(ierr); 684 ierr = VecPointwiseMult(shell->right_work,shell->right_work,shell->right);CHKERRQ(ierr); 685 } else { 686 ierr = VecSet(shell->right_work,shell->vshift);CHKERRQ(ierr); 687 } 688 ierr = MatDiagonalScale(mdata->B,shell->right_work,NULL);CHKERRQ(ierr); 689 ierr = MatAXPY(D,1.0,mdata->B,str);CHKERRQ(ierr); 690 } 691 } 692 break; 693 case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 694 case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 695 if (shell->dshift || shell->vshift != zero) SETERRQ3(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices with diagonal shift",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name); 696 break; 697 default: SETERRQ3(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name); 698 } 699 if (shell->axpy && shell->axpy_vscale != zero) { 700 Mat X; 701 PetscObjectState axpy_state; 702 MatStructure str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */ 703 704 ierr = MatShellGetContext(shell->axpy,(void *)&X);CHKERRQ(ierr); 705 ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr); 706 if (shell->axpy_state != axpy_state) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 707 if (!mdata->axpy) { 708 str = DIFFERENT_NONZERO_PATTERN; 709 ierr = MatProductCreate(shell->axpy,B,NULL,&mdata->axpy);CHKERRQ(ierr); 710 ierr = MatProductSetType(mdata->axpy,product->type);CHKERRQ(ierr); 711 ierr = MatProductSetFromOptions(mdata->axpy);CHKERRQ(ierr); 712 ierr = MatProductSymbolic(mdata->axpy);CHKERRQ(ierr); 713 } else { /* May be that shell->axpy has changed */ 714 PetscBool flg; 715 716 ierr = MatProductReplaceMats(shell->axpy,B,NULL,mdata->axpy);CHKERRQ(ierr); 717 ierr = MatHasOperation(mdata->axpy,MATOP_PRODUCTSYMBOLIC,&flg);CHKERRQ(ierr); 718 if (!flg) { 719 str = DIFFERENT_NONZERO_PATTERN; 720 ierr = MatProductSetFromOptions(mdata->axpy);CHKERRQ(ierr); 721 ierr = MatProductSymbolic(mdata->axpy);CHKERRQ(ierr); 722 } 723 } 724 ierr = MatProductNumeric(mdata->axpy);CHKERRQ(ierr); 725 ierr = MatAXPY(D,shell->axpy_vscale,mdata->axpy,str);CHKERRQ(ierr); 726 } 727 } 728 } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Missing numeric operation"); 729 PetscFunctionReturn(0); 730 } 731 732 static PetscErrorCode MatProductSymbolic_Shell_X(Mat D) 733 { 734 PetscErrorCode ierr; 735 Mat_Product *product; 736 Mat A,B; 737 MatShellMatFunctionList matmat; 738 Mat_Shell *shell; 739 PetscBool flg; 740 char composedname[256]; 741 MatMatDataShell *mdata; 742 743 PetscFunctionBegin; 744 MatCheckProduct(D,1); 745 product = D->product; 746 if (product->data) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data not empty"); 747 A = product->A; 748 B = product->B; 749 shell = (Mat_Shell*)A->data; 750 matmat = shell->matmat; 751 ierr = PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr); 752 while (matmat) { 753 ierr = PetscStrcmp(composedname,matmat->composedname,&flg);CHKERRQ(ierr); 754 flg = (PetscBool)(flg && (matmat->ptype == product->type)); 755 if (flg) break; 756 matmat = matmat->next; 757 } 758 if (!flg) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Composedname \"%s\" for product type %s not found",composedname,MatProductTypes[product->type]); 759 switch (product->type) { 760 case MATPRODUCT_AB: 761 ierr = MatSetSizes(D,A->rmap->n,B->cmap->n,A->rmap->N,B->cmap->N);CHKERRQ(ierr); 762 break; 763 case MATPRODUCT_AtB: 764 ierr = MatSetSizes(D,A->cmap->n,B->cmap->n,A->cmap->N,B->cmap->N);CHKERRQ(ierr); 765 break; 766 case MATPRODUCT_ABt: 767 ierr = MatSetSizes(D,A->rmap->n,B->rmap->n,A->rmap->N,B->rmap->N);CHKERRQ(ierr); 768 break; 769 case MATPRODUCT_RARt: 770 ierr = MatSetSizes(D,B->rmap->n,B->rmap->n,B->rmap->N,B->rmap->N);CHKERRQ(ierr); 771 break; 772 case MATPRODUCT_PtAP: 773 ierr = MatSetSizes(D,B->cmap->n,B->cmap->n,B->cmap->N,B->cmap->N);CHKERRQ(ierr); 774 break; 775 default: SETERRQ3(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name); 776 } 777 /* respect users who passed in a matrix for which resultname is the base type */ 778 if (matmat->resultname) { 779 ierr = PetscObjectBaseTypeCompare((PetscObject)D,matmat->resultname,&flg);CHKERRQ(ierr); 780 if (!flg) { 781 ierr = MatSetType(D,matmat->resultname);CHKERRQ(ierr); 782 } 783 } 784 /* If matrix type was not set or different, we need to reset this pointers */ 785 D->ops->productsymbolic = MatProductSymbolic_Shell_X; 786 D->ops->productnumeric = MatProductNumeric_Shell_X; 787 /* attach product data */ 788 ierr = PetscNew(&mdata);CHKERRQ(ierr); 789 mdata->numeric = matmat->numeric; 790 mdata->destroy = matmat->destroy; 791 if (matmat->symbolic) { 792 ierr = (*matmat->symbolic)(A,B,D,&mdata->userdata);CHKERRQ(ierr); 793 } else { /* call general setup if symbolic operation not provided */ 794 ierr = MatSetUp(D);CHKERRQ(ierr); 795 } 796 if (!D->product) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product disappeared after user symbolic phase"); 797 if (D->product->data) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product data not empty after user symbolic phase"); 798 D->product->data = mdata; 799 D->product->destroy = DestroyMatMatDataShell; 800 /* Be sure to reset these pointers if the user did something unexpected */ 801 D->ops->productsymbolic = MatProductSymbolic_Shell_X; 802 D->ops->productnumeric = MatProductNumeric_Shell_X; 803 PetscFunctionReturn(0); 804 } 805 806 static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D) 807 { 808 PetscErrorCode ierr; 809 Mat_Product *product; 810 Mat A,B; 811 MatShellMatFunctionList matmat; 812 Mat_Shell *shell; 813 PetscBool flg; 814 char composedname[256]; 815 816 PetscFunctionBegin; 817 MatCheckProduct(D,1); 818 product = D->product; 819 A = product->A; 820 B = product->B; 821 ierr = MatIsShell(A,&flg);CHKERRQ(ierr); 822 if (!flg) PetscFunctionReturn(0); 823 shell = (Mat_Shell*)A->data; 824 matmat = shell->matmat; 825 ierr = PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr); 826 while (matmat) { 827 ierr = PetscStrcmp(composedname,matmat->composedname,&flg);CHKERRQ(ierr); 828 flg = (PetscBool)(flg && (matmat->ptype == product->type)); 829 if (flg) break; 830 matmat = matmat->next; 831 } 832 if (flg) { D->ops->productsymbolic = MatProductSymbolic_Shell_X; } 833 else { ierr = PetscInfo2(D," symbolic product %s not registered for product type %s\n",composedname,MatProductTypes[product->type]);CHKERRQ(ierr); } 834 PetscFunctionReturn(0); 835 } 836 837 static PetscErrorCode MatShellSetMatProductOperation_Private(Mat A,MatProductType ptype,PetscErrorCode (*symbolic)(Mat,Mat,Mat,void**),PetscErrorCode (*numeric)(Mat,Mat,Mat,void*),PetscErrorCode (*destroy)(void*),char *composedname,const char *resultname) 838 { 839 PetscBool flg; 840 PetscErrorCode ierr; 841 Mat_Shell *shell; 842 MatShellMatFunctionList matmat; 843 844 PetscFunctionBegin; 845 if (!numeric) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing numeric routine"); 846 if (!composedname) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing composed name"); 847 848 /* add product callback */ 849 shell = (Mat_Shell*)A->data; 850 matmat = shell->matmat; 851 if (!matmat) { 852 ierr = PetscNew(&shell->matmat);CHKERRQ(ierr); 853 matmat = shell->matmat; 854 } else { 855 MatShellMatFunctionList entry = matmat; 856 while (entry) { 857 ierr = PetscStrcmp(composedname,entry->composedname,&flg);CHKERRQ(ierr); 858 flg = (PetscBool)(flg && (entry->ptype == ptype)); 859 if (flg) break; 860 matmat = entry; 861 entry = entry->next; 862 } 863 if (!flg) { 864 ierr = PetscNew(&matmat->next);CHKERRQ(ierr); 865 matmat = matmat->next; 866 } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"This should not happen"); 867 } 868 869 matmat->symbolic = symbolic; 870 matmat->numeric = numeric; 871 matmat->destroy = destroy; 872 matmat->ptype = ptype; 873 ierr = PetscFree(matmat->composedname);CHKERRQ(ierr); 874 ierr = PetscFree(matmat->resultname);CHKERRQ(ierr); 875 ierr = PetscStrallocpy(composedname,&matmat->composedname);CHKERRQ(ierr); 876 ierr = PetscStrallocpy(resultname,&matmat->resultname);CHKERRQ(ierr); 877 ierr = PetscInfo3(A,"Composing %s for product type %s with result %s\n",matmat->composedname,MatProductTypes[matmat->ptype],matmat->resultname ? matmat->resultname : "not specified");CHKERRQ(ierr); 878 ierr = PetscObjectComposeFunction((PetscObject)A,matmat->composedname,MatProductSetFromOptions_Shell_X);CHKERRQ(ierr); 879 PetscFunctionReturn(0); 880 } 881 882 /*@C 883 MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a shell matrix. 884 885 Logically Collective on Mat 886 887 Input Parameters: 888 + A - the shell matrix 889 . ptype - the product type 890 . symbolic - the function for the symbolic phase (can be NULL) 891 . numeric - the function for the numerical phase 892 . destroy - the function for the destruction of the needed data generated during the symbolic phase (can be NULL) 893 . Btype - the matrix type for the matrix to be multiplied against 894 - Ctype - the matrix type for the result (can be NULL) 895 896 Level: advanced 897 898 Usage: 899 $ extern PetscErrorCode usersymbolic(Mat,Mat,Mat,void**); 900 $ extern PetscErrorCode usernumeric(Mat,Mat,Mat,void*); 901 $ extern PetscErrorCode userdestroy(void*); 902 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 903 $ MatShellSetMatProductOperation(A,MATPRODUCT_AB,usersymbolic,usernumeric,userdestroy,MATSEQAIJ,MATDENSE); 904 $ [ create B of type SEQAIJ etc..] 905 $ MatProductCreate(A,B,NULL,&C); 906 $ MatProductSetType(C,MATPRODUCT_AB); 907 $ MatProductSetFromOptions(C); 908 $ MatProductSymbolic(C); -> actually runs the user defined symbolic operation 909 $ MatProductNumeric(C); -> actually runs the user defined numeric operation 910 $ [ use C = A*B ] 911 912 Notes: 913 MATPRODUCT_ABC is not supported yet. Not supported in Fortran. 914 If the symbolic phase is not specified, MatSetUp() is called on the result matrix that must have its type set if Ctype is NULL. 915 Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback. 916 PETSc will take care of calling the user-defined callbacks. 917 It is allowed to specify the same callbacks for different Btype matrix types. 918 The couple (Btype,ptype) uniquely identifies the operation: the last specified callbacks takes precedence. 919 920 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatProductType, MatType, MatSetUp() 921 @*/ 922 PetscErrorCode MatShellSetMatProductOperation(Mat A,MatProductType ptype,PetscErrorCode (*symbolic)(Mat,Mat,Mat,void**),PetscErrorCode (*numeric)(Mat,Mat,Mat,void*),PetscErrorCode (*destroy)(void *),MatType Btype,MatType Ctype) 923 { 924 PetscErrorCode ierr; 925 926 PetscFunctionBegin; 927 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 928 PetscValidLogicalCollectiveEnum(A,ptype,2); 929 if (ptype == MATPRODUCT_ABC) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Not for product type %s",MatProductTypes[ptype]); 930 if (!numeric) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Missing numeric routine, argument 4"); 931 PetscValidPointer(Btype,6); 932 if (Ctype) PetscValidPointer(Ctype,7); 933 ierr = PetscTryMethod(A,"MatShellSetMatProductOperation_C",(Mat,MatProductType,PetscErrorCode(*)(Mat,Mat,Mat,void**),PetscErrorCode(*)(Mat,Mat,Mat,void*),PetscErrorCode(*)(void*),MatType,MatType),(A,ptype,symbolic,numeric,destroy,Btype,Ctype));CHKERRQ(ierr); 934 PetscFunctionReturn(0); 935 } 936 937 PetscErrorCode MatShellSetMatProductOperation_Shell(Mat A,MatProductType ptype,PetscErrorCode (*symbolic)(Mat,Mat,Mat,void**),PetscErrorCode (*numeric)(Mat,Mat,Mat,void*),PetscErrorCode (*destroy)(void *),MatType Btype,MatType Ctype) 938 { 939 PetscBool flg; 940 PetscErrorCode ierr; 941 char composedname[256]; 942 MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList; 943 PetscMPIInt size; 944 945 PetscFunctionBegin; 946 PetscValidType(A,1); 947 while (Bnames) { /* user passed in the root name */ 948 ierr = PetscStrcmp(Btype,Bnames->rname,&flg);CHKERRQ(ierr); 949 if (flg) break; 950 Bnames = Bnames->next; 951 } 952 while (Cnames) { /* user passed in the root name */ 953 ierr = PetscStrcmp(Ctype,Cnames->rname,&flg);CHKERRQ(ierr); 954 if (flg) break; 955 Cnames = Cnames->next; 956 } 957 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr); 958 Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype; 959 Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype; 960 ierr = PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,Btype);CHKERRQ(ierr); 961 ierr = MatShellSetMatProductOperation_Private(A,ptype,symbolic,numeric,destroy,composedname,Ctype);CHKERRQ(ierr); 962 PetscFunctionReturn(0); 963 } 964 965 PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str) 966 { 967 Mat_Shell *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data; 968 PetscErrorCode ierr; 969 PetscBool matflg; 970 MatShellMatFunctionList matmatA; 971 972 PetscFunctionBegin; 973 ierr = MatIsShell(B,&matflg);CHKERRQ(ierr); 974 if (!matflg) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Matrix %s not derived from MATSHELL",((PetscObject)B)->type_name); 975 976 ierr = PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps));CHKERRQ(ierr); 977 ierr = PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr); 978 979 if (shellA->ops->copy) { 980 ierr = (*shellA->ops->copy)(A,B,str);CHKERRQ(ierr); 981 } 982 shellB->vscale = shellA->vscale; 983 shellB->vshift = shellA->vshift; 984 if (shellA->dshift) { 985 if (!shellB->dshift) { 986 ierr = VecDuplicate(shellA->dshift,&shellB->dshift);CHKERRQ(ierr); 987 } 988 ierr = VecCopy(shellA->dshift,shellB->dshift);CHKERRQ(ierr); 989 } else { 990 ierr = VecDestroy(&shellB->dshift);CHKERRQ(ierr); 991 } 992 if (shellA->left) { 993 if (!shellB->left) { 994 ierr = VecDuplicate(shellA->left,&shellB->left);CHKERRQ(ierr); 995 } 996 ierr = VecCopy(shellA->left,shellB->left);CHKERRQ(ierr); 997 } else { 998 ierr = VecDestroy(&shellB->left);CHKERRQ(ierr); 999 } 1000 if (shellA->right) { 1001 if (!shellB->right) { 1002 ierr = VecDuplicate(shellA->right,&shellB->right);CHKERRQ(ierr); 1003 } 1004 ierr = VecCopy(shellA->right,shellB->right);CHKERRQ(ierr); 1005 } else { 1006 ierr = VecDestroy(&shellB->right);CHKERRQ(ierr); 1007 } 1008 ierr = MatDestroy(&shellB->axpy);CHKERRQ(ierr); 1009 shellB->axpy_vscale = 0.0; 1010 shellB->axpy_state = 0; 1011 if (shellA->axpy) { 1012 ierr = PetscObjectReference((PetscObject)shellA->axpy);CHKERRQ(ierr); 1013 shellB->axpy = shellA->axpy; 1014 shellB->axpy_vscale = shellA->axpy_vscale; 1015 shellB->axpy_state = shellA->axpy_state; 1016 } 1017 if (shellA->zrows) { 1018 ierr = ISDuplicate(shellA->zrows,&shellB->zrows);CHKERRQ(ierr); 1019 if (shellA->zcols) { 1020 ierr = ISDuplicate(shellA->zcols,&shellB->zcols);CHKERRQ(ierr); 1021 } 1022 ierr = VecDuplicate(shellA->zvals,&shellB->zvals);CHKERRQ(ierr); 1023 ierr = VecCopy(shellA->zvals,shellB->zvals);CHKERRQ(ierr); 1024 ierr = VecDuplicate(shellA->zvals_w,&shellB->zvals_w);CHKERRQ(ierr); 1025 ierr = PetscObjectReference((PetscObject)shellA->zvals_sct_r);CHKERRQ(ierr); 1026 ierr = PetscObjectReference((PetscObject)shellA->zvals_sct_c);CHKERRQ(ierr); 1027 shellB->zvals_sct_r = shellA->zvals_sct_r; 1028 shellB->zvals_sct_c = shellA->zvals_sct_c; 1029 } 1030 1031 matmatA = shellA->matmat; 1032 if (matmatA) { 1033 while (matmatA->next) { 1034 ierr = MatShellSetMatProductOperation_Private(B,matmatA->ptype,matmatA->symbolic,matmatA->numeric,matmatA->destroy,matmatA->composedname,matmatA->resultname);CHKERRQ(ierr); 1035 matmatA = matmatA->next; 1036 } 1037 } 1038 PetscFunctionReturn(0); 1039 } 1040 1041 PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M) 1042 { 1043 PetscErrorCode ierr; 1044 void *ctx; 1045 1046 PetscFunctionBegin; 1047 ierr = MatShellGetContext(mat,&ctx);CHKERRQ(ierr); 1048 ierr = MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M);CHKERRQ(ierr); 1049 ierr = PetscObjectChangeTypeName((PetscObject)(*M),((PetscObject)mat)->type_name);CHKERRQ(ierr); 1050 if (op != MAT_DO_NOT_COPY_VALUES) { 1051 ierr = MatCopy(mat,*M,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 1052 } 1053 PetscFunctionReturn(0); 1054 } 1055 1056 PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y) 1057 { 1058 Mat_Shell *shell = (Mat_Shell*)A->data; 1059 PetscErrorCode ierr; 1060 Vec xx; 1061 PetscObjectState instate,outstate; 1062 1063 PetscFunctionBegin; 1064 if (!shell->ops->mult) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMult() for this MATSHELL"); 1065 ierr = MatShellPreZeroRight(A,x,&xx);CHKERRQ(ierr); 1066 ierr = MatShellPreScaleRight(A,xx,&xx);CHKERRQ(ierr); 1067 ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr); 1068 ierr = (*shell->ops->mult)(A,xx,y);CHKERRQ(ierr); 1069 ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr); 1070 if (instate == outstate) { 1071 /* increase the state of the output vector since the user did not update its state themself as should have been done */ 1072 ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr); 1073 } 1074 ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr); 1075 ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr); 1076 ierr = MatShellPostZeroLeft(A,y);CHKERRQ(ierr); 1077 1078 if (shell->axpy) { 1079 Mat X; 1080 PetscObjectState axpy_state; 1081 1082 ierr = MatShellGetContext(shell->axpy,(void *)&X);CHKERRQ(ierr); 1083 ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr); 1084 if (shell->axpy_state != axpy_state) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 1085 1086 ierr = MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left);CHKERRQ(ierr); 1087 ierr = VecCopy(x,shell->axpy_right);CHKERRQ(ierr); 1088 ierr = MatMult(shell->axpy,shell->axpy_right,shell->axpy_left);CHKERRQ(ierr); 1089 ierr = VecAXPY(y,shell->axpy_vscale,shell->axpy_left);CHKERRQ(ierr); 1090 } 1091 PetscFunctionReturn(0); 1092 } 1093 1094 PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z) 1095 { 1096 Mat_Shell *shell = (Mat_Shell*)A->data; 1097 PetscErrorCode ierr; 1098 1099 PetscFunctionBegin; 1100 if (y == z) { 1101 if (!shell->right_add_work) {ierr = VecDuplicate(z,&shell->right_add_work);CHKERRQ(ierr);} 1102 ierr = MatMult(A,x,shell->right_add_work);CHKERRQ(ierr); 1103 ierr = VecAXPY(z,1.0,shell->right_add_work);CHKERRQ(ierr); 1104 } else { 1105 ierr = MatMult(A,x,z);CHKERRQ(ierr); 1106 ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr); 1107 } 1108 PetscFunctionReturn(0); 1109 } 1110 1111 PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y) 1112 { 1113 Mat_Shell *shell = (Mat_Shell*)A->data; 1114 PetscErrorCode ierr; 1115 Vec xx; 1116 PetscObjectState instate,outstate; 1117 1118 PetscFunctionBegin; 1119 if (!shell->ops->multtranspose) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMultTranspose() for this MATSHELL"); 1120 ierr = MatShellPreZeroLeft(A,x,&xx);CHKERRQ(ierr); 1121 ierr = MatShellPreScaleLeft(A,xx,&xx);CHKERRQ(ierr); 1122 ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr); 1123 ierr = (*shell->ops->multtranspose)(A,xx,y);CHKERRQ(ierr); 1124 ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr); 1125 if (instate == outstate) { 1126 /* increase the state of the output vector since the user did not update its state themself as should have been done */ 1127 ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr); 1128 } 1129 ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr); 1130 ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr); 1131 ierr = MatShellPostZeroRight(A,y);CHKERRQ(ierr); 1132 1133 if (shell->axpy) { 1134 Mat X; 1135 PetscObjectState axpy_state; 1136 1137 ierr = MatShellGetContext(shell->axpy,(void *)&X);CHKERRQ(ierr); 1138 ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr); 1139 if (shell->axpy_state != axpy_state) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 1140 ierr = MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left);CHKERRQ(ierr); 1141 ierr = VecCopy(x,shell->axpy_left);CHKERRQ(ierr); 1142 ierr = MatMultTranspose(shell->axpy,shell->axpy_left,shell->axpy_right);CHKERRQ(ierr); 1143 ierr = VecAXPY(y,shell->axpy_vscale,shell->axpy_right);CHKERRQ(ierr); 1144 } 1145 PetscFunctionReturn(0); 1146 } 1147 1148 PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z) 1149 { 1150 Mat_Shell *shell = (Mat_Shell*)A->data; 1151 PetscErrorCode ierr; 1152 1153 PetscFunctionBegin; 1154 if (y == z) { 1155 if (!shell->left_add_work) {ierr = VecDuplicate(z,&shell->left_add_work);CHKERRQ(ierr);} 1156 ierr = MatMultTranspose(A,x,shell->left_add_work);CHKERRQ(ierr); 1157 ierr = VecAXPY(z,1.0,shell->left_add_work);CHKERRQ(ierr); 1158 } else { 1159 ierr = MatMultTranspose(A,x,z);CHKERRQ(ierr); 1160 ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr); 1161 } 1162 PetscFunctionReturn(0); 1163 } 1164 1165 /* 1166 diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 1167 */ 1168 PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v) 1169 { 1170 Mat_Shell *shell = (Mat_Shell*)A->data; 1171 PetscErrorCode ierr; 1172 1173 PetscFunctionBegin; 1174 if (shell->ops->getdiagonal) { 1175 ierr = (*shell->ops->getdiagonal)(A,v);CHKERRQ(ierr); 1176 } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Must provide shell matrix with routine to return diagonal using\nMatShellSetOperation(S,MATOP_GET_DIAGONAL,...)"); 1177 ierr = VecScale(v,shell->vscale);CHKERRQ(ierr); 1178 if (shell->dshift) { 1179 ierr = VecAXPY(v,1.0,shell->dshift);CHKERRQ(ierr); 1180 } 1181 ierr = VecShift(v,shell->vshift);CHKERRQ(ierr); 1182 if (shell->left) {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);} 1183 if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);} 1184 if (shell->zrows) { 1185 ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1186 ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1187 } 1188 if (shell->axpy) { 1189 Mat X; 1190 PetscObjectState axpy_state; 1191 1192 ierr = MatShellGetContext(shell->axpy,(void *)&X);CHKERRQ(ierr); 1193 ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr); 1194 if (shell->axpy_state != axpy_state) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 1195 ierr = MatCreateVecs(shell->axpy,NULL,shell->axpy_left ? NULL : &shell->axpy_left);CHKERRQ(ierr); 1196 ierr = MatGetDiagonal(shell->axpy,shell->axpy_left);CHKERRQ(ierr); 1197 ierr = VecAXPY(v,shell->axpy_vscale,shell->axpy_left);CHKERRQ(ierr); 1198 } 1199 PetscFunctionReturn(0); 1200 } 1201 1202 PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a) 1203 { 1204 Mat_Shell *shell = (Mat_Shell*)Y->data; 1205 PetscErrorCode ierr; 1206 PetscBool flg; 1207 1208 PetscFunctionBegin; 1209 ierr = MatHasCongruentLayouts(Y,&flg);CHKERRQ(ierr); 1210 if (!flg) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot shift shell matrix if it is not congruent"); 1211 if (shell->left || shell->right) { 1212 if (!shell->dshift) { 1213 ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift);CHKERRQ(ierr); 1214 ierr = VecSet(shell->dshift,a);CHKERRQ(ierr); 1215 } else { 1216 if (shell->left) {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);} 1217 if (shell->right) {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);} 1218 ierr = VecShift(shell->dshift,a);CHKERRQ(ierr); 1219 } 1220 if (shell->left) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);} 1221 if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);} 1222 } else shell->vshift += a; 1223 if (shell->zrows) { 1224 ierr = VecShift(shell->zvals,a);CHKERRQ(ierr); 1225 } 1226 PetscFunctionReturn(0); 1227 } 1228 1229 PetscErrorCode MatDiagonalSet_Shell_Private(Mat A,Vec D,PetscScalar s) 1230 { 1231 Mat_Shell *shell = (Mat_Shell*)A->data; 1232 PetscErrorCode ierr; 1233 1234 PetscFunctionBegin; 1235 if (!shell->dshift) {ierr = VecDuplicate(D,&shell->dshift);CHKERRQ(ierr);} 1236 if (shell->left || shell->right) { 1237 if (!shell->right_work) {ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work);CHKERRQ(ierr);} 1238 if (shell->left && shell->right) { 1239 ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr); 1240 ierr = VecPointwiseDivide(shell->right_work,shell->right_work,shell->right);CHKERRQ(ierr); 1241 } else if (shell->left) { 1242 ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr); 1243 } else { 1244 ierr = VecPointwiseDivide(shell->right_work,D,shell->right);CHKERRQ(ierr); 1245 } 1246 ierr = VecAXPY(shell->dshift,s,shell->right_work);CHKERRQ(ierr); 1247 } else { 1248 ierr = VecAXPY(shell->dshift,s,D);CHKERRQ(ierr); 1249 } 1250 PetscFunctionReturn(0); 1251 } 1252 1253 PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins) 1254 { 1255 Mat_Shell *shell = (Mat_Shell*)A->data; 1256 Vec d; 1257 PetscErrorCode ierr; 1258 PetscBool flg; 1259 1260 PetscFunctionBegin; 1261 ierr = MatHasCongruentLayouts(A,&flg);CHKERRQ(ierr); 1262 if (!flg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Cannot diagonal set or shift shell matrix if it is not congruent"); 1263 if (ins == INSERT_VALUES) { 1264 if (!A->ops->getdiagonal) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Operation MATOP_GETDIAGONAL must be set first"); 1265 ierr = VecDuplicate(D,&d);CHKERRQ(ierr); 1266 ierr = MatGetDiagonal(A,d);CHKERRQ(ierr); 1267 ierr = MatDiagonalSet_Shell_Private(A,d,-1.);CHKERRQ(ierr); 1268 ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr); 1269 ierr = VecDestroy(&d);CHKERRQ(ierr); 1270 if (shell->zrows) { 1271 ierr = VecCopy(D,shell->zvals);CHKERRQ(ierr); 1272 } 1273 } else { 1274 ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr); 1275 if (shell->zrows) { 1276 ierr = VecAXPY(shell->zvals,1.0,D);CHKERRQ(ierr); 1277 } 1278 } 1279 PetscFunctionReturn(0); 1280 } 1281 1282 PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a) 1283 { 1284 Mat_Shell *shell = (Mat_Shell*)Y->data; 1285 PetscErrorCode ierr; 1286 1287 PetscFunctionBegin; 1288 shell->vscale *= a; 1289 shell->vshift *= a; 1290 if (shell->dshift) { 1291 ierr = VecScale(shell->dshift,a);CHKERRQ(ierr); 1292 } 1293 shell->axpy_vscale *= a; 1294 if (shell->zrows) { 1295 ierr = VecScale(shell->zvals,a);CHKERRQ(ierr); 1296 } 1297 PetscFunctionReturn(0); 1298 } 1299 1300 static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right) 1301 { 1302 Mat_Shell *shell = (Mat_Shell*)Y->data; 1303 PetscErrorCode ierr; 1304 1305 PetscFunctionBegin; 1306 if (left) { 1307 if (!shell->left) { 1308 ierr = VecDuplicate(left,&shell->left);CHKERRQ(ierr); 1309 ierr = VecCopy(left,shell->left);CHKERRQ(ierr); 1310 } else { 1311 ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr); 1312 } 1313 if (shell->zrows) { 1314 ierr = VecPointwiseMult(shell->zvals,shell->zvals,left);CHKERRQ(ierr); 1315 } 1316 } 1317 if (right) { 1318 if (!shell->right) { 1319 ierr = VecDuplicate(right,&shell->right);CHKERRQ(ierr); 1320 ierr = VecCopy(right,shell->right);CHKERRQ(ierr); 1321 } else { 1322 ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr); 1323 } 1324 if (shell->zrows) { 1325 if (!shell->left_work) { 1326 ierr = MatCreateVecs(Y,NULL,&shell->left_work);CHKERRQ(ierr); 1327 } 1328 ierr = VecSet(shell->zvals_w,1.0);CHKERRQ(ierr); 1329 ierr = VecScatterBegin(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1330 ierr = VecScatterEnd(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1331 ierr = VecPointwiseMult(shell->zvals,shell->zvals,shell->zvals_w);CHKERRQ(ierr); 1332 } 1333 } 1334 if (shell->axpy) { 1335 ierr = MatDiagonalScale(shell->axpy,left,right);CHKERRQ(ierr); 1336 } 1337 PetscFunctionReturn(0); 1338 } 1339 1340 PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t) 1341 { 1342 Mat_Shell *shell = (Mat_Shell*)Y->data; 1343 PetscErrorCode ierr; 1344 1345 PetscFunctionBegin; 1346 if (t == MAT_FINAL_ASSEMBLY) { 1347 shell->vshift = 0.0; 1348 shell->vscale = 1.0; 1349 shell->axpy_vscale = 0.0; 1350 shell->axpy_state = 0; 1351 ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr); 1352 ierr = VecDestroy(&shell->left);CHKERRQ(ierr); 1353 ierr = VecDestroy(&shell->right);CHKERRQ(ierr); 1354 ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr); 1355 ierr = VecDestroy(&shell->axpy_left);CHKERRQ(ierr); 1356 ierr = VecDestroy(&shell->axpy_right);CHKERRQ(ierr); 1357 ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr); 1358 ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr); 1359 ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr); 1360 ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr); 1361 } 1362 PetscFunctionReturn(0); 1363 } 1364 1365 static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool *missing,PetscInt *d) 1366 { 1367 PetscFunctionBegin; 1368 *missing = PETSC_FALSE; 1369 PetscFunctionReturn(0); 1370 } 1371 1372 PetscErrorCode MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str) 1373 { 1374 Mat_Shell *shell = (Mat_Shell*)Y->data; 1375 PetscErrorCode ierr; 1376 1377 PetscFunctionBegin; 1378 if (X == Y) { 1379 ierr = MatScale(Y,1.0 + a);CHKERRQ(ierr); 1380 PetscFunctionReturn(0); 1381 } 1382 if (!shell->axpy) { 1383 ierr = MatConvertFrom_Shell(X,MATSHELL,MAT_INITIAL_MATRIX,&shell->axpy);CHKERRQ(ierr); 1384 shell->axpy_vscale = a; 1385 ierr = PetscObjectStateGet((PetscObject)X,&shell->axpy_state);CHKERRQ(ierr); 1386 } else { 1387 ierr = MatAXPY(shell->axpy,a/shell->axpy_vscale,X,str);CHKERRQ(ierr); 1388 } 1389 PetscFunctionReturn(0); 1390 } 1391 1392 static struct _MatOps MatOps_Values = {NULL, 1393 NULL, 1394 NULL, 1395 NULL, 1396 /* 4*/ MatMultAdd_Shell, 1397 NULL, 1398 MatMultTransposeAdd_Shell, 1399 NULL, 1400 NULL, 1401 NULL, 1402 /*10*/ NULL, 1403 NULL, 1404 NULL, 1405 NULL, 1406 NULL, 1407 /*15*/ NULL, 1408 NULL, 1409 NULL, 1410 MatDiagonalScale_Shell, 1411 NULL, 1412 /*20*/ NULL, 1413 MatAssemblyEnd_Shell, 1414 NULL, 1415 NULL, 1416 /*24*/ MatZeroRows_Shell, 1417 NULL, 1418 NULL, 1419 NULL, 1420 NULL, 1421 /*29*/ NULL, 1422 NULL, 1423 NULL, 1424 NULL, 1425 NULL, 1426 /*34*/ MatDuplicate_Shell, 1427 NULL, 1428 NULL, 1429 NULL, 1430 NULL, 1431 /*39*/ MatAXPY_Shell, 1432 NULL, 1433 NULL, 1434 NULL, 1435 MatCopy_Shell, 1436 /*44*/ NULL, 1437 MatScale_Shell, 1438 MatShift_Shell, 1439 MatDiagonalSet_Shell, 1440 MatZeroRowsColumns_Shell, 1441 /*49*/ NULL, 1442 NULL, 1443 NULL, 1444 NULL, 1445 NULL, 1446 /*54*/ NULL, 1447 NULL, 1448 NULL, 1449 NULL, 1450 NULL, 1451 /*59*/ NULL, 1452 MatDestroy_Shell, 1453 NULL, 1454 MatConvertFrom_Shell, 1455 NULL, 1456 /*64*/ NULL, 1457 NULL, 1458 NULL, 1459 NULL, 1460 NULL, 1461 /*69*/ NULL, 1462 NULL, 1463 MatConvert_Shell, 1464 NULL, 1465 NULL, 1466 /*74*/ NULL, 1467 NULL, 1468 NULL, 1469 NULL, 1470 NULL, 1471 /*79*/ NULL, 1472 NULL, 1473 NULL, 1474 NULL, 1475 NULL, 1476 /*84*/ NULL, 1477 NULL, 1478 NULL, 1479 NULL, 1480 NULL, 1481 /*89*/ NULL, 1482 NULL, 1483 NULL, 1484 NULL, 1485 NULL, 1486 /*94*/ NULL, 1487 NULL, 1488 NULL, 1489 NULL, 1490 NULL, 1491 /*99*/ NULL, 1492 NULL, 1493 NULL, 1494 NULL, 1495 NULL, 1496 /*104*/ NULL, 1497 NULL, 1498 NULL, 1499 NULL, 1500 NULL, 1501 /*109*/ NULL, 1502 NULL, 1503 NULL, 1504 NULL, 1505 MatMissingDiagonal_Shell, 1506 /*114*/ NULL, 1507 NULL, 1508 NULL, 1509 NULL, 1510 NULL, 1511 /*119*/ NULL, 1512 NULL, 1513 NULL, 1514 NULL, 1515 NULL, 1516 /*124*/ NULL, 1517 NULL, 1518 NULL, 1519 NULL, 1520 NULL, 1521 /*129*/ NULL, 1522 NULL, 1523 NULL, 1524 NULL, 1525 NULL, 1526 /*134*/ NULL, 1527 NULL, 1528 NULL, 1529 NULL, 1530 NULL, 1531 /*139*/ NULL, 1532 NULL, 1533 NULL 1534 }; 1535 1536 PetscErrorCode MatShellSetContext_Shell(Mat mat,void *ctx) 1537 { 1538 Mat_Shell *shell = (Mat_Shell*)mat->data; 1539 1540 PetscFunctionBegin; 1541 shell->ctx = ctx; 1542 PetscFunctionReturn(0); 1543 } 1544 1545 static PetscErrorCode MatShellSetVecType_Shell(Mat mat,VecType vtype) 1546 { 1547 PetscErrorCode ierr; 1548 1549 PetscFunctionBegin; 1550 ierr = PetscFree(mat->defaultvectype);CHKERRQ(ierr); 1551 ierr = PetscStrallocpy(vtype,(char**)&mat->defaultvectype);CHKERRQ(ierr); 1552 PetscFunctionReturn(0); 1553 } 1554 1555 PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A) 1556 { 1557 Mat_Shell *shell = (Mat_Shell*)A->data; 1558 1559 PetscFunctionBegin; 1560 shell->managescalingshifts = PETSC_FALSE; 1561 A->ops->diagonalset = NULL; 1562 A->ops->diagonalscale = NULL; 1563 A->ops->scale = NULL; 1564 A->ops->shift = NULL; 1565 A->ops->axpy = NULL; 1566 PetscFunctionReturn(0); 1567 } 1568 1569 PetscErrorCode MatShellSetOperation_Shell(Mat mat,MatOperation op,void (*f)(void)) 1570 { 1571 Mat_Shell *shell = (Mat_Shell*)mat->data; 1572 1573 PetscFunctionBegin; 1574 switch (op) { 1575 case MATOP_DESTROY: 1576 shell->ops->destroy = (PetscErrorCode (*)(Mat))f; 1577 break; 1578 case MATOP_VIEW: 1579 if (!mat->ops->viewnative) { 1580 mat->ops->viewnative = mat->ops->view; 1581 } 1582 mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f; 1583 break; 1584 case MATOP_COPY: 1585 shell->ops->copy = (PetscErrorCode (*)(Mat,Mat,MatStructure))f; 1586 break; 1587 case MATOP_DIAGONAL_SET: 1588 case MATOP_DIAGONAL_SCALE: 1589 case MATOP_SHIFT: 1590 case MATOP_SCALE: 1591 case MATOP_AXPY: 1592 case MATOP_ZERO_ROWS: 1593 case MATOP_ZERO_ROWS_COLUMNS: 1594 if (shell->managescalingshifts) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()"); 1595 (((void(**)(void))mat->ops)[op]) = f; 1596 break; 1597 case MATOP_GET_DIAGONAL: 1598 if (shell->managescalingshifts) { 1599 shell->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f; 1600 mat->ops->getdiagonal = MatGetDiagonal_Shell; 1601 } else { 1602 shell->ops->getdiagonal = NULL; 1603 mat->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f; 1604 } 1605 break; 1606 case MATOP_MULT: 1607 if (shell->managescalingshifts) { 1608 shell->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1609 mat->ops->mult = MatMult_Shell; 1610 } else { 1611 shell->ops->mult = NULL; 1612 mat->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1613 } 1614 break; 1615 case MATOP_MULT_TRANSPOSE: 1616 if (shell->managescalingshifts) { 1617 shell->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1618 mat->ops->multtranspose = MatMultTranspose_Shell; 1619 } else { 1620 shell->ops->multtranspose = NULL; 1621 mat->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1622 } 1623 break; 1624 default: 1625 (((void(**)(void))mat->ops)[op]) = f; 1626 break; 1627 } 1628 PetscFunctionReturn(0); 1629 } 1630 1631 PetscErrorCode MatShellGetOperation_Shell(Mat mat,MatOperation op,void(**f)(void)) 1632 { 1633 Mat_Shell *shell = (Mat_Shell*)mat->data; 1634 1635 PetscFunctionBegin; 1636 switch (op) { 1637 case MATOP_DESTROY: 1638 *f = (void (*)(void))shell->ops->destroy; 1639 break; 1640 case MATOP_VIEW: 1641 *f = (void (*)(void))mat->ops->view; 1642 break; 1643 case MATOP_COPY: 1644 *f = (void (*)(void))shell->ops->copy; 1645 break; 1646 case MATOP_DIAGONAL_SET: 1647 case MATOP_DIAGONAL_SCALE: 1648 case MATOP_SHIFT: 1649 case MATOP_SCALE: 1650 case MATOP_AXPY: 1651 case MATOP_ZERO_ROWS: 1652 case MATOP_ZERO_ROWS_COLUMNS: 1653 *f = (((void (**)(void))mat->ops)[op]); 1654 break; 1655 case MATOP_GET_DIAGONAL: 1656 if (shell->ops->getdiagonal) 1657 *f = (void (*)(void))shell->ops->getdiagonal; 1658 else 1659 *f = (((void (**)(void))mat->ops)[op]); 1660 break; 1661 case MATOP_MULT: 1662 if (shell->ops->mult) 1663 *f = (void (*)(void))shell->ops->mult; 1664 else 1665 *f = (((void (**)(void))mat->ops)[op]); 1666 break; 1667 case MATOP_MULT_TRANSPOSE: 1668 if (shell->ops->multtranspose) 1669 *f = (void (*)(void))shell->ops->multtranspose; 1670 else 1671 *f = (((void (**)(void))mat->ops)[op]); 1672 break; 1673 default: 1674 *f = (((void (**)(void))mat->ops)[op]); 1675 } 1676 PetscFunctionReturn(0); 1677 } 1678 1679 /*MC 1680 MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free. 1681 1682 Level: advanced 1683 1684 .seealso: MatCreateShell() 1685 M*/ 1686 1687 PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A) 1688 { 1689 Mat_Shell *b; 1690 PetscErrorCode ierr; 1691 1692 PetscFunctionBegin; 1693 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 1694 1695 ierr = PetscNewLog(A,&b);CHKERRQ(ierr); 1696 A->data = (void*)b; 1697 1698 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 1699 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 1700 1701 b->ctx = NULL; 1702 b->vshift = 0.0; 1703 b->vscale = 1.0; 1704 b->managescalingshifts = PETSC_TRUE; 1705 A->assembled = PETSC_TRUE; 1706 A->preallocated = PETSC_FALSE; 1707 1708 ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellGetContext_C",MatShellGetContext_Shell);CHKERRQ(ierr); 1709 ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetContext_C",MatShellSetContext_Shell);CHKERRQ(ierr); 1710 ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetVecType_C",MatShellSetVecType_Shell);CHKERRQ(ierr); 1711 ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetManageScalingShifts_C",MatShellSetManageScalingShifts_Shell);CHKERRQ(ierr); 1712 ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetOperation_C",MatShellSetOperation_Shell);CHKERRQ(ierr); 1713 ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellGetOperation_C",MatShellGetOperation_Shell);CHKERRQ(ierr); 1714 ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetMatProductOperation_C",MatShellSetMatProductOperation_Shell);CHKERRQ(ierr); 1715 ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr); 1716 PetscFunctionReturn(0); 1717 } 1718 1719 /*@C 1720 MatCreateShell - Creates a new matrix class for use with a user-defined 1721 private data storage format. 1722 1723 Collective 1724 1725 Input Parameters: 1726 + comm - MPI communicator 1727 . m - number of local rows (must be given) 1728 . n - number of local columns (must be given) 1729 . M - number of global rows (may be PETSC_DETERMINE) 1730 . N - number of global columns (may be PETSC_DETERMINE) 1731 - ctx - pointer to data needed by the shell matrix routines 1732 1733 Output Parameter: 1734 . A - the matrix 1735 1736 Level: advanced 1737 1738 Usage: 1739 $ extern PetscErrorCode mult(Mat,Vec,Vec); 1740 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 1741 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 1742 $ [ Use matrix for operations that have been set ] 1743 $ MatDestroy(mat); 1744 1745 Notes: 1746 The shell matrix type is intended to provide a simple class to use 1747 with KSP (such as, for use with matrix-free methods). You should not 1748 use the shell type if you plan to define a complete matrix class. 1749 1750 Fortran Notes: 1751 To use this from Fortran with a ctx you must write an interface definition for this 1752 function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing 1753 in as the ctx argument. 1754 1755 PETSc requires that matrices and vectors being used for certain 1756 operations are partitioned accordingly. For example, when 1757 creating a shell matrix, A, that supports parallel matrix-vector 1758 products using MatMult(A,x,y) the user should set the number 1759 of local matrix rows to be the number of local elements of the 1760 corresponding result vector, y. Note that this is information is 1761 required for use of the matrix interface routines, even though 1762 the shell matrix may not actually be physically partitioned. 1763 For example, 1764 1765 $ 1766 $ Vec x, y 1767 $ extern PetscErrorCode mult(Mat,Vec,Vec); 1768 $ Mat A 1769 $ 1770 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 1771 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 1772 $ VecGetLocalSize(y,&m); 1773 $ VecGetLocalSize(x,&n); 1774 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 1775 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 1776 $ MatMult(A,x,y); 1777 $ MatDestroy(&A); 1778 $ VecDestroy(&y); 1779 $ VecDestroy(&x); 1780 $ 1781 1782 1783 MATSHELL handles MatShift(), MatDiagonalSet(), MatDiagonalScale(), MatAXPY(), MatScale(), MatZeroRows() and MatZeroRowsColumns() internally, so these 1784 operations cannot be overwritten unless MatShellSetManageScalingShifts() is called. 1785 1786 1787 For rectangular matrices do all the scalings and shifts make sense? 1788 1789 Developers Notes: 1790 Regarding shifting and scaling. The general form is 1791 1792 diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 1793 1794 The order you apply the operations is important. For example if you have a dshift then 1795 apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift 1796 you get s*vscale*A + diag(shift) 1797 1798 A is the user provided function. 1799 1800 KSP/PC uses changes in the Mat's "state" to decide if preconditioners need to be rebuilt: PCSetUp() only calls the setup() for 1801 for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a MATSHELL to trigger 1802 an update in the preconditioner you must call MatAssemblyBegin()/MatAssemblyEnd() or PetscObjectStateIncrease((PetscObject)mat); 1803 each time the MATSHELL matrix has changed. 1804 1805 Matrix product operations (i.e. MatMat, MatTranposeMat etc) can be specified using MatShellSetMatProductOperation() 1806 1807 Calling MatAssemblyBegin()/MatAssemblyEnd() on a MATSHELL removes any previously supplied shift and scales that were provided 1808 with MatDiagonalSet(), MatShift(), MatScale(), or MatDiagonalScale(). 1809 1810 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext(), MATSHELL, MatShellSetManageScalingShifts(), MatShellSetMatProductOperation() 1811 @*/ 1812 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) 1813 { 1814 PetscErrorCode ierr; 1815 1816 PetscFunctionBegin; 1817 ierr = MatCreate(comm,A);CHKERRQ(ierr); 1818 ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr); 1819 ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); 1820 ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); 1821 ierr = MatSetUp(*A);CHKERRQ(ierr); 1822 PetscFunctionReturn(0); 1823 } 1824 1825 /*@ 1826 MatShellSetContext - sets the context for a shell matrix 1827 1828 Logically Collective on Mat 1829 1830 Input Parameters: 1831 + mat - the shell matrix 1832 - ctx - the context 1833 1834 Level: advanced 1835 1836 Fortran Notes: 1837 To use this from Fortran you must write a Fortran interface definition for this 1838 function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 1839 1840 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 1841 @*/ 1842 PetscErrorCode MatShellSetContext(Mat mat,void *ctx) 1843 { 1844 PetscErrorCode ierr; 1845 1846 PetscFunctionBegin; 1847 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1848 ierr = PetscTryMethod(mat,"MatShellSetContext_C",(Mat,void*),(mat,ctx));CHKERRQ(ierr); 1849 PetscFunctionReturn(0); 1850 } 1851 1852 /*@C 1853 MatShellSetVecType - Sets the type of Vec returned by MatCreateVecs() 1854 1855 Logically collective 1856 1857 Input Parameters: 1858 + mat - the shell matrix 1859 - vtype - type to use for creating vectors 1860 1861 Notes: 1862 1863 Level: advanced 1864 1865 .seealso: MatCreateVecs() 1866 @*/ 1867 PetscErrorCode MatShellSetVecType(Mat mat,VecType vtype) 1868 { 1869 PetscErrorCode ierr; 1870 1871 PetscFunctionBegin; 1872 ierr = PetscTryMethod(mat,"MatShellSetVecType_C",(Mat,VecType),(mat,vtype));CHKERRQ(ierr); 1873 PetscFunctionReturn(0); 1874 } 1875 1876 /*@ 1877 MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the MATSHELL. Must be called immediately 1878 after MatCreateShell() 1879 1880 Logically Collective on Mat 1881 1882 Input Parameter: 1883 . mat - the shell matrix 1884 1885 Level: advanced 1886 1887 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatShellSetOperation() 1888 @*/ 1889 PetscErrorCode MatShellSetManageScalingShifts(Mat A) 1890 { 1891 PetscErrorCode ierr; 1892 1893 PetscFunctionBegin; 1894 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1895 ierr = PetscTryMethod(A,"MatShellSetManageScalingShifts_C",(Mat),(A));CHKERRQ(ierr); 1896 PetscFunctionReturn(0); 1897 } 1898 1899 /*@C 1900 MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function. 1901 1902 Logically Collective on Mat 1903 1904 Input Parameters: 1905 + mat - the shell matrix 1906 . f - the function 1907 . base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated 1908 - ctx - an optional context for the function 1909 1910 Output Parameter: 1911 . flg - PETSC_TRUE if the multiply is likely correct 1912 1913 Options Database: 1914 . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1915 1916 Level: advanced 1917 1918 Fortran Notes: 1919 Not supported from Fortran 1920 1921 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMultTranspose() 1922 @*/ 1923 PetscErrorCode MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg) 1924 { 1925 PetscErrorCode ierr; 1926 PetscInt m,n; 1927 Mat mf,Dmf,Dmat,Ddiff; 1928 PetscReal Diffnorm,Dmfnorm; 1929 PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1930 1931 PetscFunctionBegin; 1932 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1933 ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v);CHKERRQ(ierr); 1934 ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr); 1935 ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf);CHKERRQ(ierr); 1936 ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr); 1937 ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr); 1938 1939 ierr = MatComputeOperator(mf,MATAIJ,&Dmf);CHKERRQ(ierr); 1940 ierr = MatComputeOperator(mat,MATAIJ,&Dmat);CHKERRQ(ierr); 1941 1942 ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr); 1943 ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 1944 ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr); 1945 ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr); 1946 if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) { 1947 flag = PETSC_FALSE; 1948 if (v) { 1949 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); 1950 ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr); 1951 ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr); 1952 ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr); 1953 } 1954 } else if (v) { 1955 ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr); 1956 } 1957 if (flg) *flg = flag; 1958 ierr = MatDestroy(&Ddiff);CHKERRQ(ierr); 1959 ierr = MatDestroy(&mf);CHKERRQ(ierr); 1960 ierr = MatDestroy(&Dmf);CHKERRQ(ierr); 1961 ierr = MatDestroy(&Dmat);CHKERRQ(ierr); 1962 PetscFunctionReturn(0); 1963 } 1964 1965 /*@C 1966 MatShellTestMultTranpose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function. 1967 1968 Logically Collective on Mat 1969 1970 Input Parameters: 1971 + mat - the shell matrix 1972 . f - the function 1973 . base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated 1974 - ctx - an optional context for the function 1975 1976 Output Parameter: 1977 . flg - PETSC_TRUE if the multiply is likely correct 1978 1979 Options Database: 1980 . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1981 1982 Level: advanced 1983 1984 Fortran Notes: 1985 Not supported from Fortran 1986 1987 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMult() 1988 @*/ 1989 PetscErrorCode MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg) 1990 { 1991 PetscErrorCode ierr; 1992 Vec x,y,z; 1993 PetscInt m,n,M,N; 1994 Mat mf,Dmf,Dmat,Ddiff; 1995 PetscReal Diffnorm,Dmfnorm; 1996 PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1997 1998 PetscFunctionBegin; 1999 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2000 ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v);CHKERRQ(ierr); 2001 ierr = MatCreateVecs(mat,&x,&y);CHKERRQ(ierr); 2002 ierr = VecDuplicate(y,&z);CHKERRQ(ierr); 2003 ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr); 2004 ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr); 2005 ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf);CHKERRQ(ierr); 2006 ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr); 2007 ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr); 2008 ierr = MatComputeOperator(mf,MATAIJ,&Dmf);CHKERRQ(ierr); 2009 ierr = MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf);CHKERRQ(ierr); 2010 ierr = MatComputeOperatorTranspose(mat,MATAIJ,&Dmat);CHKERRQ(ierr); 2011 2012 ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr); 2013 ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 2014 ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr); 2015 ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr); 2016 if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) { 2017 flag = PETSC_FALSE; 2018 if (v) { 2019 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); 2020 ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr); 2021 ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr); 2022 ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr); 2023 } 2024 } else if (v) { 2025 ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr); 2026 } 2027 if (flg) *flg = flag; 2028 ierr = MatDestroy(&mf);CHKERRQ(ierr); 2029 ierr = MatDestroy(&Dmat);CHKERRQ(ierr); 2030 ierr = MatDestroy(&Ddiff);CHKERRQ(ierr); 2031 ierr = MatDestroy(&Dmf);CHKERRQ(ierr); 2032 ierr = VecDestroy(&x);CHKERRQ(ierr); 2033 ierr = VecDestroy(&y);CHKERRQ(ierr); 2034 ierr = VecDestroy(&z);CHKERRQ(ierr); 2035 PetscFunctionReturn(0); 2036 } 2037 2038 /*@C 2039 MatShellSetOperation - Allows user to set a matrix operation for a shell matrix. 2040 2041 Logically Collective on Mat 2042 2043 Input Parameters: 2044 + mat - the shell matrix 2045 . op - the name of the operation 2046 - g - the function that provides the operation. 2047 2048 Level: advanced 2049 2050 Usage: 2051 $ extern PetscErrorCode usermult(Mat,Vec,Vec); 2052 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 2053 $ MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 2054 2055 Notes: 2056 See the file include/petscmat.h for a complete list of matrix 2057 operations, which all have the form MATOP_<OPERATION>, where 2058 <OPERATION> is the name (in all capital letters) of the 2059 user interface routine (e.g., MatMult() -> MATOP_MULT). 2060 2061 All user-provided functions (except for MATOP_DESTROY) should have the same calling 2062 sequence as the usual matrix interface routines, since they 2063 are intended to be accessed via the usual matrix interface 2064 routines, e.g., 2065 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 2066 2067 In particular each function MUST return an error code of 0 on success and 2068 nonzero on failure. 2069 2070 Within each user-defined routine, the user should call 2071 MatShellGetContext() to obtain the user-defined context that was 2072 set by MatCreateShell(). 2073 2074 Use MatSetOperation() to set an operation for any matrix type. For matrix product operations (i.e. MatMat, MatTransposeMat etc) use MatShellSetMatProductOperation() 2075 2076 Fortran Notes: 2077 For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not 2078 generate a matrix. See src/mat/tests/ex120f.F 2079 2080 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatShellSetManageScalingShifts(), MatShellSetMatProductOperation() 2081 @*/ 2082 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*g)(void)) 2083 { 2084 PetscErrorCode ierr; 2085 2086 PetscFunctionBegin; 2087 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2088 ierr = PetscTryMethod(mat,"MatShellSetOperation_C",(Mat,MatOperation,void (*)(void)),(mat,op,g));CHKERRQ(ierr); 2089 PetscFunctionReturn(0); 2090 } 2091 2092 /*@C 2093 MatShellGetOperation - Gets a matrix function for a shell matrix. 2094 2095 Not Collective 2096 2097 Input Parameters: 2098 + mat - the shell matrix 2099 - op - the name of the operation 2100 2101 Output Parameter: 2102 . g - the function that provides the operation. 2103 2104 Level: advanced 2105 2106 Notes: 2107 See the file include/petscmat.h for a complete list of matrix 2108 operations, which all have the form MATOP_<OPERATION>, where 2109 <OPERATION> is the name (in all capital letters) of the 2110 user interface routine (e.g., MatMult() -> MATOP_MULT). 2111 2112 All user-provided functions have the same calling 2113 sequence as the usual matrix interface routines, since they 2114 are intended to be accessed via the usual matrix interface 2115 routines, e.g., 2116 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 2117 2118 Within each user-defined routine, the user should call 2119 MatShellGetContext() to obtain the user-defined context that was 2120 set by MatCreateShell(). 2121 2122 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext() 2123 @*/ 2124 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**g)(void)) 2125 { 2126 PetscErrorCode ierr; 2127 2128 PetscFunctionBegin; 2129 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2130 ierr = PetscUseMethod(mat,"MatShellGetOperation_C",(Mat,MatOperation,void (**)(void)),(mat,op,g));CHKERRQ(ierr); 2131 PetscFunctionReturn(0); 2132 } 2133 2134 /*@ 2135 MatIsShell - Inquires if a matrix is derived from MATSHELL 2136 2137 Input Parameter: 2138 . mat - the matrix 2139 2140 Output Parameter: 2141 . flg - the boolean value 2142 2143 Level: developer 2144 2145 Notes: in the future, we should allow the object type name to be changed still using the MatShell data structure for other matrices (i.e. MATTRANSPOSEMAT, MATSCHURCOMPLEMENT etc) 2146 2147 .seealso: MatCreateShell() 2148 @*/ 2149 PetscErrorCode MatIsShell(Mat mat, PetscBool *flg) 2150 { 2151 PetscFunctionBegin; 2152 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2153 PetscValidPointer(flg,2); 2154 *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell); 2155 PetscFunctionReturn(0); 2156 } 2157