openfoam/src/OpenFOAM/global/fileOperations/uncollatedFileOperation/uncollatedFileOperation.C
Mark Olesen d34dfbe0b7 ENH: dummy fileOperation: placeholder for interfaces taking a reference
STYLE: align readOnProc/writeOnProc naming within masterUncollated
2023-05-23 11:12:37 +02:00

808 lines
19 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017 OpenFOAM Foundation
Copyright (C) 2020-2023 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "uncollatedFileOperation.H"
#include "Time.H"
#include "Fstream.H"
#include "addToRunTimeSelectionTable.H"
#include "decomposedBlockData.H"
#include "dummyISstream.H"
#include "unthreadedInitialise.H"
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
namespace Foam
{
namespace fileOperations
{
defineTypeNameAndDebug(uncollatedFileOperation, 0);
addToRunTimeSelectionTable
(
fileOperation,
uncollatedFileOperation,
word
);
addToRunTimeSelectionTable
(
fileOperation,
uncollatedFileOperation,
comm
);
// Mark as not needing threaded mpi
addNamedToRunTimeSelectionTable
(
fileOperationInitialise,
unthreadedInitialise,
word,
uncollated
);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::fileName Foam::fileOperations::uncollatedFileOperation::filePathInfo
(
const bool checkGlobal,
const bool isFile,
const IOobject& io,
const bool search
) const
{
if (io.instance().isAbsolute())
{
fileName objectPath(io.instance()/io.name());
if (isFileOrDir(isFile, objectPath))
{
return objectPath;
}
}
else
{
fileName path(io.path());
fileName objectPath(path/io.name());
if (isFileOrDir(isFile, objectPath))
{
return objectPath;
}
else
{
if
(
checkGlobal
&& io.time().processorCase()
&& (
io.instance() == io.time().system()
|| io.instance() == io.time().constant()
)
)
{
// Constant & system can come from global case
fileName parentObjectPath =
io.rootPath()/io.time().globalCaseName()
/io.instance()/io.db().dbDir()/io.local()/io.name();
if (isFileOrDir(isFile, parentObjectPath))
{
return parentObjectPath;
}
}
// Check if parallel "procesors" directory
if (io.time().processorCase())
{
refPtr<dirIndexList> pDirs
(
fileOperation::lookupAndCacheProcessorsPath
(
io.objectPath(),
false // No additional parallel synchronisation
)
);
for (const dirIndex& dirIdx : pDirs())
{
const fileName& pDir = dirIdx.first();
fileName objPath =
processorsPath(io, io.instance(), pDir)
/io.name();
if (objPath != objectPath && isFileOrDir(isFile, objPath))
{
return objPath;
}
}
}
// Check for approximately same time. E.g. if time = 1e-2 and
// directory is 0.01 (due to different time formats)
if (search && !Foam::isDir(path))
{
word newInstancePath = io.time().findInstancePath
(
instant(io.instance())
);
if (newInstancePath.size())
{
fileName fName
(
io.rootPath()/io.caseName()
/newInstancePath/io.db().dbDir()/io.local()/io.name()
);
if (isFileOrDir(isFile, fName))
{
return fName;
}
}
}
}
}
return fileName();
}
Foam::refPtr<Foam::fileOperation::dirIndexList>
Foam::fileOperations::uncollatedFileOperation::lookupProcessorsPath
(
const fileName& fName
) const
{
// No additional parallel synchronisation
return fileOperation::lookupAndCacheProcessorsPath(fName, false);
}
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Construction helper: self/world/local communicator and IO ranks
static Tuple2<label, labelList> getCommPattern()
{
// Default is COMM_SELF (only involves itself)
Tuple2<label, labelList> commAndIORanks
(
UPstream::selfComm,
fileOperation::getGlobalIORanks()
);
if (UPstream::parRun() && commAndIORanks.second().size() > 1)
{
// Multiple masters: ranks for my IO range
commAndIORanks.first() = UPstream::allocateCommunicator
(
UPstream::worldComm,
fileOperation::subRanks(commAndIORanks.second())
);
}
return commAndIORanks;
}
} // End namespace Foam
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
void Foam::fileOperations::uncollatedFileOperation::init(bool verbose)
{
verbose = (verbose && Foam::infoDetailLevel > 0);
if (verbose)
{
DetailInfo
<< "I/O : " << typeName << endl;
}
}
Foam::fileOperations::uncollatedFileOperation::uncollatedFileOperation
(
bool verbose
)
:
fileOperation
(
getCommPattern()
),
managedComm_(getManagedComm(comm_)) // Possibly locally allocated
{
init(verbose);
}
Foam::fileOperations::uncollatedFileOperation::uncollatedFileOperation
(
const Tuple2<label, labelList>& commAndIORanks,
const bool distributedRoots,
bool verbose
)
:
fileOperation(commAndIORanks, distributedRoots),
managedComm_(-1) // Externally managed
{
init(verbose);
}
void Foam::fileOperations::uncollatedFileOperation::storeComm() const
{
// From externally -> locally managed
managedComm_ = getManagedComm(comm_);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::fileOperations::uncollatedFileOperation::~uncollatedFileOperation()
{
// Wait for any outstanding file operations
flush();
UPstream::freeCommunicator(managedComm_);
}
// * * * * * * * * * * * * * Filesystem Operations * * * * * * * * * * * * * //
bool Foam::fileOperations::uncollatedFileOperation::mkDir
(
const fileName& dir,
mode_t mode
) const
{
return Foam::mkDir(dir, mode);
}
bool Foam::fileOperations::uncollatedFileOperation::chMod
(
const fileName& fName,
mode_t mode
) const
{
return Foam::chMod(fName, mode);
}
mode_t Foam::fileOperations::uncollatedFileOperation::mode
(
const fileName& fName,
const bool followLink
) const
{
return Foam::mode(fName, followLink);
}
Foam::fileName::Type Foam::fileOperations::uncollatedFileOperation::type
(
const fileName& fName,
const bool followLink
) const
{
return Foam::type(fName, followLink);
}
bool Foam::fileOperations::uncollatedFileOperation::exists
(
const fileName& fName,
const bool checkGzip,
const bool followLink
) const
{
return Foam::exists(fName, checkGzip, followLink);
}
bool Foam::fileOperations::uncollatedFileOperation::isDir
(
const fileName& fName,
const bool followLink
) const
{
return Foam::isDir(fName, followLink);
}
bool Foam::fileOperations::uncollatedFileOperation::isFile
(
const fileName& fName,
const bool checkGzip,
const bool followLink
) const
{
return Foam::isFile(fName, checkGzip, followLink);
}
off_t Foam::fileOperations::uncollatedFileOperation::fileSize
(
const fileName& fName,
const bool followLink
) const
{
return Foam::fileSize(fName, followLink);
}
time_t Foam::fileOperations::uncollatedFileOperation::lastModified
(
const fileName& fName,
const bool followLink
) const
{
return Foam::lastModified(fName, followLink);
}
double Foam::fileOperations::uncollatedFileOperation::highResLastModified
(
const fileName& fName,
const bool followLink
) const
{
return Foam::highResLastModified(fName, followLink);
}
bool Foam::fileOperations::uncollatedFileOperation::mvBak
(
const fileName& fName,
const std::string& ext
) const
{
return Foam::mvBak(fName, ext);
}
bool Foam::fileOperations::uncollatedFileOperation::rm
(
const fileName& fName
) const
{
return Foam::rm(fName);
}
bool Foam::fileOperations::uncollatedFileOperation::rmDir
(
const fileName& dir,
const bool silent,
const bool emptyOnly
) const
{
return Foam::rmDir(dir, silent, emptyOnly);
}
Foam::fileNameList Foam::fileOperations::uncollatedFileOperation::readDir
(
const fileName& dir,
const fileName::Type type,
const bool filtergz,
const bool followLink
) const
{
return Foam::readDir(dir, type, filtergz, followLink);
}
bool Foam::fileOperations::uncollatedFileOperation::cp
(
const fileName& src,
const fileName& dst,
const bool followLink
) const
{
return Foam::cp(src, dst, followLink);
}
bool Foam::fileOperations::uncollatedFileOperation::ln
(
const fileName& src,
const fileName& dst
) const
{
return Foam::ln(src, dst);
}
bool Foam::fileOperations::uncollatedFileOperation::mv
(
const fileName& src,
const fileName& dst,
const bool followLink
) const
{
return Foam::mv(src, dst, followLink);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::fileName Foam::fileOperations::uncollatedFileOperation::filePath
(
const bool checkGlobal,
const IOobject& io,
const word& typeName,
const bool search
) const
{
if (debug)
{
Pout<< "uncollatedFileOperation::filePath :"
<< " objectPath:" << io.objectPath()
<< " checkGlobal:" << checkGlobal << endl;
}
fileName objPath(filePathInfo(checkGlobal, true, io, search));
if (debug)
{
Pout<< "uncollatedFileOperation::filePath :"
<< " Returning from file searching:" << endl
<< " objectPath:" << io.objectPath() << endl
<< " filePath :" << objPath << endl << endl;
}
return objPath;
}
Foam::fileName Foam::fileOperations::uncollatedFileOperation::dirPath
(
const bool checkGlobal,
const IOobject& io,
const bool search
) const
{
if (debug)
{
Pout<< "uncollatedFileOperation::dirPath :"
<< " objectPath:" << io.objectPath()
<< " checkGlobal:" << checkGlobal << endl;
}
fileName objPath(filePathInfo(checkGlobal, false, io, search));
if (debug)
{
Pout<< "uncollatedFileOperation::dirPath :"
<< " Returning from directory searching:" << endl
<< " objectPath:" << io.objectPath() << endl
<< " dirPath :" << objPath << endl << endl;
}
return objPath;
}
Foam::fileNameList Foam::fileOperations::uncollatedFileOperation::readObjects
(
const objectRegistry& db,
const fileName& instance,
const fileName& local,
word& newInstance
) const
{
if (debug)
{
Pout<< "uncollatedFileOperation::readObjects :"
<< " db:" << db.objectPath()
<< " instance:" << instance << endl;
}
//- Use non-time searching version
fileNameList objectNames
(
fileOperation::readObjects(db, instance, local, newInstance)
);
if (newInstance.empty())
{
// Find similar time
fileName newInst = db.time().findInstancePath(instant(instance));
if (!newInst.empty() && newInst != instance)
{
// Try with new time
objectNames = fileOperation::readObjects
(
db,
newInst,
local,
newInstance
);
}
}
if (debug)
{
Pout<< "uncollatedFileOperation::readObjects :"
<< " newInstance:" << newInstance
<< " objectNames:" << objectNames << endl;
}
return objectNames;
}
bool Foam::fileOperations::uncollatedFileOperation::readHeader
(
IOobject& io,
const fileName& fName,
const word& typeName
) const
{
if (debug)
{
Pout<< "uncollatedFileOperation::readHeader :"
<< " fName:" << fName
<< " typeName:" << typeName << endl;
}
if (fName.empty())
{
if (IOobject::debug)
{
InfoInFunction
<< "file " << io.objectPath() << " could not be opened"
<< endl;
}
return false;
}
autoPtr<ISstream> isPtr(NewIFstream(fName));
if (!isPtr || !isPtr->good())
{
return false;
}
// Regular header or from decomposed data
bool ok = decomposedBlockData::readHeader(io, *isPtr);
if (debug)
{
Pout<< "uncollatedFileOperation::readHeader :"
<< " for fName:" << fName
<< " ok:" << ok
<< " headerClassName:" << io.headerClassName() << endl;
}
return ok;
}
Foam::autoPtr<Foam::ISstream>
Foam::fileOperations::uncollatedFileOperation::readStream
(
regIOobject& io,
const fileName& fName,
const word& typeName,
const bool readOnProc
) const
{
if (!readOnProc)
{
return autoPtr<ISstream>(new dummyISstream());
}
if (fName.empty())
{
FatalErrorInFunction
<< "cannot find file " << io.objectPath()
<< exit(FatalError);
}
autoPtr<ISstream> isPtr = NewIFstream(fName);
if (!isPtr || !isPtr->good())
{
FatalIOError
(
"uncollatedFileOperation::readStream()",
__FILE__,
__LINE__,
fName,
0
) << "cannot open file"
<< exit(FatalIOError);
}
else if (!io.readHeader(*isPtr))
{
FatalIOErrorInFunction(*isPtr)
<< "problem while reading header for object " << io.name()
<< exit(FatalIOError);
}
if (!decomposedBlockData::isCollatedType(io))
{
// Short circuit: non-collated format.
return isPtr;
}
else
{
// Analyse the objectpath to find out the processor we're trying
// to access
label proci = detectProcessorPath(io.objectPath());
if (proci == -1)
{
FatalIOErrorInFunction(*isPtr)
<< "could not detect processor number"
<< " from objectPath:" << io.objectPath()
<< " fName:" << fName
<< exit(FatalIOError);
}
// Analyse the fileName for any processor subset. Note: this
// should really be part of filePath() which should return
// both file and index in file.
fileName path, procDir, local;
procRangeType group;
label nProcs;
splitProcessorPath(fName, path, procDir, local, group, nProcs);
// The local rank (offset)
if (!group.empty())
{
proci = proci - group.start();
}
// Read data and return as stream
return decomposedBlockData::readBlock(proci, *isPtr, io);
}
}
bool Foam::fileOperations::uncollatedFileOperation::read
(
regIOobject& io,
const bool masterOnly,
const IOstreamOption::streamFormat format,
const word& typeName
) const
{
bool ok = false;
if (!masterOnly || Pstream::master(UPstream::worldComm))
{
if (debug)
{
Pout<< "uncollatedFileOperation::read :"
<< " Reading object " << io.objectPath()
<< " from file " << endl;
}
// Set flag for e.g. codeStream
const bool oldGlobal = io.globalObject(masterOnly);
// If codeStream originates from dictionary which is
// not IOdictionary we have a problem so use global
const bool oldMasterOnly = regIOobject::masterOnlyReading;
regIOobject::masterOnlyReading = masterOnly;
// Read file
ok = io.readData(io.readStream(typeName));
io.close();
// Restore flags
io.globalObject(oldGlobal);
regIOobject::masterOnlyReading = oldMasterOnly;
if (debug)
{
Pout<< "uncollatedFileOperation::read :"
<< " Done reading object " << io.objectPath()
<< " from file " << endl;
}
}
if (masterOnly && Pstream::parRun())
{
Pstream::broadcasts
(
UPstream::worldComm,
io.headerClassName(),
io.note()
);
if (UPstream::master(UPstream::worldComm))
{
OPBstream toAll
(
UPstream::masterNo(),
UPstream::worldComm,
format
);
bool okWrite = io.writeData(toAll);
ok = ok && okWrite;
}
else
{
IPBstream fromMaster
(
UPstream::masterNo(),
UPstream::worldComm,
format
);
ok = io.readData(fromMaster);
}
}
return ok;
}
Foam::autoPtr<Foam::ISstream>
Foam::fileOperations::uncollatedFileOperation::NewIFstream
(
const fileName& filePath
) const
{
return autoPtr<ISstream>(new IFstream(filePath));
}
Foam::autoPtr<Foam::OSstream>
Foam::fileOperations::uncollatedFileOperation::NewOFstream
(
const fileName& pathName,
IOstreamOption streamOpt,
const bool writeOnProc
) const
{
return autoPtr<OSstream>(new OFstream(pathName, streamOpt));
}
Foam::autoPtr<Foam::OSstream>
Foam::fileOperations::uncollatedFileOperation::NewOFstream
(
IOstreamOption::atomicType atomic,
const fileName& pathName,
IOstreamOption streamOpt,
const bool writeOnProc
) const
{
return autoPtr<OSstream>(new OFstream(atomic, pathName, streamOpt));
}
// ************************************************************************* //