https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
11#include "SystemBase.h"
12#include "libmesh/petsc_vector.h"
13#include "libmesh/petsc_solver_exception.h"
14
15registerMooseObject("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
67void
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)
81void
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
95Real
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
106void
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}
registerMooseObject("ExternalPetscSolverApp", ExternalPETScProblem)
PETSC_EXTERN PetscErrorCode externalPETScDiffusionFDMSolve(TS, Vec, Vec, PetscReal, PetscReal, PetscBool *)
PETSC_EXTERN PetscErrorCode FormInitialSolution(TS, Vec, void *)
const ConsoleStream _console
This is an interface to call a pure PETSc solver.
const VariableName & _sync_to_var_name
The name of the variable to transfer to.
virtual void externalSolve() override
PetscBool _petsc_converged
If PETSc solver converged.
Vec & _petsc_sol
PETSc solver solution.
virtual Real computeResidualL2Norm() override
ExternalPETScProblem(const InputParameters &params)
virtual void advanceState() override
Vec & _petsc_sol_old
Solution at the previous time step.
Vec & _petsc_udot
Udot (u_n-u_{n-1})/dt.
static InputParameters validParams()
virtual void syncSolutions(Direction) override
This is a demo used to demonstrate how to couple an external app through the MOOSE wrapper APP.
static InputParameters validParams()
virtual Real & dt() const
virtual void advanceState()
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 MooseMesh & mesh() override
virtual Real & time() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
void mooseError(Args &&... args) const
MeshBase & getMesh()
const Parallel::Communicator & comm() const