engine.hpp:单粒子碰撞引擎与结果类型

这个文件做什么

ParticleState 描述被跟踪粒子,BackgroundComponent 描述背景,CollisionRequest 给出一次推进的输入。MccEngine 根据已编译模型计算碰撞;StepOutcome 记录原粒子变化、新产物和背景交换量。调用单粒子接口后,主程序要自行提交结果。

主要类型与入口

MccEngine, ParticleState, BackgroundComponent, CollisionRequest, StepOutcome, EventRecord, ConservationLedger

上面列出的是入口名称,具体参数以源码声明为准。

Tip

  • The projectile is the tracked incoming particle. The primary outcome tells what happens to that original particle record: update, removal or species change. Background partners are described by density and temperature.

  • Reservoir deltas track background gains/losses of particles, momentum and energy. A conservation ledger compares totals before and after reactions. Do not apply both as background source terms.

What this file does

ParticleState and BackgroundComponent describe the inputs. CollisionRequest controls a call; StepOutcome describes primary changes, products and reservoir exchange. The host must apply single-particle outcomes. See the implementation page for sampling details.

Main types and entry points

MccEngine, ParticleState, BackgroundComponent, CollisionRequest, StepOutcome, EventRecord, ConservationLedger

The names above are an interface index; consult the source declarations for exact parameters.

源码 / Source

