VM2D 1.14
Vortex methods for 2D flows simulation
Loading...
Searching...
No Matches
Velocity2DBiotSavart.cpp
Go to the documentation of this file.
1/*--------------------------------*- VM2D -*-----------------*---------------*\
2| ## ## ## ## #### ##### | | Version 1.14 |
3| ## ## ### ### ## ## ## ## | VM2D: Vortex Method | 2026/03/06 |
4| ## ## ## # ## ## ## ## | for 2D Flow Simulation *----------------*
5| #### ## ## ## ## ## | Open Source Code |
6| ## ## ## ###### ##### | https://www.github.com/vortexmethods/VM2D |
7| |
8| Copyright (C) 2017-2026 I. Marchevsky, K. Sokol, E. Ryatina, A. Kolganova |
9*-----------------------------------------------------------------------------*
10| File name: Velocity2DBiotSavart.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
41
42#include "Airfoil2D.h"
43#include "Boundary2D.h"
44#include "MeasureVP2D.h"
45#include "Mechanics2D.h"
46#include "StreamParser.h"
47#include "Wake2D.h"
48#include "World2D.h"
49#include "Gmres2D.h"
50
51using namespace VM2D;
52
58
63
64
65inline void ModifyE2(double* ee2, double dst2)
66{
67 if (dst2 > 0)
68 {
69 if (dst2 < ee2[0])
70 {
71 ee2[2] = ee2[1];
72 ee2[1] = ee2[0];
73 ee2[0] = dst2;
74 }//if (dist2<ee2[0])
75 else
76 {
77 if (dst2 < ee2[1])
78 {
79 ee2[2] = ee2[1];
80 ee2[1] = dst2;
81 }// if (dist2<ee2[1])
82 else
83 if (dst2 < ee2[2])
84 ee2[2] = dst2;
85 }//else
86 }//if (dst2>0)
87}
88
89
90
91//Вычисление конвективных скоростей и радиусов вихревых доменов в заданном наборе точек от следа
92float VelocityBiotSavart::CalcConvVeloToSetOfPointsFromWake(const WakeDataBase& pointsDb, std::vector<Point2D>& velo, std::vector<double>& domainRadius, bool calcVelo, bool calcRadius)
93{
94 std::vector<Point2D> selfVelo(pointsDb.vtx.size());
95 domainRadius.resize(pointsDb.vtx.size());
96
97 double cft = IDPI;
98
99#pragma warning (push)
100#pragma warning (disable: 4101)
101 //Локальные переменные для цикла
102 Point2D velI;
103 Point2D tempVel;
104 double dst2eps, dst2;
105#pragma warning (pop)
106
107 VMlib::vmTimer timer;
108 timer.start();
109
110 if (calcVelo)
111 {
112#pragma omp parallel for default(none) shared(selfVelo, cft, calcVelo, calcRadius, pointsDb, domainRadius) private(tempVel, velI, dst2, dst2eps) schedule(dynamic, DYN_SCHEDULE)
113 for (int i = 0; i < pointsDb.vtx.size(); ++i)
114 {
115 double ee2[3] = { 10000.0, 10000.0, 10000.0 };
116
117 velI.toZero();
118
119 const Point2D& posI = pointsDb.vtx[i].r();
120
121 for (size_t j = 0; j < W.getWake().vtx.size(); ++j)
122 {
123 const Point2D& posJ = W.getWake().vtx[j].r();
124
125 dst2 = (posI - posJ).length2();
126
127 //Модифицируем массив квадратов расстояний до ближайших вихрей из wake
128#ifndef TESTONLYVELO
129 if (calcRadius)
130 VMlib::ModifyE2(ee2, dst2);
131#endif
132
133 const double& gamJ = W.getWake().vtx[j].g();
134 const double sigmaJ2 = sqr(W.getWake().vtx[j].sigma());
135
136 tempVel.toZero();
137 dst2eps = VMlib::boundDenom(dst2, sigmaJ2); //Сглаживать надо!!!
138
139 tempVel = { -posI[1] + posJ[1], posI[0] - posJ[0] };
140 tempVel *= (gamJ / dst2eps);
141 velI += tempVel;
142 }
143
144 for (size_t j = 0; j < W.getSource().vtx.size(); ++j)
145 {
146 const Point2D& posJ = W.getSource().vtx[j].r();
147 const double& gamJ = W.getPassport().physicalProperties.accelCft(W.getCurrentTime()) * W.getSource().vtx[j].g();
148 const double sigmaJ2 = sqr(W.getSource().vtx[j].sigma());
149
150 tempVel.toZero();
151
152 dst2 = dist2(posI, posJ);
153 dst2eps = VMlib::boundDenom(dst2, sigmaJ2); //Сглаживать надо!!!
154
155 tempVel = { posI[0] - posJ[0], posI[1] - posJ[1] };
156 tempVel *= (gamJ / dst2eps);
157 velI += tempVel;
158 }
159#ifndef TESTONLYVELO
160 if (calcRadius)
161 {
162 for (size_t s = 0; s < W.getNumberOfBoundary(); ++s)
163 {
164 const auto& bou = W.getBoundary(s);
165 //Модифицируем массив квадратов расстояний до ближайших вихрей из virtualWake
166 for (size_t j = 0; j < bou.virtualWake.vtx.size(); ++j)
167 ModifyE2(ee2, dist2(posI, bou.virtualWake.vtx[j].r()));
168 }
169 }
170#endif
171
172 velI *= cft;
173 selfVelo[i] = velI;
174
175#ifndef TESTONLYVELO
176 if (calcRadius)
177 domainRadius[i] = 1.0 * sqrt((ee2[0] + ee2[1] + ee2[2]) / 3.0);
178#endif
179 }
180 }
181 else if (calcRadius)
182 {
183#pragma omp parallel for default(none) shared(selfVelo, cft, calcVelo, calcRadius, pointsDb, domainRadius) private(tempVel, velI, dst2) schedule(dynamic, DYN_SCHEDULE)
184 for (int i = 0; i < pointsDb.vtx.size(); ++i)
185 {
186 double ee2[3] = { 10000.0, 10000.0, 10000.0 };
187
188 velI.toZero();
189
190 const Point2D& posI = pointsDb.vtx[i].r();
191
192 for (size_t j = 0; j < W.getWake().vtx.size(); ++j)
193 {
194 const Point2D& posJ = W.getWake().vtx[j].r();
195
196 dst2 = dist2(posI, posJ);
197
198 //Модифицируем массив квадратов расстояний до ближайших вихрей из wake
199 VMlib::ModifyE2(ee2, dst2);
200 }
201
202 for (size_t s = 0; s < W.getNumberOfBoundary(); ++s)
203 {
204 for (size_t j = 0; j < W.getBoundary(s).virtualWake.vtx.size(); ++j)
205 {
206 const Point2D& posJ = W.getBoundary(s).virtualWake.vtx[j].r();
207 dst2 = dist2(posI, posJ);
208
209 //Модифицируем массив квадратов расстояний до ближайших вихрей из virtualWake
210 ModifyE2(ee2, dst2);
211 }
212 }
213
214 domainRadius[i] = 1.0 * sqrt((ee2[0] + ee2[1] + ee2[2]) / 3.0);
215 }
216 } //else
217
218
219 timer.stop();
220
221 if (calcVelo)
222 for (size_t i = 0; i < velo.size(); ++i)
223 velo[i] += selfVelo[i];
224
225#ifdef USE_CUDA
226 if (calcVelo)
227 W.getCuda().CopyMemToDev<double, 2>(velo.size(), (double*)velo.data(), pointsDb.devVelPtr);
228 if (calcRadius)
229 W.getCuda().CopyMemToDev<double, 1>(domainRadius.size(), domainRadius.data(), pointsDb.devRadPtr);
230#endif
231 return (float)timer.duration();
232}//CalcConvVeloToSetOfPointsFromWake(...)
233
234
235
236
237#if defined(USE_CUDA)
238double VelocityBiotSavart::GPUCalcConvVeloToSetOfPointsFromWake(std::unique_ptr<BHcu::CudaTreeInfo>& cntrTree, const WakeDataBase& pointsDb, std::vector<Point2D>& velo, std::vector<double>& domainRadius, bool calcVelo, bool calcRadius)
239{
240 VMlib::vmTimer timerA;
241
242 if ((&pointsDb == &W.getWake()) || (&pointsDb == &W.getBoundary(0).virtualWake) || (&pointsDb == &W.getMeasureVP().getWakeVP()))
243 {
244 size_t npt = pointsDb.vtx.size();
245 double*& dev_ptr_pt = pointsDb.devVtxPtr;
246
247 if ((W.getNumberOfBoundary() > 0) && (&pointsDb == &W.getBoundary(0).virtualWake))
248 {
249 for (size_t q = 1; q < W.getNumberOfBoundary(); ++q)
250 npt += W.getBoundary(q).virtualWake.vtx.size();
251 }
252
253 const size_t nvt = W.getWake().vtx.size();
254 double*& dev_ptr_vt = W.getWake().devVtxPtr;
255 const size_t nsr = W.getSource().vtx.size();
256 double*& dev_ptr_sr = W.getSource().devVtxPtr;
257 const size_t nbou = W.getNumberOfBoundary();
258
259 //size_t* const& dev_nPanels = W.getCuda().dev_ptr_nPanels;
260 size_t* const& dev_nVortices = W.getCuda().dev_ptr_nVortices;
261
262 double** const& dev_ptr_ptr_vtx = W.getCuda().dev_ptr_ptr_vtx;
263
264 std::vector<Point2D> Vel(npt);
265 std::vector<double> Rad(npt);
266 std::vector<Point2D> newV(npt);
267
268 double*& dev_ptr_vel = pointsDb.devVelPtr;
269 double*& dev_ptr_rad = pointsDb.devRadPtr;
270
271 if (npt > 0)
272 {
273 timerA.start();
274 cuCalculateConvVeloWake(npt, dev_ptr_pt, nvt, dev_ptr_vt, nsr, dev_ptr_sr, nbou, dev_nVortices, dev_ptr_ptr_vtx, dev_ptr_vel, dev_ptr_rad, calcVelo, calcRadius);
275 timerA.stop();
276
277 if (calcVelo)
278 {
279 W.getCuda().CopyMemFromDev<double, 2>(npt, dev_ptr_vel, (double*)newV.data(), 20);
280
281 for (size_t q = 0; q < npt; ++q)
282 Vel[q] = newV[q];
283
284 if ((&pointsDb == &W.getWake()) || (&pointsDb == &W.getMeasureVP().getWakeVP()))
285 {
286 for (size_t q = 0; q < npt; ++q)
287 velo[q] += Vel[q];
288 }//if &pointsDb
289 }//if calcVelo
290
291 if (calcRadius)
292 {
293 if ((&pointsDb == &W.getWake()) || (&pointsDb == &W.getMeasureVP().getWakeVP()))
294 {
295 Rad.resize(npt);
296 W.getCuda().CopyMemFromDev<double, 1>(npt, dev_ptr_rad, Rad.data(), 211);
297
298 for (size_t q = 0; q < Rad.size(); ++q)
299 domainRadius[q] = Rad[q];
300 }//if &pointsDb
301 }//if calcRadius
302 }//if npt > 0
303 }//if &pointsDb
304 return timerA.duration();
305}//GPUCalcConvVeloToSetOfPointsFromWake(...)
306#endif
Заголовочный файл с описанием класса Airfoil.
Заголовочный файл с описанием класса Boundary.
Заголовочный файл с функциями для метода GMRES.
Заголовочный файл с описанием класса MeasureVP.
Заголовочный файл с описанием класса Mechanics.
Заголовочный файл с описанием класса StreamParser.
const double IDPI
Число .
Definition defs.h:79
void ModifyE2(double *ee2, double dst2)
Заголовочный файл с описанием класса VelocityBiotSavart.
Заголовочный файл с описанием класса Wake.
Заголовочный файл с описанием класса World2D.
VirtualWake virtualWake
Виртуальный вихревой след конкретного профиля
Definition Boundary2D.h:86
const WakeDataBase & getWakeVP() const
Возврат wakeVP.
PhysicalProperties physicalProperties
Структура с физическими свойствами задачи
Definition Passport2D.h:301
virtual float CalcConvVeloToSetOfPointsFromWake(const WakeDataBase &pointsDb, std::vector< Point2D > &velo, std::vector< double > &domainRadius, bool calcVelo, bool calcRadius) override
Вычисление конвективных скоростей и радиусов вихревых доменов в заданном наборе точек от следа
virtual ~VelocityBiotSavart()
Деструктор
VelocityBiotSavart(const World2D &W_)
Конструктор
Абстрактный класс, определяющий способ вычисления скоростей
Definition Velocity2D.h:105
const World2D & W
Константная ссылка на решаемую задачу
Definition Velocity2D.h:108
Класс, опеделяющий набор вихрей
std::vector< Vortex2D > vtx
Список вихревых элементов
Класс, опеделяющий текущую решаемую задачу
Definition World2D.h:77
const Wake & getWake() const
Возврат константной ссылки на вихревой след
Definition World2D.h:232
const WakeDataBase & getSource() const
Возврат константной ссылки на источники в области течения
Definition World2D.h:248
const Gpu & getCuda() const
Возврат константной ссылки на объект, связанный с видеокартой (GPU)
Definition World2D.h:273
const Passport & getPassport() const
Возврат константной ссылки на паспорт
Definition World2D.h:263
const Boundary & getBoundary(size_t i) const
Возврат константной ссылки на объект граничного условия
Definition World2D.h:186
size_t getNumberOfBoundary() const
Возврат количества граничных условий в задаче
Definition World2D.h:197
const MeasureVP & getMeasureVP() const
Возврат константной ссылки на measureVP.
Definition World2D.h:208
double getCurrentTime() const
Definition WorldGen.h:100
numvector< T, n > & toZero(P val=0)
Установка всех компонент вектора в константу (по умолчанию — нуль)
Definition numvector.h:528
Класс засекания времени
Definition TimesGen.h:59
double duration() const
Definition TimesGen.h:143
const vmTimer & stop() const
Останов работающего счетчика времени
Definition TimesGen.h:125
const vmTimer & start() const
Запуск (первый или повторный) счетчика времени
Definition TimesGen.h:109
void ModifyE2(double *ee2, double dst2)
Модифицирует массив квадратов расстояний до ближайших вихрей из wake.
Definition defs.cpp:236
double boundDenom(double r2, double eps2)
Способ сглаживания скорости вихря (вихрь Рэнкина или вихрь Ламба)
Definition defs.h:569
double accelCft(double currentTime) const
Функция-множитель, позволяющая моделировать разгон