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