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-------------------------------------------------------------------------------
10License
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
40Foam::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
70bool 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 (
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 {
364 (
365 "time",
366 runTime.timeName(),
367 "uniform",
368 runTime,
371 false
372 );
373
374 if (io.typeHeaderOk<IOdictionary>(true))
375 {
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 (
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 (
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 (
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// ************************************************************************* //
Input/output from string buffers.
Internal bits for wrapping libccmio - do not use directly.
tmp< GeometricField< cmptType, PatchField, GeoMesh > > component(const direction) const
Return a component of the field.
Input from file stream, using an ISstream.
Definition: IFstream.H:57
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:57
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:59
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:80
std::unique_ptr< ccmGlobalState > globalState_
Maintain overall global states (error, root-node)
Definition: ccmBase.H:69
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:126
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:460
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
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
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
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, bool mandatory=true) const
A class for handling file names.
Definition: fileName.H:76
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
A class for handling words, derived from Foam::string.
Definition: word.H:68
rDeltaTY field()
const polyBoundaryMesh & patches
engineTime & runTime
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
#define WarningInFunction
Report a warning using Foam::Warning.
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
uint8_t direction
Definition: direction.H:56
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:364
label timeIndex
Definition: getTimeIndex.H:30
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition: stdFoam.H:278
static const char *const typeName
The type name used in ensight case files.
Foam::surfaceFields.