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