VM2D 1.14
Vortex methods for 2D flows simulation
Loading...
Searching...
No Matches
MeasureVP2D.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: MeasureVP2D.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#if defined(_WIN32)
41#include <direct.h>
42#endif
43
44#include "MeasureVP2D.h"
45
46#include "Airfoil2D.h"
47#include "Boundary2D.h"
48
49#include "Mechanics2D.h"
51#include "Preprocessor.h"
52#include "StreamParser.h"
53#include "Velocity2D.h"
54#include "Wake2D.h"
55#include "World2D.h"
56#include "Gmres2D.h"
57
58using namespace VM2D;
59
60//Конструктор
62 : W(W_)
63{
64 sstrCounter = 0;
65 wakeVP.reset(new WakeDataBase(W_));
66};//MeasureVP(...)
67
68//Чтение точек, в которых нужно посчитать давление и скорость
69void MeasureVP::ReadPointsFromFile(const std::string& dir)
70{
71 std::string filename = dir + "pointsVP";
72 std::ifstream VPFile;
73
74 if (fileExistTest(filename, W.getInfo(), true, { "txt", "TXT" }))
75 {
76 std::stringstream VPFile(VMlib::Preprocessor(filename).resultString);
77
78 VMlib::StreamParser VPParser(W.getInfo(), "velocity & pressure parser", VPFile);
79
80 VPParser.get("points", initialPoints);
81 VPParser.get("history", historyPoints);
82
83 for (auto& pt : initialPoints)
84 pt = pt.rotated(-W.getPassport().rotateAngleVpPoints * PI / 180.0);
85
86 for (auto& pt : historyPoints)
87 pt = pt.rotated(-W.getPassport().rotateAngleVpPoints * PI / 180.0);
88
89
90 if (historyPoints.size() > 0)
91 {
92 sstr.resize(historyPoints.size());
93 sstrCounter = 0;
94
95 VMlib::CreateUserDirectory(dir, "velPres");
96 std::string VPFileNameList = W.getPassport().dir + "velPres/listPoints";
97 std::ofstream VPFileList(VPFileNameList.c_str());
98
99 VMlib::PrintLogoToTextFile(VPFileList, VPFileNameList.c_str(), "List of points, where velocity and pressure are measured in csv-files");
100
101 VMlib::PrintHeaderToTextFile(VPFileList, "No. FileName X Y");
102
103 for (size_t q = 0; q < historyPoints.size(); ++q)
104 {
105 VPFileList << '\n' << q << '\t' << VMlib::fileNameStep("VP-atPoint-", 2, q, "csv") << '\t' << historyPoints[q][0] << '\t' << historyPoints[q][1];
106
107 std::string VPFileNameCsv;
108 VPFileNameCsv = W.getPassport().dir + "velPres/" + VMlib::fileNameStep("VP-atPoint-", 2, q, "csv");
109
110 std::ofstream VPFileCsv(VPFileNameCsv.c_str());
111
113 VPFileCsv << "pt,t,Vx,Vy,p" << std::endl;
114 else
115 VPFileCsv << "pt,t,CVx,CVy,Cp" << std::endl;
116
117 VPFileCsv.close();
118 VPFileCsv.clear();
119 }
120
121 VPFileList.close();
122 VPFileList.clear();
123 }
124 }
125}//ReadPointsFromFile(...)
126
127//Чтение точек, в которых нужно посчитать давление и скорость
128void MeasureVP::SetPoints(const std::vector<Point2D>& points, const std::vector<Point2D>& history)
129{
130 initialPoints = points;
131 historyPoints = history;
132
133 sstr.resize(historyPoints.size());
134 sstrCounter = 0;
135
136 for (auto& pt : initialPoints)
137 pt = pt.rotated(-W.getPassport().rotateAngleVpPoints * PI / 180.0);
138
139 for (auto& pt : historyPoints)
140 pt = pt.rotated(-W.getPassport().rotateAngleVpPoints * PI / 180.0);
141
142
143 if (historyPoints.size() > 0)
144 {
146 std::string VPFileNameList = W.getPassport().dir + "velPres/listPoints";
147 std::ofstream VPFileList(VPFileNameList.c_str());
148
149 VMlib::PrintLogoToTextFile(VPFileList, VPFileNameList.c_str(), "List of points, where velocity and pressure are measured in csv-files");
150
151 VMlib::PrintHeaderToTextFile(VPFileList, "No. FileName X Y");
152
153 for (size_t q = 0; q < historyPoints.size(); ++q)
154 {
155 VPFileList << '\n' << q << '\t' << VMlib::fileNameStep("VP-atPoint-", 2, q, "csv") << '\t' << historyPoints[q][0] << '\t' << historyPoints[q][1];
156
157 std::string VPFileNameCsv;
158 VPFileNameCsv = W.getPassport().dir + "velPres/" + VMlib::fileNameStep("VP-atPoint-", 2, q, "csv");
159
160 std::ofstream VPFileCsv(VPFileNameCsv.c_str());
161
163 VPFileCsv << "pt,t,Vx,Vy,p" << std::endl;
164 else
165 VPFileCsv << "pt,t,CVx,CVy,Cp" << std::endl;
166
167 VPFileCsv.close();
168 VPFileCsv.clear();
169 }
170
171 VPFileList.close();
172 VPFileList.clear();
173 }
174}//SetPoints(...)
175
176
177// Инициализация векторов для вычисления скоростей и давлений
179{
180 W.getTimers().start("VelPres");
181
183 {
184 //W.getInfo('i') << "Preparing VP points" << std::endl;
185
186 wakeVP->vtx.clear();
187 wakeVP->vtx.reserve(initialPoints.size() + historyPoints.size() + elasticPoints.size());
188
189 Vortex2D addvtx;
190
191 velocity.clear();
192 pressure.clear();
193 domainRadius.clear();
194
195 //отключаем проверку того, что точки расположены вне профиля
196 /*
197 //определяем точки, которые не находятся внутри профилей
198 bool inside;
199 for (size_t i = 0; i < initialPoints.size(); ++i)
200 {
201 inside = false;
202 for (size_t j = 0; j < W.getNumberOfAirfoil(); ++j)
203 {
204 if (W.getAirfoil(j).isInsideGabarits(initialPoints[i]) && W.getAirfoil(j).IsPointInAirfoil(initialPoints[i]))
205 {
206 inside = true;
207 break;
208 }
209 }
210 if (!inside)
211 {
212 addvtx.r() = initialPoints[i];
213 wakeVP.vtx.push_back(addvtx);
214 }
215 }
216 */
217
218 //добавляем все точки, а не только те, которые вне профиля
219 for (size_t i = 0; i < initialPoints.size(); ++i)
220 {
221 addvtx.r() = initialPoints[i];
222 addvtx.g() = 0.0;
223 addvtx.sigma() = -1.0;
224 wakeVP->vtx.push_back(addvtx);
225
226 }//for i
227
228 for (size_t i = 0; i < historyPoints.size(); ++i)
229 {
230 addvtx.r() = historyPoints[i];
231 addvtx.g() = 0.0;
232 addvtx.sigma() = -1.0;
233 wakeVP->vtx.push_back(addvtx);
234 }//for i
235
236
237 elasticPoints.clear();
238
239 for (size_t afl = 0; afl < W.getNumberOfAirfoil(); ++afl)
240 {
241 MechanicsDeformable* ptr = dynamic_cast<MechanicsDeformable*>(&(W.getNonConstMechanics(afl)));
242 if ((ptr != nullptr) && (ptr->beam->fsi))
243 {
244 if (afl > 0)
245 {
246 W.getInfo('e') << "Only airfoil 0 can be elastic!" << std::endl;
247 exit(-345);
248 }
249
250 //if (ptr->beam->fsi) //turek
251 {
252 elasticPoints.reserve(ptr->chord.size() * 2);
253 for (size_t q = 0; q < ptr->chord.size(); ++q)
254 {
255 std::pair<size_t, size_t> pnls = ptr->chord[q].infPanels;
256 elasticPoints.push_back(
257 0.5 * (W.getAirfoil(afl).getR(pnls.first) + W.getAirfoil(afl).getR(pnls.first + 1))
258 + 0.01 * W.getAirfoil(afl).len[pnls.first] * W.getAirfoil(afl).nrm[pnls.first]
259 );
260
261 elasticPoints.push_back(
262 0.5 * (W.getAirfoil(afl).getR(pnls.second) + W.getAirfoil(afl).getR(pnls.second + 1))
263 + 0.01 * W.getAirfoil(afl).len[pnls.second] * W.getAirfoil(afl).nrm[pnls.second]
264 );
265 }
266
267 //std::ofstream elastPointsPositionsFile(W.getPassport().dir + "elastPointsPos-" + std::to_string(W.getCurrentStep()) + ".txt");
268 //for (size_t q = 0; q < elasticPoints.size(); ++q)
269 // elastPointsPositionsFile << elasticPoints[q][0] << " " << elasticPoints[q][1] << std::endl;
270 //elastPointsPositionsFile.close();
271 }
272 }
273 else //fish and other types
274 {
276 for (size_t q = 0; q < W.getAirfoil(afl).getNumberOfPanels(); ++q)
277 elasticPoints.push_back(0.5 * (W.getAirfoil(afl).getR(q) + W.getAirfoil(afl).getR(q + 1)) + W.getAirfoil(afl).nrm[q] * 1e-10);
278 }
279 }
280
281 /*
282 std::cout << "Elast_points added!\n";
283 for (size_t afl = 0; afl < W.getNumberOfAirfoil(); ++afl)
284 {
285 elasticPoints.reserve(W.getAirfoil(afl).getNumberOfPanels());
286 for (size_t q = 0; q < W.getAirfoil(afl).getNumberOfPanels(); ++q)
287 elasticPoints.push_back(0.5 * (W.getAirfoil(afl).getR(q) + W.getAirfoil(afl).getR(q + 1)) + W.getAirfoil(afl).nrm[q] * 1e-4);
288 }
289 */
290
291 for (size_t i = 0; i < elasticPoints.size(); ++i)
292 {
293 addvtx.r() = elasticPoints[i];
294 addvtx.g() = 0.0;
295 addvtx.sigma() = -1.0;
296 wakeVP->vtx.push_back(addvtx);
297 }//for i
298
299 }
300 W.getTimers().stop("VelPres");
301
302}//Initialization()
303
304//Расчет поля давления
306{
307 W.getTimers().start("VelPres");
308
309 int addWSize = (int)wakeVP->vtx.size();
310 pressure.resize(addWSize);
311
312 Point2D dri;
313 Point2D Vi;
314 Point2D vi;
315
316 const Point2D& V0 = W.getV0();
317 const double& dt = W.getPassport().timeDiscretizationProperties.dt;
318
319 double P0 = /*1*/ 0.5 * V0.length2();
320
321 Point2D cPan;
322
323#pragma warning (push)
324#pragma warning (disable: 4101)
325 double alpha;
326 double lambda;
327 double dst2eps;
328#pragma warning (pop)
329
330#pragma omp parallel for default(none) private(alpha, lambda, dri, Vi, vi, dst2eps, cPan) shared(P0, dt, V0, addWSize, std::cout, IDPI)
331 for (int i = 0; i < addWSize; ++i)
332 {
333 const Point2D& pt = wakeVP->vtx[i].r();
334
335 pressure[i] = P0;
336 pressure[i] -= 0.5 * velocity[i].length2(); //2
337
338
339 for (size_t j = 0; j < W.getWake().vtx.size(); ++j)
340 {
341 dri = pt - W.getWake().vtx[j].r();
343
344 const double sigma2 = sqr(W.getWake().vtx[j].sigma());
345 dst2eps = VMlib::boundDenom(dri.length2(), sigma2);
346
347 vi = IDPI * W.getWake().vtx[j].g() / dst2eps * dri.kcross();
348 pressure[i] += vi & Vi; //3
349 }
350
351
352 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
353 //size_t q = 0;
354 {
355 const Airfoil& afl = W.getAirfoil(q);
356 const Boundary& bou = W.getBoundary(q);
357
358 for (size_t pnl = 0; pnl < afl.getNumberOfPanels(); ++pnl)
359 {
360 Point2D s = pt - afl.getR(pnl);
361 Point2D p = pt - afl.getR(pnl + 1);
362 Point2D u0 = afl.tau[pnl];
363 double alpha = VMlib::Alpha(s, p);
364 double lambda = VMlib::Lambda(s, p);
365
366 Point2D skos = IDPI * ((alpha * u0).kcross() + (lambda * u0));
367
368 Vi = 0.5 * (bou.sheets.freeVortexSheet(pnl, 0) /* - afl.gammaThrough[pnl] / afl.len[pnl]*/) * u0;
369 vi = skos.kcross() * bou.sheets.freeVortexSheet(pnl, 0);
370 //if ((i == 0) && (pnl == 0))
371 // std::cout << "vi & Vi = " << (vi & Vi) << std::endl;
372
373 pressure[i] += vi & Vi; //4
374
375 Vi = 0.5 * (afl.getV(pnl) + afl.getV(pnl + 1));
376 vi = skos.kcross() * (bou.sheets.attachedVortexSheet(pnl, 0) - bou.oldSheets.attachedVortexSheet(pnl, 0));
377 pressure[i] += vi & Vi; //4a
378
379 vi = skos * (bou.sheets.attachedSourceSheet(pnl, 0) - bou.oldSheets.attachedSourceSheet(pnl, 0));
380 pressure[i] += vi & Vi; //4b
381 }
382 }
383
384 for (size_t bou = 0; bou < W.getNumberOfBoundary(); ++bou)
385 {
386 const Point2D& rcm = W.getAirfoil(bou).rcm;
387
388
389 //
390 //if ((i==0) && (bou == 2))
391 //{
392 // for (int q = 0; q < W.getAirfoil(bou).possibleWays.size(); ++q)
393 // {
394 // std::cout << "Possible way #" << q << ": " << std::endl;
395 // for (size_t s = 0; s < W.getAirfoil(bou).possibleWays[q].size(); ++s)
396 // std::cout << W.getAirfoil(bou).possibleWays[q][s] << " ";
397 // std::cout << std::endl;
398 // }
399 //
400 // std::ofstream of(W.getPassport().dir + "ways2.txt");
401 // for (size_t q = 0; q < W.getAirfoil(bou).getNumberOfPanels(); ++q)
402 // {
403 // cPan = 0.5 * (W.getAirfoil(bou).getR(q) + W.getAirfoil(bou).getR(q + 1));
404
405 // alpha = 0.0;
406
407 // int way = W.getAirfoil(bou).wayToVertex[q];
408 // if (way == 0)
409 // of << q << " " << rcm[0] << " " << rcm[1] << " " << cPan[0] << " " << cPan[1] << std::endl;
410 // else
411 // {
412 // of << q << " " << rcm[0] << " " << rcm[1];
413 // for (int q = 0; q < W.getAirfoil(bou).possibleWays[way - 1].size() + 1; ++q)
414 // {
415 // Point2D start = ((q == 0) ? rcm : W.getAirfoil(bou).possibleWays[way - 1][q - 1]);
416 // Point2D finish = ((q == W.getAirfoil(bou).possibleWays[way - 1].size()) ? cPan : W.getAirfoil(bou).possibleWays[way - 1][q]);
417 // of << " " << finish[0] << " " << finish[1];
418 // }
419 // of << std::endl;
420 // }
421 // }
422 // of.close();
423 //}
424 //
425
426
427 for (size_t j = 0; j < W.getAirfoil(bou).getNumberOfPanels(); ++j)
428 {
429 cPan = 0.5 * (W.getAirfoil(bou).getR(j) + W.getAirfoil(bou).getR(j + 1));
430
431 alpha = 0.0;
432
433 int way = W.getAirfoil(bou).wayToVertex[j];
434 //if (way < 0)
435 // W.getInfo('i') << "Pressure computation is incorrect, way inside airfoil is undefined" << std::endl;
436
437 if (way == 0)
438 alpha = atan2((cPan - pt) ^ (rcm - pt), (cPan - pt) & (rcm - pt));
439 else
440 if (way > 0)
441 {
442 for (int q = 0; q < W.getAirfoil(bou).possibleWays[way - 1].size() + 1; ++q)
443 {
444 Point2D start = ((q == 0) ? rcm : W.getAirfoil(bou).possibleWays[way - 1][q - 1]);
445 Point2D finish = ((q == W.getAirfoil(bou).possibleWays[way - 1].size()) ? cPan : W.getAirfoil(bou).possibleWays[way - 1][q]);
446 alpha += atan2((finish - pt) ^ (start - pt), (finish - pt) & (start - pt));
447 }
448 }
449
450
452 pressure[i] += IDPI * alpha * (W.getBoundary(bou).sheets.freeVortexSheet(j, 0) + W.getBoundary(bou).sheets.attachedVortexSheet(j, 0) - W.getBoundary(bou).oldSheets.attachedVortexSheet(j, 0)) * W.getAirfoil(bou).len[j] / dt;
453
454 pressure[i] -= IDPI * alpha * W.getAirfoil(bou).gammaThrough[j] / dt;
455
456 lambda = 0.5 * log((pt - cPan).length2());
457 pressure[i] -= IDPI * lambda * (W.getBoundary(bou).sheets.attachedSourceSheet(j, 0) - W.getBoundary(bou).oldSheets.attachedSourceSheet(j, 0)) * W.getAirfoil(bou).len[j] / dt;
458 }
459 }//for bou
460 }//for i
461
462 for (size_t i = 0; i < pressure.size(); ++i)
464
465 W.getTimers().stop("VelPres");
466}//CalcPressure()
467
468
469//Расчет поля давления
470#ifdef USE_CUDA
471void MeasureVP::GPUCalcPressure()
472{
473 W.getTimers().start("VelPres");
474
475 int addWSize = (int)wakeVP->vtx.size();
476 const Point2D& V0 = W.getV0();
477
478#if (defined(USE_CUDA))
479 {
480 cuCopyFixedArray(W.getWake().devVelPtr, W.getNonConstVelocity().wakeVortexesParams.convVelo.data(), 2 * sizeof(double) * W.getWake().vtx.size());
481 //W.getNonConstCuda().RefreshWake();
482 }
483#endif
484
485 size_t npnl = 0;
486 for (size_t q = 0; q < W.getNumberOfAirfoil(); ++q)
487 npnl += W.getAirfoil(q).getNumberOfPanels();
488
489 std::vector<double> oldAttVortexSheet, oldAttSourceSheet, gammaThroughIntensity;
490 oldAttVortexSheet.reserve(npnl);
491 oldAttSourceSheet.reserve(npnl);
492 gammaThroughIntensity.reserve(npnl);
493
494 for (size_t bou = 0; bou < W.getNumberOfBoundary(); ++bou)
495 for (size_t p = 0; p < W.getBoundary(bou).afl.getNumberOfPanels(); ++p)
496 {
497 oldAttVortexSheet.push_back(W.getBoundary(bou).oldSheets.attachedVortexSheet(p, 0));
498 oldAttSourceSheet.push_back(W.getBoundary(bou).oldSheets.attachedSourceSheet(p, 0));
499 gammaThroughIntensity.push_back(W.getAirfoil(bou).gammaThrough[p] / W.getAirfoil(bou).len[p]);
500 }
501
502 double* devOldVortexSheet;
503 cudaMalloc(&devOldVortexSheet, npnl * sizeof(double));
504 cudaMemcpy(devOldVortexSheet, oldAttVortexSheet.data(), npnl * sizeof(double), cudaMemcpyHostToDevice);
505
506 double* devOldSourceSheet;
507 cudaMalloc(&devOldSourceSheet, npnl * sizeof(double));
508 cudaMemcpy(devOldSourceSheet, oldAttSourceSheet.data(), npnl * sizeof(double), cudaMemcpyHostToDevice);
509
510 double* devGammaThroughIntensity;
511 cudaMalloc(&devGammaThroughIntensity, npnl * sizeof(double));
512 cudaMemcpy(devGammaThroughIntensity, gammaThroughIntensity.data(), npnl * sizeof(double), cudaMemcpyHostToDevice);
513
514 double* devDiffVelo;
515 cudaMalloc(&devDiffVelo, W.getWake().vtx.size() * 2 * sizeof(double));
516 cudaMemcpy(devDiffVelo, W.getVelocity().wakeVortexesParams.diffVelo.data(), W.getWake().vtx.size() * 2 * sizeof(double), cudaMemcpyHostToDevice);
517
518
519 cuCalculatePressure(addWSize, wakeVP->devVtxPtr,
520 W.getWake().vtx.size(), W.getWake().devVtxPtr, V0[0], V0[1], W.getWake().devVelPtr, devDiffVelo,
521 npnl, W.getAirfoil(0).devRPtr, W.getAirfoil(0).devFreeVortexSheetPtr, W.getAirfoil(0).devAttachedVortexSheetPtr, W.getAirfoil(0).devAttachedSourceSheetPtr,
522 devOldVortexSheet, devOldSourceSheet, devGammaThroughIntensity,
523 this->devPressurePtr);
524
525 cudaFree(devOldVortexSheet);
526 cudaFree(devOldSourceSheet);
527 cudaFree(devGammaThroughIntensity);
528 cudaFree(devDiffVelo);
529
530 std::vector<double> presGPU(addWSize);
531 cuCopyMemFromDev(presGPU.data(), this->devPressurePtr, addWSize * sizeof(double), 18);
532
533 //printf("-------------------\n");
534
535 pressure.resize(addWSize);
536
537 Point2D dri;
538 Point2D Vi;
539 Point2D vi;
540
541
542 const double& dt = W.getPassport().timeDiscretizationProperties.dt;
543
544 double P0 = /*1*/ 0.5 * V0.length2();
545
546 Point2D cPan;
547
548#pragma warning (push)
549#pragma warning (disable: 4101)
550 double alpha;
551 double lambda;
552 double dst2eps;
553#pragma warning (pop)
554
555 for (int i = 0; i < addWSize; ++i)
556 {
557 //if (fabs(pressure[i] - presGPU[i]) > 1e-5)
558 // printf("different pressure: %d, %f, %f\n", i, pressure[i], presGPU[i]);
559 pressure[i] = presGPU[i];
560 }
561
562#pragma omp parallel for default(none) private(alpha, lambda, dri, Vi, vi, dst2eps, cPan) shared(P0, dt, V0, addWSize, std::cout, IDPI)
563 for (int i = 0; i < addWSize; ++i)
564 {
565 const Point2D& pt = wakeVP->vtx[i].r();
566 for (size_t bou = 0; bou < W.getNumberOfBoundary(); ++bou)
567 {
568 const Point2D& rcm = W.getAirfoil(bou).rcm;
569
570
571 /*
572 if ((i==0) && (bou == 2))
573 {
574 for (int q = 0; q < W.getAirfoil(bou).possibleWays.size(); ++q)
575 {
576 std::cout << "Possible way #" << q << ": " << std::endl;
577 for (size_t s = 0; s < W.getAirfoil(bou).possibleWays[q].size(); ++s)
578 std::cout << W.getAirfoil(bou).possibleWays[q][s] << " ";
579 std::cout << std::endl;
580 }
581
582 std::ofstream of(W.getPassport().dir + "ways2.txt");
583 for (size_t q = 0; q < W.getAirfoil(bou).getNumberOfPanels(); ++q)
584 {
585 cPan = 0.5 * (W.getAirfoil(bou).getR(q) + W.getAirfoil(bou).getR(q + 1));
586
587 alpha = 0.0;
588
589 int way = W.getAirfoil(bou).wayToVertex[q];
590 if (way == 0)
591 of << q << " " << rcm[0] << " " << rcm[1] << " " << cPan[0] << " " << cPan[1] << std::endl;
592 else
593 {
594 of << q << " " << rcm[0] << " " << rcm[1];
595 for (int q = 0; q < W.getAirfoil(bou).possibleWays[way - 1].size() + 1; ++q)
596 {
597 Point2D start = ((q == 0) ? rcm : W.getAirfoil(bou).possibleWays[way - 1][q - 1]);
598 Point2D finish = ((q == W.getAirfoil(bou).possibleWays[way - 1].size()) ? cPan : W.getAirfoil(bou).possibleWays[way - 1][q]);
599 of << " " << finish[0] << " " << finish[1];
600 }
601 of << std::endl;
602 }
603 }
604 of.close();
605 }
606 */
607
608
609 for (size_t j = 0; j < W.getAirfoil(bou).getNumberOfPanels(); ++j)
610 {
611 cPan = 0.5 * (W.getAirfoil(bou).getR(j) + W.getAirfoil(bou).getR(j + 1));
612
613 alpha = 0.0;
614
615 int way = W.getAirfoil(bou).wayToVertex[j];
616 //if (way < 0)
617 // W.getInfo('i') << "Pressure computation is incorrect, way inside airfoil is undefined" << std::endl;
618
619 if (way == 0)
620 alpha = atan2((cPan - pt) ^ (rcm - pt), (cPan - pt) & (rcm - pt));
621 else
622 if (way > 0)
623 {
624 for (int q = 0; q < W.getAirfoil(bou).possibleWays[way - 1].size() + 1; ++q)
625 {
626 Point2D start = ((q == 0) ? rcm : W.getAirfoil(bou).possibleWays[way - 1][q - 1]);
627 Point2D finish = ((q == W.getAirfoil(bou).possibleWays[way - 1].size()) ? cPan : W.getAirfoil(bou).possibleWays[way - 1][q]);
628 alpha += atan2((finish - pt) ^ (start - pt), (finish - pt) & (start - pt));
629 }
630 }
631
633 pressure[i] += IDPI * alpha * (W.getBoundary(bou).sheets.freeVortexSheet(j, 0) + W.getBoundary(bou).sheets.attachedVortexSheet(j, 0) - W.getBoundary(bou).oldSheets.attachedVortexSheet(j, 0)) * W.getAirfoil(bou).len[j] / dt;
634
635 pressure[i] -= IDPI * alpha * W.getAirfoil(bou).gammaThrough[j] / dt;
636
637 lambda = 0.5 * log((pt - cPan).length2());
638 pressure[i] -= IDPI * lambda * (W.getBoundary(bou).sheets.attachedSourceSheet(j, 0) - W.getBoundary(bou).oldSheets.attachedSourceSheet(j, 0)) * W.getAirfoil(bou).len[j] / dt;
639 }
640 }//for bou
641 }//for i
642
643 for (size_t i = 0; i < pressure.size(); ++i)
644 {
645 pressure[i] += P0 - 0.5 * velocity[i].length2(); //2;
647 }
648
649 W.getTimers().stop("VelPres");
650}//GPUCalcPressure()
651#endif
652
653//Сохранение в файл вычисленных скоростей и давлений
655{
656 W.getTimers().start("Save");
657
658 double scaleV = 1.0, scaleP = 1.0;
660 {
661 const double& vRef = W.getPassport().physicalProperties.vRef;
662 scaleV = 1.0 / vRef;
663 scaleP = 1.0 / (0.5 * W.getPassport().physicalProperties.rho * sqr(vRef));
664 }
665
666
667 std::ofstream outfile;
668
670 const size_t nRealPressurePoints = initialPoints.size() + historyPoints.size(); //число реальных точек - без учета тех, что для гидроупругости
671
672 if (W.getPassport().timeDiscretizationProperties.fileTypeVP.second == 0) //text format VTK
673 {
674 std::string fname = VMlib::fileNameStep("VelPres", W.getPassport().timeDiscretizationProperties.nameLength, W.getCurrentStep(), "vtk");
675 outfile.open(W.getPassport().dir + "velPres/" + fname);
676
677 outfile << "# vtk DataFile Version 2.0\n";
678 outfile << "VM2D VTK result: " << (W.getPassport().dir + "velPres/" + fname).c_str() << " saved " << VMlib::CurrentDataTime() << '\n';
679 outfile << "ASCII\n";
680 outfile << "DATASET UNSTRUCTURED_GRID\n";
681 outfile << "POINTS " << nRealPressurePoints << " float\n";
682
683 for (size_t i = 0; i < nRealPressurePoints; ++i)
684 {
685 double xi = (wakeVP->vtx[i].r())[0];
686 double yi = (wakeVP->vtx[i].r())[1];
687 outfile << xi << " " << yi << " " << "0.0\n";
688 }//for i
689
690 outfile << "CELLS " << nRealPressurePoints << " " << 2 * nRealPressurePoints << '\n';
691 for (size_t i = 0; i < nRealPressurePoints; ++i)
692 outfile << "1 " << i << '\n';
693
694 outfile << "CELL_TYPES " << nRealPressurePoints << '\n';
695 for (size_t i = 0; i < nRealPressurePoints; ++i)
696 outfile << "1\n";
697
698 outfile << '\n';
699 outfile << "POINT_DATA " << nRealPressurePoints << '\n';
700
702 outfile << "VECTORS V float\n";
703 else
704 outfile << "VECTORS CV float\n";
705
706 for (size_t i = 0; i < nRealPressurePoints; ++i)
707 {
708 outfile << velocity[i][0] * scaleV << " " << velocity[i][1] * scaleV << " 0.0\n";
709 }//for i
710
711 outfile << '\n';
712
714 outfile << "SCALARS P float 1\n";
715 else
716 outfile << "SCALARS CP float 1\n";
717
718 outfile << "LOOKUP_TABLE default\n";
719
720 for (size_t i = 0; i < nRealPressurePoints; ++i)
721 {
722 outfile << pressure[i] * scaleP << '\n';
723 }//for i
724
725 outfile.close();
726 }
727 else if (W.getPassport().timeDiscretizationProperties.fileTypeVP.second == 1) //binary format VTK
728 {
729 //Тест способа хранения чисел
730 uint16_t x = 0x0001;
731 bool littleEndian = (*((uint8_t*)&x));
732 const char eolnBIN[] = "\n";
733
734 std::string fname = VMlib::fileNameStep("VelPres", W.getPassport().timeDiscretizationProperties.nameLength, W.getCurrentStep(), "vtk");
735 outfile.open(W.getPassport().dir + "velPres/" + fname, std::ios::out | std::ios::binary);
736
737 outfile << "# vtk DataFile Version 3.0" << "\r\n" << "VM2D VTK result: " << (W.getPassport().dir + "velPres/" + fname).c_str() << " saved " << VMlib::CurrentDataTime() << eolnBIN;
738 outfile << "BINARY" << eolnBIN;
739 outfile << "DATASET UNSTRUCTURED_GRID" << eolnBIN << "POINTS " << nRealPressurePoints << " " << "float" << eolnBIN;
740
741
742 Eigen::VectorXf pData = Eigen::VectorXf::Zero(nRealPressurePoints);
743 Eigen::VectorXf vData = Eigen::VectorXf::Zero(nRealPressurePoints * 3);
744 Eigen::VectorXf rData = Eigen::VectorXf::Zero(nRealPressurePoints * 3);
745
746
747 for (size_t i = 0; i < nRealPressurePoints; ++i)
748 {
749 rData(3 * i + 0) = (float)(wakeVP->vtx[i].r())[0];
750 rData(3 * i + 1) = (float)(wakeVP->vtx[i].r())[1];
751 }//for i
752
753 for (size_t i = 0; i < nRealPressurePoints; ++i)
754 {
755 vData(3 * i + 0) = (float)(velocity[i][0] * scaleV);
756 vData(3 * i + 1) = (float)(velocity[i][1] * scaleV);
757 }//for i
758
759 for (size_t i = 0; i < nRealPressurePoints; ++i)
760 {
761 pData(i) = (float)(pressure[i] * scaleP);
762 }//for i
763
764 //POINTS
765 if (littleEndian)
766 for (int i = 0; i < nRealPressurePoints * 3; ++i)
767 VMlib::SwapEnd(rData(i));
768 outfile.write(reinterpret_cast<char*>(rData.data()), nRealPressurePoints * 3 * sizeof(float));
769
770 // CELLS
771 std::vector<int> cells(2 * nRealPressurePoints);
772 for (size_t i = 0; i < nRealPressurePoints; ++i)
773 {
774 cells[2 * i + 0] = 1;
775 cells[2 * i + 1] = (int)i;
776 }
777
778 std::vector<int> cellsTypes;
779 cellsTypes.resize(nRealPressurePoints, 1);
780
781 if (littleEndian)
782 {
783 for (int i = 0; i < nRealPressurePoints * 2; ++i)
784 VMlib::SwapEnd(cells[i]);
785
786 for (int i = 0; i < nRealPressurePoints; ++i)
787 VMlib::SwapEnd(cellsTypes[i]);
788 }
789
790 outfile << eolnBIN << "CELLS " << nRealPressurePoints << " " << nRealPressurePoints * 2 << eolnBIN;
791 outfile.write(reinterpret_cast<char*>(cells.data()), nRealPressurePoints * 2 * sizeof(int));
792 outfile << eolnBIN << "CELL_TYPES " << nRealPressurePoints << eolnBIN;
793 outfile.write(reinterpret_cast<char*>(cellsTypes.data()), nRealPressurePoints * sizeof(int));
794
795 //VECTORS V
796 if (littleEndian)
797 for (int i = 0; i < nRealPressurePoints * 3; ++i)
798 VMlib::SwapEnd(vData(i));
799
800 outfile << eolnBIN << "POINT_DATA " << nRealPressurePoints << eolnBIN;
801
803 outfile << "VECTORS V " << "float" << eolnBIN;
804 else
805 outfile << "VECTORS CV " << "float" << eolnBIN;
806
807 outfile.write(reinterpret_cast<char*>(vData.data()), nRealPressurePoints * 3 * sizeof(float));
808
809 //SCALARS P
810 if (littleEndian)
811 for (int i = 0; i < nRealPressurePoints; ++i)
812 VMlib::SwapEnd(pData(i));
813
815 outfile << eolnBIN << "SCALARS P " << "float" << " 1" << eolnBIN;
816 else
817 outfile << eolnBIN << "SCALARS CP " << "float" << " 1" << eolnBIN;
818
819 outfile << "LOOKUP_TABLE default" << eolnBIN;
820 outfile.write(reinterpret_cast<char*>(pData.data()), nRealPressurePoints * sizeof(float));
821
822 outfile << eolnBIN;
823
824 outfile.close();
825 }
826 else if (W.getPassport().timeDiscretizationProperties.fileTypeVP.second == 2) //csv
827 {
828 std::string fname = VMlib::fileNameStep("VelPres", W.getPassport().timeDiscretizationProperties.nameLength, W.getCurrentStep(), "csv");
829 outfile.open(W.getPassport().dir + "velPres/" + fname);
830
832 outfile << "point,x,y,Vx,Vy,P\n";
833 else
834 outfile << "point,x,y,CVx,CVy,CP\n";
835
836 for (size_t i = 0; i < nRealPressurePoints; ++i)
837 {
838 double xi = (wakeVP->vtx[i].r())[0];
839 double yi = (wakeVP->vtx[i].r())[1];
840 outfile << i << "," << xi << "," << yi \
841 << "," << velocity[i][0] * scaleV << "," << velocity[i][1] * scaleV \
842 << "," << pressure[i] * scaleP << '\n';
843 }//for i
844 outfile.close();
845 }
846 else if (W.getPassport().timeDiscretizationProperties.fileTypeVP.second == 3) //csvBundle
847 {
848 std::string fnameBunCsv = W.getPassport().dir + "velPres/" + "velPresBundle.csv";
849 std::ofstream VPFileBunCsv(fnameBunCsv.c_str(), W.getCurrentStep() ? std::ios::app : std::ios::out);
850 {
851 if (W.getCurrentStep() == 0)
852 VPFileBunCsv << nRealPressurePoints << '\n';
853
854
855 for (size_t q = 0; q < nRealPressurePoints; ++q)
856 {
857 VPFileBunCsv << W.getCurrentStep() << "," \
858 << W.getCurrentTime() << "," \
859 << q << "," \
860 << wakeVP->vtx[q].r()[0] << "," << wakeVP->vtx[q].r()[1] << "," \
861 << velocity[q][0] * scaleV << "," << velocity[q][1] * scaleV << "," \
862 << pressure[q] * scaleP << '\n';
863 }
864 }
865
866 }
867
868
869 //Вывод в csv-файлы точек "historyPoints"
870 #pragma omp parallel for
871 for (int q = 0; q < (int)historyPoints.size(); ++q)
872 {
873
874 if (W.getCurrentStep() == 0)
875 {
876 std::string VPFileNameCsv;
877 VPFileNameCsv = W.getPassport().dir + "velPres/" + VMlib::fileNameStep("VP-atPoint-", 2, q, "csv");
878
879 std::ofstream VPFileCsv(VPFileNameCsv.c_str(), W.getCurrentStep() ? std::ios::app : std::ios::out);
880
882 VPFileCsv << "point,time,Vx,Vy,P\n";
883 else
884 VPFileCsv << "point,time,CVx,CVy,CP\n";
885
886 VPFileCsv.close();
887 }
888
889 sstr[q] << q << "," << W.getCurrentTime() << ","
890 << velocity[initialPoints.size() + q][0] * scaleV << ","
891 << velocity[initialPoints.size() + q][1] * scaleV << ","
892 << pressure[initialPoints.size() + q] * scaleP << '\n';
893
894 if (q == 0)
895 ++sstrCounter;
896 }
897
898 if (sstrCounter == 100)
899 {
900 #pragma omp parallel for
901 for (int q = 0; q < (int)historyPoints.size(); ++q)
902 {
903 std::string VPFileNameCsv;
904 VPFileNameCsv = W.getPassport().dir + "velPres/" + VMlib::fileNameStep("VP-atPoint-", 2, q, "csv");
905
906 std::ofstream VPFileCsv(VPFileNameCsv.c_str(), W.getCurrentStep() ? std::ios::app : std::ios::out);
907
908 VPFileCsv << sstr[q].str();
909
910 VPFileCsv.close();
911
912 sstr[q].str("");
913 sstr[q].clear();
914
915
916 if (q == 0)
917 sstrCounter = 0;
918 }
919 }
920
921 W.getTimers().stop("Save");
922}//SaveVP()
923
924std::vector<std::pair<Point2D, double>> MeasureVP::GetVPinElasticPoints()
925{
926 std::vector<std::pair<Point2D, double>> result;
927 result.reserve(elasticPoints.size());
928
929 const size_t nRealPressurePoints = initialPoints.size() + historyPoints.size(); //число реальных точек - без учета тех, что для гидроупругости
930
931 for (size_t q = 0; q < elasticPoints.size(); ++q)
932 result.push_back({ velocity[nRealPressurePoints + q], pressure[nRealPressurePoints + q] });
933
934 return result;
935}
Заголовочный файл с описанием класса Airfoil.
Заголовочный файл с описанием класса Boundary.
Заголовочный файл с функциями для метода GMRES.
Заголовочный файл с описанием класса MeasureVP.
Заголовочный файл с описанием класса Mechanics.
Заголовочный файл с описанием класса MechanicsDeformable.
Заголовочный файл с описанием класса Preprocessor.
Заголовочный файл с описанием класса StreamParser.
const double PI
Число .
Definition defs.h:76
const double IDPI
Число .
Definition defs.h:79
Заголовочный файл с описанием класса Velocity.
Заголовочный файл с описанием класса Wake.
Заголовочный файл с описанием класса World2D.
std::vector< double > len
Длины панелей профиля
Definition Airfoil2D.h:94
const Point2D & getR(size_t q) const
Возврат константной ссылки на вершину профиля
Definition Airfoil2D.h:113
const Point2D & getV(size_t q) const
Возврат константной ссылки на скорость вершины профиля
Definition Airfoil2D.h:137
std::vector< Point2D > nrm
Нормали к панелям профиля
Definition Airfoil2D.h:81
std::vector< Point2D > tau
Касательные к панелям профиля
Definition Airfoil2D.h:91
Point2D rcm
Положение центра масс профиля
Definition Airfoil2D.h:97
size_t getNumberOfPanels() const
Возврат количества панелей на профиле
Definition Airfoil2D.h:163
Абстрактный класс, определяющий обтекаемый профиль
Definition Airfoil2D.h:182
std::vector< double > gammaThrough
Суммарные циркуляции вихрей, пересекших панели профиля на прошлом шаге
Definition Airfoil2D.h:276
std::vector< int > wayToVertex
Номера путей к вершинам
Definition Airfoil2D.h:202
std::vector< std::vector< Point2D > > possibleWays
Возможные пути внутри профиля от точки (0, 0) к центрам всех панелей
Definition Airfoil2D.h:199
Абстрактный класс, определяющий способ удовлетворения граничного условия на обтекаемом профиле
Definition Boundary2D.h:65
Sheet oldSheets
Слои на профиле с предыдущего шага
Definition Boundary2D.h:99
Sheet sheets
Слои на профиле
Definition Boundary2D.h:96
std::vector< Point2D > initialPoints
Точки, которые считываются из файла (давление пишется в vtk-файлы)
Definition MeasureVP2D.h:68
std::vector< double > pressure
Давление в нужных точках
Definition MeasureVP2D.h:93
void ReadPointsFromFile(const std::string &dir)
Чтение точек, в которых нужно посчитать давление и скорость
void SaveVP()
Сохранение в файл вычисленных скоростей и давлений
const World2D & W
Константная ссылка на решаемую задачу
std::vector< Point2D > historyPoints
Точки, которые считываются из файла (давление пишется в vtk и csv-файлы)
Definition MeasureVP2D.h:71
std::unique_ptr< WakeDataBase > wakeVP
Умный указатель на точки, в которых нужно вычислять в данный момент времени Хранятся в виде "мнимой" ...
Definition MeasureVP2D.h:84
std::vector< Point2D > elasticPoints
Точки, в которых давление нужно вычислять в служебных целях (для задач гидроупругости),...
Definition MeasureVP2D.h:79
std::vector< double > domainRadius
Радиусы вихрей в нужных точках
Definition MeasureVP2D.h:90
void Initialization()
Инициализация векторов для вычисления скоростей и давлений Вызывается только на тех шагах расчета,...
void SetPoints(const std::vector< Point2D > &points, const std::vector< Point2D > &history)
std::vector< std::pair< Point2D, double > > GetVPinElasticPoints()
Возврат давления в "гидроупругих" точках
void CalcPressure()
Расчет поля давления
MeasureVP(const World2D &W_)
Конструктор
std::vector< Point2D > velocity
Скорости в нужных точках
Definition MeasureVP2D.h:87
std::vector< std::ostringstream > sstr
Definition MeasureVP2D.h:73
Класс, определяющий вид механической системы
std::vector< ChordPanel > chord
std::unique_ptr< Beam > beam
PhysicalProperties physicalProperties
Структура с физическими свойствами задачи
Definition Passport2D.h:301
bool calcCoefficients
Признак вычисления коэффициентов вместо сил
Definition Passport2D.h:294
double rotateAngleVpPoints
Угол поворота точек VP.
Definition Passport2D.h:297
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
VortexesParams wakeVortexesParams
Струтура, определяющая параметры вихрей в следе
Definition Velocity2D.h:112
Класс, опеделяющий набор вихрей
std::vector< Vortex2D > vtx
Список вихревых элементов
Класс, опеделяющий текущую решаемую задачу
Definition World2D.h:77
size_t getNumberOfAirfoil() const
Возврат количества профилей в задаче
Definition World2D.h:180
const Wake & getWake() const
Возврат константной ссылки на вихревой след
Definition World2D.h:232
const Airfoil & getAirfoil(size_t i) const
Возврат константной ссылки на объект профиля
Definition World2D.h:163
Velocity & getNonConstVelocity() const
Возврат неконстантной ссылки на объект для вычисления скоростей
Definition World2D.h:258
VMlib::TimersGen & getTimers() const
Возврат ссылки на временную статистику выполнения шага расчета по времени
Definition World2D.h:288
Point2D getV0() const
Возврат текущей скорости набегающего потока
Definition World2D.h:148
const Velocity & getVelocity() const
Возврат константной ссылки на объект для вычисления скоростей
Definition World2D.h:253
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
Mechanics & getNonConstMechanics(size_t i) const
Возврат неконстантной ссылки на объект механики
Definition World2D.h:225
TimeDiscretizationProperties timeDiscretizationProperties
Структура с параметрами процесса интегрирования по времени
std::string dir
Рабочий каталог задачи
Класс, позволяющий выполнять предварительную обработку файлов
Класс, позволяющий выполнять разбор файлов и строк с настройками и параметрами
bool get(const std::string &name, std::vector< Point2D > &res, const std::vector< Point2D > *defValue=nullptr, bool echoDefault=true) const
Считывание вектора из двумерных точек из базы данных
void stop(const std::string &timerLabel)
Останов счетчика
Definition TimesGen.cpp:68
void start(const std::string &timerLabel)
Запуск счетчика
Definition TimesGen.cpp:55
Класс, опеделяющий двумерный вихревой элемент
Definition Vortex2D.h:59
HD double & sigma()
Функция для доступа к радиусу вихря
Definition Vortex2D.h:108
HD Point2D & r()
Функция для доступа к радиус-вектору вихря
Definition Vortex2D.h:92
HD double & g()
Функция для доступа к циркуляции вихря
Definition Vortex2D.h:100
VMlib::LogStream & getInfo() const
Возврат ссылки на объект LogStream Используется в техничеcких целях для организации вывода
Definition WorldGen.h:82
double getCurrentTime() const
Definition WorldGen.h:100
size_t getCurrentStep() const
Возврат константной ссылки на параметры распараллеливания по MPI.
Definition WorldGen.h:99
numvector< T, 2 > kcross() const
Геометрический поворот двумерного вектора на 90 градусов
Definition numvector.h:511
auto length2() const -> typename std::remove_const< typename std::remove_reference< decltype(this->data[0])>::type >::type
Вычисление квадрата нормы (длины) вектора
Definition numvector.h:386
void PrintHeaderToTextFile(std::ofstream &str, const std::string &header)
Формирование подзаголовка в текстовом файле вывода программы VM2D/VM3D.
Definition defs.cpp:175
void CreateUserDirectory(const std::string &dir, const std::string &name)
Создание каталога
Definition defs.h:439
double Lambda(const Point2D &p, const Point2D &s)
Вспомогательная функция вычисления логарифма отношения норм векторов
Definition defs.cpp:268
void PrintLogoToTextFile(std::ofstream &str, const std::string &fileName, const std::string &descr)
Формирование заголовка файла программы VM2D/VM3D.
Definition defs.cpp:139
std::string fileNameStep(const std::string &name, int length, size_t number, const std::string &ext)
Формирование имени файла
Definition defs.h:379
double boundDenom(double r2, double eps2)
Способ сглаживания скорости вихря (вихрь Рэнкина или вихрь Ламба)
Definition defs.h:569
double Alpha(const Point2D &p, const Point2D &s)
Вспомогательная функция вычисления угла между векторами
Definition defs.cpp:262
std::string CurrentDataTime()
Формирование строки с текущем временем и датой
Definition defs.cpp:47
void SwapEnd(T &var)
Вспомогательная функция перестановки байт местами (нужно для сохранения бинарных VTK)
Definition defs.h:561
double vRef
Референсная скорость
Definition Passport2D.h:81
double rho
Плотность потока
Definition Passport2D.h:75
std::vector< Point2D > convVelo
Вектор конвективных скоростей вихрей
Definition Velocity2D.h:72
std::vector< Point2D > diffVelo
Вектор диффузионных скоростей вихрей
Definition Velocity2D.h:75
double dt
Шаг по времени
Definition PassportGen.h:67
int saveVPstep
Шаг вычисления и сохранения скорости и давления
Definition PassportGen.h:86
int nameLength
Число разрядов в имени файла
Definition PassportGen.h:76
std::pair< std::string, int > fileTypeVP
Тип файлов для сохранения скорости и давления
Definition PassportGen.h:84