我正在尝试使用OpenMP
并行化以下函数中的循环 void CEnergymulti::forcetwobody(vector<CMolecule*> m_mols,CPnt force0,CPnt torque0)
{
const int nmol=m_mols.size();
vector<CMolecule*> twomols(2);
CPnt forcetemp,torquetemp;
twomols.clear();
force0.zero();
torque0.zero();
forcetemp.zero();
torquetemp.zero();
#pragma omp parallel for reduction(+:force0,torque0) private(twomols)
for(int j=1;j<nmol;j++)
{ twomols.push_back(m_mols[0]);
twomols.push_back(m_mols[j]);
CMolecule::polarize_mutual(twomols,false, 1000);
twomols[0]->computeMol_Force_and_Torque(forcetemp,torquetemp);
force0+=forcetemp;
torque0+=torquetemp;
forcetemp.zero();
torquetemp.zero();
twomols.clear();
}
REAL converter=COUL_K*IKbT;
force0*=converter;
torque0*=converter;
return;
}
编译代码时,它会显示以下消息:
EnergyD_multi.cpp: In static member function ‘static void
CEnergymulti::forcetwobody(std::vector<CMolecule*,
std::allocator<CMolecule*> >, CPnt, CPnt)’: EnergyD_multi.cpp:226:
error: ‘torque0’ has invalid type for ‘reduction’
EnergyD_multi.cpp:226: error: ‘force0’ has invalid type for
‘reduction’
我理解变量'force0'和'torque0'既不是双重或整数类型的数据,而是类型'CPnt',这是一个定义为表示空间中三维向量的类。对于类'CPnt',运算符'+'和' - '已经由运算符重载定义。所以我的问题是:OpenMP的减少是否真的无法处理这样的重载运算符?有没有其他方法可以将此循环与OpenMP并行化而不减少'force0'和'torque0'的每个组件?
非常感谢。
答案 0 :(得分:7)
OpenMP减少无法处理这样的重载运算符。但是,还有另一种选择。重写OpenMP减少的一种方法是使用nowait
和atomic
参数。 http://bisqwit.iki.fi/story/howto/openmp/#ReductionClause
这和正常方式一样快。
如果将atomic
替换为critical
,则可以使用更复杂的重载运算符。这不如使用atomic
那么快,但在我的经验中它仍然有效。
我这样做了所以我可以使用同时操作4或8个浮点数的运算符(使用SEE或AVX)。 reduction with OpenMP with SSE/AVX
编辑:我改变了你的代码,以反映我认为你想做的事情。
void CEnergymulti::forcetwobody(vector<CMolecule*> m_mols,CPnt force0,CPnt torque0)
{
const int nmol=m_mols.size();
force0.zero();
torque0.zero();
#pragma omp parallel
{
CPnt force0_private;
CPnt torque0_private;
force0_private.clear();
torque0_private.clear();
#pragma omp for nowait
for(int j=1;j<nmol;j++)
{
CPnt forcetemp,torquetemp;
forcetemp.zero();
torquetemp.zero();
vector<CMolecule*> twomols(2);
twomols.clear();
twomols.push_back(m_mols[0]);
twomols.push_back(m_mols[j]);
CMolecule::polarize_mutual(twomols,false, 1000);
twomols[0]->computeMol_Force_and_Torque(forcetemp,torquetemp);
force0_private+=forcetemp;
torque0_private+=torquetemp;
}
#pragma omp critical
{
force0 += force0_private;
torque0 += torque0_private;
}
}
REAL converter=COUL_K*IKbT;
force0*=converter;
torque0*=converter;
return;
}
答案 1 :(得分:2)
这几天,您还可以使用declare reduction
指令(OpenMP 4.0+);例如
#pragma omp declare reduction(mysum:CPnt:omp_out += omp_in) initializer(omp_priv.zero())
#pragma omp parallel for reduction(mysum:force0,torque0) private(twomols)
for(int j=1;j<nmol;j++)
...