Bảo tồn khối lượng trong mô phỏng chất lỏng


8

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:

  1. Đặt các mục chéo thành âm của số lượng ô lỏng liền kề với ô i.Ai,i
  2. Đặt các mục và thành 1 nếu cả hai ô i và j đều có chất lỏng. A j , iAi,jAj,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 + jiji+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:

  1. Dirichlet - chỉ định các giá trị tuyệt đối tại các ranh giới.

  2. Neummann - chỉ định đạo hàm tại các ranh giới.

  3. 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

Thực hiện Physbam nước


Đâ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
        }
      }
    }

Không rõ tại sao các đối tượng tĩnh và các ô trống sẽ cho phép xóa các hàng và cột. Bạn đang đặt các hàng và cột này về 0 hoặc loại bỏ chúng hoàn toàn để đưa ra một ma trận nhỏ hơn?
trichoplax 3/03/2016

Trong trường hợp vấn đề ở đâu đó ngoài nơi bạn đoán, sẽ rất hữu ích khi xem mã, nếu đây là điều bạn vui lòng chia sẻ. Lý tưởng nhất là MCVE
trichoplax

Này trichoplax. Một ma trận có tất cả hàng hoặc cột bằng 0 sẽ là số ít, theo như tôi biết, vì vậy tôi thay vào đó loại bỏ chúng khỏi ma trận để tạo một ma trận nhỏ hơn (cũng như các mục tương ứng của chúng trong vectơ b).
Jared đếm ngày

Tôi sẽ chỉnh sửa MCVE vào tối nay khi tôi ở gần máy tính của mình với nguồn.
Jared đếm ngày

Tôi cũng nghi ngờ rằng tôi có thể đã đưa ra một giả định sai ở một nơi khác trong mã, tuy nhiên điều này chỉ liên quan đến cấu trúc ma trận (và liệu nó có phải là số ít hay không). Điều duy nhất tôi có thể nghĩ là thứ đủ tiêu chuẩn là "tế bào bề mặt" so với tế bào không khí hoặc tế bào lỏng. Nếu đây là một tế bào chất lỏng liền kề với một tế bào không khí, có điều gì khác biệt mà tôi nên làm với các cột / hàng tương ứng của nó không?
Jared đếm ngày

Câu trả lời:


2

Từ đoạn mã của bạn và kết quả của bạn cho ví dụ 2x2, tôi có thể thấy rằng bạn thực sự đang mô phỏng một miền chỉ với các điều kiện biên Neumann (tường trượt). Trong trường hợp này, hệ thống chứa một không gian rỗng và ma trận của bạn là số ít.

x

x=(Iu^u^T)x=x(u^x)u^
u^u=(1,1,,1)u^=uu .

Mặt khác, nếu bạn muốn mô phỏng không khí (ranh giới tự do hoặc Dirichlet BC), bạn sẽ cần phân biệt một bức tường và một tế bào không khí (tức là có một boolean hasLiquidlà không đủ), và áp dụng sự phân biệt chính xác cho chúng (xem bên dưới).

Như một lưu ý cuối cùng, các mục chéo của bạn là âm. Bạn có thể muốn lật các dấu hiệu để phương thức CG hoạt động.


vvn+1

vn+1=vΔtρP
vn+1
P=v
P0P0+cc(P0+c)=P0=vc

pivi+1/2ii+1

pi+1pi(pipi1)Δx2=rhs
pi+1pi+1pi

Với Dirichlet hoặc Neumann BC, ma trận luôn luôn xác định dương đối xứng. Đó là lý do tại sao các tác giả nói

Static object and empty cells don’t disrupt this structure.
In that case pressure and velocity terms can disappear from both sides
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.