1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
25 Reads CCM files as written by Prostar/ccm using ccm 2.6 (not 2.4)
27 - does polyhedral mesh
28 - does not handle 'interfaces' (couples)
29 - does not handle cyclics. Use createPatch to recreate these
31 - does patch names only if they are in the problem description
33 \*---------------------------------------------------------------------------*/
39 #include "volFields.H"
40 #include "emptyPolyPatch.H"
41 #include "symmetryPolyPatch.H"
42 #include "wallPolyPatch.H"
43 #include "SortableList.H"
51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
53 static char const kDefaultState[] = "default";
54 static int const kVertOffset = 2;
57 // Determine upper-triangular order for internal faces:
58 labelList getInternalFaceOrder
60 const cellList& cells,
61 const labelList& owner,
62 const labelList& neighbour
65 labelList oldToNew(owner.size(), -1);
67 // First unassigned face
72 const labelList& cFaces = cells[cellI];
74 SortableList<label> nbr(cFaces.size());
78 label faceI = cFaces[i];
80 label nbrCellI = neighbour[faceI];
84 // Internal face. Get cell on other side.
85 if (nbrCellI == cellI)
87 nbrCellI = owner[faceI];
97 // nbrCell is master. Let it handle this face.
103 // External face. Do later.
114 oldToNew[cFaces[nbr.indices()[i]]] = newFaceI++;
119 // Keep boundary faces in same order.
120 for (label faceI = newFaceI; faceI < owner.size(); faceI++)
122 oldToNew[faceI] = faceI;
132 const label cellType,
133 Map<label>& typeToZone,
134 List<DynamicList<label> >& zoneCells
139 Map<label>::iterator zoneFnd = typeToZone.find(cellType);
141 if (zoneFnd == typeToZone.end())
143 // New type. Allocate zone for it.
144 zoneCells.setSize(zoneCells.size() + 1);
146 label zoneI = zoneCells.size()-1;
148 Info<< "Mapping type " << cellType << " to Foam cellZone "
150 typeToZone.insert(cellType, zoneI);
152 zoneCells[zoneI].append(cellI);
156 // Existing zone for type
157 zoneCells[zoneFnd()].append(cellI);
163 void CheckError(CCMIOError const &err, const Foam::string& str)
165 if (err != kCCMIONoErr)
167 FatalErrorIn("CheckError")
168 << str << exit(FatalError);
177 labelList& foamPointMap,
178 pointField& foamPoints
181 // Read the vertices. This involves reading both the vertex data and
182 // the map, which maps the index into the data array with the ID number.
183 // As we process the vertices we need to be sure to scale them by the
184 // appropriate scaling factor. The offset is just to show you can read
185 // any chunk. Normally this would be in a for loop.
188 CCMIOEntitySize(&err, vertices, &nVertices, NULL);
190 List<int> mapData(nVertices, 0);
191 List<float> verts(3*nVertices, 0);
194 int offsetPlusSize = offset+nVertices;
199 CCMIOReadVerticesf(&err, vertices, &dims, &scale, &mapID, verts.begin(),
200 offset, offsetPlusSize);
201 CCMIOReadMap(&err, mapID, mapData.begin(), offset, offsetPlusSize);
204 //CCMIOEntityDescription(&err, vertices, &size, NULL);
205 //char *desc = new char[size + 1];
206 //CCMIOEntityDescription(&err, vertices, NULL, desc);
207 //Pout<< "label: '" << desc << "'" << endl;
210 // Convert to foamPoints
211 foamPoints.setSize(nVertices);
212 foamPoints = vector::zero;
213 foamPointMap.setSize(nVertices);
215 forAll(foamPointMap, i)
217 foamPointMap[i] = mapData[i];
218 for (direction cmpt = 0; cmpt < dims; cmpt++)
220 foamPoints[i][cmpt] = verts[dims*i + cmpt]*scale;
231 const Map<label>& prostarToFoamPatch,
232 Map<word>& foamCellTypeNames,
233 wordList& foamPatchTypes,
234 wordList& foamPatchNames
237 // ... walk through each cell type and print it...
242 CCMIONextEntity(NULL, problem, kCCMIOCellType, &i, &next)
250 // ... if it has a material type. (Note that we do not pass in
251 // an array to get the name because we do not know how long the
252 // string is yet. Many parameters to CCMIO functions that
254 // data can be NULL if that data is not needed.)
257 CCMIOReadOptstr(NULL, next, "MaterialType", &size, NULL)
261 name = new char[size + 1];
262 CCMIOReadOptstr(&err, next, "MaterialType", &size, name);
263 CCMIOGetEntityIndex(&err, next, &cellType);
265 foamCellTypeNames.insert(cellType, name);
266 Pout<< "Celltype:" << cellType << " name:" << name << endl;
272 // ... walk through each region description and print it...
280 CCMIONextEntity(NULL, problem, kCCMIOBoundaryRegion, &k, &boundary)
284 // Index of foam patch
285 label foamPatchI = -1;
292 CCMIOReadOpti(NULL, boundary, "ProstarRegionNumber", &prostarI)
296 Pout<< "For region:" << regionI
297 << " found ProstarRegionNumber:" << prostarI << endl;
303 Pout<< "For region:" << regionI
304 << "did not find ProstarRegionNumber entry. Assuming "
309 if (prostarToFoamPatch.found(prostarI))
311 foamPatchI = prostarToFoamPatch[prostarI];
313 // Read boundary type
318 CCMIOReadOptstr(NULL, boundary, "BoundaryType", &size, NULL)
322 char* s = new char[size + 1];
323 CCMIOReadOptstr(NULL, boundary, "BoundaryType", &size, s);
325 foamPatchTypes[foamPatchI] = string::validate<word>(string(s));
330 //foamPatchMap.append(prostarI);
333 // Read boundary name:
334 // - from BoundaryName field (Prostar)
335 // - from 'Label' field (ccm+?)
336 // - make up one from prostar id.
340 CCMIOReadOptstr(NULL, boundary, "BoundaryName", &size, NULL)
344 char* name = new char[size + 1];
345 CCMIOReadOptstr(NULL, boundary, "BoundaryName", &size, name);
347 foamPatchNames[foamPatchI] =
348 string::validate<word>(string(name));
354 CCMIOReadOptstr(NULL, boundary, "Label", &size, NULL)
358 char* name = new char[size + 1];
359 CCMIOReadOptstr(NULL, boundary, "Label", &size, name);
361 foamPatchNames[foamPatchI] =
362 string::validate<word>(string(name));
367 foamPatchNames[foamPatchI] =
368 foamPatchTypes[foamPatchI]
369 + Foam::name(foamPatchI);
370 Pout<< "Made up name:" << foamPatchNames[foamPatchI]
374 Pout<< "Read patch:" << foamPatchI
375 << " name:" << foamPatchNames[foamPatchI]
376 << " foamPatchTypes:" << foamPatchTypes[foamPatchI]
389 labelList& foamCellMap,
390 labelList& foamCellType,
391 Map<label>& prostarToFoamPatch,
392 DynamicList<label>& foamPatchSizes,
393 DynamicList<label>& foamPatchStarts,
394 labelList& foamFaceMap,
395 labelList& foamOwner,
396 labelList& foamNeighbour,
403 // Store cell IDs so that we know what cells are in
406 CCMIOGetEntity(&err, topology, kCCMIOCells, 0, &id);
408 CCMIOEntitySize(&err, id, &nCells, NULL);
410 std::vector<int> mapData(nCells);
411 std::vector<int> cellType(nCells);
414 CCMIOReadCells(&err, id, &mapID, &cellType[0], 0, nCells);
415 CCMIOReadMap(&err, mapID, &mapData[0], 0, nCells);
416 CheckError(err, "Error reading cells");
418 foamCellMap.setSize(nCells);
419 foamCellType.setSize(nCells);
420 forAll(foamCellMap, i)
422 foamCellMap[i] = mapData[i];
423 foamCellType[i] = cellType[i];
427 // Read the internal faces.
428 // ~~~~~~~~~~~~~~~~~~~~~~~~
430 CCMIOGetEntity(&err, topology, kCCMIOInternalFaces, 0, &id);
431 CCMIOSize nInternalFaces;
432 CCMIOEntitySize(&err, id, &nInternalFaces, NULL);
433 Pout<< "nInternalFaces:" << nInternalFaces << endl;
435 // Determine patch sizes before reading internal faces
436 label foamNFaces = nInternalFaces;
440 CCMIONextEntity(NULL, topology, kCCMIOBoundaryFaces, &index, &id)
445 CCMIOEntitySize(&err, id, &size, NULL);
447 Pout<< "Read kCCMIOBoundaryFaces entry with " << size
448 << " faces." << endl;
450 foamPatchStarts.append(foamNFaces);
451 foamPatchSizes.append(size);
454 foamPatchStarts.shrink();
455 foamPatchSizes.shrink();
457 Pout<< "patchSizes:" << foamPatchSizes << endl;
458 Pout<< "patchStarts:" << foamPatchStarts << endl;
459 Pout<< "nFaces:" << foamNFaces << endl;
461 mapData.resize(nInternalFaces);
462 CCMIOGetEntity(&err, topology, kCCMIOInternalFaces, 0, &id);
464 CCMIOReadFaces(&err, id, kCCMIOInternalFaces, NULL, &size, NULL,
465 kCCMIOStart, kCCMIOEnd);
466 std::vector<int> faces(size);
467 CCMIOReadFaces(&err, id, kCCMIOInternalFaces, &mapID, NULL, &faces[0],
468 kCCMIOStart, kCCMIOEnd);
469 std::vector<int> faceCells(2*nInternalFaces);
470 CCMIOReadFaceCells(&err, id, kCCMIOInternalFaces, &faceCells[0],
471 kCCMIOStart, kCCMIOEnd);
472 CCMIOReadMap(&err, mapID, &mapData[0], kCCMIOStart, kCCMIOEnd);
473 CheckError(err, "Error reading internal faces");
475 // Copy into Foam lists
476 foamFaceMap.setSize(foamNFaces);
477 foamFaces.setSize(foamNFaces);
478 foamOwner.setSize(foamNFaces);
479 foamNeighbour.setSize(foamNFaces);
481 unsigned int pos = 0;
483 for (unsigned int faceI = 0; faceI < nInternalFaces; faceI++)
485 foamFaceMap[faceI] = mapData[faceI];
486 foamOwner[faceI] = faceCells[2*faceI];
487 foamNeighbour[faceI] = faceCells[2*faceI+1];
488 face& f = foamFaces[faceI];
490 f.setSize(faces[pos++]);
493 f[fp] = faces[pos++];
497 // Read the boundary faces.
498 // ~~~~~~~~~~~~~~~~~~~~~~~~
504 CCMIONextEntity(NULL, topology, kCCMIOBoundaryFaces, &index, &id)
509 CCMIOEntitySize(&err, id, &nFaces, NULL);
511 mapData.resize(nFaces);
512 faceCells.resize(nFaces);
513 CCMIOReadFaces(&err, id, kCCMIOBoundaryFaces, NULL, &size, NULL,
514 kCCMIOStart, kCCMIOEnd);
516 CCMIOReadFaces(&err, id, kCCMIOBoundaryFaces, &mapID, NULL, &faces[0],
517 kCCMIOStart, kCCMIOEnd);
518 CCMIOReadFaceCells(&err, id, kCCMIOBoundaryFaces, &faceCells[0],
519 kCCMIOStart, kCCMIOEnd);
520 CCMIOReadMap(&err, mapID, &mapData[0], kCCMIOStart, kCCMIOEnd);
521 CheckError(err, "Error reading boundary faces");
527 CCMIOReadOpti(NULL, id, "ProstarRegionNumber", &prostarI)
531 Pout<< "For region:" << regionI
532 << " found ProstarRegionNumber:" << prostarI << endl;
538 Pout<< "For region:" << regionI
539 << " did not find ProstarRegionNumber entry. Assuming "
542 prostarToFoamPatch.insert(prostarI, regionI);
545 Pout<< "region:" << regionI
546 << " ProstarRegionNumber:" << prostarI
547 << " foamPatchStart:"
548 << foamPatchStarts[regionI]
550 << foamPatchSizes[regionI]
553 // Copy into Foam list.
554 unsigned int pos = 0;
556 for (unsigned int i = 0; i < nFaces; i++)
558 label foamFaceI = foamPatchStarts[regionI] + i;
560 foamFaceMap[foamFaceI] = mapData[i];
561 foamOwner[foamFaceI] = faceCells[i];
562 foamNeighbour[foamFaceI] = -1;
563 face& f = foamFaces[foamFaceI];
565 f.setSize(faces[pos++]);
568 f[fp] = faces[pos++];
580 int main(int argc, char *argv[])
582 argList::noParallel();
583 argList::validArgs.append("ccm26 file");
585 # include "setRootCase.H"
586 # include "createTime.H"
593 pointField foamPoints;
594 labelList foamPointMap;
597 labelList foamCellType;
598 labelList foamCellMap;
601 Map<label> prostarToFoamPatch;
602 DynamicList<label> foamPatchSizes;
603 DynamicList<label> foamPatchStarts;
605 labelList foamFaceMap;
607 labelList foamNeighbour;
610 // Celltypes (not the names of the zones; just the material type)
611 // and patch type names
612 Map<word> foamCellTypeNames;
613 wordList foamPatchTypes;
614 wordList foamPatchNames;
617 fileName ccmFile(args.additionalArgs()[0]);
619 if (!isFile(ccmFile))
621 FatalErrorIn(args.executable())
622 << "Cannot read file " << ccmFile
626 word ccmExt = ccmFile.ext();
628 if (ccmExt != "ccm" && ccmExt != "ccmg")
630 FatalErrorIn(args.executable())
631 << "Illegal extension " << ccmExt << " for file " << ccmFile
632 << nl << "Allowed extensions are '.ccm', '.ccmg'"
636 // Open the file. Because we did not initialize 'err' we need to pass
637 // in NULL (which always means kCCMIONoErr) and then assign the return
641 CCMIOOpenFile(NULL, ccmFile.c_str(), kCCMIORead, &root);
643 // We are going to assume that we have a state with a known name.
644 // We could instead use CCMIONextEntity() to walk through all the
645 // states in the file and present the list to the user for selection.
648 CCMIONextEntity(&err, root, kCCMIOState, &stateI, &state);
649 CheckError(err, "Error opening state");
652 CCMIOEntityDescription(&err, state, &size, NULL);
653 char *desc = new char[size + 1];
654 CCMIOEntityDescription(&err, state, NULL, desc);
655 Pout<< "Reading state '" << kDefaultState << "' (" << desc << ")"
659 // Find the first processor (i has previously been initialized to 0)
660 // and read the mesh and solution information.
663 CCMIONextEntity(&err, state, kCCMIOProcessor, &i, &processor);
664 CCMIOID solution, vertices, topology;
675 if (err != kCCMIONoErr)
677 // Maybe no solution; try again
688 if (err != kCCMIONoErr)
690 FatalErrorIn(args.executable())
691 << "Could not read the file."
696 ReadVertices(err, vertices, foamPointMap, foamPoints);
698 Pout<< "nPoints:" << foamPoints.size() << endl
699 << "bounding box:" << boundBox(foamPoints) << endl
717 Pout<< "nCells:" << foamCellMap.size() << endl
718 << "nFaces:" << foamOwner.size() << endl
719 << "nPatches:" << foamPatchStarts.size() << endl
720 << "nInternalFaces:" << foamPatchStarts[0] << endl
723 // Create some default patch names/types. These will be overwritten
724 // by any problem desciption (if it is there)
725 foamPatchTypes.setSize(foamPatchStarts.size());
726 foamPatchNames.setSize(foamPatchStarts.size());
728 forAll(foamPatchNames, i)
730 foamPatchNames[i] = word("patch") + Foam::name(i);
731 foamPatchTypes[i] = "patch";
734 // Get problem description
742 kCCMIOProblemDescription,
746 CheckError(err, "Error stepping to first problem description");
748 if (CCMIOIsValidEntity(problem)) // if we have a problem description
763 CCMIOCloseFile(&err, vertices);
764 CCMIOCloseFile(&err, topology);
765 CCMIOCloseFile(&err, solution);
766 CCMIOCloseFile(&err, root);
770 Pout<< "foamPatchNames:" << foamPatchNames << endl;
773 Pout<< "foamOwner : min:" << min(foamOwner)
774 << " max:" << max(foamOwner)
776 << "foamNeighbour : min:" << min(foamNeighbour)
777 << " max:" << max(foamNeighbour)
779 << "foamCellType : min:" << min(foamCellType)
780 << " max:" << max(foamCellType)
785 // We now have extracted all info from CCMIO:
786 // - coordinates (points)
787 // - face to point addressing (faces)
788 // - face to cell addressing (owner, neighbour)
789 // - cell based data (cellId)
792 // Renumber vertex labels to Foam point labels
794 label maxCCMPointI = max(foamPointMap);
795 labelList toFoamPoints(invert(maxCCMPointI+1, foamPointMap));
797 forAll(foamFaces, faceI)
799 inplaceRenumber(toFoamPoints, foamFaces[faceI]);
803 // Renumber cell labels
805 label maxCCMCellI = max(foamCellMap);
806 labelList toFoamCells(invert(maxCCMCellI+1, foamCellMap));
808 inplaceRenumber(toFoamCells, foamOwner);
809 inplaceRenumber(toFoamCells, foamNeighbour);
814 // Basic mesh info complete. Now convert to Foam convention:
815 // - owner < neighbour
816 // - face vertices such that normal points away from owner
817 // - order faces: upper-triangular for internal faces; boundary faces after
821 // Set owner/neighbour so owner < neighbour
822 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
824 forAll(foamNeighbour, faceI)
826 label nbr = foamNeighbour[faceI];
827 label own = foamOwner[faceI];
829 if (nbr >= foamCellType.size() || own >= foamCellType.size())
831 FatalErrorIn(args.executable())
835 << " nCells:" << foamCellType.size()
843 foamOwner[faceI] = foamNeighbour[faceI];
844 foamNeighbour[faceI] = own;
845 foamFaces[faceI] = foamFaces[faceI].reverseFace();
850 // And check the face
851 const face& f = foamFaces[faceI];
855 if (f[fp] < 0 || f[fp] >= foamPoints.size())
857 FatalErrorIn(args.executable()) << "face:" << faceI
858 << " f:" << f << abort(FatalError);
864 // Do upper-triangular ordering
865 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
868 // Create cells (inverse of face-to-cell addressing)
870 primitiveMesh::calcCells
878 // Determine face order for upper-triangular ordering
889 // Reorder faces accordingly
890 forAll(foamCells, cellI)
892 inplaceRenumber(oldToNew, foamCells[cellI]);
896 inplaceReorder(oldToNew, foamFaces);
897 inplaceReorder(oldToNew, foamOwner);
898 inplaceReorder(oldToNew, foamNeighbour);
909 fvMesh::defaultRegion,
913 xferMove<pointField>(foamPoints),
914 xferMove<faceList>(foamFaces),
915 xferCopy<labelList>(foamOwner),
916 xferMove<labelList>(foamNeighbour)
919 // Create patches. Use patch types to determine what Foam types to generate.
920 List<polyPatch*> newPatches(foamPatchNames.size());
922 label meshFaceI = foamPatchStarts[0];
924 forAll(newPatches, patchI)
926 const word& patchName = foamPatchNames[patchI];
927 const word& patchType = foamPatchTypes[patchI];
929 Pout<< "Patch:" << patchName << " start at:" << meshFaceI
930 << " size:" << foamPatchSizes[patchI]
931 << " end at:" << meshFaceI+foamPatchSizes[patchI]
934 if (patchType == "wall")
940 foamPatchSizes[patchI],
946 else if (patchType == "symmetryplane")
949 new symmetryPolyPatch
952 foamPatchSizes[patchI],
958 else if (patchType == "empty")
960 // Note: not ccm name, introduced by us above.
965 foamPatchSizes[patchI],
973 // All other ccm types become straight polyPatch:
974 // 'inlet', 'outlet', 'pressured'.
979 foamPatchSizes[patchI],
986 meshFaceI += foamPatchSizes[patchI];
989 if (meshFaceI != foamOwner.size())
991 FatalErrorIn(args.executable())
992 << "meshFaceI:" << meshFaceI
993 << " nFaces:" << foamOwner.size()
994 << abort(FatalError);
996 mesh.addFvPatches(newPatches);
1000 // Construct sets and zones from types
1001 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1003 label maxType = max(foamCellType);
1004 label minType = min(foamCellType);
1006 if (maxType > minType)
1008 // From foamCellType physical region to Foam cellZone
1009 Map<label> typeToZone;
1010 // Storage for cell zones.
1011 List<DynamicList<label> > zoneCells(0);
1013 forAll(foamCellType, cellI)
1018 foamCellType[cellI],
1024 mesh.cellZones().clear();
1025 mesh.cellZones().setSize(typeToZone.size());
1027 label nValidCellZones = 0;
1029 forAllConstIter(Map<label>, typeToZone, iter)
1031 label type = iter.key();
1032 label zoneI = iter();
1034 zoneCells[zoneI].shrink();
1036 word zoneName = "cellZone_" + name(type);
1038 Info<< "Writing zone " << type
1039 << " size " << zoneCells[zoneI].size()
1041 << zoneName << " and cellSet " << zoneName
1044 cellSet cset(mesh, zoneName, labelHashSet(zoneCells[zoneI]));
1047 mesh.cellZones().set
1060 mesh.cellZones().writeOpt() = IOobject::AUTO_WRITE;
1064 Info<< "Writing mesh to " << mesh.objectRegistry::objectPath()
1065 << "..." << nl << endl;
1068 // Construct field with calculated bc to hold Star cell Id.
1069 volScalarField cellIdField
1077 IOobject::AUTO_WRITE
1080 dimensionedScalar("cellId", dimless, 0.0)
1083 forAll(foamCellMap, cellI)
1085 cellIdField[cellI] = foamCellMap[cellI];
1088 // Construct field with calculated bc to hold cell type.
1089 volScalarField cellTypeField
1097 IOobject::AUTO_WRITE
1100 dimensionedScalar("cellType", dimless, 0.0)
1103 forAll(foamCellType, cellI)
1105 cellTypeField[cellI] = foamCellType[cellI];
1108 Info<< "Writing cellIds as volScalarField to " << cellIdField.objectPath()
1109 << "..." << nl << endl;
1112 Info<< "End\n" << endl;
1118 // ************************************************************************* //