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);
128 auto CreateBoundary = [
this](
size_t i) {
146 info(
'e') <<
"Unknown scheme!" << std::endl;
194 if (
getPassport().wakeDiscretizationProperties.sigma0 == 0)
196 double sumLength = 0.0;
197 size_t totNumPan = 0;
204 double eps = 0.5 * sumLength / totNumPan;
209 if (
getPassport().wakeDiscretizationProperties.epscol == 0)
220 prm.chord = (prm.initialGab.second[0] - prm.initialGab.first[0]) * prm.scale[0];
221 info(
'i') <<
"airfoil #" << afl <<
" chord = " << prm.chord <<
" is calculated automatically" << std::endl;
296 std::unique_ptr<Passport> revisePspPtr;
308 size_t countStrongCoupling = 0;
309 for (
size_t m = 0; m <
mechanics.size(); ++m)
315 ++countStrongCoupling;
319 bool semiImplicitStrategy = ((countStrongCoupling ==
mechanics.size()) && (
mechanics.size() > 0));
321 info(
'i') <<
"Strong (semi-implicit) coupling strategy" << std::endl;
330 if (!semiImplicitStrategy)
336 if (
getPassport().numericalSchemes.velocityComputation.second == 0 &&
getPassport().numericalSchemes.linearSystemSolver.second == 2)
343 auto& treePnlVrt = *
getCuda().inflTreePnlVortex;
345 treePnlVrt.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
350 treePnlVrt.UpdatePanelGeometry(nTotPan, (double4*)afl.devRPtr);
354 treePnlVrt.UpdatePanelAttachedVortexIntensity(afl.devAttachedVortexSheetPtr, afl.devAttachedVortexSheetLinPtr);
355 treePnlVrt.UpwardTraversal(
getPassport().numericalSchemes.gmresMultipoleOrder);
360 if (
getPassport().numericalSchemes.velocityComputation.second == 1)
367 auto& treeWake = *
getCuda().inflTreeWake;
368 treeWake.MemoryAllocate((
int)
getCuda().n_CUDA_wake);
371 treeWake.UpwardTraversal(
getPassport().numericalSchemes.nbodyMultipoleOrder);
376 auto& treePnl = *
getCuda().cntrTreePnl;
377 auto& treePnlVrt = *
getCuda().inflTreePnlVortex;
378 auto& treePnlSrc = *
getCuda().inflTreePnlSource;
379 auto& treePnlAux = *
getCuda().auxTreePnl;
383 treePnl.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
384 treePnlAux.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
385 treePnlVrt.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
387 treePnlSrc.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
393 treePnlVrt.UpdatePanelGeometry(nTotPan, (double4*)afl.devRPtr);
397 treePnl.UpdatePanelGeometry((
int)nTotPan, (double4*)afl.devRPtr);
403 treePnlSrc.UpdatePanelGeometry(nTotPan, (double4*)afl.devRPtr);
404 treePnlSrc.UpdatePanelAttachedSourceIntensity(afl.devAttachedSourceSheetPtr, afl.devAttachedSourceSheetLinPtr);
406 treePnlSrc.UpwardTraversal(
getPassport().numericalSchemes.nbodyMultipoleOrder);
410 treePnlVrt.UpdatePanelAttachedVortexIntensity(afl.devAttachedVortexSheetPtr, afl.devAttachedVortexSheetLinPtr);
411 treePnlVrt.UpwardTraversal(
getPassport().numericalSchemes.nbodyMultipoleOrder);
433 std::vector<std::pair<Point2D, Point2D>> panels;
439 for (
size_t i = 0; i < afl.getNumberOfPanels(); ++i)
440 panels.push_back({ afl.getR(i), afl.getR(i + 1) });
442 if (panels.size() > 0)
444 cntrTreePnl->UpdatePanelGeometry(panels, std::max(4, (
int)(log2(panels.size())) - 2));
456 if (
getPassport().physicalProperties.typeAccel.second == 3)
473 info(
'i') <<
"Added Masses for airfoil #" << bou <<
" = { " << lambdaAdd[bou][0] <<
", " << lambdaAdd[bou][1] <<
", " << muAdd[bou] <<
" }" << std::endl;
476 switch ((
int)(
getPassport().physicalProperties.timeAccel))
489 info(
'e') <<
"Wrong dirfection is specified!" << std::endl;
494 std::ofstream addMassFile;
497 addMassFile.open(addMassFileName);
498 addMassFile <<
"Added Masses for airfoil:" << std::endl;
501 addMassFile.open(addMassFileName, std::ios_base::app);
503 addMassFile << direction <<
"-direction: " << lambdaAdd[bou][0] <<
" " << lambdaAdd[bou][1] <<
" " << muAdd[bou] << std::endl;
512 if (nTotPan > 0 &&
getPassport().numericalSchemes.velocityComputation.second == 1)
516 getCuda().inflTreePnlVortex->UpdatePanelFreeAndAttachedVortexIntensity(afl.devFreeVortexSheetPtr, afl.devFreeVortexSheetLinPtr, afl.devAttachedVortexSheetPtr, afl.devAttachedVortexSheetLinPtr);
517 getCuda().inflTreePnlVortex->UpwardTraversal(
getPassport().numericalSchemes.nbodyMultipoleOrder);
528 std::vector<double> nut;
529 CalcVeloDifference(nut);
532 for (
size_t q = 0; q <
getWake().
vtx.size(); ++q)
562 if (
measureVP->getTotalNumberOfRealPoints() > 0)
571 std::ofstream presForcesFile;
575 presForcesFile <<
"time,Fx,Fy,Py" << std::endl;
578 presForcesFile.open(
getPassport().
dir +
"presForcesFile.csv", std::ios_base::app);
580 auto r =
measureVP->GetVPinElasticPoints();
581 Point2D presForce = { 0.0, 0.0 };
584 for (
int q = 0; q < r.size(); ++q)
590 presForcesFile <<
currentTime <<
"," << scaleP * presForce[0] <<
"," << scaleP * presForce[1] <<
"," << scaleP * yPower << std::endl;
591 presForcesFile.close();
600 if (ptr && ptr->
beam->fsi)
602 auto r =
measureVP->GetVPinElasticPoints();
620 std::vector<double> currentPres(ptr->
chord.size());
621 for (
size_t j = 0; j < ptr->
chord.size(); ++j)
624 currentPres[j] = -(r[2 * j + 0].second - r[2 * j + 1].second);
627 if (ptr->
beam->presLastSteps.size() < ptr->
beam->nLastSteps)
628 ptr->
beam->presLastSteps.push_back(currentPres);
631 for (
int w = 1; w < ptr->
beam->nLastSteps; ++w)
632 ptr->
beam->presLastSteps[w - 1] = std::move(ptr->
beam->presLastSteps[w]);
633 ptr->
beam->presLastSteps.back() = currentPres;
636 for (
int q = 0; q < ptr->
beam->R; ++q)
638 ptr->
beam->qCoeff[q] = 0;
640 if (ptr->
beam->presLastSteps.size() == ptr->
beam->nLastSteps)
642 for (
size_t j = 0; j < ptr->
chord.size(); ++j)
644 double averpres = 0.0;
647 for (
int i = 0; i < ptr->
beam->nLastSteps; ++i)
648 averpres += ptr->
beam->presLastSteps[i][j];
649 averpres /= ptr->
beam->nLastSteps;
653 ptr->
beam->qCoeff[q] /= (ptr->
beam->intSqUnitShape * ptr->
beam->L);
659 std::ofstream phiFile;
664 for (
int p = 0; p < ptr->
beam->R; ++p)
665 phiFile <<
",phi-" << std::to_string(p + 1);
666 for (
int p = 0; p < ptr->
beam->R; ++p)
667 phiFile <<
",q-" << std::to_string(p + 1);
668 phiFile << std::endl;
671 phiFile.open(
getPassport().
dir +
"phiFile.csv", std::ios_base::app);
674 for (
int p = 0; p < ptr->
beam->R; ++p)
675 phiFile <<
"," << ptr->
beam->phi(p, 0);
676 for (
int p = 0; p < ptr->
beam->R; ++p)
677 phiFile <<
"," << ptr->
beam->qCoeff[p];
679 phiFile << std::endl;
691 mech->GetHydroDynamForce();
692 mech->GenerateForcesString();
693 mech->GeneratePositionString();
718 if (semiImplicitStrategy)
748 for (
size_t m = 0; m <
mechanics.size(); ++m)
757 getInfo(
'e') <<
"Added mass of the airfoil should be non-zero!" << std::endl;
794 << std::setprecision(3) \
796 << std::setprecision(6) \
813void World2D::CheckInside(std::vector<Point2D>& newPos,
const std::vector<std::unique_ptr<AirfoilGeometry>>& oldAirfoil)
822#if (!defined(USE_CUDA))
824 for (
size_t afl = 0; afl <
airfoil.size(); ++afl)
897 for (
size_t afl = 0; afl <
airfoil.size(); ++afl)
898 nTotPanels += (
int)
airfoil[afl]->getNumberOfPanels();
906 auxTree.MemoryAllocate((
int)
getCuda().n_CUDA_pnls);
907 auxTree.UpdatePanelGeometry(nTotPanels, (double4*)
airfoil[0]->devRPtr);
909 auxTree.UpwardTraversal(0);
912 std::vector<int> hit(newPos.size());
916 double* devNewpos_ptr;
917 cudaMalloc(&devNewpos_ptr, newPos.size() *
sizeof(
double) * 2);
918 cudaMemcpy(devNewpos_ptr, newPos.data(), newPos.size() *
sizeof(
double) * 2, cudaMemcpyHostToDevice);
920 auto& cntrTreePnt = *
getCuda().cntrTreePoint;
921 cntrTreePnt.MemoryAllocate((
int)
getCuda().n_CUDA_wake);
922 cntrTreePnt.Update((
int)newPos.size(), devNewpos_ptr);
925 BHcu::treeClosestPanelToPointsCalculationWrapper(auxTree, cntrTreePnt,
getWake().devNearestPanelPtr,
true,
getAirfoil(0).devPsnPtr);
927 cudaMemcpy(hit.data(),
getWake().devNearestPanelPtr, newPos.size() *
sizeof(
int), cudaMemcpyDeviceToHost);
928 cudaFree(devNewpos_ptr);
946 std::vector<std::pair<Point2D, Point2D>> segments(newPos.size());
947 for (
size_t i = 0; i < newPos.size(); ++i)
949 segments[i].first =
wake->vtx[i].r();
950 segments[i].second = newPos[i];
952 double* devSegments_ptr;
954 cudaMalloc(&devSegments_ptr, newPos.size() *
sizeof(
double) * 4);
955 cudaMemcpy(devSegments_ptr, segments.data(), newPos.size() *
sizeof(
double) * 4, cudaMemcpyHostToDevice);
957 auto& cntrTreeSeg = *
getCuda().cntrTreeSegment;
958 cntrTreeSeg.MemoryAllocate((
int)
getCuda().n_CUDA_wake);
959 cntrTreeSeg.UpdatePanelGeometry((
int)newPos.size(), (double4*)devSegments_ptr);
962 BHcu::treePanelsSegmentsIntersectionCalculationWrapper(auxTree, cntrTreeSeg,
getWake().devNearestPanelPtr);
963 cudaMemcpy(hit.data(),
getWake().devNearestPanelPtr, newPos.size() *
sizeof(
int), cudaMemcpyDeviceToHost);
964 cudaFree(devSegments_ptr);
967 size_t panCounter = 0;
968 for (
size_t afl = 0; afl <
airfoil.size(); ++afl)
970 std::vector<double> gamma(
airfoil[afl]->getNumberOfPanels(), 0.0);
971 for (
int i = 0; i < newPos.size(); ++i)
975 if ((hit[i] >= panCounter) && (hit[i] < panCounter +
airfoil[afl]->getNumberOfPanels()))
977 if (fabs(
wake->vtx[i].g()) > 1.0)
978 std::cout <<
"Too large gamma is through: i = " << i <<
", " << hit[i] <<
", " <<
"gamma[hit[i] - panCounter] += " <<
wake->vtx[i].g() << std::endl;
980 gamma[hit[i] - panCounter] +=
wake->vtx[i].g();
981 wake->vtx[i].g() = 0.0;
985 airfoil[afl]->gammaThrough = gamma;
986 panCounter +=
airfoil[afl]->getNumberOfPanels();
1062 if (linSystemScheme == 0)
1064 double t1 = -omp_get_wtime();
1067 info(
't') <<
"Inverting matrix... ";
1069#if (defined(USE_CUDA))
1071 for (
int i = 0; i < (int)
matrReord.rows(); ++i)
1072 for (
int j = 0; j < (int)
matrReord.cols(); ++j)
1073 invMatr(i, j) = (i == j) ? 1.0 : 0.0;
1078 info(
't') <<
"done" << std::endl;
1082 info(
't') <<
"Solving system at step #0... ";
1111 info(
't') <<
"done" << std::endl;
1113 t1 += omp_get_wtime();
1182 if ((linSystemScheme == 1 || linSystemScheme == 2))
1186 nFullVars += (
int)(
boundary[i]->GetUnknownsSize());
1190 Ggam[i].resize(
boundary[i]->GetUnknownsSize());
1195 std::vector<double> Grhs(
rhsReord.size());
1196 for (
int i = 0; i <
rhsReord.size(); ++i)
1201 Gpos[i] = Gpos[i - 1] + (
int)(
boundary[i - 1]->GetUnknownsSize());
1205 Gvsize[i] = (
int)(
boundary[i]->GetUnknownsSize());
1210 std::vector<double> Gmatr(nFullVars * nFullVars);
1211 for (
size_t i = 0; i < nFullVars; ++i)
1212 for (
size_t j = 0; j < nFullVars; ++j)
1213 Gmatr[i * nFullVars + j] =
matrReord(i, j);
1216 for (
int j = 0; j <
boundary[i]->GetUnknownsSize(); ++j)
1217 auto y_test =
airfoil[i]->len[j %
airfoil[i]->getNumberOfPanels()];
1220 std::cout <<
"GMRES_Direct should be modified!" << std::endl;
1224 sol.resize(nFullVars);
1227 for (
int j = 0; j <
boundary[i]->GetUnknownsSize(); ++j)
1228 sol(cntr++) = Ggam[i][j] ;
1230 sol(cntr++) = GR[i];
1240 getInfo(
'e') <<
"Fast GMRES without CUDA is not implemented" << std::endl;
1246 getInfo(
'e') <<
"Direct GMRES for CUDA is not implemented" << std::endl;
1256 GGrhs[i].resize(
boundary[i]->GetUnknownsSize());
1258 for (
int j = 0; j <
boundary[i]->GetUnknownsSize(); ++j)
1269 double time_GMRES = -omp_get_wtime();
1271 time_GMRES += omp_get_wtime();
1274 sol.resize(nFullVars);
1277 for (
int j = 0; j <
boundary[i]->GetUnknownsSize(); ++j)
1278 sol(cntr++) = Ggam[i][j] /
airfoil[i]->len[j %
airfoil[i]->getNumberOfPanels()];
1280 sol(cntr++) = GR[i];
1304 if (linSystemScheme == 0 || linSystemScheme == 1)
1309 Eigen::MatrixXd locMatr;
1310 Eigen::MatrixXd otherMatr;
1311 Eigen::VectorXd locLastLine, locLastCol;
1313 std::vector<std::vector<Point2D>> locIQ;
1314 std::vector<std::vector<Point2D>> locOtherIQ;
1319 for (
int i = 0; i <
matrReord.rows(); ++i)
1320 for (
int j = 0; j <
matrReord.cols(); ++j)
1324 size_t currentRow = 0;
1325 size_t currentSkosRow = 0;
1327 size_t nAllVars = 0;
1328 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
1329 nAllVars +=
boundary[bou]->GetUnknownsSize();
1331 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
1333 size_t nVars =
boundary[bou]->GetUnknownsSize();
1336 locMatr.resize(nVars, nVars);
1337 locLastLine.resize(nVars);
1338 locLastCol.resize(nVars);
1342 boundary[bou]->FillMatrixSelf(locMatr, locLastLine, locLastCol);
1346 for (
size_t i = 0; i < nVars; ++i)
1350 for (
size_t j = 0; j < nVars; ++j)
1351 matrReord(i + currentSkosRow, j + currentSkosRow) = locMatr(i, j);
1353 matrReord(nAllVars + bou, i + currentSkosRow) = locLastLine(i);
1354 matrReord(i + currentSkosRow, nAllVars + bou) = locLastCol(i);
1360 size_t currentCol = 0;
1361 size_t currentSkosCol = 0;
1362 for (
size_t oth = 0; oth <
boundary.size(); ++oth)
1364 size_t nVarsOther =
boundary[oth]->GetUnknownsSize();
1368 otherMatr.resize(nVars, nVarsOther);
1373 for (
size_t i = 0; i < nVars; ++i)
1375 for (
size_t j = 0; j < nVarsOther; ++j)
1376 matrReord(i + currentSkosRow, j + currentSkosCol) = otherMatr(i, j);
1379 currentCol += nVarsOther + 1;
1380 currentSkosCol += nVarsOther;
1384 currentRow += nVars + 1;
1385 currentSkosRow += nVars;
1405 for (
size_t i = 1; i <
boundary.size(); ++i)
1411 size_t matrSkosSize = 0;
1415 matrSize += (*it)->GetUnknownsSize();
1416 matrSkosSize += (*it)->GetUnknownsSize();
1432 size_t nVari =
boundary[i]->GetUnknownsSize();
1435 size_t nVarj =
boundary[j]->GetUnknownsSize();
1436 IQ[i][j].first.resize(nVari, nVarj);
1437 IQ[i][j].second.resize(nVari, nVarj);
1464#if defined(__CUDACC__) || defined(USE_CUDA)
1465 cuda.RefreshWake(2);
1467 cuda.RefreshAfls(2);
1468 cuda.RefreshVirtualWakes(2);
1481#if defined(__CUDACC__) || defined(USE_CUDA)
1482 for (
size_t i = 0; i <
airfoil.size(); ++i)
1483 cuda.CopyMemToDev<
double, 1>(
airfoil[i]->getNumberOfPanels(),
airfoil[i]->meanEpsOverPanel.data(),
airfoil[i]->devMeanEpsOverPanelPtr);
1494 if (afl->viscousStress.size() == 0)
1495 afl->viscousStress.resize(afl->getNumberOfPanels(), 0.0);
1579void World2D::CalcVeloDifference(std::vector<double>& nut)
const
1581 nut.resize(
getWake().vtx.size());
1587 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 } };
1597 controlPoints.vtx.resize(
getWake().vtx.size() * basePoints.size());
1599 for (
size_t q = 0; q <
getWake().
vtx.size(); ++q)
1600 for (
size_t i = 0; i < basePoints.size(); ++i)
1601 controlPoints.vtx[q * basePoints.size() + i].r() =
getWake().
vtx[q].r() + basePoints[i] *
getWake().
vtx[q].sigma();
1604 cuReserveDevMem((
void*&)controlPoints.devVtxPtr, controlPoints.vtx.size() *
sizeof(
Vortex2D), 333);
1605 cuCopyWakeToDev(controlPoints.vtx.size(), controlPoints.vtx.data(), controlPoints.devVtxPtr, 444);
1606 cuReserveDevMem((
void*&)controlPoints.devVelPtr, controlPoints.vtx.size() * 2 *
sizeof(
double), 555);
1609 treeNut->MemoryAllocate((
int)
getCuda().n_CUDA_wake * (
int)basePoints.size());
1610 treeNut->Update((
int)controlPoints.vtx.size(), controlPoints.devVtxPtr);
1613 std::vector<Point2D> veloVar(
getWake().vtx.size() * basePoints.size(),
Point2D{0.0, 0.0});
1614 std::vector<double> epsVar;
1615 velocity->GPUCalcConvVeloToSetOfPointsFromWake(treeNut, controlPoints, veloVar, epsVar,
true,
false);
1617 velocity->GPUCalcConvVelocityToSetOfPointsFromSheets(treeNut, controlPoints, veloVar);
1619 cuDeleteFromDev((
void*&)controlPoints.devVtxPtr, 777);
1620 cuDeleteFromDev((
void*&)controlPoints.devVelPtr, 888);
1622 for (
size_t q = 0; q <
getWake().
vtx.size(); ++q)
1625 for (
size_t i = 1; i < basePoints.size(); ++i)
1626 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);
1628 dv2 *= 1.0 / (basePoints.size() - 1);
1629 nut[q] = 0.105 * 0.604 *
wake->vtx[q].sigma() * sqrt(dv2);
1640 for (
size_t i = 0; i <
airfoil.size(); ++i)
1644 for (
size_t i = 0; i <
airfoil.size(); ++i)
1645 boundary[i]->ComputeAttachedSheetsIntensity();
1659 size_t nvt =
wake->vtx.size();
1660 size_t nVirtVortex = 0;
1662 nVirtVortex +=
boundary[i]->virtualWake.vtx.size();
1667 size_t counter =
wake->vtx.size() - nVirtVortex;
1668 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
1670 for (
int i = 0; i < (int)
boundary[bou]->virtualWake.vtx.size(); ++i)
1672 wake->vtx[counter].g() =
boundary[bou]->virtualWake.vtx[i].g();
1684 const double c = 4.5;
1686 const auto& eps =
velocity->wakeVortexesParams.epsastWake;
1688 double minEpsast = *std::min_element(eps.begin(), eps.end());
1689 double meanEpsast = std::accumulate(eps.begin(), eps.end(), 0.0) / eps.size();
1691 double uniformH = minEpsast + 0.2 * (meanEpsast - minEpsast);
1693 std::vector<std::vector<int>> neib(
wake->vtx.size());
1694 for (
auto& nb : neib)
1697#pragma omp parallel for schedule(dynamic, 100)
1698 for (
int i = 0; i < (int)
wake->vtx.size(); ++i)
1700 const double hati = c * eps[i];
1701 const double hati2 = sqr(hati);
1702 const int dist = std::ceil(hati / uniformH);
1705 int cx = (int)(vtx[0] / uniformH);
1706 int cy = (int)(vtx[1] / uniformH);
1708 for (
int j = 0; j < (int)
wake->vtx.size(); ++j)
1711 int tx = (int)(test[0] / uniformH);
1712 int ty = (int)(test[1] / uniformH);
1714 if (abs(cx - tx) <= dist && abs(cy - ty) <= dist)
1715 if ((vtx - test).length2() < hati2)
1716 neib[i].push_back(j);
1726 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))); };
1727 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))); };
1772 std::vector<double> OIP(
wake->vtx.size(), 0.0);
1773 std::vector<double> VIP(
wake->vtx.size(), 0.0);
1774 std::vector<Point2D> GIP(
wake->vtx.size(), { 0.0, 0.0 });
1775 std::vector<Point2D> DIFFV(
wake->vtx.size(), { 0.0, 0.0 });
1778 const auto& vtx =
wake->vtx;
1779 const auto& vel =
velocity->wakeVortexesParams.convVelo;
1793 std::vector<nummatrix<double, 2, 2>> mtrL(
wake->vtx.size(), { {0.0, 0.0}, {0.0, 0.0} });
1794 std::vector<std::vector<double>> weight(
wake->vtx.size());
1797 std::vector<Point2D> sumDIFFV(
wake->vtx.size(), {0.0, 0.0});
1798 std::vector<double> sumWeight(
wake->vtx.size(), 0.0);
1800#pragma omp parallel for schedule(dynamic, 100)
1801 for (
int i = 0; i < (int)vtx.size(); ++i)
1803 const double hati = c * eps[i];
1805 double resultOIP = 0.0;
1808 const Point2D myPos = vtx[i].r();
1810 double I1 = 0.0, I0 = 1.0;
1813 weight[i].reserve(neib[i].size());
1815 for (
auto& nbr : neib[i])
1817 double dist2 = (myPos - vtx[nbr].r()).length2();
1818 double dist = sqrt(dist2);
1819 double w = W(dist, hati);
1820 I1 += vtx[nbr].g() * w;
1821 weight[i].push_back(w);
1827#pragma omp parallel for schedule(dynamic, 100)
1828 for (
int i = 0; i < (int)vtx.size(); ++i)
1830 const Point2D myPos = vtx[i].r();
1831 const double hati = c * eps[i];
1836 for (
auto& nbr : neib[i])
1838 Point2D dr = myPos - vtx[nbr].r();
1839 Point2D grweight = WW(dr, hati);
1840 double vol = (vtx[nbr].g() / OIP[nbr]);
1844 M += (dr | grweight) * vol;
1845 GIP[i] -= grweight * ((OIP[nbr] - OIP[i]) * vol);
1848 double detM = M[0][0] * M[1][1] - M[1][0] * M[0][1];
1850 if (fabs(detM) > 1e-2)
1853 GIP[i] = (L & GIP[i]);
1854 DIFFV[i] = GIP[i] * (1.0 / OIP[i]);
1861 for (
int i = 0; i < (int)vtx.size(); ++i)
1862 for (
int j = 0; j < neib[i].size(); ++j)
1863 if ((vtx[i].r() - vtx[neib[i][j]].r()).length() <= 1.0 * eps[i])
1865 sumDIFFV[i] += weight[i][j] * DIFFV[neib[i][j]];
1866 sumWeight[i] += weight[i][j];
1870 for (
int i = 0; i < (int)vtx.size(); ++i)
1872 DIFFV[i] = sumDIFFV[i] * (1.0 / sumWeight[i]);
2005 for (
int i = 0; i < (int)
wake->vtx.size(); ++i)
2009 Point2D W = -passport.physicalProperties.nu * DIFFV[i];
2011 checkVel << i <<
" " <<
wake->vtx[i].r()[0] <<
" " <<
wake->vtx[i].r()[1] <<
" " << velocity->wakeVortexesParams.epsastWake[i] <<
" " \
2012 << velocity->wakeVortexesParams.convVelo[i][0] <<
" " << velocity->wakeVortexesParams.convVelo[i][1] <<
" " \
2013 << W[0] <<
" " << W[1];
2015 if (W.length() > 1.5 * passport.physicalProperties.vRef)
2017 std::cout <<
"i = " << i <<
", W was " << W << std::endl;
2022 checkVel <<
" " << W[0] <<
" " << W[1] <<
" " << OIP[i] <<
" " << GIP[i][0] <<
" " << GIP[i][1] <<
"\n";
2025 Point2D W = velocity->wakeVortexesParams.diffVelo[i] * (nutPtr ? (1.0 + (*nutPtr)[i] / passport.physicalProperties.nu) : 1.0);
2027 const auto& diff = velocity->wakeVortexesParams;
2028 Point2D grad = diff.I2[i] * (1.0 / (diff.epsastWake[i] * diff.I0[i])) - diff.I3[i] * (diff.I1[i] /
sqr(diff.I0[i]));
2035 newPos[i] =
wake->vtx[i].r() + (velocity->wakeVortexesParams.convVelo[i] + W + getV0()) * passport.timeDiscretizationProperties.dt;
2061 mechanics[mechanicsNumber]->GenerateForcesHeader();
2062 mechanics[mechanicsNumber]->GeneratePositionHeader();
2070 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
2077 for (
size_t oth = 0; oth <
boundary.size(); ++oth)
2114#if defined(__CUDACC__) || defined(USE_CUDA)
2120 if ((sch == 1) || (sch == 2) || (sch == 0))
2124 info(
'e') <<
"schemeSwitcher is not 0, or 1, or 2! " << std::endl;
2128 cuda.RefreshWake(1);
2129 cuda.RefreshAfls(1);
2130 cuda.RefreshVirtualWakes(1);
2135 if (linSystemScheme == 0)
2202 size_t currentRow = 0;
2203 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
2205 size_t nVars =
boundary[bou]->GetUnknownsSize();
2206 Eigen::VectorXd locSol;
2207 locSol.resize(nVars);
2208 for (
size_t i = 0; i < nVars; ++i)
2209 locSol(i) =
sol(currentRow + i);
2211 boundary[bou]->SolutionToFreeVortexSheetAndVirtualVortex(locSol);
2212 currentRow += nVars;
2216 size_t nVirtVortices = 0;
2217 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
2218 nVirtVortices +=
boundary[bou]->virtualWake.vtx.size();
2220 wake->vtx.reserve(
wake->vtx.size() + nVirtVortices);
2221 for (
size_t bou = 0; bou <
boundary.size(); ++bou)
2222 for (
size_t v = 0; v <
boundary[bou]->virtualWake.vtx.size(); ++v)
2223 wake->vtx.push_back(
Vortex2D{ boundary[bou]->virtualWake.vtx[v].r(), 0.0, getPassport().wakeDiscretizationProperties.sigma0});
2257 std::vector<Point2D> newPos;
2285 if (afl->numberInPassport == 0)
2287 mechanics[afl->numberInPassport]->Move();
2292 if (mechTest !=
nullptr)
2313 airfoil[afl->numberInPassport]->Move(dr);
2314 airfoil[afl->numberInPassport]->Rotate(dphi);
2328 mechanics[afl->numberInPassport]->Move();
2340#if defined(__CUDACC__) || defined(USE_CUDA)
2341 cuda.RefreshAfls(2);
2345 bou->virtualWake.vtx.clear();
2352 for (
size_t i = 0; i <
wake->vtx.size(); ++i)
2354 wake->vtx[i].r() = newPos[i];
2366 [](
const std::unique_ptr<Mechanics>& m) {
return (m->isMoves); });
2373 [](
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
Слои на профиле
Класс, определяющий способ удовлетворения граничного условия на обтекаемом профиле
Класс, определяющий способ удовлетворения граничного условия на обтекаемом профиле
Структура, хранящая данные и указатели на массивы на CPU для оптимизации итерационного решения СЛАУ н...
Класс, обеспечивающий возможность выполнения вычислений на 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
Сброс счетчика времени
bool fileExistTest(const std::string &fileName_, LogStream &info, bool exitKey=false, const std::list< std::string > &extList={})
Проверка существования файла
void PrintLogoToStream(std::ostream &str)
Передача в поток вывода шапки программы VM2D/VM3D.
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
Конечное время