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< Vortex2Dvtx
 Список вихревых элементов
 

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 475 of file Wake2D.cpp.

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

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

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

319{
320 GetPairsBS(type);
321}
void GetPairsBS(int type)
Definition Wake2D.cpp:324
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 324 of file Wake2D.cpp.

325{
326 neighb.resize(vtx.size(), 0);
327
328 Point2D Ri, Rk;
329
331
332#pragma omp parallel for default(none) shared(type, maxG) schedule(dynamic, DYN_SCHEDULE)
333 for (int i = 0; i < vtx.size(); ++i)
334 {
335 neighb[i] = 0;
336 int s = i;
337 const Vortex2D& vtxI = vtx[i];
338
339 bool found = false;
340
341 double r2, r2test;
342
343 const double& cSP = collapseScaleParameter;
344 const double& cRBP = collapseRightBorderParameter;
345
346 while ( (!found) && ( s + 1 < (int)vtx.size() ) )
347 {
348 s++;
349 const Vortex2D& vtxK = vtx[s];
350
351 r2 = dist2(vtxI.r(), vtxK.r());
352
353 //линейное увеличение радиуса коллапса
354 double mnog = std::max(1.0, /* 2.0 * */ (vtxI.r()[0] - cRBP) / cSP);
355
357
358 if (type == 1)
359 r2test *= 4.0; //Увеличение радиуса коллапса в 2 раза для коллапса вихрей разных знаков
360
361 if (r2 < r2test)
362 {
363 switch (type)
364 {
365 case 0:
366 found = ( vtxI.g()*vtxK.g() != 0.0) && (fabs(vtxI.g() + vtxK.g()) < sqr(mnog) * maxG);
367 break;
368 case 1:
369 found = (vtxI.g()*vtxK.g() < 0.0);
370 break;
371 case 2:
372 found = (vtxI.g()*vtxK.g() > 0.0) && (fabs(vtxI.g() + vtxK.g()) < sqr(mnog) * maxG);
373 break;
374 }
375 }//if r2 < r2_test
376 }//while
377
378 if (found)
379 neighb[i] = s;
380 }//for locI
381}//GetPairsBS(...)
T sqr(T x)
Умножение a на комплексно сопряженноe к b.
Definition defsBH.h:101
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:835
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 385 of file Wake2D.cpp.

386{
387 neighb.resize(vtx.size(), 0);
388
389 Point2D Ri, Rk;
390
392
393#pragma omp parallel for default(none) shared(type, maxG) schedule(dynamic, DYN_SCHEDULE)
394 for (int i = 0; i < vtx.size(); ++i)
395 {
396 neighb[i] = 0;
397 int s = i;
398 const Vortex2D& vtxI = vtx[i];
399
400 bool found = false;
401
402 double r2, r2test = 1e+10;
403
404 const double& cSP = collapseScaleParameter;
405 const double& cRBP = collapseRightBorderParameter;
406
407 while (/*(!found) &&*/ (s + 1 < (int)vtx.size()))
408 {
409 s++;
410 const Vortex2D& vtxK = vtx[s];
411
412 r2 = dist2(vtxI.r(), vtxK.r());
413
414 if (r2 < r2test)
415 {
416 r2test = r2;
417 neighb[i] = s;
418 }//if r2 < r2_test
419 }//while
420
421 }//for locI
422}//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 273 of file Wake2D.cpp.

274{
275 std::vector<double> gamma;
276 gamma.resize(afl.getNumberOfPanels(), 0.0);
277
278 std::vector<int> through;
279 through.resize(vtx.size(), -1);
280
281//#pragma omp parallel for default(none) shared(afl, oldAfl, isMoves, through, newPos)
282 for (int i = 0; i < (int)vtx.size(); ++i)
283 {
284 size_t minN;
285
286 bool crit = isMoves ? MoveInsideMovingBoundary(newPos[i], vtx[i].r(), oldAfl, afl, minN) : MoveInside(newPos[i], vtx[i].r(), afl, minN);
287
288 if (crit)
289 through[i] = (int)minN;
290 }//for i
291
292
293 //std::stringstream sss;
294 //sss << "through_" << W.currentStep;
295 //std::ofstream of(W.getPassport().dir + "dbg/" + sss.str());
296 //for (size_t i = 0; i < gamma.size(); ++i)
297 // of << gamma[i] << std::endl;
298 //of.close();
299
300 //std::stringstream sss;
301 //sss << "through_" << W.currentStep;
302 //std::ofstream of(W.getPassport().dir + "dbg/" + sss.str());
303 //for (size_t i = 0; i < gamma.size(); ++i)
304 // of << through[i] << std::endl;
305 //of.close();
306
307 for (size_t q = 0; q < through.size(); ++q)
308 if (through[q] > -1)
309 {
310 gamma[through[q]] += vtx[q].g();
311 vtx[q].g() = 0.0;
312 }
313
314 afl.gammaThrough = gamma;
315}//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:178
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 62 of file Wake2D.cpp.

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

