1474dd773SHong Zhang /* 2474dd773SHong Zhang Code for time stepping with the multi-rate Runge-Kutta method 3474dd773SHong Zhang 4474dd773SHong Zhang Notes: 5474dd773SHong Zhang 1) The general system is written as 6474dd773SHong Zhang Udot = F(t,U) for the nonsplit version of multi-rate RK, 7474dd773SHong Zhang user should give the indexes for both slow and fast components; 8474dd773SHong Zhang 2) The general system is written as 9474dd773SHong Zhang Usdot = Fs(t,Us,Uf) 10474dd773SHong Zhang Ufdot = Ff(t,Us,Uf) for multi-rate RK with RHS splits, 11*da81f932SPierre Jolivet user should partition RHS by themselves and also provide the indexes for both slow and fast components. 12474dd773SHong Zhang */ 13474dd773SHong Zhang 14474dd773SHong Zhang #include <petsc/private/tsimpl.h> 15474dd773SHong Zhang #include <petscdm.h> 16474dd773SHong Zhang #include <../src/ts/impls/explicit/rk/rk.h> 1721052c0cSHong Zhang #include <../src/ts/impls/explicit/rk/mrk.h> 18474dd773SHong Zhang 19d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSReset_RK_MultirateNonsplit(TS ts) 20d71ae5a4SJacob Faibussowitsch { 21e5bffa22SHong Zhang TS_RK *rk = (TS_RK *)ts->data; 22e5bffa22SHong Zhang RKTableau tab = rk->tableau; 23e5bffa22SHong Zhang 24e5bffa22SHong Zhang PetscFunctionBegin; 259566063dSJacob Faibussowitsch PetscCall(VecDestroy(&rk->X0)); 269566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(tab->s, &rk->YdotRHS_slow)); 273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 28e5bffa22SHong Zhang } 29e5bffa22SHong Zhang 30d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSInterpolate_RK_MultirateNonsplit(TS ts, PetscReal itime, Vec X) 31d71ae5a4SJacob Faibussowitsch { 32e5bffa22SHong Zhang TS_RK *rk = (TS_RK *)ts->data; 33e5bffa22SHong Zhang PetscInt s = rk->tableau->s, p = rk->tableau->p, i, j; 3463a6f1b4SHong Zhang PetscReal h = ts->time_step; 35e5bffa22SHong Zhang PetscReal tt, t; 36e5bffa22SHong Zhang PetscScalar *b; 37e5bffa22SHong Zhang const PetscReal *B = rk->tableau->binterp; 38e5bffa22SHong Zhang 39e5bffa22SHong Zhang PetscFunctionBegin; 403c633725SBarry Smith PetscCheck(B, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "TSRK %s does not have an interpolation formula", rk->tableau->name); 4163a6f1b4SHong Zhang t = (itime - rk->ptime) / h; 429566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(s, &b)); 43e5bffa22SHong Zhang for (i = 0; i < s; i++) b[i] = 0; 44e5bffa22SHong Zhang for (j = 0, tt = t; j < p; j++, tt *= t) { 45ad540459SPierre Jolivet for (i = 0; i < s; i++) b[i] += h * B[i * p + j] * tt; 46e5bffa22SHong Zhang } 479566063dSJacob Faibussowitsch PetscCall(VecCopy(rk->X0, X)); 489566063dSJacob Faibussowitsch PetscCall(VecMAXPY(X, s, b, rk->YdotRHS_slow)); 499566063dSJacob Faibussowitsch PetscCall(PetscFree(b)); 503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 51e5bffa22SHong Zhang } 52e5bffa22SHong Zhang 53d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSStepRefine_RK_MultirateNonsplit(TS ts) 54d71ae5a4SJacob Faibussowitsch { 5563a6f1b4SHong Zhang TS previousts, subts; 5663a6f1b4SHong Zhang TS_RK *rk = (TS_RK *)ts->data; 5763a6f1b4SHong Zhang RKTableau tab = rk->tableau; 5863a6f1b4SHong Zhang Vec *Y = rk->Y, *YdotRHS = rk->YdotRHS; 5963a6f1b4SHong Zhang Vec vec_fast, subvec_fast; 6063a6f1b4SHong Zhang const PetscInt s = tab->s; 6163a6f1b4SHong Zhang const PetscReal *A = tab->A, *c = tab->c; 6263a6f1b4SHong Zhang PetscScalar *w = rk->work; 6363a6f1b4SHong Zhang PetscInt i, j, k; 6463a6f1b4SHong Zhang PetscReal t = ts->ptime, h = ts->time_step; 6563a6f1b4SHong Zhang 66362febeeSStefano Zampini PetscFunctionBegin; 679566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ts->vec_sol, &vec_fast)); 6863a6f1b4SHong Zhang previousts = rk->subts_current; 699566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetSubTS(rk->subts_current, "fast", &subts)); 709566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetSubTS(subts, "fast", &subts)); 7163a6f1b4SHong Zhang for (k = 0; k < rk->dtratio; k++) { 7263a6f1b4SHong Zhang for (i = 0; i < s; i++) { 739566063dSJacob Faibussowitsch PetscCall(TSInterpolate_RK_MultirateNonsplit(ts, t + k * h / rk->dtratio + h / rk->dtratio * c[i], Y[i])); 7463a6f1b4SHong Zhang for (j = 0; j < i; j++) w[j] = h / rk->dtratio * A[i * s + j]; 7563a6f1b4SHong Zhang /* update the fast components in the stage value, the slow components will be ignored, so we do not care the slow part in vec_fast */ 769566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vec_sol, vec_fast)); 779566063dSJacob Faibussowitsch PetscCall(VecMAXPY(vec_fast, i, w, YdotRHS)); 7863a6f1b4SHong Zhang /* update the fast components in the stage value */ 799566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(vec_fast, rk->is_fast, &subvec_fast)); 809566063dSJacob Faibussowitsch PetscCall(VecISCopy(Y[i], rk->is_fast, SCATTER_FORWARD, subvec_fast)); 819566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(vec_fast, rk->is_fast, &subvec_fast)); 8263a6f1b4SHong Zhang /* compute the stage RHS */ 839566063dSJacob Faibussowitsch PetscCall(TSComputeRHSFunction(ts, t + k * h / rk->dtratio + h / rk->dtratio * c[i], Y[i], YdotRHS[i])); 8463a6f1b4SHong Zhang } 859566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vec_sol, vec_fast)); 869566063dSJacob Faibussowitsch PetscCall(TSEvaluateStep(ts, tab->order, vec_fast, NULL)); 8763a6f1b4SHong Zhang /* update the fast components in the solution */ 889566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(vec_fast, rk->is_fast, &subvec_fast)); 899566063dSJacob Faibussowitsch PetscCall(VecISCopy(ts->vec_sol, rk->is_fast, SCATTER_FORWARD, subvec_fast)); 909566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(vec_fast, rk->is_fast, &subvec_fast)); 9163a6f1b4SHong Zhang 9263a6f1b4SHong Zhang if (subts) { 9363a6f1b4SHong Zhang Vec *YdotRHS_copy; 949566063dSJacob Faibussowitsch PetscCall(VecDuplicateVecs(ts->vec_sol, s, &YdotRHS_copy)); 9563a6f1b4SHong Zhang rk->subts_current = rk->subts_fast; 9663a6f1b4SHong Zhang ts->ptime = t + k * h / rk->dtratio; 9763a6f1b4SHong Zhang ts->time_step = h / rk->dtratio; 989566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetIS(rk->subts_current, "fast", &rk->is_fast)); 9963a6f1b4SHong Zhang for (i = 0; i < s; i++) { 1009566063dSJacob Faibussowitsch PetscCall(VecCopy(rk->YdotRHS_slow[i], YdotRHS_copy[i])); 1019566063dSJacob Faibussowitsch PetscCall(VecCopy(YdotRHS[i], rk->YdotRHS_slow[i])); 10263a6f1b4SHong Zhang } 10363a6f1b4SHong Zhang 1049566063dSJacob Faibussowitsch PetscCall(TSStepRefine_RK_MultirateNonsplit(ts)); 10563a6f1b4SHong Zhang 10663a6f1b4SHong Zhang rk->subts_current = previousts; 10763a6f1b4SHong Zhang ts->ptime = t; 10863a6f1b4SHong Zhang ts->time_step = h; 1099566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetIS(previousts, "fast", &rk->is_fast)); 11048a46eb9SPierre Jolivet for (i = 0; i < s; i++) PetscCall(VecCopy(YdotRHS_copy[i], rk->YdotRHS_slow[i])); 1119566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(s, &YdotRHS_copy)); 11263a6f1b4SHong Zhang } 11363a6f1b4SHong Zhang } 1149566063dSJacob Faibussowitsch PetscCall(VecDestroy(&vec_fast)); 1153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11663a6f1b4SHong Zhang } 11763a6f1b4SHong Zhang 118d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSStep_RK_MultirateNonsplit(TS ts) 119d71ae5a4SJacob Faibussowitsch { 120e5bffa22SHong Zhang TS_RK *rk = (TS_RK *)ts->data; 121e5bffa22SHong Zhang RKTableau tab = rk->tableau; 122e5bffa22SHong Zhang Vec *Y = rk->Y, *YdotRHS = rk->YdotRHS, *YdotRHS_slow = rk->YdotRHS_slow; 123e5bffa22SHong Zhang Vec stage_slow, sol_slow; /* vectors store the slow components */ 124e5bffa22SHong Zhang Vec subvec_slow; /* sub vector to store the slow components */ 125e5bffa22SHong Zhang IS is_slow = rk->is_slow; 126e5bffa22SHong Zhang const PetscInt s = tab->s; 127e5bffa22SHong Zhang const PetscReal *A = tab->A, *c = tab->c; 128e5bffa22SHong Zhang PetscScalar *w = rk->work; 12963a6f1b4SHong Zhang PetscInt i, j, dtratio = rk->dtratio; 130e5bffa22SHong Zhang PetscReal next_time_step = ts->time_step, t = ts->ptime, h = ts->time_step; 131e5bffa22SHong Zhang 132e5bffa22SHong Zhang PetscFunctionBegin; 133e5bffa22SHong Zhang rk->status = TS_STEP_INCOMPLETE; 1349566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ts->vec_sol, &stage_slow)); 1359566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ts->vec_sol, &sol_slow)); 1369566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vec_sol, rk->X0)); 137e5bffa22SHong Zhang for (i = 0; i < s; i++) { 138e5bffa22SHong Zhang rk->stage_time = t + h * c[i]; 1399566063dSJacob Faibussowitsch PetscCall(TSPreStage(ts, rk->stage_time)); 1409566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vec_sol, Y[i])); 141e5bffa22SHong Zhang for (j = 0; j < i; j++) w[j] = h * A[i * s + j]; 1429566063dSJacob Faibussowitsch PetscCall(VecMAXPY(Y[i], i, w, YdotRHS_slow)); 1439566063dSJacob Faibussowitsch PetscCall(TSPostStage(ts, rk->stage_time, i, Y)); 144e5bffa22SHong Zhang /* compute the stage RHS */ 1459566063dSJacob Faibussowitsch PetscCall(TSComputeRHSFunction(ts, t + h * c[i], Y[i], YdotRHS_slow[i])); 146e5bffa22SHong Zhang } 147e5bffa22SHong Zhang /* update the slow components in the solution */ 148e5bffa22SHong Zhang rk->YdotRHS = YdotRHS_slow; 149e5bffa22SHong Zhang rk->dtratio = 1; 1509566063dSJacob Faibussowitsch PetscCall(TSEvaluateStep(ts, tab->order, sol_slow, NULL)); 151e5bffa22SHong Zhang rk->dtratio = dtratio; 152e5bffa22SHong Zhang rk->YdotRHS = YdotRHS; 153e5bffa22SHong Zhang /* update the slow components in the solution */ 1549566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(sol_slow, is_slow, &subvec_slow)); 1559566063dSJacob Faibussowitsch PetscCall(VecISCopy(ts->vec_sol, is_slow, SCATTER_FORWARD, subvec_slow)); 1569566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(sol_slow, is_slow, &subvec_slow)); 157e5bffa22SHong Zhang 15863a6f1b4SHong Zhang rk->subts_current = ts; 15963a6f1b4SHong Zhang rk->ptime = t; 16063a6f1b4SHong Zhang rk->time_step = h; 1619566063dSJacob Faibussowitsch PetscCall(TSStepRefine_RK_MultirateNonsplit(ts)); 16263a6f1b4SHong Zhang 163e5bffa22SHong Zhang ts->ptime = t + ts->time_step; 164e5bffa22SHong Zhang ts->time_step = next_time_step; 165e5bffa22SHong Zhang rk->status = TS_STEP_COMPLETE; 16663a6f1b4SHong Zhang 167e5bffa22SHong Zhang /* free memory of work vectors */ 1689566063dSJacob Faibussowitsch PetscCall(VecDestroy(&stage_slow)); 1699566063dSJacob Faibussowitsch PetscCall(VecDestroy(&sol_slow)); 1703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 171e5bffa22SHong Zhang } 172e5bffa22SHong Zhang 173d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_RK_MultirateNonsplit(TS ts) 174d71ae5a4SJacob Faibussowitsch { 1750fe4d17eSHong Zhang TS_RK *rk = (TS_RK *)ts->data; 1760fe4d17eSHong Zhang RKTableau tab = rk->tableau; 1770fe4d17eSHong Zhang 1780fe4d17eSHong Zhang PetscFunctionBegin; 1799566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetIS(ts, "slow", &rk->is_slow)); 1809566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetIS(ts, "fast", &rk->is_fast)); 1813c633725SBarry Smith PetscCheck(rk->is_slow && rk->is_fast, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set up RHSSplits with TSRHSSplitSetIS() using split names 'slow' and 'fast' respectively in order to use multirate RK"); 1829566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetSubTS(ts, "slow", &rk->subts_slow)); 1839566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetSubTS(ts, "fast", &rk->subts_fast)); 1843c633725SBarry Smith PetscCheck(rk->subts_slow && rk->subts_fast, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set up the RHSFunctions for 'slow' and 'fast' components using TSRHSSplitSetRHSFunction() or calling TSSetRHSFunction() for each sub-TS"); 1859566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ts->vec_sol, &rk->X0)); 1869566063dSJacob Faibussowitsch PetscCall(VecDuplicateVecs(ts->vec_sol, tab->s, &rk->YdotRHS_slow)); 1870fe4d17eSHong Zhang rk->subts_current = rk->subts_fast; 1880fe4d17eSHong Zhang 18902555c94SHong Zhang ts->ops->step = TSStep_RK_MultirateNonsplit; 19002555c94SHong Zhang ts->ops->interpolate = TSInterpolate_RK_MultirateNonsplit; 1913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1920fe4d17eSHong Zhang } 1930fe4d17eSHong Zhang 19463a6f1b4SHong Zhang /* 19563a6f1b4SHong Zhang Copy DM from tssrc to tsdest, while keeping the original DMTS and DMSNES in tsdest. 19663a6f1b4SHong Zhang */ 197d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSCopyDM(TS tssrc, TS tsdest) 198d71ae5a4SJacob Faibussowitsch { 19963a6f1b4SHong Zhang DM newdm, dmsrc, dmdest; 20063a6f1b4SHong Zhang 20163a6f1b4SHong Zhang PetscFunctionBegin; 2029566063dSJacob Faibussowitsch PetscCall(TSGetDM(tssrc, &dmsrc)); 2039566063dSJacob Faibussowitsch PetscCall(DMClone(dmsrc, &newdm)); 2049566063dSJacob Faibussowitsch PetscCall(TSGetDM(tsdest, &dmdest)); 2059566063dSJacob Faibussowitsch PetscCall(DMCopyDMTS(dmdest, newdm)); 2069566063dSJacob Faibussowitsch PetscCall(DMCopyDMSNES(dmdest, newdm)); 2079566063dSJacob Faibussowitsch PetscCall(TSSetDM(tsdest, newdm)); 2089566063dSJacob Faibussowitsch PetscCall(DMDestroy(&newdm)); 2093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21063a6f1b4SHong Zhang } 21163a6f1b4SHong Zhang 212d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSReset_RK_MultirateSplit(TS ts) 213d71ae5a4SJacob Faibussowitsch { 214474dd773SHong Zhang TS_RK *rk = (TS_RK *)ts->data; 215474dd773SHong Zhang 216474dd773SHong Zhang PetscFunctionBegin; 217bb42530cSHong Zhang if (rk->subts_slow) { 2189566063dSJacob Faibussowitsch PetscCall(PetscFree(rk->subts_slow->data)); 219bb42530cSHong Zhang rk->subts_slow = NULL; 220bb42530cSHong Zhang } 221bb42530cSHong Zhang if (rk->subts_fast) { 2229566063dSJacob Faibussowitsch PetscCall(PetscFree(rk->YdotRHS_fast)); 2239566063dSJacob Faibussowitsch PetscCall(PetscFree(rk->YdotRHS_slow)); 2249566063dSJacob Faibussowitsch PetscCall(VecDestroy(&rk->X0)); 2259566063dSJacob Faibussowitsch PetscCall(TSReset_RK_MultirateSplit(rk->subts_fast)); 2269566063dSJacob Faibussowitsch PetscCall(PetscFree(rk->subts_fast->data)); 227bb42530cSHong Zhang rk->subts_fast = NULL; 228bb42530cSHong Zhang } 2293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 230474dd773SHong Zhang } 231474dd773SHong Zhang 232d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSInterpolate_RK_MultirateSplit(TS ts, PetscReal itime, Vec X) 233d71ae5a4SJacob Faibussowitsch { 234474dd773SHong Zhang TS_RK *rk = (TS_RK *)ts->data; 23563a6f1b4SHong Zhang Vec Xslow; 236474dd773SHong Zhang PetscInt s = rk->tableau->s, p = rk->tableau->p, i, j; 237474dd773SHong Zhang PetscReal h; 238474dd773SHong Zhang PetscReal tt, t; 239474dd773SHong Zhang PetscScalar *b; 240474dd773SHong Zhang const PetscReal *B = rk->tableau->binterp; 241474dd773SHong Zhang 242474dd773SHong Zhang PetscFunctionBegin; 2433c633725SBarry Smith PetscCheck(B, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "TSRK %s does not have an interpolation formula", rk->tableau->name); 244474dd773SHong Zhang 245474dd773SHong Zhang switch (rk->status) { 246474dd773SHong Zhang case TS_STEP_INCOMPLETE: 247474dd773SHong Zhang case TS_STEP_PENDING: 248474dd773SHong Zhang h = ts->time_step; 249474dd773SHong Zhang t = (itime - ts->ptime) / h; 250474dd773SHong Zhang break; 251474dd773SHong Zhang case TS_STEP_COMPLETE: 252474dd773SHong Zhang h = ts->ptime - ts->ptime_prev; 253474dd773SHong Zhang t = (itime - ts->ptime) / h + 1; /* In the interval [0,1] */ 254474dd773SHong Zhang break; 255d71ae5a4SJacob Faibussowitsch default: 256d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "Invalid TSStepStatus"); 257474dd773SHong Zhang } 2589566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(s, &b)); 259474dd773SHong Zhang for (i = 0; i < s; i++) b[i] = 0; 260474dd773SHong Zhang for (j = 0, tt = t; j < p; j++, tt *= t) { 261ad540459SPierre Jolivet for (i = 0; i < s; i++) b[i] += h * B[i * p + j] * tt; 262474dd773SHong Zhang } 26348a46eb9SPierre Jolivet for (i = 0; i < s; i++) PetscCall(VecGetSubVector(rk->YdotRHS[i], rk->is_slow, &rk->YdotRHS_slow[i])); 2649566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(X, rk->is_slow, &Xslow)); 2659566063dSJacob Faibussowitsch PetscCall(VecISCopy(rk->X0, rk->is_slow, SCATTER_REVERSE, Xslow)); 2669566063dSJacob Faibussowitsch PetscCall(VecMAXPY(Xslow, s, b, rk->YdotRHS_slow)); 2679566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(X, rk->is_slow, &Xslow)); 26848a46eb9SPierre Jolivet for (i = 0; i < s; i++) PetscCall(VecRestoreSubVector(rk->YdotRHS[i], rk->is_slow, &rk->YdotRHS_slow[i])); 2699566063dSJacob Faibussowitsch PetscCall(PetscFree(b)); 2703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 271474dd773SHong Zhang } 272474dd773SHong Zhang 273474dd773SHong Zhang /* 274474dd773SHong Zhang This is for partitioned RHS multirate RK method 275474dd773SHong Zhang The step completion formula is 276474dd773SHong Zhang 277474dd773SHong Zhang x1 = x0 + h b^T YdotRHS 278474dd773SHong Zhang 279474dd773SHong Zhang */ 280d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSEvaluateStep_RK_MultirateSplit(TS ts, PetscInt order, Vec X, PetscBool *done) 281d71ae5a4SJacob Faibussowitsch { 282474dd773SHong Zhang TS_RK *rk = (TS_RK *)ts->data; 283474dd773SHong Zhang RKTableau tab = rk->tableau; 284474dd773SHong Zhang Vec Xslow, Xfast; /* subvectors of X which store slow components and fast components respectively */ 285474dd773SHong Zhang PetscScalar *w = rk->work; 286474dd773SHong Zhang PetscReal h = ts->time_step; 287474dd773SHong Zhang PetscInt s = tab->s, j; 288474dd773SHong Zhang 289474dd773SHong Zhang PetscFunctionBegin; 2909566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vec_sol, X)); 291474dd773SHong Zhang if (rk->slow) { 292474dd773SHong Zhang for (j = 0; j < s; j++) w[j] = h * tab->b[j]; 2939566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(ts->vec_sol, rk->is_slow, &Xslow)); 2949566063dSJacob Faibussowitsch PetscCall(VecMAXPY(Xslow, s, w, rk->YdotRHS_slow)); 2959566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(ts->vec_sol, rk->is_slow, &Xslow)); 296474dd773SHong Zhang } else { 297474dd773SHong Zhang for (j = 0; j < s; j++) w[j] = h / rk->dtratio * tab->b[j]; 2989566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(X, rk->is_fast, &Xfast)); 2999566063dSJacob Faibussowitsch PetscCall(VecMAXPY(Xfast, s, w, rk->YdotRHS_fast)); 3009566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(X, rk->is_fast, &Xfast)); 301474dd773SHong Zhang } 3023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 303474dd773SHong Zhang } 304474dd773SHong Zhang 305d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSStepRefine_RK_MultirateSplit(TS ts) 306d71ae5a4SJacob Faibussowitsch { 30763a6f1b4SHong Zhang TS_RK *rk = (TS_RK *)ts->data; 30863a6f1b4SHong Zhang TS subts_fast = rk->subts_fast, currentlevelts; 30963a6f1b4SHong Zhang TS_RK *subrk_fast = (TS_RK *)subts_fast->data; 31063a6f1b4SHong Zhang RKTableau tab = rk->tableau; 31163a6f1b4SHong Zhang Vec *Y = rk->Y; 31263a6f1b4SHong Zhang Vec *YdotRHS = rk->YdotRHS, *YdotRHS_fast = rk->YdotRHS_fast; 31363a6f1b4SHong Zhang Vec Yfast, Xfast; 31463a6f1b4SHong Zhang const PetscInt s = tab->s; 31563a6f1b4SHong Zhang const PetscReal *A = tab->A, *c = tab->c; 31663a6f1b4SHong Zhang PetscScalar *w = rk->work; 31763a6f1b4SHong Zhang PetscInt i, j, k; 31863a6f1b4SHong Zhang PetscReal t = ts->ptime, h = ts->time_step; 31963a6f1b4SHong Zhang 320362febeeSStefano Zampini PetscFunctionBegin; 32163a6f1b4SHong Zhang for (k = 0; k < rk->dtratio; k++) { 3229566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(ts->vec_sol, rk->is_fast, &Xfast)); 32348a46eb9SPierre Jolivet for (i = 0; i < s; i++) PetscCall(VecGetSubVector(YdotRHS[i], rk->is_fast, &YdotRHS_fast[i])); 324a5b23f4aSJose E. Roman /* propagate fast component using small time steps */ 32563a6f1b4SHong Zhang for (i = 0; i < s; i++) { 32663a6f1b4SHong Zhang /* stage value for slow components */ 3279566063dSJacob Faibussowitsch PetscCall(TSInterpolate_RK_MultirateSplit(rk->ts_root, t + k * h / rk->dtratio + h / rk->dtratio * c[i], Y[i])); 32863a6f1b4SHong Zhang currentlevelts = rk->ts_root; 32963a6f1b4SHong Zhang while (currentlevelts != ts) { /* all the slow parts need to be interpolated separated */ 33063a6f1b4SHong Zhang currentlevelts = ((TS_RK *)currentlevelts->data)->subts_fast; 3319566063dSJacob Faibussowitsch PetscCall(TSInterpolate_RK_MultirateSplit(currentlevelts, t + k * h / rk->dtratio + h / rk->dtratio * c[i], Y[i])); 33263a6f1b4SHong Zhang } 33363a6f1b4SHong Zhang for (j = 0; j < i; j++) w[j] = h / rk->dtratio * A[i * s + j]; 33463a6f1b4SHong Zhang subrk_fast->stage_time = t + h / rk->dtratio * c[i]; 3359566063dSJacob Faibussowitsch PetscCall(TSPreStage(subts_fast, subrk_fast->stage_time)); 33663a6f1b4SHong Zhang /* stage value for fast components */ 3379566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(Y[i], rk->is_fast, &Yfast)); 3389566063dSJacob Faibussowitsch PetscCall(VecCopy(Xfast, Yfast)); 3399566063dSJacob Faibussowitsch PetscCall(VecMAXPY(Yfast, i, w, YdotRHS_fast)); 3409566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(Y[i], rk->is_fast, &Yfast)); 3419566063dSJacob Faibussowitsch PetscCall(TSPostStage(subts_fast, subrk_fast->stage_time, i, Y)); 34263a6f1b4SHong Zhang /* compute the stage RHS for fast components */ 3439566063dSJacob Faibussowitsch PetscCall(TSComputeRHSFunction(subts_fast, t + k * h * rk->dtratio + h / rk->dtratio * c[i], Y[i], YdotRHS_fast[i])); 34463a6f1b4SHong Zhang } 3459566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(ts->vec_sol, rk->is_fast, &Xfast)); 34663a6f1b4SHong Zhang /* update the value of fast components using fast time step */ 34763a6f1b4SHong Zhang rk->slow = PETSC_FALSE; 3489566063dSJacob Faibussowitsch PetscCall(TSEvaluateStep_RK_MultirateSplit(ts, tab->order, ts->vec_sol, NULL)); 34948a46eb9SPierre Jolivet for (i = 0; i < s; i++) PetscCall(VecRestoreSubVector(YdotRHS[i], rk->is_fast, &YdotRHS_fast[i])); 35063a6f1b4SHong Zhang 35163a6f1b4SHong Zhang if (subrk_fast->subts_fast) { 35263a6f1b4SHong Zhang subts_fast->ptime = t + k * h / rk->dtratio; 35363a6f1b4SHong Zhang subts_fast->time_step = h / rk->dtratio; 3549566063dSJacob Faibussowitsch PetscCall(TSStepRefine_RK_MultirateSplit(subts_fast)); 35563a6f1b4SHong Zhang } 35663a6f1b4SHong Zhang /* update the fast components of the solution */ 3579566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(ts->vec_sol, rk->is_fast, &Xfast)); 3589566063dSJacob Faibussowitsch PetscCall(VecISCopy(rk->X0, rk->is_fast, SCATTER_FORWARD, Xfast)); 3599566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(ts->vec_sol, rk->is_fast, &Xfast)); 36063a6f1b4SHong Zhang } 3613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 36263a6f1b4SHong Zhang } 36363a6f1b4SHong Zhang 364d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSStep_RK_MultirateSplit(TS ts) 365d71ae5a4SJacob Faibussowitsch { 366474dd773SHong Zhang TS_RK *rk = (TS_RK *)ts->data; 367474dd773SHong Zhang RKTableau tab = rk->tableau; 368474dd773SHong Zhang Vec *Y = rk->Y, *YdotRHS = rk->YdotRHS; 36963a6f1b4SHong Zhang Vec *YdotRHS_fast = rk->YdotRHS_fast, *YdotRHS_slow = rk->YdotRHS_slow; 370474dd773SHong Zhang Vec Yslow, Yfast; /* subvectors store the stges of slow components and fast components respectively */ 371474dd773SHong Zhang const PetscInt s = tab->s; 372474dd773SHong Zhang const PetscReal *A = tab->A, *c = tab->c; 373474dd773SHong Zhang PetscScalar *w = rk->work; 37463a6f1b4SHong Zhang PetscInt i, j; 375474dd773SHong Zhang PetscReal next_time_step = ts->time_step, t = ts->ptime, h = ts->time_step; 376474dd773SHong Zhang 377474dd773SHong Zhang PetscFunctionBegin; 378474dd773SHong Zhang rk->status = TS_STEP_INCOMPLETE; 379474dd773SHong Zhang for (i = 0; i < s; i++) { 3809566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(YdotRHS[i], rk->is_slow, &YdotRHS_slow[i])); 3819566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(YdotRHS[i], rk->is_fast, &YdotRHS_fast[i])); 382474dd773SHong Zhang } 3839566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vec_sol, rk->X0)); 384a5b23f4aSJose E. Roman /* propagate both slow and fast components using large time steps */ 385474dd773SHong Zhang for (i = 0; i < s; i++) { 386474dd773SHong Zhang rk->stage_time = t + h * c[i]; 3879566063dSJacob Faibussowitsch PetscCall(TSPreStage(ts, rk->stage_time)); 3889566063dSJacob Faibussowitsch PetscCall(VecCopy(ts->vec_sol, Y[i])); 3899566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(Y[i], rk->is_fast, &Yfast)); 3909566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(Y[i], rk->is_slow, &Yslow)); 391474dd773SHong Zhang for (j = 0; j < i; j++) w[j] = h * A[i * s + j]; 3929566063dSJacob Faibussowitsch PetscCall(VecMAXPY(Yfast, i, w, YdotRHS_fast)); 3939566063dSJacob Faibussowitsch PetscCall(VecMAXPY(Yslow, i, w, YdotRHS_slow)); 3949566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(Y[i], rk->is_fast, &Yfast)); 3959566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(Y[i], rk->is_slow, &Yslow)); 3969566063dSJacob Faibussowitsch PetscCall(TSPostStage(ts, rk->stage_time, i, Y)); 3979566063dSJacob Faibussowitsch PetscCall(TSComputeRHSFunction(rk->subts_slow, t + h * c[i], Y[i], YdotRHS_slow[i])); 3989566063dSJacob Faibussowitsch PetscCall(TSComputeRHSFunction(rk->subts_fast, t + h * c[i], Y[i], YdotRHS_fast[i])); 399474dd773SHong Zhang } 400474dd773SHong Zhang rk->slow = PETSC_TRUE; 40163a6f1b4SHong Zhang /* update the slow components of the solution using slow time step */ 4029566063dSJacob Faibussowitsch PetscCall(TSEvaluateStep_RK_MultirateSplit(ts, tab->order, ts->vec_sol, NULL)); 40363a6f1b4SHong Zhang /* YdotRHS will be used for interpolation during refinement */ 404474dd773SHong Zhang for (i = 0; i < s; i++) { 4059566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(YdotRHS[i], rk->is_slow, &YdotRHS_slow[i])); 4069566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(YdotRHS[i], rk->is_fast, &YdotRHS_fast[i])); 407474dd773SHong Zhang } 40863a6f1b4SHong Zhang 4099566063dSJacob Faibussowitsch PetscCall(TSStepRefine_RK_MultirateSplit(ts)); 41063a6f1b4SHong Zhang 411bb42530cSHong Zhang ts->ptime = t + ts->time_step; 412474dd773SHong Zhang ts->time_step = next_time_step; 413474dd773SHong Zhang rk->status = TS_STEP_COMPLETE; 4143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 415474dd773SHong Zhang } 416474dd773SHong Zhang 417d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_RK_MultirateSplit(TS ts) 418d71ae5a4SJacob Faibussowitsch { 4190fe4d17eSHong Zhang TS_RK *rk = (TS_RK *)ts->data, *nextlevelrk, *currentlevelrk; 4200fe4d17eSHong Zhang TS nextlevelts; 4210fe4d17eSHong Zhang Vec X0; 4220fe4d17eSHong Zhang 4230fe4d17eSHong Zhang PetscFunctionBegin; 4249566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetIS(ts, "slow", &rk->is_slow)); 4259566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetIS(ts, "fast", &rk->is_fast)); 4263c633725SBarry Smith PetscCheck(rk->is_slow && rk->is_fast, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set up RHSSplits with TSRHSSplitSetIS() using split names 'slow' and 'fast' respectively in order to use -ts_type bsi"); 4279566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetSubTS(ts, "slow", &rk->subts_slow)); 4289566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetSubTS(ts, "fast", &rk->subts_fast)); 4293c633725SBarry Smith PetscCheck(rk->subts_slow && rk->subts_fast, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set up the RHSFunctions for 'slow' and 'fast' components using TSRHSSplitSetRHSFunction() or calling TSSetRHSFunction() for each sub-TS"); 4300fe4d17eSHong Zhang 4319566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ts->vec_sol, &X0)); 4320fe4d17eSHong Zhang /* The TS at each level share the same tableau, work array, solution vector, stage values and stage derivatives */ 4330fe4d17eSHong Zhang currentlevelrk = rk; 4340fe4d17eSHong Zhang while (currentlevelrk->subts_fast) { 4359566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rk->tableau->s, ¤tlevelrk->YdotRHS_fast)); 4369566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rk->tableau->s, ¤tlevelrk->YdotRHS_slow)); 4379566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)X0)); 4380fe4d17eSHong Zhang currentlevelrk->X0 = X0; 4390fe4d17eSHong Zhang currentlevelrk->ts_root = ts; 4400fe4d17eSHong Zhang 4410fe4d17eSHong Zhang /* set up the ts for the slow part */ 4420fe4d17eSHong Zhang nextlevelts = currentlevelrk->subts_slow; 4434dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&nextlevelrk)); 4440fe4d17eSHong Zhang nextlevelrk->tableau = rk->tableau; 4450fe4d17eSHong Zhang nextlevelrk->work = rk->work; 4460fe4d17eSHong Zhang nextlevelrk->Y = rk->Y; 4470fe4d17eSHong Zhang nextlevelrk->YdotRHS = rk->YdotRHS; 4480fe4d17eSHong Zhang nextlevelts->data = (void *)nextlevelrk; 4499566063dSJacob Faibussowitsch PetscCall(TSCopyDM(ts, nextlevelts)); 4509566063dSJacob Faibussowitsch PetscCall(TSSetSolution(nextlevelts, ts->vec_sol)); 4510fe4d17eSHong Zhang 4520fe4d17eSHong Zhang /* set up the ts for the fast part */ 4530fe4d17eSHong Zhang nextlevelts = currentlevelrk->subts_fast; 4544dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&nextlevelrk)); 4550fe4d17eSHong Zhang nextlevelrk->tableau = rk->tableau; 4560fe4d17eSHong Zhang nextlevelrk->work = rk->work; 4570fe4d17eSHong Zhang nextlevelrk->Y = rk->Y; 4580fe4d17eSHong Zhang nextlevelrk->YdotRHS = rk->YdotRHS; 4590fe4d17eSHong Zhang nextlevelrk->dtratio = rk->dtratio; 4609566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetIS(nextlevelts, "slow", &nextlevelrk->is_slow)); 4619566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetSubTS(nextlevelts, "slow", &nextlevelrk->subts_slow)); 4629566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetIS(nextlevelts, "fast", &nextlevelrk->is_fast)); 4639566063dSJacob Faibussowitsch PetscCall(TSRHSSplitGetSubTS(nextlevelts, "fast", &nextlevelrk->subts_fast)); 4640fe4d17eSHong Zhang nextlevelts->data = (void *)nextlevelrk; 4659566063dSJacob Faibussowitsch PetscCall(TSCopyDM(ts, nextlevelts)); 4669566063dSJacob Faibussowitsch PetscCall(TSSetSolution(nextlevelts, ts->vec_sol)); 4670fe4d17eSHong Zhang 4680fe4d17eSHong Zhang currentlevelrk = nextlevelrk; 4690fe4d17eSHong Zhang } 4709566063dSJacob Faibussowitsch PetscCall(VecDestroy(&X0)); 4710fe4d17eSHong Zhang 47202555c94SHong Zhang ts->ops->step = TSStep_RK_MultirateSplit; 47302555c94SHong Zhang ts->ops->evaluatestep = TSEvaluateStep_RK_MultirateSplit; 47402555c94SHong Zhang ts->ops->interpolate = TSInterpolate_RK_MultirateSplit; 4753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4760fe4d17eSHong Zhang } 4770fe4d17eSHong Zhang 478d71ae5a4SJacob Faibussowitsch PetscErrorCode TSRKSetMultirate_RK(TS ts, PetscBool use_multirate) 479d71ae5a4SJacob Faibussowitsch { 480474dd773SHong Zhang TS_RK *rk = (TS_RK *)ts->data; 481474dd773SHong Zhang 482474dd773SHong Zhang PetscFunctionBegin; 483474dd773SHong Zhang PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 4840fe4d17eSHong Zhang rk->use_multirate = use_multirate; 4850fe4d17eSHong Zhang if (use_multirate) { 486474dd773SHong Zhang rk->dtratio = 2; 4879566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSetUp_RK_MultirateSplit_C", TSSetUp_RK_MultirateSplit)); 4889566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSReset_RK_MultirateSplit_C", TSReset_RK_MultirateSplit)); 4899566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSetUp_RK_MultirateNonsplit_C", TSSetUp_RK_MultirateNonsplit)); 4909566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSReset_RK_MultirateNonsplit_C", TSReset_RK_MultirateNonsplit)); 4910fe4d17eSHong Zhang } else { 4920fe4d17eSHong Zhang rk->dtratio = 0; 4939566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSetUp_RK_MultirateSplit_C", NULL)); 4949566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSReset_RK_MultirateSplit_C", NULL)); 4959566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSetUp_RK_MultirateNonsplit_C", NULL)); 4969566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSReset_RK_MultirateNonsplit_C", NULL)); 497474dd773SHong Zhang } 4983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 499474dd773SHong Zhang } 500474dd773SHong Zhang 501d71ae5a4SJacob Faibussowitsch PetscErrorCode TSRKGetMultirate_RK(TS ts, PetscBool *use_multirate) 502d71ae5a4SJacob Faibussowitsch { 5030fe4d17eSHong Zhang TS_RK *rk = (TS_RK *)ts->data; 5040fe4d17eSHong Zhang 5050fe4d17eSHong Zhang PetscFunctionBegin; 5060fe4d17eSHong Zhang PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 5070fe4d17eSHong Zhang *use_multirate = rk->use_multirate; 5083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5090fe4d17eSHong Zhang } 510