ccmReaderMesh.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 
30 #include "emptyPolyPatch.H"
31 #include "symmetryPolyPatch.H"
32 #include "wallPolyPatch.H"
33 #include "Fstream.H"
34 #include "IOdictionary.H"
35 
36 #include "ccmBoundaryInfo.H"
38 #include "SortableList.H"
39 #include "mergePoints.H"
40 #include "bitSet.H"
41 #include "ListOps.H"
42 
43 #include "ccmInternal.H" // include last to avoid any strange interactions
44 
45 
46 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
47 
48 Foam::labelList Foam::ccm::reader::patchStartList(label initial) const
49 {
50  labelList startLst(patchSizes_.size(), Zero);
51 
52  label patchFaceI = initial;
53  forAll(patchSizes_, patchI)
54  {
55  startLst[patchI] = patchFaceI;
56  patchFaceI += patchSizes_[patchI];
57  }
58 
59  return startLst;
60 }
61 
62 
63 void Foam::ccm::reader::printSizes() const
64 {
65  Info<<"nPoints:" << nPoints_
66  << " nCells:" << nCells_
67  << " nFaces:" << nFaces_
68  << " nInternalFaces:" << nInternalFaces_
69  << endl;
70 }
71 
72 
73 // Determine if the geometry looks good.
74 // We'll insist that everything be on the first ("default") state,
75 // and is on the same file, and has a problem description
76 //
77 // The detection reads the problem description as well
78 //
79 bool Foam::ccm::reader::detectGeometry()
80 {
81  // Call once
82  if (geometryStatus_ != UNKNOWN)
83  {
84  return (geometryStatus_ == OKAY || geometryStatus_ == READ);
85  }
86 
87  // Explicitly restricted to 'default' state node
88  ccmID stateNode;
89 
90  // Get associated problem description
91  ccmID probNode;
92 
93  // Only check the first processor
94  ccmID processorNode;
95  int procI = 0;
96 
97  // Geometry needs vertices and topology
98  ccmID verticesNode, topoNode;
99 
100  if
101  (
102  CCMIOGetState
103  (
104  nullptr,
105  (globalState_->root),
106  "default",
107  &probNode,
108  &stateNode
109  )
110  == kCCMIONoErr
111 
112  && CCMIONextEntity
113  (
114  nullptr,
115  stateNode,
116  kCCMIOProcessor,
117  &procI,
118  &processorNode
119  )
120  == kCCMIONoErr
121 
122  && CCMIOReadProcessor
123  (
124  nullptr,
125  processorNode,
126  &verticesNode,
127  &topoNode,
128  nullptr, // Ignore initialField
129  nullptr // Ignore solutionNode
130  )
131  == kCCMIONoErr
132 
133  && CCMIOIsFromSameFile((globalState_->root), verticesNode)
134  && CCMIOIsFromSameFile((globalState_->root), topoNode)
135  && CCMIOIsValidEntity(probNode)
136  )
137  {
138  readProblemDescription(probNode);
139  geometryStatus_ = OKAY;
140  }
141  else
142  {
143  // Missing/incomplete geometry node and/or problem node
144  geometryStatus_ = BAD;
145  }
146 
147  return (geometryStatus_ == OKAY || geometryStatus_ == READ);
148 }
149 
150 
151 // read the geometry without any sorting
152 void Foam::ccm::reader::readMeshTopology
153 (
154  const scalar scaleFactor
155 )
156 {
157  ccmID verticesNode, topoNode;
158 
159  // Use first ("default") state node
160  ccmID stateNode;
161  int stateI = 0;
162 
163  // Use the first processor to find the mesh nodes
164  ccmID processorNode;
165  int procI = 0;
166 
167  if
168  (
169  CCMIONextEntity
170  (
171  nullptr,
172  (globalState_->root),
173  kCCMIOState,
174  &stateI,
175  &stateNode
176  )
177  == kCCMIONoErr
178 
179  && CCMIONextEntity
180  (
181  nullptr,
182  stateNode,
183  kCCMIOProcessor,
184  &procI,
185  &processorNode
186  )
187  == kCCMIONoErr
188 
189  && CCMIOReadProcessor
190  (
191  nullptr,
192  processorNode,
193  &verticesNode,
194  &topoNode,
195  nullptr, // Ignore initialField
196  nullptr // Ignore solutionNode
197  )
198  == kCCMIONoErr
199  )
200  {
201  labelList origPointId = readVertices(verticesNode, scaleFactor);
202  readCells(topoNode);
203  readMonitoring(topoNode);
204 
205  // Renumber vertex labels (ccm -> Foam)
206  {
207  label maxId = max(origPointId);
208  labelList mapToFoam(invert(maxId+1, origPointId));
209 
210  forAll(faces_, faceI)
211  {
212  inplaceRenumber(mapToFoam, faces_[faceI]);
213  }
214  }
215  origPointId.clear();
216 
217  // Renumber owners/neighbours cell labels (ccm -> Foam)
218  {
219  label maxId = max(origCellId_);
220  labelList mapToFoam(invert(maxId+1, origCellId_));
221 
222  inplaceRenumber(mapToFoam, faceOwner_);
223  inplaceRenumber(mapToFoam, faceNeighbour_);
224  }
225 
226  // Juggle solids into fluid as required
227  juggleSolids();
228 
229  // Report sizes
230  printSizes();
231 
232  // Remove unwanted fluid/porous/solid types
233  removeUnwanted();
234 
235  // Collapse interfaces between domains (eg, fluid|porosity)
236  cleanupInterfaces();
237 
238  // Use point merge to join conformal interfaces (STARCCM)
239  mergeInplaceInterfaces();
240  }
241 }
242 
243 
244 // readVertices:
245 // 1) read the vertex data
246 // 2) read the map (which maps the index into the data array with the Id number)
247 //
248 // returns the original point Id
249 Foam::labelList Foam::ccm::reader::readVertices
250 (
251  const ccmID& verticesNode,
252  const scalar scaleFactor
253 )
254 {
255  int dims = 1;
256  float scale = 1.0;
257 
258  CCMIOSize size = 0;
259  ccmID mapId;
260 
261 #ifdef DEBUG_CCMIOREAD
262  Info<< "readVertices()" << endl;
263 #endif
264 
265  // Determine dimensions and mapId
266  CCMIOEntitySize
267  (
268  &(globalState_->error),
269  verticesNode,
270  &size,
271  nullptr
272  );
273 
274  CCMIOReadVerticesd
275  (
276  &(globalState_->error),
277  verticesNode,
278  &dims,
279  &scale,
280  &mapId,
281  nullptr,
282  kCCMIOStart,
283  kCCMIOEnd
284  );
285  assertNoError("problem finding 'Vertices' node");
286 
287  if (dims != 3)
288  {
290  << "can only handle 3-dimensional vertices"
291  << exit(FatalError);
292  }
293 
294  nPoints_ = size;
295  labelList origPointId(nPoints_);
296 
297  readMap
298  (
299  mapId,
300  origPointId
301  );
302 
303  // Temporary storage for the points - reading piecemeal is much slower
304  List<scalar> vrts(3*nPoints_);
305 
306  // The ccm data is double precision too
307  CCMIOReadVerticesd
308  (
309  &(globalState_->error),
310  verticesNode,
311  nullptr,
312  nullptr,
313  nullptr,
314  vrts.begin(),
315  kCCMIOStart,
316  kCCMIOEnd
317  );
318  assertNoError("problem reading 'Vertices' node");
319 
320  // Convert to foam Points
321  points_.setSize(nPoints_);
322 
323  scalar effectiveScale = scale * scaleFactor;
324  forAll(points_, i)
325  {
326  points_[i].x() = effectiveScale * vrts[i*3];
327  points_[i].y() = effectiveScale * vrts[i*3+1];
328  points_[i].z() = effectiveScale * vrts[i*3+2];
329  }
330 
331  vrts.clear();
332 
333 #ifdef DEBUG_CCMIOREAD
334  Info<< "readVertices: " << nPoints_ << endl;
335 #endif
336 
337  return origPointId;
338 }
339 
340 
341 // readCells:
342 // - read faces, faceOwner and faceNeighbour
343 // - finally read interfaces
344 void Foam::ccm::reader::readCells
345 (
346  const ccmID& topoNode
347 )
348 {
349  CCMIOSize size = 0;
350  ccmID cellsNode, mapId;
351  ccmID nodeId;
352 
353 #ifdef DEBUG_CCMIOREAD
354  Info<< "readCells()" << endl;
355 #endif
356 
357  // Determine dimensions and mapId information for 'Cells'
358  CCMIOGetEntity
359  (
360  &(globalState_->error),
361  topoNode,
362  kCCMIOCells,
363  0,
364  &cellsNode
365  );
366 
367  CCMIOEntitySize
368  (
369  &(globalState_->error),
370  cellsNode,
371  &size,
372  nullptr
373  );
374  assertNoError("cannot get 'Cells' node");
375 
376  nCells_ = size;
377 
378 #ifdef DEBUG_CCMIOREAD
379  Info<< "readCells: " << nCells_ << endl;
380 #endif
381 
382  // Store cell ids so that we know which cells are which
383  origCellId_.setSize(nCells_);
384  cellTableId_.setSize(nCells_);
385 
386  CCMIOReadCells
387  (
388  &(globalState_->error),
389  cellsNode,
390  &mapId,
391  cellTableId_.begin(),
392  kCCMIOStart,
393  kCCMIOEnd
394  );
395  assertNoError("Error reading 'Cells' node");
396 
397  readMap
398  (
399  mapId,
400  origCellId_
401  );
402 
403  // Determine dimensions and mapId information for 'InternalFaces'
404  CCMIOGetEntity
405  (
406  &(globalState_->error),
407  topoNode,
408  kCCMIOInternalFaces,
409  0,
410  &nodeId
411  );
412  CCMIOEntitySize
413  (
414  &(globalState_->error),
415  nodeId,
416  &size,
417  nullptr
418  );
419  nInternalFaces_ = size;
420 
421  nFaces_ = nInternalFaces_;
422 
423  // First pass:
424  //
425  // Determine patch sizes before reading internal faces
426  // also determine the original boundary regions
427 
428  label nPatches = 0;
429  DynamicList<ccmBoundaryInfo> bndInfo;
430 
431  // Number of children in the parent node is more than number of patches,
432  // but is a good start for allocation
433  if
434  (
435  CCMIOGetNumberOfChildren
436  (
437  nullptr,
438  topoNode.node,
439  &nPatches
440  ) == kCCMIONoErr
441  )
442  {
443  bndInfo.setCapacity(nPatches);
444  }
445 
446  for
447  (
448  int index = 0;
449  CCMIONextEntity
450  (
451  nullptr,
452  topoNode,
453  kCCMIOBoundaryFaces,
454  &index,
455  &nodeId
456  ) == kCCMIONoErr
457  && CCMIOEntitySize
458  (
459  &(globalState_->error),
460  nodeId,
461  &size,
462  nullptr
463  ) == kCCMIONoErr;
464  /* nop */
465  )
466  {
467  ccmBoundaryInfo info;
468  info.size = size;
469  nFaces_ += size;
470 
471  CCMIOGetEntityIndex
472  (
473  &(globalState_->error),
474  nodeId,
475  &(info.ccmIndex)
476  );
477 
478  // Name directly from the node (eg, STARCCM)
479  info.setPatchName(ccmReadOptstr("Label", nodeId));
480 
481  // Lookup the name, type from boundary region info:
482  auto dictIter = boundaryRegion_.find(info.ccmIndex);
483  if (dictIter.found())
484  {
485  dictionary& dict = dictIter.val();
486 
487  const word patchName(dict.get<word>("Label"));
488  const word patchType(dict.get<word>("BoundaryType"));
489 
490  if (!patchName.empty())
491  {
492  info.patchName = patchName;
493  }
494 
495  if (!patchType.empty())
496  {
497  info.patchType = patchType;
498  }
499 
500  // Optional, but potentially useful information:
501  dict.add("BoundaryIndex", info.ccmIndex);
502  dict.add("size", info.size);
503  }
504 
505  bndInfo.append(info);
506  }
507 
508  // Redimension lists according to the overall sizes
509  faces_.setSize(nFaces_);
510  faceOwner_.setSize(nFaces_);
511  faceNeighbour_.setSize(nFaces_);
512  origFaceId_.setSize(nFaces_);
513 
514 
515  // May be too large, but is a good place start size
516  patchSizes_.setSize(bndInfo.size());
517  origBndId_.setSize(bndInfo.size());
518  patchSizes_ = 0;
519  origBndId_ = -1;
520  nPatches = 0;
521 
522  forAll(bndInfo, infoI)
523  {
524  ccmBoundaryInfo& info = bndInfo[infoI];
525 
526  if (info.patchId != -1)
527  {
528  // Already inserted - eg, as interface
529  origBndId_[info.patchId] = info.ccmIndex;
530  }
531  else
532  {
533  info.patchId = nPatches++;
534  origBndId_[info.patchId] = info.ccmIndex;
535  }
536 
537  patchSizes_[info.patchId] += info.size;
538  }
539 
540  // Shrink to sizes actually used
541  patchSizes_.setSize(nPatches);
542  origBndId_.setSize(nPatches);
543 
544  // Boundary info indices flattened and sorted by patchId
545 
546  IndirectList<ccmBoundaryInfo> ccmLookupOrder(bndInfo, labelList());
547  {
548  DynamicList<label> addr(bndInfo.size());
549  for (int patchI = 0; patchI < nPatches; ++patchI)
550  {
551  forAll(bndInfo, infoI)
552  {
553  if (bndInfo[infoI].patchId == patchI)
554  {
555  addr.append(infoI);
556  }
557  }
558  }
559 
560  ccmLookupOrder.addressing() = std::move(addr);
561  }
562 
563 
564  //
565  // Now we are ready to do the reading
566  //
567  CCMIOGetEntity
568  (
569  &(globalState_->error),
570  topoNode,
571  kCCMIOInternalFaces,
572  0,
573  &nodeId
574  );
575 
576  // get allocation sizes
577  CCMIOReadFaces
578  (
579  &(globalState_->error),
580  nodeId,
581  kCCMIOInternalFaces,
582  &mapId,
583  &size,
584  nullptr,
585  kCCMIOStart,
586  kCCMIOEnd
587  );
588 
589  List<label> mapData(nInternalFaces_);
590  List<label> faceCells(2*nInternalFaces_);
591  List<label> ccmFaces(size);
592 
593  CCMIOReadFaces
594  (
595  &(globalState_->error),
596  nodeId,
597  kCCMIOInternalFaces,
598  nullptr,
599  nullptr,
600  ccmFaces.begin(),
601  kCCMIOStart,
602  kCCMIOEnd
603  );
604 
605  CCMIOReadFaceCells
606  (
607  &(globalState_->error),
608  nodeId,
609  kCCMIOInternalFaces,
610  faceCells.begin(),
611  kCCMIOStart,
612  kCCMIOEnd
613  );
614  assertNoError("Error reading internal faces");
615 
616  readMap
617  (
618  mapId,
619  mapData
620  );
621 
622  // Copy into Foam list
623  // ccmFaces are organized as [nVert vrt1 .. vrtN]
624  unsigned int pos = 0;
625  for (label faceI = 0; faceI < nInternalFaces_; ++faceI)
626  {
627  origFaceId_[faceI] = mapData[faceI];
628  faceOwner_[faceI] = faceCells[2*faceI];
629  faceNeighbour_[faceI] = faceCells[2*faceI+1];
630  face& f = faces_[faceI];
631 
632  f.setSize(ccmFaces[pos++]);
633  forAll(f, fp)
634  {
635  f[fp] = ccmFaces[pos++];
636  }
637  }
638 
639  // Read the boundary faces
640  // ~~~~~~~~~~~~~~~~~~~~~~~
641  label patchFaceI = nInternalFaces_;
642 
643  forAll(ccmLookupOrder, lookupI)
644  {
645  const ccmBoundaryInfo& info = ccmLookupOrder[lookupI];
646  const unsigned int patchSize = info.size;
647 
648  if
649  (
650  CCMIOGetEntity
651  (
652  &(globalState_->error),
653  topoNode,
654  kCCMIOBoundaryFaces,
655  info.ccmIndex,
656  &nodeId
657  ) == kCCMIONoErr
658  )
659  {
660  CCMIOReadFaces
661  (
662  &(globalState_->error),
663  nodeId,
664  kCCMIOBoundaryFaces,
665  &mapId,
666  &size, // size needed for the faces
667  nullptr,
668  kCCMIOStart,
669  kCCMIOEnd
670  );
671 
672  mapData.setSize(patchSize);
673  faceCells.setSize(patchSize);
674  ccmFaces.setSize(size);
675 
676  readMap
677  (
678  mapId,
679  mapData
680  );
681 
682  CCMIOReadFaces
683  (
684  &(globalState_->error),
685  nodeId,
686  kCCMIOBoundaryFaces,
687  nullptr,
688  nullptr,
689  ccmFaces.begin(),
690  kCCMIOStart,
691  kCCMIOEnd
692  );
693  CCMIOReadFaceCells
694  (
695  &(globalState_->error),
696  nodeId,
697  kCCMIOBoundaryFaces,
698  faceCells.begin(),
699  kCCMIOStart,
700  kCCMIOEnd
701  );
702  assertNoError
703  (
704  "Error reading boundary face cells - index "
705  + ::Foam::name(info.ccmIndex)
706  );
707 
708  // Copy into Foam list
709  // ccmFaces are organized as [nVert vrt1 .. vrtN]
710  unsigned int pos = 0;
711  for (unsigned int i = 0; i < patchSize; ++i, ++patchFaceI)
712  {
713  origFaceId_[patchFaceI] = mapData[i];
714  faceOwner_[patchFaceI] = faceCells[i];
715  faceNeighbour_[patchFaceI] = -1;
716 
717  face& f = faces_[patchFaceI];
718 
719  f.setSize(ccmFaces[pos++]);
720  forAll(f, fp)
721  {
722  f[fp] = ccmFaces[pos++];
723  }
724  }
725  }
726  else
727  {
728  assertNoError
729  (
730  "Error reading boundary faces - index "
731  + ::Foam::name(info.ccmIndex)
732  );
733  }
734  }
735 
736  readInterfaces(cellsNode);
737 }
738 
739 
740 // Read any interfaces
741 // 1) interfaces between domains (fluid/solid, fluid/porosity)
742 // 2) PROSTAR baffles
743 //
744 void Foam::ccm::reader::readInterfaces
745 (
746  const ccmID& cellsNode
747 )
748 {
749 #ifdef DEBUG_CCMIOREAD
750  Info<< "readInterfaces()" << endl;
751 #endif
752 
753  label nBaffleInterface = 0, nInterfaceTotal = 0;
754  CCMIOIndex size = 0, dims = 0;
755 
756  bafInterfaces_.clear();
757  domInterfaces_.clear();
758 
759  ccmID interfaceNode;
760 
761  if
762  (
763  CCMIOGetEntity
764  (
765  nullptr,
766  cellsNode,
767  kCCMIOInterfaces,
768  0,
769  &interfaceNode
770  )
771  == kCCMIONoErr
772 
773  && CCMIOGetOptInfo
774  (
775  nullptr,
776  interfaceNode,
777  "FaceIds",
778  nullptr,
779  &size,
780  &dims,
781  nullptr
782  )
783  == kCCMIONoErr
784 
785  && size > 0 && dims == 2
786  )
787  {
788  nInterfaceTotal = size;
789  }
790  else
791  {
792  return;
793  }
794 
795  // Get ProstarBaffles
796  // formatted as [ prostarId faceId1 faceId2 celltableId ]
797  if
798  (
799  CCMIOGetOptInfo
800  (
801  nullptr,
802  interfaceNode,
803  "ProstarBaffles",
804  nullptr,
805  &size,
806  nullptr,
807  nullptr
808  )
809  == kCCMIONoErr
810 
811  && size > 0
812  )
813  {
814  // Be paranoid - force an integral value of 4
815  nBaffleInterface = (size - size % 4) / 4;
816  }
817 
818  // Determine sizes
819  label nDomainInterface = nInterfaceTotal - nBaffleInterface;
820 
821  // Maximum dimension
822  List<int> mapData(max(2 * nInterfaceTotal, 4 * nBaffleInterface), -1);
823 
824  bafInterfaces_.setSize(nBaffleInterface);
825  domInterfaces_.setSize(nDomainInterface);
826 
827  // Face number mapping
828  label maxId = max(origFaceId_);
829  labelList toFoamFaces(invert(maxId+1, origFaceId_));
830 
831  if (nBaffleInterface > 0)
832  {
833  mapData = -1;
834 
835  CCMIOReadOpt1i
836  (
837  &(globalState_->error),
838  interfaceNode,
839  "ProstarBaffles",
840  mapData.begin(),
841  kCCMIOStart,
842  kCCMIOEnd
843  );
844  assertNoError("problem reading interface 'ProstarBaffles'");
845 
846 
847  // Copy/compress the desired entries (cannot use a SubList)
848  // Transform
849  // from [ prostarId faceId1 faceId2 celltableId ]
850  // to [ faceId1 faceId2 ]
851  for (label i=0; i < nBaffleInterface; ++i)
852  {
853  mapData[i*2] = mapData[i*4+1];
854  mapData[i*2+1] = mapData[i*4+2];
855  }
856 
857  for (label i=2*nBaffleInterface; i < 4*nBaffleInterface; ++i)
858  {
859  mapData[i] = -1;
860  }
861 
862  // Translate ccm faceId -> foam faceId
863  inplaceRenumber(toFoamFaces, mapData);
864 
865  forAll(bafInterfaces_, i)
866  {
867  bafInterfaces_[i][0] = mapData[i*2];
868  bafInterfaces_[i][1] = mapData[i*2+1];
869  }
870  }
871 
872  // Baffles are not domInterfaces, use hash to skip them
873  SubList<label> subMap(mapData, 2*nBaffleInterface);
874  labelHashSet hashedFace(subMap);
875 
876  mapData = -1;
877 
878  CCMIOReadOpt2i
879  (
880  &(globalState_->error),
881  interfaceNode,
882  "FaceIds",
883  mapData.begin(),
884  kCCMIOStart,
885  kCCMIOEnd
886  );
887  assertNoError("problem reading interface 'FaceIds'");
888 
889  // Translate ccm faceId -> foam faceId
890  // newer version handles negatives indices
891  inplaceRenumber(toFoamFaces, mapData);
892 
893  nDomainInterface = 0;
894  for (label i=0; i < nInterfaceTotal; ++i)
895  {
896  label face0 = mapData[i*2];
897  label face1 = mapData[i*2+1];
898 
899  if
900  (
901  !hashedFace.found(face0)
902  && !hashedFace.found(face1)
903  )
904  {
905  domInterfaces_[nDomainInterface][0] = face0;
906  domInterfaces_[nDomainInterface][1] = face1;
907  ++nDomainInterface;
908  if (nDomainInterface >= domInterfaces_.size())
909  {
910  break;
911  }
912  }
913  }
914 
915  // Truncate for extra safety
916  domInterfaces_.setSize(nDomainInterface);
917 }
918 
919 
920 // Read monitoring faces
921 //
922 void Foam::ccm::reader::readMonitoring
923 (
924  const ccmID& topoId
925 )
926 {
927 #ifdef DEBUG_CCMIOREAD
928  Info<< "readMonitoring()" << endl;
929 #endif
930 
931 #ifdef WITH_MONITORING
932  CCMIONode topoNode, monitorParent;
933  CCMIONode monitorNode;
934 
935  // CCMIOID -> CCMIONODE
936  if
937  (
938  CCMIOGetEntityNode
939  (
940  nullptr,
941  topoId,
942  &topoNode
943  )
944  == kCCMIONoErr
945 
946  // Get "/Meshes/FaceBasedTopology/MonitorBoundaryRegions"
947  && CCMIOGetNode
948  (
949  nullptr,
950  topoNode,
951  "MonitorBoundaryRegions",
952  &monitorParent
953  )
954  == kCCMIONoErr
955  )
956  {
957  labelList toFoamFaces(invert(nFaces_+1, origFaceId_));
958 
959  // Simulate CCMIONextEntity
960  for
961  (
962  int index = 0;
963  CCMIOGetNextChildWithLabel
964  (
965  nullptr,
966  monitorParent,
967  "boundaryFaces",
968  &index,
969  &monitorNode
970  ) == kCCMIONoErr;
971  /* nop */
972  )
973  {
974 #ifdef DEBUG_MONITORING
975  Info<< "index = " << index << endl;
976 #endif
977 
978  int nMonFaces = 0;
979  // Simulate EntitySize ?
980  CCMIOReadNodei
981  (
982  nullptr,
983  monitorNode,
984  "NumFaces",
985  &nMonFaces
986  );
987 
988  int ccmRegionId = ccmGetEntityIndex(monitorNode);
989 
990  ccmID mapId;
991 
992  int idVal;
993  CCMIOReadNodei
994  (
995  nullptr,
996  monitorNode,
997  "MapId",
998  &idVal
999  );
1000 
1001 #ifdef DEBUG_MONITORING
1002  Info<< "monitoring mapId " << idVal
1003  << " with nFaces = " << nMonFaces
1004  << endl;
1005 #endif
1006  // Is it risky changing parents here?
1007  CCMIOGetEntity
1008  (
1009  nullptr,
1010  (globalState_->root),
1011  kCCMIOMap,
1012  idVal,
1013  &mapId
1014  );
1015 
1016  List<label> mapData(nMonFaces);
1017  // mapData.setSize(nMonFaces);
1018  // faceCells.setSize(nMonFaces);
1019 
1020  readMap
1021  (
1022  mapId,
1023  mapData
1024  );
1025 
1026 #ifdef DEBUG_MONITORING
1027  Info<< "map: " << mapData << nl
1028  << "toFoam: " << toFoamFaces
1029  << endl;
1030 #endif
1031 
1032  // Translate ccm faceId -> foam faceId
1033  // newer version handles negatives indices
1034  inplaceRenumber(toFoamFaces, mapData);
1035 
1036 #ifdef DEBUG_MONITORING
1037  Info<< "map: " << mapData << nl
1038  << "ccmRegionId: " << ccmRegionId << endl;
1039 #endif
1040 
1041  auto iter = boundaryRegion_.cfind(ccmRegionId);
1042 
1043  word zoneName;
1044  if (iter.found())
1045  {
1046  iter().readEntry("Label", zoneName);
1047  }
1048  else
1049  {
1050  zoneName = "monitoring_" + Foam::name(ccmRegionId);
1051  }
1052 
1053  monitoringSets_.insert(zoneName, mapData);
1054 
1055  // CCMIONode subNode;
1056  //
1057  //- simulate ReadFaceCells with kCCMIOBoundaryFaces
1058  // CCMIOGetNode(nullptr, childNode, "Cells", &subNode);
1059  // CCMIORead1i
1060  // (
1061  // nullptr, subNode, faceCells.begin(),
1062  // kCCMIOStart, kCCMIOEnd
1063  // );
1064  //
1065  // Info << "cells: " << faceCells << endl;
1066  }
1067  }
1068 #endif
1069 }
1070 
1071 
1072 // Move solid faces from Default_Boundary_Region -> Default_Boundary_Solid
1073 void Foam::ccm::reader::juggleSolids()
1074 {
1075  if (!option().keepSolid())
1076  {
1077  return;
1078  }
1079 
1080  // Find "Default_Boundary_Region"
1081  label defaultBoundaryRegion = boundaryRegion_.findIndex
1082  (
1083  defaultBoundaryName
1084  );
1085 
1086  // Find "Default_Boundary_Solid"
1087  label defaultBoundarySolid = boundaryRegion_.findIndex
1088  (
1089  defaultSolidBoundaryName
1090  );
1091 
1092  // Cannot do anything if Default_Boundary_Region does not exist
1093  // or if Default_Boundary_Solid already exists
1094  if
1095  (
1096  defaultBoundaryRegion < 0
1097  || defaultBoundarySolid >= 0
1098  )
1099  {
1100  return;
1101  }
1102 
1103  // Identify solid cells
1104  // ~~~~~~~~~~~~~~~~~~~~
1105  label nSolids = 0;
1106  bitSet solidCells(cellTableId_.size(), false);
1107  {
1108  Map<word> solidMap = cellTable_.solids();
1109 
1110  forAll(cellTableId_, cellI)
1111  {
1112  if (solidMap.found(cellTableId_[cellI]))
1113  {
1114  solidCells.set(cellI);
1115  ++nSolids;
1116  }
1117  }
1118  }
1119 
1120  if (!nSolids)
1121  {
1122  return;
1123  }
1124 
1125 
1126  // The corresponding Foam patch
1127  const label patchIndex = origBndId_.find(defaultBoundaryRegion);
1128  const label nPatchFaces = patchSizes_[patchIndex];
1129 
1130  labelList patchStarts(patchStartList(nInternalFaces_));
1131  label adjustPatch = 0;
1132  for (label i = 0; i < nPatchFaces; ++i)
1133  {
1134  label faceI = patchStarts[patchIndex] + i;
1135  label cellI = faceOwner_[faceI];
1136 
1137  if (solidCells.test(cellI))
1138  {
1139  ++adjustPatch;
1140  }
1141  }
1142 
1143  // No solid cells on the Default_Boundary_Region
1144  if (!adjustPatch)
1145  {
1146  return;
1147  }
1148 
1149 
1150  // Insert Default_Boundary_Solid immediately after Default_Boundary_Region
1151  // then we only need to adjust a single patch and can easily re-merge
1152  // later
1153  label nPatches = patchSizes_.size();
1154  patchStarts.setSize(nPatches+1, 0);
1155  patchSizes_.setSize(nPatches+1, 0);
1156  origBndId_.setSize(nPatches+1, 0);
1157 
1158  // make room for new entry
1159  for (label i = nPatches; i > patchIndex; --i)
1160  {
1161  patchStarts[i] = patchStarts[i-1];
1162  patchSizes_[i] = patchSizes_[i-1];
1163  origBndId_[i] = origBndId_[i-1];
1164  }
1165 
1166  // Adjust start and sizes
1167  patchSizes_[patchIndex] -= adjustPatch;
1168  patchSizes_[patchIndex+1] = adjustPatch;
1169  patchStarts[patchIndex+1] =
1170  patchStarts[patchIndex] + patchSizes_[patchIndex];
1171 
1172  origBndId_[patchIndex+1] = boundaryRegion_.append
1173  (
1174  dictionary
1175  (
1176  IStringStream
1177  (
1178  "BoundaryType wall;"
1179  "Label " + word(defaultSolidBoundaryName) + ";"
1180  )()
1181  )
1182  );
1183 
1184  label fluidFace = patchStarts[patchIndex];
1185  label solidFace = patchStarts[patchIndex+1];
1186 
1187  labelList oldToNew(identity(nFaces_));
1188  for (label i = 0; i < nPatchFaces; ++i)
1189  {
1190  label faceI = patchStarts[patchIndex] + i;
1191  label cellI = faceOwner_[faceI];
1192 
1193  if (solidCells.test(cellI))
1194  {
1195  oldToNew[faceI] = solidFace++;
1196  }
1197  else
1198  {
1199  oldToNew[faceI] = fluidFace++;
1200  }
1201  }
1202 
1203  // Re-order faces, owners/neighbours
1204  inplaceReorder(oldToNew, faces_);
1205  inplaceReorder(oldToNew, faceOwner_);
1206  inplaceReorder(oldToNew, faceNeighbour_);
1207  inplaceReorder(oldToNew, origFaceId_);
1208 
1209  renumberInterfaces(oldToNew);
1210 }
1211 
1212 
1213 // In CCM, separate mesh domains are used for fluid/porous/solid
1214 // Thus the fluid/porous/solid cells correspond uniquely to a face owner
1215 void Foam::ccm::reader::removeUnwanted()
1216 {
1217  // Identify fluid/porous/solid cells for removal
1218  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1219  label nRemove = 0;
1220  bitSet removeCells(cellTableId_.size(), false);
1221 
1222  {
1223  Map<word> fluidMap = cellTable_.fluids();
1224  Map<word> porousMap = selectPorous(cellTable_);
1225  Map<word> solidMap = cellTable_.solids();
1226  Map<word> removeMap;
1227 
1228  forAll(cellTableId_, cellI)
1229  {
1230  label tableId = cellTableId_[cellI];
1231 
1232  if
1233  (
1234  porousMap.found(tableId)
1235  ? !option().keepPorous()
1236  : fluidMap.found(tableId)
1237  ? !option().keepFluid()
1238  : solidMap.found(tableId)
1239  ? !option().keepSolid()
1240  : false
1241  )
1242  {
1243  removeCells.set(cellI);
1244  ++nRemove;
1245  removeMap.set(tableId, cellTable_.name(tableId));
1246  }
1247  }
1248 
1249  if (nRemove)
1250  {
1251  Map<word> keepMap;
1252 
1253  forAllConstIters(cellTable_, iter)
1254  {
1255  const label tableId = iter.key();
1256  if (!removeMap.found(tableId))
1257  {
1258  keepMap.set(tableId, cellTable_.name(tableId));
1259  }
1260  }
1261 
1262  Info<<"remove "<< nRemove << " cells in "
1263  << removeMap.size() << " unwanted cellZone(s)" << nl;
1264 
1265  forAllConstIters(removeMap, iter)
1266  {
1267  Info<< " zone "
1268  << iter.key() << " : " << iter.val() << nl;
1269  }
1270 
1271  Info<<"retain "<< (nCells_ - nRemove) << " cells in "
1272  << keepMap.size() << " cellZone(s)" << nl;
1273 
1274  forAllConstIters(keepMap, iter)
1275  {
1276  Info<< " zone "
1277  << iter.key() << " : " << iter.val() << nl;
1278  }
1279  }
1280  }
1281 
1282  if (!nRemove)
1283  {
1284  return;
1285  }
1286 
1287  // Remove all faces where the owner corresponds to a removed cell
1288  // Adjust the nInternalFaces and patch sizes accordingly
1289  label adjustInternal = 0;
1290  labelList adjustPatchSize(patchSizes_.size(), Zero);
1291 
1292  label newFaceI = 0;
1293  label oldFaceI = nFaces_ - 1;
1294  labelList oldToNew(nFaces_, -1);
1295  for (label faceI = 0; faceI < nFaces_; ++faceI)
1296  {
1297  label cellI = faceOwner_[faceI];
1298  if (removeCells.test(cellI))
1299  {
1300  if (faceI < nInternalFaces_)
1301  {
1302  ++adjustInternal;
1303  }
1304  else
1305  {
1306  // need to adjust the patch sizes
1307  label beg = nInternalFaces_;
1308  forAll(patchSizes_, patchI)
1309  {
1310  label end = beg + patchSizes_[patchI];
1311 
1312  if (faceI >= beg && faceI < end)
1313  {
1314  ++adjustPatchSize[patchI];
1315  break;
1316  }
1317 
1318  beg = end;
1319  }
1320  }
1321 
1322  // Put discarded faces at the end of the list
1323  oldToNew[faceI] = oldFaceI--;
1324  }
1325  else
1326  {
1327  if (newFaceI != faceI)
1328  {
1329  faces_[newFaceI] = faces_[faceI];
1330  faceOwner_[newFaceI] = faceOwner_[faceI];
1331  faceNeighbour_[newFaceI] = faceNeighbour_[faceI];
1332  origFaceId_[newFaceI] = origFaceId_[faceI];
1333  }
1334 
1335  // New position for the face
1336  oldToNew[faceI] = newFaceI++;
1337  }
1338  }
1339 
1340  nFaces_ = newFaceI;
1341 
1342  // Redimension
1343  faces_.setSize(nFaces_);
1344  faceOwner_.setSize(nFaces_);
1345  faceNeighbour_.setSize(nFaces_);
1346  origFaceId_.setSize(nFaces_);
1347 
1348  // Adjust internal faces and patch sizes
1349 
1350  nInternalFaces_ -= adjustInternal;
1351  forAll(patchSizes_, patchI)
1352  {
1353  patchSizes_[patchI] -= adjustPatchSize[patchI];
1354  }
1355 
1356  renumberInterfaces(oldToNew);
1357 
1358  // Renumber cells
1359  label nCell = 0;
1360  oldToNew.setSize(nCells_, -1);
1361  for (label cellI = 0; cellI < nCells_; ++cellI)
1362  {
1363  if (!removeCells.test(cellI))
1364  {
1365  if (nCell != cellI)
1366  {
1367  origCellId_[nCell] = origCellId_[cellI];
1368  cellTableId_[nCell] = cellTableId_[cellI];
1369  }
1370  oldToNew[cellI] = nCell;
1371  ++nCell;
1372  }
1373  }
1374 
1375  inplaceRenumber(oldToNew, faceOwner_);
1376  inplaceRenumber(oldToNew, faceNeighbour_);
1377 
1378  // Redimension
1379  nCells_ = nCell;
1380  origCellId_.setSize(nCells_);
1381  cellTableId_.setSize(nCells_);
1382 
1383 
1384  // Remove unused points - adjust points, faces accordingly
1385  oldToNew.setSize(nPoints_);
1386  oldToNew = -1;
1387 
1388  // Mark up all the used points
1389  forAll(faces_, faceI)
1390  {
1391  const labelList& facePoints = faces_[faceI];
1392 
1393  forAll(facePoints, ptI)
1394  {
1395  ++oldToNew[facePoints[ptI]];
1396  }
1397  }
1398 
1399  label nPointUsed = 0;
1400  forAll(oldToNew, ptI)
1401  {
1402  if (oldToNew[ptI] >= 0)
1403  {
1404  oldToNew[ptI] = nPointUsed;
1405  if (ptI != nPointUsed)
1406  {
1407  points_[nPointUsed] = points_[ptI];
1408  }
1409  ++nPointUsed;
1410  }
1411  }
1412 
1413  nPoints_ = nPointUsed;
1414  points_.setSize(nPoints_);
1415 
1416  forAll(faces_, faceI)
1417  {
1418  inplaceRenumber(oldToNew, faces_[faceI]);
1419  }
1420 
1421  // Report sizes
1422  printSizes();
1423 }
1424 
1425 
1426 void Foam::ccm::reader::validateInterface
1427 (
1428  List<labelPair>& lst
1429 )
1430 {
1431  label nElem = 0;
1432  forAll(lst, elemI)
1433  {
1434  label face0 = lst[elemI][0];
1435  label face1 = lst[elemI][1];
1436 
1437  if (face0 < nFaces_ && face1 < nFaces_)
1438  {
1439  if (nElem != elemI)
1440  {
1441  lst[nElem][0] = face0;
1442  lst[nElem][1] = face1;
1443  }
1444  ++nElem;
1445  }
1446  }
1447  lst.setSize(nElem);
1448 }
1449 
1450 
1451 void Foam::ccm::reader::renumberInterfaces
1452 (
1453  const labelUList& oldToNew
1454 )
1455 {
1456  forAll(domInterfaces_, elemI)
1457  {
1458  domInterfaces_[elemI][0] = oldToNew[domInterfaces_[elemI][0]];
1459  domInterfaces_[elemI][1] = oldToNew[domInterfaces_[elemI][1]];
1460  }
1461 
1462  forAll(bafInterfaces_, elemI)
1463  {
1464  bafInterfaces_[elemI][0] = oldToNew[bafInterfaces_[elemI][0]];
1465  bafInterfaces_[elemI][1] = oldToNew[bafInterfaces_[elemI][1]];
1466  }
1467 
1468  validateInterface(domInterfaces_);
1469  validateInterface(bafInterfaces_);
1470 }
1471 
1472 
1473 //
1474 // 1) remove interfaces between domains (fluid/porosity; fluid/solid, etc)
1475 // 2) reorganize baffle interfaces into [0-N/2; N/2-N] lists at the beginning
1476 // of the corresponding patch
1477 //
1478 void Foam::ccm::reader::cleanupInterfaces()
1479 {
1480  validateInterface(bafInterfaces_);
1481  validateInterface(domInterfaces_);
1482 
1483  if (bafInterfaces_.size() <= 0 && domInterfaces_.size() <= 0)
1484  {
1485  Info<<"0 baffle interface pairs" << nl
1486  <<"0 domain interface pairs" << endl;
1487  return;
1488  }
1489 
1490 #ifdef DEBUG_BAFFLES
1491  Info<< "baffle Interfaces " << bafInterfaces_ << nl
1492  << "domain Interfaces " << domInterfaces_ << nl
1493  << "nCells:" << nCells_ << nl
1494  << "nFaces:" << nFaces_ << nl
1495  << "patchSizes:" << patchSizes_ << nl
1496  << "nInternalFaces:" << nInternalFaces_ << endl;
1497 
1498  forAll(domInterfaces_, elemI)
1499  {
1500  const label face0 = domInterfaces_[elemI][0];
1501  const label face1 = domInterfaces_[elemI][1];
1502 
1503  Info<< "interface [" << elemI << "] = "
1504  << face0 << " - " << face1 << " own/neigh = "
1505  << faceOwner_[face0] << "/" << faceNeighbour_[face0] << " "
1506  << faceOwner_[face1] << "/" << faceNeighbour_[face1] << endl;
1507  }
1508 #endif
1509 
1510  // Only reorder faces that need it
1511  labelList oldToNew(nFaces_, -1);
1512 
1513  // - move side0 face from domInterfaces to join the internal faces
1514  // - move the redundant side1 to the end of the list for later deletion
1515  label begOfList = nInternalFaces_;
1516  label endOfList = nFaces_ - 1;
1517 
1518  // The patch sizes (and the start) will definitely change
1519  const labelList origPatchStarts(patchStartList(nInternalFaces_));
1520  labelList adjustPatchSize(patchSizes_.size(), Zero);
1521  labelList bafflePatchCount(patchSizes_.size(), Zero);
1522 
1523  // The new dimensions after merging the domain interfaces:
1524  nInternalFaces_ += domInterfaces_.size();
1525  nFaces_ -= domInterfaces_.size();
1526 
1527  Info<< domInterfaces_.size() << " domain interface pairs";
1528  if (domInterfaces_.size())
1529  {
1530  Info<<" to merge" << endl;
1531  printSizes();
1532  }
1533  else
1534  {
1535  Info<< endl;
1536  }
1537 
1538  forAll(domInterfaces_, elemI)
1539  {
1540  label face0 = domInterfaces_[elemI][0];
1541  label face1 = domInterfaces_[elemI][1];
1542 
1543  oldToNew[face0] = begOfList++;
1544  oldToNew[face1] = endOfList--; // End of list for truncationx
1545 
1546  // face0 gets a new neighbour, face1 loses its owner
1547  faceNeighbour_[face0] = faceOwner_[face1];
1548  faceOwner_[face1] = -1;
1549 
1550  // Need to adjust the patch sizes
1551  forAll(patchSizes_, patchI)
1552  {
1553  label beg = origPatchStarts[patchI];
1554  label end = beg + patchSizes_[patchI];
1555 
1556  if (face0 >= beg && face0 < end)
1557  {
1558  ++adjustPatchSize[patchI];
1559  }
1560  if (face1 >= beg && face1 < end)
1561  {
1562  ++adjustPatchSize[patchI];
1563  }
1564  }
1565  }
1566 
1567  // Count the number of baffles per patch
1568  forAll(bafInterfaces_, elemI)
1569  {
1570  label face0 = bafInterfaces_[elemI][0];
1571  label face1 = bafInterfaces_[elemI][1];
1572 
1573  forAll(patchSizes_, patchI)
1574  {
1575  label beg = origPatchStarts[patchI];
1576  label end = beg + patchSizes_[patchI];
1577 
1578  if (face0 >= beg && face0 < end)
1579  {
1580  ++bafflePatchCount[patchI];
1581  }
1582  if (face1 >= beg && face1 < end)
1583  {
1584  ++bafflePatchCount[patchI];
1585  }
1586  }
1587  }
1588 
1589 
1590  if (option().removeBaffles())
1591  {
1592  // The new dimensions after merging the baffles:
1593  nInternalFaces_ += bafInterfaces_.size();
1594  nFaces_ -= bafInterfaces_.size();
1595  }
1596 
1597  Info<< bafInterfaces_.size() << " baffle interface pairs";
1598  if (bafInterfaces_.size())
1599  {
1600  if (option().removeBaffles())
1601  {
1602  Info<< " to merge" << endl;
1603  printSizes();
1604  }
1605  else
1606  {
1607  Info<< " to be sorted" << endl;
1608  }
1609  }
1610  else
1611  {
1612  Info<< endl;
1613  }
1614 
1615  if (option().removeBaffles())
1616  {
1617  forAll(bafInterfaces_, elemI)
1618  {
1619  label face0 = bafInterfaces_[elemI][0];
1620  label face1 = bafInterfaces_[elemI][1];
1621 
1622  oldToNew[face0] = begOfList++;
1623  oldToNew[face1] = endOfList--; // End of list for truncation
1624 
1625  // face0 gets a new neighbour, face1 loses its owner
1626  faceNeighbour_[face0] = faceOwner_[face1];
1627  faceOwner_[face1] = -1;
1628  }
1629 
1630 
1631  // Boundary faces continue from the new nInternalFaces
1632  label pos = nInternalFaces_;
1633  forAll(patchSizes_, patchI)
1634  {
1635  label beg = origPatchStarts[patchI];
1636  label end = beg + patchSizes_[patchI];
1637 
1638  // Fill in values for the remainder of the boundary patch
1639  for (label faceI = beg; faceI < end; ++faceI)
1640  {
1641  if (oldToNew[faceI] < 0)
1642  {
1643  oldToNew[faceI] = pos;
1644  ++pos;
1645  }
1646  }
1647  }
1648 
1649  // Baffles have been resolved - remove last traces
1650  bafInterfaces_.clear();
1651  }
1652  else
1653  {
1654  // This check is probably unnecessary
1655  forAll(bafflePatchCount, patchI)
1656  {
1657  if (bafflePatchCount[patchI] % 2)
1658  {
1659  Info<< "WARNING: patch " << patchI
1660  << " has an uneven number of baffles ("
1661  << bafflePatchCount[patchI] << ") expect strange results"
1662  << endl;
1663  }
1664  }
1665 
1666 
1667  // Reordered faces continue from the new nInternalFaces
1668  label pos = nInternalFaces_;
1669  forAll(patchSizes_, patchI)
1670  {
1671  const label beg = origPatchStarts[patchI];
1672  const label end = beg + patchSizes_[patchI];
1673 
1674  const label nsize = bafflePatchCount[patchI];
1675  if (nsize > 0)
1676  {
1677  // Reorganize baffle interfaces into [0-N/2; N/2-N] lists
1678  // at the beginning of the corresponding patch
1679  const label nsizeby2 = (nsize - nsize % 2) / 2;
1680  label nsorted = 0;
1681 
1682  // Renumber the normal (baffle) interfaces
1683  forAll(bafInterfaces_, elemI)
1684  {
1685  const label face0 = bafInterfaces_[elemI][0];
1686  const label face1 = bafInterfaces_[elemI][1];
1687 
1688  if
1689  (
1690  (face0 >= beg && face0 < end)
1691  || (face1 >= beg && face1 < end)
1692  )
1693  {
1694  oldToNew[face0] = pos + nsorted;
1695  oldToNew[face1] = pos + nsorted + nsizeby2;
1696 
1697  // Mark destination of the faces, but cannot renumber
1698  // yet. Use negative to potential overlap with other
1699  // patch regions
1700  bafInterfaces_[elemI][0] = -oldToNew[face0];
1701  bafInterfaces_[elemI][1] = -oldToNew[face1];
1702 
1703  ++nsorted;
1704  }
1705  }
1706  pos += 2*nsorted;
1707  }
1708 
1709  // Fill in values for the remainder of the boundary patch
1710  for (label faceI = beg; faceI < end; ++faceI)
1711  {
1712  if (oldToNew[faceI] < 0)
1713  {
1714  oldToNew[faceI] = pos;
1715  ++pos;
1716  }
1717  }
1718  }
1719 
1720  // Finalize new numbers for the normal (baffle) interfaces
1721  forAll(bafInterfaces_, elemI)
1722  {
1723  bafInterfaces_[elemI][0] = abs(bafInterfaces_[elemI][0]);
1724  bafInterfaces_[elemI][1] = abs(bafInterfaces_[elemI][1]);
1725  }
1726  }
1727 
1728 #ifdef DEBUG_BAFFLES
1729  Info<< "remap with " << oldToNew << nl
1730  << "owners:" << faceOwner_ << nl
1731  << "neighbours:" << faceNeighbour_ << nl
1732  << endl;
1733 #endif
1734 
1735  // Re-order faces, owners/neighbours
1736  inplaceReorder(oldToNew, faces_);
1737  inplaceReorder(oldToNew, faceOwner_);
1738  inplaceReorder(oldToNew, faceNeighbour_);
1739  inplaceReorder(oldToNew, origFaceId_);
1740 
1741  if (monitoringSets_.size())
1742  {
1743 #ifdef WITH_MONITORING
1744  // Modify oldToNew mapping to account for monitoring faces that
1745  // coincided with a domain interface
1746  //
1747  // TODO - should modify flip map as well
1748  forAll(domInterfaces_, elemI)
1749  {
1750  label face0 = domInterfaces_[elemI][0];
1751  label face1 = domInterfaces_[elemI][1];
1752  oldToNew[face1] = oldToNew[face0];
1753  }
1754 
1755  forAllIters(monitoringSets_, iter)
1756  {
1757  inplaceRenumber(oldToNew, iter());
1758  }
1759 #endif
1760  }
1761 
1762  // We can finally drop this information now
1763  domInterfaces_.clear();
1764 
1765  // Truncate lists
1766  faces_.setSize(nFaces_);
1767  faceOwner_.setSize(nFaces_);
1768  faceNeighbour_.setSize(nFaces_);
1769  origFaceId_.setSize(nFaces_);
1770 
1771  // Remove empty patches:
1772 
1773  // Fix patch sizes:
1774  oldToNew.setSize(patchSizes_.size());
1775  oldToNew = -1;
1776 
1777  label nPatches = 0;
1778  forAll(patchSizes_, patchI)
1779  {
1780  patchSizes_[patchI] -= adjustPatchSize[patchI];
1781  if (option().removeBaffles())
1782  {
1783  patchSizes_[patchI] -= bafflePatchCount[patchI];
1784  }
1785 
1786  if (patchSizes_[patchI])
1787  {
1788  oldToNew[patchI] = nPatches++;
1789  }
1790  }
1791 
1792  inplaceReorder(oldToNew, patchSizes_);
1793  inplaceReorder(oldToNew, origBndId_);
1794 
1795  patchSizes_.setSize(nPatches);
1796  origBndId_.setSize(nPatches);
1797 
1798 #ifdef DEBUG_BAFFLES
1799  Info<< "nCells:" << nCells_ << nl
1800  << "nFaces:" << nFaces_ << nl
1801  << "PatchSizes:" << patchSizes_ << nl
1802  << "nInternalFaces:" << nInternalFaces_ << nl
1803  << endl;
1804 #endif
1805 }
1806 
1807 
1808 //
1809 // Merge STARCCM in-place interfaces
1810 //
1811 void Foam::ccm::reader::mergeInplaceInterfaces()
1812 {
1813  if (interfaceDefinitions_.empty())
1814  {
1815  return;
1816  }
1817  if (!option().mergeInterfaces())
1818  {
1819  Info<< interfaceDefinitions_.size() << " interface definitions"
1820  << " - leaving unmerged" << endl;
1821  return;
1822  }
1823 
1824  // List of patch pairs that are interfaces
1825  DynamicList<labelPair> interfacePatches(interfaceDefinitions_.size());
1826 
1827  label nWarn = 0;
1828 
1829  forAllConstIters(interfaceDefinitions_, iter)
1830  {
1831  const interfaceEntry& ifentry = iter.val();
1832 
1833  labelPair patchPair
1834  (
1835  origBndId_.find(ifentry.bnd0),
1836  origBndId_.find(ifentry.bnd1)
1837  );
1838 
1839  if
1840  (
1841  patchPair[0] == patchPair[1]
1842  || patchPair[0] < 0
1843  || patchPair[1] < 0
1844  )
1845  {
1846  // This should not happen
1847  Info<<"Warning : bad interface " << ifentry.id << " " << ifentry
1848  <<" on patches " << patchPair << endl;
1849  }
1850  else if
1851  (
1852  patchSizes_[patchPair[0]] != patchSizes_[patchPair[1]]
1853  || patchSizes_[patchPair[0]] == 0
1854  || patchSizes_[patchPair[1]] == 0
1855  )
1856  {
1857  if (!nWarn++)
1858  {
1859  Info<<"Warning: skip interface with zero or different"
1860  << " number of faces" << nl;
1861  }
1862 
1863  Info<<" Interface:" << ifentry.id << " " << ifentry
1864  <<" patches " << patchPair
1865  <<" sizes ("
1866  << patchSizes_[patchPair[0]]
1867  << " " << patchSizes_[patchPair[1]] << ")"
1868  << nl;
1869  }
1870  else
1871  {
1872  interfacePatches.append(patchPair);
1873  }
1874  }
1875 
1876  if (interfacePatches.empty())
1877  {
1878  return;
1879  }
1880 
1881 
1882  // Local point mapping
1883  labelList mergedPointMap;
1884 
1885  // Global remapping
1886  labelList oldToNew(identity(points_.size()));
1887 
1888  const labelList origPatchStarts(patchStartList(nInternalFaces_));
1889 
1890  label nMergedTotal = 0;
1891 
1892  // Markup points to merge
1893  bitSet whichPoints(points_.size());
1894 
1895  Info<< "interface merge points (tol="
1896  << option().mergeTol() << "):" << endl;
1897 
1898  DynamicList<label> interfacesToMerge(interfacePatches.size());
1899  forAll(interfacePatches, interI)
1900  {
1901  const label patch0 = interfacePatches[interI][0];
1902  const label patch1 = interfacePatches[interI][1];
1903  const label nPatch0Faces = patchSizes_[patch0];
1904  const label nPatch1Faces = patchSizes_[patch1];
1905 
1906  // Markup points to merge
1907  whichPoints.reset();
1908  for (label local0FaceI = 0; local0FaceI < nPatch0Faces; ++local0FaceI)
1909  {
1910  const face& f = faces_[origPatchStarts[patch0] + local0FaceI];
1911 
1912  forAll(f, fp)
1913  {
1914  // Simultaneously account for previous point merges
1915  whichPoints.set(oldToNew[f[fp]]);
1916  }
1917  }
1918  for (label local1FaceI = 0; local1FaceI < nPatch1Faces; ++local1FaceI)
1919  {
1920  const face& f = faces_[origPatchStarts[patch1] + local1FaceI];
1921 
1922  forAll(f, fp)
1923  {
1924  // Simultaneously account for previous point merges
1925  whichPoints.set(oldToNew[f[fp]]);
1926  }
1927  }
1928 
1929  // The global addresses
1930  labelList addr(whichPoints.toc());
1931 
1932  const UIndirectList<point> pointsToMerge(points_, addr);
1933 
1934  Info<< " patch " << patch0 << "," << patch1 << ": ("
1935  << nPatch0Faces << " and " << nPatch1Faces << " faces) " << flush;
1936 
1937  const label nMerged = mergePoints
1938  (
1939  pointsToMerge,
1940  option().mergeTol(),
1941  false,
1942  mergedPointMap
1943  );
1944 
1945  Info<< nMerged << " from " << pointsToMerge.size() << " points"
1946  << endl;
1947 
1948  if (nMerged)
1949  {
1950  // Transcribe local to global addressing
1951  forAll(mergedPointMap, i)
1952  {
1953  oldToNew[addr[i]] = addr[mergedPointMap[i]];
1954  }
1955 
1956  interfacesToMerge.append(interI);
1957  nMergedTotal += nMerged;
1958  }
1959  }
1960 
1961 
1962  //
1963  // Nothing to do
1964  //
1965  if (!nMergedTotal)
1966  {
1967  return;
1968  }
1969 
1970  // Update point references to account for point merge:
1971  forAll(faces_, faceI)
1972  {
1973  inplaceRenumber(oldToNew, faces_[faceI]);
1974  }
1975 
1976  // Determine which points are actually in use:
1977  oldToNew.setSize(nPoints_);
1978  oldToNew = -1;
1979 
1980  // Mark up all the used points
1981  forAll(faces_, faceI)
1982  {
1983  const labelList& facePoints = faces_[faceI];
1984 
1985  forAll(facePoints, ptI)
1986  {
1987  ++oldToNew[facePoints[ptI]];
1988  }
1989  }
1990 
1991  label nPointUsed = 0;
1992  forAll(oldToNew, ptI)
1993  {
1994  if (oldToNew[ptI] >= 0)
1995  {
1996  oldToNew[ptI] = nPointUsed;
1997  if (ptI != nPointUsed)
1998  {
1999  points_[nPointUsed] = points_[ptI];
2000  }
2001  ++nPointUsed;
2002  }
2003  }
2004 
2005  // Info<< "merge " << nMergedTotal << " points from "
2006  // << nPoints_ << " to " << nPointUsed << endl;
2007 
2008  nPoints_ = nPointUsed;
2009  points_.setSize(nPoints_);
2010 
2011  forAll(faces_, faceI)
2012  {
2013  inplaceRenumber(oldToNew, faces_[faceI]);
2014  }
2015 
2016 
2017  //
2018  // Merge the faces as well
2019  //
2020  Info<< "interface merge faces:" << endl;
2021 
2022  nMergedTotal = 0;
2023  labelList adjustPatchSize(patchSizes_.size(), Zero);
2024  forAll(interfacesToMerge, mergeI)
2025  {
2026  const label patch0 = interfacePatches[interfacesToMerge[mergeI]][0];
2027  const label patch1 = interfacePatches[interfacesToMerge[mergeI]][1];
2028 
2029  labelList faceAddr0(patchSizes_[patch0]);
2030  labelList faceAddr1(patchSizes_[patch1]);
2031 
2032  forAll(faceAddr0, localFaceI)
2033  {
2034  faceAddr0[localFaceI] = origPatchStarts[patch0] + localFaceI;
2035  }
2036  forAll(faceAddr1, localFaceI)
2037  {
2038  faceAddr1[localFaceI] = origPatchStarts[patch1] + localFaceI;
2039  }
2040 
2041  if (faceAddr0.size() != faceAddr1.size())
2042  {
2043  // This should not occur, we avoided the same thing above
2044  continue;
2045  }
2046 
2047  // Improve comparison speed by sorting by distance
2048  SortableList<scalar> pts0MagSqr
2049  (
2050  magSqr
2051  (
2053  (
2054  UIndirectList<face>
2055  (
2056  faces_,
2057  faceAddr0
2058  ),
2059  points_
2060  ).faceCentres()
2061  )
2062  );
2063  SortableList<scalar> pts1MagSqr
2064  (
2065  magSqr
2066  (
2068  (
2069  UIndirectList<face>
2070  (
2071  faces_,
2072  faceAddr1
2073  ),
2074  points_
2075  ).faceCentres()
2076  )
2077  );
2078 
2079  label nMerged = 0;
2080 
2081  // Record which faces failed to merge - use slower ad hoc merging
2082  labelHashSet failed0, failed1;
2083  forAll(pts0MagSqr, sortI)
2084  {
2085  const label face0I = faceAddr0[pts0MagSqr.indices()[sortI]];
2086  const label face1I = faceAddr1[pts1MagSqr.indices()[sortI]];
2087 
2088  // This is what we expect
2089  if (face::compare(faces_[face0I], faces_[face1I]))
2090  {
2091  ++nMerged;
2092 
2093  // Moved from boundary patch to internal patch
2094  ++adjustPatchSize[patch0];
2095  ++adjustPatchSize[patch1];
2096 
2097  if (faceOwner_[face0I] < faceOwner_[face1I])
2098  {
2099  // keep 0, discard 1
2100  faceNeighbour_[face0I] = faceOwner_[face1I];
2101  faceNeighbour_[face1I] = faceOwner_[face1I] = -1;
2102  }
2103  else
2104  {
2105  // keep 1, discard 0
2106  faceNeighbour_[face1I] = faceOwner_[face0I];
2107  faceNeighbour_[face0I] = faceOwner_[face0I] = -1;
2108  }
2109  }
2110  else
2111  {
2112  failed0.set(face0I);
2113  failed1.set(face1I);
2114  }
2115  }
2116 
2117  // Perhaps some sorting issues, recheck
2118  if (failed0.size())
2119  {
2120  // Note which one were successful
2121  labelHashSet done(failed0.size());
2122 
2123  forAllConstIters(failed0, iter0)
2124  {
2125  const label face0I = iter0.key();
2126 
2127  forAllConstIters(failed1, iter1)
2128  {
2129  const label face1I = iter1.key();
2130 
2131  // This is what we expect
2132  if (face::compare(faces_[face0I], faces_[face1I]))
2133  {
2134  ++nMerged;
2135 
2136  // Moved from boundary patch to internal patch
2137  ++adjustPatchSize[patch0];
2138  ++adjustPatchSize[patch1];
2139 
2140  if (faceOwner_[face0I] < faceOwner_[face1I])
2141  {
2142  // keep 0, discard 1
2143  faceNeighbour_[face0I] = faceOwner_[face1I];
2144  faceNeighbour_[face1I] = faceOwner_[face1I] = -1;
2145  }
2146  else
2147  {
2148  // keep 1, discard 0
2149  faceNeighbour_[face1I] = faceOwner_[face0I];
2150  faceNeighbour_[face0I] = faceOwner_[face0I] = -1;
2151  }
2152 
2153  failed1.erase(face1I); // Never check again
2154  done.set(face0I); // Mark as done
2155  break; // Stop looking
2156  }
2157  }
2158  }
2159 
2160  // Transfer to note how many were successful
2161  failed0 = done;
2162  }
2163 
2164  Info<< " patch " << patch0 << ", " << patch1 << ": "
2165  << nMerged << " from " << faceAddr0.size() << " faces";
2166 
2167  if (failed0.size())
2168  {
2169  Info<< " (" << failed0.size() << " merged ad hoc)";
2170  }
2171  Info<< endl;
2172 
2173 
2174  nMergedTotal += nMerged;
2175  }
2176 
2177 
2178  // Nothing to do
2179  if (!nMergedTotal)
2180  {
2181  return;
2182  }
2183 
2184  // Info<< "merge " << nMergedTotal << " faces from "
2185  // << nFaces_ << " to " << (nFaces_ - nMergedTotal) << endl;
2186 
2187  oldToNew.setSize(nFaces_);
2188  oldToNew = -1;
2189 
2190  // Remaining external faces will be shifted here:
2191  label extFaceI = nInternalFaces_ + nMergedTotal;
2192 
2193  // Start over
2194  nInternalFaces_ = 0;
2195  label nFaceUsed = 0;
2196  for (label faceI = 0; faceI < nFaces_; ++faceI)
2197  {
2198  if (faceOwner_[faceI] != -1)
2199  {
2200  if (faceNeighbour_[faceI] != -1)
2201  {
2202  // Internal face
2203  oldToNew[faceI] = nInternalFaces_;
2204  ++nInternalFaces_;
2205  ++nFaceUsed;
2206  }
2207  else
2208  {
2209  // External face
2210  oldToNew[faceI] = extFaceI;
2211  ++extFaceI;
2212  ++nFaceUsed;
2213  }
2214  }
2215  }
2216 
2217  if (nFaceUsed != extFaceI)
2218  {
2220  << "coding error: used " << nFaceUsed
2221  << " faces, but expected to use " << extFaceI << " faces"
2222  << exit(FatalError);
2223  }
2224 
2225  // Re-order faces, owners/neighbours
2226  inplaceReorder(oldToNew, faces_, true);
2227  inplaceReorder(oldToNew, faceOwner_, true);
2228  inplaceReorder(oldToNew, faceNeighbour_, true);
2229  inplaceReorder(oldToNew, origFaceId_, true);
2230 
2231  nFaces_ = nFaceUsed;
2232 
2233  faces_.setSize(nFaces_);
2234  faceOwner_.setSize(nFaces_);
2235  faceNeighbour_.setSize(nFaces_);
2236  origFaceId_.setSize(nFaces_);
2237 
2238  // Fix patch sizes:
2239  oldToNew.setSize(patchSizes_.size());
2240  oldToNew = -1;
2241 
2242  label nPatches = 0;
2243  forAll(patchSizes_, patchI)
2244  {
2245  patchSizes_[patchI] -= adjustPatchSize[patchI];
2246  if (patchSizes_[patchI])
2247  {
2248  oldToNew[patchI] = nPatches++;
2249  }
2250  }
2251 
2252  inplaceReorder(oldToNew, patchSizes_);
2253  inplaceReorder(oldToNew, origBndId_);
2254 
2255  patchSizes_.setSize(nPatches);
2256  origBndId_.setSize(nPatches);
2257 
2258  // Report we are done
2259  Info<< ".." << endl;
2260 }
2261 
2262 
2263 //
2264 // Re-order mesh into Foam convention
2265 // - owner < neighbour
2266 // - face vertices such that normal points away from owner
2267 // - order faces: upper-triangular for internal faces;
2268 // boundary faces after internal faces
2269 //
2270 void Foam::ccm::reader::reorderMesh()
2271 {
2272  // Set owner/neighbour so owner < neighbour
2273  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2274 
2275  forAll(faceOwner_, faceI)
2276  {
2277  label nbr = faceNeighbour_[faceI];
2278  label own = faceOwner_[faceI];
2279 
2280  if (nbr >= cellTableId_.size() || own >= cellTableId_.size())
2281  {
2283  << "face:" << faceI
2284  << " nbr:" << nbr
2285  << " own:" << own
2286  << " nCells:" << cellTableId_.size()
2287  << exit(FatalError);
2288  }
2289 
2290  if (nbr >= 0 && nbr < own)
2291  {
2292  faceOwner_[faceI] = faceNeighbour_[faceI];
2293  faceNeighbour_[faceI] = own;
2294  faces_[faceI] = faces_[faceI].reverseFace();
2295  }
2296 
2297  // And check the face
2298  const face& f = faces_[faceI];
2299 
2300  forAll(f, fp)
2301  {
2302  if (f[fp] < 0 || f[fp] >= points_.size())
2303  {
2305  << "face:" << faceI << " f:" << f
2306  << abort(FatalError);
2307  }
2308  }
2309  }
2310 
2311  // Do upper-triangular ordering
2312  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2313  labelList oldToNew(faceOwner_.size(), -1);
2314 
2315  // Create cells (inverse of face-to-cell addressing)
2316  cellList cellFaceAddr;
2317  primitiveMesh::calcCells
2318  (
2319  cellFaceAddr,
2320  faceOwner_,
2321  faceNeighbour_,
2322  nCells_
2323  );
2324 
2325  label newFaceI = 0;
2326  forAll(cellFaceAddr, cellI)
2327  {
2328  const labelList& cFaces = cellFaceAddr[cellI];
2329  SortableList<label> nbr(cFaces.size(), -1);
2330 
2331  forAll(cFaces, i)
2332  {
2333  label faceI = cFaces[i];
2334  label nbrCellI = faceNeighbour_[faceI];
2335 
2336  if (nbrCellI >= 0)
2337  {
2338  // Internal face. Get cell on other side
2339  if (nbrCellI == cellI)
2340  {
2341  nbrCellI = faceOwner_[faceI];
2342  }
2343 
2344  // cellI is master
2345  if (cellI < nbrCellI)
2346  {
2347  nbr[i] = nbrCellI;
2348  }
2349  }
2350  }
2351 
2352  nbr.sort();
2353 
2354  forAll(nbr, i)
2355  {
2356  if (nbr[i] >= 0)
2357  {
2358  oldToNew[cFaces[nbr.indices()[i]]] = newFaceI++;
2359  }
2360  }
2361  }
2362 
2363  // Reorder faces accordingly
2364  inplaceReorder(oldToNew, faces_);
2365  inplaceReorder(oldToNew, faceOwner_);
2366  inplaceReorder(oldToNew, faceNeighbour_);
2367  inplaceReorder(oldToNew, origFaceId_);
2368 
2369  forAllIters(monitoringSets_, iter)
2370  {
2371  labelList& lst = iter.val();
2372  inplaceRenumber(oldToNew, lst);
2373 
2374  // disallow monitoring on boundaries
2375  label nElem = 0;
2376  forAll(lst, i)
2377  {
2378  if (lst[i] >= 0 && lst[i] < nInternalFaces_)
2379  {
2380  if (nElem != i)
2381  {
2382  lst[nElem] = lst[i];
2383  }
2384  ++nElem;
2385  }
2386  }
2387 
2388  if (nElem)
2389  {
2390  lst.setSize(nElem);
2391  }
2392  else
2393  {
2394  Info << "remove monitor " << iter.key() << endl;
2395  monitoringSets_.erase(iter);
2396  }
2397  }
2398 }
2399 
2400 
2401 // Attach patches
2402 //
2403 // - patchSizes_ : obvious
2404 // - origBndId_ : lookup for patch name/type
2405 //
2406 void Foam::ccm::reader::addPatches
2407 (
2408  polyMesh& mesh
2409 ) const
2410 {
2411  // Create patches
2412  // use patch types to determine what Foam types to generate
2413  List<polyPatch*> newPatches(origBndId_.size());
2414 
2415  label meshFaceI = nInternalFaces_;
2416  wordHashSet hashedNames(origBndId_.size());
2417 
2418  // lookup patch names/types from the problem description
2419  // provide some fallback values
2420  forAll(newPatches, patchI)
2421  {
2422  const word fallbackName(polyPatch::defaultName(patchI));
2423  word patchName;
2424  word patchType;
2425 
2426  auto citer = boundaryRegion_.cfind(origBndId_[patchI]);
2427 
2428  if (citer.found())
2429  {
2430  citer().readEntry("Label", patchName);
2431  citer().readEntry("BoundaryType", patchType);
2432  }
2433  else
2434  {
2435  patchName = fallbackName;
2436  patchType = "patch";
2437  }
2438 
2439  // Avoid duplicate names
2440  // - don't bother checking if the modified name is also a duplicate
2441  if (hashedNames.found(patchName))
2442  {
2443  Info<< "renamed patch " << patchName << " to ";
2444  patchName = fallbackName + "_" + patchName;
2445  Info<< patchName << endl;
2446  }
2447  hashedNames.insert(patchName);
2448 
2449  Info<< "patch " << patchI
2450  << " (start: " << meshFaceI << " size: " << patchSizes_[patchI]
2451  << ") name: " << patchName
2452  << endl;
2453 
2454  if (patchType == "wall")
2455  {
2456  newPatches[patchI] =
2457  new wallPolyPatch
2458  (
2459  patchName,
2460  patchSizes_[patchI],
2461  meshFaceI,
2462  patchI,
2463  mesh.boundaryMesh(),
2464  patchType
2465  );
2466  }
2467  else if (patchType == "symmetry")
2468  {
2469  newPatches[patchI] =
2470  new symmetryPolyPatch
2471  (
2472  patchName,
2473  patchSizes_[patchI],
2474  meshFaceI,
2475  patchI,
2476  mesh.boundaryMesh(),
2477  patchType
2478  );
2479  }
2480  else if (patchType == "empty")
2481  {
2482  // Note: not ccm name, may have been introduced by us
2483  newPatches[patchI] =
2484  new emptyPolyPatch
2485  (
2486  patchName,
2487  patchSizes_[patchI],
2488  meshFaceI,
2489  patchI,
2490  mesh.boundaryMesh(),
2491  patchType
2492  );
2493  }
2494  else
2495  {
2496  // All other ccm types become straight polyPatch:
2497  // 'inlet', 'outlet', 'pressure'.
2498  newPatches[patchI] =
2499  new polyPatch
2500  (
2501  patchName,
2502  patchSizes_[patchI],
2503  meshFaceI,
2504  patchI,
2505  mesh.boundaryMesh(),
2506  patchType
2507  );
2508  }
2509 
2510  meshFaceI += patchSizes_[patchI];
2511  }
2512 
2513  if (meshFaceI != mesh.nFaces())
2514  {
2516  << "meshFaceI:" << meshFaceI << " nFaces:" << mesh.nFaces()
2517  << abort(FatalError);
2518  }
2519 
2520  mesh.addPatches(newPatches);
2521 }
2522 
2523 
2524 
2525 // Attach faceZones based on the monitoring boundary conditions
2526 void Foam::ccm::reader::addFaceZones
2527 (
2528  polyMesh& mesh
2529 ) const
2530 {
2531  label nZone = monitoringSets_.size();
2532  mesh.faceZones().setSize(nZone);
2533 
2534  if (!nZone)
2535  {
2536  return;
2537  }
2538 
2539  nZone = 0;
2540  forAllConstIters(monitoringSets_, iter)
2541  {
2542  Info<< "faceZone " << nZone
2543  << " (size: " << iter().size() << ") name: "
2544  << iter.key() << endl;
2545 
2546  mesh.faceZones().set
2547  (
2548  nZone,
2549  new faceZone
2550  (
2551  iter.key(),
2552  iter(),
2553  false, // none are flipped
2554  nZone,
2555  mesh.faceZones()
2556  )
2557  );
2558 
2559  ++nZone;
2560  }
2561 
2562  mesh.faceZones().writeOpt() = IOobject::AUTO_WRITE;
2563  warnDuplicates("faceZones", mesh.faceZones().names());
2564 }
2565 
2566 
2567 // Remove most of the ccm-specific information with the exception of information
2568 // auxiliary to the normal polyMesh:
2569 // (cellTableId_, origCellId_, origFaceId_, interfaces_, ...)
2571 {
2572  // allow re-reading the file
2573  if (geometryStatus_ == OKAY || geometryStatus_ == READ)
2574  {
2575  geometryStatus_ = UNKNOWN;
2576  }
2577 
2578  points_.clear();
2579  faces_.clear();
2580  faceOwner_.clear();
2581  faceNeighbour_.clear();
2582 
2583  origBndId_.clear();
2584  patchSizes_.clear();
2585 }
2586 
2587 
2588 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2589 
2592  const objectRegistry& registry,
2593  const fileName& remappingDictName
2594 )
2595 {
2596  if (!readGeometry())
2597  {
2598  return nullptr;
2599  }
2600 
2601  // merge cellTable and rename boundaryRegion
2602  remapMeshInfo(registry, remappingDictName);
2603 
2604  // Construct polyMesh
2605  // ~~~~~~~~~~~~~~~~~~
2607  (
2608  IOobject
2609  (
2611  "constant",
2612  registry,
2615  ),
2616  std::move(points_),
2617  std::move(faces_),
2618  std::move(faceOwner_),
2619  std::move(faceNeighbour_)
2620  );
2621  polyMesh& mesh = *meshPtr;
2622 
2623  addPatches(mesh);
2624 
2625  // Attach cellZones based on the cellTable Id
2626  // any other values can be extracted later from the cellTable dictionary
2627  cellTable_.addCellZones(mesh, cellTableId_);
2628  warnDuplicates("cellZones", mesh.cellZones().names());
2629 
2630  addFaceZones(mesh);
2631 
2632  warnDuplicates("boundaries", mesh.boundaryMesh().names());
2633  clearGeom();
2634 
2635  return meshPtr;
2636 }
2637 
2638 
2639 // ************************************************************************* //
Foam::autoPtr::New
static autoPtr< T > New(Args &&... args)
Construct autoPtr of T with forwarding arguments.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
Foam::IOobject
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:104
meshPtr
Foam::autoPtr< Foam::fvMesh > meshPtr(nullptr)
Foam::IOobject::AUTO_WRITE
Definition: IOobject.H:129
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
uindirectPrimitivePatch.H
nPatches
label nPatches
Definition: readKivaGrid.H:396
Foam::polyMesh::defaultRegion
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:318
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
wallPolyPatch.H
symmetryPolyPatch.H
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
bitSet.H
Foam::ccm::reader::clearGeom
void clearGeom()
Clear out some information after obtaining a polyMesh.
Definition: ccmReaderMesh.C:2570
Foam::invert
labelList invert(const label len, const labelUList &map)
Create an inverse one-to-one mapping.
Definition: ListOps.C:36
Foam::inplaceRenumber
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:61
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Foam::face::compare
static int compare(const face &a, const face &b)
Compare faces.
Definition: face.C:300
Foam::labelPair
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
Foam::objectRegistry
Registry of regIOobjects.
Definition: objectRegistry.H:60
Foam::flush
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:342
SortableList.H
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::cellList
List< cell > cellList
A List of cells.
Definition: cellListFwd.H:47
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
forAllIters
#define forAllIters(container, iter)
Iterate across all elements in the container object.
Definition: stdFoam.H:223
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
stdFoam::end
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:121
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
emptyPolyPatch.H
Foam::mergePoints
label mergePoints(const PointList &points, const scalar mergeTol, const bool verbose, labelList &pointMap, typename PointList::const_reference origin=PointList::value_type::zero)
Sorts and merges points. All points closer than/equal mergeTol get merged.
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
IOdictionary.H
Foam::autoPtr< Foam::polyMesh >
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:381
Foam::nl
constexpr char nl
Definition: Ostream.H:385
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Fstream.H
f
labelList f(nPoints)
Foam::List< label >
Foam::identity
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Definition: labelList.C:38
mergePoints.H
Merge points. See below.
Foam::wordHashSet
HashSet< word > wordHashSet
A HashSet with word keys.
Definition: HashSet.H:406
ccmBoundaryInfo.H
Container for holding STARCCM boundary information.
Foam::inplaceReorder
void inplaceReorder(const labelUList &oldToNew, ListType &input, const bool prune=false)
Inplace reorder the elements of a list.
Definition: ListOpsTemplates.C:124
ccmReader.H
patchId
label patchId(-1)
ListOps.H
Various functions to operate on Lists.
Foam::uindirectPrimitivePatch
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
Definition: uindirectPrimitivePatch.H:49
Foam::labelUList
UList< label > labelUList
A UList of labels.
Definition: UList.H:80
Foam::patchIdentifier::defaultName
static word defaultName(const label n=-1)
Default patch name: "patch" or "patchN".
Definition: patchIdentifier.H:75
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys and label hasher.
Definition: HashSet.H:409
Foam::ccm::reader::mesh
autoPtr< polyMesh > mesh(const objectRegistry &registry, const fileName &remappingDictName=fileName::null)
Construct the polyMesh from the read geometry.
Definition: ccmReaderMesh.C:2591
Foam::IOobject::NO_READ
Definition: IOobject.H:123
Foam::pos
dimensionedScalar pos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:177