xref: /petsc/src/ts/trajectory/utils/reconstruct.c (revision 5f80ce2ab25dff0f4601e710601cbbcecf323266)
1 #include <petsc/private/tshistoryimpl.h>
2 #include <petscts.h>
3 
4 /* these two functions have been stolen from bdf.c */
5 static inline void LagrangeBasisVals(PetscInt n,PetscReal t,const PetscReal T[],PetscScalar L[])
6 {
7   PetscInt k,j;
8   for (k=0; k<n; k++) {
9     for (L[k]=1, j=0; j<n; j++) {
10       if (j != k) L[k] *= (t - T[j])/(T[k] - T[j]);
11     }
12   }
13 }
14 
15 static inline void LagrangeBasisDers(PetscInt n,PetscReal t,const PetscReal T[],PetscScalar dL[])
16 {
17   PetscInt k,j,i;
18   for (k=0; k<n; k++) {
19     for (dL[k]=0, j=0; j<n; j++) {
20       if (j != k) {
21         PetscReal L = 1/(T[k] - T[j]);
22         for (i=0; i<n; i++) {
23           if (i != j && i != k) L *= (t - T[i])/(T[k] - T[i]);
24         }
25         dL[k] += L;
26       }
27     }
28   }
29 }
30 
31 static inline PetscInt LagrangeGetId(PetscReal t, PetscInt n, const PetscReal T[], const PetscBool Taken[])
32 {
33   PetscInt _tid = 0;
34   while (_tid < n && PetscAbsReal(t-T[_tid]) > PETSC_SMALL) _tid++;
35   if (_tid < n && !Taken[_tid]) {
36     return _tid;
37   } else { /* we get back a negative id, where the maximum time is stored, since we use usually reconstruct backward in time */
38     PetscReal max = PETSC_MIN_REAL;
39     PetscInt  maxloc = n;
40     _tid = 0;
41     while (_tid < n) { maxloc = (max < T[_tid] && !Taken[_tid]) ? (max = T[_tid],_tid) : maxloc; _tid++; }
42     return -maxloc-1;
43   }
44 }
45 
46 PetscErrorCode TSTrajectoryReconstruct_Private(TSTrajectory tj,TS ts,PetscReal t,Vec U,Vec Udot)
47 {
48   TSHistory       tsh = tj->tsh;
49   const PetscReal *tshhist;
50   const PetscInt  *tshhist_id;
51   PetscInt        id, cnt, i, tshn;
52 
53   PetscFunctionBegin;
54   CHKERRQ(TSHistoryGetLocFromTime(tsh,t,&id));
55   CHKERRQ(TSHistoryGetHistory(tsh,&tshn,&tshhist,&tshhist_id,NULL));
56   if (id == -1 || id == -tshn - 1) {
57     PetscReal t0 = tshn ? tshhist[0]      : 0.0;
58     PetscReal tf = tshn ? tshhist[tshn-1] : 0.0;
59     SETERRQ(PetscObjectComm((PetscObject)tj),PETSC_ERR_PLIB,"Requested time %g is outside the history interval [%g, %g] (%d)",(double)t,(double)t0,(double)tf,tshn);
60   }
61   if (tj->monitor) {
62     CHKERRQ(PetscViewerASCIIPrintf(tj->monitor,"Reconstructing at time %g, order %D\n",(double)t,tj->lag.order));
63   }
64   if (!tj->lag.T) {
65     PetscInt o = tj->lag.order+1;
66     CHKERRQ(PetscMalloc5(o,&tj->lag.L,o,&tj->lag.T,o,&tj->lag.WW,2*o,&tj->lag.TT,o,&tj->lag.TW));
67     for (i = 0; i < o; i++) tj->lag.T[i] = PETSC_MAX_REAL;
68     CHKERRQ(VecDuplicateVecs(U ? U : Udot,o,&tj->lag.W));
69   }
70   cnt = 0;
71   CHKERRQ(PetscArrayzero(tj->lag.TT,2*(tj->lag.order+1)));
72   if (id < 0 || Udot) { /* populate snapshots for interpolation */
73     PetscInt s,nid = id < 0 ? -(id+1) : id;
74 
75     PetscInt up = PetscMin(nid + tj->lag.order/2+1,tshn);
76     PetscInt low = PetscMax(up-tj->lag.order-1,0);
77     up = PetscMin(PetscMax(low + tj->lag.order + 1,up),tshn);
78     if (tj->monitor) {
79       CHKERRQ(PetscViewerASCIIPushTab(tj->monitor));
80     }
81 
82     /* first see if we can reuse any */
83     for (s = up-1; s >= low; s--) {
84       PetscReal t = tshhist[s];
85       PetscInt tid = LagrangeGetId(t,tj->lag.order+1,tj->lag.T,tj->lag.TT);
86       if (tid < 0) continue;
87       if (tj->monitor) {
88         CHKERRQ(PetscViewerASCIIPrintf(tj->monitor,"Reusing snapshot %D, step %D, time %g\n",tid,tshhist_id[s],(double)t));
89       }
90       tj->lag.TT[tid] = PETSC_TRUE;
91       tj->lag.WW[cnt] = tj->lag.W[tid];
92       tj->lag.TW[cnt] = t;
93       tj->lag.TT[tj->lag.order+1 + s-low] = PETSC_TRUE; /* tell the next loop to skip it */
94       cnt++;
95     }
96 
97     /* now load the missing ones */
98     for (s = up-1; s >= low; s--) {
99       PetscReal t = tshhist[s];
100       PetscInt tid;
101 
102       if (tj->lag.TT[tj->lag.order+1 + s-low]) continue;
103       tid = LagrangeGetId(t,tj->lag.order+1,tj->lag.T,tj->lag.TT);
104       PetscCheck(tid < 0,PetscObjectComm((PetscObject)tj),PETSC_ERR_PLIB,"This should not happen");
105       tid = -tid-1;
106       if (tj->monitor) {
107         if (tj->lag.T[tid] < PETSC_MAX_REAL) {
108           CHKERRQ(PetscViewerASCIIPrintf(tj->monitor,"Discarding snapshot %D at time %g\n",tid,(double)tj->lag.T[tid]));
109         } else {
110           CHKERRQ(PetscViewerASCIIPrintf(tj->monitor,"New snapshot %D\n",tid));
111         }
112         CHKERRQ(PetscViewerASCIIPushTab(tj->monitor));
113       }
114       CHKERRQ(TSTrajectoryGetVecs(tj,ts,tshhist_id[s],&t,tj->lag.W[tid],NULL));
115       tj->lag.T[tid] = t;
116       if (tj->monitor) {
117         CHKERRQ(PetscViewerASCIIPopTab(tj->monitor));
118       }
119       tj->lag.TT[tid] = PETSC_TRUE;
120       tj->lag.WW[cnt] = tj->lag.W[tid];
121       tj->lag.TW[cnt] = t;
122       tj->lag.TT[tj->lag.order+1 + s-low] = PETSC_TRUE;
123       cnt++;
124     }
125     if (tj->monitor) {
126       CHKERRQ(PetscViewerASCIIPopTab(tj->monitor));
127     }
128   }
129   CHKERRQ(PetscArrayzero(tj->lag.TT,tj->lag.order+1));
130   if (id >=0 && U) { /* requested time match */
131     PetscInt tid = LagrangeGetId(t,tj->lag.order+1,tj->lag.T,tj->lag.TT);
132     if (tj->monitor) {
133       CHKERRQ(PetscViewerASCIIPrintf(tj->monitor,"Retrieving solution from exact step\n"));
134       CHKERRQ(PetscViewerASCIIPushTab(tj->monitor));
135     }
136     if (tid < 0) {
137       tid = -tid-1;
138       if (tj->monitor) {
139         if (tj->lag.T[tid] < PETSC_MAX_REAL) {
140           CHKERRQ(PetscViewerASCIIPrintf(tj->monitor,"Discarding snapshot %D at time %g\n",tid,(double)tj->lag.T[tid]));
141         } else {
142           CHKERRQ(PetscViewerASCIIPrintf(tj->monitor,"New snapshot %D\n",tid));
143         }
144         CHKERRQ(PetscViewerASCIIPushTab(tj->monitor));
145       }
146       CHKERRQ(TSTrajectoryGetVecs(tj,ts,tshhist_id[id],&t,tj->lag.W[tid],NULL));
147       if (tj->monitor) {
148         CHKERRQ(PetscViewerASCIIPopTab(tj->monitor));
149       }
150       tj->lag.T[tid] = t;
151     } else if (tj->monitor) {
152       CHKERRQ(PetscViewerASCIIPrintf(tj->monitor,"Reusing snapshot %D step %D, time %g\n",tid,tshhist_id[id],(double)t));
153     }
154     CHKERRQ(VecCopy(tj->lag.W[tid],U));
155     CHKERRQ(PetscObjectStateGet((PetscObject)U,&tj->lag.Ucached.state));
156     CHKERRQ(PetscObjectGetId((PetscObject)U,&tj->lag.Ucached.id));
157     tj->lag.Ucached.time = t;
158     tj->lag.Ucached.step = tshhist_id[id];
159     if (tj->monitor) {
160       CHKERRQ(PetscViewerASCIIPopTab(tj->monitor));
161     }
162   }
163   if (id < 0 && U) {
164     if (tj->monitor) {
165       CHKERRQ(PetscViewerASCIIPrintf(tj->monitor,"Interpolating solution with %D snapshots\n",cnt));
166     }
167     LagrangeBasisVals(cnt,t,tj->lag.TW,tj->lag.L);
168     CHKERRQ(VecZeroEntries(U));
169     CHKERRQ(VecMAXPY(U,cnt,tj->lag.L,tj->lag.WW));
170     CHKERRQ(PetscObjectStateGet((PetscObject)U,&tj->lag.Ucached.state));
171     CHKERRQ(PetscObjectGetId((PetscObject)U,&tj->lag.Ucached.id));
172     tj->lag.Ucached.time = t;
173     tj->lag.Ucached.step = PETSC_MIN_INT;
174   }
175   if (Udot) {
176     if (tj->monitor) {
177       CHKERRQ(PetscViewerASCIIPrintf(tj->monitor,"Interpolating derivative with %D snapshots\n",cnt));
178     }
179     LagrangeBasisDers(cnt,t,tj->lag.TW,tj->lag.L);
180     CHKERRQ(VecZeroEntries(Udot));
181     CHKERRQ(VecMAXPY(Udot,cnt,tj->lag.L,tj->lag.WW));
182     CHKERRQ(PetscObjectStateGet((PetscObject)Udot,&tj->lag.Udotcached.state));
183     CHKERRQ(PetscObjectGetId((PetscObject)Udot,&tj->lag.Udotcached.id));
184     tj->lag.Udotcached.time = t;
185     tj->lag.Udotcached.step = PETSC_MIN_INT;
186   }
187   PetscFunctionReturn(0);
188 }
189