engine.hpp

  1// SPDX-License-Identifier: Apache-2.0
  2//
  3// G02_MCC_network engine.
  4//
  5// MccEngine::collide() samples one explicit particle step against one or two
  6// background reservoir components and returns an immutable StepOutcome. The
  7// caller (host PIC loop) owns the particle store and decides how to commit the
  8// outcome atomically.
  9// 阅读顺序:输入 ParticleState / CollisionRequest → 输出 StepOutcome → MccEngine 接口。
 10// 本文件定义“传入什么、返回什么”;抽样流程在 fun_G02_mcc_engine.cpp。
 11// MCC(Monte Carlo Collision)用随机抽样再现大量粒子的统计碰撞规律。
 12#pragma once
 13
 14#include "common.hpp"
 15#include "compile.hpp"
 16#include "model.hpp"
 17
 18#include <cstdint>
 19#include <filesystem>
 20#include <memory>
 21#include <string>
 22#include <unordered_map>
 23#include <vector>
 24
 25namespace algoplasma {
 26namespace mcc {
 27
 28// 1. 输入:一个显式跟踪的模拟粒子。位置用 m,速度用 m/s;weight 是代表的真实粒子数。
 29// species 与 state 必须是模型中相互匹配的有效编号;id 用于可重放的随机抽样。
 30struct ParticleState {
 31    SpeciesId species{invalid_species};
 32    StateId state{invalid_state};
 33    Vec3 position{};
 34    Vec3 velocity{};
 35    Real weight{1.0};
 36    std::uint64_t id{0};
 37    std::uint64_t birth_step{0};
 38    std::uint32_t cell{0};
 39};
 40
 41// 背景粒子不逐个存储,用密度 n [m^-3]、温度 T [K]、平均漂移速度描述。
 42// state=invalid_state 表示按物种汇总的背景,不能照搬为 projectile 的状态。
 43struct BackgroundComponent {
 44    SpeciesId species{invalid_species};
 45    Real density_m3{};
 46    Real temperature_k{300.0};
 47    Vec3 drift_m_per_s{};
 48    // An invalid state preserves the v1 species-aggregated background contract.
 49    StateId state{invalid_state};
 50};
 51
 52// 一个 channel(通道)就是当前入射物种/能级可走的一条反应。
 53// majorant 是该通道碰撞频率的保守上界 [s^-1],用来先生成候选事件。
 54struct PreparedChannel {
 55    std::size_t index{0};
 56    Real majorant_s_inv{};
 57    Real density_product{};
 58    SpeciesId diagnostic_background{invalid_species};
 59};
 60
 61// Prefix 用累计权重查找通道;Alias 预建别名表,两者抽样的目标概率相同。
 62enum class ChannelSampler : std::uint8_t { Prefix, Alias };
 63using BackgroundIndex = std::unordered_map<std::uint32_t, const BackgroundComponent*>;
 64using ChannelCacheLookup = const struct CachedChannels* (*)(void*, SpeciesId, StateId);
 65
 66// 同一背景及入射物种/能级下复用的抽样表;背景条件改变后不能沿用旧表。
 67struct CachedChannels {
 68    SpeciesId species{invalid_species};
 69    StateId state{invalid_state};
 70    std::vector<PreparedChannel> channels;
 71    std::vector<Real> cumulative_majorants;
 72    std::vector<Real> alias_probability;
 73    std::vector<std::size_t> alias_index;
 74    Real total_majorant{};
 75};
 76
 77// 一次调用的完整条件。projectile 是调用开始时的入射粒子;dt_s 为时间步 [s]。
 78// background_view / cached_channels 为借用指针,其数据在同步调用结束前必须有效。
 79struct CollisionRequest {
 80    ParticleState projectile;
 81    std::vector<BackgroundComponent> background;
 82    Real dt_s{};
 83    std::uint64_t global_step{0};
 84    std::uint64_t seed{0};
 85    // 0 selects CompiledModel::options.max_events_per_step (default 64).
 86    std::uint32_t max_events_per_step{0};
 87    // Borrowed for a synchronous batch call; when absent, background is used.
 88    const std::vector<BackgroundComponent>* background_view{nullptr};
 89    bool exact_pruning{false};
 90    const CachedChannels* cached_channels{nullptr}; // synchronous batch call only
 91};
 92
 93// 2. 输出:primary 是沿当前粒子身份继续跟踪的主粒子,可能变物种或被移除。
 94// None 不改动;Update 更新状态;Remove 删除;MoveSpecies 移入另一个物种的存储区。
 95enum class PrimaryAction : std::uint8_t {
 96    None = 0,
 97    Update = 1,
 98    Remove = 2,
 99    MoveSpecies = 3
100};
101
102[[nodiscard]] const char* to_string(PrimaryAction value) noexcept;
103
104// 额外生成的显式粒子描述。全局唯一新编号由宿主/批量提交层分配,
105// parent_id、event_index、product_ordinal 用来标识出生来源。
106struct CreatedProduct {
107    std::uint64_t parent_id{0};
108    std::uint32_t event_index{0};
109    std::uint32_t product_ordinal{0};
110    SpeciesId species{invalid_species};
111    StateId state{invalid_state};
112    Vec3 position{};
113    Vec3 velocity{};
114    Real weight{1.0};
115    std::uint64_t birth_step{0};
116    std::uint32_t cell{0};
117};
118
119// 背景库的收支:消耗为负,生成为正;已乘粒子权重。
120// 返回这些量供宿主更新背景,本引擎不会自行改变背景密度或温度。
121struct ReservoirDelta {
122    SpeciesId species{invalid_species};
123    StateId state{invalid_state};
124    Real physical_particles{};
125    Vec3 momentum_kg_m_per_s{};
126    Real kinetic_energy_j{};
127    Real internal_energy_j{};
128};
129
130// 候选事件记录。null_event(空碰撞)只消耗抽样时间,不改变粒子速度。
131// has_* 为 false 时,相应诊断数值不应解释为已计算出的物理量。
132struct EventRecord {
133    std::uint32_t event_index{0};
134    ReactionId reaction{invalid_reaction};
135    CollisionAlgorithm algorithm{CollisionAlgorithm::C02Elastic};
136    bool real_event{false};
137    bool null_event{false};
138    Real majorant_s_inv{};
139    Real sampled_rate_s_inv{};
140    SpeciesId background_species{invalid_species};
141    bool has_relative_energy{false};
142    Real relative_energy_ev{};
143    bool has_cross_section{false};
144    Real cross_section_m2{};
145};
146
147// 守恒账本同时计入显式粒子、背景和辐射/未解析能量,不能只比较主粒子动能。
148// 动量与能量项已乘权重;电荷项记录每次反应式的电荷平衡 [C]。
149struct ConservationLedger {
150    Real charge_before_c{};
151    Real charge_after_c{};
152    Vec3 momentum_before_kg_m_per_s{};
153    Vec3 momentum_after_kg_m_per_s{};
154    Real kinetic_before_j{};
155    Real kinetic_after_j{};
156    Real internal_before_j{};
157    Real internal_after_j{};
158    // Energy released by internal/chemical rearrangement, excluding the part
159    // already accounted for by explicit state energies.
160    Real released_energy_j{};
161    Real radiated_or_unresolved_j{};
162    Real energy_residual_j{};
163    Real tolerance_j{};
164};
165
166// 汇总本次调用的变化,宿主检查成功后再提交到自己的粒子数组。
167// candidates = real_events + null_events;候选次数不等于真实碰撞次数。
168struct StepOutcome {
169    PrimaryAction primary_action{PrimaryAction::None};
170    ParticleState primary_after{};
171    SpeciesId primary_destination{invalid_species};
172    std::vector<CreatedProduct> created;
173    std::vector<ReservoirDelta> reservoir;
174    std::vector<EventRecord> events;
175    std::vector<std::pair<ReactionId, std::uint32_t>> reaction_counts;
176    ConservationLedger ledger;
177    std::uint32_t candidates{0};
178    std::uint32_t real_events{0};
179    std::uint32_t null_events{0};
180    bool event_limit_reached{false};
181};
182
183// 单通道诊断;rate_defined=false 表示此处未计算真实频率,不表示频率为零。
184struct ChannelDiagnostics {
185    ReactionId reaction{invalid_reaction};
186    CollisionAlgorithm algorithm{CollisionAlgorithm::C02Elastic};
187    RateKind rate_kind{RateKind::CrossSection};
188    bool rate_defined{false};
189    Real rate_s_inv{};
190    Real majorant_s_inv{};
191};
192
193// 3. 计算入口:持有只读编译模型,产生变化描述,不负责位置推进/电磁场求解。
194class MccEngine {
195public:
196    // 已有 CompiledModel 时直接构造;load 则依次读取 CSV、校验并编译模型。
197    explicit MccEngine(CompiledModel model);
198
199    [[nodiscard]] static MccEngine load(const std::filesystem::path& package_dir,
200                                        CompileOptions options = {});
201
202    [[nodiscard]] const CompiledModel& model() const noexcept { return *model_; }
203
204    // 把 CSV 中的名字换为运行时编号;初始化时查一次,循环里复用编号。
205    [[nodiscard]] SpeciesId species_id(const std::string& name) const;
206    [[nodiscard]] StateId state_id(SpeciesId species, const std::string& label) const;
207    [[nodiscard]] std::string species_name(SpeciesId species) const;
208
209    // collide 为受限步进:达到候选上限会标记 event_limit_reached;
210    // 主粒子变物种时也可能提前结束。需要完整 dt 时使用 collide_full / MccStepper。
211    // Sample one step. Throws Error on any invalid input, missing background,
212    // domain violation, majorant violation or failed conservation check. On
213    // success the input request is never modified and the returned StepOutcome
214    // is the only artifact.
215    [[nodiscard]] StepOutcome collide(const CollisionRequest& request) const;
216
217    // Complete the requested dt, including after a primary species change.
218    // Exceeding max_candidates is a hard error rather than a truncated step.
219    [[nodiscard]] StepOutcome collide_full(const CollisionRequest& request,
220                                           std::uint32_t max_candidates = 1000000,
221                                           bool record_events = false) const;
222
223    // Per-channel majorants and, for temperature-based rate coefficients, the
224    // exact instantaneous rate. Useful for host diagnostics and tests.
225    [[nodiscard]] std::vector<ChannelDiagnostics> evaluate_channels(
226        const CollisionRequest& request) const;
227
228private:
229    // 批量层使用的缓存与统一抽样内核;普通调用者使用上面的公开入口即可。
230    [[nodiscard]] CachedChannels prepare_channels(
231        const std::vector<BackgroundComponent>& background,
232        SpeciesId species, StateId state, bool exact_pruning,
233        ChannelSampler sampler) const;
234    [[nodiscard]] StepOutcome collide_impl(const CollisionRequest& request,
235                                           bool complete_step,
236                                           std::uint32_t max_candidates,
237                                           bool record_events,
238                                           const BackgroundIndex* background_index = nullptr,
239                                           ChannelCacheLookup cache_lookup = nullptr,
240                                           void* cache_context = nullptr) const;
241    [[nodiscard]] BackgroundIndex index_background(
242        const std::vector<BackgroundComponent>& background) const;
243    [[nodiscard]] StepOutcome collide_full_batch(
244        const CollisionRequest& request, const BackgroundIndex& background_index,
245        ChannelCacheLookup lookup, void* lookup_context,
246        std::uint32_t max_candidates, bool record_events) const;
247    std::shared_ptr<const CompiledModel> model_;
248    friend class MccStepper;
249};
250
251} // namespace mcc
252} // namespace algoplasma

文件归属 / File location

G_Collision/G02_MCC_network/engine.hpp

Collision