2015-08-30 5 views
1

Я написал программу, которая вычисляет и анимирует орбиту плутонов, и начал переписывать ее с помощью классов, потому что это кажется разумным способом введения большего количества планет в симуляцию. У меня есть класс, который определяет физику, а затем загружает данные конкретной планеты, чтобы получить орбитальные данные.Извлечение данных из классов Python

class Planet(object): 
     m_sun = 1.989*(10**30) 
     G = 6.67*(10**-11) 
     dt = 1 
     coords = [] 
     def __init__(self, x, y, vx, vy, m): 
      self.x = x 
      self.y = y 
      self.vx = vx 
      self.vy = vy 
      self.m = m 


     def genData(self): 
      while self.dt < 100000000: 
       r = ((self.x)**2 + (self.y)**2)**0.5 
       a = ((self.G*self.m_sun)/r**2) 
       ax = -a*((self.x)/r) 
       ay = -a*((self.y)/r) 
       self.vx = self.vx + ax*self.dt 
       self.vy = self.vy + ay*self.dt 
       self.x = self.x + self.vx*self.dt 
       self.y = self.y + self.vy*self.dt 
       coord = (self.x, self.y) 
       print coord 
       self.coords.append(coord) 
       self.dt = self.dt + 1000 

pluto = Planet(4495978707000, 0, 0, 4670, 1.305*(10**22)) 
pluto.genData() 

Я уверен, что он не является совершенным, но это, кажется, работает (это первый класс я построил сам по себе). Мой вопрос заключается в том, как извлечь данные из «коордов» в список, с которым я могу работать вне класса.

Я хочу генерировать данные для каждой планеты, а затем использовать эти данные для создания анимации в Pygame. Например, список координат (x, y) для плутонов, земли, сатурна и т. Д. Как бы то ни было, он отображает данные, но он, похоже, не доступен извне класса.

Надеюсь, мой вопрос имеет смысл.

Спасибо!

+0

Это не связано с вопросом о доступе к данным 'coords', но вы, кажется, используете' self.dt' для двух разных вещей. Вы используете его в вычислительном коде как размер шага времени, но также и в состоянии цикла while в качестве общего истекшего времени. Вероятно, это должны быть отдельные переменные (при этом истекшее время увеличивается по времени, каждый из которых проходит через цикл). – Blckknght

+0

Спасибо, я всегда ценю комментарии о том, как улучшить код. – jm22b

+0

@Blckknght: Yikes! Я этого даже не заметил! Это объясняет сумасшедший выход. :) –

ответ

3

Вы попробовали pluto.coords?

Доступ к членам класса извне осуществляется с помощью экземпляра, за которым следует точка, за которым следует имя члена, т. Е. Доступ к атрибуту. Это так же, как вы это делали при вызове метода genData().

Кстати, вы можете определить константы с помощью экспоненциальной нотации:

m_sun = 1.989e+30 
G = 6.67e-11 

и

pluto = Planet(4495978707000, 0, 0, 4670, 1.305e+22) 

который является более удобным для чтения (важно) и сохраняет несколько вычислений для определения вашего класса (менее /не важно).

+0

Спасибо! Я этого не сделал, и это похоже на то, что мне нужно. – jm22b

2

На самом деле это очень легко, просто pluto.coords:

pluto = Planet(4495978707000, 0, 0, 4670, 1.305*(10**22)) 
pluto.genData() 
print pluto.coords 
+0

Вы правы, это очень легко. Большое спасибо! – jm22b

3

Вместо того чтобы хранить значения в self.coords, yield the values:

def genData(self): 
     while self.dt < 100000000: 
      ... 
      self.x = self.x + self.vx*self.dt 
      self.y = self.y + self.vy*self.dt 
      coord = (self.x, self.y) 
      yield coord 
      self.dt = self.dt + 1000 

pluto = Planet(4495978707000, 0, 0, 4670, 1.305*(10**22)) 

for coord in pluto.genData(): 
    print(coord) 

Обратите внимание, что это делает genDatagenerator function.

Чтобы получить список координат, вы можете накапливать значения в цикле:

coords = [] 
for coord in pluto.genData(): 
    coords.append(coord) 

или использовать coords = list(pluto.genData()).


К слову, это обычно хорошая политика для разделения кода, который вычисляется из кода, который печатает. Таким образом, вы можете вызывать код, который вычисляет много раз, или включать его в цепочку вычислений, не вызывая при этом печати операторов печати.


