https://mooseframework.inl.gov
Loading...
Searching...
No Matches
LinearFVGradientManager.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
12#include "FEProblemBase.h"
13#include "FVGradientMethod.h"
14#include "MooseApp.h"
15#include "PerfGraphInterface.h"
16#include "PerfGuard.h"
18#include "SystemBase.h"
20#include "MooseError.h"
21#include "ElemInfo.h"
22#include "FaceInfo.h"
23#include "MathFVUtils.h"
24
25#include "libmesh/numeric_vector.h"
26#include "libmesh/system.h"
27
28using namespace libMesh;
29
30namespace
31{
32template <typename DestinationContainer>
33void
34copyGradient(const LinearFVGradientReader::GradientContainer & source,
35 DestinationContainer & destination)
36{
37 mooseAssert(!Threads::in_threads, "Linear FV gradient state copying is not thread-safe.");
38 mooseAssert(source.size() == destination.size(),
39 "Gradient state component counts must match when copying states.");
40
41 for (const auto component : index_range(source))
42 {
43 mooseAssert(source[component], "Source gradient component vector must be initialized.");
44 mooseAssert(destination[component],
45 "Destination gradient component vector must be initialized.");
46 *destination[component] = *source[component];
47 }
48}
49}
50
51const FVGradientMethod &
52LinearFVGradientManager::resolveFVGradientMethod(const GradientMethodName & method_name)
53{
54 auto & fe_problem = _sys.feProblem();
55
56 if (!fe_problem.hasFVGradientMethod(method_name))
57 {
58 if (method_name == "green-gauss")
59 {
60 auto params = fe_problem.getMooseApp().getFactory().getValidParams("FVGreenGaussGradient");
61 fe_problem.addFVGradientMethod("FVGreenGaussGradient", method_name, params);
62 }
63 else if (method_name == "green-gauss-venkatakrishnan")
64 {
65 auto params = fe_problem.getMooseApp().getFactory().getValidParams("FVGreenGaussGradient");
66 params.set<MooseEnum>("limiter") = "venkatakrishnan";
67 fe_problem.addFVGradientMethod("FVGreenGaussGradient", method_name, params);
68 }
69 }
70
71 if (!fe_problem.hasFVGradientMethod(method_name))
72 mooseError("Unable to find FVGradientMethod with name '", method_name, "'");
73
74 return fe_problem.getFVGradientMethod(method_name);
76
78LinearFVGradientManager::registerFVGradient(const unsigned int variable_number,
79 const FVGradientMethod & method,
80 const unsigned int oldest_state)
82 auto * const variable =
83 dynamic_cast<MooseVariableFieldBase *>(_sys.variableWarehouse().getVariable(variable_number));
84 if (!variable)
85 mooseError("Linear FV gradients were requested for variable number ",
86 variable_number,
87 " on system '",
88 _sys.name(),
89 "', but no field variable with that number exists on the system.");
90
91 auto & container = _linear_fv_gradient_container_by_method[&method];
92 container.variable_numbers.insert(variable_number);
93
94 resizeGradientStateStorage(container, oldest_state);
95
96 const auto & current_solution = _sys.system().current_local_solution;
97 if (current_solution && current_solution->initialized())
98 {
99 if (container.current_values.empty())
100 initializeContainer(container.current_values);
101 if (container.next_values.empty())
102 initializeContainer(container.next_values);
103 setCurrentGradientState(container);
104 }
105
106 return LinearFVGradientReader(_sys, container.state_values, method, variable_number);
107}
108
109void
111{
113 return;
114
115 auto * const perf_graph_interface = dynamic_cast<PerfGraphInterface *>(&_sys);
116 mooseAssert(perf_graph_interface,
117 "LinearFVGradientManager requires its owning system to implement "
118 "PerfGraphInterface.");
119 const auto perf_id = perf_graph_interface->registerTimedSection("LinearVariableFV_Gradients", 3);
120 mooseAssert(!Threads::in_threads, "PerfGraph timing cannot be used within threaded sections");
121 PerfGuard time_guard(perf_graph_interface->perfGraph(), perf_id);
122
123 // Keep current values unchanged until every replacement has been computed so boundary
124 // conditions consistently use gradients from the previous update.
125 // BCs may use cell gradients to compute the boundary face value, which is itself used to
126 // compute cell gradients
127 for (auto & method_container_pair : _linear_fv_gradient_container_by_method)
128 computeLinearFVGradientContainer(*method_container_pair.first);
129
130 for (auto & method_container_pair : _linear_fv_gradient_container_by_method)
131 finalizeLinearFVGradientContainer(method_container_pair.second);
132}
133
134void
136{
137 if (&reader.system() != &_sys)
138 mooseError("Requested update for a linear FV gradient field from a different system than '",
139 _sys.name(),
140 "'.");
141
142 const auto method_container_pair = _linear_fv_gradient_container_by_method.find(&reader.method());
143 if (method_container_pair != _linear_fv_gradient_container_by_method.end())
144 {
145 auto * const perf_graph_interface = dynamic_cast<PerfGraphInterface *>(&_sys);
146 mooseAssert(perf_graph_interface,
147 "LinearFVGradientManager requires its owning system to implement "
148 "PerfGraphInterface.");
149 const auto perf_id =
150 perf_graph_interface->registerTimedSection("LinearVariableFV_Gradients", 3);
151 mooseAssert(!Threads::in_threads, "PerfGraph timing cannot be used within threaded sections");
152 PerfGuard time_guard(perf_graph_interface->perfGraph(), perf_id);
153
154 auto & container = computeLinearFVGradientContainer(reader.method());
156 return;
157 }
158
159 mooseError("Requested update for an unregistered linear FV gradient field on system '",
160 _sys.name(),
161 "'.");
162}
163
164bool
169
170void
172{
173 container.clear();
174 const auto & current_solution = _sys.system().current_local_solution;
175 mooseAssert(current_solution && current_solution->initialized(),
176 "Current solution must exist before building FV gradient storage.");
177 container.resize(_sys.mesh().dimension());
178 for (auto & component : container)
179 component = current_solution->zero_clone();
180}
181
182void
184 const unsigned int oldest_state)
185{
186 const auto required_states = static_cast<std::size_t>(oldest_state) + 1;
187 const auto old_size = container.state_values.size();
188 if (required_states > old_size && _sys.solutionStatesInitialized() && oldest_state > 0)
189 mooseError("Linear FV gradient state ",
190 oldest_state,
191 " was requested on system '",
192 _sys.name(),
193 "' after solution states were initialized. Old gradient states must be requested "
194 "during setup.");
195
196 if (required_states > old_size)
197 container.state_values.resize(required_states);
198}
199
200void
202{
203 for (auto & [method, container] : _linear_fv_gradient_container_by_method)
204 for (const auto state : make_range(std::size_t(1), container.state_values.size()))
205 if (container.state_values[state].empty())
206 {
207 GradientContainer state_values(_sys.mesh().dimension());
208 for (const auto component : index_range(state_values))
209 state_values[component] = &_sys.addVector(
210 gradientStateVectorName(*method, state, component), true, libMesh::GHOSTED);
211 container.state_values[state] = std::move(state_values);
212 }
213}
214
215void
217{
218 mooseAssert(!container.state_values.empty(),
219 "Gradient state storage must contain a current state.");
220 auto & current_view = container.state_values[0];
221 current_view.clear();
222 current_view.reserve(container.current_values.size());
223 for (auto & component : container.current_values)
224 current_view.push_back(component.get());
225}
226
227std::string
229 const unsigned int state,
230 const unsigned int component)
231{
232 return "linear_fv_gradient_" + method.name() + "_state_" + std::to_string(state) + "_component_" +
233 std::to_string(component);
234}
235
236void
238 LinearFVGradientContainer & container)
239{
240 if (container.has_checked_restart_history)
241 return;
242
243 container.has_checked_restart_history = true;
244 if (container.state_values.size() <= 1)
245 return;
246
247 const auto & app = _sys.feProblem().getMooseApp();
248 if (!app.isRestarting() && !app.isRecovering())
249 return;
250
251 const auto & restartable_equation_systems = _sys.feProblem().getRestartableEquationSystems();
252 for (const auto state : make_range(std::size_t(1), container.state_values.size()))
253 for (const auto component : index_range(container.state_values[state]))
254 {
255 const auto vector_name = gradientStateVectorName(method, state, component);
256 for (const auto variable_number : container.variable_numbers)
257 {
258 const auto & variable = _sys.getVariable(0, variable_number);
259 if (!restartable_equation_systems.isVariableRestored(
260 _sys.name(), vector_name, variable.name()))
261 mooseError("Linear FV gradient state ",
262 state,
263 " for variable '",
264 variable.name(),
265 "' using gradient method '",
266 method.name(),
267 "' was requested on system '",
268 _sys.name(),
269 "', but vector '",
270 vector_name,
271 "' was not available in the restart data.");
272 }
273 }
274
275 container.has_initialized_history = true;
276}
277
280{
281 // Gradient requests can be registered before the current solution vector exists, so the current
282 // and replacement fields cannot always be created when the request is recorded. These fields
283 // must be zero clones of the solution vector to inherit its finalized layout and parallel type.
284 // Requests can also arrive after the normal initialization phase. Initializing immediately
285 // before computation handles both cases, while the empty checks make repeated calls harmless.
287
288 auto & container = libmesh_map_find(_linear_fv_gradient_container_by_method, &method);
289
290 mooseAssert(!container.state_values.empty(),
291 "Gradient state storage must contain a current state.");
292 mooseAssert(!container.state_values[0].empty(),
293 "Gradient storage must be initialized before gradient computation.");
294 mooseAssert(!container.next_values.empty(),
295 "Replacement gradient storage must be initialized before gradient computation.");
296 mooseAssert(container.next_values.size() == container.current_values.size(),
297 "Next and current gradient containers must have the same size.");
298
299 method.computeGradient(_sys, container.next_values, container.variable_numbers);
300
301 return container;
302}
303
304void
306{
307 mooseAssert(!container.state_values.empty(),
308 "Gradient state storage must contain a current state.");
309 mooseAssert(container.next_values.size() == container.current_values.size(),
310 "Next and current gradient containers must have the same size.");
311 container.current_values.swap(container.next_values);
312 setCurrentGradientState(container);
313
314 if (!container.has_initialized_history)
315 {
316 for (const auto state : make_range(std::size_t(1), container.state_values.size()))
317 copyGradient(container.state_values[0], container.state_values[state]);
318 container.has_initialized_history = true;
319 }
320
321 container.has_computed_gradient = true;
322}
323
324void
326{
327 for (auto & [method, container] : _linear_fv_gradient_container_by_method)
328 {
329 if (container.current_values.empty())
330 initializeContainer(container.current_values);
331 if (container.next_values.empty())
332 initializeContainer(container.next_values);
333 setCurrentGradientState(container);
334 checkRestartedGradientHistory(*method, container);
335 }
336}
337
338void
340{
341 for (auto & method_container_pair : _linear_fv_gradient_container_by_method)
342 {
343 method_container_pair.second.current_values.clear();
344 method_container_pair.second.next_values.clear();
345 method_container_pair.second.has_computed_gradient = false;
346 }
347
349}
350
351void
353{
354 for (auto & [method, container] : _linear_fv_gradient_container_by_method)
355 if (container.state_values.size() > 1 && !container.has_computed_gradient)
357
358 for (auto & [_, container] : _linear_fv_gradient_container_by_method)
359 if (container.state_values.size() > 1 && !container.has_computed_gradient)
361}
362
363void
365 const Moose::SolutionIterationType iteration_type, const bool skip_current_to_old)
366{
367 mooseAssert(iteration_type != Moose::SolutionIterationType::Nonlinear,
368 "Linear FV gradient storage does not support nonlinear iteration states.");
369 if (iteration_type != Moose::SolutionIterationType::Time)
370 return;
371
372 mooseAssert(!Threads::in_threads, "Linear FV gradient state copying is not thread-safe.");
374
375 for (auto & [_, container] : _linear_fv_gradient_container_by_method)
376 {
377 const auto number_of_states = container.state_values.size();
378 if (number_of_states <= 1)
379 continue;
380
381 mooseAssert(container.has_computed_gradient,
382 "Current gradient state must be initialized before advancing time states.");
383 // Mirror solution-state advancement: some restore workflows preserve state 1 by skipping the
384 // current-to-old copy while still shifting every deeper state.
385 const std::size_t stop = skip_current_to_old ? 1 : 0;
386 for (std::size_t state = number_of_states - 1; state > stop; --state)
387 copyGradient(container.state_values[state - 1], container.state_values[state]);
388 }
389}
390
391void
393{
394 mooseAssert(!Threads::in_threads, "Linear FV gradient state copying is not thread-safe.");
395 for (auto & [_, container] : _linear_fv_gradient_container_by_method)
396 {
397 if (container.state_values.size() <= 1)
398 continue;
399
400 mooseAssert(container.has_computed_gradient,
401 "Current gradient state must be initialized before restoration.");
402 copyGradient(container.state_values[1], container.state_values[0]);
403 copyGradient(container.state_values[0], container.next_values);
404 }
405}
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
const RestartableEquationSystems & getRestartableEquationSystems() const
Get the RestartableEquationSystems object.
Base class for linear finite-volume cell-gradient methods.
void computeGradient(SystemBase &system, GradientContainer &gradient, const std::unordered_set< unsigned int > &variable_numbers) const
Compute the final gradient values for the requested variables.
void resizeGradientStateStorage(LinearFVGradientContainer &container, unsigned int oldest_state)
Ensure that a method container stores every requested time state.
void setCurrentGradientState(LinearFVGradientContainer &container) const
Set solution state zero to the current gradient.
LinearFVGradientContainer & computeLinearFVGradientContainer(const FVGradientMethod &method)
Compute replacement field values for a registered gradient method.
LinearFVGradientReader::GradientContainer GradientContainer
Non-owning view with one vector per spatial component of a cell-centered gradient field.
void initializeContainer(OwnedGradientContainer &container) const
Allocate one zeroed vector per spatial component for gradient storage.
SystemBase & _sys
Reference to the system object.
void finalizeLinearFVGradientContainer(LinearFVGradientContainer &container)
Replace the current gradient storage with the freshly computed new gradients.
std::unordered_map< const FVGradientMethod *, LinearFVGradientContainer > _linear_fv_gradient_container_by_method
Gradient containers keyed by the method object that produces them.
void updateFVGradient(const LinearFVGradientReader &reader)
Update a registered gradient reader explicitly.
void computeGradients()
Compute and finalize all registered linear FV gradient fields.
static std::string gradientStateVectorName(const FVGradientMethod &method, unsigned int state, unsigned int component)
Return the stable system-vector name for one old gradient component.
void rebuildLinearFVGradientStorage()
Rebuild cached gradient values and reusable scratch storage after mesh/DOF changes.
void copyPreviousGradientStates(Moose::SolutionIterationType iteration_type, bool skip_current_to_old)
Copy published gradient values into requested older states.
void initializeGradientStatesForTimeAdvance()
Compute and publish uninitialized gradients before their first time-state advancement.
const FVGradientMethod & resolveFVGradientMethod(const GradientMethodName &method_name)
Resolve a named gradient method, constructing a built-in method when needed.
LinearFVGradientReader registerFVGradient(unsigned int variable_number, const FVGradientMethod &method, unsigned int oldest_state=0)
Register a variable for gradient values produced by a method object.
void checkRestartedGradientHistory(const FVGradientMethod &method, LinearFVGradientContainer &container)
Validate and mark gradient history loaded during restart or recovery.
std::vector< std::unique_ptr< libMesh::NumericVector< libMesh::Number > > > OwnedGradientContainer
Owned vectors used for the current gradient and its replacement.
bool hasLinearFVGradients() const
Whether any linear finite-volume gradient fields have been registered to this object.
void restoreGradientStates()
Restore current gradients from state one after a failed timestep.
void initializeLinearFVGradientHistoryStorage()
Register named system vectors for requested historical gradient states.
void initializeLinearFVGradientStorage()
Initialize private current and replacement gradient storage.
Read-only view of one variable's cell-centered linear finite-volume gradient values.
const FVGradientMethod & method() const
Method object that produces the stored values.
const SystemBase & system() const
System whose DOF map indexes the stored values.
std::vector< libMesh::NumericVector< libMesh::Number > * > GradientContainer
One vector per spatial component of the cell-centered gradient.
Factory & getFactory()
Retrieve a writable reference to the Factory associated with this App.
Definition MooseApp.h:407
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
MooseApp & getMooseApp() const
Get the MooseApp this class is associated with.
Definition MooseBase.h:87
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
virtual unsigned int dimension() const
Returns MeshBase::mesh_dimension(), (not MeshBase::spatial_dimension()!) of the underlying libMesh me...
Definition MooseMesh.C:2994
This class provides an interface for common operations on field variables of both FE and FV types wit...
Interface for objects interacting with the PerfGraph.
Scope guard for starting and stopping timing for a node.
Definition PerfGuard.h:26
MooseVariableFieldBase & getVariable(THREAD_ID tid, const std::string &var_name) const
Gets a reference to a variable of with specified name.
Definition SystemBase.C:89
bool solutionStatesInitialized() const
Whether or not the solution states have been initialized via initSolutionState()
Definition SystemBase.h:931
FEProblemBase & feProblem()
Definition SystemBase.h:104
virtual const std::string & name() const
const VariableWarehouse & variableWarehouse(THREAD_ID tid=0) const
Definition SystemBase.h:784
MooseMesh & mesh()
Definition SystemBase.h:100
NumericVector< Number > & addVector(const std::string &vector_name, const bool project, const libMesh::ParallelType type)
Adds a solution length vector to the system.
Definition SystemBase.C:605
virtual libMesh::System & system()=0
Get the reference to the libMesh system.
MooseVariableBase * getVariable(const std::string &var_name) const
Get a variable from the warehouse.
std::unique_ptr< NumericVector< Number > > current_local_solution
SolutionIterationType
Definition MooseTypes.h:270
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
auto index_range(const T &sizable)
IntRange< T > make_range(T beg, T end)
Gradient values for all variables using the same gradient method.
bool has_computed_gradient
Whether the current gradient has received a computed value.
bool has_initialized_history
Whether the old gradient states contain valid values.
OwnedGradientContainer current_values
Owned current gradient values.
GradientStateContainer state_values
Published gradient values indexed by solution time state.
bool has_checked_restart_history
Whether restart data has been checked for this gradient method.
std::unordered_set< unsigned int > variable_numbers
Variable numbers whose gradients are stored in the gradient containers.
OwnedGradientContainer next_values
Replacement gradient values computed before publication.