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 {
28  allocateStorage(true);
29 
31  for (size_t i = 0; i < _transformed_pps.size(); i++)
32  _transformed_pps_values[i].resize(4);
34  for (size_t i = 0; i < _secondary_transformed_pps.size(); i++)
36 }
37 
38 void
39 SecantSolve::allocateStorage(const bool primary)
40 {
41  TagID fxn_m1_tagid;
42  TagID xn_m1_tagid;
43  TagID fxn_m2_tagid;
44  TagID xn_m2_tagid;
45  if (primary)
46  {
47  xn_m1_tagid = _problem.addVectorTag("xn_m1", Moose::VECTOR_TAG_SOLUTION);
48  fxn_m1_tagid = _problem.addVectorTag("fxn_m1", Moose::VECTOR_TAG_SOLUTION);
49  xn_m2_tagid = _problem.addVectorTag("xn_m2", Moose::VECTOR_TAG_SOLUTION);
50  fxn_m2_tagid = _problem.addVectorTag("fxn_m2", Moose::VECTOR_TAG_SOLUTION);
51  _xn_m1_tagid = xn_m1_tagid;
52  _fxn_m1_tagid = fxn_m1_tagid;
53  _xn_m2_tagid = xn_m2_tagid;
54  _fxn_m2_tagid = fxn_m2_tagid;
55  }
56  else
57  {
58  xn_m1_tagid = _problem.addVectorTag("secondary_xn_m1", Moose::VECTOR_TAG_SOLUTION);
59  fxn_m1_tagid = _problem.addVectorTag("secondary_fxn_m1", Moose::VECTOR_TAG_SOLUTION);
60  xn_m2_tagid = _problem.addVectorTag("secondary_xn_m2", Moose::VECTOR_TAG_SOLUTION);
61  fxn_m2_tagid = _problem.addVectorTag("secondary_fxn_m2", Moose::VECTOR_TAG_SOLUTION);
62  _secondary_xn_m1_tagid = xn_m1_tagid;
63  _secondary_fxn_m1_tagid = fxn_m1_tagid;
64  _secondary_xn_m2_tagid = xn_m2_tagid;
65  _secondary_fxn_m2_tagid = fxn_m2_tagid;
66  }
67 
68  // TODO: We would only need to store the solution for the degrees of freedom that
69  // will be transformed, not the entire solution.
70  // Store solution vectors for the two previous points and their evaluation
71  _solver_sys.addVector(xn_m1_tagid, false, PARALLEL);
72  _solver_sys.addVector(fxn_m1_tagid, false, PARALLEL);
73  _solver_sys.addVector(xn_m2_tagid, false, PARALLEL);
74  _solver_sys.addVector(fxn_m2_tagid, false, PARALLEL);
75 }
76 
77 void
79 {
80  TagID fxn_m1_tagid;
81  TagID xn_m1_tagid;
82  TagID fxn_m2_tagid;
83  TagID xn_m2_tagid;
84  if (primary)
85  {
86  fxn_m1_tagid = _fxn_m1_tagid;
87  xn_m1_tagid = _xn_m1_tagid;
88  fxn_m2_tagid = _fxn_m2_tagid;
89  xn_m2_tagid = _xn_m2_tagid;
90  }
91  else
92  {
93  fxn_m1_tagid = _secondary_fxn_m1_tagid;
94  xn_m1_tagid = _secondary_xn_m1_tagid;
95  fxn_m2_tagid = _secondary_fxn_m2_tagid;
96  xn_m2_tagid = _secondary_xn_m2_tagid;
97  }
98 
99  // Check to make sure allocateStorage has been called
100  mooseAssert(fxn_m1_tagid != Moose::INVALID_TAG_ID,
101  "allocateStorage has not been called with primary = " + Moose::stringify(primary));
102  mooseAssert(xn_m1_tagid != Moose::INVALID_TAG_ID,
103  "allocateStorage has not been called with primary = " + Moose::stringify(primary));
104  mooseAssert(fxn_m2_tagid != Moose::INVALID_TAG_ID,
105  "allocateStorage has not been called with primary = " + Moose::stringify(primary));
106  mooseAssert(xn_m2_tagid != Moose::INVALID_TAG_ID,
107  "allocateStorage has not been called with primary = " + Moose::stringify(primary));
108 
109  // Save previous variable values
111  NumericVector<Number> & fxn_m1 = _solver_sys.getVector(fxn_m1_tagid);
112  NumericVector<Number> & xn_m1 = _solver_sys.getVector(xn_m1_tagid);
113  NumericVector<Number> & fxn_m2 = _solver_sys.getVector(fxn_m2_tagid);
114  NumericVector<Number> & xn_m2 = _solver_sys.getVector(xn_m2_tagid);
115 
116  // Advance one step
117  xn_m2 = xn_m1;
118 
119  // Before a solve, solution is a sequence term, after a solve, solution is the evaluated term
120  xn_m1 = solution;
121 
122  // Since we did not update on the 0th iteration, the solution is also the previous evaluated term
123  const unsigned int it = primary ? _fixed_point_it : _main_fixed_point_it;
124  if (it == 1)
125  fxn_m2 = solution;
126  // Otherwise we just advance
127  else
128  fxn_m2 = fxn_m1;
129 }
130 
131 void
133 {
134  const std::vector<PostprocessorName> * transformed_pps;
135  std::vector<std::vector<PostprocessorValue>> * transformed_pps_values;
136  if (primary)
137  {
138  transformed_pps = &_transformed_pps;
139  transformed_pps_values = &_transformed_pps_values;
140  }
141  else
142  {
143  transformed_pps = &_secondary_transformed_pps;
144  transformed_pps_values = &_secondary_transformed_pps_values;
145  }
146  const unsigned int it = primary ? _fixed_point_it : _main_fixed_point_it;
147 
148  // Save previous postprocessor values
149  for (size_t i = 0; i < (*transformed_pps).size(); i++)
150  {
151  // Advance one step
152  (*transformed_pps_values)[i][3] = (*transformed_pps_values)[i][1];
153 
154  // Save current value
155  // Primary: this is done before the timestep's solves and before timestep_begin transfers,
156  // so the value is the result of the previous Secant update (xn_m1)
157  // Secondary: this is done after the secondary solve, but before timestep_end postprocessors
158  // are computed, or timestep_end transfers are received.
159  // This value is the same as before the solve (xn_m1)
160  (*transformed_pps_values)[i][1] = getPostprocessorValueByName((*transformed_pps)[i]);
161 
162  // Since we did not update on the 1st iteration, the pp is also the previous evaluated term
163  if (it == 2)
164  (*transformed_pps_values)[i][2] = (*transformed_pps_values)[i][1];
165  // Otherwise we just advance
166  else
167  (*transformed_pps_values)[i][2] = (*transformed_pps_values)[i][0];
168  }
169 }
170 
171 bool
173 {
174  // Need at least two evaluations to compute the Secant slope
175  if (primary)
176  return _fixed_point_it > 0;
177  else
178  return _main_fixed_point_it > 0;
179 }
180 
181 void
183 {
184  if ((primary ? _fixed_point_it : _main_fixed_point_it) < 2)
185  return;
186 
187  Real relaxation_factor;
188  const std::vector<PostprocessorName> * transformed_pps;
189  std::vector<std::vector<PostprocessorValue>> * transformed_pps_values;
190  if (primary)
191  {
192  relaxation_factor = _relax_factor;
193  transformed_pps = &_transformed_pps;
194  transformed_pps_values = &_transformed_pps_values;
195  }
196  else
197  {
198  relaxation_factor = _secondary_relaxation_factor;
199  transformed_pps = &_secondary_transformed_pps;
200  transformed_pps_values = &_secondary_transformed_pps_values;
201  }
202 
203  // Relax postprocessors for the main application
204  for (size_t i = 0; i < (*transformed_pps).size(); i++)
205  {
206  // Get new postprocessor value
207  const Real fxn_m1 = getPostprocessorValueByName((*transformed_pps)[i]);
208  const Real xn_m1 = (*transformed_pps_values)[i][1];
209  const Real fxn_m2 = (*transformed_pps_values)[i][2];
210  const Real xn_m2 = (*transformed_pps_values)[i][3];
211 
212  // Save fxn_m1, received or computed before the solve
213  (*transformed_pps_values)[i][0] = fxn_m1;
214 
215  // Compute and set relaxed value
216  Real new_value = fxn_m1;
217  if (!MooseUtils::absoluteFuzzyEqual(fxn_m1 - xn_m1 - fxn_m2 + xn_m2, 0))
218  new_value = xn_m1 - (fxn_m1 - xn_m1) * (xn_m1 - xn_m2) / (fxn_m1 - xn_m1 - fxn_m2 + xn_m2);
219 
220  // Relax update if desired
221  new_value = relaxation_factor * new_value + (1 - relaxation_factor) * xn_m1;
222 
223  _problem.setPostprocessorValueByName((*transformed_pps)[i], new_value);
224  }
225 }
226 
227 void
228 SecantSolve::transformVariables(const std::set<dof_id_type> & target_dofs, const bool primary)
229 {
230  Real relaxation_factor;
231  TagID fxn_m1_tagid;
232  TagID xn_m1_tagid;
233  TagID fxn_m2_tagid;
234  TagID xn_m2_tagid;
235  if (primary)
236  {
237  relaxation_factor = _relax_factor;
238  fxn_m1_tagid = _fxn_m1_tagid;
239  xn_m1_tagid = _xn_m1_tagid;
240  fxn_m2_tagid = _fxn_m2_tagid;
241  xn_m2_tagid = _xn_m2_tagid;
242  }
243  else
244  {
245  relaxation_factor = _secondary_relaxation_factor;
246  fxn_m1_tagid = _secondary_fxn_m1_tagid;
247  xn_m1_tagid = _secondary_xn_m1_tagid;
248  fxn_m2_tagid = _secondary_fxn_m2_tagid;
249  xn_m2_tagid = _secondary_xn_m2_tagid;
250  }
251 
253  NumericVector<Number> & xn_m1 = _solver_sys.getVector(xn_m1_tagid);
254  NumericVector<Number> & fxn_m2 = _solver_sys.getVector(fxn_m2_tagid);
255  NumericVector<Number> & xn_m2 = _solver_sys.getVector(xn_m2_tagid);
256 
257  // Save the most recent evaluation of the coupled problem
258  NumericVector<Number> & fxn_m1 = _solver_sys.getVector(fxn_m1_tagid);
259  fxn_m1 = solution;
260 
261  for (const auto & dof : target_dofs)
262  {
263  // Avoid 0 denominator issue
264  Real new_value = fxn_m1(dof);
265  if (!MooseUtils::absoluteFuzzyEqual(solution(dof) - xn_m1(dof) - fxn_m2(dof) + xn_m2(dof), 0))
266  new_value = xn_m1(dof) - (solution(dof) - xn_m1(dof)) * (xn_m1(dof) - xn_m2(dof)) /
267  (solution(dof) - xn_m1(dof) - fxn_m2(dof) + xn_m2(dof));
268 
269  // Relax update
270  new_value = relaxation_factor * new_value + (1 - relaxation_factor) * xn_m1(dof);
271 
272  solution.set(dof, new_value);
273  }
274  solution.close();
276 }
277 
278 void
280  const std::vector<Real> & timestep_begin_norms,
281  const std::vector<Real> & timestep_end_norms) const
282 {
283  _console << "\n 0 Secant initialization |R| = "
284  << Console::outputNorm(std::numeric_limits<Real>::max(), initial_norm) << '\n';
285 
286  Real max_norm_old = initial_norm;
287  for (unsigned int i = 0; i <= _fixed_point_it; ++i)
288  {
289  Real max_norm = std::max(timestep_begin_norms[i], timestep_end_norms[i]);
290  std::stringstream secant_prefix;
291  if (i < 1)
292  secant_prefix << " Secant initialization |R| = ";
293  else
294  secant_prefix << " Secant step |R| = ";
295 
296  _console << std::setw(2) << i + 1 << secant_prefix.str()
297  << Console::outputNorm(max_norm_old, max_norm) << '\n';
298  max_norm_old = max_norm;
299  }
300 }
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
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether two variables are equal within an absolute tolerance.
Definition: MooseUtils.h:380
unsigned int TagID
Definition: MooseTypes.h:210
NumericVector< Number > & solution()
Definition: SystemBase.h:195
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:78
virtual TagID addVectorTag(const TagName &tag_name, const Moose::VectorTagType type=Moose::VECTOR_TAG_RESIDUAL)
Create a Tag.
Definition: SubProblem.C:92
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...
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:182
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:279
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:1245
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:228
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:132
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
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
SystemBase & _solver_sys
Reference to a system for creating vectors as needed for the solve, etc.
Definition: SolveObject.h:55
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:623
const TagID INVALID_TAG_ID
Definition: MooseTypes.C:23
virtual void allocateStorage(const bool primary) override final
Allocate storage for the fixed point algorithm.
Definition: SecantSolve.C:39
virtual bool useFixedPointAlgorithmUpdateInsteadOfPicard(const bool primary) override final
Use the fixed point algorithm transform instead of simply using the Picard update.
Definition: SecantSolve.C:172
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 NumericVector< Number > & getVector(const std::string &name)
Get a raw NumericVector by name.
Definition: SystemBase.C:916
SecantSolve(Executioner &ex)
Definition: SecantSolve.C:26
unsigned int _main_fixed_point_it
fixed point iteration counter for the main app