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

Структура, хранящая данные и указатели на массивы на GPU для оптимизации итерационного решения СЛАУ на GPU. More...

#include <cpuTreeInfo.h>

Collaboration diagram for VM2D::CpuTreeInfo:

Public Member Functions

 CpuTreeInfo (tree_T treeType_, object_T objectType_, scheme_T schemeType_)
 
 ~CpuTreeInfo ()
 
float Update (const std::vector< Vortex2D > &vtx, int cntrLev=0)
 
float UpdatePanelGeometry (const std::vector< std::pair< Point2D, Point2D > > &panels, int cntrLev)
 
void RadixSortMortonCodes ()
 
void RadixSortInternalCells ()
 
int Delta (int i, int j) const
 
void CalcAABB ()
 
float Build ()
 
float UpwardTraversal (int order)
 
float DownwardTraversalVorticesToPoints (CpuTreeInfo &cntrTree, std::vector< Point2D > &vel, std::vector< double > &epsast, double theta, int order, bool calcRadius)
 
float DownwardTraversalClosestPanelToPoints (CpuTreeInfo &cntrTree, std::vector< std::pair< int, double > > &indexPnlDist, bool findOnlyInside, double *pseudonormals)
 
float DownwardTraversalVorticesToPanels (CpuTreeInfo &cntrTree, std::vector< double > &rhs, std::vector< double > &rhsLin, double theta, int order)
 

Public Attributes

int controlLevel
 
std::vector< Point2Dobject
 
std::vector< double > gamma
 
std::vector< double > sigma
 
tree_T treeType
 
object_T objectType
 
scheme_T schemeType
 
std::vector< int > mass
 
Point2D maxr
 
Point2D minr
 
std::vector< Point2Dmoms
 
std::vector< Point2DED
 
std::vector< unsigned int > mortonCodesKeyUnsort
 
std::vector< unsigned int > mortonCodesKey
 
std::vector< int > mortonCodesIdxUnsort
 
std::vector< int > mortonCodesIdx
 
std::vector< int > levelUnsort
 
std::vector< int > levelSort
 
std::vector< int > indexUnsort
 
std::vector< int > indexSort
 
std::vector< int > indexSortT
 
std::vector< int > indexControlCells
 
std::vector< Point2Dcenter
 
std::vector< Point4Dlowerupper
 
std::vector< Point4DgabForLeaves
 
std::vector< int > parent
 
std::vector< std::pair< int, int > > child
 
std::vector< std::pair< int, int > > range
 
OptimizedRadixSorter< int > codesSorter
 
OptimizedRadixSorter< int > levelSorter
 

Detailed Description

Структура, хранящая данные и указатели на массивы на GPU для оптимизации итерационного решения СЛАУ на GPU.

Author
Марчевский Илья Константинович
Сокол Ксения Сергеевна
Рятина Евгения Павловна
Колганова Александра Олеговна

\Version 1.14

Date
6 марта 2026 г. ‍/ struct infoForMatVecMul { std::vector<int> nClosePanels; ///количество листьев дерева (панелей), находящихся в ближней зоне std::vector<int> nFarCells; ///количество ячеек, находящихся в дальней зоне

std::vector<int> closePrefixSum; ///префиксная сумма для ближней зоны std::vector<int> farPrefixSum; ///префиксная сумма для дальней зоны

Point2D* i00D; ///указатель на GPU, хранящий влияние панелей из ближней зоны Point2D* i01D; ///аналог i00D, но используется для кусочно-линейной схемы Point2D* i10D; ///аналог i00D, но используется для кусочно-линейной схемы Point2D* i11D; ///аналог i00D, но используется для кусочно-линейной схемы

int* nClosePanelsD; ///количество листьев дерева (панелей), находящихся в ближней зоне int* nFarCellsD; ///количество ячеек, находящихся в дальней зоне

int* closeCellsIdxD; ///индексы ячеек ближней зоны int* farCellsIdxD; ///индексы ячеек дальней зоны

int* closePrefixSumD; ///префиксная сумма для ближней зоны int* farPrefixSumD; ///префиксная сумма для дальней зоны };

/*!
\brief Класс, определяющий структуры дерева для быстрых методов при их реализации на CPU

\author Марчевский Илья Константинович
\author Сокол Ксения Сергеевна
\author Рятина Евгения Павловна
\author Колганова Александра Олеговна

\version 1.14
\date 6 марта 2026 г.

Definition at line 95 of file cpuTreeInfo.h.

Constructor & Destructor Documentation

◆ CpuTreeInfo()

VM2D::CpuTreeInfo::CpuTreeInfo ( tree_T  treeType_,
object_T  objectType_,
scheme_T  schemeType_ 
)

Definition at line 125 of file cpuTreeInfo.cpp.

126 :
127 treeType(treeType_),
128 objectType(objectType_),
129 schemeType(schemeType_)
130 {
131 /*
132 switch (objectType)
133 {
134 case object_T::point2:
135 sizeOfElement = sizeof(Point2D);
136 break;
137
138 case object_T::point4:
139 sizeOfElement = sizeof(Vortex2D);
140 break;
141
142 case object_T::panel:
143 switch (treeType)
144 {
145 case tree_T::aux:
146 sizeOfElement = sizeof(double) * 6;
147 break;
148 case tree_T::contr:
149 sizeOfElement = sizeof(Point2D);
150 break;
151 case tree_T::vortex:
152 case tree_T::source:
153 sizeOfElement = sizeof(double) * 12;
154 break;
155 }
156 break;
157 }
158 */
159 };

◆ ~CpuTreeInfo()

VM2D::CpuTreeInfo::~CpuTreeInfo ( )

Definition at line 161 of file cpuTreeInfo.cpp.

161{};

Member Function Documentation

◆ Build()

float VM2D::CpuTreeInfo::Build ( )

Definition at line 476 of file cpuTreeInfo.cpp.

