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
50#include "BarnesHut.h"
51
52using namespace VM2D;
53
59
64
65
66inline void ModifyE2(double* ee2, double dst2)
67{
68 if (dst2 > 0)
69 {
70 if (dst2 < ee2[0])
71 {
72 ee2[2] = ee2[1];
73 ee2[1] = ee2[0];
74 ee2[0] = dst2;
75 }//if (dist2<ee2[0])
76 else
77 {
78 if (dst2 < ee2[1])
79 {
80 ee2[2] = ee2[1];
81 ee2[1] = dst2;
82 }// if (dist2<ee2[1])
83 else
84 if (dst2 < ee2[2])
85 ee2[2] = dst2;
86 }//else
87 }//if (dst2>0)
88}
89
90
91
92//Вычисление конвективных скоростей и радиусов вихревых доменов в заданном наборе точек от следа
93void VelocityBiotSavart::CalcConvVeloToSetOfPointsFromWake(const WakeDataBase& pointsDb, std::vector<Point2D>& velo, std::vector<double>& domainRadius, bool calcVelo, bool calcRadius)
94{
95 std::vector<Point2D> selfVelo(pointsDb.vtx.size());
96 domainRadius.resize(pointsDb.vtx.size());
97
98 double cft = IDPI;
99
100#pragma warning (push)
101#pragma warning (disable: 4101)
102 //Локальные переменные для цикла
103 Point2D velI;
104 Point2D tempVel;
105 double dst2eps, dst2;
106#pragma warning (pop)
107
109
110 if (calcVelo)
111 {
112#pragma omp parallel for default(none) shared(selfVelo, cft, calcVelo, calcRadius, eps2, 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
135 tempVel.toZero();
136 dst2eps = VMlib::boundDenom(dst2, eps2); //Сглаживать надо!!!
137
138 tempVel = { -posI[1] + posJ[1], posI[0] - posJ[0] };
139 tempVel *= (gamJ / dst2eps);
140 velI += tempVel;
141 }
142
143 for (size_t j = 0; j < W.getSource().vtx.size(); ++j)
144 {
145 const Point2D& posJ = W.getSource().vtx[j].r();
146 const double& gamJ = W.getPassport().physicalProperties.accelCft(W.getCurrentTime()) * W.getSource().vtx[j].g();
147
148 tempVel.toZero();
149
150 dst2 = dist2(posI, posJ);
151 dst2eps = VMlib::boundDenom(dst2, W.getPassport().wakeDiscretizationProperties.eps2); //Сглаживать надо!!!
152
153 tempVel = { posI[0] - posJ[0], posI[1] - posJ[1] };
154 tempVel *= (gamJ / dst2eps);
155 velI += tempVel;
156 }
157#ifndef TESTONLYVELO
158 if (calcRadius)
159 {
160 for (size_t s = 0; s < W.getNumberOfBoundary(); ++s)
161 {
162 const auto& bou = W.getBoundary(s);
163 //Модифицируем массив квадратов расстояний до ближайших вихрей из virtualWake
164 for (size_t j = 0; j < bou.virtualWake.vtx.size(); ++j)
165 ModifyE2(ee2, dist2(posI, bou.virtualWake.vtx[j].r()));
166 }
167 }
168#endif
169
170 velI *= cft;
171 selfVelo[i] = velI;
172
173#ifndef TESTONLYVELO
174 if (calcRadius)
175 domainRadius[i] = 1.0 * sqrt((ee2[0] + ee2[1] + ee2[2]) / 3.0);
176#endif
177 }
178 }
179 else if (calcRadius)
180 {
181#pragma omp parallel for default(none) shared(selfVelo, cft, calcVelo, calcRadius, pointsDb, domainRadius) private(tempVel, velI, dst2) schedule(dynamic, DYN_SCHEDULE)
182 for (int i = 0; i < pointsDb.vtx.size(); ++i)
183 {
184 double ee2[3] = { 10000.0, 10000.0, 10000.0 };
185
186 velI.toZero();
187
188 const Point2D& posI = pointsDb.vtx[i].r();
189
190 for (size_t j = 0; j < W.getWake().vtx.size(); ++j)
191 {
192 const Point2D& posJ = W.getWake().vtx[j].r();
193
194 dst2 = dist2(posI, posJ);
195
196 //Модифицируем массив квадратов расстояний до ближайших вихрей из wake
197 VMlib::ModifyE2(ee2, dst2);
198 }
199
200 for (size_t s = 0; s < W.getNumberOfBoundary(); ++s)
201 {
202 for (size_t j = 0; j < W.getBoundary(s).virtualWake.vtx.size(); ++j)
203 {
204 const Point2D& posJ = W.getBoundary(s).virtualWake.vtx[j].r();
205 dst2 = dist2(posI, posJ);
206
207 //Модифицируем массив квадратов расстояний до ближайших вихрей из virtualWake
208 ModifyE2(ee2, dst2);
209 }
210 }
211
212 domainRadius[i] = 1.0 * sqrt((ee2[0] + ee2[1] + ee2[2]) / 3.0);
213 }
214 } //else
215
216
217 if (calcVelo)
218 for (size_t i = 0; i < velo.size(); ++i)
219 velo[i] += selfVelo[i];
220
221#ifdef USE_CUDA
222 if (calcVelo)
223 W.getCuda().CopyMemToDev<double, 2>(velo.size(), (double*)velo.data(), pointsDb.devVelPtr);
224 if (calcRadius)
225 W.getCuda().CopyMemToDev<double, 1>(domainRadius.size(), domainRadius.data(), pointsDb.devRadPtr);
226#endif
227
228}//CalcConvVeloToSetOfPointsFromWake(...)
229
230
231
232
233#if defined(USE_CUDA)
234void VelocityBiotSavart::GPUCalcConvVeloToSetOfPointsFromWake(std::unique_ptr<BHcu::CudaTreeInfo>& cntrTree, const WakeDataBase& pointsDb, std::vector<Point2D>& velo, std::vector<double>& domainRadius, bool calcVelo, bool calcRadius)
235{
236 if ((&pointsDb == &W.getWake()) || (&pointsDb == &W.getBoundary(0).virtualWake) || (&pointsDb == &W.getMeasureVP().getWakeVP()))
237 {
238 size_t npt = pointsDb.vtx.size();
239 double*& dev_ptr_pt = pointsDb.devVtxPtr;
240
241 if ((W.getNumberOfBoundary() > 0) && (&pointsDb == &W.getBoundary(0).virtualWake))
242 {
243 for (size_t q = 1; q < W.getNumberOfBoundary(); ++q)
244 npt += W.getBoundary(q).virtualWake.vtx.size();
245 }
246
247 const size_t nvt = W.getWake().vtx.size();
248 double*& dev_ptr_vt = W.getWake().devVtxPtr;
249 const size_t nsr = W.getSource().vtx.size();
250 double*& dev_ptr_sr = W.getSource().devVtxPtr;
251 const size_t nbou = W.getNumberOfBoundary();
252
253 //size_t* const& dev_nPanels = W.getCuda().dev_ptr_nPanels;
254 size_t* const& dev_nVortices = W.getCuda().dev_ptr_nVortices;
255
256 double** const& dev_ptr_ptr_vtx = W.getCuda().dev_ptr_ptr_vtx;
257
258 std::vector<Point2D> Vel(npt);
259 std::vector<double> Rad(npt);
260 std::vector<Point2D> newV(npt);
261
262 double*& dev_ptr_vel = pointsDb.devVelPtr;
263 double*& dev_ptr_rad = pointsDb.devRadPtr;
264 const double& eps2 = W.getPassport().wakeDiscretizationProperties.eps2;
265
266 if (npt > 0)
267 {
268 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, eps2, calcVelo, calcRadius);
269
270 if (calcVelo)
271 {
272 W.getCuda().CopyMemFromDev<double, 2>(npt, dev_ptr_vel, (double*)newV.data(), 20);
273
274 for (size_t q = 0; q < npt; ++q)
275 Vel[q] = newV[q];
276
277 if ((&pointsDb == &W.getWake()) || (&pointsDb == &W.getMeasureVP().getWakeVP()))
278 {
279 for (size_t q = 0; q < npt; ++q)
280 velo[q] += Vel[q];
281 }//if &pointsDb
282 }//if calcVelo
283
284 if (calcRadius)
285 {
286 if ((&pointsDb == &W.getWake()) || (&pointsDb == &W.getMeasureVP().getWakeVP()))
287 {
288 Rad.resize(npt);
289 W.getCuda().CopyMemFromDev<double, 1>(npt, dev_ptr_rad, Rad.data(), 211);
290
291 for (size_t q = 0; q < Rad.size(); ++q)
292 domainRadius[q] = Rad[q];
293 }//if &pointsDb
294 }//if calcRadius
295 }//if npt > 0
296 }//if &pointsDb
297}//GPUCalcConvVeloToSetOfPointsFromWake(...)
298#endif
Заголовочный файл с описанием класса Airfoil.
Заголовок основного класса BarnesHut.
Заголовочный файл с описанием класса Boundary.
Заголовочный файл с описанием класса MeasureVP.
Заголовочный файл с описанием класса Mechanics.
Заголовочный файл с описанием класса StreamParser.
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:289
WakeDiscretizationProperties wakeDiscretizationProperties
Структура с параметрами дискретизации вихревого следа
Definition Passport2D.h:292
virtual ~VelocityBiotSavart()
Деструктор
VelocityBiotSavart(const World2D &W_)
Конструктор
virtual void CalcConvVeloToSetOfPointsFromWake(const WakeDataBase &pointsDb, std::vector< Point2D > &velo, std::vector< double > &domainRadius, bool calcVelo, bool calcRadius) override
Вычисление конвективных скоростей и радиусов вихревых доменов в заданном наборе точек от следа
Абстрактный класс, определяющий способ вычисления скоростей
Definition Velocity2D.h:105
const World2D & W
Константная ссылка на решаемую задачу
Definition Velocity2D.h:108
Класс, опеделяющий набор вихрей
std::vector< Vortex2D > vtx
Список вихревых элементов
Класс, опеделяющий текущую решаемую задачу
Definition World2D.h:74
const Wake & getWake() const
Возврат константной ссылки на вихревой след
Definition World2D.h:226
const WakeDataBase & getSource() const
Возврат константной ссылки на источники в области течения
Definition World2D.h:236
const Gpu & getCuda() const
Возврат константной ссылки на объект, связанный с видеокартой (GPU)
Definition World2D.h:261
const Passport & getPassport() const
Возврат константной ссылки на паспорт
Definition World2D.h:251
const Boundary & getBoundary(size_t i) const
Возврат константной ссылки на объект граничного условия
Definition World2D.h:180
size_t getNumberOfBoundary() const
Возврат количества граничных условий в задаче
Definition World2D.h:191
const MeasureVP & getMeasureVP() const
Возврат константной ссылки на measureVP.
Definition World2D.h:202
double getCurrentTime() const
Definition WorldGen.h:100
numvector< T, n > & toZero(P val=0)
Установка всех компонент вектора в константу (по умолчанию — нуль)
Definition numvector.h:527
const double IDPI
Число .
Definition defs.h:85
void ModifyE2(double *ee2, double dst2)
Модифицирует массив квадратов расстояний до ближайших вихрей из wake.
Definition defs.cpp:236
double boundDenom(double r2, double eps2)
Способ сглаживания скорости вихря (вихрь Рэнкина или вихрь Ламба)
Definition defs.h:563
double accelCft(double currentTime) const
Функция-множитель, позволяющая моделировать разгон
double eps2
Квадрат радиуса вихря
Definition Passport2D.h:129