VM2D  1.12
Vortex methods for 2D flows simulation
Airfoil2DRect.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: Airfoil2DRect.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 #include "Airfoil2DRect.h"
41 
42 #include "Boundary2D.h"
43 #include "MeasureVP2D.h"
44 #include "Mechanics2D.h"
45 #include "nummatrix.h"
46 #include "Passport2D.h"
47 #include "Preprocessor.h"
48 #include "StreamParser.h"
49 #include "Velocity2D.h"
50 #include "Wake2D.h"
51 #include "World2D.h"
52 #include "AirfoilGeometry.h"
53 
54 #include "spline/spline.h"
55 
56 using namespace VM2D;
57 
58 //Считывание профиля из файла
59 void AirfoilRect::ReadFromFile(const std::string& dir) //загрузка профиля из файла, его поворот и масштабирование
60 {
62  std::string filename = dir + param.fileAirfoil;
63  std::ifstream airfoilFile;
64 
65  if (fileExistTest(filename, W.getInfo(), { "txt", "TXT" }))
66  {
67  std::stringstream airfoilFile(VMlib::Preprocessor(filename).resultString);
68 
69  VMlib::StreamParser airfoilParser(W.getInfo(), "airfoil file parser", airfoilFile);
70 
71  m = 0.0; //TODO
72  J = 0.0; //TODO
73  rcm = { 0.0, 0.0 }; //TODO
74  phiAfl = 0.0;
75 
76  inverse = param.inverse;
77 
78 
79 
80  //*
81 
83  //Проверяем отсутствие "задвоенных" подряд идущих точек
84  //airfoilParser.get("r", r_);
85  std::vector<Point2D> rFromFile;
86  airfoilParser.get("r", rFromFile);
87 
88  if (rFromFile.size() > 0)
89  {
90  if (param.requiredNPanels <= rFromFile.size()) {
91 
92  r_.reserve(rFromFile.size());
93  r_.push_back(rFromFile[0]);
94  for (size_t i = 1; i < rFromFile.size(); ++i)
95  if ((rFromFile[i] - rFromFile[i - 1]).length2() > 1e-12)
96  r_.push_back(rFromFile[i]);
97 
98  //Если первая совпадает с последней, то убираем последнюю
99  if ((r_.back() - r_.front()).length2() < 1e-12)
100  r_.resize(r_.size() - 1);
101  }
102  else
103  {
104  W.getInfo('e') << "Airfoil shape is given explicitely, it can not be automatically split!" << std::endl;
105  exit(200);
106  }
107  }
108  else
109  {
110  //std::vector<GeomPoint> geomFromFile(X.size()); //new
111  std::vector<GeomPoint> geomFromFile; //VM2D
112 
113  //for (int q = 0; q < X.size(); ++q) // new
114  //{ //
115  // geomFromFile[q].r = { X[q], Y[q] }; //
116  // geomFromFile[q].type = key[q]; //
117  //} //
118  airfoilParser.get("geometry", geomFromFile); //VM2D
119 
120  if ((geomFromFile.front().r - geomFromFile.back().r).length2() < 1e-12)
121  geomFromFile.resize(geomFromFile.size() - 1);
122 
123 
124  //size_t reqN = NumberOfPoints; //new
125  size_t reqN = param.requiredNPanels; //VM2D
126 
127  std::vector<double> L(geomFromFile.size());
128  double totalLength = 0.0;
129  std::vector<size_t> nc = {};
130  std::vector<size_t> ni = {};
131 
132  for (size_t i = 0; i < geomFromFile.size(); ++i)
133  {
134  const Point2D& p1 = geomFromFile[i].r;
135  const Point2D& p2 = geomFromFile[(i + 1) % geomFromFile.size()].r;
136 
137  L[i] = (p2 - p1).length();
138  totalLength += L[i];
139  }
140 
141 
142  //Ищем первый сплайн
143  size_t i = 0;
144  std::vector<size_t> splineStart, splineFinish;
145 
146  while (i < geomFromFile.size())
147  {
148  while (i < geomFromFile.size() && !(geomFromFile[i].type == "c"))
149  ++i;
150 
151  if (i < geomFromFile.size())
152  {
153  splineStart.push_back(i);
154  ++i;
155  //ищем второй конец
156  while (i < geomFromFile.size() && !(geomFromFile[i].type == "c"))
157  ++i;
158 
159  splineFinish.push_back(i);
160  }
161  }
162 
163  if ((splineStart.size() > 0) && (splineStart[0] != 0))
164  splineFinish.back() = splineStart[0];
165 
166  //std::vector<Point2D> r_; //new
167 
168  if (reqN == 0)
169  {
170  r_.reserve(geomFromFile.size());
171  for (size_t i = 0; i < geomFromFile.size(); ++i)
172  r_.push_back(geomFromFile[i].r);
173  }
174  else
175  {
176  double hRef = totalLength / reqN;
177 
178  std::vector<int> nPanels;
179 
180  bool cyclic = (splineStart.size() == 0);
181 
182  if (cyclic)
183  {
184  splineStart.push_back(0);
185  splineFinish.push_back(geomFromFile.size());
186  }
187 
188  for (size_t s = 0; s < splineStart.size(); ++s)
189  {
190  //Сплайн
191  std::vector<double> T, X, Y;
192 
193  size_t splineLegs = splineFinish[s] - splineStart[s];
194  if (splineFinish[s] <= splineStart[s])
195  splineLegs += geomFromFile.size();
196 
197  T.reserve(splineLegs + 1);
198  X.reserve(T.size());
199  Y.reserve(T.size());
200 
201  double tbuf = 0.0;
202 
203  for (size_t i = splineStart[s]; i <= splineStart[s] + splineLegs; ++i)
204  {
205  const Point2D& pt = geomFromFile[i % geomFromFile.size()].r;
206 
207  T.push_back(tbuf);
208  X.push_back(pt[0]);
209  Y.push_back(pt[1]);
210 
211  if ((i == splineStart[s]) && (splineFinish[s] - splineStart[s] == 1))
212  {
213  double halfL = (i < geomFromFile.size()) ? 0.5 * L[i] : 0.5 * (geomFromFile.front().r - geomFromFile.back().r).length();
214  tbuf += halfL;
215  T.push_back(tbuf);
216  Point2D nextPt = geomFromFile[(i + 1) % geomFromFile.size()].r;
217 
218  X.push_back(0.5 * (pt[0] + nextPt[0]));
219  Y.push_back(0.5 * (pt[1] + nextPt[1]));
220 
221  tbuf += halfL;
222  }
223  else
224  tbuf += (i < geomFromFile.size()) ? L[i] : (geomFromFile.front().r - geomFromFile.back().r).length();
225  }
226 
227 
228 
229  tk::spline s1, s2;
230  if (cyclic)
231  {
232  s1.set_boundary(tk::spline::cyclic);
233  s2.set_boundary(tk::spline::cyclic);
234  }
235  else
236  {
237  s1.set_boundary(tk::spline::second_deriv, 0.0, tk::spline::second_deriv, 0.0);
238  s2.set_boundary(tk::spline::second_deriv, 0.0, tk::spline::second_deriv, 0.0);
239  }
240 
241  s1.set_points(T, X);
242  s2.set_points(T, Y);
243 
244  int NumberOfPanelsSpline = (int)ceil(T.back() / hRef);
245  double hSpline = T.back() / NumberOfPanelsSpline;
246 
247  for (int i = 0; i < NumberOfPanelsSpline; ++i)
248  r_.push_back({ s1(hSpline * i), s2(hSpline * i) });
249 
250  nPanels.push_back(NumberOfPanelsSpline);
251 
252  }
253  }
254  }//else geometry
255 
256 
257 
258  //std::ofstream of("airfoil.txt");
259  //for (size_t i = 0; i < r_.size(); ++i)
260  // of << r_[i] << "," << std::endl;
261  //of.close();
262 
263  if (r_.size() == 0)
264  {
265  W.getInfo('e') << "No points on airfoil contour!" << std::endl;
266  exit(200);
267  }
268 
269  if (inverse)
270  std::reverse(r_.begin(), r_.end());
271 
272 
273  v_.resize(0);
274  for (size_t q = 0; q < r_.size(); ++q)
275  v_.push_back({ 0.0, 0.0 });
276 
277  Move(param.basePoint);
278  Scale(param.scale);
279 
280  double rotationAngle = param.angle;
282  rotationAngle = -param.angle - 0.5 * PI;
283 
284  Rotate(-rotationAngle);
285  //в конце Rotate нормали, касательные и длины вычисляются сами
286 
287  gammaThrough.clear();
288  gammaThrough.resize(r_.size(), 0.0);
289 
290  //Вычисляем площадь
291  area = 0.0;
292  for (size_t q = 0; q < r_.size(); ++q)
293  {
294  const Point2D& cntq = 0.5 * (getR(q) + getR(q + 1));
295  const Point2D& drq = getR(q + 1) - getR(q);
296  area += fabs(cntq[0] * drq[1] - cntq[1] * drq[0]);
297  }
298  area *= 0.5;
299  }
300 }//ReadFromFile(...)
301 
302 //Вычисление числителей и знаменателей диффузионных скоростей в заданном наборе точек, обусловленных геометрией профиля, и вычисление вязкого трения
303 void AirfoilRect::GetDiffVelocityI0I3ToSetOfPointsAndViscousStresses(const WakeDataBase& pointsDb, std::vector<double>& domainRadius, std::vector<double>& I0, std::vector<Point2D>& I3)
304 {
305  std::vector<double> selfI0;
306  std::vector<Point2D> selfI3;
307 
308  std::vector<double> currViscousStress;
309  currViscousStress.resize(r_.size(), 0.0);
310 
311 
312  selfI0.resize(pointsDb.vtx.size(), 0.0);
313  selfI3.resize(pointsDb.vtx.size(), { 0.0, 0.0 });
314 
315 #pragma warning (push)
316 #pragma warning (disable: 4101)
317  //Локальные переменные для цикла
318  Point2D q, xi, xi_m, v0;
319  double lxi, lxi_m, lenj_m;
320 
321  Point2D mn;
322  int new_n;
323  Point2D h;
324 
325  Point2D vec;
326  double s, d;
327 
328  double vs;
329  double iDDomRad, domRad, expon;
330 #pragma warning (pop)
331 
332 #pragma omp parallel for \
333  default(none) \
334  shared(domainRadius, pointsDb, selfI0, selfI3, currViscousStress, PI) \
335  private(xi, xi_m, lxi, lxi_m, lenj_m, v0, q, new_n, mn, h, d, s, vec, vs, expon, domRad, iDDomRad) schedule(dynamic, DYN_SCHEDULE)
336  for (int i = 0; i < pointsDb.vtx.size(); ++i)
337  {
338  const Vortex2D& vtxI = pointsDb.vtx[i];
339 
340  domRad = std::max(domainRadius[i], W.getPassport().wakeDiscretizationProperties.getMinEpsAst());
341  iDDomRad = 1.0 / domRad;
342 
343  for (size_t j = 0; j < r_.size(); ++j)
344  {
345  vs = 0.0;
346  q = vtxI.r() - 0.5 * (getR(j) + getR(j + 1));
347  vec = tau[j];
348 
349  s = q & vec;
350  d = fabs(q & nrm[j]);
351 
352  if ((d < 50.0 * len[j]) && (fabs(s) < 50.0 * len[j]))
353  {
354  v0 = vec * len[j];
355 
356  if ((d > 5.0 * len[j]) || (fabs(s) > 5.0 * len[j]))
357  {
358  xi = q * iDDomRad;
359  lxi = xi.length();
360 
361  expon = exp(-lxi) * len[j];
362  mn = nrm[j] * expon;
363 
364  if (selfI0[i] != -PI * domRad)
365  {
366  selfI0[i] += (xi & mn) * (lxi + 1.0) / (lxi * lxi);
367  selfI3[i] += mn;
368  }
369 
370  vs = vtxI.g() * expon / (PI * sqr(meanEpsOverPanel[j]));
371  }
372  else if ((d >= 0.1 * len[j]) || (fabs(s) > 0.5 * len[j]))
373  {
374  vs = 0.0;
375  double den = (fabs(s) < 0.5 * len[j]) ? d : (fabs(s) + d - 0.5 * len[j]);
376 
377  new_n = std::max(1, static_cast<int>(ceil(5.0 * len[j] / den)));
378  //new_n = 100;
379  h = v0 * (1.0 / new_n);
380 
381  for (int m = 0; m < new_n; ++m)
382  {
383  xi_m = (vtxI.r() - (getR(j) + h * (m + 0.5))) * iDDomRad;
384  lxi_m = xi_m.length();
385 
386  lenj_m = len[j] / new_n;
387  expon = exp(-lxi_m) * lenj_m;
388 
389  mn = nrm[j] * expon;
390  if (selfI0[i] != -PI * domRad)
391  {
392  selfI0[i] += (xi_m & mn) * (lxi_m + 1.0) / (lxi_m * lxi_m);
393  selfI3[i] += mn;
394  }
395  vs += expon;
396  }//for m
397  vs *= vtxI.g() / (PI * sqr(meanEpsOverPanel[j]));
398  }
399  else
400  {
401 
402  selfI0[i] = -PI * domRad;
403  double mnog = 2.0 * domRad * (1.0 - exp(-len[j] * iDDomRad / 2.0) * cosh(fabs(s) * iDDomRad));
404  selfI3[i] = nrm[j] * mnog;
405  vs = mnog * vtxI.g() / (PI * sqr(meanEpsOverPanel[j]));
406  }
407  }//if d<50 len
408 
409 #pragma omp atomic
410  currViscousStress[j] += vs;
411  }//for j
412  }//for i
413 
414 
415  if (&pointsDb == &(W.getWake()))
416  for (size_t i = 0; i < viscousStress.size(); ++i)
417  {
418  viscousStress[i] += currViscousStress[i];
419  }
420 
421  for (size_t i = 0; i < I0.size(); ++i)
422  {
423  domRad = std::max(domainRadius[i], W.getPassport().wakeDiscretizationProperties.getMinEpsAst());
424 
425  if (I0[i] != -PI * domRad)
426  {
427  if (selfI0[i] == -PI * domRad)
428  {
429  I0[i] = selfI0[i];
430  I3[i] = selfI3[i];
431  }
432  else
433  {
434  I0[i] += selfI0[i];
435  I3[i] += selfI3[i];
436  }
437  }
438  }
439 }; //GetDiffVelocityI0I3ToSetOfPointsAndViscousStresses(...)
440 
441 
442 void AirfoilRect::GetDiffVelocityI0I3ToWakeAndViscousStresses(const WakeDataBase& pointsDb, std::vector<double>& domainRadius, std::vector<double>& I0, std::vector<Point2D>& I3)
443 {
444  if (&pointsDb == &(W.getWake()))
445  {
446  viscousStress.clear();
447  viscousStress.resize(r_.size(), 0.0);
448  }
449 
450  GetDiffVelocityI0I3ToSetOfPointsAndViscousStresses(pointsDb, domainRadius, I0, I3);
451 }//GetDiffVelocityI0I3ToWakeAndViscousStresses(...)
452 
453 
454 #if defined(USE_CUDA)
455 void AirfoilRect::GPUGetDiffVelocityI0I3ToSetOfPointsAndViscousStresses(const WakeDataBase& pointsDb, std::vector<double>& domainRadius, std::vector<double>& I0, std::vector<Point2D>& I3)
456 {
457  std::vector<double> newViscousStress;
458 
459  //Обнуление вязких напряжений
460  if (&pointsDb == &(W.getWake()))
461  {
462  viscousStress.clear();
463  viscousStress.resize(r_.size(), 0.0);
464  }
465 
466  //CUDA-ядро вызывается 1 раз и учитывает влияние сразу всех профилей
467  if ((numberInPassport == 0) && ((&pointsDb == &(W.getWake())) || (&pointsDb == &(W.getBoundary(0).virtualWake))))
468  {
469  size_t npt = pointsDb.vtx.size();
470 
471  if (&pointsDb == &(W.getBoundary(0).virtualWake))
472  {
473  for (size_t q = 1; q < W.getNumberOfAirfoil(); ++q)
474  npt += W.getBoundary(q).virtualWake.vtx.size();
475  }
476 
477  double*& dev_ptr_pt = pointsDb.devVtxPtr;
478  double*& dev_ptr_rad = pointsDb.devRadPtr;
479  double*& dev_ptr_meanEps = devMeanEpsOverPanelPtr;
480  const size_t nr = r_.size();
481  double*& dev_ptr_r = devRPtr;
482 
483  double*& dev_ptr_i0 = pointsDb.devI0Ptr;
484  double*& dev_ptr_i3 = pointsDb.devI3Ptr;
486 
487  size_t nTotPan = 0;
488  for (size_t s = 0; s < W.getNumberOfAirfoil(); ++s)
489  nTotPan += W.getAirfoil(s).getNumberOfPanels();
490 
491 
492  std::vector<Point2D> newI3(npt); //(I3.size());
493  std::vector<double> newI0(npt); //(I0.size());
494  newViscousStress.resize(nTotPan);
495 
496 
497 
498  if ((npt > 0) && (nr > 0))
499  {
500  double*& dev_ptr_visstr = devViscousStressesPtr;
501 
502  std::vector<double> locvisstr(nTotPan);
503 
504  std::vector<double> zeroVec(nTotPan, 0.0);
505  cuCopyFixedArray(dev_ptr_visstr, zeroVec.data(), nTotPan * sizeof(double));
506 
507  cuCalculateSurfDiffVeloWake(npt, dev_ptr_pt, nTotPan, dev_ptr_r, dev_ptr_i0, dev_ptr_i3, dev_ptr_rad, dev_ptr_meanEps, minRad, dev_ptr_visstr);
508 
509  W.getCuda().CopyMemFromDev<double, 2>(npt, dev_ptr_i3, (double*)newI3.data());
510  W.getCuda().CopyMemFromDev<double, 1>(npt, dev_ptr_i0, newI0.data());
511  W.getCuda().CopyMemFromDev<double, 1>(nTotPan, dev_ptr_visstr, newViscousStress.data());
512 
513 
514  if (&pointsDb == &(W.getWake()))
515  {
516  for (size_t q = 0; q < I3.size(); ++q)
517  {
518  I0[q] += newI0[q];
519  I3[q] += newI3[q];
520  }
521  }
522 
523  if (&pointsDb == &(W.getBoundary(0).virtualWake))
524  {
525  size_t curCounter = 0;
526  for (size_t s = 0; s < W.getNumberOfAirfoil(); ++s)
527  for (size_t q = 0; q < W.getBoundary(s).virtualWake.vtx.size(); ++q)
528  {
529  //std::cout << "s = " << s << ", q = " << q << std::endl;
530  W.getNonConstVelocity().virtualVortexesParams[s].I0[q] += newI0[curCounter];
531  W.getNonConstVelocity().virtualVortexesParams[s].I3[q] += newI3[curCounter];
532  ++curCounter;
533  }
534  }
535 
536 
537 
538  size_t curGlobPnl = 0;
539  for (size_t s = 0; s < W.getNumberOfAirfoil(); ++s) //W.getNumberOfAirfoil()
540  {
541  std::vector<double>& tmpVisStress = W.getNonConstAirfoil(s).tmpViscousStresses;
542  const size_t& np = W.getAirfoil(s).getNumberOfPanels();
543  tmpVisStress.resize(0);
544  tmpVisStress.insert(tmpVisStress.end(), newViscousStress.begin() + curGlobPnl, newViscousStress.begin() + curGlobPnl + np);
545  curGlobPnl += np;
546  }
547 
548  }
549  }//if numberInPassport==0
550 
551 
552  if ( (&pointsDb == &(W.getWake())) || (&pointsDb == &(W.getBoundary(0).virtualWake)) )
553  for (size_t i = 0; i < viscousStress.size(); ++i)
554  viscousStress[i] += tmpViscousStresses[i];
555 
556 }//GPUGetDiffVelocityI0I3ToSetOfPointsAndViscousStresses
557 #endif
558 
559 
560 bool AirfoilRect::IsPointInAirfoil(const Point2D& point) const
561 {
562  double sumAngle = 0.0;
563 
564  Point2D v1, v2;
565 
566  for (size_t i = 0; i < r_.size(); ++i)
567  {
568  v1 = getR(i) - point;
569  v2 = getR(i+1) - point;
570  sumAngle += atan2(v1^v2, v1 & v2);
571  }
572 
573  if (fabs(sumAngle) < 0.1)
574  return false;
575  else
576  return true;
577 }//IsPointInAirfoil(...)
578 
579 //Перемещение профиля
580 void AirfoilRect::Move(const Point2D& dr) //перемещение профиля как единого целого на вектор dr
581 {
582  for (size_t i = 0; i < r_.size(); ++i)
583  r_[i] += dr;
584  rcm += dr;
585  CalcNrmTauLen();
586  GetGabarits();
587 }//Move(...)
588 
589 
590 //Поворот профиля
591 void AirfoilRect::Rotate(double alpha) //поворот профиля на угол alpha вокруг центра масс
592 {
593  phiAfl += alpha;
594  nummatrix<double, 2, 2> rotMatrix = { { cos(alpha), -sin(alpha) }, { sin(alpha), cos(alpha) } };
595 
596  for (size_t i = 0; i < r_.size(); ++i)
597  r_[i] = rcm + (rotMatrix & (r_[i] - rcm));
598 
599 
600  CalcNrmTauLen();
601  GetGabarits();
602 }//Rotate(...)
603 
604 
605 //Масштабирование профиля
606 void AirfoilRect::Scale(const Point2D& factor) //масштабирование профиля на коэффициент factor относительно центра масс
607 {
608  for (size_t i = 0; i < r_.size(); ++i)
609  r_[i] = rcm + Point2D{ factor[0] * (r_[i] - rcm)[0], factor[1] * (r_[i] - rcm)[1] };
610 
611  CalcNrmTauLen();
612  GetGabarits();
613 }//Scale(...)
614 
615 // Вычисление нормалей, касательных и длин панелей по текущему положению вершин
617 {
618  if (nrm.size() != r_.size())
619  {
620  nrm.resize(r_.size());
621  tau.resize(r_.size());
622  len.resize(r_.size());
623  }
624 
625  Point2D rpan;
626 
627  for (size_t i = 0; i < r_.size(); ++i)
628  {
629  rpan = (getR(i + 1) - getR(i));
630  len[i] = rpan.length();
631  tau[i] = rpan.unit();
632 
633  nrm[i] = { tau[i][1], -tau[i][0] };
634  }
635 
636  //закольцовываем
637  nrm.push_back(nrm[0]);
638  tau.push_back(tau[0]);
639  len.push_back(len[0]);
640 }//CalcNrmTauLen()
641 
642 //Вычисляет габаритный прямоугольник профиля
643 void AirfoilRect::GetGabarits(double gap) //определение габаритного прямоугольника
644 {
645  lowLeft = { 1E+10, 1E+10 };
646  upRight = { -1E+10, -1E+10 };
647 
648  for (size_t i = 0; i < r_.size(); ++i)
649  {
650  lowLeft[0] = std::min(lowLeft[0], r_[i][0]);
651  lowLeft[1] = std::min(lowLeft[1], r_[i][1]);
652 
653  upRight[0] = std::max(upRight[0], r_[i][0]);
654  upRight[1] = std::max(upRight[1], r_[i][1]);
655  }
656 
657  Point2D size = upRight - lowLeft;
658  lowLeft -= size*gap;
659  upRight += size*gap;
660 }//GetGabarits(...)
661 
662 
663 
664 //Вычисление коэффициентов матрицы A для расчета влияния панели на панель
665 std::vector<double> AirfoilRect::getA(size_t p, size_t i, const Airfoil& airfoil, size_t j) const
666 {
667  std::vector<double> res(p*p, 0.0);
668 
669  if ( (i == j) && (&airfoil == this))
670  {
671  res[0] = 0.5 * (tau[i] ^ nrm[i]);
672  if (p == 1)
673  return res;
674 
675  res[3] = (1.0 / 12.0) * res[0];
676  if (p == 2)
677  return res;
678 
679  if (p > 2)
680  throw (-42);
681 
682  }//if i==j
683 
684  const auto& miq = W.getIQ(numberInPassport, airfoil.numberInPassport);
685 
686  res[0] = miq.first(i, j);
687 
688  if (p == 1)
689  return res;
690 
691  res[1] = miq.first(i, airfoil.getNumberOfPanels() + j);
692 
693  res[2] = miq.first(getNumberOfPanels() + i, j);
694 
695  res[3] = miq.first(getNumberOfPanels() + i, airfoil.getNumberOfPanels() + j);
696 
697  if (p == 2)
698  return res;
699 
700  if (p > 2)
701  throw (-42);
702 
703  //Хотя сюда никогда и не попадем
704  return res;
705 }//getA(...)
706 
707 //Вычисление коэффициентов матрицы A для расчета влияния профиля самого на себя
708 void AirfoilRect::calcIQ(size_t p, const Airfoil& otherAirfoil, std::pair<Eigen::MatrixXd, Eigen::MatrixXd>& matrPair) const
709 {
710  bool self = (&otherAirfoil == this);
711 
712  size_t aflNSelf = numberInPassport;
713  size_t aflNOther = otherAirfoil.numberInPassport;
714 
715  size_t npI;
716  size_t npJ;
717 
718  numvector<double, 3> alpha, lambda;
719 
720  //auxillary vectors
721  Point2D p1, s1, p2, s2, di, dj, i00, i01, i10, i11;
722  numvector<Point2D, 3> v00, v11;
723  numvector<Point2D, 2> v01, v10;
724 
725 #pragma omp parallel for \
726  default(none) \
727  shared(otherAirfoil, self, aflNSelf, aflNOther, matrPair, p, IDPI, IQPI) \
728  private(npI, npJ, alpha, lambda, p1, s1, p2, s2, di, dj, i00, i01, i10, i11, v00, v11, v01, v10) schedule(dynamic, DYN_SCHEDULE)
729  for(int i = 0; i < (int)getNumberOfPanels(); ++i)
730  for (int j = 0; j < (int)otherAirfoil.getNumberOfPanels(); ++j)
731  {
732  npI = getNumberOfPanels();
733  npJ = otherAirfoil.getNumberOfPanels();
734 
735  if ((i == j) && self)
736  {
737 
738  matrPair.first(i, j) = 0.0;
739  matrPair.second(i, j) = 0.0;
740 
741  if (p == 2)
742  {
743  matrPair.first(i, npJ + j) = 0.0;
744  matrPair.first(npI + i, j) = 0.0;
745 
746  matrPair.second(i, npJ + j) = -IQPI;
747  matrPair.second(npI + i, j) = IQPI;
748 
749  matrPair.first(npI + i, npJ + j) = 0.0;
750  matrPair.second(npI + i, npJ + j) = 0.0;
751 
752  }
753  if (p > 2)
754  throw (-42);
755  }//if i==j
756  else
757  {
758  const Point2D& taui = tau[i];
759  const Point2D& tauj = otherAirfoil.tau[j];
760 
761  p1 = getR(i + 1) - otherAirfoil.getR(j + 1);
762  s1 = getR(i + 1) - otherAirfoil.getR(j);
763  p2 = getR(i) - otherAirfoil.getR(j + 1);
764  s2 = getR(i) - otherAirfoil.getR(j);
765  di = getR(i + 1) - getR(i);
766  dj = otherAirfoil.getR(j + 1) - otherAirfoil.getR(j);
767 
768  alpha = { \
769  (self && isAfter(j, i)) ? 0.0 : VMlib::Alpha(s2, s1), \
770  VMlib::Alpha(s2, p1), \
771  (self && isAfter(i, j)) ? 0.0 : VMlib::Alpha(p1, p2) \
772  };
773 
774  lambda = { \
775  (self && isAfter(j, i)) ? 0.0 : VMlib::Lambda(s2, s1), \
776  VMlib::Lambda(s2, p1), \
777  (self && isAfter(i, j)) ? 0.0 : VMlib::Lambda(p1, p2) \
778  };
779 
780  v00 = {
781  VMlib::Omega(s1, taui, tauj),
782  -VMlib::Omega(di, taui, tauj),
783  VMlib::Omega(p2, taui, tauj)
784  };
785 
786  i00 = IDPI / len[i] * (-(alpha[0] * v00[0] + alpha[1] * v00[1] + alpha[2] * v00[2]).kcross() \
787  + (lambda[0] * v00[0] + lambda[1] * v00[1] + lambda[2] * v00[2]));
788 
789  matrPair.first(i, j) = i00 & nrm[i];
790  matrPair.second(i, j) = i00 & taui;
791 
792 
793  if (p == 2)
794  {
795  v01 = {
796  0.5 / (dj.length()) * (((p1 + s1) & tauj) * VMlib::Omega(s1, taui, tauj) - s1.length2() * taui),
797  -0.5 * di.length() / dj.length() * VMlib::Omega(s1 + p2, tauj, tauj)
798  };
799 
800  i01 = IDPI / len[i] * (-((alpha[0] + alpha[2]) * v01[0] + (alpha[1] + alpha[2]) * v01[1]).kcross() \
801  + ((lambda[0] + lambda[2]) * v01[0] + (lambda[1] + lambda[2]) * v01[1]) - 0.5 * di.length() * tauj);
802 
803  matrPair.first(i, npJ + j) = i01 & nrm[i];
804  matrPair.second(i, npJ + j) = i01 & taui;
805 
806 
807  v10 = {
808  -0.5 / di.length() * (((s1 + s2) & taui) * VMlib::Omega(s1, taui, tauj) - s1.length2() * tauj),
809  0.5 * dj.length() / di.length() * VMlib::Omega(s1 + p2, taui, taui)
810  };
811 
812  i10 = IDPI / len[i] * (-((alpha[0] + alpha[2]) * v10[0] + alpha[2] * v10[1]).kcross() \
813  + ((lambda[0] + lambda[2]) * v10[0] + lambda[2] * v10[1]) + 0.5 * dj.length() * taui);
814 
815  matrPair.first(npI + i, j) = i10 & nrm[i];
816  matrPair.second(npI + i, j) = i10 & taui;
817 
818 
819  v11 = {
820  1.0 / (12.0 * di.length() * dj.length()) * (2.0 * (s1 & VMlib::Omega(s1 - 3.0 * p2, taui, tauj)) * VMlib::Omega(s1, taui, tauj) - s1.length2() * (s1 - 3.0 * p2)) - 0.25 * VMlib::Omega(s1, taui, tauj),
821  -di.length() / (12.0 * dj.length()) * VMlib::Omega(di, tauj, tauj),
822  -dj.length() / (12.0 * di.length()) * VMlib::Omega(dj, taui, taui)
823  };
824 
825  i11 = IDPI / len[i] * (-((alpha[0] + alpha[2]) * v11[0] + (alpha[1] + alpha[2]) * v11[1] + alpha[2] * v11[2]).kcross()\
826  + (lambda[0] + lambda[2]) * v11[0] + (lambda[1] + lambda[2]) * v11[1] + lambda[2] * v11[2] \
827  + 1.0 / 12.0 * (dj.length() * taui + di.length() * tauj - 2.0 * VMlib::Omega(s1, taui, tauj)));
828 
829  matrPair.first(npI + i, npJ + j) = i11 & nrm[i];
830  matrPair.second(npI + i, npJ + j) = i11 & taui;
831  }
832 
833 
834  if (p > 2)
835  throw (-42);
836  }//else(i == j)
837 
838  }//for(...)
839 }//getIQ(...)
840 
841 
842 void AirfoilRect::GetInfluenceFromVorticesToPanel(size_t panel, const Vortex2D* ptr, ptrdiff_t count, std::vector<double>& panelRhs) const
843 {
845 }//GetInfluenceFromVorticesToPanel(...)
846 
847 
848 //Вычисление влияния части подряд идущих источников из области течения на панель для правой части
849 void AirfoilRect::GetInfluenceFromSourcesToPanel(size_t panel, const Vortex2D* ptr, ptrdiff_t count, std::vector<double>& panelRhs) const
850 {
852 }//GetInfluenceFromSourcesToPanel(...)
853 
854 //Вычисление влияния слоя источников конкретной прямолинейной панели на вихрь в области течения
855 void AirfoilRect::GetInfluenceFromSourceSheetToVortex(size_t panel, const Vortex2D& vtx, Point2D& vel) const
856 {
858 }//GetInfluenceFromSourceSheetToVortex(...)
859 
860 //Вычисление влияния вихревых слоев (свободный + присоединенный) конкретной прямолинейной панели на вихрь в области течения
861 void AirfoilRect::GetInfluenceFromVortexSheetToVortex(size_t panel, const Vortex2D& vtx, Point2D& vel) const
862 {
864 }//GetInfluenceFromVortexSheetToVortex(...)
865 
866 void AirfoilRect::GetInfluenceFromVInfToPanel(std::vector<double>& vInfRhs) const
867 {
869 }//GetInfluenceFromVInfToPanel(...)
virtual void Rotate(double alpha) override
Поворот профиля
virtual void GetInfluenceFromSourcesToRectPanel(size_t panel, const Vortex2D *ptr, ptrdiff_t count, std::vector< double > &wakeRhs) const =0
Вычисление влияния части подряд источников из области течения на прямолинейную панель для правой част...
const std::pair< Eigen::MatrixXd, Eigen::MatrixXd > & getIQ(size_t i, size_t j) const
Возврат константной ссылки на объект, связанный с матрицей интегралов от (r-xi)/|r-xi|^2.
Definition: World2D.h:237
virtual void calcIQ(size_t p, const Airfoil &otherAirfoil, std::pair< Eigen::MatrixXd, Eigen::MatrixXd > &matrPair) const override
Вычисление коэффициентов матрицы, состоящей из интегралов от (r-xi)/|r-xi|^2.
virtual void GetGabarits(double gap=0.02) override
Вычисляет габаритный прямоугольник профиля
Заголовочный файл с описанием класса Passport (двумерный) и cоответствующими структурами ...
std::vector< double > viscousStress
Касательные напряжения на панелях профиля
Definition: Airfoil2D.h:188
Шаблонный класс, определяющий вектор фиксированной длины Фактически представляет собой массив...
Definition: numvector.h:95
bool geographicalAngles
Признак работы в "географической" системе координат
Definition: Passport2D.h:283
const double PI
Число .
Definition: defs.h:73
double m
Масса профиля
Definition: Airfoil2D.h:86
Заголовочный файл с описанием класса Wake.
virtual void GetInfluenceFromVorticesToRectPanel(size_t panel, const Vortex2D *ptr, ptrdiff_t count, std::vector< double > &wakeRhs) const =0
Вычисление влияния части подряд идущих вихрей из вихревого следа на прямолинейную панель для правой ч...
bool inverse
Признак разворота нормалей (для расчета внутреннего течения)
Definition: Passport2D.h:237
Заголовочный файл с описанием класса World2D.
double area
Площадь профиля
Definition: Airfoil2D.h:83
bool inverse
Признак разворота нормалей (для расчета внутренних течений)
Definition: Airfoil2D.h:139
Описание класса nummatrix.
const World2D & W
Константная ссылка на решаемую задачу
Definition: Airfoil2D.h:71
void CalcNrmTauLen()
Вычисление нормалей, касательных и длин панелей по текущему положению вершин
virtual void ReadFromFile(const std::string &dir) override
Считывание профиля из файла
const double IDPI
Число .
Definition: defs.h:76
const Wake & getWake() const
Возврат константной ссылки на вихревой след
Definition: World2D.h:197
std::vector< Point2D > v_
Скорости начал панелей
Definition: Airfoil2D.h:67
std::vector< double > gammaThrough
Суммарные циркуляции вихрей, пересекших панели профиля на прошлом шаге
Definition: Airfoil2D.h:196
double J
Полярный момент инерции профиля относительно центра масс
Definition: Airfoil2D.h:89
Point2D lowLeft
Левый нижний угол габаритного прямоугольника профиля
Definition: Airfoil2D.h:190
const size_t numberInPassport
Номер профиля в паспорте
Definition: Airfoil2D.h:74
Заголовочный файл с описанием класса AirfoilRect.
virtual void GetInfluenceFromVortexSheetAtRectPanelToVortex(size_t panel, const Vortex2D &vtx, Point2D &vel) const =0
Вычисление влияния вихревых слоев (свободный + присоединенный) конкретной прямолинейной панели на вих...
P length() const
Вычисление 2-нормы (длины) вектора
Definition: numvector.h:371
Заголовочный файл с описанием класса Preprocessor.
Класс, позволяющий выполнять предварительную обработку файлов
Definition: Preprocessor.h:59
Заголовочный файл с описанием класса Mechanics.
const Point2D & getR(size_t q) const
Возврат константной ссылки на вершину профиля
Definition: Airfoil2D.h:101
virtual void GetInfluenceFromVInfToPanel(std::vector< double > &vInfRhs) const override
Вычисление влияния набегающего потока на панель для правой части
virtual void GetInfluenceFromVorticesToPanel(size_t panel, const Vortex2D *ptr, ptrdiff_t count, std::vector< double > &panelRhs) const override
Вычисление влияния части подряд идущих вихрей из вихревого следа на панель для правой части ...
HD Point2D & r()
Функция для доступа к радиус-вектору вихря
Definition: Vortex2D.h:85
Шаблонный класс, определяющий матрицу фиксированного размера Фактически представляет собой массив...
Definition: nummatrix.h:62
HD double & g()
Функция для доступа к циркуляции вихря
Definition: Vortex2D.h:93
double Alpha(const Point2D &p, const Point2D &s)
Вспомогательная функция вычисления угла между векторами
Definition: defs.cpp:259
size_t getNumberOfPanels() const
Возврат количества панелей на профиле
Definition: Airfoil2D.h:139
auto length2() const -> typename std::remove_const< typename std::remove_reference< decltype(this->data[0])>::type >::type
Вычисление квадрата нормы (длины) вектора
Definition: numvector.h:383
const double IQPI
Число .
Definition: defs.h:82
virtual void Scale(const Point2D &) override
Масштабирование профиля
size_t requiredNPanels
Желаемое число панелей для разбиения геометрии
Definition: Passport2D.h:219
double angle
Угол поворота (угол атаки)
Definition: Passport2D.h:231
Point2D upRight
Правый верхний угол габаритного прямоугольника профиля
Definition: Airfoil2D.h:191
virtual std::vector< double > getA(size_t p, size_t i, const Airfoil &airfoil, size_t j) const override
Вычисление коэффициентов матрицы A для расчета влияния панели на панель
std::vector< VortexesParams > virtualVortexesParams
Вектор струтур, определяющий параметры виртуальных вихрей для профилей
Definition: Velocity2D.h:108
Point2D Omega(const Point2D &a, const Point2D &b, const Point2D &c)
Вспомогательная функция вычисления величины .
Definition: defs.cpp:271
T sqr(T x)
Возведение числа в квадрат
Definition: defs.h:430
virtual void GetDiffVelocityI0I3ToSetOfPointsAndViscousStresses(const WakeDataBase &pointsDb, std::vector< double > &domainRadius, std::vector< double > &I0, std::vector< Point2D > &I3) override
Вычисление числителей и знаменателей диффузионных скоростей в заданном наборе точек, обусловленных геометрией профиля, и вычисление вязкого трения
double Lambda(const Point2D &p, const Point2D &s)
Вспомогательная функция вычисления логарифма отношения норм векторов
Definition: defs.cpp:265
const Boundary & getBoundary(size_t i) const
Возврат константной ссылки на объект граничного условия
Definition: World2D.h:153
virtual void Move(const Point2D &dr) override
Перемещение профиля
virtual void GetInfluenceFromVortexSheetToVortex(size_t panel, const Vortex2D &vtx, Point2D &vel) const override
Вычисление влияния вихревых слоев (свободный + присоединенный) конкретной прямолинейной панели на вих...
size_t getNumberOfAirfoil() const
Возврат количества профилей в задаче
Definition: World2D.h:147
Definition: Airfoil2D.h:45
Заголовочный файл с описанием класса StreamParser.
std::vector< Vortex2D > vtx
Список вихревых элементов
virtual bool IsPointInAirfoil(const Point2D &point) const override
Определяет, находится ли точка с радиус-вектором внутри профиля
Velocity & getNonConstVelocity() const
Возврат неконстантной ссылки на объект для вычисления скоростей
Definition: World2D.h:217
Point2D basePoint
Смещение центра масс (перенос профиля)
Definition: Passport2D.h:222
std::vector< Point2D > r_
Координаты начал панелей
Definition: Airfoil2D.h:64
Класс, опеделяющий двумерный вектор
Definition: Point2D.h:75
bool fileExistTest(std::string &fileName, LogStream &info, const std::list< std::string > &extList={})
Проверка существования файла
Definition: defs.h:324
auto unit(P newlen=1) const -> numvector< typename std::remove_const< decltype(this->data[0]*newlen)>::type, n >
Вычисление орта вектора или вектора заданной длины, коллинеарного данному
Definition: numvector.h:399
std::vector< Point2D > tau
Касательные к панелям профиля
Definition: Airfoil2D.h:182
Структура, задающая параметры профиля
Definition: Passport2D.h:213
virtual void GetInfluenceFromSourceSheetToVortex(size_t panel, const Vortex2D &vtx, Point2D &vel) const override
Вычисление влияния слоя источников конкретной прямолинейной панели на вихрь в области течения ...
virtual void GetInfluenceFromSourcesToPanel(size_t panel, const Vortex2D *ptr, ptrdiff_t count, std::vector< double > &panelRhs) const override
Вычисление влияния части подряд идущих источников из области течения на панель для правой части ...
VMlib::LogStream & getInfo() const
Возврат ссылки на объект LogStream Используется в техничеcких целях для организации вывода ...
Definition: WorldGen.h:74
virtual void GetInfluenceFromVInfToRectPanel(std::vector< double > &vInfRhs) const =0
Вычисление влияния набегающего потока на прямолинейную панель для правой части
Заголовочный файл с описанием класса MeasureVP.
double phiAfl
Поворот профиля
Definition: Airfoil2D.h:80
const Passport & getPassport() const
Возврат константной ссылки на паспорт
Definition: World2D.h:222
const Gpu & getCuda() const
Возврат константной ссылки на объект, связанный с видеокартой (GPU)
Definition: World2D.h:227
Класс, опеделяющий двумерный вихревой элемент
Definition: Vortex2D.h:51
Point2D rcm
Положение центра масс профиля
Definition: Airfoil2D.h:77
VirtualWake virtualWake
Виртуальный вихревой след конкретного профиля
Definition: Boundary2D.h:85
std::vector< Point2D > nrm
Нормали к панелям профиля
Definition: Airfoil2D.h:177
std::string fileAirfoil
Имя файла с начальным состоянием профилей (без полного пути)
Definition: Passport2D.h:216
Абстрактный класс, определяющий обтекаемый профиль
Definition: Airfoil2D.h:60
virtual void GetInfluenceFromSourceSheetAtRectPanelToVortex(size_t panel, const Vortex2D &vtx, Point2D &vel) const =0
Вычисление влияния слоя источников конкретной прямолинейной панели на вихрь в области течения ...
std::vector< double > meanEpsOverPanel
Средние значения Eps на панелях
Definition: Airfoil2D.h:92
const Airfoil & getAirfoil(size_t i) const
Возврат константной ссылки на объект профиля
Definition: World2D.h:130
std::vector< AirfoilParams > airfoilParams
Список структур с параметрами профилей
Definition: Passport2D.h:280
Класс, опеделяющий набор вихрей
WakeDiscretizationProperties wakeDiscretizationProperties
Структура с параметрами дискретизации вихревого следа
Definition: Passport2D.h:299
std::vector< double > len
Длины панелей профиля
Definition: Airfoil2D.h:185
Заголовочный файл с описанием класса Velocity.
Point2D scale
Коэффициент масштабирования
Definition: Passport2D.h:225
bool isAfter(size_t i, size_t j) const
Проверка, идет ли вершина i следом за вершиной j.
Definition: Airfoil2D.cpp:62
Airfoil & getNonConstAirfoil(size_t i) const
Возврат неконстантной ссылки на объект профиля
Definition: World2D.h:142
Класс, позволяющий выполнять разбор файлов и строк с настройками и параметрами
Definition: StreamParser.h:151
Заголовочный файл с описанием класса Boundary.
virtual void GetDiffVelocityI0I3ToWakeAndViscousStresses(const WakeDataBase &pointsDb, std::vector< double > &domainRadius, std::vector< double > &I0, std::vector< Point2D > &I3) override
double getMinEpsAst() const
Функция минимально возможного значения для epsAst.
Definition: Passport2D.h:166