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
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