1 /* 2 Code for timestepping with implicit Runge-Kutta method 3 4 Notes: 5 The general system is written as 6 7 F(t,U,Udot) = 0 8 9 */ 10 #include <petsc/private/tsimpl.h> /*I "petscts.h" I*/ 11 #include <petscdm.h> 12 #include <petscdt.h> 13 14 static TSIRKType TSIRKDefault = TSIRKGAUSS; 15 static PetscBool TSIRKRegisterAllCalled; 16 static PetscBool TSIRKPackageInitialized; 17 static PetscFunctionList TSIRKList; 18 19 struct _IRKTableau{ 20 PetscReal *A,*b,*c; 21 PetscScalar *A_inv,*A_inv_rowsum,*I_s; 22 PetscReal *binterp; /* Dense output formula */ 23 }; 24 25 typedef struct _IRKTableau *IRKTableau; 26 27 typedef struct { 28 char *method_name; 29 PetscInt order; /* Classical approximation order of the method */ 30 PetscInt nstages; /* Number of stages */ 31 PetscBool stiffly_accurate; 32 PetscInt pinterp; /* Interpolation order */ 33 IRKTableau tableau; 34 Vec U0; /* Backup vector */ 35 Vec Z; /* Combined stage vector */ 36 Vec *Y; /* States computed during the step */ 37 Vec Ydot; /* Work vector holding time derivatives during residual evaluation */ 38 Vec U; /* U is used to compute Ydot = shift(Y-U) */ 39 Vec *YdotI; /* Work vectors to hold the residual evaluation */ 40 Mat TJ; /* KAIJ matrix for the Jacobian of the combined system */ 41 PetscScalar *work; /* Scalar work */ 42 TSStepStatus status; 43 PetscBool rebuild_completion; 44 PetscReal ccfl; 45 } TS_IRK; 46 47 /*@C 48 TSIRKTableauCreate - create the tableau for TSIRK and provide the entries 49 50 Not Collective 51 52 Input Parameters: 53 + ts - timestepping context 54 . nstages - number of stages, this is the dimension of the matrices below 55 . A - stage coefficients (dimension nstages*nstages, row-major) 56 . b - step completion table (dimension nstages) 57 . c - abscissa (dimension nstages) 58 . binterp - coefficients of the interpolation formula (dimension nstages) 59 . A_inv - inverse of A (dimension nstages*nstages, row-major) 60 . A_inv_rowsum - row sum of the inverse of A (dimension nstages) 61 - I_s - identity matrix (dimension nstages*nstages) 62 63 Level: advanced 64 65 .seealso: TSIRK, TSIRKRegister() 66 @*/ 67 PetscErrorCode TSIRKTableauCreate(TS ts,PetscInt nstages,const PetscReal *A,const PetscReal *b,const PetscReal *c,const PetscReal *binterp,const PetscScalar *A_inv,const PetscScalar *A_inv_rowsum,const PetscScalar *I_s) 68 { 69 TS_IRK *irk = (TS_IRK*)ts->data; 70 IRKTableau tab = irk->tableau; 71 PetscErrorCode ierr; 72 73 PetscFunctionBegin; 74 irk->order = nstages; 75 ierr = PetscMalloc3(PetscSqr(nstages),&tab->A,PetscSqr(nstages),&tab->A_inv,PetscSqr(nstages),&tab->I_s);CHKERRQ(ierr); 76 ierr = PetscMalloc4(nstages,&tab->b,nstages,&tab->c,nstages,&tab->binterp,nstages,&tab->A_inv_rowsum);CHKERRQ(ierr); 77 ierr = PetscArraycpy(tab->A,A,PetscSqr(nstages));CHKERRQ(ierr); 78 ierr = PetscArraycpy(tab->b,b,nstages);CHKERRQ(ierr); 79 ierr = PetscArraycpy(tab->c,c,nstages);CHKERRQ(ierr); 80 /* optional coefficient arrays */ 81 if (binterp) { 82 ierr = PetscArraycpy(tab->binterp,binterp,nstages);CHKERRQ(ierr); 83 } 84 if (A_inv) { 85 ierr = PetscArraycpy(tab->A_inv,A_inv,PetscSqr(nstages));CHKERRQ(ierr); 86 } 87 if (A_inv_rowsum) { 88 ierr = PetscArraycpy(tab->A_inv_rowsum,A_inv_rowsum,nstages);CHKERRQ(ierr); 89 } 90 if (I_s) { 91 ierr = PetscArraycpy(tab->I_s,I_s,PetscSqr(nstages));CHKERRQ(ierr); 92 } 93 PetscFunctionReturn(0); 94 } 95 96 /* Arrays should be freed with PetscFree3(A,b,c) */ 97 static PetscErrorCode TSIRKCreate_Gauss(TS ts) 98 { 99 PetscInt nstages; 100 PetscReal *gauss_A_real,*gauss_b,*b,*gauss_c; 101 PetscScalar *gauss_A,*gauss_A_inv,*gauss_A_inv_rowsum,*I_s; 102 PetscScalar *G0,*G1; 103 PetscInt i,j; 104 Mat G0mat,G1mat,Amat; 105 PetscErrorCode ierr; 106 107 PetscFunctionBegin; 108 ierr = TSIRKGetNumStages(ts,&nstages);CHKERRQ(ierr); 109 ierr = PetscMalloc3(PetscSqr(nstages),&gauss_A_real,nstages,&gauss_b,nstages,&gauss_c);CHKERRQ(ierr); 110 ierr = PetscMalloc4(PetscSqr(nstages),&gauss_A,PetscSqr(nstages),&gauss_A_inv,nstages,&gauss_A_inv_rowsum,PetscSqr(nstages),&I_s);CHKERRQ(ierr); 111 ierr = PetscMalloc3(nstages,&b,PetscSqr(nstages),&G0,PetscSqr(nstages),&G1);CHKERRQ(ierr); 112 ierr = PetscDTGaussQuadrature(nstages,0.,1.,gauss_c,b);CHKERRQ(ierr); 113 for (i=0; i<nstages; i++) gauss_b[i] = b[i]; /* copy to possibly-complex array */ 114 115 /* A^T = G0^{-1} G1 */ 116 for (i=0; i<nstages; i++) { 117 for (j=0; j<nstages; j++) { 118 G0[i*nstages+j] = PetscPowRealInt(gauss_c[i],j); 119 G1[i*nstages+j] = PetscPowRealInt(gauss_c[i],j+1)/(j+1); 120 } 121 } 122 /* The arrays above are row-aligned, but we create dense matrices as the transpose */ 123 ierr = MatCreateSeqDense(PETSC_COMM_SELF,nstages,nstages,G0,&G0mat);CHKERRQ(ierr); 124 ierr = MatCreateSeqDense(PETSC_COMM_SELF,nstages,nstages,G1,&G1mat);CHKERRQ(ierr); 125 ierr = MatCreateSeqDense(PETSC_COMM_SELF,nstages,nstages,gauss_A,&Amat);CHKERRQ(ierr); 126 ierr = MatLUFactor(G0mat,NULL,NULL,NULL);CHKERRQ(ierr); 127 ierr = MatMatSolve(G0mat,G1mat,Amat);CHKERRQ(ierr); 128 ierr = MatTranspose(Amat,MAT_INPLACE_MATRIX,&Amat);CHKERRQ(ierr); 129 for (i=0; i<nstages; i++) 130 for (j=0; j<nstages; j++) 131 gauss_A_real[i*nstages+j] = PetscRealPart(gauss_A[i*nstages+j]); 132 133 ierr = MatDestroy(&G0mat);CHKERRQ(ierr); 134 ierr = MatDestroy(&G1mat);CHKERRQ(ierr); 135 ierr = MatDestroy(&Amat);CHKERRQ(ierr); 136 ierr = PetscFree3(b,G0,G1);CHKERRQ(ierr); 137 138 {/* Invert A */ 139 /* PETSc does not provide a routine to calculate the inverse of a general matrix. 140 * To get the inverse of A, we form a sequential BAIJ matrix from it, consisting of a single block with block size 141 * equal to the dimension of A, and then use MatInvertBlockDiagonal(). */ 142 Mat A_baij; 143 PetscInt idxm[1]={0},idxn[1]={0}; 144 const PetscScalar *A_inv; 145 146 ierr = MatCreateSeqBAIJ(PETSC_COMM_SELF,nstages,nstages,nstages,1,NULL,&A_baij);CHKERRQ(ierr); 147 ierr = MatSetOption(A_baij,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr); 148 ierr = MatSetValuesBlocked(A_baij,1,idxm,1,idxn,gauss_A,INSERT_VALUES);CHKERRQ(ierr); 149 ierr = MatAssemblyBegin(A_baij,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 150 ierr = MatAssemblyEnd(A_baij,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 151 ierr = MatInvertBlockDiagonal(A_baij,&A_inv);CHKERRQ(ierr); 152 ierr = PetscMemcpy(gauss_A_inv,A_inv,nstages*nstages*sizeof(PetscScalar));CHKERRQ(ierr); 153 ierr = MatDestroy(&A_baij);CHKERRQ(ierr); 154 } 155 156 /* Compute row sums A_inv_rowsum and identity I_s */ 157 for (i=0; i<nstages; i++) { 158 gauss_A_inv_rowsum[i] = 0; 159 for (j=0; j<nstages; j++) { 160 gauss_A_inv_rowsum[i] += gauss_A_inv[i+nstages*j]; 161 I_s[i+nstages*j] = 1.*(i == j); 162 } 163 } 164 ierr = TSIRKTableauCreate(ts,nstages,gauss_A_real,gauss_b,gauss_c,NULL,gauss_A_inv,gauss_A_inv_rowsum,I_s);CHKERRQ(ierr); 165 ierr = PetscFree3(gauss_A_real,gauss_b,gauss_c);CHKERRQ(ierr); 166 ierr = PetscFree4(gauss_A,gauss_A_inv,gauss_A_inv_rowsum,I_s);CHKERRQ(ierr); 167 PetscFunctionReturn(0); 168 } 169 170 /*@C 171 TSIRKRegister - adds a TSIRK implementation 172 173 Not Collective 174 175 Input Parameters: 176 + sname - name of user-defined IRK scheme 177 - function - function to create method context 178 179 Notes: 180 TSIRKRegister() may be called multiple times to add several user-defined families. 181 182 Sample usage: 183 .vb 184 TSIRKRegister("my_scheme",MySchemeCreate); 185 .ve 186 187 Then, your scheme can be chosen with the procedural interface via 188 $ TSIRKSetType(ts,"my_scheme") 189 or at runtime via the option 190 $ -ts_irk_type my_scheme 191 192 Level: advanced 193 194 .seealso: TSIRKRegisterAll() 195 @*/ 196 PetscErrorCode TSIRKRegister(const char sname[],PetscErrorCode (*function)(TS)) 197 { 198 PetscErrorCode ierr; 199 200 PetscFunctionBegin; 201 ierr = TSIRKInitializePackage();CHKERRQ(ierr); 202 ierr = PetscFunctionListAdd(&TSIRKList,sname,function);CHKERRQ(ierr); 203 PetscFunctionReturn(0); 204 } 205 206 /*@C 207 TSIRKRegisterAll - Registers all of the implicit Runge-Kutta methods in TSIRK 208 209 Not Collective, but should be called by all processes which will need the schemes to be registered 210 211 Level: advanced 212 213 .seealso: TSIRKRegisterDestroy() 214 @*/ 215 PetscErrorCode TSIRKRegisterAll(void) 216 { 217 PetscErrorCode ierr; 218 219 PetscFunctionBegin; 220 if (TSIRKRegisterAllCalled) PetscFunctionReturn(0); 221 TSIRKRegisterAllCalled = PETSC_TRUE; 222 223 ierr = TSIRKRegister(TSIRKGAUSS,TSIRKCreate_Gauss);CHKERRQ(ierr); 224 PetscFunctionReturn(0); 225 } 226 227 /*@C 228 TSIRKRegisterDestroy - Frees the list of schemes that were registered by TSIRKRegister(). 229 230 Not Collective 231 232 Level: advanced 233 234 .seealso: TSIRKRegister(), TSIRKRegisterAll() 235 @*/ 236 PetscErrorCode TSIRKRegisterDestroy(void) 237 { 238 PetscFunctionBegin; 239 TSIRKRegisterAllCalled = PETSC_FALSE; 240 PetscFunctionReturn(0); 241 } 242 243 /*@C 244 TSIRKInitializePackage - This function initializes everything in the TSIRK package. It is called 245 from TSInitializePackage(). 246 247 Level: developer 248 249 .seealso: PetscInitialize() 250 @*/ 251 PetscErrorCode TSIRKInitializePackage(void) 252 { 253 PetscErrorCode ierr; 254 255 PetscFunctionBegin; 256 if (TSIRKPackageInitialized) PetscFunctionReturn(0); 257 TSIRKPackageInitialized = PETSC_TRUE; 258 ierr = TSIRKRegisterAll();CHKERRQ(ierr); 259 ierr = PetscRegisterFinalize(TSIRKFinalizePackage);CHKERRQ(ierr); 260 PetscFunctionReturn(0); 261 } 262 263 /*@C 264 TSIRKFinalizePackage - This function destroys everything in the TSIRK package. It is 265 called from PetscFinalize(). 266 267 Level: developer 268 269 .seealso: PetscFinalize() 270 @*/ 271 PetscErrorCode TSIRKFinalizePackage(void) 272 { 273 PetscErrorCode ierr; 274 275 PetscFunctionBegin; 276 ierr = PetscFunctionListDestroy(&TSIRKList);CHKERRQ(ierr); 277 TSIRKPackageInitialized = PETSC_FALSE; 278 PetscFunctionReturn(0); 279 } 280 281 /* 282 This function can be called before or after ts->vec_sol has been updated. 283 */ 284 static PetscErrorCode TSEvaluateStep_IRK(TS ts,PetscInt order,Vec U,PetscBool *done) 285 { 286 TS_IRK *irk = (TS_IRK*)ts->data; 287 IRKTableau tab = irk->tableau; 288 Vec *YdotI = irk->YdotI; 289 PetscScalar *w = irk->work; 290 PetscReal h; 291 PetscInt j; 292 PetscErrorCode ierr; 293 294 PetscFunctionBegin; 295 switch (irk->status) { 296 case TS_STEP_INCOMPLETE: 297 case TS_STEP_PENDING: 298 h = ts->time_step; break; 299 case TS_STEP_COMPLETE: 300 h = ts->ptime - ts->ptime_prev; break; 301 default: SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_PLIB,"Invalid TSStepStatus"); 302 } 303 304 ierr = VecCopy(ts->vec_sol,U);CHKERRQ(ierr); 305 for (j=0; j<irk->nstages; j++) w[j] = h*tab->b[j]; 306 ierr = VecMAXPY(U,irk->nstages,w,YdotI);CHKERRQ(ierr); 307 PetscFunctionReturn(0); 308 } 309 310 static PetscErrorCode TSRollBack_IRK(TS ts) 311 { 312 TS_IRK *irk = (TS_IRK*)ts->data; 313 PetscErrorCode ierr; 314 315 PetscFunctionBegin; 316 ierr = VecCopy(irk->U0,ts->vec_sol);CHKERRQ(ierr); 317 PetscFunctionReturn(0); 318 } 319 320 static PetscErrorCode TSStep_IRK(TS ts) 321 { 322 TS_IRK *irk = (TS_IRK*)ts->data; 323 IRKTableau tab = irk->tableau; 324 PetscScalar *A_inv = tab->A_inv,*A_inv_rowsum = tab->A_inv_rowsum; 325 const PetscInt nstages = irk->nstages; 326 SNES snes; 327 PetscInt i,j,its,lits,bs; 328 TSAdapt adapt; 329 PetscInt rejections = 0; 330 PetscBool accept = PETSC_TRUE; 331 PetscReal next_time_step = ts->time_step; 332 PetscErrorCode ierr; 333 334 PetscFunctionBegin; 335 if (!ts->steprollback) { 336 ierr = VecCopy(ts->vec_sol,irk->U0);CHKERRQ(ierr); 337 } 338 ierr = VecGetBlockSize(ts->vec_sol,&bs);CHKERRQ(ierr); 339 for (i=0; i<nstages; i++) { 340 ierr = VecStrideScatter(ts->vec_sol,i*bs,irk->Z,INSERT_VALUES);CHKERRQ(ierr); 341 } 342 343 irk->status = TS_STEP_INCOMPLETE; 344 while (!ts->reason && irk->status != TS_STEP_COMPLETE) { 345 ierr = VecCopy(ts->vec_sol,irk->U);CHKERRQ(ierr); 346 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 347 ierr = SNESSolve(snes,NULL,irk->Z);CHKERRQ(ierr); 348 ierr = SNESGetIterationNumber(snes,&its);CHKERRQ(ierr); 349 ierr = SNESGetLinearSolveIterations(snes,&lits);CHKERRQ(ierr); 350 ts->snes_its += its; ts->ksp_its += lits; 351 ierr = VecStrideGatherAll(irk->Z,irk->Y,INSERT_VALUES);CHKERRQ(ierr); 352 for (i=0; i<nstages; i++) { 353 ierr = VecZeroEntries(irk->YdotI[i]);CHKERRQ(ierr); 354 for (j=0; j<nstages; j++) { 355 ierr = VecAXPY(irk->YdotI[i],A_inv[i+j*nstages]/ts->time_step,irk->Y[j]);CHKERRQ(ierr); 356 } 357 ierr = VecAXPY(irk->YdotI[i],-A_inv_rowsum[i]/ts->time_step,irk->U);CHKERRQ(ierr); 358 } 359 irk->status = TS_STEP_INCOMPLETE; 360 ierr = TSEvaluateStep_IRK(ts,irk->order,ts->vec_sol,NULL);CHKERRQ(ierr); 361 irk->status = TS_STEP_PENDING; 362 ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr); 363 ierr = TSAdaptChoose(adapt,ts,ts->time_step,NULL,&next_time_step,&accept);CHKERRQ(ierr); 364 irk->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE; 365 if (!accept) { 366 ierr = TSRollBack_IRK(ts);CHKERRQ(ierr); 367 ts->time_step = next_time_step; 368 goto reject_step; 369 } 370 371 ts->ptime += ts->time_step; 372 ts->time_step = next_time_step; 373 break; 374 reject_step: 375 ts->reject++; accept = PETSC_FALSE; 376 if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) { 377 ts->reason = TS_DIVERGED_STEP_REJECTED; 378 ierr = PetscInfo2(ts,"Step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,rejections);CHKERRQ(ierr); 379 } 380 } 381 PetscFunctionReturn(0); 382 } 383 384 static PetscErrorCode TSInterpolate_IRK(TS ts,PetscReal itime,Vec U) 385 { 386 TS_IRK *irk = (TS_IRK*)ts->data; 387 PetscInt nstages = irk->nstages,pinterp = irk->pinterp,i,j; 388 PetscReal h; 389 PetscReal tt,t; 390 PetscScalar *bt; 391 const PetscReal *B = irk->tableau->binterp; 392 PetscErrorCode ierr; 393 394 PetscFunctionBegin; 395 if (!B) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"TSIRK %s does not have an interpolation formula",irk->method_name); 396 switch (irk->status) { 397 case TS_STEP_INCOMPLETE: 398 case TS_STEP_PENDING: 399 h = ts->time_step; 400 t = (itime - ts->ptime)/h; 401 break; 402 case TS_STEP_COMPLETE: 403 h = ts->ptime - ts->ptime_prev; 404 t = (itime - ts->ptime)/h + 1; /* In the interval [0,1] */ 405 break; 406 default: SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_PLIB,"Invalid TSStepStatus"); 407 } 408 ierr = PetscMalloc1(nstages,&bt);CHKERRQ(ierr); 409 for (i=0; i<nstages; i++) bt[i] = 0; 410 for (j=0,tt=t; j<pinterp; j++,tt*=t) { 411 for (i=0; i<nstages; i++) { 412 bt[i] += h * B[i*pinterp+j] * tt; 413 } 414 } 415 ierr = VecMAXPY(U,nstages,bt,irk->YdotI);CHKERRQ(ierr); 416 PetscFunctionReturn(0); 417 } 418 419 static PetscErrorCode TSIRKTableauReset(TS ts) 420 { 421 TS_IRK *irk = (TS_IRK*)ts->data; 422 IRKTableau tab = irk->tableau; 423 PetscErrorCode ierr; 424 425 PetscFunctionBegin; 426 if (!tab) PetscFunctionReturn(0); 427 ierr = PetscFree3(tab->A,tab->A_inv,tab->I_s);CHKERRQ(ierr); 428 ierr = PetscFree4(tab->b,tab->c,tab->binterp,tab->A_inv_rowsum);CHKERRQ(ierr); 429 PetscFunctionReturn(0); 430 } 431 432 static PetscErrorCode TSReset_IRK(TS ts) 433 { 434 TS_IRK *irk = (TS_IRK*)ts->data; 435 PetscErrorCode ierr; 436 437 PetscFunctionBegin; 438 ierr = TSIRKTableauReset(ts);CHKERRQ(ierr); 439 if (irk->tableau) { 440 ierr = PetscFree(irk->tableau);CHKERRQ(ierr); 441 } 442 if (irk->method_name) { 443 ierr = PetscFree(irk->method_name);CHKERRQ(ierr); 444 } 445 if (irk->work) { 446 ierr = PetscFree(irk->work);CHKERRQ(ierr); 447 } 448 ierr = VecDestroyVecs(irk->nstages,&irk->Y);CHKERRQ(ierr); 449 ierr = VecDestroyVecs(irk->nstages,&irk->YdotI);CHKERRQ(ierr); 450 ierr = VecDestroy(&irk->Ydot);CHKERRQ(ierr); 451 ierr = VecDestroy(&irk->Z);CHKERRQ(ierr); 452 ierr = VecDestroy(&irk->U);CHKERRQ(ierr); 453 ierr = VecDestroy(&irk->U0);CHKERRQ(ierr); 454 ierr = MatDestroy(&irk->TJ);CHKERRQ(ierr); 455 PetscFunctionReturn(0); 456 } 457 458 static PetscErrorCode TSIRKGetVecs(TS ts,DM dm,Vec *U) 459 { 460 TS_IRK *irk = (TS_IRK*)ts->data; 461 PetscErrorCode ierr; 462 463 PetscFunctionBegin; 464 if (U) { 465 if (dm && dm != ts->dm) { 466 ierr = DMGetNamedGlobalVector(dm,"TSIRK_U",U);CHKERRQ(ierr); 467 } else *U = irk->U; 468 } 469 PetscFunctionReturn(0); 470 } 471 472 static PetscErrorCode TSIRKRestoreVecs(TS ts,DM dm,Vec *U) 473 { 474 PetscErrorCode ierr; 475 476 PetscFunctionBegin; 477 if (U) { 478 if (dm && dm != ts->dm) { 479 ierr = DMRestoreNamedGlobalVector(dm,"TSIRK_U",U);CHKERRQ(ierr); 480 } 481 } 482 PetscFunctionReturn(0); 483 } 484 485 /* 486 This defines the nonlinear equations that is to be solved with SNES 487 G[e\otimes t + C*dt, Z, Zdot] = 0 488 Zdot = (In \otimes S)*Z - (In \otimes Se) U 489 where S = 1/(dt*A) 490 */ 491 static PetscErrorCode SNESTSFormFunction_IRK(SNES snes,Vec ZC,Vec FC,TS ts) 492 { 493 TS_IRK *irk = (TS_IRK*)ts->data; 494 IRKTableau tab = irk->tableau; 495 const PetscInt nstages = irk->nstages; 496 const PetscReal *c = tab->c; 497 const PetscScalar *A_inv = tab->A_inv,*A_inv_rowsum = tab->A_inv_rowsum; 498 DM dm,dmsave; 499 Vec U,*YdotI = irk->YdotI,Ydot = irk->Ydot,*Y = irk->Y; 500 PetscReal h = ts->time_step; 501 PetscInt i,j; 502 PetscErrorCode ierr; 503 504 PetscFunctionBegin; 505 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 506 ierr = TSIRKGetVecs(ts,dm,&U);CHKERRQ(ierr); 507 ierr = VecStrideGatherAll(ZC,Y,INSERT_VALUES);CHKERRQ(ierr); 508 dmsave = ts->dm; 509 ts->dm = dm; 510 for (i=0; i<nstages; i++) { 511 ierr = VecZeroEntries(Ydot);CHKERRQ(ierr); 512 for (j=0; j<nstages; j++) { 513 ierr = VecAXPY(Ydot,A_inv[j*nstages+i]/h,Y[j]);CHKERRQ(ierr); 514 } 515 ierr = VecAXPY(Ydot,-A_inv_rowsum[i]/h,U);CHKERRQ(ierr); /* Ydot = (S \otimes In)*Z - (Se \otimes In) U */ 516 ierr = TSComputeIFunction(ts,ts->ptime+ts->time_step*c[i],Y[i],Ydot,YdotI[i],PETSC_FALSE);CHKERRQ(ierr); 517 } 518 ierr = VecStrideScatterAll(YdotI,FC,INSERT_VALUES);CHKERRQ(ierr); 519 ts->dm = dmsave; 520 ierr = TSIRKRestoreVecs(ts,dm,&U);CHKERRQ(ierr); 521 PetscFunctionReturn(0); 522 } 523 524 /* 525 For explicit ODE, the Jacobian is 526 JC = I_n \otimes S - J \otimes I_s 527 For DAE, the Jacobian is 528 JC = M_n \otimes S - J \otimes I_s 529 */ 530 static PetscErrorCode SNESTSFormJacobian_IRK(SNES snes,Vec ZC,Mat JC,Mat JCpre,TS ts) 531 { 532 TS_IRK *irk = (TS_IRK*)ts->data; 533 IRKTableau tab = irk->tableau; 534 const PetscInt nstages = irk->nstages; 535 const PetscReal *c = tab->c; 536 DM dm,dmsave; 537 Vec *Y = irk->Y,Ydot = irk->Ydot; 538 Mat J; 539 PetscScalar *S; 540 PetscInt i,j,bs; 541 PetscErrorCode ierr; 542 543 PetscFunctionBegin; 544 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 545 /* irk->Ydot has already been computed in SNESTSFormFunction_IRK (SNES guarantees this) */ 546 dmsave = ts->dm; 547 ts->dm = dm; 548 ierr = VecGetBlockSize(Y[nstages-1],&bs);CHKERRQ(ierr); 549 if (ts->equation_type <= TS_EQ_ODE_EXPLICIT) { /* Support explicit formulas only */ 550 ierr = VecStrideGather(ZC,(nstages-1)*bs,Y[nstages-1],INSERT_VALUES);CHKERRQ(ierr); 551 ierr = MatKAIJGetAIJ(JC,&J);CHKERRQ(ierr); 552 ierr = TSComputeIJacobian(ts,ts->ptime+ts->time_step*c[nstages-1],Y[nstages-1],Ydot,0,J,J,PETSC_FALSE);CHKERRQ(ierr); 553 ierr = MatKAIJGetS(JC,NULL,NULL,&S);CHKERRQ(ierr); 554 for (i=0; i<nstages; i++) 555 for (j=0; j<nstages; j++) 556 S[i+nstages*j] = tab->A_inv[i+nstages*j]/ts->time_step; 557 ierr = MatKAIJRestoreS(JC,&S);CHKERRQ(ierr); 558 } else 559 SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"TSIRK %s does not support implicit formula",irk->method_name); /* ToDo: need the mass matrix for DAE */ 560 ts->dm = dmsave; 561 PetscFunctionReturn(0); 562 } 563 564 static PetscErrorCode DMCoarsenHook_TSIRK(DM fine,DM coarse,void *ctx) 565 { 566 PetscFunctionBegin; 567 PetscFunctionReturn(0); 568 } 569 570 static PetscErrorCode DMRestrictHook_TSIRK(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse,void *ctx) 571 { 572 TS ts = (TS)ctx; 573 Vec U,U_c; 574 PetscErrorCode ierr; 575 576 PetscFunctionBegin; 577 ierr = TSIRKGetVecs(ts,fine,&U);CHKERRQ(ierr); 578 ierr = TSIRKGetVecs(ts,coarse,&U_c);CHKERRQ(ierr); 579 ierr = MatRestrict(restrct,U,U_c);CHKERRQ(ierr); 580 ierr = VecPointwiseMult(U_c,rscale,U_c);CHKERRQ(ierr); 581 ierr = TSIRKRestoreVecs(ts,fine,&U);CHKERRQ(ierr); 582 ierr = TSIRKRestoreVecs(ts,coarse,&U_c);CHKERRQ(ierr); 583 PetscFunctionReturn(0); 584 } 585 586 static PetscErrorCode DMSubDomainHook_TSIRK(DM dm,DM subdm,void *ctx) 587 { 588 PetscFunctionBegin; 589 PetscFunctionReturn(0); 590 } 591 592 static PetscErrorCode DMSubDomainRestrictHook_TSIRK(DM dm,VecScatter gscat,VecScatter lscat,DM subdm,void *ctx) 593 { 594 TS ts = (TS)ctx; 595 Vec U,U_c; 596 PetscErrorCode ierr; 597 598 PetscFunctionBegin; 599 ierr = TSIRKGetVecs(ts,dm,&U);CHKERRQ(ierr); 600 ierr = TSIRKGetVecs(ts,subdm,&U_c);CHKERRQ(ierr); 601 602 ierr = VecScatterBegin(gscat,U,U_c,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 603 ierr = VecScatterEnd(gscat,U,U_c,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 604 605 ierr = TSIRKRestoreVecs(ts,dm,&U);CHKERRQ(ierr); 606 ierr = TSIRKRestoreVecs(ts,subdm,&U_c);CHKERRQ(ierr); 607 PetscFunctionReturn(0); 608 } 609 610 static PetscErrorCode TSSetUp_IRK(TS ts) 611 { 612 TS_IRK *irk = (TS_IRK*)ts->data; 613 IRKTableau tab = irk->tableau; 614 DM dm; 615 Mat J; 616 Vec R; 617 const PetscInt nstages = irk->nstages; 618 PetscInt vsize,bs; 619 PetscErrorCode ierr; 620 621 PetscFunctionBegin; 622 if (!irk->work) { 623 ierr = PetscMalloc1(irk->nstages,&irk->work);CHKERRQ(ierr); 624 } 625 if (!irk->Y) { 626 ierr = VecDuplicateVecs(ts->vec_sol,irk->nstages,&irk->Y);CHKERRQ(ierr); 627 } 628 if (!irk->YdotI) { 629 ierr = VecDuplicateVecs(ts->vec_sol,irk->nstages,&irk->YdotI);CHKERRQ(ierr); 630 } 631 if (!irk->Ydot) { 632 ierr = VecDuplicate(ts->vec_sol,&irk->Ydot);CHKERRQ(ierr); 633 } 634 if (!irk->U) { 635 ierr = VecDuplicate(ts->vec_sol,&irk->U);CHKERRQ(ierr); 636 } 637 if (!irk->U0) { 638 ierr = VecDuplicate(ts->vec_sol,&irk->U0);CHKERRQ(ierr); 639 } 640 if (!irk->Z) { 641 ierr = VecCreate(PetscObjectComm((PetscObject)ts->vec_sol),&irk->Z);CHKERRQ(ierr); 642 ierr = VecGetSize(ts->vec_sol,&vsize);CHKERRQ(ierr); 643 ierr = VecSetSizes(irk->Z,PETSC_DECIDE,vsize*irk->nstages);CHKERRQ(ierr); 644 ierr = VecGetBlockSize(ts->vec_sol,&bs);CHKERRQ(ierr); 645 ierr = VecSetBlockSize(irk->Z,irk->nstages*bs);CHKERRQ(ierr); 646 ierr = VecSetFromOptions(irk->Z);CHKERRQ(ierr); 647 } 648 ierr = TSGetDM(ts,&dm);CHKERRQ(ierr); 649 ierr = DMCoarsenHookAdd(dm,DMCoarsenHook_TSIRK,DMRestrictHook_TSIRK,ts);CHKERRQ(ierr); 650 ierr = DMSubDomainHookAdd(dm,DMSubDomainHook_TSIRK,DMSubDomainRestrictHook_TSIRK,ts);CHKERRQ(ierr); 651 652 ierr = TSGetSNES(ts,&ts->snes);CHKERRQ(ierr); 653 ierr = VecDuplicate(irk->Z,&R);CHKERRQ(ierr); 654 ierr = SNESSetFunction(ts->snes,R,SNESTSFormFunction,ts);CHKERRQ(ierr); 655 ierr = SNESGetJacobian(ts->snes,&J,NULL,NULL,NULL);CHKERRQ(ierr); 656 if (!irk->TJ) { 657 /* Create the KAIJ matrix for solving the stages */ 658 ierr = MatCreateKAIJ(J,nstages,nstages,tab->A_inv,tab->I_s,&irk->TJ);CHKERRQ(ierr); 659 } 660 ierr = SNESSetJacobian(ts->snes,irk->TJ,irk->TJ,SNESTSFormJacobian,ts);CHKERRQ(ierr); 661 ierr = VecDestroy(&R);CHKERRQ(ierr); 662 PetscFunctionReturn(0); 663 } 664 665 static PetscErrorCode TSSetFromOptions_IRK(PetscOptionItems *PetscOptionsObject,TS ts) 666 { 667 TS_IRK *irk = (TS_IRK*)ts->data; 668 char tname[256] = TSIRKGAUSS; 669 PetscErrorCode ierr; 670 671 PetscFunctionBegin; 672 ierr = PetscOptionsHead(PetscOptionsObject,"IRK ODE solver options");CHKERRQ(ierr); 673 { 674 PetscBool flg1,flg2; 675 ierr = PetscOptionsInt("-ts_irk_nstages","Stages of the IRK method","TSIRKSetNumStages",irk->nstages,&irk->nstages,&flg1);CHKERRQ(ierr); 676 ierr = PetscOptionsFList("-ts_irk_type","Type of IRK method","TSIRKSetType",TSIRKList,irk->method_name[0] ? irk->method_name : tname,tname,sizeof(tname),&flg2);CHKERRQ(ierr); 677 if (flg1 ||flg2 || !irk->method_name[0]) { /* Create the method tableau after nstages or method is set */ 678 ierr = TSIRKSetType(ts,tname);CHKERRQ(ierr); 679 } 680 } 681 ierr = PetscOptionsTail();CHKERRQ(ierr); 682 PetscFunctionReturn(0); 683 } 684 685 static PetscErrorCode TSView_IRK(TS ts,PetscViewer viewer) 686 { 687 TS_IRK *irk = (TS_IRK*)ts->data; 688 PetscBool iascii; 689 PetscErrorCode ierr; 690 691 PetscFunctionBegin; 692 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 693 if (iascii) { 694 IRKTableau tab = irk->tableau; 695 TSIRKType irktype; 696 char buf[512]; 697 698 ierr = TSIRKGetType(ts,&irktype);CHKERRQ(ierr); 699 ierr = PetscViewerASCIIPrintf(viewer," IRK type %s\n",irktype);CHKERRQ(ierr); 700 ierr = PetscFormatRealArray(buf,sizeof(buf),"% 8.6f",irk->nstages,tab->c);CHKERRQ(ierr); 701 ierr = PetscViewerASCIIPrintf(viewer," Abscissa c = %s\n",buf);CHKERRQ(ierr); 702 ierr = PetscViewerASCIIPrintf(viewer,"Stiffly accurate: %s\n",irk->stiffly_accurate ? "yes" : "no");CHKERRQ(ierr); 703 ierr = PetscFormatRealArray(buf,sizeof(buf),"% 8.6f",PetscSqr(irk->nstages),tab->A);CHKERRQ(ierr); 704 ierr = PetscViewerASCIIPrintf(viewer," A coefficients A = %s\n",buf);CHKERRQ(ierr); 705 } 706 PetscFunctionReturn(0); 707 } 708 709 static PetscErrorCode TSLoad_IRK(TS ts,PetscViewer viewer) 710 { 711 PetscErrorCode ierr; 712 SNES snes; 713 TSAdapt adapt; 714 715 PetscFunctionBegin; 716 ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr); 717 ierr = TSAdaptLoad(adapt,viewer);CHKERRQ(ierr); 718 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 719 ierr = SNESLoad(snes,viewer);CHKERRQ(ierr); 720 /* function and Jacobian context for SNES when used with TS is always ts object */ 721 ierr = SNESSetFunction(snes,NULL,NULL,ts);CHKERRQ(ierr); 722 ierr = SNESSetJacobian(snes,NULL,NULL,NULL,ts);CHKERRQ(ierr); 723 PetscFunctionReturn(0); 724 } 725 726 /*@C 727 TSIRKSetType - Set the type of IRK scheme 728 729 Logically collective 730 731 Input Parameters: 732 + ts - timestepping context 733 - irktype - type of IRK scheme 734 735 Options Database: 736 . -ts_irk_type <gauss> 737 738 Level: intermediate 739 740 .seealso: TSIRKGetType(), TSIRK, TSIRKType, TSIRKGAUSS 741 @*/ 742 PetscErrorCode TSIRKSetType(TS ts,TSIRKType irktype) 743 { 744 PetscErrorCode ierr; 745 746 PetscFunctionBegin; 747 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 748 PetscValidCharPointer(irktype,2); 749 ierr = PetscTryMethod(ts,"TSIRKSetType_C",(TS,TSIRKType),(ts,irktype));CHKERRQ(ierr); 750 PetscFunctionReturn(0); 751 } 752 753 /*@C 754 TSIRKGetType - Get the type of IRK IMEX scheme 755 756 Logically collective 757 758 Input Parameter: 759 . ts - timestepping context 760 761 Output Parameter: 762 . irktype - type of IRK-IMEX scheme 763 764 Level: intermediate 765 766 .seealso: TSIRKGetType() 767 @*/ 768 PetscErrorCode TSIRKGetType(TS ts,TSIRKType *irktype) 769 { 770 PetscErrorCode ierr; 771 772 PetscFunctionBegin; 773 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 774 ierr = PetscUseMethod(ts,"TSIRKGetType_C",(TS,TSIRKType*),(ts,irktype));CHKERRQ(ierr); 775 PetscFunctionReturn(0); 776 } 777 778 /*@C 779 TSIRKSetNumStages - Set the number of stages of IRK scheme 780 781 Logically collective 782 783 Input Parameters: 784 + ts - timestepping context 785 - nstages - number of stages of IRK scheme 786 787 Options Database: 788 . -ts_irk_nstages <int>: Number of stages 789 790 Level: intermediate 791 792 .seealso: TSIRKGetNumStages(), TSIRK 793 @*/ 794 PetscErrorCode TSIRKSetNumStages(TS ts,PetscInt nstages) 795 { 796 PetscErrorCode ierr; 797 798 PetscFunctionBegin; 799 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 800 ierr = PetscTryMethod(ts,"TSIRKSetNumStages_C",(TS,PetscInt),(ts,nstages));CHKERRQ(ierr); 801 PetscFunctionReturn(0); 802 } 803 804 /*@C 805 TSIRKGetNumStages - Get the number of stages of IRK scheme 806 807 Logically collective 808 809 Input Parameters: 810 + ts - timestepping context 811 - nstages - number of stages of IRK scheme 812 813 Level: intermediate 814 815 .seealso: TSIRKSetNumStages(), TSIRK 816 @*/ 817 PetscErrorCode TSIRKGetNumStages(TS ts,PetscInt *nstages) 818 { 819 PetscErrorCode ierr; 820 821 PetscFunctionBegin; 822 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 823 PetscValidIntPointer(nstages,2); 824 ierr = PetscTryMethod(ts,"TSIRKGetNumStages_C",(TS,PetscInt*),(ts,nstages));CHKERRQ(ierr); 825 PetscFunctionReturn(0); 826 } 827 828 static PetscErrorCode TSIRKGetType_IRK(TS ts,TSIRKType *irktype) 829 { 830 TS_IRK *irk = (TS_IRK*)ts->data; 831 832 PetscFunctionBegin; 833 *irktype = irk->method_name; 834 PetscFunctionReturn(0); 835 } 836 837 static PetscErrorCode TSIRKSetType_IRK(TS ts,TSIRKType irktype) 838 { 839 TS_IRK *irk = (TS_IRK*)ts->data; 840 PetscErrorCode ierr,(*irkcreate)(TS); 841 842 PetscFunctionBegin; 843 if (irk->method_name) { 844 ierr = PetscFree(irk->method_name);CHKERRQ(ierr); 845 ierr = TSIRKTableauReset(ts);CHKERRQ(ierr); 846 } 847 ierr = PetscFunctionListFind(TSIRKList,irktype,&irkcreate);CHKERRQ(ierr); 848 if (!irkcreate) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown TSIRK type \"%s\" given",irktype); 849 ierr = (*irkcreate)(ts);CHKERRQ(ierr); 850 ierr = PetscStrallocpy(irktype,&irk->method_name);CHKERRQ(ierr); 851 PetscFunctionReturn(0); 852 } 853 854 static PetscErrorCode TSIRKSetNumStages_IRK(TS ts,PetscInt nstages) 855 { 856 TS_IRK *irk = (TS_IRK*)ts->data; 857 858 PetscFunctionBegin; 859 if (nstages<=0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"input argument, %d, out of range",nstages); 860 irk->nstages = nstages; 861 PetscFunctionReturn(0); 862 } 863 864 static PetscErrorCode TSIRKGetNumStages_IRK(TS ts,PetscInt *nstages) 865 { 866 TS_IRK *irk = (TS_IRK*)ts->data; 867 868 PetscFunctionBegin; 869 PetscValidIntPointer(nstages,2); 870 *nstages = irk->nstages; 871 PetscFunctionReturn(0); 872 } 873 874 static PetscErrorCode TSDestroy_IRK(TS ts) 875 { 876 PetscErrorCode ierr; 877 878 PetscFunctionBegin; 879 ierr = TSReset_IRK(ts);CHKERRQ(ierr); 880 if (ts->dm) { 881 ierr = DMCoarsenHookRemove(ts->dm,DMCoarsenHook_TSIRK,DMRestrictHook_TSIRK,ts);CHKERRQ(ierr); 882 ierr = DMSubDomainHookRemove(ts->dm,DMSubDomainHook_TSIRK,DMSubDomainRestrictHook_TSIRK,ts);CHKERRQ(ierr); 883 } 884 ierr = PetscFree(ts->data);CHKERRQ(ierr); 885 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetType_C",NULL);CHKERRQ(ierr); 886 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetType_C",NULL);CHKERRQ(ierr); 887 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetNumStages_C",NULL);CHKERRQ(ierr); 888 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetNumStages_C",NULL);CHKERRQ(ierr); 889 PetscFunctionReturn(0); 890 } 891 892 /*MC 893 TSIRK - ODE and DAE solver using Implicit Runge-Kutta schemes 894 895 Notes: 896 897 TSIRK uses the sparse Kronecker product matrix implementation of MATKAIJ to achieve good arithmetic intensity. 898 899 The default is TSIRK3, it can be changed with TSIRKSetType() or -ts_irk_type 900 901 If the equation is implicit or a DAE, then TSSetEquationType() needs to be set accordingly. Refer to the manual for further information. 902 903 Consider trying TSROSW if the stiff part is linear or weakly nonlinear. 904 905 Level: beginner 906 907 .seealso: TSCreate(), TS, TSSetType(), TSIRKSetType(), TSIRKGetType(), 908 TSIRK1BEE, TSIRK2C, TSIRK2D, TSIRK2E, TSIRK3, TSIRKL2, TSIRKA2, TSIRKARS122, 909 TSIRK4, TSIRK5, TSIRKPRSSP2, TSIRKARS443, TSIRKBPR3, TSIRKType, TSIRKRegister() 910 911 M*/ 912 PETSC_EXTERN PetscErrorCode TSCreate_IRK(TS ts) 913 { 914 TS_IRK *irk; 915 PetscErrorCode ierr; 916 917 PetscFunctionBegin; 918 ierr = TSIRKInitializePackage();CHKERRQ(ierr); 919 920 ts->ops->reset = TSReset_IRK; 921 ts->ops->destroy = TSDestroy_IRK; 922 ts->ops->view = TSView_IRK; 923 ts->ops->load = TSLoad_IRK; 924 ts->ops->setup = TSSetUp_IRK; 925 ts->ops->step = TSStep_IRK; 926 ts->ops->interpolate = TSInterpolate_IRK; 927 ts->ops->evaluatestep = TSEvaluateStep_IRK; 928 ts->ops->rollback = TSRollBack_IRK; 929 ts->ops->setfromoptions = TSSetFromOptions_IRK; 930 ts->ops->snesfunction = SNESTSFormFunction_IRK; 931 ts->ops->snesjacobian = SNESTSFormJacobian_IRK; 932 933 ts->usessnes = PETSC_TRUE; 934 935 ierr = PetscNewLog(ts,&irk);CHKERRQ(ierr); 936 ts->data = (void*)irk; 937 938 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetType_C",TSIRKSetType_IRK);CHKERRQ(ierr); 939 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetType_C",TSIRKGetType_IRK);CHKERRQ(ierr); 940 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetNumStages_C",TSIRKSetNumStages_IRK);CHKERRQ(ierr); 941 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetNumStages_C",TSIRKGetNumStages_IRK);CHKERRQ(ierr); 942 /* 3-stage IRK_Gauss is the default */ 943 ierr = PetscNew(&irk->tableau);CHKERRQ(ierr); 944 irk->nstages = 3; 945 ierr = TSIRKSetType(ts,TSIRKDefault);CHKERRQ(ierr); 946 PetscFunctionReturn(0); 947 } 948