solution.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2019-2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "solution.H"
30 #include "HashPtrTable.H"
31 #include "Function1.H"
32 #include "Time.H"
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38  defineDebugSwitchWithName(solution, "solution", 0);
39 }
40 
41 // List of sub-dictionaries to rewrite
43 ({
44  "preconditioner",
45  "smoother"
46 });
47 
48 
49 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
50 
51 void Foam::solution::read(const dictionary& dict)
52 {
53  const dictionary* dictptr;
54 
55  if ((dictptr = dict.findDict("cache")) != nullptr)
56  {
57  cache_ = *dictptr;
58  caching_ = cache_.getOrDefault("active", true);
59  }
60 
61  if ((dictptr = dict.findDict("relaxationFactors")) != nullptr)
62  {
63  const dictionary& relaxDict = *dictptr;
64 
65  bool needsCompat = true;
66 
67  if ((dictptr = relaxDict.findDict("fields")) != nullptr)
68  {
69  needsCompat = false;
70  fieldRelaxDict_ = *dictptr;
71  fieldRelaxCache_.clear();
72  }
73 
74  if ((dictptr = relaxDict.findDict("equations")) != nullptr)
75  {
76  needsCompat = false;
77  eqnRelaxDict_ = *dictptr;
78  eqnRelaxCache_.clear();
79  }
80 
81  if (needsCompat)
82  {
83  // backwards compatibility
84  fieldRelaxDict_.clear();
85  fieldRelaxCache_.clear();
86 
87  for (const word& e : relaxDict.toc())
88  {
89  scalar value = relaxDict.get<scalar>(e);
90 
91  if (e.starts_with('p'))
92  {
93  fieldRelaxDict_.add(e, value);
94  }
95  else if (e.starts_with("rho"))
96  {
97  fieldRelaxDict_.add(e, value);
98  }
99  }
100 
101  eqnRelaxDict_ = relaxDict;
102  eqnRelaxCache_.clear();
103  }
104 
105 
106  fieldRelaxDefault_ = Function1<scalar>::NewIfPresent
107  (
108  "default",
109  fieldRelaxDict_
110  );
111  if (!fieldRelaxDefault_)
112  {
113  fieldRelaxDefault_.reset
114  (
115  new Function1Types::Constant<scalar>("default", 0)
116  );
117  }
118 
119  eqnRelaxDefault_ = Function1<scalar>::NewIfPresent
120  (
121  "default",
122  eqnRelaxDict_
123  );
124  if (!eqnRelaxDefault_)
125  {
126  eqnRelaxDefault_.reset
127  (
128  new Function1Types::Constant<scalar>("default", 0)
129  );
130  }
131 
132  DebugInfo
133  << "Relaxation factors:" << nl
134  << "fields: " << fieldRelaxDict_ << nl
135  << "equations: " << eqnRelaxDict_ << endl;
136  }
137 
138  if ((dictptr = dict.findDict("solvers")) != nullptr)
139  {
140  solvers_ = *dictptr;
141  upgradeSolverDict(solvers_);
142  }
143 }
144 
145 
146 const Foam::dictionary& Foam::solution::selectedDict() const
147 {
148  word select;
149 
150  if (readIfPresent("select", select, keyType::LITERAL))
151  {
152  return subDict(select);
153  }
154 
155  return *this;
156 }
157 
158 
159 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
160 
161 Foam::solution::solution
162 (
163  const objectRegistry& obr,
165  const fileName& dictName,
166  const dictionary* fallback
167 )
168 :
170  (
171  IOobject
172  (
173  dictName,
174  obr.time().system(),
175  obr,
176  rOpt,
177  IOobject::NO_WRITE
178  ),
179  fallback
180  ),
181  cache_(),
182  caching_(false),
183  fieldRelaxDict_(),
184  eqnRelaxDict_(),
185  solvers_()
186 {
187  // Treat as MUST_READ_IF_MODIFIED whenever possible
188  if
189  (
191  || (isReadOptional() && headerOk())
192  )
193  {
195  addWatch();
196  }
197 
199  {
200  read(selectedDict());
201  }
202 }
203 
204 
205 Foam::solution::solution
206 (
207  const objectRegistry& obr,
208  const fileName& dictName,
209  const dictionary* fallback
210 )
211 :
212  solution(obr, obr.readOpt(), dictName, fallback)
213 {}
214 
215 
216 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
217 
218 // No default destructor in header (incomplete types)
220 {}
221 
222 
223 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
224 
226 (
227  dictionary& dict,
228  const bool verbose
229 )
230 {
231  label nChanged = 0;
232 
233  // backward compatibility:
234  // recast primitive entries into dictionary entries
235  for (const entry& dEntry : dict)
236  {
237  if (!dEntry.isDict())
238  {
239  ITstream& is = dEntry.stream();
240  word name(is);
241  dictionary subdict;
242 
243  subdict.add("solver", name);
244  subdict <<= dictionary(is);
245 
246  // preconditioner and smoother entries can be
247  // 1) primitiveEntry w/o settings,
248  // 2) or a dictionaryEntry.
249  // transform primitiveEntry with settings -> dictionaryEntry
250  for (const word& dictName : subDictNames)
251  {
252  entry* eptr = subdict.findEntry(dictName, keyType::LITERAL);
253 
254  if (eptr && !eptr->isDict())
255  {
256  ITstream& is = eptr->stream();
257  is >> name;
258 
259  if (!is.eof())
260  {
261  dictionary newDict;
262  newDict.add(dictName, name);
263  newDict <<= dictionary(is);
264 
265  subdict.set(dictName, newDict);
266  }
267  }
268  }
269 
270  // write out information to help people adjust to the new syntax
271  if (verbose && Pstream::master())
272  {
273  Info<< "// using new solver syntax:\n"
274  << dEntry.keyword() << subdict << endl;
275  }
276 
277  // overwrite with dictionary entry
278  dict.set(dEntry.keyword(), subdict);
279 
280  ++nChanged;
281  }
282  }
283 
284  return nChanged;
285 }
286 
287 
288 bool Foam::solution::cache(const word& name) const
289 {
290  if (caching_)
291  {
292  DebugInfo<< "Cache: find entry for " << name << endl;
293  return cache_.found(name);
294  }
295 
296  return false;
297 }
298 
299 
300 // void Foam::solution::enableCache(const word& name) const
301 // {
302 // if (!cache_.found(name))
303 // {
304 // DebugInfo<< "Cache: enable cache for " << name << endl;
305 // cache_.add(name, true);
306 // caching_ = true;
307 // }
308 // }
309 
310 
311 bool Foam::solution::relaxField(const word& name) const
312 {
313  DebugInfo
314  << "Field relaxation factor for " << name
315  << " is " << (fieldRelaxDict_.found(name) ? "set" : "unset") << endl;
316 
317  return fieldRelaxDict_.found(name) || fieldRelaxDict_.found("default");
318 }
319 
320 
322 {
323  DebugInfo<< "Find equation relaxation factor for " << name << endl;
324  return eqnRelaxDict_.found(name) || eqnRelaxDict_.found("default");
325 }
326 
327 
328 bool Foam::solution::relaxField(const word& name, scalar& factor) const
329 {
330  DebugInfo<< "Lookup field relaxation factor for " << name << endl;
331 
332  if (fieldRelaxDict_.found(name))
333  {
334  factor = Function1<scalar>::New
335  (
336  fieldRelaxCache_, // cache
337  name,
338  fieldRelaxDict_,
340  )().value(time().timeOutputValue());
341 
342  return true;
343  }
344  else if (fieldRelaxDict_.found("default") && fieldRelaxDefault_)
345  {
346  factor = fieldRelaxDefault_->value(time().timeOutputValue());
347  return true;
348  }
349 
350  // Fallthrough - nothing found
351  return false;
352 }
353 
354 
355 bool Foam::solution::relaxEquation(const word& name, scalar& factor) const
356 {
357  DebugInfo<< "Lookup equation relaxation factor for " << name << endl;
358 
359  if (eqnRelaxDict_.found(name))
360  {
361  factor = Function1<scalar>::New
362  (
363  eqnRelaxCache_, // cache
364  name,
365  eqnRelaxDict_,
367  )().value(time().timeOutputValue());
368 
369  return true;
370  }
371  else if (eqnRelaxDict_.found("default") && eqnRelaxDefault_)
372  {
373  factor = eqnRelaxDefault_->value(time().timeOutputValue());
374  return true;
375  }
376 
377  // Fallthrough - nothing found
378  return false;
379 }
380 
381 
382 Foam::scalar Foam::solution::fieldRelaxationFactor(const word& name) const
383 {
384  // Any initial value
385  scalar factor = 0;
386 
387  if (!relaxField(name, factor))
388  {
389  FatalIOErrorInFunction(fieldRelaxDict_)
390  << "Cannot find field relaxation factor for '" << name
391  << "' or a suitable default value." << nl
393  }
394 
395  return factor;
396 }
397 
398 
399 Foam::scalar Foam::solution::equationRelaxationFactor(const word& name) const
400 {
401  // Any initial value
402  scalar factor = 0;
403 
404  if (!relaxEquation(name, factor))
405  {
406  FatalIOErrorInFunction(eqnRelaxDict_)
407  << "Cannot find equation relaxation factor for '" << name
408  << "' or a suitable default value."
410  }
411 
412  return factor;
413 }
414 
417 {
418  return selectedDict();
419 }
420 
421 
423 {
424  DebugInfo<< "Lookup subDict : " << name << endl;
425  return selectedDict().subDict(name);
426 }
427 
430 {
431  return solvers_;
432 }
433 
434 
436 {
437  DebugInfo<< "Lookup solver for " << name << endl;
438  return solvers_.subDict(name);
439 }
440 
441 
443 {
444  DebugInfo<< "Lookup solver for " << name << endl;
445  return solvers_.subDict(name);
446 }
447 
448 
450 {
451  if (regIOobject::read())
452  {
453  read(selectedDict());
454 
455  return true;
456  }
457 
458  return false;
459 }
460 
461 
462 // ************************************************************************* //
Top level data entry class for use in dictionaries. Provides a mechanism to specify a variable as a c...
scalar equationRelaxationFactor(const word &name) const
Get the relaxation factor for the given equation. Fatal if not found.
Definition: solution.C:392
dictionary dict
A class for handling file names.
Definition: fileName.H:72
readOption readOpt() const noexcept
Get the read option.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
virtual bool read()
Read object.
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
defineDebugSwitchWithName(pointMVCWeight, "pointMVCWeight", 0)
bool read()
Read the solution dictionary.
Definition: solution.C:442
static const Foam::List< Foam::word > subDictNames({ "preconditioner", "smoother" })
List< bool > select(const label n, const labelUList &locations)
Construct a selection list of bools (all false) with the given pre-size, subsequently add specified l...
Definition: BitOps.C:134
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
const dictionary & solver(const word &name) const
The solver controls dictionary for the given field. Same as solverDict(...)
Definition: solution.C:435
const word dictName("faMeshDefinition")
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
bool headerOk()
Read and check header info. Does not check the headerClassName.
Definition: regIOobject.C:505
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:625
bool relaxField(const word &name) const
True if the relaxation factor is given for the field.
Definition: solution.C:304
const dictionary & solverDict(const word &name) const
The solver controls dictionary for the given field. Same as solversDict().subDict(...)
Definition: solution.C:428
bool isReadOptional() const noexcept
True if (LAZY_READ) bits are set [same as READ_IF_PRESENT].
bool relaxEquation(const word &name) const
True if the relaxation factor is given for the equation.
Definition: solution.C:314
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:127
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
dictionary()
Default construct, a top-level empty dictionary.
Definition: dictionary.C:68
virtual Type value(const scalar x) const
Return value as a function of (scalar) independent variable.
Definition: Function1.C:62
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
A class for handling words, derived from Foam::string.
Definition: word.H:63
const dictionary & solutionDict() const
The entire dictionary or the optional "select" sub-dictionary.
Definition: solution.C:409
bool cache(const word &name) const
True if the given field should be cached.
Definition: solution.C:281
String literal.
Definition: keyType.H:82
#define DebugInfo
Report an information message using Foam::Info.
static autoPtr< Function1< Type > > NewIfPresent(const word &entryName, const dictionary &dict, const word &redirectType, const objectRegistry *obrPtr=nullptr)
An optional selector, with fallback redirection.
Definition: Function1New.C:209
virtual void addWatch()
Add file watch on object (if registered and READ_IF_MODIFIED)
Definition: regIOobject.C:277
const dictionary & solversDict() const
The solver controls dictionary (all fields)
Definition: solution.C:422
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:627
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1082
scalar fieldRelaxationFactor(const word &name) const
Get the relaxation factor for the given field. Fatal if not found.
Definition: solution.C:375
meshDefDict readIfPresent("polyMeshPatches", polyPatchNames)
virtual ~solution()
Destructor. Non-default in header (incomplete types)
Definition: solution.C:212
const entry * findEntry(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:84
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual bool isDict() const noexcept
Return true if this entry is a dictionary.
Definition: entry.H:287
Selector class for relaxation factors, solver type and solution.
Definition: solution.H:92
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition: dictionary.C:765
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T, or return the given default value. FatalIOError if it is found and the number of...
int system(const std::string &command, const bool bg=false)
Execute the specified command via the shell.
Definition: POSIX.C:1702
Registry of regIOobjects.
void clear()
Clear the dictionary.
Definition: dictionary.C:844
virtual ITstream & stream() const =0
Return token stream, if entry is a primitive entry.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
Regular expression.
Definition: keyType.H:83
static label upgradeSolverDict(dictionary &dict, const bool verbose=true)
Update from older solver controls syntax.
Definition: solution.C:219
bool eof() const noexcept
True if end of input seen.
Definition: IOstream.H:289
An input stream of tokens.
Definition: ITstream.H:52
Namespace for OpenFOAM.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:63
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...
readOption
Enumeration defining read preferences.