libROM  v1.0
Data-driven physical simulation library
AdaptiveDMD.cpp
1 
11 // Description: Implementation of the AdaptiveDMD algorithm.
12 
13 #include "AdaptiveDMD.h"
14 #include "manifold_interp/VectorInterpolator.h"
15 
16 #include "linalg/Matrix.h"
17 #include "linalg/Vector.h"
18 #include <algorithm>
19 
20 namespace CAROM {
21 
22 AdaptiveDMD::AdaptiveDMD(int dim, double desired_dt, std::string rbf,
23  std::string interp_method, double closest_rbf_val,
24  bool alt_output_basis, std::shared_ptr<Vector> state_offset) :
25  DMD(dim, alt_output_basis, state_offset)
26 {
27  CAROM_VERIFY(rbf == "G" || rbf == "IQ" || rbf == "IMQ");
28  CAROM_VERIFY(interp_method == "LS" || interp_method == "IDW"
29  || interp_method == "LP");
30  CAROM_VERIFY(closest_rbf_val >= 0.0 && closest_rbf_val <= 1.0);
31  d_dt = desired_dt;
32  d_interp_method = interp_method;
33  d_rbf = rbf;
34  d_closest_rbf_val = closest_rbf_val;
35 }
36 
37 void AdaptiveDMD::train(double energy_fraction, const Matrix* W0,
38  double linearity_tol)
39 {
40  std::unique_ptr<const Matrix> f_snapshots = getInterpolatedSnapshots();
41  CAROM_VERIFY(f_snapshots->numColumns() > 1);
42  CAROM_VERIFY(energy_fraction > 0 && energy_fraction <= 1);
43  d_energy_fraction = energy_fraction;
44  constructDMD(*f_snapshots, d_rank, d_num_procs, W0, linearity_tol);
45 }
46 
47 void AdaptiveDMD::train(int k, const Matrix* W0, double linearity_tol)
48 {
49  std::unique_ptr<const Matrix> f_snapshots = getInterpolatedSnapshots();
50  CAROM_VERIFY(f_snapshots->numColumns() > 1);
51  CAROM_VERIFY(k > 0 && k <= f_snapshots->numColumns() - 1);
52  d_energy_fraction = -1.0;
53  d_k = k;
54  constructDMD(*f_snapshots, d_rank, d_num_procs, W0, linearity_tol);
55 }
56 
57 void AdaptiveDMD::interpolateSnapshots()
58 {
59  CAROM_VERIFY(d_interp_snapshots.size() == 0);
60  CAROM_VERIFY(d_snapshots.size() == d_sampled_times.size());
61  CAROM_VERIFY(d_sampled_times.size() > 1);
62 
63  if (d_rank == 0) std::cout << "Number of snapshots is: " << d_snapshots.size()
64  << std::endl;
65 
66  bool automate_dt = false;
67  if (d_dt <= 0.0)
68  {
69  automate_dt = true;
70  std::vector<double> d_sampled_dts;
71  for (int i = 1; i < d_sampled_times.size(); i++)
72  {
73  d_sampled_dts.push_back(d_sampled_times[i] - d_sampled_times[i - 1]);
74  }
75 
76  auto m = d_sampled_dts.begin() + d_sampled_dts.size() / 2;
77  std::nth_element(d_sampled_dts.begin(), m, d_sampled_dts.end());
78  if (d_rank == 0)
79  std::cout << "Setting desired dt to the median dt between the samples: "
80  << d_sampled_dts[d_sampled_dts.size() / 2] << std::endl;
81 
82  d_dt = d_sampled_dts[d_sampled_dts.size() / 2];
83  }
84  CAROM_VERIFY(d_sampled_times.back() > d_dt);
85 
86  // Find the nearest dt that evenly divides the snapshots.
87  int num_time_steps = std::round(d_sampled_times.back() / d_dt);
88  if (automate_dt && num_time_steps < d_sampled_times.size())
89  {
90  num_time_steps = d_sampled_times.size();
91  if (d_rank == 0) std::cout <<
92  "There will be less interpolated snapshots than FOM snapshots. dt will be decreased."
93  << std::endl;
94  }
95  const double new_dt = d_sampled_times.back() / num_time_steps;
96  if (new_dt != d_dt)
97  {
98  d_dt = new_dt;
99  if (d_rank == 0) std::cout << "Setting desired dt to " << d_dt <<
100  " to ensure a constant dt given the final sampled time." << std::endl;
101  }
102 
103  // Solve the linear system if required.
104  std::unique_ptr<Matrix> f_T;
105  std::unique_ptr<std::vector<Vector>> sampled_times = scalarsToVectors(
107  double epsilon = convertClosestRBFToEpsilon(*sampled_times, d_rbf,
108  d_closest_rbf_val);
109 
110  if (d_interp_method == "LS")
111  {
112  f_T = solveLinearSystem(*sampled_times, d_snapshots, d_interp_method,
113  d_rbf, epsilon);
114  }
115 
116  // Create interpolated snapshots using d_dt as the desired dt.
117  for (int i = 0; i <= num_time_steps; i++)
118  {
119  double curr_time = i * d_dt;
120  if (d_rank == 0) std::cout << "Creating new interpolated sample at: " <<
121  d_t_offset + curr_time << std::endl;
122  Vector point(&curr_time, 1, false);
123 
124  // Obtain distances from database points to new point
125  std::vector<double> rbf = obtainRBFToTrainingPoints(
126  *sampled_times, d_interp_method,
127  d_rbf, epsilon, point);
128 
129  // Obtain the interpolated snapshot.
130  std::shared_ptr<CAROM::Vector> curr_interpolated_snapshot =
131  obtainInterpolatedVector(
132  d_snapshots, *f_T, d_interp_method, rbf);
133  d_interp_snapshots.push_back(curr_interpolated_snapshot);
134  }
135 
136  if (d_rank == 0) std::cout << "Number of interpolated snapshots is: " <<
137  d_interp_snapshots.size() << std::endl;
138 }
139 
141 {
142  return d_dt;
143 }
144 
145 std::unique_ptr<const Matrix> AdaptiveDMD::getInterpolatedSnapshots()
146 {
147  if (d_interp_snapshots.size() == 0) interpolateSnapshots();
148  return createSnapshotMatrix(d_interp_snapshots);
149 }
150 
151 }
double getTrueDt() const
Get the true dt between interpolated snapshots.
std::unique_ptr< const Matrix > getInterpolatedSnapshots()
Get the interpolated snapshot matrix contained within d_interp_snapshots.
void train(double energy_fraction, const Matrix *W0=NULL, double linearity_tol=0.0)
Definition: AdaptiveDMD.cpp:37
Definition: DMD.h:71
void constructDMD(const Matrix &f_snapshots, int rank, int num_procs, const Matrix *W0, double linearity_tol)
Construct the DMD object.
Definition: DMD.cpp:256
double d_energy_fraction
The energy fraction used to obtain the DMD modes.
Definition: DMD.h:397
double d_dt
The time step size between samples.
Definition: DMD.h:352
std::unique_ptr< const Matrix > createSnapshotMatrix(const std::vector< std::shared_ptr< Vector >> &snapshots)
Get the snapshot matrix contained within d_snapshots.
Definition: DMD.cpp:699
std::vector< double > d_sampled_times
The stored times of each sample.
Definition: DMD.h:367
double d_t_offset
The time offset of the first sample.
Definition: DMD.h:357
std::vector< std::shared_ptr< Vector > > d_snapshots
std::vector holding the snapshots.
Definition: DMD.h:362
int d_rank
The rank of the process this object belongs to.
Definition: DMD.h:337
int d_num_procs
The number of processors being run on.
Definition: DMD.h:342
int d_k
The number of columns used after obtaining the SVD decomposition.
Definition: DMD.h:402
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 convertClosestRBFToEpsilon(const std::vector< Vector > &parameter_points, const std::string &rbf, double closest_rbf_val)
Convert closest RBF value to an epsilon value.