Loading...
Searching...
No Matches
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-------------------------------------------------------------------------------
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 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;
121
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 (
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 ),
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 ),
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 ),
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// ************************************************************************* //
Input/output from string buffers.
Internal bits for wrapping libccmio - do not use directly.
static const char *const typeName
Typename for Field.
Definition Field.H:93
tmp< GeometricField< cmptType, PatchField, GeoMesh > > component(const direction) const
Return a component of the field.
Input from file stream as an ISstream, normally using std::ifstream for the actual input.
Definition IFstream.H:55
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
List of IOobjects with searching and retrieving facilities. Implemented as a HashTable,...
@ NO_REGISTER
Do not request registration (bool: false).
@ READ_IF_PRESENT
Reading is optional [identical to LAZY_READ].
@ NO_WRITE
Ignore writing from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition Time.H:75
std::unique_ptr< ccmGlobalState > globalState_
Maintain overall global states (error, root-node).
Definition ccmBase.H:79
static bool assertNoError(int err, const char *msg)
Die with msg if there is an error.
Definition ccmBase.C:28
FOAM_DLL_EXPORT void writeSolution(const IOobjectList &objects, const fileName &remappingDictName=fileName::null)
Write the solutions.
static FOAM_DLL_EXPORT string defaultMeshName
The name for the topology file reference.
Definition ccmWriter.H:228
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
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...
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, IOobjectOption::readOption readOpt=IOobjectOption::MUST_READ) const
Find entry and assign to T val. FatalIOError if it is found and the number of tokens is incorrect,...
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
A class for handling file names.
Definition fileName.H:75
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
A class for handling words, derived from Foam::string.
Definition word.H:66
rDeltaTY field()
const polyBoundaryMesh & patches
engineTime & runTime
const auto & io
#define WarningInFunction
Report a warning using Foam::Warning.
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
GeometricField< vector, fvPatchField, volMesh > volVectorField
GeometricField< scalar, fvPatchField, volMesh > volScalarField
messageStream Info
Information stream (stdout output on master, null elsewhere).
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
uint8_t direction
Definition direction.H:49
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
Ostream & flush(Ostream &os)
Flush stream.
Definition Ostream.H:509
label timeIndex
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition stdFoam.H:235
Foam::surfaceFields.