374 using int2 = std::pair<int, int>;
386 const int nnodes = 2 * (int)
object.size() - 1;
387 const int nbodies = (int)
object.size();
389 for (
int k = nbodies; k < nnodes; ++k)
407 const int kch = ((nnodes - 1) - k);
409 int2 chdPair =
child[srt];
415 for (i = 0; i < 2; i++)
417 int chd = i * chdPair.second + (1 - i) * chdPair.first;
418 ch = (chd >= nbodies) ? (chd - nbodies) : ((nnodes - 1) -
indexSortT[chd]);
419 if ((chd >= nbodies) || (
mass[nnodes - 1 - ch] >= 0))
425 for (i = 0; i < 2; i++)
427 const int chd = i * chdPair.second + (1 - i) * chdPair.first;
435 ::fmin(xyAB[0], xyAB[2]), ::fmin(xyAB[1], xyAB[3]),
436 ::fmax(xyAB[0], xyAB[2]), ::fmax(xyAB[1], xyAB[3])
448 const double4 loup = double4{
449 ::fmin(lu[0][0], lu[1][0]),
450 ::fmin(lu[0][1], lu[1][1]),
451 ::fmax(lu[0][2], lu[1][2]),
452 ::fmax(lu[0][3], lu[1][3]) };
458 0.5 * (loup[0] + loup[2]),
459 0.5 * (loup[1] + loup[3])
467 mass[nnodes - 1 - k] = m[0] + m[1];
481 int nObject = (int)
object.size();
486 auto minmaxX = std::minmax_element(
object.begin(),
object.end(), Point2D::cmp<
'x'>);
487 auto minmaxY = std::minmax_element(
object.begin(),
object.end(), Point2D::cmp<
'y'>);
488 minr =
Point2D({ (*minmaxX.first)[0], (*minmaxY.first)[1] });
489 maxr =
Point2D({ (*minmaxX.second)[0], (*minmaxY.second)[1] });
492 double lmax, quadSideFactor;
495 quadSideFactor =
rbound / lmax;
497#pragma omp parallel for
498 for (
int bdy = 0; bdy < nObject; ++bdy)
502 unsigned int xx =
ExpandBits((
unsigned int)rScaled[0]);
503 unsigned int yy =
ExpandBits((
unsigned int)rScaled[1]);
518#pragma omp parallel for
519 for (
int i = 0; i < nObject - 1; ++i)
523 int Deltap1 =
Delta(i, i + 1);
524 int Deltam1 =
Delta(i, i - 1);
526 int d = (Deltap1 - Deltam1 > 0) ? 1 : -1;
528 int delta_min = (d > 0) ? Deltam1 : Deltap1;
531 int pos = i + Lmax * d;
533 while (
Delta(i, pos) > delta_min)
540 for (
int t = (Lmax >> 1); t >= 1; t >>= 1)
542 pos = i + (L + t) * d;
544 if (
Delta(i, pos) > delta_min)
551 int delta_node =
Delta(i, j);
559 for (
int p = 1, t =
ceilhalf(L); L > (1 << (p - 1)); ++p, t =
ceilpow2(L, p))
561 pos = i + (s + t) * d;
563 int dl =
Delta(i, pos);
569 int gammaPos = i + s * d + d * (d < 0);
571 int Mmin = std::min(i, j);
572 int Mmax = std::max(i, j);
575 int right = gammaPos + 1;
578 int childLeft = (Mmin == gammaPos) * nObject + left;
579 range[childLeft] = { Mmin, gammaPos };
583 int childRight = (Mmax == gammaPos + 1) * nObject + right;
584 range[childRight] = { gammaPos + 1, Mmax };
587 child[i] = { childLeft, childRight };
593 for (
int i = 0; i < nObject - 1; ++i)
598 for (
int i = 0; i < nObject; ++i)
645 std::pair<double, double> rm_sq = std::make_pair<double, double>((lowerUpper[0] - rhs[0]) * (lowerUpper[0] - rhs[0]),
646 (lowerUpper[1] - rhs[1]) * (lowerUpper[1] - rhs[1]));
647 std::pair<double, double> rM_sq = std::make_pair<double, double>((lowerUpper[2] - rhs[0]) * (lowerUpper[2] - rhs[0]),
648 (lowerUpper[3] - rhs[1]) * (lowerUpper[3] - rhs[1]));
650 if ((lowerUpper[2] + lowerUpper[0]) * 0.5 < rhs[0])
651 std::swap(rm_sq.first, rM_sq.first);
653 if ((lowerUpper[3] + lowerUpper[1]) * 0.5 < rhs[1])
654 std::swap(rm_sq.second, rM_sq.second);
656 const double dx = rm_sq.first + rM_sq.second;
657 const double dy = rM_sq.first + rm_sq.second;
727 const int nbodies = (int)
object.size();
728 const int nnodes = 2 * nbodies - 1;
729 const int npoints = (int)cntrTree.
object.size();
732 const int maxDepth = 32;
737#pragma omp parallel for schedule(dynamic, 1)
745 bool isCntrLeaf = (k >= cntrTree.
object.size());
750 indexOfPoint = leafIndex;
751 query = cntrTree.
object[leafIndex];
754 fmin(pnlCntrGab[0], pnlCntrGab[2]), fmin(pnlCntrGab[1], pnlCntrGab[3]),
755 fmax(pnlCntrGab[0], pnlCntrGab[2]), fmax(pnlCntrGab[1], pnlCntrGab[3])
760 query = cntrTree.
center[k];
764 std::pair<int, double> stack[maxDepth];
768 std::pair<int, int> nearestLocation{ -1, 0 };
770 if ((findOnlyInside) && (md2 != 0))
772 indexPnlDist[indexK] = { -1, -1.0 };
777 stack[0] = { 0, md2 };
779 double dist_to_nearest_object = 1e+100;
783 std::pair<int, double> nd = stack[depth];
786 if (nd.second > dist_to_nearest_object)
789 std::pair<int, int> chBoth =
child[nd.first];
791 bool isLeftLeaf = (chBoth.first >=
object.size());
792 bool isRightLeaf = (chBoth.second >=
object.size());
794 double4 L_box, R_box;
795 double4 pnlLeftGab, pnlRightGab;
801 int n = chBoth.first - (int)
object.size();
804 fmin(pnlLeftGab[0], pnlLeftGab[2]), fmin(pnlLeftGab[1], pnlLeftGab[3]),
805 fmax(pnlLeftGab[0], pnlLeftGab[2]), fmax(pnlLeftGab[1], pnlLeftGab[3])
813 int n = chBoth.second - (int)
object.size();
816 fmin(pnlRightGab[0], pnlRightGab[2]), fmin(pnlRightGab[1], pnlRightGab[3]),
817 fmax(pnlRightGab[0], pnlRightGab[2]), fmax(pnlRightGab[1], pnlRightGab[3])
821 double L_mindist2 =
mindist2(L_box, query);
822 double R_mindist2 =
mindist2(R_box, query);
827 bool pushLeft =
false;
828 bool pushRight =
false;
834 int n = chBoth.first - (int)
object.size();
837 if (dist_code.first <= dist_to_nearest_object)
839 dist_to_nearest_object = dist_code.first;
851 int n = chBoth.second - (int)
object.size();
854 if (dist_code.first <= dist_to_nearest_object)
856 dist_to_nearest_object = dist_code.first;
864 if (pushLeft && !pushRight)
867 stack[depth] = { chBoth.first, L_mindist2 };
869 else if (!pushLeft && pushRight)
872 stack[depth] = { chBoth.second, R_mindist2 };
874 else if (pushLeft && pushRight)
876 if (L_mindist2 < R_mindist2)
880 stack[depth] = { chBoth.second, R_mindist2 };
883 stack[depth] = { chBoth.first, L_mindist2 };
889 stack[depth] = { chBoth.first, L_mindist2 };
892 stack[depth] = { chBoth.second, R_mindist2 };
900 indexPnlDist[cntrTree.
mortonCodesIdx[k - npoints]] = { nearestLocation.first, sqrt(dist_to_nearest_object) };
904 double radius = sqrt(dist_to_nearest_object) + 0.5 * sqrt(sqr(gabCntrl[2] - gabCntrl[0]) + sqr(gabCntrl[3] - gabCntrl[1]));
907 int stackCandidates[maxDepth];
909 stackCandidates[0] = 0;
911 std::vector<int> candidates;
912 candidates.reserve(100);
916 int nd = stackCandidates[depth];
919 std::pair<int, int> chBoth =
child[nd];
921 bool isLeftLeaf = (chBoth.first >=
object.size());
922 bool isRightLeaf = (chBoth.second >=
object.size());
928 int n = chBoth.first - (int)
object.size();
931 fmin(pnlLeftGab[0], pnlLeftGab[2]), fmin(pnlLeftGab[1], pnlLeftGab[3]),
932 fmax(pnlLeftGab[0], pnlLeftGab[2]), fmax(pnlLeftGab[1], pnlLeftGab[3])
941 int n = chBoth.second - (int)
object.size();
944 fmin(pnlRightGab[0], pnlRightGab[2]), fmin(pnlRightGab[1], pnlRightGab[3]),
945 fmax(pnlRightGab[0], pnlRightGab[2]), fmax(pnlRightGab[1], pnlRightGab[3])
955 if (dist2L < sqr(radius))
958 candidates.push_back(
mortonCodesIdx[chBoth.first -
object.size()]);
960 stackCandidates[++depth] = chBoth.first;
963 if (dist2R < sqr(radius))
966 candidates.push_back(
mortonCodesIdx[chBoth.second -
object.size()]);
968 stackCandidates[++depth] = chBoth.second;
973 for (
int particle = cntrTree.
range[k].first; particle <= cntrTree.
range[k].second; ++particle)
977 double currentMinDist2 = 1e+100;
978 int indexMinDist = -1;
979 for (
int i = 0; i < candidates.size(); ++i)
983 if (dst2 < currentMinDist2)
985 currentMinDist2 = dst2;
986 indexMinDist = candidates[i];
989 indexPnlDist[cntrTree.
mortonCodesIdx[particle]] = { indexMinDist, sqrt(currentMinDist2) };
1002 float t1 = (float)omp_get_wtime();
1006 using int2 = std::pair<int, int>;
1008 if (
object.size() > 0)
1012 double itolsq = 1.0 / (theta * theta);
1014 const int nbodies = (int)
object.size();
1015 const int nnodes = 2 * nbodies - 1;
1016 const int npoints = (int)cntrTree.
object.size();
1023 double d_1, d_2, d_3, dst23, dst12;
1028 double2 v{ 0.0,0.0 };
1039 const int maxDepth = 32;
1041 int posStack[maxDepth];
1042 int nodeStack[maxDepth];
1046#pragma omp for schedule(dynamic,1)
1050 std::vector<Point2D> vParticles;
1051 std::vector<numvector<double, 3>> epsastParticles;
1054 d_1 = d_2 = d_3 = 1e+5;
1055 std::vector<Point2D> Ek(order, { 0.0, 0.0 });
1057 bool isCntrLeaf = (k >= npoints);
1062 indexOfPoint = leafIndex;
1063 p = cntrTree.
object[leafIndex];
1064 sgm2Contr = sqr(
sigma[leafIndex]);
1070 sgm2Contr = sqr((gab[2] - gab[0] + gab[3] - gab[1]));
1071 vParticles.resize(cntrTree.
range[k].second - cntrTree.
range[k].first + 1, { 0.0, 0.0 });
1072 epsastParticles.resize(cntrTree.
range[k].second - cntrTree.
range[k].first + 1, { 1e+5, 1e+5, 1e+5 });
1077 nodeStack[0] = nnodes - 1;
1081 pd = posStack[depth];
1082 nd = nodeStack[depth];
1088 const int chd = (pd == 0) ? chBoth.first : chBoth.second;
1091 posStack[depth] = pd;
1093 isVortex = (chd >= nbodies);
1101 ps =
object[vortexIndex];
1102 gm =
gamma[vortexIndex];
1103 sgm2 = sqr(
sigma[vortexIndex]);
1109 n = (nnodes - 1) - srtT;
1114 sumSide2 = sqr((gab[2] - gab[0] + gab[3] - gab[1]));
1118 r2 = dr[0] * dr[0] + dr[1] * dr[1];
1119 if ((isVortex && isCntrLeaf) || ((sumSide2 + sgm2Contr) * itolsq < r2))
1129 if ((calcRadius) && (isCntrLeaf))
1131 if ((r2 < d_3) && (r2 > 0.0))
1133 dst23 = std::fmin(r2, d_2);
1134 d_3 = std::fmax(r2, d_2);
1136 dst12 = std::fmin(dst23, d_1);
1137 d_2 = std::fmax(dst23, d_1);
1142 const double f = gm / std::fmax(r2, sgm2);
1151 if ((order > 1) && r2 > 0.0)
1153 Point2D cftr = (1.0 / r2) * dr;
1159 for (
int s = 1; s < order; ++s)
1161 th = s * multz(th, cftr);
1162 Ek[s] += (s % 2 ? -1.0 : 1.0) * th * gm;
1167 for (
int s = 1; s < order; ++s)
1169 th = s * multz(th, cftr);
1178 for (
int q = 0; q <= s; ++q)
1182 Ek[q] += ((q % 2 ? -1.0 : 1.0) *
ifac[s - q + 1]) * multzA(th, mom[s - q]);
1186 Ek[0] +=
ifac[s + 1] * multzA(multz(th, cftr), mom[s]);
1195 if (depth + 1 < maxDepth)
1199 posStack[depth] = 1;
1200 nodeStack[depth] = nd;
1210 else if (!isCntrLeaf)
1212 for (
int pnt = cntrTree.
range[k].first; pnt <= cntrTree.
range[k].second; ++pnt)
1217 vParticles[pnt - cntrTree.
range[k].first] += (gm / std::fmax(dz2, sgm2)) * dz;
1221 double& m_3 = epsastParticles[pnt - cntrTree.
range[k].first][2];
1222 double& m_2 = epsastParticles[pnt - cntrTree.
range[k].first][1];
1223 double& m_1 = epsastParticles[pnt - cntrTree.
range[k].first][0];
1225 if ((dz2 < m_3) && (dz2 > 0.0))
1227 dst23 = std::fmin(dz2, m_2);
1228 m_3 = std::fmax(dz2, m_2);
1230 dst12 = std::fmin(dst23, m_1);
1231 m_2 = std::fmax(dst23, m_1);
1247 vel[indexOfPoint] =
IDPI * v.kcross();
1249 epsast[indexOfPoint] = 1.0 * sqrt((d_1 + d_2 + d_3) / 3.0);
1253 for (
int pnt = cntrTree.
range[k].first; pnt <= cntrTree.
range[k].second; ++pnt)
1257 v = Ek[0] + vParticles[pnt - cntrTree.
range[k].first];
1258 for (
int q = 1; q < order; ++q)
1260 v +=
ifac[q + 1] * multzA(Ek[q], dzPow);
1261 dzPow = multz(dzPow, dz);
1267 const auto& es = epsastParticles[pnt - cntrTree.
range[k].first];
1268 epsast[cntrTree.
mortonCodesIdx[pnt]] = 1.0 * sqrt((es[0] + es[1] + es[2]) / 3.0);
1276 float t2 = (float)omp_get_wtime();
1283 float t1 = (float)omp_get_wtime();
1287 using int2 = std::pair<int, int>;
1289 const int nbodies = (int)
object.size();
1290 const int npoints = (int)cntrTree.
object.size();
1292 rhs.assign(npoints, 0.0);
1293 bool scheme =
false;
1298 rhsLin.assign(npoints, 0.0);
1302 if (nbodies <= 0 || npoints <= 0)
1307 double itolsq = 1.0 / (theta * theta);
1308 const int nnodes = 2 * nbodies - 1;
1310 const int maxDepth = 32;
1312#pragma omp parallel for schedule(dynamic, 1)
1313 for (
int k = 0; k < npoints; ++k)
1316 const double2 p = cntrTree.
object[indexOfPoint];
1317 const double4& pnl = cntrTree.
gabForLeaves[indexOfPoint];
1318 const double2 beg{ pnl[0], pnl[1] };
1319 const double2 end{ pnl[2], pnl[3] };
1320 const double2 rPan = end - beg;
1321 const double dlen2 = rPan.length2();
1322 const double idlen = 1.0 / sqrt(dlen2);
1323 const double2 tau = idlen * rPan;
1325 double vallin = 0.0;
1326 int posStack[maxDepth];
1327 int nodeStack[maxDepth];
1328 std::array<double2, orderAlignment> Eloc;
1332 nodeStack[0] = nnodes - 1;
1335 int pd = posStack[depth];
1336 int nd = nodeStack[depth];
1341 const int chd = (pd == 0) ? chBoth.first : chBoth.second;
1343 posStack[depth] = pd;
1345 const bool isVortex = (chd >= nbodies);
1353 double sumSide2 = 0.0;
1362 ps =
object[vortexIndex];
1363 gm =
gamma[vortexIndex];
1370 n = (nnodes - 1) - srtT;
1374 const double sumSide = gab[2] - gab[0] + gab[3] - gab[1];
1375 sumSide2 = sumSide * sumSide;
1378 const double2 dr = p - ps;
1379 const double r2 = dr[0] * dr[0] + dr[1] * dr[1];
1382 if (isVortex || (sumSide2 + dlen2) * itolsq < r2)
1386 const double2 ss = ps - beg;
1387 const double2 pp = ps - end;
1389 const double alpha = atan2(pp[0] * ss[1] - pp[1] * ss[0], pp[0] * ss[0] + pp[1] * ss[1]);
1396 const double txx = tau[0] * tau[0];
1397 const double txy = tau[0] * tau[1];
1398 const double tyy = tau[1] * tau[1];
1402 u1[0] = (pp[0] + ss[0]) * (txx - tyy) + 2.0 * (pp[1] + ss[1]) * txy;
1404 u1[1] = (pp[1] + ss[1]) * (tyy - txx) + 2.0 * (pp[0] + ss[0]) * txy;
1406 const double lambda = 0.5 * log(ss.length2() / pp.length2());
1408 const double tempVelLin = gm * (alpha * (u1[0] * tau[0] + u1[1] * tau[1]) +
1409 lambda * (-u1[1] * tau[0] + u1[0] * tau[1]));
1411 vallin -= 0.5 * idlen * tempVelLin;
1418 std::fill(Eloc.begin(), Eloc.begin() + order, double2{ 0.0, 0.0 });
1420 double2 thetaLoc = (1.0 / r2) * (p - ps);
1423 for (
int q = 0; q < order; ++q)
1425 for (
int s = q; s >= 0; --s)
1427 const double sign = ((2 * q - s) & 1) ? -1.0 : 1.0;
1429 Eloc[s] += sign *
ifac[q - s + 1] * multzA(thetaLoc, mom[q - s]);
1432 thetaLoc = ((q + 1.0) / r2) * multz(thetaLoc, p - ps);
1436 double2 v = 0.5 * Eloc[0];
1438 double2 vL{ 0.0, 0.0 };
1443 double2 taudL = (0.5 / dlen2) * rPan;
1445 const double2 taudLc = taudL;
1447 for (
int kk = 1; kk < order; ++kk)
1449 mulP = multz(mulP, kp);
1454 v +=
ifac[kk + 2] * multz(Eloc[kk], multzA(taudL, mulP));
1456 vL +=
ifac[kk + 3] * multz(Eloc[kk], multzA(multz(taudL, taudLc), multz(mulP, (kk + 1.0) * rPan)));
1459 val += 2.0 * (-v[1] * rPan[0] + v[0] * rPan[1]);
1461 vallin += 2.0 * (-vL[1] * rPan[0] + vL[0] * rPan[1]);
1466 if (depth + 1 < maxDepth)
1470 posStack[depth] = 1;
1471 nodeStack[depth] = nd;
1486 const double cf =
IDPI * idlen;
1488 rhs[indexOfPoint] = cf * val;
1490 rhsLin[indexOfPoint] = cf * vallin;
1494 float t2 = (float)omp_get_wtime();