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' は double または integer 型のデータではなく、空間内の 3 次元ベクトルを表すために定義されたクラスである 'CPnt' 型であることを理解しています。クラス 'CPnt' の場合、演算子 '+' および '-' は、演算子のオーバーロードによって既に定義されています。私の質問は次のとおりです。OpenMP のリダクションでは、そのようなオーバーロードされた演算子を処理できないというのは本当ですか? 「force0」と「torque0」の各コンポーネントを削減せずに、このループを OpenMP で並列化する別の方法はありますか?

どうもありがとう。

4

2 に答える 2

8

OpenMP リダクションがそのようなオーバーロードされた演算子を処理できないのは事実です。ただし、代替手段があります。OpenMP でリダクションを書き直す 1 つの方法は、パラメーターnowaitatomicパラメーターを使用することです。 http://bisqwit.iki.fi/story/howto/openmp/#ReductionClause .これは通常の方法と同じくらい高速です。

と置き換えるatomicと、criticalより複雑なオーバーロードされた演算子を使用できます。これは使用するほど速くはありませんatomicが、私の経験ではまだうまく機能しています.

これを行ったのは、(SEE または AVX を使用して) 一度に 4 つまたは 8 つの float を操作するオペレーターを使用できるようにするためです。 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 に答える