VM2D 1.14
Vortex methods for 2D flows simulation
Loading...
Searching...
No Matches
BH::MortonTree Class Reference

Структура, соответствующая мортоновскому дереву More...

#include <TreeBH.h>

Collaboration diagram for BH::MortonTree:

Public Member Functions

void getStatistics (int &numParticles, int &treshold, std::pair< int, int > &partLevel, std::pair< int, int > &leafsLevel, int &lowLevelCells) const
 
double & getBinom (int n, int k)
 
 MortonTree (const params &prm_, int maxTreeLevel_, std::vector< PointsCopy > &points)
 
void MakeRootMortonTree ()
 Построение корня дерева и задание его общих параметров
 
void BuildMortonInternalTree ()
 Построение внутренних ячеек дерева
 
void BuildMortonParticlesTree ()
 Построение верхушек дерева — отдельных частиц
 
void FillMortonLowCells (int cell=0)
 Функция заполнения списка нижних ячеек дерева (до которых производится обход)
 
void FillMortonLowCellsA ()
 
void CalculateMortonTreeParams (int cell, int omplevel)
 Вычисление параметров дерева (циркуляций и высших моментов)
 
void CalcLocalCoeffToLowLevel (int lowCell, std::unique_ptr< MortonTree > &treeInf, int fromWho, bool calcCloseTrees)
 
void CalcVeloBiotSavart (int lowCell, std::unique_ptr< MortonTree > &treeInf)
 
void CalcVeloTaylorExpansion (int lowCell)
 
void AddVelo (int lowCell)
 
void MinMaxCellsSearch (int numCell)
 
void MinMaxCellsCalc (BH::treeCellT &cell)
 
void GabsPyr (int numCell)
 
void ShareGabs (int numCell)
 

Public Attributes

std::vector< TParticleCodemortonCodes
 Список мортоновских кодов, вычисляемых по положениям частиц
 
std::vector< double > iFact
 Спикок обратных факториалов целых чисел
 
std::vector< double > binomCft
 
const int maxTreeLevel
 Максимальная глубина дерева при его обходе
 
std::vector< int > mortonLowCells
 Вектор индесков ячеек нижнего уровня в дереве
 
std::vector< treeCellTmortonTree
 Мортоновское дерево Размер дерева равен сумме числа внутренних вершин (число частиц без единицы) и числа частиц резервируется на 1 штуку больше для удобства работы ячейки [0 ... pos.size()-2] отвечают внутренним узлам, ячейка с идексом pos.size()-1 не используется ячейки [pos.size() ... 2*pos.size()-1] отвечают частицам
 

Private Member Functions

int Delta (int i, int j) const
 
int PrefixLength (int cell) const
 
std::pair< unsigned int, int > Prefix (int cell) const
 
void SetCellGeometry (int cell)
 Функция вычисления геометрических параметров внутренней ячейки дерева
 
void BuildInternalTreeCell (int i)
 Функция построения i-й внутренней ячейки дерева
 
void RSort_Node3 (TParticleCode *m, TParticleCode *m_temp, unsigned int n)
 Поразрядная сортировка мортоновских кодов
 
void RSort_step3 (TParticleCode *source, TParticleCode *dest, unsigned int n, unsigned int *offset, unsigned char sortable_bit)
 Вспомогательная функция к RSort_Node3.
 
void RSort_Parallel (TParticleCode *m, TParticleCode *m_temp, unsigned int n, unsigned int *s)
 Параллельная версия поразрядной сортировки мортоновских кодов
 

Static Private Member Functions

static unsigned int ExpandBits (unsigned int v)
 "Разрежение" двоичного представления беззнакового целого, вставляя по одному нулику между всеми битами
 
static unsigned int Morton2D (const Point2D &r)
 
static std::pair< Point2D, Point2DFindEnclosingRectangleOld (const std::vector< PointsCopy > &points)
 Поиск габаритного прямоугольника системы точек (для OpenMP 2.0)
 

Private Attributes

const paramsprm
 Ссылка на параметры, загружаемые из файла
 
std::vector< PointsCopy > & pointsCopy
 Ссылка на список обобщенных вихрей, по которым строится дерево
 
double iQuadSideVar
 
Point2D lowLeft
 Положение нижнего левого угла дерева
 

Detailed Description

Структура, соответствующая мортоновскому дереву

Author
Марчевский Илья Константинович
Сокол Ксения Сергеевна
Рятина Евгения Павловна
Колганова Александра Олеговна \Version 1.14
Date
6 марта 2026 г.

Definition at line 146 of file TreeBH.h.

Constructor & Destructor Documentation

◆ MortonTree()

BH::MortonTree::MortonTree ( const params prm_,
int  maxTreeLevel_,
std::vector< PointsCopy > &  points 
)

Definition at line 49 of file TreeBH.cpp.

50 : prm(prm_), pointsCopy(points), maxTreeLevel(maxTreeLevel_)
51 {
52 mortonTree.resize(2 * points.size());
53 for (auto& c : mortonTree)
54 {
55 c.mom.resize(prm.order + 1);
56 c.E.resize(prm.order);
57 }
58
59 mortonCodes.resize(points.size());
60 mortonLowCells.reserve(points.size());
61
62
63 //Вычисляем факториалы и биномиальные коэффиценты
64 iFact.resize(prm.order + 1);
65 binomCft.resize((prm.order + 1) * (prm.order + 1));
66
67 iFact[0] = 1.0;
68 for (int i = 1; i <= prm.order; ++i)
69 iFact[i] = iFact[i - 1] / i;
70 getBinom(0, 0) = 1.0;
71 for (int i = 1; i <= prm.order; ++i)
72 {
73 getBinom(i, 0) = 1.0;
74 getBinom(i, i) = 1.0;
75 for (int j = 1; j < i; ++j)
76 getBinom(i, j) = getBinom(i - 1, j - 1) + getBinom(i - 1, j);
77 }//for i
78 }//MortonTree(...)
std::vector< treeCellT > mortonTree
Мортоновское дерево Размер дерева равен сумме числа внутренних вершин (число частиц без единицы) и чи...
Definition TreeBH.h:257
std::vector< PointsCopy > & pointsCopy
Ссылка на список обобщенных вихрей, по которым строится дерево
Definition TreeBH.h:153
std::vector< int > mortonLowCells
Вектор индесков ячеек нижнего уровня в дереве
Definition TreeBH.h:247
const params & prm
Ссылка на параметры, загружаемые из файла
Definition TreeBH.h:150
std::vector< TParticleCode > mortonCodes
Список мортоновских кодов, вычисляемых по положениям частиц
Definition TreeBH.h:157
double & getBinom(int n, int k)
Definition TreeBH.h:238
std::vector< double > binomCft
Definition TreeBH.h:223
const int maxTreeLevel
Максимальная глубина дерева при его обходе
Definition TreeBH.h:226
std::vector< double > iFact
Спикок обратных факториалов целых чисел
Definition TreeBH.h:219
int order
Точность расчета скоростей:
Definition ParamsBH.h:78
Here is the call graph for this function:

