50 : prm(prm_), pointsCopy(points), maxTreeLevel(maxTreeLevel_)
75 for (
int j = 1; j < i; ++j)
84 double shared_minx = 1e+10, shared_maxx = -1e+10, shared_miny = 1e+10, shared_maxy = -1e+10;
87 double minx = 1e+10, maxx = -1e+10, miny = 1e+10, maxy = -1e+10;
89 for (
int ii = 0; ii < (int)points.size(); ++ii)
91 const Point2D& r = points[ii].r();
92 minx = std::min(r[0], minx);
93 maxx = std::max(r[0], maxx);
94 miny = std::min(r[1], miny);
95 maxy = std::max(r[1], maxy);
99 shared_minx = std::min(shared_minx, minx);
100 shared_maxx = std::max(shared_maxx, maxx);
101 shared_miny = std::min(shared_miny, miny);
102 shared_maxy = std::max(shared_maxy, maxy);
106 return { {shared_minx, shared_miny}, {shared_maxx, shared_maxy} };
144 double iLeft = gabs.first[0];
145 double iBottom = gabs.first[1];
147 double iRight = gabs.second[0];
148 double iTop = gabs.second[1];
150 Point2D posCentre = { 0.5 * (iLeft + iRight), 0.5 * (iBottom + iTop) };
152 double quadSide = std::max(iRight - iLeft, iTop - iBottom);
159#pragma omp parallel for schedule(dynamic, 1000)
160 for (
int i = 0; i < (int)
pointsCopy.size(); ++i)
163 unsigned int mortonCode =
Morton2D(locR);
177 std::vector<unsigned int> s(256 * omp_get_max_threads());
178 std::vector<TParticleCode> mortonCodes_temp(
pointsCopy.size());
189 if ((j < 0) || (j > (
int)
pointsCopy.size() - 1))
203 for (
unsigned int c = (ki ^ kj); c; c >>= 1, ++count);
205 if ((!count) && (i != j))
210 for (
unsigned int add = ((i + 1) ^ (j + 1)); add; add >>= 1, ++addCount);
231 return { el >> (2 *
codeLength - length), length };
240 std::tie<unsigned int, int>(pr, prLength) =
Prefix(cell);
243 Point2D sz = { 1.0 / (double)(1 <<
ceilhalf(prLength)), 1.0 / (1 << (prLength / 2)) };
247 for (
int i = 0; i < prLength; i += 2)
248 if (pr & (1 << (prLength - i - 1)))
249 pos[0] += 1.0 / (1 << (1 + i / 2));
251 for (
int i = 1; i < prLength; i += 2)
252 if (pr & (1 << (prLength - i - 1)))
253 pos[1] += 1.0 / (1 << (1 + i / 2));
268 int delta_min =
Delta(i, i - d);
271 while (
Delta(i, i + Lmax * d) > delta_min)
275 for (
int t = (Lmax >> 1); t >= 1; t >>= 1)
276 if (
Delta(i, i + (L + t) * d) > delta_min)
280 int delta_node =
Delta(i, j);
282 for (
int p = 1, t =
ceilhalf(L); L > (1 << (p - 1)); ++p, t =
ceilpow2(L, p))
284 int dl =
Delta(i, i + (s + t) * d);
288 int gamma = i + s * d + std::min(d, 0);
290 auto min_max = std::minmax(i, j);
292 const int& left = gamma;
293 const int& right = gamma + 1;
298 bool ifLeftParticle = (min_max.first == gamma);
299 treeCell.
child[0] = ifLeftParticle ? n + left : left;
305 bool ifRightParticle = (min_max.second == gamma + 1);
306 treeCell.
child[1] = ifRightParticle ? n + right : right;
316#pragma omp parallel for schedule(dynamic, 1000)
317 for (
int q = 0; q < (int)
pointsCopy.size() - 1; ++q)
323#pragma omp parallel for schedule(dynamic, 1000)
324 for (
int q = 0; q < (int)
pointsCopy.size() - 1; ++q)
332#pragma omp parallel for
333 for (
int q = 0; q < (int)
pointsCopy.size(); ++q)
341 cell.
size = { 0.0, 0.0 };
366 std::vector<int> good_matches_private;
367#pragma omp for nowait
368 for (
int cell = 0; cell < (int)
mortonTree.size(); ++cell)
370 good_matches_private.push_back(cell);
380 const int maxLevelOmp = int(log2(omp_get_max_threads()));
385#pragma omp parallel shared(cl, omplevel) num_threads(2) if (omplevel < maxLevelOmp + 1)
389 for (
int s = 0; s < 2; ++s)
394 for (
auto& m : cl.mom)
397 for (
int s = 0; s < 2; ++s)
400 const Point2D& g = chld.mom[0];
404 h[0] = (chld.center) - (cl.center);
406 h[i] = multz(h[i - 1], h[0]);
408 for (
int p = 1; p <=
prm.
order; ++p)
410 Point2D shiftMom = chld.mom[p];
411 for (
int k = 1; k <= p; ++k)
413 shiftMom +=
getBinom(p, k) * multz(chld.mom[p - k], h[k - 1]);
416 cl.mom[p] += shiftMom;
430 for (
int p = 1; p <=
prm.
order; ++p)
442 if (treeInf.get() !=
this || lowCell != fromWho)
444 auto& wh = treeInf->mortonTree[fromWho];
447 h = wh.size[0] + wh.size[1];
448 h0 = lt.size[0] + lt.size[1];
459 if (wh.range[1] == wh.range[0])
460 lt.closeCells.push_back(fromWho);
467 for (
int diag = 0; diag <
prm.
order; ++diag)
469 for (
int q = 0; q <= diag; ++q)
470 lt.E[q] += ((q % 2 ? -1.0 : 1.0) *
iFact[diag - q]) * multzA(varTheta, wh.mom[diag - q]);
472 varTheta = (diag + 1) * multz(varTheta, rr);
484 else if (calcCloseTrees)
486 lt.closeCells.push_back(fromWho);
490 else if (calcCloseTrees)
492 lt.closeCells.push_back(lowCell);
502 for (
int i = lc.range[0]; i <= lc.range[1]; ++i)
509 for (
size_t k = 0; k < lc.closeCells.size(); ++k)
516 auto& rg = treeInf->mortonTree[lc.closeCells[k]].range;
517 for (
int j = rg[0]; j <= rg[1]; ++j)
519 auto& pt = treeInf->mortonCodes[j];
522 const double& gamJ = pt.g;
523 r2 = (posI - posJ).length2();
524 dst2eps = std::max(r2,
prm.
eps2);
525 velI += (gamJ / dst2eps) * (posI - posJ).
kcross();
539 for (
int i = lc.range[0]; i <= lc.range[1]; ++i)
545 for (
int k = 1; k <
prm.
order - 1; ++k)
547 v +=
iFact[k] * multzA(lc.E[k], hh);
548 hh = multz(hh, deltaPos);
562 v = (v | (v << 8)) & 0x00FF00FF;
568 v = (v | (v << 4)) & 0x0F0F0F0F;
574 v = (v | (v << 2)) & 0x33333333;
580 v = (v | (v << 1)) & 0x55555555;
610 const unsigned int& xx =
ExpandBits((
unsigned int)(rscale[0]));
611 const unsigned int& yy =
ExpandBits((
unsigned int)(rscale[1]));
612 return yy | (xx << 1);
622 for (
unsigned int i = 0; i < n; ++i)
625 unsigned int off = (src->
key >> (sortable_bit * 8)) & 0xFF;
626 dest[offset[off]++] = *src;
633 unsigned int s[
sizeof(m->
key) * 256] = { 0 };
635 for (
unsigned int i = 0; i < n; ++i)
637 unsigned int key = m[i].
key;
638 for (
unsigned int digit = 0; digit <
sizeof(m->
key); digit++)
639 ++s[((key >> (digit << 3)) & 0xFF) + (digit << 8)];
643 for (
unsigned int digit = 0; digit <
sizeof(m->
key); digit++)
645 unsigned int off = 0;
646 for (
unsigned int i = 0; i < 256; i++)
648 auto& rs = s[i + (digit << 8)];
649 unsigned int value = rs;
656 for (
unsigned int digit = 0; digit <
sizeof(m->
key); digit++)
659 std::swap(m, m_temp);
666 if (
sizeof(m->
key) == 1)
668 std::swap(m, m_temp);
682 unsigned char threads = omp_get_max_threads();
685#pragma omp parallel num_threads(threads)
689 unsigned int l = omp_get_thread_num();
690 unsigned int div = n / omp_get_num_threads();
691 unsigned int mod = n % omp_get_num_threads();
692 unsigned int left_index = l < mod ? (div + (mod == 0 ? 0 : 1)) * l : n - (omp_get_num_threads() - l) * div;
693 unsigned int right_index = left_index + div - (mod > l ? 0 : 1);
695 for (
unsigned int digit = 0; digit <
sizeof(m->
key); ++digit)
697 unsigned int s_sum[256] = { 0 };
698 unsigned int s0[256] = { 0 };
699 unsigned char* b1 = (
unsigned char*)&
source[right_index].key;
700 unsigned char* b2 = (
unsigned char*)&
source[left_index].key;
706 for (
unsigned int i = 0; i < 256; i++)
708 s[i + 256 * l] = s0[i];
712 for (
unsigned int j = 0; j < threads; j++)
714 for (
unsigned int i = 0; i < 256; i++)
716 s_sum[i] += s[i + 256 * j];
719 s0[i] += s[i + 256 * j];
724 for (
unsigned int i = 1; i < 256; ++i)
726 s_sum[i] += s_sum[i - 1];
727 s0[i] += s_sum[i - 1];
729 unsigned char* b = (
unsigned char*)&
source[right_index].key + digit;
734 dest[--s0[*b]] = *v1--;
743 if (
sizeof(m->
key) == 1)
749 void MortonTree::getStatistics(
int& numParticles,
int& treshold, std::pair<int, int>& partLevel, std::pair<int, int>& leafsLevel,
int& lowLevelCells)
const
754 int leafsLevelMin = (int)1e+9;
755 int leafsLevelMax = 0;
756 for (
int q = 0; q < numParticles - 1; ++q)
764 if (level > leafsLevelMax)
765 leafsLevelMax = level;
767 if (level < leafsLevelMin)
768 leafsLevelMin = level;
776 if (level > leafsLevelMax)
777 leafsLevelMax = level;
779 if (level < leafsLevelMin)
780 leafsLevelMin = level;
786 leafsLevel = { leafsLevelMin, leafsLevelMax };
789 int partLevelMin = (int)1e+9;
790 int partLevelMax = 0;
791 for (
int q = 0; q < numParticles - 1; ++q)
796 if (level > partLevelMax)
797 partLevelMax = level;
799 if (level < partLevelMin)
800 partLevelMin = level;
803 partLevel = { partLevelMin + 1, partLevelMax + 1 };
819 std::cout <<
"!!!!!!!!!!!!" << std::endl;
821 int ch0 = cell.child[0];
822 int ch1 = cell.child[1];
825 cell.hasGabs =
false;
831 int spoint = cell.
range[0];
832 int epoint = cell.
range[1];
834 double minx = 1e+10, maxx = -1e+10, miny = 1e+10, maxy = -1e+10;
836 for (
int ii = spoint; ii <= epoint; ++ii)
839 minx = std::min(r[0], minx);
840 maxx = std::max(r[0], maxx);
841 miny = std::min(r[1], miny);
842 maxy = std::max(r[1], maxy);
860 pcell.minx_miny[0] = std::min(lcell.minx_miny[0], rcell.minx_miny[0]);
861 pcell.minx_miny[1] = std::min(lcell.minx_miny[1], rcell.minx_miny[1]);
862 pcell.maxx_maxy[0] = std::max(lcell.maxx_maxy[0], rcell.maxx_maxy[0]);
863 pcell.maxx_maxy[1] = std::max(lcell.maxx_maxy[1], rcell.maxx_maxy[1]);
866 pcell.center = (pcell.minx_miny + pcell.maxx_maxy) * 0.5;
867 pcell.size = pcell.maxx_maxy - pcell.minx_miny;
876 int ch0 = cell.child[0];
877 int ch1 = cell.child[1];
Заголовок класса Tree для метода Барнса - Хата для CPU.
void BuildMortonParticlesTree()
Построение верхушек дерева — отдельных частиц
void MinMaxCellsSearch(int numCell)
std::vector< treeCellT > mortonTree
Мортоновское дерево Размер дерева равен сумме числа внутренних вершин (число частиц без единицы) и чи...
void BuildInternalTreeCell(int i)
Функция построения i-й внутренней ячейки дерева
int Delta(int i, int j) const
std::vector< PointsCopy > & pointsCopy
Ссылка на список обобщенных вихрей, по которым строится дерево
void CalcLocalCoeffToLowLevel(int lowCell, std::unique_ptr< MortonTree > &treeInf, int fromWho, bool calcCloseTrees)
void MinMaxCellsCalc(BH::treeCellT &cell)
void RSort_step3(TParticleCode *source, TParticleCode *dest, unsigned int n, unsigned int *offset, unsigned char sortable_bit)
Вспомогательная функция к RSort_Node3.
void RSort_Node3(TParticleCode *m, TParticleCode *m_temp, unsigned int n)
Поразрядная сортировка мортоновских кодов
MortonTree(const params &prm_, int maxTreeLevel_, std::vector< PointsCopy > &points)
void FillMortonLowCells(int cell=0)
Функция заполнения списка нижних ячеек дерева (до которых производится обход)
void CalcVeloTaylorExpansion(int lowCell)
void ShareGabs(int numCell)
void BuildMortonInternalTree()
Построение внутренних ячеек дерева
std::pair< unsigned int, int > Prefix(int cell) const
static std::pair< Point2D, Point2D > FindEnclosingRectangleOld(const std::vector< PointsCopy > &points)
Поиск габаритного прямоугольника системы точек (для OpenMP 2.0)
void MakeRootMortonTree()
Построение корня дерева и задание его общих параметров
static unsigned int Morton2D(const Point2D &r)
std::vector< int > mortonLowCells
Вектор индесков ячеек нижнего уровня в дереве
static unsigned int ExpandBits(unsigned int v)
"Разрежение" двоичного представления беззнакового целого, вставляя по одному нулику между всеми битам...
void FillMortonLowCellsA()
Point2D lowLeft
Положение нижнего левого угла дерева
void RSort_Parallel(TParticleCode *m, TParticleCode *m_temp, unsigned int n, unsigned int *s)
Параллельная версия поразрядной сортировки мортоновских кодов
void getStatistics(int &numParticles, int &treshold, std::pair< int, int > &partLevel, std::pair< int, int > &leafsLevel, int &lowLevelCells) const
const params & prm
Ссылка на параметры, загружаемые из файла
std::vector< TParticleCode > mortonCodes
Список мортоновских кодов, вычисляемых по положениям частиц
double & getBinom(int n, int k)
int PrefixLength(int cell) const
void GabsPyr(int numCell)
void CalcVeloBiotSavart(int lowCell, std::unique_ptr< MortonTree > &treeInf)
std::vector< double > binomCft
const int maxTreeLevel
Максимальная глубина дерева при его обходе
std::vector< double > iFact
Спикок обратных факториалов целых чисел
void CalculateMortonTreeParams(int cell, int omplevel)
Вычисление параметров дерева (циркуляций и высших моментов)
void SetCellGeometry(int cell)
Функция вычисления геометрических параметров внутренней ячейки дерева
Класс, содержащий параметры метода Баонса - Хата для CPU.
double eps
Радиус вихревого элемента
int NumOfLevelsVortex
Максимальное количество уровней дерева
double theta
Параметр точности
int order
Точность расчета скоростей:
double eps2
Квадрат радиуса вихревого элемента
numvector< T, 2 > kcross() const
Геометрический поворот двумерного вектора на 90 градусов
auto length2() const -> typename std::remove_const< typename std::remove_reference< decltype(this->data[0])>::type >::type
Вычисление квадрата нормы (длины) вектора
numvector< T, n > & toZero(P val=0)
Установка всех компонент вектора в константу (по умолчанию — нуль)
int ceilhalf(unsigned int x)
Округление "в потолок" результата деления пополам, эквивалент ceil(x / 2)
int ceilpow2(unsigned int x, unsigned int p)
Округление "в потолок" результата деления на степень двойки, эквивалент ceil(x / (2^p))
T sqr(T x)
Умножение a на комплексно сопряженноe к b.
int sign(T val)
Шаблонная функция знака числа Написана оптимизированная версия, которая работает самым быстрым возмож...
long long op
Глобальная переменная - счетчик количества операций
Структура, соответствующая частице и ее мортоновскому коду
unsigned int key
Мортоновский код частицы
Структура, соответствующая ячейке мортоновского дерева
numvector< int, 2 > range
Диапазон индексов частиц в ячейке: 0 - первая; 1 - последняя
Point2D center
Положение центра ячейки
Point2D size
Размер ячейки по x и по y (для листа (0;0)
numvector< int, 2 > child
Индексы потомков (если это не particle): 0 - левый, 1 - правый