179{
180 panThrough = -1;
181
183
184 //проверка габ. прямоугольника
185 if (!afl.inverse && afl.isOutsideGabarits(newPos) && afl.isOutsideGabarits(oldPos))
186 return false;
187
188 bool hit = false;
189
190 double angle = 0;
191 double cs, sn;
192
193 double dist2 = 1000000000.0;
194
195 for (size_t i = 0; i < afl.getNumberOfPanels(); ++i)
196 {
197 Point2D v1, v2, vv;
198 v1 = afl.getR(i) - newPos;
199
200 v2 = afl.getR(i + 1) - newPos;
201
202 vv = afl.getR(i + 1) - afl.getR(i);
203
204 double dst = v1.length2() + v2.length2();
205 if (dst < dist2)
206 {
207 dist2 = dst;
208 panThrough = i;
209 }
210
211 cs = v1 & v2;
212 sn = v1 ^ v2;
213
214 angle += atan2(sn, cs);
215 }//for i
216
217 hit = ((angle > 3.14) || (angle < -3.14));
218
219 if (afl.inverse)
220 hit = !hit;
221
222 return hit;
223}//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 55 of file WakeDataBase2D.cpp.

56{
57 std::string filename = dir + fileName;
58 std::ifstream wakeFile, testFile;
59
60 char firstChar = '/', secondChar = '*';
61
62 if (fileExistTest(filename, W.getInfo(), true, { "txt", "TXT" }))
63 {
64 testFile.open(filename);
65 testFile >> firstChar;
66 testFile >> secondChar;
67
68 //std::cout << "CHARS: " << firstChar << " " << secondChar << std::endl;
69 testFile.close();
70 }
71
72
73 //Считывание из словаря
74 if (firstChar == '/' && secondChar == '*')
75 {
76 if (fileExistTest(filename, W.getInfo(), true, { "txt", "TXT" }))
77 {
78 std::stringstream wakeFile(VMlib::Preprocessor(filename).resultString);
79
81 VMlib::StreamParser wakeParser(XXX, "vortex wake file parser", wakeFile);
82
83 wakeParser.get("vtx", vtx);
84 }
85 }
86 else
87 {
88 //Считывание из обычного текстового файла
89 if (fileExistTest(filename, W.getInfo(), true, { "txt", "TXT" }))
90 {
91 wakeFile.open(filename);
92 int nnn;
93 wakeFile >> nnn;
94 vtx.reserve(nnn);
95 for (int i = 0; i < nnn; ++i)
96 {
97 Vortex2D v;
98 wakeFile >> v.r()[0] >> v.r()[1] >> v.g();
99 vtx.push_back(v);
100 }
101
102 wakeFile.close();
103 }
104 }
105
106}//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:342
Here is the call graph for this function:

◆ RemoveFar()

int Wake::RemoveFar ( )

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

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

Definition at line 788 of file Wake2D.cpp.

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

◆ RemoveZero()

size_t Wake::RemoveZero ( )

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

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

Definition at line 808 of file Wake2D.cpp.

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

◆ Restruct()

void Wake::Restruct ( )

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

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

Definition at line 831 of file Wake2D.cpp.

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

◆ SaveKadrVtk()

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

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

Definition at line 109 of file WakeDataBase2D.cpp.