Member Function Documentation

◆ AddVelo()

void BH::MortonTree::AddVelo ( int  lowCell)

Добавление влияния дальней зоны для правой части

Parameters
[in]lowCell— индекс ячейки нижнего уровня, в которой рассчитывается влияние

◆ BuildInternalTreeCell()

void BH::MortonTree::BuildInternalTreeCell ( int  i)
private

Функция построения i-й внутренней ячейки дерева

Definition at line 264 of file TreeBH.cpp.

265 {
266 const int n = (int)pointsCopy.size();
267 int d = sign(Delta(i, i + 1) - Delta(i, i - 1));
268 int delta_min = Delta(i, i - d);
269
270 int Lmax = 2;
271 while (Delta(i, i + Lmax * d) > delta_min)
272 Lmax *= 2;
273
274 int L = 0;
275 for (int t = (Lmax >> 1); t >= 1; t >>= 1)
276 if (Delta(i, i + (L + t) * d) > delta_min)
277 L += t;
278
279 int j = i + L * d;
280 int delta_node = Delta(i, j);
281 int s = 0;
282 for (int p = 1, t = ceilhalf(L); L > (1 << (p - 1)); ++p, t = ceilpow2(L, p))
283 {
284 int dl = Delta(i, i + (s + t) * d);
285 if (dl > delta_node)
286 s += t;
287 }//for p
288 int gamma = i + s * d + std::min(d, 0);
289
290 auto min_max = std::minmax(i, j);
291
292 const int& left = gamma;
293 const int& right = gamma + 1;
294
295 treeCellT& treeCell = mortonTree[i];
296
297 // Левый потомок - лист или внутренний узел
298 bool ifLeftParticle = (min_max.first == gamma);
299 treeCell.child[0] = ifLeftParticle ? n + left : left;
300 mortonTree[treeCell.child[0]].range = { min_max.first, gamma };
301 mortonTree[treeCell.child[0]].particle = ifLeftParticle;
302 mortonTree[treeCell.child[0]].parent = i;
303
304 // Правый потомок - лист или внутренний узел
305 bool ifRightParticle = (min_max.second == gamma + 1);
306 treeCell.child[1] = ifRightParticle ? n + right : right;
307 mortonTree[treeCell.child[1]].range = { gamma + 1, min_max.second };
308 mortonTree[treeCell.child[1]].particle = ifRightParticle;
309 mortonTree[treeCell.child[1]].parent = i;
310 }//BuildInternalTreeCell(...)
int Delta(int i, int j) const
Definition TreeBH.cpp:187
int ceilhalf(unsigned int x)
Округление "в потолок" результата деления пополам, эквивалент ceil(x / 2)
Definition defsBH.h:134
int ceilpow2(unsigned int x, unsigned int p)
Округление "в потолок" результата деления на степень двойки, эквивалент ceil(x / (2^p))
Definition defsBH.h:128
int sign(T val)
Шаблонная функция знака числа Написана оптимизированная версия, которая работает самым быстрым возмож...
Definition defsBH.h:111
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BuildMortonInternalTree()

void BH::MortonTree::BuildMortonInternalTree ( )

Построение внутренних ячеек дерева

Definition at line 314 of file TreeBH.cpp.

315 {
316#pragma omp parallel for schedule(dynamic, 1000)
317 for (int q = 0; q < (int)pointsCopy.size() - 1; ++q)
319
320 mortonTree[pointsCopy.size() - 1].leaf = false;
321 mortonTree[pointsCopy.size() - 1].particle = false;
322
323#pragma omp parallel for schedule(dynamic, 1000)
324 for (int q = 0; q < (int)pointsCopy.size() - 1; ++q)
326 }//BuildMortonInternalTree()
void BuildInternalTreeCell(int i)
Функция построения i-й внутренней ячейки дерева
Definition TreeBH.cpp:264
void SetCellGeometry(int cell)
Функция вычисления геометрических параметров внутренней ячейки дерева
Definition TreeBH.cpp:236
Here is the call graph for this function:

◆ BuildMortonParticlesTree()

void BH::MortonTree::BuildMortonParticlesTree ( )

Построение верхушек дерева — отдельных частиц

Definition at line 330 of file TreeBH.cpp.

331 {
332#pragma omp parallel for
333 for (int q = 0; q < (int)pointsCopy.size(); ++q)
334 {
335 auto& pt = mortonCodes[q];
336
337 auto& cell = mortonTree[pointsCopy.size() + q];
338 cell.center = pt.r;
339
340 cell.leaf = true;
341 cell.size = { 0.0, 0.0 };
342 }//for q
343 }//BuildMortonParticlesTree(...)
Here is the call graph for this function:

◆ CalcLocalCoeffToLowLevel()

void BH::MortonTree::CalcLocalCoeffToLowLevel ( int  lowCell,
std::unique_ptr< MortonTree > &  treeInf,
int  fromWho,
bool  calcCloseTrees 
)