477 {
478 VMlib::vmTimer timer;
479 timer.start();
480
481 int nObject = (int)object.size();
482 if (nObject > 0)
483 {
484 //treeBoundingBox;
485 //to_parallel
486 auto minmaxX = std::minmax_element(object.begin(), object.end(), Point2D::cmp<'x'>);
487 auto minmaxY = std::minmax_element(object.begin(), object.end(), Point2D::cmp<'y'>);
488 minr = Point2D({ (*minmaxX.first)[0], (*minmaxY.first)[1] });
489 maxr = Point2D({ (*minmaxX.second)[0], (*minmaxY.second)[1] });
490
491 //treeMortonCodes;
492 double lmax, quadSideFactor;
493 lmax = std::max(maxr[0] - minr[0], maxr[1] - minr[1]);
494 Point2D rcen = 0.5 * (maxr + minr); //координаты центра
495 quadSideFactor = rbound / lmax; //1;
496
497#pragma omp parallel for
498 for (int bdy = 0; bdy < nObject; ++bdy)
499 {
500 Point2D rScaled = twoPowCodeLength * ((object[bdy] - rcen) * quadSideFactor + 0.5 * Point2D{ rbound, rbound });
501
502 unsigned int xx = ExpandBits((unsigned int)rScaled[0]);
503 unsigned int yy = ExpandBits((unsigned int)rScaled[1]);
504 mortonCodesKeyUnsort[bdy] = yy | (xx << 1);
505 mortonCodesIdxUnsort[bdy] = bdy;
506 //printf("{%d, %d},\n", bdy, mortonCodesKeyUnsort[bdy]);
507 }
508
509
510
512 //for (int i = 0; i < nObject; ++i)
513 //printf("{%d, %d},\n", mortonCodesKey[i], mortonCodesIdx[i]);
514
515 //treeMortonInternalNodes
516 //if (treeType != tree_T::contr) для CPU нужны внутренние ячейки для обоих деревьев
517 {
518#pragma omp parallel for
519 for (int i = 0; i < nObject - 1; ++i)
520 {
521 int codei = mortonCodesKey[i];
522
523 int Deltap1 = Delta(i, i + 1);
524 int Deltam1 = Delta(i, i - 1);
525
526 int d = (Deltap1 - Deltam1 > 0) ? 1 : -1;
527
528 int delta_min = (d > 0) ? Deltam1 : Deltap1;
529
530 int Lmax = 2;
531 int pos = i + Lmax * d;
532
533 while (Delta(i, pos) > delta_min)
534 {
535 Lmax *= 2;
536 pos = i + Lmax * d;
537 }
538
539 int L = 0;
540 for (int t = (Lmax >> 1); t >= 1; t >>= 1)
541 {
542 pos = i + (L + t) * d;
543
544 if (Delta(i, pos) > delta_min)
545 L += t;
546 }
547
548 int j = i + L * d;
549 pos = j;
550
551 int delta_node = Delta(i, j);
552
553 levelUnsort[i] = delta_node;
554 indexUnsort[i] = i;
555 //if (i == 2)
556 // printf("!!! %d, %d\n", mortonCodesKey[i], mortonCodesKey[j]);
557
558 int s = 0;
559 for (int p = 1, t = ceilhalf(L); L > (1 << (p - 1)); ++p, t = ceilpow2(L, p))
560 {
561 pos = i + (s + t) * d;
562
563 int dl = Delta(i, pos);
564
565 if (dl > delta_node)
566 s += t;
567 }//for p
568
569 int gammaPos = i + s * d + d * (d < 0); // = std::min(d, 0);
570
571 int Mmin = std::min(i, j);
572 int Mmax = std::max(i, j);
573
574 int left = gammaPos;
575 int right = gammaPos + 1;
576
577 // -
578 int childLeft = (Mmin == gammaPos) * nObject + left;
579 range[childLeft] = { Mmin, gammaPos };
580 parent[childLeft] = i;
581
582 // -
583 int childRight = (Mmax == gammaPos + 1) * nObject + right;
584 range[childRight] = { gammaPos + 1, Mmax };
585 parent[childRight] = i;
586
587 child[i] = { childLeft, childRight };
588 //printf("i:%d, %d, {%d, %d}\n", indexUnsort[i], levelUnsort[i], childLeft, childRight);
589 }
590
591 //if (treeType == tree_T::contr)
592 {
593 for (int i = 0; i < nObject - 1; ++i)
594 {
596 indexControlCells.push_back(i);
597 }
598 for (int i = 0; i < nObject; ++i)
599 {
600 if (levelUnsort[parent[nObject + i]] < controlLevel)
601 indexControlCells.push_back(nObject + i);
602 }
603 }
605 }// if contr
606 }
607 timer.stop();
608
609 return (float)timer.duration();
610 }//Build()
#define rbound
Definition Gpudefs.h:103
#define twoPowCodeLength
Definition Gpudefs.h:102
std::vector< std::pair< int, int > > range
std::vector< int > indexControlCells
std::vector< int > levelUnsort
std::vector< unsigned int > mortonCodesKeyUnsort
std::vector< int > parent
std::vector< unsigned int > mortonCodesKey
void RadixSortInternalCells()
std::vector< int > indexUnsort
std::vector< int > mortonCodesIdxUnsort
int Delta(int i, int j) const
std::vector< std::pair< int, int > > child
Класс засекания времени
Definition TimesGen.h:59
double duration() const
Definition TimesGen.h:143
const vmTimer & stop() const
Останов работающего счетчика времени
Definition TimesGen.h:125
const vmTimer & start() const
Запуск (первый или повторный) счетчика времени
Definition TimesGen.h:109
int ceilhalf(int x)
unsigned int ExpandBits(unsigned int v)
int ceilpow2(int x, int p)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalcAABB()

void VM2D::CpuTreeInfo::CalcAABB ( )

Definition at line 370 of file cpuTreeInfo.cpp.

371 {
372 using double4 = Point4D;
373 using double2 = Point2D;
374 using int2 = std::pair<int, int>;
375
376#pragma omp parallel
377 {
378 int i, j, ch, flag;
379
380 double4 lu[2];
381
382 //int cm;
383 int m[2];
384
385
386 const int nnodes = 2 * (int)object.size() - 1;
387 const int nbodies = (int)object.size();
388#pragma omp for
389 for (int k = nbodies; k < nnodes; ++k)
390 {
391 //MortonTree:
392 // 0 1 2 ... (nb-2) x (nb+0) (nb+1) (nb+2) ... (nb+(nb-1))
393 // ---------------- -----------------------------------
394 // cells bodies
395
396 //Martin's tree:
397 // 0 1 2 ... (nb-1) x x x x (nn-(nb-1)) ... (nn-2) (nn-1)
398 // ---------------- ----------------------------
399 // bodies sorted and reversed cells
400
401 flag = 0;
402 j = 0;
403 // iterate over all cells assigned to thread
404 while (flag == 0)
405 {
406 j = 2;
407 const int kch = ((nnodes - 1) - k);
408 const int srt = indexSort[kch];
409 int2 chdPair = child[srt];
410
411 //cm = 0;
412
413 //int chdSorted[2];
414
415 for (i = 0; i < 2; i++)
416 {
417 int chd = i * chdPair.second + (1 - i) * chdPair.first; // i==0 => .x; i==1 => .y
418 ch = (chd >= nbodies) ? (chd - nbodies) : ((nnodes - 1) - indexSortT[chd]);
419 if ((chd >= nbodies) || (mass[nnodes - 1 - ch] >= 0))
420 j--;
421 }
422
423 if (j == 0)
424 {
425 for (i = 0; i < 2; i++)
426 {
427 const int chd = i * chdPair.second + (1 - i) * chdPair.first;
428 if (chd >= nbodies)
429 {
430 ch = chd - nbodies;
431 const int sortedBody = mortonCodesIdx[ch];
432
433 double4 xyAB = gabForLeaves[sortedBody];
434 lu[i] = double4{
435 ::fmin(xyAB[0], xyAB[2]), ::fmin(xyAB[1], xyAB[3]),
436 ::fmax(xyAB[0], xyAB[2]), ::fmax(xyAB[1], xyAB[3])
437 };
438 m[i] = 1;
439 }
440 else
441 {
442 const int srtT = indexSortT[chd];
443 lu[i] = lowerupper[chd];
444 m[i] = mass[srtT];
445 }
446 }
447
448 const double4 loup = double4{
449 ::fmin(lu[0][0], lu[1][0]),
450 ::fmin(lu[0][1], lu[1][1]),
451 ::fmax(lu[0][2], lu[1][2]),
452 ::fmax(lu[0][3], lu[1][3]) };
453
454 lowerupper[srt] = loup;
455
456 // Центр текущего узла = центр его AABB
457 center[srt] = double2{
458 0.5 * (loup[0] + loup[2]),
459 0.5 * (loup[1] + loup[3])
460 };
461 flag = 1;
462 }//if j==0
463
464#pragma omp flush
465
466 if (flag != 0)
467 mass[nnodes - 1 - k] = m[0] + m[1];
468
469 }//while flag
470 }//for k
471 }
472 }//CalcAABB(...)
std::vector< int > indexSort
std::vector< int > mortonCodesIdx
std::vector< Point2D > center
std::vector< Point4D > gabForLeaves
std::vector< int > indexSortT
std::vector< Point4D > lowerupper
std::vector< int > mass
Here is the caller graph for this function:

◆ Delta()

int VM2D::CpuTreeInfo::Delta ( int  i,
int  j 
) const

Definition at line 92 of file cpuTreeInfo.cpp.

