/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . Description Construct a cell shape from face information \*---------------------------------------------------------------------------*/ #include "cellShapeRecognition.H" #include "labelList.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // cellShape create3DCellShape ( const label cellIndex, const labelList& faceLabels, const faceList& faces, const labelList& owner, const labelList& neighbour, const label fluentCellModelID ) { // List of pointers to shape models for 3-D shape recognition static List fluentCellModelLookup ( 7, nullptr ); fluentCellModelLookup[2] = cellModel::ptr(cellModel::TET); fluentCellModelLookup[4] = cellModel::ptr(cellModel::HEX); fluentCellModelLookup[5] = cellModel::ptr(cellModel::PYR); fluentCellModelLookup[6] = cellModel::ptr(cellModel::PRISM); static label faceMatchingOrder[7][6] = { {-1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1}, { 0, 1, 2, 3, -1, -1}, // tet {-1, -1, -1, -1, -1, -1}, { 0, 2, 4, 3, 5, 1}, // hex { 0, 1, 2, 3, 4, -1}, // pyr { 0, 2, 3, 4, 1, -1}, // prism }; const cellModel& curModel = *fluentCellModelLookup[fluentCellModelID]; // Checking if (faceLabels.size() != curModel.nFaces()) { FatalErrorInFunction << "Number of face labels not equal to" << "number of face in the model. " << "Number of face labels: " << faceLabels.size() << " number of faces in model: " << curModel.nFaces() << abort(FatalError); } // make a list of outward-pointing faces labelListList localFaces(faceLabels.size()); forAll(faceLabels, facei) { const label curFaceLabel = faceLabels[facei]; const labelList& curFace = faces[curFaceLabel]; if (owner[curFaceLabel] == cellIndex) { localFaces[facei] = curFace; } else if (neighbour[curFaceLabel] == cellIndex) { // Reverse the face localFaces[facei].setSize(curFace.size()); forAllReverse(curFace, i) { localFaces[facei][curFace.size() - i - 1] = curFace[i]; } } else { FatalErrorInFunction << "face " << curFaceLabel << " does not belong to cell " << cellIndex << ". Face owner: " << owner[curFaceLabel] << " neighbour: " << neighbour[curFaceLabel] << abort(FatalError); } } // Algorithm: // Make an empty list of pointLabels and initialise it with -1. Pick the // first face from modelFaces and look through the faces to find one with // the same number of labels. Insert face by copying its labels into // pointLabels. Mark the face as used. Loop through all model faces. // For each model face loop through faces. If the face is unused and the // numbers of labels fit, try to match the face onto the point labels. If // at least one edge is matched, insert the face into pointLabels. If at // any stage the matching algorithm reaches the end of faces, the matching // algorithm has failed. Once all the faces are matched, the list of // pointLabels defines the model. // Make a list of empty pointLabels labelList pointLabels(curModel.nPoints(), -1); // Follow the used mesh faces List meshFaceUsed(localFaces.size(), false); // Get the raw model faces const faceList& modelFaces = curModel.modelFaces(); // Insert the first face into the list const labelList& firstModelFace = modelFaces[faceMatchingOrder[fluentCellModelID][0]]; bool found = false; forAll(localFaces, meshFacei) { if (localFaces[meshFacei].size() == firstModelFace.size()) { // Match. Insert points into the pointLabels found = true; const labelList& curMeshFace = localFaces[meshFacei]; meshFaceUsed[meshFacei] = true; forAll(curMeshFace, pointi) { pointLabels[firstModelFace[pointi]] = curMeshFace[pointi]; } break; } } if (!found) { FatalErrorInFunction << "Cannot find match for first face. " << "cell model: " << curModel.name() << " first model face: " << firstModelFace << " Mesh faces: " << localFaces << abort(FatalError); } for (label modelFacei = 1; modelFacei < modelFaces.size(); modelFacei++) { // get the next model face const labelList& curModelFace = modelFaces [faceMatchingOrder[fluentCellModelID][modelFacei]]; found = false; // Loop through mesh faces until a match is found forAll(localFaces, meshFacei) { if ( !meshFaceUsed[meshFacei] && localFaces[meshFacei].size() == curModelFace.size() ) { // A possible match. A mesh face will be rotated, so make a copy labelList meshFaceLabels = localFaces[meshFacei]; for ( label rotation = 0; rotation < meshFaceLabels.size(); rotation++ ) { // try matching the face label nMatchedLabels = 0; forAll(meshFaceLabels, pointi) { if ( pointLabels[curModelFace[pointi]] == meshFaceLabels[pointi] ) { nMatchedLabels++; } } if (nMatchedLabels >= 2) { // match! found = true; } if (found) { // match found. Insert mesh face forAll(meshFaceLabels, pointi) { pointLabels[curModelFace[pointi]] = meshFaceLabels[pointi]; } meshFaceUsed[meshFacei] = true; break; } else { // No match found. Rotate face label firstLabel = meshFaceLabels[0]; for (label i = 1; i < meshFaceLabels.size(); i++) { meshFaceLabels[i - 1] = meshFaceLabels[i]; } meshFaceLabels.last() = firstLabel; } } if (found) break; } } if (!found) { // A model face is not matched. Shape detection failed FatalErrorInFunction << "Cannot find match for face " << modelFacei << ".\nModel: " << curModel.name() << " model face: " << curModelFace << " Mesh faces: " << localFaces << "Matched points: " << pointLabels << abort(FatalError); } } return cellShape(curModel, pointLabels); } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace Foam // ************************************************************************* //