Я хочу, чтобы генерировать данные для каждой планеты, а затем использовать эти данные для создания анимации в Pygame.

Звучит так, как будто вам не нужно накапливать данные. Вы можете нарисовать текущую точку для каждой планеты, не зная историю координат планеты. В этом случае, с помощью функции генератора будет более эффективно использует память, так как они позволят вам создавать следующую координату для каждой планеты без необходимости хранить все координаты в списке первый:

# In Python2 
import itertools as IT 
for coords in IT.izip(*[planet.genData() for planet in [pluto, neptune, uranus, ...]]): 
    # plot coords 

или

# In Python3 
for coords in zip(*[planet.genData() for planet in [pluto, neptune, uranus, ...]]): 
    # plot coords 
+0

Зависит немного от прецедента. Возможно, координаты будут снова доступны объектом. Они могут быть восстановлены, но их хранение также кажется жизнеспособным. Вы можете сделать то и другое. – mhawke

+0

@ mhawke: Да, это правда. Когда я впервые просмотрел код, я думал, что цикл while бесконечен. – unutbu

+0

Благодарим вас за комментарий. Я нашел эту очень хорошую нить, которую я буду использовать, чтобы лучше понять «почему» вашего замечания. Я еще не знаком с «урожаем»! http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python – jm22b

4

На ваш вопрос был дан ответ, но у меня есть информация, которую вы должны найти полезной для улучшения своей программы. Технически эта информация принадлежит комментарию (поскольку вы на самом деле не спрашивали об этом в своем вопросе), но это не поместилось. :) орбита

  1. Плутона наклонена немного к эклиптике, так что если вы хотите построить его вместе с несколькими другими планетами в Солнечной системе, вы должны работать в 3D, чтобы быть точным. Но я предполагаю, что это не очень важно для вашего приложения.

  2. Земная орбита крошечная по сравнению с Плутоном, поэтому вам, вероятно, потребуется реализовать масштабирование, чтобы увидеть их как на одной анимации.

  3. Вы можете получить больше точности при расчетах, используя Standard gravitational parameter, а не используя отдельные значения G и массы.

  4. Ваш алгоритм вычисления скорости и положения называется Euler integration. Это эквивалентно аппроксимации кривой орбиты полигоном. Это работает, но это не очень точно. Поэтому вам нужно сделать очень маленькую дельту времени, в противном случае орбита будет не очень реалистичной, и она может даже не быть замкнутой кривой. И даже это не очень помогает, потому что ошибка является аккумулятивной, поэтому в конечном итоге вычисленная орбита будет мало напоминать реальность.

Нет метод численного интегрирования является совершенным (за исключением очень простых функций), но популярным семейством методов интеграции, которые являются более точными (и, следовательно, работать нормально с гораздо большим шагом по времени) являются Runge-Kutta methods. Вы можете найти множество примеров кода вычисления орбиты с использованием метода Рунге-Кутты; В большинстве примеров кода используется вариант, известный как RK4.

Тем не менее, я настоятельно прошу вас попробовать Leapfrog интеграции. Очень легко закодировать синхронизированную форму Leapfrog, и она имеет большую выгоду от Рунге-Кутты в том, что она симплектична, что (примерно) означает, что она сохраняет энергию, поэтому ошибка не будет накапливаться с орбиты на орбиту.

+0

Спасибо! Много полезной информации для меня, чтобы копать в – jm22b

+0

Что касается вашего комментария об интеграции Euler; Когда я запускаю свое моделирование Плутона, которое является «полным» и использует ту же физическую модель, что и в моем ОП, узор орбиты производит своего рода «переплетение корзины». Разве это не «закрытая кривая»? – jm22b

+0

@Jacobadtr: Это звучит так, хотя 1000 секунд на шаг на Плутоне не должны давать вам абсолютно сумасшедшую траекторию ... Я думаю, вы проверили, что ваша начальная позиция и скорость действительны, но это легко используйте километры вместо метров (или наоборот). :) Я никогда не пробовал вычислять траекторию Плутона (в основном я делаю простые вещи, где я могу работать годами и AU), но IIRC интеграция Эйлера с орбитой Марса не приведет к закрытой кривой с временным шагом в один день - вы нужно спуститься на час или меньше, если вы хотите вычислить несколько оборотов. –

Смежные вопросы