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
28#include <algorithm>
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 mooseAssert(
47 source[component]->size() == destination[component]->size() &&
48 source[component]->local_size() == destination[component]->local_size() &&
49 source[component]->first_local_index() == destination[component]->first_local_index() &&
50 source[component]->last_local_index() == destination[component]->last_local_index(),
51 "Source and destination gradient component vectors must have matching parallel "
52 "layouts.");
53 *destination[component] = *source[component];
54 }
55}
56}
57
58const FVGradientMethod &
59LinearFVGradientManager::resolveFVGradientMethod(const GradientMethodName & method_name)
60{
61 auto & fe_problem = _sys.feProblem();
62
63 if (!fe_problem.hasFVGradientMethod(method_name))
64 {
65 if (method_name == "green-gauss")
66 {
67 auto params = fe_problem.getMooseApp().getFactory().getValidParams("FVGreenGaussGradient");
68 fe_problem.addFVGradientMethod("FVGreenGaussGradient", method_name, params);
69 }
70 else if (method_name == "green-gauss-venkatakrishnan")
71 {
72 auto params = fe_problem.getMooseApp().getFactory().getValidParams("FVGreenGaussGradient");
73 params.set<MooseEnum>("limiter") = "venkatakrishnan";
74 fe_problem.addFVGradientMethod("FVGreenGaussGradient", method_name, params);
75 }
76 }
77
78 if (!fe_problem.hasFVGradientMethod(method_name))
79 mooseError("Unable to find FVGradientMethod with name '", method_name, "'");
80
81 return fe_problem.getFVGradientMethod(method_name);
82}
83
85LinearFVGradientManager::registerFVGradient(const unsigned int variable_number,
86 const FVGradientMethod & method,
87 const unsigned int oldest_state)
88{
89 auto * const variable =
90 dynamic_cast<MooseVariableFieldBase *>(_sys.variableWarehouse().getVariable(variable_number));
91 if (!variable)
92 mooseError("Linear FV gradients were requested for variable number ",
93 variable_number,
94 " on system '",
95 _sys.name(),
96 "', but no field variable with that number exists on the system.");
97
98 auto [method_container, inserted] = _linear_fv_gradient_container_by_method.try_emplace(&method);
99 if (inserted)
100 _linear_fv_gradient_methods.push_back(&method);
101 auto & container = method_container->second;
102 container.variable_numbers.insert(variable_number);
103
104 resizeGradientStateStorage(container, oldest_state);
105
106 const auto & current_solution = _sys.system().current_local_solution;
107 if (current_solution && current_solution->initialized())
108 {
109 if (container.current_values.empty())
110 initializeContainer(container.current_values);
111 if (container.next_values.empty())
112 initializeContainer(container.next_values);
113 setCurrentGradientState(container);
114 }
115
116 return LinearFVGradientReader(_sys, container.state_values, method, variable_number);
117}
118
119void
124
125void
127{
128 if (&excluded_reader.system() != &_sys)
129 mooseError("Cannot exclude a linear FV gradient field from a different system than '",
130 _sys.name(),
131 "'.");
132
133 auto gradient_methods = _linear_fv_gradient_methods;
134 gradient_methods.erase(
135 std::remove(gradient_methods.begin(), gradient_methods.end(), &excluded_reader.method()),
136 gradient_methods.end());
137 computeGradientsForMethods(gradient_methods);
138}
139
140void
142 const std::vector<const FVGradientMethod *> & gradient_methods)
143{
144 if (gradient_methods.empty() || !_sys.solutionStatesInitialized())
145 return;
146
147 auto * const perf_graph_interface = dynamic_cast<PerfGraphInterface *>(&_sys);
148 mooseAssert(perf_graph_interface,
149 "LinearFVGradientManager requires its owning system to implement "
150 "PerfGraphInterface.");
151 const auto perf_id = perf_graph_interface->registerTimedSection("LinearVariableFV_Gradients", 3);
152 mooseAssert(!Threads::in_threads, "PerfGraph timing cannot be used within threaded sections");
153 PerfGuard time_guard(perf_graph_interface->perfGraph(), perf_id);
154
155 // Keep current values unchanged until every replacement has been computed so boundary
156 // conditions consistently use gradients from the previous update.
157 // BCs may use cell gradients to compute the boundary face value, which is itself used to
158 // compute cell gradients
159 for (const auto * const method : gradient_methods)
161
162 for (const auto * const method : gradient_methods)
164 libmesh_map_find(_linear_fv_gradient_container_by_method, method));
165}
166
167void
169{
170 if (&reader.system() != &_sys)
171 mooseError("Requested update for a linear FV gradient field from a different system than '",
172 _sys.name(),
173 "'.");
174
175 const auto method_container_pair = _linear_fv_gradient_container_by_method.find(&reader.method());
176 if (method_container_pair != _linear_fv_gradient_container_by_method.end())
177 {
178 auto * const perf_graph_interface = dynamic_cast<PerfGraphInterface *>(&_sys);
179 mooseAssert(perf_graph_interface,
180 "LinearFVGradientManager requires its owning system to implement "
181 "PerfGraphInterface.");
182 const auto perf_id =
183 perf_graph_interface->registerTimedSection("LinearVariableFV_Gradients", 3);
184 mooseAssert(!Threads::in_threads, "PerfGraph timing cannot be used within threaded sections");
185 PerfGuard time_guard(perf_graph_interface->perfGraph(), perf_id);
186
187 auto & container = computeLinearFVGradientContainer(reader.method());
189 return;
190 }
191
192 mooseError("Requested update for an unregistered linear FV gradient field on system '",
193 _sys.name(),
194 "'.");
195}
196
197bool
202
203void
205{
206 container.clear();
207 const auto & current_solution = _sys.system().current_local_solution;
208 mooseAssert(current_solution && current_solution->initialized(),
209 "Current solution must exist before building FV gradient storage.");
210 container.resize(_sys.mesh().dimension());
211 for (auto & component : container)
212 component = current_solution->zero_clone();
213}
214
215void
217 const unsigned int oldest_state)
218{
219 const auto required_states = static_cast<std::size_t>(oldest_state) + 1;
220 const auto old_size = container.state_values.size();
221 if (required_states > old_size && _sys.solutionStatesInitialized() && oldest_state > 0)
222 mooseError("Linear FV gradient state ",
223 oldest_state,
224 " was requested on system '",
225 _sys.name(),
226 "' after solution states were initialized. Old gradient states must be requested "
227 "during setup.");
228
229 if (required_states > old_size)
230 container.state_values.resize(required_states);
231}
232
233void
235{
236 for (auto & [method, container] : _linear_fv_gradient_container_by_method)
237 for (const auto state : make_range(std::size_t(1), container.state_values.size()))
238 if (container.state_values[state].empty())
239 {
240 GradientContainer state_values(_sys.mesh().dimension());
241 for (const auto component : index_range(state_values))
242 state_values[component] = &_sys.addVector(
243 gradientStateVectorName(*method, state, component), true, libMesh::GHOSTED);
244 container.state_values[state] = std::move(state_values);
245 }
246}
247
248void
250{
251 mooseAssert(!container.state_values.empty(),
252 "Gradient state storage must contain a current state.");
253 auto & current_view = container.state_values[0];
254 current_view.clear();
255 current_view.reserve(container.current_values.size());
256 for (auto & component : container.current_values)
257 current_view.push_back(component.get());
258}
259
260std::string
262 const unsigned int state,
263 const unsigned int component)
264{
265 return "linear_fv_gradient_" + method.name() + "_state_" + std::to_string(state) + "_component_" +
266 std::to_string(component);
267}
268
269void
271 LinearFVGradientContainer & container)
272{
273 if (container.has_checked_restart_history)
274 return;
275
276 container.has_checked_restart_history = true;
277 if (container.state_values.size() <= 1)
278 return;
279
280 const auto & app = _sys.feProblem().getMooseApp();
281 if (!app.isRestarting() && !app.isRecovering())
282 return;
283
284 const auto & restartable_equation_systems = _sys.feProblem().getRestartableEquationSystems();
285 for (const auto state : make_range(std::size_t(1), container.state_values.size()))
286 for (const auto component : index_range(container.state_values[state]))
287 {
288 const auto vector_name = gradientStateVectorName(method, state, component);
289 for (const auto variable_number : container.variable_numbers)
290 {
291 const auto & variable = _sys.getVariable(0, variable_number);
292 if (!restartable_equation_systems.isVariableRestored(
293 _sys.name(), vector_name, variable.name()))
294 mooseError("Linear FV gradient state ",
295 state,
296 " for variable '",
297 variable.name(),
298 "' using gradient method '",
299 method.name(),
300 "' was requested on system '",
301 _sys.name(),
302 "', but vector '",
303 vector_name,
304 "' was not available in the restart data.");
305 }
306 }
307
308 container.has_initialized_history = true;
309}
310
313{
314 // Gradient requests can be registered before the current solution vector exists, so the current
315 // and replacement fields cannot always be created when the request is recorded. These fields
316 // must be zero clones of the solution vector to inherit its finalized layout and parallel type.
317 // Requests can also arrive after the normal initialization phase. Initializing immediately
318 // before computation handles both cases, while the empty checks make repeated calls harmless.
320
321 auto & container = libmesh_map_find(_linear_fv_gradient_container_by_method, &method);
322
323 mooseAssert(!container.state_values.empty(),
324 "Gradient state storage must contain a current state.");
325 mooseAssert(!container.state_values[0].empty(),
326 "Gradient storage must be initialized before gradient computation.");
327 mooseAssert(!container.next_values.empty(),
328 "Replacement gradient storage must be initialized before gradient computation.");
329 mooseAssert(container.next_values.size() == container.current_values.size(),
330 "Next and current gradient containers must have the same size.");
331
332 method.computeGradient(_sys, container.next_values, container.variable_numbers);
333
334 return container;
335}
336
337void
339{
340 mooseAssert(!container.state_values.empty(),
341 "Gradient state storage must contain a current state.");
342 mooseAssert(container.next_values.size() == container.current_values.size(),
343 "Next and current gradient containers must have the same size.");
344 container.current_values.swap(container.next_values);
345 setCurrentGradientState(container);
346
347 if (!container.has_initialized_history)
348 {
349 for (const auto state : make_range(std::size_t(1), container.state_values.size()))
350 copyGradient(container.state_values[0], container.state_values[state]);
351 container.has_initialized_history = true;
352 }
353
354 container.has_computed_gradient = true;
355}
356
357void
359{
360 for (auto & [method, container] : _linear_fv_gradient_container_by_method)
361 {
362 if (container.current_values.empty())
363 initializeContainer(container.current_values);
364 if (container.next_values.empty())
365 initializeContainer(container.next_values);
366 setCurrentGradientState(container);
367 checkRestartedGradientHistory(*method, container);
368 }
369}
370
371void
373{
374 for (auto & method_container_pair : _linear_fv_gradient_container_by_method)
375 {
376 method_container_pair.second.current_values.clear();
377 method_container_pair.second.next_values.clear();
378 method_container_pair.second.has_computed_gradient = false;
379 }
380
382}
383
384void
386{
387 for (auto & [method, container] : _linear_fv_gradient_container_by_method)
388 if (container.state_values.size() > 1 && !container.has_computed_gradient)
390
391 for (auto & [_, container] : _linear_fv_gradient_container_by_method)
392 if (container.state_values.size() > 1 && !container.has_computed_gradient)
394}
395
396void
398 const Moose::SolutionIterationType iteration_type, const bool skip_current_to_old)
399{
400 mooseAssert(iteration_type != Moose::SolutionIterationType::Nonlinear,
401 "Linear FV gradient storage does not support nonlinear iteration states.");
402 if (iteration_type != Moose::SolutionIterationType::Time)
403 return;
404
405 mooseAssert(!Threads::in_threads, "Linear FV gradient state copying is not thread-safe.");
407
408 for (auto & [_, container] : _linear_fv_gradient_container_by_method)
409 {
410 const auto number_of_states = container.state_values.size();
411 if (number_of_states <= 1)
412 continue;
413
414 mooseAssert(container.has_computed_gradient,
415 "Current gradient state must be initialized before advancing time states.");
416 // Mirror solution-state advancement: some restore workflows preserve state 1 by skipping the
417 // current-to-old copy while still shifting every deeper state.
418 const std::size_t stop = skip_current_to_old ? 1 : 0;
419 for (std::size_t state = number_of_states - 1; state > stop; --state)
420 copyGradient(container.state_values[state - 1], container.state_values[state]);
421 }
422}
423
424void
426{
427 mooseAssert(!Threads::in_threads, "Linear FV gradient state copying is not thread-safe.");
428 for (auto & [_, container] : _linear_fv_gradient_container_by_method)
429 {
430 if (container.state_values.size() <= 1)
431 continue;
432
433 mooseAssert(container.has_computed_gradient,
434 "Current gradient state must be initialized before restoration.");
435 copyGradient(container.state_values[1], container.state_values[0]);
436 copyGradient(container.state_values[0], container.next_values);
437 }
438}
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.
InputParameters getValidParams(const std::string &name) const
Get valid parameters for the object.
Definition Factory.C:68
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
void computeGradientsForMethods(const std::vector< const FVGradientMethod * > &gradient_methods)
Compute and finalize the supplied registered gradient methods.
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.
void computeGradientsExcept(const LinearFVGradientReader &excluded_reader)
Compute and finalize every registered linear FV gradient field except one method.
SystemBase & _sys
Reference to the system object.
void finalizeLinearFVGradientContainer(LinearFVGradientContainer &container)
Replace the current gradient storage with the freshly computed new gradients.
std::vector< const FVGradientMethod * > _linear_fv_gradient_methods
Registered gradient methods in registration order.
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:404
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:2949
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:92
bool solutionStatesInitialized() const
Whether or not the solution states have been initialized via initSolutionState()
Definition SystemBase.h:929
FEProblemBase & feProblem()
Definition SystemBase.h:104
virtual const std::string & name() const
const VariableWarehouse & variableWarehouse(THREAD_ID tid=0) const
Definition SystemBase.h:787
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:608
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
auto index_range(const T &sizable)
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.