Saya mencoba menerapkan versi 2D makalah Foster dan Fedkiw, "Animasi Praktis Cairan" di sini: http://physbam.stanford.edu/~fedkiw/papers/stanford2001-02.pdf
Sebagian besar semuanya berfungsi, kecuali bagian 8: "Konservasi Misa." Di sana, kami membuat matriks persamaan untuk menghitung tekanan yang diperlukan untuk membuat cairan divergen bebas.
Saya percaya kode saya cocok dengan kertas, namun saya mendapatkan matriks yang tidak dapat diselesaikan selama konservasi langkah massal.
Berikut langkah-langkah saya untuk menghasilkan matriks A:
- Atur entri diagonal ke negatif dari jumlah sel cair yang berdekatan ke sel i.
- Atur entri dan menjadi 1 jika kedua sel i dan j memiliki cairan.
Perhatikan bahwa, dalam implementasi saya, sel , dalam kotak cair sesuai dengan baris gridWidth dalam matriks.
Makalah ini menyebutkan, "Objek statis dan sel kosong tidak mengganggu struktur ini. Dalam hal ini istilah tekanan dan kecepatan dapat menghilang dari kedua sisi", jadi saya menghapus kolom dan baris untuk sel yang tidak memiliki cairan.
Jadi pertanyaan saya adalah: Mengapa matriks saya tunggal? Apakah saya melewatkan semacam kondisi batas di tempat lain di koran? Apakah ini fakta bahwa implementasi saya adalah 2D?
Berikut ini adalah contoh matriks dari implementasi saya untuk kisi 2x2 di mana sel pada 0,0 tidak memiliki cairan:
-1 0 1
0 -1 1
1 1 -2
Edit
Penelitian saya membuat saya percaya bahwa saya tidak benar menangani kondisi batas.
Pertama-tama, pada titik ini saya dapat mengatakan bahwa matriks saya mewakili persamaan Poisson tekanan diskrit. Ini adalah analog diskrit dari penerapan operator Laplacian yang menggabungkan perubahan tekanan lokal ke divergensi sel.
Sejauh yang saya bisa mengerti, karena kita berurusan dengan perbedaan tekanan, kondisi batas diperlukan untuk "menjangkar" tekanan ke nilai referensi absolut. Kalau tidak, mungkin ada sejumlah solusi tak terbatas untuk set persamaan.
Dalam catatan ini , 3 cara berbeda diberikan untuk menerapkan kondisi batas, sejauh yang saya pahami:
Dirichlet - menentukan nilai absolut di batas.
Neummann - menentukan turunan pada batas.
Robin - menentukan beberapa jenis kombinasi linear dari nilai absolut dan turunannya pada batas.
Makalah Foster dan Fedki tidak menyebutkan semua ini, tetapi saya percaya bahwa mereka menegakkan kondisi batas Dirichlet, penting karena pernyataan ini pada akhir 7.1.2, "Tekanan dalam sel permukaan diatur ke tekanan atmosfer."
Saya telah membaca catatan yang saya tautkan beberapa kali dan masih tidak mengerti perhitungan matematika yang terjadi. Bagaimana tepatnya kita menegakkan syarat batas ini? Melihat implementasi lain, tampaknya ada semacam gagasan tentang sel "Hantu" yang terletak pada batas.
Di sini saya telah menautkan ke beberapa sumber yang mungkin bermanfaat bagi orang lain yang membaca ini.
Catatan tentang kondisi batas untuk Matriks Poisson
Postingan Ilmu Komputasi StackExchange pada kondisi batas Neumann
Pos Ilmu Komputasi StackExchange di Poisson Solver
Berikut adalah kode yang saya gunakan untuk menghasilkan matriks. Perhatikan bahwa, alih-alih menghapus kolom dan baris secara eksplisit, saya membuat dan menggunakan peta dari indeks sel cair ke kolom / baris matriks terakhir.
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
FluidGridCell cell = cells[i][j];
if (!cell.hasLiquid)
continue;
// get indices for the grid and matrix
int gridIndex = i + cells.length * j;
int matrixIndex = gridIndexToMatrixIndex.get((Integer)gridIndex);
// count the number of adjacent liquid cells
int adjacentLiquidCellCount = 0;
if (i != 0) {
if (cells[i-1][j].hasLiquid)
adjacentLiquidCellCount++;
}
if (i != cells.length-1) {
if (cells[i+1][j].hasLiquid)
adjacentLiquidCellCount++;
}
if (j != 0) {
if (cells[i][j-1].hasLiquid)
adjacentLiquidCellCount++;
}
if (j != cells[0].length-1) {
if (cells[i][j+1].hasLiquid)
adjacentLiquidCellCount++;
}
// the diagonal entries are the negative count of liquid cells
liquidMatrix.setEntry(matrixIndex, // column
matrixIndex, // row
-adjacentLiquidCellCount); // value
// set off-diagonal values of the pressure matrix
if (cell.hasLiquid) {
if (i != 0) {
if (cells[i-1][j].hasLiquid) {
int adjacentGridIndex = (i-1) + j * cells.length;
int adjacentMatrixIndex = gridIndexToMatrixIndex.get((Integer)adjacentGridIndex);
liquidMatrix.setEntry(matrixIndex, // column
adjacentMatrixIndex, // row
1.0); // value
liquidMatrix.setEntry(adjacentMatrixIndex, // column
matrixIndex, // row
1.0); // value
}
}
if (i != cells.length-1) {
if (cells[i+1][j].hasLiquid) {
int adjacentGridIndex = (i+1) + j * cells.length;
int adjacentMatrixIndex = gridIndexToMatrixIndex.get((Integer)adjacentGridIndex);
liquidMatrix.setEntry(matrixIndex, // column
adjacentMatrixIndex, // row
1.0); // value
liquidMatrix.setEntry(adjacentMatrixIndex, // column
matrixIndex, // row
1.0); // value
}
}
if (j != 0) {
if (cells[i][j-1].hasLiquid) {
int adjacentGridIndex = i + (j-1) * cells.length;
int adjacentMatrixIndex = gridIndexToMatrixIndex.get((Integer)adjacentGridIndex);
liquidMatrix.setEntry(matrixIndex, // column
adjacentMatrixIndex, // row
1.0); // value
liquidMatrix.setEntry(adjacentMatrixIndex, // column
matrixIndex, // row
1.0); // value
}
}
if (j != cells[0].length-1) {
if (cells[i][j+1].hasLiquid) {
int adjacentGridIndex = i + (j+1) * cells.length;
int adjacentMatrixIndex = gridIndexToMatrixIndex.get((Integer)adjacentGridIndex);
liquidMatrix.setEntry(matrixIndex, // column
adjacentMatrixIndex, // row
1.0); // value
liquidMatrix.setEntry(adjacentMatrixIndex, // column
matrixIndex, // row
1.0); // value
}
}
}