17 #include "BasisGenerator.h"
18 #include "svd/StaticSVD.h"
19 #include "svd/RandomizedSVD.h"
20 #include "svd/IncrementalSVDStandard.h"
21 #include "svd/IncrementalSVDFastUpdate.h"
22 #include "svd/IncrementalSVDBrand.h"
29 BasisGenerator::BasisGenerator(
32 const std::string& basis_file_name,
35 d_incremental(incremental),
38 d_write_snapshots(options.write_snapshots)
40 CAROM_VERIFY(options.
dim > 0);
57 if (!basis_file_name.empty()) {
69 d_next_sample_time = 0.0;
74 options, basis_file_name));
79 options, basis_file_name));
84 options, basis_file_name));
89 MPI_Initialized(&mpi_init);
91 MPI_Comm_size(MPI_COMM_WORLD, &d_num_procs);
112 CAROM_VERIFY(time >= 0.0);
115 if(d_update_right_SV)
118 return time >= d_next_sample_time;
127 bool add_without_increase)
129 CAROM_VERIFY(u_in != 0);
130 CAROM_VERIFY(
d_svd->getNumSamples() <
d_svd->getMaxNumSamples());
133 Vector u_vec(u_in, getDim(),
true);
134 if (u_vec.
norm() == 0.0) {
135 printf(
"WARNING: BasisGenerator::takeSample skipped trivial sample.\n");
139 return d_svd->takeSample(u_in, add_without_increase);
144 const std::string& kind,
149 CAROM_ASSERT(!base_file_name.empty());
150 CAROM_VERIFY(kind ==
"basis" || kind ==
"snapshot");
155 std::unique_ptr<const Matrix> mat;
156 std::unique_ptr<const Vector> singular_vals;
158 if (kind ==
"basis") {
162 else if (kind ==
"snapshot") {
166 int num_rows = mat->numRows();
167 int num_cols = mat->numColumns();
168 if (col_min < 0) col_min = 0;
169 if (col_max > num_cols-1) col_max = num_cols-1;
171 CAROM_VERIFY(col_max >= col_min);
173 for (
int j = col_min; j <= col_max; j++) {
174 double* u_in =
new double[num_rows];
175 for (
int i = 0; i < num_rows; i++) {
176 if (kind ==
"basis") {
177 u_in[i] = mat->item(i,j) * singular_vals->item(j);
180 u_in[i] = mat->item(i,j);
183 d_svd->takeSample(u_in,
false);
190 const std::string& kind,
203 CAROM_VERIFY(u_in != 0);
204 CAROM_VERIFY(rhs_in != 0);
205 CAROM_VERIFY(time >= 0);
211 Vector u_vec(u_in, dim,
true);
212 if (u_vec.
norm() == 0.0) {
213 return d_next_sample_time;
220 Vector l(basis->numColumns(),
false);
221 basis->transposeMult(u_vec, l);
224 Vector basisl(basis->numRows(),
true);
225 basis->mult(l, basisl);
228 std::unique_ptr<Vector> eta = u_vec.
minus(basisl);
231 Vector rhs_vec(rhs_in, dim,
true);
232 basis->transposeMult(rhs_vec, l);
235 basis->mult(l, basisl);
238 std::unique_ptr<Vector> eta_dot = rhs_vec.
minus(basisl);
242 double local_norm = 0.0;
243 for (
int i = 0; i < dim; ++i) {
244 double val = fabs(eta->item(i) + d_dt*eta_dot->item(i));
245 if (val > local_norm) {
249 if (d_num_procs == 1) {
250 global_norm = local_norm;
253 MPI_Allreduce(&local_norm,
262 double tmp = d_sampling_time_step_scale*sqrt(d_tol/global_norm);
263 if (tmp < d_min_sampling_time_step_scale) {
264 d_dt *= d_min_sampling_time_step_scale;
266 else if (tmp > d_max_sampling_time_step_scale) {
267 d_dt *= d_max_sampling_time_step_scale;
275 else if (d_dt > d_max_time_between_samples) {
276 d_dt = d_max_time_between_samples;
280 d_next_sample_time = time + d_dt;
281 return d_next_sample_time;
288 BasisGenerator::resetDt(
299 const double energyFractionThreshold,
301 const std::string & cutoffOutputPath,
302 const int first_sv,
const bool squareSV)
307 CAROM_VERIFY(rom_dim <= sing_vals->dim());
310 for (
int sv = first_sv; sv < sing_vals->dim(); ++sv) {
311 const double s = (*sing_vals)(sv);
312 sum += squareSV ? s * s : s;
315 int p = std::floor(-std::log10(energyFractionThreshold));
316 std::vector<double> energy_fractions(p);
318 for (
int i = 0; i < p; ++i) {
319 energy_fractions[i] = 1 - std::pow(10, -1 - i);
323 bool reached_cutoff =
false;
324 double partialSum = 0.0;
327 std::ostream* output_stream;
329 if (!cutoffOutputPath.empty()) {
330 output_stream =
new std::ofstream(cutoffOutputPath);
332 output_stream = &std::cout;
335 for (
int sv = first_sv; sv < sing_vals->dim(); ++sv) {
336 const double s = (*sing_vals)(sv);
337 partialSum += squareSV ? s * s : s;
338 for (
int i = count; i < p; ++i)
340 if (partialSum / sum > 1.0 - std::pow(10, -1 - i))
342 *output_stream <<
"For energy fraction: 0.";
343 for (
int j = 0; j < i+1; ++j) *output_stream <<
"9";
344 *output_stream <<
", take first " << sv+1 <<
" of "
345 << sing_vals->dim() <<
" basis vectors" << std::endl;
353 if (!reached_cutoff && partialSum / sum > 1.0 - energyFractionThreshold)
356 reached_cutoff =
true;
360 if (!reached_cutoff) cutoff = sing_vals->dim();
361 *output_stream << std::fixed << std::setprecision(p+1);
362 *output_stream <<
"For energy fraction: " << 1.0 - energyFractionThreshold <<
364 << cutoff <<
" of " << sing_vals->dim() <<
" basis vectors" << std::endl;
366 if (!cutoffOutputPath.empty()) {
367 static_cast<std::ofstream*
>(output_stream)->close();
368 delete output_stream;
void loadSampleRange(const std::string &base_file_name, const std::string &kind="basis", int col_min=0, int col_max=1e9, Database::formats db_format=Database::formats::HDF5)
Load previously saved sample (basis or state) within a column range.
void finalSummary(const double energyFractionThreshold, int &cutoff, const std::string &cutoffOutputPath="", const int first_sv=0, const bool squareSV=true)
Prints the summary of recommended numbers of basis vectors.
BasisReader * d_basis_reader
Reader of basis vectors.
bool isNextSample(double time)
Returns true if it is time for the next svd sample.
std::shared_ptr< const Matrix > getSpatialBasis()
Returns the basis vectors for the current time interval as a Matrix.
BasisWriter * d_basis_writer
Writer of basis vectors.
void loadSamples(const std::string &base_file_name, const std::string &kind="basis", int cut_off=1e9, Database::formats db_format=Database::formats::HDF5)
Load previously saved sample (basis or state).
boost::shared_ptr< SVD > d_svd
Pointer to the abstract SVD algorithm object.
std::shared_ptr< const Vector > getSingularValues()
Returns the singular values for the current time interval as a Vector.
~BasisGenerator()
Destructor.
double computeNextSampleTime(double *u_in, double *rhs_in, double time)
Computes next time an svd sample is needed.
bool takeSample(double *u_in, bool add_without_increase=false)
Sample the new state, u_in, at the given time.
std::unique_ptr< Matrix > getSnapshotMatrix()
Returns the snapshot matrix for the requested time.
std::unique_ptr< Matrix > getSpatialBasis()
Returns the spatial basis vectors as a Matrix.
std::unique_ptr< Vector > getSingularValues()
Returns the singular values for the requested time.
formats
Implemented database file formats. Add to this enum each time a new database format is implemented.
bool fast_update_brand
If true use the exact Brand's algorithm for the incremental SVD.
double max_time_between_samples
The upper bound on time between samples of the incremental SVD algorithm.
int dim
The dimension of the system on this processor.
double max_sampling_time_step_scale
The maximum overall scale factor to apply to time step of the incremental SVD algorithm.
int max_num_samples
The maximum number of samples.
double singular_value_tol
The singular value tolerance used in the SVD algorithm.
double linearity_tol
The tolerance of the incremental SVD algorithm to determine whether or not a sample is linearly depen...
double sampling_tol
The sampling control tolerance of the incremental SVD algorithm. Limits error in projection of soluti...
double min_sampling_time_step_scale
The minimum overall scale factor to apply to time step of the incremental SVD algorithm.
bool randomized
Whether to use the randomized SVD algorithm.
bool update_right_SV
Whether to update the right singular values.
bool fast_update
If true use the fast update version of the incremental SVD algorithm.
double initial_dt
The initial simulation time step of the incremental SVD algorithm.
int max_basis_dimension
The maximum dimension of the basis.
double sampling_time_step_scale
The scaling factor to apply to sampling algorithm of the incremental SVD algorithm.
double norm() const
Form the norm of this.
std::unique_ptr< Vector > minus(const Vector &other) const
Subtracts other and this and returns the result.