MDの実行エンジンクラス MDUnitを通してすべての作業を行う。 複数のプロジェクトになるべく一つのコードで対応する。 そのため、ProjectManagerクラスがパラメータファイルのModeに応じた 適切なProjectクラス(の子クラス)にMDUnitのインスタンスを渡す。 ユーザはProjectクラスのRunメソッドの中を記述することでMDを実行する仕組みとなっている。
コンパイルにはMPIが必要。MPIライブラリの無い環境ではコンパイルができないため、先にインストールしておくこと。
最初にmakefile.optを作成し、コンパイラ(CC)およびコンパイルオプション(CPPFLAGS)、 必要ならばライブラリオプション(LDFLAGS)を記述しておく。その上で、
$ makeとすれば動くはず。 素早くコンパイルしたい場合は、make -jが良い。 以下はmakefile.optの記述例。
CC=mpic++ CPPFLAGS= -O3 -funroll-loops LDFLAGS=-lmpi
CC=mpicxx CPPFLAGS=-Os -noparallel +Op -DPOWER
CC=g++ LDFLAGS=-lmpich CPPFLAGS=-O3 -funroll-loops
CC=mpCC CPPFLAGS= -O5 -q64 -DPOWER
コンパイルができたら、実行してみる。デフォルトではベンチマークを取る。 以下のように表示されたら成功。
$ ./mdacp # Number of Processes: 1 # Input file is not specified. input.cfg is used. # Mode = Benchmark # Number of Particles = 62500 # System Size = (50,50,50) # Desity = 0.5 # Cutoff Length = 2.5 # TimeStep = 0.001 # ControlTemperature = no # IsPeriodic = yes #Energy = -2.00818 0.151 0.364681 -2.00818# observe 0.251 0.36874 -2.00819# observe 0.351 0.444665 -2.00816# observe 0.451 0.496116 -2.00817# observe 0.551 0.518531 -2.00817# observe 0.651 0.541055 -2.00817# observe 0.751 0.559876 -2.00817# observe 0.851 0.577013 -2.00817# observe 0.951 0.588248 -2.00818# observe 1.051 0.599503 -2.00818# observe #Energy = -2.00817 # N=62500 21.6639 [SEC] 2.88498 [MUPS] # Number of Pair-list Construction: 17
次に、並列実行をしてみる。例えば8並列なら
$ mpirun -np 8 ./mdacpとする。以下のような表示がされるはず。
$ mpirun -np 8 ./mdacp # Number of Processes: 8 # Input file is not specified. input.cfg is used. # Mode = Benchmark # Number of Particles = 500000 # System Size = (100,100,100) # Desity = 0.5 # Cutoff Length = 2.5 # TimeStep = 0.001 # ControlTemperature = no # IsPeriodic = yes #Energy = -2.00818 0.151 0.365109 -2.00818# observe 0.251 0.369157 -2.00819# observe 0.351 0.445891 -2.00816# observe 0.451 0.496593 -2.00817# observe 0.551 0.521196 -2.00817# observe 0.651 0.542904 -2.00817# observe 0.751 0.561414 -2.00817# observe 0.851 0.576258 -2.00817# observe 0.951 0.588979 -2.00817# observe 1.051 0.599142 -2.00817# observe #Energy = -2.00817 # N=500000 43.1095 [SEC] 11.5984 [MUPS] # Number of Pair-list Construction: 18
パラメータファイル(*.cfg)を用意し、それを第一引数に渡す。
$ mpirun -np 8 ./mdacp hoge.cfgインプットファイルを省略した場合には、input.cfgが読み込まれる。
パラメータファイルは
parameter1=value1 parameter2=value2 parameter3=value3の形で羅列する。文頭に#をつければコメントとして解釈される。 以下、大事なパラメータ(予約語)。
SystemSizeX=100 SystemSizeY=50 SystemSizeZ=50とする。
GridX=1 GridY=8 GridZ=8と指定すれば、128*16*16の直方体領域を各プロセスに割り当てる。 GridX*GridY*GridZはMPIのプロセス数と一致しなければならない。
LocalGridX=2 LocalGridX=2 LocalGridX=2と指定すれば、2*2*2のグリッドに連続したランク番号が振られるように 割り振るため、1つのノードが担当する領域は2*2*2の立方体状になり、 ノード間通信が減る。LocalGridX,Y,Zは、それぞれGridX, GridY, GridZの約数である必要がある。
予約語以外は自分で好きなように設定してよい。 設定するものとしては、InitialVelocityやTotalLoop、ControlTemperatureなど。 全てはParameterクラスのインスタンス、paramに入って渡されてくるので、 Parameter::GetIntegerなどで値を受け取る。
一つのコードで複数のプロジェクトに対応するため、モードを指定することで動作を分けている。 具体的にはProjectManager::ExecuteProject内でModeを判別し、もしMode=Benchmarkならbenchmark.cc内のBenchmark::Runを、 Mode=Collisionならcollision.cc内のCollision::Runを呼ぶようにしている。 たとえばCollision::Runの引数としてMDUnitのインスタンスmduと Parameterのインスタンスparamが 渡されるので、ユーザはそれを通じてシミュレーションを行う。
Projectクラスを継承したクラスを作成することで新しいプロジェクトを作ることができる。 たとえば液滴衝突モード「Collision」は、collision.cc/collision.hに実装がある。 まず、collision.hにProjectクラスの派生クラスとして Collisionクラスが定義され、コンストラクタで
ProjectManager::GetInstance().AddProject("Collision",this);
と、プロジェクトの追加のためのコードが呼ばれている。
これはcollision.ccにある
Collision collision;によりインスタンスが静的に作られる時に呼ばれ、自動的にProjectManagerは 「Collision」モードを知り、対応するProjectクラスのインスタンスを得る。 その後、main関数にて読み込まれたパラメタファイルのModeが「Collision」であれば、Collisionクラスの インスタンスのRunメソッドを呼ぶ。
パラメータファイルに書いた情報はparamのメソッドを呼ぶことで受け取る。 もし
Density=0.70と書いた情報を受け取りたければ、
double density = param.GetDoubleDef("Density",0.5)
などとする。この例では、もし「Density」がパラメタファイルに記述されていなければ0.5が設定される。
同様に、整数や真偽値も受け取ることができる。
たとえばループ数TotalLoopは
TotalLoop=1000とパラメータファイルに記述しておき、
const int TOTAL_LOOP =param.GetIntegerDef("TotalLoop",1000);
と受け取る。
IsPeriodic=yes ControlTemperature=noなどは、
bool isPeriodic = param.GetBooleanDef("IsPeriodic",false);
bool controlTemperature = param.GetBooleanDef("ControlTemperature",false);
などとして受け取る。
粒子の配置にはMDUnit::AddParticleを使う。 AddParticle(double x[D], double v[D])は、xを位置、vを速度とするような 粒子を追加する。どのプロセスに追加するべきかは自動的に判定される。 もし 座標(50,50,50)に速度0の粒子を追加したければ、
double x[D],v[D]; x[X] =50.0; y[Y] =50.0; z[Z] =50.0; v[X] = 0; v[Y] = 0; v[Z] = 0; mdu->AddParticle(x,v);とすれば良い。
時間を一ステップ進めるには、Calculateメソッドを呼ぶ。 現在の時間はGetSimulationTime、温度はTemperature、全エネルギーはTotalEnergyで分かる。 もしTOTAL_LOOPだけループをまわす間、 OBSERVE_LOOPステップごとに時間と温度を表示したければ、
for (int i=0; i<TOTAL_LOOP; i++) {
mdu->Calculate();
if (i%OBSERVE_LOOP==0) {
mout << mdu->GetSimulationTime() << " "<< mdu->Temperature() << endl;
}
}
などとすればよい。
Key=Valueの形をしたファイルを読み込み、std::mapに管理、valueをintとして解釈して返す GetIntegerや、キー定義されていない場合のデフォルト値を指定する GetIntegerDefなどのメソッドを持つ。
$ mpirun -np 8 ./mdacp collision.cfgとすると、8並列で実行され、conf000.cdからconf040.cdが出力される。 これはcdviewにより表示できる。
$ cdview conf*.cdとしてまとめて読み込んで、マウスで動かしたり、アニメーションにより衝突の様子を追うことができる。 cdviewがない場合には、gnuplotで
gnuplot> sp "conf000.cd" u 3:4:5などとすれば表示できる。