https://mooseframework.inl.gov
PrintMatricesNSProblem.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "PrintMatricesNSProblem.h"
11 #include "NonlinearSystemBase.h"
12 #include "NS.h"
13 #include "MooseMesh.h"
14 #include "MooseVariableFieldBase.h"
15 #include "libmesh/nonlinear_solver.h"
16 #include "libmesh/petsc_matrix.h"
17 #include "libmesh/petsc_vector.h"
18 #include "libmesh/dof_map.h"
19 #include "libmesh/nonlinear_implicit_system.h"
20 #include <petscmat.h>
21 #include <slepceps.h>
22 
23 registerMooseObject("NavierStokesTestApp", PrintMatricesNSProblem);
24 
27 {
29  params.addRequiredParam<TagName>(
30  "pressure_mass_matrix", "The matrix tag name corresponding to the pressure mass matrix.");
31  params.addRequiredParam<TagName>(
32  "velocity_mass_matrix", "The matrix tag name corresponding to the velocity mass matrix.");
33  params.addParam<std::vector<TagName>>(
34  "augmented_lagrange_matrices",
35  {},
36  "Matrices corresponding to finite element weak forms used to create augmented Lagrange "
37  "perturbations. Example weak forms include volumetric grad-div and face jumps for "
38  "discontinuous Galerkin discretizations. This is a vector because, for example, a user may "
39  "pass one matrix that corresponds just to grad-div, another corresponding to face jumps, and "
40  "yet another corresponding to the sum of the two.");
41  params.addRequiredParam<NonlinearVariableName>("u", "The interior x-velocity variable");
42  params.addRequiredParam<NonlinearVariableName>("v", "The interior y-velocity variable");
43  params.addParam<NonlinearVariableName>(NS::pressure, "The pressure in the volume");
44  params.addParam<NonlinearVariableName>(NS::pressure + "_bar", "The pressure on the facets");
45  params.addParam<bool>("print", true, "Whether to print the matrices");
46  return params;
47 }
48 
50  : FEProblem(parameters),
51  _pressure_mass_matrix(getParam<TagName>("pressure_mass_matrix")),
52  _velocity_mass_matrix(getParam<TagName>("velocity_mass_matrix")),
53  _augmented_lagrange_matrices(getParam<std::vector<TagName>>("augmented_lagrange_matrices"))
54 {
55  if (_communicator.size() > 1)
56  mooseError("This problem can only be used in serial");
57 }
58 
59 void
61 {
63 
64  const bool print = getParam<bool>("print");
65 
66  const bool has_p = isParamValid(NS::pressure);
67  const bool has_pbar = isParamValid(NS::pressure + "_bar");
68 
69  auto & nl = getNonlinearSystemBase(0);
70  auto & dof_map = nl.dofMap();
71  auto & lm_mesh = mesh().getMesh();
72 
73  const auto & u_var = nl.getVariable(0, getParam<NonlinearVariableName>("u"));
74  const auto & v_var = nl.getVariable(0, getParam<NonlinearVariableName>("v"));
75  const MooseVariableFieldBase * p_var = nullptr;
76  const MooseVariableFieldBase * pb_var = nullptr;
77  if (has_p)
78  p_var = &nl.getVariable(0, getParam<NonlinearVariableName>(NS::pressure));
79  if (has_pbar)
80  pb_var = &nl.getVariable(0, getParam<NonlinearVariableName>(NS::pressure + "_bar"));
81 
82  // Retrieve DOF indices for each variable
83  std::vector<dof_id_type> u_indices, v_indices, p_vol_indices, pb_indices, vel_indices, p_indices;
84  dof_map.local_variable_indices(u_indices, lm_mesh, u_var.number());
85  dof_map.local_variable_indices(v_indices, lm_mesh, v_var.number());
86  if (has_p)
87  dof_map.local_variable_indices(p_vol_indices, lm_mesh, p_var->number());
88  if (has_pbar)
89  dof_map.local_variable_indices(pb_indices, lm_mesh, pb_var->number());
90  vel_indices = u_indices;
91  vel_indices.insert(vel_indices.end(), v_indices.begin(), v_indices.end());
92  p_indices = p_vol_indices;
93  if (has_pbar)
94  p_indices.insert(p_indices.end(), pb_indices.begin(), pb_indices.end());
95 
96  // Retrieve mass matrices and system matrix
97  PetscMatrix<Number> vel_p_mat(_communicator), p_vel_mat(_communicator), p_mass_mat(_communicator),
98  vel_mass_mat(_communicator);
99  const auto pressure_mass_matrix_tag_id = getMatrixTagID(_pressure_mass_matrix);
100  auto & system_size_pressure_mass_matrix = nl.getMatrix(pressure_mass_matrix_tag_id);
101  const auto velocity_mass_matrix_tag_id = getMatrixTagID(_velocity_mass_matrix);
102  auto & system_size_velocity_mass_matrix = nl.getMatrix(velocity_mass_matrix_tag_id);
103  auto * const system_matrix =
104  dynamic_cast<PetscMatrix<Number> *>(&nl.nonlinearSolver()->system().get_system_matrix());
105  mooseAssert(system_matrix, "Must be a PETSc matrix");
106 
107  auto write_matrix = [this](Mat write_mat, const std::string & mat_name)
108  {
109  PetscViewer matviewer;
110  LibmeshPetscCallA(
111  _communicator.get(),
112  PetscViewerBinaryOpen(_communicator.get(), mat_name.c_str(), FILE_MODE_WRITE, &matviewer));
113  LibmeshPetscCallA(_communicator.get(), MatView(write_mat, matviewer));
114  LibmeshPetscCallA(_communicator.get(), PetscViewerDestroy(&matviewer));
115  };
116 
117  auto do_vel_p =
118  [this,
119  write_matrix,
120  print,
121  &vel_indices,
122  &system_size_pressure_mass_matrix,
123  &system_size_velocity_mass_matrix,
124  system_matrix,
125  &vel_p_mat,
126  &p_vel_mat,
127  &p_mass_mat,
128  &vel_mass_mat](const auto & pressure_indices, const std::string & outer_matrix_name)
129  {
130  // Computes and writes to file the product LHS * M^-1 * RHS
131  auto compute_triple_product_matrix =
132  [this, print, write_matrix](PetscMatrix<Number> & lhs,
133  PetscMatrix<Number> & mass_matrix,
134  PetscMatrix<Number> & rhs,
135  const std::string & inner_matrix_name)
136  {
137  Mat I, M, Minv;
138 
139  // Create the identity matrix
140  LibmeshPetscCall(MatCreateDense(_communicator.get(),
141  mass_matrix.local_m(),
142  mass_matrix.local_n(),
143  mass_matrix.m(),
144  mass_matrix.n(),
145  nullptr,
146  &I));
147  const PetscScalar one = 1.0;
148  for (const auto i : make_range(mass_matrix.row_start(), mass_matrix.row_stop()))
149  {
150  const auto petsc_i = cast_int<PetscInt>(i);
151  LibmeshPetscCall(MatSetValues(I, 1, &petsc_i, 1, &petsc_i, &one, INSERT_VALUES));
152  }
153  LibmeshPetscCall(MatAssemblyBegin(I, MAT_FINAL_ASSEMBLY));
154  LibmeshPetscCall(MatAssemblyEnd(I, MAT_FINAL_ASSEMBLY));
155 
156  // Create Minv
157  LibmeshPetscCall(MatCreateDense(_communicator.get(),
158  mass_matrix.local_m(),
159  mass_matrix.local_n(),
160  mass_matrix.m(),
161  mass_matrix.n(),
162  nullptr,
163  &Minv));
164 
165  // Factor mass matrix
166  LibmeshPetscCall(MatConvert(mass_matrix.mat(), MATDENSE, MAT_INITIAL_MATRIX, &M));
167  LibmeshPetscCall(MatLUFactor(M, nullptr, nullptr, nullptr));
168 
169  // Solve for Minv
170  LibmeshPetscCall(MatMatSolve(M, I, Minv));
171 
172  //
173  // Compute triple product and write the result
174  //
175 
176  Mat triple_product_mat;
177  LibmeshPetscCall(MatMatMatMult(
178  lhs.mat(), Minv, rhs.mat(), MAT_INITIAL_MATRIX, PETSC_DEFAULT, &triple_product_mat));
179 
180  PetscMatrix<Number> triple_product(triple_product_mat, _communicator);
181  if (print)
182  {
183  _console << std::endl << "Printing the '" << inner_matrix_name << "' matrix" << std::endl;
184  triple_product.print();
185  }
186  write_matrix(triple_product.mat(), inner_matrix_name + std::string(".mat"));
187 
188  LibmeshPetscCall(MatDestroy(&triple_product_mat));
189  LibmeshPetscCall(MatDestroy(&I));
190  LibmeshPetscCall(MatDestroy(&M));
191  LibmeshPetscCall(MatDestroy(&Minv));
192  };
193 
194  // Select blocks we care about (coupling between variables)
195  system_size_pressure_mass_matrix.create_submatrix(
196  p_mass_mat, pressure_indices, pressure_indices);
197  system_size_velocity_mass_matrix.create_submatrix(vel_mass_mat, vel_indices, vel_indices);
198  system_matrix->create_submatrix(vel_p_mat, vel_indices, pressure_indices);
199  system_matrix->create_submatrix(p_vel_mat, pressure_indices, vel_indices);
200 
201  compute_triple_product_matrix(
202  vel_p_mat, p_mass_mat, p_vel_mat, outer_matrix_name + "_grad_div");
203  compute_triple_product_matrix(
204  p_vel_mat, vel_mass_mat, vel_p_mat, outer_matrix_name + "_div_grad");
205  };
206 
207  if (has_p)
208  do_vel_p(p_vol_indices, "vel_p");
209  if (has_pbar)
210  do_vel_p(pb_indices, "vel_pb");
211  do_vel_p(p_indices, "vel_all_p");
212 
213  // Print / write velocity block for each augmented Lagrange matrix
214  for (const auto & augmented_lagrange_name : _augmented_lagrange_matrices)
215  {
216  PetscMatrix<Number> jump_mat(_communicator);
217  const auto jump_matrix_tag_id = getMatrixTagID(augmented_lagrange_name);
218  auto & system_size_jump_matrix = nl.getMatrix(jump_matrix_tag_id);
219  system_size_jump_matrix.create_submatrix(jump_mat, vel_indices, vel_indices);
220  if (print)
221  {
222  _console << std::endl
223  << "Printing the jump matrix '" << augmented_lagrange_name << "'" << std::endl;
224  jump_mat.print();
225  }
226  write_matrix(jump_mat.mat(), augmented_lagrange_name + std::string(".mat"));
227  }
228 }
registerMooseObject("NavierStokesTestApp", PrintMatricesNSProblem)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
unsigned int number() const
virtual void onTimestepEnd() override
A problem that solves and prints matrices used when solving the incompressible Navier-Stokes equation...
virtual void onTimestepEnd() override
const Parallel::Communicator & _communicator
void addRequiredParam(const std::string &name, const std::string &doc_string)
static InputParameters validParams()
PrintMatricesNSProblem(const InputParameters &parameters)
const TagName & _pressure_mass_matrix
The tag name of the pressure mass matrix.
bool isParamValid(const std::string &name) const
processor_id_type size() const
const TagName & _velocity_mass_matrix
The tag name of the velocity mass matrix.
T triple_product(const TypeVector< T > &a, const TypeVector< T > &b, const TypeVector< T > &c)
static InputParameters validParams()
const std::vector< TagName > & _augmented_lagrange_matrices
The tag name of the jump matrix.
MeshBase & getMesh()
virtual TagID getMatrixTagID(const TagName &tag_name) const
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
virtual void insert(libMesh::NumericVector< libMesh::Number > &vector)=0
static const std::string pressure
Definition: NS.h:56
IntRange< T > make_range(T beg, T end)
virtual MooseMesh & mesh() override
void mooseError(Args &&... args) const
const ConsoleStream _console