libROM  v1.0
Data-driven physical simulation library
VectorInterpolator.cpp
1 
11 // Description: Implementation of the VectorInterpolator algorithm.
12 
13 #include "VectorInterpolator.h"
14 
15 #include <limits.h>
16 #include <cmath>
17 #include "linalg/Matrix.h"
18 #include "linalg/Vector.h"
19 #include "linalg/scalapack_wrapper.h"
20 #include "mpi.h"
21 
22 /* Use C++11 built-in shared pointers if available; else fallback to Boost. */
23 #if __cplusplus >= 201103L
24 #include <memory>
25 #else
26 #include <boost/shared_ptr.hpp>
27 #endif
28 
29 /* Use automatically detected Fortran name-mangling scheme */
30 #define dposv CAROM_FC_GLOBAL(dposv, DPOSV)
31 
32 extern "C" {
33  // Solve a system of linear equations.
34  void dposv(char*, int*, int*, double*, int*, double*, int*, int*);
35 }
36 
37 using namespace std;
38 
39 namespace CAROM {
40 
41 VectorInterpolator::VectorInterpolator(const std::vector<Vector> &
42  parameter_points,
43  const std::vector<std::shared_ptr<Matrix>> & rotation_matrices,
44  const std::vector<std::shared_ptr<Vector>> & reduced_vectors,
45  int ref_point,
46  std::string rbf,
47  std::string interp_method,
48  double closest_rbf_val,
49  bool compute_gradients) :
50  Interpolator(parameter_points,
51  rotation_matrices,
52  ref_point,
53  rbf,
54  interp_method,
55  closest_rbf_val,
56  compute_gradients)
57 {
58  CAROM_VERIFY(reduced_vectors.size() == rotation_matrices.size());
59 
60  // Rotate the reduced vectors
61  for (int i = 0; i < reduced_vectors.size(); i++)
62  {
63  // The ref_point does not need to be rotated
64  if (i == d_ref_point)
65  d_rotated_reduced_vectors.push_back(reduced_vectors[i]);
66  else
67  {
68  std::shared_ptr<Vector> Q_tA = rotation_matrices[i]->transposeMult(
69  *reduced_vectors[i]);
70  d_rotated_reduced_vectors.push_back(Q_tA);
71  }
72  }
73 }
74 
75 void VectorInterpolator::obtainLambda()
76 {
77  if (d_interp_method == "LS")
78  {
79  d_lambda_T = solveLinearSystem(d_parameter_points, d_gammas,
81  }
82 }
83 
84 std::unique_ptr<Vector> VectorInterpolator::obtainLogInterpolatedVector(
85  std::vector<double>& rbf)
86 {
87  return obtainInterpolatedVector(d_gammas, *d_lambda_T, d_interp_method, rbf);
88 }
89 
90 std::shared_ptr<Vector> VectorInterpolator::interpolate(const Vector & point)
91 {
92  if (d_gammas.size() == 0)
93  {
94 
95  for (int i = 0; i < d_parameter_points.size(); i++)
96  {
97  // For ref point, gamma is the zero vector.
98  if (i == d_ref_point)
99  {
100  Vector* gamma = new Vector(d_rotated_reduced_vectors[d_ref_point]->dim(),
101  d_rotated_reduced_vectors[d_ref_point]->distributed());
102  d_gammas.push_back(std::shared_ptr<Vector>(gamma));
103  }
104  else
105  {
106  // Gamma is Y - X
107  std::shared_ptr<Vector> gamma = d_rotated_reduced_vectors[i]->minus(
108  *d_rotated_reduced_vectors[d_ref_point]);
109  d_gammas.push_back(gamma);
110  }
111  }
112 
113  // Obtain lambda for the P interpolation vector
114  obtainLambda();
115  }
116 
117  // Obtain distances from database points to new point
118  std::vector<double> rbf = obtainRBFToTrainingPoints(d_parameter_points,
119  d_interp_method, d_rbf, d_epsilon, point);
120 
121  // Interpolate gammas to get gamma for new point
122  std::unique_ptr<Vector> log_interpolated_vector = obtainLogInterpolatedVector(
123  rbf);
124 
126  {
127  if(d_interp_method == "LS")
128  {
129  for (int i = 0; i < point.dim(); ++i)
130  {
131  std::vector<double> rbf = obtainRBFGradientToTrainingPoints(d_parameter_points,
132  d_interp_method,d_rbf, d_epsilon, point, i);
133  std::shared_ptr<Vector> gradient_vector(obtainLogInterpolatedVector(rbf));
134  d_interpolation_gradient.push_back(gradient_vector);
135  }
136  }
137  else
138  {
139  CAROM_ERROR("Interpolated gradients are only implemented for \"LS\"");
140  }
141  }
142 
143  // The exp mapping is X + the interpolated gamma
144  std::shared_ptr<Vector> interpolated_vector =
145  d_rotated_reduced_vectors[d_ref_point]->plus(
146  *log_interpolated_vector);
147  return interpolated_vector;
148 }
149 
150 std::unique_ptr<Vector> obtainInterpolatedVector(const
151  std::vector<std::shared_ptr<Vector>> &
152  data, const Matrix & f_T,
153  std::string interp_method, std::vector<double>& rbf)
154 {
155  Vector* interpolated_vector = new Vector(data[0]->dim(),
156  data[0]->distributed());
157  if (interp_method == "LS")
158  {
159  for (int i = 0; i < f_T.numRows(); i++)
160  {
161  for (int j = 0; j < rbf.size(); j++)
162  {
163  interpolated_vector->getData()[i] += f_T(i, j) * rbf[j];
164  }
165  }
166  }
167  else if (interp_method == "IDW")
168  {
169  double sum = rbfWeightedSum(rbf);
170  for (int i = 0; i < data[0]->dim(); i++)
171  {
172  for (int j = 0; j < rbf.size(); j++)
173  {
174  interpolated_vector->getData()[i] += data[j]->getData()[i] * rbf[j];
175  }
176  interpolated_vector->getData()[i] /= sum;
177  }
178  }
179  else if (interp_method == "LP")
180  {
181  for (int i = 0; i < data[0]->dim(); i++)
182  {
183  for (int j = 0; j < rbf.size(); j++)
184  {
185  interpolated_vector->getData()[i] += data[j]->getData()[i] * rbf[j];
186  }
187  }
188  }
189 
190  return std::unique_ptr<Vector>(interpolated_vector);
191 }
192 
193 std::unique_ptr<Matrix> solveLinearSystem(
194  const std::vector<Vector> & parameter_points,
195  const std::vector<std::shared_ptr<Vector>> & data,
196  const std::string & interp_method,
197  const std::string & rbf, double epsilon)
198 {
199  int mpi_init, rank;
200  MPI_Initialized(&mpi_init);
201  if (mpi_init == 0) {
202  MPI_Init(nullptr, nullptr);
203  }
204 
205  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
206 
207  Matrix* f_T = NULL;
208  if (interp_method == "LS")
209  {
210  // Solving f = B*lambda
211  f_T = new Matrix(data[0]->dim(), data.size(), false);
212  for (int i = 0; i < f_T->numRows(); i++)
213  {
214  for (int j = 0; j < f_T->numColumns(); j++)
215  {
216  f_T->item(i, j) = data[j]->getData()[i];
217  }
218  }
219 
220  // Obtain B vector by calculating RBF.
221  Matrix* B = new Matrix(data.size(), data.size(), false);
222  for (int i = 0; i < B->numRows(); i++)
223  {
224  B->item(i, i) = 1.0;
225  for (int j = i + 1; j < B->numColumns(); j++)
226  {
227  double res = obtainRBF(rbf, epsilon, parameter_points[i],
228  parameter_points[j]);
229  B->item(i, j) = res;
230  B->item(j, i) = res;
231  }
232  }
233 
234  char uplo = 'U';
235  int gamma_size = data.size();
236  int num_elements = data[0]->dim();
237  int info;
238 
239  dposv(&uplo, &gamma_size, &num_elements, B->getData(), &gamma_size,
240  f_T->getData(), &gamma_size, &info);
241  if (info != 0)
242  {
243  std::cout << "Linear solve failed. Please choose a different epsilon value." <<
244  std::endl;
245  }
246  CAROM_VERIFY(info == 0);
247 
248  delete B;
249  }
250 
251  return std::unique_ptr<Matrix>(f_T);
252 }
253 
254 }
double d_epsilon
The RBF parameter that determines the width of influence. a small epsilon: larger influential width a...
Definition: Interpolator.h:95
int d_ref_point
The index within the vector of parameter points to the reference point.
Definition: Interpolator.h:76
std::unique_ptr< Matrix > d_lambda_T
The RHS of the linear solve in tangential space.
Definition: Interpolator.h:110
std::vector< Vector > d_parameter_points
The sampled parameter points.
Definition: Interpolator.h:100
bool d_compute_gradients
Flag that determines if a gradient with respect to the parameters should be computed.
Definition: Interpolator.h:116
std::string d_rbf
The RBF type (gaussian, multiquadric, inverse quadratic, inverse multiquadric)
Definition: Interpolator.h:82
std::string d_interp_method
The interpolation method (linear solve, inverse distance weighting, lagrangian polynomials)
Definition: Interpolator.h:88
int numRows() const
Returns the number of rows of the Matrix on this processor.
Definition: Matrix.h:200
double * getData() const
Get the vector data as a pointer.
Definition: Vector.h:558
int dim() const
Returns the dimension of the Vector on this processor.
Definition: Vector.h:251
std::shared_ptr< Vector > interpolate(const Vector &point)
Obtain the interpolated reduced vector of the unsampled parameter point.
double rbfWeightedSum(std::vector< double > &rbf)
Compute the sum of the RBF weights.
std::vector< double > obtainRBFGradientToTrainingPoints(const std::vector< Vector > &parameter_points, const std::string &interp_method, const std::string &rbf, double epsilon, const Vector &point, const int index)
Compute the RBF gradient from the parameter points with the unsampled parameter point.
std::vector< double > obtainRBFToTrainingPoints(const std::vector< Vector > &parameter_points, const std::string &interp_method, const std::string &rbf, double epsilon, const Vector &point)
Compute the RBF from the parameter points with the unsampled parameter point.
double obtainRBF(std::string rbf, double epsilon, const Vector &point1, const Vector &point2)
Compute the RBF between two points.