Расчет коэффицентов локального разложения для нижних ячеек

Parameters
[in]lowCellиндекс ячейки нижнего уровня, в которой будет рассчитываться влияние
[in]treeInfссылка на влияющее дерево
[in]fromWhoиндекс влияющей ячейки во влияющем дереве
[in]calcCloseTreesпризнак заполнения списка ближних ячеек (нижнего уровня) к ячейке lowCell

Definition at line 436 of file TreeBH.cpp.

437 {
438 auto& lt = mortonTree[lowCell];
439 //if (calcCloseTrees)
440 // lt.closeCells.resize(0);
441
442 if (treeInf.get() != this || lowCell != fromWho)
443 {
444 auto& wh = treeInf->mortonTree[fromWho];
445
446 double h, h0;
447 h = wh.size[0] + wh.size[1];
448 h0 = lt.size[0] + lt.size[1];
449
450 Point2D& r0 = lt.center;
451 Point2D& r1 = wh.center;
452
453 Point2D rr = r0 - r1;
454
455 double crit2 = rr.length2();
456 // если выполнен критерий дальности => считаем коэффициенты
457 if ((crit2 >= sqr((h0 + h + 2.0 * prm.eps) / prm.theta)) && (wh.level <= prm.NumOfLevelsVortex))
458 {
459 if (wh.range[1] == wh.range[0])
460 lt.closeCells.push_back(fromWho);
461 else
462 {
463 Point2D rr = r0 - r1;
464 rr *= 1.0 / rr.length2();
465
466 Point2D varTheta = rr;
467 for (int diag = 0; diag < prm.order; ++diag)
468 {
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]);
471
472 varTheta = (diag + 1) * multz(varTheta, rr);
473 }
474 lt.E[0] += iFact[prm.order] * multzA(varTheta, wh.mom[prm.order]);
475 }
476 }//if crit2
477 else // если не выполнен критерий, то рекурсия
478 {
479 if ((!wh.leaf) && (wh.level < prm.NumOfLevelsVortex))
480 {
481 CalcLocalCoeffToLowLevel(lowCell, treeInf, wh.child[0], calcCloseTrees);
482 CalcLocalCoeffToLowLevel(lowCell, treeInf, wh.child[1], calcCloseTrees);
483 }
484 else if (calcCloseTrees)
485 {
486 lt.closeCells.push_back(fromWho);
487 }
488 }//else if
489 }//if (lowTree != this)
490 else if (calcCloseTrees)
491 {
492 lt.closeCells.push_back(lowCell); //себя тоже добавляем в ближнюю зону
493 }
494 }//CalcLocalCoeffToLowLevel(...)
void CalcLocalCoeffToLowLevel(int lowCell, std::unique_ptr< MortonTree > &treeInf, int fromWho, bool calcCloseTrees)
Definition TreeBH.cpp:436
double eps
Радиус вихревого элемента
Definition ParamsBH.h:68
int NumOfLevelsVortex
Максимальное количество уровней дерева
Definition ParamsBH.h:81
double theta
Параметр точности
Definition ParamsBH.h:84
auto length2() const -> typename std::remove_const< typename std::remove_reference< decltype(this->data[0])>::type >::type
Вычисление квадрата нормы (длины) вектора
Definition numvector.h:389
T sqr(T x)
Умножение a на комплексно сопряженноe к b.
Definition defsBH.h:101
Point2D multz(const Point2D &a, const Point2D &b)
Умножение комплексных чисел
Definition Point2D.h:208
Point2D multzA(const Point2D &a, const Point2D &b)
Умножение a на комплексно сопряженноe к b.
Definition Point2D.h:217
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalculateMortonTreeParams()

void BH::MortonTree::CalculateMortonTreeParams ( int  cell,
int  omplevel 
)

Вычисление параметров дерева (циркуляций и высших моментов)

Расчет мультипольных моментов всех ячеек дерева

Parameters
[in]cellячейка для вычисления мультипольных моментов
[in]omplevelтекущий уровень вложенности OpenMP

Definition at line 378 of file TreeBH.cpp.

379 {
380 const int maxLevelOmp = int(log2(omp_get_max_threads()));
381
382 auto& cl = mortonTree[cell];
383 if (!cl.particle)
384 {
385#pragma omp parallel /*default(none)*/ shared(cl, omplevel) num_threads(2) if (omplevel < maxLevelOmp + 1)
386 {
387 std::vector<Point2D> h(prm.order);
388#pragma omp for
389 for (int s = 0; s < 2; ++s)
390 CalculateMortonTreeParams(cl.child[s], omplevel + 1);
391
392#pragma omp single
393 {
394 for (auto& m : cl.mom)
395 m.toZero();
396
397 for (int s = 0; s < 2; ++s)//цикл по двум потомкам
398 {
399 auto& chld = mortonTree[cl.child[s]];
400 const Point2D& g = chld.mom[0];
401 cl.mom[0] += g;
402
403
404 h[0] = (chld.center) - (cl.center);
405 for (int i = 1; i < prm.order; ++i)
406 h[i] = multz(h[i - 1], h[0]);
407
408 for (int p = 1; p <= prm.order; ++p)
409 {
410 Point2D shiftMom = chld.mom[p];
411 for (int k = 1; k <= p; ++k)
412 {
413 shiftMom += getBinom(p, k) * multz(chld.mom[p - k], h[k - 1]);
414 //ADDOP(2);
415 }//for k
416 cl.mom[p] += shiftMom;
417 }//for m
418
419 }//for s
420 }//single
421 }//parallel
422 }//if(!particle)
423 else
424 {
425 //расчет моментов ячейки нижнего уровня для вихрей или для панелей
426 //C учетом того, что дерево строится до частиц --- только монопольный момент отличен от нуля
427 cl.mom[0][0] = mortonCodes[cl.range[0]].g;
428 cl.mom[0][1] = 0.0;
429
430 for (int p = 1; p <= prm.order; ++p)
431 cl.mom[p].toZero();
432 }//else
433 }//CalculateMortonTreeParams(...)
void CalculateMortonTreeParams(int cell, int omplevel)
Вычисление параметров дерева (циркуляций и высших моментов)
Definition TreeBH.cpp:378
numvector< T, n > & toZero(P val=0)
Установка всех компонент вектора в константу (по умолчанию — нуль)
Definition numvector.h:530
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalcVeloBiotSavart()

