Bicameral Engine
GPU-resident engine for a magic-research open-world game
Loading...
Searching...
No Matches
reaction_test_table.cpp
Go to the documentation of this file.
1// reaction_test_table.cpp — 試験用の反応表の中身(reaction_test_table.h)。
2// 生成エンタルピー(J/mol、298.15 K)と比熱(mJ/(mol·K))は NIST の値を丸めた。セルロースは C6H10O5 の 1 単位あたり
3// (燃焼熱から逆算した約 −963 kJ/mol)、比熱は約 1.3 J/(g·K)。この値だと熱分解が発熱になる(実際は生成物が複雑でほぼ中立)。
4// 速度: 熱分解は Broido–Shafizadeh の値の桁、ほかは 600〜1000 K で燃え始めるように置いた仮の値。
5// 熱伝導率(T-0089): 現実の値(木 0.12・炭 0.1・気体 0.017〜0.027 W/(m·K))に倍率を掛けた試験の値。
6// 現実の値だと木の中を 0.5 m 伝わるのに数日かかり、空気の伝導はほぼ 0(現実の火は放射と対流で広がる。M3)。
7// 「リアルっぽいが、反応が遅すぎない」ように大きくする(ユーザー 2026-10-01)。M3 で放射と対流が入ったら見直す。
8// 倍率は gpu_probe_fire_test で決めた(1 回のクリックで、木箱の壁の 9 割が約 50 秒で炭になる):
9// 固体 × 20000・気体 × 5000。固体を大きくしすぎる(× 80000)と、熱が燃える前に薄まって火が消える。
10// 倍率を全部同じにすると、燃えたセルの熱が空気へ逃げて広がらない(気体 × 5 万: 火が 1 セルで消える)
12
13namespace bicameral::sim {
14
15 namespace {
16
17 ElementCount Atom(std::string_view element, uint32_t count) {
18 return {.element = std::string(element), .count = count};
19 }
20
21 // 反応物(速度式で次数 1)
22 RuleTerm Reactant(std::string_view species, uint32_t coefficient) {
23 return {.species = std::string(species), .coefficient = coefficient, .firstOrder = true};
24 }
25
26 RuleTerm Product(std::string_view species, uint32_t coefficient) {
27 return {.species = std::string(species), .coefficient = coefficient, .firstOrder = false};
28 }
29
30 // 熱伝導率の試験の倍率と、現実の値(mW/(m·K))から試験の値にする
31 constexpr uint32_t TEST_SOLID_CONDUCTIVITY_SCALE = 20000;
32 constexpr uint32_t TEST_GAS_CONDUCTIVITY_SCALE = 5000;
33
34 constexpr uint32_t SolidConductivity(uint32_t realMilliwattsPerMeterKelvin) {
35 return realMilliwattsPerMeterKelvin * TEST_SOLID_CONDUCTIVITY_SCALE;
36 }
37
38 constexpr uint32_t GasConductivity(uint32_t realMilliwattsPerMeterKelvin) {
39 return realMilliwattsPerMeterKelvin * TEST_GAS_CONDUCTIVITY_SCALE;
40 }
41
42 std::vector<ElementDefinition> Elements() {
43 return {
44 {.name = "C", .atomicMass = 12011},
45 {.name = "H", .atomicMass = 1008},
46 {.name = "O", .atomicMass = 15999},
47 {.name = "N", .atomicMass = 14007},
48 };
49 }
50
51 std::vector<SpeciesDefinition> Species() {
52 return {
53 {.name = "cellulose",
54 .composition = {Atom("C", 6), Atom("H", 10), Atom("O", 5)},
55 .formationEnthalpy = -963000,
56 .heatCapacity = 211000,
57 .thermalConductivity = SolidConductivity(120)},
58 {.name = "carbon",
59 .composition = {Atom("C", 1)},
60 .formationEnthalpy = 0,
61 .heatCapacity = 8520,
62 .thermalConductivity = SolidConductivity(100)},
63 {.name = "oxygen",
64 .composition = {Atom("O", 2)},
65 .formationEnthalpy = 0,
66 .heatCapacity = 29378,
67 .thermalConductivity = GasConductivity(27)},
68 {.name = "nitrogen",
69 .composition = {Atom("N", 2)},
70 .formationEnthalpy = 0,
71 .heatCapacity = 29124,
72 .thermalConductivity = GasConductivity(26)},
73 {.name = "carbon_dioxide",
74 .composition = {Atom("C", 1), Atom("O", 2)},
75 .formationEnthalpy = -393509,
76 .heatCapacity = 37135,
77 .thermalConductivity = GasConductivity(17)},
78 {.name = "carbon_monoxide",
79 .composition = {Atom("C", 1), Atom("O", 1)},
80 .formationEnthalpy = -110527,
81 .heatCapacity = 29142,
82 .thermalConductivity = GasConductivity(25)},
83 {.name = "water_vapor",
84 .composition = {Atom("H", 2), Atom("O", 1)},
85 .formationEnthalpy = -241826,
86 .heatCapacity = 33580,
87 .thermalConductivity = GasConductivity(25)},
88 };
89 }
90
91 std::vector<RuleDefinition> Rules() {
92 return {
93 // 酸素なしで炭と水蒸気になる(一次反応)
94 {.name = "cellulose_pyrolysis",
95 .reactants = {Reactant("cellulose", 1)},
96 .products = {Product("carbon", 6), Product("water_vapor", 5)},
97 .rate = {.preExponentialMantissa = 28, .preExponentialExponent10 = 18, .activationEnergy = 242400}},
98 // 木が燃える(O2 を炭の燃焼と取り合う)
99 {.name = "cellulose_combustion",
100 .reactants = {Reactant("cellulose", 1), Reactant("oxygen", 6)},
101 .products = {Product("carbon_dioxide", 6), Product("water_vapor", 5)},
102 .rate = {.preExponentialMantissa = 2, .preExponentialExponent10 = 10, .activationEnergy = 150000}},
103 {.name = "carbon_combustion",
104 .reactants = {Reactant("carbon", 1), Reactant("oxygen", 1)},
105 .products = {Product("carbon_dioxide", 1)},
106 .rate = {.preExponentialMantissa = 3, .preExponentialExponent10 = 8, .activationEnergy = 160000}},
107 // 熱いと CO が増える
108 {.name = "carbon_partial_combustion",
109 .reactants = {Reactant("carbon", 2), Reactant("oxygen", 1)},
110 .products = {Product("carbon_monoxide", 2)},
111 .rate = {.preExponentialMantissa = 15, .preExponentialExponent10 = 8, .activationEnergy = 200000}},
112 // 吸熱(熱を資源として取り合う場面)
113 {.name = "boudouard",
114 .reactants = {Reactant("carbon", 1), Reactant("carbon_dioxide", 1)},
115 .products = {Product("carbon_monoxide", 2)},
116 .rate = {.preExponentialMantissa = 1, .preExponentialExponent10 = 10, .activationEnergy = 250000}},
117 };
118 }
119
120 } // namespace
121
123 return {.elements = Elements(), .species = Species(), .rules = Rules()};
124 }
125
126} // namespace bicameral::sim
constexpr uint32_t SolidConductivity(uint32_t realMilliwattsPerMeterKelvin)
RuleTerm Reactant(std::string_view species, uint32_t coefficient)
constexpr uint32_t GasConductivity(uint32_t realMilliwattsPerMeterKelvin)
ElementCount Atom(std::string_view element, uint32_t count)
RuleTerm Product(std::string_view species, uint32_t coefficient)
ReactionTableDefinition MakeCombustionTestTable()