Эффективный способ моделирования многих столкновений частиц?

Я хотел бы написать небольшую программу, имитирующую многие столкновения частиц, начиная сначала в 2D (я бы расширил ее до 3D позже), чтобы (в 3D) смоделировать сходимость к распределению Больцмана, а также посмотреть, как распределение развивается в 2D.

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

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

Итак, теперь: даже если этот подход будет работать с производительностью (скажем, 40fps), может ли кто-нибудь придумать способ избежать ненужных проверок столкновений?

моя собственная идея состояла в том, чтобы разделить доску (или в 3D: space) на квадраты (Кубы), которые имеют размеры, по крайней мере, диаметров частиц и реализовать способ проверки только для столкновений, если центры двух частиц находятся в пределах смежных квадратов в сетке...

Я был бы рад услышать больше идей, так как я хотел бы увеличить количество частиц столько, сколько я могу, и все еще иметь расчет/моделирование в реальном времени.

Edit: все столкновения являются чисто упругими столкновениями без каких-либо других сил, выполняющих работу на взвешенные частицы. Начальная ситуация, которую я буду реализовывать, будет определяться некоторыми переменными, выбранными Пользователем для выбора случайных начальных положений и скоростей.

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

5 ответов


если вы думаете об этом, частицы, движущиеся по плану, действительно являются 3D-системой, где три измерения x, y и время (t).

скажем, "шаг времени" идет от t0 to t1. Для каждой частицы вы создаете 3D-сегмент линии, идущий от P0(x0, y0, t0) to P1(x1, y1, t1) основанный на настоящих положении, скорости и направлении частицы.

разделите 3D-пространство в 3D-сетке и свяжите каждый сегмент 3D-линии с ячейками крест.

теперь каждая ячейка сетки должна быть проверена. Если он связан с 0 или 1 сегментами, он не нуждается в дополнительной проверке (отметьте его как проверенный). Если он содержит 2 или более сегментов, вам нужно проверить наличие столкновения между ними: вычислить 3D-точку столкновения Pt, сократите два сегмента до конца в этот момент (и удалите ссылку на ячейки, которые они больше не пересекают), создайте два новых сегмента, начиная с Pt вновь вычисленные P1 пункты согласно новым направлению / скорости взвешенные частицы. Добавьте эти новые сегменты линии в сетку и отметьте ячейку как отмеченную. Добавление сегмента линии в сетку превратит все скрещенные ячейки в непроверенное состояние.

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

редактировать

  • для частиц 3D, приспособьтесь над разрешением к 4D.
  • Octrees-хорошая форма сетки 3D-разделения пространства в этом случае, так как вы можете " пузыриться" проверено/unnchecked статус быстро найти клетки, требующих внимания.

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

скажем, весло находится в верхнем левом углу экрана, а мяч находится рядом с нижним левым углом экрана...

--------------------
|▌                 |
|                  |
|                  |
|     ○            |
--------------------

нет необходимости проверять столкновение каждый раз, когда мяч движется. Вместо этого разделите игровое поле на два прямо посередине. Мяч в левой части поля? (простой точка внутри прямоугольника алгоритма)

  Left       Right
         |
---------|----------
|▌       |         |
|        |         |
|        |         |
|     ○  |         |
---------|----------
         |

Если ответ да, разделите левую сторону снова, на этот раз горизонтально, чтобы у нас был верхний левый и нижний левый раздел.

   Left       Right
          |
 ---------|----------
 |▌       |         |
 |        |         |
-----------         |
 |        |         |
 |     ○  |         |
 ---------|----------
          |

этот мяч в том же левом верхнем углу экрана, что и весло? Если нет, не нужно проверять на столкновение! только объекты, которые находятся в одном разделе, должны быть проверены на столкновение друг с другом. Сделав ряд простых (и дешевых) точек внутри прямоугольник проверяет, вы можете легко сэкономить от выполнения более дорогой проверки формы/геометрии столкновения.

вы можете продолжать разбивать пространство на все меньшие и меньшие куски, пока объект не охватит два раздела. Это основной принцип BSP (техника, впервые появившаяся в ранних 3D-играх, таких как Quake). Существует целая куча теории в интернете о пространственном разбиении на 2 и 3 размеры.

http://en.wikipedia.org/wiki/Space_partitioning

