ccmWriterSolution.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-2022 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 "ccmWriter.H"
29 #include "dictionary.H"
30 #include "IFstream.H"
31 #include "StringStream.H"
32 #include "volFields.H"
33 #include "surfaceFields.H"
34 #include "ccmInternal.H" // include last to avoid any strange interactions
35 
36 
37 // * * * * * * * * * * * * * * * Static Data Member * * * * * * * * * * * * //
38 
39 // names for known field types
40 Foam::dictionary Foam::ccm::writer::defaultNameMapping
41 (
42  IStringStream
43  (
44  // volScalarField
45  "p { name P; Label \"Pressure\"; units \"Pa\"; }"
46  // "?? { name PTER; Label \"Thermo. Pressure\"; units \"Pa\"; }"
47  // "yPlus { name YPLU; Label \"YPLUS\"; }"
48  // "?? { name DIST; Label \"Normal Distance\"; units \"m\"; }"
49  // "?? { name H; Label \"Enthalpy\"; units \"J/kg\"; }"
50  "rho { name DENS; Label \"Density\"; units \"kg/m3\"; }"
51  "T { name T; Label \"Temperature\"; units \"K\"; }"
52  "k { name TE; Label \"Turb Kinetic Energy\"; units \"m2/s2\"; }"
53  "epsilon { name ED; Label \"Dissipation Rate\"; units \"m2/s3\"; }"
54  "mu { name LAMV; Label \"Molecular Viscosity\"; units \"Pa s\"; }"
55  "mut { name VIS; Label \"Turbulent Viscosity\"; units \"Pa s\"; }"
56  // volVectorField
57  "U { name ALL; Label \"Velocity\"; units \"m/s\"; }"
58  // U-components:
59  "_0U { name SU; Label \"Velocity Component U\"; units \"m/s\"; }"
60  "_1U { name SV; Label \"Velocity Component V\"; units \"m/s\"; }"
61  "_2U { name SW; Label \"Velocity Component W\"; units \"m/s\"; }"
62  // surfaceScalarField
63  "phi { name MassFlux; Label \"Mass Flux\"; units \"kg/s\"; }"
64  )()
65 );
66 
67 
68 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
69 
70 bool Foam::ccm::writer::newFieldNode
71 (
72  const ccmID& phaseNode,
73  const word& fieldName,
74  const dictionary& nameMapping,
75  const ccmDimension& dims,
76  ccmID& fieldNode
77 ) const
78 {
79  const dictionary* subDictPtr = nameMapping.findDict(fieldName);
80 
81  if (!subDictPtr)
82  {
83  return false;
84  }
85 
86  const dictionary& dict = *subDictPtr;
87 
88  word shortName;
89  if (!dict.readIfPresent("name", shortName))
90  {
91  return false;
92  }
93 
94  string ccmLabel(fieldName);
95  dict.readIfPresent("Label", ccmLabel);
96 
97  CCMIONewField
98  (
99  &(globalState_->error),
100  phaseNode,
101  ccmLabel.c_str(),
102  shortName.c_str(),
103  dims(),
104  &fieldNode
105  );
106 
107 
108  string units;
109  if (dims() == kCCMIOScalar && dict.readIfPresent("units", units))
110  {
111  CCMIOWriteOptstr
112  (
113  &(globalState_->error),
114  fieldNode,
115  "Units",
116  units.c_str()
117  );
118  }
119 
120  return true;
122 }
123 
124 
125 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
126 
128 (
129  const IOobjectList& objects,
130  const fileName& remappingDictName
131 )
132 {
133  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
134 
135  if (!isA<fvMesh>(mesh_))
136  {
138  << "cannot write solutions with a polyMesh instead of a fvMesh"
139  << endl;
140  return;
141  }
142 
143  dictionary remapDict;
144 
145  if (remappingDictName.empty())
146  {
147  remapDict = IOdictionary
148  (
149  IOobject
150  (
151  "remapping",
152  mesh_.time().constant(),
153  mesh_,
157  )
158  );
159  }
160  else
161  {
162  // Specified (absolute/relative) name: treat like MUST_READ
163  remapDict = dictionary(IFstream(remappingDictName)());
164  }
165 
166 
167  dictionary nameMapping(defaultNameMapping);
168 
169  // Merge without overwrite
170  const dictionary* subDictPtr = remapDict.findDict("fields");
171 
172  if (subDictPtr)
173  {
174  nameMapping |= *subDictPtr;
175  }
176 
177 
178  ccmID stateNode, processorNode, nodeId;
179  int procI = 0;
180 
181  // Create first ("default") state node
182  CCMIONewState
183  (
184  &(globalState_->error),
185  (globalState_->root),
186  "default",
187  nullptr,
188  nullptr,
189  &stateNode
190  );
191  assertNoError("could not create default state");
192 
193  // Use first processor or create a new one
194  procI = 0;
195  if
196  (
197  CCMIONextEntity
198  (
199  nullptr,
200  stateNode,
201  kCCMIOProcessor,
202  &procI,
203  &processorNode
204  )
205  != kCCMIONoErr
206  )
207  {
208  CCMIONewEntity
209  (
210  &(globalState_->error),
211  stateNode,
212  kCCMIOProcessor,
213  nullptr,
214  &processorNode
215  );
216  assertNoError("could not create processor node");
217  }
218 
219  // Remove old data (if it exists)
220  CCMIOClearProcessor
221  (
222  nullptr, stateNode, processorNode,
223  true, // Clear vertices
224  true, // Clear topology
225  true, // Clear initial field
226  true, // Clear solution
227  true // Clear lagrangian
228  );
229 
230  //
231  // Create vertices and topology nodes
232  // and references to vertices and topology files
233  //
234  {
235  ccmID verticesNode, topoNode;
236  CCMIONewEntity
237  (
238  &(globalState_->error),
239  (globalState_->root),
240  kCCMIOVertices,
241  nullptr,
242  &verticesNode
243  );
244 
245  CCMIONewEntity
246  (
247  &(globalState_->error),
248  (globalState_->root),
249  kCCMIOTopology,
250  nullptr,
251  &topoNode
252  );
253 
254  string topoFileName = defaultMeshName + ".ccmg";
255 
256  CCMIOWriteProcessor
257  (
258  &(globalState_->error),
259  processorNode,
260  topoFileName.c_str(), &verticesNode,// verticesFile, verticesNode
261  topoFileName.c_str(), &topoNode, // topologyFile, topologyNode
262  nullptr, nullptr, // initialField unchanged
263  nullptr, nullptr // no solutionFile, solution unchanged
264  );
265  }
266  assertNoError("Error after writing geometry processor");
267 
268  CCMIONewState
269  (
270  &(globalState_->error),
271  (globalState_->root),
272  "Restart_1",
273  nullptr,
274  nullptr,
275  &stateNode
276  );
277  assertNoError("could not create Restart_1 state");
278 
279  // Use first processor or create a new one
280  procI = 0;
281  if
282  (
283  CCMIONextEntity
284  (
285  nullptr,
286  stateNode,
287  kCCMIOProcessor,
288  &procI,
289  &processorNode
290  )
291  != kCCMIONoErr
292  )
293  {
294  CCMIONewEntity
295  (
296  &(globalState_->error),
297  stateNode,
298  kCCMIOProcessor,
299  nullptr,
300  &processorNode
301  );
302  assertNoError("could not create 'Processor' node");
303  }
304 
305  // Remove old data (if it exists)
306  CCMIOClearProcessor
307  (
308  nullptr, stateNode, processorNode,
309  true, // Clear vertices
310  true, // Clear topology
311  true, // Clear initial field
312  true, // Clear solution
313  true // Clear lagrangian
314  );
315 
316  // Write out some simple solution data
317  ccmID phaseNode, fieldSetNode;
318 
319  // Use first FieldSet
320  int fieldSetI = 0;
321  if
322  (
323  CCMIONextEntity
324  (
325  nullptr,
326  (globalState_->root),
327  kCCMIOFieldSet,
328  &fieldSetI,
329  &fieldSetNode
330  )
331  != kCCMIONoErr
332  )
333  {
334  CCMIONewEntity
335  (
336  &(globalState_->error),
337  (globalState_->root),
338  kCCMIOFieldSet,
339  nullptr,
340  &fieldSetNode
341  );
342  assertNoError("could not create FieldSet node");
343  }
344 
345  // RestartInfo
346  {
347  ccmID restartInfoNode, restartDataNode;
348  CCMIONewEntity
349  (
350  &(globalState_->error),
351  fieldSetNode,
352  kCCMIORestart,
353  nullptr,
354  &restartInfoNode
355  );
356  assertNoError("could not create restartInfoNode node");
357 
358  // Get time information
359  const Time& runTime = mesh_.time();
360  label timeIndex = 0;
361  if
362  (
363  runTime.timeName() != runTime.constant()
364  && runTime.timeName() != "0"
365  )
366  {
367  IOobject io
368  (
369  "time",
370  runTime.timeName(),
371  "uniform",
372  runTime,
376  );
377 
378  if (io.typeHeaderOk<IOdictionary>(true))
379  {
380  IOdictionary(io).readEntry("index", timeIndex);
381  }
382  }
383 
384  CCMIOWriteRestartInfo
385  (
386  &(globalState_->error),
387  restartInfoNode,
388  "ccm::writer", // solverName
389  timeIndex, // iteration
390  0.0, // time
391  nullptr, // timeUnits: default (s)
392  0.0 // startAngle: non-rotating mesh
393  );
394 
395  // RestartData
396  CCMIONewEntity
397  (
398  &(globalState_->error),
399  restartInfoNode,
400  kCCMIORestartData,
401  nullptr,
402  &restartDataNode
403  );
404  assertNoError("could not create restartDataNode node");
405 
406  // Minimal information required by PROSTAR
407 
408  CCMIOWriteOptf
409  (
410  nullptr,
411  restartDataNode,
412  "SCALE",
413  0.001 // [m] -> [mm]: PROSTAR is still a bit buggy here
414  );
415 
416 
417  // Add Phase data
418  CCMIONewIndexedEntity
419  (
420  &(globalState_->error),
421  restartDataNode,
422  kCCMIOFieldPhase,
423  1,
424  nullptr,
425  &nodeId
426  );
427 
428  // HACK: for calculating Mach number
429  // FIXME: use thermodynamicProperties /or/ thermophysicalProperties
430  CCMIOWriteOptf
431  (
432  nullptr,
433  nodeId,
434  "Material Specific Heat",
435  1007
436  );
437 
438  CCMIOWriteOptf
439  (
440  nullptr,
441  nodeId,
442  "Material Molecular Weight",
443  28.96
444  );
445  }
446 
447  CCMIONewIndexedEntity
448  (
449  &(globalState_->error),
450  fieldSetNode,
451  kCCMIOFieldPhase,
452  1,
453  "Phase_0001",
454  &phaseNode
455  );
456 
457  forAllConstIters(objects, iter)
458  {
459  const IOobject& io = *iter.val();
460 
461  const word fieldName = io.name();
462  const word fieldType = io.headerClassName();
463 
464  if (!nameMapping.found(fieldName))
465  {
466  continue;
467  }
468 
469  if (fieldType == volScalarField::typeName)
470  {
471  Info<< " " << fieldName << flush;
472 
474  (
475  IOobject
476  (
477  fieldName,
478  mesh_.time().timeName(),
479  mesh_,
483  ),
484  refCast<const fvMesh>(mesh_)
485  );
486 
487  ccmID fieldNode;
488 
489  // Info<< " call newFieldNode " << fieldName << flush;
490 
491  if
492  (
493  !newFieldNode
494  (
495  phaseNode,
496  fieldName,
497  nameMapping,
498  kCCMIOScalar,
499  fieldNode
500  )
501  )
502  {
503  continue;
504  }
505 
506  // Write cellData first
507  CCMIONewEntity
508  (
509  &(globalState_->error),
510  fieldNode,
511  kCCMIOFieldData,
512  nullptr,
513  &nodeId
514  );
515 
516  CCMIOWriteFieldDatad
517  (
518  &(globalState_->error),
519  nodeId,
520  maps_->cells,
521  kCCMIOCell,
522  const_cast<scalar*>
523  (
524  field.primitiveField().begin()
525  ),
526  kCCMIOStart,
527  kCCMIOEnd
528  );
529  assertNoError("writing internalField " + fieldName);
530 
531  // Write boundaryData
532  forAll(patches, patchI)
533  {
534  CCMIONewEntity
535  (
536  &(globalState_->error),
537  fieldNode,
538  kCCMIOFieldData,
539  nullptr,
540  &nodeId
541  );
542 
543  CCMIOWriteFieldDatad
544  (
545  &(globalState_->error),
546  nodeId,
547  maps_->boundary[patchI],
548  kCCMIOFace,
549  const_cast<scalar*>
550  (
551  field.boundaryField()[patchI].begin()
552  ),
553  kCCMIOStart,
554  kCCMIOEnd
555  );
556  }
557 
558  assertNoError("writing boundaryField " + fieldName);
559  }
560  else if (fieldType == volVectorField::typeName && fieldName == "U")
561  {
562  Info<< " " << fieldName << flush;
563 
564  volVectorField vfield
565  (
566  IOobject
567  (
568  fieldName,
569  mesh_.time().timeName(),
570  mesh_,
574  ),
575  refCast<const fvMesh>(mesh_)
576  );
577 
578 
579  ccmID vectorNode;
580  newFieldNode
581  (
582  phaseNode,
583  fieldName,
584  nameMapping,
585  kCCMIOVector,
586  vectorNode
587  );
588 
589  for (direction cmpt=0; cmpt < pTraits<vector>::nComponents; ++cmpt)
590  {
591  word componentName("_" + Foam::name(cmpt) + fieldName);
592  volScalarField field(vfield.component(cmpt));
593 
594  CCMIOComponent ccmComponent = kCCMIOVectorX;
595  switch (cmpt)
596  {
597  case 0:
598  ccmComponent = kCCMIOVectorX;
599  break;
600  case 1:
601  ccmComponent = kCCMIOVectorY;
602  break;
603  case 2:
604  ccmComponent = kCCMIOVectorZ;
605  break;
606  }
607 
608  ccmID componentNode;
609  if
610  (
611  !newFieldNode
612  (
613  phaseNode,
614  componentName,
615  nameMapping,
616  kCCMIOScalar,
617  componentNode
618  )
619  )
620  {
621  continue;
622  }
623 
624  // Re-register with vector field
625  CCMIOWriteMultiDimensionalFieldData
626  (
627  &(globalState_->error),
628  vectorNode,
629  ccmComponent,
630  componentNode
631  );
632 
633  // Write cellData first
634  CCMIONewEntity
635  (
636  &(globalState_->error),
637  componentNode,
638  kCCMIOFieldData,
639  nullptr,
640  &nodeId
641  );
642 
643  CCMIOWriteFieldDatad
644  (
645  &(globalState_->error),
646  nodeId,
647  maps_->cells,
648  kCCMIOCell,
649  const_cast<scalar*>
650  (
651  field.primitiveField().begin()
652  ),
653  kCCMIOStart, kCCMIOEnd
654  );
655  assertNoError
656  (
657  "writing internalField " + fieldName + " " + componentName
658  );
659 
660 
661  // Write boundaryData
662  forAll(patches, patchI)
663  {
664  CCMIONewEntity
665  (
666  &(globalState_->error),
667  componentNode,
668  kCCMIOFieldData,
669  nullptr,
670  &nodeId
671  );
672 
673  CCMIOWriteFieldDatad
674  (
675  &(globalState_->error),
676  nodeId,
677  maps_->boundary[patchI],
678  kCCMIOFace,
679  const_cast<scalar*>
680  (
681  field.boundaryField()[patchI].begin()
682  ),
683  kCCMIOStart, kCCMIOEnd
684  );
685  }
686 
687  assertNoError
688  (
689  "writing boundaryField " + fieldName + " " + componentName
690  );
691  }
692  }
693  else if (fieldType == surfaceScalarField::typeName)
694  {
695 #if 0
696  // Still have problems reading surface fields in PROSTAR
697  Info<< " " << fieldName << flush;
698 
700  (
701  IOobject
702  (
703  fieldName,
704  mesh_.time().timeName(),
705  mesh_,
709  ),
710  refCast<const fvMesh>(mesh_)
711  );
712 
713  ccmID fieldNode;
714 
715  // Info<< " call newFieldNode " << fieldName << flush;
716 
717  if
718  (
719  !newFieldNode
720  (
721  phaseNode,
722  fieldName,
723  nameMapping,
724  kCCMIOScalar,
725  fieldNode
726  )
727  )
728  {
729  continue;
730  }
731 
732  // Write cell faceData first
733  CCMIONewEntity
734  (
735  &(globalState_->error),
736  fieldNode,
737  kCCMIOFieldData,
738  nullptr,
739  &nodeId
740  );
741 
742  CCMIOWriteFieldDatad
743  (
744  &(globalState_->error),
745  nodeId,
746  maps_->internalFaces,
747  kCCMIOFace,
748  const_cast<scalar*>
749  (
750  field.primitiveField().cdata()
751  ),
752  kCCMIOStart,
753  kCCMIOEnd
754  );
755  assertNoError("writing internalField " + fieldName);
756 
757  // Write boundaryData
758  forAll(patches, patchI)
759  {
760  CCMIONewEntity
761  (
762  &(globalState_->error),
763  fieldNode,
764  kCCMIOFieldData,
765  nullptr,
766  &nodeId
767  );
768 
769  CCMIOWriteFieldDatad
770  (
771  &(globalState_->error),
772  nodeId,
773  maps_->boundary[patchI],
774  kCCMIOFace,
775  const_cast<scalar*>
776  (
777  field.boundaryField()[patchI].cdata()
778  ),
779  kCCMIOStart,
780  kCCMIOEnd
781  );
782  }
783 
784  assertNoError("writing boundaryField " + fieldName);
785 #endif
786  }
787  }
788  Info<< endl;
789 
790  assertNoError("Error before writing processor");
791 
792  CCMIOWriteProcessor
793  (
794  &(globalState_->error),
795  processorNode,
796  nullptr, nullptr, // vertices
797  nullptr, nullptr, // topology
798  nullptr, nullptr, // initial field
799  nullptr, &fieldSetNode
800  );
801  assertNoError("Error after writing processor");
802 }
803 
804 
805 // ************************************************************************* //
Foam::surfaceFields.
dictionary dict
rDeltaTY field()
uint8_t direction
Definition: direction.H:46
A class for handling file names.
Definition: fileName.H:72
List of IOobjects with searching and retrieving facilities. Implemented as a HashTable, so the various sorted methods should be used if traversing in parallel.
Definition: IOobjectList.H:55
FOAM_DLL_EXPORT void writeSolution(const IOobjectList &objects, const fileName &remappingDictName=fileName::null)
Write the solutions.
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:130
Input/output from string buffers.
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:518
::Foam::direction nComponents(const expressions::valueTypeCode) noexcept
The number of components associated with given valueTypeCode.
Definition: exprTraits.C:40
Ignore writing from objectRegistry::writeObject()
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:76
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:400
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:72
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const auto & io
Reading is optional [identical to LAZY_READ].
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh...
Internal bits for wrapping libccmio - do not use directly.
const word typeName("volScalarField::Internal")
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:508
#define WarningInFunction
Report a warning using Foam::Warning.
const polyBoundaryMesh & patches
std::unique_ptr< ccmGlobalState > globalState_
Maintain overall global states (error, root-node)
Definition: ccmBase.H:79
messageStream Info
Information stream (stdout output on master, null elsewhere)
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:188
Do not request registration (bool: false)
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
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 it is a dictionary) otherwise return nullptr...
Definition: dictionaryI.H:124