93 {
94 if ((j < 0) || (j > (int)object.size() - 1))
95 return -1;
96
97 if (i > j)
98 std::swap(i, j);
99
100 //if ((i < 0) || (j > n-1))
101 // exit(111);
102
103 const unsigned int ki = mortonCodesKey[i];
104 const unsigned int kj = mortonCodesKey[j];
105
106 //Поиск номера самого старшего ненулевого бита в числе c
107 int count = 0;
108 for (unsigned int c = (ki ^ kj); c; c >>= 1, ++count);
109
110 if ((!count) && (i != j))
111 {
112 int addCount = 0;
113 //единички к номерам i и j добавлены для совместимости с Wolfram Mathematica,
114 //для кода они не важны, но дерево без них почти наверняка построится по-другому
115 for (unsigned int add = ((i + 1) ^ (j + 1)); add; add >>= 1, ++addCount);
116 return 2 * codeLength + (2 * codeLength - addCount);
117 }//if ((!count) && (i != j))
118
119 return (2 * codeLength - count);
120 }//Delta(...)
#define codeLength
Definition Gpudefs.h:101
Here is the caller graph for this function:

◆ DownwardTraversalClosestPanelToPoints()

float VM2D::CpuTreeInfo::DownwardTraversalClosestPanelToPoints ( CpuTreeInfo cntrTree,
std::vector< std::pair< int, double > > &  indexPnlDist,
bool  findOnlyInside,
double *  pseudonormals 
)

Definition at line 724 of file cpuTreeInfo.cpp.

725 {
726 using double4 = Point4D;
727 const int nbodies = (int)object.size(); //количество вихрей
728 const int nnodes = 2 * nbodies - 1; //количество узлов дерева вихрей (листья-вихри + внутренние узлы)
729 const int npoints = (int)cntrTree.object.size(); //количество точек наблюдения
730
731 int indexOfPoint;
732 const int maxDepth = 32;
733
734 VMlib::vmTimer timer;
735 timer.start();
736
737#pragma omp parallel for schedule(dynamic, 1)
738 for (int indexK = 0; indexK < (int)cntrTree.indexControlCells.size(); ++indexK)
739 {
740 Point2D query;
741
742 const int k = cntrTree.indexControlCells[indexK];
743
744 Point4D gabCntrl;
745 bool isCntrLeaf = (k >= cntrTree.object.size());
746
747 if (isCntrLeaf)
748 {
749 const int leafIndex = cntrTree.mortonCodesIdx[k - npoints];
750 indexOfPoint = leafIndex;
751 query = cntrTree.object[leafIndex];
752 Point4D pnlCntrGab = cntrTree.gabForLeaves[cntrTree.mortonCodesIdx[leafIndex]];
753 gabCntrl = {
754 fmin(pnlCntrGab[0], pnlCntrGab[2]), fmin(pnlCntrGab[1], pnlCntrGab[3]),
755 fmax(pnlCntrGab[0], pnlCntrGab[2]), fmax(pnlCntrGab[1], pnlCntrGab[3])
756 };
757 }
758 else
759 {
760 query = cntrTree.center[k];
761 gabCntrl = cntrTree.lowerupper[k];
762 }
763
764 std::pair<int, double> stack[maxDepth];
765 int depth;
766
767 double md2 = mindist2(lowerupper[0], query);
768 std::pair<int, int> nearestLocation{ -1, 0 };
769
770 if ((findOnlyInside) && (md2 != 0))
771 {
772 indexPnlDist[indexK] = { -1, -1.0 };
773 continue;
774 }
775
776 depth = 0;
777 stack[0] = { 0, md2 };
778
779 double dist_to_nearest_object = 1e+100;
780
781 while (depth >= 0)
782 {
783 std::pair<int, double> nd = stack[depth];
784 --depth;
785
786 if (nd.second > dist_to_nearest_object)
787 continue;
788
789 std::pair<int, int> chBoth = child[nd.first];
790
791 bool isLeftLeaf = (chBoth.first >= object.size());
792 bool isRightLeaf = (chBoth.second >= object.size());
793
794 double4 L_box, R_box;
795 double4 pnlLeftGab, pnlRightGab;
796
797 if (!isLeftLeaf)
798 L_box = lowerupper[chBoth.first];
799 else
800 {
801 int n = chBoth.first - (int)object.size();
802 pnlLeftGab = gabForLeaves[mortonCodesIdx[n]];
803 L_box = {
804 fmin(pnlLeftGab[0], pnlLeftGab[2]), fmin(pnlLeftGab[1], pnlLeftGab[3]),
805 fmax(pnlLeftGab[0], pnlLeftGab[2]), fmax(pnlLeftGab[1], pnlLeftGab[3])
806 };
807 }
808
809 if (!isRightLeaf)
810 R_box = lowerupper[chBoth.second];
811 else
812 {
813 int n = chBoth.second - (int)object.size();
814 pnlRightGab = gabForLeaves[mortonCodesIdx[n]];
815 R_box = {
816 fmin(pnlRightGab[0], pnlRightGab[2]), fmin(pnlRightGab[1], pnlRightGab[3]),
817 fmax(pnlRightGab[0], pnlRightGab[2]), fmax(pnlRightGab[1], pnlRightGab[3])
818 };
819 }
820
821 double L_mindist2 = mindist2(L_box, query);
822 double R_mindist2 = mindist2(R_box, query);
823
824 double L_minmaxdist2 = minmaxdist2(L_box, query);
825 double R_minmaxdist2 = minmaxdist2(R_box, query);
826
827 bool pushLeft = false;
828 bool pushRight = false;
829
830 if (L_mindist2 <= R_minmaxdist2 * onePlusMachineEps) // L is worth considering
831 {
832 if (isLeftLeaf) // leaf node
833 {
834 int n = chBoth.first - (int)object.size();
835
836 std::pair<double, int> dist_code = distance_calculator_point2segment(query, pnlLeftGab);
837 if (dist_code.first <= dist_to_nearest_object)
838 {
839 dist_to_nearest_object = dist_code.first;
840 nearestLocation = { mortonCodesIdx[n], dist_code.second };
841 }
842 }
843 else
844 pushLeft = true;
845 }
846
847 if (R_mindist2 <= L_minmaxdist2 * onePlusMachineEps) // R is worth considering
848 {
849 if (isRightLeaf) // leaf node
850 {
851 int n = chBoth.second - (int)object.size();
852
853 std::pair<double, int> dist_code = distance_calculator_point2segment(query, pnlRightGab);
854 if (dist_code.first <= dist_to_nearest_object)
855 {
856 dist_to_nearest_object = dist_code.first;
857 nearestLocation = { mortonCodesIdx[n], (int)dist_code.second };
858 }
859 }
860 else
861 pushRight = true;
862 }
863
864 if (pushLeft && !pushRight)
865 {
866 ++depth;
867 stack[depth] = { chBoth.first, L_mindist2 };
868 }
869 else if (!pushLeft && pushRight)
870 {
871 ++depth;
872 stack[depth] = { chBoth.second, R_mindist2 };
873 }
874 else if (pushLeft && pushRight)
875 {
876 if (L_mindist2 < R_mindist2)
877 {
878 // Сначала добавляем правый (дальний) вниз стека
879 ++depth;
880 stack[depth] = { chBoth.second, R_mindist2 };
881 // Потом левый (ближний) наверх - будет обработан первым
882 ++depth;
883 stack[depth] = { chBoth.first, L_mindist2 };
884 }
885 else
886 {
887 // Сначала добавляем левый (дальний) вниз стека
888 ++depth;
889 stack[depth] = { chBoth.first, L_mindist2 };
890 // Потом правый (ближний) наверх - будет обработан первым
891 ++depth;
892 stack[depth] = { chBoth.second, R_mindist2 };
893 }
894 }
895 }//while depth
896
897
898 if (isCntrLeaf)
899 {
900 indexPnlDist[cntrTree.mortonCodesIdx[k - npoints]] = { nearestLocation.first, sqrt(dist_to_nearest_object) };
901 continue;
902 }
903
904 double radius = sqrt(dist_to_nearest_object) + 0.5 * sqrt(sqr(gabCntrl[2] - gabCntrl[0]) + sqr(gabCntrl[3] - gabCntrl[1]));
905
906
907 int stackCandidates[maxDepth];
908 depth = 0;
909 stackCandidates[0] = 0;
910
911 std::vector<int> candidates;
912 candidates.reserve(100);
913
914 while (depth >= 0)
915 {
916 int nd = stackCandidates[depth];
917 --depth;
918
919 std::pair<int, int> chBoth = child[nd];
920
921 bool isLeftLeaf = (chBoth.first >= object.size());
922 bool isRightLeaf = (chBoth.second >= object.size());
923
924 Point4D gabL, gabR;
925
926 if (isLeftLeaf)
927 {
928 int n = chBoth.first - (int)object.size();
929 Point4D pnlLeftGab = gabForLeaves[mortonCodesIdx[n]];
930 gabL = {
931 fmin(pnlLeftGab[0], pnlLeftGab[2]), fmin(pnlLeftGab[1], pnlLeftGab[3]),
932 fmax(pnlLeftGab[0], pnlLeftGab[2]), fmax(pnlLeftGab[1], pnlLeftGab[3])
933 };
934 }
935 else
936 gabL = lowerupper[chBoth.first];
937
938
939 if (isRightLeaf)
940 {
941 int n = chBoth.second - (int)object.size();
942 Point4D pnlRightGab = gabForLeaves[mortonCodesIdx[n]];
943 gabR = {
944 fmin(pnlRightGab[0], pnlRightGab[2]), fmin(pnlRightGab[1], pnlRightGab[3]),
945 fmax(pnlRightGab[0], pnlRightGab[2]), fmax(pnlRightGab[1], pnlRightGab[3])
946 };
947 }
948 else
949 gabR = lowerupper[chBoth.second];
950
951
952 double dist2L = MinDist2AABB(gabCntrl, gabL);
953 double dist2R = MinDist2AABB(gabCntrl, gabR);
954
955 if (dist2L < sqr(radius))
956 {
957 if (isLeftLeaf)
958 candidates.push_back(mortonCodesIdx[chBoth.first - object.size()]);
959 else
960 stackCandidates[++depth] = chBoth.first;
961 }
962
963 if (dist2R < sqr(radius))
964 {
965 if (isRightLeaf)
966 candidates.push_back(mortonCodesIdx[chBoth.second - object.size()]);
967 else
968 stackCandidates[++depth] = chBoth.second;
969 }
970
971 }//while depth
972
973 for (int particle = cntrTree.range[k].first; particle <= cntrTree.range[k].second; ++particle)
974 {
975 Point2D observPoint = cntrTree.object[cntrTree.mortonCodesIdx[particle]];
976
977 double currentMinDist2 = 1e+100;
978 int indexMinDist = -1;
979 for (int i = 0; i < candidates.size(); ++i)
980 {
981 Point4D pnl = gabForLeaves[candidates[i]];
982 double dst2 = distance_calculator_point2segment(observPoint, gabForLeaves[candidates[i]]).first;
983 if (dst2 < currentMinDist2)
984 {
985 currentMinDist2 = dst2;
986 indexMinDist = candidates[i];
987 }
988 }
989 indexPnlDist[cntrTree.mortonCodesIdx[particle]] = { indexMinDist, sqrt(currentMinDist2) };
990 }
991 }//for k
992
993 //*/
994
995 timer.stop();
996 return (float)timer.duration();
997 }
size_t size() const
Definition numvector.h:114
double minmaxdist2(const Point4D &lowerUpper, const Point2D &rhs) noexcept
std::pair< double, int > distance_calculator_point2segment(const Point2D &point, const Point4D &object)
const double onePlusMachineEps
double MinDist2AABB(const Point4D &gabI, const Point4D &gabJ)
double mindist2(const Point4D &lowerUpper, const Point2D &rhs) noexcept
T sqr(T x)
Возведение числа в квадрат
Definition defs.h:455
Here is the call graph for this function:

