libROM  v1.0
Data-driven physical simulation library
PCHIPInterpolator.cpp
1 
17 #include "PCHIPInterpolator.h"
18 
19 #include <cfloat>
20 #include <limits.h>
21 #include <cmath>
22 #include "linalg/Vector.h"
23 #include "mpi.h"
24 
25 /* Use C++11 built-in shared pointers if available; else fallback to Boost. */
26 #if __cplusplus >= 201103L
27 #include <memory>
28 #else
29 #include <boost/shared_ptr.hpp>
30 #endif
31 using namespace std;
32 
33 namespace CAROM {
34 
35 void PCHIPInterpolator::interpolate(std::vector<Vector>& snapshot_ts,
36  std::vector<std::shared_ptr<Vector>>& snapshots,
37  std::vector<Vector>& output_ts,
38  std::vector<std::shared_ptr<Vector>>& output_snapshots)
39 {
40  CAROM_VERIFY(snapshot_ts.size() == snapshots.size());
41  CAROM_VERIFY(snapshot_ts.size() > 2);
42  CAROM_VERIFY(output_ts.size() > 1);
43  CAROM_VERIFY(output_snapshots.size() == 0);
44  CAROM_VERIFY(snapshot_ts[0](0) - FLT_EPSILON <= output_ts[0](0) &&
45  output_ts[output_ts.size()-1](0) <=
46  snapshot_ts[snapshot_ts.size()-1](0) + FLT_EPSILON);
47  for(int i = 1; i < snapshot_ts.size(); ++i)
48  {
49  CAROM_VERIFY(snapshots[i-1]->dim() == snapshots[i]->dim());
50  CAROM_VERIFY(snapshot_ts[i-1](0) < snapshot_ts[i](0));
51  CAROM_VERIFY(output_ts[i-1](0) < output_ts[i](0));
52  }
53 
54  int n_out = output_ts.size();
55  int n_snap = snapshots.size();
56  int n_dim = snapshots[0]->dim();
57 
58  for(int i = 0; i < n_out; ++i)
59  {
60  Vector* temp_snapshot = new Vector(snapshots[0]->dim(),
61  snapshots[0]->distributed());
62  output_snapshots.push_back(std::shared_ptr<Vector>(temp_snapshot));
63  }
64 
65  for(int i = 0; i < n_dim; ++i)
66  {
67  double h_temp,delta_temp, t;
68  std::vector<double> h,d,delta,t_in,y_in;
69  for(int j = 0; j < n_snap-1; ++j)
70  {
71  h_temp = snapshot_ts[j+1](0) - snapshot_ts[j](0);
72  h.push_back(h_temp);
73  delta_temp = (snapshots[j+1]->getData()[i] - snapshots[j]->getData()[i])/h_temp;
74  delta.push_back(delta_temp);
75  t_in.push_back(snapshot_ts[j](0));
76  y_in.push_back(snapshots[j]->getData()[i]);
77  }
78  t_in.push_back(snapshot_ts[n_snap-1](0));
79  y_in.push_back(snapshots[n_snap-1]->getData()[i]);
80 
81  double d_temp = ((2*h[0] + h[1])*delta[0] - h[0]*delta[1])/(h[0]+h[1]);
82  if(sign(d_temp)!=sign(delta[0]))
83  {
84  d_temp = 0;
85  }
86  else if (sign(delta[0]) != sign(delta[1]) && abs(d_temp) > abs(3*delta[0]))
87  {
88  d_temp = 3*delta[0];
89  }
90  d.push_back(d_temp);
91  int counter = 0;
92  for(int j = 0; j < n_snap-2; ++j)
93  {
94  d_temp = computeDerivative(delta[j],delta[j+1],h[j],h[j+1]);
95  d.push_back(d_temp);
96  while(output_ts[counter](0) <= t_in[j+1])
97  {
98  t = output_ts[counter](0);
99  output_snapshots[counter]->getData()[i] = y_in[j]*computeH1(t,t_in[j],
100  t_in[j+1]) +
101  y_in[j+1]*computeH2(t,t_in[j],t_in[j+1]) +
102  d[j]*computeH3(t,t_in[j],t_in[j+1]) +
103  d[j+1]*computeH4(t,t_in[j],t_in[j+1]);
104  counter++;
105  }
106  }
107 
108  d_temp = ((2*h[n_snap-2]+h[n_snap-3])*delta[n_snap-2] - h[n_snap-2]*delta[n_snap
109  -3])/(h[n_snap-2]+h[n_snap-3]);
110  if(sign(d_temp) != sign(delta[n_snap-2]))
111  {
112  d_temp = 0;
113  }
114  else if (sign(delta[n_snap-2]) != sign(delta[n_snap-3])
115  && abs(d_temp) > abs(3*delta[n_snap-2]))
116  {
117  d_temp = 3*delta[n_snap-2];
118  }
119  d.push_back(d_temp);
120 
121  while(counter < n_out
122  && output_ts[counter](0) <= t_in[n_snap-1] + FLT_EPSILON )
123  {
124  t = output_ts[counter](0);
125  output_snapshots[counter]->getData()[i] = y_in[n_snap-2]*computeH1(t,
126  t_in[n_snap-2],t_in[n_snap-1]) +
127  y_in[n_snap-1]*computeH2(t,t_in[n_snap-2],t_in[n_snap-1]) +
128  d[n_snap-2]*computeH3(t,t_in[n_snap-2],t_in[n_snap-1]) +
129  d[n_snap-1]*computeH4(t,t_in[n_snap-2],t_in[n_snap-1]);
130  counter++;
131  }
132  CAROM_VERIFY(counter == n_out);
133  }
134 }
135 
136 void PCHIPInterpolator::interpolate(std::vector<Vector>& snapshot_ts,
137  std::vector<std::shared_ptr<Vector>>& snapshots,
138  int n_out,
139  std::vector<Vector>& output_ts,
140  std::vector<std::shared_ptr<Vector>>& output_snapshots)
141 {
142  CAROM_VERIFY(snapshot_ts.size() == snapshots.size());
143  CAROM_VERIFY(snapshot_ts.size() > 0);
144  CAROM_VERIFY(n_out > 2);
145  CAROM_VERIFY(output_ts.size() == 0 && output_snapshots.size() == 0);
146 
147  int n_snap = snapshots.size();
148  int n_dim = snapshots[0]->dim();
149 
150  double t_min = snapshot_ts[0](0);
151  double t_max = snapshot_ts[n_snap-1](0);
152  double dt = (t_max-t_min)/(n_out-1);
153  output_ts.clear();
154 
155  for(int i = 0; i < n_out; ++i)
156  {
157  Vector temp_t(1, false);
158  temp_t(0) = t_min + i*dt;
159  output_ts.push_back(temp_t);
160  }
161  interpolate(snapshot_ts,snapshots,output_ts, output_snapshots);
162 }
163 
164 double PCHIPInterpolator::computeDerivative(double S1, double S2,
165  double h1,
166  double h2) const
167 {
168  double d = 0.0;
169  double alpha = (h1 + 2*h2)/(3*(h1+h2));
170  if(S1*S2 > 0)
171  {
172  d = S1*S2/(alpha*S2 + (1-alpha)*S1);
173  }
174  return d;
175 }
176 
177 double PCHIPInterpolator::computeH1(double x, double xl, double xr) const
178 {
179  const double h = xr - xl;
180  return computePhi((xr-x)/h);
181 }
182 
183 double PCHIPInterpolator::computeH2(double x, double xl, double xr) const
184 {
185  const double h = xr - xl;
186  return computePhi((x-xl)/h);
187 }
188 
189 double PCHIPInterpolator::computeH3(double x, double xl, double xr) const
190 {
191  const double h = xr-xl;
192  return -h*computePsi((xr-x)/h);
193 }
194 
195 double PCHIPInterpolator::computeH4(double x, double xl, double xr) const
196 {
197  const double h = xr-xl;
198  return h*computePsi((x-xl)/h);
199 }
200 
201 double PCHIPInterpolator::computePhi(double t) const
202 {
203  return 3.*pow(t,2.) - 2*pow(t,3.);
204 }
205 
206 double PCHIPInterpolator::computePsi(double t) const
207 {
208  return pow(t,3.) - pow(t,2.);
209 }
210 
211 int PCHIPInterpolator::sign(double a) const
212 {
213  constexpr double TOL = 1e-15;
214  if(abs(a) < TOL)return 0;
215  else if(a > 0) return 1;
216  else if (a < 0) return -1;
217  return 0;
218 }
219 
220 }