65#include "treeKernels.cuh"
75 passport(dynamic_cast<const
Passport&>(passport_)),
85 std::vector<std::string> timerLabels = {
"Step",
"MatRhs",
"Solve",
"ConvVel",
"Nut",
"DiffVel",
"Force",
"VelPres",
"Inside",
"Restr",
"Save"};
86 timers = std::make_unique<VMlib::TimersGen>(*
this, timerLabels);
118 auto CreateBoundary = [
this](
size_t i) {
136 info(
'e') <<
"Unknown scheme!" << std::endl;
184 if (
getPassport().wakeDiscretizationProperties.sigma0 == 0)
186 double sumLength = 0.0;
187 size_t totNumPan = 0;
194 double eps = 0.5 * sumLength / totNumPan;
199 if (
getPassport().wakeDiscretizationProperties.epscol == 0)
210 prm.chord = (prm.initialGab.second[0] - prm.initialGab.first[0]) * prm.scale[0];
211 info(
'i') <<
"airfoil #" << afl <<
" chord = " << prm.chord <<
" is calculated automatically" << std::endl;
286 std::unique_ptr<Passport> revisePspPtr;
298 size_t countStrongCoupling = 0;
299 for (
size_t m = 0; m <
mechanics.size(); ++m)
305 ++countStrongCoupling;
309 bool semiImplicitStrategy = ((countStrongCoupling ==
mechanics.size()) && (
mechanics.size() > 0));
311 info(
'i') <<
"Strong (semi-implicit) coupling strategy" << std::endl;
320 if (!semiImplicitStrategy)
326 if (
getPassport().numericalSchemes.velocityComputation.second == 0 &&
getPassport().numericalSchemes.linearSystemSolver.second == 2)
333 auto& treePnlVrt = *
getCuda().inflTreePnlVortex;
335 treePnlVrt.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
340 treePnlVrt.UpdatePanelGeometry(nTotPan, (double4*)afl.devRPtr);
344 treePnlVrt.UpdatePanelAttachedVortexIntensity(afl.devAttachedVortexSheetPtr, afl.devAttachedVortexSheetLinPtr);
345 treePnlVrt.UpwardTraversal(
getPassport().numericalSchemes.gmresMultipoleOrder);
350 if (
getPassport().numericalSchemes.velocityComputation.second == 1)
357 auto& treeWake = *
getCuda().inflTreeWake;
358 treeWake.MemoryAllocate((
int)
getCuda().n_CUDA_wake);
361 treeWake.UpwardTraversal(
getPassport().numericalSchemes.nbodyMultipoleOrder);
366 auto& treePnl = *
getCuda().cntrTreePnl;
367 auto& treePnlVrt = *
getCuda().inflTreePnlVortex;
368 auto& treePnlSrc = *
getCuda().inflTreePnlSource;
369 auto& treePnlAux = *
getCuda().auxTreePnl;
373 treePnl.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
374 treePnlAux.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
375 treePnlVrt.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
377 treePnlSrc.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
383 treePnlVrt.UpdatePanelGeometry(nTotPan, (double4*)afl.devRPtr);
387 treePnl.UpdatePanelGeometry((
int)nTotPan, (double4*)afl.devRPtr);
393 treePnlSrc.UpdatePanelGeometry(nTotPan, (double4*)afl.devRPtr);
394 treePnlSrc.UpdatePanelAttachedSourceIntensity(afl.devAttachedSourceSheetPtr, afl.devAttachedSourceSheetLinPtr);
396 treePnlSrc.UpwardTraversal(
getPassport().numericalSchemes.nbodyMultipoleOrder);
400 treePnlVrt.UpdatePanelAttachedVortexIntensity(afl.devAttachedVortexSheetPtr, afl.devAttachedVortexSheetLinPtr);
401 treePnlVrt.UpwardTraversal(
getPassport().numericalSchemes.nbodyMultipoleOrder);
410 std::vector<std::pair<Point2D, Point2D>> panels;
416 for (
size_t i = 0; i < afl.getNumberOfPanels(); ++i)
417 panels.push_back({ afl.getR(i), afl.getR(i + 1) });
419 if (panels.size() > 0)
421 cntrTreePnl->UpdatePanelGeometry(panels, std::max(4, (
int)(log2(panels.size())) - 2));
433 if (
getPassport().physicalProperties.typeAccel.second == 3)
450 info(
'i') <<
"Added Masses for airfoil #" << bou <<
" = { " << lambdaAdd[bou][0] <<
", " << lambdaAdd[bou][1] <<
", " << muAdd[bou] <<
" }" << std::endl;
453 switch ((
int)(
getPassport().physicalProperties.timeAccel))
466 info(
'e') <<
"Wrong dirfection is specified!" << std::endl;
471 std::ofstream addMassFile;
474 addMassFile.open(addMassFileName);
475 addMassFile <<
"Added Masses for airfoil:" << std::endl;
478 addMassFile.open(addMassFileName, std::ios_base::app);
480 addMassFile << direction <<
"-direction: " << lambdaAdd[bou][0] <<
" " << lambdaAdd[bou][1] <<
" " << muAdd[bou] << std::endl;
489 if (nTotPan > 0 &&
getPassport().numericalSchemes.velocityComputation.second == 1)
493 getCuda().inflTreePnlVortex->UpdatePanelFreeAndAttachedVortexIntensity(afl.devFreeVortexSheetPtr, afl.devFreeVortexSheetLinPtr, afl.devAttachedVortexSheetPtr, afl.devAttachedVortexSheetLinPtr);
494 getCuda().inflTreePnlVortex->UpwardTraversal(
getPassport().numericalSchemes.nbodyMultipoleOrder);
505 std::vector<double> nut;
506 CalcVeloDifference(nut);
509 for (
size_t q = 0; q <
getWake().
vtx.size(); ++q)
539 if (
measureVP->getTotalNumberOfRealPoints() > 0)
548 std::ofstream presForcesFile;
552 presForcesFile <<
"time,Fx,Fy,Py" << std::endl;
555 presForcesFile.open(
getPassport().
dir +
"presForcesFile.csv", std::ios_base::app);
557 auto r =
measureVP->GetVPinElasticPoints();
558 Point2D presForce = { 0.0, 0.0 };
561 for (
int q = 0; q < r.size(); ++q)
567 presForcesFile <<
currentTime <<
"," << scaleP * presForce[0] <<
"," << scaleP * presForce[1] <<
"," << scaleP * yPower << std::endl;
568 presForcesFile.close();
577 if (ptr && ptr->
beam->fsi)
579 auto r =
measureVP->GetVPinElasticPoints();
597 std::vector<double> currentPres(ptr->
chord.size());
598 for (
size_t j = 0; j < ptr->
chord.size(); ++j)
601 currentPres[j] = -(r[2 * j + 0].second - r[2 * j + 1].second);
604 if (ptr->
beam->presLastSteps.size() < ptr->
beam->nLastSteps)
605 ptr->
beam->presLastSteps.push_back(currentPres);
608 for (
int w = 1; w < ptr->
beam->nLastSteps; ++w)
609 ptr->
beam->presLastSteps[w - 1] = std::move(ptr->
beam->presLastSteps[w]);
610 ptr->
beam->presLastSteps.back() = currentPres;
613 for (
int q = 0; q < ptr->
beam->R; ++q)
615 ptr->
beam->qCoeff[q] = 0;
617 if (ptr->
beam->presLastSteps.size() == ptr->
beam->nLastSteps)
619 for (
size_t j = 0; j < ptr->
chord.size(); ++j)
621 double averpres = 0.0;
624 for (
int i = 0; i < ptr->
beam->nLastSteps; ++i)
625 averpres += ptr->
beam->presLastSteps[i][j];
626 averpres /= ptr->
beam->nLastSteps;
630 ptr->
beam->qCoeff[q] /= (ptr->
beam->intSqUnitShape * ptr->
beam->L);
636 std::ofstream phiFile;
641 for (
int p = 0; p < ptr->
beam->R; ++p)
642 phiFile <<
",phi-" << std::to_string(p + 1);
643 for (
int p = 0; p < ptr->
beam->R; ++p)
644 phiFile <<
",q-" << std::to_string(p + 1);
645 phiFile << std::endl;
648 phiFile.open(
getPassport().
dir +
"phiFile.csv", std::ios_base::app);
651 for (
int p = 0; p < ptr->
beam->R; ++p)
652 phiFile <<
"," << ptr->
beam->phi(p, 0);
653 for (
int p = 0; p < ptr->
beam->R; ++p)
654 phiFile <<
"," << ptr->
beam->qCoeff[p];
656 phiFile << std::endl;
668 mech->GetHydroDynamForce();
669 mech->GenerateForcesString();
670 mech->GeneratePositionString();
697 if (semiImplicitStrategy)
727 for (
size_t m = 0; m <
mechanics.size(); ++m)
736 getInfo(
'e') <<
"Added mass of the airfoil should be non-zero!" << std::endl;
773 << std::setprecision(3) \
775 << std::setprecision(6) \
792void World2D::CheckInside(std::vector<Point2D>& newPos,
const std::vector<std::unique_ptr<AirfoilGeometry>>& oldAirfoil)
801#if (!defined(USE_CUDA))
803 for (
size_t afl = 0; afl <
airfoil.size(); ++afl)
876 for (
size_t afl = 0; afl <
airfoil.size(); ++afl)
877 nTotPanels += (
int)
airfoil[afl]->getNumberOfPanels();
885 auxTree.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
886 auxTree.UpdatePanelGeometry(nTotPanels, (double4*)
airfoil[0]->devRPtr);
888 auxTree.UpwardTraversal(0);
891 std::vector<int> hit(newPos.size());
895 double* devNewpos_ptr;
896 cudaMalloc(&devNewpos_ptr, newPos.size() *
sizeof(
double) * 2);
897 cudaMemcpy(devNewpos_ptr, newPos.data(), newPos.size() *
sizeof(
double) * 2, cudaMemcpyHostToDevice);
899 auto& cntrTreePnt = *
getCuda().cntrTreePoint;
900 cntrTreePnt.MemoryAllocate((
int)
getCuda().n_CUDA_wake);
901 cntrTreePnt.Update((
int)newPos.size(), devNewpos_ptr);
904 BHcu::treeClosestPanelToPointsCalculationWrapper(auxTree, cntrTreePnt,
getWake().devNearestPanelPtr,
true,
getAirfoil(0).devPsnPtr);
906 cudaMemcpy(hit.data(),
getWake().devNearestPanelPtr, newPos.size() *
sizeof(
int), cudaMemcpyDeviceToHost);
907 cudaFree(devNewpos_ptr);
925 std::vector<std::pair<Point2D, Point2D>> segments(newPos.size());
926 for (
size_t i = 0; i < newPos.size(); ++i)
928 segments[i].first =
wake->vtx[i].r();
929 segments[i].second = newPos[i];
931 double* devSegments_ptr;
933 cudaMalloc(&devSegments_ptr, newPos.size() *
sizeof(
double) * 4);
934 cudaMemcpy(devSegments_ptr, segments.data(), newPos.size() *
sizeof(
double) * 4, cudaMemcpyHostToDevice);
936 auto& cntrTreeSeg = *
getCuda().cntrTreeSegment;
937 cntrTreeSeg.MemoryAllocate((
int)
getCuda().n_CUDA_wake);
938 cntrTreeSeg.UpdatePanelGeometry((
int)newPos.size(), (double4*)devSegments_ptr);
941 BHcu::treePanelsSegmentsIntersectionCalculationWrapper(auxTree, cntrTreeSeg,
getWake().devNearestPanelPtr);
942 cudaMemcpy(hit.data(),
getWake().devNearestPanelPtr, newPos.size() *
sizeof(
int), cudaMemcpyDeviceToHost);
943 cudaFree(devSegments_ptr);
946 size_t panCounter = 0;
947 for (
size_t afl = 0; afl <
airfoil.size(); ++afl)
949 std::vector<double> gamma(
airfoil[afl]->getNumberOfPanels(), 0.0);
950 for (
int i = 0; i < newPos.size(); ++i)
954 if ((hit[i] >= panCounter) && (hit[i] < panCounter +
airfoil[afl]->getNumberOfPanels()))
956 if (fabs(
wake->vtx[i].g()) > 1.0)
957 std::cout <<
"Too large gamma is through: i = " << i <<
", " << hit[i] <<
", " <<
"gamma[hit[i] - panCounter] += " <<
wake->vtx[i].g() << std::endl;
959 gamma[hit[i] - panCounter] +=
wake->vtx[i].g();
960 wake->vtx[i].g() = 0.0;
964 airfoil[afl]->gammaThrough = gamma;
965 panCounter +=
airfoil[afl]->getNumberOfPanels();
1041 if (linSystemScheme == 0)
1043 double t1 = -omp_get_wtime();
1046 info(
't') <<
"Inverting matrix... ";
1048#if (defined(USE_CUDA))
1050 for (
int i = 0; i < (int)
matrReord.rows(); ++i)
1051 for (
int j = 0; j < (int)
matrReord.cols(); ++j)
1052 invMatr(i, j) = (i == j) ? 1.0 : 0.0;
1057 info(
't') <<
"done" << std::endl;
1061 info(
't') <<
"Solving system at step #0... ";
1090 info(
't') <<
"done" << std::endl;
1092 t1 += omp_get_wtime();
1161 if ((linSystemScheme == 1 || linSystemScheme == 2))
1165 nFullVars += (
int)(
boundary[i]->GetUnknownsSize());
1169 Ggam[i].resize(
boundary[i]->GetUnknownsSize());
1174 std::vector<double> Grhs(
rhsReord.size());
1175 for (
int i = 0; i <
rhsReord.size(); ++i)
1180 Gpos[i] = Gpos[i - 1] + (
int)(
boundary[i - 1]->GetUnknownsSize());
1184 Gvsize[i] = (
int)(
boundary[i]->GetUnknownsSize());
1189 std::vector<double> Gmatr(nFullVars * nFullVars);
1190 for (
size_t i = 0; i < nFullVars; ++i)
1191 for (
size_t j = 0; j < nFullVars; ++j)
1192 Gmatr[i * nFullVars + j] =
matrReord(i, j);
1195 for (
int j = 0; j <
boundary[i]->GetUnknownsSize(); ++j)
1196 auto y_test =
airfoil[i]->len[j %
airfoil[i]->getNumberOfPanels()];
1199 std::cout <<
"GMRES_Direct should be modified!" << std::endl;
1203 sol.resize(nFullVars);
1206 for (
int j = 0; j <
boundary[i]->GetUnknownsSize(); ++j)
1207 sol(cntr++) = Ggam[i][j] ;
1209 sol(cntr++) = GR[i];
1219 getInfo(
'e') <<
"Fast GMRES without CUDA is not implemented" << std::endl;
1225 getInfo(
'e') <<
"Direct GMRES for CUDA is not implemented" << std::endl;
1235 GGrhs[i].resize(
boundary[i]->GetUnknownsSize());
1237 for (
int j = 0; j <
boundary[i]->GetUnknownsSize(); ++j)
1248 double time_GMRES = -omp_get_wtime();
1250 time_GMRES += omp_get_wtime();
1253 sol.resize(nFullVars);
1256 for (
int j = 0; j <
boundary[i]->GetUnknownsSize(); ++j)
1257 sol(cntr++) = Ggam[i][j] /
airfoil[i]->len[j %
airfoil[i]->getNumberOfPanels()];
1259 sol(cntr++) = GR[i];
1283 if (linSystemScheme == 0 || linSystemScheme == 1)
1288 Eigen::MatrixXd locMatr;
1289 Eigen::MatrixXd otherMatr;
1290 Eigen::VectorXd locLastLine, locLastCol;
1292 std::vector<std::vector<Point2D>> locIQ;
1293 std::vector<std::vector<Point2D>> locOtherIQ;
1298 for (
int i = 0; i <
matrReord.rows(); ++i)
1299 for (
int j = 0; j <
matrReord.cols(); ++j)
1303 size_t currentRow = 0;
1304 size_t currentSkosRow = 0;
1306 size_t nAllVars = 0;
1307 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
1308 nAllVars +=
boundary[bou]->GetUnknownsSize();
1310 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
1312 size_t nVars =
boundary[bou]->GetUnknownsSize();
1315 locMatr.resize(nVars, nVars);
1316 locLastLine.resize(nVars);
1317 locLastCol.resize(nVars);
1321 boundary[bou]->FillMatrixSelf(locMatr, locLastLine, locLastCol);
1325 for (
size_t i = 0; i < nVars; ++i)
1329 for (
size_t j = 0; j < nVars; ++j)
1330 matrReord(i + currentSkosRow, j + currentSkosRow) = locMatr(i, j);
1332 matrReord(nAllVars + bou, i + currentSkosRow) = locLastLine(i);
1333 matrReord(i + currentSkosRow, nAllVars + bou) = locLastCol(i);
1339 size_t currentCol = 0;
1340 size_t currentSkosCol = 0;
1341 for (
size_t oth = 0; oth <
boundary.size(); ++oth)
1343 size_t nVarsOther =
boundary[oth]->GetUnknownsSize();
1347 otherMatr.resize(nVars, nVarsOther);
1352 for (
size_t i = 0; i < nVars; ++i)
1354 for (
size_t j = 0; j < nVarsOther; ++j)
1355 matrReord(i + currentSkosRow, j + currentSkosCol) = otherMatr(i, j);
1358 currentCol += nVarsOther + 1;
1359 currentSkosCol += nVarsOther;
1363 currentRow += nVars + 1;
1364 currentSkosRow += nVars;
1384 for (
size_t i = 1; i <
boundary.size(); ++i)
1390 size_t matrSkosSize = 0;
1394 matrSize += (*it)->GetUnknownsSize();
1395 matrSkosSize += (*it)->GetUnknownsSize();
1411 size_t nVari =
boundary[i]->GetUnknownsSize();
1414 size_t nVarj =
boundary[j]->GetUnknownsSize();
1415 IQ[i][j].first.resize(nVari, nVarj);
1416 IQ[i][j].second.resize(nVari, nVarj);
1443#if defined(__CUDACC__) || defined(USE_CUDA)
1444 cuda.RefreshWake(2);
1446 cuda.RefreshAfls(2);
1447 cuda.RefreshVirtualWakes(2);
1460#if defined(__CUDACC__) || defined(USE_CUDA)
1461 for (
size_t i = 0; i <
airfoil.size(); ++i)
1462 cuda.CopyMemToDev<
double, 1>(
airfoil[i]->getNumberOfPanels(),
airfoil[i]->meanEpsOverPanel.data(),
airfoil[i]->devMeanEpsOverPanelPtr);
1473 if (afl->viscousStress.size() == 0)
1474 afl->viscousStress.resize(afl->getNumberOfPanels(), 0.0);
1558void World2D::CalcVeloDifference(std::vector<double>& nut)
const
1560 nut.resize(
getWake().vtx.size());
1566 std::vector<Point2D> basePoints = { {0.,0.}, { -2.10684, -1.84373 }, { 0.494872,-3.43051 }, { -1.8307,-0.772619 }, { -2.97035,-1.77037 }, { -0.869454,-2.66541 }, { -1.81226,-2.74913 }, { -0.93585,0.525783 }, { -2.84757,1.56598 }, { -0.140883,1.06415 }, { -3.2381,0.623172 }, { -1.70686,2.57839 }, { -3.36087,-0.827564 }, { 0.869454,-2.66541 }, { 1.81226,-2.74913 }, { 1.8307,-0.772618 }, { 0.794967,0.794967 }, { 2.78945,-0.204392 }, { 1.04125,-0.439927 }, { -0.366572,3.2381 }, { 1.39868,1.39868 }, { -1.04125,-0.439927 }, { 0.623172,3.2381 }, { 0.0, -1.13645 }, { 1.22688,2.50847 }, { 3.2381,0.623172 }, { 2.97035,-1.77037 }, { 2.78461,2.04139 }, { 0.0, -1.99554 }, { -2.78945,-0.204392 }, { -0.494871,-3.43051 }, { 2.10684,-1.84373 }, { 3.36087,-0.827563 }, { -0.635755,2.30225 }, { -1.87866,1.46859 }, { 2.50847,1.22688 }, { 2.04139,2.78461 } };
1576 controlPoints.vtx.resize(
getWake().vtx.size() * basePoints.size());
1578 for (
size_t q = 0; q <
getWake().
vtx.size(); ++q)
1579 for (
size_t i = 0; i < basePoints.size(); ++i)
1580 controlPoints.vtx[q * basePoints.size() + i].r() =
getWake().
vtx[q].r() + basePoints[i] *
getWake().
vtx[q].sigma();
1583 cuReserveDevMem((
void*&)controlPoints.devVtxPtr, controlPoints.vtx.size() *
sizeof(
Vortex2D), 333);
1584 cuCopyWakeToDev(controlPoints.vtx.size(), controlPoints.vtx.data(), controlPoints.devVtxPtr, 444);
1585 cuReserveDevMem((
void*&)controlPoints.devVelPtr, controlPoints.vtx.size() * 2 *
sizeof(
double), 555);
1588 treeNut->MemoryAllocate((
int)
getCuda().n_CUDA_wake * (
int)basePoints.size());
1589 treeNut->Update((
int)controlPoints.vtx.size(), controlPoints.devVtxPtr);
1592 std::vector<Point2D> veloVar(
getWake().vtx.size() * basePoints.size(),
Point2D{0.0, 0.0});
1593 std::vector<double> epsVar;
1594 velocity->GPUCalcConvVeloToSetOfPointsFromWake(treeNut, controlPoints, veloVar, epsVar,
true,
false);
1596 velocity->GPUCalcConvVelocityToSetOfPointsFromSheets(treeNut, controlPoints, veloVar);
1598 cuDeleteFromDev((
void*&)controlPoints.devVtxPtr, 777);
1599 cuDeleteFromDev((
void*&)controlPoints.devVelPtr, 888);
1601 for (
size_t q = 0; q <
getWake().
vtx.size(); ++q)
1604 for (
size_t i = 1; i < basePoints.size(); ++i)
1605 dv2 += (veloVar[q * basePoints.size()] - veloVar[q * basePoints.size() + i]).length2() * pow(
getWake().vtx[q].sigma() / (controlPoints.vtx[q * basePoints.size() + i].r() -
getWake().vtx[q].r()).length(), 0.6666667);
1607 dv2 *= 1.0 / (basePoints.size() - 1);
1608 nut[q] = 0.105 * 0.604 *
wake->vtx[q].sigma() * sqrt(dv2);
1619 for (
size_t i = 0; i <
airfoil.size(); ++i)
1623 for (
size_t i = 0; i <
airfoil.size(); ++i)
1624 boundary[i]->ComputeAttachedSheetsIntensity();
1638 size_t nvt =
wake->vtx.size();
1639 size_t nVirtVortex = 0;
1641 nVirtVortex +=
boundary[i]->virtualWake.vtx.size();
1646 size_t counter =
wake->vtx.size() - nVirtVortex;
1647 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
1649 for (
int i = 0; i < (int)
boundary[bou]->virtualWake.vtx.size(); ++i)
1651 wake->vtx[counter].g() =
boundary[bou]->virtualWake.vtx[i].g();
1663 const double c = 4.5;
1665 const auto& eps =
velocity->wakeVortexesParams.epsastWake;
1667 double minEpsast = *std::min_element(eps.begin(), eps.end());
1668 double meanEpsast = std::accumulate(eps.begin(), eps.end(), 0.0) / eps.size();
1670 double uniformH = minEpsast + 0.2 * (meanEpsast - minEpsast);
1672 std::vector<std::vector<int>> neib(
wake->vtx.size());
1673 for (
auto& nb : neib)
1676#pragma omp parallel for schedule(dynamic, 100)
1677 for (
int i = 0; i < (int)
wake->vtx.size(); ++i)
1679 const double hati = c * eps[i];
1680 const double hati2 = sqr(hati);
1681 const int dist = std::ceil(hati / uniformH);
1684 int cx = (int)(vtx[0] / uniformH);
1685 int cy = (int)(vtx[1] / uniformH);
1687 for (
int j = 0; j < (int)
wake->vtx.size(); ++j)
1690 int tx = (int)(test[0] / uniformH);
1691 int ty = (int)(test[1] / uniformH);
1693 if (abs(cx - tx) <= dist && abs(cy - ty) <= dist)
1694 if ((vtx - test).length2() < hati2)
1695 neib[i].push_back(j);
1705 auto W = [](
double xi,
double R) {
double t = xi / R;
return (t > 1 ? 0.0 : 40.0 / (7.0 *
PI * R * R) * (t > 0.5 ? 2.0 * cubPower(1.0 - t) : 1.0 - 6.0 * sqr(t) * (1.0 - t))); };
1706 auto WW = [zeroVec](
const Point2D& v,
double R) {
double t = v.
length() / R;
return (t > 1 ? zeroVec : v * (240.0 / (7.0 *
PI * sqr(sqr(R))) * (t > 0.5 ? -sqr(1.0 - t) / t : -2.0 + 3.0 * t))); };
1751 std::vector<double> OIP(
wake->vtx.size(), 0.0);
1752 std::vector<double> VIP(
wake->vtx.size(), 0.0);
1753 std::vector<Point2D> GIP(
wake->vtx.size(), { 0.0, 0.0 });
1754 std::vector<Point2D> DIFFV(
wake->vtx.size(), { 0.0, 0.0 });
1757 const auto& vtx =
wake->vtx;
1758 const auto& vel =
velocity->wakeVortexesParams.convVelo;
1772 std::vector<nummatrix<double, 2, 2>> mtrL(
wake->vtx.size(), { {0.0, 0.0}, {0.0, 0.0} });
1773 std::vector<std::vector<double>> weight(
wake->vtx.size());
1776 std::vector<Point2D> sumDIFFV(
wake->vtx.size(), {0.0, 0.0});
1777 std::vector<double> sumWeight(
wake->vtx.size(), 0.0);
1779#pragma omp parallel for schedule(dynamic, 100)
1780 for (
int i = 0; i < (int)vtx.size(); ++i)
1782 const double hati = c * eps[i];
1784 double resultOIP = 0.0;
1787 const Point2D myPos = vtx[i].r();
1789 double I1 = 0.0, I0 = 1.0;
1792 weight[i].reserve(neib[i].size());
1794 for (
auto& nbr : neib[i])
1796 double dist2 = (myPos - vtx[nbr].r()).length2();
1797 double dist = sqrt(dist2);
1798 double w = W(dist, hati);
1799 I1 += vtx[nbr].g() * w;
1800 weight[i].push_back(w);
1806#pragma omp parallel for schedule(dynamic, 100)
1807 for (
int i = 0; i < (int)vtx.size(); ++i)
1809 const Point2D myPos = vtx[i].r();
1810 const double hati = c * eps[i];
1815 for (
auto& nbr : neib[i])
1817 Point2D dr = myPos - vtx[nbr].r();
1818 Point2D grweight = WW(dr, hati);
1819 double vol = (vtx[nbr].g() / OIP[nbr]);
1823 M += (dr | grweight) * vol;
1824 GIP[i] -= grweight * ((OIP[nbr] - OIP[i]) * vol);
1827 double detM = M[0][0] * M[1][1] - M[1][0] * M[0][1];
1829 if (fabs(detM) > 1e-2)
1832 GIP[i] = (L & GIP[i]);
1833 DIFFV[i] = GIP[i] * (1.0 / OIP[i]);
1840 for (
int i = 0; i < (int)vtx.size(); ++i)
1841 for (
int j = 0; j < neib[i].size(); ++j)
1842 if ((vtx[i].r() - vtx[neib[i][j]].r()).length() <= 1.0 * eps[i])
1844 sumDIFFV[i] += weight[i][j] * DIFFV[neib[i][j]];
1845 sumWeight[i] += weight[i][j];
1849 for (
int i = 0; i < (int)vtx.size(); ++i)
1851 DIFFV[i] = sumDIFFV[i] * (1.0 / sumWeight[i]);
1984 for (
int i = 0; i < (int)
wake->vtx.size(); ++i)
1988 Point2D W = -passport.physicalProperties.nu * DIFFV[i];
1990 checkVel << i <<
" " <<
wake->vtx[i].r()[0] <<
" " <<
wake->vtx[i].r()[1] <<
" " << velocity->wakeVortexesParams.epsastWake[i] <<
" " \
1991 << velocity->wakeVortexesParams.convVelo[i][0] <<
" " << velocity->wakeVortexesParams.convVelo[i][1] <<
" " \
1992 << W[0] <<
" " << W[1];
1994 if (W.length() > 1.5 * passport.physicalProperties.vRef)
1996 std::cout <<
"i = " << i <<
", W was " << W << std::endl;
2001 checkVel <<
" " << W[0] <<
" " << W[1] <<
" " << OIP[i] <<
" " << GIP[i][0] <<
" " << GIP[i][1] <<
"\n";
2004 Point2D W = velocity->wakeVortexesParams.diffVelo[i] * (nutPtr ? (1.0 + (*nutPtr)[i] / passport.physicalProperties.nu) : 1.0);
2006 const auto& diff = velocity->wakeVortexesParams;
2007 Point2D grad = diff.I2[i] * (1.0 / (diff.epsastWake[i] * diff.I0[i])) - diff.I3[i] * (diff.I1[i] /
sqr(diff.I0[i]));
2014 newPos[i] =
wake->vtx[i].r() + (velocity->wakeVortexesParams.convVelo[i] + W + getV0()) * passport.timeDiscretizationProperties.dt;
2040 mechanics[mechanicsNumber]->GenerateForcesHeader();
2041 mechanics[mechanicsNumber]->GeneratePositionHeader();
2049 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
2056 for (
size_t oth = 0; oth <
boundary.size(); ++oth)
2093#if defined(__CUDACC__) || defined(USE_CUDA)
2099 if ((sch == 1) || (sch == 2) || (sch == 0))
2103 info(
'e') <<
"schemeSwitcher is not 0, or 1, or 2! " << std::endl;
2107 cuda.RefreshWake(1);
2108 cuda.RefreshAfls(1);
2109 cuda.RefreshVirtualWakes(1);
2114 if (linSystemScheme == 0)
2181 size_t currentRow = 0;
2182 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
2184 size_t nVars =
boundary[bou]->GetUnknownsSize();
2185 Eigen::VectorXd locSol;
2186 locSol.resize(nVars);
2187 for (
size_t i = 0; i < nVars; ++i)
2188 locSol(i) =
sol(currentRow + i);
2190 boundary[bou]->SolutionToFreeVortexSheetAndVirtualVortex(locSol);
2191 currentRow += nVars;
2195 size_t nVirtVortices = 0;
2196 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
2197 nVirtVortices +=
boundary[bou]->virtualWake.vtx.size();
2199 wake->vtx.reserve(
wake->vtx.size() + nVirtVortices);
2200 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
2201 for (
size_t v = 0; v <
boundary[bou]->virtualWake.vtx.size(); ++v)
2202 wake->vtx.push_back(
Vortex2D{ boundary[bou]->virtualWake.vtx[v].r(), 0.0, getPassport().wakeDiscretizationProperties.sigma0});
2236 std::vector<Point2D> newPos;
2264 if (afl->numberInPassport == 0)
2266 mechanics[afl->numberInPassport]->Move();
2271 if (mechTest !=
nullptr)
2292 airfoil[afl->numberInPassport]->Move(dr);
2293 airfoil[afl->numberInPassport]->Rotate(dphi);
2307 mechanics[afl->numberInPassport]->Move();
2319#if defined(__CUDACC__) || defined(USE_CUDA)
2320 cuda.RefreshAfls(2);
2324 bou->virtualWake.vtx.clear();
2331 for (
size_t i = 0; i <
wake->vtx.size(); ++i)
2333 wake->vtx[i].r() = newPos[i];
2345 [](
const std::unique_ptr<Mechanics>& m) {
return (m->isMoves); });
2352 [](
const std::unique_ptr<Mechanics>& m) {
return (m->isMoves || m->isDeform); });
Заголовочный файл с описанием класса AirfoilRect.
Заголовочный файл с описанием класса BoundaryConstLayerAver.
Заголовочный файл с описанием класса BoundaryLinLayerAver.
Заголовочный файл с описанием класса BoundaryVortexCollocN.
Заголовочный файл с функциями для метода GMRES.
Заголовочный файл с описанием класса MeasureVP.
Заголовочный файл с описанием класса MechanicsRigidGivenLaw.
Заголовочный файл с описанием класса MechanicsRigidImmovable.
Заголовочный файл с описанием класса MechanicsRigidOscillPart.
Заголовочный файл с описанием класса MechanicsRigidRotatePart.
Заголовочный файл с описанием класса StreamParser.
Заголовочный файл с описанием класса VelocityBarnesHut.
Заголовочный файл с описанием класса VelocityBiotSavart.
Заголовочный файл с описанием класса Wake.
Заголовочный файл с описанием класса World2D.
Класс, определяющий форму профиля
std::vector< double > len
Длины панелей профиля
const Point2D & getR(size_t q) const
Возврат константной ссылки на вершину профиля
std::vector< Point2D > nrm
Нормали к панелям профиля
Point2D rcm
Положение центра масс профиля
size_t getNumberOfPanels() const
Возврат количества панелей на профиле
void calcMeanEpsOverPanel()
Вычисление средних значений eps на панелях
Класс, определяющий тип обтекаемого профиля
Класс, определяющий способ удовлетворения граничного условия на обтекаемом профиле
Sheet sheets
Слои на профиле
Класс, определяющий способ удовлетворения граничного условия на обтекаемом профиле
Класс, определяющий способ удовлетворения граничного условия на обтекаемом профиле
Структура, хранящая данные и указатели на массивы на GPU для оптимизации итерационного решения СЛАУ н...
Класс, обеспечивающий возможность выполнения вычислений на GPU по технологии Nvidia CUDA.
void setAccelCoeff(double cft_)
Установка коэффициента разгона потока
void setMaxGamma(double gam_)
Установка максимально допустимой циркуляции вихря
void setSchemeSwitcher(int schemeSwitcher_)
Установка переключателя расчетных схем
Класс, отвечающий за вычисление поля скорости и давления в заданых точках для вывода
Абстрактный класс, определяющий вид механической системы
Point2D hydroDynamForce
Вектор гидродинамической силы и момент, действующие на профиль
void GeneratePositionString()
Сохранение строки со статистикой в файл нагрузок
void GenerateForcesString()
Сохранение строки со статистикой в файл нагрузок
Класс, определяющий вид механической системы
Класс, определяющий вид механической системы
Класс, определяющий вид механической системы
Point2D & getR()
текущее отклонение профиля
double & getPhi()
текущий угол поворота профиля
Point2D & getV()
текущая скорость профиля
bool & getStrongCoupling()
double & getW()
текущая угловая скорость профиля
Класс, определяющий вид механической системы
Класс, опеделяющий паспорт двумерной задачи
std::string wakesDir
Каталог с файлами вихревых следов
PhysicalProperties physicalProperties
Структура с физическими свойствами задачи
std::string defaultsFileFullName
WakeDiscretizationProperties wakeDiscretizationProperties
Структура с параметрами дискретизации вихревого следа
std::vector< std::string > varLine
std::string airfoilsDir
Каталог с файлами профилей
std::vector< AirfoilParams > airfoilParams
Список структур с параметрами профилей
std::string switchersFileFullName
std::string mechanicsFileFullName
std::string fileFullName
Имена файлов
void GetReviseParamsFromParser(const Passport &newPassport, const std::vector< std::string > paramList)
Считывание измененных параметров
NumericalSchemes numericalSchemes
Структура с используемыми численными схемами
const double & attachedVortexSheet(size_t n, size_t moment) const
const double & freeVortexSheet(size_t n, size_t moment) const
Класс, определяющий способ вычисления скоростей
Класс, определяющий способ вычисления скоростей
Класс, опеделяющий набор вихрей
std::vector< Vortex2D > vtx
Список вихревых элементов
Класс, опеделяющий вихревой след (пелену)
size_t getNumberOfAirfoil() const
Возврат количества профилей в задаче
std::unique_ptr< CpuTreeInfo > inflTreeWake
Деревья для быстрого метода
Gpu cuda
Объект, управляющий графическим ускорителем
void ReserveMemoryForMatrixAndRhs()
Вычисляем размер матрицы и резервируем память под нее и под правую часть
bool isAnyMovable() const
Возврат признака того, что хотя бы один из профилей подвижный
void WakeAndAirfoilsMotion(bool dynamics, std::vector< double > *nutPtr=nullptr)
Перемещение вихрей и профилей на шаге
std::vector< std::unique_ptr< Airfoil > > airfoil
Список умных указателей на обтекаемые профили
VMlib::vmTimer timerInitialBuild
bool isAnyMovableOrDeformable() const
Возврат признака того, что хотя бы один из профилей подвижный или деформируемый
std::unique_ptr< MeasureVP > measureVP
Умный указатель на алгоритм вычисления полей скоростей и давления (для сохранения в файл)
Eigen::MatrixXd matrReord
Матрица системы
bool useInverseMatrix
Признак использования обратной матрицы
const Wake & getWake() const
Возврат константной ссылки на вихревой след
Eigen::MatrixXd invMatr
Обратная матрица
void CalcPanelsVeloAndAttachedSheets()
Вычисление скоростей панелей и интенсивностей присоединенных слоев вихрей и источников
void CalcVortexVelo()
Вычисление скоростей (и конвективных, и диффузионных) вихрей (в пелене и виртуальных),...
std::vector< std::unique_ptr< AirfoilGeometry > > oldAirfoil
Список умных указателей на обтекаемые профили для сохранения старого положения
World2D(const VMlib::PassportGen &passport_)
Конструктор
const Airfoil & getAirfoil(size_t i) const
Возврат константной ссылки на объект профиля
const std::vector< std::unique_ptr< Mechanics > > & getMechanicsVector() const
VMlib::vmTimer timerInside
Gpu & getNonConstCuda() const
Возврат неконстантной ссылки на объект, связанный с видеокартой (GPU)
std::unique_ptr< WakeDataBase > source
Умный указатель на источники
void CalcAndSolveLinearSystem()
Набор матрицы, правой части и решение СЛАУ
Eigen::VectorXd rhsReord
Правая часть системы
void MoveVortexes(std::vector< Point2D > &newPos, std::vector< double > *nutPtr=nullptr)
Вычисляем новые положения вихрей (в пелене и виртуальных)
std::vector< size_t > dispBoundaryInSystem
Список номеров, с которых начинаются элементы правой части (или матрицы) системы для профилей
VMlib::TimersGen & getTimers() const
Возврат ссылки на временную статистику выполнения шага расчета по времени
void FillIQ()
Заполнение матрицы, состоящей из интегралов от (r-xi) / |r-xi|^2.
std::vector< std::unique_ptr< Mechanics > > mechanics
Список умных указателей на типы механической системы для каждого профиля
const Gpu & getCuda() const
Возврат константной ссылки на объект, связанный с видеокартой (GPU)
std::vector< std::unique_ptr< Boundary > > boundary
Список умных указателей на формирователи граничных условий на профилях
const Passport & getPassport() const
Возврат константной ссылки на паспорт
std::unique_ptr< CpuTreeInfo > cntrTreePnl
Passport & getNonConstPassport() const
Возврат неконстантной ссылки на паспорт
void GenerateMechanicsHeader(size_t mechanicsNumber)
std::unique_ptr< CpuTreeInfo > cntrTreeVP
void CheckInside(std::vector< Point2D > &newPos, const std::vector< std::unique_ptr< AirfoilGeometry > > &oldAirfoil)
Проверка проникновения вихрей внутрь профиля
void SolveLinearSystem()
Решение системы линейных алгебраических уравнений
std::unique_ptr< Wake > wake
Умный указатель на вихревой след
const Boundary & getBoundary(size_t i) const
Возврат константной ссылки на объект граничного условия
bool ifDivisible(int val) const
size_t getNumberOfBoundary() const
Возврат количества граничных условий в задаче
std::unique_ptr< Velocity > velocity
Умный укзатель на объект, определяющий методику вычисления скоростей
const Passport & passport
Константная ссылка на паспорт конкретного расчета
void FillMatrixAndRhs()
Заполнение матрицы системы для всех профилей
virtual void Step() override
Функция выполнения предварительного шага
VMlib::vmTimer timerFillMatrix
Eigen::VectorXd sol
Решение системы
Mechanics & getNonConstMechanics(size_t i) const
Возврат неконстантной ссылки на объект механики
std::vector< std::vector< std::pair< Eigen::MatrixXd, Eigen::MatrixXd > > > IQ
Матрица, состоящая из пар матриц, в которых хранятся касательные и нормальные компоненты интегралов о...
Airfoil & getNonConstAirfoil(size_t i) const
Возврат неконстантной ссылки на объект профиля
VMlib::vmTimer timerSlaeSolve
std::unique_ptr< CpuTreeInfo > cntrTreeWake
Wake & getNonConstWake() const
Возврат неконстантной ссылки на вихревой след
void endl()
Вывод в поток логов пустой строки
void assignStream(std::ostream *pStr_, const std::string &label_)
Связывание потока логов с потоком вывода
Абстрактный класс, опеделяющий паспорт задачи
TimeDiscretizationProperties timeDiscretizationProperties
Структура с параметрами процесса интегрирования по времени
std::string problemName
Название задачи
std::string dir
Рабочий каталог задачи
size_t problemNumber
Номер задачи
void GenerateStatString(size_t stepNo, double curTime, size_t N)
Формирование очередной строки файла временной статистики
void stop(const std::string &timerLabel)
Останов счетчика
void start(const std::string &timerLabel)
Запуск счетчика
void resetAll()
Сброс всех счетчиков
double durationStep() const
Вывод счетчика всего шага в секундах
Класс, опеделяющий двумерный вихревой элемент
std::unique_ptr< TimersGen > timers
Сведения о временах выполнения основных операций
double currentTime
Текущее время в решаемой задаче
VMlib::LogStream & getInfo() const
Возврат ссылки на объект LogStream Используется в техничеcких целях для организации вывода
double getCurrentTime() const
size_t currentStep
Текущий номер шага в решаемой задаче
size_t getCurrentStep() const
Возврат константной ссылки на параметры распараллеливания по MPI.
LogStream info
Поток для вывода логов и сообщений об ошибках
Шаблонный класс, определяющий матрицу фиксированного размера Фактически представляет собой массив,...
nummatrix< T, n, m > & toZero(T val=0.0)
numvector< T, 2 > kcross() const
Геометрический поворот двумерного вектора на 90 градусов
numvector< T, n > & toZero(P val=0)
Установка всех компонент вектора в константу (по умолчанию — нуль)
P length() const
Вычисление 2-нормы (длины) вектора
const vmTimer & stop() const
Останов работающего счетчика времени
const vmTimer & start() const
Запуск (первый или повторный) счетчика времени
const vmTimer & reset() const
Сброс счетчика времени
void PrintLogoToStream(std::ostream &str)
Передача в поток вывода шапки программы VM2D/VM3D.
bool fileExistTest(std::string &fileName, LogStream &info, bool exitKey=false, const std::list< std::string > &extList={})
Проверка существования файла
T sqr(T x)
Возведение числа в квадрат
static std::ostream * defaultWorld2DLogStream
Поток вывода логов и ошибок задачи
Описание класса nummatrix.
std::pair< std::string, int > boundaryCondition
Метод аппроксимации граничных условий
std::pair< std::string, int > velocityComputation
std::pair< std::string, int > linearSystemSolver
double accelCft(double currentTime) const
Функция-множитель, позволяющая моделировать разгон
double vRef
Референсная скорость
double nu
Коэффициент кинематической вязкости среды
double rho
Плотность потока
std::string fileSource
Имя файла с положениями источников (без полного пути)
double epscol
Радиус коллапса
std::string fileWake
Имя файла с начальным состоянием вихревого следа (без полного пути)
double sigma0
Радиус вихря
double maxGamma
Максимально допустимая циркуляция вихря
double timeStart
Начальное время
std::vector< std::string > reviseParameters
Список перечитываемых параметров
int saveVPstep
Шаг вычисления и сохранения скорости и давления
int revisePassportStep
Шаг перечитывания паспорта
double timeStop
Конечное время