void BH::MortonTree::CalcVeloBiotSavart ( int  lowCell,
std::unique_ptr< MortonTree > &  treeInf 
)

Расчет влияния от ближних ячеек по формуле Био - Савара

Parameters
[in]lowCellиндекс ячейки нижнего уровня, в которой рассчитывается влияние
[in]treeInfвлияющее дерево (чтобы брать ближние ячейки по индексу из нужного массива)

Definition at line 499 of file TreeBH.cpp.

500 {
501 auto& lc = mortonTree[lowCell];
502 for (int i = lc.range[0]; i <= lc.range[1]; ++i)
503 {
504 //Локальные переменные для цикла
505 Point2D velI, velLinI;
506 double dst2eps;
507 double r2;
508
509 for (size_t k = 0; k < lc.closeCells.size(); ++k)
510 {
511 velI.toZero();
512 velLinI.toZero();
513
514 const Point2D& posI = mortonCodes[i].r;
515
516 auto& rg = treeInf->mortonTree[lc.closeCells[k]].range;
517 for (int j = rg[0]; j <= rg[1]; ++j)
518 {
519 auto& pt = treeInf->mortonCodes[j];
520
521 const Point2D& posJ = pt.r;
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();
526 }//for j
527
528 pointsCopy[mortonCodes[i].originNumber].veloCopy += velI;
529 }//for k
530
531 }//for i
532 }//CalcVeloBiotSavart(...)
double eps2
Квадрат радиуса вихревого элемента
Definition ParamsBH.h:71
numvector< T, 2 > kcross() const
Геометрический поворот двумерного вектора на 90 градусов
Definition numvector.h:513
Here is the call graph for this function:

◆ CalcVeloTaylorExpansion()

void BH::MortonTree::CalcVeloTaylorExpansion ( int  lowCell)

Расчет влияния от дальней зоны при помощи Тейлоровского разложения

Parameters
[in]lowCell— индекс ячейки нижнего уровня, в которой рассчитывается влияние

Definition at line 536 of file TreeBH.cpp.

537 {
538 auto& lc = mortonTree[lowCell];
539 for (int i = lc.range[0]; i <= lc.range[1]; ++i)
540 {
541 Point2D deltaPos = mortonCodes[i].r - lc.center;
542 Point2D v = lc.E[0];
543
544 Point2D hh = deltaPos;
545 for (int k = 1; k < prm.order - 1; ++k)
546 {
547 v += iFact[k] * multzA(lc.E[k], hh);
548 hh = multz(hh, deltaPos);
549 }//for k
550 v += iFact[prm.order-1] * multzA(lc.E[prm.order-1], hh);
551
552 pointsCopy[mortonCodes[i].originNumber].veloCopy += Point2D({ -v[1], v[0] });
553
554 }//for i
555 }//CalcVeloTaylorExpansion(...)

◆ Delta()

int BH::MortonTree::Delta ( int  i,
int  j 
) const
private

Функция вычисления длины общей части префиксов двух (а значит - и диапазона) частиц

Parameters
[in]iиндекс одной из частиц в отсортированном по мортоновским кодам списке
[in]jиндекс второй из частиц в отсортированном по мортоновским кодам списке
Returns
длину общей части мортоновского кода

Definition at line 187 of file TreeBH.cpp.

188 {
189 if ((j < 0) || (j > (int)pointsCopy.size() - 1))
190 return -1;
191
192 if (i > j)
193 std::swap(i, j);
194
195 //if ((i < 0) || (j > n-1))
196 // exit(111);
197
198 const unsigned int& ki = mortonCodes[i].key;
199 const unsigned int& kj = mortonCodes[j].key;
200
201 //Поиск номера самого старшего ненулевого бита в числе c
202 int count = 0;
203 for (unsigned int c = (ki ^ kj); c; c >>= 1, ++count);
204
205 if ((!count) && (i != j))
206 {
207 int addCount = 0;
208 //единички к номерам i и j добавлены для совместимости с Wolfram Mathematica,
209 //для кода они не важны, но дерево без них почти наверняка построится по-другому
210 for (unsigned int add = ((i + 1) ^ (j + 1)); add; add >>= 1, ++addCount);
211 return 2 * codeLength + (2 * codeLength - addCount);
212 }//if ((!count) && (i != j))
213
214 return (2 * codeLength - count);
215 }//Delta(...)
#define codeLength
Definition Gpudefs.h:97
Here is the caller graph for this function:

◆ ExpandBits()

unsigned int BH::MortonTree::ExpandBits ( unsigned int  v)
staticprivate

"Разрежение" двоичного представления беззнакового целого, вставляя по одному нулику между всеми битами

Definition at line 559 of file TreeBH.cpp.

