54 #include "spline/spline.h" 63 std::ifstream airfoilFile;
85 std::vector<Point2D> rFromFile;
86 airfoilParser.get(
"r", rFromFile);
88 if (rFromFile.size() > 0)
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]);
99 if ((
r_.back() -
r_.front()).length2() < 1e-12)
100 r_.resize(
r_.size() - 1);
104 W.
getInfo(
'e') <<
"Airfoil shape is given explicitely, it can not be automatically split!" << std::endl;
111 std::vector<GeomPoint> geomFromFile;
118 airfoilParser.get(
"geometry", geomFromFile);
120 if ((geomFromFile.front().r - geomFromFile.back().r).length2() < 1e-12)
121 geomFromFile.resize(geomFromFile.size() - 1);
127 std::vector<double> L(geomFromFile.size());
128 double totalLength = 0.0;
129 std::vector<size_t> nc = {};
130 std::vector<size_t> ni = {};
132 for (
size_t i = 0; i < geomFromFile.size(); ++i)
134 const Point2D& p1 = geomFromFile[i].r;
135 const Point2D& p2 = geomFromFile[(i + 1) % geomFromFile.size()].r;
137 L[i] = (p2 - p1).length();
144 std::vector<size_t> splineStart, splineFinish;
146 while (i < geomFromFile.size())
148 while (i < geomFromFile.size() && !(geomFromFile[i].type ==
"c"))
151 if (i < geomFromFile.size())
153 splineStart.push_back(i);
156 while (i < geomFromFile.size() && !(geomFromFile[i].type ==
"c"))
159 splineFinish.push_back(i);
163 if ((splineStart.size() > 0) && (splineStart[0] != 0))
164 splineFinish.back() = splineStart[0];
170 r_.reserve(geomFromFile.size());
171 for (
size_t i = 0; i < geomFromFile.size(); ++i)
172 r_.push_back(geomFromFile[i].r);
176 double hRef = totalLength / reqN;
178 std::vector<int> nPanels;
180 bool cyclic = (splineStart.size() == 0);
184 splineStart.push_back(0);
185 splineFinish.push_back(geomFromFile.size());
188 for (
size_t s = 0; s < splineStart.size(); ++s)
191 std::vector<double> T, X, Y;
193 size_t splineLegs = splineFinish[s] - splineStart[s];
194 if (splineFinish[s] <= splineStart[s])
195 splineLegs += geomFromFile.size();
197 T.reserve(splineLegs + 1);
203 for (
size_t i = splineStart[s]; i <= splineStart[s] + splineLegs; ++i)
205 const Point2D& pt = geomFromFile[i % geomFromFile.size()].r;
211 if ((i == splineStart[s]) && (splineFinish[s] - splineStart[s] == 1))
213 double halfL = (i < geomFromFile.size()) ? 0.5 * L[i] : 0.5 * (geomFromFile.front().r - geomFromFile.back().r).length();
216 Point2D nextPt = geomFromFile[(i + 1) % geomFromFile.size()].r;
218 X.push_back(0.5 * (pt[0] + nextPt[0]));
219 Y.push_back(0.5 * (pt[1] + nextPt[1]));
224 tbuf += (i < geomFromFile.size()) ? L[i] : (geomFromFile.front().r - geomFromFile.back().r).length();
232 s1.set_boundary(tk::spline::cyclic);
233 s2.set_boundary(tk::spline::cyclic);
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);
244 int NumberOfPanelsSpline = (int)ceil(T.back() / hRef);
245 double hSpline = T.back() / NumberOfPanelsSpline;
247 for (
int i = 0; i < NumberOfPanelsSpline; ++i)
248 r_.push_back({ s1(hSpline * i), s2(hSpline * i) });
250 nPanels.push_back(NumberOfPanelsSpline);
265 W.
getInfo(
'e') <<
"No points on airfoil contour!" << std::endl;
270 std::reverse(
r_.begin(),
r_.end());
274 for (
size_t q = 0; q <
r_.size(); ++q)
275 v_.push_back({ 0.0, 0.0 });
280 double rotationAngle = param.
angle;
282 rotationAngle = -param.
angle - 0.5 *
PI;
292 for (
size_t q = 0; q <
r_.size(); ++q)
296 area += fabs(cntq[0] * drq[1] - cntq[1] * drq[0]);
305 std::vector<double> selfI0;
306 std::vector<Point2D> selfI3;
308 std::vector<double> currViscousStress;
309 currViscousStress.resize(
r_.size(), 0.0);
312 selfI0.resize(pointsDb.
vtx.size(), 0.0);
313 selfI3.resize(pointsDb.
vtx.size(), { 0.0, 0.0 });
315 #pragma warning (push) 316 #pragma warning (disable: 4101) 319 double lxi, lxi_m, lenj_m;
329 double iDDomRad, domRad, expon;
330 #pragma warning (pop) 332 #pragma omp parallel for \ 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)
341 iDDomRad = 1.0 / domRad;
343 for (
size_t j = 0; j <
r_.size(); ++j)
346 q = vtxI.
r() - 0.5 * (
getR(j) +
getR(j + 1));
350 d = fabs(q &
nrm[j]);
352 if ((d < 50.0 *
len[j]) && (fabs(s) < 50.0 *
len[j]))
356 if ((d > 5.0 * len[j]) || (fabs(s) > 5.0 * len[j]))
361 expon = exp(-lxi) * len[j];
364 if (selfI0[i] != -
PI * domRad)
366 selfI0[i] += (xi & mn) * (lxi + 1.0) / (lxi * lxi);
372 else if ((d >= 0.1 * len[j]) || (fabs(s) > 0.5 * len[j]))
375 double den = (fabs(s) < 0.5 * len[j]) ? d : (fabs(s) + d - 0.5 * len[j]);
377 new_n = std::max(1, static_cast<int>(ceil(5.0 * len[j] / den)));
379 h = v0 * (1.0 / new_n);
381 for (
int m = 0;
m < new_n; ++
m)
383 xi_m = (vtxI.
r() - (
getR(j) + h * (
m + 0.5))) * iDDomRad;
386 lenj_m = len[j] / new_n;
387 expon = exp(-lxi_m) * lenj_m;
390 if (selfI0[i] != -
PI * domRad)
392 selfI0[i] += (xi_m & mn) * (lxi_m + 1.0) / (lxi_m * lxi_m);
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;
410 currViscousStress[j] += vs;
421 for (
size_t i = 0; i < I0.size(); ++i)
425 if (I0[i] != -
PI * domRad)
427 if (selfI0[i] == -
PI * domRad)
454 #if defined(USE_CUDA) 455 void AirfoilRect::GPUGetDiffVelocityI0I3ToSetOfPointsAndViscousStresses(
const WakeDataBase& pointsDb, std::vector<double>& domainRadius, std::vector<double>& I0, std::vector<Point2D>& I3)
457 std::vector<double> newViscousStress;
469 size_t npt = pointsDb.
vtx.size();
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;
483 double*& dev_ptr_i0 = pointsDb.devI0Ptr;
484 double*& dev_ptr_i3 = pointsDb.devI3Ptr;
492 std::vector<Point2D> newI3(npt);
493 std::vector<double> newI0(npt);
494 newViscousStress.resize(nTotPan);
498 if ((npt > 0) && (nr > 0))
500 double*& dev_ptr_visstr = devViscousStressesPtr;
502 std::vector<double> locvisstr(nTotPan);
504 std::vector<double> zeroVec(nTotPan, 0.0);
505 cuCopyFixedArray(dev_ptr_visstr, zeroVec.data(), nTotPan *
sizeof(double));
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);
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());
516 for (
size_t q = 0; q < I3.size(); ++q)
525 size_t curCounter = 0;
538 size_t curGlobPnl = 0;
543 tmpVisStress.resize(0);
544 tmpVisStress.insert(tmpVisStress.end(), newViscousStress.begin() + curGlobPnl, newViscousStress.begin() + curGlobPnl + np);
562 double sumAngle = 0.0;
566 for (
size_t i = 0; i <
r_.size(); ++i)
568 v1 =
getR(i) - point;
569 v2 =
getR(i+1) - point;
570 sumAngle += atan2(v1^v2, v1 & v2);
573 if (fabs(sumAngle) < 0.1)
582 for (
size_t i = 0; i <
r_.size(); ++i)
596 for (
size_t i = 0; i <
r_.size(); ++i)
608 for (
size_t i = 0; i <
r_.size(); ++i)
618 if (
nrm.size() !=
r_.size())
620 nrm.resize(
r_.size());
621 tau.resize(
r_.size());
622 len.resize(
r_.size());
627 for (
size_t i = 0; i <
r_.size(); ++i)
648 for (
size_t i = 0; i <
r_.size(); ++i)
667 std::vector<double> res(p*p, 0.0);
669 if ( (i == j) && (&airfoil ==
this))
671 res[0] = 0.5 * (
tau[i] ^
nrm[i]);
675 res[3] = (1.0 / 12.0) * res[0];
686 res[0] = miq.first(i, j);
710 bool self = (&otherAirfoil ==
this);
721 Point2D p1, s1, p2, s2, di, dj, i00, i01, i10, i11;
725 #pragma omp parallel for \ 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) 735 if ((i == j) &&
self)
738 matrPair.first(i, j) = 0.0;
739 matrPair.second(i, j) = 0.0;
743 matrPair.first(i, npJ + j) = 0.0;
744 matrPair.first(npI + i, j) = 0.0;
746 matrPair.second(i, npJ + j) = -
IQPI;
747 matrPair.second(npI + i, j) =
IQPI;
749 matrPair.first(npI + i, npJ + j) = 0.0;
750 matrPair.second(npI + i, npJ + j) = 0.0;
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);
766 dj = otherAirfoil.
getR(j + 1) - otherAirfoil.
getR(j);
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]));
789 matrPair.first(i, j) = i00 &
nrm[i];
790 matrPair.second(i, j) = i00 & taui;
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);
803 matrPair.first(i, npJ + j) = i01 & nrm[i];
804 matrPair.second(i, npJ + j) = i01 & taui;
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);
815 matrPair.first(npI + i, j) = i10 & nrm[i];
816 matrPair.second(npI + i, j) = i10 & taui;
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] \
829 matrPair.first(npI + i, npJ + j) = i11 & nrm[i];
830 matrPair.second(npI + i, npJ + j) = i11 & taui;
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.
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
Касательные напряжения на панелях профиля
Шаблонный класс, определяющий вектор фиксированной длины Фактически представляет собой массив...
bool geographicalAngles
Признак работы в "географической" системе координат
Заголовочный файл с описанием класса Wake.
virtual void GetInfluenceFromVorticesToRectPanel(size_t panel, const Vortex2D *ptr, ptrdiff_t count, std::vector< double > &wakeRhs) const =0
Вычисление влияния части подряд идущих вихрей из вихревого следа на прямолинейную панель для правой ч...
bool inverse
Признак разворота нормалей (для расчета внутреннего течения)
Заголовочный файл с описанием класса World2D.
double area
Площадь профиля
bool inverse
Признак разворота нормалей (для расчета внутренних течений)
Описание класса nummatrix.
const World2D & W
Константная ссылка на решаемую задачу
void CalcNrmTauLen()
Вычисление нормалей, касательных и длин панелей по текущему положению вершин
virtual void ReadFromFile(const std::string &dir) override
Считывание профиля из файла
const Wake & getWake() const
Возврат константной ссылки на вихревой след
std::vector< Point2D > v_
Скорости начал панелей
std::vector< double > gammaThrough
Суммарные циркуляции вихрей, пересекших панели профиля на прошлом шаге
double J
Полярный момент инерции профиля относительно центра масс
Point2D lowLeft
Левый нижний угол габаритного прямоугольника профиля
const size_t numberInPassport
Номер профиля в паспорте
Заголовочный файл с описанием класса AirfoilRect.
virtual void GetInfluenceFromVortexSheetAtRectPanelToVortex(size_t panel, const Vortex2D &vtx, Point2D &vel) const =0
Вычисление влияния вихревых слоев (свободный + присоединенный) конкретной прямолинейной панели на вих...
P length() const
Вычисление 2-нормы (длины) вектора
Заголовочный файл с описанием класса Preprocessor.
Класс, позволяющий выполнять предварительную обработку файлов
Заголовочный файл с описанием класса Mechanics.
const Point2D & getR(size_t q) const
Возврат константной ссылки на вершину профиля
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()
Функция для доступа к радиус-вектору вихря
Шаблонный класс, определяющий матрицу фиксированного размера Фактически представляет собой массив...
HD double & g()
Функция для доступа к циркуляции вихря
double Alpha(const Point2D &p, const Point2D &s)
Вспомогательная функция вычисления угла между векторами
size_t getNumberOfPanels() const
Возврат количества панелей на профиле
auto length2() const -> typename std::remove_const< typename std::remove_reference< decltype(this->data[0])>::type >::type
Вычисление квадрата нормы (длины) вектора
virtual void Scale(const Point2D &) override
Масштабирование профиля
size_t requiredNPanels
Желаемое число панелей для разбиения геометрии
double angle
Угол поворота (угол атаки)
Point2D upRight
Правый верхний угол габаритного прямоугольника профиля
virtual std::vector< double > getA(size_t p, size_t i, const Airfoil &airfoil, size_t j) const override
Вычисление коэффициентов матрицы A для расчета влияния панели на панель
std::vector< VortexesParams > virtualVortexesParams
Вектор струтур, определяющий параметры виртуальных вихрей для профилей
Point2D Omega(const Point2D &a, const Point2D &b, const Point2D &c)
Вспомогательная функция вычисления величины .
T sqr(T x)
Возведение числа в квадрат
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)
Вспомогательная функция вычисления логарифма отношения норм векторов
const Boundary & getBoundary(size_t i) const
Возврат константной ссылки на объект граничного условия
virtual void Move(const Point2D &dr) override
Перемещение профиля
virtual void GetInfluenceFromVortexSheetToVortex(size_t panel, const Vortex2D &vtx, Point2D &vel) const override
Вычисление влияния вихревых слоев (свободный + присоединенный) конкретной прямолинейной панели на вих...
size_t getNumberOfAirfoil() const
Возврат количества профилей в задаче
Заголовочный файл с описанием класса StreamParser.
std::vector< Vortex2D > vtx
Список вихревых элементов
virtual bool IsPointInAirfoil(const Point2D &point) const override
Определяет, находится ли точка с радиус-вектором внутри профиля
Velocity & getNonConstVelocity() const
Возврат неконстантной ссылки на объект для вычисления скоростей
Point2D basePoint
Смещение центра масс (перенос профиля)
std::vector< Point2D > r_
Координаты начал панелей
Класс, опеделяющий двумерный вектор
bool fileExistTest(std::string &fileName, LogStream &info, const std::list< std::string > &extList={})
Проверка существования файла
auto unit(P newlen=1) const -> numvector< typename std::remove_const< decltype(this->data[0]*newlen)>::type, n >
Вычисление орта вектора или вектора заданной длины, коллинеарного данному
std::vector< Point2D > tau
Касательные к панелям профиля
Структура, задающая параметры профиля
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ких целях для организации вывода ...
virtual void GetInfluenceFromVInfToRectPanel(std::vector< double > &vInfRhs) const =0
Вычисление влияния набегающего потока на прямолинейную панель для правой части
Заголовочный файл с описанием класса MeasureVP.
double phiAfl
Поворот профиля
const Passport & getPassport() const
Возврат константной ссылки на паспорт
const Gpu & getCuda() const
Возврат константной ссылки на объект, связанный с видеокартой (GPU)
Класс, опеделяющий двумерный вихревой элемент
Point2D rcm
Положение центра масс профиля
VirtualWake virtualWake
Виртуальный вихревой след конкретного профиля
std::vector< Point2D > nrm
Нормали к панелям профиля
std::string fileAirfoil
Имя файла с начальным состоянием профилей (без полного пути)
Абстрактный класс, определяющий обтекаемый профиль
virtual void GetInfluenceFromSourceSheetAtRectPanelToVortex(size_t panel, const Vortex2D &vtx, Point2D &vel) const =0
Вычисление влияния слоя источников конкретной прямолинейной панели на вихрь в области течения ...
std::vector< double > meanEpsOverPanel
Средние значения Eps на панелях
const Airfoil & getAirfoil(size_t i) const
Возврат константной ссылки на объект профиля
std::vector< AirfoilParams > airfoilParams
Список структур с параметрами профилей
Класс, опеделяющий набор вихрей
WakeDiscretizationProperties wakeDiscretizationProperties
Структура с параметрами дискретизации вихревого следа
std::vector< double > len
Длины панелей профиля
Заголовочный файл с описанием класса Velocity.
Point2D scale
Коэффициент масштабирования
bool isAfter(size_t i, size_t j) const
Проверка, идет ли вершина i следом за вершиной j.
Airfoil & getNonConstAirfoil(size_t i) const
Возврат неконстантной ссылки на объект профиля
Класс, позволяющий выполнять разбор файлов и строк с настройками и параметрами
Заголовочный файл с описанием класса Boundary.
virtual void GetDiffVelocityI0I3ToWakeAndViscousStresses(const WakeDataBase &pointsDb, std::vector< double > &domainRadius, std::vector< double > &I0, std::vector< Point2D > &I3) override
double getMinEpsAst() const
Функция минимально возможного значения для epsAst.