/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2015-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- 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 . \*---------------------------------------------------------------------------*/ #include "distributedTriSurfaceMesh.H" #include "mapDistribute.H" #include "Random.H" #include "addToRunTimeSelectionTable.H" #include "triangleFuncs.H" #include "matchPoints.H" #include "globalIndex.H" #include "Time.H" #include "IFstream.H" #include "decompositionMethod.H" #include "geomDecomp.H" #include "vectorList.H" #include "bitSet.H" #include "PatchTools.H" #include "OBJstream.H" #include "labelBits.H" #include "profiling.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { defineTypeNameAndDebug(distributedTriSurfaceMesh, 0); addToRunTimeSelectionTable ( searchableSurface, distributedTriSurfaceMesh, dict ); //- Combine operator for volume types class volumeCombineOp { public: void operator()(volumeType& x, const volumeType& y) const { if (x == volumeType::MIXED || y == volumeType::MIXED) { FatalErrorInFunction << "Illegal volume type " << volumeType::names[x] << "," << volumeType::names[y] << exit(FatalError); } else { switch (x) { case volumeType::UNKNOWN: { if (y == volumeType::INSIDE || y == volumeType::OUTSIDE) { x = y; } } break; case volumeType::INSIDE: { if (y == volumeType::OUTSIDE) { FatalErrorInFunction << "Conflicting volume types " << volumeType::names[x] << "," << volumeType::names[y] << exit(FatalError); } } break; case volumeType::OUTSIDE: { if (y == volumeType::INSIDE) { FatalErrorInFunction << "Conflicting volume types " << volumeType::names[x] << "," << volumeType::names[y] << exit(FatalError); } } break; case volumeType::MIXED: break; } } } }; //- Combine operator for nearest typedef Tuple2 nearestAndDist; const nearestAndDist nearestZero ( nearestAndDist ( pointIndexHit(), -GREAT ) ); class nearestEqOp { public: void operator()(nearestAndDist& x, const nearestAndDist& y) const { if (x.first().hit()) { if (y.first().hit() && y.second() < x.second()) { x = y; } } else if (y.first().hit()) { x = y; } } }; } const Foam::Enum < Foam::distributedTriSurfaceMesh::distributionType > Foam::distributedTriSurfaceMesh::distributionTypeNames_ ({ { distributionType::FOLLOW, "follow" }, { distributionType::INDEPENDENT, "independent" }, { distributionType::DISTRIBUTED, "distributed" }, { distributionType::FROZEN, "frozen" } }); // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // Foam::word Foam::distributedTriSurfaceMesh::findLocalInstance ( const IOobject& io ) { // Modified findInstance which also looks in parent directory word instance ( io.time().findInstance ( io.local(), word::null, IOobject::READ_IF_PRESENT ) ); if (instance.size()) { return instance; } // Replicate findInstance operation but now on parent directory // Search in parent directory fileName parentDir = io.rootPath()/io.time().globalCaseName() /io.instance()/io.db().dbDir()/io.local()/io.name(); if (fileHandler().isDir(parentDir)) { return io.instance(); } instantList ts = io.time().times(); label instanceI; const scalar startValue = io.time().timeOutputValue(); for (instanceI = ts.size()-1; instanceI >= 0; --instanceI) { if (ts[instanceI].value() <= startValue) { break; } } // continue searching from here for (; instanceI >= 0; --instanceI) { // Shortcut: if actual directory is the timeName we've already tested it if (ts[instanceI].name() == io.instance()) { continue; } fileName parentDir = io.rootPath()/io.time().globalCaseName() /ts[instanceI].name()/io.db().dbDir()/io.local()/io.name(); if (fileHandler().isDir(parentDir)) { return ts[instanceI].name(); } } // times() usually already includes the constant() so would have been // checked above. Re-test if // - times() is empty. Sometimes this can happen (e.g. decomposePar with // collated) // - times()[0] is not constant if (!ts.size() || ts[0].name() != io.time().constant()) { // Note. This needs to be a hard-coded constant, rather than the // constant function of the time, because the latter points to // the case constant directory in parallel cases fileName parentDir = io.rootPath()/io.time().globalCaseName() /io.time().constant()/io.db().dbDir()/io.local()/io.name(); if (fileHandler().isDir(parentDir)) { return io.time().constant(); } } FatalErrorInFunction << "Cannot find directory " << io.local() << " in times " << ts << exit(FatalError); return word::null; } // Read my additional data from the dictionary bool Foam::distributedTriSurfaceMesh::read() { // Get bb of all domains. procBb_.setSize(Pstream::nProcs()); if (dict_.empty()) { // Did not find the distributed version; assume master has loaded the // triSurfaceMesh version. Make up some settings. const boundBox& localBb = triSurfaceMesh::bounds(); procBb_[Pstream::myProcNo()] = treeBoundBoxList(1, treeBoundBox(localBb)); Pstream::gatherList(procBb_); Pstream::scatterList(procBb_); dict_.add("bounds", procBb_[Pstream::myProcNo()]); // Wanted distribution type distType_ = DISTRIBUTED; //INDEPENDENT; dict_.add("distributionType", distributionTypeNames_[distType_]); // Merge distance mergeDist_ = SMALL; dict_.add("mergeDistance", mergeDist_); // Force underlying triSurfaceMesh to calculate volume type // (is topological walk; does not construct tree) surfaceClosed_ = triSurfaceMesh::hasVolumeType(); Pstream::scatter(surfaceClosed_); dict_.add("closed", surfaceClosed_); // Delay calculating outside vol type since constructs tree. Is ok // after distributing since then local surfaces much smaller //outsideVolType_ = volumeType::UNKNOWN; //if (surfaceClosed_) //{ // point outsidePt(localBb.max()+localBb.midpoint()); // List outsideVolTypes; // triSurfaceMesh::getVolumeType // ( // pointField(1, outsidePt), // outsideVolTypes // ); // outsideVolType_ = outsideVolTypes[0]; //} //dict_.add("outsideVolumeType", volumeType::names[outsideVolType_]); } else { dict_.readEntry("bounds", procBb_[Pstream::myProcNo()]); Pstream::gatherList(procBb_); Pstream::scatterList(procBb_); // Wanted distribution type distType_ = distributionTypeNames_.get("distributionType", dict_); // Merge distance dict_.readEntry("mergeDistance", mergeDist_); // Distribution type surfaceClosed_ = dict_.getOrDefault("closed", false); outsideVolType_ = volumeType::names.getOrDefault ( "outsideVolumeType", dict_, volumeType::UNKNOWN ); } return true; } // Is segment fully local? bool Foam::distributedTriSurfaceMesh::isLocal ( const List& myBbs, const point& start, const point& end ) { forAll(myBbs, bbi) { if (myBbs[bbi].contains(start) && myBbs[bbi].contains(end)) { return true; } } return false; } //void Foam::distributedTriSurfaceMesh::splitSegment //( // const label segmenti, // const point& start, // const point& end, // const treeBoundBox& bb, // // DynamicList& allSegments, // DynamicList