◆ DownwardTraversalVorticesToPanels()

float VM2D::CpuTreeInfo::DownwardTraversalVorticesToPanels ( CpuTreeInfo cntrTree,
std::vector< double > &  rhs,
std::vector< double > &  rhsLin,
double  theta,
int  order 
)

Definition at line 1281 of file cpuTreeInfo.cpp.

1282 {
1283 float t1 = (float)omp_get_wtime();
1284
1285 using double4 = Point4D;
1286 using double2 = Point2D;
1287 using int2 = std::pair<int, int>;
1288
1289 const int nbodies = (int)object.size(); //количество вихрей
1290 const int npoints = (int)cntrTree.object.size(); //количество панелей
1291
1292 rhs.assign(npoints, 0.0);
1293 bool scheme = false;
1294 if (cntrTree.schemeType == scheme_T::linScheme)
1295 scheme = true;
1296
1297 if(scheme)
1298 rhsLin.assign(npoints, 0.0);
1299 else
1300 rhsLin.clear();
1301
1302 if (nbodies <= 0 || npoints <= 0)
1303 return 0.0f;
1304
1305//#pragma omp parallel
1306 {
1307 double itolsq = 1.0 / (theta * theta);
1308 const int nnodes = 2 * nbodies - 1; //количество узлов дерева вихрей (листья-вихри + внутренние узлы)
1309
1310 const int maxDepth = 32;
1311
1312#pragma omp parallel for schedule(dynamic, 1)//Временно: обход по панелям как на GPU!!!
1313 for (int k = 0; k < npoints; ++k)
1314 {
1315 const int indexOfPoint = cntrTree.mortonCodesIdx[k]; //истинный индекс точки наблюдения
1316 const double2 p = cntrTree.object[indexOfPoint]; //координаты центра панели
1317 const double4& pnl = cntrTree.gabForLeaves[indexOfPoint]; //начало и конец панели наблюдения
1318 const double2 beg{ pnl[0], pnl[1] }; //отдельно начало
1319 const double2 end{ pnl[2], pnl[3] }; //отдельно конец
1320 const double2 rPan = end - beg; //направляющий вектор панели
1321 const double dlen2 = rPan.length2(); //длина панели в квадрате
1322 const double idlen = 1.0 / sqrt(dlen2); //обратная длина
1323 const double2 tau = idlen * rPan; //вектор касательной к панели, направленный от начала к концу
1324 double val = 0.0; //обнуление результата (константная составляющая скорости)
1325 double vallin = 0.0; //обнуление результата (линейная составляющая скорости)
1326 int posStack[maxDepth];
1327 int nodeStack[maxDepth];
1328 std::array<double2, orderAlignment> Eloc; //коэффициенты локальных разложений
1329
1330 int depth = 0;
1331 posStack[0] = 0;
1332 nodeStack[0] = nnodes - 1;
1333 while (depth >= 0)
1334 {
1335 int pd = posStack[depth]; //0 или 1 --- какого потомка ячейки nd обходим (левого или правого)
1336 int nd = nodeStack[depth]; //индекс родительской ячейки дерева, которую обходим, и которая находится на верхушке стека;
1337
1338 int2 chBoth = child[indexSort[(nnodes - 1) - nd]]; //индексы обоих потомков узла nd
1339 while (pd < 2)
1340 {
1341 const int chd = (pd == 0) ? chBoth.first : chBoth.second;
1342 ++pd;
1343 posStack[depth] = pd;
1344
1345 const bool isVortex = (chd >= nbodies); //признак того, что обрабатывамая ячейка --- лист (в правой половине дерева в порядке karrasOrder)
1346
1347 int n; //для хранения индекса вихря или индекса ячейки
1348 int srtT = -1; //истинный индекс внутреннего узла дерева
1349
1350 double2 ps; //координаты влияющего вихря, если обрабатываемая вершина --- лист, или центра влияющей ячейки, если обрабатывается внутренняя ячейка дерева
1351 double gm = 0.0; //циркуляция вихря, если обрабатываемая вершина --- лист, или 0-й мультипольный момент (суммарная циркуляция вихрей) если обрабатывается внутренняя ячейка дерева
1352
1353 double sumSide2 = 0.0; //габариты обрабатываемой ячейки
1354
1355 const Point2D* mom = nullptr; //указатель на набор мультипольных моментов влияющей ячейки
1356
1357 if (isVortex) //если лист
1358 {
1359 n = chd - nbodies; //номер вихря в Мортоновском порядке
1360 const int vortexIndex = mortonCodesIdx[n]; //истинный номер вихря
1361
1362 ps = object[vortexIndex]; //координаты влияющего вихря
1363 gm = gamma[vortexIndex]; //циркуляция влияющего вихря
1364
1365 sumSide2 = 0.0; //листовая ячейка (вихрь) размера не имеет, т.к. является точкой
1366 }//if (isVortex)
1367 else
1368 {
1369 srtT = indexSortT[chd]; //номер внутреннего узла в "развернутом порядке burtscherOrder" (когда корень --- 0-й), отвечающий узлу chd
1370 n = (nnodes - 1) - srtT; //номер внутреннего узла в порядке burtscherOrder (когда корень --- последний)
1371 ps = center[chd]; //координаты центра внутреннего узла --- влияющей ячейки
1372
1373 const double4& gab = lowerupper[chd]; //габарит влияющей ячейки
1374 const double sumSide = gab[2] - gab[0] + gab[3] - gab[1]; //сумма габаритов (полупериметр)
1375 sumSide2 = sumSide * sumSide; //квадрат суммы габаритов влияющей ячейки
1376 }//if (!isVortex)
1377
1378 const double2 dr = p - ps; //радиус-вектор из центра влияющей ячейки в точку наблюдения
1379 const double r2 = dr[0] * dr[0] + dr[1] * dr[1]; //квадрат модуля предыдущего
1380
1381 // Для вихря всегда считаем точное влияние. Для ячейки проверяем MAC.
1382 if (isVortex || (sumSide2 + dlen2) * itolsq < r2)
1383 {
1384 if (isVortex) //если лист --- считаем напрямую
1385 {
1386 const double2 ss = ps - beg;
1387 const double2 pp = ps - end;
1388
1389 const double alpha = atan2(pp[0] * ss[1] - pp[1] * ss[0], pp[0] * ss[0] + pp[1] * ss[1]);
1390
1391 if (r2 > 1e-20)
1392 val -= gm * alpha;
1393
1394 if (scheme) //если схема Т1
1395 {
1396 const double txx = tau[0] * tau[0];
1397 const double txy = tau[0] * tau[1];
1398 const double tyy = tau[1] * tau[1];
1399
1400 double2 u1;
1401
1402 u1[0] = (pp[0] + ss[0]) * (txx - tyy) + 2.0 * (pp[1] + ss[1]) * txy;
1403
1404 u1[1] = (pp[1] + ss[1]) * (tyy - txx) + 2.0 * (pp[0] + ss[0]) * txy;
1405
1406 const double lambda = 0.5 * log(ss.length2() / pp.length2());
1407
1408 const double tempVelLin = gm * (alpha * (u1[0] * tau[0] + u1[1] * tau[1]) +
1409 lambda * (-u1[1] * tau[0] + u1[0] * tau[1]));
1410
1411 vallin -= 0.5 * idlen * tempVelLin;
1412 }//if(linScheme)
1413 }//if (isVortex)
1414 else //если не лист --- мультипольное приближение
1415 {
1416 mom = moms.data() + srtT * orderAlignment;
1417 //std::vector<double2> Eloc(order, double2{ 0.0, 0.0 });
1418 std::fill(Eloc.begin(), Eloc.begin() + order, double2{ 0.0, 0.0 }); //обнуляем коэффициенты локального разложения
1419
1420 double2 thetaLoc = (1.0 / r2) * (p - ps);
1421
1422 // Коэффициенты локального разложения
1423 for (int q = 0; q < order; ++q)
1424 {
1425 for (int s = q; s >= 0; --s)
1426 {
1427 const double sign = ((2 * q - s) & 1) ? -1.0 : 1.0;
1428
1429 Eloc[s] += sign * ifac[q - s + 1] * multzA(thetaLoc, mom[q - s]);
1430 }
1431
1432 thetaLoc = ((q + 1.0) / r2) * multz(thetaLoc, p - ps);
1433 }
1434
1435 // Интегрирование локального разложения по панели для T0 и T1
1436 double2 v = 0.5 * Eloc[0];
1437
1438 double2 vL{ 0.0, 0.0 };
1439
1440 double2 kp = rPan;
1441 double2 mulP = kp;
1442
1443 double2 taudL = (0.5 / dlen2) * rPan;
1444
1445 const double2 taudLc = taudL;
1446
1447 for (int kk = 1; kk < order; ++kk)
1448 {
1449 mulP = multz(mulP, kp);
1450
1451 taudL *= 0.5;
1452
1453 if (!(kk & 1)) // Константная проекционная функция
1454 v += ifac[kk + 2] * multz(Eloc[kk], multzA(taudL, mulP));
1455 else if(scheme) // Линейная проекционная функция
1456 vL += ifac[kk + 3] * multz(Eloc[kk], multzA(multz(taudL, taudLc), multz(mulP, (kk + 1.0) * rPan)));
1457 }
1458
1459 val += 2.0 * (-v[1] * rPan[0] + v[0] * rPan[1]);
1460 if(scheme)
1461 vallin += 2.0 * (-vL[1] * rPan[0] + vL[0] * rPan[1]);
1462 }
1463 }//MAC
1464 else //ячейка близкая --- спускаемся по дереву
1465 {
1466 if (depth + 1 < maxDepth)
1467 {
1468 if (pd == 1) //если это была обработка левого потомка, и по нему пришлось идти вниз по дереву
1469 {
1470 posStack[depth] = 1;
1471 nodeStack[depth] = nd;
1472
1473 ++depth;
1474 }
1475
1476 nd = n;
1477 pd = 0;
1478
1479 chBoth = child[indexSort[(nnodes - 1) - nd]];
1480 }
1481 }
1482 }//while (pd < 2)
1483 --depth; // Оба потомка обработаны -> снимаем узел со стека
1484 }//while (depth >= 0)
1485
1486 const double cf = IDPI * idlen;
1487
1488 rhs[indexOfPoint] = cf * val;
1489 if(scheme)
1490 rhsLin[indexOfPoint] = cf * vallin;
1491 }//for npoints
1492 }
1493
1494 float t2 = (float)omp_get_wtime();
1495 return (t2 - t1);
1496 }//DownwardTraversalVorticesToPanels(...)
const double ifac[]
Definition Gpudefs.h:142
#define orderAlignment
Definition Gpudefs.h:94
const double IDPI
Число .
Definition defs.h:79
std::vector< Point2D > moms
std::vector< double > gamma
Point2D multz(const Point2D &a, const Point2D &b)
Умножение комплексных чисел
Definition Point2D.h:210
Point2D multzA(const Point2D &a, const Point2D &b)
Умножение a на комплексно сопряженноe к b.
Definition Point2D.h:219
int sign(T x)
Усовершенствованный сигнум
Definition defs.h:485
Here is the caller graph for this function:

