57 v = (v | (v << 8)) & 0x00FF00FF;
63 v = (v | (v << 4)) & 0x0F0F0F0F;
69 v = (v | (v << 2)) & 0x33333333;
75 v = (v | (v << 1)) & 0x55555555;
89 const unsigned int& xx =
ExpandBits((
unsigned int)(rscale[0]));
90 const unsigned int& yy =
ExpandBits((
unsigned int)(rscale[1]));
91 return yy | (xx << 1);
101 unsigned char threads = omp_get_max_threads();
104#pragma omp parallel num_threads(threads)
108 unsigned int l = omp_get_thread_num();
109 unsigned int div = n / omp_get_num_threads();
110 unsigned int mod = n % omp_get_num_threads();
111 unsigned int left_index = l < mod ? (div + (mod == 0 ? 0 : 1)) * l : n - (omp_get_num_threads() - l) * div;
112 unsigned int right_index = left_index + div - (mod > l ? 0 : 1);
114 for (
unsigned int digit = 0; digit <
sizeof(m->
key); ++digit)
116 unsigned int s_sum[256] = { 0 };
117 unsigned int s0[256] = { 0 };
118 unsigned char* b1 = (
unsigned char*)&
source[right_index].key;
119 unsigned char* b2 = (
unsigned char*)&
source[left_index].key;
125 for (
unsigned int i = 0; i < 256; i++)
127 s[i + 256 * l] = s0[i];
131 for (
unsigned int j = 0; j < threads; j++)
133 for (
unsigned int i = 0; i < 256; i++)
135 s_sum[i] += s[i + 256 * j];
138 s0[i] += s[i + 256 * j];
143 for (
unsigned int i = 1; i < 256; ++i)
145 s_sum[i] += s_sum[i - 1];
146 s0[i] += s_sum[i - 1];
148 unsigned char* b = (
unsigned char*)&
source[right_index].key + digit;
153 dest[--s0[*b]] = *v1--;
162 if (
sizeof(m->
key) == 1)
169 inline size_t BinSearch(
const std::vector<std::pair<double, size_t>>& currentNN,
double x,
int low,
int high)
173 if (x > currentNN[high].first)
176 while (low <= high) {
177 mid = (low + high) / 2;
179 if (currentNN[mid].first == x)
182 if (currentNN[mid].first < x)
190 void newSort(std::vector<std::pair<double, size_t>>& mass, std::vector<std::pair<double, size_t>>& dstKeys) {
191 const size_t k = mass.size();
194 for (
size_t i = 0; i < k; ++i)
196 double elem = mass[i].first;
199 for (
size_t j = 0; j < k; ++j)
200 cnt += (mass[j].first < elem);
207 dstKeys[cnt] = mass[i];
214 std::vector<std::pair<double, size_t>>& currentNN,
const std::vector<std::pair<double, size_t>>& candidateNN,
215 std::vector<size_t>& loc,
216 std::vector<size_t>& counter,
217 std::vector<size_t>& offset,
218 std::vector<size_t>& counterScan,
219 std::vector<std::pair<double, size_t>>& updateNN
222 const size_t k = candidateNN.size() / 2;
224 for (
size_t j = 0; j < 2 * k; ++j)
225 loc[j] =
BinSearch(currentNN, candidateNN[j].first, 0, (
int)k - 1);
227 for (
size_t j = 0; j < 2 * k; ++j)
230 for (
size_t j = 0; j < 2 * k; ++j)
232 if ((loc[j] > 0) && ((loc[j] == k) || (candidateNN[j].second == currentNN[loc[j] - 1].second)))
235 offset[j] = counter[2 * loc[j]]++;
239 for (
size_t j = 1; j < 2 * k; ++j)
240 counterScan[j] = counterScan[j - 1] + counter[j - 1];
243 for (
size_t j = 0; j < k; ++j)
245 index = counterScan[2 * j + 1];
247 updateNN[index] = currentNN[j];
250 for (
size_t j = 0; j < 2 * k; ++j)
252 if (2 * loc[j] < 2 * k)
254 index = counterScan[2 * loc[j]] + offset[j];
256 updateNN[index] = candidateNN[j];
260 currentNN.swap(updateNN);
264 std::pair<bool, bool>
calcCheck(
const Vortex2D& vtxi,
const Vortex2D& vtxk,
double maxG,
double cSP,
double cRBP,
double epsCol,
int type,
double& d2)
266 bool flagExit =
false;
270 double mnog = std::max(1.0, (vtxi.
r()[0] - cRBP) / cSP);
271 double r2test = (epsCol * mnog) * (epsCol * mnog);
276 d2 = (vtxi.
r() - vtxk.
r()).length2();
281 return {
true,
false };
284 const double gi = vtxi.
g();
285 const double gk = vtxk.
g();
292 check = (fabs(gi * gk) != 0.0) && (fabs(gi + gk) < (mnog * mnog) * maxG);
295 check = (gi * gk < 0.0);
298 check = (gi * gk > 0.0) && (fabs(gi + gk) < (mnog * mnog) * maxG);
303 return {
false, check };
308void WakekNNnewForCollaps(
const std::vector<Vortex2D>& vtx,
const size_t k, std::vector<std::vector<std::pair<double, size_t>>>& initdist,
309 double cSP,
double cRBP,
double maxG,
double epsCol,
int type)
313 double preTime = -omp_get_wtime();
315 const size_t n = vtx.size();
318 auto xx = std::minmax_element(vtx.begin(), vtx.end(), [](
const Vortex2D& P1,
const Vortex2D& P2) {return P1.r()[0] < P2.r()[0]; });
319 auto yy = std::minmax_element(vtx.begin(), vtx.end(), [](
const Vortex2D& P1,
const Vortex2D& P2) {return P1.r()[1] < P2.r()[1]; });
321 double scale = std::max(xx.second->r()[0] - xx.first->r()[0], yy.second->r()[1] - yy.first->r()[1]);
324 std::vector<unsigned int> s(256 * omp_get_max_threads());
326 std::vector<TParticleCode> mcdata(vtx.size());
327 std::vector<TParticleCode> mcdata_temp(vtx.size());
332 const int nSdvig = 5;
333 double tStart[nSdvig], tFinish[nSdvig];
334 double tm[nSdvig][5];
336 preTime += omp_get_wtime();
338 std::pair<double, size_t> zeroPair = std::make_pair<double, size_t>(0.0, 0);
339 std::pair<double, size_t> minusOnePair = std::make_pair<double, size_t>(-1.0, 0);
341 std::vector<std::pair<double, size_t>> dist(2 * k, { -1.0, 0 });
342 std::vector<size_t> loc(2 * k);
343 std::vector<size_t> counter(2 * k, 0);
344 std::vector<size_t> offset(2 * k, 0);
345 std::vector<size_t> counterScan(2 * k, 0);
346 std::vector<std::pair<double, size_t>> dstKeys1(2 * k, zeroPair);
348 std::vector<std::pair<double, size_t>> updateNN(k, zeroPair);
349 std::vector<std::pair<double, size_t>> dstKeys(k, zeroPair);
352 for (
size_t sdvig = 0; sdvig < nSdvig ; ++sdvig)
354 tStart[sdvig] = omp_get_wtime();
356 const Point2D& lowLeft = { xx.first->r()[0], yy.first->r()[1] };
357 double* time = tm[sdvig];
361 time[0] = omp_get_wtime();
362#pragma omp parallel for
363 for (
int i = 0; i < vtx.size(); ++i)
365 Point2D sh = (vtx[i].r() - lowLeft) * (0.75 / scale) + sdvig *
Point2D{ 0.05, 0.05 };
366 mcdata[i].key = Morton2D(sh);
367 mcdata[i].originNumber = i;
370 time[1] = omp_get_wtime();
373 RSort_Parallel(mcdata.data(), mcdata_temp.data(), (
int)mcdata.size(), s.data());
375 time[2] = omp_get_wtime();
377 for (
size_t idx = 0; idx < 2 * k; ++idx)
379 dist[idx] = minusOnePair;
380 dstKeys1[idx] = zeroPair;
381 loc[idx] = counter[idx] = offset[idx] = counterScan[idx] = 0;
384 for (
size_t idx = 0; idx < k; ++idx)
385 updateNN[idx] = dstKeys[idx] = zeroPair;
387 time[3] = omp_get_wtime();
389#pragma omp parallel for firstprivate(dist, loc, counter, offset, counterScan, updateNN, dstKeys, dstKeys1)
390 for (
int i = 0; i < initdist.size(); ++i)
392 const Vortex2D& vtxi = vtx[mcdata[i].originNumber];
396 std::vector<std::pair<double, size_t>>& fillPosition = ((sdvig == 0) ? initdist[mcdata[i].originNumber] : dist);
398 while ((cntr < k) && (search >= 0))
400 const Vortex2D& vtxk = vtx[mcdata[search].originNumber];
401 bool flagExit, check;
403 std::tie(flagExit, check) = calcCheck(vtxi, vtxk, maxG, cSP, cRBP, epsCol, type, d2);
408 if ((mcdata[search].originNumber > mcdata[i].originNumber) && check)
409 fillPosition[cntr++] = { d2, mcdata[search].originNumber };
414 for (
int w = cntr; w < k; ++w)
415 fillPosition[cntr++] = { 100000000.0, 0 };
419 while ((cntr < 2 * k) && (search < mcdata.size()))
421 const Vortex2D& vtxk = vtx[mcdata[search].originNumber];
422 bool flagExit, check;
424 std::tie(flagExit, check) = calcCheck(vtxi, vtxk, maxG, cSP, cRBP, epsCol, type, d2);
429 if ((mcdata[search].originNumber > mcdata[i].originNumber) && check)
430 fillPosition[cntr++] = { d2, mcdata[search].originNumber };
434 for (
int w = cntr; w < 2 * k; ++w)
435 fillPosition[cntr++] = { 100000000.0, 0 };
439 newSort(initdist[mcdata[i].originNumber], dstKeys1);
440 initdist[mcdata[i].originNumber].resize(k);
444 newSort(dist, dstKeys1);
445 newMerge(mcdata[i].originNumber, initdist[mcdata[i].originNumber], dist, loc, counter, offset, counterScan, updateNN);
446 newSort(initdist[mcdata[i].originNumber], dstKeys);
450 time[4] = omp_get_wtime();
452 tFinish[sdvig] = omp_get_wtime();
468 auto xx = std::minmax_element(vtx.begin(), vtx.end(), [](const Vortex2D& P1, const Vortex2D& P2) {return P1.r()[0] < P2.r()[0]; });
469 auto yy = std::minmax_element(vtx.begin(), vtx.end(), [](const Vortex2D& P1, const Vortex2D& P2) {return P1.r()[1] < P2.r()[1]; });
471 double scale = std::max(xx.second->r()[0] - xx.first->r()[0], yy.second->r()[1] - yy.first->r()[1]);
473 //сортировка массива (data) по мортоновским кодам
474 std::vector<unsigned int> s(256 * omp_get_max_threads());
476 std::vector<TParticleCode> mcdata(vtx.size());
477 std::vector<TParticleCode> mcdata_temp(vtx.size());
479 //std::vector<unsigned int> iq;
482 const int nSdvig = 5;
483 double tStart[nSdvig], tFinish[nSdvig];
484 double tm[nSdvig][5];
486 preTime += omp_get_wtime();
488 std::pair<double, size_t> zeroPair = std::make_pair<double, size_t>(0.0, 0);
489 std::pair<double, size_t> minusOnePair = std::make_pair<double, size_t>(-1.0, 0);
491 std::vector<std::pair<double, size_t>> dist(2 * k, { -1.0, 0 });
492 std::vector<size_t> loc(2 * k);
493 std::vector<size_t> counter(2 * k, 0);
494 std::vector<size_t> offset(2 * k, 0);
495 std::vector<size_t> counterScan(2 * k, 0);
496 std::vector<std::pair<double, size_t>> dstKeys1(2 * k, zeroPair);
498 std::vector<std::pair<double, size_t>> updateNN(k, zeroPair);
499 std::vector<std::pair<double, size_t>> dstKeys(k, zeroPair);
502 for (size_t sdvig = 0; sdvig < nSdvig; ++sdvig)
504 tStart[sdvig] = omp_get_wtime();
506 const Point2D& lowLeft = { xx.first->r()[0], yy.first->r()[1] };
507 double* time = tm[sdvig];
509 //масштабирование координат вихрей в [0;0.75)^2, поиск их мортоновских кодов
511 time[0] = omp_get_wtime();
512#pragma omp parallel for
513 for (int i = 0; i < vtx.size(); ++i)
515 Point2D sh = (vtx[i].r() - lowLeft) * (0.75 / scale) + sdvig * Point2D{ 0.05, 0.05 };
516 mcdata[i].key = Morton2D(sh);
517 mcdata[i].originNumber = i;
520 time[1] = omp_get_wtime();
522 //сортировка единого массива (data и query) по мортоновским кодам
523 RSort_Parallel(mcdata.data(), mcdata_temp.data(), (int)mcdata.size(), s.data());
525 time[2] = omp_get_wtime();
527 for (size_t idx = 0; idx < 2 * k; ++idx)
529 dist[idx] = minusOnePair;
530 dstKeys1[idx] = zeroPair;
531 loc[idx] = counter[idx] = offset[idx] = counterScan[idx] = 0;
534 for (size_t idx = 0; idx < k; ++idx)
535 updateNN[idx] = dstKeys[idx] = zeroPair;
537 time[3] = omp_get_wtime();
539#pragma omp parallel for firstprivate(dist, loc, counter, offset, counterScan, updateNN, dstKeys, dstKeys1)
540 for (int i = 0; i < initdist.size(); ++i)
542 const Vortex2D& vtxi = vtx[mcdata[i].originNumber];
545 int search = i - 1; // iq[i];
546 std::vector<std::pair<double, size_t>>& fillPosition = ((sdvig == 0) ? initdist[mcdata[i].originNumber] : dist);
548 while ((cntr < k) && (search >= 0))
550 const Vortex2D& vtxk = vtx[mcdata[search].originNumber];
551 double d2 = (vtxi.r()-vtxk.r()).length2();
552 fillPosition[cntr++] = { d2, mcdata[search].originNumber };
556 for (int w = cntr; w < k; ++w)
557 fillPosition[cntr++] = { 100000000.0, 0 };
561 while ((cntr < 2 * k) && (search < mcdata.size()))
563 const Vortex2D& vtxk = vtx[mcdata[search].originNumber];
564 double d2 = (vtxi.r() - vtxk.r()).length2();
565 fillPosition[cntr++] = { d2, mcdata[search].originNumber };
568 for (int w = cntr; w < 2 * k; ++w)
569 fillPosition[cntr++] = { 100000000.0, 0 };
573 newSort(initdist[mcdata[i].originNumber], dstKeys1);
574 initdist[mcdata[i].originNumber].resize(k);
578 newSort(dist, dstKeys1);
579 newMerge(mcdata[i].originNumber, initdist[mcdata[i].originNumber], dist, loc, counter, offset, counterScan, updateNN);
580 newSort(initdist[mcdata[i].originNumber], dstKeys);
584 time[4] = omp_get_wtime();
586 tFinish[sdvig] = omp_get_wtime();
590 //for (size_t sd = 0; sd < nSdvig; ++sd)
591 // std::cout << "knn[" << sd << "] = " << tFinish[sd] - tStart[sd] << "sec. " << std::endl;
593} // WakekNNnewForEpsast
Описание констант и параметров для взаимодействия с графическим ускорителем
Класс, опеделяющий двумерный вихревой элемент
HD Point2D & r()
Функция для доступа к радиус-вектору вихря
HD double & g()
Функция для доступа к циркуляции вихря
void WakekNNnewForCollaps(const std::vector< Vortex2D > &vtx, const size_t k, std::vector< std::vector< std::pair< double, size_t > > > &initdist, double cSP, double cRBP, double maxG, double epsCol, int type)
unsigned int ExpandBits(unsigned int v)
void newMerge(int iii, std::vector< std::pair< double, size_t > > ¤tNN, const std::vector< std::pair< double, size_t > > &candidateNN, std::vector< size_t > &loc, std::vector< size_t > &counter, std::vector< size_t > &offset, std::vector< size_t > &counterScan, std::vector< std::pair< double, size_t > > &updateNN)
void RSort_Parallel(TParticleCode *m, TParticleCode *m_temp, unsigned int n, unsigned int *s)
Сортировка массива из мортоновский кодов
unsigned int Morton2D(const Point2D &r)
std::pair< bool, bool > calcCheck(const Vortex2D &vtxi, const Vortex2D &vtxk, double maxG, double cSP, double cRBP, double epsCol, int type, double &d2)
void newSort(std::vector< std::pair< double, size_t > > &mass, std::vector< std::pair< double, size_t > > &dstKeys)
const int twoPowCodeLengthVar
size_t BinSearch(const std::vector< std::pair< double, size_t > > ¤tNN, double x, int low, int high)
unsigned int key
Мортоновский код частицы