C++: ã¤ã³ãã« ã¹ã¬ããã£ã³ã°・ãã«ãã£ã³ã°・ãããã¯ã使ã£ã¦ç°¡åã«ä¸¦åå
æè¿ã¯ãã«ãã³ã¢CPUãå½ããåã«ãªã£ã¦ãã¦、ããã使ã£ã¦ç°¡åã«ä¸¦åå¦çããã°ã©ãã³ã°ãã§ããªãã、é ãæ©ã¾ãã¦ããã®ã ã、ã¤ã³ãã«ã®ã¹ã¬ããã£ã³ã°・ãã«ãã£ã³ã°・ãããã¯(Threading Building Blocks, TBB)ãé常ã«è¯ãã§ããæè¡ã§ãããã¨ãç¥ã£ã。
ããã¾ã§ã¯MPIãã、OpenMPãã、CUDAãããã¡ããã¡ããæãåºãã¤ã¤ã、ã©ããæ£ç´é¢åã ã£ã。趣å³ã®ããã°ã©ãã³ã°ã§ã¯ããã§ã楽ããããããã®ã ãã©、åã«ããå¦çã並ååã§é«éã«ãããã ãã®å ´å、並åå¦çã«é¢ããé¢åãªæç¶ããªã©ã¯æ¥µåçããã。ã¾ã、ã©ããã¦ãæ³¥èãããæ¹ã«ãªããã¨ãå¤ã。ä¾ãã°、Cã§ã¯ç°¡åã«æ¸ããã®ã ãã©、C++ã®æ©è½ã使ã£ãå¦çãããã¥ããã£ããã。
ããã§、TBBãç»å ´ãã。ãã«ãã³ã¢ãã¡ãã¼ã³ã¢ãã©ãããã©ã¼ã ä¸ã§ã®å©ç¨ã¨ãªãã、æè¿ã§ã¯ä¸è¬ã®ãã¼ãPCã§ãããã«ãã³ã¢CPUã使ããã¦ãããã¨ãèããã¨、ä¸ã«ããæ§ã ãªä¸¦åå¦çç°å¢ã®ãã¡、ãã«ãã³ã¢CPUã§ã®ä¸¦ååããã£ã¨ãæã¾ãã¦ããã ããã¨æã。å®é、èªåããã«ãã³ã¢CPUä¸ã§ã®ä¸¦åå¦çãç°¡åã«ã§ããªããã®ãã¨ããèãã¦ãã。ããã«、å¾æ¥ã®æ³¥èãã®æ®ã並ååã«æ¯ã¹ã¦、C++ãã³ãã¬ã¼ãã«ããã³ã¼ãã£ã³ã°ã¹ã¿ã¤ã«ã¯ã¹ãã¼ãã 。
ãã¦、TBBãå©ç¨ããã«ã¯TBBå ¬å¼ãµã¤ããããã¦ã³ãã¼ããã¦ããã°ãã。ãªã¼ãã³ã½ã¼ã¹çãç¨æããã¦ããã®ã§、ããã使ã£ã¦èªç±ã«ããã°ã©ã ãä½æã§ãã。ã¾ã、ãã®ãµã¤ãã«ã¯ãã¥ã¼ããªã¢ã«ããªãã¡ã¬ã³ã¹ãç¨æããã¦ãã。ããã«、æ¥æ¬èªçã®ããã¥ã¡ã³ããXLsoftã®TBBãµã¤ãããå©ç¨ã§ãã。ããã®ãã¥ã¼ããªã¢ã«ãä¸éãèªãã°å¤§æµã®å ´åã§å©ç¨ã§ããããã«ãªãã ãã。
ä»åã¯、「ã¯ããã¦ã®CUDAããã°ã©ãã³ã°ã§ååååå¦è¨ç®」ã§ä½æããC++çã®ãªãã¡ãã£ã¦ååååå¦(MD)è¨ç®ããã°ã©ã ãTBBãå©ç¨ãã¦ä¸¦åå¦çãè¡ã£ã¦ã¿ã。é常ã«ç°¡åã ã£ã。ç¸äºä½ç¨è¨ç®ã®é¢æ°ãé¢æ°ãªãã¸ã§ã¯ãã«å¤æ´ããã ãã 。TBBã«ã¤ãã¦ç¥ã£ã¦ããã°5åãããããªããããããªã。ãããªã«ç°¡åã«ä¸¦ååãã§ããã®ã§ããã°、ãã£ã¨æ©ãã«ç¥ãããã£ã。ã¾ã、ç¾èã¯ä¸è¦ã«å¦ãã、ä»å使ã£ãã³ã¼ããä¸ã«ç¤ºã。é(æ°´è²)ã§ç¤ºããé¨åãæ¸ãå ããã³ã¼ã、赤(ãã³ã¯)ã§ç¤ºããé¨åãåã£ãã³ã¼ã、æ°´è²ã¨ãã³ã¯ã®ã³ã¼ãã¯å ±éã®ã³ã¼ãã§ãã。å®éã«ä¿®æ£ããé¨åã¯éã¨èµ¤ã§ç¤ºããã³ã¼ãã ã、ãããå ¨ä½ã«å¯¾ãã¦å¦ä½ã«å°ãªããåãã£ã¦ããããã ããã。
MDããã°ã©ã ã®èª¬æã¯ä¸è¿°ã®ã¨ã³ããªã«æ¸ããã¦ãã。ã¾ã、å©ç¨ããTBBã«ã¤ãã¦ã¯、ã¾ã、mainé¢æ°ã§task_scheduler_init init;ã¨ãã¦åæåãè¡ã£ã¦ãã。ããã¦、ç¸äºä½ç¨ã®è¨ç®ãè¡ãSimpleMD::Calcã¡ã³ãé¢æ°ãSimpleMDCalcé¢æ°ãªãã¸ã§ã¯ãã¨ãã¦å®è£ ã、SimpleMD::Runã¡ã³ãé¢æ°å ã§parallel_for(blocked_range(0, num_atoms, 500), SimpleMDCalc(num_atoms, crd, f, ene, chg)); ã¨ãã¦å¼ã³åºãã¦ãã。blocked_rangeã®ç¬¬3å¼æ°ã§ç²åº¦(å復åæ°)ãæå®ãã¦ãã。TBBã«ã¤ãã¦ã®è©³ãã説æã«ã¤ãã¦ã¯、XLsoftã®ãã¥ã¼ããªã¢ã«ãåç
§ãã¦æ¬²ãã。
æå¾ã«å®éã®è¨ç®æéã測å®ããã®ã§、ããã示ã。ãã£ã¼ãã§ã¯ã³ã¢ã«å¯¾ããå®è¡é度åä¸ã®å²åã示ãã¦ãã。4ã³ã¢ã®Xeonã8åæè¼ãããSMPç°å¢ã§、19,393åã®çä¼¼ååãä¸å¿ãã50à 以å ã«çºçããã¦5ã¹ãããã®è¨ç®ãè¡ã£ã。å ã¿ã«ã³ã¢æ°ã®æå®ã¯task_scheduler_init init;ã§è¡ã。ä¾ãã°8ã³ã¢ãæå®ããå ´åã¯、init(8);ã¨ããã°ãã。
single 78.18ç§ 2 cores 39.28ç§ 1.985å 4 cores 22.67ç§ 3.449å 8 cores 11.70ç§ 6.682å 16 cores 7.27ç§ 10.784å
ãããã«è¤æ°ã³ã¢ãå©ç¨ããã¨ããç¨åº¦ã¯ãµãã£ã¦ãã¾ãã、ããã§ãããã ãç°¡åã«å©ç¨ã§ãããã¨ãèããã¨ååãªæ§è½ãçºæ®ããã¦ããã¨æã。
simple_md_tbb.cpp
///////////////////////////////////////////////////////////////////// // Simple Molecular Dynamics by nox, 2009.06.22 // // Perform molecular dynamics for pseudo-atoms without internal // interactions, such as bonds, angles, dihedrals. Only vdW and // Coulomb interactions. #include <iostream> #include <iomanip> #include <fstream> #include <sstream> #include <cmath> #include "tbb/task_scheduler_init.h" #include "tbb/parallel_for.h" #include "tbb/blocked_range.h" using namespace std; using namespace tbb; class SimpleMD { private: int num_steps; int num_atoms; double cap_range; double* crd; double* f; double* ene; double* chg; public: SimpleMD(int, char*); ~SimpleMD(); void ReadCrd(char*); void Center(); void Calc(); void Move(); void PrintCrd(); void Run(); double Energy() const { double sum = 0.0f; for (int i = 0; i < num_atoms; i++) sum += ene[i]; return sum / 2.0f; } double DistanceXYZ(int i, int j, int k) const { return crd[i * 3 + k] - crd[j * 3 + k]; } double Distance(int i, int j) const { double dx = crd[i * 3] - crd[j * 3]; double dy = crd[i * 3 + 1] - crd[j * 3 + 1]; double dz = crd[i * 3 + 2] - crd[j * 3 + 2]; return sqrt(dx * dx + dy * dy + dz * dz); } }; // Calculate energies and forces // Total energy = vdW + Coulomb // vdW // U = eps * [(Rij / r[i])^12 - 2 * (Rij / r[i])^6] // F = -12 * eps / Rij * [(Rij / r[i])^13 - (Rij / r[i])^7] * r_xyz / r[i] // Coulomb // U = SUM_i>j qiqj / r[i] // F = SUM_j qiqj / r[i]^3 * r_xyz class SimpleMDCalc { private: int num_atoms; double* crd; double* f; double* ene; double* chg; public: SimpleMDCalc(int num_atoms_, double* crd_, double* f_, double* ene_, double* chg_) : num_atoms(num_atoms_), crd(crd_), f(f_), ene(ene_), chg(chg_) { } double DistanceXYZ(int i, int j, int k) const { return crd[i * 3 + k] - crd[j * 3 + k]; } double Distance(int i, int j) const { double dx = crd[i * 3] - crd[j * 3]; double dy = crd[i * 3 + 1] - crd[j * 3 + 1]; double dz = crd[i * 3 + 2] - crd[j * 3 + 2]; return sqrt(dx * dx + dy * dy + dz * dz); } void operator()(const blocked_range<int>& br) const { const double eps = 0.2f; const double Rij = 2.5f; double r, r_xyz, df, r12, r6, q; for (int i = br.begin(); i != br.end(); i++) { ene[i] = 0.0f; for (int j = i + 1; j < num_atoms; j++) { r = Distance(i, j); q = chg[i] * chg[j]; r12 = pow(Rij / r, 12); r6 = pow(Rij / r, 6); ene[i] += 2.0 * (eps * (r12 - 2.0f * r6) + q / r); for (int k = 0; k < 3; k++) { r_xyz = DistanceXYZ(i, j, k); df = (12 * eps / Rij) * (r12 * Rij / r - r6 * Rij / r) * r_xyz / r; df += q / pow(r, 3) * r_xyz; f[i * 3 + k] += df; f[j * 3 + k] -= df; } } } } }; SimpleMD::SimpleMD(int n, char* fname) : num_steps(n) { ReadCrd(fname); f = new double[num_atoms * 3]; ene = new double[num_atoms]; for (int i = 0; i < num_atoms; i++) { for (int j = 0; j < 3; j++) f[i * 3 + j] = 0.0f; ene[i] = 0.0f; } Center(); } SimpleMD::~SimpleMD() { delete[] ene; delete[] f; delete[] chg; delete[] crd; } void SimpleMD::ReadCrd(char* fname) { fstream fs(fname, ios_base::in); string line; stringstream ss; if (!fs.is_open()) { cerr << "File open error: " << fname << endl; exit(1); } getline(fs, line); cout << line << endl; getline(fs, line); ss.str(line); ss >> num_atoms; ss.clear(); getline(fs, line); ss.str(line); ss >> cap_range; ss.clear(); crd = new double[num_atoms * 3]; chg = new double[num_atoms]; for (int i = 0; i < num_atoms; i++) { getline(fs, line); ss.str(line); ss >> crd[i * 3] >> crd[i * 3 + 1] >> crd[i * 3 + 2] >> chg[i]; ss.clear(); ss.str(""); } fs.close(); } void SimpleMD::Center() { double d[3] = { 0.0f, 0.0f, 0.0f }; for (int i = 0; i < num_atoms; i++) { for (int j = 0; j < 3; j++) d[j] += crd[i * 3 + j]; } for (int j = 0; j < 3; j++) d[j] /= num_atoms; for (int i = 0; i < num_atoms; i++) for (int j = 0; j < 3; j++) crd[i * 3 + j] -= d[j]; } void SimpleMD::Calc() { const double eps = 0.2f; const double Rij = 2.5f; double r, r_xyz, df, r12, r6, q; for (int i = 0; i < num_atoms; i++) { ene[i] = 0.0f; for (int j = i + 1; j < num_atoms; j++) { r = Distance(i, j); q = chg[i] * chg[j]; r12 = pow(Rij / r, 12); r6 = pow(Rij / r, 6); ene[i] += 2.0 * (eps * (r12 - 2.0f * r6) + q / r); for (int k = 0; k < 3; k++) { r_xyz = DistanceXYZ(i, j, k); df = (12 * eps / Rij) * (r12 * Rij / r - r6 * Rij / r) * r_xyz / r; df += q / pow(r, 3) * r_xyz; f[i * 3 + k] += df; f[j * 3 + k] -= df; } } } } void SimpleMD::Move() { double r, dr; for (int i = 0; i < num_atoms; i++) { for (int j = 0; j < 3; j++) { crd[i * 3 + j] += f[i * 3 + j] * 0.01f; f[i * 3 + j] = 0.0f; } r = 0.0f; for (int j = 0; j < 3; j++) r += crd[i * 3 + j] * crd[i * 3 + j]; dr = r - cap_range * cap_range; if (dr > 0.0f) { for (int j = 0; j < 3; j++) f[i * 3 + j] -= crd[i * 3 + j] / cap_range * dr * 0.01f; } } } void SimpleMD::PrintCrd() { cout << endl; cout << num_atoms << endl; cout << cap_range << endl; for (int i = 0; i < num_atoms; i++) { for (int j = 0; j < 3; j++) cout << " " << fixed << setw(10) << setprecision(6) << crd[i * 3 + j]; cout << " " << fixed << setw(8) << setprecision(4) << chg[i]; cout << endl; } } void SimpleMD::Run() { for (int i = 0; i < num_steps; i++) { Calc(); parallel_for(blocked_range<int>(0, num_atoms, 500), SimpleMDCalc(num_atoms, crd, f, ene, chg)); Move(); Center(); cout << "Energy (" << setw(7) << i + 1 << "): "; cout << fixed << setw(15) << setprecision(5) << Energy() << endl; } } int main(int argc, char** argv) { if (argc < 3) { cerr << "Simple Molecular Dynamics by nox" << endl; cerr << endl; cerr << " Usage: " << argv[0] << " crd_file num_step" << endl; exit(1); } task_scheduler_init init; stringstream ss; int nstep; ss.str(argv[2]); ss >> nstep; SimpleMD md(nstep, argv[1]); md.PrintCrd(); md.Run(); md.PrintCrd(); return 0; }
ã³ã³ãã¤ã«æ¹æ³
ä¸è¨ã®ã³ã¼ãä¸、赤åé¨å(ãã³ã¯ãå«ã)ã¯åé¤ãããã¨。TBBã©ã¤ãã©ãªã¸ã®ãã¹ãéããå¾ã§、Linux(GCCãIntel C++)ã§ã¯、
g++ simple_md_tbb.cpp -O3 -ltbb
icpc simple_md_tbb.cpp -O3 -ltbb
Windows(VC8/9)ã§ã¯、
cl simple_md_tbb.cpp /EHsc /O2 /MD
ã¨、ããã°ãã。
ããã¾ã§ã¯MPIãã、OpenMPãã、CUDAãããã¡ããã¡ããæãåºãã¤ã¤ã、ã©ããæ£ç´é¢åã ã£ã。趣å³ã®ããã°ã©ãã³ã°ã§ã¯ããã§ã楽ããããããã®ã ãã©、åã«ããå¦çã並ååã§é«éã«ãããã ãã®å ´å、並åå¦çã«é¢ããé¢åãªæç¶ããªã©ã¯æ¥µåçããã。ã¾ã、ã©ããã¦ãæ³¥èãããæ¹ã«ãªããã¨ãå¤ã。ä¾ãã°、Cã§ã¯ç°¡åã«æ¸ããã®ã ãã©、C++ã®æ©è½ã使ã£ãå¦çãããã¥ããã£ããã。
ããã§、TBBãç»å ´ãã。ãã«ãã³ã¢ãã¡ãã¼ã³ã¢ãã©ãããã©ã¼ã ä¸ã§ã®å©ç¨ã¨ãªãã、æè¿ã§ã¯ä¸è¬ã®ãã¼ãPCã§ãããã«ãã³ã¢CPUã使ããã¦ãããã¨ãèããã¨、ä¸ã«ããæ§ã ãªä¸¦åå¦çç°å¢ã®ãã¡、ãã«ãã³ã¢CPUã§ã®ä¸¦ååããã£ã¨ãæã¾ãã¦ããã ããã¨æã。å®é、èªåããã«ãã³ã¢CPUä¸ã§ã®ä¸¦åå¦çãç°¡åã«ã§ããªããã®ãã¨ããèãã¦ãã。ããã«、å¾æ¥ã®æ³¥èãã®æ®ã並ååã«æ¯ã¹ã¦、C++ãã³ãã¬ã¼ãã«ããã³ã¼ãã£ã³ã°ã¹ã¿ã¤ã«ã¯ã¹ãã¼ãã 。
ãã¦、TBBãå©ç¨ããã«ã¯TBBå ¬å¼ãµã¤ããããã¦ã³ãã¼ããã¦ããã°ãã。ãªã¼ãã³ã½ã¼ã¹çãç¨æããã¦ããã®ã§、ããã使ã£ã¦èªç±ã«ããã°ã©ã ãä½æã§ãã。ã¾ã、ãã®ãµã¤ãã«ã¯ãã¥ã¼ããªã¢ã«ããªãã¡ã¬ã³ã¹ãç¨æããã¦ãã。ããã«、æ¥æ¬èªçã®ããã¥ã¡ã³ããXLsoftã®TBBãµã¤ãããå©ç¨ã§ãã。ããã®ãã¥ã¼ããªã¢ã«ãä¸éãèªãã°å¤§æµã®å ´åã§å©ç¨ã§ããããã«ãªãã ãã。
ä»åã¯、「ã¯ããã¦ã®CUDAããã°ã©ãã³ã°ã§ååååå¦è¨ç®」ã§ä½æããC++çã®ãªãã¡ãã£ã¦ååååå¦(MD)è¨ç®ããã°ã©ã ãTBBãå©ç¨ãã¦ä¸¦åå¦çãè¡ã£ã¦ã¿ã。é常ã«ç°¡åã ã£ã。ç¸äºä½ç¨è¨ç®ã®é¢æ°ãé¢æ°ãªãã¸ã§ã¯ãã«å¤æ´ããã ãã 。TBBã«ã¤ãã¦ç¥ã£ã¦ããã°5åãããããªããããããªã。ãããªã«ç°¡åã«ä¸¦ååãã§ããã®ã§ããã°、ãã£ã¨æ©ãã«ç¥ãããã£ã。ã¾ã、ç¾èã¯ä¸è¦ã«å¦ãã、ä»å使ã£ãã³ã¼ããä¸ã«ç¤ºã。é(æ°´è²)ã§ç¤ºããé¨åãæ¸ãå ããã³ã¼ã、赤(ãã³ã¯)ã§ç¤ºããé¨åãåã£ãã³ã¼ã、æ°´è²ã¨ãã³ã¯ã®ã³ã¼ãã¯å ±éã®ã³ã¼ãã§ãã。å®éã«ä¿®æ£ããé¨åã¯éã¨èµ¤ã§ç¤ºããã³ã¼ãã ã、ãããå ¨ä½ã«å¯¾ãã¦å¦ä½ã«å°ãªããåãã£ã¦ããããã ããã。
MDããã°ã©ã ã®èª¬æã¯ä¸è¿°ã®ã¨ã³ããªã«æ¸ããã¦ãã。ã¾ã、å©ç¨ããTBBã«ã¤ãã¦ã¯、ã¾ã、mainé¢æ°ã§task_scheduler_init init;ã¨ãã¦åæåãè¡ã£ã¦ãã。ããã¦、ç¸äºä½ç¨ã®è¨ç®ãè¡ãSimpleMD::Calcã¡ã³ãé¢æ°ãSimpleMDCalcé¢æ°ãªãã¸ã§ã¯ãã¨ãã¦å®è£ ã、SimpleMD::Runã¡ã³ãé¢æ°å ã§parallel_for(blocked_range
æå¾ã«å®éã®è¨ç®æéã測å®ããã®ã§、ããã示ã。ãã£ã¼ãã§ã¯ã³ã¢ã«å¯¾ããå®è¡é度åä¸ã®å²åã示ãã¦ãã。4ã³ã¢ã®Xeonã8åæè¼ãããSMPç°å¢ã§、19,393åã®çä¼¼ååãä¸å¿ãã50à 以å ã«çºçããã¦5ã¹ãããã®è¨ç®ãè¡ã£ã。å ã¿ã«ã³ã¢æ°ã®æå®ã¯task_scheduler_init init;ã§è¡ã。ä¾ãã°8ã³ã¢ãæå®ããå ´åã¯、init(8);ã¨ããã°ãã。
single 78.18ç§ 2 cores 39.28ç§ 1.985å 4 cores 22.67ç§ 3.449å 8 cores 11.70ç§ 6.682å 16 cores 7.27ç§ 10.784å
ãããã«è¤æ°ã³ã¢ãå©ç¨ããã¨ããç¨åº¦ã¯ãµãã£ã¦ãã¾ãã、ããã§ãããã ãç°¡åã«å©ç¨ã§ãããã¨ãèããã¨ååãªæ§è½ãçºæ®ããã¦ããã¨æã。
simple_md_tbb.cpp
///////////////////////////////////////////////////////////////////// // Simple Molecular Dynamics by nox, 2009.06.22 // // Perform molecular dynamics for pseudo-atoms without internal // interactions, such as bonds, angles, dihedrals. Only vdW and // Coulomb interactions. #include <iostream> #include <iomanip> #include <fstream> #include <sstream> #include <cmath> #include "tbb/task_scheduler_init.h" #include "tbb/parallel_for.h" #include "tbb/blocked_range.h" using namespace std; using namespace tbb; class SimpleMD { private: int num_steps; int num_atoms; double cap_range; double* crd; double* f; double* ene; double* chg; public: SimpleMD(int, char*); ~SimpleMD(); void ReadCrd(char*); void Center(); void Calc(); void Move(); void PrintCrd(); void Run(); double Energy() const { double sum = 0.0f; for (int i = 0; i < num_atoms; i++) sum += ene[i]; return sum / 2.0f; } double DistanceXYZ(int i, int j, int k) const { return crd[i * 3 + k] - crd[j * 3 + k]; } double Distance(int i, int j) const { double dx = crd[i * 3] - crd[j * 3]; double dy = crd[i * 3 + 1] - crd[j * 3 + 1]; double dz = crd[i * 3 + 2] - crd[j * 3 + 2]; return sqrt(dx * dx + dy * dy + dz * dz); } }; // Calculate energies and forces // Total energy = vdW + Coulomb // vdW // U = eps * [(Rij / r[i])^12 - 2 * (Rij / r[i])^6] // F = -12 * eps / Rij * [(Rij / r[i])^13 - (Rij / r[i])^7] * r_xyz / r[i] // Coulomb // U = SUM_i>j qiqj / r[i] // F = SUM_j qiqj / r[i]^3 * r_xyz class SimpleMDCalc { private: int num_atoms; double* crd; double* f; double* ene; double* chg; public: SimpleMDCalc(int num_atoms_, double* crd_, double* f_, double* ene_, double* chg_) : num_atoms(num_atoms_), crd(crd_), f(f_), ene(ene_), chg(chg_) { } double DistanceXYZ(int i, int j, int k) const { return crd[i * 3 + k] - crd[j * 3 + k]; } double Distance(int i, int j) const { double dx = crd[i * 3] - crd[j * 3]; double dy = crd[i * 3 + 1] - crd[j * 3 + 1]; double dz = crd[i * 3 + 2] - crd[j * 3 + 2]; return sqrt(dx * dx + dy * dy + dz * dz); } void operator()(const blocked_range<int>& br) const { const double eps = 0.2f; const double Rij = 2.5f; double r, r_xyz, df, r12, r6, q; for (int i = br.begin(); i != br.end(); i++) { ene[i] = 0.0f; for (int j = i + 1; j < num_atoms; j++) { r = Distance(i, j); q = chg[i] * chg[j]; r12 = pow(Rij / r, 12); r6 = pow(Rij / r, 6); ene[i] += 2.0 * (eps * (r12 - 2.0f * r6) + q / r); for (int k = 0; k < 3; k++) { r_xyz = DistanceXYZ(i, j, k); df = (12 * eps / Rij) * (r12 * Rij / r - r6 * Rij / r) * r_xyz / r; df += q / pow(r, 3) * r_xyz; f[i * 3 + k] += df; f[j * 3 + k] -= df; } } } } }; SimpleMD::SimpleMD(int n, char* fname) : num_steps(n) { ReadCrd(fname); f = new double[num_atoms * 3]; ene = new double[num_atoms]; for (int i = 0; i < num_atoms; i++) { for (int j = 0; j < 3; j++) f[i * 3 + j] = 0.0f; ene[i] = 0.0f; } Center(); } SimpleMD::~SimpleMD() { delete[] ene; delete[] f; delete[] chg; delete[] crd; } void SimpleMD::ReadCrd(char* fname) { fstream fs(fname, ios_base::in); string line; stringstream ss; if (!fs.is_open()) { cerr << "File open error: " << fname << endl; exit(1); } getline(fs, line); cout << line << endl; getline(fs, line); ss.str(line); ss >> num_atoms; ss.clear(); getline(fs, line); ss.str(line); ss >> cap_range; ss.clear(); crd = new double[num_atoms * 3]; chg = new double[num_atoms]; for (int i = 0; i < num_atoms; i++) { getline(fs, line); ss.str(line); ss >> crd[i * 3] >> crd[i * 3 + 1] >> crd[i * 3 + 2] >> chg[i]; ss.clear(); ss.str(""); } fs.close(); } void SimpleMD::Center() { double d[3] = { 0.0f, 0.0f, 0.0f }; for (int i = 0; i < num_atoms; i++) { for (int j = 0; j < 3; j++) d[j] += crd[i * 3 + j]; } for (int j = 0; j < 3; j++) d[j] /= num_atoms; for (int i = 0; i < num_atoms; i++) for (int j = 0; j < 3; j++) crd[i * 3 + j] -= d[j]; } void SimpleMD::Calc() { const double eps = 0.2f; const double Rij = 2.5f; double r, r_xyz, df, r12, r6, q; for (int i = 0; i < num_atoms; i++) { ene[i] = 0.0f; for (int j = i + 1; j < num_atoms; j++) { r = Distance(i, j); q = chg[i] * chg[j]; r12 = pow(Rij / r, 12); r6 = pow(Rij / r, 6); ene[i] += 2.0 * (eps * (r12 - 2.0f * r6) + q / r); for (int k = 0; k < 3; k++) { r_xyz = DistanceXYZ(i, j, k); df = (12 * eps / Rij) * (r12 * Rij / r - r6 * Rij / r) * r_xyz / r; df += q / pow(r, 3) * r_xyz; f[i * 3 + k] += df; f[j * 3 + k] -= df; } } } } void SimpleMD::Move() { double r, dr; for (int i = 0; i < num_atoms; i++) { for (int j = 0; j < 3; j++) { crd[i * 3 + j] += f[i * 3 + j] * 0.01f; f[i * 3 + j] = 0.0f; } r = 0.0f; for (int j = 0; j < 3; j++) r += crd[i * 3 + j] * crd[i * 3 + j]; dr = r - cap_range * cap_range; if (dr > 0.0f) { for (int j = 0; j < 3; j++) f[i * 3 + j] -= crd[i * 3 + j] / cap_range * dr * 0.01f; } } } void SimpleMD::PrintCrd() { cout << endl; cout << num_atoms << endl; cout << cap_range << endl; for (int i = 0; i < num_atoms; i++) { for (int j = 0; j < 3; j++) cout << " " << fixed << setw(10) << setprecision(6) << crd[i * 3 + j]; cout << " " << fixed << setw(8) << setprecision(4) << chg[i]; cout << endl; } } void SimpleMD::Run() { for (int i = 0; i < num_steps; i++) { Calc(); parallel_for(blocked_range<int>(0, num_atoms, 500), SimpleMDCalc(num_atoms, crd, f, ene, chg)); Move(); Center(); cout << "Energy (" << setw(7) << i + 1 << "): "; cout << fixed << setw(15) << setprecision(5) << Energy() << endl; } } int main(int argc, char** argv) { if (argc < 3) { cerr << "Simple Molecular Dynamics by nox" << endl; cerr << endl; cerr << " Usage: " << argv[0] << " crd_file num_step" << endl; exit(1); } task_scheduler_init init; stringstream ss; int nstep; ss.str(argv[2]); ss >> nstep; SimpleMD md(nstep, argv[1]); md.PrintCrd(); md.Run(); md.PrintCrd(); return 0; }
ã³ã³ãã¤ã«æ¹æ³
ä¸è¨ã®ã³ã¼ãä¸、赤åé¨å(ãã³ã¯ãå«ã)ã¯åé¤ãããã¨。TBBã©ã¤ãã©ãªã¸ã®ãã¹ãéããå¾ã§、Linux(GCCãIntel C++)ã§ã¯、
g++ simple_md_tbb.cpp -O3 -ltbb
icpc simple_md_tbb.cpp -O3 -ltbb
Windows(VC8/9)ã§ã¯、
cl simple_md_tbb.cpp /EHsc /O2 /MD
ã¨、ããã°ãã。
ã³ã¡ã³ã