◆ DownwardTraversalVorticesToPoints()

float VM2D::CpuTreeInfo::DownwardTraversalVorticesToPoints ( CpuTreeInfo cntrTree,
std::vector< Point2D > &  vel,
std::vector< double > &  epsast,
double  theta,
int  order,
bool  calcRadius 
)

Definition at line 1000 of file cpuTreeInfo.cpp.

1001 {
1002 float t1 = (float)omp_get_wtime();
1003
1004 using double4 = Point4D;
1005 using double2 = Point2D;
1006 using int2 = std::pair<int, int>;
1007
1008 if (object.size() > 0)
1009 {
1010#pragma omp parallel
1011 {
1012 double itolsq = 1.0 / (theta * theta);
1013
1014 const int nbodies = (int)object.size(); //количество вихрей
1015 const int nnodes = 2 * nbodies - 1; //количество узлов дерева вихрей (листья-вихри + внутренние узлы)
1016 const int npoints = (int)cntrTree.object.size(); //количество точек наблюдения
1017
1018 int nd; // индекс родительской ячейки дерева, которую обходим, и которая находится на верхушке стека;
1019 int2 chBoth; //индексы обоих потомков узла nd
1020 int pd; // 0 или 1 --- какого потомка ячейки nd обходим (левого или правого)
1021
1022 // для вычисления квадратов расстояний до трех ближайших вихрей
1023 double d_1, d_2, d_3, dst23, dst12;
1024 int indexOfPoint; //истинный индекс точки наблюдения
1025 int srtT; //истинный индекс внутреннего узла дерева
1026
1027 double2 p; //координаты точки наблюдения
1028 double2 v{ 0.0,0.0 }; //результат расчета скорости в точке наблюдения
1029
1030 bool isVortex; //признак того, что обрабатываемая вершина - лист
1031 double2 ps; //координаты влияющего вихря, если обрабатываемая вершина --- лист, или центра влияющей ячейки, если обрабатывается внутренняя ячейка дерева
1032 double gm; //циркуляция вихря, если обрабатываемая вершина --- лист, или 0-й мультипольный момент (суммарная циркуляция вихрей) если обрабатывается внутренняя ячейка дерева
1033 double sgm2;
1034 double sgm2Contr;
1035 double sumSide2; //габариты обрабатываемой ячейки
1036 double2 dr; //радиус-вектор из центра влияющей ячейки в точку наблюдения
1037 double r2; //квадрат модуля предыдущего
1038
1039 const int maxDepth = 32;
1040
1041 int posStack[maxDepth];
1042 int nodeStack[maxDepth];
1043 int depth;
1044 const Point2D* mom = nullptr;
1045
1046#pragma omp for schedule(dynamic,1)
1047 for (int indexK = 0; indexK < (int)cntrTree.indexControlCells.size(); ++indexK)
1048 {
1049 const int k = cntrTree.indexControlCells[indexK];
1050 std::vector<Point2D> vParticles;
1051 std::vector<numvector<double, 3>> epsastParticles;
1052
1053 v.toZero();
1054 d_1 = d_2 = d_3 = 1e+5;
1055 std::vector<Point2D> Ek(order, { 0.0, 0.0 });
1056
1057 bool isCntrLeaf = (k >= npoints);
1058
1059 if (isCntrLeaf)
1060 {
1061 const int leafIndex = cntrTree.mortonCodesIdx[k - npoints];
1062 indexOfPoint = leafIndex;
1063 p = cntrTree.object[leafIndex];
1064 sgm2Contr = sqr(sigma[leafIndex]);
1065 }
1066 else
1067 {
1068 p = cntrTree.center[k];
1069 const Point4D& gab = cntrTree.lowerupper[k];
1070 sgm2Contr = sqr((gab[2] - gab[0] + gab[3] - gab[1]));
1071 vParticles.resize(cntrTree.range[k].second - cntrTree.range[k].first + 1, { 0.0, 0.0 });
1072 epsastParticles.resize(cntrTree.range[k].second - cntrTree.range[k].first + 1, { 1e+5, 1e+5, 1e+5 });
1073 }
1074
1075 depth = 0;
1076 posStack[0] = 0;
1077 nodeStack[0] = nnodes - 1;
1078
1079 while (depth >= 0)
1080 {
1081 pd = posStack[depth];
1082 nd = nodeStack[depth];
1083
1084 chBoth = child[indexSort[(nnodes - 1) - nd]];
1085
1086 while (pd < 2)
1087 {
1088 const int chd = (pd == 0) ? chBoth.first : chBoth.second;
1089
1090 ++pd;
1091 posStack[depth] = pd;
1092
1093 isVortex = (chd >= nbodies);
1094
1095 int n;
1096 if (isVortex)
1097 {
1098 n = chd - nbodies;
1099 const int vortexIndex = mortonCodesIdx[n]; // истинный индекс вихря
1100
1101 ps = object[vortexIndex];
1102 gm = gamma[vortexIndex];
1103 sgm2 = sqr(sigma[vortexIndex]);
1104 sumSide2 = 0.0; // ???
1105 }
1106 else
1107 {
1108 srtT = indexSortT[chd];
1109 n = (nnodes - 1) - srtT;
1110
1111 ps = center[chd];
1112
1113 const Point4D& gab = lowerupper[chd];
1114 sumSide2 = sqr((gab[2] - gab[0] + gab[3] - gab[1]));
1115 }
1116
1117 dr = p - ps;
1118 r2 = dr[0] * dr[0] + dr[1] * dr[1];
1119 if ((isVortex && isCntrLeaf) || ((sumSide2 + sgm2Contr) * itolsq < r2)) // если выполнен критерий дальности (может быть как влияние кластера, так и одного дальнего вихря)
1120 {
1121 // Если это ячейка, берём её mm
1122 if (!isVortex)
1123 {
1124 mom = moms.data() + srtT * orderAlignment;
1125 gm = mom[0][0]; // нулевой момент = суммарная циркуляция
1126 sgm2 = 0.0;
1127 }
1128
1129 if ((calcRadius) && (isCntrLeaf))
1130 {
1131 if ((r2 < d_3) && (r2 > 0.0))
1132 {
1133 dst23 = std::fmin(r2, d_2);
1134 d_3 = std::fmax(r2, d_2);
1135
1136 dst12 = std::fmin(dst23, d_1);
1137 d_2 = std::fmax(dst23, d_1);
1138
1139 d_1 = dst12;
1140 }
1141 }
1142 const double f = gm / std::fmax(r2, sgm2);
1143
1144 if (isCntrLeaf)
1145 v += f * dr;
1146
1147 if (!isCntrLeaf)
1148 Ek[0] += f * dr; // = theta[m] * m[m]
1149
1150 // Вклад высших мм если влияет ячейка
1151 if ((order > 1) && r2 > 0.0)
1152 {
1153 Point2D cftr = (1.0 / r2) * dr;
1154 Point2D th = cftr;
1155
1156 if (isVortex)
1157 {
1158 if (!isCntrLeaf)
1159 for (int s = 1; s < order; ++s)
1160 {
1161 th = s * multz(th, cftr);
1162 Ek[s] += (s % 2 ? -1.0 : 1.0) * th * gm;
1163 }
1164 }
1165 else
1166 {
1167 for (int s = 1; s < order; ++s)
1168 {
1169 th = s * multz(th, cftr);
1170
1171 if (isCntrLeaf)
1172 {
1173 Point2D add = ifac[s + 1] * multzA(th, mom[s]);
1174 v += add;
1175 }
1176 else
1177 {
1178 for (int q = 0; q <= s; ++q)
1179 {
1180 //if (s == q)
1181 // std::cout << "E[" << q << "] += " << (q % 2 ? -1.0 : 1.0) << " * " << ifac[s - q + 1] << " * " << th << " * " << mom[s - q] << "\n";
1182 Ek[q] += ((q % 2 ? -1.0 : 1.0) * ifac[s - q + 1]) * multzA(th, mom[s - q]);
1183 }
1184
1185 if (s == order - 1)
1186 Ek[0] += ifac[s + 1] * multzA(multz(th, cftr), mom[s]);
1187 }
1188 }
1189 }
1190 }
1191 }
1192 else if (!isVortex)
1193 {
1194 // Ячейка слишком близка -> спускаемся ниже по дереву
1195 if (depth + 1 < maxDepth)
1196 {
1197 if (pd == 1)//если это была обработка левого потомка, и по нему пришлось идти вниз по дереву
1198 {
1199 posStack[depth] = 1;
1200 nodeStack[depth] = nd;
1201 ++depth;
1202 }
1203
1204 nd = n;
1205 pd = 0;
1206
1207 chBoth = child[indexSort[(nnodes - 1) - nd]];
1208 }
1209 }
1210 else if (!isCntrLeaf)
1211 {
1212 for (int pnt = cntrTree.range[k].first; pnt <= cntrTree.range[k].second; ++pnt)
1213 {
1214 Point2D dz = cntrTree.object[cntrTree.mortonCodesIdx[pnt]] - ps;
1215 double dz2 = dz.length2();
1216
1217 vParticles[pnt - cntrTree.range[k].first] += (gm / std::fmax(dz2, sgm2)) * dz;
1218
1219 if (calcRadius)
1220 {
1221 double& m_3 = epsastParticles[pnt - cntrTree.range[k].first][2];
1222 double& m_2 = epsastParticles[pnt - cntrTree.range[k].first][1];
1223 double& m_1 = epsastParticles[pnt - cntrTree.range[k].first][0];
1224
1225 if ((dz2 < m_3) && (dz2 > 0.0))
1226 {
1227 dst23 = std::fmin(dz2, m_2);
1228 m_3 = std::fmax(dz2, m_2);
1229
1230 dst12 = std::fmin(dst23, m_1);
1231 m_2 = std::fmax(dst23, m_1);
1232
1233 m_1 = dst12;
1234 }
1235 }
1236 }
1237 } // БС
1238 }//while pd
1239
1240 // Оба потомка обработаны -> снимаем узел со стека
1241 --depth;
1242 }//while depth
1243
1244
1245 if (isCntrLeaf)
1246 {
1247 vel[indexOfPoint] = IDPI * v.kcross();
1248 if (calcRadius)
1249 epsast[indexOfPoint] = 1.0 * sqrt((d_1 + d_2 + d_3) / 3.0);
1250 }
1251 else
1252 {
1253 for (int pnt = cntrTree.range[k].first; pnt <= cntrTree.range[k].second; ++pnt)
1254 {
1255 Point2D dz = cntrTree.object[cntrTree.mortonCodesIdx[pnt]] - p;
1256 Point2D dzPow = dz;
1257 v = Ek[0] + vParticles[pnt - cntrTree.range[k].first];
1258 for (int q = 1; q < order; ++q)
1259 {
1260 v += ifac[q + 1] * multzA(Ek[q], dzPow);
1261 dzPow = multz(dzPow, dz);
1262 }
1263 vel[cntrTree.mortonCodesIdx[pnt]] = IDPI * v.kcross();
1264
1265 if (calcRadius)
1266 {
1267 const auto& es = epsastParticles[pnt - cntrTree.range[k].first];
1268 epsast[cntrTree.mortonCodesIdx[pnt]] = 1.0 * sqrt((es[0] + es[1] + es[2]) / 3.0);
1269 }
1270 }
1271 }
1272 }//for k
1273 }
1274 }//pragma omp parallel
1275
1276 float t2 = (float)omp_get_wtime();
1277 return (t2 - t1);
1278 }//DownwardTraversalVorticesToPoints(...)
std::vector< double > sigma
auto length2() const -> typename std::remove_const< typename std::remove_reference< decltype(this->data[0])>::type >::type
Вычисление квадрата нормы (длины) вектора
Definition numvector.h:386
numvector< T, n > & toZero(P val=0)
Установка всех компонент вектора в константу (по умолчанию — нуль)
Definition numvector.h:528
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RadixSortInternalCells()

