// ■分子動力学法(Molecular Dynamics Method) // 右ボタンで停止、左ボタンで再開します。 #include "myWin.h" #include "stdlib.h" #include "time.h" #include "math.h" #define frand()((double)rand()/(RAND_MAX+1)) #define Xmax 10 // X最大位置 #define Ymax 10 // Y最大位置 #define Nmax 100 // 分子個数の最大数 #define EPSI 1.0 //フィッティングパラメータε(ポテンシャルの深さ) #define SIGMA 1 //フィッティングパラメータσ(衝突直径) typedef struct{ double X, Y;} point; static point F[Nmax]; //分子に働く力 static point R[2][Nmax]; //分子の位置 static point V[2][Nmax]; //分子の速度 double E1; //計算用(E1 = -48ε・σ^13 の値) double E2; //計算用(E2 = 24ε・σ^7 の値) double MG; //質量(分子の質量を1とする) double DT; //時間刻み double TM; //時間(今はカウントのみ。将来拡張用) int N; //分子の数 int ID1, ID2; //現時刻と次時刻切替え用添字, static HDC hBuff; static HBITMAP hBM; //ビットマップ表示用 void drawEllipse(int X1, int Y1, int X2, int Y2, int lColor, int bColor){//■端部の円形 HPEN pen=CreatePen(PS_SOLID, 1, lColor) ; SelectObject(hBuff, pen) ; HBRUSH brush=CreateSolidBrush(bColor) ; SelectObject(hBuff, brush); Ellipse(hBuff,X1,Y1, X2,Y2) ; DeleteObject(brush) ; DeleteObject(pen); } void drawBox(int X1, int Y1, int X2, int Y2, int lColor, int bColor){//■端部の円形 HPEN pen=CreatePen(PS_SOLID, 1, lColor) ; SelectObject(hBuff, pen) ; HBRUSH brush=CreateSolidBrush(bColor) ; SelectObject(hBuff, brush); Rectangle(hBuff,X1-10,Y1-10, X2+10,Y2+10); DeleteObject(brush) ; brush=CreateSolidBrush(0xFFFFFF) ; SelectObject(hBuff, brush); Rectangle(hBuff,X1,Y1, X2,Y2) ; DeleteObject(brush); DeleteObject(pen); } void crearBitmap(){ //■ビットマップクリア SelectObject(hBuff,GetStockObject(NULL_PEN)); PatBlt(hBuff,0, 0,1000,400,WHITENESS); } void compForce(){//■力の計算(Lennard-Jones Potentialによる力) for(int i=0; i<N;i++){ // Φ(r)=4ε{(σ/r)^12 - (σ/r)^6 F[i].X = F[i].Y = 0; // F(r) =4ε{-12(σ/r)^13 + 6(σ/r)^7} for(int j=0; j<N;j++){ // E1 = -48ε・σ^13 , E2 = 24 *ε・σ^7 if(i != j){ double dX = R[ID1][j].X - R[ID1][i].X; double dY = R[ID1][j].Y - R[ID1][i].Y; double DR = sqrt(dX * dX + dY * dY), FF ; if(DR < 1) DR =1; FF = E1 / pow(DR,13) + E2 / pow(DR,7); F[i].X += FF * dX / DR; F[i].Y += FF * dY / DR; } } } } void compVel(){//■速度計算 for(int i=0;i<N;i++){ V[ID2][i].X = V[ID1][i].X + DT * F[i].X / MG; V[ID2][i].Y = V[ID1][i].Y + DT * F[i].Y / MG; } double T = 0; // 温度境界条件(温度一定とするための処理) for(int i=0;i<N;i++){ double VX = V[ID2][i].X, VY = V[ID2][i].Y; T += VX * VX + VY * VY; } T = sqrt(T) *0.1; if(T > 0.00001){ for(int i=0;i<N;i++){ V[ID2][i].X /= T; V[ID2][i].Y /= T; } } } void compPlace(){//■位置計算 for(int i=0;i<N;i++){ R[ID2][i].X = R[ID1][i].X + DT * V[ID2][i].X; R[ID2][i].Y = R[ID1][i].Y + DT * V[ID2][i].Y; } } void boundWall(){//■壁衝突 double HS = 0.5 * SIGMA, XM=Xmax-HS, YM=Ymax-HS; for(int i=0;i<N;i++){ double IDX=R[ID2][i].X, IDY=R[ID2][i].Y; if(IDX < HS){ R[ID2][i].X = HS; V[ID2][i].X = abs(V[ID2][i].X);} if(IDX > XM){ R[ID2][i].X = XM; V[ID2][i].X = -abs(V[ID2][i].X);} if(IDY < HS){ R[ID2][i].Y = HS; V[ID2][i].Y = abs(V[ID2][i].Y);} if(IDY > YM){ R[ID2][i].Y = YM; V[ID2][i].Y = -abs(V[ID2][i].Y);} } } void initData(){//初期設定 N=10; DT=0.05; MG = 1; ID1 = 0; ID2 = 1;TM=0; E1 = -48 * EPSI * pow((double)SIGMA ,13); E2 = 24 * EPSI * pow((double)SIGMA , 7); for(int i=0;i<N;i++) F[i].X = F[i].Y = V[0][i].X =V[0][i].Y = 0; srand((int)time(NULL));int i=0; for(int i=0;i<N;i++){ R[0][i].X = frand() * (Xmax - 2)+1 ; R[0][i].Y = frand() * (Ymax - 2)+1 ; V[0][i].X=frand(); V[0][i].Y=frand(); int iflag=true, NN=0; while(iflag && NN<100){//近すぎる分子があったらずらすが、 NN++; //100回を限度とする。 for(int j=0; j<2;j++) for(int k=0; k<i;k++){ iflag=false; double DX=R[0][i].X-R[0][k].X, DY=R[0][i].Y-R[0][k].Y; if(DX*DX+DY*DY < 5 ){ iflag=true; R[0][i].X+=2;if(R[0][i].X> Xmax-1)R[0][i].X=1; R[0][i].Y+=2;if(R[0][i].Y> Ymax-1)R[0][i].Y=1; } } } } } void display(){//■表示 crearBitmap(); drawBox(30,20, 30+Xmax*20, 20+Ymax*20, 0,0xFF0000); for (int i = 0; i<N; i++){ drawEllipse((int)(R[ID1][i].X*20+20), (int)(R[ID1][i].Y*20+10), (int)(R[ID1][i].X*20+40), (int)(R[ID1][i].Y*20+30),0, 0xFF); } } void exec(){ TM=TM+DT;compForce(); compVel(); compPlace(); boundWall(); ID1=ID2; ID2=1-ID2; display(); } void procTimer(HWND hw, WPARAM wp,LPARAM lp){ //■タイマー処理 exec(); InvalidateRect(hw,NULL,TRUE); } void procLButtonDown(HWND hw, WPARAM wp,LPARAM lp){ //■左ボタン処理 SetTimer(hw,1,10,NULL); // 画面キャプチャのときここをコメントにする //exec(); InvalidateRect(hw,NULL,TRUE); // アニメーションのときここをコメントにする } void procRButtonDown(HWND hw, WPARAM wp,LPARAM lp){ //■左ボタン処理 KillTimer(hw,1); } void initBitmap(HWND hw){ //■ビットマップ初期設定 HDC hdc=GetDC(hw); hBM=CreateCompatibleBitmap(hdc,1000,400); hBuff=CreateCompatibleDC(hdc); SelectObject(hBuff,hBM); crearBitmap(); ReleaseDC(hw,hdc); } void procCreate(HWND hw, WPARAM wp,LPARAM lp){ //■Create時処理 SetWindowText(hw,TEXT("分子運動 左ボタンで開始, 右ボタンで停止")); MoveWindow(hw,0,0,280,280,TRUE); initBitmap(hw); initData();display(); InvalidateRect(hw,NULL,TRUE); procLButtonDown(hw, wp,lp); } void procPaint(HWND hw, WPARAM wp,LPARAM lp){ //■Paint時処理 PAINTSTRUCT ps; HDC hdc=BeginPaint(hw, &ps); BitBlt(hdc, 0,0,1000,400,hBuff,0,0,SRCCOPY); EndPaint(hw,&ps); } LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp,LPARAM lp){//■Window Procedure switch(msg){ case WM_DESTROY : PostQuitMessage(0) ; return 0; case WM_CREATE : procCreate(hw,wp,lp) ; return 0; case WM_PAINT : procPaint(hw,wp,lp) ; return 0; case WM_TIMER : procTimer(hw,wp,lp) ; return 0; case WM_LBUTTONDOWN : procLButtonDown(hw,wp,lp) ; break; case WM_RBUTTONDOWN : procRButtonDown(hw,wp,lp) ; break; } return DefWindowProc(hw,msg,wp,lp); }