VM2D 1.14
Vortex methods for 2D flows simulation
Loading...
Searching...
No Matches
Gpu2D.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: Gpu2D.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 "Gpu2D.h"
41
42#include "Airfoil2D.h"
43#include "Boundary2D.h"
44#include "MeasureVP2D.h"
45#include "Mechanics2D.h"
46#include "StreamParser.h"
47#include "Velocity2D.h"
48#include "Wake2D.h"
49#include "World2D.h"
50
51using namespace VM2D;
52
53
54//int Gpu::nReserve = 0;
55
56Gpu::Gpu(const World2D& W_)
57 : W(W_)
58{
59#if defined(__CUDACC__) || defined(USE_CUDA)
60
61
62// Откомментировать следующую строку, если запускается счет на кластере, каждый узел которого
63// имеет несколько видеокарт, при этом хочется одновременно решать несколько задач --- каждую на своей видеокарте ---
64// каждая задача по своему номеру, деленному по модулю числа видеокарт на узле будет привязана к своей видеокарте;
65// на каждый узел при этом отправлять СТОЛЬКО MPI-нитей, СКОЛЬКО ТАМ ВИДЕОКАРТ;
66// число задач НАСТОЯТЕЛЬНО РЕКОМЕНДУЕТСЯ ВЫБИРАТЬ ТОЧНО РАВНЫМ СУММАРНОМУ ЧИСЛУ ВИДЕОКАРТ,
67// т.е. чтобы все задачи стартовали сразу же.
68//
69// Uncomment the following string if the program runs on the computer cluster with several graphic cards on every node
70// and you want to solve several tasks simultaneously --- EVERY TASK ON ITS OWN GRAPHIC CARD;
71// every task will be associated with separate graphic card;
72// send THE SAME AMOUNT OF MPI-THREADS for the node as THE NUMBER OF GRAPHIC CARDS on this node;
73// IT IS STRONGLY RECOMMENDED TO CHOOSE THE NUMBER OF TASKS EXACTLY EQUAL TO TOTAL VIDEO CARDs NUMBERS,
74// i.e. to start all the tasks simultaneously.
75
76
77// blocks = cuSelect(W.getPassport().problemNumber % 4); //The index of the used video card will be equal to the task number
78 // in the task list (to modulo 4 --- number of graphic cards on each node)
79
80 blocks = cuSelect(0); //The index of the used video card will be equal to the task number
81 cuReserveDevMem((void*&)dev_blocks, sizeof(int), 0);
82 cuCopyFixedArray(dev_blocks, &blocks, sizeof(int), 0);
83
84 cuSetConstants(sizeof(Vortex2D)/sizeof(double), Vortex2D::offsPos / sizeof(double), Vortex2D::offsGam / sizeof(double) );
85
86 n_CUDA_wake = 0;
87 inflTreeWake.reset(new BHcu::CudaTreeInfo(blocks, tree_T::vortex, object_T::point3, scheme_T::noScheme, true));
88 cntrTreeWake.reset(new BHcu::CudaTreeInfo(blocks, tree_T::contr, object_T::point3, scheme_T::noScheme, false));
89
90 scheme_T sch;
92 {
93 case 1:
95 break;
96 case 2:
98 break;
99 }
100 cntrTreePnl.reset(new BHcu::CudaTreeInfo(blocks, tree_T::contr, object_T::panel, sch, false));
101 inflTreePnlVortex.reset(new BHcu::CudaTreeInfo(blocks, tree_T::vortex, object_T::panel, sch, false));
102 inflTreePnlSource.reset(new BHcu::CudaTreeInfo(blocks, tree_T::source, object_T::panel, sch, false));
103
104 n_CUDA_velVP = 0;
105 cntrTreeVP.reset(new BHcu::CudaTreeInfo(blocks, tree_T::contr, object_T::point2, scheme_T::noScheme, false));
106
107 //вспомогательное дерево панелей для контроля протыкания
108 auxTreePnl.reset(new BHcu::CudaTreeInfo(blocks, tree_T::aux, object_T::panel, scheme_T::noScheme, false));
109 cntrTreePoint.reset(new BHcu::CudaTreeInfo(blocks, tree_T::contr, object_T::point2, scheme_T::noScheme, false));
110 cntrTreeSegment.reset(new BHcu::CudaTreeInfo(blocks, tree_T::contr, object_T::panel, scheme_T::noScheme, false));
111
112 n_CUDA_source = 0;
113 n_CUDA_afls = 0;
114 n_CUDA_pnls = 0;
115
116#endif
117}
118
119
121{
122#if defined(__CUDACC__) || defined(USE_CUDA)
123 ReleaseDevMem(W.getWake().devVtxPtr, 1);
124 ReleaseDevMem(W.getWake().devVelPtr, 2);
125 ReleaseDevMem(W.getWake().devRadPtr, 3);
126 ReleaseDevMem(W.getWake().devI0Ptr, 4);
127 ReleaseDevMem(W.getWake().devI0fPtr, 4);
128 ReleaseDevMem(W.getWake().devI1Ptr, 5);
129 ReleaseDevMem(W.getWake().devI2Ptr, 6);
130 ReleaseDevMem(W.getWake().devI3Ptr, 7);
131 ReleaseDevMem(W.getWake().devI3fPtr, 7);
132
133 ReleaseDevMem(W.getWake().devMeshPtr, 8);
134 ReleaseDevMem(W.getWake().devNeiPtr, 9);
135 ReleaseDevMem(W.getWake().devNearestPanelPtr, 9);
136
137 if (W.getSource().vtx.size() > 0)
138 ReleaseDevMem(W.getSource().devVtxPtr, 10);
139
140 if (W.getNumberOfAirfoil() > 0)
141 for (size_t s = 0; s < 1/*n_CUDA_afls*/; ++s)
142 {
143 ReleaseDevMem(W.getBoundary(s).virtualWake.devVtxPtr, 11);
144 ReleaseDevMem(W.getBoundary(s).virtualWake.devVelPtr, 12);
145 ReleaseDevMem(W.getBoundary(s).virtualWake.devRadPtr, 13);
146 ReleaseDevMem(W.getBoundary(s).virtualWake.devI0Ptr, 14);
147 ReleaseDevMem(W.getBoundary(s).virtualWake.devI0fPtr, 14);
148 ReleaseDevMem(W.getBoundary(s).virtualWake.devI1Ptr, 15);
149 ReleaseDevMem(W.getBoundary(s).virtualWake.devI2Ptr, 16);
150 ReleaseDevMem(W.getBoundary(s).virtualWake.devI3Ptr, 17);
151 ReleaseDevMem(W.getBoundary(s).virtualWake.devI3fPtr, 17);
152
153 ReleaseDevMem(W.getBoundary(s).afl.devRPtr, 18);
154 ReleaseDevMem(W.getBoundary(s).afl.devPsnPtr, 181);
155 ReleaseDevMem(W.getBoundary(s).afl.devRhsPtr, 19);
156 ReleaseDevMem(W.getBoundary(s).afl.devRhsLinPtr, 191);
157
158 ReleaseDevMem(W.getBoundary(s).afl.devFreeVortexSheetPtr, 20);
159 ReleaseDevMem(W.getBoundary(s).afl.devAttachedVortexSheetPtr, 21);
160 ReleaseDevMem(W.getBoundary(s).afl.devAttachedSourceSheetPtr, 22);
161
162 ReleaseDevMem(W.getBoundary(s).afl.devFreeVortexSheetLinPtr, 20);
163 ReleaseDevMem(W.getBoundary(s).afl.devAttachedVortexSheetLinPtr, 21);
164 ReleaseDevMem(W.getBoundary(s).afl.devAttachedSourceSheetLinPtr, 22);
165
166 ReleaseDevMem(W.getBoundary(s).afl.devMeanEpsOverPanelPtr, 23);
167 ReleaseDevMem(W.getBoundary(s).afl.devViscousStressesPtr, 24);
168 }
169
170 if (n_CUDA_afls)
171 {
172 ReleaseDevMem(dev_ptr_nPanels, 25);
173 ReleaseDevMem(dev_ptr_nVortices, 26);
174
175 ReleaseDevMem(dev_ptr_ptr_vtx, 27);
176 ReleaseDevMem(dev_ptr_ptr_vel, 28);
177 ReleaseDevMem(dev_ptr_ptr_rad, 29);
178 ReleaseDevMem(dev_ptr_ptr_i0, 30);
179 ReleaseDevMem(dev_ptr_ptr_i0f, 30);
180 ReleaseDevMem(dev_ptr_ptr_i1, 31);
181 ReleaseDevMem(dev_ptr_ptr_i2, 32);
182 ReleaseDevMem(dev_ptr_ptr_i3, 33);
183 ReleaseDevMem(dev_ptr_ptr_i3f, 33);
184
185 ReleaseDevMem(dev_ptr_ptr_r, 34);
186 ReleaseDevMem(dev_ptr_ptr_rhs, 35);
187
188 ReleaseDevMem(dev_ptr_ptr_freeVortexSheet, 36);
189 ReleaseDevMem(dev_ptr_ptr_attachedVortexSheet, 37);
190 ReleaseDevMem(dev_ptr_ptr_attachedSourceSheet, 38);
191
192 ReleaseDevMem(dev_ptr_ptr_meanEpsOverPanel, 39);
193
194 ReleaseDevMem(dev_ptr_ptr_viscousStresses, 40);
195 }
196
197 if (W.getMeasureVP().getWakeVP().vtx.size())
198 {
199 ReleaseDevMem(W.getMeasureVP().getWakeVP().devVtxPtr, 41);
200 ReleaseDevMem(W.getMeasureVP().getWakeVP().devVelPtr, 42);
201 ReleaseDevMem(W.getMeasureVP().getWakeVP().devRadPtr, 43);
202 }
203
204 ReleaseDevMem(dev_blocks, 44);
205#endif
206}
207
208#if defined(__CUDACC__) || defined(USE_CUDA)
209
210
211//Обновление состояния следа wake
212void Gpu::RefreshWake(int code)
213{
214 if (W.getWake().vtx.size() > 0)
215 {
216 //Если зарезервировано меньше, чем вихрей в пелене
217 if (W.getWake().vtx.size() > n_CUDA_wake)
218 {
219 size_t curLength = n_CUDA_wake;
220
221 //Освобождаем всю память на видеокарте
222 if (curLength > 0)
223 {
224 ReleaseDevMem(W.getWake().devVtxPtr, 44);
225 ReleaseDevMem(W.getWake().devVelPtr, 45);
226 ReleaseDevMem(W.getWake().devRadPtr, 46);
227 ReleaseDevMem(W.getWake().devI0Ptr, 47);
228 ReleaseDevMem(W.getWake().devI0fPtr, 47);
229 ReleaseDevMem(W.getWake().devI1Ptr, 48);
230 ReleaseDevMem(W.getWake().devI2Ptr, 49);
231 ReleaseDevMem(W.getWake().devI3Ptr, 50);
232 ReleaseDevMem(W.getWake().devI3fPtr, 50);
233
234 ReleaseDevMem(W.getWake().devMeshPtr, 51);
235 ReleaseDevMem(W.getWake().devNeiPtr, 52);
236 ReleaseDevMem(W.getWake().devNearestPanelPtr, 52);
237 }
238
239 size_t sz = curLength;
240 while (W.getWake().vtx.size() > sz)
241 sz += INC_VORT_DEV;
242
243 //Резервируем новое количество памяти
244 W.getWake().devVtxPtr = ReserveDevMem<double, sizeof(Vortex2D) / sizeof(double)>(sz, n_CUDA_wake);
245
246 W.getWake().devVelPtr = ReserveDevMem<double, 2>(sz, n_CUDA_wake);
247 W.getWake().devRadPtr = ReserveDevMem<double, 1>(sz, n_CUDA_wake);
248
249 W.getWake().devI0Ptr = ReserveDevMem<double, 1>(sz, n_CUDA_wake);
250 W.getWake().devI0fPtr = ReserveDevMem<float, 1>(sz, n_CUDA_wake);
251 W.getWake().devI1Ptr = ReserveDevMem<double, 1>(sz, n_CUDA_wake);
252 W.getWake().devI2Ptr = ReserveDevMem<double, 2>(sz, n_CUDA_wake);
253 W.getWake().devI3Ptr = ReserveDevMem<double, 2>(sz, n_CUDA_wake);
254 W.getWake().devI3fPtr = ReserveDevMem<float, 2>(sz, n_CUDA_wake);
255
256 W.getWake().devMeshPtr = ReserveDevMem<int, 2>(sz, n_CUDA_wake);
257 W.getWake().devNeiPtr = ReserveDevMem<int, 1>(sz, n_CUDA_wake);
258 W.getWake().devNearestPanelPtr = ReserveDevMem<int, 1>(sz, n_CUDA_wake);
259
260 //mesh.resize(n_CUDA_vel, { 0, 0 });
261
262 W.getInfo('i') << "CUDA memory resize: " << curLength << " -> " << n_CUDA_wake << " vortices" << std::endl;
263 }// if (W.getWake().vtx.size() > n_CUDA_wake)
264
265 //Обнуляем память, выделенную выше для хранения следа
266 cuClearWakeMem(W.getWake().vtx.size(), W.getWake().devVtxPtr);
267
268 //Копирование следа на видеокарту
269 //double t1 = omp_get_wtime();
270 //cuCopyWakeToDevAsync(W.getWake().vtx.size(), W.getWake().vtx.data(), W.getWake().devVtxPtr, 1);
271 cuCopyWakeToDev(W.getWake().vtx.size(), W.getWake().vtx.data(), W.getWake().devVtxPtr, 1);
272 //double t2 = omp_get_wtime();
273 //std::cout << "CopyTime = " << t2 - t1 << std::endl;
274 }
275
276 if (W.getSource().vtx.size() > 0)
277 {
278 //Если зарезервировано меньше, чем источников в пелене
279 if (W.getSource().vtx.size() > n_CUDA_source)
280 {
281 size_t curLength = n_CUDA_source;
282
283 //Освобождаем всю память на видеокарте
284 if (curLength > 0)
285 ReleaseDevMem(W.getSource().devVtxPtr, 53);
286
287 size_t sz = curLength;
288 while (W.getSource().vtx.size() > sz)
289 sz += INC_VORT_DEV;
290
291 //Резервируем новое количество памяти
292 W.getSource().devVtxPtr = ReserveDevMem<double, sizeof(Vortex2D) / sizeof(double)>(sz, n_CUDA_source);
293
294
295 W.getInfo('i') << "CUDA memory resize: " << curLength << " -> " << sz << " sources" << std::endl;
296 }// if (W.getSource().vtx.size() > N_CUDA_source)
297
298
299 //Обнуляем память, выделенную выше для хранения следа
300 cuClearWakeMem(W.getSource().vtx.size(), W.getSource().devVtxPtr);
301
302 //Копирование следа на видеокарту
303 cuCopyWakeToDev(W.getSource().vtx.size(), W.getSource().vtx.data(), W.getSource().devVtxPtr, 2);
304
305
306 }
307}
308
309
310
311//Обновление состояния сетки для вычисления VP
312void Gpu::RefreshVP(int code)
313{
314 if (W.getMeasureVP().getWakeVP().vtx.size() > 0)
315 {
316 //Если зарезервировано меньше, чем вихрей в пелене
317 if (W.getMeasureVP().getWakeVP().vtx.size() > n_CUDA_velVP)
318 {
319 size_t curLength = n_CUDA_velVP;
320
321 //Освобождаем всю память на видеокарте
322 if (curLength > 0)
323 {
324 ReleaseDevMem(W.getMeasureVP().getWakeVP().devVtxPtr, 54);
325 ReleaseDevMem(W.getMeasureVP().getWakeVP().devVelPtr, 55);
326 ReleaseDevMem(W.getMeasureVP().getWakeVP().devRadPtr, 56);
327 }
328
329 size_t sz = curLength;
330 while (W.getMeasureVP().getWakeVP().vtx.size() > sz)
331 sz += INC_VORT_DEV;
332
333 //Резервируем новое количество памяти
334 W.getMeasureVP().getWakeVP().devVtxPtr = ReserveDevMem<double, sizeof(Vortex2D) / sizeof(double)>(sz, n_CUDA_velVP);
335 W.getMeasureVP().getWakeVP().devVelPtr = ReserveDevMem<double, 2>(sz, n_CUDA_velVP);
336 W.getMeasureVP().getWakeVP().devRadPtr = ReserveDevMem<double, 1>(sz, n_CUDA_velVP);
337
338 W.getInfo('i') << "CUDA memory resize: " << curLength << " -> " << n_CUDA_velVP << " points_VP" << std::endl;
339 }// if (W.getWake().vtx.size() > N_CUDA_velvp)
340
341 //Обнуляем память, выделенную выше для хранения следа
342 cuClearWakeMem(W.getMeasureVP().getWakeVP().vtx.size(), W.getMeasureVP().getWakeVP().devVtxPtr);
343
344 //Копирование следа на видеокарту
345 cuCopyWakeToDev(W.getMeasureVP().getWakeVP().vtx.size(), W.getMeasureVP().getWakeVP().vtx.data(), W.getMeasureVP().getWakeVP().devVtxPtr, 3);
346 }
347}
348
349void Gpu::AllocateSolution(double*& dev_sol, size_t n)
350{
351 size_t new_n;
352 dev_sol = ReserveDevMem<double, 1>(n, new_n);
353}
354
355void Gpu::SetSolution(double* sol, double* dev_sol, size_t n)
356{
357 CopyMemToDev<double,1>(n, sol, dev_sol);
358 //dev_sol = ReserveDevMemAndCopyFixedArray(n, sol);
359}
360
361void Gpu::ReleaseSolution(double* dev_sol)
362{
363 ReleaseDevMem(dev_sol, 100);
364}
365
366//Обновление состояния всех профилей и слоев на них
367void Gpu::RefreshAfls(int code)
368{
369 //std::cout << "RefreshAfls (code = " << code << ") start" << std::endl;
370
371 if (W.getNumberOfBoundary() > 0)
372 {
373 if (W.getNumberOfBoundary() > n_CUDA_afls)
374 {
375 if (n_CUDA_afls)
376 for (size_t s = 0; s < 1/*n_CUDA_afls*/; ++s)
377 {
378 ReleaseDevMem(W.getBoundary(s).afl.devRPtr, 57);
379 ReleaseDevMem(W.getBoundary(s).afl.devPsnPtr, 571);
380 ReleaseDevMem(W.getBoundary(s).afl.devRhsPtr, 58);
381 ReleaseDevMem(W.getBoundary(s).afl.devRhsLinPtr, 581);
382 ReleaseDevMem(W.getBoundary(s).afl.devMeanEpsOverPanelPtr, 59);
383
384 ReleaseDevMem(W.getBoundary(s).afl.devFreeVortexSheetPtr, 60);
385 ReleaseDevMem(W.getBoundary(s).afl.devAttachedVortexSheetPtr, 61);
386 ReleaseDevMem(W.getBoundary(s).afl.devAttachedSourceSheetPtr, 62);
387
388 ReleaseDevMem(W.getBoundary(s).afl.devFreeVortexSheetLinPtr, 60);
389 ReleaseDevMem(W.getBoundary(s).afl.devAttachedVortexSheetLinPtr, 61);
390 ReleaseDevMem(W.getBoundary(s).afl.devAttachedSourceSheetLinPtr, 62);
391
392 ReleaseDevMem(W.getBoundary(s).afl.devViscousStressesPtr, 63);
393 }
394
395 if (n_CUDA_afls)
396 {
397 ReleaseDevMem(dev_ptr_nPanels, 64);
398 ReleaseDevMem(dev_ptr_ptr_r, 65);
399 ReleaseDevMem(dev_ptr_ptr_rhs, 66);
400
401 ReleaseDevMem(dev_ptr_ptr_freeVortexSheet, 67);
402 ReleaseDevMem(dev_ptr_ptr_attachedVortexSheet, 68);
403 ReleaseDevMem(dev_ptr_ptr_attachedSourceSheet, 69);
404
405 ReleaseDevMem(dev_ptr_nVortices, 70);
406 ReleaseDevMem(dev_ptr_ptr_vtx, 71);
407 ReleaseDevMem(dev_ptr_ptr_rad, 72);
408 ReleaseDevMem(dev_ptr_ptr_vel, 73);
409 ReleaseDevMem(dev_ptr_ptr_i0, 74);
410 ReleaseDevMem(dev_ptr_ptr_i0f, 74);
411 ReleaseDevMem(dev_ptr_ptr_i1, 75);
412 ReleaseDevMem(dev_ptr_ptr_i2, 76);
413 ReleaseDevMem(dev_ptr_ptr_i3, 77);
414 ReleaseDevMem(dev_ptr_ptr_i3f, 77);
415 }
416
417 //Временный массив для агрегации числа панелей (без округления вверх до блока) на профилях для их последующей отправки в dev_ptr_nPanels
418 std::vector<size_t> host_nPanels(0);
419
420 size_t totnPanels = 0;
421
422 for (size_t s = 0; s < W.getNumberOfBoundary(); ++s)
423 {
424 const size_t& nps = W.getBoundary(s).afl.getNumberOfPanels();
425 host_nPanels.push_back(nps);
426 totnPanels += nps;
427 }
428 dev_ptr_nPanels = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), host_nPanels.data());
429
430 const int totNVars = (int)totnPanels * (W.getPassport().numericalSchemes.boundaryCondition.second);
431
432 W.getBoundary(0).afl.devRPtr = ReserveDevMem<double, 4>(totnPanels, n_CUDA_pnls);
433 W.getBoundary(0).afl.devPsnPtr = ReserveDevMem<double, 6>(totnPanels, n_CUDA_pnls);
434 W.getBoundary(0).afl.devRhsPtr = ReserveDevMem<double, 1>(totnPanels, n_CUDA_pnls);
435 W.getBoundary(0).afl.devRhsLinPtr = ReserveDevMem<double, 1>(totnPanels, n_CUDA_pnls);
436 W.getBoundary(0).afl.devMeanEpsOverPanelPtr = ReserveDevMem<double, 1>(totnPanels, n_CUDA_pnls);
437
438 W.getBoundary(0).afl.devFreeVortexSheetPtr = ReserveDevMem<double, 1>(totnPanels, n_CUDA_pnls);
439 W.getBoundary(0).afl.devAttachedVortexSheetPtr = ReserveDevMem<double, 1>(totnPanels, n_CUDA_pnls);
440 W.getBoundary(0).afl.devAttachedSourceSheetPtr = ReserveDevMem<double, 1>(totnPanels, n_CUDA_pnls);
441
443 {
444 W.getBoundary(0).afl.devFreeVortexSheetLinPtr = ReserveDevMem<double, 1>(totnPanels, n_CUDA_pnls);
445 W.getBoundary(0).afl.devAttachedVortexSheetLinPtr = ReserveDevMem<double, 1>(totnPanels, n_CUDA_pnls);
446 W.getBoundary(0).afl.devAttachedSourceSheetLinPtr = ReserveDevMem<double, 1>(totnPanels, n_CUDA_pnls);
447 }
448 else
449 {
450 W.getBoundary(0).afl.devFreeVortexSheetLinPtr = nullptr;
451 W.getBoundary(0).afl.devAttachedVortexSheetLinPtr = nullptr;
452 W.getBoundary(0).afl.devAttachedSourceSheetLinPtr = nullptr;
453 }
454
455 W.getBoundary(0).afl.devViscousStressesPtr = ReserveDevMem<double, 1>(totnPanels, n_CUDA_pnls);//ViscousStress
456
457 for (size_t s = 1; s < W.getNumberOfBoundary(); ++s)
458 {
459 W.getBoundary(s).afl.devRPtr = W.getBoundary(s - 1).afl.devRPtr + 4 * host_nPanels[s - 1];
460 W.getBoundary(s).afl.devPsnPtr = W.getBoundary(s - 1).afl.devPsnPtr + 6 * host_nPanels[s - 1];
461 W.getBoundary(s).afl.devRhsPtr = W.getBoundary(s - 1).afl.devRhsPtr + 1 * host_nPanels[s - 1];
462 W.getBoundary(s).afl.devRhsLinPtr = W.getBoundary(s - 1).afl.devRhsLinPtr + 1 * host_nPanels[s - 1];
463 W.getBoundary(s).afl.devMeanEpsOverPanelPtr = W.getBoundary(s - 1).afl.devMeanEpsOverPanelPtr + 1 * host_nPanels[s - 1];
464
465 W.getBoundary(s).afl.devFreeVortexSheetPtr = W.getBoundary(s - 1).afl.devFreeVortexSheetPtr + 1 * host_nPanels[s - 1];
466 W.getBoundary(s).afl.devAttachedVortexSheetPtr = W.getBoundary(s - 1).afl.devAttachedVortexSheetPtr + 1 * host_nPanels[s - 1];
467 W.getBoundary(s).afl.devAttachedSourceSheetPtr = W.getBoundary(s - 1).afl.devAttachedSourceSheetPtr + 1 * host_nPanels[s - 1];
468
470 {
471 W.getBoundary(s).afl.devFreeVortexSheetLinPtr = W.getBoundary(s - 1).afl.devFreeVortexSheetLinPtr + 1 * host_nPanels[s - 1];
472 W.getBoundary(s).afl.devAttachedVortexSheetLinPtr = W.getBoundary(s - 1).afl.devAttachedVortexSheetLinPtr + 1 * host_nPanels[s - 1];
473 W.getBoundary(s).afl.devAttachedSourceSheetLinPtr = W.getBoundary(s - 1).afl.devAttachedSourceSheetLinPtr + 1 * host_nPanels[s - 1];
474 }
475 else
476 {
477 W.getBoundary(s).afl.devFreeVortexSheetLinPtr = nullptr;
478 W.getBoundary(s).afl.devAttachedVortexSheetLinPtr = nullptr;
479 W.getBoundary(s).afl.devAttachedSourceSheetLinPtr = nullptr;
480 }
481
482
483 W.getBoundary(s).afl.devViscousStressesPtr = W.getBoundary(s - 1).afl.devViscousStressesPtr + 1 * host_nPanels[s - 1];
484 }
485
486 for (size_t s = 0; s < W.getNumberOfBoundary(); ++s)
487 {
488 W.getBoundary(s).afl.tmpRhs.resize(totNVars, 0.0);
489 W.getBoundary(s).afl.tmpViscousStresses.resize(W.getBoundary(s).afl.getNumberOfPanels(), 0.0);
490 }// for s
491
492 //Временные массивы для агрегации указателей на видеокарте
493 std::vector<double*> host_ptr_r;
494 std::vector<double*> host_ptr_psn;
495 std::vector<double*> host_ptr_rhs;
496 std::vector<double*> host_ptr_rhsLin;
497
498 std::vector<double*> host_ptr_freeVortexSheet;
499 std::vector<double*> host_ptr_attachedVortexSheet;
500 std::vector<double*> host_ptr_attachedSourceSheet;
501
502 std::vector<double*> host_ptr_freeVortexSheetLin;
503 std::vector<double*> host_ptr_attachedVortexSheetLin;
504 std::vector<double*> host_ptr_attachedSourceSheetLin;
505
506 std::vector<double*> host_ptr_meanEpsOverPanel;
507
508 std::vector<double*> host_ptr_viscousStresses;
509
510 for (size_t q = 0; q < W.getNumberOfBoundary(); ++q)
511 {
512 host_ptr_r.push_back(W.getBoundary(q).afl.devRPtr);
513 host_ptr_psn.push_back(W.getBoundary(q).afl.devPsnPtr);
514 host_ptr_rhs.push_back(W.getBoundary(q).afl.devRhsPtr);
515 host_ptr_rhsLin.push_back(W.getBoundary(q).afl.devRhsLinPtr);
516
517 host_ptr_freeVortexSheet.push_back(W.getBoundary(q).afl.devFreeVortexSheetPtr);
518 host_ptr_attachedVortexSheet.push_back(W.getBoundary(q).afl.devAttachedVortexSheetPtr);
519 host_ptr_attachedSourceSheet.push_back(W.getBoundary(q).afl.devAttachedSourceSheetPtr);
520
521 host_ptr_freeVortexSheetLin.push_back(W.getBoundary(q).afl.devFreeVortexSheetLinPtr);
522 host_ptr_attachedVortexSheetLin.push_back(W.getBoundary(q).afl.devAttachedVortexSheetLinPtr);
523 host_ptr_attachedSourceSheetLin.push_back(W.getBoundary(q).afl.devAttachedSourceSheetLinPtr);
524
525 host_ptr_meanEpsOverPanel.push_back(W.getBoundary(q).afl.devMeanEpsOverPanelPtr);
526
527 host_ptr_viscousStresses.push_back(W.getBoundary(q).afl.devViscousStressesPtr);
528 }
529
530 dev_ptr_ptr_r = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), host_ptr_r.data());
531 dev_ptr_ptr_rhs = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), host_ptr_rhs.data());
532
533 dev_ptr_ptr_freeVortexSheet = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), host_ptr_freeVortexSheet.data());
534 dev_ptr_ptr_attachedVortexSheet = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), host_ptr_attachedVortexSheet.data());
535 dev_ptr_ptr_attachedSourceSheet = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), host_ptr_attachedSourceSheet.data());
536
537 dev_ptr_ptr_viscousStresses = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), host_ptr_viscousStresses.data());
538
539 dev_ptr_ptr_meanEpsOverPanel = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), host_ptr_meanEpsOverPanel.data());
540
541 std::vector<double*> zeroPtrVec(W.getNumberOfBoundary(), nullptr);
542 std::vector<float*> zeroPtrVecf(W.getNumberOfBoundary(), nullptr);
543 dev_ptr_ptr_vtx = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), zeroPtrVec.data());
544 dev_ptr_ptr_rad = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), zeroPtrVec.data());
545 dev_ptr_ptr_vel = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), zeroPtrVec.data());
546 dev_ptr_ptr_i0 = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), zeroPtrVec.data());
547 dev_ptr_ptr_i0f = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), zeroPtrVecf.data());
548 dev_ptr_ptr_i1 = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), zeroPtrVec.data());
549 dev_ptr_ptr_i2 = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), zeroPtrVec.data());
550 dev_ptr_ptr_i3 = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), zeroPtrVec.data());
551 dev_ptr_ptr_i3f = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), zeroPtrVecf.data());
552
553 std::vector<size_t> zeroVec(W.getNumberOfBoundary(), 0);
554 dev_ptr_nVortices = ReserveDevMemAndCopyFixedArray(W.getNumberOfBoundary(), zeroVec.data());
555
556 }//if (W.getNumberOfBoundary() > n_CUDA_afls)
557
558
559 for (size_t s = 0; s < W.getNumberOfBoundary(); ++s)
560 {
561 size_t np = W.getBoundary(s).afl.getNumberOfPanels();
562 //size_t nv = W.getBoundary(s).GetUnknownsSize();
563
564 //Копирование вершин профиля на видеокарту
565 std::vector<double> rbegend(4 * np);
566 std::vector<double> pseudonorm(6 * np);
567 for (size_t q = 0; q < np; ++q)
568 {
569 rbegend[4 * q + 0] = W.getBoundary(s).afl.getR(q)[0];
570 rbegend[4 * q + 1] = W.getBoundary(s).afl.getR(q)[1];
571 rbegend[4 * q + 2] = W.getBoundary(s).afl.getR(q+1)[0];
572 rbegend[4 * q + 3] = W.getBoundary(s).afl.getR(q+1)[1];
573
574 pseudonorm[6 * q + 0] = W.getBoundary(s).afl.psn[q].first[0];
575 pseudonorm[6 * q + 1] = W.getBoundary(s).afl.psn[q].first[1];
576 pseudonorm[6 * q + 2] = W.getBoundary(s).afl.nrm[q][0];
577 pseudonorm[6 * q + 3] = W.getBoundary(s).afl.nrm[q][1];
578 pseudonorm[6 * q + 4] = W.getBoundary(s).afl.psn[q].second[0];
579 pseudonorm[6 * q + 5] = W.getBoundary(s).afl.psn[q].second[1];
580 }
581
582 cuCopyFixedArrayPoint4D(W.getBoundary(s).afl.devRPtr, (Point2D*)rbegend.data(), np, code);
583 cuCopyFixedArrayPoint6D(W.getBoundary(s).afl.devPsnPtr, (Point2D*)pseudonorm.data(), np, code);
584
585 //Копирование слоев на видеокарту
586 std::vector<double> host_freeVortexSheet(np);
587 std::vector<double> host_attachedVortexSheet(np);
588 std::vector<double> host_attachedSourceSheet(np);
589
590 std::vector<double> host_freeVortexSheetLin(np);
591 std::vector<double> host_attachedVortexSheetLin(np);
592 std::vector<double> host_attachedSourceSheetLin(np);
593
594 const Sheet& sh = W.getBoundary(s).sheets;
595
597
598 for (size_t p = 0; p < np; ++p)
599 {
600 host_attachedVortexSheet[p] = sh.attachedVortexSheet(p, 0);
601 host_attachedSourceSheet[p] = sh.attachedSourceSheet(p, 0);
602 host_freeVortexSheet[p] = sh.freeVortexSheet(p, 0);
603
604 if (sch == 2)
605 {
606 host_attachedVortexSheetLin[p] = sh.attachedVortexSheet(p, 1);
607 host_attachedSourceSheetLin[p] = sh.attachedSourceSheet(p, 1);
608 host_freeVortexSheetLin[p] = sh.freeVortexSheet(p, 1);
609 }//for p
610 }//for p
611
612 cuCopyFixedArray(W.getBoundary(s).afl.devFreeVortexSheetPtr, host_freeVortexSheet.data(), sizeof(double) * host_freeVortexSheet.size(), 102);
613 cuCopyFixedArray(W.getBoundary(s).afl.devAttachedVortexSheetPtr, host_attachedVortexSheet.data(), sizeof(double)* host_attachedVortexSheet.size(), 103);
614 cuCopyFixedArray(W.getBoundary(s).afl.devAttachedSourceSheetPtr, host_attachedSourceSheet.data(), sizeof(double)* host_attachedSourceSheet.size(), 104);
615
616 if (sch == 2)
617 {
618 cuCopyFixedArray(W.getBoundary(s).afl.devFreeVortexSheetLinPtr, host_freeVortexSheetLin.data(), sizeof(double) * host_freeVortexSheetLin.size(), 105);
619 cuCopyFixedArray(W.getBoundary(s).afl.devAttachedVortexSheetLinPtr, host_attachedVortexSheetLin.data(), sizeof(double) * host_attachedVortexSheetLin.size(), 106);
620 cuCopyFixedArray(W.getBoundary(s).afl.devAttachedSourceSheetLinPtr, host_attachedSourceSheetLin.data(), sizeof(double) * host_attachedSourceSheetLin.size(), 107);
621 }
622 }
623 }
624 n_CUDA_afls = W.getNumberOfBoundary();
625}//RefreshAfls()
626
627
628//Обновление состояния "виртуальных следов" - только что рожденных вихрей на профилях
629void Gpu::RefreshVirtualWakes(int code)
630{
631 if (n_CUDA_virtWake.size() == 0)
632 {
633 n_CUDA_virtWake.resize(W.getNumberOfBoundary(), 0);
634 n_CUDA_totalVirtWake = 0;
635 }
636
637 size_t totnVirt = 0, totnPan = 0;
638 for (size_t s = 0; s < W.getNumberOfBoundary(); ++s)
639 {
640 totnVirt += W.getBoundary(s).virtualWake.vtx.size();
641 totnPan += W.getBoundary(s).afl.getNumberOfPanels();
642 }
643
644 const size_t& szVtx = std::max(totnVirt, W.getPassport().wakeDiscretizationProperties.minVortexPerPanel * totnPan);
645
646 //Чистим все массивы
647 if (szVtx > n_CUDA_totalVirtWake)
648 {
649 if (n_CUDA_totalVirtWake > 0)
650 for (size_t s = 0; s < 1/*W.getNumberOfBoundary()*/; ++s)
651 {
652 ReleaseDevMem(W.getBoundary(s).virtualWake.devVtxPtr, 70);
653 ReleaseDevMem(W.getBoundary(s).virtualWake.devVelPtr, 71);
654 ReleaseDevMem(W.getBoundary(s).virtualWake.devRadPtr, 72);
655 ReleaseDevMem(W.getBoundary(s).virtualWake.devI0Ptr, 73);
656 ReleaseDevMem(W.getBoundary(s).virtualWake.devI0fPtr, 73);
657 ReleaseDevMem(W.getBoundary(s).virtualWake.devI1Ptr, 74);
658 ReleaseDevMem(W.getBoundary(s).virtualWake.devI2Ptr, 75);
659 ReleaseDevMem(W.getBoundary(s).virtualWake.devI3Ptr, 76);
660 ReleaseDevMem(W.getBoundary(s).virtualWake.devI3fPtr, 76);
661 }
662
663 if (n_CUDA_afls)
664 {
665 W.getBoundary(0).virtualWake.devVtxPtr = ReserveDevMem<double, sizeof(Vortex2D) / sizeof(double)>(szVtx, n_CUDA_totalVirtWake, 80);
666 W.getBoundary(0).virtualWake.devVelPtr = ReserveDevMem<double, 2>(szVtx, n_CUDA_totalVirtWake, 81);
667 W.getBoundary(0).virtualWake.devRadPtr = ReserveDevMem<double, 1>(szVtx, n_CUDA_totalVirtWake, 82);
668
669 //std::cout << "szVtx = " << szVtx << ", n_CUDA_totalVirtWake = " << n_CUDA_totalVirtWake << std::endl;
670
671 W.getBoundary(0).virtualWake.devI0Ptr = ReserveDevMem<double, 1>(szVtx, n_CUDA_totalVirtWake, 83);
672 W.getBoundary(0).virtualWake.devI0fPtr = ReserveDevMem<float, 1>(szVtx, n_CUDA_totalVirtWake, 84);
673 W.getBoundary(0).virtualWake.devI1Ptr = ReserveDevMem<double, 1>(szVtx, n_CUDA_totalVirtWake, 85);
674 W.getBoundary(0).virtualWake.devI2Ptr = ReserveDevMem<double, 2>(szVtx, n_CUDA_totalVirtWake, 86);
675 W.getBoundary(0).virtualWake.devI3Ptr = ReserveDevMem<double, 2>(szVtx, n_CUDA_totalVirtWake, 87);
676 W.getBoundary(0).virtualWake.devI3fPtr = ReserveDevMem<float, 2>(szVtx, n_CUDA_totalVirtWake, 88);
677 }
678 }
679
680 for (size_t s = 1; s < W.getNumberOfBoundary(); ++s)
681 {
682 size_t nprev = W.getBoundary(s - 1).virtualWake.vtx.size();
683 W.getBoundary(s).virtualWake.devVtxPtr = W.getBoundary(s - 1).virtualWake.devVtxPtr + (sizeof(Vortex2D) / sizeof(double)) * nprev;
684 W.getBoundary(s).virtualWake.devVelPtr = W.getBoundary(s - 1).virtualWake.devVelPtr + 2 * nprev;
685 W.getBoundary(s).virtualWake.devRadPtr = W.getBoundary(s - 1).virtualWake.devRadPtr + 1 * nprev;
686 W.getBoundary(s).virtualWake.devI0Ptr = W.getBoundary(s - 1).virtualWake.devI0Ptr + 1 * nprev;
687 W.getBoundary(s).virtualWake.devI0fPtr = W.getBoundary(s - 1).virtualWake.devI0fPtr + 1 * nprev;
688 W.getBoundary(s).virtualWake.devI1Ptr = W.getBoundary(s - 1).virtualWake.devI1Ptr + 1 * nprev;
689 W.getBoundary(s).virtualWake.devI2Ptr = W.getBoundary(s - 1).virtualWake.devI2Ptr + 2 * nprev;
690 W.getBoundary(s).virtualWake.devI3Ptr = W.getBoundary(s - 1).virtualWake.devI3Ptr + 2 * nprev;
691 W.getBoundary(s).virtualWake.devI3fPtr = W.getBoundary(s - 1).virtualWake.devI3fPtr + 2 * nprev;
692 }
693
694 std::vector<size_t> host_nVortices(0);
695 host_nVortices.reserve(W.getNumberOfBoundary());
696
697 for (size_t q = 0; q < W.getNumberOfBoundary(); ++q)
698 host_nVortices.push_back(W.getBoundary(q).virtualWake.vtx.size());
699
700 cuCopyFixedArray(dev_ptr_nVortices, host_nVortices.data(), W.getNumberOfBoundary()*sizeof(size_t), 108);
701
702 for (size_t s = 0; s < W.getNumberOfBoundary(); ++s)
703 {
704 //Временные массивы для агрегации указателей на видеокарте
705 std::vector<double*> host_ptr_vtx;
706 std::vector<double*> host_ptr_vel;
707 std::vector<double*> host_ptr_rad;
708 std::vector<double*> host_ptr_i0;
709 std::vector<float*> host_ptr_i0f;
710 std::vector<double*> host_ptr_i1;
711 std::vector<double*> host_ptr_i2;
712 std::vector<double*> host_ptr_i3;
713 std::vector<float*> host_ptr_i3f;
714
715 for (size_t q = 0; q < W.getNumberOfBoundary(); ++q)
716 {
717 host_ptr_vtx.push_back(W.getBoundary(q).virtualWake.devVtxPtr);
718 host_ptr_vel.push_back(W.getBoundary(q).virtualWake.devVelPtr);
719 host_ptr_rad.push_back(W.getBoundary(q).virtualWake.devRadPtr);
720 host_ptr_i0.push_back(W.getBoundary(q).virtualWake.devI0Ptr);
721 host_ptr_i0f.push_back(W.getBoundary(q).virtualWake.devI0fPtr);
722 host_ptr_i1.push_back(W.getBoundary(q).virtualWake.devI1Ptr);
723 host_ptr_i2.push_back(W.getBoundary(q).virtualWake.devI2Ptr);
724 host_ptr_i3.push_back(W.getBoundary(q).virtualWake.devI3Ptr);
725 host_ptr_i3f.push_back(W.getBoundary(q).virtualWake.devI3fPtr);
726 }
727
728 size_t nBytes = W.getNumberOfBoundary() * sizeof(double*);
729 cuCopyFixedArray(dev_ptr_ptr_vtx, host_ptr_vtx.data(), nBytes, 109);
730 cuCopyFixedArray(dev_ptr_ptr_rad, host_ptr_rad.data(), nBytes, 110);
731 cuCopyFixedArray(dev_ptr_ptr_vel, host_ptr_vel.data(), nBytes, 111);
732 cuCopyFixedArray(dev_ptr_ptr_i0, host_ptr_i0.data(), nBytes, 112);
733 cuCopyFixedArray(dev_ptr_ptr_i0f, host_ptr_i0f.data(), nBytes, 112);
734 cuCopyFixedArray(dev_ptr_ptr_i1, host_ptr_i1.data(), nBytes, 113);
735 cuCopyFixedArray(dev_ptr_ptr_i2, host_ptr_i2.data(), nBytes, 114);
736 cuCopyFixedArray(dev_ptr_ptr_i3, host_ptr_i3.data(), nBytes, 115);
737 cuCopyFixedArray(dev_ptr_ptr_i3f, host_ptr_i3f.data(), nBytes, 115);
738 }//if (n_CUDA_virtWake[s] < W.getBoundary(s).virtualWake.vtx.size())
739
740 //Обнуляем память, выделенную выше для хранения виртуального следа
741 if (W.getNumberOfBoundary() > 0)
742 {
743 cuClearWakeMem(szVtx, W.getBoundary(0).virtualWake.devVtxPtr);
744 for (size_t s = 0; s < W.getNumberOfBoundary(); ++s)
745 cuCopyWakeToDev(W.getBoundary(s).virtualWake.vtx.size(), W.getBoundary(s).virtualWake.vtx.data(), W.getBoundary(s).virtualWake.devVtxPtr, 4);
746 }
747}
748
749#endif
Заголовочный файл с описанием класса Airfoil.
Заголовочный файл с описанием класса Boundary.
Заголовочный файл с описанием класса Gpu.
#define INC_VORT_DEV
Definition Gpudefs.h:77
scheme_T
Definition Gpudefs.h:151
Заголовочный файл с описанием класса MeasureVP.
Заголовочный файл с описанием класса Mechanics.
Заголовочный файл с описанием класса StreamParser.
Заголовочный файл с описанием класса Velocity.
Заголовочный файл с описанием класса Wake.
Заголовочный файл с описанием класса World2D.
std::vector< std::pair< Point2D, Point2D > > psn
Псевдонормали к панелям профиля
Definition Airfoil2D.h:86
const Point2D & getR(size_t q) const
Возврат константной ссылки на вершину профиля
Definition Airfoil2D.h:113
std::vector< Point2D > nrm
Нормали к панелям профиля
Definition Airfoil2D.h:81
size_t getNumberOfPanels() const
Возврат количества панелей на профиле
Definition Airfoil2D.h:163
const Airfoil & afl
Definition Boundary2D.h:77
Sheet sheets
Слои на профиле
Definition Boundary2D.h:96
VirtualWake virtualWake
Виртуальный вихревой след конкретного профиля
Definition Boundary2D.h:86
const World2D & W
Константная ссылка на решаемую задачу
Definition Gpu2D.h:72
Gpu(const World2D &W_)
Конструктор
Definition Gpu2D.cpp:56
const WakeDataBase & getWakeVP() const
Возврат wakeVP.
WakeDiscretizationProperties wakeDiscretizationProperties
Структура с параметрами дискретизации вихревого следа
Definition Passport2D.h:292
NumericalSchemes numericalSchemes
Структура с используемыми численными схемами
Definition Passport2D.h:295
Класс, опеделяющий слои на поверхности обтекаемого профиля
Definition Sheet2D.h:63
const double & attachedVortexSheet(size_t n, size_t moment) const
Definition Sheet2D.h:105
const double & attachedSourceSheet(size_t n, size_t moment) const
Definition Sheet2D.h:110
const double & freeVortexSheet(size_t n, size_t moment) const
Definition Sheet2D.h:100
std::vector< Vortex2D > vtx
Список вихревых элементов
Класс, опеделяющий текущую решаемую задачу
Definition World2D.h:74
size_t getNumberOfAirfoil() const
Возврат количества профилей в задаче
Definition World2D.h:174
const Wake & getWake() const
Возврат константной ссылки на вихревой след
Definition World2D.h:226
const WakeDataBase & getSource() const
Возврат константной ссылки на источники в области течения
Definition World2D.h:236
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
Класс, опеделяющий двумерный вихревой элемент
Definition Vortex2D.h:59
VMlib::LogStream & getInfo() const
Возврат ссылки на объект LogStream Используется в техничеcких целях для организации вывода
Definition WorldGen.h:82
std::pair< std::string, int > boundaryCondition
Метод аппроксимации граничных условий
Definition Passport2D.h:189
int minVortexPerPanel
Минимальное число вихрей, рождаемых на каждой панели профииля
Definition Passport2D.h:141