void VM2D::CpuTreeInfo::RadixSortInternalCells ( )

Definition at line 335 of file cpuTreeInfo.cpp.

336 {
337 int nObject = (int)object.size();
338 int n = nObject - 1;
339
340 if (n == 0)
341 return;
342
343
344 std::memcpy(levelSort.data(), levelUnsort.data(), levelUnsort.size() * sizeof(unsigned));
345 std::memcpy(indexSort.data(), indexUnsort.data(), levelUnsort.size() * sizeof(int));
346
347 levelSorter.sort((int*)levelSort.data(), indexSort.data(), 0, levelUnsort.size());
348
349 /*
350 std::vector<std::pair<unsigned, int>> pr(levelUnsort.size());
351 for (size_t q = 0; q < levelUnsort.size(); ++q)
352 pr[q] = { levelUnsort[q], indexUnsort[q] };
353 std::sort(pr.begin(), pr.end(), [](auto ka, auto kb) {return ka.first < kb.first;});
354
355 for (size_t q = 0; q < levelUnsort.size(); ++q)
356 {
357 levelSort[q] = pr[q].first;
358 indexSort[q] = pr[q].second;
359 }
360 */
361
362 for (int k = 0; k < n; ++k)
363 indexSortT[indexSort[k]] = k;
364
365 }//RadixSortInternalCells()
OptimizedRadixSorter< int > levelSorter
std::vector< int > levelSort
void sort(int *keys, ValueType *values, size_t n)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ RadixSortMortonCodes()

