1 2 #include <petsc/private/matimpl.h> 3 #include <../src/mat/impls/mffd/mffdimpl.h> /*I "petscmat.h" I*/ 4 5 PetscFunctionList MatMFFDList = 0; 6 PetscBool MatMFFDRegisterAllCalled = PETSC_FALSE; 7 8 PetscClassId MATMFFD_CLASSID; 9 PetscLogEvent MATMFFD_Mult; 10 11 static PetscBool MatMFFDPackageInitialized = PETSC_FALSE; 12 /*@C 13 MatMFFDFinalizePackage - This function destroys everything in the MatMFFD package. It is 14 called from PetscFinalize(). 15 16 Level: developer 17 18 .keywords: Petsc, destroy, package 19 .seealso: PetscFinalize(), MatCreateMFFD(), MatCreateSNESMF() 20 @*/ 21 PetscErrorCode MatMFFDFinalizePackage(void) 22 { 23 PetscErrorCode ierr; 24 25 PetscFunctionBegin; 26 ierr = PetscFunctionListDestroy(&MatMFFDList);CHKERRQ(ierr); 27 MatMFFDPackageInitialized = PETSC_FALSE; 28 MatMFFDRegisterAllCalled = PETSC_FALSE; 29 PetscFunctionReturn(0); 30 } 31 32 /*@C 33 MatMFFDInitializePackage - This function initializes everything in the MatMFFD package. It is called 34 from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to MatCreate_MFFD() 35 when using static libraries. 36 37 Level: developer 38 39 .keywords: Vec, initialize, package 40 .seealso: PetscInitialize() 41 @*/ 42 PetscErrorCode MatMFFDInitializePackage(void) 43 { 44 char logList[256]; 45 char *className; 46 PetscBool opt; 47 PetscErrorCode ierr; 48 49 PetscFunctionBegin; 50 if (MatMFFDPackageInitialized) PetscFunctionReturn(0); 51 MatMFFDPackageInitialized = PETSC_TRUE; 52 /* Register Classes */ 53 ierr = PetscClassIdRegister("MatMFFD",&MATMFFD_CLASSID);CHKERRQ(ierr); 54 /* Register Constructors */ 55 ierr = MatMFFDRegisterAll();CHKERRQ(ierr); 56 /* Register Events */ 57 ierr = PetscLogEventRegister("MatMult MF", MATMFFD_CLASSID,&MATMFFD_Mult);CHKERRQ(ierr); 58 59 /* Process info exclusions */ 60 ierr = PetscOptionsGetString(NULL,NULL, "-info_exclude", logList, 256, &opt);CHKERRQ(ierr); 61 if (opt) { 62 ierr = PetscStrstr(logList, "matmffd", &className);CHKERRQ(ierr); 63 if (className) { 64 ierr = PetscInfoDeactivateClass(MATMFFD_CLASSID);CHKERRQ(ierr); 65 } 66 } 67 /* Process summary exclusions */ 68 ierr = PetscOptionsGetString(NULL,NULL, "-log_exclude", logList, 256, &opt);CHKERRQ(ierr); 69 if (opt) { 70 ierr = PetscStrstr(logList, "matmffd", &className);CHKERRQ(ierr); 71 if (className) { 72 ierr = PetscLogEventDeactivateClass(MATMFFD_CLASSID);CHKERRQ(ierr); 73 } 74 } 75 ierr = PetscRegisterFinalize(MatMFFDFinalizePackage);CHKERRQ(ierr); 76 PetscFunctionReturn(0); 77 } 78 79 /*@C 80 MatMFFDSetType - Sets the method that is used to compute the 81 differencing parameter for finite differene matrix-free formulations. 82 83 Input Parameters: 84 + mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMFFD() 85 or MatSetType(mat,MATMFFD); 86 - ftype - the type requested, either MATMFFD_WP or MATMFFD_DS 87 88 Level: advanced 89 90 Notes: 91 For example, such routines can compute h for use in 92 Jacobian-vector products of the form 93 94 F(x+ha) - F(x) 95 F'(u)a ~= ---------------- 96 h 97 98 .seealso: MatCreateSNESMF(), MatMFFDRegister(), MatMFFDSetFunction(), MatCreateMFFD() 99 @*/ 100 PetscErrorCode MatMFFDSetType(Mat mat,MatMFFDType ftype) 101 { 102 PetscErrorCode ierr,(*r)(MatMFFD); 103 MatMFFD ctx = (MatMFFD)mat->data; 104 PetscBool match; 105 106 PetscFunctionBegin; 107 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 108 PetscValidCharPointer(ftype,2); 109 110 ierr = PetscObjectTypeCompare((PetscObject)mat,MATMFFD,&match);CHKERRQ(ierr); 111 if (!match) PetscFunctionReturn(0); 112 113 /* already set, so just return */ 114 ierr = PetscObjectTypeCompare((PetscObject)ctx,ftype,&match);CHKERRQ(ierr); 115 if (match) PetscFunctionReturn(0); 116 117 /* destroy the old one if it exists */ 118 if (ctx->ops->destroy) { 119 ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr); 120 } 121 122 ierr = PetscFunctionListFind(MatMFFDList,ftype,&r);CHKERRQ(ierr); 123 if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatMFFD type %s given",ftype); 124 ierr = (*r)(ctx);CHKERRQ(ierr); 125 ierr = PetscObjectChangeTypeName((PetscObject)ctx,ftype);CHKERRQ(ierr); 126 PetscFunctionReturn(0); 127 } 128 129 static PetscErrorCode MatGetDiagonal_MFFD(Mat,Vec); 130 131 typedef PetscErrorCode (*FCN1)(void*,Vec); /* force argument to next function to not be extern C*/ 132 static PetscErrorCode MatMFFDSetFunctioniBase_MFFD(Mat mat,FCN1 func) 133 { 134 MatMFFD ctx = (MatMFFD)mat->data; 135 136 PetscFunctionBegin; 137 ctx->funcisetbase = func; 138 /* allow users to compose their own getdiagonal and allow MatHasOperation return false if the two functions pointers are not set */ 139 if (!mat->ops->getdiagonal || mat->ops->getdiagonal == MatGetDiagonal_MFFD) { 140 mat->ops->getdiagonal = mat->ops->getdiagonal ? ( func ? mat->ops->getdiagonal : NULL) : 141 ( (func && ctx->funci) ? MatGetDiagonal_MFFD : NULL); 142 } 143 PetscFunctionReturn(0); 144 } 145 146 typedef PetscErrorCode (*FCN2)(void*,PetscInt,Vec,PetscScalar*); /* force argument to next function to not be extern C*/ 147 static PetscErrorCode MatMFFDSetFunctioni_MFFD(Mat mat,FCN2 funci) 148 { 149 MatMFFD ctx = (MatMFFD)mat->data; 150 151 PetscFunctionBegin; 152 ctx->funci = funci; 153 /* allow users to compose their own getdiagonal and allow MatHasOperation return false if the two functions pointers are not set */ 154 if (!mat->ops->getdiagonal || mat->ops->getdiagonal == MatGetDiagonal_MFFD) { 155 mat->ops->getdiagonal = mat->ops->getdiagonal ? ( funci ? mat->ops->getdiagonal : NULL) : 156 ( (funci && ctx->funcisetbase) ? MatGetDiagonal_MFFD : NULL); 157 } 158 PetscFunctionReturn(0); 159 } 160 161 static PetscErrorCode MatMFFDResetHHistory_MFFD(Mat J) 162 { 163 MatMFFD ctx = (MatMFFD)J->data; 164 165 PetscFunctionBegin; 166 ctx->ncurrenth = 0; 167 PetscFunctionReturn(0); 168 } 169 170 /*@C 171 MatMFFDRegister - Adds a method to the MatMFFD registry. 172 173 Not Collective 174 175 Input Parameters: 176 + name_solver - name of a new user-defined compute-h module 177 - routine_create - routine to create method context 178 179 Level: developer 180 181 Notes: 182 MatMFFDRegister() may be called multiple times to add several user-defined solvers. 183 184 Sample usage: 185 .vb 186 MatMFFDRegister("my_h",MyHCreate); 187 .ve 188 189 Then, your solver can be chosen with the procedural interface via 190 $ MatMFFDSetType(mfctx,"my_h") 191 or at runtime via the option 192 $ -mat_mffd_type my_h 193 194 .keywords: MatMFFD, register 195 196 .seealso: MatMFFDRegisterAll(), MatMFFDRegisterDestroy() 197 @*/ 198 PetscErrorCode MatMFFDRegister(const char sname[],PetscErrorCode (*function)(MatMFFD)) 199 { 200 PetscErrorCode ierr; 201 202 PetscFunctionBegin; 203 ierr = PetscFunctionListAdd(&MatMFFDList,sname,function);CHKERRQ(ierr); 204 PetscFunctionReturn(0); 205 } 206 207 /* ----------------------------------------------------------------------------------------*/ 208 static PetscErrorCode MatDestroy_MFFD(Mat mat) 209 { 210 PetscErrorCode ierr; 211 MatMFFD ctx = (MatMFFD)mat->data; 212 213 PetscFunctionBegin; 214 ierr = VecDestroy(&ctx->w);CHKERRQ(ierr); 215 ierr = VecDestroy(&ctx->drscale);CHKERRQ(ierr); 216 ierr = VecDestroy(&ctx->dlscale);CHKERRQ(ierr); 217 ierr = VecDestroy(&ctx->dshift);CHKERRQ(ierr); 218 ierr = VecDestroy(&ctx->dshiftw);CHKERRQ(ierr); 219 ierr = VecDestroy(&ctx->current_u);CHKERRQ(ierr); 220 if (ctx->current_f_allocated) { 221 ierr = VecDestroy(&ctx->current_f);CHKERRQ(ierr); 222 } 223 if (ctx->ops->destroy) {ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);} 224 ierr = PetscHeaderDestroy(&ctx);CHKERRQ(ierr); 225 mat->data = 0; 226 227 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetBase_C",NULL);CHKERRQ(ierr); 228 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C",NULL);CHKERRQ(ierr); 229 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioni_C",NULL);CHKERRQ(ierr); 230 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunction_C",NULL);CHKERRQ(ierr); 231 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctionError_C",NULL);CHKERRQ(ierr); 232 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetCheckh_C",NULL);CHKERRQ(ierr); 233 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetPeriod_C",NULL);CHKERRQ(ierr); 234 ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDResetHHistory_C",NULL);CHKERRQ(ierr); 235 PetscFunctionReturn(0); 236 } 237 238 static PetscErrorCode MatSetUp_MFFD(Mat mat) 239 { 240 PetscErrorCode ierr; 241 242 PetscFunctionBegin; 243 ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr); 244 ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr); 245 PetscFunctionReturn(0); 246 } 247 248 /* 249 MatMFFDView_MFFD - Views matrix-free parameters. 250 251 */ 252 static PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer) 253 { 254 PetscErrorCode ierr; 255 MatMFFD ctx = (MatMFFD)J->data; 256 PetscBool iascii, viewbase, viewfunction; 257 const char *prefix; 258 259 PetscFunctionBegin; 260 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 261 if (iascii) { 262 ierr = PetscViewerASCIIPrintf(viewer,"Matrix-free approximation:\n");CHKERRQ(ierr); 263 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 264 ierr = PetscViewerASCIIPrintf(viewer,"err=%g (relative error in function evaluation)\n",(double)ctx->error_rel);CHKERRQ(ierr); 265 if (!((PetscObject)ctx)->type_name) { 266 ierr = PetscViewerASCIIPrintf(viewer,"The compute h routine has not yet been set\n");CHKERRQ(ierr); 267 } else { 268 ierr = PetscViewerASCIIPrintf(viewer,"Using %s compute h routine\n",((PetscObject)ctx)->type_name);CHKERRQ(ierr); 269 } 270 if (ctx->ops->view) { 271 ierr = (*ctx->ops->view)(ctx,viewer);CHKERRQ(ierr); 272 } 273 ierr = PetscObjectGetOptionsPrefix((PetscObject)J, &prefix);CHKERRQ(ierr); 274 275 ierr = PetscOptionsHasName(((PetscObject)J)->options,prefix, "-mat_mffd_view_base", &viewbase);CHKERRQ(ierr); 276 if (viewbase) { 277 ierr = PetscViewerASCIIPrintf(viewer, "Base:\n");CHKERRQ(ierr); 278 ierr = VecView(ctx->current_u, viewer);CHKERRQ(ierr); 279 } 280 ierr = PetscOptionsHasName(((PetscObject)J)->options,prefix, "-mat_mffd_view_function", &viewfunction);CHKERRQ(ierr); 281 if (viewfunction) { 282 ierr = PetscViewerASCIIPrintf(viewer, "Function:\n");CHKERRQ(ierr); 283 ierr = VecView(ctx->current_f, viewer);CHKERRQ(ierr); 284 } 285 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 286 } 287 PetscFunctionReturn(0); 288 } 289 290 /* 291 MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This 292 allows the user to indicate the beginning of a new linear solve by calling 293 MatAssemblyXXX() on the matrix free matrix. This then allows the 294 MatCreateMFFD_WP() to properly compute ||U|| only the first time 295 in the linear solver rather than every time. 296 297 This function is referenced directly from MatAssemblyEnd_SNESMF(), which may be in a different shared library hence 298 it must be labeled as PETSC_EXTERN 299 */ 300 PETSC_EXTERN PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt) 301 { 302 PetscErrorCode ierr; 303 MatMFFD j = (MatMFFD)J->data; 304 305 PetscFunctionBegin; 306 ierr = MatMFFDResetHHistory(J);CHKERRQ(ierr); 307 j->vshift = 0.0; 308 j->vscale = 1.0; 309 PetscFunctionReturn(0); 310 } 311 312 /* 313 MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a: 314 315 y ~= (F(u + ha) - F(u))/h, 316 where F = nonlinear function, as set by SNESSetFunction() 317 u = current iterate 318 h = difference interval 319 */ 320 static PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y) 321 { 322 MatMFFD ctx = (MatMFFD)mat->data; 323 PetscScalar h; 324 Vec w,U,F; 325 PetscErrorCode ierr; 326 PetscBool zeroa; 327 328 PetscFunctionBegin; 329 if (!ctx->current_u) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MatMFFDSetBase() has not been called, this is often caused by forgetting to call \n\t\tMatAssemblyBegin/End on the first Mat in the SNES compute function"); 330 /* We log matrix-free matrix-vector products separately, so that we can 331 separate the performance monitoring from the cases that use conventional 332 storage. We may eventually modify event logging to associate events 333 with particular objects, hence alleviating the more general problem. */ 334 ierr = PetscLogEventBegin(MATMFFD_Mult,a,y,0,0);CHKERRQ(ierr); 335 336 w = ctx->w; 337 U = ctx->current_u; 338 F = ctx->current_f; 339 /* 340 Compute differencing parameter 341 */ 342 if (!((PetscObject)ctx)->type_name) { 343 ierr = MatMFFDSetType(mat,MATMFFD_WP);CHKERRQ(ierr); 344 ierr = MatSetFromOptions(mat);CHKERRQ(ierr); 345 } 346 ierr = (*ctx->ops->compute)(ctx,U,a,&h,&zeroa);CHKERRQ(ierr); 347 if (zeroa) { 348 ierr = VecSet(y,0.0);CHKERRQ(ierr); 349 PetscFunctionReturn(0); 350 } 351 352 if (mat->erroriffailure && PetscIsInfOrNanScalar(h)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Computed Nan differencing parameter h"); 353 if (ctx->checkh) { 354 ierr = (*ctx->checkh)(ctx->checkhctx,U,a,&h);CHKERRQ(ierr); 355 } 356 357 /* keep a record of the current differencing parameter h */ 358 ctx->currenth = h; 359 #if defined(PETSC_USE_COMPLEX) 360 ierr = PetscInfo2(mat,"Current differencing parameter: %g + %g i\n",(double)PetscRealPart(h),(double)PetscImaginaryPart(h));CHKERRQ(ierr); 361 #else 362 ierr = PetscInfo1(mat,"Current differencing parameter: %15.12e\n",h);CHKERRQ(ierr); 363 #endif 364 if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) { 365 ctx->historyh[ctx->ncurrenth] = h; 366 } 367 ctx->ncurrenth++; 368 369 /* w = u + ha */ 370 if (ctx->drscale) { 371 ierr = VecPointwiseMult(ctx->drscale,a,U);CHKERRQ(ierr); 372 ierr = VecAYPX(U,h,w);CHKERRQ(ierr); 373 } else { 374 ierr = VecWAXPY(w,h,a,U);CHKERRQ(ierr); 375 } 376 377 /* compute func(U) as base for differencing; only needed first time in and not when provided by user */ 378 if (ctx->ncurrenth == 1 && ctx->current_f_allocated) { 379 ierr = (*ctx->func)(ctx->funcctx,U,F);CHKERRQ(ierr); 380 } 381 ierr = (*ctx->func)(ctx->funcctx,w,y);CHKERRQ(ierr); 382 383 ierr = VecAXPY(y,-1.0,F);CHKERRQ(ierr); 384 ierr = VecScale(y,1.0/h);CHKERRQ(ierr); 385 386 if ((ctx->vshift != 0.0) || (ctx->vscale != 1.0)) { 387 ierr = VecAXPBY(y,ctx->vshift,ctx->vscale,a);CHKERRQ(ierr); 388 } 389 if (ctx->dlscale) { 390 ierr = VecPointwiseMult(y,ctx->dlscale,y);CHKERRQ(ierr); 391 } 392 if (ctx->dshift) { 393 if (!ctx->dshiftw) { 394 ierr = VecDuplicate(y,&ctx->dshiftw);CHKERRQ(ierr); 395 } 396 ierr = VecPointwiseMult(ctx->dshift,a,ctx->dshiftw);CHKERRQ(ierr); 397 ierr = VecAXPY(y,1.0,ctx->dshiftw);CHKERRQ(ierr); 398 } 399 400 if (mat->nullsp) {ierr = MatNullSpaceRemove(mat->nullsp,y);CHKERRQ(ierr);} 401 402 ierr = PetscLogEventEnd(MATMFFD_Mult,a,y,0,0);CHKERRQ(ierr); 403 PetscFunctionReturn(0); 404 } 405 406 /* 407 MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix 408 409 y ~= (F(u + ha) - F(u))/h, 410 where F = nonlinear function, as set by SNESSetFunction() 411 u = current iterate 412 h = difference interval 413 */ 414 PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a) 415 { 416 MatMFFD ctx = (MatMFFD)mat->data; 417 PetscScalar h,*aa,*ww,v; 418 PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON; 419 Vec w,U; 420 PetscErrorCode ierr; 421 PetscInt i,rstart,rend; 422 423 PetscFunctionBegin; 424 if (!ctx->funci) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing Functioni function"); 425 if (!ctx->funcisetbase) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing FunctioniBase function"); 426 w = ctx->w; 427 U = ctx->current_u; 428 ierr = (*ctx->func)(ctx->funcctx,U,a);CHKERRQ(ierr); 429 ierr = (*ctx->funcisetbase)(ctx->funcctx,U);CHKERRQ(ierr); 430 ierr = VecCopy(U,w);CHKERRQ(ierr); 431 432 ierr = VecGetOwnershipRange(a,&rstart,&rend);CHKERRQ(ierr); 433 ierr = VecGetArray(a,&aa);CHKERRQ(ierr); 434 for (i=rstart; i<rend; i++) { 435 ierr = VecGetArray(w,&ww);CHKERRQ(ierr); 436 h = ww[i-rstart]; 437 if (h == 0.0) h = 1.0; 438 if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin; 439 else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin; 440 h *= epsilon; 441 442 ww[i-rstart] += h; 443 ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr); 444 ierr = (*ctx->funci)(ctx->funcctx,i,w,&v);CHKERRQ(ierr); 445 aa[i-rstart] = (v - aa[i-rstart])/h; 446 447 /* possibly shift and scale result */ 448 if ((ctx->vshift != 0.0) || (ctx->vscale != 1.0)) { 449 aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart]; 450 } 451 452 ierr = VecGetArray(w,&ww);CHKERRQ(ierr); 453 ww[i-rstart] -= h; 454 ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr); 455 } 456 ierr = VecRestoreArray(a,&aa);CHKERRQ(ierr); 457 PetscFunctionReturn(0); 458 } 459 460 static PetscErrorCode MatDiagonalScale_MFFD(Mat mat,Vec ll,Vec rr) 461 { 462 MatMFFD aij = (MatMFFD)mat->data; 463 PetscErrorCode ierr; 464 465 PetscFunctionBegin; 466 if (ll && !aij->dlscale) { 467 ierr = VecDuplicate(ll,&aij->dlscale);CHKERRQ(ierr); 468 } 469 if (rr && !aij->drscale) { 470 ierr = VecDuplicate(rr,&aij->drscale);CHKERRQ(ierr); 471 } 472 if (ll) { 473 ierr = VecCopy(ll,aij->dlscale);CHKERRQ(ierr); 474 } 475 if (rr) { 476 ierr = VecCopy(rr,aij->drscale);CHKERRQ(ierr); 477 } 478 PetscFunctionReturn(0); 479 } 480 481 static PetscErrorCode MatDiagonalSet_MFFD(Mat mat,Vec ll,InsertMode mode) 482 { 483 MatMFFD aij = (MatMFFD)mat->data; 484 PetscErrorCode ierr; 485 486 PetscFunctionBegin; 487 if (mode == INSERT_VALUES) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No diagonal set with INSERT_VALUES"); 488 if (!aij->dshift) { 489 ierr = VecDuplicate(ll,&aij->dshift);CHKERRQ(ierr); 490 } 491 ierr = VecAXPY(aij->dshift,1.0,ll);CHKERRQ(ierr); 492 PetscFunctionReturn(0); 493 } 494 495 static PetscErrorCode MatShift_MFFD(Mat Y,PetscScalar a) 496 { 497 MatMFFD shell = (MatMFFD)Y->data; 498 499 PetscFunctionBegin; 500 shell->vshift += a; 501 PetscFunctionReturn(0); 502 } 503 504 static PetscErrorCode MatScale_MFFD(Mat Y,PetscScalar a) 505 { 506 MatMFFD shell = (MatMFFD)Y->data; 507 508 PetscFunctionBegin; 509 shell->vscale *= a; 510 PetscFunctionReturn(0); 511 } 512 513 PETSC_EXTERN PetscErrorCode MatMFFDSetBase_MFFD(Mat J,Vec U,Vec F) 514 { 515 PetscErrorCode ierr; 516 MatMFFD ctx = (MatMFFD)J->data; 517 518 PetscFunctionBegin; 519 ierr = MatMFFDResetHHistory(J);CHKERRQ(ierr); 520 if (!ctx->current_u) { 521 ierr = VecDuplicate(U,&ctx->current_u);CHKERRQ(ierr); 522 ierr = VecLockPush(ctx->current_u);CHKERRQ(ierr); 523 } 524 ierr = VecLockPop(ctx->current_u);CHKERRQ(ierr); 525 ierr = VecCopy(U,ctx->current_u);CHKERRQ(ierr); 526 ierr = VecLockPush(ctx->current_u);CHKERRQ(ierr); 527 if (F) { 528 if (ctx->current_f_allocated) {ierr = VecDestroy(&ctx->current_f);CHKERRQ(ierr);} 529 ctx->current_f = F; 530 ctx->current_f_allocated = PETSC_FALSE; 531 } else if (!ctx->current_f_allocated) { 532 ierr = MatCreateVecs(J,NULL,&ctx->current_f);CHKERRQ(ierr); 533 534 ctx->current_f_allocated = PETSC_TRUE; 535 } 536 if (!ctx->w) { 537 ierr = VecDuplicate(ctx->current_u,&ctx->w);CHKERRQ(ierr); 538 } 539 J->assembled = PETSC_TRUE; 540 PetscFunctionReturn(0); 541 } 542 543 typedef PetscErrorCode (*FCN3)(void*,Vec,Vec,PetscScalar*); /* force argument to next function to not be extern C*/ 544 545 static PetscErrorCode MatMFFDSetCheckh_MFFD(Mat J,FCN3 fun,void *ectx) 546 { 547 MatMFFD ctx = (MatMFFD)J->data; 548 549 PetscFunctionBegin; 550 ctx->checkh = fun; 551 ctx->checkhctx = ectx; 552 PetscFunctionReturn(0); 553 } 554 555 /*@C 556 MatMFFDSetOptionsPrefix - Sets the prefix used for searching for all 557 MatMFFD options in the database. 558 559 Collective on Mat 560 561 Input Parameter: 562 + A - the Mat context 563 - prefix - the prefix to prepend to all option names 564 565 Notes: 566 A hyphen (-) must NOT be given at the beginning of the prefix name. 567 The first character of all runtime options is AUTOMATICALLY the hyphen. 568 569 Level: advanced 570 571 .keywords: SNES, matrix-free, parameters 572 573 .seealso: MatSetFromOptions(), MatCreateSNESMF(), MatCreateMFFD() 574 @*/ 575 PetscErrorCode MatMFFDSetOptionsPrefix(Mat mat,const char prefix[]) 576 577 { 578 MatMFFD mfctx = mat ? (MatMFFD)mat->data : (MatMFFD)NULL; 579 PetscErrorCode ierr; 580 581 PetscFunctionBegin; 582 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 583 PetscValidHeaderSpecific(mfctx,MATMFFD_CLASSID,1); 584 ierr = PetscObjectSetOptionsPrefix((PetscObject)mfctx,prefix);CHKERRQ(ierr); 585 PetscFunctionReturn(0); 586 } 587 588 static PetscErrorCode MatSetFromOptions_MFFD(PetscOptionItems *PetscOptionsObject,Mat mat) 589 { 590 MatMFFD mfctx = (MatMFFD)mat->data; 591 PetscErrorCode ierr; 592 PetscBool flg; 593 char ftype[256]; 594 595 PetscFunctionBegin; 596 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 597 PetscValidHeaderSpecific(mfctx,MATMFFD_CLASSID,1); 598 ierr = PetscObjectOptionsBegin((PetscObject)mfctx);CHKERRQ(ierr); 599 ierr = PetscOptionsFList("-mat_mffd_type","Matrix free type","MatMFFDSetType",MatMFFDList,((PetscObject)mfctx)->type_name,ftype,256,&flg);CHKERRQ(ierr); 600 if (flg) { 601 ierr = MatMFFDSetType(mat,ftype);CHKERRQ(ierr); 602 } 603 604 ierr = PetscOptionsReal("-mat_mffd_err","set sqrt relative error in function","MatMFFDSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);CHKERRQ(ierr); 605 ierr = PetscOptionsInt("-mat_mffd_period","how often h is recomputed","MatMFFDSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);CHKERRQ(ierr); 606 607 flg = PETSC_FALSE; 608 ierr = PetscOptionsBool("-mat_mffd_check_positivity","Insure that U + h*a is nonnegative","MatMFFDSetCheckh",flg,&flg,NULL);CHKERRQ(ierr); 609 if (flg) { 610 ierr = MatMFFDSetCheckh(mat,MatMFFDCheckPositivity,0);CHKERRQ(ierr); 611 } 612 if (mfctx->ops->setfromoptions) { 613 ierr = (*mfctx->ops->setfromoptions)(PetscOptionsObject,mfctx);CHKERRQ(ierr); 614 } 615 ierr = PetscOptionsEnd();CHKERRQ(ierr); 616 PetscFunctionReturn(0); 617 } 618 619 static PetscErrorCode MatMFFDSetPeriod_MFFD(Mat mat,PetscInt period) 620 { 621 MatMFFD ctx = (MatMFFD)mat->data; 622 623 PetscFunctionBegin; 624 ctx->recomputeperiod = period; 625 PetscFunctionReturn(0); 626 } 627 628 static PetscErrorCode MatMFFDSetFunction_MFFD(Mat mat,PetscErrorCode (*func)(void*,Vec,Vec),void *funcctx) 629 { 630 MatMFFD ctx = (MatMFFD)mat->data; 631 632 PetscFunctionBegin; 633 ctx->func = func; 634 ctx->funcctx = funcctx; 635 PetscFunctionReturn(0); 636 } 637 638 static PetscErrorCode MatMFFDSetFunctionError_MFFD(Mat mat,PetscReal error) 639 { 640 MatMFFD ctx = (MatMFFD)mat->data; 641 642 PetscFunctionBegin; 643 if (error != PETSC_DEFAULT) ctx->error_rel = error; 644 PetscFunctionReturn(0); 645 } 646 647 static PetscErrorCode MatMissingDiagonal_MFFD(Mat A,PetscBool *missing,PetscInt *d) 648 { 649 PetscFunctionBegin; 650 *missing = PETSC_FALSE; 651 PetscFunctionReturn(0); 652 } 653 654 /*MC 655 MATMFFD - MATMFFD = "mffd" - A matrix free matrix type. 656 657 Level: advanced 658 659 .seealso: MatCreateMFFD(), MatCreateSNESMF(), MatMFFDSetFunction(), MatMFFDSetType(), 660 MatMFFDSetFunctionError(), MatMFFDDSSetUmin(), MatMFFDSetFunction() 661 MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateSNESMF(), 662 MatMFFDGetH(), 663 M*/ 664 PETSC_EXTERN PetscErrorCode MatCreate_MFFD(Mat A) 665 { 666 MatMFFD mfctx; 667 PetscErrorCode ierr; 668 669 PetscFunctionBegin; 670 ierr = MatMFFDInitializePackage();CHKERRQ(ierr); 671 672 ierr = PetscHeaderCreate(mfctx,MATMFFD_CLASSID,"MatMFFD","Matrix-free Finite Differencing","Mat",PetscObjectComm((PetscObject)A),MatDestroy_MFFD,MatView_MFFD);CHKERRQ(ierr); 673 674 mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON; 675 mfctx->recomputeperiod = 1; 676 mfctx->count = 0; 677 mfctx->currenth = 0.0; 678 mfctx->historyh = NULL; 679 mfctx->ncurrenth = 0; 680 mfctx->maxcurrenth = 0; 681 ((PetscObject)mfctx)->type_name = 0; 682 683 mfctx->vshift = 0.0; 684 mfctx->vscale = 1.0; 685 686 /* 687 Create the empty data structure to contain compute-h routines. 688 These will be filled in below from the command line options or 689 a later call with MatMFFDSetType() or if that is not called 690 then it will default in the first use of MatMult_MFFD() 691 */ 692 mfctx->ops->compute = 0; 693 mfctx->ops->destroy = 0; 694 mfctx->ops->view = 0; 695 mfctx->ops->setfromoptions = 0; 696 mfctx->hctx = 0; 697 698 mfctx->func = 0; 699 mfctx->funcctx = 0; 700 mfctx->w = NULL; 701 702 A->data = mfctx; 703 704 A->ops->mult = MatMult_MFFD; 705 A->ops->destroy = MatDestroy_MFFD; 706 A->ops->setup = MatSetUp_MFFD; 707 A->ops->view = MatView_MFFD; 708 A->ops->assemblyend = MatAssemblyEnd_MFFD; 709 A->ops->scale = MatScale_MFFD; 710 A->ops->shift = MatShift_MFFD; 711 A->ops->diagonalscale = MatDiagonalScale_MFFD; 712 A->ops->diagonalset = MatDiagonalSet_MFFD; 713 A->ops->setfromoptions = MatSetFromOptions_MFFD; 714 A->ops->missingdiagonal = MatMissingDiagonal_MFFD; 715 A->assembled = PETSC_TRUE; 716 717 ierr = PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetBase_C",MatMFFDSetBase_MFFD);CHKERRQ(ierr); 718 ierr = PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetFunctioniBase_C",MatMFFDSetFunctioniBase_MFFD);CHKERRQ(ierr); 719 ierr = PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetFunctioni_C",MatMFFDSetFunctioni_MFFD);CHKERRQ(ierr); 720 ierr = PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetFunction_C",MatMFFDSetFunction_MFFD);CHKERRQ(ierr); 721 ierr = PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetCheckh_C",MatMFFDSetCheckh_MFFD);CHKERRQ(ierr); 722 ierr = PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetPeriod_C",MatMFFDSetPeriod_MFFD);CHKERRQ(ierr); 723 ierr = PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetFunctionError_C",MatMFFDSetFunctionError_MFFD);CHKERRQ(ierr); 724 ierr = PetscObjectComposeFunction((PetscObject)A,"MatMFFDResetHHistory_C",MatMFFDResetHHistory_MFFD);CHKERRQ(ierr); 725 726 mfctx->mat = A; 727 728 ierr = PetscObjectChangeTypeName((PetscObject)A,MATMFFD);CHKERRQ(ierr); 729 PetscFunctionReturn(0); 730 } 731 732 /*@ 733 MatCreateMFFD - Creates a matrix-free matrix. See also MatCreateSNESMF() 734 735 Collective on Vec 736 737 Input Parameters: 738 + comm - MPI communicator 739 . m - number of local rows (or PETSC_DECIDE to have calculated if M is given) 740 This value should be the same as the local size used in creating the 741 y vector for the matrix-vector product y = Ax. 742 . n - This value should be the same as the local size used in creating the 743 x vector for the matrix-vector product y = Ax. (or PETSC_DECIDE to have 744 calculated if N is given) For square matrices n is almost always m. 745 . M - number of global rows (or PETSC_DETERMINE to have calculated if m is given) 746 - N - number of global columns (or PETSC_DETERMINE to have calculated if n is given) 747 748 749 Output Parameter: 750 . J - the matrix-free matrix 751 752 Options Database Keys: call MatSetFromOptions() to trigger these 753 + -mat_mffd_type - wp or ds (see MATMFFD_WP or MATMFFD_DS) 754 - -mat_mffd_err - square root of estimated relative error in function evaluation 755 - -mat_mffd_period - how often h is recomputed, defaults to 1, everytime 756 757 758 Level: advanced 759 760 Notes: 761 The matrix-free matrix context merely contains the function pointers 762 and work space for performing finite difference approximations of 763 Jacobian-vector products, F'(u)*a, 764 765 The default code uses the following approach to compute h 766 767 .vb 768 F'(u)*a = [F(u+h*a) - F(u)]/h where 769 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 770 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 771 where 772 error_rel = square root of relative error in function evaluation 773 umin = minimum iterate parameter 774 .ve 775 776 You can call SNESSetJacobian() with MatMFFDComputeJacobian() if you are using matrix and not a different 777 preconditioner matrix 778 779 The user can set the error_rel via MatMFFDSetFunctionError() and 780 umin via MatMFFDDSSetUmin(); see Users-Manual: ch_snes for details. 781 782 The user should call MatDestroy() when finished with the matrix-free 783 matrix context. 784 785 Options Database Keys: 786 + -mat_mffd_err <error_rel> - Sets error_rel 787 . -mat_mffd_unim <umin> - Sets umin (for default PETSc routine that computes h only) 788 - -mat_mffd_check_positivity 789 790 .keywords: default, matrix-free, create, matrix 791 792 .seealso: MatDestroy(), MatMFFDSetFunctionError(), MatMFFDDSSetUmin(), MatMFFDSetFunction() 793 MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateSNESMF(), 794 MatMFFDGetH(), MatMFFDRegister(), MatMFFDComputeJacobian() 795 796 @*/ 797 PetscErrorCode MatCreateMFFD(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,Mat *J) 798 { 799 PetscErrorCode ierr; 800 801 PetscFunctionBegin; 802 ierr = MatCreate(comm,J);CHKERRQ(ierr); 803 ierr = MatSetSizes(*J,m,n,M,N);CHKERRQ(ierr); 804 ierr = MatSetType(*J,MATMFFD);CHKERRQ(ierr); 805 ierr = MatSetUp(*J);CHKERRQ(ierr); 806 PetscFunctionReturn(0); 807 } 808 809 /*@ 810 MatMFFDGetH - Gets the last value that was used as the differencing 811 parameter. 812 813 Not Collective 814 815 Input Parameters: 816 . mat - the matrix obtained with MatCreateSNESMF() 817 818 Output Paramter: 819 . h - the differencing step size 820 821 Level: advanced 822 823 .keywords: SNES, matrix-free, parameters 824 825 .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(), MatCreateMFFD(), MATMFFD, MatMFFDResetHHistory() 826 @*/ 827 PetscErrorCode MatMFFDGetH(Mat mat,PetscScalar *h) 828 { 829 MatMFFD ctx = (MatMFFD)mat->data; 830 PetscErrorCode ierr; 831 PetscBool match; 832 833 PetscFunctionBegin; 834 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 835 PetscValidPointer(h,2); 836 ierr = PetscObjectTypeCompare((PetscObject)mat,MATMFFD,&match);CHKERRQ(ierr); 837 if (!match) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONG,"Not a MFFD matrix"); 838 839 *h = ctx->currenth; 840 PetscFunctionReturn(0); 841 } 842 843 /*@C 844 MatMFFDSetFunction - Sets the function used in applying the matrix free. 845 846 Logically Collective on Mat 847 848 Input Parameters: 849 + mat - the matrix free matrix created via MatCreateSNESMF() or MatCreateMFFD() 850 . func - the function to use 851 - funcctx - optional function context passed to function 852 853 Calling Sequence of func: 854 $ func (void *funcctx, Vec x, Vec f) 855 856 + funcctx - user provided context 857 . x - input vector 858 - f - computed output function 859 860 Level: advanced 861 862 Notes: 863 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 864 matrix inside your compute Jacobian routine 865 866 If this is not set then it will use the function set with SNESSetFunction() if MatCreateSNESMF() was used. 867 868 .keywords: SNES, matrix-free, function 869 870 .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD, 871 MatMFFDSetHHistory(), MatMFFDResetHHistory(), SNESetFunction() 872 @*/ 873 PetscErrorCode MatMFFDSetFunction(Mat mat,PetscErrorCode (*func)(void*,Vec,Vec),void *funcctx) 874 { 875 PetscErrorCode ierr; 876 877 PetscFunctionBegin; 878 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 879 ierr = PetscTryMethod(mat,"MatMFFDSetFunction_C",(Mat,PetscErrorCode (*)(void*,Vec,Vec),void*),(mat,func,funcctx));CHKERRQ(ierr); 880 PetscFunctionReturn(0); 881 } 882 883 /*@C 884 MatMFFDSetFunctioni - Sets the function for a single component 885 886 Logically Collective on Mat 887 888 Input Parameters: 889 + mat - the matrix free matrix created via MatCreateSNESMF() 890 - funci - the function to use 891 892 Level: advanced 893 894 Notes: 895 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 896 matrix inside your compute Jacobian routine. 897 This function is necessary to compute the diagonal of the matrix. 898 899 900 .keywords: SNES, matrix-free, function 901 902 .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatMFFDSetHHistory(), MatMFFDResetHHistory(), SNESetFunction(), MatGetDiagonal() 903 904 @*/ 905 PetscErrorCode MatMFFDSetFunctioni(Mat mat,PetscErrorCode (*funci)(void*,PetscInt,Vec,PetscScalar*)) 906 { 907 PetscErrorCode ierr; 908 909 PetscFunctionBegin; 910 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 911 ierr = PetscTryMethod(mat,"MatMFFDSetFunctioni_C",(Mat,PetscErrorCode (*)(void*,PetscInt,Vec,PetscScalar*)),(mat,funci));CHKERRQ(ierr); 912 PetscFunctionReturn(0); 913 } 914 915 /*@C 916 MatMFFDSetFunctioniBase - Sets the base vector for a single component function evaluation 917 918 Logically Collective on Mat 919 920 Input Parameters: 921 + mat - the matrix free matrix created via MatCreateSNESMF() 922 - func - the function to use 923 924 Level: advanced 925 926 Notes: 927 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 928 matrix inside your compute Jacobian routine. 929 This function is necessary to compute the diagonal of the matrix. 930 931 932 .keywords: SNES, matrix-free, function 933 934 .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD 935 MatMFFDSetHHistory(), MatMFFDResetHHistory(), SNESetFunction(), MatGetDiagonal() 936 @*/ 937 PetscErrorCode MatMFFDSetFunctioniBase(Mat mat,PetscErrorCode (*func)(void*,Vec)) 938 { 939 PetscErrorCode ierr; 940 941 PetscFunctionBegin; 942 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 943 ierr = PetscTryMethod(mat,"MatMFFDSetFunctioniBase_C",(Mat,PetscErrorCode (*)(void*,Vec)),(mat,func));CHKERRQ(ierr); 944 PetscFunctionReturn(0); 945 } 946 947 /*@ 948 MatMFFDSetPeriod - Sets how often h is recomputed, by default it is everytime 949 950 Logically Collective on Mat 951 952 Input Parameters: 953 + mat - the matrix free matrix created via MatCreateSNESMF() 954 - period - 1 for everytime, 2 for every second etc 955 956 Options Database Keys: 957 + -mat_mffd_period <period> 958 959 Level: advanced 960 961 962 .keywords: SNES, matrix-free, parameters 963 964 .seealso: MatCreateSNESMF(),MatMFFDGetH(), 965 MatMFFDSetHHistory(), MatMFFDResetHHistory() 966 @*/ 967 PetscErrorCode MatMFFDSetPeriod(Mat mat,PetscInt period) 968 { 969 PetscErrorCode ierr; 970 971 PetscFunctionBegin; 972 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 973 PetscValidLogicalCollectiveInt(mat,period,2); 974 ierr = PetscTryMethod(mat,"MatMFFDSetPeriod_C",(Mat,PetscInt),(mat,period));CHKERRQ(ierr); 975 PetscFunctionReturn(0); 976 } 977 978 /*@ 979 MatMFFDSetFunctionError - Sets the error_rel for the approximation of 980 matrix-vector products using finite differences. 981 982 Logically Collective on Mat 983 984 Input Parameters: 985 + mat - the matrix free matrix created via MatCreateMFFD() or MatCreateSNESMF() 986 - error_rel - relative error (should be set to the square root of 987 the relative error in the function evaluations) 988 989 Options Database Keys: 990 + -mat_mffd_err <error_rel> - Sets error_rel 991 992 Level: advanced 993 994 Notes: 995 The default matrix-free matrix-vector product routine computes 996 .vb 997 F'(u)*a = [F(u+h*a) - F(u)]/h where 998 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 999 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else 1000 .ve 1001 1002 .keywords: SNES, matrix-free, parameters 1003 1004 .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD 1005 MatMFFDSetHHistory(), MatMFFDResetHHistory() 1006 @*/ 1007 PetscErrorCode MatMFFDSetFunctionError(Mat mat,PetscReal error) 1008 { 1009 PetscErrorCode ierr; 1010 1011 PetscFunctionBegin; 1012 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1013 PetscValidLogicalCollectiveReal(mat,error,2); 1014 ierr = PetscTryMethod(mat,"MatMFFDSetFunctionError_C",(Mat,PetscReal),(mat,error));CHKERRQ(ierr); 1015 PetscFunctionReturn(0); 1016 } 1017 1018 /*@ 1019 MatMFFDSetHHistory - Sets an array to collect a history of the 1020 differencing values (h) computed for the matrix-free product. 1021 1022 Logically Collective on Mat 1023 1024 Input Parameters: 1025 + J - the matrix-free matrix context 1026 . histroy - space to hold the history 1027 - nhistory - number of entries in history, if more entries are generated than 1028 nhistory, then the later ones are discarded 1029 1030 Level: advanced 1031 1032 Notes: 1033 Use MatMFFDResetHHistory() to reset the history counter and collect 1034 a new batch of differencing parameters, h. 1035 1036 .keywords: SNES, matrix-free, h history, differencing history 1037 1038 .seealso: MatMFFDGetH(), MatCreateSNESMF(), 1039 MatMFFDResetHHistory(), MatMFFDSetFunctionError() 1040 1041 @*/ 1042 PetscErrorCode MatMFFDSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory) 1043 { 1044 MatMFFD ctx = (MatMFFD)J->data; 1045 PetscErrorCode ierr; 1046 PetscBool match; 1047 1048 PetscFunctionBegin; 1049 PetscValidHeaderSpecific(J,MAT_CLASSID,1); 1050 if (history) PetscValidPointer(history,2); 1051 PetscValidLogicalCollectiveInt(J,nhistory,3); 1052 ierr = PetscObjectTypeCompare((PetscObject)J,MATMFFD,&match);CHKERRQ(ierr); 1053 if (!match) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_WRONG,"Not a MFFD matrix"); 1054 ctx->historyh = history; 1055 ctx->maxcurrenth = nhistory; 1056 ctx->currenth = 0.; 1057 PetscFunctionReturn(0); 1058 } 1059 1060 /*@ 1061 MatMFFDResetHHistory - Resets the counter to zero to begin 1062 collecting a new set of differencing histories. 1063 1064 Logically Collective on Mat 1065 1066 Input Parameters: 1067 . J - the matrix-free matrix context 1068 1069 Level: advanced 1070 1071 Notes: 1072 Use MatMFFDSetHHistory() to create the original history counter. 1073 1074 .keywords: SNES, matrix-free, h history, differencing history 1075 1076 .seealso: MatMFFDGetH(), MatCreateSNESMF(), 1077 MatMFFDSetHHistory(), MatMFFDSetFunctionError() 1078 1079 @*/ 1080 PetscErrorCode MatMFFDResetHHistory(Mat J) 1081 { 1082 PetscErrorCode ierr; 1083 1084 PetscFunctionBegin; 1085 PetscValidHeaderSpecific(J,MAT_CLASSID,1); 1086 ierr = PetscTryMethod(J,"MatMFFDResetHHistory_C",(Mat),(J));CHKERRQ(ierr); 1087 PetscFunctionReturn(0); 1088 } 1089 1090 /*@ 1091 MatMFFDSetBase - Sets the vector U at which matrix vector products of the 1092 Jacobian are computed 1093 1094 Logically Collective on Mat 1095 1096 Input Parameters: 1097 + J - the MatMFFD matrix 1098 . U - the vector 1099 - F - (optional) vector that contains F(u) if it has been already computed 1100 1101 Notes: This is rarely used directly 1102 1103 If F is provided then it is not recomputed. Otherwise the function is evaluated at the base 1104 point during the first MatMult() after each call to MatMFFDSetBase(). 1105 1106 Level: advanced 1107 1108 @*/ 1109 PetscErrorCode MatMFFDSetBase(Mat J,Vec U,Vec F) 1110 { 1111 PetscErrorCode ierr; 1112 1113 PetscFunctionBegin; 1114 PetscValidHeaderSpecific(J,MAT_CLASSID,1); 1115 PetscValidHeaderSpecific(U,VEC_CLASSID,2); 1116 if (F) PetscValidHeaderSpecific(F,VEC_CLASSID,3); 1117 ierr = PetscTryMethod(J,"MatMFFDSetBase_C",(Mat,Vec,Vec),(J,U,F));CHKERRQ(ierr); 1118 PetscFunctionReturn(0); 1119 } 1120 1121 /*@C 1122 MatMFFDSetCheckh - Sets a function that checks the computed h and adjusts 1123 it to satisfy some criteria 1124 1125 Logically Collective on Mat 1126 1127 Input Parameters: 1128 + J - the MatMFFD matrix 1129 . fun - the function that checks h 1130 - ctx - any context needed by the function 1131 1132 Options Database Keys: 1133 . -mat_mffd_check_positivity 1134 1135 Level: advanced 1136 1137 Notes: For example, MatMFFDCheckPositivity() insures that all entries 1138 of U + h*a are non-negative 1139 1140 The function you provide is called after the default h has been computed and allows you to 1141 modify it. 1142 1143 .seealso: MatMFFDCheckPositivity() 1144 @*/ 1145 PetscErrorCode MatMFFDSetCheckh(Mat J,PetscErrorCode (*fun)(void*,Vec,Vec,PetscScalar*),void *ctx) 1146 { 1147 PetscErrorCode ierr; 1148 1149 PetscFunctionBegin; 1150 PetscValidHeaderSpecific(J,MAT_CLASSID,1); 1151 ierr = PetscTryMethod(J,"MatMFFDSetCheckh_C",(Mat,PetscErrorCode (*)(void*,Vec,Vec,PetscScalar*),void*),(J,fun,ctx));CHKERRQ(ierr); 1152 PetscFunctionReturn(0); 1153 } 1154 1155 /*@ 1156 MatMFFDCheckPositivity - Checks that all entries in U + h*a are positive or 1157 zero, decreases h until this is satisfied. 1158 1159 Logically Collective on Vec 1160 1161 Input Parameters: 1162 + U - base vector that is added to 1163 . a - vector that is added 1164 . h - scaling factor on a 1165 - dummy - context variable (unused) 1166 1167 Options Database Keys: 1168 . -mat_mffd_check_positivity 1169 1170 Level: advanced 1171 1172 Notes: This is rarely used directly, rather it is passed as an argument to 1173 MatMFFDSetCheckh() 1174 1175 .seealso: MatMFFDSetCheckh() 1176 @*/ 1177 PetscErrorCode MatMFFDCheckPositivity(void *dummy,Vec U,Vec a,PetscScalar *h) 1178 { 1179 PetscReal val, minval; 1180 PetscScalar *u_vec, *a_vec; 1181 PetscErrorCode ierr; 1182 PetscInt i,n; 1183 MPI_Comm comm; 1184 1185 PetscFunctionBegin; 1186 PetscValidHeaderSpecific(U,VEC_CLASSID,2); 1187 PetscValidHeaderSpecific(a,VEC_CLASSID,3); 1188 PetscValidPointer(h,4); 1189 ierr = PetscObjectGetComm((PetscObject)U,&comm);CHKERRQ(ierr); 1190 ierr = VecGetArray(U,&u_vec);CHKERRQ(ierr); 1191 ierr = VecGetArray(a,&a_vec);CHKERRQ(ierr); 1192 ierr = VecGetLocalSize(U,&n);CHKERRQ(ierr); 1193 minval = PetscAbsScalar(*h*1.01); 1194 for (i=0; i<n; i++) { 1195 if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) { 1196 val = PetscAbsScalar(u_vec[i]/a_vec[i]); 1197 if (val < minval) minval = val; 1198 } 1199 } 1200 ierr = VecRestoreArray(U,&u_vec);CHKERRQ(ierr); 1201 ierr = VecRestoreArray(a,&a_vec);CHKERRQ(ierr); 1202 ierr = MPIU_Allreduce(&minval,&val,1,MPIU_REAL,MPIU_MIN,comm);CHKERRQ(ierr); 1203 if (val <= PetscAbsScalar(*h)) { 1204 ierr = PetscInfo2(U,"Scaling back h from %g to %g\n",(double)PetscRealPart(*h),(double)(.99*val));CHKERRQ(ierr); 1205 if (PetscRealPart(*h) > 0.0) *h = 0.99*val; 1206 else *h = -0.99*val; 1207 } 1208 PetscFunctionReturn(0); 1209 } 1210