1 /* 2 Code for timestepping with Rosenbrock W methods 3 4 Notes: 5 The general system is written as 6 7 G(t,X,Xdot) = F(t,X) 8 9 where G represents the stiff part of the physics and F represents the non-stiff part. 10 This method is designed to be linearly implicit on G and can use an approximate and lagged Jacobian. 11 12 */ 13 #include <private/tsimpl.h> /*I "petscts.h" I*/ 14 15 #include <../src/mat/blockinvert.h> 16 17 static const TSRosWType TSRosWDefault = TSROSW2P; 18 static PetscBool TSRosWRegisterAllCalled; 19 static PetscBool TSRosWPackageInitialized; 20 21 typedef struct _RosWTableau *RosWTableau; 22 struct _RosWTableau { 23 char *name; 24 PetscInt order; /* Classical approximation order of the method */ 25 PetscInt s; /* Number of stages */ 26 PetscInt pinterp; /* Interpolation order */ 27 PetscReal *A; /* Propagation table, strictly lower triangular */ 28 PetscReal *Gamma; /* Stage table, lower triangular with nonzero diagonal */ 29 PetscReal *b; /* Step completion table */ 30 PetscReal *ASum; /* Row sum of A */ 31 PetscReal *GammaSum; /* Row sum of Gamma, only needed for non-autonomous systems */ 32 PetscReal *At; /* Propagation table in transformed variables */ 33 PetscReal *bt; /* Step completion table in transformed variables */ 34 PetscReal *GammaInv; /* Inverse of Gamma, used for transformed variables */ 35 }; 36 typedef struct _RosWTableauLink *RosWTableauLink; 37 struct _RosWTableauLink { 38 struct _RosWTableau tab; 39 RosWTableauLink next; 40 }; 41 static RosWTableauLink RosWTableauList; 42 43 typedef struct { 44 RosWTableau tableau; 45 Vec *Y; /* States computed during the step, used to complete the step */ 46 Vec Ydot; /* Work vector holding Ydot during residual evaluation */ 47 Vec Ystage; /* Work vector for the state value at each stage */ 48 Vec Zdot; /* Ydot = Zdot + shift*Y */ 49 Vec Zstage; /* Y = Zstage + Y */ 50 PetscScalar *work; /* Scalar work */ 51 PetscReal shift; 52 PetscReal stage_time; 53 PetscBool recompute_jacobian; /* Recompute the Jacobian at each stage, default is to freeze the Jacobian at the start of each step */ 54 } TS_RosW; 55 56 #undef __FUNCT__ 57 #define __FUNCT__ "TSRosWRegisterAll" 58 /*@C 59 TSRosWRegisterAll - Registers all of the additive Runge-Kutta implicit-explicit methods in TSRosW 60 61 Not Collective, but should be called by all processes which will need the schemes to be registered 62 63 Level: advanced 64 65 .keywords: TS, TSRosW, register, all 66 67 .seealso: TSRosWRegisterDestroy() 68 @*/ 69 PetscErrorCode TSRosWRegisterAll(void) 70 { 71 PetscErrorCode ierr; 72 73 PetscFunctionBegin; 74 if (TSRosWRegisterAllCalled) PetscFunctionReturn(0); 75 TSRosWRegisterAllCalled = PETSC_TRUE; 76 77 { 78 const PetscReal g = 1. + 1./PetscSqrtReal(2.0); 79 const PetscReal 80 A[2][2] = {{0,0}, {1.,0}}, 81 Gamma[2][2] = {{g,0}, {-2.*g,g}}, 82 b[2] = {0.5,0.5}; 83 ierr = TSRosWRegister(TSROSW2P,2,2,&A[0][0],&Gamma[0][0],b);CHKERRQ(ierr); 84 } 85 { 86 const PetscReal g = 1. - 1./PetscSqrtReal(2.0); 87 const PetscReal 88 A[2][2] = {{0,0}, {1.,0}}, 89 Gamma[2][2] = {{g,0}, {-2.*g,g}}, 90 b[2] = {0.5,0.5}; 91 ierr = TSRosWRegister(TSROSW2M,2,2,&A[0][0],&Gamma[0][0],b);CHKERRQ(ierr); 92 } 93 PetscFunctionReturn(0); 94 } 95 96 #undef __FUNCT__ 97 #define __FUNCT__ "TSRosWRegisterDestroy" 98 /*@C 99 TSRosWRegisterDestroy - Frees the list of schemes that were registered by TSRosWRegister(). 100 101 Not Collective 102 103 Level: advanced 104 105 .keywords: TSRosW, register, destroy 106 .seealso: TSRosWRegister(), TSRosWRegisterAll(), TSRosWRegisterDynamic() 107 @*/ 108 PetscErrorCode TSRosWRegisterDestroy(void) 109 { 110 PetscErrorCode ierr; 111 RosWTableauLink link; 112 113 PetscFunctionBegin; 114 while ((link = RosWTableauList)) { 115 RosWTableau t = &link->tab; 116 RosWTableauList = link->next; 117 ierr = PetscFree5(t->A,t->Gamma,t->b,t->ASum,t->GammaSum);CHKERRQ(ierr); 118 ierr = PetscFree3(t->At,t->bt,t->GammaInv);CHKERRQ(ierr); 119 ierr = PetscFree(t->name);CHKERRQ(ierr); 120 ierr = PetscFree(link);CHKERRQ(ierr); 121 } 122 TSRosWRegisterAllCalled = PETSC_FALSE; 123 PetscFunctionReturn(0); 124 } 125 126 #undef __FUNCT__ 127 #define __FUNCT__ "TSRosWInitializePackage" 128 /*@C 129 TSRosWInitializePackage - This function initializes everything in the TSRosW package. It is called 130 from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to TSCreate_RosW() 131 when using static libraries. 132 133 Input Parameter: 134 path - The dynamic library path, or PETSC_NULL 135 136 Level: developer 137 138 .keywords: TS, TSRosW, initialize, package 139 .seealso: PetscInitialize() 140 @*/ 141 PetscErrorCode TSRosWInitializePackage(const char path[]) 142 { 143 PetscErrorCode ierr; 144 145 PetscFunctionBegin; 146 if (TSRosWPackageInitialized) PetscFunctionReturn(0); 147 TSRosWPackageInitialized = PETSC_TRUE; 148 ierr = TSRosWRegisterAll();CHKERRQ(ierr); 149 ierr = PetscRegisterFinalize(TSRosWFinalizePackage);CHKERRQ(ierr); 150 PetscFunctionReturn(0); 151 } 152 153 #undef __FUNCT__ 154 #define __FUNCT__ "TSRosWFinalizePackage" 155 /*@C 156 TSRosWFinalizePackage - This function destroys everything in the TSRosW package. It is 157 called from PetscFinalize(). 158 159 Level: developer 160 161 .keywords: Petsc, destroy, package 162 .seealso: PetscFinalize() 163 @*/ 164 PetscErrorCode TSRosWFinalizePackage(void) 165 { 166 PetscErrorCode ierr; 167 168 PetscFunctionBegin; 169 TSRosWPackageInitialized = PETSC_FALSE; 170 ierr = TSRosWRegisterDestroy();CHKERRQ(ierr); 171 PetscFunctionReturn(0); 172 } 173 174 #undef __FUNCT__ 175 #define __FUNCT__ "TSRosWRegister" 176 /*@C 177 TSRosWRegister - register a Rosenbrock W scheme by providing the entries in the Butcher tableau and optionally embedded approximations and interpolation 178 179 Not Collective, but the same schemes should be registered on all processes on which they will be used 180 181 Input Parameters: 182 + name - identifier for method 183 . order - approximation order of method 184 . s - number of stages, this is the dimension of the matrices below 185 . A - Table of propagated stage coefficients (dimension s*s, row-major), strictly lower triangular 186 . Gamma - Table of coefficients in implicit stage equations (dimension s*s, row-major), lower triangular with nonzero diagonal 187 - b - Step completion table (dimension s) 188 189 Notes: 190 Several Rosenbrock W methods are provided, this function is only needed to create new methods. 191 192 Level: advanced 193 194 .keywords: TS, register 195 196 .seealso: TSRosW 197 @*/ 198 PetscErrorCode TSRosWRegister(const TSRosWType name,PetscInt order,PetscInt s, 199 const PetscReal A[],const PetscReal Gamma[],const PetscReal b[]) 200 { 201 PetscErrorCode ierr; 202 RosWTableauLink link; 203 RosWTableau t; 204 PetscInt i,j,k; 205 PetscScalar *GammaInv; 206 207 PetscFunctionBegin; 208 ierr = PetscMalloc(sizeof(*link),&link);CHKERRQ(ierr); 209 ierr = PetscMemzero(link,sizeof(*link));CHKERRQ(ierr); 210 t = &link->tab; 211 ierr = PetscStrallocpy(name,&t->name);CHKERRQ(ierr); 212 t->order = order; 213 t->s = s; 214 ierr = PetscMalloc5(s*s,PetscReal,&t->A,s*s,PetscReal,&t->Gamma,s,PetscReal,&t->b,s,PetscReal,&t->ASum,s,PetscReal,&t->GammaSum);CHKERRQ(ierr); 215 ierr = PetscMalloc3(s*s,PetscReal,&t->At,s,PetscReal,&t->bt,s*s,PetscReal,&t->GammaInv);CHKERRQ(ierr); 216 ierr = PetscMemcpy(t->A,A,s*s*sizeof(A[0]));CHKERRQ(ierr); 217 ierr = PetscMemcpy(t->Gamma,Gamma,s*s*sizeof(Gamma[0]));CHKERRQ(ierr); 218 ierr = PetscMemcpy(t->b,b,s*sizeof(b[0]));CHKERRQ(ierr); 219 for (i=0; i<s; i++) { 220 t->ASum[i] = 0; 221 t->GammaSum[i] = 0; 222 for (j=0; j<s; j++) { 223 t->ASum[i] += A[i*s+j]; 224 t->GammaSum[i] = Gamma[i*s+j]; 225 } 226 } 227 ierr = PetscMalloc(s*s*sizeof(PetscScalar),&GammaInv);CHKERRQ(ierr); /* Need to use Scalar for inverse, then convert back to Real */ 228 for (i=0; i<s*s; i++) GammaInv[i] = Gamma[i]; 229 switch (s) { 230 case 1: GammaInv[0] = 1./GammaInv[0]; break; 231 case 2: ierr = Kernel_A_gets_inverse_A_2(GammaInv,0);CHKERRQ(ierr); break; 232 case 3: ierr = Kernel_A_gets_inverse_A_3(GammaInv,0);CHKERRQ(ierr); break; 233 case 4: ierr = Kernel_A_gets_inverse_A_4(GammaInv,0);CHKERRQ(ierr); break; 234 case 5: { 235 PetscInt ipvt5[5]; 236 MatScalar work5[5*5]; 237 ierr = Kernel_A_gets_inverse_A_5(GammaInv,ipvt5,work5,0);CHKERRQ(ierr); break; 238 } 239 case 6: ierr = Kernel_A_gets_inverse_A_6(GammaInv,0);CHKERRQ(ierr); break; 240 case 7: ierr = Kernel_A_gets_inverse_A_7(GammaInv,0);CHKERRQ(ierr); break; 241 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not implemented for %D stages",s); 242 } 243 for (i=0; i<s*s; i++) t->GammaInv[i] = PetscRealPart(GammaInv[i]); 244 ierr = PetscFree(GammaInv);CHKERRQ(ierr); 245 for (i=0; i<s; i++) { 246 for (j=0; j<s; j++) { 247 t->At[i*s+j] = 0; 248 for (k=0; k<s; k++) { 249 t->At[i*s+j] += t->A[i*s+k] * t->GammaInv[k*s+j]; 250 } 251 } 252 t->bt[i] = 0; 253 for (j=0; j<s; j++) { 254 t->bt[i] += t->b[j] * t->GammaInv[j*s+i]; 255 } 256 } 257 link->next = RosWTableauList; 258 RosWTableauList = link; 259 PetscFunctionReturn(0); 260 } 261 262 #undef __FUNCT__ 263 #define __FUNCT__ "TSStep_RosW" 264 static PetscErrorCode TSStep_RosW(TS ts) 265 { 266 TS_RosW *ros = (TS_RosW*)ts->data; 267 RosWTableau tab = ros->tableau; 268 const PetscInt s = tab->s; 269 const PetscReal *At = tab->At,*Gamma = tab->Gamma,*bt = tab->bt,*ASum = tab->ASum,*GammaInv = tab->GammaInv; 270 PetscScalar *w = ros->work; 271 Vec *Y = ros->Y,Zdot = ros->Zdot,Zstage = ros->Zstage; 272 SNES snes; 273 PetscInt i,j,its,lits; 274 PetscReal next_time_step; 275 PetscReal h,t; 276 PetscErrorCode ierr; 277 278 PetscFunctionBegin; 279 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 280 next_time_step = ts->time_step; 281 h = ts->time_step; 282 t = ts->ptime; 283 284 for (i=0; i<s; i++) { 285 ros->stage_time = t + h*ASum[i]; 286 ros->shift = 1./(h*Gamma[i*s+i]); 287 288 ierr = VecCopy(ts->vec_sol,Zstage);CHKERRQ(ierr); 289 ierr = VecMAXPY(Zstage,i,&At[i*s+0],Y);CHKERRQ(ierr); 290 291 for (j=0; j<i; j++) w[j] = 1./h * GammaInv[i*s+j]; 292 ierr = VecZeroEntries(Zdot);CHKERRQ(ierr); 293 ierr = VecMAXPY(Zdot,i,w,Y);CHKERRQ(ierr); 294 295 /* Initial guess taken from last stage */ 296 ierr = VecZeroEntries(Y[i]);CHKERRQ(ierr); 297 298 if (!ros->recompute_jacobian && !i) { 299 ierr = SNESSetLagJacobian(snes,-2);CHKERRQ(ierr); /* Recompute the Jacobian on this solve, but not again */ 300 } 301 302 ierr = SNESSolve(snes,PETSC_NULL,Y[i]);CHKERRQ(ierr); 303 ierr = SNESGetIterationNumber(snes,&its);CHKERRQ(ierr); 304 ierr = SNESGetLinearSolveIterations(snes,&lits);CHKERRQ(ierr); 305 ts->nonlinear_its += its; ts->linear_its += lits; 306 } 307 ierr = VecMAXPY(ts->vec_sol,s,bt,Y);CHKERRQ(ierr); 308 309 ts->ptime += ts->time_step; 310 ts->time_step = next_time_step; 311 ts->steps++; 312 PetscFunctionReturn(0); 313 } 314 315 #undef __FUNCT__ 316 #define __FUNCT__ "TSInterpolate_RosW" 317 static PetscErrorCode TSInterpolate_RosW(TS ts,PetscReal itime,Vec X) 318 { 319 TS_RosW *ros = (TS_RosW*)ts->data; 320 321 PetscFunctionBegin; 322 SETERRQ1(((PetscObject)ts)->comm,PETSC_ERR_SUP,"TSRosW %s does not have an interpolation formula",ros->tableau->name); 323 PetscFunctionReturn(0); 324 } 325 326 /*------------------------------------------------------------*/ 327 #undef __FUNCT__ 328 #define __FUNCT__ "TSReset_RosW" 329 static PetscErrorCode TSReset_RosW(TS ts) 330 { 331 TS_RosW *ros = (TS_RosW*)ts->data; 332 PetscInt s; 333 PetscErrorCode ierr; 334 335 PetscFunctionBegin; 336 if (!ros->tableau) PetscFunctionReturn(0); 337 s = ros->tableau->s; 338 ierr = VecDestroyVecs(s,&ros->Y);CHKERRQ(ierr); 339 ierr = VecDestroy(&ros->Ydot);CHKERRQ(ierr); 340 ierr = VecDestroy(&ros->Ystage);CHKERRQ(ierr); 341 ierr = VecDestroy(&ros->Zdot);CHKERRQ(ierr); 342 ierr = VecDestroy(&ros->Zstage);CHKERRQ(ierr); 343 ierr = PetscFree(ros->work);CHKERRQ(ierr); 344 PetscFunctionReturn(0); 345 } 346 347 #undef __FUNCT__ 348 #define __FUNCT__ "TSDestroy_RosW" 349 static PetscErrorCode TSDestroy_RosW(TS ts) 350 { 351 PetscErrorCode ierr; 352 353 PetscFunctionBegin; 354 ierr = TSReset_RosW(ts);CHKERRQ(ierr); 355 ierr = PetscFree(ts->data);CHKERRQ(ierr); 356 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWGetType_C","",PETSC_NULL);CHKERRQ(ierr); 357 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetType_C","",PETSC_NULL);CHKERRQ(ierr); 358 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetRecomputeJacobian_C","",PETSC_NULL);CHKERRQ(ierr); 359 PetscFunctionReturn(0); 360 } 361 362 /* 363 This defines the nonlinear equation that is to be solved with SNES 364 G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0 365 */ 366 #undef __FUNCT__ 367 #define __FUNCT__ "SNESTSFormFunction_RosW" 368 static PetscErrorCode SNESTSFormFunction_RosW(SNES snes,Vec X,Vec F,TS ts) 369 { 370 TS_RosW *ros = (TS_RosW*)ts->data; 371 PetscErrorCode ierr; 372 373 PetscFunctionBegin; 374 ierr = VecWAXPY(ros->Ydot,ros->shift,X,ros->Zdot);CHKERRQ(ierr); /* Ydot = shift*X + Zdot */ 375 ierr = VecWAXPY(ros->Ystage,1.0,X,ros->Zstage);CHKERRQ(ierr); /* Ystage = X + Zstage */ 376 ierr = TSComputeIFunction(ts,ros->stage_time,ros->Ystage,ros->Ydot,F,PETSC_FALSE);CHKERRQ(ierr); 377 PetscFunctionReturn(0); 378 } 379 380 #undef __FUNCT__ 381 #define __FUNCT__ "SNESTSFormJacobian_RosW" 382 static PetscErrorCode SNESTSFormJacobian_RosW(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *str,TS ts) 383 { 384 TS_RosW *ros = (TS_RosW*)ts->data; 385 PetscErrorCode ierr; 386 387 PetscFunctionBegin; 388 /* ros->Ydot and ros->Ystage have already been computed in SNESTSFormFunction_RosW (SNES guarantees this) */ 389 ierr = TSComputeIJacobian(ts,ros->stage_time,ros->Ystage,ros->Ydot,ros->shift,A,B,str,PETSC_TRUE);CHKERRQ(ierr); 390 PetscFunctionReturn(0); 391 } 392 393 #undef __FUNCT__ 394 #define __FUNCT__ "TSSetUp_RosW" 395 static PetscErrorCode TSSetUp_RosW(TS ts) 396 { 397 TS_RosW *ros = (TS_RosW*)ts->data; 398 RosWTableau tab = ros->tableau; 399 PetscInt s = tab->s; 400 PetscErrorCode ierr; 401 402 PetscFunctionBegin; 403 if (!ros->tableau) { 404 ierr = TSRosWSetType(ts,TSRosWDefault);CHKERRQ(ierr); 405 } 406 ierr = VecDuplicateVecs(ts->vec_sol,s,&ros->Y);CHKERRQ(ierr); 407 ierr = VecDuplicate(ts->vec_sol,&ros->Ydot);CHKERRQ(ierr); 408 ierr = VecDuplicate(ts->vec_sol,&ros->Ystage);CHKERRQ(ierr); 409 ierr = VecDuplicate(ts->vec_sol,&ros->Zdot);CHKERRQ(ierr); 410 ierr = VecDuplicate(ts->vec_sol,&ros->Zstage);CHKERRQ(ierr); 411 ierr = PetscMalloc(s*sizeof(ros->work[0]),&ros->work);CHKERRQ(ierr); 412 PetscFunctionReturn(0); 413 } 414 /*------------------------------------------------------------*/ 415 416 #undef __FUNCT__ 417 #define __FUNCT__ "TSSetFromOptions_RosW" 418 static PetscErrorCode TSSetFromOptions_RosW(TS ts) 419 { 420 TS_RosW *ros = (TS_RosW*)ts->data; 421 PetscErrorCode ierr; 422 char rostype[256]; 423 424 PetscFunctionBegin; 425 ierr = PetscOptionsHead("RosW ODE solver options");CHKERRQ(ierr); 426 { 427 RosWTableauLink link; 428 PetscInt count,choice; 429 PetscBool flg; 430 const char **namelist; 431 SNES snes; 432 433 ierr = PetscStrncpy(rostype,TSRosWDefault,sizeof rostype);CHKERRQ(ierr); 434 for (link=RosWTableauList,count=0; link; link=link->next,count++) ; 435 ierr = PetscMalloc(count*sizeof(char*),&namelist);CHKERRQ(ierr); 436 for (link=RosWTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name; 437 ierr = PetscOptionsEList("-ts_rosw_type","Family of Rosenbrock-W method","TSRosWSetType",(const char*const*)namelist,count,rostype,&choice,&flg);CHKERRQ(ierr); 438 ierr = TSRosWSetType(ts,flg ? namelist[choice] : rostype);CHKERRQ(ierr); 439 ierr = PetscFree(namelist);CHKERRQ(ierr); 440 441 ierr = PetscOptionsBool("-ts_rosw_recompute_jacobian","Recompute the Jacobian at each stage","TSRosWSetRecomputeJacobian",ros->recompute_jacobian,&ros->recompute_jacobian,PETSC_NULL);CHKERRQ(ierr); 442 443 /* Rosenbrock methods are linearly implicit, so set that unless the user has specifically asked for something else */ 444 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 445 if (!((PetscObject)snes)->type_name) { 446 ierr = SNESSetType(snes,SNESKSPONLY);CHKERRQ(ierr); 447 } 448 ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); 449 } 450 ierr = PetscOptionsTail();CHKERRQ(ierr); 451 PetscFunctionReturn(0); 452 } 453 454 #undef __FUNCT__ 455 #define __FUNCT__ "PetscFormatRealArray" 456 static PetscErrorCode PetscFormatRealArray(char buf[],size_t len,const char *fmt,PetscInt n,const PetscReal x[]) 457 { 458 PetscErrorCode ierr; 459 PetscInt i; 460 size_t left,count; 461 char *p; 462 463 PetscFunctionBegin; 464 for (i=0,p=buf,left=len; i<n; i++) { 465 ierr = PetscSNPrintfCount(p,left,fmt,&count,x[i]);CHKERRQ(ierr); 466 if (count >= left) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Insufficient space in buffer"); 467 left -= count; 468 p += count; 469 *p++ = ' '; 470 } 471 p[i ? 0 : -1] = 0; 472 PetscFunctionReturn(0); 473 } 474 475 #undef __FUNCT__ 476 #define __FUNCT__ "TSView_RosW" 477 static PetscErrorCode TSView_RosW(TS ts,PetscViewer viewer) 478 { 479 TS_RosW *ros = (TS_RosW*)ts->data; 480 RosWTableau tab = ros->tableau; 481 PetscBool iascii; 482 PetscErrorCode ierr; 483 484 PetscFunctionBegin; 485 ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 486 if (iascii) { 487 const TSRosWType rostype; 488 PetscInt i; 489 PetscReal abscissa[512]; 490 char buf[512]; 491 ierr = TSRosWGetType(ts,&rostype);CHKERRQ(ierr); 492 ierr = PetscViewerASCIIPrintf(viewer," Rosenbrock-W %s\n",rostype);CHKERRQ(ierr); 493 ierr = PetscFormatRealArray(buf,sizeof buf,"% 8.6f",tab->s,tab->ASum);CHKERRQ(ierr); 494 ierr = PetscViewerASCIIPrintf(viewer," Abscissa of A = %s\n",buf);CHKERRQ(ierr); 495 for (i=0; i<tab->s; i++) abscissa[i] = tab->ASum[i] + tab->Gamma[i]; 496 ierr = PetscFormatRealArray(buf,sizeof buf,"% 8.6f",tab->s,abscissa);CHKERRQ(ierr); 497 ierr = PetscViewerASCIIPrintf(viewer," Abscissa of A+Gamma = %s\n",buf);CHKERRQ(ierr); 498 } 499 ierr = SNESView(ts->snes,viewer);CHKERRQ(ierr); 500 PetscFunctionReturn(0); 501 } 502 503 #undef __FUNCT__ 504 #define __FUNCT__ "TSRosWSetType" 505 /*@C 506 TSRosWSetType - Set the type of Rosenbrock-W scheme 507 508 Logically collective 509 510 Input Parameter: 511 + ts - timestepping context 512 - rostype - type of Rosenbrock-W scheme 513 514 Level: intermediate 515 516 .seealso: TSRosWGetType() 517 @*/ 518 PetscErrorCode TSRosWSetType(TS ts,const TSRosWType rostype) 519 { 520 PetscErrorCode ierr; 521 522 PetscFunctionBegin; 523 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 524 ierr = PetscTryMethod(ts,"TSRosWSetType_C",(TS,const TSRosWType),(ts,rostype));CHKERRQ(ierr); 525 PetscFunctionReturn(0); 526 } 527 528 #undef __FUNCT__ 529 #define __FUNCT__ "TSRosWGetType" 530 /*@C 531 TSRosWGetType - Get the type of Rosenbrock-W scheme 532 533 Logically collective 534 535 Input Parameter: 536 . ts - timestepping context 537 538 Output Parameter: 539 . rostype - type of Rosenbrock-W scheme 540 541 Level: intermediate 542 543 .seealso: TSRosWGetType() 544 @*/ 545 PetscErrorCode TSRosWGetType(TS ts,const TSRosWType *rostype) 546 { 547 PetscErrorCode ierr; 548 549 PetscFunctionBegin; 550 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 551 ierr = PetscUseMethod(ts,"TSRosWGetType_C",(TS,const TSRosWType*),(ts,rostype));CHKERRQ(ierr); 552 PetscFunctionReturn(0); 553 } 554 555 #undef __FUNCT__ 556 #define __FUNCT__ "TSRosWSetRecomputeJacobian" 557 /*@C 558 TSRosWSetRecomputeJacobian - Set whether to recompute the Jacobian at each stage. The default is to update the Jacobian once per step. 559 560 Logically collective 561 562 Input Parameter: 563 + ts - timestepping context 564 - flg - PETSC_TRUE to recompute the Jacobian at each stage 565 566 Level: intermediate 567 568 .seealso: TSRosWGetType() 569 @*/ 570 PetscErrorCode TSRosWSetRecomputeJacobian(TS ts,PetscBool flg) 571 { 572 PetscErrorCode ierr; 573 574 PetscFunctionBegin; 575 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 576 ierr = PetscTryMethod(ts,"TSRosWSetRecomputeJacobian_C",(TS,PetscBool),(ts,flg));CHKERRQ(ierr); 577 PetscFunctionReturn(0); 578 } 579 580 EXTERN_C_BEGIN 581 #undef __FUNCT__ 582 #define __FUNCT__ "TSRosWGetType_RosW" 583 PetscErrorCode TSRosWGetType_RosW(TS ts,const TSRosWType *rostype) 584 { 585 TS_RosW *ros = (TS_RosW*)ts->data; 586 PetscErrorCode ierr; 587 588 PetscFunctionBegin; 589 if (!ros->tableau) {ierr = TSRosWSetType(ts,TSRosWDefault);CHKERRQ(ierr);} 590 *rostype = ros->tableau->name; 591 PetscFunctionReturn(0); 592 } 593 #undef __FUNCT__ 594 #define __FUNCT__ "TSRosWSetType_RosW" 595 PetscErrorCode TSRosWSetType_RosW(TS ts,const TSRosWType rostype) 596 { 597 TS_RosW *ros = (TS_RosW*)ts->data; 598 PetscErrorCode ierr; 599 PetscBool match; 600 RosWTableauLink link; 601 602 PetscFunctionBegin; 603 if (ros->tableau) { 604 ierr = PetscStrcmp(ros->tableau->name,rostype,&match);CHKERRQ(ierr); 605 if (match) PetscFunctionReturn(0); 606 } 607 for (link = RosWTableauList; link; link=link->next) { 608 ierr = PetscStrcmp(link->tab.name,rostype,&match);CHKERRQ(ierr); 609 if (match) { 610 ierr = TSReset_RosW(ts);CHKERRQ(ierr); 611 ros->tableau = &link->tab; 612 PetscFunctionReturn(0); 613 } 614 } 615 SETERRQ1(((PetscObject)ts)->comm,PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",rostype); 616 PetscFunctionReturn(0); 617 } 618 619 #undef __FUNCT__ 620 #define __FUNCT__ "TSRosWSetRecomputeJacobian_RosW" 621 PetscErrorCode TSRosWSetRecomputeJacobian_RosW(TS ts,PetscBool flg) 622 { 623 TS_RosW *ros = (TS_RosW*)ts->data; 624 625 PetscFunctionBegin; 626 ros->recompute_jacobian = flg; 627 PetscFunctionReturn(0); 628 } 629 EXTERN_C_END 630 631 /* ------------------------------------------------------------ */ 632 /*MC 633 TSRosW - ODE solver using Rosenbrock-W schemes 634 635 These methods are intended for problems with well-separated time scales, especially when a slow scale is strongly 636 nonlinear such that it is expensive to solve with a fully implicit method. The user should provide the stiff part 637 of the equation using TSSetIFunction() and the non-stiff part with TSSetRHSFunction(). 638 639 Notes: 640 This method currently only works with autonomous ODE and DAE. 641 642 Developer notes: 643 Rosenbrock-W methods are typically specified for autonomous ODE 644 645 $ xdot = f(x) 646 647 by the stage equations 648 649 $ k_i = h f(x_0 + sum_j alpha_ij k_j) + h J sum_j gamma_ij k_j 650 651 and step completion formula 652 653 $ x_1 = x_0 + sum_j b_j k_j 654 655 with step size h and coefficients alpha_ij, gamma_ij, and b_i. Implementing the method in this form would require f(x) 656 and the Jacobian J to be available, in addition to the shifted matrix I - h gamma_ii J. Following Hairer and Wanner, 657 we define new variables for the stage equations 658 659 $ y_i = gamma_ij k_j 660 661 The k_j can be recovered because Gamma is invertible. Let C be the lower triangular part of Gamma^{-1} and define 662 663 $ A = Alpha Gamma^{-1}, bt^T = b^T Gamma^{-i} 664 665 to rewrite the method as 666 667 $ [M/(h gamma_ii) - J] y_i = f(x_0 + sum_j a_ij y_j) + M sum_j (c_ij/h) y_j 668 $ x_1 = x_0 + sum_j bt_j y_j 669 670 where we have introduced the mass matrix M. Continue by defining 671 672 $ ydot_i = 1/(h gamma_ii) y_i - sum_j (c_ij/h) y_j 673 674 or, more compactly in tensor notation 675 676 $ Ydot = 1/h (Gamma^{-1} \otimes I) Y . 677 678 Note that Gamma^{-1} is lower triangular. With this definition of Ydot in terms of known quantities and the current 679 stage y_i, the stage equations reduce to performing one Newton step (typically with a lagged Jacobian) on the 680 equation 681 682 $ g(x_0 + sum_j a_ij y_j + y_i, ydot_i) = 0 683 684 with initial guess y_i = 0. 685 686 Level: beginner 687 688 .seealso: TSCreate(), TS, TSSetType(), TSRosWRegister() 689 690 M*/ 691 EXTERN_C_BEGIN 692 #undef __FUNCT__ 693 #define __FUNCT__ "TSCreate_RosW" 694 PetscErrorCode TSCreate_RosW(TS ts) 695 { 696 TS_RosW *ros; 697 PetscErrorCode ierr; 698 699 PetscFunctionBegin; 700 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES) 701 ierr = TSRosWInitializePackage(PETSC_NULL);CHKERRQ(ierr); 702 #endif 703 704 ts->ops->reset = TSReset_RosW; 705 ts->ops->destroy = TSDestroy_RosW; 706 ts->ops->view = TSView_RosW; 707 ts->ops->setup = TSSetUp_RosW; 708 ts->ops->step = TSStep_RosW; 709 ts->ops->interpolate = TSInterpolate_RosW; 710 ts->ops->setfromoptions = TSSetFromOptions_RosW; 711 ts->ops->snesfunction = SNESTSFormFunction_RosW; 712 ts->ops->snesjacobian = SNESTSFormJacobian_RosW; 713 714 ierr = PetscNewLog(ts,TS_RosW,&ros);CHKERRQ(ierr); 715 ts->data = (void*)ros; 716 717 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWGetType_C","TSRosWGetType_RosW",TSRosWGetType_RosW);CHKERRQ(ierr); 718 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetType_C","TSRosWSetType_RosW",TSRosWSetType_RosW);CHKERRQ(ierr); 719 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetRecomputeJacobian_C","TSRosWSetRecomputeJacobian_RosW",TSRosWSetRecomputeJacobian_RosW);CHKERRQ(ierr); 720 PetscFunctionReturn(0); 721 } 722 EXTERN_C_END 723