xref: /petsc/src/ts/impls/explicit/rk/mrk.c (revision 37d05b0256c1e9ba4bc423c4eccb3df226931ef0)
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 
TSReset_RK_MultirateNonsplit(TS ts)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 
TSInterpolate_RK_MultirateNonsplit(TS ts,PetscReal itime,Vec X)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 
TSStepRefine_RK_MultirateNonsplit(TS ts)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 
TSStep_RK_MultirateNonsplit(TS ts)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 
TSSetUp_RK_MultirateNonsplit(TS ts)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 */
TSCopyDM(TS tssrc,TS tsdest)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 
TSReset_RK_MultirateSplit(TS ts)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 
TSInterpolate_RK_MultirateSplit(TS ts,PetscReal itime,Vec X)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 */
TSEvaluateStep_RK_MultirateSplit(TS ts,PetscInt order,Vec X,PetscBool * done)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 
TSStepRefine_RK_MultirateSplit(TS ts)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 
TSStep_RK_MultirateSplit(TS ts)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 
TSSetUp_RK_MultirateSplit(TS ts)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, &currentlevelrk->YdotRHS_fast));
4369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(rk->tableau->s, &currentlevelrk->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 
TSRKSetMultirate_RK(TS ts,PetscBool use_multirate)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 
TSRKGetMultirate_RK(TS ts,PetscBool * use_multirate)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