libROM  v1.0
Data-driven physical simulation library
Interpolator.cpp
1 
11 // Description: Implementation of the Interpolator algorithm.
12 
13 #include "Interpolator.h"
14 
15 #include <limits.h>
16 #include <cmath>
17 #include "linalg/Matrix.h"
18 #include "linalg/scalapack_wrapper.h"
19 #include "mpi.h"
20 
21 /* Use C++11 built-in shared pointers if available; else fallback to Boost. */
22 #if __cplusplus >= 201103L
23 #include <memory>
24 #else
25 #include <boost/shared_ptr.hpp>
26 #endif
27 
28 using namespace std;
29 
30 namespace CAROM {
31 
32 Interpolator::Interpolator(std::vector<Vector*> parameter_points,
33  std::vector<Matrix*> rotation_matrices,
34  int ref_point,
35  std::string rbf,
36  std::string interp_method,
37  double closest_rbf_val)
38 {
39  CAROM_VERIFY(parameter_points.size() == rotation_matrices.size());
40  CAROM_VERIFY(parameter_points.size() > 1);
41  CAROM_VERIFY(rbf == "G" || rbf == "IQ" || rbf == "IMQ");
42  CAROM_VERIFY(interp_method == "LS" || interp_method == "IDW"
43  || interp_method == "LP");
44  CAROM_VERIFY(closest_rbf_val >= 0.0 && closest_rbf_val <= 1.0);
45 
46  // Get the rank of this process, and the number of processors.
47  int mpi_init;
48  MPI_Initialized(&mpi_init);
49  if (mpi_init == 0) {
50  MPI_Init(nullptr, nullptr);
51  }
52 
53  MPI_Comm_rank(MPI_COMM_WORLD, &d_rank);
54  MPI_Comm_size(MPI_COMM_WORLD, &d_num_procs);
55 
56  d_parameter_points = parameter_points;
57  d_rotation_matrices = rotation_matrices;
58  d_ref_point = ref_point;
59  d_lambda_T = NULL;
60  d_rbf = rbf;
61  d_interp_method = interp_method;
62  d_epsilon = convertClosestRBFToEpsilon(parameter_points, rbf, closest_rbf_val);
63 }
64 
65 Interpolator::~Interpolator()
66 {
67  delete d_lambda_T;
68 }
69 
70 std::vector<double> obtainRBFToTrainingPoints(std::vector<Vector*>
71  parameter_points,
72  std::string interp_method, std::string rbf, double epsilon, Vector* point)
73 {
74  std::vector<double> rbfs;
75  if (interp_method == "LS")
76  {
77  for (int i = 0; i < parameter_points.size(); i++)
78  {
79  rbfs.push_back(obtainRBF(rbf, epsilon, point, parameter_points[i]));
80  }
81  }
82  else if (interp_method == "IDW")
83  {
84  bool distance_is_zero = false;
85  for (int i = 0; i < parameter_points.size(); i++)
86  {
87  rbfs.push_back(obtainRBF(rbf, epsilon, point, parameter_points[i]));
88  if (rbfs.back() == 1.0)
89  {
90  distance_is_zero = true;
91  }
92  }
93  if (distance_is_zero)
94  {
95  for (int i = 0; i < rbfs.size(); i++)
96  {
97  if (rbfs[i] != 1.0)
98  {
99  rbfs[i] = 0.0;
100  }
101  }
102  }
103  }
104  else if (interp_method == "LP")
105  {
106  for (int i = 0; i < parameter_points.size(); i++)
107  {
108  double coeff;
109  bool first = true;
110  for (int j = 0; j < parameter_points.size(); j++)
111  {
112  if (i == j)
113  {
114  continue;
115  }
116 
117  Vector numerator_vec, denomenator_vec;
118  point->minus(*parameter_points[j], numerator_vec);
119  parameter_points[i]->minus(*parameter_points[j], denomenator_vec);
120  double numerator = numerator_vec.norm();
121  double denomenator = denomenator_vec.norm();
122 
123  if (first)
124  {
125  coeff = (numerator / denomenator);
126  first = false;
127  }
128  else
129  {
130  coeff *= (numerator / denomenator);
131  }
132  }
133  rbfs.push_back(coeff);
134  }
135  }
136  return rbfs;
137 }
138 
139 double rbfWeightedSum(std::vector<double>& rbf)
140 {
141  double sum = 0.0;
142  for (int i = 0; i < rbf.size(); i++)
143  {
144  sum += rbf[i];
145  }
146  return sum;
147 }
148 
149 double obtainRBF(std::string rbf, double epsilon, Vector* point1,
150  Vector* point2)
151 {
152  Vector diff;
153  point1->minus(*point2, diff);
154  double eps_norm_squared = epsilon * epsilon * diff.norm2();
155  double res = 0.0;
156 
157  // Gaussian RBF
158  if (rbf == "G")
159  {
160  res = std::exp(-eps_norm_squared);
161  }
162  // Inverse quadratic RBF
163  else if (rbf == "IQ")
164  {
165  res = 1.0 / (1.0 + eps_norm_squared);
166  }
167  // Inverse multiquadric RBF
168  else if (rbf == "IMQ")
169  {
170  res = 1.0 / std::sqrt(1.0 + eps_norm_squared);
171  }
172 
173  return res;
174 }
175 
176 double convertClosestRBFToEpsilon(std::vector<Vector*> parameter_points,
177  std::string rbf, double closest_rbf_val)
178 {
179  double closest_point_dist = INT_MAX;
180  double epsilon;
181  for (int i = 0; i < parameter_points.size(); i++)
182  {
183  for (int j = 0; j < parameter_points.size(); j++)
184  {
185  if (i == j)
186  {
187  continue;
188  }
189 
190  Vector diff;
191  parameter_points[i]->minus(*parameter_points[j], diff);
192  double dist = diff.norm2();
193  if (dist < closest_point_dist)
194  {
195  closest_point_dist = dist;
196 
197  // Gaussian RBF
198  if (rbf == "G")
199  {
200  epsilon = std::sqrt(-std::log(closest_rbf_val) / diff.norm2());
201  }
202  // Inverse quadratic RBF
203  else if (rbf == "IQ")
204  {
205  epsilon = std::sqrt(((1.0 / closest_rbf_val) - 1.0) / diff.norm2());
206  }
207  // Inverse multiquadric RBF
208  else if (rbf == "IMQ")
209  {
210  epsilon = std::sqrt((std::pow(1.0 / closest_rbf_val, 2) - 1.0) / diff.norm2());
211  }
212  }
213  }
214  }
215 
216  return epsilon;
217 }
218 
219 std::vector<Matrix*> obtainRotationMatrices(std::vector<Vector*>
220  parameter_points,
221  std::vector<Matrix*> bases,
222  int ref_point)
223 {
224  // Get the rank of this process, and the number of processors.
225  int mpi_init;
226  int rank;
227  int num_procs;
228  MPI_Initialized(&mpi_init);
229  if (mpi_init == 0) {
230  MPI_Init(nullptr, nullptr);
231  }
232 
233  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
234  MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
235 
236  std::vector<Matrix*> rotation_matrices;
237 
238  // Obtain the rotation matrices to rotate the bases into
239  // the same generalized coordinate space.
240  for (int i = 0; i < parameter_points.size(); i++)
241  {
242  CAROM_VERIFY(bases[i]->numRows() == bases[ref_point]->numRows());
243  CAROM_VERIFY(bases[i]->numColumns() == bases[ref_point]->numColumns());
244  CAROM_VERIFY(bases[i]->distributed() == bases[ref_point]->distributed());
245 
246  // If at ref point, the rotation_matrix is the identity matrix
247  // since the ref point doesn't need to be rotated.
248  if (i == ref_point)
249  {
250  Matrix* identity_matrix = new Matrix(bases[i]->numColumns(),
251  bases[i]->numColumns(), false);
252  for (int j = 0; j < identity_matrix->numColumns(); j++) {
253  identity_matrix->item(j, j) = 1.0;
254  }
255  rotation_matrices.push_back(identity_matrix);
256  continue;
257  }
258 
259  Matrix* basis_mult_basis = bases[i]->transposeMult(bases[ref_point]);
260  Matrix* basis = new Matrix(basis_mult_basis->numRows(),
261  basis_mult_basis->numColumns(), false);
262  Matrix* basis_right = new Matrix(basis_mult_basis->numColumns(),
263  basis_mult_basis->numColumns(), false);
264 
265  // We need to compute the SVD of basis_mult_basis. Since it is
266  // undistributed due to the transposeMult, let's use lapack's serial SVD
267  // on rank 0 only.
268  if (rank == 0)
269  {
270  Vector* sv = new Vector(basis_mult_basis->numColumns(), false);
271  SerialSVD(basis_mult_basis, basis_right, sv, basis);
272  delete sv;
273  }
274 
275  // Broadcast U and V which are computed only on root.
276  MPI_Bcast(basis->getData(), basis->numRows() * basis->numColumns(), MPI_DOUBLE,
277  0, MPI_COMM_WORLD);
278  MPI_Bcast(basis_right->getData(),
279  basis_right->numRows() * basis_right->numColumns(), MPI_DOUBLE, 0,
280  MPI_COMM_WORLD);
281 
282  // Obtain the rotation matrix.
283  Matrix* rotation_matrix = basis->mult(basis_right);
284 
285  delete basis_mult_basis;
286  delete basis;
287  delete basis_right;
288  rotation_matrices.push_back(rotation_matrix);
289  }
290 
291  return rotation_matrices;
292 }
293 
294 }
double * getData() const
Get the matrix data as a pointer.
Definition: Matrix.h:1107
int numColumns() const
Returns the number of columns in the Matrix. This method will return the same value from each process...
Definition: Matrix.h:220
Matrix * transposeMult(const Matrix &other) const
Multiplies the transpose of this Matrix with other and returns the product, reference version.
Definition: Matrix.h:642
Matrix * mult(const Matrix &other) const
Multiplies this Matrix with other and returns the product, reference version.
Definition: Matrix.h:283
const double & item(int row, int col) const
Const Matrix member access. Matrix data is stored in row-major format.
Definition: Matrix.h:1007
int numRows() const
Returns the number of rows of the Matrix on this processor.
Definition: Matrix.h:194
double norm() const
Form the norm of this.
Definition: Vector.cpp:242
Vector * minus(const Vector &other) const
Subtracts other and this and returns the result, reference version.
Definition: Vector.h:538
double norm2() const
Form the squared norm of this.
Definition: Vector.cpp:249
double rbfWeightedSum(std::vector< double > &rbf)
Compute the sum of the RBF weights.
double convertClosestRBFToEpsilon(std::vector< Vector * > parameter_points, std::string rbf, double closest_rbf_val)
Convert closest RBF value to an epsilon value.
void SerialSVD(Matrix *A, Matrix *U, Vector *S, Matrix *V)
Computes the SVD of a undistributed matrix in serial.
Definition: Matrix.cpp:2279
std::vector< double > obtainRBFToTrainingPoints(std::vector< Vector * > parameter_points, std::string interp_method, std::string rbf, double epsilon, Vector *point)
Compute the RBF from the parameter points with the unsampled parameter point.
std::vector< Matrix * > obtainRotationMatrices(std::vector< Vector * > parameter_points, std::vector< Matrix * > bases, int ref_point)
Obtain the rotation matrices for all the parameter points using the basis of the reference point.
double obtainRBF(std::string rbf, double epsilon, Vector *point1, Vector *point2)
Compute the RBF between two points.