11#include <tbb/parallel_sort.h>
12#include <tbb/task_arena.h>
16namespace MDAlgorithms {
29template <
size_t ND,
template <
size_t>
class MDEventType,
typename EventIterator>
class MDEventTreeBuilder {
31 using IntT =
typename MDEvent::IntT;
32 using MortonT =
typename MDEvent::MortonT;
49 const EventIterator
end;
73 void sortEvents(std::vector<MDEventType<ND>> &mdEvents);
77 std::unique_ptr<Task>
popTask();
88 std::vector<Mantid::Geometry::MDDimensionExtents<coord_t>>
m_extents;
95template <
size_t ND,
template <
size_t>
class MDEventType,
typename EventIterator>
99 : m_numWorkers(numWorkers), m_eventsThreshold(threshold), m_masterFinished{false}, m_space{space}, m_bc{bc},
102 for (
size_t ax = 0; ax < ND; ++ax) {
104 m_extents.back().setExtents(space(ax, 0), space(ax, 1));
108template <
size_t ND,
template <
size_t>
class MDEventType,
typename EventIterator>
111 auto err = convertToIndex(mdEvents, m_space);
112 sortEvents(mdEvents);
113 auto root = doDistributeEvents(mdEvents);
117template <
size_t ND,
template <
size_t>
class MDEventType,
typename EventIterator>
120 if (mdEvents.size() <= m_bc->getSplitThreshold()) {
121 m_bc->incBoxesCounter(0);
125 Task tsk{root, mdEvents.
begin(), mdEvents.end(), m_mortonMin, m_mortonMax, m_bc->getMaxDepth() + 1, 1};
127 if (m_numWorkers == 1)
128 distributeEvents(tsk, SLAVE);
130 std::vector<std::thread> workers;
131 workers.emplace_back([
this, &tsk]() {
132 distributeEvents(tsk, MASTER);
133 m_masterFinished =
true;
134 waitAndLaunchSlave();
136 for (
auto i = 1; i < m_numWorkers; ++i)
138 for (
auto &worker : workers)
145template <
size_t ND,
template <
size_t>
class MDEventType,
typename EventIterator>
150#pragma omp parallel for num_threads(m_numWorkers)
151 for (int64_t i = 0; i < static_cast<int64_t>(mdEvents.size()); ++i) {
153 IndexCoordinateSwitcher::convertToIndex(mdEvents[i], space);
155 morton_index::indexToCoordinates<ND, IntT, MortonT>(IndexCoordinateSwitcher::getIndex(mdEvents[i]), space);
156 newCoord -= oldCoord;
158 for (
size_t d = 0;
d < ND; ++
d)
159 threadErr[
d] = std::max(threadErr[
d], std::abs(newCoord[
d]));
162 for (
const auto &err : perThread)
163 for (
size_t d = 0;
d < ND; ++
d)
164 maxErr[
d] = std::max(maxErr[
d], err[
d]);
168template <
size_t ND,
template <
size_t>
class MDEventType,
typename EventIterator>
171 tbb::task_arena limited_arena(m_numWorkers);
172 limited_arena.execute([&]() {
173 tbb::parallel_sort(mdEvents.begin(), mdEvents.end(), [](
const MDEventType<ND> &a,
const MDEventType<ND> &b) {
174 return IndexCoordinateSwitcher::getIndex(a) < IndexCoordinateSwitcher::getIndex(b);
179template <
size_t ND,
template <
size_t>
class MDEventType,
typename EventIterator>
182 std::lock_guard<std::mutex> g(m_mutex);
183 m_tasks.emplace(tsk);
186template <
size_t ND,
template <
size_t>
class MDEventType,
typename EventIterator>
187std::unique_ptr<typename MDEventTreeBuilder<ND, MDEventType, EventIterator>::Task>
189 std::lock_guard<std::mutex> g(m_mutex);
193 auto task = std::make_unique<Task>(m_tasks.front());
199template <
size_t ND,
template <
size_t>
class MDEventType,
typename EventIterator>
202 auto pTsk = popTask();
204 distributeEvents(*pTsk.get(), SLAVE);
205 else if (m_masterFinished)
208 std::this_thread::sleep_for(std::chrono::nanoseconds(100));
216template <
size_t ND,
template <
size_t>
class MDEventType,
typename EventIterator>
218 const size_t childBoxCount = m_bc->getNumSplit();
219 const size_t splitThreshold = m_bc->getSplitThreshold();
221 if (tsk.
maxDepth-- == 1 || std::distance(tsk.
begin, tsk.
end) <=
static_cast<int>(splitThreshold)) {
229 const MortonT childBoxWidth = thisBoxWidth / childBoxCount;
231 auto eventIt = tsk.
begin;
233 struct RecursionHelper {
234 std::pair<EventIterator, EventIterator> eventRange;
235 std::pair<MortonT, MortonT> mortonBounds;
238 std::vector<RecursionHelper> children;
239 children.reserve(childBoxCount);
242 for (
size_t i = 0; i < childBoxCount; ++i) {
246 const auto boxLower = tsk.
lowerBound + ((childBoxWidth + 1) * i);
249 const auto boxUpper = childBoxWidth + boxLower;
251 const auto boxEventStart = eventIt;
253 if (eventIt < tsk.
end) {
254 if (morton_index::morton_contains<MortonT>(boxLower, boxUpper, IndexCoordinateSwitcher::getIndex(*eventIt)))
255 eventIt = std::upper_bound(
256 boxEventStart, tsk.
end, boxUpper,
257 [](
const MortonT &
m,
const typename std::iterator_traits<EventIterator>::value_type &event) {
258 return m < IndexCoordinateSwitcher::getIndex(event);
265 std::vector<Mantid::Geometry::MDDimensionExtents<coord_t>> extents(ND);
266 auto minCoord = morton_index::indexToCoordinates<ND, IntT, MortonT>(boxLower, m_space);
267 auto maxCoord = morton_index::indexToCoordinates<ND, IntT, MortonT>(boxUpper, m_space);
268 for (
unsigned ax = 0; ax < ND; ++ax) {
269 extents[ax].setExtents(minCoord[ax], maxCoord[ax]);
273 if (std::distance(boxEventStart, eventIt) <=
static_cast<int64_t
>(splitThreshold) || tsk.
maxDepth == 1) {
274 for (
auto it = boxEventStart; it < eventIt; ++it)
275 IndexCoordinateSwitcher::convertToCoordinates(*it, m_space);
276 m_bc->incBoxesCounter(tsk.
level);
277 newBox =
new Box(m_bc.get(), tsk.
level, extents, boxEventStart, eventIt);
279 m_bc->incGridBoxesCounter(tsk.
level);
283 children.emplace_back(RecursionHelper{{boxEventStart, eventIt}, {boxLower, boxUpper}, newBox});
287 std::sort(children.begin(), children.end(), [](RecursionHelper &a, RecursionHelper &b) {
290 const auto &ac = a.box->getExtents(i).getMin();
291 const auto &bc = b.box->getExtents(i).getMin();
299 std::vector<API::IMDNode *> boxes;
300 boxes.reserve(childBoxCount);
301 std::transform(std::cbegin(children), std::cend(children), std::back_inserter(boxes),
302 [](
const auto &ch) {
return ch.box; });
303 tsk.root->setChildren(boxes, 0, boxes.size());
306 for (
auto &ch : children) {
309 ch.eventRange.second,
310 ch.mortonBounds.first,
311 ch.mortonBounds.second,
314 if (wtp == MASTER && (
size_t)std::distance(newTask.begin, newTask.end) < m_eventsThreshold)
315 pushTask(std::move(newTask));
317 distributeEvents(newTask, wtp);
#define PARALLEL_THREAD_NUMBER
Templated super-class of a multi-dimensional event "box".
Templated class for a multi-dimensional event "box".
Templated class for a GRIDDED multi-dimensional event "box".
A Task is a unit of work to be scheduled and run by a ThreadPool.
Class to create the box structure of MDWorkspace.
TreeWithIndexError distribute(std::vector< MDEventType< ND > > &mdEvents)
typename MDEvent::IntT IntT
const morton_index::MDSpaceBounds< ND > & m_space
void pushTask(Task &&tsk)
const size_t m_eventsThreshold
std::unique_ptr< Task > popTask()
BoxBase * doDistributeEvents(std::vector< MDEventType< ND > > &mdEvents)
std::atomic< bool > m_masterFinished
void distributeEvents(Task &tsk, const WORKER_TYPE &wtp)
Does actual work on creating tasks in MASTER mode and executing tasks in SLAVE mode.
const MortonT m_mortonMin
morton_index::MDCoordinate< ND > convertToIndex(std::vector< MDEventType< ND > > &mdEvents, const morton_index::MDSpaceBounds< ND > &space)
const MortonT m_mortonMax
MDEventTreeBuilder(const int numWorkers, const size_t threshold, const API::BoxController_sptr &bc, const morton_index::MDSpaceBounds< ND > &space)
std::vector< Mantid::Geometry::MDDimensionExtents< coord_t > > m_extents
typename MDEvent::template AccessFor< EventDistributor > IndexCoordinateSwitcher
typename MDEvent::MortonT MortonT
std::queue< Task > m_tasks
void sortEvents(std::vector< MDEventType< ND > > &mdEvents)
void waitAndLaunchSlave()
MDEventType< ND > MDEvent
const API::BoxController_sptr & m_bc
std::shared_ptr< BoxController > BoxController_sptr
Shared ptr to BoxController.
Helper class which provides the Collimation Length for SANS instruments.
Eigen::Array< float, static_cast< int >(ND), 1 > MDCoordinate
Eigen::Array< float, static_cast< int >(ND), 2 > MDSpaceBounds
Structure to mark the classes, which can switch the "physical" meaning of the union used in MDLeanEve...
Structure to store the subtask of creating subtree from the range of events.
const EventIterator begin
const MDEventType< ND >::MortonT lowerBound
const MDEventType< ND >::MortonT upperBound
morton_index::MDCoordinate< ND > err