void VM2D::CpuTreeInfo::RadixSortMortonCodes ( )

Definition at line 309 of file cpuTreeInfo.cpp.

310 {
311 int nObject = (int)object.size();
312 if (nObject <= 0)
313 return;
314
315 std::memcpy(mortonCodesKey.data(), mortonCodesKeyUnsort.data(), mortonCodesKeyUnsort.size() * sizeof(unsigned));
316 std::memcpy(mortonCodesIdx.data(), mortonCodesIdxUnsort.data(), mortonCodesIdxUnsort.size() * sizeof(int));
317
318 codesSorter.sort((int*)mortonCodesKey.data(), mortonCodesIdx.data(), 0, mortonCodesKeyUnsort.size());
319
320 /*
321 std::vector<std::pair<unsigned, int>> pr(mortonCodesKeyUnsort.size());
322 for (size_t q = 0; q < mortonCodesKeyUnsort.size(); ++q)
323 pr[q] = { mortonCodesKeyUnsort[q], mortonCodesIdxUnsort[q] };
324 std::sort(pr.begin(), pr.end(), [](auto ka, auto kb) {return ka.first < kb.first;});
325
326 for (size_t q = 0; q < mortonCodesKeyUnsort.size(); ++q)
327 {
328 mortonCodesKey[q] = pr[q].first;
329 mortonCodesIdx[q] = pr[q].second;
330 }
331 */
332
333 }//RadixSortMortonCodes()
OptimizedRadixSorter< int > codesSorter
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Update()

float VM2D::CpuTreeInfo::Update ( const std::vector< Vortex2D > &  vtx,
int  cntrLev = 0 
)

Definition at line 164 of file cpuTreeInfo.cpp.

165 {
166 VMlib::vmTimer timer;
167 timer.reset();
168
169 timer.start();
170 int nObject = (int)vtx.size();
171
172 if (cntrLev == 0)
173 controlLevel = std::max(4, (int)(log2(nObject) - 3));
174 else
175 controlLevel = cntrLev;
176
177 indexControlCells.resize(0);
178 indexControlCells.reserve(nObject);
179
180 bool inflTree = (treeType == tree_T::vortex || treeType == tree_T::source);
181
182 object.resize(nObject);
183 //if (objectType == object_T::point4 && inflTree)
184 {
185 gamma.resize(nObject);
186 sigma.resize(nObject);
187 }
188
189 gabForLeaves.resize(nObject);
190 mortonCodesKeyUnsort.resize(nObject);
191 mortonCodesIdxUnsort.resize(nObject);
192 mortonCodesKey.resize(nObject);
193 mortonCodesIdx.resize(nObject);
194
195 levelUnsort.resize(nObject - 1);
196 levelSort.resize(nObject - 1);
197 indexUnsort.resize(nObject - 1);
198 indexSort.resize(nObject - 1);
199 indexSortT.resize(nObject - 1);
200 range.resize(2 * nObject);
201 parent.resize(2 * nObject);
202 child.resize(nObject - 1);
203 lowerupper.resize(nObject - 1);
204 center.resize(nObject - 1);
205
206 if (inflTree)
207 {
208 moms.resize((nObject - 1) * orderAlignment);
209 mass.resize(nObject - 1);
210 }
211
212
213 for (int v = 0; v < nObject; ++v)
214 {
215 Point2D r = vtx[v].r();
216 object[v] = r;
217 if (objectType == object_T::point4 /* && inflTree*/) //влияющее дерево вихрей
218 {
219 //if (inflTree)
220 {
221 gamma[v] = vtx[v].g();
222 sigma[v] = vtx[v].sigma();
223 }
224 gabForLeaves[v] = Point4D({ r[0] - sigma[v], r[1] - sigma[v], r[0] + sigma[v], r[1] + sigma[v] });
225 }
226 else
227 gabForLeaves[v] = Point4D({ r[0] - 0.0, r[1] - 0.0, r[0] + 0.0, r[1] + 0.0 });
228 }
229
230 timer.stop();
231 return (float)timer.duration();
232 }
const vmTimer & reset() const
Сброс счетчика времени
Definition TimesGen.h:101
Here is the call graph for this function:
Here is the caller graph for this function:

