[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
hrom_test_location.cpp
1 #include "hrom_test_location.h"
2 #include <iostream>
3 #include <filesystem>
4 #include <deal.II/base/conditional_ostream.h>
5 #include <deal.II/lac/trilinos_sparse_matrix.h>
6 #include "parameters/all_parameters.h"
7 #include "pod_basis_base.h"
8 #include "multi_core_helper_functions.h"
9 #include "reduced_order_solution.h"
10 #include "linear_solver/linear_solver.h"
11 #include <Epetra_Vector.h>
12 #include <EpetraExt_MatrixMatrix.h>
13 #include <Epetra_LinearProblem.h>
14 #include <Epetra_SerialComm.h>
15 #include "Amesos.h"
16 #include <Amesos_Lapack.h>
17 #include "flow_solver/flow_solver.h"
18 #include "flow_solver/flow_solver_factory.h"
19 #include <deal.II/base/parameter_handler.h>
20 
21 namespace PHiLiP {
22 namespace ProperOrthogonalDecomposition {
23 
24 template <int dim, int nstate>
25 HROMTestLocation<dim, nstate>::HROMTestLocation(const RowVectorXd& parameter, std::unique_ptr<ROMSolution<dim, nstate>> rom_solution, std::shared_ptr< DGBase<dim, double> > dg_input, Epetra_Vector weights)
26  : TestLocationBase<dim, nstate>(parameter, std::move(rom_solution))
27  , dg(dg_input)
28  , ECSW_weights(weights)
29 {
30 }
31 
32 template <int dim, int nstate>
34 
35  this->pcout << "Computing adjoint-based error estimate between initial ROM and updated ROM..." << std::endl;
36 
37  dealii::ParameterHandler dummy_handler;
38  std::unique_ptr<FlowSolver::FlowSolver<dim,nstate>> flow_solver = FlowSolver::FlowSolverFactory<dim,nstate>::select_flow_case(&this->rom_solution->params, dummy_handler);
39  flow_solver->dg->solution = this->rom_solution->solution;
40  const bool compute_dRdW = true;
41  flow_solver->dg->assemble_residual(compute_dRdW);
42 
43  // Build hyperreduced Jacobian
44  Epetra_CrsMatrix epetra_system_matrix = flow_solver->dg->system_matrix.trilinos_matrix();
45  std::shared_ptr<Epetra_CrsMatrix> reduced_system_matrix = generate_hyper_reduced_jacobian(epetra_system_matrix);
46 
47  // Find test basis W with hyperreduced Jacobian
48  const Epetra_CrsMatrix epetra_pod_basis = pod_updated->getPODBasis()->trilinos_matrix();
49  std::shared_ptr<Epetra_CrsMatrix> epetra_petrov_galerkin_basis_ptr = generate_test_basis(*reduced_system_matrix, epetra_pod_basis);
50  Epetra_CrsMatrix epetra_petrov_galerkin_basis = *epetra_petrov_galerkin_basis_ptr;
51 
52  Epetra_Vector epetra_gradient(epetra_pod_basis.RowMap());
53 
54  // Iterate over local indices and copy manually
55  for (unsigned int i = 0; i < this->rom_solution->gradient.local_size(); ++i){
56  epetra_gradient.ReplaceMyValue(static_cast<int>(i), 0, this->rom_solution->gradient.local_element(i));
57  }
58 
59  Epetra_Vector epetra_reduced_gradient(epetra_pod_basis.DomainMap());
60 
61  epetra_pod_basis.Multiply(true, epetra_gradient, epetra_reduced_gradient);
62 
63  Epetra_CrsMatrix epetra_reduced_jacobian_transpose(Epetra_DataAccess::Copy, epetra_petrov_galerkin_basis.DomainMap(), pod_updated->getPODBasis()->n());
64  EpetraExt::MatrixMatrix::Multiply(epetra_petrov_galerkin_basis, true, epetra_petrov_galerkin_basis, false, epetra_reduced_jacobian_transpose);
65 
66  Epetra_Vector epetra_reduced_adjoint(epetra_reduced_jacobian_transpose.DomainMap());
67  epetra_reduced_gradient.Scale(-1);
68  if (this->rom_solution->params.reduced_order_param.residual_error_bool == true){
69  epetra_reduced_adjoint.PutScalar(0);
70  }
71  else{
72  Epetra_LinearProblem linearProblem(&epetra_reduced_jacobian_transpose, &epetra_reduced_adjoint, &epetra_reduced_gradient);
73 
74  Amesos_Lapack Solver(linearProblem);
75 
76  Teuchos::ParameterList List;
77  Solver.SetParameters(List);
78  Solver.SymbolicFactorization();
79  Solver.NumericFactorization();
80  Solver.Solve();
81  }
82 
83  Epetra_Vector epetra_reduced_residual(epetra_petrov_galerkin_basis.DomainMap());
84  Epetra_Vector epetra_residual(Epetra_DataAccess::Copy, epetra_petrov_galerkin_basis.RangeMap(), const_cast<double *>(flow_solver->dg->right_hand_side.begin()));
85  epetra_petrov_galerkin_basis.Multiply(true, epetra_residual, epetra_reduced_residual);
86 
87  // Compute dual weighted residual
89  epetra_reduced_adjoint.Dot(epetra_reduced_residual, &this->initial_rom_to_final_rom_error);
91 
92  this->pcout << "Parameter: " << this->parameter << ". Error estimate between initial ROM and updated ROM: " << this->initial_rom_to_final_rom_error << std::endl;
93 }
94 
95 template <int dim, int nstate>
96 std::shared_ptr<Epetra_CrsMatrix> HROMTestLocation<dim, nstate>::generate_hyper_reduced_jacobian(const Epetra_CrsMatrix &system_matrix)
97 {
98  /* Refer to Equation (12) in:
99  https://onlinelibrary.wiley.com/doi/10.1002/nme.6603 (includes definitions of matrices used below such as L_e and L_e_PLUS)
100  Create empty Hyper-reduced Jacobian Epetra structure */
101  Epetra_MpiComm epetra_comm(MPI_COMM_WORLD);
102  Epetra_Map system_matrix_rowmap = system_matrix.RowMap();
103  Epetra_CrsMatrix local_system_matrix = copy_matrix_to_all_cores(system_matrix);
104  Epetra_CrsMatrix reduced_jacobian(Epetra_DataAccess::Copy, system_matrix_rowmap, system_matrix.NumGlobalCols());
105  int N = system_matrix.NumGlobalRows();
106  Epetra_BlockMap element_map = ECSW_weights.Map();
107  const unsigned int max_dofs_per_cell = this->dg->dof_handler.get_fe_collection().max_dofs_per_cell();
108  std::vector<dealii::types::global_dof_index> current_dofs_indices(max_dofs_per_cell);
109  std::vector<dealii::types::global_dof_index> neighbour_dofs_indices(max_dofs_per_cell);
110 
111  // Loop through elements
112  for (const auto &cell : this->dg->dof_handler.active_cell_iterators())
113  {
114  // Add the contributilons of an element if the weight from the NNLS is non-zero
115  if (cell->is_locally_owned()){
116  int global = cell->active_cell_index();
117  const int local_element = element_map.LID(global);
118  if (ECSW_weights[local_element] != 0){
119  const int fe_index_curr_cell = cell->active_fe_index();
120  const dealii::FESystem<dim,dim> &current_fe_ref = this->dg->fe_collection[fe_index_curr_cell];
121  const int n_dofs_curr_cell = current_fe_ref.n_dofs_per_cell();
122 
123  current_dofs_indices.resize(n_dofs_curr_cell);
124  cell->get_dof_indices(current_dofs_indices);
125 
126  int numE;
127  int row_i = current_dofs_indices[0];
128  double *row = new double[local_system_matrix.NumGlobalCols()];
129  int *global_indices = new int[local_system_matrix.NumGlobalCols()];
130  // Use the Jacobian to determine the stencil around the current element
131  local_system_matrix.ExtractGlobalRowCopy(row_i, local_system_matrix.NumGlobalCols(), numE, row, global_indices);
132  int neighbour_dofs_curr_cell = 0;
133  for (int i = 0; i < numE; i++){
134  neighbour_dofs_curr_cell +=1;
135  neighbour_dofs_indices.resize(neighbour_dofs_curr_cell);
136  neighbour_dofs_indices[neighbour_dofs_curr_cell-1] = global_indices[i];
137  }
138 
139  delete[] row;
140  delete[] global_indices;
141 
142  // Create L_e matrix and transposed L_e matrix for current cell
143  const Epetra_SerialComm sComm;
144  Epetra_Map LeRowMap(n_dofs_curr_cell, 0, sComm);
145  Epetra_Map LeTRowMap(N, 0, sComm);
146  Epetra_CrsMatrix L_e(Epetra_DataAccess::Copy, LeRowMap, LeTRowMap, 1);
147  Epetra_CrsMatrix L_e_T(Epetra_DataAccess::Copy, LeTRowMap, n_dofs_curr_cell);
148  Epetra_Map LePLUSRowMap(neighbour_dofs_curr_cell, 0, sComm);
149  Epetra_CrsMatrix L_e_PLUS(Epetra_DataAccess::Copy, LePLUSRowMap, LeTRowMap, 1);
150  double posOne = 1.0;
151 
152  for(int i = 0; i < n_dofs_curr_cell; i++){
153  const int col = current_dofs_indices[i];
154  L_e.InsertGlobalValues(i, 1, &posOne , &col);
155  L_e_T.InsertGlobalValues(col, 1, &posOne , &i);
156  }
157  L_e.FillComplete(LeTRowMap, LeRowMap);
158  L_e_T.FillComplete(LeRowMap, LeTRowMap);
159 
160  for(int i = 0; i < neighbour_dofs_curr_cell; i++){
161  const int col = neighbour_dofs_indices[i];
162  L_e_PLUS.InsertGlobalValues(i, 1, &posOne , &col);
163  }
164  L_e_PLUS.FillComplete(LeTRowMap, LePLUSRowMap);
165 
166  // Find contribution of element to the Jacobian
167  Epetra_CrsMatrix J_L_e_T(Epetra_DataAccess::Copy, local_system_matrix.RowMap(), neighbour_dofs_curr_cell);
168  Epetra_CrsMatrix J_e_m(Epetra_DataAccess::Copy, LeRowMap, neighbour_dofs_curr_cell);
169  EpetraExt::MatrixMatrix::Multiply(local_system_matrix, false, L_e_PLUS, true, J_L_e_T, true);
170  EpetraExt::MatrixMatrix::Multiply(L_e, false, J_L_e_T, false, J_e_m, true);
171 
172  // Jacobian for this element in the global dimensions
173  Epetra_CrsMatrix J_temp(Epetra_DataAccess::Copy, LeRowMap, N);
174  Epetra_CrsMatrix J_global_e(Epetra_DataAccess::Copy, LeTRowMap, N);
175  EpetraExt::MatrixMatrix::Multiply(J_e_m, false, L_e_PLUS, false, J_temp, true);
176  EpetraExt::MatrixMatrix::Multiply(L_e_T, false, J_temp, false, J_global_e, true);
177 
178  // Add the contribution of the element to the hyper-reduced Jacobian with scaling from the weights
179  double scaling = ECSW_weights[local_element];
180  EpetraExt::MatrixMatrix::Add(J_global_e, false, scaling, reduced_jacobian, 1.0);
181  }
182  }
183  }
184  reduced_jacobian.FillComplete();
185  return std::make_shared<Epetra_CrsMatrix>(reduced_jacobian);
186 }
187 
188 template <int dim, int nstate>
189 std::shared_ptr<Epetra_CrsMatrix> HROMTestLocation<dim, nstate>::generate_test_basis(Epetra_CrsMatrix &system_matrix, const Epetra_CrsMatrix &pod_basis)
190 {
191  Epetra_Map system_matrix_rowmap = system_matrix.RowMap();
192  Epetra_CrsMatrix petrov_galerkin_basis(Epetra_DataAccess::Copy, system_matrix_rowmap, pod_basis.NumGlobalCols());
193  EpetraExt::MatrixMatrix::Multiply(system_matrix, false, pod_basis, false, petrov_galerkin_basis, true);
194 
195  return std::make_shared<Epetra_CrsMatrix>(petrov_galerkin_basis);
196 }
197 
198 #if PHILIP_DIM==1
200 #endif
201 
202 #if PHILIP_DIM!=1
204 #endif
205 
206 }
207 }
Base class for a ROM/HROM point, differences would be in the second DWR error indicator.
std::shared_ptr< DGBase< dim, double > > dg
Smart pointer to DGBase.
Files for the baseline physics.
Definition: ADTypes.hpp:10
std::shared_ptr< Epetra_CrsMatrix > generate_hyper_reduced_jacobian(const Epetra_CrsMatrix &system_matrix)
Generate hyper-reduced jacobian matrix.
dealii::ConditionalOStream pcout
ConditionalOStream.
static std::unique_ptr< FlowSolver< dim, nstate > > select_flow_case(const Parameters::AllParameters *const parameters_input, const dealii::ParameterHandler &parameter_handler_input)
Factory to return the correct flow solver given input file.
Class to compute and store adjoint-based error estimates with hyperreduction.
double initial_rom_to_final_rom_error
Error from initial ROM to final ROM.
Epetra_Vector ECSW_weights
ECSW hyper-reduction weights.
HROMTestLocation(const RowVectorXd &parameter, std::unique_ptr< ROMSolution< dim, nstate >> rom_solution, std::shared_ptr< DGBase< dim, double > > dg_input, Epetra_Vector weights)
Constructor.
std::unique_ptr< ROMSolution< dim, nstate > > rom_solution
ROM solution.
void compute_initial_rom_to_final_rom_error(std::shared_ptr< ProperOrthogonalDecomposition::PODBase< dim >> pod_updated) override
Compute error between initial ROM and final ROM.
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
Class to hold information about the reduced-order solution.
std::shared_ptr< Epetra_CrsMatrix > generate_test_basis(Epetra_CrsMatrix &epetra_system_matrix, const Epetra_CrsMatrix &pod_basis)
Generate test basis.