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