https://mooseframework.inl.gov
SteffensenSolve.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 "SteffensenSolve.h"
11 
12 #include "Executioner.h"
13 #include "FEProblemBase.h"
14 #include "NonlinearSystem.h"
16 #include "Console.h"
18 
21 {
23 
24  return params;
25 }
26 
28 
29 void
31 {
32  findTransformedSystem(primary);
33 
34  TagID fxn_m1_tagid;
35  TagID xn_m1_tagid;
36  const std::vector<PostprocessorName> * transformed_pps;
37  std::vector<std::vector<PostprocessorValue>> * transformed_pps_values;
38  if (primary)
39  {
40  xn_m1_tagid = _problem.addVectorTag("xn_m1", Moose::VECTOR_TAG_SOLUTION);
41  fxn_m1_tagid = _problem.addVectorTag("fxn_m1", Moose::VECTOR_TAG_SOLUTION);
42  transformed_pps = &_transformed_pps;
43  transformed_pps_values = &_transformed_pps_values;
44  _xn_m1_tagid = xn_m1_tagid;
45  _fxn_m1_tagid = fxn_m1_tagid;
46  }
47  else
48  {
49  xn_m1_tagid = _problem.addVectorTag("secondary_xn_m1", Moose::VECTOR_TAG_SOLUTION);
50  fxn_m1_tagid = _problem.addVectorTag("secondary_fxn_m1", Moose::VECTOR_TAG_SOLUTION);
51  transformed_pps = &_secondary_transformed_pps;
52  transformed_pps_values = &_secondary_transformed_pps_values;
53  _secondary_xn_m1_tagid = xn_m1_tagid;
54  _secondary_fxn_m1_tagid = fxn_m1_tagid;
55  }
56 
57  // Store a copy of the previous solution here
58  // If we don't have a transformed system, we are not accelerating variables
59  if (_transformed_sys)
60  {
61  _transformed_sys->addVector(xn_m1_tagid, false, PARALLEL);
62  _transformed_sys->addVector(fxn_m1_tagid, false, PARALLEL);
63  }
64 
65  // Allocate storage for the previous postprocessor values
66  (*transformed_pps_values).resize((*transformed_pps).size());
67  for (size_t i = 0; i < (*transformed_pps).size(); i++)
68  (*transformed_pps_values)[i].resize(2);
69 }
70 
71 void
73 {
75 
77  if (!dynamic_cast<DefaultMultiAppFixedPointConvergence *>(&convergence))
78  mooseError(
79  "Only DefaultMultiAppFixedPointConvergence objects may be used for "
80  "'multiapp_fixed_point_convergence' when using the Steffensen fixed point algorithm.");
81 }
82 
83 void
85 {
86  unsigned int iteration;
87  TagID fxn_m1_tagid;
88  TagID xn_m1_tagid;
89  if (primary)
90  {
91  iteration = _fixed_point_it;
92  fxn_m1_tagid = _fxn_m1_tagid;
93  xn_m1_tagid = _xn_m1_tagid;
94  }
95  else
96  {
97  iteration = _main_fixed_point_it;
98  fxn_m1_tagid = _secondary_fxn_m1_tagid;
99  xn_m1_tagid = _secondary_xn_m1_tagid;
100  }
101 
102  // Check to make sure allocateStorage has been called
103  mooseAssert(fxn_m1_tagid != Moose::INVALID_TAG_ID,
104  "allocateStorage has not been called with primary = " + Moose::stringify(primary));
105  mooseAssert(xn_m1_tagid != Moose::INVALID_TAG_ID,
106  "allocateStorage has not been called with primary = " + Moose::stringify(primary));
107 
108  // Save previous variable values
110  NumericVector<Number> & fxn_m1 = _transformed_sys->getVector(fxn_m1_tagid);
111  NumericVector<Number> & xn_m1 = _transformed_sys->getVector(xn_m1_tagid);
112 
113  // What 'solution' is with regards to the Steffensen solve depends on the step
114  if (iteration % 2 == 1)
115  xn_m1 = solution;
116  else
117  fxn_m1 = solution;
118 }
119 
120 void
122 {
123  unsigned int iteration;
124  const std::vector<PostprocessorName> * transformed_pps;
125  std::vector<std::vector<PostprocessorValue>> * transformed_pps_values;
126  if (primary)
127  {
128  iteration = _fixed_point_it;
129  transformed_pps = &_transformed_pps;
130  transformed_pps_values = &_transformed_pps_values;
131  }
132  else
133  {
134  iteration = _main_fixed_point_it;
135  transformed_pps = &_secondary_transformed_pps;
136  transformed_pps_values = &_secondary_transformed_pps_values;
137  }
138 
139  // Save previous postprocessor values
140  for (size_t i = 0; i < (*transformed_pps).size(); i++)
141  {
142  if (iteration % 2 == 0)
143  (*transformed_pps_values)[i][1] = getPostprocessorValueByName((*transformed_pps)[i]);
144  else
145  (*transformed_pps_values)[i][0] = getPostprocessorValueByName((*transformed_pps)[i]);
146  }
147 }
148 
149 bool
151 {
152  // Need at least two values to compute the Steffensen update, and the update is only performed
153  // every other iteration as two evaluations of the coupled problem are necessary
154  if (primary)
155  return _fixed_point_it > 1 && (_fixed_point_it % 2 == 0);
156  else
157  return _main_fixed_point_it > 1 && (_main_fixed_point_it % 2 == 0);
158 }
159 
160 void
162 {
163  Real relaxation_factor;
164  const std::vector<PostprocessorName> * transformed_pps;
165  std::vector<std::vector<PostprocessorValue>> * transformed_pps_values;
166  if (primary)
167  {
168  relaxation_factor = _relax_factor;
169  transformed_pps = &_transformed_pps;
170  transformed_pps_values = &_transformed_pps_values;
171  }
172  else
173  {
174  relaxation_factor = _secondary_relaxation_factor;
175  transformed_pps = &_secondary_transformed_pps;
176  transformed_pps_values = &_secondary_transformed_pps_values;
177  }
178 
179  // Relax postprocessors for the main application
180  for (size_t i = 0; i < (*transformed_pps).size(); i++)
181  {
182  // Get new postprocessor value
183  const Real current_value = getPostprocessorValueByName((*transformed_pps)[i]);
184  const Real fxn_m1 = (*transformed_pps_values)[i][0];
185  const Real xn_m1 = (*transformed_pps_values)[i][1];
186 
187  // Compute and set relaxed value
188  Real new_value = current_value;
189  if (!MooseUtils::absoluteFuzzyEqual(current_value + xn_m1 - 2 * fxn_m1, 0))
190  new_value =
191  xn_m1 - (fxn_m1 - xn_m1) * (fxn_m1 - xn_m1) / (current_value + xn_m1 - 2 * fxn_m1);
192 
193  // Relax update
194  new_value = relaxation_factor * new_value + (1 - relaxation_factor) * fxn_m1;
195 
196  _problem.setPostprocessorValueByName((*transformed_pps)[i], new_value);
197  }
198 }
199 
200 void
201 SteffensenSolve::transformVariables(const std::set<dof_id_type> & transformed_dofs,
202  const bool primary)
203 {
204  Real relaxation_factor;
205  TagID fxn_m1_tagid;
206  TagID xn_m1_tagid;
207  if (primary)
208  {
209  relaxation_factor = _relax_factor;
210  fxn_m1_tagid = _fxn_m1_tagid;
211  xn_m1_tagid = _xn_m1_tagid;
212  }
213  else
214  {
215  relaxation_factor = _secondary_relaxation_factor;
216  fxn_m1_tagid = _secondary_fxn_m1_tagid;
217  xn_m1_tagid = _secondary_xn_m1_tagid;
218  }
219 
221  NumericVector<Number> & fxn_m1 = _transformed_sys->getVector(fxn_m1_tagid);
222  NumericVector<Number> & xn_m1 = _transformed_sys->getVector(xn_m1_tagid);
223 
224  for (const auto & dof : transformed_dofs)
225  {
226  // Avoid 0 denominator issue
227  Real new_value = solution(dof);
228  if (!MooseUtils::absoluteFuzzyEqual(solution(dof) + xn_m1(dof) - 2 * fxn_m1(dof), 0))
229  new_value = xn_m1(dof) - (fxn_m1(dof) - xn_m1(dof)) * (fxn_m1(dof) - xn_m1(dof)) /
230  (solution(dof) + xn_m1(dof) - 2 * fxn_m1(dof));
231 
232  // Relax update
233  new_value = relaxation_factor * new_value + (1 - relaxation_factor) * fxn_m1(dof);
234 
235  solution.set(dof, new_value);
236  }
237  solution.close();
239 }
240 
241 void
243  const Real initial_norm,
244  const std::vector<Real> & timestep_begin_norms,
245  const std::vector<Real> & timestep_end_norms) const
246 {
247  _console << "\n 0 Steffensen initialization |R| = "
248  << Console::outputNorm(std::numeric_limits<Real>::max(), initial_norm) << '\n';
249 
250  Real max_norm_old = initial_norm;
251  for (unsigned int i = 0; i <= _fixed_point_it; ++i)
252  {
253  Real max_norm = std::max(timestep_begin_norms[i], timestep_end_norms[i]);
254  std::stringstream steffensen_prefix;
255  if (i == 0)
256  steffensen_prefix << " Steffensen initialization |R| = ";
257  else if (i % 2 == 0)
258  steffensen_prefix << " Steffensen half-step |R| = ";
259  else
260  steffensen_prefix << " Steffensen step |R| = ";
261 
262  _console << std::setw(2) << i + 1 << steffensen_prefix.str()
263  << Console::outputNorm(max_norm_old, max_norm) << '\n';
264 
265  max_norm_old = max_norm;
266  }
267 }
std::vector< std::vector< PostprocessorValue > > _transformed_pps_values
Previous values of the relaxed postprocessors.
virtual void printFixedPointConvergenceHistory(Real initial_norm, const std::vector< Real > &timestep_begin_norms, const std::vector< Real > &timestep_end_norms) const override final
Print the convergence history of the coupling, at every fixed point iteration.
std::vector< std::vector< PostprocessorValue > > _secondary_transformed_pps_values
Previous values of the postprocessors relaxed outside of the fixed point iteration (used as a subapp)...
FEProblemBase & _problem
Reference to FEProblem.
Definition: SolveObject.h:47
SteffensenSolve(Executioner &ex)
unsigned int TagID
Definition: MooseTypes.h:238
NumericVector< Number > & solution()
Definition: SystemBase.h:197
PARALLEL
void setPostprocessorValueByName(const PostprocessorName &name, const PostprocessorValue &value, std::size_t t_index=0)
Set the value of a PostprocessorValue.
virtual TagID addVectorTag(const TagName &tag_name, const Moose::VectorTagType type=Moose::VECTOR_TAG_RESIDUAL)
Create a Tag.
Definition: SubProblem.C:93
virtual void transformPostprocessors(const bool primary) override final
Use the fixed point algorithm to transform the postprocessors.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
virtual void savePostprocessorValues(const bool primary) override final
Saves the current values of the postprocessors, and update the old(er) vectors.
virtual void transformVariables(const std::set< dof_id_type > &transformed_dofs, const bool primary) override final
Use the fixed point algorithm to transform the variables.
std::vector< PostprocessorName > _secondary_transformed_pps
Postprocessors to be relaxed outside of fixed point iteration (used as a subapp)
auto max(const L &left, const R &right)
const std::vector< PostprocessorName > _transformed_pps
The postprocessors (transferred or not) that are going to be relaxed.
NumericVector< Number > & addVector(const std::string &vector_name, const bool project, const libMesh::ParallelType type)
Adds a solution length vector to the system.
TagID _fxn_m1_tagid
Vector tag id for the most recent solution variable, pre-Steffensen transform, as a main app...
TagID _xn_m1_tagid
Vector tag id for the solution variable before the latest solve, as a main app.
void update()
Update the system (doing libMesh magic)
Definition: SystemBase.C:1244
const Real _relax_factor
Relaxation factor for fixed point Iteration.
virtual Convergence & getConvergence(const std::string &name, const THREAD_ID tid=0) const
Gets a Convergence object.
virtual bool useFixedPointAlgorithmUpdateInsteadOfPicard(const bool primary) override final
Use the fixed point algorithm transform instead of simply using the Picard update.
const ConvergenceName & getMultiAppFixedPointConvergenceName() const
Gets the MultiApp fixed point convergence object name.
TagID _secondary_xn_m1_tagid
Vector tag id for the solution variable before the latest solve, as a sub app.
Executioners are objects that do the actual work of solving your problem.
Definition: Executioner.h:30
virtual void saveVariableValues(const bool primary) override final
Saves the current values of the variables, and update the old(er) vectors.
Real _secondary_relaxation_factor
Relaxation factor outside of fixed point iteration (used as a subapp)
virtual void allocateStorage(const bool primary) override final
Allocate storage for the fixed point algorithm.
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
virtual void close()=0
virtual const PostprocessorValue & getPostprocessorValueByName(const PostprocessorName &name) const
Retrieve the value of the Postprocessor.
unsigned int _fixed_point_it
static InputParameters validParams()
TagID _secondary_fxn_m1_tagid
Vector tag id for the most recent solution variable, pre-Steffensen transform, as a sub app...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void initialSetup() override
Method that should be executed once, before any solve calls.
static std::string outputNorm(const Real &old_norm, const Real &norm, const unsigned int precision=6)
A helper function for outputting norms in color.
Definition: Console.C:619
const TagID INVALID_TAG_ID
Definition: MooseTypes.C:23
SystemBase * _transformed_sys
System holding the transformed variables.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:281
virtual void set(const numeric_index_type i, const Number value)=0
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
virtual void initialSetup() override
Method that should be executed once, before any solve calls.
void findTransformedSystem(const bool primary)
Find the system holding the variables to be transformed (accelerated or relaxed)
virtual NumericVector< Number > & getVector(const std::string &name)
Get a raw NumericVector by name.
Definition: SystemBase.C:934
static InputParameters validParams()
unsigned int _main_fixed_point_it
fixed point iteration counter for the main app