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 -------------------------------------------------------------------------------
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 "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
37 const char* Foam::ccm::reader::cellTableOpti[] =
38 {
39  "MaterialId", "PorosityId", "SpinId", "GroupId", "ColorIdx", nullptr
40 };
41 
42 // The cellTable string options - "Label" handled separately
43 const char* Foam::ccm::reader::cellTableOptstr[] =
44 {
45  "MaterialType", nullptr
46 };
47 
48 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 
50 // Simulate GetEntityIndex
51 // CCMIOGetEntityIndex(nullptr, nodeId, &internalId);
52 int 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 
88 std::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 
123 std::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
171 void 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
197 void 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
218 void 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
309 void 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 //
424 void 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  (
604  IOobject
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
650 Foam::ccm::reader::reader(const fileName& file, const reader::options& opts)
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 // ************************************************************************* //
Foam::ccm::reader::option
const reader::options & option() const
Reference to the reader options.
Definition: ccmReader.C:717
Foam::IOobject::NO_WRITE
Definition: IOobject.H:195
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::IOdictionary
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:54
Foam::IOobject
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:169
Foam::ccm::reader::~reader
~reader()
Destructor (closes file)
Definition: ccmReader.C:709
Foam::fileName
A class for handling file names.
Definition: fileName.H:73
Foam::IFstream
Input from file stream, using an ISstream.
Definition: IFstream.H:53
Foam::ccm::base::globalState_
std::unique_ptr< ccmGlobalState > globalState_
Maintain overall global states (error, root-node)
Definition: ccmBase.H:69
Foam::word::validate
static word validate(const std::string &s, const bool prefix=false)
Construct validated word (no invalid characters).
Definition: word.C:45
Foam::isFile
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:658
Foam::ccm::reader::printInfo
void printInfo() const
Print general information about the mesh.
Definition: ccmReader.C:522
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::ccm::base::assertNoError
static bool assertNoError(int err, const char *msg)
Die with msg if there is an error.
Definition: ccmBase.C:35
Foam::ccm::reader::hasSolution
bool hasSolution()
Return true if file has solutions associated with it.
Definition: ccmReader.C:571
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
Foam::objectRegistry
Registry of regIOobjects.
Definition: objectRegistry.H:60
Foam::ccm::reader::remapMeshInfo
bool remapMeshInfo(const objectRegistry &registry, const fileName &remappingDictName=fileName::null)
Remap cellTable and boundaryRegion according to dictionary.
Definition: ccmReader.C:593
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::IOstreamOption
The IOstreamOption is a simple container for options an IOstream can normally have.
Definition: IOstreamOption.H:63
Foam::ccm::reader::readGeometry
bool readGeometry(const scalar scaleFactor=1.0)
Detect and read geometry if possible.
Definition: ccmReader.C:536
IFstream.H
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::ccm::reader::hasGeometry
bool hasGeometry()
Return true if file has geometry associated with it.
Definition: ccmReader.C:564
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
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
IOdictionary.H
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::ccm::reader::options
Definition: ccmReader.H:587
Foam::ccm::reader::writeMesh
void writeMesh(const polyMesh &mesh, IOstreamOption streamOpt=IOstreamOption(IOstreamOption::BINARY)) const
Write the polyMesh.
Definition: ccmReader.C:579
Foam::boundBox
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
Foam::name
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
Foam::ccm::interfaceEntry::isInPlace
static bool isInPlace(const std::string &configurationType)
Check for in-place interfaces.
Definition: ccmInterfaceDefinitions.H:107
ccmReader.H
Foam::ccm::base
Base functionality common to reader and writer classes.
Definition: ccmBase.H:62
Foam::pos
dimensionedScalar pos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:177