15 #include "linalg/Matrix.h"
16 #include "linalg/Vector.h"
17 #include "linalg/scalapack_wrapper.h"
18 #include "utils/Utilities.h"
19 #include "utils/CSVDatabase.h"
20 #include "utils/HDFDatabase.h"
26 #if __cplusplus >= 201103L
29 #include <boost/shared_ptr.hpp>
33 #define zgetrf CAROM_FC_GLOBAL(zgetrf, ZGETRF)
34 #define zgetri CAROM_FC_GLOBAL(zgetri, ZGETRI)
38 void zgetrf(
int*,
int*,
double*,
int*,
int*,
int*);
41 void zgetri(
int*,
double*,
int*,
int*,
double*,
int*,
int*);
48 CAROM_VERIFY(dim > 0);
52 MPI_Initialized(&mpi_init);
54 MPI_Init(
nullptr,
nullptr);
57 MPI_Comm_rank(MPI_COMM_WORLD, &
d_rank);
68 CAROM_VERIFY(dim > 0);
69 CAROM_VERIFY(dt > 0.0);
73 MPI_Initialized(&mpi_init);
75 MPI_Init(
nullptr,
nullptr);
78 MPI_Comm_rank(MPI_COMM_WORLD, &
d_rank);
92 MPI_Initialized(&mpi_init);
94 MPI_Init(
nullptr,
nullptr);
97 MPI_Comm_rank(MPI_COMM_WORLD, &
d_rank);
102 load(base_file_name);
106 Matrix* phi_imaginary,
int k,
107 double dt,
double t_offset,
Vector* state_offset)
111 MPI_Initialized(&mpi_init);
113 MPI_Init(
nullptr,
nullptr);
116 MPI_Comm_rank(MPI_COMM_WORLD, &
d_rank);
161 CAROM_VERIFY(u_in != 0);
162 CAROM_VERIFY(t >= 0.0);
179 if (
d_rank == 0) std::cout <<
"Removing existing snapshot at time: " <<
182 delete last_snapshot;
207 CAROM_VERIFY(energy_fraction > 0 && energy_fraction <= 1);
218 CAROM_VERIFY(k > 0 && k <= f_snapshots->numColumns() - 1);
226 std::pair<Matrix*, Matrix*>
242 for (
int i = 0; i < snapshots->
numRows(); i++)
244 for (
int j = 0; j < snapshots->
numColumns() - 1; j++)
246 f_snapshots_in->
item(i, j) = snapshots->
item(i, j);
247 f_snapshots_out->
item(i, j) = snapshots->
item(i, j + 1);
256 return std::pair<Matrix*,Matrix*>(f_snapshots_in, f_snapshots_out);
265 Matrix* f_snapshots_out_mult_d_basis_right =
267 Matrix* f_snapshots_out_mult_d_basis_right_mult_d_S_inv =
268 f_snapshots_out_mult_d_basis_right->
mult(dmd_internal_obj.
S_inv);
269 d_phi_real = f_snapshots_out_mult_d_basis_right_mult_d_S_inv->
mult(
274 delete f_snapshots_out_mult_d_basis_right;
275 delete f_snapshots_out_mult_d_basis_right_mult_d_S_inv;
290 double linearity_tol)
294 Matrix* f_snapshots_in = f_snapshot_pair.first;
295 Matrix* f_snapshots_out = f_snapshot_pair.second;
301 CAROM_VERIFY(MPI_Allgather(MPI_IN_PLACE,
307 MPI_COMM_WORLD) == MPI_SUCCESS);
309 row_offset[i] = row_offset[i + 1] - row_offset[i];
312 CAROM_VERIFY(row_offset[0] == 0);
317 SLPK_Matrix svd_input;
320 initialize_matrix(&svd_input, f_snapshots_in->
numColumns(),
326 scatter_block(&svd_input, 1, row_offset[rank] + 1,
329 row_offset[rank + 1] - row_offset[rank], rank);
332 std::unique_ptr<SVDManager> d_factorizer(
new SVDManager);
335 svd_init(d_factorizer.get(), &svd_input);
336 d_factorizer->dov = 1;
337 factorize(d_factorizer.get());
338 free_matrix_data(&svd_input);
345 d_sv.push_back(d_factorizer->S[i]);
353 double total_energy = 0.0;
356 total_energy += d_factorizer->S[i];
358 double current_energy = 0.0;
361 current_energy += d_factorizer->S[i];
371 if (
d_rank == 0) std::cout <<
"Using " <<
d_k <<
" basis vectors out of " <<
381 gather_block(&
d_basis->
item(0, 0), d_factorizer->V,
382 1, row_offset[
static_cast<unsigned>(
d_rank)]+1,
383 d_k, row_offset[
static_cast<unsigned>(
d_rank) + 1] -
384 row_offset[
static_cast<unsigned>(
d_rank)],
389 gather_transposed_block(&d_basis_right->
item(0, 0), d_factorizer->U, 1, 1,
395 for (
int i = 0; i <
d_k; ++i)
397 d_S_inv->
item(i, i) = 1 / d_factorizer->S[
static_cast<unsigned>(i)];
406 CAROM_VERIFY(linearity_tol >= 0.0);
407 std::vector<int> lin_independent_cols_W;
412 for (
int i = 0; i < d_basis_init->
numRows(); i++)
416 d_basis_init->
item(i, j) = W0->
item(i, j);
428 for (
int i = 0; i < f_snapshots->
numRows(); i++)
435 d_basis_init->
mult(l, W0l);
454 if (k >= linearity_tol)
456 lin_independent_cols_W.push_back(j);
463 W0->
numColumns() + lin_independent_cols_W.size(),
true);
464 for (
int i = 0; i < d_basis_new->
numRows(); i++)
468 d_basis_new->
item(i, j) = W0->
item(i, j);
470 for (
int j = 0; j < lin_independent_cols_W.size(); j++)
473 lin_independent_cols_W[j]);
487 if (
d_rank == 0) std::cout <<
"After adding W0, now using " <<
d_k <<
488 " basis vectors." << std::endl;
493 Matrix* d_basis_mult_f_snapshots_out_mult_d_basis_right =
494 d_basis_mult_f_snapshots_out->
mult(d_basis_right);
497 d_A_tilde = d_basis_mult_f_snapshots_out_mult_d_basis_right->
mult(d_S_inv);
501 Matrix* d_basis_mult_f_snapshots_out_mult_d_basis_right_mult_d_S_inv =
502 d_basis_mult_f_snapshots_out_mult_d_basis_right->
mult(d_S_inv);
503 d_A_tilde = d_basis_mult_f_snapshots_out_mult_d_basis_right_mult_d_S_inv->
mult(
506 delete d_basis_mult_f_snapshots_out_mult_d_basis_right_mult_d_S_inv;
513 struct DMDInternal dmd_internal = {f_snapshots_in, f_snapshots_out,
d_basis, d_basis_right, d_S_inv, &eigenpair};
517 for (
int i = 0; i < init->
dim(); i++)
519 init->
item(i) = f_snapshots_in->
item(i, 0);
527 delete d_basis_right;
529 delete d_basis_mult_f_snapshots_out;
530 delete d_basis_mult_f_snapshots_out_mult_d_basis_right;
531 delete f_snapshots_in;
532 delete f_snapshots_out;
537 release_context(&svd_input);
545 *d_phi_real_squared += *d_phi_real_squared_2;
549 *d_phi_imaginary_squared -= *d_phi_imaginary_squared_2;
551 const int dprs_row = d_phi_real_squared->
numRows();
552 const int dprs_col = d_phi_real_squared->
numColumns();
553 double* inverse_input =
new double[dprs_row * dprs_col * 2];
554 for (
int i = 0; i < d_phi_real_squared->
numRows(); i++)
557 for (
int j = 0; j < d_phi_real_squared->
numColumns() * 2; j++)
561 inverse_input[d_phi_real_squared->
numColumns() * 2 * i + j] =
562 d_phi_real_squared->
item(i, k);
566 inverse_input[d_phi_imaginary_squared->
numColumns() * 2 * i + j] =
567 d_phi_imaginary_squared->
item(i, k);
576 int mtx_size = d_phi_real_squared->
numColumns();
577 int lwork = mtx_size*mtx_size*std::max(10,
d_num_procs);
578 int* ipiv =
new int [mtx_size];
579 double* work =
new double [lwork];
582 zgetrf(&mtx_size, &mtx_size, inverse_input, &mtx_size, ipiv, &info);
583 zgetri(&mtx_size, inverse_input, &mtx_size, ipiv, work, &lwork, &info);
620 d_projected_init_imaginary_1);
622 delete d_phi_real_squared_2;
623 delete d_projected_init_real_1;
624 delete d_projected_init_real_2;
625 delete d_phi_imaginary_squared_2;
626 delete d_projected_init_imaginary_1;
627 delete d_projected_init_imaginary_2;
629 delete rhs_imaginary;
631 delete [] inverse_input;
637 std::cout <<
"t_offset is updated from " <<
d_t_offset <<
638 " to " << t_offset << std::endl;
649 CAROM_VERIFY(t >= 0.0);
653 std::pair<Matrix*, Matrix*> d_phi_pair =
phiMultEigs(t, deg);
654 Matrix* d_phi_mult_eigs_real = d_phi_pair.first;
655 Matrix* d_phi_mult_eigs_imaginary = d_phi_pair.second;
657 Vector* d_predicted_state_real_1 = d_phi_mult_eigs_real->
mult(
659 Vector* d_predicted_state_real_2 = d_phi_mult_eigs_imaginary->
mult(
661 Vector* d_predicted_state_real = d_predicted_state_real_1->
minus(
662 d_predicted_state_real_2);
663 addOffset(d_predicted_state_real, t, deg);
665 delete d_phi_mult_eigs_real;
666 delete d_phi_mult_eigs_imaginary;
667 delete d_predicted_state_real_1;
668 delete d_predicted_state_real_2;
670 return d_predicted_state_real;
685 return std::pow(eig, t /
d_dt);
688 std::pair<Matrix*, Matrix*>
694 for (
int i = 0; i <
d_k; i++)
697 for (
int k = 0; k < deg; ++k)
701 d_eigs_exp_real->
item(i, i) = std::real(eig_exp);
702 d_eigs_exp_imaginary->
item(i, i) = std::imag(eig_exp);
707 *d_phi_mult_eigs_real -= *d_phi_mult_eigs_real_2;
710 *d_phi_mult_eigs_imaginary += *d_phi_mult_eigs_imaginary_2;
712 delete d_eigs_exp_real;
713 delete d_eigs_exp_imaginary;
714 delete d_phi_mult_eigs_real_2;
715 delete d_phi_mult_eigs_imaginary_2;
717 return std::pair<Matrix*,Matrix*>(d_phi_mult_eigs_real,
718 d_phi_mult_eigs_imaginary);
736 CAROM_VERIFY(snapshots.size() > 0);
737 CAROM_VERIFY(snapshots[0]->dim() > 0);
738 for (
int i = 0 ; i < snapshots.size() - 1; i++)
740 CAROM_VERIFY(snapshots[i]->dim() == snapshots[i + 1]->dim());
741 CAROM_VERIFY(snapshots[i]->distributed() == snapshots[i + 1]->distributed());
744 Matrix* snapshot_mat =
new Matrix(snapshots[0]->dim(), snapshots.size(),
745 snapshots[0]->distributed());
747 for (
int i = 0; i < snapshots[0]->dim(); i++)
749 for (
int j = 0; j < snapshots.size(); j++)
751 snapshot_mat->
item(i, j) = snapshots[j]->item(i);
761 CAROM_ASSERT(!base_file_name.empty());
764 std::string full_file_name = base_file_name;
766 database.
open(full_file_name,
"r");
771 sprintf(tmp,
"t_offset");
777 sprintf(tmp,
"num_eigs");
781 std::vector<double> eigs_real;
782 std::vector<double> eigs_imag;
784 sprintf(tmp,
"eigs_real");
785 eigs_real.resize(num_eigs);
788 sprintf(tmp,
"eigs_imag");
789 eigs_imag.resize(num_eigs);
792 for (
int i = 0; i < num_eigs; i++)
794 d_eigs.push_back(std::complex<double>(eigs_real[i], eigs_imag[i]));
798 full_file_name = base_file_name +
"_basis";
802 full_file_name = base_file_name +
"_A_tilde";
806 full_file_name = base_file_name +
"_phi_real";
810 full_file_name = base_file_name +
"_phi_imaginary";
814 full_file_name = base_file_name +
"_phi_real_squared_inverse";
818 full_file_name = base_file_name +
"_phi_imaginary_squared_inverse";
822 full_file_name = base_file_name +
"_projected_init_real";
826 full_file_name = base_file_name +
"_projected_init_imaginary";
830 full_file_name = base_file_name +
"_state_offset";
840 MPI_Barrier(MPI_COMM_WORLD);
846 load(std::string(base_file_name));
852 CAROM_ASSERT(!base_file_name.empty());
858 std::string full_file_name = base_file_name;
860 database.
create(full_file_name);
865 sprintf(tmp,
"t_offset");
871 sprintf(tmp,
"num_eigs");
874 std::vector<double> eigs_real;
875 std::vector<double> eigs_imag;
877 for (
int i = 0; i <
d_eigs.size(); i++)
879 eigs_real.push_back(
d_eigs[i].real());
880 eigs_imag.push_back(
d_eigs[i].imag());
883 sprintf(tmp,
"eigs_real");
886 sprintf(tmp,
"eigs_imag");
891 std::string full_file_name;
895 full_file_name = base_file_name +
"_basis";
901 full_file_name = base_file_name +
"_A_tilde";
905 full_file_name = base_file_name +
"_phi_real";
908 full_file_name = base_file_name +
"_phi_imaginary";
911 full_file_name = base_file_name +
"_phi_real_squared_inverse";
914 full_file_name = base_file_name +
"_phi_imaginary_squared_inverse";
917 full_file_name = base_file_name +
"_projected_init_real";
920 full_file_name = base_file_name +
"_projected_init_imaginary";
925 full_file_name = base_file_name +
"_state_offset";
929 MPI_Barrier(MPI_COMM_WORLD);
935 save(std::string(base_file_name));
void putDoubleVector(const std::string &file_name, const std::vector< double > &data, int nelements, const bool distributed=false) override
Writes a vector of doubles associated with the supplied filename to the currently open CSV database f...
void putComplexVector(const std::string &file_name, const std::vector< std::complex< double >> &data, int nelements)
Writes a vector of complex doubles associated with the supplied filename.
std::pair< Matrix *, Matrix * > phiMultEigs(double t, int deg=0)
Internal function to multiply d_phi with the eigenvalues.
Matrix * d_phi_real
The real part of d_phi.
std::vector< std::complex< double > > d_eigs
A vector holding the complex eigenvalues of the eigenmodes.
Matrix * d_phi_real_squared_inverse
The real part of d_phi_squared_inverse.
virtual ~DMD()
Destroy the DMD object.
double d_energy_fraction
The energy fraction used to obtain the DMD modes.
int d_dim
The total dimension of the sample vector.
Vector * predict(double t, int deg=0)
Predict state given a time. Uses the projected initial condition of the training dataset (the first c...
virtual void train(double energy_fraction, const Matrix *W0=NULL, double linearity_tol=0.0)
Train the DMD model with energy fraction criterion.
bool d_init_projected
Whether the initial condition has been projected.
Matrix * d_A_tilde
A_tilde.
virtual void takeSample(double *u_in, double t)
Sample the new state, u_in. Any samples in d_snapshots taken at the same or later time will be erased...
virtual void addOffset(Vector *&result, double t=0.0, int deg=0)
Add the appropriate offset when predicting the solution.
virtual std::complex< double > computeEigExp(std::complex< double > eig, double t)
Compute the appropriate exponential function when predicting the solution.
const Matrix * createSnapshotMatrix(std::vector< Vector * > snapshots)
Get the snapshot matrix contained within d_snapshots.
void constructDMD(const Matrix *f_snapshots, int rank, int num_procs, const Matrix *W0, double linearity_tol)
Construct the DMD object.
void projectInitialCondition(const Vector *init, double t_offset=-1.0)
Project new initial condition using d_phi. Calculate pinv(phi) x init, or more precisely,...
void summary(std::string base_file_name)
Output the DMD record in CSV files.
virtual std::pair< Matrix *, Matrix * > computeDMDSnapshotPair(const Matrix *snapshots)
Returns a pair of pointers to the minus and plus snapshot matrices.
double d_dt
The time step size between samples.
Vector * d_state_offset
State offset in snapshot.
virtual void save(std::string base_file_name)
Save the object state to a file.
const Matrix * getSnapshotMatrix()
Get the snapshot matrix contained within d_snapshots.
std::vector< double > d_sv
std::vector holding the signular values.
virtual void setOffset(Vector *offset_vector, int order)
Set the offset of a certain order.
std::vector< Vector * > d_sampled_times
The stored times of each sample.
double getTimeOffset() const
Get the time offset contained within d_t_offset.
int d_num_singular_vectors
The maximum number of singular vectors.
Matrix * d_phi_imaginary
The imaginary part of d_phi.
double d_t_offset
The time offset of the first sample.
Vector * d_projected_init_real
The real part of the projected initial condition.
int d_rank
The rank of the process this object belongs to.
std::vector< Vector * > d_snapshots
std::vector holding the snapshots.
DMD()
Unimplemented default constructor.
Matrix * d_basis
The left singular vector basis.
int d_num_procs
The number of processors being run on.
bool d_alt_output_basis
Whether to use the alternative basis for output, i.e. phi = U^(+)*V*Omega^(-1)*X.
virtual void load(std::string base_file_name)
Load the object state from a file.
Matrix * d_phi_imaginary_squared_inverse
The imaginary part of d_phi_squared_inverse.
Vector * d_projected_init_imaginary
The imaginary part of the projected initial condition.
bool d_trained
Whether the DMD has been trained or not.
virtual void computePhi(DMDInternal dmd_internal_obj)
Compute phi.
int d_k
The number of columns used after obtaining the SVD decomposition.
void getInteger(const std::string &key, int &data)
Reads an integer associated with the supplied key from the currently open database file.
void putDouble(const std::string &key, double data)
Writes a double associated with the supplied key to currently open database file.
void putInteger(const std::string &key, int data)
Writes an integer associated with the supplied key to currently open database file.
void getDouble(const std::string &key, double &data)
Reads a double associated with the supplied key from the currently open database file.
virtual bool create(const std::string &file_name, const MPI_Comm comm=MPI_COMM_NULL) override
Creates a new HDF5 database file with the supplied name.
virtual bool open(const std::string &file_name, const std::string &type, const MPI_Comm comm=MPI_COMM_NULL) override
Opens an existing HDF5 database file with the supplied name.
virtual void getDoubleArray(const std::string &key, double *data, int nelements, const bool distributed=false)
Reads an array of doubles associated with the supplied key from the currently open HDF5 database file...
virtual void putDoubleArray(const std::string &key, const double *const data, int nelements, const bool distributed=false)
Writes an array of doubles associated with the supplied key to the currently open HDF5 database file.
virtual bool close()
Closes the currently open HDF5 database file.
double * getData() const
Get the matrix data as a pointer.
bool distributed() const
Returns true if the Matrix is distributed.
void write(const std::string &base_file_name) const
write Matrix into (a) HDF file(s).
int numColumns() const
Returns the number of columns in the Matrix. This method will return the same value from each process...
int numDistributedRows() const
Returns the number of rows of the Matrix across all processors.
void orthogonalize(bool double_pass=false, double zero_tol=1.0e-15)
Orthonormalizes the matrix.
Matrix * transposeMult(const Matrix &other) const
Multiplies the transpose of this Matrix with other and returns the product, reference version.
Matrix * mult(const Matrix &other) const
Multiplies this Matrix with other and returns the product, reference version.
const double & item(int row, int col) const
Const Matrix member access. Matrix data is stored in row-major format.
int numRows() const
Returns the number of rows of the Matrix on this processor.
void read(const std::string &base_file_name)
read Matrix into (a) HDF file(s).
void read(const std::string &base_file_name)
read Vector from (a) HDF file(s).
Vector * minus(const Vector &other) const
Subtracts other and this and returns the result, reference version.
void write(const std::string &base_file_name)
write Vector into (a) HDF file(s).
Vector * plus(const Vector &other) const
Adds other and this and returns the result, reference version.
const double & item(int i) const
Const Vector member access.
double inner_product(const Vector &other) const
Inner product, reference form.
int dim() const
Returns the dimension of the Vector on this processor.
struct ComplexEigenPair NonSymmetricRightEigenSolve(Matrix *A)
Computes the eigenvectors/eigenvalues of an NxN real nonsymmetric matrix.
Matrix * ev_real
The real component of the eigenvectors in matrix form.
std::vector< std::complex< double > > eigs
The corresponding complex eigenvalues.
Matrix * ev_imaginary
The imaginary component of the eigenvectors in matrix form.
ComplexEigenPair * eigenpair
The resultant DMD eigenvalues and eigenvectors.
Matrix * snapshots_out
The snapshot vectors of output.
Matrix * basis
The left singular vector basis.
Matrix * basis_right
The right singular vector basis.
Matrix * S_inv
The inverse of singular values.
static bool file_exist(const std::string &filename)
Verifies if a file exists.