ensightWriterCaching.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) 2016-2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "ensightWriterCaching.H"
29 #include "ListOps.H"
30 #include "OTstream.H"
31 #include "Fstream.H"
32 
33 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
34 
35 namespace Foam
36 {
37 
38 // Compare time values with tolerance
39 static const equalOp<scalar> equalTimes(ROOTSMALL);
40 
41 // Use ListOps findLower (with tolerance), to find the location of the next
42 // time-related index.
43 // The returned index is always 0 or larger (no negative values).
44 static label findTimeIndex(const UList<scalar>& list, const scalar val)
45 {
46  label idx =
47  findLower
48  (
49  list,
50  val,
51  0,
52  [](const scalar a, const scalar b)
53  {
54  return (a < b) && (Foam::mag(b - a) > ROOTSMALL);
55  }
56  );
57 
58  if (idx < 0 || !equalTimes(list[idx], val))
59  {
60  ++idx;
61  }
62 
63  return idx;
64 }
65 
66 } // End namespace Foam
67 
68 
69 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
70 
72 :
73  dictName_(cacheFileName)
74 {}
75 
76 
77 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
78 
80 {
81  const dictionary* dictptr = cache_.findDict("fields", keyType::LITERAL);
82 
83  if (!dictptr)
84  {
85  dictptr = &dictionary::null;
86  }
87 
88  return *dictptr;
89 }
90 
91 
92 Foam::dictionary& Foam::ensightOutput::writerCaching::fieldDict
93 (
94  const word& fieldName
95 )
96 {
97  return
98  cache_
99  .subDictOrAdd("fields", keyType::LITERAL)
100  .subDictOrAdd(fieldName, keyType::LITERAL);
101 }
102 
103 
104 bool Foam::ensightOutput::writerCaching::remove(const word& fieldName)
105 {
106  dictionary* dictptr = cache_.findDict("fields", keyType::LITERAL);
107 
108  if (dictptr)
109  {
110  return dictptr->remove(fieldName);
111  }
112 
113  return false;
114 }
115 
116 
118 {
119  times_.clear();
120  geoms_.clear();
121  cache_.clear();
122 }
123 
124 
125 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
126 
127 Foam::label Foam::ensightOutput::writerCaching::readPreviousTimes
128 (
129  const fileName& dictFile,
130  const scalar timeValue
131 )
132 {
133  // Track the used geometry intervals as a bitSet
134 
135  // Note: only called from master
136  label timeIndex = 0;
137  cache_.clear();
138 
139  IFstream is(dictFile);
140 
141  if (is.good() && cache_.read(is))
142  {
143  geoms_.clear();
144 
145  cache_.readIfPresent("times", times_);
146  timeIndex = findTimeIndex(times_, timeValue);
147 
148  labelList geomIndices;
149  scalarList meshTimes;
150 
151  if (cache_.readIfPresent("geometry", geomIndices))
152  {
153  // Convert indices to bitSet entries
154  geoms_.set(geomIndices);
155  }
156 
157  // Make length consistent with time information.
158  // We read/write the indices instead of simply dumping the bitSet.
159  // This makes the contents more human readable.
160  geoms_.resize(times_.size());
161  }
162 
163  return timeIndex;
164 }
166 
168 {
169  return max(0, times_.size()-1);
170 }
171 
173 {
174  return max(0, geoms_.find_last());
175 }
176 
177 
178 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
179 
181 {
182  if (geoms_.count() <= 1)
183  {
184  // Static
185  return 0;
186  }
187  if (geoms_.size() == times_.size() && geoms_.all())
188  {
189  // Geometry changing is identical to fields changing
190  return 1;
191  }
192 
193  // Geometry changing differently from fields
194  return 2;
195 }
196 
197 
198 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
199 
201 (
202  const fileName& baseDir,
203  const scalar timeValue,
204  const bool geomChanged,
205  const word& fieldName,
206  const word& fieldType,
207  const word& varName
208 )
209 {
210  const fileName dictFile(baseDir/dictName_);
211 
212  bool stateChanged = false;
213 
214  const label timeIndex =
215  (
216  times_.empty()
217  ? readPreviousTimes(dictFile, timeValue)
218  : findTimeIndex(times_, timeValue)
219  );
220 
221 
222  // Update stored times list and geometry index
223 
224  if (timeIndex < geoms_.size()-1)
225  {
226  // Clear old content when shrinking
227  geoms_.unset(timeIndex);
228  }
229 
230  // Extend or truncate list
231  geoms_.resize(timeIndex+1);
232  times_.resize(timeIndex+1, VGREAT);
233 
234  if (!equalTimes(times_[timeIndex], timeValue))
235  {
236  stateChanged = true;
237  times_[timeIndex] = timeValue;
238  }
239 
240  if (geomChanged)
241  {
242  stateChanged = true;
243  geoms_.set(timeIndex);
244  }
245 
246  // Update time/geometry information in dictionary
247 
248  // Note: to avoid inadvertent loss of precision,
249  // generate output tokens for the list of times directly
250  {
251  // Same as: cache_.set("times", times_);
252  OTstream os;
253  os << times_;
254 
255  tokenList toks(std::move(os.tokens()));
256  cache_.set(new primitiveEntry("times", std::move(toks)));
257  }
258  cache_.set("geometry", geoms_.sortedToc());
259 
260  // Add field information to dictionary
261  dictionary& dict = fieldDict(fieldName);
262 
263  if (dict.empty())
264  {
265  stateChanged = true;
266 
267  dict.set("type", fieldType);
268  if (!varName.empty() && varName != fieldName)
269  {
270  // Use variable name, if it differs from fieldName
271  dict.set("name", varName);
272  }
273  }
274 
275  if (stateChanged)
276  {
277  OFstream os(dictFile);
278  os.precision(16); // increased precision to avoid rounding
279  os << "// State file for writer output" << nl << nl;
280  cache_.write(os, false);
281 
282  os << nl << "// End" << nl;
283  }
284 
285  return stateChanged;
286 }
287 
288 
289 // ************************************************************************* //
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
dictionary dict
label findLower(const ListType &input, const T &val, const label start, const ComparePredicate &comp)
Binary search to find the index of the last element in a sorted list that is less than value...
bool update(const fileName &baseDir, const scalar timeValue, const bool geomChanged, const word &fieldName, const word &fieldType, const word &varName=word::null)
Update time/geometry information and file cache. This routine should only be called from the master p...
A class for handling file names.
Definition: fileName.H:72
static const equalOp< scalar > equalTimes(ROOTSMALL)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:489
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
const dictionary & fieldsDict() const
Get or create the &#39;fields&#39; information dictionary.
List< token > tokenList
List of token, used for dictionary primitive entry (for example)
Definition: tokenList.H:32
dictionary & subDictOrAdd(const word &keyword, enum keyType::option matchOpt=keyType::REGEX)
Find and return a sub-dictionary for manipulation.
Definition: dictionary.C:481
Various functions to operate on Lists.
bool remove(const word &keyword)
Remove an entry specified by keyword.
static label findTimeIndex(const UList< scalar > &list, const scalar val)
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
A class for handling words, derived from Foam::string.
Definition: word.H:63
static const dictionary null
An empty dictionary, which is also the parent for all dictionaries.
Definition: dictionary.H:474
String literal.
Definition: keyType.H:82
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
OBJstream os(runTime.globalPath()/outputName)
int geometryTimeset() const
Expected timeset for the geometry.
label latestGeomIndex() const
The most current geometry index.
List< label > labelList
A List of labels.
Definition: List.H:62
writerCaching(const word &cacheFileName)
Construct with specified cache name.
label latestTimeIndex() const
The most current time index.
Namespace for OpenFOAM.
label timeIndex
Definition: getTimeIndex.H:24
const dictionary * findDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary pointer if present (and a sub-dictionary) otherwise return nullptr...
Definition: dictionaryI.H:124