Tôi đang cố gắng thực hiện một phiên bản 2D của bài báo của Foster và Fedkiw, "Hoạt hình thực tế về chất lỏng" tại đây: http://physbam.stanford.edu/~fedkiw/ con / tafford2001-02.pdf
Hầu hết mọi thứ đều hoạt động, ngoại trừ phần 8: "Bảo tồn khối lượng". Ở đó, chúng tôi thiết lập một ma trận các phương trình để tính toán áp lực cần thiết để làm cho chất lỏng phân kỳ tự do.
Tôi tin rằng mã của tôi phù hợp với bài báo, tuy nhiên tôi đang nhận được một ma trận không thể giải được trong quá trình bảo tồn bước khối.
Dưới đây là các bước của tôi để tạo ma trận A:
- Đặt các mục chéo thành âm của số lượng ô lỏng liền kề với ô i.
- Đặt các mục và thành 1 nếu cả hai ô i và j đều có chất lỏng. A j , i
Lưu ý rằng, trong triển khai của tôi, ô , trong lưới chất lỏng tương ứng với hàng lướiWidth trong ma trận.j i + ∗ j
Bài viết đề cập, "Đối tượng tĩnh và các ô trống không phá vỡ cấu trúc này. Trong trường hợp đó, các thuật ngữ áp suất và vận tốc có thể biến mất từ cả hai phía", vì vậy tôi xóa các cột và hàng cho các ô không có chất lỏng.
Vì vậy, câu hỏi của tôi là: Tại sao ma trận của tôi là số ít? Tôi có thiếu một số loại điều kiện biên ở một nơi khác trong bài báo không? Có phải thực tế là việc thực hiện của tôi là 2D?
Dưới đây là một ma trận ví dụ từ việc triển khai của tôi cho lưới 2x2 trong đó ô ở 0,0 không có chất lỏng:
-1 0 1
0 -1 1
1 1 -2
Biên tập
Nghiên cứu của tôi đã khiến tôi tin rằng tôi không xử lý đúng các điều kiện biên.
Trước hết, tại thời điểm này tôi có thể nói rằng ma trận của tôi đại diện cho phương trình Poisson áp suất rời rạc. Nó là tương tự rời rạc của việc áp dụng toán tử Laplacian khớp nối thay đổi áp suất cục bộ để phân kỳ tế bào.
Theo như tôi có thể hiểu, vì chúng ta đang đối phó với sự chênh lệch áp suất, nên cần có các điều kiện biên để "neo" áp lực đến một giá trị tham chiếu tuyệt đối. Mặt khác, có thể có một số lượng vô hạn các giải pháp cho tập hợp các phương trình.
Trong các ghi chú này , 3 cách khác nhau được đưa ra để áp dụng các điều kiện biên, theo sự hiểu biết tốt nhất của tôi:
Dirichlet - chỉ định các giá trị tuyệt đối tại các ranh giới.
Neummann - chỉ định đạo hàm tại các ranh giới.
Robin - chỉ định một số loại kết hợp tuyến tính của giá trị tuyệt đối và đạo hàm tại các ranh giới.
Bài báo của Foster và Fedki không đề cập đến bất kỳ điều nào trong số này, nhưng tôi tin rằng họ thi hành các điều kiện biên Dirichlet, đáng chú ý vì tuyên bố này vào cuối 7.1.2, "Áp suất trong một tế bào bề mặt được đặt thành áp suất khí quyển."
Tôi đã đọc các ghi chú tôi đã liên kết một vài lần và vẫn không hiểu lắm về toán học đang diễn ra. Làm thế nào chính xác để chúng ta thực thi các điều kiện biên? Nhìn vào các triển khai khác, dường như có một số loại khái niệm về một tế bào "Ghost" nằm ở ranh giới.
Ở đây tôi đã liên kết với một vài nguồn có thể hữu ích cho những người khác đọc nó.
Lưu ý về điều kiện biên cho ma trận Poisson
Khoa học tính toán StackExchange bài về điều kiện biên Neumann
Khoa học tính toán StackExchange bài đăng trên Poisson Solver
Đây là mã tôi sử dụng để tạo ma trận. Lưu ý rằng, thay vì xóa rõ ràng các cột và hàng, tôi tạo và sử dụng bản đồ từ các chỉ mục ô lỏng đến các cột / hàng ma trận cuối cùng.
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
}
}
}