110{
111 W.getTimers().start("Save");
112
114 {
115 std::ofstream outfile;
116 size_t numberNonZero = 0;
117
118 if (vtx.size() > 0)
119 numberNonZero += vtx.size();
120 else
121 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
122 numberNonZero += W.getAirfoil(q).getNumberOfPanels();
123 VMlib::CreateDirectory(W.getPassport().dir, "snapshots");
124
125 if (W.getPassport().timeDiscretizationProperties.fileTypeVtx.second == 0) //text format vtk
126 {
127 std::string fname = VMlib::fileNameStep(filePrefix, W.getPassport().timeDiscretizationProperties.nameLength, W.getCurrentStep(), "vtk");
128 outfile.open(W.getPassport().dir + "snapshots/" + fname);
129
130 outfile << "# vtk DataFile Version 2.0" << std::endl;
131 outfile << "VM2D VTK result: " << (W.getPassport().dir + "snapshots/" + fname).c_str() << " saved " << VMlib::CurrentDataTime() << std::endl;
132 outfile << "ASCII" << std::endl;
133 outfile << "DATASET UNSTRUCTURED_GRID" << std::endl;
134 outfile << "POINTS " << numberNonZero << " float" << std::endl;
135
136
137 if (vtx.size() > 0)
138 for (auto& v : vtx)
139 {
140 const Point2D& r = v.r();
141 outfile << r[0] << " " << r[1] << " " << "0.0" << std::endl;
142 }//for v
143 else
144 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
145 for (size_t s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
146 {
147 const Point2D& r = W.getAirfoil(q).getR(s);
148 outfile << r[0] << " " << r[1] << " " << "0.0" << std::endl;
149 }
150
151 outfile << "CELLS " << numberNonZero << " " << 2 * numberNonZero << std::endl;
152 for (size_t i = 0; i < numberNonZero; ++i)
153 outfile << "1 " << i << std::endl;
154
155 outfile << "CELL_TYPES " << numberNonZero << std::endl;
156 for (size_t i = 0; i < numberNonZero; ++i)
157 outfile << "1" << std::endl;
158
159 outfile << std::endl;
160 outfile << "POINT_DATA " << numberNonZero << std::endl;
161 outfile << "SCALARS Gamma float 1" << std::endl;
162 outfile << "LOOKUP_TABLE default" << std::endl;
163
164 if (vtx.size() > 0)
165 for (auto& v : vtx)
166 outfile << v.g() << std::endl;
167 else
168 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
169 for (size_t s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
170 outfile << "0.0" << std::endl;
171
172 outfile.close();
173 }//if fileType = text
174 else if (W.getPassport().timeDiscretizationProperties.fileTypeVtx.second == 1) //binary format vtk
175 {
176 //Тест способа хранения чисел
177 uint16_t x = 0x0001;
178 bool littleEndian = (*((uint8_t*)&x));
179 const char eolnBIN[] = "\n";
180
181 std::string fname = VMlib::fileNameStep(filePrefix, W.getPassport().timeDiscretizationProperties.nameLength, W.getCurrentStep(), "vtk");
182 outfile.open(W.getPassport().dir + "snapshots/" + fname, std::ios::out | std::ios::binary);
183
184 outfile << "# vtk DataFile Version 3.0" << "\r\n" << "VM2D VTK result: " << (W.getPassport().dir + "snapshots/" + fname).c_str() << " saved " << VMlib::CurrentDataTime() << eolnBIN;
185 outfile << "BINARY" << eolnBIN;
186 outfile << "DATASET UNSTRUCTURED_GRID" << eolnBIN << "POINTS " << numberNonZero << " " << "float" << eolnBIN;
187
188 if (vtx.size() > 0)
189 {
190 Eigen::VectorXf rData = Eigen::VectorXf::Zero(vtx.size() * 3);
191 for (size_t i = 0; i < vtx.size(); ++i)
192 {
193 rData(3 * i) = (float)(vtx[i].r())[0];
194 rData(3 * i + 1) = (float)(vtx[i].r())[1];
195 }//for i
196
197 if (littleEndian)
198 for (int i = 0; i < vtx.size() * 3; ++i)
199 VMlib::SwapEnd(rData(i));
200 outfile.write(reinterpret_cast<char*>(rData.data()), vtx.size() * 3 * sizeof(float));
201 }
202 else
203 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
204 {
205 Eigen::VectorXf rData = Eigen::VectorXf::Zero(W.getAirfoil(q).getNumberOfPanels() * 3);
206 for (size_t s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
207 {
208 rData(3 * s) = (float)(W.getAirfoil(q).getR(s))[0];
209 rData(3 * s + 1) = (float)(W.getAirfoil(q).getR(s))[1];
210 }//for i
211
212 if (littleEndian)
213 for (int i = 0; i < W.getAirfoil(q).getNumberOfPanels() * 3; ++i)
214 VMlib::SwapEnd(rData(i));
215 outfile.write(reinterpret_cast<char*>(rData.data()), W.getAirfoil(q).getNumberOfPanels() * 3 * sizeof(float));
216 }
217
218 // CELLS
219 std::vector<int> cells(2 * numberNonZero);
220 for (size_t i = 0; i < numberNonZero; ++i)
221 {
222 cells[2 * i] = 1;
223 cells[2 * i + 1] = (int)i;
224 }
225
226 std::vector<int> cellsTypes;
227 cellsTypes.resize(numberNonZero, 1);
228
229 if (littleEndian)
230 {
231 for (int i = 0; i < numberNonZero * 2; ++i)
232 VMlib::SwapEnd(cells[i]);
233
234 for (int i = 0; i < numberNonZero; ++i)
235 VMlib::SwapEnd(cellsTypes[i]);
236 }
237
238 outfile << eolnBIN << "CELLS " << numberNonZero << " " << numberNonZero * 2 << eolnBIN;
239 outfile.write(reinterpret_cast<char*>(cells.data()), numberNonZero * 2 * sizeof(int));
240 outfile << eolnBIN << "CELL_TYPES " << numberNonZero << eolnBIN;
241 outfile.write(reinterpret_cast<char*>(cellsTypes.data()), numberNonZero * sizeof(int));
242
243 //gammas
244 outfile << eolnBIN << "POINT_DATA " << numberNonZero << eolnBIN;
245 outfile << eolnBIN << "SCALARS Gamma " << "float" << " 1" << eolnBIN;
246 outfile << "LOOKUP_TABLE default" << eolnBIN;
247
248 if (vtx.size() > 0)
249 {
250 Eigen::VectorXf pData = Eigen::VectorXf::Zero(numberNonZero);
251 for (int s = 0; s < vtx.size(); ++s)
252 pData(s) = (float)vtx[s].g();
253
254 if (littleEndian)
255 for (int i = 0; i < vtx.size(); ++i)
256 VMlib::SwapEnd(pData(i));
257 outfile.write(reinterpret_cast<char*>(pData.data()), vtx.size() * sizeof(float));
258 }
259 else
260 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
261 {
262 Eigen::VectorXf pData = Eigen::VectorXf::Zero(W.getAirfoil(q).getNumberOfPanels());
263 for (int s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
264 pData(s) = 0;
265
266 if (littleEndian)
267 for (int i = 0; i < W.getAirfoil(q).getNumberOfPanels(); ++i)
268 VMlib::SwapEnd(pData(i));
269 outfile.write(reinterpret_cast<char*>(pData.data()), W.getAirfoil(q).getNumberOfPanels() * sizeof(float));
270 }
271
272 outfile << eolnBIN;
273 outfile.close();
274 }//if binary
276 {
277 std::string fname = VMlib::fileNameStep(filePrefix, W.getPassport().timeDiscretizationProperties.nameLength, W.getCurrentStep(), "csv");
278 outfile.open(W.getPassport().dir + "snapshots/" + fname);
279
280 outfile << "point,x,y,G " << std::endl;
281
282 int counter = 0;
283
284 if (vtx.size() > 0)
285 for (auto& v : vtx)
286 outfile << counter++ << "," << v.r()[0] << "," << v.r()[1] << "," << v.g() << std::endl;
287 else
288 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
289 for (size_t s = 0; s < W.getAirfoil(q).getNumberOfPanels(); ++s)
290 {
291 const Point2D& r = W.getAirfoil(q).getR(s);
292 outfile << counter++ << "," << r[0] << "," << r[1] << "," << "0.0" << std::endl;
293 }
294 outfile.close();
295 }//if fileType = text
296
297 }
298
299 W.getTimers().stop("Save");
300}
bool ifDivisible(int val) const
Definition World2D.h:278
TimeDiscretizationProperties timeDiscretizationProperties
Структура с параметрами процесса интегрирования по времени
std::string dir
Рабочий каталог задачи
size_t getCurrentStep() const
Возврат константной ссылки на параметры распараллеливания по MPI.
Definition WorldGen.h:99
std::string fileNameStep(const std::string &name, int length, size_t number, const std::string &ext)
Формирование имени файла
Definition defs.h:381
void CreateDirectory(const std::string &dir, const std::string &name)
Создание каталога
Definition defs.h:441
std::string CurrentDataTime()
Формирование строки с текущем временем и датой
Definition defs.cpp:47
void SwapEnd(T &var)
Вспомогательная функция перестановки байт местами (нужно для сохранения бинарных VTK)
Definition defs.h:555
std::pair< std::string, int > fileTypeVtx
Тип файлов для сохранения скорости и давления
Definition PassportGen.h:73
int saveVtxStep
Шаг сохранения кадров в бинарные файлы
Definition PassportGen.h:75
int nameLength
Число разрядов в имени файла
Definition PassportGen.h:70
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: