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 word fieldName = (*iter()).name();
460  const word fieldType = (*iter()).headerClassName();
461 
462  if (!nameMapping.found(fieldName))
463  {
464  continue;
465  }
466 
467  if (fieldType == volScalarField::typeName)
468  {
469  Info<< " " << fieldName << flush;
470 
472  (
473  IOobject
474  (
475  fieldName,
476  mesh_.time().timeName(),
477  mesh_,
480  ),
481  refCast<const fvMesh>(mesh_)
482  );
483 
484  ccmID fieldNode;
485 
486  // Info<< " call newFieldNode " << fieldName << flush;
487 
488  if
489  (
490  !newFieldNode
491  (
492  phaseNode,
493  fieldName,
494  nameMapping,
495  kCCMIOScalar,
496  fieldNode
497  )
498  )
499  {
500  continue;
501  }
502 
503  // Write cellData first
504  CCMIONewEntity
505  (
506  &(globalState_->error),
507  fieldNode,
508  kCCMIOFieldData,
509  nullptr,
510  &nodeId
511  );
512 
513  CCMIOWriteFieldDatad
514  (
515  &(globalState_->error),
516  nodeId,
517  maps_->cells,
518  kCCMIOCell,
519  const_cast<scalar*>
520  (
521  field.primitiveField().begin()
522  ),
523  kCCMIOStart,
524  kCCMIOEnd
525  );
526  assertNoError("writing internalField " + fieldName);
527 
528  // Write boundaryData
529  forAll(patches, patchI)
530  {
531  CCMIONewEntity
532  (
533  &(globalState_->error),
534  fieldNode,
535  kCCMIOFieldData,
536  nullptr,
537  &nodeId
538  );
539 
540  CCMIOWriteFieldDatad
541  (
542  &(globalState_->error),
543  nodeId,
544  maps_->boundary[patchI],
545  kCCMIOFace,
546  const_cast<scalar*>
547  (
548  field.boundaryField()[patchI].begin()
549  ),
550  kCCMIOStart,
551  kCCMIOEnd
552  );
553  }
554 
555  assertNoError("writing boundaryField " + fieldName);
556  }
557  else if (fieldType == volVectorField::typeName && fieldName == "U")
558  {
559  Info<< " " << fieldName << flush;
560 
561  volVectorField vfield
562  (
563  IOobject
564  (
565  fieldName,
566  mesh_.time().timeName(),
567  mesh_,
570  ),
571  refCast<const fvMesh>(mesh_)
572  );
573 
574 
575  ccmID vectorNode;
576  newFieldNode
577  (
578  phaseNode,
579  fieldName,
580  nameMapping,
581  kCCMIOVector,
582  vectorNode
583  );
584 
585  for (direction cmpt=0; cmpt < pTraits<vector>::nComponents; ++cmpt)
586  {
587  word componentName("_" + Foam::name(cmpt) + fieldName);
588  volScalarField field(vfield.component(cmpt));
589 
590  CCMIOComponent ccmComponent = kCCMIOVectorX;
591  switch(cmpt) {
592  case 0:
593  ccmComponent = kCCMIOVectorX;
594  break;
595  case 1:
596  ccmComponent = kCCMIOVectorY;
597  break;
598  case 2:
599  ccmComponent = kCCMIOVectorZ;
600  break;
601  }
602 
603  ccmID componentNode;
604  if
605  (
606  !newFieldNode
607  (
608  phaseNode,
609  componentName,
610  nameMapping,
611  kCCMIOScalar,
612  componentNode
613  )
614  )
615  {
616  continue;
617  }
618 
619  // Re-register with vector field
620  CCMIOWriteMultiDimensionalFieldData
621  (
622  &(globalState_->error),
623  vectorNode,
624  ccmComponent,
625  componentNode
626  );
627 
628  // Write cellData first
629  CCMIONewEntity
630  (
631  &(globalState_->error),
632  componentNode,
633  kCCMIOFieldData,
634  nullptr,
635  &nodeId
636  );
637 
638  CCMIOWriteFieldDatad
639  (
640  &(globalState_->error),
641  nodeId,
642  maps_->cells,
643  kCCMIOCell,
644  const_cast<scalar*>
645  (
646  field.primitiveField().begin()
647  ),
648  kCCMIOStart, kCCMIOEnd
649  );
650  assertNoError
651  (
652  "writing internalField " + fieldName + " " + componentName
653  );
654 
655 
656  // Write boundaryData
657  forAll(patches, patchI)
658  {
659  CCMIONewEntity
660  (
661  &(globalState_->error),
662  componentNode,
663  kCCMIOFieldData,
664  nullptr,
665  &nodeId
666  );
667 
668  CCMIOWriteFieldDatad
669  (
670  &(globalState_->error),
671  nodeId,
672  maps_->boundary[patchI],
673  kCCMIOFace,
674  const_cast<scalar*>
675  (
676  field.boundaryField()[patchI].begin()
677  ),
678  kCCMIOStart, kCCMIOEnd
679  );
680  }
681 
682  assertNoError
683  (
684  "writing boundaryField " + fieldName + " " + componentName
685  );
686  }
687  }
688  else if (fieldType == surfaceScalarField::typeName)
689  {
690 #if 0
691  // Still have problems reading surface fields in PROSTAR
692  Info<< " " << fieldName << flush;
693 
695  (
696  IOobject
697  (
698  fieldName,
699  mesh_.time().timeName(),
700  mesh_,
703  ),
704  refCast<const fvMesh>(mesh_)
705  );
706 
707  ccmID fieldNode;
708 
709  // Info<< " call newFieldNode " << fieldName << flush;
710 
711  if
712  (
713  !newFieldNode
714  (
715  phaseNode,
716  fieldName,
717  nameMapping,
718  kCCMIOScalar,
719  fieldNode
720  )
721  )
722  {
723  continue;
724  }
725 
726  // Write cell faceData first
727  CCMIONewEntity
728  (
729  &(globalState_->error),
730  fieldNode,
731  kCCMIOFieldData,
732  nullptr,
733  &nodeId
734  );
735 
736  CCMIOWriteFieldDatad
737  (
738  &(globalState_->error),
739  nodeId,
740  maps_->internalFaces,
741  kCCMIOFace,
742  const_cast<scalar*>
743  (
744  field.primitiveField().cdata()
745  ),
746  kCCMIOStart,
747  kCCMIOEnd
748  );
749  assertNoError("writing internalField " + fieldName);
750 
751  // Write boundaryData
752  forAll(patches, patchI)
753  {
754  CCMIONewEntity
755  (
756  &(globalState_->error),
757  fieldNode,
758  kCCMIOFieldData,
759  nullptr,
760  &nodeId
761  );
762 
763  CCMIOWriteFieldDatad
764  (
765  &(globalState_->error),
766  nodeId,
767  maps_->boundary[patchI],
768  kCCMIOFace,
769  const_cast<scalar*>
770  (
771  field.boundaryField()[patchI].cdata()
772  ),
773  kCCMIOStart,
774  kCCMIOEnd
775  );
776  }
777 
778  assertNoError("writing boundaryField " + fieldName);
779 #endif
780  }
781  }
782  Info<< endl;
783 
784  assertNoError("Error before writing processor");
785 
786  CCMIOWriteProcessor
787  (
788  &(globalState_->error),
789  processorNode,
790  nullptr, nullptr, // vertices
791  nullptr, nullptr, // topology
792  nullptr, nullptr, // initial field
793  nullptr, &fieldSetNode
794  );
795  assertNoError("Error after writing processor");
796 }
797 
798 
799 // ************************************************************************* //
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
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:129
Input/output from string buffers.
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
::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:82
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:421
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:81
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
Reading is optional [identical to LAZY_READ].
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
Internal bits for wrapping libccmio - do not use directly.
const word typeName("volScalarField::Internal")
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:521
#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:67
messageStream Info
Information stream (stdout output on master, null elsewhere)
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
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 a sub-dictionary) otherwise return nullptr...
Definition: dictionaryI.H:124