ccmReaderSolution.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-2021 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 "ccmReader.H"
29 #include "ccmInternal.H" // include last to avoid any strange interactions
30 
31 
32 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
33 
34 // Get information about available fields.
35 // - assume that all fields are available for all solution intervals
36 // eg,
37 // /FieldSets/FieldSet-1/Phase-1/Fields/Velocity
38 // /FieldSets/FieldSet-1/Phase-1/Fields/Pressure
39 // ...
40 void Foam::ccm::reader::determineFieldInfo
41 (
42  const ccmID& fieldSetNode,
43  fieldTable& table
44 )
45 {
46  char fullName[kCCMIOMaxStringLength + 1];
47  char shortName[kCCMIOProstarShortNameLength+1];
48 
49  // Loop through all phases
50  ccmID phaseNode;
51  int phaseI = 0;
52 
53  while
54  (
55  CCMIONextEntity
56  (
57  nullptr,
58  fieldSetNode,
59  kCCMIOFieldPhase,
60  &phaseI,
61  &phaseNode
62  )
63  == kCCMIONoErr
64  )
65  {
66  CCMIODimensionality dims;
67 
68  // Examine each field in this fieldSet
69  ccmID fieldNode;
70  int fieldI = 0;
71 
72  // Get full/short names and dimension (scalar/vector/tensor).
73  // Use short name as unique identifier.
74 
75  while
76  (
77  CCMIONextEntity
78  (
79  nullptr,
80  phaseNode,
81  kCCMIOField,
82  &fieldI,
83  &fieldNode
84  )
85  == kCCMIONoErr
86 
87  && CCMIOReadField
88  (
89  nullptr,
90  fieldNode,
91  fullName,
92  shortName,
93  &dims,
94  nullptr
95  )
96  == kCCMIONoErr
97  )
98  {
99  // The shortName *should* be a word, but some fields seem
100  // to have blanks!
101  {
102  char *ptr = shortName;
103  while (*ptr)
104  {
105  if (!word::valid(*ptr))
106  {
107  *ptr = '_';
108  }
109  ptr++;
110  }
111  }
112 
113  word fieldName(shortName);
114 
115  if (dims == kCCMIOScalar)
116  {
117  auto tableIter = table.find(fieldName);
118 
119  if (!tableIter.good())
120  {
121  // Add to table as required
122  fieldEntry entry(fieldName, fullName);
123 
124  entry.units
125  (
126  ccmReadOptstr("Units", fieldNode)
127  );
128 
129  table.push_back(entry);
130 
131  tableIter = table.find(fieldName);
132  }
133  fieldEntry& entry = *tableIter;
134 
135  // Obtain sizes of data field
136  // - only process cell/face data
137  ccmID dataNode;
138  int dataI = 0;
139 
140  CCMIODataLocation dataLocation;
141  CCMIOIndex maxId;
142 
143  while
144  (
145  CCMIONextEntity
146  (
147  nullptr,
148  fieldNode,
149  kCCMIOFieldData,
150  &dataI,
151  &dataNode
152  )
153  == kCCMIONoErr
154 
155  && CCMIOEntitySize
156  (
157  nullptr,
158  dataNode,
159  nullptr,
160  &maxId
161  )
162  == kCCMIONoErr
163 
164  && CCMIOReadFieldDatad
165  (
166  nullptr,
167  dataNode,
168  nullptr,
169  &dataLocation,
170  nullptr,
171  kCCMIOStart,
172  kCCMIOEnd
173  )
174  == kCCMIONoErr
175  )
176  {
177  if (dataLocation == kCCMIOCell)
178  {
179  entry.maxCellId(maxId);
180  }
181  else if (dataLocation == kCCMIOFace)
182  {
183  entry.maxFaceId(maxId);
184  }
185  }
186  }
187  }
188  }
189 }
190 
191 
192 // Get information about all available solutions.
193 // - it is sufficient to examine the first processor
194 //
195 // The "States":
196 // Restart_1/Processor-1
197 // -OR-
198 // Transient_1/Processor-1
199 // ...
200 // Transient_N/Processor-1
201 //
202 // point to the "FieldSets":
203 // FieldSet-1/RestartInfo
204 //
205 bool Foam::ccm::reader::detectSolution()
206 {
207  // call once
208  if (solutionStatus_ != UNKNOWN)
209  {
210  return (solutionStatus_ == OKAY || solutionStatus_ == READ);
211  }
212 
213  // loop through all States
214  ccmID stateNode;
215  int stateI = 0;
216  while
217  (
218  CCMIONextEntity
219  (
220  nullptr,
221  (globalState_->root),
222  kCCMIOState,
223  &stateI,
224  &stateNode
225  )
226  == kCCMIONoErr
227  )
228  {
229  // Loop through all processors/solutions
230  ccmID processorNode;
231  ccmID solutionNode;
232  int procI = 0;
233 
234  while
235  (
236  CCMIONextEntity
237  (
238  nullptr,
239  stateNode,
240  kCCMIOProcessor,
241  &procI,
242  &processorNode
243  )
244  == kCCMIONoErr
245 
246  && CCMIOReadProcessor
247  (
248  nullptr,
249  processorNode,
250  nullptr, // Ignore verticesNode
251  nullptr, // Ignore topologyNode
252  nullptr, // Ignore initialField
253  &solutionNode
254  )
255  == kCCMIONoErr
256  )
257  {
258  // Restrict to solutions with RestartInfo on the first cpu
259  // (there is normally only one set of restart data)
260  ccmID restartNode;
261  int restartI = 0;
262 
263  char solutionName[kCCMIOMaxStringLength + 1];
264  int iteration = 0;
265  float timeValue = 0;
266 
267  if
268  (
269  CCMIONextEntity
270  (
271  nullptr,
272  solutionNode,
273  kCCMIORestart,
274  &restartI,
275  &restartNode
276  )
277  == kCCMIONoErr
278 
279  && CCMIOEntityName
280  (
281  nullptr,
282  stateNode,
283  solutionName
284  )
285  == kCCMIONoErr
286 
287  && CCMIOReadRestartInfo
288  (
289  nullptr,
290  restartNode,
291  nullptr, // Ignore solverName
292  &iteration,
293  &timeValue,
294  nullptr, // Ignore timeUnits
295  nullptr // Ignore startAngle
296  )
297  == kCCMIONoErr
298  )
299  {
300  solutionTable_.append
301  (
302  solutionEntry(solutionName, iteration, timeValue)
303  );
304  }
305 
306  // Determine field information
307  determineFieldInfo(solutionNode, fieldTable_);
308 
309  // check Lagrangian data
310  ccmID lagrangianNode;
311  ccmID lagrangianSolutions;
312  int lagrangianI = 0;
313 
314  if
315  (
316  CCMIONextEntity
317  (
318  nullptr,
319  processorNode,
320  kCCMIOLagrangianData,
321  &lagrangianI,
322  &lagrangianNode
323  )
324  == kCCMIONoErr
325 
326  && CCMIOReadLagrangianData
327  (
328  nullptr,
329  lagrangianNode,
330  nullptr,
331  &lagrangianSolutions
332  )
333  == kCCMIONoErr
334  )
335  {
336  determineFieldInfo(lagrangianSolutions, lagrangianTable_);
337  }
338  }
339  }
340 
341  if (solutionTable_.size() && fieldTable_.size())
342  {
343  solutionStatus_ = OKAY;
344  }
345  else
346  {
347  solutionStatus_ = BAD;
348  }
349 
350  return (solutionStatus_ == OKAY || solutionStatus_ == READ);
351 }
352 
353 #define SOLID_STRESS_HACK
354 
355 //
356 // Read solution and field combination
357 //
360 (
361  const word& solutionName,
362  const word& fieldName,
363  const bool wallData
364 )
365 {
366  // get State by name
367  ccmID stateNode;
368  ccmID solutionNode;
369 
370  if
371  (
372  CCMIOGetState
373  (
374  nullptr,
375  (globalState_->root),
376  solutionName.c_str(),
377  nullptr,
378  &stateNode
379  )
380  != kCCMIONoErr
381  )
382  {
383  return tmp<scalarField>::New();
384  }
385 
386  label maxId = 0;
387  CCMIODataLocation requestedLocation = kCCMIOCell;
388 
389  const auto tableIter = fieldTable_.find(fieldName);
390 
391  if (tableIter.good())
392  {
393  const fieldEntry& entry = *tableIter;
394 
395  maxId = entry.maxCellId();
396 
397  if (wallData)
398  {
399  maxId = entry.maxFaceId();
400  requestedLocation = kCCMIOFace;
401  }
402  }
403 
404  // Can skip empty/unknown fields immediately
405  if (!maxId)
406  {
407  return tmp<scalarField>::New();
408  }
409 
410  char shortName[kCCMIOProstarShortNameLength+1];
411 
412  List<label> mapData;
413  List<scalar> rawData;
414 
415  auto tscalarData = tmp<scalarField>::New(maxId + 1, option().undefScalar());
416  auto& scalarData = tscalarData.ref();
417 
418 
419  CCMIODimensionality dims;
420 
421  // Loop across all processors
422  ccmID processorNode;
423  int procI = 0;
424 
425  while
426  (
427  CCMIONextEntity
428  (
429  nullptr,
430  stateNode,
431  kCCMIOProcessor,
432  &procI,
433  &processorNode
434  )
435  == kCCMIONoErr
436 
437  && CCMIOReadProcessor
438  (
439  nullptr,
440  processorNode,
441  nullptr, // Ignore verticesNode
442  nullptr, // Ignore topologyNode
443  nullptr, // Ignore initialField
444  &solutionNode
445  )
446  == kCCMIONoErr
447  )
448  {
449  // loop through all phases
450  int phaseI = 0;
451  ccmID phaseNode;
452 
453  while
454  (
455  CCMIONextEntity
456  (
457  nullptr,
458  solutionNode,
459  kCCMIOFieldPhase,
460  &phaseI,
461  &phaseNode
462  )
463  == kCCMIONoErr
464  )
465  {
466  // Get Field that matches the name
467  ccmID fieldNode;
468  int fieldI = 0;
469 
470  while
471  (
472  CCMIONextEntity
473  (
474  nullptr,
475  phaseNode,
476  kCCMIOField,
477  &fieldI,
478  &fieldNode
479  )
480  == kCCMIONoErr
481  )
482  {
483  // Get full/short names and dimension (scalar/vector/tensor)
484  // use short name as unique identifier
485  CCMIOReadField
486  (
487  &(globalState_->error),
488  fieldNode,
489  nullptr,
490  shortName,
491  &dims,
492  nullptr
493  );
494  assertNoError
495  (
496  "reading post data field: "
497  + string(shortName)
498  );
499 
500  if (fieldName == shortName && dims == kCCMIOScalar)
501  {
502  // Obtain sizes of data field
503  ccmID dataNode;
504  ccmID mapId;
505  int dataI = 0;
506  while
507  (
508  CCMIONextEntity
509  (
510  nullptr,
511  fieldNode,
512  kCCMIOFieldData,
513  &dataI,
514  &dataNode
515  )
516  == kCCMIONoErr
517  )
518  {
519  CCMIODataLocation dataLocation;
520  CCMIOSize n;
521 
522  // Only process cell/face data
523  if
524  (
525  CCMIOEntitySize
526  (
527  nullptr,
528  dataNode,
529  &n,
530  nullptr
531  )
532  == kCCMIONoErr
533 
534  && CCMIOReadFieldDatad
535  (
536  nullptr,
537  dataNode,
538  &mapId,
539  &dataLocation,
540  nullptr,
541  kCCMIOStart,
542  kCCMIOEnd
543  )
544  == kCCMIONoErr
545 
546  && dataLocation == requestedLocation
547  )
548  {
549 #ifdef SOLID_STRESS_HACK
550  bool okayCombination = true;
551 
552  CCMIOSize len;
553  if
554  (
555  CCMIOEntityDescription
556  (
557  nullptr,
558  dataNode,
559  &len,
560  nullptr
561  )
562  == kCCMIONoErr
563  )
564  {
565  char* dataLabel = new char[len + 1];
566 
567  if
568  (
569  CCMIOEntityDescription
570  (
571  nullptr,
572  dataNode,
573  &len,
574  dataLabel
575  )
576  == kCCMIONoErr
577  )
578  {
579  if
580  (
581  (
582  strstr(fieldName.c_str(), "SIG")
583  || strstr(fieldName.c_str(), "EPS")
584  )
585  && strstr(dataLabel, "So") == nullptr
586  )
587  {
588  okayCombination = false;
589  // skip non-solid
590  }
591  }
592 
593  delete[] dataLabel;
594  }
595 
596  if (!okayCombination)
597  {
598  continue;
599  }
600 #endif
601 
602  mapData.setSize(n);
603  rawData.setSize(n);
604 
605  readMap
606  (
607  mapId,
608  mapData
609  );
610 
611  CCMIOReadFieldDatad
612  (
613  &(globalState_->error),
614  dataNode,
615  nullptr,
616  nullptr,
617  rawData.data(),
618  kCCMIOStart,
619  kCCMIOEnd
620  );
621  assertNoError
622  (
623  "reading post data field: "
624  + string(shortName)
625  );
626 
627  // transcribe to output list
628  forAll(mapData, i)
629  {
630  const label cellId = mapData[i];
631  scalarData[cellId] = rawData[i];
632  }
633  }
634  }
635  }
636  }
637  }
638  }
639 
640  // Overwrite possible junk in cell 0 (often used as /dev/null)
641  scalarData[0] = option().undefScalar();
642 
643  return tscalarData;
644 }
645 
646 
647 // ************************************************************************* //
T * data() noexcept
Return pointer to the underlying array serving as data storage.
Definition: UListI.H:265
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
void setSize(const label n)
Alias for resize()
Definition: List.H:325
A class for handling words, derived from Foam::string.
Definition: word.H:63
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
static bool valid(char c)
Is this character valid for a word?
Definition: wordI.H:52
Internal bits for wrapping libccmio - do not use directly.
FOAM_DLL_EXPORT tmp< scalarField > readField(const word &solutionName, const word &fieldName, const bool wallData=false)
Read solution and field combination.
A ccm field entry with short name, name, maxId and type.
label cellId
label n
A class for managing temporary objects.
Definition: HashPtrTable.H:50
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:63