560 {
561 // вставит 1 нуль
562 v = (v | (v << 8)) & 0x00FF00FF; // 00000000`00000000`abcdefgh`ijklmnop
563 // | 00000000`abcdefgh`ijklmnop`00000000
564 // = 00000000`abcdefgh`XXXXXXXX`ijklmnop
565 // & 00000000`11111111`00000000`11111111
566 // = 00000000`abcdefgh`00000000`ijklmnop
567
568 v = (v | (v << 4)) & 0x0F0F0F0F; // 00000000`abcdefgh`00000000`ijklmnop
569 // | 0000abcd`efgh0000`0000ijkl`mnop0000
570 // = 0000abcd`XXXXefgh`0000ijkl`XXXXmnop
571 // & 00001111`00001111`00001111`00001111
572 // = 0000abcd`0000efgh`0000ijkl`0000mnop
573
574 v = (v | (v << 2)) & 0x33333333; // 0000abcd`0000efgh`0000ijkl`0000mnop
575 // | 00abcd00`00efgh00`00ijkl00`00mnop00
576 // = 00abXXcd`00efXXgh`00ijXXkl`00mnXXop
577 // & 00110011`00110011`00110011`00110011
578 // = 00ab00cd`00ef00gh`00ij00kl`00mn00op
579
580 v = (v | (v << 1)) & 0x55555555; // 00ab00cd`00ef00gh`00ij00kl`00mn00op
581 // | 0ab00cd0`0ef00gh0`0ij00kl0`0mn00op0
582 // = 0aXb0cXd`0eXf0gXh`0iXj0kXl`0mXn0oXp
583 // & 01010101`01010101`01010101`01010101
584 // = 0a0b0c0d`0e0f0g0h`0i0j0k0l`0m0n0o0p
585 return v;
586 }
Here is the caller graph for this function:

◆ FillMortonLowCells()

void BH::MortonTree::FillMortonLowCells ( int  cell = 0)

Функция заполнения списка нижних ячеек дерева (до которых производится обход)

Definition at line 348 of file TreeBH.cpp.

349 {
350 if (mortonTree[cell].leaf)
351 mortonLowCells.push_back(cell);
352 else
353 {
354 FillMortonLowCells(mortonTree[cell].child[0]);
355 FillMortonLowCells(mortonTree[cell].child[1]);
356 }//else
357 }//FillMortonLowCells(...)
void FillMortonLowCells(int cell=0)
Функция заполнения списка нижних ячеек дерева (до которых производится обход)
Definition TreeBH.cpp:348
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FillMortonLowCellsA()

void BH::MortonTree::FillMortonLowCellsA ( )

Definition at line 362 of file TreeBH.cpp.

363 {
364#pragma omp parallel
365 {
366 std::vector<int> good_matches_private;
367#pragma omp for nowait
368 for (int cell = 0; cell < (int)mortonTree.size(); ++cell)
369 if (!mortonTree[mortonTree[cell].parent].leaf && mortonTree[cell].leaf)
370 good_matches_private.push_back(cell);
371#pragma omp critical
372 mortonLowCells.insert(mortonLowCells.end(), good_matches_private.begin(), good_matches_private.end());
373 }//parallel
374 }//FillMortonLowCellsA()

◆ FindEnclosingRectangleOld()

std::pair< Point2D, Point2D > BH::MortonTree::FindEnclosingRectangleOld ( const std::vector< PointsCopy > &  points)
staticprivate

Поиск габаритного прямоугольника системы точек (для OpenMP 2.0)

Definition at line 82 of file TreeBH.cpp.

83 {
84 double shared_minx = 1e+10, shared_maxx = -1e+10, shared_miny = 1e+10, shared_maxy = -1e+10;
85#pragma omp parallel
86 {
87 double minx = 1e+10, maxx = -1e+10, miny = 1e+10, maxy = -1e+10;
88#pragma omp for nowait
89 for (int ii = 0; ii < (int)points.size(); ++ii)
90 {
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);
96 }//for ii
97#pragma omp critical
98 {
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);
103 }//critical
104 }//parallel
105
106 return { {shared_minx, shared_miny}, {shared_maxx, shared_maxy} };
107 }//FindEnclosingRectangleOld(...)
Here is the caller graph for this function:

◆ GabsPyr()

void BH::MortonTree::GabsPyr ( int  numCell)

Definition at line 870 of file TreeBH.cpp.

871 {
872 auto& cell = mortonTree[numCell];
873 if (cell.hasGabs)
874 return;
875
876 int ch0 = cell.child[0];
877 int ch1 = cell.child[1];
878 if (!mortonTree[ch0].hasGabs)
879 GabsPyr(ch0);
880 if (!mortonTree[ch1].hasGabs)
881 GabsPyr(ch1);
882
883 ShareGabs(numCell/*, cell.minx_miny, cell.maxx_maxy*/);
884 }
void ShareGabs(int numCell)
Definition TreeBH.cpp:854
void GabsPyr(int numCell)
Definition TreeBH.cpp:870
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getBinom()

double & BH::MortonTree::getBinom ( int  n,
int  k 
)
inline

Извлечение биномиального коэффициента из массива binomCft

Returns
ссылку на C_n^k

Definition at line 238 of file TreeBH.h.

239 {
240 return binomCft[n * (prm.order + 1) + k];
241 }
Here is the caller graph for this function:

◆ getStatistics()

void BH::MortonTree::getStatistics ( int &  numParticles,
int &  treshold,
std::pair< int, int > &  partLevel,
std::pair< int, int > &  leafsLevel,
int &  lowLevelCells 
) const

Сбор статистики по дереву

Parameters
[out]numParticlesчисло частиц в дереве
[out]tresholdуровень, до которого производится обход
[out]partLevelнаименьший и наибольший уровни, на которых находятся частицы
[out]leafsLevelнаименьший и наибольший уровни, на которых ячейки, до которых производится обход
[out]lowLevelCellsчисло ячеек "нижнего" уровня (до которых производится обход)

Definition at line 749 of file TreeBH.cpp.

