Python으로 만든 중력 시뮬레이션


개강도 얼마 안남았고 하루하루를 게임과 인터넷 서핑으로 무료하게 보내다가 오랜만에 나름 생산적인 일을 하기로 했다. 오늘의 유머에서 어떤 사람이 제작한 생태계 시뮬레이션에 대한 글을 보고 갑자기 아무거나 코딩을 하고 싶다는 생각이 들었고 뭘 만들까 고민하다가 중력 시뮬레이션을 만들기로 했다. 물론 내가 유일하게 제대로 할 수 있는 언어인 파이썬으로 :D

물체 구현

종강한지 꽤 되어서 다 잊어버리지 않았을까 걱정했는데 다행히 전에 짰던 코드를 좀 보니까 웬만큼 기억이 났다. 객체지향, 클래스, 메쏘드, 어쩌구… 파이썬 짱짱맨!

복잡한 물체의 중력을 구현하긴 귀찮으므로 (메모리의 문제도 있고 내 코딩 실력의 문제도 있고) 모든 물체는 구형으로 (사실은 원형으로) 통일하기로 했다. 그래픽 구현 모듈로는 파이썬 내장 기본 모듈인 tkinter을 사용했다. 각 물체에 해당되는 클래스인 Object 클래스를 만들어서 (객체 object와 혼동된다면 기분탓) 위치, 속도, 질량, 반지름, 색을 입력받는다. 하다보니 벡터 클래스가 필요할 듯 싶어 하나 만들었다.

일단 초기 위치에 물체를 그리고 매 time interval마다 속도에 따라 일정 거리만큼 움직이도록 하엿다.

중력 구현

매 interval마다 중력을 계산해서 가속도를 계산하고 속도를 계속 업데이트 하도록 하였다. 중력을 계산하는게 은근 고역이었는데, 실제 상황과 최대한 비슷하게 만들고 싶다는 되도 않는 욕심이 생겼기 때문이었다. 한 픽셀을 0.01 AU, 시뮬레이션 상에서 1초가 실제로 30일이라고 정했고 질량 단위로는 지구의 질량을 사용하기로 했다. 그에 따라서 중력 상수를 다시 계산했는데 물리 공부 안한지 오래 되어서 그런가 이 간단한게 왜이렇게 계산이 안되는지… 자다가 일어난 직후에 바로 해서 그런 것 같다.

다음은 태양-지구 시뮬레이션. 참고로 실제 조건과 거의 일치한다.

그런데 문제가 발생했다. 두 물체가 매우 가까이 접근하면 다음과 같은 물리적으로 말이 안되는 이상한 현상이 나타나는 것이다.

시간이 불연속적이여서 조금씩 오차가 생기는데 중력이 매우 클 때 이 오차가 극대화되는게 아닌가 싶다. 그래서 물체의 충돌을 구현해서 아예 두 물체가 매우 가깝게 다가오는 일이 없도록 하기로 하였다.

충돌 구현

처음에는 그냥 두 물체가 서로 겹치는지 조사해서 겹친다면 그에 따라 속도를 반대로 바꾸어 주려고 했으나 생각보다 문제가 쉽지 않았다. 두 물체가 충돌하는 경우에는 어렵지 않게 되겠는데 세 물체가 동시에 충돌하는 등의 경우에는 그 방법이 통하지 않았다.

어떻게 할지 고민하다가 중력 구현할 때 이미 힘의 개념을 사용했으니 여기에 충돌에 의한 충격력을 추가하기로 했다. 두 물체가 겹칠 때 겹치는 두께에 비례하게 두 물체의 중심에서 벗어나는 방향으로 힘을 준다. 사실 이 쪽이 실제로 현실에서 일어나는 일에 더 가깝기도 하다.  작용 반작용 법칙도 자연스럽게 만족하며 물체가 많아져도 문제가 없다. 그냥 가해지는 힘을 전부 더하면 되기 때문이다. 중력보다 충돌에 의한 충격력이 충분히 커지도록 적당히 비례 상수를 설정했다. 결과는 나름 만족스러웠다.

다음은 3체 문제. 참고로 실제로는 저것보다 부드럽다. 버벅거리는건 반디캠 문제;;

이건 대칭적인 4체 문제. 그런데 계속 진행하다 보니 어느 순간부터 대칭성이 깨지고 하나가 밖으로 튕겨 나갔다. 역시 시간이 불연속적이여서 발생하는 오차는 무시할 수 없나 보다.

공 하나를 엄청나게 크게 만들고 큰 질량을 부여해서 거의 균일한 중력장을 만들 수도 있고 공을 불규칙하게 많이 만들어서 어떤 행동을 보이는지 관찰할 수도 있다. 전자는 귀찮아서 패스하고 후자는 다음과 같다.

뭉치는 듯 하다가 결국 흩어지는데 불완전탄성 충돌을 구현한다면 서로 뭉쳐서 별을 형성하는 것을 볼 수 있을 것 같다. 중간중간에 몇몇 공들이 튀어나가는 건 버그인데 역시 불연속적인 시간 때문에 발생한다. 충돌에 의한 충격력을 계산할 때 쓰이는 비례 계수가 지나치게 클 때 이 버그가 많이 발생한다. 문제는 공들의 질량에 따라서 딱 적당한 비례 계수의 값이 변한다는 것이다. 그래서 공들의 질량을 바꿀 때마다 비례 계수를 바꾸어 주어야 하는데 이를 해결할 수 있는 방안을 아직 떠올리지 못했다.

기타 짜잘한 것들

앞으로 척도를 넣고 시작, 일시정지, 다시시작 기능을 만드는 등 짜잘한 것들을 구현할 계획이다. 할 수만 있다면 사용자가 시뮬레이션을 실행하는 도중에 물체를 만들거나 각종 상수들을 바꾸는 등의 일을 할 수 있도록 하고 싶다.

오랜만에 코딩하니 꽤 재밌다. 계산과학 연합전공을 포기하려고 했는데 다시 할까 고민해봐야겠다.

2 comments

  1. 제법 흥미로운데요? 혹시 메일로 코드 한번만 보내주실 수 있을까요… 파이썬은 클래스나 메쏘드 개념이 생소해서 어떻게 프로그래밍하는지 모르겠네요.

  2. 안녕하세요
    현재 파이썬을 독학하고 있는 고등학교 1학년 학생입니다.
    글을 읽고 큰 감명을 받았습니다.
    파이썬을 독학하고 있어서 매우 간단하고 자잘한 프로그램만을 짤 수 있는 수준입니다.
    정말 누가 안된다면 메일을 통해 간단한 질문을 주고 받는 형식으로 파이썬을 배우고 싶습니다.
    정말 기초적인 수준으로 파이썬을 배운지 약 2주일 정도 되었습니다.
    While If Else Print Input 정도 다룰 수 있습니다.
    안된다면 거절하셔도 아무 상관없습니다.
    혹시 누가 되었다면 죄송합니다. 부탁드립니다. 감사합니다.

Leave a Reply to 최승우 Cancel reply