Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Новиков. Магистерская диссертация.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
523.12 Кб
Скачать

8 Реализация этапа проекции

8.1 Входные данные

Как уже было сказано ранее, солвер для вычисления давления решает задачу численно эквивалентную решению уравнения Пуассона, однако внутри расчётной области могут быть произвольным образом разбросаны узлы, содержащие граничные условия: как Дирихле, так и Неймана.

Большая часть условий Дирихле равна нулю, т.к. обозначает те области пространства, в которых нет дыма. В том случае, если в поставленной задаче есть ненулевые условия Дирихле, они упаковываются в формат CSR и передаются в солвер.

С условиями Неймана все немного сложнее. У каждой ячейки MACgrid’а 6 нормалей, а значит, при подобном подходе нам придётся передавать в солвер 6 CSR-векторов с граничными условиями Неймана, а затем распаковывать их на GPU. В процессе вычисления так же придётся где-то хранить узлы «призраки», возникающие в результате расчёта условий Неймана.

Гораздо проще подставить формулы аппроксимации для «узлов-призраков» в изначальную систему разностных уравнений. В этом случае сами «узлы-призраки» будут вычеркнуты из системы, а значения граничных условий перейдут в .

Это можно выполнить следующим образом (см выкладки в [17]):

Предположим, что ячейка с индексом (i+1,j,k) заполнена твердым телом, тогда задано условие Неймана:

Подставим в исходное разностное уравнение. Получаем:

Заметим, что коэффициент при изменился, и он равен количеству невыколотых соседей . Запомним это - с коэффициентом мы будем работать на этапах сглаживания и подсчёта невязки. Так же заметим, что заданное значение условия Неймана вычитается из правой части. Это вычитание можно произвести уже сейчас на этапе подготовки входных массивов, что и выполняется.

Итого солвер получает на вход: маску, хранящую информацию о том, находится ли в данной точке дым, воздух или твердый объект, CSR сетку с ненулевыми значениями условий Дирихле и правую часть уравнения, исправленную в соответствии с заданными условиями Неймана.

8.2 Сглаживатель

Первый этап работы многосеточного решателя – это сглаживание. В качестве сглаживателя разумно использовать схему «красное-черное» для метода Гаусса-Зейделя, позволяющую добиться эффективного распараллеливания на GPU[16].

Узлы с чётной суммой координат помещаются в одну «красную» группу, а узлы с нечётной суммой в другую «чёрную». Затем для каждой из групп поочередно выполняются итерации метода Якоби. Такое разбиение помогает CUDA-потокам при распараллеливании на GPU на каждом шаге либо только читать, либо только писать в узел, что делает вычисления детерминированными и значительно ускоряет производительность.

Таким образом, принимая во внимание главу о граничных условиях, нам необходимо выполнить:

Где верхние индексы обозначают итерацию, – значение правой части дополненное граничными условиями Неймана, а – количество соседних невыколотых узлов, причем , если (i,j,k) узел выколот.

Как уже было сказано, метод «красное-чёрное» позволяет добиться хорошего качества распараллеливания на GPU. Так как каждый из узлов одного цвета при выполнении итераций сглаживания зависит только от узлов другого цвета, внутри итерации для каждого из узлов выполняется либо чтение, либо запись, но никогда не обе операции. Данный подход позволяет достичь скорости метода Гаусса-Зейделя, использовав для расчетов на каждой итерации только одну сетку, а не две, как в случае с методом Якоби[22].

Рисунок 3: Красно-чёрная раскраска сетки. Срез на одном из слоев расчетной сетки. При расчёте черных узлов используются значения из красных и наоборот.

Однако у данного подхода есть несовершенство при использовании на графических ускорителях – шаблон доступа к памяти. Графические ускорители устроены таким образом, что наибольшая производительность достигается, когда все потоки работают с участками памяти, расположенными подряд[21]. По этой причине в данной реализации каждый расчётный слой хранится в линеаризованном массиве таком, что в нем сначала расположены только «красные» узлы, а затем только «чёрные». CUDA-ядра при этом работают на CUDA-grid’ах, вытянутых в линию. Таким образом на каждой итерации CUDA-ядра читают данные только из одного массива, а пишут в другой. Для того, чтобы не возникало путаницы, индекс в линеаризованном массиве рассчитывается специальной функцией по координатам узла, и такой подход используется для всех сеток внутри солвера, включая невязки, маски и правые части.

Рисунок 4: Линеаризация двумерного массива