750 {
751 numParticles = (int)pointsCopy.size();
752 treshold = maxTreeLevel;
753
754 int leafsLevelMin = (int)1e+9;
755 int leafsLevelMax = 0;
756 for (int q = 0; q < numParticles - 1; ++q)
757 {
758 if (!mortonTree[mortonTree[q].parent].leaf)
759 {
760 if (mortonTree[q].leaf)
761 {
762 int level = mortonTree[q].level;
763
764 if (level > leafsLevelMax)
765 leafsLevelMax = level;
766
767 if (level < leafsLevelMin)
768 leafsLevelMin = level;
769
770 continue;
771 }
772
773 if ((mortonTree[mortonTree[q].child[0]].particle) || (mortonTree[mortonTree[q].child[1]].particle))
774 {
775 int level = mortonTree[q].level + 1;
776 if (level > leafsLevelMax)
777 leafsLevelMax = level;
778
779 if (level < leafsLevelMin)
780 leafsLevelMin = level;
781
782 continue;
783 }
784 }
785 }
786 leafsLevel = { leafsLevelMin, leafsLevelMax };
787
788
789 int partLevelMin = (int)1e+9;
790 int partLevelMax = 0;
791 for (int q = 0; q < numParticles - 1; ++q)
792 {
793 if ((mortonTree[mortonTree[q].child[0]].particle) || (mortonTree[mortonTree[q].child[1]].particle))
794 {
795 int level = mortonTree[q].level;
796 if (level > partLevelMax)
797 partLevelMax = level;
798
799 if (level < partLevelMin)
800 partLevelMin = level;
801 }
802 }
803 partLevel = { partLevelMin + 1, partLevelMax + 1 };
804 lowLevelCells = (int)mortonLowCells.size();
805 }

◆ MakeRootMortonTree()

void BH::MortonTree::MakeRootMortonTree ( )

Построение корня дерева и задание его общих параметров

Definition at line 140 of file TreeBH.cpp.

141 {
143
144 double iLeft = gabs.first[0];
145 double iBottom = gabs.first[1];
146
147 double iRight = gabs.second[0];
148 double iTop = gabs.second[1];
149
150 Point2D posCentre = { 0.5 * (iLeft + iRight), 0.5 * (iBottom + iTop) };
151
152 double quadSide = std::max(iRight - iLeft, iTop - iBottom);
153 iQuadSideVar = 1.0 / (quadSide * (1.0 + 1.0 / ((1 << codeLength) - 1)));
154 lowLeft = posCentre - 0.5*quadSide*Point2D{ 1.0, 1.0 };
155
156 //iQuadSideVar = 1.0;
157 //lowLeft = Point2D{ 0.0, 0.0 };
158
159#pragma omp parallel for schedule(dynamic, 1000)
160 for (int i = 0; i < (int)pointsCopy.size(); ++i)
161 {
162 Point2D locR = (pointsCopy[i].r() - lowLeft) * iQuadSideVar;
163 unsigned int mortonCode = Morton2D(locR);
164
165 auto& mc = mortonCodes[i];
166 mc.key = mortonCode;
167 mc.originNumber = i;
168 mc.r = pointsCopy[i].r();
169 mc.g = pointsCopy[i].g();
170 }//for i
171
172 //std::cout << "omp_threads = " << omp_get_max_threads() << std::endl;
173
174 //RSort_Node3(mortonCodes.data(), mortonCodes_temp.data(), (int)pointsCopy.size());
175
176 //Временные массивы для сортировки
177 std::vector<unsigned int> s(256 * omp_get_max_threads());
178 std::vector<TParticleCode> mortonCodes_temp(pointsCopy.size());
179 RSort_Parallel(mortonCodes.data(), mortonCodes_temp.data(), (int)pointsCopy.size(), s.data());
180
181 mortonTree[0].range = { 0, (int)pointsCopy.size() - 1 };
182 mortonTree[0].particle = false;
183 }//MakeRootMortonTree()
static std::pair< Point2D, Point2D > FindEnclosingRectangleOld(const std::vector< PointsCopy > &points)
Поиск габаритного прямоугольника системы точек (для OpenMP 2.0)
Definition TreeBH.cpp:82
double iQuadSideVar
Definition TreeBH.h:165
static unsigned int Morton2D(const Point2D &r)
Definition TreeBH.cpp:591
Point2D lowLeft
Положение нижнего левого угла дерева
Definition TreeBH.h:168
void RSort_Parallel(TParticleCode *m, TParticleCode *m_temp, unsigned int n, unsigned int *s)
Параллельная версия поразрядной сортировки мортоновских кодов
Definition TreeBH.cpp:677
Here is the call graph for this function:

◆ MinMaxCellsCalc()

void BH::MortonTree::MinMaxCellsCalc ( BH::treeCellT cell)

Definition at line 829 of file TreeBH.cpp.

830 {
831 int spoint = cell.range[0];
832 int epoint = cell.range[1];
833
834 double minx = 1e+10, maxx = -1e+10, miny = 1e+10, maxy = -1e+10;
835
836 for (int ii = spoint; ii <= epoint; ++ii)
837 {
838 const Point2D& r = mortonCodes[ii].r;
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);
843 }
844 cell.minx_miny[0] = minx;
845 cell.minx_miny[1] = miny;
846 cell.maxx_maxy[0] = maxx;
847 cell.maxx_maxy[1] = maxy;
848
849 cell.center = (cell.minx_miny + cell.maxx_maxy) * 0.5;
850 cell.size = cell.maxx_maxy - cell.minx_miny;
851
852 }
numvector< int, 2 > range
Диапазон индексов частиц в ячейке: 0 - первая; 1 - последняя
Definition TreeBH.h:100
Point2D minx_miny
Definition TreeBH.h:130
Point2D center
Положение центра ячейки
Definition TreeBH.h:113
Point2D maxx_maxy
Definition TreeBH.h:130
Point2D size
Размер ячейки по x и по y (для листа (0;0)
Definition TreeBH.h:110
Here is the caller graph for this function:

◆ MinMaxCellsSearch()

void BH::MortonTree::MinMaxCellsSearch ( int  numCell)

Definition at line 809 of file TreeBH.cpp.

810 {
811 auto& cell = mortonTree[numCell];
812 if (cell.leaf)
813 {
814 MinMaxCellsCalc(cell);
815 cell.hasGabs = true;
816 }
817 else
818 {
819 std::cout << "!!!!!!!!!!!!" << std::endl;
820
821 int ch0 = cell.child[0];
822 int ch1 = cell.child[1];
825 cell.hasGabs = false;
826 }
827 }
void MinMaxCellsSearch(int numCell)
Definition TreeBH.cpp:809
void MinMaxCellsCalc(BH::treeCellT &cell)
Definition TreeBH.cpp:829
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Morton2D()

unsigned int BH::MortonTree::Morton2D ( const Point2D r)
staticprivate

Мортоновский код для пары из чисел типа double Исходные числа (r[0], r[1]) - строго в диапазоне [0, 1 / (1.0 + 1/(2^codeLength - 1) ))

Definition at line 591 of file TreeBH.cpp.

592 {
593 /*
594 if (x < 0) std::cout << "x*... < 0" << std::endl;
595 if (y < 0) std::cout << "y*... < 0" << std::endl;
596
597 if (x * twoPowCodeLength > twoPowCodeLengthMinus)
598 std::cout << "x*... > ..." << std::endl;
599
600 if (y * twoPowCodeLength > twoPowCodeLengthMinus)
601 std::cout << "y*... > ..." << std::endl;
602
603 x = std::min(std::max(x * twoPowCodeLength, 0.0), twoPowCodeLengthMinus);
604 y = std::min(std::max(y * twoPowCodeLength, 0.0), twoPowCodeLengthMinus);
605
606 unsigned int xx = expandBits((unsigned int)x);
607 unsigned int yy = expandBits((unsigned int)y);
608 */
609 const Point2D& rscale = twoPowCodeLength * r;
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);
613 }
#define twoPowCodeLength
Definition Gpudefs.h:98
static unsigned int ExpandBits(unsigned int v)
"Разрежение" двоичного представления беззнакового целого, вставляя по одному нулику между всеми битам...
Definition TreeBH.cpp:559
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Prefix()

