Ядра SPH: глибокий розбір Poly6, Spiky, Viscosity та кубічного B-сплайна
Будь-яка симуляція методом згладженої гідродинаміки частинок (SPH) живе або гине залежно від вибору ядра. Та сама фізика, зважена неправильною функцією, або вибухає в шум, або злипається в нефізичні грудки. Ось чому ядра мають значення — і як обрати правильне.
1. Роль ядра в SPH
У SPH будь-яка фізична величина (густина, тиск, швидкість)
обчислюється не в точці, а як зважена сума значень
сусідніх частинок. Ядро W(r, h) — це вагова
функція, яка визначає, наскільки сильно частинка на відстані
r впливає на центральну частинку в межах радіуса
згладжування h (smoothing length).
Ключове спостереження: ядро — це не просто «вага за відстанню».
Різні фізичні величини потребують різних
похідних ядра: густина використовує саме
W, тиск — градієнт ∇W, а в'язкість —
лапласіан ∇²W. Погано підібране ядро для градієнта
призводить до нестабільності навіть якщо густина обчислюється
коректно.
Одне й те саме ядро для всіх операторів (як робили у ранніх реалізаціях) призводить до частинкового кластерингу — «particle clumping» — коли частинки злипаються в парах на відстані, де градієнт ядра дорівнює нулю. Це фундаментальна причина, чому сучасні реалізації SPH використовують окремі ядра для тиску (Spiky) і в'язкості (Viscosity).
2. Математичні вимоги
Щоб ядро було коректним для SPH, воно повинно задовольняти чотирьом умовам:
- Нормалізація: ∫ W(r, h) dr = 1 у всьому просторі — інакше інтерполяція зміщує величини систематично.
- Компактний носій (compact support): W(r, h) = 0 при r > h — це дозволяє обмежити пошук сусідів радіусом h і використовувати просторове хешування замість O(N²) перебору.
- Додатність: W(r, h) ≥ 0 всюди — фізичні величини на кшталт густини не можуть бути від'ємними.
- Спадання з відстанню (monotonic decay): найближчі сусіди повинні впливати сильніше за дальні, а на межі носія (r = h) ядро і, бажано, його похідна плавно йдуть до нуля (C¹-неперервність), щоб уникнути розривів сили.
Нормувальна константа σ (наприклад,
315/(64πh⁹) для Poly6 у 3D) виводиться саме з цієї
умови і залежить від розмірності простору (1D/2D/3D мають різні
константи).
3. Ядро Poly6
Poly6 (запропоновано Müller et al., 2003) — гладка поліноміальна функція, ідеальна для обчислення густини, де важлива гладкість, а не точність градієнта біля центру.
W_poly6(r, h) = 0, r > h
Проблема Poly6 — його градієнт прямує до нуля при r → 0:
Коли r → 0, множник r обнуляє весь градієнт. Це означає, що для двох частинок, які злиплись впритул, сила відштовхування, обчислена через градієнт Poly6, зникає — саме тому це ядро не можна використовувати для тиску. Використання Poly6 лише для густини — стандартна практика.
4. Ядро Spiky
Ядро Spiky вирішує проблему нульового градієнта біля центру за рахунок «гострої» вершини (звідси назва) — похідна лишається ненульовою навіть при r → 0.
При r → 0 градієнт прямує до −45/(πh⁶) · h² —
ненульова константа, яка забезпечує сильне
відштовхування частинок, що злиплись. Це ключова властивість, яка
запобігає взаємопроникненню частинок під високим тиском.
На практиці силу тиску симетризують, щоб уникнути порушення
третього закону Ньютона через асиметрію тиску pᵢ ≠ pⱼ:
Fᵢ = −Σⱼ mⱼ · (pᵢ + pⱼ)/(2ρⱼ) · ∇W_spiky(rᵢ − rⱼ, h).
Це гарантує рівність дії й протидії з точністю до заокруглення.
5. Ядро в'язкості
В'язкість вимагає лапласіана поля швидкості
(∇²W), а не градієнта. Ні Poly6, ні Spiky не дають
монотонного, стабільного лапласіана — Müller et al.
запропонували окреме ядро саме для цієї мети.
Лапласіан цього ядра лінійний і завжди додатний у межах носія — це гарантує, що в'язка сила завжди діє в напрямку вирівнювання швидкостей (як фізична в'язкість і повинна), без паразитних осциляцій, які виникали б із лапласіана Poly6 чи Spiky.
6. Кубічний B-сплайн
Ядро Мональхана-Ласерсона (кубічний B-сплайн) — стандарт у науковій астрофізичній SPH (GADGET, PHANTOM), на відміну від ігрового набору Poly6/Spiky/Viscosity. Воно кусочно-визначене на двох інтервалах і дає один набір формул для густини, градієнта і лапласіана — з коректною поведінкою в усіх трьох випадках:
1 − 3/2·q² + 3/4·q³, 0 ≤ q ≤ 1
1/4·(2 − q)³, 1 ≤ q ≤ 2
0, q > 2
(σ₃ = 1/π у 3D)
На відміну від Poly6/Spiky/Viscosity, кубічний сплайн C²-гладкий (неперервна друга похідна) — важливо для довгих астрофізичних симуляцій, де накопичення похибки на мільярдах кроків критичне. Носій охоплює 2h замість h — тому потребує більше сусідів (≈ 50 у 3D) для тієї ж роздільної здатності.
У сучасних SPH-кодах (SPHysics, DualSPHysics) кубічний сплайн часто заміняють ядрами Wendland (C2, C4, C6) — вони не мають «pairing instability» кубічного сплайна при малому числі сусідів і швидше згасають, зменшуючи вартість пошуку сусідів.
7. Порівняння ядер
| Ядро | Найкраще для | Носій | Град. при r→0 | Гладкість |
|---|---|---|---|---|
| Poly6 | Густина ρ | h | 0 (погано для сили) | C¹ |
| Spiky | Сила тиску | h | Ненульовий ✅ | C⁰ при r=0 |
| Viscosity | В'язка сила (лапласіан) | h | — | Монотонний ∇² |
| Cubic spline | Астрофізичний SPH (усі оператори) | 2h | Ненульовий ✅ | C² |
| Wendland C2 | Сучасний SPH при великих N | h | Ненульовий ✅ | C² компактний |
8. Типові помилки
Одне ядро для всього
Найпоширеніша помилка новачків — обчислювати і густину, і тиск, і в'язкість через градієнт одного й того ж Poly6. Результат: частинки, злипаючись, не відштовхуються (градієнт → 0), і симуляція «замерзає» в купки замість плавної течії рідини.
Неправильна нормувальна константа для розмірності
Константи 315/(64πh⁹) для Poly6 і
15/(πh⁶) для Spiky коректні лише в 3D.
Для 2D-симуляцій (плоска рідина в canvas/WebGL side-view)
потрібні окремі нормувальні множники — інакше загальна маса
системи «пливе».
Занадто мале або занадто велике h
Занадто мале h → мало сусідів → шумна, нестабільна апроксимація (недостатньо статистики). Занадто велике h → надмірне згладжування, втрата деталей, вища вартість O(N·k). Практичне правило: h таке, щоб у носії було 20–40 сусідів у 2D, 30–60 у 3D.
9. Псевдокод
Три ядра в одному об'єкті (JS)
// Ядра SPH — 2D варіант (canvas / WebGL side simulations)
function makeKernels(h) {
const h2 = h * h, h6 = h**6, h9 = h**9;
return {
// Poly6 — тільки для густини
poly6(r) {
if (r > h) return 0;
const diff = h2 − r * r;
return (315 / (64 * Math.PI * h9)) * diff**3;
},
// Spiky gradient — сила тиску (ненульовий градієнт при r→0)
spikyGrad(r, dir) {
if (r > h || r === 0) return [0, 0];
const coeff = −45 / (Math.PI * h6) * (h − r)**2;
return [coeff * dir[0], coeff * dir[1]];
},
// Viscosity Laplacian — гарантовано монотонний, стабільний
viscLaplacian(r) {
if (r > h) return 0;
return (45 / (Math.PI * h6)) * (h − r);
}
};
}
Побачити ядра SPH у дії
Симуляція рідини використовує Poly6 для густини, Spiky для тиску і ядро в'язкості — саме те розділення, яке описане в цій статті.
⭐ SPH Fluid 🔵 Молекулярна динаміка