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

Класс, опеделяющий вихревой след (пелену) More...

#include <Wake2D.h>

Inheritance diagram for VM2D::Wake:
Collaboration diagram for VM2D::Wake:

Public Member Functions

 Wake (const World2D &W_)
 Конструктор инициализации
 
 ~Wake ()
 Деструктор
 
void Inside (const std::vector< Point2D > &newPos, Airfoil &afl, bool isMoves, const AirfoilGeometry &oldAfl)
 Проверка пересечения вихрями следа профиля при перемещении
 
void Restruct ()
 Реструктуризация вихревого следа
 
int RemoveFar ()
 Зануление далеко улетевших вихрей
 
size_t RemoveZero ()
 Исключение нулевых и мелких вихрей
 
bool MoveInside (const Point2D &newPos, const Point2D &oldPos, const Airfoil &afl, size_t &panThrough) const
 Проверка проникновения точки через границу профиля
 
bool MoveInsideMovingBoundary (const Point2D &newPos, const Point2D &oldPos, const AirfoilGeometry &oldAfl, const Airfoil &afl, size_t &panThrough) const
 Проверка проникновения точки через границу профиля
 
void GetPairs (int type)
 Поиск ближайшего соседа
 
void GetPairsBS (int type)
 
void GetPairsClosestNeib (int type)
 
void GetPairsBH (int type)
 
int Collaps (int type, int times)
 Коллапс вихрей
 
int CollapsNew (int type, int times)
 
int CollapsNewFast (int type, int times, std::vector< Vortex2D > &ri, std::vector< Vortex2D > &rj, std::vector< Point2D > &rnew, std::vector< std::pair< int, int > > &rindex)
 
void ReadFromFile (const std::string &dir, const std::string &fileName)
 Считывание вихревого следа из файла
 
void SaveKadrVtk (const std::string &filePrefix="Kadr") const
 Сохранение вихревого следа в файл .vtk.
 

Public Attributes

double collapseRightBorderParameter
 абсцисса, правее которой происходит линейный (вправо) рост радиуса коллапса
 
double collapseScaleParameter
 характерный масштаб, на котором происходит рост радиуса коллапса
 
const World2DW
 Константная ссылка на решаемую задачу
 
std::vector< Vortex2D > vtx
 Список вихревых элементов
 

Private Attributes

std::vector< int > neighb
 Вектор потенциальных соседей для будущего коллапса
 
std::vector< int > neighbNew
 

Detailed Description

Класс, опеделяющий вихревой след (пелену)

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

Definition at line 62 of file Wake2D.h.

Constructor & Destructor Documentation

◆ Wake()

VM2D::Wake::Wake ( const World2D W_)
inline

Конструктор инициализации

Parameters
[in]W_константная ссылка на решаемую задачу

Definition at line 76 of file Wake2D.h.

77 : WakeDataBase(W_)
78 {
81 };
WakeDataBase(const World2D &W_)
Конструктор инициализации
double collapseRightBorderParameter
абсцисса, правее которой происходит линейный (вправо) рост радиуса коллапса
Definition Wake2D.h:161
double collapseScaleParameter
характерный масштаб, на котором происходит рост радиуса коллапса
Definition Wake2D.h:164

◆ ~Wake()

VM2D::Wake::~Wake ( )
inline

Деструктор

Definition at line 84 of file Wake2D.h.

84{ };

Member Function Documentation

◆ Collaps()

int Wake::Collaps ( int  type,
int  times 
)

Коллапс вихрей

Parameters
[in]typeтип коллапса:
  • 0 — без приоритета знаков
  • 1 — коллапсировать только вихри разных знаков
  • 2 — коллапсировать только вихри одного знака
[in]timesчисло проходов алгоритма коллапса
Returns
число зануленных вихрей

Definition at line 476 of file Wake2D.cpp.

477{
478 int nHlop = 0; //общее число убитых вихрей
479
480 //int loc_hlop = 0; //
481
482 std::vector<bool> flag; //как только вихрь сколлапсировался flag = 1
483 for (int z = 0; z < times; ++z)
484 {
485
486#if (defined(__CUDACC__) || defined(USE_CUDA)) && (defined(CU_PAIRS))
489 //if (W.getPassport().numericalSchemes.velocityComputation.second == 0)
490 {
491 const_cast<Gpu&>(W.getCuda()).RefreshWake(3);
492
493 double NeibStart = omp_get_wtime();
494 GPUGetPairs(type);
495 double NeibFinish = omp_get_wtime();
496 std::cout << "GPU_direct_closest_neib = " << NeibFinish - NeibStart << std::endl;
497 }
499
500 //else
501 //{
502 // double NeibStart = omp_get_wtime();
503 // GetPairs(type);
504 // //GetPairsClosestNeib(type);
505 // double NeibFinish = omp_get_wtime();
506 // std::cout << "CPU_direct_closest_neib = " << NeibFinish - NeibStart << std::endl;
507 //}
508#else
509 GetPairs(type);
510#endif
511
512
513 //std::ofstream neibFile(W.getPassport().dir + "neib" + std::to_string(W.currentStep));
514 //for (size_t q = 0; q < neighb.size(); ++q)
515 // neibFile << q << " " << neighb[q] << std::endl;
516 //neibFile.close();
517
518
519 //loc_hlop = 0;//число схлопнутых вихрей
520//*
521 flag.clear();
522 flag.resize(vtx.size(), false);
523
524 double sumAbsGam, iws;
525 Point2D newPos;
526
527 for (size_t vt = 0; vt + 1 < vtx.size(); ++vt)
528 {
529 Vortex2D& vtxI = vtx[vt];
530
531 if (!flag[vt])
532 {
533 int ssd = neighb[vt];
534
535 if ((ssd < 0) || (ssd >= flag.size()))
536 std::cout << "ssd = " << ssd << ", flag.size() = " << flag.size() << ", vtx.size() = " << vtx.size() << std::endl;
537
538 if ((ssd != 0) && (!flag[ssd]))
539 {
540 Vortex2D& vtxK = vtx[ssd];
541
542 flag[ssd] = true;
543
544 Vortex2D sumVtx;
545 sumVtx.g() = vtxI.g() + vtxK.g();
546 sumVtx.sigma() = std::max(vtxI.sigma(), vtxK.sigma());
547
548 switch (type)
549 {
550 case 0:
551 case 2:
552 sumAbsGam = fabs(vtxI.g()) + fabs(vtxK.g());
553
554 iws = sumAbsGam > 1e-10 ? 1.0 / sumAbsGam : 1.0;
555
556 sumVtx.r() = (vtxI.r() * fabs(vtxI.g()) + vtxK.r() * fabs(vtxK.g())) * iws;
557 break;
558
559 case 1:
560 sumVtx.r() = (fabs(vtxI.g()) > fabs(vtxK.g())) ? vtxI.r() : vtxK.r();
561 break;
562 }
563
564 bool fl_hit = true;
565 //double Ch1[2];
566 size_t hitpan = -1;
567
568 for (size_t afl = 0; afl < W.getNumberOfAirfoil(); ++afl)
569 {
570 //проверим, не оказался ли новый вихрь внутри контура
571 if (MoveInside(sumVtx.r(), vtxI.r(), W.getAirfoil(afl), hitpan) || MoveInside(sumVtx.r(), vtxK.r(), W.getAirfoil(afl), hitpan))
572 fl_hit = false;
573 }//for
574
575 if (fl_hit)
576 {
577 vtxI = sumVtx;
578 vtxK.g() = 0.0;
579 nHlop++;
580 }//if (fl_hit)
581
582 }//if ((ssd!=0)&&(!flag[ssd]))
583 }//if !flag[vt]
584 }//for vt
585//*/
586 }//for z
587
588 return nHlop;
589}//Collaps(...)
Класс, обеспечивающий возможность выполнения вычислений на GPU по технологии Nvidia CUDA.
Definition Gpu2D.h:71
std::vector< Vortex2D > vtx
Список вихревых элементов
const World2D & W
Константная ссылка на решаемую задачу
bool MoveInside(const Point2D &newPos, const Point2D &oldPos, const Airfoil &afl, size_t &panThrough) const
Проверка проникновения точки через границу профиля
Definition Wake2D.cpp:63
std::vector< int > neighb
Вектор потенциальных соседей для будущего коллапса
Definition Wake2D.h:66
void GetPairs(int type)
Поиск ближайшего соседа
Definition Wake2D.cpp:319
size_t getNumberOfAirfoil() const
Возврат количества профилей в задаче
Definition World2D.h:180
VMlib::vmTimer timerMerging
Definition World2D.h:373
const Airfoil & getAirfoil(size_t i) const
Возврат константной ссылки на объект профиля
Definition World2D.h:163
const Gpu & getCuda() const
Возврат константной ссылки на объект, связанный с видеокартой (GPU)
Definition World2D.h:273
Класс, опеделяющий двумерный вихревой элемент
Definition Vortex2D.h:59
HD double & sigma()
Функция для доступа к радиусу вихря
Definition Vortex2D.h:108
HD Point2D & r()
Функция для доступа к радиус-вектору вихря
Definition Vortex2D.h:92
HD double & g()
Функция для доступа к циркуляции вихря
Definition Vortex2D.h:100
const vmTimer & stop() const
Останов работающего счетчика времени
Definition TimesGen.h:125
const vmTimer & start() const
Запуск (первый или повторный) счетчика времени
Definition TimesGen.h:109
const vmTimer & reset() const
Сброс счетчика времени
Definition TimesGen.h:101
void vt(const Vector3d &x, const Matrix3d *T, Matrix3d &M)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CollapsNew()