std::pair< unsigned int, int > BH::MortonTree::Prefix ( int  cell) const
private

Функция вычисления общего префикса и его длины для всех частиц в конкретной ячейке

Parameters
[in]cellиндекс ячейки дерева в линейном массиве
Returns
пару из общей части мортоновских кодов всех частиц в данной ячейке и ее длины

Definition at line 227 of file TreeBH.cpp.

228 {
229 int length = PrefixLength(cell);
230 unsigned int el = mortonCodes[mortonTree[cell].range[0]].key;
231 return { el >> (2 * codeLength - length), length };
232 }//Prefix(...)
int PrefixLength(int cell) const
Definition TreeBH.cpp:219
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PrefixLength()

int BH::MortonTree::PrefixLength ( int  cell) const
private

Функция вычисления длины общей части префиксов всех частиц в конкретной ячейке

Parameters
[in]cellиндекс ячейки дерева в линейном массиве
Returns
длину общей части мортоновских кодов всех частиц в данной ячейке

Definition at line 219 of file TreeBH.cpp.

220 {
221 const auto& range = mortonTree[cell].range;
222 return std::min(Delta(range[0], range[1]), 2 * codeLength);
223 }//PrefixLength(...)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RSort_Node3()

void BH::MortonTree::RSort_Node3 ( TParticleCode m,
TParticleCode m_temp,
unsigned int  n 
)
private

Поразрядная сортировка мортоновских кодов

Definition at line 630 of file TreeBH.cpp.

631 {
632 // Заводим массив корзин
633 unsigned int s[sizeof(m->key) * 256] = { 0 };
634 // Заполняем массив корзин для всех разрядов
635 for (unsigned int i = 0; i < n; ++i)
636 {
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)];
640 }
641
642 // Пересчитываем смещения для корзин
643 for (unsigned int digit = 0; digit < sizeof(m->key); digit++)
644 {
645 unsigned int off = 0;
646 for (unsigned int i = 0; i < 256; i++)
647 {
648 auto& rs = s[i + (digit << 8)];
649 unsigned int value = rs;
650 rs = off;
651 off += value;
652 }
653 }
654
655 // Вызов сортировки по битам от младших к старшим (LSD)
656 for (unsigned int digit = 0; digit < sizeof(m->key); digit++)
657 {
658 RSort_step3(m, m_temp, n, &s[digit << 8], digit);
659 std::swap(m, m_temp);
660 //TParticleCode* temp = m;
661 //m = m_temp;
662 //m_temp = temp;
663 }
664
665 // Если ключ структуры однобайтовый, копируем отсортированное в исходный массив
666 if (sizeof(m->key) == 1)
667 {
668 std::swap(m, m_temp);
669 //TParticleCode* temp = m;
670 //m = m_temp;
671 //m_temp = temp;
672 memcpy(m, m_temp, n * sizeof(TParticleCode));
673 }
674 }
void RSort_step3(TParticleCode *source, TParticleCode *dest, unsigned int n, unsigned int *offset, unsigned char sortable_bit)
Вспомогательная функция к RSort_Node3.
Definition TreeBH.cpp:618
unsigned int key
Мортоновский код частицы
Definition Point2D.h:57
Here is the call graph for this function:

◆ RSort_Parallel()

void BH::MortonTree::RSort_Parallel ( TParticleCode m,
TParticleCode m_temp,
unsigned int  n,
unsigned int *  s 
)
inlineprivate

Параллельная версия поразрядной сортировки мортоновских кодов

Definition at line 677 of file TreeBH.cpp.

678 {
679 if (n == 0)
680 return;
681 // Количество задействованных потоков
682 unsigned char threads = omp_get_max_threads();
683 //std::cout << "threads = " << (int)threads << std::endl;
684
685#pragma omp parallel num_threads(threads)
686 {
688 TParticleCode* dest = m_temp;
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);
694
695 for (unsigned int digit = 0; digit < sizeof(m->key); ++digit)
696 {
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;
701 while (b1 >= b2)
702 {
703 ++s0[*(b1 + digit)];
704 b1 -= sizeof(TParticleCode);
705 }
706 for (unsigned int i = 0; i < 256; i++)
707 {
708 s[i + 256 * l] = s0[i];
709 }
710
711#pragma omp barrier
712 for (unsigned int j = 0; j < threads; j++)
713 {
714 for (unsigned int i = 0; i < 256; i++)
715 {
716 s_sum[i] += s[i + 256 * j];
717 if (j < l)
718 {
719 s0[i] += s[i + 256 * j];
720 }
721 }
722 }
723
724 for (unsigned int i = 1; i < 256; ++i)
725 {
726 s_sum[i] += s_sum[i - 1];
727 s0[i] += s_sum[i - 1];
728 }
729 unsigned char* b = (unsigned char*)&source[right_index].key + digit;
730 TParticleCode* v1 = &source[right_index];
731 TParticleCode* v2 = &source[left_index];
732 while (v1 >= v2)
733 {
734 dest[--s0[*b]] = *v1--;
735 b -= sizeof(TParticleCode);
736 }
737#pragma omp barrier
738 std::swap(source, dest);
739 }
740 }
741
742 // Если ключ структуры однобайтовый, просто копируем в исходный массив
743 if (sizeof(m->key) == 1)
744 {
745 memcpy(m, m_temp, n * sizeof(TParticleCode));
746 }
747 }
Here is the caller graph for this function:

◆ RSort_step3()

void BH::MortonTree::RSort_step3 ( TParticleCode source,
TParticleCode dest,
unsigned int  n,
unsigned int *  offset,
unsigned char  sortable_bit 
)
inlineprivate

Вспомогательная функция к RSort_Node3.

Definition at line 618 of file TreeBH.cpp.

619 {
620 //unsigned char* b = (unsigned char*)&source[n].key + sortable_bit;
621
622 for (unsigned int i = 0; i < n; ++i)
623 {
624 TParticleCode* src = &source[i];
625 unsigned int off = (src->key >> (sortable_bit * 8)) & 0xFF;
626 dest[offset[off]++] = *src;
627 }
628 }
Here is the caller graph for this function:

◆ SetCellGeometry()

void BH::MortonTree::SetCellGeometry ( int  cell)
private

Функция вычисления геометрических параметров внутренней ячейки дерева

Definition at line 236 of file TreeBH.cpp.

237 {
238 int prLength;
239 unsigned int pr;
240 std::tie<unsigned int, int>(pr, prLength) = Prefix(cell);
241 prLength -= PrefixLength(0);
242
243 Point2D sz = { 1.0 / (double)(1 << ceilhalf(prLength)), 1.0 / (1 << (prLength / 2)) };
244
245 Point2D pos = 0.5 * sz;
246
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));
250
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));
254
255 mortonTree[cell].center = pos * (1.0 / iQuadSideVar) + lowLeft;
256 mortonTree[cell].size = sz * (1.0 / iQuadSideVar);
257 mortonTree[cell].level = prLength;
258
259 mortonTree[cell].leaf = (prLength >= maxTreeLevel);
260 }//SetCellGeometry(...)
std::pair< unsigned int, int > Prefix(int cell) const
Definition TreeBH.cpp:227
size_t size() const
Definition numvector.h:114
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ShareGabs()

void BH::MortonTree::ShareGabs ( int  numCell)

Definition at line 854 of file TreeBH.cpp.

855 {
856 auto& lcell = mortonTree[mortonTree[numCell].child[0]]; //левый ребенок
857 auto& rcell = mortonTree[mortonTree[numCell].child[1]]; //правый ребенок
858 auto& pcell = mortonTree[numCell];
859 {
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]);
864 }
865
866 pcell.center = (pcell.minx_miny + pcell.maxx_maxy) * 0.5;
867 pcell.size = pcell.maxx_maxy - pcell.minx_miny;
868 }
Here is the caller graph for this function:

Member Data Documentation

◆ binomCft

std::vector<double> BH::MortonTree::binomCft

список биномиальных коэффициентов (имеет смысл только нижняя треугольная часть матрицы, остальные = 0)

Definition at line 223 of file TreeBH.h.

◆ iFact

std::vector<double> BH::MortonTree::iFact

Спикок обратных факториалов целых чисел

Definition at line 219 of file TreeBH.h.

◆ iQuadSideVar

double BH::MortonTree::iQuadSideVar
private

Масштабный фактор дерева (на сколько нужно умножить сторону квадрата содержащего все частицы, чтобы новый квадрат имел размер [0, U]x[0, U], где U выбирается так, чтобы все мортоновские коды заданной длины были в диапазоне [0, 1), т.е. положение частицы должно быть в диапазоне [0, 1 / (1.0 + 1/(2^codeLength - 1) ))

Definition at line 165 of file TreeBH.h.

◆ lowLeft

Point2D BH::MortonTree::lowLeft
private

Положение нижнего левого угла дерева

Definition at line 168 of file TreeBH.h.

◆ maxTreeLevel

const int BH::MortonTree::maxTreeLevel

Максимальная глубина дерева при его обходе

Definition at line 226 of file TreeBH.h.

◆ mortonCodes

std::vector<TParticleCode> BH::MortonTree::mortonCodes

Список мортоновских кодов, вычисляемых по положениям частиц

Definition at line 157 of file TreeBH.h.

◆ mortonLowCells

std::vector<int> BH::MortonTree::mortonLowCells

Вектор индесков ячеек нижнего уровня в дереве

Definition at line 247 of file TreeBH.h.

◆ mortonTree

std::vector<treeCellT> BH::MortonTree::mortonTree

Мортоновское дерево Размер дерева равен сумме числа внутренних вершин (число частиц без единицы) и числа частиц резервируется на 1 штуку больше для удобства работы ячейки [0 ... pos.size()-2] отвечают внутренним узлам, ячейка с идексом pos.size()-1 не используется ячейки [pos.size() ... 2*pos.size()-1] отвечают частицам

Definition at line 257 of file TreeBH.h.

◆ pointsCopy

std::vector<PointsCopy>& BH::MortonTree::pointsCopy
private

Ссылка на список обобщенных вихрей, по которым строится дерево

Definition at line 153 of file TreeBH.h.

◆ prm

const params& BH::MortonTree::prm
private

Ссылка на параметры, загружаемые из файла

Definition at line 150 of file TreeBH.h.


The documentation for this class was generated from the following files: