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