в 2 измерениях вы часто использовали бы BSP или quadtree. В 3-х измерениях вы часто используете octree. Однако основополагающий принцип остается прежним.


вы можете думать по линии "разделяй и властвуй". Идея состоит в том, чтобы идентифицировать ортогональные параметры, не влияющие друг на друга. например, можно подумать о расщеплении компонента импульса вдоль оси 2 в случае 2D (ось 3 в 3D) и вычислить столкновение/положение независимо. Другим способом идентификации таких параметров может быть группировка частиц, которые движутся перпендикулярно друг другу. Таким образом, даже если они влияют, чистый импульс вдоль этих линий не меняется.

Я согласен выше не полностью отвечает на ваш вопрос, но передает фундаментальную идею, которую вы можете найти полезной здесь.


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

P   position
V   speed

и массив информации N*(N-1)/2 между частицами A(i) и A(j), где i

    MAT[i][j] = { dx, dy, dz, sx, sy, sz }. 

что означает, что по отношению к частице j частица j имеет расстояние, состоящее из трех компонентов dx, dy и dz; и Дельта-vee, умноженное на dt, которое является sx, sy, sz.

для перехода на instant t+dt вы предварительно обновите положения всех частиц на основе их скорости

px[i] += dx[i]  // px,py,pz make up vector P; dx,dy,dz is vector V premultiplied by dt
py[i] += dy[i]  // Which means that we could use "particle 0" as a fixed origin
pz[i] += dz[i]  // except you can't collide with the origin, since it's virtual

затем вы проверяете весь массив N*(N-1)/2 и предварительно вычисляете новое относительное расстояние между каждой парой частиц.

dx1 = dx + sx
dy1 = dy + sy
dz1 = dz + sz
DN  = dx1*dx1+dy1*dy1+dz1*dz1  # This is the new distance

если DN

затем вы вычисляете точно, где это произошло, т. е. вы вычисляете точное d't столкновения, которое вы можете сделать со старого расстояния квадрат D2 (dx*dx+dy * dy+dz * dz) и новый DN: это

d't = [(SQRT(D2)-D)/(SQRT(D2)-SQRT(DN))]*dt

(время, необходимое для уменьшения расстояния от SQRT(D2) до D, со скоростью, которая покрывает расстояние SQRT(D2)-SQRT (DN) во времени dt). это делает гипотезу, что частица j, видимая из рамки рефренса частицы i, не "перескочила".

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

зная d'T, и d " t = dt - d't, вы можете повторить позицию расчет на Pi и Pj с использованием dx*d't/dt и т. д. и получите точное положение P частиц i и j в момент столкновения; вы обновите скорости, затем интегрируете его для оставшихся d"t и получите положения в конце времени dt.

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

поэтому вместо выполнения вычислений мы просто отмечаем, что столкновение произошло в d не для частицы (i,j), а в конце пробега мы сохраняем минимум d'T, при котором произошло столкновение, и между которыми.

то есть, предположим, мы проверяем частицы 25 и 110 и находим столкновение при 0.7 dt; затем мы находим столкновение между 110 и 139 при 0.3 dt. Нет столкновений раньше, чем 0.3 dt.

мы входим в фазу обновления столкновения и" сталкиваемся " 110 и 139 и обновляем их положение и скорость. Затем повторите вычисления 2*(N-2) для каждого (i, 110) и (i, 139).

мы обнаружим, что столкновение с частицей 25, вероятно, все еще имеет место, но уже при 0,5 dt, а может быть, и при 0,9 dt между 139 и 80. 0.5 dt-это новый минимум, поэтому мы повторяем расчет столкновения между 25 и 110 и повторяем, испытывая небольшое "замедление" в алгоритме для каждого столкновения.

таким образом, единственный риск сейчас-это "призрачные столкновения", т. е. частица находится на D > диаметре от цели в момент времени t-dt и находится на D > диаметр С другой стороны в момент времени t.

этого вы можете избежать, только выбрав dt так, чтобы ни одна частица никогда не перемещалась больше половины своего диаметра в любом данном dt. На самом деле, вы можете использовать адаптивный dt, основанный на скорости самой быстрой частицы. Столкновения призраков все еще возможны; дальнейшее уточнение заключается в уменьшении dt на основе ближайшего расстояния между любыми двумя частицами.

