libROM  v1.0
Data-driven physical simulation library
DEIM.cpp
1 
11 // Description: Interface to the DEIM algorithm to determine the rows of the
12 // rhs to be sampled for the interpolation of the rhs.
13 
14 #include "linalg/Matrix.h"
15 #include "Utilities.h"
16 #include "mpi.h"
17 #include <cmath>
18 #include <vector>
19 #include <map>
20 #include <set>
21 
22 #include "DEIM.h"
23 
24 using namespace std;
25 
26 namespace CAROM {
27 
28 void
29 DEIM(const Matrix* f_basis,
30  int num_f_basis_vectors_used,
31  std::vector<int>& f_sampled_row,
32  std::vector<int>& f_sampled_rows_per_proc,
33  Matrix& f_basis_sampled_inv,
34  int myid,
35  int num_procs)
36 {
37  CAROM_VERIFY(num_procs == f_sampled_rows_per_proc.size());
38  // This algorithm determines the rows of f that should be sampled, the
39  // processor that owns each sampled row, and fills f_basis_sampled_inv with
40  // the inverse of the sampled rows of the basis of the RHS.
41 
42  // Create an MPI_Datatype for the RowInfo struct.
43  MPI_Datatype MaxRowType, oldtypes[2];
44  int blockcounts[2];
45  MPI_Aint offsets[2], extent, lower_bound;
46  MPI_Status stat;
47  offsets[0] = 0;
48  oldtypes[0] = MPI_DOUBLE;
49  blockcounts[0] = 1;
50 
51  /*
52  MPI_Type_extent is deprecated in MPI-2 and removed in
53  MPI-3. MPI_Type_extent has been replaced by MPI_Type_get_extent.
54  */
55 #if (MPI_VERSION == 1)
56  MPI_Type_extent(MPI_DOUBLE, &extent);
57 #else
58  MPI_Type_get_extent(MPI_DOUBLE, &lower_bound, &extent);
59 #endif
60 
61  offsets[1] = extent;
62  oldtypes[1] = MPI_INT;
63  blockcounts[1] = 2;
64 
65  /*
66  MPI_Type_struct is deprecated in MPI-2 and removed in
67  MPI-3. MPI_Type_struct has been replaced by MPI_Type_create_struct.
68  */
69 #if (MPI_VERSION == 1)
70  MPI_Type_struct(2, blockcounts, offsets, oldtypes, &MaxRowType);
71 #else
72  MPI_Type_create_struct(2, blockcounts, offsets, oldtypes, &MaxRowType);
73 #endif
74  MPI_Type_commit(&MaxRowType);
75 
76  // Create an MPI_Op for the RowInfoMax function.
77  MPI_Op RowInfoOp;
78  MPI_Op_create((MPI_User_function*)RowInfoMax, true, &RowInfoOp);
79 
80  // Get the number of basis vectors and the size of each basis vector.
81  CAROM_VERIFY(0 < num_f_basis_vectors_used
82  && num_f_basis_vectors_used <= f_basis->numColumns());
83  int num_basis_vectors =
84  std::min(num_f_basis_vectors_used, f_basis->numColumns());
85  CAROM_VERIFY(num_basis_vectors == f_sampled_row.size());
86  CAROM_VERIFY(num_basis_vectors == f_basis_sampled_inv.numRows()
87  && num_basis_vectors == f_basis_sampled_inv.numColumns());
88  CAROM_VERIFY(!f_basis_sampled_inv.distributed());
89  int basis_size = f_basis->numRows();
90 
91  // The small matrix inverted by the algorithm. We'll allocate the largest
92  // matrix we'll need and set its size at each step in the algorithm.
93  Matrix M(num_basis_vectors, num_basis_vectors, false);
94 
95  // Scratch space used throughout the algorithm.
96  double* c = new double [num_basis_vectors];
97 
98  vector<set<int> > proc_sampled_f_row(num_procs);
99  vector<map<int, int> > proc_f_row_to_tmp_fs_row(num_procs);
100  int num_f_basis_cols = f_basis_sampled_inv.numColumns();
101  Matrix tmp_fs(f_basis_sampled_inv.numRows(),
102  num_f_basis_cols,
103  f_basis_sampled_inv.distributed());
104 
105  // Figure out the 1st sampled row of the RHS.
106  RowInfo f_bv_max_local, f_bv_max_global;
107  f_bv_max_local.row_val = -1.0;
108  f_bv_max_local.proc = myid;
109  for (int i = 0; i < basis_size; ++i) {
110  double f_bv_val = fabs(f_basis->item(i, 0));
111  if (f_bv_val > f_bv_max_local.row_val) {
112  f_bv_max_local.row_val = f_bv_val;
113  f_bv_max_local.row = i;
114  }
115  }
116  MPI_Allreduce(&f_bv_max_local, &f_bv_max_global, 1,
117  MaxRowType, RowInfoOp, MPI_COMM_WORLD);
118 
119  // Now get the first sampled row of the basis of the RHS.
120  if (f_bv_max_global.proc == myid) {
121  for (int j = 0; j < num_basis_vectors; ++j) {
122  c[j] = f_basis->item(f_bv_max_global.row, j);
123  }
124  }
125  MPI_Bcast(c, num_basis_vectors, MPI_DOUBLE,
126  f_bv_max_global.proc, MPI_COMM_WORLD);
127  // Now add the first sampled row of the basis of the RHS to tmp_fs.
128  for (int j = 0; j < num_basis_vectors; ++j) {
129  tmp_fs.item(0, j) = c[j];
130  }
131  proc_sampled_f_row[f_bv_max_global.proc].insert(f_bv_max_global.row);
132  proc_f_row_to_tmp_fs_row[f_bv_max_global.proc][f_bv_max_global.row] = 0;
133 
134  // Now repeat the process for the other sampled rows of the basis of the
135  // RHS.
136  for (int i = 1; i < num_basis_vectors; ++i) {
137  // If we currently know about S sampled rows of the basis of the RHS then
138  // M contains the first S columns of those S sampled rows.
139  M.setSize(i, i);
140  for (int row = 0; row < i; ++row) {
141  for (int col = 0; col < i; ++col) {
142  M.item(row, col) = tmp_fs.item(row, col);
143  }
144  }
145 
146  // Invert M.
147  M.inverse();
148 
149  // Now compute c, the inverse of M times the next column of the sampled
150  // rows of the basis of the RHS.
151  for (int minv_row = 0; minv_row < i; ++minv_row) {
152  double tmp = 0.0;
153  for (int minv_col = 0; minv_col < i; ++minv_col) {
154  tmp += M.item(minv_row, minv_col)*tmp_fs.item(minv_col, i);
155  }
156  c[minv_row] = tmp;
157  }
158 
159  // Now figure out the next sampled row of the basis of f.
160  // Compute the first S basis vectors of the RHS times c and find the
161  // row of this product have the greatest absolute value. This is the
162  // next sampled row of the basis of f.
163  f_bv_max_local.row_val = -1.0;
164  f_bv_max_local.proc = myid;
165  for (int F_row = 0; F_row < basis_size; ++F_row) {
166  double tmp = 0.0;
167  for (int F_col = 0; F_col < i; ++F_col) {
168  tmp += f_basis->item(F_row, F_col)*c[F_col];
169  }
170  double r_val = fabs(f_basis->item(F_row, i) - tmp);
171  if (r_val > f_bv_max_local.row_val) {
172  f_bv_max_local.row_val = r_val;
173  f_bv_max_local.row = F_row;
174  }
175  }
176  MPI_Allreduce(&f_bv_max_local, &f_bv_max_global, 1,
177  MaxRowType, RowInfoOp, MPI_COMM_WORLD);
178 
179  // Now get the next sampled row of the basis of f.
180  if (f_bv_max_global.proc == myid) {
181  for (int j = 0; j < num_basis_vectors; ++j) {
182  c[j] = f_basis->item(f_bv_max_global.row, j);
183  }
184  }
185  MPI_Bcast(c, num_basis_vectors, MPI_DOUBLE,
186  f_bv_max_global.proc, MPI_COMM_WORLD);
187  // Now add the ith sampled row of the basis of the RHS to tmp_fs.
188  for (int j = 0; j < num_basis_vectors; ++j) {
189  tmp_fs.item(i, j) = c[j];
190  }
191  proc_sampled_f_row[f_bv_max_global.proc].insert(f_bv_max_global.row);
192  proc_f_row_to_tmp_fs_row[f_bv_max_global.proc][f_bv_max_global.row] = i;
193  }
194 
195  // Fill f_sampled_row, and f_sampled_rows_per_proc. Unscramble tmp_fs into
196  // f_basis_sampled_inv.
197  int idx = 0;
198  for (int i = 0; i < num_procs; ++i) {
199  set<int>& this_proc_sampled_f_row = proc_sampled_f_row[i];
200  map<int, int>& this_proc_f_row_to_tmp_fs_row =
201  proc_f_row_to_tmp_fs_row[i];
202  f_sampled_rows_per_proc[i] = this_proc_sampled_f_row.size();
203  for (set<int>::iterator j = this_proc_sampled_f_row.begin();
204  j != this_proc_sampled_f_row.end(); ++j) {
205  int this_f_row = *j;
206  f_sampled_row[idx] = this_f_row;
207  int tmp_fs_row = this_proc_f_row_to_tmp_fs_row[this_f_row];
208  for (int col = 0; col < num_f_basis_cols; ++col) {
209  f_basis_sampled_inv.item(idx, col) = tmp_fs.item(tmp_fs_row, col);
210  }
211  ++idx;
212  }
213  }
214 
215  // Now invert f_basis_sampled_inv.
216  f_basis_sampled_inv.inverse();
217 
218  // Free the MPI_Datatype and MPI_Op.
219  MPI_Type_free(&MaxRowType);
220  MPI_Op_free(&RowInfoOp);
221 
222  delete [] c;
223 }
224 
225 }
void setSize(int num_rows, int num_cols)
Sets the number of rows and columns of the matrix and reallocates storage if needed....
Definition: Matrix.h:147
Matrix * inverse() const
Computes and returns the inverse of this.
Definition: Matrix.h:814
bool distributed() const
Returns true if the Matrix is distributed.
Definition: Matrix.h:177
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
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
void DEIM(const Matrix *f_basis, int num_f_basis_vectors_used, std::vector< int > &f_sampled_row, std::vector< int > &f_sampled_rows_per_proc, Matrix &f_basis_sampled_inv, int myid, int num_procs)
Computes the DEIM algorithm on the given basis.
Definition: DEIM.cpp:29