VM2D  1.12
Vortex methods for 2D flows simulation
Wake2D.cpp
Go to the documentation of this file.
1 /*--------------------------------*- VM2D -*-----------------*---------------*\
2 | ## ## ## ## #### ##### | | Version 1.12 |
3 | ## ## ### ### ## ## ## ## | VM2D: Vortex Method | 2024/01/14 |
4 | ## ## ## # ## ## ## ## | for 2D Flow Simulation *----------------*
5 | #### ## ## ## ## ## | Open Source Code |
6 | ## ## ## ###### ##### | https://www.github.com/vortexmethods/VM2D |
7 | |
8 | Copyright (C) 2017-2024 I. Marchevsky, K. Sokol, E. Ryatina, A. Kolganova |
9 *-----------------------------------------------------------------------------*
10 | File name: Wake2D.cpp |
11 | Info: Source code of VM2D |
12 | |
13 | This file is part of VM2D. |
14 | VM2D is free software: you can redistribute it and/or modify it |
15 | under the terms of the GNU General Public License as published by |
16 | the Free Software Foundation, either version 3 of the License, or |
17 | (at your option) any later version. |
18 | |
19 | VM2D is distributed in the hope that it will be useful, but WITHOUT |
20 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
21 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
22 | for more details. |
23 | |
24 | You should have received a copy of the GNU General Public License |
25 | along with VM2D. If not, see <http://www.gnu.org/licenses/>. |
26 \*---------------------------------------------------------------------------*/
27 
28 
40 #if defined(_WIN32)
41  #include <direct.h>
42 #endif
43 
44 #include <fstream>
45 #include <sys/stat.h>
46 #include <sys/types.h>
47 
48 #include "Wake2D.h"
49 
50 #include "knnCPU.h"
51 #include "knn.cuh"
52 
53 #include "Airfoil2D.h"
54 #include "Boundary2D.h"
55 #include "MeasureVP2D.h"
56 #include "Mechanics2D.h"
57 #include "Passport2D.h"
58 #include "Preprocessor.h"
59 #include "StreamParser.h"
60 #include "Velocity2D.h"
61 #include "World2D.h"
62 #include <algorithm>
63 
64 using namespace VM2D;
65 
66 bool Wake::MoveInside(const Point2D& newPos, const Point2D& oldPos, const Airfoil& afl, size_t& panThrough)
67 {
68  //const double porog_r = 1e-12;
69 
70  //double minDist = 1.0E+10; //расстояние до пробиваемой панели
71  panThrough = -1;
72 
73  //проверка габ. прямоугольника
74  if (afl.isOutsideGabarits(newPos) && afl.isOutsideGabarits(oldPos))
75  return false;
76 
77  //если внутри габ. прямоугольника - проводим контроль
78  bool hit = false;
79 
80  //std::pair<double, double> gabPointX = std::minmax(newPos[0], oldPos[0]);
81  //std::pair<double, double> gabPointY = std::minmax(newPos[1], oldPos[1]);
82 
83  //std::pair<double, double> gabPanelX, gabPanelY;
84 
85  //Проверка на пересечение
86  //double r0 = 0, r1 = 0, r2 = 0, r3 = 0;
87 
88  //int cnt = 0;
89  for (size_t j = 0; j < afl.getNumberOfPanels(); ++j)
90  {
91  const Point2D& aflRj = afl.getR(j);
92  const Point2D& aflRj1 = afl.getR(j + 1);
93 
94 // gabPanelX = std::minmax(aflRj[0], aflRj1[0]);
95 // gabPanelY = std::minmax(aflRj[1], aflRj1[1]);
96 
97 // if ((gabPointX.second >= gabPanelX.first) && (gabPanelX.second >= gabPointX.first) && (gabPointY.second >= gabPanelY.first) && (gabPanelY.second >= gabPointY.first))
98 // {
99  if ((((aflRj - oldPos) ^ (newPos - oldPos)) * ((aflRj1 - oldPos) ^ (newPos - oldPos)) <= 0) && \
100  (((oldPos - aflRj) ^ (aflRj1 - aflRj)) * ((newPos - aflRj) ^ (aflRj1 - aflRj)) <= 0))
101  {
102  hit = true;
103  panThrough = j;
104  break;
105  }
106 // }
107 // else { ++cnt; }
108  }//for j
109 
110 // std::cout << cnt << std::endl;
111 
112  return hit;
113 }//MoveInside(...)
114 
115 
116 //bool Wake::MoveInside(const Point2D& newPos, const Point2D& oldPos, const Airfoil& afl, size_t& panThrough)
117 //{
118 // const double porog_r = 1e-12;
119 //
120 // double minDist = 1.0E+10; //расстояние до пробиваемой панели
121 // panThrough = -1;
122 //
123 // //проверка габ. прямоугольника
124 // if (afl.isOutsideGabarits(newPos) && afl.isOutsideGabarits(oldPos))
125 // return false;
126 //
127 // //если внутри габ. прямоугольника - проводим контроль
128 // bool hit = false;
129 //
130 // //Определение прямой: Ax+By+D=0 - перемещение вихря
131 // double A = newPos[1] - oldPos[1];
132 // double B = oldPos[0] - newPos[0];
133 // double D = oldPos[1] * newPos[0] - oldPos[0] * newPos[1];
134 //
135 // double A1, B1, D1;
136 //
137 // std::pair<double, double> gabPointX = std::minmax(newPos[0], oldPos[0]);
138 // std::pair<double, double> gabPointY = std::minmax(newPos[1], oldPos[1]);
139 //
140 // std::pair<double, double> gabPanelX, gabPanelY;
141 //
142 // //Проверка на пересечение
143 // double r0 = 0, r1 = 0, r2 = 0, r3 = 0;
144 //
145 // for (size_t j = 0; j < afl.getNumberOfPanels(); ++j)
146 // {
147 // r0 = A * afl.getR(j)[0] + B * afl.getR(j)[1] + D;
148 // r1 = A * afl.getR(j + 1)[0] + B * afl.getR(j + 1)[1] + D;
149 //
150 // if (fabs(r0) < porog_r) r0 = 0.0;
151 // if (fabs(r1) < porog_r) r1 = 0.0;
152 //
153 // if (r0*r1 > 0)
154 // continue;
155 //
156 // //Определение прямой:A1x+B1y+D1=0 - панель
157 // A1 = afl.getR(j + 1)[1] - afl.getR(j)[1];
158 // B1 = afl.getR(j)[0] - afl.getR(j + 1)[0];
159 // D1 = afl.getR(j)[1] * afl.getR(j + 1)[0] - afl.getR(j)[0] * afl.getR(j + 1)[1];
160 //
161 // r2 = A1 * oldPos[0] + B1 * oldPos[1] + D1;
162 // r3 = A1 * newPos[0] + B1 * newPos[1] + D1;
163 //
164 // if (fabs(r2) < porog_r) r2 = 0.0;
165 // if (fabs(r3) < porog_r) r3 = 0.0;
166 //
167 // if (r2*r3 > 0)
168 // continue;
169 //
170 // hit = true;// пробила!
171 // double d2 = (oldPos[0] - (B*D1 - D * B1) / (A*B1 - B * A1))*(oldPos[0] - (B*D1 - D * B1) / (A*B1 - B * A1)) + \
172 // (oldPos[1] - (A1*D - D1 * A) / (A*B1 - B * A1))*(oldPos[1] - (A1*D - D1 * A) / (A*B1 - B * A1));
173 //
174 // if (d2 < minDist)
175 // {
176 // minDist = d2;
177 // panThrough = j;
178 // }//if d2
179 // }//for j
180 //
181 //
182 // return hit;
183 //}//MoveInside(...)
184 
185 bool Wake::MoveInsideMovingBoundary(const Point2D& newPos, const Point2D& oldPos, const Airfoil& oldAfl, const Airfoil& afl, size_t& panThrough)
186 {
187  panThrough = -1;
188 
190 
191  //проверка габ. прямоугольника
192  if (!afl.inverse && afl.isOutsideGabarits(newPos) && afl.isOutsideGabarits(oldPos))
193  return false;
194 
195  bool hit = false;
196 
197  double angle = 0;
198  double cs, sn;
199 
200  double dist2 = 1000000000.0;
201 
202  for (size_t i = 0; i < afl.getNumberOfPanels(); ++i)
203  {
204  Point2D v1, v2, vv;
205  v1 = afl.getR(i) - newPos;
206 
207  v2 = afl.getR(i + 1) - newPos;
208 
209  vv = afl.getR(i + 1) - afl.getR(i);
210 
211  double dst = v1.length2() + v2.length2();
212  if (dst < dist2)
213  {
214  dist2 = dst;
215  panThrough = i;
216  }
217 
218  cs = v1 & v2;
219  sn = v1 ^ v2;
220 
221  angle += atan2(sn, cs);
222  }//for i
223 
224  hit = ((angle > 3.14) || (angle < -3.14));
225 
226  if (afl.inverse)
227  hit = !hit;
228 
229  return hit;
230 }//MoveInsideMovingBoundary(...)
231 
232 //bool Wake::MoveInsideMovingBoundary(const Point2D& newPos, const Point2D& oldPos, const Airfoil& oldAfl, const Airfoil& afl, size_t& panThrough)
233 //{
234 // panThrough = -1;
235 //
236 // /// \todo сравнить производительности двух inside-ов
237 //
238 // //проверка габ. прямоугольника
239 // if (afl.isOutsideGabarits(newPos) && afl.isOutsideGabarits(oldPos))
240 // return false;
241 //
242 // bool hit = false;
243 //
244 // double angle = 0;
245 // double cs, sn;
246 //
247 // double dist2 = 1000000000.0;
248 //
249 // for (int i = 0; i < afl.getNumberOfPanels(); ++i)
250 // {
251 // Point2D v1, v2, vv;
252 // v1 = afl.getR(i) - newPos;
253 //
254 // v2 = afl.getR(i + 1) - newPos;
255 //
256 // vv = afl.getR(i + 1) - afl.getR(i);
257 //
258 // double dst = v1.length2() + v2.length2();
259 // if (dst < dist2)
260 // {
261 // dist2 = dst;
262 // panThrough = i;
263 // }
264 //
265 // cs = v1 * v2;
266 // sn = v1 ^ v2;
267 //
268 // angle += atan2(sn, cs);
269 // }//for i
270 //
271 // hit = ((angle > 3.00) || (angle < -3.00));
272 //
273 // return hit;
274 //}//MoveInsideMovingBoundary(...)
275 
276 
277 
278 //Проверка пересечения вихрями следа профиля при перемещении
279 void Wake::Inside(const std::vector<Point2D>& newPos, Airfoil& afl, bool isMoves, const Airfoil& oldAfl)
280 {
281  std::vector<double> gamma;
282  gamma.resize(afl.getNumberOfPanels(), 0.0);
283 
284  std::vector<int> through;
285  through.resize(vtx.size(), -1);
286 
287 #pragma omp parallel for default(none) shared(afl, oldAfl, isMoves, through, newPos)
288  for (int i = 0; i < (int)vtx.size(); ++i)
289  {
290  size_t minN;
291 
292  bool crit = isMoves ? MoveInsideMovingBoundary(newPos[i], vtx[i].r(), oldAfl, afl, minN) : MoveInside(newPos[i], vtx[i].r(), afl, minN);
293 
294  if (crit)
295  through[i] = (int)minN;
296  }//for i
297 
298 
299  //std::stringstream sss;
300  //sss << "through_" << W.currentStep;
301  //std::ofstream of(W.getPassport().dir + "dbg/" + sss.str());
302  //for (size_t i = 0; i < gamma.size(); ++i)
303  // of << gamma[i] << std::endl;
304  //of.close();
305 
306  for (size_t q = 0; q < through.size(); ++q)
307  if (through[q] > -1)
308  {
309  gamma[through[q]] += vtx[q].g();
310  vtx[q].g() = 0.0;
311  }
312 
313  afl.gammaThrough = gamma;
314 }//Inside(...)
315 
316 //Поиск ближайшего соседа
317 void Wake::GetPairs(int type)
318 {
319  GetPairsBS(type);
320 }
321 
322 //Поиск ближайшего соседа
323 void Wake::GetPairsBS(int type)
324 {
325  neighb.resize(0);
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  int s = i;
336  const Vortex2D& vtxI = vtx[i];
337 
338  bool found = false;
339 
340  double r2, r2test;
341 
342  const double& cSP = collapseScaleParameter;
343  const double& cRBP = collapseRightBorderParameter;
344 
345  while ( (!found) && ( s + 1 < (int)vtx.size() ) )
346  {
347  s++;
348  const Vortex2D& vtxK = vtx[s];
349 
350  r2 = dist2(vtxI.r(), vtxK.r());
351 
352  //линейное увеличение радиуса коллапса
353  double mnog = std::max(1.0, /* 2.0 * */ (vtxI.r()[0] - cRBP) / cSP);
354 
355  r2test = sqr( W.getPassport().wakeDiscretizationProperties.epscol * mnog );
356 
357  if (type == 1)
358  r2test *= 4.0; //Увеличение радиуса коллапса в 2 раза для коллапса вихрей разных знаков
359 
360  //if (mnog > 1.0)
361  // r2test = sqr(0.005*cSP);
362 
363  if (r2 < r2test)
364  {
365  switch (type)
366  {
367  case 0:
368  found = ( fabs(vtxI.g()*vtxK.g()) != 0.0) && (fabs(vtxI.g() + vtxK.g()) < sqr(mnog) * maxG);
369  break;
370  case 1:
371  found = (vtxI.g()*vtxK.g() < 0.0);
372  break;
373  case 2:
374  found = (vtxI.g()*vtxK.g() > 0.0) && (fabs(vtxI.g() + vtxK.g()) < sqr(mnog) * maxG);
375  break;
376  }
377  }//if r2 < r2_test
378  }//while
379 
380  if (found)
381  neighb[i] = s;
382  }//for locI
383 }//GetPairsBS(...)
384 
385 
386 #if defined(USE_CUDA)
387 void Wake::GPUGetPairs(int type)
388 {
389  size_t npt = vtx.size();
390 
391  double tCUDASTART = 0.0, tCUDAEND = 0.0;
392 
393  tCUDASTART += omp_get_wtime();
394  std::vector<int> tnei(npt, 0);
395  neighb.resize(npt, 0);
396 
397  if (npt > 0)
398  {
399  cuCalculatePairs(npt, devVtxPtr, devMeshPtr, devNeiPtr, 2.0*W.getPassport().wakeDiscretizationProperties.epscol, sqr(W.getPassport().wakeDiscretizationProperties.epscol), type);
400 
401  W.getCuda().CopyMemFromDev<int, 1>(npt, devNeiPtr, neighb.data(), 30);
402  }
403 
404  tCUDAEND += omp_get_wtime();
405 
406  //W.getInfo('t') << "GPU_Pairs: " << (tCUDAEND - tCUDASTART) << std::endl;
407 }
408 #endif
409 
410 
411 // Коллапс вихрей
412 int Wake::Collaps(int type, int times)
413 {
414  int nHlop = 0; //общее число убитых вихрей
415 
416  //int loc_hlop = 0; //
417 
418  std::vector<bool> flag; //как только вихрь сколлапсировался flag = 1
419  for (int z = 0; z < times; ++z)
420  {
421 
422 #if (defined(__CUDACC__) || defined(USE_CUDA)) && (defined(CU_PAIRS))
423 
425  {
426  const_cast<Gpu&>(W.getCuda()).RefreshWake(3);
427  GPUGetPairs(type);
428  }
429  else
430  GetPairs(type);
431 #else
432  GetPairs(type);
433 #endif
434 
435  //loc_hlop = 0;//число схлопнутых вихрей
436 
437  flag.clear();
438  flag.resize(vtx.size(), false);
439 
440  double sumAbsGam, iws;
441  Point2D newPos;
442 
443  for (size_t vt = 0; vt + 1 < vtx.size(); ++vt)
444  {
445  Vortex2D& vtxI = vtx[vt];
446 
447  if (!flag[vt])
448  {
449  //std::cout << "A" << std::endl;
450 
451  int ssd = neighb[vt];
452 
453  //std::cout << "B" << std::endl;
454 
455  if ((ssd < 0) || (ssd >= flag.size()))
456  std::cout << "ssd = " << ssd << ", flag.size() = " << flag.size() << ", vtx.size() = " << vtx.size() << std::endl;
457 
458  if ((ssd != 0) && (!flag[ssd]))
459  {
460  //std::cout << "C0" << std::endl;
461 
462  Vortex2D& vtxK = vtx[ssd];
463 
464  //std::cout << "C" << std::endl;
465 
466  flag[ssd] = true;
467 
468  Vortex2D sumVtx;
469  sumVtx.g() = vtxI.g() + vtxK.g();
470 
471  switch (type)
472  {
473  case 0:
474  case 2:
475  sumAbsGam = fabs(vtxI.g()) + fabs(vtxK.g());
476 
477  iws = sumAbsGam > 1e-10 ? 1.0 / sumAbsGam : 1.0;
478 
479  sumVtx.r() = (vtxI.r() * fabs(vtxI.g()) + vtxK.r() * fabs(vtxK.g())) * iws;
480  break;
481 
482  case 1:
483  sumVtx.r() = (fabs(vtxI.g()) > fabs(vtxK.g())) ? vtxI.r() : vtxK.r();
484  break;
485  }
486 
487  bool fl_hit = true;
488  //double Ch1[2];
489  size_t hitpan = -1;
490 
491  //std::cout << "D" << std::endl;
492 
493  for (size_t afl = 0; afl < W.getNumberOfAirfoil(); ++afl)
494  {
495  //проверим, не оказался ли новый вихрь внутри контура
496  if (MoveInside(sumVtx.r(), vtxI.r(), W.getAirfoil(afl), hitpan) || MoveInside(sumVtx.r(), vtxK.r(), W.getAirfoil(afl), hitpan))
497  fl_hit = false;
498  }//for
499 
500  //std::cout << "E" << std::endl;
501 
502  if (fl_hit)
503  {
504  vtxI = sumVtx;
505  vtxK.g() = 0.0;
506  nHlop++;
507  }//if (fl_hit)
508 
509  //std::cout << "F" << std::endl;
510 
511  }//if ((ssd!=0)&&(!flag[ssd]))
512  }//if !flag[vt]
513  }//for vt
514 
515  }//for z
516 
517  return nHlop;
518 }//Collaps(...)
519 
520 // Коллапс вихрей
521 int Wake::CollapsNew(int type, int times)
522 {
523  int nHlop = 0; //общее число убитых вихрей
524 
525  const double& cSP = collapseScaleParameter;
526  const double& cRBP = collapseRightBorderParameter;
527 
529 
530  //int loc_hlop = 0; // neigh
531 
532  std::vector<bool> flag; //как только вихрь сколлапсировался flag = 1
533  for (int z = 0; z < times; ++z)
534  {
535  //loc_hlop = 0;//число схлопнутых вихрей
536 
537  flag.clear();
538  flag.resize(vtx.size(), false);
539 
540  double sumAbsGam, iws, r2, r2test;
541  Point2D newPos;
542 
543  for (size_t vt = 0; vt + 1 < vtx.size(); ++vt)
544  {
545  Vortex2D& vtxI = vtx[vt];
546  if (!flag[vt])
547  {
548  for (int s = 0; s < knb - 1; ++s)
549  {
550  int ssd = neighbNew[vt * (knb - 1) + s];
551  Vortex2D& vtxK = vtx[ssd];
552 
553  r2 = dist2(vtxI.r(), vtxK.r());
554  //линейное увеличение радиуса коллапса
555  double mnog = std::max(1.0, /* 2.0 * */ (vtxI.r()[0] - cRBP) / cSP);
557  if (type == 1)
558  r2test *= 4.0; //Увеличение радиуса коллапса в 2 раза для коллапса вихрей разных знаков
559 
560  bool keyGamma = false;
561  switch (type)
562  {
563  case 0:
564  keyGamma = (fabs(vtxI.g() * vtxK.g()) != 0.0) && (fabs(vtxI.g() + vtxK.g()) < sqr(mnog) * maxG);
565  break;
566  case 1:
567  keyGamma = (vtxI.g() * vtxK.g() < 0.0);
568  break;
569  case 2:
570  keyGamma = (vtxI.g() * vtxK.g() > 0.0) && (fabs(vtxI.g() + vtxK.g()) < sqr(mnog) * maxG);
571  break;
572  }
573 
574  if ((r2 < r2test) && (keyGamma))
575  {
576  if ((ssd != 0) && (!flag[ssd]))
577  {
578  flag[ssd] = true;
579 
580  Vortex2D sumVtx;
581  sumVtx.g() = vtxI.g() + vtxK.g();
582 
583  switch (type)
584  {
585  case 0:
586  case 2:
587  sumAbsGam = fabs(vtxI.g()) + fabs(vtxK.g());
588 
589  if (sumAbsGam > 1e-10)
590  sumVtx.r() = (vtxI.r() * fabs(vtxI.g()) + vtxK.r() * fabs(vtxK.g())) * (1.0 / sumAbsGam);
591  else
592  sumVtx.r() = 0.5 * (vtxI.r() + vtxK.r());
593 
594  break;
595 
596  case 1:
597  sumVtx.r() = (fabs(vtxI.g()) > fabs(vtxK.g())) ? vtxI.r() : vtxK.r();
598  break;
599  }
600 
601  bool fl_hit = true;
602  size_t hitpan = -1;
603 
604  for (size_t afl = 0; afl < W.getNumberOfAirfoil(); ++afl)
605  {
606  //проверим, не оказался ли новый вихрь внутри контура
607  if (MoveInside(sumVtx.r(), vtxI.r(), W.getAirfoil(afl), hitpan) || MoveInside(sumVtx.r(), vtxK.r(), W.getAirfoil(afl), hitpan))
608  fl_hit = false;
609  }//for
610 
611  if (fl_hit)
612  {
613  vtxI = sumVtx;
614  vtxK.g() = 0.0;
615  nHlop++;
616  flag[vt] = true;
617  }//if (fl_hit)
618 
619  }//if ((ssd!=0)&&(!flag[ssd]))
620  }
621 
622  if (flag[vt])
623  break;
624  }// for s
625  }//if !flag[vt]
626  }//for vt
627 
628  }//for z
629 
630  return nHlop;
631 }//Collaps(...)
632 
633 
634 
636 {
637  int nFar = 0;
640  Point2D zerovec = { 0.0, 0.0 };
641 #pragma omp parallel for default(none) shared(distFar2, zerovec) reduction(+:nFar)
642  for (int i = 0; i <static_cast<int>(vtx.size()); ++i)
643  {
644  if (dist2(vtx[i].r(), zerovec) > distFar2)
645  {
646  vtx[i].g() = 0.0;
647  nFar++;
648  }
649  }
650 
651  return nFar;
652 }//RemoveFar()
653 
654 
656 {
657  const double porog_g = 1e-15;
658 
659  std::vector<Vortex2D/*, VM2D::MyAlloc<VMlib::Vortex2D>*/> newWake;
660 
661  newWake.reserve(vtx.size());
662 
663  for (size_t q = 0; q < vtx.size(); ++q)
664  if (fabs(vtx[q].g()) > porog_g)
665  newWake.push_back(vtx[q]);
666 
667  size_t delta = vtx.size() - newWake.size();
668 
669  newWake.swap(vtx);
670 
671  return delta;
672 }//RemoveZero()
673 
674 
675 
676 
677 
678 
679 
680 
681 
682 
683 
684 //Реструктуризация вихревого следа
686 {
687  W.getTimestat().timeRestruct.first += omp_get_wtime();
688 
689  // Определение параметров, отвечающих за увеличение радиуса коллапса
690  std::vector<double> rightBorder, horizSpan;
691  rightBorder.reserve(W.getNumberOfAirfoil());
692  horizSpan.reserve(W.getNumberOfAirfoil());
693 
694  for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
695  {
696 
697  rightBorder.emplace_back(W.getAirfoil(q).upRight[0]);
698  horizSpan.emplace_back(W.getAirfoil(q).upRight[0] - W.getAirfoil(q).lowLeft[0]);
699  }
700 
701  if (W.getNumberOfAirfoil() > 0)
702  {
703  W.getNonConstWake().collapseRightBorderParameter = *std::max_element(rightBorder.begin(), rightBorder.end());
704  W.getNonConstWake().collapseScaleParameter = *std::max_element(horizSpan.begin(), horizSpan.end());
705  }
706  else
707  {
710  }
711 #if defined(__CUDACC__) || defined(USE_CUDA)
713 #endif
714 
715 
716 
718 
719 
720  //CPU/GPU - прямой алгоритм
721  //Collaps(1, 1);
722  //Collaps(2, 1);
723 
724 
725  //*
726  //быстрый алгоритм
727  for (int collapsStep = 1; collapsStep <= 2; ++collapsStep)
728  {
729 #if defined(USE_CUDA)
730 #define knnGPU
731 #endif
732 
733  neighbNew.resize(vtx.size() * (knb - 1));
734 
735  if (vtx.size() > 2 * knb)
736  {
737 #ifndef knnGPU
738  //CPU
739  std::vector<std::vector<std::pair<double, size_t>>> initdist(vtx.size());
740  for (auto& d : initdist)
741  d.resize(2 * knb, { -1.0, -1 });
742 
743  WakekNN(vtx, knb, initdist);//CPU
744 #else
745  std::vector<std::pair<double, size_t>> initdistcuda(knb * vtx.size(), { -1.0, -1 }); //CUDA
746  kNNcuda(vtx, knb, initdistcuda, vecForKnn); //CUDA
747 #endif
748 
749  for (int i = 0; i < vtx.size(); ++i)
750  {
751 #ifndef knnGPU
752  neighbNew[i] = (int)initdist[i][1].second;
753 #else
754  for (int j = 0; j < knb - 1; ++j)
755  neighbNew[i * (knb - 1) + j] = (int)initdistcuda[(i * knb) + (j + 1)].second;
756 #endif
757  }
758  }
759 
760  CollapsNew(collapsStep, 1);
761 
762  }
763 
765 //*/
766 
767  RemoveFar();
768  RemoveZero();
769 
770  W.getTimestat().timeRestruct.second += omp_get_wtime();
771 }//Restruct()
772 
773 
774 //bool Wake::isPointInsideAirfoil(const Point2D& pos, const Airfoil& afl)
775 //{
776 // Point2D posFar = { 100.0, 100.0 };
777 //
778 // Point2D r1, r2;
779 //
780 // int nIntersec = 0;
781 //
782 // for (int i = 0; i < afl.np; ++i)
783 // {
784 // r1 = afl.r[i];
785 // r2 = afl.r[i+1];
786 //
787 // if ((area(pos, posFar, r1) * area(pos, posFar, r2) <= -1.e-10) && (area(r1, r2, pos) * area(r1, r2, posFar) <= -1.e-10))
788 // nIntersec++;
789 // }
790 // return nIntersec % 2;
791 //}
792 //
793 //double Wake::area(Point2D p1, Point2D p2, Point2D p3)
794 //{
795 // return (p2[0] - p1[0]) * (p3[1] - p1[1]) - (p2[1] - p1[1]) * (p3[0] - p1[0]);
796 //}
Заголовочный файл с описанием класса Passport (двумерный) и cоответствующими структурами ...
Times & getTimestat() const
Возврат ссылки на временную статистику выполнения шага расчета по времени
Definition: World2D.h:242
std::pair< std::string, int > velocityComputation
Definition: Passport2D.h:190
Заголовочный файл с описанием класса Wake.
Заголовочный файл с описанием класса World2D.
Gpu & getNonConstCuda() const
Возврат неконстантной ссылки на объект, связанный с видеокартой (GPU)
Definition: World2D.h:232
bool inverse
Признак разворота нормалей (для расчета внутренних течений)
Definition: Airfoil2D.h:139
timePeriod timeRestruct
Начало и конец процесса реструктуризации пелены
Definition: Times2D.h:101
Заголовочный файл с описанием класса Airfoil.
double maxGamma
Максимально допустимая циркуляция вихря
Definition: Passport2D.h:157
const Wake & getWake() const
Возврат константной ссылки на вихревой след
Definition: World2D.h:197
std::vector< double > gammaThrough
Суммарные циркуляции вихрей, пересекших панели профиля на прошлом шаге
Definition: Airfoil2D.h:196
Point2D lowLeft
Левый нижний угол габаритного прямоугольника профиля
Definition: Airfoil2D.h:190
Заголовочный файл с описанием класса Preprocessor.
Заголовочный файл с описанием класса Mechanics.
const Point2D & getR(size_t q) const
Возврат константной ссылки на вершину профиля
Definition: Airfoil2D.h:101
static const int knb
Definition: Wake2D.h:65
HD Point2D & r()
Функция для доступа к радиус-вектору вихря
Definition: Vortex2D.h:85
HD double & g()
Функция для доступа к циркуляции вихря
Definition: Vortex2D.h:93
int RemoveFar()
Зануление далеко улетевших вихрей
Definition: Wake2D.cpp:635
size_t getNumberOfPanels() const
Возврат количества панелей на профиле
Definition: Airfoil2D.h:139
double collapseRightBorderParameter
абсцисса, правее которой происходит линейный (вправо) рост радиуса коллапса
Definition: Wake2D.h:152
auto length2() const -> typename std::remove_const< typename std::remove_reference< decltype(this->data[0])>::type >::type
Вычисление квадрата нормы (длины) вектора
Definition: numvector.h:383
Класс, обеспечивающий возможность выполнения вычислений на GPU по технологии Nvidia CUDA...
Definition: Gpu2D.h:67
size_t RemoveZero()
Исключение нулевых и мелких вихрей
Definition: Wake2D.cpp:655
Point2D upRight
Правый верхний угол габаритного прямоугольника профиля
Definition: Airfoil2D.h:191
void GetPairs(int type)
Поиск ближайшего соседа
Definition: Wake2D.cpp:317
T sqr(T x)
Возведение числа в квадрат
Definition: defs.h:430
void GetPairsBS(int type)
Definition: Wake2D.cpp:323
Wake & getNonConstWake() const
Возврат неконстантной ссылки на вихревой след
Definition: World2D.h:202
bool MoveInside(const Point2D &newPos, const Point2D &oldPos, const Airfoil &afl, size_t &panThrough)
Проверка проникновения точки через границу профиля
Definition: Wake2D.cpp:66
size_t getNumberOfAirfoil() const
Возврат количества профилей в задаче
Definition: World2D.h:147
Definition: Airfoil2D.h:45
bool MoveInsideMovingBoundary(const Point2D &newPos, const Point2D &oldPos, const Airfoil &oldAfl, const Airfoil &afl, size_t &panThrough)
Проверка проникновения точки через границу профиля
Definition: Wake2D.cpp:185
Заголовочный файл с описанием класса StreamParser.
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:788
std::vector< Vortex2D > vtx
Список вихревых элементов
NumericalSchemes numericalSchemes
Структура с используемыми численными схемами
Definition: Passport2D.h:302
const World2D & W
Константная ссылка на решаемую задачу
Класс, опеделяющий двумерный вектор
Definition: Point2D.h:75
Заголовочный файл с описанием класса MeasureVP.
void setCollapseCoeff(double pos_, double refLength_)
Установка правой границы самого правого профиля (для организации увеличения радиуса коллапса) ...
Definition: Gpu2D.h:253
const Passport & getPassport() const
Возврат константной ссылки на паспорт
Definition: World2D.h:222
const Gpu & getCuda() const
Возврат константной ссылки на объект, связанный с видеокартой (GPU)
Definition: World2D.h:227
Класс, опеделяющий двумерный вихревой элемент
Definition: Vortex2D.h:51
int Collaps(int type, int times)
Коллапс вихрей
Definition: Wake2D.cpp:412
std::vector< int > neighbNew
Definition: Wake2D.h:66
Абстрактный класс, определяющий обтекаемый профиль
Definition: Airfoil2D.h:60
std::vector< int > neighb
Вектор потенциальных соседей для будущего коллапса
Definition: Wake2D.h:63
double collapseScaleParameter
характерный масштаб, на котором происходит рост радиуса коллапса
Definition: Wake2D.h:155
const Airfoil & getAirfoil(size_t i) const
Возврат константной ссылки на объект профиля
Definition: World2D.h:130
void WakekNN(const std::vector< Vortex2D > &vtx, const size_t k, std::vector< std::vector< std::pair< double, size_t >>> &initdist)
Definition: knnCPU.cpp:447
void Inside(const std::vector< Point2D > &newPos, Airfoil &afl, bool isMoves, const Airfoil &oldAfl)
Проверка пересечения вихрями следа профиля при перемещении
Definition: Wake2D.cpp:279
WakeDiscretizationProperties wakeDiscretizationProperties
Структура с параметрами дискретизации вихревого следа
Definition: Passport2D.h:299
Заголовочный файл с описанием класса Velocity.
int CollapsNew(int type, int times)
Definition: Wake2D.cpp:521
void Restruct()
Реструктуризация вихревого следа
Definition: Wake2D.cpp:685
Заголовочный файл с описанием класса Boundary.
double distFar
Расстояние от центра самого подветренного (правого) профиля, на котором вихри уничтожаются ...
Definition: Passport2D.h:148
bool isOutsideGabarits(const Point2D &r) const
Определяет, находится ли точка с радиус-вектором вне габаритного прямоугольника профиля ...
Definition: Airfoil2D.cpp:76
double epscol
Радиус коллапса
Definition: Passport2D.h:145