int Wake::CollapsNew ( int  type,
int  times 
)

Definition at line 592 of file Wake2D.cpp.

593{
594 int nHlop = 0; //общее число убитых вихрей
595
596 const double& cSP = collapseScaleParameter;
597 const double& cRBP = collapseRightBorderParameter;
598
600
601 //int loc_hlop = 0; // neigh
602
603 std::vector<bool> flag; //как только вихрь сколлапсировался flag = 1
604
605 for (int z = 0; z < times; ++z)
606 {
607 //loc_hlop = 0;//число схлопнутых вихрей
608
609 flag.clear();
610 flag.resize(vtx.size(), false);
611
612 double sumAbsGam, iws;
613 Point2D newPos;
614
615 for (size_t vt = 0; vt + 1 < vtx.size(); ++vt)
616 {
617 Vortex2D& vtxI = vtx[vt];
618 if (!flag[vt])
619 {
620
621 for (int s = 0; s < knbForRestruct; ++s)
622 {
623 //int ssd = neighb[vt];
624 int ssd = neighbNew[vt * knbForRestruct + s];
625 if (ssd == 0)
626 continue;
627
628 Vortex2D& vtxK = vtx[ssd];
629
630 if (/*(ssd != 0) &&*/ (!flag[ssd])) //ssd==0 always true
631 {
632
633
634 Vortex2D sumVtx;
635 sumVtx.g() = vtxI.g() + vtxK.g();
636 sumVtx.sigma() = std::max(vtxI.sigma(), vtxK.sigma());
637
638 switch (type)
639 {
640 case 0:
641 case 2:
642 sumAbsGam = fabs(vtxI.g()) + fabs(vtxK.g());
643 iws = sumAbsGam > 1e-10 ? 1.0 / sumAbsGam : 1.0;
644 sumVtx.r() = (vtxI.r() * fabs(vtxI.g()) + vtxK.r() * fabs(vtxK.g())) * iws;
645 break;
646
647 case 1:
648 sumVtx.r() = (fabs(vtxI.g()) > fabs(vtxK.g())) ? vtxI.r() : vtxK.r();
649 break;
650 }
651
652 bool fl_hit = true;
653 size_t hitpan = -1;
654
655 for (size_t afl = 0; afl < W.getNumberOfAirfoil(); ++afl)
656 {
657 //проверим, не оказался ли новый вихрь внутри контура
658 if (MoveInside(sumVtx.r(), vtxI.r(), W.getAirfoil(afl), hitpan) || MoveInside(sumVtx.r(), vtxK.r(), W.getAirfoil(afl), hitpan))
659 {
660 //std::cout << "HIT" << std::endl;
661 fl_hit = false;
662 }
663 }//for
664
665 if (fl_hit)
666 {
667 vtxI = sumVtx;
668 vtxK.g() = 0.0;
669 nHlop++;
670 flag[vt] = true;
671 flag[ssd] = true;
672 }//if (fl_hit)
673
674 }//if ((ssd!=0)&&(!flag[ssd]))
675
676 if (flag[vt])
677 break;
678 }// for s
679 }//if !flag[vt]
680 }//for vt
681
682 }//for z
683
684 return nHlop;
685}//CollapsNew(...)
WakeDiscretizationProperties wakeDiscretizationProperties
Структура с параметрами дискретизации вихревого следа
Definition Passport2D.h:304
std::vector< int > neighbNew
Definition Wake2D.h:69
const Passport & getPassport() const
Возврат константной ссылки на паспорт
Definition World2D.h:263
double maxGamma
Максимально допустимая циркуляция вихря
Definition Passport2D.h:144
Here is the call graph for this function:

◆ CollapsNewFast()

int Wake::CollapsNewFast ( int  type,
int  times,
std::vector< Vortex2D > &  ri,
std::vector< Vortex2D > &  rj,
std::vector< Point2D > &  rnew,
std::vector< std::pair< int, int > > &  rindex 
)

Definition at line 688 of file Wake2D.cpp.

689{
690 int nHlop = 0; //общее число убитых вихрей
691
692 const double& cSP = collapseScaleParameter;
693 const double& cRBP = collapseRightBorderParameter;
694
696
697 //int loc_hlop = 0; // neigh
698
699 std::vector<bool> flag; //как только вихрь сколлапсировался flag = 1
700
701 for (int z = 0; z < times; ++z)
702 {
703 //loc_hlop = 0;//число схлопнутых вихрей
704
705 flag.clear();
706 flag.resize(vtx.size(), false);
707
708 double sumAbsGam, iws;
709 Point2D newPos;
710
711 for (size_t vt = 0; vt + 1 < vtx.size(); ++vt)
712 {
713 Vortex2D& vtxI = vtx[vt];
714 if (!flag[vt])
715 {
716
717 for (int s = 0; s < knbForRestruct; ++s)
718 {
719 //int ssd = neighb[vt];
720 int ssd = neighbNew[vt * knbForRestruct + s];
721 if (ssd == 0)
722 continue;
723
724 Vortex2D& vtxK = vtx[ssd];
725
726 if (/*(ssd != 0) &&*/ (!flag[ssd])) //ssd==0 always true
727 {
728
729
730 Vortex2D sumVtx;
731 sumVtx.g() = vtxI.g() + vtxK.g();
732 sumVtx.sigma() = std::max(vtxI.sigma(), vtxK.sigma());
733
734 switch (type)
735 {
736 case 0:
737 case 2:
738 sumAbsGam = fabs(vtxI.g()) + fabs(vtxK.g());
739 iws = sumAbsGam > 1e-10 ? 1.0 / sumAbsGam : 1.0;
740 sumVtx.r() = (vtxI.r() * fabs(vtxI.g()) + vtxK.r() * fabs(vtxK.g())) * iws;
741 break;
742
743 case 1:
744 sumVtx.r() = (fabs(vtxI.g()) > fabs(vtxK.g())) ? vtxI.r() : vtxK.r();
745 break;
746 }
747
748 bool fl_hit = true;
749 size_t hitpan = -1;
750
751 //for (size_t afl = 0; afl < W.getNumberOfAirfoil(); ++afl) //кол-во профилей
752 //{
753 ri.push_back(Vortex2D(vtxI.r(), vtxI.g(), vtxI.sigma()));
754 rj.push_back(Vortex2D(vtxK.r(), vtxK.g(), vtxK.sigma()));
755 rindex.push_back({ (int)vt, ssd });
756 rnew.push_back(sumVtx.r());
757 nHlop++;
758 flag[vt] = true;
759 flag[ssd] = true;
760
761 //проверим, не оказался ли новый вихрь внутри контура
762 //if (MoveInside(sumVtx.r(), vtxI.r(), W.getAirfoil(afl), hitpan) || MoveInside(sumVtx.r(), vtxK.r(), W.getAirfoil(afl), hitpan))
763 //{
764 // //std::cout << "HIT" << std::endl;
765 // fl_hit = false;
766 //}
767 //}//for
768
769 //if (fl_hit)
770 //{
771 // vtxI = sumVtx;
772 // vtxK.g() = 0.0;
773 // //nHlop++;
774 // flag[vt] = true;
775 // flag[ssd] = true;
776 //}//if (fl_hit)
777
778 }//if ((ssd!=0)&&(!flag[ssd]))
779
780 if (flag[vt])
781 break;
782 }// for s
783 }//if !flag[vt]
784 }//for vt
785
786 }//for z
787
788 return nHlop;
789}//CollapsNew(...)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetPairs()

void Wake::GetPairs ( int  type)

Поиск ближайшего соседа

Parameters
[in]typeтип коллапса:
  • 0 — без приоритета знаков
  • 1 — коллапсировать только вихри разных знаков
  • 2 — коллапсировать только вихри одного знака

Definition at line 319 of file Wake2D.cpp.

320{
321 GetPairsBS(type);
322}
void GetPairsBS(int type)
Definition Wake2D.cpp:325
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetPairsBH()

void VM2D::Wake::GetPairsBH ( int  type)

◆ GetPairsBS()

void Wake::GetPairsBS ( int  type)
Todo:
Доделать

Definition at line 325 of file Wake2D.cpp.

326{
327 neighb.resize(vtx.size(), 0);
328
329 Point2D Ri, Rk;
330
332
333#pragma omp parallel for default(none) shared(type, maxG) schedule(dynamic, DYN_SCHEDULE)
334 for (int i = 0; i < vtx.size(); ++i)
335 {
336 neighb[i] = 0;
337 int s = i;
338 const Vortex2D& vtxI = vtx[i];
339
340 bool found = false;
341
342 double r2, r2test;
343
344 const double& cSP = collapseScaleParameter;
345 const double& cRBP = collapseRightBorderParameter;
346
347 while ( (!found) && ( s + 1 < (int)vtx.size() ) )
348 {
349 s++;
350 const Vortex2D& vtxK = vtx[s];
351
352 r2 = dist2(vtxI.r(), vtxK.r());
353
354 //линейное увеличение радиуса коллапса
355 double mnog = std::max(1.0, /* 2.0 * */ (vtxI.r()[0] - cRBP) / cSP);
356
358
359 if (type == 1)
360 r2test *= 4.0; //Увеличение радиуса коллапса в 2 раза для коллапса вихрей разных знаков
361
362 if (r2 < r2test)
363 {
364 switch (type)
365 {
366 case 0:
367 found = ( vtxI.g()*vtxK.g() != 0.0) && (fabs(vtxI.g() + vtxK.g()) < sqr(mnog) * maxG);
368 break;
369 case 1:
370 found = (vtxI.g()*vtxK.g() < 0.0);
371 break;
372 case 2:
373 found = (vtxI.g()*vtxK.g() > 0.0) && (fabs(vtxI.g() + vtxK.g()) < sqr(mnog) * maxG);
374 break;
375 }
376 }//if r2 < r2_test
377 }//while
378
379 if (found)
380 neighb[i] = s;
381 }//for locI
382}//GetPairsBS(...)
T sqr(T x)
Возведение числа в квадрат
Definition defs.h:455
auto dist2(const numvector< T, n > &x, const numvector< P, n > &y) -> typename std::remove_const< decltype(x[0] - y[0])>::type
Вычисление квадрата расстояния между двумя точками
Definition numvector.h:836
double epscol
Радиус коллапса
Definition Passport2D.h:132
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetPairsClosestNeib()

void Wake::GetPairsClosestNeib ( int  type)

Definition at line 386 of file Wake2D.cpp.

387{
388 neighb.resize(vtx.size(), 0);
389
390 Point2D Ri, Rk;
391
393
394#pragma omp parallel for default(none) shared(type, maxG) schedule(dynamic, DYN_SCHEDULE)
395 for (int i = 0; i < vtx.size(); ++i)
396 {
397 neighb[i] = 0;
398 int s = i;
399 const Vortex2D& vtxI = vtx[i];
400
401 bool found = false;
402
403 double r2, r2test = 1e+10;
404
405 const double& cSP = collapseScaleParameter;
406 const double& cRBP = collapseRightBorderParameter;
407
408 while (/*(!found) &&*/ (s + 1 < (int)vtx.size()))
409 {
410 s++;
411 const Vortex2D& vtxK = vtx[s];
412
413 r2 = dist2(vtxI.r(), vtxK.r());
414
415 if (r2 < r2test)
416 {
417 r2test = r2;
418 neighb[i] = s;
419 }//if r2 < r2_test
420 }//while
421
422 }//for locI
423}//GetPairsClosestNeib(...)
Here is the call graph for this function:

◆ Inside()

void Wake::Inside ( const std::vector< Point2D > &  newPos,
Airfoil afl,
bool  isMoves,
const AirfoilGeometry oldAfl 
)

Проверка пересечения вихрями следа профиля при перемещении

Исполняется сразу для всех вихрей в пелене, осуществляет проверку для отдельного профиля
Вихри, попавшие внутрь профиля, получают нулевую циркуляцию, а их "бывшая" циркуляция передается в вектор gammaThrough в структуру данных профиля

Parameters
[in]newPosконстантная ссылка на вектор из новых положений вихрей в вихревом следе
[in]isMovesпризнак того, что профиль подвижный
[in]oldAflконстантная ссылка контролируемый профиль до перемещения (используется, если у профиля стоит признак того, что он движется)
[in,out]aflссылка на контролируемый профиль (происходит изменение afl->gammaThrough)

Definition at line 274 of file Wake2D.cpp.

275{
276 std::vector<double> gamma;
277 gamma.resize(afl.getNumberOfPanels(), 0.0);
278
279 std::vector<int> through;
280 through.resize(vtx.size(), -1);
281
282//#pragma omp parallel for default(none) shared(afl, oldAfl, isMoves, through, newPos)
283 for (int i = 0; i < (int)vtx.size(); ++i)
284 {
285 size_t minN;
286
287 bool crit = isMoves ? MoveInsideMovingBoundary(newPos[i], vtx[i].r(), oldAfl, afl, minN) : MoveInside(newPos[i], vtx[i].r(), afl, minN);
288
289 if (crit)
290 through[i] = (int)minN;
291 }//for i
292
293
294 //std::stringstream sss;
295 //sss << "through_" << W.currentStep;
296 //std::ofstream of(W.getPassport().dir + "dbg/" + sss.str());
297 //for (size_t i = 0; i < gamma.size(); ++i)
298 // of << gamma[i] << std::endl;
299 //of.close();
300
301 //std::stringstream sss;
302 //sss << "through_" << W.currentStep;
303 //std::ofstream of(W.getPassport().dir + "dbg/" + sss.str());
304 //for (size_t i = 0; i < gamma.size(); ++i)
305 // of << through[i] << std::endl;
306 //of.close();
307
308 for (size_t q = 0; q < through.size(); ++q)
309 if (through[q] > -1)
310 {
311 gamma[through[q]] += vtx[q].g();
312 vtx[q].g() = 0.0;
313 }
314
315 afl.gammaThrough = gamma;
316}//Inside(...)
size_t getNumberOfPanels() const
Возврат количества панелей на профиле
Definition Airfoil2D.h:163
std::vector< double > gammaThrough
Суммарные циркуляции вихрей, пересекших панели профиля на прошлом шаге
Definition Airfoil2D.h:276
bool MoveInsideMovingBoundary(const Point2D &newPos, const Point2D &oldPos, const AirfoilGeometry &oldAfl, const Airfoil &afl, size_t &panThrough) const
Проверка проникновения точки через границу профиля
Definition Wake2D.cpp:179
Here is the call graph for this function:

◆ MoveInside()

bool Wake::MoveInside ( const Point2D newPos,
const Point2D oldPos,
const Airfoil afl,
size_t &  panThrough 
) const

Проверка проникновения точки через границу профиля

Parameters
[in]newPosконстантная ссылка на смещенное (новое) положение
[in]oldPosконстантная ссылка на несмещенное (старое) положение
[in]aflконстантная ссылка на контролируемый профиль
[out]panThroughномер "протыкаемой" панели return признак пересечения профиля

Definition at line 63 of file Wake2D.cpp.

64{
65 //const double porog_r = 1e-12;
66
67 //double minDist = 1.0E+10; //расстояние до пробиваемой панели
68 panThrough = -1;
69
70 //проверка габ. прямоугольника
71
72 if (afl.isOutsideGabarits(newPos) && afl.isOutsideGabarits(oldPos))
73 {
74 ++W.gabb;
75 return false;
76 }
77
78 //если внутри габ. прямоугольника - проводим контроль
79 bool hit = false;
80
81
82 for (size_t j = 0; j < afl.getNumberOfPanels(); ++j)
83 {
84 const Point2D& aflRj = afl.getR(j);
85 const Point2D& aflRj1 = afl.getR(j + 1);
86
87 ++W.checkPan;
88
89 if ((((aflRj - oldPos) ^ (newPos - oldPos)) * ((aflRj1 - oldPos) ^ (newPos - oldPos)) <= 0) && \
90 (((oldPos - aflRj) ^ (aflRj1 - aflRj)) * ((newPos - aflRj) ^ (aflRj1 - aflRj)) <= 0))
91 {
92 hit = true;
93 panThrough = j;
94 break;
95 }
96 }//for j
97
98
99
100 if (hit)
101 ++W.check01;
102 else
103 ++W.check02;
104
105 return hit;
106}//MoveInside(...)
const Point2D & getR(size_t q) const
Возврат константной ссылки на вершину профиля
Definition Airfoil2D.h:113
bool isOutsideGabarits(const Point2D &r) const
Определяет, находится ли точка с радиус-вектором вне габаритного прямоугольника профиля
Definition Airfoil2D.cpp:90
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MoveInsideMovingBoundary()

bool Wake::MoveInsideMovingBoundary ( const Point2D newPos,
const Point2D oldPos,
const AirfoilGeometry oldAfl,
const Airfoil afl,
size_t &  panThrough 
) const

Проверка проникновения точки через границу профиля

Parameters
[in]newPosконстантная ссылка на смещенное (новое) положение вихря
[in]oldPosконстантная ссылка на несмещенное (старое) положение вихря
[in]oldAflконстантная ссылка на состояние контролируемого профиля до перемещения
[in]aflконстантная ссылка на контролируемый профиль
[out]panThroughномер "протыкаемой" панели return признак пересечения профиля
Todo:
сравнить производительности двух inside-ов

Definition at line 179 of file Wake2D.cpp.

180{
181 panThrough = -1;
182
184
185 //проверка габ. прямоугольника
186 if (!afl.inverse && afl.isOutsideGabarits(newPos) && afl.isOutsideGabarits(oldPos))
187 return false;
188
189 bool hit = false;
190
191 double angle = 0;
192 double cs, sn;
193
194 double dist2 = 1000000000.0;
195
196 for (size_t i = 0; i < afl.getNumberOfPanels(); ++i)
197 {
198 Point2D v1, v2, vv;
199 v1 = afl.getR(i) - newPos;
200
201 v2 = afl.getR(i + 1) - newPos;
202
203 vv = afl.getR(i + 1) - afl.getR(i);
204
205 double dst = v1.length2() + v2.length2();
206 if (dst < dist2)
207 {
208 dist2 = dst;
209 panThrough = i;
210 }
211
212 cs = v1 & v2;
213 sn = v1 ^ v2;
214
215 angle += atan2(sn, cs);
216 }//for i
217
218 hit = ((angle > 3.14) || (angle < -3.14));
219
220 if (afl.inverse)
221 hit = !hit;
222
223 return hit;
224}//MoveInsideMovingBoundary(...)
bool inverse
Признак разворота нормалей (для расчета внутренних течений)
Definition Airfoil2D.h:76
auto length2() const -> typename std::remove_const< typename std::remove_reference< decltype(this->data[0])>::type >::type
Вычисление квадрата нормы (длины) вектора
Definition numvector.h:386
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadFromFile()

void WakeDataBase::ReadFromFile ( const std::string &  dir,
const std::string &  fileName 
)
inherited

Считывание вихревого следа из файла

Parameters
[in]dirконстантная ссылка на строку, задающую каталог, где лежит файл с вихревым следом
[in]fileNameконстантная ссылка на строку, задающую имя файла с вихревым следом

Definition at line 56 of file WakeDataBase2D.cpp.

57{
58 std::string filename = dir + fileName;
59 std::ifstream wakeFile, testFile;
60
61 char firstChar = '/', secondChar = '*';
62
63 if (fileExistTest(filename, W.getInfo(), true, { "txt", "TXT" }))
64 {
65 testFile.open(filename);
66 testFile >> firstChar;
67 testFile >> secondChar;
68
69 //std::cout << "CHARS: " << firstChar << " " << secondChar << std::endl;
70 testFile.close();
71 }
72
73
74 //Считывание из словаря
75 if (firstChar == '/' && secondChar == '*')
76 {
77 if (fileExistTest(filename, W.getInfo(), true, { "txt", "TXT" }))
78 {
79 std::stringstream wakeFile(VMlib::Preprocessor(filename).resultString);
80
82 VMlib::StreamParser wakeParser(XXX, "vortex wake file parser", wakeFile);
83
84 wakeParser.get("vtx", vtx);
85
86 for (auto& v : vtx)
87 v.sigma() = W.getPassport().wakeDiscretizationProperties.sigma0;
88
89 }
90 }
91 else
92 {
93 //Считывание из обычного текстового файла
94 if (fileExistTest(filename, W.getInfo(), true, { "txt", "TXT" }))
95 {
96 wakeFile.open(filename);
97 int nnn;
98 wakeFile >> nnn;
99 vtx.reserve(nnn);
100 for (int i = 0; i < nnn; ++i)
101 {
102 Vortex2D v;
103 wakeFile >> v.r()[0] >> v.r()[1] >> v.g();
105 vtx.push_back(v);
106 }
107
108 wakeFile.close();
109 }
110 }
111
112}//ReadFromFile(...)
Класс, определяющий работу с потоком логов
Definition LogStream.h:57
Класс, позволяющий выполнять предварительную обработку файлов
Класс, позволяющий выполнять разбор файлов и строк с настройками и параметрами
VMlib::LogStream & getInfo() const
Возврат ссылки на объект LogStream Используется в техничеcких целях для организации вывода
Definition WorldGen.h:82
bool fileExistTest(std::string &fileName, LogStream &info, bool exitKey=false, const std::list< std::string > &extList={})
Проверка существования файла
Definition defs.h:340
double sigma0
Радиус вихря
Definition Passport2D.h:126
Here is the call graph for this function:

◆ RemoveFar()

int Wake::RemoveFar ( )

Зануление далеко улетевших вихрей

Returns
число вихрей в дальнем следе, которые занулены
Todo:
Пока профиль 1, расстояние от его центра; сделать от самого правого профиля

Definition at line 793 of file Wake2D.cpp.

794{
795 int nFar = 0;
798 Point2D zerovec = { 0.0, 0.0 };
799#pragma omp parallel for default(none) shared(distFar2, zerovec) reduction(+:nFar)
800 for (int i = 0; i <static_cast<int>(vtx.size()); ++i)
801 {
802 if (dist2(vtx[i].r(), zerovec) > distFar2)
803 {
804 vtx[i].g() = 0.0;
805 nFar++;
806 }
807 }
808
809 return nFar;
810}//RemoveFar()
double distFar
Расстояние от центра самого подветренного (правого) профиля, на котором вихри уничтожаются
Definition Passport2D.h:135
Here is the call graph for this function:

◆ RemoveZero()

size_t Wake::RemoveZero ( )

Исключение нулевых и мелких вихрей

Returns
число исключенных вихрей

Definition at line 813 of file Wake2D.cpp.

814{
815 const double porog_g = 1e-15;
816
817 std::vector<Vortex2D/*, VM2D::MyAlloc<VMlib::Vortex2D>*/> newWake;
818
819 newWake.reserve(vtx.size());
820
821 for (size_t q = 0; q < vtx.size(); ++q)
822 if (fabs(vtx[q].g()) > porog_g)
823 newWake.push_back(vtx[q]);
824
825 size_t delta = vtx.size() - newWake.size();
826
827 newWake.swap(vtx);
828
829 return delta;
830}//RemoveZero()

◆ Restruct()

void Wake::Restruct ( )

Реструктуризация вихревого следа

Исполняется сразу для всех вихрей в пелене
Вихри, находящиеся далеко от профилей, удаляются
Вихри, которые сильно сблизились, коллапсируются

Definition at line 836 of file Wake2D.cpp.

837{
838 W.getTimers().start("Restr");
839
841 {
842 double timePreKnn = -omp_get_wtime();
843
844 // Определение параметров, отвечающих за увеличение радиуса коллапса
845 std::vector<double> rightBorder, horizSpan;
846 rightBorder.reserve(W.getNumberOfAirfoil());
847 horizSpan.reserve(W.getNumberOfAirfoil());
848
849 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
850 {
851
852 rightBorder.emplace_back(W.getAirfoil(q).upRight[0]);
853 horizSpan.emplace_back(W.getAirfoil(q).upRight[0] - W.getAirfoil(q).lowLeft[0]);
854 }
855
856 if (W.getNumberOfAirfoil() > 0)
857 {
858 W.getNonConstWake().collapseRightBorderParameter = *std::max_element(rightBorder.begin(), rightBorder.end());
859 W.getNonConstWake().collapseScaleParameter = *std::max_element(horizSpan.begin(), horizSpan.end());
860 }
861 else
862 {
865 }
866#if defined(__CUDACC__) || defined(USE_CUDA)
868#endif
869
870 timePreKnn += omp_get_wtime();
871
872 //std::cout << "timePreKnn = " << timePreKnn * 1000 << " ms" << std::endl;
873
874
876
877
878 bool useFastCollapseAlgorithm = false;
879#if defined(__CUDACC__) || defined(USE_CUDA)
881 useFastCollapseAlgorithm = true;
882#endif
883
884 if (!useFastCollapseAlgorithm)
885 {
886 //CPU/GPU - прямой алгоритм
887 //double timeCollaps = -omp_get_wtime();
888 Collaps(0, 1);
889 //Collaps(1, 1);
890 //Collaps(2, 1);
891 //timeCollaps += omp_get_wtime();
892 //std::cout << "timeCollaps = " << timeCollaps * 1000 << " ms" << std::endl;
893 }
894 else
895 {
896 //быстрый алгоритм
897 for (int collapsStep = 0; collapsStep < 1; ++collapsStep)
898 {
899 //ttB = -omp_get_wtime();
900
901 double timeResize = -omp_get_wtime();
902 neighbNew.resize(vtx.size() * knbForRestruct);
903 timeResize += omp_get_wtime();
904
905 //std::cout << "timeResize = " << timeResize * 1000 << " ms" << std::endl;
906
907 const double& cSP = collapseScaleParameter;
908 const double& cRBP = collapseRightBorderParameter;
909 const double& maxG = W.getPassport().wakeDiscretizationProperties.maxGamma;
910 const double& epsCol = W.getPassport().wakeDiscretizationProperties.epscol;
911
912#ifndef USE_CUDA
913 //CPU
914 std::vector<std::vector<std::pair<double, size_t>>> initdist(vtx.size());
915 for (auto& d : initdist)
916 d.resize(2 * knbForRestruct, { -1.0, -1 });
917 double timeKnn = -omp_get_wtime();
918 WakekNNnewForCollaps(vtx, knbForRestruct, initdist, cSP, cRBP, maxG, epsCol, collapsStep);//CPU
919 timeKnn += omp_get_wtime();
920 //std::cout << "Time_Knn_CPU = " << timeKnn * 1000 << " ms" << std::endl;
921#else
922 double timeAlloc = -omp_get_wtime();
923 std::vector<std::pair<double, size_t>> initdistcuda(knbForRestruct * vtx.size()); //CUDA
924 timeAlloc += omp_get_wtime();
925 //std::cout << "timeAlloc = " << timeAlloc * 1000 << " ms" << std::endl;
926
927 double timeKnn = -omp_get_wtime();
928 W.getNonConstCuda().RefreshWake(5);
929
932 //Построение дерева для вихрей
933 BHcu::CudaTreeInfo knnTree(W.getCuda().blocks, tree_T::contr, object_T::point4, scheme_T::noScheme, false);
934 knnTree.MemoryAllocate((int)W.getCuda().n_CUDA_wake);
935 knnTree.Update((int)W.getWake().vtx.size(), W.getWake().devVtxPtr);
936 knnTree.Build();
937
938 Point2D minr, maxr;
939
940 cudaMemcpy(&minr, knnTree.minrD, sizeof(Point2D), cudaMemcpyDeviceToHost);
941 cudaMemcpy(&maxr, knnTree.maxrD, sizeof(Point2D), cudaMemcpyDeviceToHost);
942
943
944 kNNcuda<knbForRestruct>(minr, maxr, W.getCuda().blocks, vtx, initdistcuda, vecForKnn, cSP, cRBP, maxG, epsCol, collapsStep); //CUDA
946 timeKnn += omp_get_wtime();
947 //std::cout << "Time_Knn_GPU = " << timeKnn * 1000 << " ms" << std::endl;
948#endif
949
950 double timeCopy = -omp_get_wtime();
951#pragma omp parallel for
952 for (int i = 0; i < vtx.size(); ++i)
953 {
954#ifndef USE_CUDA
955 for (int j = 0; j < knbForRestruct; ++j)
956 neighbNew[i * knbForRestruct + j] = (int)initdist[i][j].second;
957#else
958 for (int j = 0; j < knbForRestruct; ++j)
959 neighbNew[i * knbForRestruct + j] = (int)initdistcuda[i * knbForRestruct + j].second;
960#endif
961 }
962 timeCopy += omp_get_wtime();
963 //std::cout << "timeCopy = " << timeCopy * 1000 << " ms" << std::endl;
964
965 //
966 //std::ofstream initdistFile(W.getPassport().dir + "initdist-GPU" + std::to_string(W.currentStep));
967 //for (int i = 0; i < vtx.size(); ++i)
968 //{
969 // initdistFile << i;
970 // for (int k = 0; k < knb; ++k)
971 // initdistFile << " " << neighbNew[i * (knb)+k] << " " << (vtx[i].r() - vtx[neighbNew[i * (knb)+k]].r()).length();
972 // initdistFile << std::endl;
973 //
974 // //for (int k = 0; k < knb; ++k)
975 // //initdistFile << " " << neighbNew[i * (knb)+k] << " " << vtx[neighbNew[i * (knb)+k]].g() << " " << (vtx[neighbNew[i * (knb)+k]].r() - vtx[i].r()).length() << "; ";
976 // //initdistFile << std::endl;
977 //}
978 //initdistFile.close();
979 //
980
981
982 double timeReserve = -omp_get_wtime();
983 std::vector<Vortex2D> ri, rj;
984 std::vector<Point2D> rnew;
985 std::vector<std::pair<int, int>> rindex;
986 ri.reserve(vtx.size());
987 rj.reserve(vtx.size());
988 rnew.reserve(vtx.size());
989
990 rindex.reserve(vtx.size());
991 timeReserve += omp_get_wtime();
992 //std::cout << "timeReserve = " << timeReserve * 1000 << " ms" << std::endl;
993
994
995#ifdef USE_CUDA
996 //поиск пар для объединения
997 int nHlop = CollapsNewFast(0, 1, ri, rj, rnew, rindex); //тут заполняются ri, rj, rnew, rindex
998
999 //формирование траекторий объединямых вихрей
1000 std::vector<std::pair<Point2D, Point2D>> segments(2 * ri.size());
1001 for (size_t i = 0; i < ri.size(); ++i)
1002 {
1003 segments[2 * i + 0].first = ri[i];
1004 segments[2 * i + 0].second = rnew[i];
1005
1006 segments[2 * i + 1].first = rj[i];
1007 segments[2 * i + 1].second = rnew[i];
1008 }
1009
1010 //контроль протыкания
1011 std::vector<int> hit(segments.size());
1012 if (ri.size() > 0)
1013 {
1014 double* devSegments_ptr;
1015
1016 cudaMalloc(&devSegments_ptr, segments.size() * sizeof(double) * 4);
1017 cudaMemcpy(devSegments_ptr, segments.data(), segments.size() * sizeof(double) * 4, cudaMemcpyHostToDevice);
1018
1020 auto& cntrTreeSeg = *W.getCuda().cntrTreeSegment;
1021 cntrTreeSeg.MemoryAllocate((int)W.getCuda().n_CUDA_wake);
1022 cntrTreeSeg.UpdatePanelGeometry((int)segments.size(), (double4*)devSegments_ptr);
1023 cntrTreeSeg.Build();
1024
1025 BHcu::treePanelsSegmentsIntersectionCalculationWrapper(*W.getNonConstCuda().auxTreePnl, cntrTreeSeg,
1026 W.getWake().devNearestPanelPtr);
1027
1028 W.timerInside.stop();
1029
1030 cudaMemcpy(hit.data(), W.getWake().devNearestPanelPtr, segments.size() * sizeof(int), cudaMemcpyDeviceToHost);
1031 cudaFree(devSegments_ptr);
1032 }//if ri.size() > 0
1033
1034 for (size_t i = 0; i < ri.size(); ++i)
1035 {
1036 if (hit[2 * i + 0] == -1 && hit[2 * i + 1] == -1)
1037 {
1038 vtx[rindex[i].first].r() = rnew[i];
1039 vtx[rindex[i].first].g() += vtx[rindex[i].second].g();
1040 vtx[rindex[i].first].sigma() = std::max(vtx[rindex[i].first].sigma(), vtx[rindex[i].second].sigma());
1041
1042 vtx[rindex[i].second].g() = 0.0;
1043 }
1044 }
1045
1046#else
1047 double timeCollaps;
1048 //CollapsNew(0, 1);
1049 timeCollaps = -omp_get_wtime();
1050 int nHlop = CollapsNewFast(0, 1, ri, rj, rnew, rindex);
1051
1052 timeCollaps += omp_get_wtime();
1053
1054 size_t hitA, hitB;
1055 bool ifInside;
1056#pragma omp parallel for private (hitA, hitB, ifInside)
1057 for (int i = 0; i < (int)ri.size(); ++i)
1058 {
1059 ifInside = false;
1060 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
1061 {
1062 MoveInside(rnew[i], ri[i], W.getAirfoil(q), hitA);
1063 MoveInside(rnew[i], rj[i], W.getAirfoil(q), hitB);
1064 if ((hitA != size_t(-1)) || (hitB != size_t(-1)))
1065 ifInside = true;
1066 }
1067 if (!ifInside)
1068 {
1069 vtx[rindex[i].first].r() = rnew[i];
1070 vtx[rindex[i].first].g() += vtx[rindex[i].second].g();
1071 vtx[rindex[i].first].sigma() = std::max(vtx[rindex[i].first].sigma(), vtx[rindex[i].second].sigma());
1072
1073 vtx[rindex[i].second].g() = 0.0;
1074
1075 }
1076 }
1077#endif
1078 }
1079 }
1080
1081 }
1082 double timeRemove = -omp_get_wtime();
1083 RemoveFar();
1084 RemoveZero();
1085 timeRemove += omp_get_wtime();
1086 //std::cout << "timeRemove = " << timeRemove * 1000 << std::endl;
1087
1088 W.getTimers().stop("Restr");
1089//*
1090// std::cout << "Pre-knn time = " << timePreKnn * 1000.0 << " ms" << std::endl;
1091// std::cout << "Pre-knn resize time = " << timeResize * 1000.0 << " ms" << std::endl;
1092// std::cout << "Time_Knn_GPU = " << timeKnn * 1000 << " ms" << std::endl;
1093// std::cout << "Post-knn copy time = " << timeCopy * 1000.0 << " ms" << std::endl;
1094// std::cout << "Reserve_time = " << timeReserve * 1000 << " ms" << std::endl;
1095// std::cout << "Collaps_time = " << timeCollaps * 1000 << " ms" << std::endl;
1096// std::cout << "Copy2_time = " << timeCopy2 * 1000 << " ms" << std::endl;
1097// std::cout << "Ray_time = " << timeRay * 1000 << " ms" << std::endl;
1098// std::cout << "Collaps2_time = " << timeCollaps2 * 1000 << " ms" << std::endl;
1099// std::cout << "Remove_time = " << timeRemove * 1000 << " ms" << std::endl;
1100
1101
1102//*/
1103}
Point2D upRight
Правый верхний угол габаритного прямоугольника профиля
Definition Airfoil2D.h:271
Point2D lowLeft
Левый нижний угол габаритного прямоугольника профиля
Definition Airfoil2D.h:270
void setCollapseCoeff(double pos_, double refLength_)
Установка правой границы самого правого профиля (для организации увеличения радиуса коллапса)
Definition Gpu2D.h:293
NumericalSchemes numericalSchemes
Структура с используемыми численными схемами
Definition Passport2D.h:307
int RemoveFar()
Зануление далеко улетевших вихрей
Definition Wake2D.cpp:793
size_t RemoveZero()
Исключение нулевых и мелких вихрей
Definition Wake2D.cpp:813
int Collaps(int type, int times)
Коллапс вихрей
Definition Wake2D.cpp:476
int CollapsNewFast(int type, int times, std::vector< Vortex2D > &ri, std::vector< Vortex2D > &rj, std::vector< Point2D > &rnew, std::vector< std::pair< int, int > > &rindex)
Definition Wake2D.cpp:688
const Wake & getWake() const
Возврат константной ссылки на вихревой след
Definition World2D.h:232
VMlib::vmTimer timerInside
Definition World2D.h:372
Gpu & getNonConstCuda() const
Возврат неконстантной ссылки на объект, связанный с видеокартой (GPU)
Definition World2D.h:278
VMlib::TimersGen & getTimers() const
Возврат ссылки на временную статистику выполнения шага расчета по времени
Definition World2D.h:288
Wake & getNonConstWake() const
Возврат неконстантной ссылки на вихревой след
Definition World2D.h:237
void stop(const std::string &timerLabel)
Останов счетчика
Definition TimesGen.cpp:68
void start(const std::string &timerLabel)
Запуск счетчика
Definition TimesGen.cpp:55
void WakekNNnewForCollaps(const std::vector< Vortex2D > &vtx, const size_t k, std::vector< std::vector< std::pair< double, size_t > > > &initdist, double cSP, double cRBP, double maxG, double epsCol, int type)
Definition knnCPU.cpp:308
std::pair< std::string, int > velocityComputation
Definition Passport2D.h:180
Here is the call graph for this function:

◆ SaveKadrVtk()

void WakeDataBase::SaveKadrVtk ( const std::string &  filePrefix = "Kadr") const
inherited

Сохранение вихревого следа в файл .vtk.

Definition at line 115 of file WakeDataBase2D.cpp.

116{
117 W.getTimers().start("Save");
118
120 {
121 std::ofstream outfile;
122 size_t numberNonZero = 0;
123
124 if (vtx.size() > 0)
125 numberNonZero += vtx.size();
126 else
127 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
128 numberNonZero += W.getAirfoil(q).getNumberOfPanels();
130
131 if (W.getPassport().timeDiscretizationProperties.fileTypeVtx.second == 0) //text format vtk
132 {
133 std::string fname = VMlib::fileNameStep(filePrefix, W.getPassport().timeDiscretizationProperties.nameLength, W.getCurrentStep(), "vtk");
134 outfile.open(W.getPassport().dir + "snapshots/" + fname);
135
136 outfile << "# vtk DataFile Version 2.0\n";
137 outfile << "VM2D VTK result: " << (W.getPassport().dir + "snapshots/" + fname).c_str() << " saved " << VMlib::CurrentDataTime() << '\n';
138 outfile << "ASCII\n";
139 outfile << "DATASET UNSTRUCTURED_GRID\n";
140 outfile << "POINTS " << numberNonZero << " float\n";
141
142
143 if (vtx.size() > 0)
144 for (auto& v : vtx)
145 {
146 const Point2D& r = v.r();
147 outfile << r[0] << " " << r[1] << " " << "0.0\n";
148 }//for v
149 else
150 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
151 for (size_t s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
152 {
153 const Point2D& r = W.getAirfoil(q).getR(s);
154 outfile << r[0] << " " << r[1] << " " << "0.0\n";
155 }
156
157 outfile << "CELLS " << numberNonZero << " " << 2 * numberNonZero << '\n';
158 for (size_t i = 0; i < numberNonZero; ++i)
159 outfile << "1 " << i << '\n';
160
161 outfile << "CELL_TYPES " << numberNonZero << '\n';
162 for (size_t i = 0; i < numberNonZero; ++i)
163 outfile << "1\n";
164
165 outfile << '\n';
166 outfile << "POINT_DATA " << numberNonZero << '\n';
167 outfile << "SCALARS Gamma float 1\n";
168 outfile << "LOOKUP_TABLE default\n";
169
170 if (vtx.size() > 0)
171 for (auto& v : vtx)
172 outfile << v.g() << '\n';
173 else
174 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
175 for (size_t s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
176 outfile << "0.0\n";
177
178 outfile << "SCALARS Sigma float 1\n";
179 outfile << "LOOKUP_TABLE default\n";
180
181 if (vtx.size() > 0)
182 for (auto& v : vtx)
183 outfile << v.sigma() << '\n';
184 else
185 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
186 for (size_t s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
187 outfile << "0.0\n";
188
189#ifdef TURB
190 outfile << "SCALARS nut float 1\n";
191 outfile << "LOOKUP_TABLE default\n";
192
193 if (vtx.size() > 0)
194 for (auto& v : vtx)
195 outfile << sqr(v.sigma() / 4.48) / W.getPassport().timeDiscretizationProperties.dt - W.getPassport().physicalProperties.nu << '\n';
196 else
197 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
198 for (size_t s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
199 outfile << "0.0\n";
200#endif
201
202
203 outfile.close();
204 }//if fileType = text
205 else if (W.getPassport().timeDiscretizationProperties.fileTypeVtx.second == 1) //binary format vtk
206 {
207 //Тест способа хранения чисел
208 uint16_t x = 0x0001;
209 bool littleEndian = (*((uint8_t*)&x));
210 const char eolnBIN[] = "\n";
211
212 std::string fname = VMlib::fileNameStep(filePrefix, W.getPassport().timeDiscretizationProperties.nameLength, W.getCurrentStep(), "vtk");
213 outfile.open(W.getPassport().dir + "snapshots/" + fname, std::ios::out | std::ios::binary);
214
215 outfile << "# vtk DataFile Version 3.0" << "\r\n" << "VM2D VTK result: " << (W.getPassport().dir + "snapshots/" + fname).c_str() << " saved " << VMlib::CurrentDataTime() << eolnBIN;
216 outfile << "BINARY" << eolnBIN;
217 outfile << "DATASET UNSTRUCTURED_GRID" << eolnBIN << "POINTS " << numberNonZero << " " << "float" << eolnBIN;
218
219 if (vtx.size() > 0)
220 {
221 Eigen::VectorXf rData = Eigen::VectorXf::Zero(vtx.size() * 3);
222 for (size_t i = 0; i < vtx.size(); ++i)
223 {
224 rData(3 * i) = (float)(vtx[i].r())[0];
225 rData(3 * i + 1) = (float)(vtx[i].r())[1];
226 }//for i
227
228 if (littleEndian)
229 for (int i = 0; i < vtx.size() * 3; ++i)
230 VMlib::SwapEnd(rData(i));
231 outfile.write(reinterpret_cast<char*>(rData.data()), vtx.size() * 3 * sizeof(float));
232 }
233 else
234 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
235 {
236 Eigen::VectorXf rData = Eigen::VectorXf::Zero(W.getAirfoil(q).getNumberOfPanels() * 3);
237 for (size_t s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
238 {
239 rData(3 * s) = (float)(W.getAirfoil(q).getR(s))[0];
240 rData(3 * s + 1) = (float)(W.getAirfoil(q).getR(s))[1];
241 }//for i
242
243 if (littleEndian)
244 for (int i = 0; i < W.getAirfoil(q).getNumberOfPanels() * 3; ++i)
245 VMlib::SwapEnd(rData(i));
246 outfile.write(reinterpret_cast<char*>(rData.data()), W.getAirfoil(q).getNumberOfPanels() * 3 * sizeof(float));
247 }
248
249 // CELLS
250 std::vector<int> cells(2 * numberNonZero);
251 for (size_t i = 0; i < numberNonZero; ++i)
252 {
253 cells[2 * i] = 1;
254 cells[2 * i + 1] = (int)i;
255 }
256
257 std::vector<int> cellsTypes;
258 cellsTypes.resize(numberNonZero, 1);
259
260 if (littleEndian)
261 {
262 for (int i = 0; i < numberNonZero * 2; ++i)
263 VMlib::SwapEnd(cells[i]);
264
265 for (int i = 0; i < numberNonZero; ++i)
266 VMlib::SwapEnd(cellsTypes[i]);
267 }
268
269 outfile << eolnBIN << "CELLS " << numberNonZero << " " << numberNonZero * 2 << eolnBIN;
270 outfile.write(reinterpret_cast<char*>(cells.data()), numberNonZero * 2 * sizeof(int));
271 outfile << eolnBIN << "CELL_TYPES " << numberNonZero << eolnBIN;
272 outfile.write(reinterpret_cast<char*>(cellsTypes.data()), numberNonZero * sizeof(int));
273
274 //gammas
275 outfile << eolnBIN << "POINT_DATA " << numberNonZero << eolnBIN;
276 outfile << eolnBIN << "SCALARS Gamma " << "float" << " 1" << eolnBIN;
277 outfile << "LOOKUP_TABLE default" << eolnBIN;
278
279 if (vtx.size() > 0)
280 {
281 Eigen::VectorXf pData = Eigen::VectorXf::Zero(numberNonZero);
282 for (int s = 0; s < vtx.size(); ++s)
283 pData(s) = (float)vtx[s].g();
284
285 if (littleEndian)
286 for (int i = 0; i < vtx.size(); ++i)
287 VMlib::SwapEnd(pData(i));
288 outfile.write(reinterpret_cast<char*>(pData.data()), vtx.size() * sizeof(float));
289 }
290 else
291 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
292 {
293 Eigen::VectorXf pData = Eigen::VectorXf::Zero(W.getAirfoil(q).getNumberOfPanels());
294 for (int s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
295 pData(s) = 0;
296
297 if (littleEndian)
298 for (int i = 0; i < W.getAirfoil(q).getNumberOfPanels(); ++i)
299 VMlib::SwapEnd(pData(i));
300 outfile.write(reinterpret_cast<char*>(pData.data()), W.getAirfoil(q).getNumberOfPanels() * sizeof(float));
301 }
302
303 outfile << eolnBIN;
304
305
306 //sigmas
307 outfile << eolnBIN << "SCALARS Sigma " << "float" << " 1" << eolnBIN;
308 outfile << "LOOKUP_TABLE default" << eolnBIN;
309
310 if (vtx.size() > 0)
311 {
312 Eigen::VectorXf pData = Eigen::VectorXf::Zero(numberNonZero);
313 for (int s = 0; s < vtx.size(); ++s)
314 pData(s) = (float)vtx[s].sigma();
315
316 if (littleEndian)
317 for (int i = 0; i < vtx.size(); ++i)
318 VMlib::SwapEnd(pData(i));
319 outfile.write(reinterpret_cast<char*>(pData.data()), vtx.size() * sizeof(float));
320 }
321 else
322 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
323 {
324 Eigen::VectorXf pData = Eigen::VectorXf::Zero(W.getAirfoil(q).getNumberOfPanels());
325 for (int s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
326 pData(s) = 0;
327
328 if (littleEndian)
329 for (int i = 0; i < W.getAirfoil(q).getNumberOfPanels(); ++i)
330 VMlib::SwapEnd(pData(i));
331 outfile.write(reinterpret_cast<char*>(pData.data()), W.getAirfoil(q).getNumberOfPanels() * sizeof(float));
332 }
333
334 outfile << eolnBIN;
335
336#ifdef TURB
337 //nut
338 outfile << eolnBIN << "SCALARS nut " << "float" << " 1" << eolnBIN;
339 outfile << "LOOKUP_TABLE default" << eolnBIN;
340
341 if (vtx.size() > 0)
342 {
343 Eigen::VectorXf pData = Eigen::VectorXf::Zero(numberNonZero);
344 for (int s = 0; s < vtx.size(); ++s)
345 pData(s) = (float)(sqr(vtx[s].sigma() / 4.48) / W.getPassport().timeDiscretizationProperties.dt - W.getPassport().physicalProperties.nu);;
346
347 if (littleEndian)
348 for (int i = 0; i < vtx.size(); ++i)
349 VMlib::SwapEnd(pData(i));
350 outfile.write(reinterpret_cast<char*>(pData.data()), vtx.size() * sizeof(float));
351 }
352 else
353 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
354 {
355 Eigen::VectorXf pData = Eigen::VectorXf::Zero(W.getAirfoil(q).getNumberOfPanels());
356 for (int s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
357 pData(s) = 0;
358
359 if (littleEndian)
360 for (int i = 0; i < W.getAirfoil(q).getNumberOfPanels(); ++i)
361 VMlib::SwapEnd(pData(i));
362 outfile.write(reinterpret_cast<char*>(pData.data()), W.getAirfoil(q).getNumberOfPanels() * sizeof(float));
363 }
364
365 outfile << eolnBIN;
366#endif
367
368
369 outfile.close();
370 }//if binary
371
373 {
374 std::string fname = VMlib::fileNameStep(filePrefix, W.getPassport().timeDiscretizationProperties.nameLength, W.getCurrentStep(), "csv");
375 outfile.open(W.getPassport().dir + "snapshots/" + fname);
376
377 outfile << "point,x,y,G,S";
378#ifdef TURB
379 outfile << ",nut";
380#endif
381 outfile << '\n';
382
383 int counter = 0;
384
385 if (vtx.size() > 0)
386 for (auto& v : vtx)
387 {
388 outfile << counter++ << "," << v.r()[0] << "," << v.r()[1] << "," << v.g() << "," << v.sigma();
389#ifdef TURB
390 outfile << "," << sqr(v.sigma() / 4.48) / W.getPassport().timeDiscretizationProperties.dt - W.getPassport().physicalProperties.nu;
391#endif
392 outfile << '\n';
393 }
394 else
395 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
396 for (size_t s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
397 {
398 const Point2D& r = W.getAirfoil(q).getR(s);
399 outfile << counter++ << "," << r[0] << "," << r[1] << "," << "0.0" << "," << "0.0";
400#ifdef TURB
401 outfile << "," << 0.0;
402#endif
403 outfile << '\n';
404 }
405 outfile.close();
406 }//if fileType = text
407
408 }
409
410 W.getTimers().stop("Save");
411}//SaveKadrVtk()
PhysicalProperties physicalProperties
Структура с физическими свойствами задачи
Definition Passport2D.h:301
bool ifDivisible(int val) const
Definition World2D.h:290
TimeDiscretizationProperties timeDiscretizationProperties
Структура с параметрами процесса интегрирования по времени
std::string dir
Рабочий каталог задачи
size_t getCurrentStep() const
Возврат константной ссылки на параметры распараллеливания по MPI.
Definition WorldGen.h:99
void CreateUserDirectory(const std::string &dir, const std::string &name)
Создание каталога
Definition defs.h:439
std::string fileNameStep(const std::string &name, int length, size_t number, const std::string &ext)
Формирование имени файла
Definition defs.h:379
std::string CurrentDataTime()
Формирование строки с текущем временем и датой
Definition defs.cpp:47
void SwapEnd(T &var)
Вспомогательная функция перестановки байт местами (нужно для сохранения бинарных VTK)
Definition defs.h:561
double nu
Коэффициент кинематической вязкости среды
Definition Passport2D.h:99
double dt
Шаг по времени
Definition PassportGen.h:67
std::pair< std::string, int > fileTypeVtx
Тип файлов для сохранения скорости и давления
Definition PassportGen.h:79
int saveVtxStep
Шаг сохранения кадров в бинарные файлы
Definition PassportGen.h:81
int nameLength
Число разрядов в имени файла
Definition PassportGen.h:76
Here is the call graph for this function:

Member Data Documentation

◆ collapseRightBorderParameter

double VM2D::Wake::collapseRightBorderParameter

абсцисса, правее которой происходит линейный (вправо) рост радиуса коллапса

Definition at line 161 of file Wake2D.h.

◆ collapseScaleParameter

double VM2D::Wake::collapseScaleParameter

характерный масштаб, на котором происходит рост радиуса коллапса

Definition at line 164 of file Wake2D.h.

◆ neighb

std::vector<int> VM2D::Wake::neighb
private

Вектор потенциальных соседей для будущего коллапса

Definition at line 66 of file Wake2D.h.

◆ neighbNew

std::vector<int> VM2D::Wake::neighbNew
private

Definition at line 69 of file Wake2D.h.

◆ vtx

std::vector<Vortex2D> VM2D::WakeDataBase::vtx
inherited

Список вихревых элементов

Definition at line 81 of file WakeDataBase2D.h.

◆ W

const World2D& VM2D::WakeDataBase::W
inherited

Константная ссылка на решаемую задачу

Definition at line 71 of file WakeDataBase2D.h.


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