◆ UpdatePanelGeometry()

float VM2D::CpuTreeInfo::UpdatePanelGeometry ( const std::vector< std::pair< Point2D, Point2D > > &  panels,
int  cntrLev 
)

Definition at line 236 of file cpuTreeInfo.cpp.

237 {
238 VMlib::vmTimer timer;
239 timer.reset();
240
241 timer.start();
242
243 int nObject = (int)panels.size();
244
245 if (cntrLev == 0)
246 controlLevel = std::max(4, (int)(log2(nObject) - 3));
247 else
248 controlLevel = cntrLev;
249
250 indexControlCells.resize(0);
251 indexControlCells.reserve(nObject);
252
253 object.resize(nObject);
254
256 {
257 gamma.resize(nObject);
258 sigma.resize(nObject);
259 }
260
261 gabForLeaves.resize(nObject);
262 mortonCodesKeyUnsort.resize(nObject);
263 mortonCodesIdxUnsort.resize(nObject);
264 mortonCodesKey.resize(nObject);
265 mortonCodesIdx.resize(nObject);
266
267 levelUnsort.resize(nObject - 1);
268 levelSort.resize(nObject - 1);
269 indexUnsort.resize(nObject - 1);
270 indexSort.resize(nObject - 1);
271 indexSortT.resize(nObject - 1);
272 range.resize(2 * nObject);
273 parent.resize(2 * nObject);
274 child.resize(nObject - 1);
275 lowerupper.resize(nObject - 1);
276 center.resize(nObject - 1);
277
278 mass.resize(nObject - 1);
279
280 if (treeType != tree_T::contr)
281 {
282 moms.resize((nObject - 1) * orderAlignment);
283 }
284
285 for (int v = 0; v < nObject; ++v)
286 {
287 Point2D r = 0.5 * (panels[v].first + panels[v].second);
288 object[v] = r;
289
291 {
292 // gamma[v] = vtx[v].g();
293 // sigma[v] = vtx[v].sigma();
294 }
295
296
297
298 gabForLeaves[v] = Point4D({ panels[v].first[0], panels[v].first[1], panels[v].second[0], panels[v].second[1] });
299 }
300
301 timer.stop();
302 return (float)timer.duration();
303 }
Here is the call graph for this function:

◆ UpwardTraversal()

float VM2D::CpuTreeInfo::UpwardTraversal ( int  order)

Definition at line 613 of file cpuTreeInfo.cpp.

614 {
615 VMlib::vmTimer timer;
616 timer.start();
617
618 if (object.size() > 0)
619 {
620 mass.assign(object.size() - 1, -1);
621
623 {
624#include <SummChoice.h>
625 }
626 else
627 CalcAABB();
628 }
629 timer.stop();
630
631 return (float)timer.duration();
632 }//UpwardTraversal(...)
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ center

std::vector<Point2D> VM2D::CpuTreeInfo::center

Definition at line 130 of file cpuTreeInfo.h.

◆ child

std::vector<std::pair<int, int> > VM2D::CpuTreeInfo::child

Definition at line 135 of file cpuTreeInfo.h.

◆ codesSorter

OptimizedRadixSorter<int> VM2D::CpuTreeInfo::codesSorter

Definition at line 140 of file cpuTreeInfo.h.

◆ controlLevel

int VM2D::CpuTreeInfo::controlLevel

Definition at line 98 of file cpuTreeInfo.h.

◆ ED

std::vector<Point2D> VM2D::CpuTreeInfo::ED

Definition at line 112 of file cpuTreeInfo.h.

◆ gabForLeaves

std::vector<Point4D> VM2D::CpuTreeInfo::gabForLeaves

Definition at line 132 of file cpuTreeInfo.h.

◆ gamma

std::vector<double> VM2D::CpuTreeInfo::gamma

Definition at line 101 of file cpuTreeInfo.h.

◆ indexControlCells

std::vector<int> VM2D::CpuTreeInfo::indexControlCells

Definition at line 128 of file cpuTreeInfo.h.

◆ indexSort

std::vector<int> VM2D::CpuTreeInfo::indexSort

Definition at line 125 of file cpuTreeInfo.h.

◆ indexSortT

std::vector<int> VM2D::CpuTreeInfo::indexSortT

Definition at line 126 of file cpuTreeInfo.h.

◆ indexUnsort

std::vector<int> VM2D::CpuTreeInfo::indexUnsort

Definition at line 124 of file cpuTreeInfo.h.

◆ levelSort

std::vector<int> VM2D::CpuTreeInfo::levelSort

Definition at line 122 of file cpuTreeInfo.h.

◆ levelSorter

OptimizedRadixSorter<int> VM2D::CpuTreeInfo::levelSorter

Definition at line 141 of file cpuTreeInfo.h.

◆ levelUnsort

std::vector<int> VM2D::CpuTreeInfo::levelUnsort

Definition at line 121 of file cpuTreeInfo.h.

◆ lowerupper

std::vector<Point4D> VM2D::CpuTreeInfo::lowerupper

Definition at line 131 of file cpuTreeInfo.h.

◆ mass

std::vector<int> VM2D::CpuTreeInfo::mass

Definition at line 108 of file cpuTreeInfo.h.

◆ maxr

Point2D VM2D::CpuTreeInfo::maxr

Definition at line 110 of file cpuTreeInfo.h.

◆ minr

Point2D VM2D::CpuTreeInfo::minr

Definition at line 110 of file cpuTreeInfo.h.

◆ moms

std::vector<Point2D> VM2D::CpuTreeInfo::moms

Definition at line 111 of file cpuTreeInfo.h.

◆ mortonCodesIdx

std::vector<int> VM2D::CpuTreeInfo::mortonCodesIdx

Definition at line 119 of file cpuTreeInfo.h.

◆ mortonCodesIdxUnsort

std::vector<int> VM2D::CpuTreeInfo::mortonCodesIdxUnsort

Definition at line 118 of file cpuTreeInfo.h.

◆ mortonCodesKey

std::vector<unsigned int> VM2D::CpuTreeInfo::mortonCodesKey

Definition at line 116 of file cpuTreeInfo.h.

◆ mortonCodesKeyUnsort

std::vector<unsigned int> VM2D::CpuTreeInfo::mortonCodesKeyUnsort

Definition at line 115 of file cpuTreeInfo.h.

◆ object

std::vector<Point2D> VM2D::CpuTreeInfo::object

Definition at line 100 of file cpuTreeInfo.h.

◆ objectType

object_T VM2D::CpuTreeInfo::objectType

Definition at line 105 of file cpuTreeInfo.h.

◆ parent

std::vector<int> VM2D::CpuTreeInfo::parent

Definition at line 134 of file cpuTreeInfo.h.

◆ range

std::vector<std::pair<int, int> > VM2D::CpuTreeInfo::range

Definition at line 136 of file cpuTreeInfo.h.

◆ schemeType

scheme_T VM2D::CpuTreeInfo::schemeType

Definition at line 106 of file cpuTreeInfo.h.

◆ sigma

std::vector<double> VM2D::CpuTreeInfo::sigma

Definition at line 102 of file cpuTreeInfo.h.

◆ treeType

tree_T VM2D::CpuTreeInfo::treeType

Definition at line 104 of file cpuTreeInfo.h.


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