таким образом, это правда, что алгоритм замедляет значительно в непосредственной близости от столкновения, но он невероятно ускоряется, когда столкновения маловероятны. Если минимальное расстояние (которое мы вычисляем почти бесплатно во время цикла) между двумя частицами таково, что самая быстрая частица (которую мы также узнаем почти бесплатно) не может покрыть его менее чем за пятьдесят dts, это увеличение скорости на 4900% прямо там.

во всяком случае, в общем случае без столкновения мы теперь сделали пять сумм (на самом деле больше похоже на тридцать четыре из-за массива индексирование), три продукта и несколько назначений для каждой пары частиц. Если мы включим пару (k,k), чтобы учесть само обновление частицы, у нас есть хорошее приближение стоимости до сих пор.

этот метод имеет преимущество быть O(N^2) - он масштабируется с количеством частиц - вместо того, чтобы быть O (M^3) - масштабирование с объемом вовлеченного пространства.

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

P.S.: Это на самом деле очень похоже на подход Николя Репике, в том числе необходимость замедления в 4D окрестности нескольких столкновений.


пока не произойдет столкновение между двумя частицами (или между частицей и стенкой), интеграция тривиальна. Подход здесь состоит в том, чтобы рассчитать время первого столкновения, интегрировать до тех пор, затем рассчитать время второго столкновения и так далее. Давайте определим tw[i] как раз iTh частица принимает ударить первую стену. Это довольно легко рассчитать, хотя необходимо учитывать диаметр сферы.

расчет время tc[i,j] столкновения двух частиц i и j занимает немного больше времени, и следует из исследования во время их расстояние d:

d^2=Δx(t)^2+Δy(t)^2+Δz(t)^2

мы изучаем, если существует t позитивный такой, что d^2=D^2, будучи D диаметр частиц(или сумма двух радиусов частиц, если вы хотите их по-разному). Теперь рассмотрим первый член суммы на RHS,

Δx(t)^2=(x[i](t)-x[j](t))^2=

Δx(t)^2=(x[i](t0)-x[j](t0)+(u[i]-u[j])t)^2=

Δx(t)^2=(x[i](t0)-x[j](t0))^2+2(x[i](t0)-x[j](t0))(u[i]-u[j])t + (u[i]-u[j])^2t^2

где новые термины, появляющиеся, определяют закон движения двух частиц для x координации

x[i](t)=x[i](t0)+u[i]t

x[j](t)=x[j](t0)+u[j]t

и t0 время начальной настройки. Пусть тогда (u[i],v[i],w[i]) быть тремя составляющими скоростей i-ой частицы. То же самое для остальных трех координат и суммирование, мы получаем полиномиальное уравнение 2-го порядка в t,

at^2+2bt+c=0,

здесь

a=(u[i]-u[j])^2+(v[i]-v[j])^2+(w[i]-w[j])^2

b=(x[i](t0)-x[j](t0))(u[i]-u[j]) + (y[i](t0)-y[j](t0))(v[i]-v[j]) + (z[i](t0)-z[j](t0))(w[i]-w[j])

c=(x[i](t0)-x[j](t0))^2 + (y[i](t0)-y[j](t0))^2 + (z[i](t0)-z[j](t0))^2-D^2

теперь есть много критериев для оценки существования реального решения и т. д... Вы можете оценить это позже, если хотите оптимизировать его. В любом случае вы получите tc[i,j], и если он сложный или отрицательный, вы устанавливаете его в плюс бесконечность. Чтобы ускорить, помните, что tc[i,j] симметрично, и вы также хотите установить tc[i,i] к бесконечности для удобства.

тогда вы берете минимум tmin массива tw и матрицы tc, и интеграцию во времени времени tmin.

теперь вычесть tmin ко всем элементам tw и tc.

в случае упругого столкновения со стенкой i - Я частица, вы просто переворачиваете скорость этой частицы и пересчитываете только tw[i] и tc[i,k] для любой другой k.

в случае столкновения двух частиц вы пересчитываете tw[i],tw[j] и tc[i,k],tc[j,k] для всех остальных k. Оценка упругого столкновения в 3D не является тривиальной, возможно, вы можете использовать это

http://www.atmos.illinois.edu/courses/atmos100/userdocs/3Dcollisions.html

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

не забудьте добавить дополнительные промежуточные временные шаги, если вы хотите построить свойство против времени.