ccmReader.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 "ccmReader.H"
29#include "IFstream.H"
30#include "IOdictionary.H"
31
32#include "ccmInternal.H" // include last to avoid any strange interactions
33
34// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35
36// The cellTable integer options
37const char* Foam::ccm::reader::cellTableOpti[] =
38{
39 "MaterialId", "PorosityId", "SpinId", "GroupId", "ColorIdx", nullptr
40};
41
42// The cellTable string options - "Label" handled separately
43const char* Foam::ccm::reader::cellTableOptstr[] =
44{
45 "MaterialType", nullptr
46};
47
48// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49
50// Simulate GetEntityIndex
51// CCMIOGetEntityIndex(nullptr, nodeId, &internalId);
52int Foam::ccm::reader::ccmGetEntityIndex(ccmNODE node)
53{
54 int intval = 0;
55 char name[kCCMIOMaxStringLength + 1];
56
57 if
58 (
59 CCMIOGetName
60 (
61 nullptr,
62 node,
63 name
64 )
65 == kCCMIONoErr
66 )
67 {
68 char const *pos = strrchr(name, '-');
69
70 if (!pos)
71 {
72 intval = 0;
73 }
74 else
75 {
76 // Negative ID number
77 if (pos != name && (*(pos - 1) == '-'))
78 --pos;
79
80 intval = atoi(++pos);
81 }
82 }
83
84 return intval;
85}
86
87
88std::string Foam::ccm::reader::ccmReadNodestr
89(
90 const char* opt,
91 ccmNODE node
92)
93{
94 char *strval = 0;
95 std::string str;
96
97 if
98 (
99 CCMIOReadNodestr
100 (
101 nullptr,
102 node,
103 opt,
104 &strval
105 )
106 == kCCMIONoErr
107 && strval
108 )
109 {
110 str = strval;
111 }
112
113 // Allocated by CCMIOReadNodestr
114 if (strval)
115 {
116 free(strval);
117 }
118
119 return str;
120}
121
122
123std::string Foam::ccm::reader::ccmReadOptstr
124(
125 const char* opt,
126 ccmID node
127)
128{
129 std::string str;
130 int len = 0;
131
132 if
133 (
134 CCMIOReadOptstr
135 (
136 nullptr,
137 node,
138 opt,
139 &len,
140 nullptr
141 )
142 == kCCMIONoErr
143 && len
144 )
145 {
146 char* strval = new char[len + 1];
147 if
148 (
149 CCMIOReadOptstr
150 (
151 nullptr,
152 node,
153 opt,
154 &len,
155 strval
156 )
157 == kCCMIONoErr
158 )
159 {
160 strval[len] = '\0';
161 str = strval;
162 }
163 delete[] strval;
164 }
165
166 return str;
167}
168
169
170// Read map data and check error
171void Foam::ccm::reader::readMap
172(
173 const ccmID& mapId,
174 labelList& data
175)
176{
177 if (globalState_->hasError())
178 {
179 return;
180 }
181
182 CCMIOReadMap
183 (
184 &(globalState_->error),
185 mapId,
186 data.data(),
187 kCCMIOStart,
188 kCCMIOEnd
189 );
190 assertNoError("error reading map");
191}
192
193
194// readProblemDescription:
195// - get cellTable and boundaryRegion information
196// - some regions defined here may be unused by our mesh
197void Foam::ccm::reader::readProblemDescription
198(
199 const ccmID& probNode
200)
201{
202 readInterfaceDefinitions();
203 readProblemDescription_boundaryRegion(probNode);
204 readProblemDescription_cellTable(probNode);
205
206#ifdef DEBUG_CCMIOREAD
207 Info<< "InterfaceDefinitions: " << interfaceDefinitions_ << nl
208 << "cellTable" << cellTable_ << nl
209 << "boundaryRegion" << boundaryRegion_ << endl;
210#endif
211}
212
213
214// readInterfaceDefinitions:
215// - get /InterfaceDefinitions.
216// used by STARCCM to define in-place interfaces, etc
217// - only handle in-place one here
218void Foam::ccm::reader::readInterfaceDefinitions()
219{
220 interfaceDefinitions_.clear();
221
222 // /InterfaceDefinitions
223 // ---------------------
224
225 CCMIONode rootNode;
226 CCMIONode interfaceDefNode;
227
228 // CCMIOID -> CCMIONODE
229 if
230 (
231 CCMIOGetEntityNode
232 (
233 nullptr,
234 (globalState_->root),
235 &rootNode
236 )
237 == kCCMIONoErr
238
239 // Get "/InterfaceDefinitions"
240 &&
241 CCMIOGetNode
242 (
243 nullptr,
244 rootNode,
245 "InterfaceDefinitions",
246 &interfaceDefNode
247 )
248 == kCCMIONoErr
249 )
250 {
251 CCMIONode interfaceNode;
252
253 // Simulate CCMIONextEntity
254 for
255 (
256 int index = 0;
257 CCMIOGetNextChildWithLabel
258 (
259 nullptr,
260 interfaceDefNode,
261 "Interface",
262 &index,
263 &interfaceNode
264 ) == kCCMIONoErr;
265 /* nop */
266 )
267 {
268 interfaceEntry ifentry(ccmGetEntityIndex(interfaceNode));
269
270 if
271 (
272 CCMIOReadNodei
273 (
274 nullptr,
275 interfaceNode,
276 "Boundary0",
277 &(ifentry.bnd0)
278 )
279 == kCCMIONoErr
280
281 && CCMIOReadNodei
282 (
283 nullptr,
284 interfaceNode,
285 "Boundary1",
286 &(ifentry.bnd1)
287 )
288 == kCCMIONoErr
289
290 // only handle 'IN_PLACE' interfaces
292 (
293 ccmReadNodestr("Configuration", interfaceNode)
294 )
295 )
296 {
297 interfaceDefinitions_.add(ifentry);
298 }
299 }
300 }
301}
302
303
304// readProblemDescription - get boundaryRegion information
305//
306// CCM Node: /ProblemDescriptions/ProblemDescription-N/BoundaryRegion-N
307//
308// Requires InterfaceDefinitions first
309void Foam::ccm::reader::readProblemDescription_boundaryRegion
310(
311 const ccmID& probNode
312)
313{
314 if (option().useNumberedNames())
315 {
316 Info<< "using numbered patch/zone names" << endl;
317 }
318
319 boundaryRegion_.clear();
320
321 ccmID node;
322
323 // boundaryRegion information
324 // --------------------------
325 for
326 (
327 int nodeI = 0;
328 CCMIONextEntity
329 (
330 nullptr,
331 probNode,
332 kCCMIOBoundaryRegion,
333 &nodeI,
334 &node
335 ) == kCCMIONoErr;
336 /* nop */
337 )
338 {
339 // Read boundaryRegionId
340 int Id = 0;
341 CCMIOGetEntityIndex
342 (
343 &(globalState_->error),
344 node,
345 &Id
346 );
347 assertNoError("error reading boundaryRegion index");
348
349 dictionary dict;
350
351 // Read boundary type
352 // (inlet|outlet|symmetry|wall|
353 // cyclic|stagnation|pressure|baffle|freestream)
354 {
355 const char* opt = "BoundaryType";
356 std::string str = ccmReadOptstr(opt, node);
357
358 if (str.empty())
359 {
360 dict.add(opt, "empty");
361 }
362 else if (str == "internal")
363 {
364 // Old PROSTAR bug: "monitoring" mislabeled as "internal"
365 dict.add(opt, "monitoring");
366 }
367 else
368 {
369 dict.add(opt, word::validate(str, true));
370 }
371 }
372
373
374 // Read boundary name:
375 // - from 'Label' field (STARCCM+)
376 // - from 'BoundaryName' field (PROSTAR and/or STARCCM+)
377 // - fallback: generate one from boundary type and boundaryRegionId
378 {
379 const char* opt = "Label";
380 std::string str;
381
382 if (option().useNumberedNames())
383 {
384 str = "patch_" + ::Foam::name(Id);
385 }
386 else if
387 (
388 option().renameInterfaces()
389 && interfaceDefinitions_.isInterface(Id)
390 )
391 {
392#ifdef DEBUG_CCMIOREAD
393 Info<< "boundary is on an interface: remap name for "
394 << Id << endl;
395#endif
396 // Substitute immediately with interface name
397 str = interfaceDefinitions_.interfaceName(Id);
398 }
399 else if
400 (
401 (str = ccmReadOptstr(opt, node)).empty()
402 && (str = ccmReadOptstr("BoundaryName", node)).empty()
403 )
404 {
405 // Fallback
406 str = dict.get<word>("BoundaryType") + "_" + ::Foam::name(Id);
407 }
408
409 if (!str.empty())
410 {
411 dict.add(opt, word::validate(str, true));
412 }
413 }
414
415 boundaryRegion_.insert(Id, dict);
416 }
417}
418
419
420// readProblemDescription - get cellTable information
421//
422// CCM Node: /ProblemDescriptions/ProblemDescription-N/CellType-N
423//
424void Foam::ccm::reader::readProblemDescription_cellTable
425(
426 const ccmID& probNode
427)
428{
429 cellTable_.clear();
430
431 ccmID node;
432
433 // cellTable information
434 // ---------------------
435 for
436 (
437 int nodeI = 0;
438 CCMIONextEntity
439 (
440 nullptr,
441 probNode,
442 kCCMIOCellType,
443 &nodeI,
444 &node
445 ) == kCCMIONoErr;
446 /* nop */
447 )
448 {
449 // Read cellTableId (CellType)
450 int Id = 0;
451 CCMIOGetEntityIndex
452 (
453 &(globalState_->error),
454 node,
455 &Id
456 );
457 assertNoError("error reading cellTable index");
458
459 dictionary dict;
460
461 // Special treatment for "Label"
462 {
463 const char* opt = "Label";
464 std::string str;
465
466 if (!option().useNumberedNames())
467 {
468 str = ccmReadOptstr(opt, node);
469 }
470
471 if (str.empty())
472 {
473 str = "zone_" + ::Foam::name(Id);
474 }
475
476 dict.add(opt, word::validate(str, true));
477 }
478
479
480 // Other string options
481 for (int i=0; cellTableOptstr[i]; ++i)
482 {
483 const char* opt = cellTableOptstr[i];
484 std::string str = ccmReadOptstr(opt, node);
485
486 if (!str.empty())
487 {
488 dict.add(opt, word::validate(str, true));
489 }
490 }
491
492 // Add non-zero integer options
493 for (int i=0; cellTableOpti[i]; ++i)
494 {
495 const char* opt = cellTableOpti[i];
496 int intval;
497
498 if
499 (
500 CCMIOReadOpti
501 (
502 nullptr,
503 node,
504 opt,
505 &intval
506 )
507 == kCCMIONoErr
508 && intval != 0
509 )
510 {
511 dict.add(opt, intval);
512 }
513 }
514
515 cellTable_.insert(Id, dict);
516 }
517}
518
519
520// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
521
523{
524 Info<< "Mesh Information" << nl
525 << "----------------" << nl
526 << "boundingBox: " << boundBox(points_) << nl
527 << "nPoints: " << nPoints_ << nl
528 << "nCells: " << nCells_ << nl
529 << "nFaces: " << nFaces_ << nl
530 << "nInternalFaces: " << nInternalFaces_ << nl
531 << "nBaffles: " << bafInterfaces_.size() << endl;
532}
533
534
536(
537 const scalar scaleFactor
538)
539{
540 detectGeometry();
541
542 if (geometryStatus_ == OKAY)
543 {
544 // Sanity on the scaling factor
545
546 readMeshTopology(scaleFactor <= VSMALL ? 1 : scaleFactor);
547 reorderMesh();
548
549 // assume success if we have points and cells
550 if (nCells_ && points_.size())
551 {
552 geometryStatus_ = READ;
553 }
554 else
555 {
556 geometryStatus_ = BAD;
557 }
558 }
559
560 return (geometryStatus_ == OKAY || geometryStatus_ == READ);
561}
562
563
565{
566 detectGeometry();
567 return (geometryStatus_ == OKAY || geometryStatus_ == READ);
568}
569
570
572{
573 detectSolution();
574 return (solutionStatus_ == OKAY || solutionStatus_ == READ);
575}
576
577
579(
580 const polyMesh& mesh,
581 IOstreamOption streamOpt
582) const
583{
584 mesh.removeFiles();
585
586 Info<< "Writing polyMesh" << endl;
587 mesh.writeObject(streamOpt, true);
588 writeAux(mesh);
589}
590
591
593(
594 const objectRegistry& registry,
595 const fileName& remappingDictName
596)
597{
598 dictionary remapDict;
599
600 if (remappingDictName.empty())
601 {
602 remapDict = IOdictionary
603 (
605 (
606 "remapping",
607 "constant",
608 registry,
611 false
612 )
613 );
614 }
615 else
616 {
617 // Specified (absolute) name: treat like MUST_READ
618 remapDict = dictionary(IFstream(remappingDictName)());
619 }
620
621 bool ok = false;
622
623 if (remapDict.empty())
624 {
625 return false;
626 }
627
628
629 // Merge specified cellTable entries together
630 if (remapDict.isDict("cellTable"))
631 {
632 cellTable_.combine(remapDict.subDict("cellTable"), cellTableId_);
633 ok = true;
634 }
635
636 // Rename boundaries
637 if (remapDict.isDict("boundaryRegion"))
638 {
639 boundaryRegion_.rename(remapDict.subDict("boundaryRegion"));
640 ok = true;
641 }
642
643 return ok;
644}
645
646
647// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
648
649// Construct from reading a file
651:
652 base(),
653 options_(new options(opts)),
654 geometryStatus_(UNKNOWN),
655 solutionStatus_(UNKNOWN),
656 interfaceDefinitions_(),
657 boundaryRegion_(),
658 cellTable_(),
659 nPoints_(0),
660 nInternalFaces_(0),
661 nFaces_(0),
662 nCells_(0),
663 points_(),
664 faces_(),
665 faceOwner_(),
666 faceNeighbour_(),
667 bafInterfaces_(),
668 domInterfaces_(),
669 origFaceId_(),
670 origCellId_(),
671 cellTableId_(),
672 origBndId_(),
673 patchSizes_(),
674 solutionTable_(),
675 fieldTable_(),
676 lagrangianTable_()
677{
678 if (!option().keptSomeRegion())
679 {
681 << "must retain at least one region type: fluid | porous | solid"
682 << exit(FatalError);
683 }
684
685 if (!isFile(file, false))
686 {
688 << "Cannot read file " << file
689 << exit(FatalError);
690 }
691
692 // Reinitialize error state from the return value
693 globalState_->error = CCMIOOpenFile
694 (
695 nullptr,
696 file.c_str(),
697 kCCMIORead,
698 &(globalState_->root)
699 );
700 assertNoError("Error opening file for reading");
701
702 detectGeometry();
703 detectSolution();
704}
705
706
707// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
708
710{
711 close();
712}
713
714
715// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
716
718{
719 return *options_;
720}
721
722
723// ************************************************************************* //
Internal bits for wrapping libccmio - do not use directly.
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
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
The IOstreamOption is a simple container for options an IOstream can normally have.
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:64
Base functionality common to reader and writer classes.
Definition: ccmBase.H:63
std::unique_ptr< ccmGlobalState > globalState_
Maintain overall global states (error, root-node)
Definition: ccmBase.H:69
static bool assertNoError(int err, const char *msg)
Die with msg if there is an error.
Definition: ccmBase.C:35
static bool isInPlace(const std::string &configurationType)
Check for in-place interfaces.
Reads CCM files as written by PROSTAR/STARCCM.
Definition: ccmReader.H:187
bool remapMeshInfo(const objectRegistry &registry, const fileName &remappingDictName=fileName::null)
Remap cellTable and boundaryRegion according to dictionary.
Definition: ccmReader.C:593
~reader()
Destructor (closes file)
Definition: ccmReader.C:709
bool hasSolution()
Return true if file has solutions associated with it.
Definition: ccmReader.C:571
const reader::options & option() const
Reference to the reader options.
Definition: ccmReader.C:717
bool hasGeometry()
Return true if file has geometry associated with it.
Definition: ccmReader.C:564
bool readGeometry(const scalar scaleFactor=1.0)
Detect and read geometry if possible.
Definition: ccmReader.C:536
void printInfo() const
Print general information about the mesh.
Definition: ccmReader.C:522
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 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
void writeMesh() const
Write equivalent mesh information at the polyMesh faceInstances time.
A class for handling file names.
Definition: fileName.H:76
virtual void validate()
Validate the turbulence fields after construction.
Definition: kkLOmega.C:597
Registry of regIOobjects.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
dimensionedScalar pos(const dimensionedScalar &ds)
List< label > labelList
A List of labels.
Definition: List.H:66
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
bool isFile(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist as a FILE in the file system?
Definition: MSwindows.C:666
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
dictionary dict