https://mooseframework.inl.gov
SecantSolve.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 "SecantSolve.h"
11 
12 #include "Executioner.h"
13 #include "FEProblemBase.h"
14 #include "NonlinearSystem.h"
16 #include "Console.h"
17 
20 {
22 
23  return params;
24 }
25 
27 {
29  for (size_t i = 0; i < _transformed_pps.size(); i++)
30  _transformed_pps_values[i].resize(4);
32  for (size_t i = 0; i < _secondary_transformed_pps.size(); i++)
34 }
35 
36 void
37 SecantSolve::allocateStorage(const bool primary)
38 {
39  findTransformedSystem(primary);
40  if (!_transformed_sys)
41  return;
42 
43  // TODO: We would only need to store the solution for the degrees of freedom that
44  // will be transformed, not the entire solution.
45  // Store solution vectors for the two previous points and their evaluation
46  if (primary)
47  {
48  _xn_m1_tagid =
53 
58  }
59  else
60  {
65 
70  }
71 }
72 
73 void
75 {
76  TagID fxn_m1_tagid;
77  TagID xn_m1_tagid;
78  TagID fxn_m2_tagid;
79  TagID xn_m2_tagid;
80  if (primary)
81  {
82  fxn_m1_tagid = _fxn_m1_tagid;
83  xn_m1_tagid = _xn_m1_tagid;
84  fxn_m2_tagid = _fxn_m2_tagid;
85  xn_m2_tagid = _xn_m2_tagid;
86  }
87  else
88  {
89  fxn_m1_tagid = _secondary_fxn_m1_tagid;
90  xn_m1_tagid = _secondary_xn_m1_tagid;
91  fxn_m2_tagid = _secondary_fxn_m2_tagid;
92  xn_m2_tagid = _secondary_xn_m2_tagid;
93  }
94 
95  // Check to make sure allocateStorage has been called
96  mooseAssert(fxn_m1_tagid != Moose::INVALID_TAG_ID,
97  "allocateStorage has not been called with primary = " + Moose::stringify(primary));
98  mooseAssert(xn_m1_tagid != Moose::INVALID_TAG_ID,
99  "allocateStorage has not been called with primary = " + Moose::stringify(primary));
100  mooseAssert(fxn_m2_tagid != Moose::INVALID_TAG_ID,
101  "allocateStorage has not been called with primary = " + Moose::stringify(primary));
102  mooseAssert(xn_m2_tagid != Moose::INVALID_TAG_ID,
103  "allocateStorage has not been called with primary = " + Moose::stringify(primary));
104 
105  // Save previous variable values
107  NumericVector<Number> & fxn_m1 = _transformed_sys->getVector(fxn_m1_tagid);
108  NumericVector<Number> & xn_m1 = _transformed_sys->getVector(xn_m1_tagid);
109  NumericVector<Number> & fxn_m2 = _transformed_sys->getVector(fxn_m2_tagid);
110  NumericVector<Number> & xn_m2 = _transformed_sys->getVector(xn_m2_tagid);
111 
112  // Advance one step
113  xn_m2 = xn_m1;
114 
115  // Before a solve, solution is a sequence term, after a solve, solution is the evaluated term
116  // Primary is copied back by _transformed_sys->copyPreviousFixedPointSolutions()
117  if (!primary)
118  xn_m1 = solution;
119 
120  // Since we did not update on the 0th iteration, the solution is also the previous evaluated term
121  const unsigned int it = primary ? _fixed_point_it : _main_fixed_point_it;
122  if (it == 1)
123  fxn_m2 = solution;
124  // Otherwise we just advance
125  else
126  fxn_m2 = fxn_m1;
127 }
128 
129 void
131 {
132  const std::vector<PostprocessorName> * transformed_pps;
133  std::vector<std::vector<PostprocessorValue>> * transformed_pps_values;
134  if (primary)
135  {
136  transformed_pps = &_transformed_pps;
137  transformed_pps_values = &_transformed_pps_values;
138  }
139  else
140  {
141  transformed_pps = &_secondary_transformed_pps;
142  transformed_pps_values = &_secondary_transformed_pps_values;
143  }
144  const unsigned int it = primary ? _fixed_point_it : _main_fixed_point_it;
145 
146  // Save previous postprocessor values
147  for (size_t i = 0; i < (*transformed_pps).size(); i++)
148  {
149  // Advance one step
150  (*transformed_pps_values)[i][3] = (*transformed_pps_values)[i][1];
151 
152  // Save current value
153  // Primary: this is done before the timestep's solves and before timestep_begin transfers,
154  // so the value is the result of the previous Secant update (xn_m1)
155  // Secondary: this is done after the secondary solve, but before timestep_end postprocessors
156  // are computed, or timestep_end transfers are received.
157  // This value is the same as before the solve (xn_m1)
158  (*transformed_pps_values)[i][1] = getPostprocessorValueByName((*transformed_pps)[i]);
159 
160  // Since we did not update on the 1st iteration, the pp is also the previous evaluated term
161  if (it == 2)
162  (*transformed_pps_values)[i][2] = (*transformed_pps_values)[i][1];
163  // Otherwise we just advance
164  else
165  (*transformed_pps_values)[i][2] = (*transformed_pps_values)[i][0];
166  }
167 }
168 
169 bool
171 {
172  // Need at least two evaluations to compute the Secant slope
173  if (primary)
174  return _fixed_point_it > 0;
175  else
176  return _main_fixed_point_it > 0;
177 }
178 
179 void
181 {
182  if ((primary ? _fixed_point_it : _main_fixed_point_it) < 2)
183  return;
184 
185  Real relaxation_factor;
186  const std::vector<PostprocessorName> * transformed_pps;
187  std::vector<std::vector<PostprocessorValue>> * transformed_pps_values;
188  if (primary)
189  {
190  relaxation_factor = _relax_factor;
191  transformed_pps = &_transformed_pps;
192  transformed_pps_values = &_transformed_pps_values;
193  }
194  else
195  {
196  relaxation_factor = _secondary_relaxation_factor;
197  transformed_pps = &_secondary_transformed_pps;
198  transformed_pps_values = &_secondary_transformed_pps_values;
199  }
200 
201  // Relax postprocessors for the main application
202  for (size_t i = 0; i < (*transformed_pps).size(); i++)
203  {
204  // Get new postprocessor value
205  const Real fxn_m1 = getPostprocessorValueByName((*transformed_pps)[i]);
206  const Real xn_m1 = (*transformed_pps_values)[i][1];
207  const Real fxn_m2 = (*transformed_pps_values)[i][2];
208  const Real xn_m2 = (*transformed_pps_values)[i][3];
209 
210  // Save fxn_m1, received or computed before the solve
211  (*transformed_pps_values)[i][0] = fxn_m1;
212 
213  // Compute and set relaxed value
214  Real new_value = fxn_m1;
215  if (!MooseUtils::absoluteFuzzyEqual(fxn_m1 - xn_m1 - fxn_m2 + xn_m2, 0))
216  new_value = xn_m1 - (fxn_m1 - xn_m1) * (xn_m1 - xn_m2) / (fxn_m1 - xn_m1 - fxn_m2 + xn_m2);
217 
218  // Relax update if desired
219  new_value = relaxation_factor * new_value + (1 - relaxation_factor) * xn_m1;
220 
221  _problem.setPostprocessorValueByName((*transformed_pps)[i], new_value);
222  }
223 }
224 
225 void
226 SecantSolve::transformVariables(const std::set<dof_id_type> & target_dofs, const bool primary)
227 {
228  Real relaxation_factor;
229  TagID fxn_m1_tagid;
230  TagID xn_m1_tagid;
231  TagID fxn_m2_tagid;
232  TagID xn_m2_tagid;
233  if (primary)
234  {
235  relaxation_factor = _relax_factor;
236  fxn_m1_tagid = _fxn_m1_tagid;
237  xn_m1_tagid = _xn_m1_tagid;
238  fxn_m2_tagid = _fxn_m2_tagid;
239  xn_m2_tagid = _xn_m2_tagid;
240  }
241  else
242  {
243  relaxation_factor = _secondary_relaxation_factor;
244  fxn_m1_tagid = _secondary_fxn_m1_tagid;
245  xn_m1_tagid = _secondary_xn_m1_tagid;
246  fxn_m2_tagid = _secondary_fxn_m2_tagid;
247  xn_m2_tagid = _secondary_xn_m2_tagid;
248  }
249 
251  NumericVector<Number> & xn_m1 = _transformed_sys->getVector(xn_m1_tagid);
252  NumericVector<Number> & fxn_m2 = _transformed_sys->getVector(fxn_m2_tagid);
253  NumericVector<Number> & xn_m2 = _transformed_sys->getVector(xn_m2_tagid);
254 
255  // Save the most recent evaluation of the coupled problem
256  NumericVector<Number> & fxn_m1 = _transformed_sys->getVector(fxn_m1_tagid);
257  fxn_m1 = solution;
258 
259  for (const auto & dof : target_dofs)
260  {
261  // Avoid 0 denominator issue
262  Real new_value = fxn_m1(dof);
263  if (!MooseUtils::absoluteFuzzyEqual(solution(dof) - xn_m1(dof) - fxn_m2(dof) + xn_m2(dof), 0))
264  new_value = xn_m1(dof) - (solution(dof) - xn_m1(dof)) * (xn_m1(dof) - xn_m2(dof)) /
265  (solution(dof) - xn_m1(dof) - fxn_m2(dof) + xn_m2(dof));
266 
267  // Relax update
268  new_value = relaxation_factor * new_value + (1 - relaxation_factor) * xn_m1(dof);
269 
270  solution.set(dof, new_value);
271  }
272  solution.close();
274 }
275 
276 void
278  const std::vector<Real> & timestep_begin_norms,
279  const std::vector<Real> & timestep_end_norms) const
280 {
281  _console << "\n 0 Secant initialization |R| = "
282  << Console::outputNorm(std::numeric_limits<Real>::max(), initial_norm) << '\n';
283 
284  Real max_norm_old = initial_norm;
285  for (unsigned int i = 0; i <= _fixed_point_it; ++i)
286  {
287  Real max_norm = std::max(timestep_begin_norms[i], timestep_end_norms[i]);
288  std::stringstream secant_prefix;
289  if (i < 1)
290  secant_prefix << " Secant initialization |R| = ";
291  else
292  secant_prefix << " Secant step |R| = ";
293 
294  _console << std::setw(2) << i + 1 << secant_prefix.str()
295  << Console::outputNorm(max_norm_old, max_norm) << '\n';
296  max_norm_old = max_norm;
297  }
298 }
std::vector< std::vector< PostprocessorValue > > _transformed_pps_values
Previous values of the relaxed postprocessors.
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
TagID _secondary_xn_m1_tagid
Vector tag id for the solution variable before the latest solve, as a sub app.
Definition: SecantSolve.h:100
unsigned int TagID
Definition: MooseTypes.h:238
NumericVector< Number > & solution()
Definition: SystemBase.h:197
TagID _secondary_fxn_m2_tagid
Vector tag id for the result of the last but one secondary solve, as a sub app.
Definition: SecantSolve.h:103
PARALLEL
static InputParameters validParams()
Definition: SecantSolve.C:19
void setPostprocessorValueByName(const PostprocessorName &name, const PostprocessorValue &value, std::size_t t_index=0)
Set the value of a PostprocessorValue.
TagID _secondary_xn_m2_tagid
Vector tag id for the solution variable two primary solves ago, as a sub app.
Definition: SecantSolve.h:106
virtual void saveVariableValues(const bool primary) override final
Saves the current values of the variables, and update the old(er) vectors.
Definition: SecantSolve.C:74
virtual TagID addVectorTag(const TagName &tag_name, const Moose::VectorTagType type=Moose::VECTOR_TAG_RESIDUAL)
Create a Tag.
Definition: SubProblem.C:93
TagID _xn_m2_tagid
Vector tag id for the solution variable two solves ago, as a main app.
Definition: SecantSolve.h:94
TagID _fxn_m1_tagid
Vector tag id for the most recent solution variable, pre-Secant transform, as a main app...
Definition: SecantSolve.h:85
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const TagName PREVIOUS_FP_SOLUTION_TAG
Definition: MooseTypes.C:29
std::vector< PostprocessorName > _secondary_transformed_pps
Postprocessors to be relaxed outside of fixed point iteration (used as a subapp)
virtual void transformPostprocessors(const bool primary) override final
Use the fixed point algorithm to transform the postprocessors.
Definition: SecantSolve.C:180
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.
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.
Definition: SecantSolve.C:277
NumericVector< Number > & addVector(const std::string &vector_name, const bool project, const libMesh::ParallelType type)
Adds a solution length vector to the system.
void update()
Update the system (doing libMesh magic)
Definition: SystemBase.C:1244
TagID _secondary_fxn_m1_tagid
Vector tag id for the most recent solution variable, pre-Secant transform, as a sub app...
Definition: SecantSolve.h:97
const Real _relax_factor
Relaxation factor for fixed point Iteration.
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.
Definition: SecantSolve.C:226
Executioners are objects that do the actual work of solving your problem.
Definition: Executioner.h:30
Real _secondary_relaxation_factor
Relaxation factor outside of fixed point iteration (used as a subapp)
virtual void savePostprocessorValues(const bool primary) override final
Saves the current values of the postprocessors, and update the old(er) vectors.
Definition: SecantSolve.C:130
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
virtual void needSolutionState(const unsigned int state, Moose::SolutionIterationType iteration_type=Moose::SolutionIterationType::Time, libMesh::ParallelType parallel_type=GHOSTED)
Registers that the solution state state is needed.
Definition: SystemBase.C:1452
virtual void close()=0
TagID _fxn_m2_tagid
Vector tag id for the result of the last but one solve, as a main app.
Definition: SecantSolve.h:91
virtual const PostprocessorValue & getPostprocessorValueByName(const PostprocessorName &name) const
Retrieve the value of the Postprocessor.
unsigned int _fixed_point_it
TagID _xn_m1_tagid
Vector tag id for the solution variable before the latest solve, as a main app.
Definition: SecantSolve.h:88
static InputParameters validParams()
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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.
virtual void allocateStorage(const bool primary) override final
Allocate storage for the fixed point algorithm.
Definition: SecantSolve.C:37
virtual bool useFixedPointAlgorithmUpdateInsteadOfPicard(const bool primary) override final
Use the fixed point algorithm transform instead of simply using the Picard update.
Definition: SecantSolve.C:170
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.
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
SecantSolve(Executioner &ex)
Definition: SecantSolve.C:26
unsigned int _main_fixed_point_it
fixed point iteration counter for the main app