#201914
大家经常会在程序中见到 reduce()
,比如在 applications/solvers/basic/potentialFoam/potentialFoam.C
:
// Calculate mean velocity
scalar u = sum(mag(Upatch));
label patchSize = Upatch.size();
reduce(u, sumOp<scalar>());
reduce(patchSize, sumOp<label>());
这个是什么意思呢?
在并行计算中,每个语句都会在各进程执行,对于 scalar u = sum(mag(Upatch))
这一句,就是把 patch 上的速度值相加,每个进程上都会得到一个 u ,因此,这是有问题的,我们希望的是有一个最后的 u,而现在每个线程都有一个。所以存在合并问题。这个在 OpenFOAM 的并行计算中,就用 reduce() 来解决。
实际上,reduce 在并行计算 (MPI) 中,叫归约,是指在分布在不同进程中的数据间进行交互的运算,常用的运算有求和、求最大或最小值等。
当然,不必对并行计算要有深入的了解才能使用。在 OpenFOAM 中,提供了这样的操作模板,见
src/foam/db/IOstreams/Pstreams/PstreamReduceOps.H
// Reduce operation with user specified communication schedule
template <class T, class BinaryOp>
void reduce
(
const List<Pstream::commsStruct>& comms,
T& Value,
const BinaryOp& bop
)
{
Pstream::gather(comms, Value, bop); // 将各进程的 Value 按 bop 操作归约到 0 进程/主进程
Pstream::scatter(comms, Value); // 将 Value 发送给所有进程
}
// Reduce using either linear or tree communication schedule
template <class T, class BinaryOp>
void reduce
(
T& Value,
const BinaryOp& bop
)
{
if (Pstream::nProcs() < Pstream::nProcsSimpleSum)
{
reduce(Pstream::linearCommunication(), Value, bop);
}
else
{
reduce(Pstream::treeCommunication(), Value, bop);
}
}
因此,reduce()
既作了归约,也做了分发的工作,使所有进程可获得归约的结果。