Внутри границ

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

for (i = 0 ; i < n ; i++)
{
  for (j = 0 ; j < n ; j++)
  {
     if (isBoundary(i,j)
     {
        sum = 0;
        count = 0;
        if (!isBoundary(i+1,j) {
           sum += x[i+1][j];
        }
        if (!isBoundary(i-1,j) {
           sum += x[i-1][j];
        }
        if (!isBoundary(i,j+1) {
           sum += x[i][j+1];
        }
        if (!isBoundary(i,j-1) {
           sum += x[i-1][j];
        }
        x[i][j] = sum / 4;
     }
  }
}

К сожалению, дым поглощается и исчезает при контакте с граничной поверхностью.
Моего математического фона недостаточно для понимания каждой части вычислений, поэтому я буду очень признателен, если кто-то укажет мне правильное направление.

2 ответа

Мне удалось найти решение, вот оно для потенциальных людей с такой же проблемой

void set_bnd ( int N, int b, float * x, int * insideBound )
{
    int i, j;
    float sum, tmp;
    int count;

    for ( i=1 ; i<=N ; i++ ) {
        x[IX(0  ,i)] = b==1 ? -x[IX(1,i)] : x[IX(1,i)];
        x[IX(N+1,i)] = b==1 ? -x[IX(N,i)] : x[IX(N,i)];
        x[IX(i,0  )] = b==2 ? -x[IX(i,1)] : x[IX(i,1)];
        x[IX(i,N+1)] = b==2 ? -x[IX(i,N)] : x[IX(i,N)];
    }
    x[IX(0  ,0  )] = 0.5f*(x[IX(1,0  )]+x[IX(0  ,1)]);
    x[IX(0  ,N+1)] = 0.5f*(x[IX(1,N+1)]+x[IX(0  ,N)]);
    x[IX(N+1,0  )] = 0.5f*(x[IX(N,0  )]+x[IX(N+1,1)]);
    x[IX(N+1,N+1)] = 0.5f*(x[IX(N,N+1)]+x[IX(N+1,N)]);

    if (!b) return;

    for ( i=1 ; i<=N ; i++ ) {
        for ( j=1 ; j<=N ; j++ ) {
            sum = 0.0f;
            count = 0;
            if (insideBound[IX(i,j)] == 1)
            {
                if (insideBound[IX(i-1,j)] != 1)
                {
                    count++;
                    if (b == 2)
                        tmp = -x[IX(i-1,j)];
                    else 
                        tmp = x[IX(i-1,j)];

                    sum = sum + tmp;
                }

                if (insideBound[IX(i+1,j)] != 1)
                {
                    count++;
                    if (b == 2)
                        tmp = -x[IX(i+1,j)];
                    else
                        tmp =  x[IX(i+1,j)];
                    sum = sum + tmp;
                } 

                if (insideBound[IX(i,j-1)] != 1)
                {
                    count++;
                    if (b == 1)
                        tmp = - x[IX(i, j-1)];
                    else 
                        tmp =  x[IX(i, j-1)];
                    sum = sum + tmp;
                } 

                if (insideBound[IX(i,j+1)] != 1)
                {
                    count++;
                    if (b == 1)
                        tmp = -x[IX(i, j+1)];
                    else 
                        tmp = x[IX(i, j+1)];
                    sum = sum + tmp;
                } 

                if (count > 0)
                {
                    x[IX(i,j)] = -sum / count;
                } else {
                    x[IX(i,j)]  = 0;
                }
            }
        }
    }
}

insideBound - логический массив (0,1), который указывает на ячейки, являющиеся границами. Работает с одной или несколькими граничными областями, но они должны иметь ширину и высоту не менее 3 ячеек.

Вот некоторый код, чтобы объяснить дальше.
insideBound - массив (1 - граница, 0 - пусто, жидкость может проходить через желоб)

#define FOR_EACH_CELL for ( i=1 ; i<=N ; i++ ) { for ( j=1 ; j<=N ; j++ ) {


void set_bnd ( int N, int b, float * x, int * insideBound )
{
int i, j;
float sum;
int count;

for ( i=1 ; i<=N ; i++ ) {
    x[IX(0  ,i)] = b==1 ? -x[IX(1,i)] : x[IX(1,i)];
    x[IX(N+1,i)] = b==1 ? -x[IX(N,i)] : x[IX(N,i)];
    x[IX(i,0  )] = b==2 ? -x[IX(i,1)] : x[IX(i,1)];
    x[IX(i,N+1)] = b==2 ? -x[IX(i,N)] : x[IX(i,N)];
}
x[IX(0  ,0  )] = 0.5f*(x[IX(1,0  )]+x[IX(0  ,1)]);
x[IX(0  ,N+1)] = 0.5f*(x[IX(1,N+1)]+x[IX(0  ,N)]);
x[IX(N+1,0  )] = 0.5f*(x[IX(N,0  )]+x[IX(N+1,1)]);
x[IX(N+1,N+1)] = 0.5f*(x[IX(N,N+1)]+x[IX(N+1,N)]);

if (!b) return;

FOR_EACH_CELL
    sum = 0.0f;
    count = 0;
    if (insideBound[IX(i,j)] == 1)
    {
        if (insideBound[IX(i-1,j)] != 1)
        {
            count++;
            sum = sum + x[IX(i-1,j)];
        }

        if (insideBound[IX(i+1,j)] != 1)
        {
            count++;
            sum = sum + x[IX(i+1,j)];
        }

        if (insideBound[IX(i,j-1)] != 1)
        {
            count++;
            sum = sum + x[IX(i, j-1)];
        }

        if (insideBound[IX(i,j+1)] != 1)
        {
            count++;
            sum = sum + x[IX(i, j+1)];
        }

        if (count > 0)
        {
            x[IX(i,j)] = -sum / count;
        } else {
            x[IX(i,j)]  = 0;
        }


    }

END_FOR

}

За книгу (рабочая):
В первом цикле задаются верхняя, правая, нижняя и левая граничные ячейки. Поскольку для них существует только одна смежная ячейка, которая не связана, ячейка получает свое значение. (Я не знаю, почему это противоположно для U и то же значение для V)

После первого цикла устанавливаются значения угловых границ. Здесь они получают средние значения из соседних ячеек (я думаю, поскольку нет соседних ячеек, которые не являются граничными, они используют граничные ячейки).

Мой не работает должным образом:
if (! b) return - игнорирует вычисления для плотности и обновляет только скорость.
Цикл вычисляет значения для всех граничных ячеек (опять же, средние значения из соседних ячеек, которые сами не являются границами). Я получаю почти реалистичный результат от этих методов, но есть большие потери в плотности и некоторые ошибки со слишком большими границами, когда жидкость полностью исчезает.

Другие вопросы по тегам