Loading [MathJax]/extensions/tex2jax.js
https://mooseframework.inl.gov
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
ExternalPETScProblem.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 "ExternalPETScProblem.h"
11 #include "SystemBase.h"
12 #include "libmesh/petsc_vector.h"
13 #include "libmesh/petsc_solver_exception.h"
14 
15 registerMooseObject("ExternalPetscSolverApp", ExternalPETScProblem);
16 
19 {
21  params.addRequiredParam<VariableName>("sync_variable",
22  "The variable PETSc external solution will be synced to");
23  return params;
24 }
25 
27  : ExternalProblem(params),
28  _sync_to_var_name(getParam<VariableName>("sync_variable")),
29  // Require ExternalPetscSolverApp
30  _external_petsc_app(static_cast<ExternalPetscSolverApp &>(_app)),
31  _ts(_external_petsc_app.getPetscTS()),
32  // RestartableData is required for recovering when PETSc solver runs as a master app
33  _petsc_sol(declareRestartableData<Vec>("petsc_sol")),
34  _petsc_sol_old(declareRestartableData<Vec>("petsc_sol_old")),
35  _petsc_udot(declareRestartableData<Vec>("petsc_udot"))
36 {
37  DM da;
38  LibmeshPetscCall(TSGetDM(_ts, &da));
39  // Create a global solution vector
40  LibmeshPetscCall(DMCreateGlobalVector(da, &_petsc_sol));
41  // This is required because libMesh incorrectly treats the PETSc parallel vector as a ghost vector
42  // We should be able to remove this line of code once libMesh is updated
43  LibmeshPetscCall(VecMPISetGhost(_petsc_sol, 0, nullptr));
44  // The solution at the previous time step
45  LibmeshPetscCall(VecDuplicate(_petsc_sol, &_petsc_sol_old));
46  // Udot
47  LibmeshPetscCall(VecDuplicate(_petsc_sol, &_petsc_udot));
48  // RHS
49  LibmeshPetscCall(VecDuplicate(_petsc_sol, &_petsc_rhs));
50  // Form an initial condition
51  LibmeshPetscCall(FormInitialSolution(_ts, _petsc_sol, NULL));
52  LibmeshPetscCall(VecCopy(_petsc_sol, _petsc_sol_old));
53  LibmeshPetscCall(VecSet(_petsc_udot, 0));
54 }
55 
57 {
58  // Destroy all handles of external Petsc solver
59  auto ierr = VecDestroy(&_petsc_sol);
60  ierr = VecDestroy(&_petsc_sol_old);
61  ierr = VecDestroy(&_petsc_udot);
62  ierr = VecDestroy(&_petsc_rhs);
63  // Don't throw during destruction, just abort
64  CHKERRABORT(this->comm().get(), ierr);
65 }
66 
67 void
69 {
70  _console << "PETSc External Solve!" << std::endl;
71  // "_petsc_sol_old" is the solution of the current time step, and "_petsc_sol" will be updated
72  // to store the solution of the next time step after this call.
73  // This call advances a time step so that there is an opportunity to
74  // exchange information with MOOSE simulations.
75  LibmeshPetscCall(externalPETScDiffusionFDMSolve(
77 }
78 
79 // This function is called when MOOSE time stepper actually moves to the next time step
80 // "PostTimeStep" may not be called for certain cases (e.g., auto_advance=false)
81 void
83 {
85  // Compute udot using a backward Euler method
86  // If the external code uses a different method,
87  // udot should be retrieved from the external solver
88  LibmeshPetscCall(VecCopy(_petsc_sol, _petsc_udot));
89  LibmeshPetscCall(VecAXPY(_petsc_udot, -1., _petsc_sol_old));
90  LibmeshPetscCall(VecScale(_petsc_udot, 1. / dt()));
91  // Save current solution because we are moving to the next time step
92  LibmeshPetscCall(VecCopy(_petsc_sol, _petsc_sol_old));
93 }
94 
95 Real
97 {
98  LibmeshPetscCall(
99  TSComputeIFunction(_ts, time(), _petsc_sol, _petsc_udot, _petsc_rhs, PETSC_FALSE));
100  PetscReal norm;
101  LibmeshPetscCall(VecNorm(_petsc_rhs, NORM_2, &norm));
102 
103  return norm;
104 }
105 
106 void
108 {
109  if (direction == Direction::FROM_EXTERNAL_APP)
110  {
111  _console << "syncSolutions from external petsc App" << std::endl;
112  DM da;
113  // xs: start grid point in x direction on local
114  // ys: start grid point in y direciton on local
115  // xm: number of grid points in x direciton on local
116  // ym: number of grid points in y direction on local
117  // Mx: number of grid points in x direction on all processors
118  PetscInt i, j, xs, ys, xm, ym, Mx;
119  PetscScalar ** _petsc_sol_array;
120  LibmeshPetscCall(TSGetDM(_ts, &da));
121  LibmeshPetscCall(DMDAGetInfo(da,
122  PETSC_IGNORE,
123  &Mx,
124  PETSC_IGNORE,
125  PETSC_IGNORE,
126  PETSC_IGNORE,
127  PETSC_IGNORE,
128  PETSC_IGNORE,
129  PETSC_IGNORE,
130  PETSC_IGNORE,
131  PETSC_IGNORE,
132  PETSC_IGNORE,
133  PETSC_IGNORE,
134  PETSC_IGNORE));
135  LibmeshPetscCall(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL));
136  LibmeshPetscCall(DMDAVecGetArray(da, _petsc_sol, &_petsc_sol_array));
137 
138  // Take the solution from PETSc, and sync it to one MOOSE variable
139  // We currently support one variable only but it is straightforward
140  // to have multiple moose variables
141  MeshBase & to_mesh = mesh().getMesh();
142  auto & sync_to_var = getVariable(
143  0, _sync_to_var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_STANDARD);
144 
145  for (j = ys; j < ys + ym; j++)
146  for (i = xs; i < xs + xm; i++)
147  {
148  Node * to_node = to_mesh.node_ptr(i + j * Mx);
149  // For the current example, we need to update only one variable.
150  // This line of code is used to make sure users won't make a mistake in the demo input file.
151  // If multiple variables need to be transfered for some use cases, users should
152  // loop over variables and copy necessary data.
153  if (to_node->n_comp(sync_to_var.sys().number(), sync_to_var.number()) > 1)
154  mooseError("Does not support multiple components");
155 
156  dof_id_type dof = to_node->dof_number(sync_to_var.sys().number(), sync_to_var.number(), 0);
157  // Copy the solution to the right location
158  sync_to_var.sys().solution().set(dof, _petsc_sol_array[j][i]);
159  }
160 
161  sync_to_var.sys().solution().close();
162 
163  LibmeshPetscCall(DMDAVecRestoreArray(da, _petsc_sol, &_petsc_sol_array));
164 
165  // Make the solution and the current local solution consistent
166  sync_to_var.sys().update();
167  }
168  else if (direction == Direction::TO_EXTERNAL_APP)
169  {
170  _console << "syncSolutions to external petsc App " << std::endl;
171  // We could the similar thing to sync the solution back to PETSc.
172  }
173 }
virtual Real & time() const
This is an interface to call a pure PETSc solver.
Vec & _petsc_udot
Udot (u_n-u_{n-1})/dt.
static InputParameters validParams()
const Parallel::Communicator & comm() const
virtual void syncSolutions(Direction) override
Vec & _petsc_sol
PETSc solver solution.
This is a demo used to demonstrate how to couple an external app through the MOOSE wrapper APP...
virtual Real computeResidualL2Norm() override
virtual void externalSolve() override
PETSC_EXTERN PetscErrorCode externalPETScDiffusionFDMSolve(TS, Vec, Vec, PetscReal, PetscReal, PetscBool *)
void addRequiredParam(const std::string &name, const std::string &doc_string)
virtual const MooseVariableFieldBase & getVariable(const THREAD_ID tid, const std::string &var_name, Moose::VarKindType expected_var_type=Moose::VarKindType::VAR_ANY, Moose::VarFieldType expected_var_field_type=Moose::VarFieldType::VAR_FIELD_ANY) const override
virtual void advanceState()
TS & _ts
PETSc solver.
Vec _petsc_rhs
RHS vector.
MeshBase & getMesh()
Vec & _petsc_sol_old
Solution at the previous time step.
auto norm(const T &a) -> decltype(std::abs(a))
registerMooseObject("ExternalPetscSolverApp", ExternalPETScProblem)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void advanceState() override
PetscBool _petsc_converged
If PETSc solver converged.
virtual MooseMesh & mesh() override
void mooseError(Args &&... args) const
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
const ConsoleStream _console
virtual Real & dt() const
PETSC_EXTERN PetscErrorCode FormInitialSolution(TS, Vec, void *)
const VariableName & _sync_to_var_name
The name of the variable to transfer to.
ExternalPETScProblem(const InputParameters &params)
uint8_t dof_id_type
static InputParameters validParams()