data_t::DataUpdate handleEventsGillespie( CPUKernel *const kernel, scalar timeStep, bool filterEventsInAdvance, bool approximateRate, std::vector<event_t> &&events, std::vector<record_t> *maybeRecords, reaction_counts_map *maybeCounts) { using rdy_particle_t = readdy::model::Particle; const auto &box = kernel->context().boxSize().data(); const auto &pbc = kernel->context().periodicBoundaryConditions().data(); data_t::EntriesUpdate newParticles{}; std::vector<data_t::size_type> decayedEntries{}; if (!events.empty()) { const auto &ctx = kernel->context(); auto data = kernel->getCPUKernelStateModel().getParticleData(); /** * Handle gathered reaction events */ { auto shouldEval = [&](const event_t &event) { return filterEventsInAdvance || shouldPerformEvent(event.rate, timeStep, approximateRate); }; auto depending = [&](const event_t &e1, const event_t &e2) { return (e1.idx1 == e2.idx1 || (e2.nEducts == 2 && e1.idx1 == e2.idx2) || (e1.nEducts == 2 && (e1.idx2 == e2.idx1 || (e2.nEducts == 2 && e1.idx2 == e2.idx2)))); }; auto eval = [&](const event_t &event) { auto entry1 = event.idx1; if (event.nEducts == 1) { auto reaction = ctx.reactions().order1ByType(event.t1)[event.reactionIndex]; if (maybeRecords != nullptr) { record_t record; record.id = reaction->id(); performReaction(data, ctx, entry1, entry1, newParticles, decayedEntries, reaction, &record); bcs::fixPosition(record.where, box, pbc); maybeRecords->push_back(record); } else { performReaction(data, ctx, entry1, entry1, newParticles, decayedEntries, reaction, nullptr); } if (maybeCounts != nullptr) { auto &counts = *maybeCounts; counts.at(reaction->id())++; } } else { auto reaction = ctx.reactions().order2ByType(event.t1, event.t2)[event.reactionIndex]; if (maybeRecords != nullptr) { record_t record; record.id = reaction->id(); performReaction(data, ctx, entry1, event.idx2, newParticles, decayedEntries, reaction, &record); bcs::fixPosition(record.where, box, pbc); maybeRecords->push_back(record); } else { performReaction(data, ctx, entry1, event.idx2, newParticles, decayedEntries, reaction, nullptr); } if (maybeCounts != nullptr) { auto &counts = *maybeCounts; counts.at(reaction->id())++; } } }; algo::performEvents(events, shouldEval, depending, eval); } } return std::make_pair(std::move(newParticles), std::move(decayedEntries)); }
void findEvents(std::size_t /*tid*/, data_iter_t begin, data_iter_t end, nl_bounds nlBounds, const CPUKernel *const kernel, scalar dt, bool approximateRate, const neighbor_list &nl, event_promise_t &events, std::promise<std::size_t> &n_events) { std::vector<event_t> eventsUpdate; const auto &data = *kernel->getCPUKernelStateModel().getParticleData(); const auto &box = kernel->context().boxSize().data(); const auto &pbc = kernel->context().periodicBoundaryConditions().data(); auto index = static_cast<std::size_t>(std::distance(data.begin(), begin)); for (auto it = begin; it != end; ++it, ++index) { const auto &entry = *it; // this being false should really not happen, though if (!entry.deactivated) { // order 1 { const auto &reactions = kernel->context().reactions().order1ByType(entry.type); for (auto it_reactions = reactions.begin(); it_reactions != reactions.end(); ++it_reactions) { const auto rate = (*it_reactions)->rate(); if (rate > 0 && shouldPerformEvent(rate, dt, approximateRate)) { eventsUpdate.emplace_back(1, (*it_reactions)->nProducts(), index, index, rate, 0, static_cast<event_t::reaction_index_type>(it_reactions - reactions.begin()), entry.type, 0); } } } } } for(auto cell = std::get<0>(nlBounds); cell != std::get<1>(nlBounds); ++cell) { for(auto particleIt = nl.particlesBegin(cell); particleIt != nl.particlesEnd(cell); ++particleIt) { const auto &entry = data.entry_at(*particleIt); if(entry.deactivated) { log::critical("deactivated entry in uncontrolled approximation!"); continue; } nl.forEachNeighbor(*particleIt, cell, [&](const auto neighborIdx) { const auto &neighbor = data.entry_at(neighborIdx); if(!neighbor.deactivated) { const auto &reactions = kernel->context().reactions().order2ByType(entry.type, neighbor.type); if (!reactions.empty()) { const auto distSquared = bcs::distSquared(neighbor.pos, entry.pos, box, pbc); for (auto it_reactions = reactions.begin(); it_reactions < reactions.end(); ++it_reactions) { const auto &react = *it_reactions; const auto rate = react->rate(); if (rate > 0 && distSquared < react->eductDistanceSquared() && shouldPerformEvent(rate, dt, approximateRate)) { const auto reaction_index = static_cast<event_t::reaction_index_type>(it_reactions - reactions.begin()); eventsUpdate.emplace_back(2, react->nProducts(), *particleIt, neighborIdx, rate, 0, reaction_index, entry.type, neighbor.type); } } } } }); } } n_events.set_value(eventsUpdate.size()); events.set_value(std::move(eventsUpdate)); }