web-dev-qa-db-ja.com

シミュレーションコードのパフォーマンスを向上させる最適な設計

私は Discrete Element Method のコードを書いています。ボール(球)と壁(平面)が相互に作用しています。

これらのシミュレーションは数十億の時間ステップにわたって実行されるため、ここでのパフォーマンスは本当に重要です。現在、私はさまざまなデザインを検討しており、どちらが最適かわかりません。

私はそれらと私の疑問を説明しようとします。


代替案1-おそらくメンテナンス性に最適

ボールの1つのクラス:

class Balls:
   /* contains:
  geometry
  forces
  positions
  velocities
  etc.
  of balls */

壁の1つのクラス:

class Walls:
   /* contains:
  geometry
  forces
  positions
  velocities
  etc.
  of Walls */

ソルバーも含むアセンブリ:

class Assembly:
  /* contains:
  balls object
  walls object
  other parameters for the Assembly

  Solver:
   method to compute interactions balls-balls and walls-balls
   method to advance time (time integration)

ここでの質問は、どのようにしてオーバーヘッドを少なくするかです。ソルバーは、他の2つのクラスのほとんどすべての属性にアクセスする必要があります。ゲッターを作成するか、Worldクラスを他の2つのfriendとして宣言しますか?

代替案2-混乱する可能性がある

ソルバークラス:

class Solver:
  /* Contains:
  some solver related parameters (e.g., step size)
  Two methods:
   method to compute interactions balls-balls and walls-balls
   method to advance time (time integration)

壁とボールのすべての定義を含むアセンブリクラス

class Assembly:
  /* contains basically all attributes of the two 
  classes Walls and Balls shown in the alternative 1 and 
  a method which calls the two methods of the class solver
  by passing the balls/walls attributes by reference */

ここでも、参照によって属性を渡したり、WorldクラスをfriendクラスのSolverとして宣言したり、ゲッターを使用したりする方が良いでしょうか。

代替案3-保守性が低い

すべてを1つのクラスに結合します(実際には考慮されていません)。


最後に、オーバーヘッドを最も減らす設計は何ですか?私より良いデザインを提案できますか?


編集:注意すべきは、クラスBallsおよびWallsでは、すべてを1つのオブジェクトに格納することです。つまり、オブジェクトBalls ballsには例が含まれます(アセンブリ全体に2つのボールしか含まれていない場合):

vector<Eigen::Vector3d> ball_positions = {Eigen::Vector3d(x1,y1,z1),
                                          Eigen::Vector3d(x2,y2,z2)}
vector<double> ball_radii = {r1,r2}
2
David

パフォーマンスが危機に瀕している場合、確実に知る唯一の方法はベンチマークです。

代替1には、ポリモーフィズムを使用する場合、簡単に拡張できるという利点があります。

class SimulationObject {
    // common properties 
    // virtual functions for anything that changes according to real objects
}; 

class Sphere: public SimulationObject {
    ...
};
class Wall: public SimulationObject {
    ...
};

仮想関数 は、余分な間接参照があるため、わずかなオーバーヘッドがあります(最近のCPUでは大した問題ではありません)。ただし、タイプによって動作を変えるために必要な追加の条件付きステートメントと比較すると、これは無視できます。

double dispatch を使用して、さまざまな種類のオブジェクト間の可能な相互作用の組み合わせの爆発に非常に効果的に対処できます。今日は球と球だけです。しかし、球、立方体、壁がある場合はどうでしょうか。壁にぶつかる前に、球が他の球または立方体で跳ねる可能性がある場所

他の選択肢は本当に私には持続可能ではないようです。また、条件付きの長いチェーンを通過して、特定の相互作用/組み合わせの特定のケースを把握する必要がある場合、パフォーマンスが向上するかどうかはわかりません。

3
Christophe