mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
Improvements to existing functionality
--------------------------------------
- MPI is initialised without thread support if it is not needed e.g. uncollated
- Use native c++11 threading; avoids problem with static destruction order.
- etc/cellModels now only read if needed.
- etc/controlDict can now be read from the environment variable FOAM_CONTROLDICT
- Uniform files (e.g. '0/uniform/time') are now read only once on the master only
(with the masterUncollated or collated file handlers)
- collated format writes to 'processorsNNN' instead of 'processors'. The file
format is unchanged.
- Thread buffer and file buffer size are no longer limited to 2Gb.
The global controlDict file contains parameters for file handling. Under some
circumstances, e.g. running in parallel on a system without NFS, the user may
need to set some parameters, e.g. fileHandler, before the global controlDict
file is read from file. To support this, OpenFOAM now allows the global
controlDict to be read as a string set to the FOAM_CONTROLDICT environment
variable.
The FOAM_CONTROLDICT environment variable can be set to the content the global
controlDict file, e.g. from a sh/bash shell:
export FOAM_CONTROLDICT=$(foamDictionary $FOAM_ETC/controlDict)
FOAM_CONTROLDICT can then be passed to mpirun using the -x option, e.g.:
mpirun -np 2 -x FOAM_CONTROLDICT simpleFoam -parallel
Note that while this avoids the need for NFS to read the OpenFOAM configuration
the executable still needs to load shared libraries which must either be copied
locally or available via NFS or equivalent.
New: Multiple IO ranks
----------------------
The masterUncollated and collated fileHandlers can now use multiple ranks for
writing e.g.:
mpirun -np 6 simpleFoam -parallel -ioRanks '(0 3)'
In this example ranks 0 ('processor0') and 3 ('processor3') now handle all the
I/O. Rank 0 handles 0,1,2 and rank 3 handles 3,4,5. The set of IO ranks should always
include 0 as first element and be sorted in increasing order.
The collated fileHandler uses the directory naming processorsNNN_XXX-YYY where
NNN is the total number of processors and XXX and YYY are first and last
processor in the rank, e.g. in above example the directories would be
processors6_0-2
processors6_3-5
and each of the collated files in these contains data of the local ranks
only. The same naming also applies when e.g. running decomposePar:
decomposePar -fileHandler collated -ioRanks '(0 3)'
New: Distributed data
---------------------
The individual root directories can be placed on different hosts with different
paths if necessary. In the current framework it is necessary to specify the
root per slave process but this has been simplified with the option of specifying
the root per host with the -hostRoots command line option:
mpirun -np 6 simpleFoam -parallel -ioRanks '(0 3)' \
-hostRoots '("machineA" "/tmp/" "machineB" "/tmp")'
The hostRoots option is followed by a list of machine name + root directory, the
machine name can contain regular expressions.
New: hostCollated
-----------------
The new hostCollated fileHandler automatically sets the 'ioRanks' according to
the host name with the lowest rank e.g. to run simpleFoam on 6 processors with
ranks 0-2 on machineA and ranks 3-5 on machineB with the machines specified in
the hostfile:
mpirun -np 6 --hostfile hostfile simpleFoam -parallel -fileHandler hostCollated
This is equivalent to
mpirun -np 6 --hostfile hostfile simpleFoam -parallel -fileHandler collated -ioRanks '(0 3)'
This example will write directories:
processors6_0-2/
processors6_3-5/
A typical example would use distributed data e.g. no two nodes, machineA and
machineB, each with three processes:
decomposePar -fileHandler collated -case cavity
# Copy case (constant/*, system/*, processors6/) to master:
rsync -a cavity machineA:/tmp/
# Create root on slave:
ssh machineB mkdir -p /tmp/cavity
# Run
mpirun --hostfile hostfile icoFoam \
-case /tmp/cavity -parallel -fileHandler hostCollated \
-hostRoots '("machineA" "/tmp" "machineB" "/tmp")'
Contributed by Mattijs Janssens
590 lines
16 KiB
C++
590 lines
16 KiB
C++
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration |
|
|
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
|
|
\\/ M anipulation | Copyright (C) 2015-2016 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/>.
|
|
|
|
Class
|
|
Foam::UPstream
|
|
|
|
Description
|
|
Inter-processor communications stream
|
|
|
|
SourceFiles
|
|
UPstream.C
|
|
UPstreamCommsStruct.C
|
|
gatherScatter.C
|
|
combineGatherScatter.C
|
|
gatherScatterList.C
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#ifndef UPstream_H
|
|
#define UPstream_H
|
|
|
|
#include "labelList.H"
|
|
#include "DynamicList.H"
|
|
#include "HashTable.H"
|
|
#include "string.H"
|
|
#include "Enum.H"
|
|
#include "ListOps.H"
|
|
#include "LIFOStack.H"
|
|
|
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
|
|
namespace Foam
|
|
{
|
|
|
|
/*---------------------------------------------------------------------------*\
|
|
Class UPstream Declaration
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
class UPstream
|
|
{
|
|
|
|
public:
|
|
|
|
//- Types of communications
|
|
enum class commsTypes
|
|
{
|
|
blocking,
|
|
scheduled,
|
|
nonBlocking
|
|
};
|
|
|
|
//- Names of the communication types
|
|
static const Enum<commsTypes> commsTypeNames;
|
|
|
|
// Public classes
|
|
|
|
//- Structure for communicating between processors
|
|
class commsStruct
|
|
{
|
|
// Private data
|
|
|
|
//- procID of above processor
|
|
label above_;
|
|
|
|
//- procIDs of processors directly below me
|
|
labelList below_;
|
|
|
|
//- procIDs of all processors below (so not just directly below)
|
|
labelList allBelow_;
|
|
|
|
//- procIDs of all processors not below.
|
|
// (inverse set of allBelow_ and minus myProcNo)
|
|
labelList allNotBelow_;
|
|
|
|
|
|
public:
|
|
|
|
// Constructors
|
|
|
|
//- Construct null
|
|
commsStruct();
|
|
|
|
//- Construct from components
|
|
commsStruct
|
|
(
|
|
const label above,
|
|
const labelList& below,
|
|
const labelList& allBelow,
|
|
const labelList& allNotBelow
|
|
);
|
|
|
|
//- Construct from components; construct allNotBelow_
|
|
commsStruct
|
|
(
|
|
const label nProcs,
|
|
const label myProcID,
|
|
const label above,
|
|
const labelList& below,
|
|
const labelList& allBelow
|
|
);
|
|
|
|
|
|
// Member Functions
|
|
|
|
// Access
|
|
|
|
label above() const
|
|
{
|
|
return above_;
|
|
}
|
|
|
|
const labelList& below() const
|
|
{
|
|
return below_;
|
|
}
|
|
|
|
const labelList& allBelow() const
|
|
{
|
|
return allBelow_;
|
|
}
|
|
|
|
const labelList& allNotBelow() const
|
|
{
|
|
return allNotBelow_;
|
|
}
|
|
|
|
|
|
// Member operators
|
|
|
|
bool operator==(const commsStruct&) const;
|
|
|
|
bool operator!=(const commsStruct&) const;
|
|
|
|
|
|
// Ostream Operator
|
|
|
|
friend Ostream& operator<<(Ostream&, const commsStruct&);
|
|
};
|
|
|
|
|
|
//- combineReduce operator for lists. Used for counting.
|
|
class listEq
|
|
{
|
|
|
|
public:
|
|
|
|
template<class T>
|
|
void operator()(T& x, const T& y) const
|
|
{
|
|
forAll(y, i)
|
|
{
|
|
if (y[i].size())
|
|
{
|
|
x[i] = y[i];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
private:
|
|
|
|
// Private data
|
|
|
|
//- By default this is not a parallel run
|
|
static bool parRun_;
|
|
|
|
//- Have support for threads?
|
|
static bool haveThreads_;
|
|
|
|
//- Standard transfer message type
|
|
static int msgType_;
|
|
|
|
// Communicator specific data
|
|
|
|
//- Free communicators
|
|
static LIFOStack<label> freeComms_;
|
|
|
|
//- My processor number
|
|
static DynamicList<int> myProcNo_;
|
|
|
|
//- List of process IDs
|
|
static DynamicList<List<int>> procIDs_;
|
|
|
|
//- Parent communicator
|
|
static DynamicList<label> parentCommunicator_;
|
|
|
|
//- Linear communication schedule
|
|
static DynamicList<List<commsStruct>> linearCommunication_;
|
|
|
|
//- Multi level communication schedule
|
|
static DynamicList<List<commsStruct>> treeCommunication_;
|
|
|
|
|
|
// Private Member Functions
|
|
|
|
//- Set data for parallel running
|
|
static void setParRun(const label nProcs, const bool haveThreads);
|
|
|
|
//- Calculate linear communication schedule
|
|
static List<commsStruct> calcLinearComm(const label nProcs);
|
|
|
|
//- Calculate tree communication schedule
|
|
static List<commsStruct> calcTreeComm(const label nProcs);
|
|
|
|
//- Helper function for tree communication schedule determination
|
|
// Collects all processorIDs below a processor
|
|
static void collectReceives
|
|
(
|
|
const label procID,
|
|
const List<DynamicList<label>>& receives,
|
|
DynamicList<label>& allReceives
|
|
);
|
|
|
|
//- Allocate a communicator with index
|
|
static void allocatePstreamCommunicator
|
|
(
|
|
const label parentIndex,
|
|
const label index
|
|
);
|
|
|
|
//- Free a communicator
|
|
static void freePstreamCommunicator
|
|
(
|
|
const label index
|
|
);
|
|
|
|
|
|
protected:
|
|
|
|
// Protected data
|
|
|
|
//- Communications type of this stream
|
|
commsTypes commsType_;
|
|
|
|
public:
|
|
|
|
// Declare name of the class and its debug switch
|
|
ClassName("UPstream");
|
|
|
|
|
|
// Static data
|
|
|
|
//- Should compact transfer be used in which floats replace doubles
|
|
//- reducing the bandwidth requirement at the expense of some loss
|
|
//- in accuracy
|
|
static bool floatTransfer;
|
|
|
|
//- Number of processors at which the sum algorithm changes from linear
|
|
//- to tree
|
|
static int nProcsSimpleSum;
|
|
|
|
//- Default commsType
|
|
static commsTypes defaultCommsType;
|
|
|
|
//- Number of polling cycles in processor updates
|
|
static int nPollProcInterfaces;
|
|
|
|
//- Optional maximum message size (bytes)
|
|
static int maxCommsSize;
|
|
|
|
//- MPI buffer-size (bytes)
|
|
static const int mpiBufferSize;
|
|
|
|
//- Default communicator (all processors)
|
|
static label worldComm;
|
|
|
|
//- Debugging: warn for use of any communicator differing from warnComm
|
|
static label warnComm;
|
|
|
|
|
|
// Constructors
|
|
|
|
//- Construct given optional buffer size
|
|
UPstream(const commsTypes commsType)
|
|
:
|
|
commsType_(commsType)
|
|
{}
|
|
|
|
|
|
// Member functions
|
|
|
|
//- Allocate a new communicator
|
|
static label allocateCommunicator
|
|
(
|
|
const label parent,
|
|
const labelList& subRanks,
|
|
const bool doPstream = true
|
|
);
|
|
|
|
//- Free a previously allocated communicator
|
|
static void freeCommunicator
|
|
(
|
|
const label communicator,
|
|
const bool doPstream = true
|
|
);
|
|
|
|
//- Free all communicators
|
|
static void freeCommunicators(const bool doPstream);
|
|
|
|
//- Helper class for allocating/freeing communicators
|
|
class communicator
|
|
{
|
|
label comm_;
|
|
|
|
//- Disallow copy and assignment
|
|
communicator(const communicator&);
|
|
void operator=(const communicator&);
|
|
|
|
public:
|
|
|
|
communicator
|
|
(
|
|
const label parent,
|
|
const labelList& subRanks,
|
|
const bool doPstream
|
|
)
|
|
:
|
|
comm_(allocateCommunicator(parent, subRanks, doPstream))
|
|
{}
|
|
|
|
~communicator()
|
|
{
|
|
freeCommunicator(comm_);
|
|
}
|
|
|
|
operator label() const
|
|
{
|
|
return comm_;
|
|
}
|
|
};
|
|
|
|
//- Return physical processor number (i.e. processor number in
|
|
//- worldComm) given communicator and procssor
|
|
static int baseProcNo(const label myComm, const int procID);
|
|
|
|
//- Return processor number in communicator (given physical processor
|
|
//- number) (= reverse of baseProcNo)
|
|
static label procNo(const label comm, const int baseProcID);
|
|
|
|
//- Return processor number in communicator (given processor number
|
|
//- and communicator)
|
|
static label procNo
|
|
(
|
|
const label myComm,
|
|
const label currentComm,
|
|
const int currentProcID
|
|
);
|
|
|
|
//- Add the valid option this type of communications library
|
|
//- adds/requires on the command line
|
|
static void addValidParOptions(HashTable<string>& validParOptions);
|
|
|
|
//- Initialisation function called from main
|
|
// Spawns slave processes and initialises inter-communication
|
|
static bool init(int& argc, char**& argv, const bool needsThread);
|
|
|
|
//- Special purpose initialisation function.
|
|
// Performs a basic MPI_Init without any other setup.
|
|
// Only used for applications that need MPI communication when
|
|
// OpenFOAM is running in a non-parallel mode.
|
|
// \note Behaves as a no-op if MPI has already been initialized.
|
|
// Fatal if MPI has already been finalized.
|
|
static bool initNull();
|
|
|
|
// Non-blocking comms
|
|
|
|
//- Get number of outstanding requests
|
|
static label nRequests();
|
|
|
|
//- Truncate number of outstanding requests
|
|
static void resetRequests(const label sz);
|
|
|
|
//- Wait until all requests (from start onwards) have finished.
|
|
static void waitRequests(const label start = 0);
|
|
|
|
//- Wait until request i has finished.
|
|
static void waitRequest(const label i);
|
|
|
|
//- Non-blocking comms: has request i finished?
|
|
static bool finishedRequest(const label i);
|
|
|
|
static int allocateTag(const char*);
|
|
|
|
static int allocateTag(const word&);
|
|
|
|
static void freeTag(const char*, const int tag);
|
|
|
|
static void freeTag(const word&, const int tag);
|
|
|
|
|
|
//- Is this a parallel run?
|
|
static bool& parRun()
|
|
{
|
|
return parRun_;
|
|
}
|
|
|
|
//- Have support for threads
|
|
static bool haveThreads()
|
|
{
|
|
return haveThreads_;
|
|
}
|
|
|
|
//- Number of processes in parallel run
|
|
static label nProcs(const label communicator = 0)
|
|
{
|
|
return procIDs_[communicator].size();
|
|
}
|
|
|
|
//- Process index of the master
|
|
static int masterNo()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//- Am I the master process
|
|
static bool master(const label communicator = 0)
|
|
{
|
|
return myProcNo_[communicator] == masterNo();
|
|
}
|
|
|
|
//- Number of this process (starting from masterNo() = 0)
|
|
static int myProcNo(const label communicator = 0)
|
|
{
|
|
return myProcNo_[communicator];
|
|
}
|
|
|
|
static label parent(const label communicator)
|
|
{
|
|
return parentCommunicator_(communicator);
|
|
}
|
|
|
|
//- Process ID of given process index
|
|
static List<int>& procID(label communicator)
|
|
{
|
|
return procIDs_[communicator];
|
|
}
|
|
|
|
//- Process index of first slave
|
|
static int firstSlave()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
//- Process index of last slave
|
|
static int lastSlave(const label communicator = 0)
|
|
{
|
|
return nProcs(communicator) - 1;
|
|
}
|
|
|
|
//- Communication schedule for linear all-to-master (proc 0)
|
|
static const List<commsStruct>& linearCommunication
|
|
(
|
|
const label communicator = 0
|
|
)
|
|
{
|
|
return linearCommunication_[communicator];
|
|
}
|
|
|
|
//- Communication schedule for tree all-to-master (proc 0)
|
|
static const List<commsStruct>& treeCommunication
|
|
(
|
|
const label communicator = 0
|
|
)
|
|
{
|
|
return treeCommunication_[communicator];
|
|
}
|
|
|
|
//- Message tag of standard messages
|
|
static int& msgType()
|
|
{
|
|
return msgType_;
|
|
}
|
|
|
|
|
|
//- Get the communications type of the stream
|
|
commsTypes commsType() const
|
|
{
|
|
return commsType_;
|
|
}
|
|
|
|
//- Set the communications type of the stream
|
|
commsTypes commsType(const commsTypes ct)
|
|
{
|
|
commsTypes oldCommsType = commsType_;
|
|
commsType_ = ct;
|
|
return oldCommsType;
|
|
}
|
|
|
|
|
|
//- Exit program
|
|
static void exit(int errnum = 1);
|
|
|
|
//- Abort program
|
|
static void abort();
|
|
|
|
//- Exchange label with all processors (in the communicator).
|
|
// sendData[proci] is the label to send to proci.
|
|
// After return recvData contains the data from the other processors.
|
|
static void allToAll
|
|
(
|
|
const labelUList& sendData,
|
|
labelUList& recvData,
|
|
const label communicator = 0
|
|
);
|
|
|
|
//- Exchange data with all processors (in the communicator)
|
|
// sendSizes, sendOffsets give (per processor) the slice of
|
|
// sendData to send, similarly recvSizes, recvOffsets give the slice
|
|
// of recvData to receive
|
|
static void allToAll
|
|
(
|
|
const char* sendData,
|
|
const UList<int>& sendSizes,
|
|
const UList<int>& sendOffsets,
|
|
|
|
char* recvData,
|
|
const UList<int>& recvSizes,
|
|
const UList<int>& recvOffsets,
|
|
|
|
const label communicator = 0
|
|
);
|
|
|
|
//- Receive data from all processors on the master
|
|
static void gather
|
|
(
|
|
const char* sendData,
|
|
int sendSize,
|
|
|
|
char* recvData,
|
|
const UList<int>& recvSizes,
|
|
const UList<int>& recvOffsets,
|
|
const label communicator = 0
|
|
);
|
|
|
|
//- Send data to all processors from the root of the communicator
|
|
static void scatter
|
|
(
|
|
const char* sendData,
|
|
const UList<int>& sendSizes,
|
|
const UList<int>& sendOffsets,
|
|
|
|
char* recvData,
|
|
int recvSize,
|
|
const label communicator = 0
|
|
);
|
|
};
|
|
|
|
|
|
Ostream& operator<<(Ostream&, const UPstream::commsStruct&);
|
|
|
|
// Template specialisation for access of commsStruct
|
|
template<>
|
|
UPstream::commsStruct&
|
|
UList<UPstream::commsStruct>::operator[](const label);
|
|
template<>
|
|
const UPstream::commsStruct&
|
|
UList<UPstream::commsStruct>::operator[](const label) const;
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
|
|
} // End namespace Foam
|
|
|
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
|
|
#endif
|
|
|
|
// ************************************************************************* //
|