7

我正在尝试使用 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 的减少是否真的不能处理这种重载的运算符?有没有其他方法可以在不减少“force0”和“torque0”的每个组件的情况下将该循环与 OpenMP 并行化?

非常感谢。

4

2 回答 2

8

确实,OpenMP 缩减无法处理这种重载的运算符。但是,还有另一种选择。在 OpenMP 中重写缩减的一种方法是使用nowaitatomic参数。 http://bisqwit.iki.fi/story/howto/openmp/#ReductionClause 。这和正常方式一样快。

如果您替换atomiccritical您可以使用更复杂的重载运算符。这不如使用快,atomic但根据我的经验,它仍然运作良好。

我这样做是为了可以使用一次对 4 或 8 个浮点数进行操作的运算符(使用 SEE 或 AVX)。 通过 SSE/AVX 使用 OpenMP 减少

编辑:我更改了您的代码以反映我认为会做您想做的事情。

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;
}
于 2013-04-24T08:00:20.597 回答
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++)
...
于 2019-09-11T00:21:19.527 回答