Ejemplo n.º 1
0
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));
}
Ejemplo n.º 2
0
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));
}