@classytic/stage 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +18 -0
  2. package/dist/atomic/aufbau.d.mts +144 -0
  3. package/dist/atomic/aufbau.mjs +384 -0
  4. package/dist/atomic/elements.d.mts +67 -0
  5. package/dist/atomic/elements.mjs +785 -0
  6. package/dist/atomic/emission.d.mts +112 -0
  7. package/dist/atomic/emission.mjs +179 -0
  8. package/dist/atomic/index.d.mts +8 -0
  9. package/dist/atomic/index.mjs +9 -0
  10. package/dist/atomic/periodic.d.mts +82 -0
  11. package/dist/atomic/periodic.mjs +231 -0
  12. package/dist/atomic/properties.d.mts +100 -0
  13. package/dist/atomic/properties.mjs +574 -0
  14. package/dist/atomic/shells.d.mts +137 -0
  15. package/dist/atomic/shells.mjs +170 -0
  16. package/dist/atomic/trends.d.mts +148 -0
  17. package/dist/atomic/trends.mjs +225 -0
  18. package/dist/chem/chromatography.d.mts +66 -0
  19. package/dist/chem/chromatography.mjs +63 -0
  20. package/dist/chem/complex.d.mts +114 -0
  21. package/dist/chem/complex.mjs +234 -0
  22. package/dist/chem/cycle.d.mts +75 -0
  23. package/dist/chem/cycle.mjs +145 -0
  24. package/dist/chem/equation.d.mts +86 -0
  25. package/dist/chem/equation.mjs +168 -0
  26. package/dist/chem/formula.d.mts +90 -0
  27. package/dist/chem/formula.mjs +201 -0
  28. package/dist/chem/functional-groups.d.mts +31 -0
  29. package/dist/chem/functional-groups.mjs +187 -0
  30. package/dist/chem/hazard.d.mts +94 -0
  31. package/dist/chem/hazard.mjs +329 -0
  32. package/dist/chem/index.d.mts +34 -33
  33. package/dist/chem/index.mjs +34 -28
  34. package/dist/chem/ionic.d.mts +98 -0
  35. package/dist/chem/ionic.mjs +156 -0
  36. package/dist/chem/layout.d.mts +46 -0
  37. package/dist/chem/layout.mjs +342 -0
  38. package/dist/chem/lewis.d.mts +79 -0
  39. package/dist/chem/lewis.mjs +163 -0
  40. package/dist/chem/molecular-orbital.d.mts +114 -0
  41. package/dist/chem/molecular-orbital.mjs +201 -0
  42. package/dist/chem/molecule.d.mts +154 -0
  43. package/dist/chem/molecule.mjs +282 -0
  44. package/dist/chem/nmr.d.mts +153 -0
  45. package/dist/chem/nmr.mjs +165 -0
  46. package/dist/chem/polymer.d.mts +65 -0
  47. package/dist/chem/polymer.mjs +179 -0
  48. package/dist/chem/redox.d.mts +138 -0
  49. package/dist/chem/redox.mjs +328 -0
  50. package/dist/chem/relations.d.mts +183 -0
  51. package/dist/chem/relations.mjs +299 -0
  52. package/dist/chem/skeleton.d.mts +51 -0
  53. package/dist/chem/skeleton.mjs +186 -0
  54. package/dist/chem/solution.d.mts +116 -0
  55. package/dist/chem/solution.mjs +186 -0
  56. package/dist/chem/species.d.mts +47 -0
  57. package/dist/chem/species.mjs +128 -0
  58. package/dist/chem/stereo.d.mts +108 -0
  59. package/dist/chem/stereo.mjs +286 -0
  60. package/dist/chem/stoichiometry.d.mts +95 -0
  61. package/dist/chem/stoichiometry.mjs +145 -0
  62. package/dist/chem/synthesis.d.mts +113 -0
  63. package/dist/chem/synthesis.mjs +281 -0
  64. package/dist/chem/vsepr.d.mts +80 -0
  65. package/dist/chem/vsepr.mjs +247 -0
  66. package/dist/circuit/ac.d.mts +163 -0
  67. package/dist/circuit/ac.mjs +452 -0
  68. package/dist/circuit/dc.d.mts +92 -0
  69. package/dist/circuit/dc.mjs +333 -0
  70. package/dist/circuit/index.d.mts +5 -92
  71. package/dist/circuit/index.mjs +5 -332
  72. package/dist/circuit/network.d.mts +99 -0
  73. package/dist/circuit/network.mjs +440 -0
  74. package/dist/circuit/topology.d.mts +102 -0
  75. package/dist/circuit/topology.mjs +143 -0
  76. package/dist/colour/absorption.d.mts +79 -0
  77. package/dist/colour/absorption.mjs +137 -0
  78. package/dist/colour/index.d.mts +6 -0
  79. package/dist/colour/index.mjs +7 -0
  80. package/dist/colour/name.d.mts +14 -0
  81. package/dist/colour/name.mjs +76 -0
  82. package/dist/colour/observer.d.mts +31 -0
  83. package/dist/colour/observer.mjs +46 -0
  84. package/dist/colour/spectrum.d.mts +61 -0
  85. package/dist/colour/spectrum.mjs +108 -0
  86. package/dist/colour/srgb.d.mts +49 -0
  87. package/dist/colour/srgb.mjs +108 -0
  88. package/dist/core/constants.d.mts +138 -0
  89. package/dist/core/constants.mjs +139 -0
  90. package/dist/core/index.d.mts +3 -1
  91. package/dist/core/index.mjs +3 -1
  92. package/dist/core/vec3.d.mts +94 -0
  93. package/dist/core/vec3.mjs +123 -0
  94. package/dist/core/worked.d.mts +35 -0
  95. package/dist/core/worked.mjs +44 -0
  96. package/dist/electro/cell.d.mts +102 -0
  97. package/dist/electro/cell.mjs +170 -0
  98. package/dist/electro/conductivity.d.mts +157 -0
  99. package/dist/electro/conductivity.mjs +156 -0
  100. package/dist/electro/couples.d.mts +114 -0
  101. package/dist/electro/couples.mjs +334 -0
  102. package/dist/electro/electrolysis.d.mts +96 -0
  103. package/dist/electro/electrolysis.mjs +274 -0
  104. package/dist/electro/faraday.d.mts +150 -0
  105. package/dist/electro/faraday.mjs +118 -0
  106. package/dist/electro/index.d.mts +6 -0
  107. package/dist/electro/index.mjs +7 -0
  108. package/dist/finance/accounting/adjustments.d.mts +17 -0
  109. package/dist/finance/accounting/adjustments.mjs +202 -0
  110. package/dist/finance/accounting/analysis.d.mts +8 -0
  111. package/dist/finance/accounting/analysis.mjs +205 -0
  112. package/dist/finance/accounting/clubs.d.mts +21 -0
  113. package/dist/finance/accounting/clubs.mjs +217 -0
  114. package/dist/finance/accounting/company-statements.d.mts +7 -0
  115. package/dist/finance/accounting/company-statements.mjs +150 -0
  116. package/dist/finance/accounting/harness.d.mts +7 -0
  117. package/dist/finance/accounting/harness.mjs +45 -0
  118. package/dist/finance/accounting/index.d.mts +18 -0
  119. package/dist/finance/accounting/index.mjs +18 -0
  120. package/dist/finance/accounting/journalize.d.mts +16 -0
  121. package/dist/finance/accounting/journalize.mjs +128 -0
  122. package/dist/finance/accounting/manufacturing.d.mts +8 -0
  123. package/dist/finance/accounting/manufacturing.mjs +236 -0
  124. package/dist/finance/accounting/partnership.d.mts +7 -0
  125. package/dist/finance/accounting/partnership.mjs +152 -0
  126. package/dist/finance/accounting/period-case.d.mts +6 -0
  127. package/dist/finance/accounting/period-case.mjs +71 -0
  128. package/dist/finance/accounting/post.d.mts +9 -0
  129. package/dist/finance/accounting/post.mjs +84 -0
  130. package/dist/finance/accounting/precision.d.mts +9 -0
  131. package/dist/finance/accounting/precision.mjs +15 -0
  132. package/dist/finance/accounting/rules.d.mts +21 -0
  133. package/dist/finance/accounting/rules.mjs +37 -0
  134. package/dist/finance/accounting/solve.d.mts +28 -0
  135. package/dist/finance/accounting/solve.mjs +92 -0
  136. package/dist/finance/accounting/statements.d.mts +7 -0
  137. package/dist/finance/accounting/statements.mjs +142 -0
  138. package/dist/finance/accounting/types.d.mts +649 -0
  139. package/dist/finance/accounting/validate.d.mts +7 -0
  140. package/dist/finance/accounting/validate.mjs +67 -0
  141. package/dist/finance/accounting/verification.d.mts +24 -0
  142. package/dist/finance/accounting/verification.mjs +386 -0
  143. package/dist/finance/bizsim.d.mts +21 -39
  144. package/dist/finance/bizsim.mjs +276 -97
  145. package/dist/finance/index.d.mts +20 -43
  146. package/dist/finance/index.mjs +19 -77
  147. package/dist/finance/investment-math.d.mts +7 -0
  148. package/dist/finance/investment-math.mjs +18 -0
  149. package/dist/finance/management-accounting/budgeting.d.mts +7 -0
  150. package/dist/finance/management-accounting/budgeting.mjs +189 -0
  151. package/dist/finance/management-accounting/cash-budget.d.mts +7 -0
  152. package/dist/finance/management-accounting/cash-budget.mjs +154 -0
  153. package/dist/finance/management-accounting/costing.d.mts +8 -0
  154. package/dist/finance/management-accounting/costing.mjs +175 -0
  155. package/dist/finance/management-accounting/decisions.d.mts +8 -0
  156. package/dist/finance/management-accounting/decisions.mjs +164 -0
  157. package/dist/finance/management-accounting/index.d.mts +13 -0
  158. package/dist/finance/management-accounting/index.mjs +13 -0
  159. package/dist/finance/management-accounting/integrated-budget.d.mts +8 -0
  160. package/dist/finance/management-accounting/integrated-budget.mjs +67 -0
  161. package/dist/finance/management-accounting/inventory-costing.d.mts +7 -0
  162. package/dist/finance/management-accounting/inventory-costing.mjs +173 -0
  163. package/dist/finance/management-accounting/investment-appraisal.d.mts +7 -0
  164. package/dist/finance/management-accounting/investment-appraisal.mjs +148 -0
  165. package/dist/finance/management-accounting/management-case.d.mts +8 -0
  166. package/dist/finance/management-accounting/management-case.mjs +91 -0
  167. package/dist/finance/management-accounting/master-budget.d.mts +7 -0
  168. package/dist/finance/management-accounting/master-budget.mjs +137 -0
  169. package/dist/finance/management-accounting/production-costing.d.mts +8 -0
  170. package/dist/finance/management-accounting/production-costing.mjs +214 -0
  171. package/dist/finance/management-accounting/types.d.mts +644 -0
  172. package/dist/finance/management-accounting/variances.d.mts +7 -0
  173. package/dist/finance/management-accounting/variances.mjs +150 -0
  174. package/dist/index.d.mts +6 -6
  175. package/dist/index.mjs +1 -1
  176. package/dist/math/analysis.d.mts +61 -0
  177. package/dist/math/analysis.mjs +187 -0
  178. package/dist/math/answer-check.d.mts +50 -0
  179. package/dist/math/answer-check.mjs +106 -0
  180. package/dist/math/calculus.d.mts +4 -9
  181. package/dist/math/calculus.mjs +216 -7
  182. package/dist/math/complex.d.mts +93 -0
  183. package/dist/math/complex.mjs +239 -0
  184. package/dist/math/expr.d.mts +23 -0
  185. package/dist/math/expr.mjs +36 -0
  186. package/dist/math/index.d.mts +8 -22
  187. package/dist/math/index.mjs +8 -37
  188. package/dist/math/latex.mjs +2 -1
  189. package/dist/math/parse.mjs +1 -1
  190. package/dist/math/poly.d.mts +55 -0
  191. package/dist/math/poly.mjs +273 -0
  192. package/dist/math/rearrange.d.mts +14 -0
  193. package/dist/math/rearrange.mjs +125 -0
  194. package/dist/math/solve.d.mts +21 -0
  195. package/dist/math/solve.mjs +75 -0
  196. package/dist/networking/addressing.d.mts +26 -0
  197. package/dist/networking/addressing.mjs +33 -0
  198. package/dist/networking/cloud/access.d.mts +36 -0
  199. package/dist/networking/cloud/access.mjs +95 -0
  200. package/dist/networking/cloud/containers.d.mts +43 -0
  201. package/dist/networking/cloud/containers.mjs +54 -0
  202. package/dist/networking/cloud/edge.d.mts +17 -0
  203. package/dist/networking/cloud/edge.mjs +31 -0
  204. package/dist/networking/cloud/failure-domains.d.mts +19 -0
  205. package/dist/networking/cloud/failure-domains.mjs +22 -0
  206. package/dist/networking/cloud/geo-routing.d.mts +22 -0
  207. package/dist/networking/cloud/geo-routing.mjs +64 -0
  208. package/dist/networking/cloud/index.d.mts +18 -0
  209. package/dist/networking/cloud/index.mjs +19 -0
  210. package/dist/networking/cloud/inference-reliability.d.mts +30 -0
  211. package/dist/networking/cloud/inference-reliability.mjs +76 -0
  212. package/dist/networking/cloud/inference.d.mts +118 -0
  213. package/dist/networking/cloud/inference.mjs +179 -0
  214. package/dist/networking/cloud/infrastructure.d.mts +45 -0
  215. package/dist/networking/cloud/infrastructure.mjs +96 -0
  216. package/dist/networking/cloud/observability.d.mts +24 -0
  217. package/dist/networking/cloud/observability.mjs +34 -0
  218. package/dist/networking/cloud/orchestration.d.mts +32 -0
  219. package/dist/networking/cloud/orchestration.mjs +38 -0
  220. package/dist/networking/cloud/recovery.d.mts +21 -0
  221. package/dist/networking/cloud/recovery.mjs +27 -0
  222. package/dist/networking/cloud/releases.d.mts +42 -0
  223. package/dist/networking/cloud/releases.mjs +135 -0
  224. package/dist/networking/cloud/scaling.d.mts +25 -0
  225. package/dist/networking/cloud/scaling.mjs +65 -0
  226. package/dist/networking/cloud/secrets.d.mts +39 -0
  227. package/dist/networking/cloud/secrets.mjs +68 -0
  228. package/dist/networking/cloud/server-deployment.d.mts +29 -0
  229. package/dist/networking/cloud/server-deployment.mjs +72 -0
  230. package/dist/networking/cloud/storage.d.mts +16 -0
  231. package/dist/networking/cloud/storage.mjs +58 -0
  232. package/dist/networking/cloud/vpc.d.mts +18 -0
  233. package/dist/networking/cloud/vpc.mjs +100 -0
  234. package/dist/networking/delivery.d.mts +34 -0
  235. package/dist/networking/delivery.mjs +52 -0
  236. package/dist/networking/index.d.mts +47 -0
  237. package/dist/networking/index.mjs +47 -0
  238. package/dist/networking/ipv6.d.mts +28 -0
  239. package/dist/networking/ipv6.mjs +17 -0
  240. package/dist/networking/journeys.d.mts +83 -0
  241. package/dist/networking/journeys.mjs +161 -0
  242. package/dist/networking/models/airtime.d.mts +87 -0
  243. package/dist/networking/models/airtime.mjs +130 -0
  244. package/dist/networking/models/cellular.d.mts +157 -0
  245. package/dist/networking/models/cellular.mjs +252 -0
  246. package/dist/networking/models/encapsulation.d.mts +98 -0
  247. package/dist/networking/models/encapsulation.mjs +132 -0
  248. package/dist/networking/models/handover.d.mts +116 -0
  249. package/dist/networking/models/handover.mjs +209 -0
  250. package/dist/networking/models/handshake.d.mts +90 -0
  251. package/dist/networking/models/handshake.mjs +122 -0
  252. package/dist/networking/models/index.d.mts +14 -0
  253. package/dist/networking/models/index.mjs +15 -0
  254. package/dist/networking/models/media.d.mts +82 -0
  255. package/dist/networking/models/media.mjs +188 -0
  256. package/dist/networking/models/satellite.d.mts +86 -0
  257. package/dist/networking/models/satellite.mjs +121 -0
  258. package/dist/networking/models/spectrum.d.mts +83 -0
  259. package/dist/networking/models/spectrum.mjs +235 -0
  260. package/dist/networking/models/switch.d.mts +80 -0
  261. package/dist/networking/models/switch.mjs +155 -0
  262. package/dist/networking/models/vlan.d.mts +62 -0
  263. package/dist/networking/models/vlan.mjs +100 -0
  264. package/dist/networking/models/vpn.d.mts +66 -0
  265. package/dist/networking/models/vpn.mjs +125 -0
  266. package/dist/networking/models/wifi-privacy.d.mts +82 -0
  267. package/dist/networking/models/wifi-privacy.mjs +130 -0
  268. package/dist/networking/models/wifi.d.mts +240 -0
  269. package/dist/networking/models/wifi.mjs +562 -0
  270. package/dist/networking/nat-traversal.d.mts +24 -0
  271. package/dist/networking/nat-traversal.mjs +38 -0
  272. package/dist/networking/protocols.d.mts +17 -0
  273. package/dist/networking/protocols.mjs +57 -0
  274. package/dist/networking/queue.d.mts +12 -0
  275. package/dist/networking/queue.mjs +18 -0
  276. package/dist/networking/route-learning.d.mts +23 -0
  277. package/dist/networking/route-learning.mjs +43 -0
  278. package/dist/networking/routing.d.mts +11 -0
  279. package/dist/networking/routing.mjs +25 -0
  280. package/dist/networking/signals.d.mts +26 -0
  281. package/dist/networking/signals.mjs +35 -0
  282. package/dist/networking/subnet.d.mts +49 -0
  283. package/dist/networking/subnet.mjs +89 -0
  284. package/dist/networking/tcp-reliability.d.mts +24 -0
  285. package/dist/networking/tcp-reliability.mjs +38 -0
  286. package/dist/networking/topology/contract.d.mts +123 -0
  287. package/dist/networking/topology/index.d.mts +4 -0
  288. package/dist/networking/topology/index.mjs +4 -0
  289. package/dist/networking/topology/presets.d.mts +7 -0
  290. package/dist/networking/topology/presets.mjs +302 -0
  291. package/dist/networking/topology/simulation.d.mts +8 -0
  292. package/dist/networking/topology/simulation.mjs +179 -0
  293. package/dist/networking/wireless.d.mts +11 -0
  294. package/dist/networking/wireless.mjs +17 -0
  295. package/dist/optics/imaging.d.mts +218 -0
  296. package/dist/optics/imaging.mjs +276 -0
  297. package/dist/optics/index.d.mts +7 -0
  298. package/dist/optics/index.mjs +8 -0
  299. package/dist/optics/laws.d.mts +70 -0
  300. package/dist/optics/laws.mjs +195 -0
  301. package/dist/optics/prism.d.mts +148 -0
  302. package/dist/optics/prism.mjs +197 -0
  303. package/dist/optics/refraction.d.mts +201 -0
  304. package/dist/optics/refraction.mjs +270 -0
  305. package/dist/optics/wave-optics.d.mts +171 -0
  306. package/dist/optics/wave-optics.mjs +259 -0
  307. package/dist/physics/ac/index.d.mts +183 -0
  308. package/dist/physics/ac/index.mjs +203 -0
  309. package/dist/physics/dynamics/forces.d.mts +98 -0
  310. package/dist/physics/dynamics/forces.mjs +153 -0
  311. package/dist/physics/dynamics/friction.d.mts +76 -0
  312. package/dist/physics/dynamics/friction.mjs +119 -0
  313. package/dist/physics/dynamics/system.d.mts +68 -0
  314. package/dist/physics/dynamics/system.mjs +125 -0
  315. package/dist/physics/electrostatics/index.d.mts +169 -0
  316. package/dist/physics/electrostatics/index.mjs +249 -0
  317. package/dist/physics/energy/centre-of-mass.d.mts +115 -0
  318. package/dist/physics/energy/centre-of-mass.mjs +180 -0
  319. package/dist/physics/energy/conservation.d.mts +81 -0
  320. package/dist/physics/energy/conservation.mjs +129 -0
  321. package/dist/physics/energy/power.d.mts +90 -0
  322. package/dist/physics/energy/power.mjs +167 -0
  323. package/dist/physics/energy/spring.d.mts +73 -0
  324. package/dist/physics/energy/spring.mjs +129 -0
  325. package/dist/physics/energy/store.d.mts +63 -0
  326. package/dist/physics/energy/store.mjs +108 -0
  327. package/dist/physics/energy/theorem.d.mts +65 -0
  328. package/dist/physics/energy/theorem.mjs +113 -0
  329. package/dist/physics/energy/work.d.mts +114 -0
  330. package/dist/physics/energy/work.mjs +219 -0
  331. package/dist/physics/gravitation/body.d.mts +85 -0
  332. package/dist/physics/gravitation/body.mjs +168 -0
  333. package/dist/physics/gravitation/kepler.d.mts +127 -0
  334. package/dist/physics/gravitation/kepler.mjs +216 -0
  335. package/dist/physics/gravitation/law.d.mts +117 -0
  336. package/dist/physics/gravitation/law.mjs +175 -0
  337. package/dist/physics/gravitation/orbit.d.mts +119 -0
  338. package/dist/physics/gravitation/orbit.mjs +202 -0
  339. package/dist/physics/gravitation/potential.d.mts +114 -0
  340. package/dist/physics/gravitation/potential.mjs +202 -0
  341. package/dist/physics/gravitation/variation.d.mts +97 -0
  342. package/dist/physics/gravitation/variation.mjs +175 -0
  343. package/dist/physics/index.d.mts +35 -0
  344. package/dist/physics/index.mjs +36 -0
  345. package/dist/physics/integral-sweep.d.mts +63 -0
  346. package/dist/physics/integral-sweep.mjs +126 -0
  347. package/dist/physics/kinematics/equations.d.mts +47 -0
  348. package/dist/physics/kinematics/equations.mjs +126 -0
  349. package/dist/physics/kinematics/free-fall.d.mts +53 -0
  350. package/dist/physics/kinematics/free-fall.mjs +71 -0
  351. package/dist/physics/kinematics/given.d.mts +16 -0
  352. package/dist/physics/kinematics/given.mjs +55 -0
  353. package/dist/physics/kinematics/roots.d.mts +41 -0
  354. package/dist/physics/kinematics/roots.mjs +72 -0
  355. package/dist/physics/kinematics/solve.d.mts +52 -0
  356. package/dist/physics/kinematics/solve.mjs +172 -0
  357. package/dist/physics/magnetism/biot-savart.d.mts +161 -0
  358. package/dist/physics/magnetism/biot-savart.mjs +353 -0
  359. package/dist/physics/magnetism/flux.d.mts +94 -0
  360. package/dist/physics/magnetism/flux.mjs +313 -0
  361. package/dist/physics/magnetism/geomagnetism.d.mts +151 -0
  362. package/dist/physics/magnetism/geomagnetism.mjs +184 -0
  363. package/dist/physics/magnetism/index.d.mts +12 -0
  364. package/dist/physics/magnetism/index.mjs +74 -0
  365. package/dist/physics/magnetism/lorentz.d.mts +28 -0
  366. package/dist/physics/magnetism/lorentz.mjs +88 -0
  367. package/dist/physics/magnetism/magnetic-force.d.mts +102 -0
  368. package/dist/physics/magnetism/magnetic-force.mjs +169 -0
  369. package/dist/physics/momentum/collide.d.mts +77 -0
  370. package/dist/physics/momentum/collide.mjs +115 -0
  371. package/dist/physics/momentum/impulse.d.mts +89 -0
  372. package/dist/physics/momentum/impulse.mjs +159 -0
  373. package/dist/physics/momentum/planar.d.mts +60 -0
  374. package/dist/physics/momentum/planar.mjs +110 -0
  375. package/dist/physics/projectile.d.mts +107 -0
  376. package/dist/physics/projectile.mjs +185 -0
  377. package/dist/physics/rotation/angular.d.mts +85 -0
  378. package/dist/physics/rotation/angular.mjs +130 -0
  379. package/dist/physics/rotation/circular.d.mts +79 -0
  380. package/dist/physics/rotation/circular.mjs +131 -0
  381. package/dist/physics/rotation/inertia.d.mts +164 -0
  382. package/dist/physics/rotation/inertia.mjs +332 -0
  383. package/dist/physics/rotation/torque.d.mts +65 -0
  384. package/dist/physics/rotation/torque.mjs +134 -0
  385. package/dist/physics/vectors.d.mts +64 -0
  386. package/dist/physics/vectors.mjs +114 -0
  387. package/dist/quantity/index.d.mts +119 -0
  388. package/dist/quantity/index.mjs +417 -0
  389. package/dist/relation/derive.d.mts +74 -0
  390. package/dist/relation/derive.mjs +73 -0
  391. package/dist/relation/index.d.mts +56 -0
  392. package/dist/relation/index.mjs +234 -0
  393. package/dist/scene/evaluators.mjs +1 -1
  394. package/dist/sim/thermal.mjs +45 -20
  395. package/dist/thermo/calorimetry.d.mts +207 -0
  396. package/dist/thermo/calorimetry.mjs +345 -0
  397. package/dist/thermo/cycles.d.mts +142 -0
  398. package/dist/thermo/cycles.mjs +256 -0
  399. package/dist/thermo/entropy.d.mts +87 -0
  400. package/dist/thermo/entropy.mjs +140 -0
  401. package/dist/thermo/expansion.d.mts +130 -0
  402. package/dist/thermo/expansion.mjs +178 -0
  403. package/dist/thermo/gas.d.mts +197 -0
  404. package/dist/thermo/gas.mjs +279 -0
  405. package/dist/thermo/heat-transfer.d.mts +164 -0
  406. package/dist/thermo/heat-transfer.mjs +217 -0
  407. package/dist/thermo/index.d.mts +9 -82
  408. package/dist/thermo/index.mjs +9 -132
  409. package/dist/thermo/processes.d.mts +95 -0
  410. package/dist/thermo/processes.mjs +154 -0
  411. package/dist/thermo/temperature.d.mts +174 -0
  412. package/dist/thermo/temperature.mjs +236 -0
  413. package/dist/waves/damping.d.mts +224 -0
  414. package/dist/waves/damping.mjs +317 -0
  415. package/dist/waves/doppler.d.mts +72 -0
  416. package/dist/waves/doppler.mjs +125 -0
  417. package/dist/waves/index.d.mts +10 -0
  418. package/dist/waves/index.mjs +10 -0
  419. package/dist/waves/pendulum.d.mts +130 -0
  420. package/dist/waves/pendulum.mjs +211 -0
  421. package/dist/waves/pitch.d.mts +125 -0
  422. package/dist/waves/pitch.mjs +158 -0
  423. package/dist/waves/shm.d.mts +170 -0
  424. package/dist/waves/shm.mjs +279 -0
  425. package/dist/waves/springs.d.mts +103 -0
  426. package/dist/waves/springs.mjs +176 -0
  427. package/dist/waves/superposition.d.mts +124 -0
  428. package/dist/waves/superposition.mjs +196 -0
  429. package/dist/waves/wave.d.mts +154 -0
  430. package/dist/waves/wave.mjs +178 -0
  431. package/package.json +74 -2
@@ -0,0 +1,108 @@
1
+ import { Structure } from "./molecule.mjs";
2
+
3
+ //#region src/chem/stereo.d.ts
4
+ /**
5
+ * Compare two branches by CIP priority.
6
+ *
7
+ * Returns a negative number when the first outranks the second, positive when the second does, and
8
+ * `undefined` when they cannot be separated within the spheres explored, which for a real molecule
9
+ * means they are the same branch.
10
+ *
11
+ * The comparison walks outward one sphere at a time. At each sphere both branches offer a list of
12
+ * atoms sorted heaviest first; the lists are compared position by position, and the first
13
+ * difference decides it. Only if they are identical does the walk go further out.
14
+ */
15
+ declare function comparePriority(structure: Structure, centre: number, firstAtom: number, secondAtom: number, maxSpheres?: number): number | undefined;
16
+ /**
17
+ * The same comparison, for two branches hanging off DIFFERENT atoms.
18
+ *
19
+ * Needed by the meso check, where the two branches being weighed against each other belong to the
20
+ * two ends of the molecule rather than to one centre. Passing both to {@link comparePriority} with
21
+ * a single centre let each walk escape backwards through the other's parent, so two branches that
22
+ * are plainly the same came out different and no meso form was ever found.
23
+ */
24
+ declare function compareBranches(structure: Structure, firstAtom: number, firstFrom: number, secondAtom: number, secondFrom: number, maxSpheres?: number): number | undefined;
25
+ interface RankedSubstituent {
26
+ readonly atom: number;
27
+ readonly element: string;
28
+ /** 1 is highest priority. */
29
+ readonly rank: number;
30
+ }
31
+ /**
32
+ * The substituents of an atom in priority order, highest first.
33
+ *
34
+ * Returns undefined when two of them cannot be separated, which is the honest answer: a carbon with
35
+ * two identical groups on it has no handedness, and saying so is more useful than an arbitrary
36
+ * ordering that would then produce a confident R or S for a molecule that is neither.
37
+ */
38
+ declare function rankSubstituents(structure: Structure, centre: number): RankedSubstituent[] | undefined;
39
+ interface Stereocentre {
40
+ readonly atom: number;
41
+ readonly substituents: readonly RankedSubstituent[];
42
+ }
43
+ /**
44
+ * Every carbon with four different groups on it.
45
+ *
46
+ * The definition, applied rather than paraphrased. A carbon qualifies when the four things attached
47
+ * to it can all be told apart by the priority rules, which is a stronger statement than "four
48
+ * different atoms" and is why 3-methylhexane has a stereocentre and 3-methylpentane does not: in
49
+ * the second, two of the branches are both ethyl.
50
+ */
51
+ declare function stereocentres(structure: Structure): Stereocentre[];
52
+ /**
53
+ * How many stereoisomers a molecule has, from its stereocentre count.
54
+ *
55
+ * Two arrangements at each centre, independently, so 2^n. This is the upper bound: see
56
+ * {@link stereoisomerCount} for the number a molecule with an internal mirror plane actually has.
57
+ */
58
+ declare const maximumStereoisomers: (centres: number) => number;
59
+ interface StereoisomerCount {
60
+ readonly centres: number;
61
+ /** Two arrangements at each centre, independently. */
62
+ readonly maximum: number;
63
+ /** What the molecule actually has. */
64
+ readonly actual: number;
65
+ /** True when one arrangement is its own mirror image and so is not a separate substance. */
66
+ readonly hasMeso: boolean;
67
+ readonly because: string;
68
+ }
69
+ /**
70
+ * How many stereoisomers a molecule really has.
71
+ *
72
+ * The rule of 2^n over-counts whenever the molecule has an internal mirror plane. Tartaric acid has
73
+ * two stereocentres and three isomers, not four: the arrangement with one centre left-handed and
74
+ * the other right-handed is superimposable on its own reflection, so the two that 2^n counts
75
+ * separately are one substance, and that substance is not optically active at all.
76
+ *
77
+ * Detected by asking whether the centres are mirror images of one another, which is checkable with
78
+ * the machinery already here: the branches leading away from each centre have to be
79
+ * indistinguishable, and indistinguishable is exactly what {@link comparePriority} reports when it
80
+ * cannot separate two branches.
81
+ *
82
+ * Restricted to the two-centre case, which is the one syllabuses set. A molecule with more centres
83
+ * and partial symmetry needs a full search over configurations, and this reports the maximum for
84
+ * those rather than guessing.
85
+ */
86
+ declare function stereoisomerCount(structure: Structure): StereoisomerCount;
87
+ type DoubleBondShape = 'E' | 'Z';
88
+ interface DoubleBondStereo {
89
+ readonly a: number;
90
+ readonly b: number;
91
+ /** The higher-priority substituent on each carbon. */
92
+ readonly higherOnA: number;
93
+ readonly higherOnB: number;
94
+ }
95
+ /**
96
+ * Double bonds that can show E/Z, with the higher-priority group on each end identified.
97
+ *
98
+ * A double bond has a shape worth naming only when BOTH its carbons carry two different groups. If
99
+ * either end has two of the same thing, swapping them changes nothing and there is only one
100
+ * compound, which is why 1,1-dichloroethene has no isomers and 1,2-dichloroethene has two.
101
+ *
102
+ * Which arrangement is E and which is Z cannot be read off the connection table: it depends on
103
+ * where the groups actually are in space, which a graph does not record. So this reports WHICH
104
+ * group wins on each end, and the geometry has to say the rest.
105
+ */
106
+ declare function stereogenicDoubleBonds(structure: Structure): DoubleBondStereo[];
107
+ //#endregion
108
+ export { DoubleBondShape, DoubleBondStereo, RankedSubstituent, Stereocentre, StereoisomerCount, compareBranches, comparePriority, maximumStereoisomers, rankSubstituents, stereocentres, stereogenicDoubleBonds, stereoisomerCount };
@@ -0,0 +1,286 @@
1
+ import { elementBySymbol } from "../atomic/elements.mjs";
2
+ import { bondsAt, implicitHydrogens, otherEnd } from "./molecule.mjs";
3
+
4
+ //#region src/chem/stereo.ts
5
+ /**
6
+ * Stereochemistry: which carbons have a handedness, and which way round each one is.
7
+ *
8
+ * ## The question, and why ranking is the whole of it
9
+ *
10
+ * Two molecules can have the same atoms joined in the same order and still be different substances,
11
+ * because four different groups around one carbon can be arranged two ways that are mirror images
12
+ * and cannot be superimposed. Telling those two apart needs a rule for which group outranks which,
13
+ * and that rule is the Cahn-Ingold-Prelog priority.
14
+ *
15
+ * Almost every treatment gives the rule as "highest atomic number first, and if there is a tie,
16
+ * look further out". The second half is where all the difficulty lives and it is where textbooks
17
+ * stop. Looking further out means comparing two whole branches, and the comparison has a definite
18
+ * shape: gather the atoms at distance one from each branch, sort them heaviest first, compare the
19
+ * two lists; if they match, gather distance two, and so on. It is a breadth-first comparison of
20
+ * trees, and written that way it is neither vague nor hard.
21
+ *
22
+ * {@link comparePriority} does exactly that, so a learner can be shown the sphere at which two
23
+ * branches finally differed rather than being told the answer.
24
+ *
25
+ * ## Double bonds are duplicated, which is the part that looks like a trick
26
+ *
27
+ * A doubly bonded oxygen counts twice. That is not a convention invented to break ties: the rule is
28
+ * that an atom joined by a double bond is treated as joined to two of that atom, because a double
29
+ * bond is two connections. So the carbon of an aldehyde carries (O, O, H) and the carbon of an
30
+ * alcohol carries (O, H, H), and the aldehyde outranks it for a reason rather than by decree.
31
+ *
32
+ * ## What this covers, and what it refuses
33
+ *
34
+ * Tetrahedral carbon centres, and double bonds for E/Z. The priority comparison explores outward
35
+ * through the whole molecule, so it settles the cases that matter at this level.
36
+ *
37
+ * It does NOT implement the auxiliary descriptors CIP needs for rings that are symmetric until
38
+ * several spheres out, or for deciding between two branches that are identical in constitution and
39
+ * differ only in their own stereochemistry. Those exist, they are genuinely intricate, and a
40
+ * kernel that guessed at them would be wrong quietly. {@link comparePriority} returns undefined
41
+ * where it cannot separate two branches, and everything above it reports that rather than picking.
42
+ *
43
+ * Pure: no React, no pixels.
44
+ */
45
+ /** Proton number, which is what "higher atomic number wins" is comparing. */
46
+ const protons = (element) => elementBySymbol(element)?.Z ?? 0;
47
+ /**
48
+ * The atoms one step out from `atom`, coming from `cameFrom`, heaviest first.
49
+ *
50
+ * Doubly and triply bonded neighbours appear as many times as the bond order, which is the
51
+ * duplication rule. Implicit hydrogens are included, because a hydrogen is a substituent and
52
+ * leaving it out would make a CH2 look like a CH.
53
+ */
54
+ function neighbours(structure, atom, cameFrom) {
55
+ const out = [];
56
+ for (const bond of bondsAt(structure, atom)) {
57
+ const other = otherEnd(bond, atom);
58
+ const element = structure.atoms[other].element;
59
+ const order = bond.aromatic ? 2 : bond.order;
60
+ if (other !== cameFrom) out.push({
61
+ element,
62
+ id: other
63
+ });
64
+ for (let k = 1; k < order; k += 1) out.push({
65
+ element,
66
+ id: void 0
67
+ });
68
+ }
69
+ for (let k = 0; k < implicitHydrogens(structure, atom); k += 1) out.push({
70
+ element: "H",
71
+ id: void 0
72
+ });
73
+ return out.sort((a, b) => protons(b.element) - protons(a.element));
74
+ }
75
+ /**
76
+ * Compare two branches by CIP priority.
77
+ *
78
+ * Returns a negative number when the first outranks the second, positive when the second does, and
79
+ * `undefined` when they cannot be separated within the spheres explored, which for a real molecule
80
+ * means they are the same branch.
81
+ *
82
+ * The comparison walks outward one sphere at a time. At each sphere both branches offer a list of
83
+ * atoms sorted heaviest first; the lists are compared position by position, and the first
84
+ * difference decides it. Only if they are identical does the walk go further out.
85
+ */
86
+ function comparePriority(structure, centre, firstAtom, secondAtom, maxSpheres = 12) {
87
+ return compareBranches(structure, firstAtom, centre, secondAtom, centre, maxSpheres);
88
+ }
89
+ /**
90
+ * The same comparison, for two branches hanging off DIFFERENT atoms.
91
+ *
92
+ * Needed by the meso check, where the two branches being weighed against each other belong to the
93
+ * two ends of the molecule rather than to one centre. Passing both to {@link comparePriority} with
94
+ * a single centre let each walk escape backwards through the other's parent, so two branches that
95
+ * are plainly the same came out different and no meso form was ever found.
96
+ */
97
+ function compareBranches(structure, firstAtom, firstFrom, secondAtom, secondFrom, maxSpheres = 12) {
98
+ const first = protons(structure.atoms[firstAtom].element);
99
+ const second = protons(structure.atoms[secondAtom].element);
100
+ if (first !== second) return second - first;
101
+ let frontA = [{
102
+ atom: firstAtom,
103
+ cameFrom: firstFrom
104
+ }];
105
+ let frontB = [{
106
+ atom: secondAtom,
107
+ cameFrom: secondFrom
108
+ }];
109
+ for (let sphere = 0; sphere < maxSpheres; sphere += 1) {
110
+ if (frontA.length === 0 && frontB.length === 0) return void 0;
111
+ const expand = (front) => {
112
+ const list = [];
113
+ const next = [];
114
+ for (const node of front) for (const n of neighbours(structure, node.atom, node.cameFrom)) {
115
+ list.push(n.element);
116
+ if (n.id !== void 0) next.push({
117
+ atom: n.id,
118
+ cameFrom: node.atom
119
+ });
120
+ }
121
+ return {
122
+ list,
123
+ next
124
+ };
125
+ };
126
+ const a = expand(frontA);
127
+ const b = expand(frontB);
128
+ const sortedA = [...a.list].sort((x, y) => protons(y) - protons(x));
129
+ const sortedB = [...b.list].sort((x, y) => protons(y) - protons(x));
130
+ const length = Math.max(sortedA.length, sortedB.length);
131
+ for (let k = 0; k < length; k += 1) {
132
+ const pa = protons(sortedA[k] ?? "");
133
+ const pb = protons(sortedB[k] ?? "");
134
+ if (pa !== pb) return pb - pa;
135
+ }
136
+ frontA = a.next;
137
+ frontB = b.next;
138
+ }
139
+ }
140
+ /**
141
+ * The substituents of an atom in priority order, highest first.
142
+ *
143
+ * Returns undefined when two of them cannot be separated, which is the honest answer: a carbon with
144
+ * two identical groups on it has no handedness, and saying so is more useful than an arbitrary
145
+ * ordering that would then produce a confident R or S for a molecule that is neither.
146
+ */
147
+ function rankSubstituents(structure, centre) {
148
+ const attached = bondsAt(structure, centre).map((bond) => otherEnd(bond, centre));
149
+ const hydrogens = implicitHydrogens(structure, centre);
150
+ if (attached.length + hydrogens !== 4) return void 0;
151
+ const sorted = [...attached];
152
+ for (let i = 0; i < sorted.length; i += 1) for (let j = i + 1; j < sorted.length; j += 1) {
153
+ const order = comparePriority(structure, centre, sorted[i], sorted[j]);
154
+ if (order === void 0) return void 0;
155
+ if (order > 0) [sorted[i], sorted[j]] = [sorted[j], sorted[i]];
156
+ }
157
+ const ranked = sorted.map((atom, index) => ({
158
+ atom,
159
+ element: structure.atoms[atom].element,
160
+ rank: index + 1
161
+ }));
162
+ if (hydrogens === 1) return ranked;
163
+ if (hydrogens === 0) return ranked;
164
+ }
165
+ /**
166
+ * Every carbon with four different groups on it.
167
+ *
168
+ * The definition, applied rather than paraphrased. A carbon qualifies when the four things attached
169
+ * to it can all be told apart by the priority rules, which is a stronger statement than "four
170
+ * different atoms" and is why 3-methylhexane has a stereocentre and 3-methylpentane does not: in
171
+ * the second, two of the branches are both ethyl.
172
+ */
173
+ function stereocentres(structure) {
174
+ const found = [];
175
+ for (const atom of structure.atoms) {
176
+ if (atom.element !== "C" || atom.aromatic) continue;
177
+ const substituents = rankSubstituents(structure, atom.id);
178
+ if (substituents) found.push({
179
+ atom: atom.id,
180
+ substituents
181
+ });
182
+ }
183
+ return found;
184
+ }
185
+ /**
186
+ * How many stereoisomers a molecule has, from its stereocentre count.
187
+ *
188
+ * Two arrangements at each centre, independently, so 2^n. This is the upper bound: see
189
+ * {@link stereoisomerCount} for the number a molecule with an internal mirror plane actually has.
190
+ */
191
+ const maximumStereoisomers = (centres) => 2 ** centres;
192
+ /**
193
+ * Whether two stereocentres are mirror images of each other through the middle of the molecule.
194
+ *
195
+ * True when the branches leading away from each centre are the same on both sides, which is what
196
+ * makes the molecule superimposable on its own reflection.
197
+ */
198
+ function centresArePaired(structure, first, second) {
199
+ const branchesOf = (centre, away) => bondsAt(structure, centre).map((bond) => otherEnd(bond, centre)).filter((id) => id !== away);
200
+ const a = branchesOf(first, second);
201
+ const b = branchesOf(second, first);
202
+ if (a.length !== b.length) return false;
203
+ const spare = [...b];
204
+ for (const branch of a) {
205
+ const match = spare.findIndex((other) => compareBranches(structure, branch, first, other, second) === void 0);
206
+ if (match === -1) return false;
207
+ spare.splice(match, 1);
208
+ }
209
+ return true;
210
+ }
211
+ /**
212
+ * How many stereoisomers a molecule really has.
213
+ *
214
+ * The rule of 2^n over-counts whenever the molecule has an internal mirror plane. Tartaric acid has
215
+ * two stereocentres and three isomers, not four: the arrangement with one centre left-handed and
216
+ * the other right-handed is superimposable on its own reflection, so the two that 2^n counts
217
+ * separately are one substance, and that substance is not optically active at all.
218
+ *
219
+ * Detected by asking whether the centres are mirror images of one another, which is checkable with
220
+ * the machinery already here: the branches leading away from each centre have to be
221
+ * indistinguishable, and indistinguishable is exactly what {@link comparePriority} reports when it
222
+ * cannot separate two branches.
223
+ *
224
+ * Restricted to the two-centre case, which is the one syllabuses set. A molecule with more centres
225
+ * and partial symmetry needs a full search over configurations, and this reports the maximum for
226
+ * those rather than guessing.
227
+ */
228
+ function stereoisomerCount(structure) {
229
+ const centres = stereocentres(structure);
230
+ const maximum = maximumStereoisomers(centres.length);
231
+ if (centres.length !== 2) return {
232
+ centres: centres.length,
233
+ maximum,
234
+ actual: maximum,
235
+ hasMeso: false,
236
+ because: centres.length < 2 ? "with fewer than two stereocentres there is no internal mirror plane to lose an isomer to" : "more than two centres are not searched for internal symmetry here, so this is the upper bound"
237
+ };
238
+ const paired = centresArePaired(structure, centres[0].atom, centres[1].atom);
239
+ return {
240
+ centres: 2,
241
+ maximum,
242
+ actual: paired ? maximum - 1 : maximum,
243
+ hasMeso: paired,
244
+ because: paired ? "the two centres carry the same groups, so the arrangement with one of each handedness is superimposable on its own mirror image: that meso form is one substance rather than two, and it is not optically active" : "the two centres carry different groups, so every one of the four arrangements is a distinct substance"
245
+ };
246
+ }
247
+ /**
248
+ * Double bonds that can show E/Z, with the higher-priority group on each end identified.
249
+ *
250
+ * A double bond has a shape worth naming only when BOTH its carbons carry two different groups. If
251
+ * either end has two of the same thing, swapping them changes nothing and there is only one
252
+ * compound, which is why 1,1-dichloroethene has no isomers and 1,2-dichloroethene has two.
253
+ *
254
+ * Which arrangement is E and which is Z cannot be read off the connection table: it depends on
255
+ * where the groups actually are in space, which a graph does not record. So this reports WHICH
256
+ * group wins on each end, and the geometry has to say the rest.
257
+ */
258
+ function stereogenicDoubleBonds(structure) {
259
+ const found = [];
260
+ for (const bond of structure.bonds) {
261
+ if (bond.order !== 2 || bond.aromatic) continue;
262
+ const higher = (end, far) => {
263
+ const groups = bondsAt(structure, end).map((b) => otherEnd(b, end)).filter((id) => id !== far);
264
+ const hydrogens = implicitHydrogens(structure, end);
265
+ if (groups.length + hydrogens !== 2) return void 0;
266
+ if (groups.length === 1 && hydrogens === 1) return groups[0];
267
+ if (groups.length !== 2) return void 0;
268
+ const order = comparePriority(structure, end, groups[0], groups[1]);
269
+ if (order === void 0) return void 0;
270
+ return order < 0 ? groups[0] : groups[1];
271
+ };
272
+ const higherOnA = higher(bond.a, bond.b);
273
+ const higherOnB = higher(bond.b, bond.a);
274
+ if (higherOnA === void 0 || higherOnB === void 0) continue;
275
+ found.push({
276
+ a: bond.a,
277
+ b: bond.b,
278
+ higherOnA,
279
+ higherOnB
280
+ });
281
+ }
282
+ return found;
283
+ }
284
+
285
+ //#endregion
286
+ export { compareBranches, comparePriority, maximumStereoisomers, rankSubstituents, stereocentres, stereogenicDoubleBonds, stereoisomerCount };
@@ -0,0 +1,95 @@
1
+ import { BalancedEquation } from "./equation.mjs";
2
+
3
+ //#region src/chem/stoichiometry.d.ts
4
+ /** How much of a substance is present, in whichever way it was measured. */
5
+ interface Amount {
6
+ /** Grams. */
7
+ readonly mass?: number;
8
+ /** Moles, if they are known directly. */
9
+ readonly moles?: number;
10
+ /** Volume in cubic decimetres, for something in solution. */
11
+ readonly volumeDm3?: number;
12
+ /** Concentration in mol per cubic decimetre, used with the volume. */
13
+ readonly concentration?: number;
14
+ }
15
+ /** Moles of a substance from however it was given. */
16
+ declare function molesOf(formula: string, amount: Amount): number;
17
+ interface ReactantState {
18
+ readonly formula: string;
19
+ readonly coefficient: number;
20
+ readonly moles: number;
21
+ /**
22
+ * Moles available divided by the coefficient: how many times the equation can run on this one.
23
+ *
24
+ * The number the whole calculation turns on, and the one a mass comparison never reaches.
25
+ */
26
+ readonly equationRuns: number;
27
+ readonly limiting: boolean;
28
+ /** Moles of this reactant left when the limiting one is spent. */
29
+ readonly leftOver: number;
30
+ }
31
+ interface ProductState {
32
+ readonly formula: string;
33
+ readonly coefficient: number;
34
+ readonly moles: number;
35
+ readonly mass: number;
36
+ }
37
+ interface Reaction {
38
+ readonly equation: BalancedEquation;
39
+ /** How many times the equation as written can proceed. */
40
+ readonly runs: number;
41
+ readonly reactants: readonly ReactantState[];
42
+ readonly products: readonly ProductState[];
43
+ readonly limiting: ReactantState;
44
+ }
45
+ /**
46
+ * Work a reaction out from the amounts given.
47
+ *
48
+ * The equation is balanced here rather than taken on trust, because every mole ratio below depends
49
+ * on the coefficients and an unbalanced equation would make all of them confidently wrong.
50
+ */
51
+ declare function react(equation: string, amounts: Readonly<Record<string, Amount>>): Reaction;
52
+ /** The most of a product the equation allows, in grams. */
53
+ declare function theoreticalYield(reaction: Reaction, product: string): number;
54
+ interface YieldReport {
55
+ /** Measured over theoretical, as a percentage. Reported even when it is impossible. */
56
+ readonly percent: number;
57
+ /** Why this figure cannot be a yield, when it cannot be. */
58
+ readonly impossible?: string;
59
+ }
60
+ /**
61
+ * The measured mass as a percentage of the theoretical one, whatever it comes to.
62
+ *
63
+ * Reports rather than refuses, because a figure above a hundred per cent is a real thing that comes
64
+ * out of a real balance and is the single most useful measurement in the topic: it is the one that
65
+ * tells you something is wrong with the sample. A lab teaching that has to be able to SHOW 112 per
66
+ * cent before asking what it means.
67
+ *
68
+ * What it must not do is call that a yield. So the number comes back with the reason it is not one
69
+ * attached, and {@link percentageYield} is the strict form built on this for the places where the
70
+ * value has to be legitimate.
71
+ */
72
+ declare function apparentYield(theoretical: number, measured: number): YieldReport;
73
+ /**
74
+ * The fraction of the theoretical yield actually obtained, as a percentage.
75
+ *
76
+ * Refuses anything above a hundred. A flask cannot produce more than the equation allows, so a
77
+ * figure above it is evidence about the sample rather than about the reaction, and reporting it as
78
+ * a yield hides the one piece of information the number actually carries. Use {@link apparentYield}
79
+ * where that figure needs to be shown rather than accepted.
80
+ */
81
+ declare function percentageYield(theoretical: number, measured: number): number;
82
+ /**
83
+ * The mass of one reactant needed to use up a given amount of another exactly.
84
+ *
85
+ * What a preparation asks: how much of this do I weigh out so nothing is wasted.
86
+ */
87
+ declare function amountNeeded(equation: string, have: {
88
+ formula: string;
89
+ amount: Amount;
90
+ }, want: string): {
91
+ moles: number;
92
+ mass: number;
93
+ };
94
+ //#endregion
95
+ export { Amount, ProductState, ReactantState, Reaction, YieldReport, amountNeeded, apparentYield, molesOf, percentageYield, react, theoreticalYield };
@@ -0,0 +1,145 @@
1
+ import { molarMass } from "./formula.mjs";
2
+ import { balance } from "./equation.mjs";
3
+
4
+ //#region src/chem/stoichiometry.ts
5
+ /**
6
+ * How much of what: limiting reagent, theoretical yield, and what is left over.
7
+ *
8
+ * ## The whole subject is one division
9
+ *
10
+ * Every quantitative question reduces to the same move. Convert what you have into moles, divide
11
+ * each by its coefficient, and whichever comes out smallest runs out first. That ratio, the moles
12
+ * available per unit of equation, is the only number that matters: it says how many times the
13
+ * reaction as written can proceed, and everything else is that number multiplied by a coefficient.
14
+ *
15
+ * So {@link react} computes it once and reads every answer off it. There is no separate method for
16
+ * limiting reagent, for yield, for excess: they are three questions about one quantity.
17
+ *
18
+ * ## The limiting reagent is not the one there is least of
19
+ *
20
+ * The most common mistake in the topic, and it is a mistake about what "least" means. Ten grams of
21
+ * hydrogen and twenty-five of oxygen: there is less hydrogen by mass and far more by moles, and the
22
+ * oxygen runs out first because the equation needs two hydrogens for every oxygen. Comparing masses
23
+ * answers a question nobody asked, and comparing moles without dividing by the coefficients answers
24
+ * a different wrong one.
25
+ *
26
+ * ## Yield is measured, and the theoretical figure is not a prediction of it
27
+ *
28
+ * The theoretical yield is what the equation permits. What comes out of a flask is always less:
29
+ * some product stays in solution, some is lost in transfer, the reaction may not finish. So
30
+ * {@link percentageYield} takes a measured mass and compares, and a yield above a hundred per cent
31
+ * is refused rather than reported, because it means the product is wet or impure and the useful
32
+ * answer is to say so.
33
+ *
34
+ * Pure: no React, no pixels.
35
+ */
36
+ /** Moles of a substance from however it was given. */
37
+ function molesOf(formula, amount) {
38
+ if (amount.moles !== void 0) return amount.moles;
39
+ if (amount.mass !== void 0) return amount.mass / molarMass(formula);
40
+ if (amount.volumeDm3 !== void 0 && amount.concentration !== void 0) return amount.volumeDm3 * amount.concentration;
41
+ throw new Error(`not enough to work out the moles of ${formula}: give a mass, a number of moles, or a volume together with a concentration`);
42
+ }
43
+ /**
44
+ * Work a reaction out from the amounts given.
45
+ *
46
+ * The equation is balanced here rather than taken on trust, because every mole ratio below depends
47
+ * on the coefficients and an unbalanced equation would make all of them confidently wrong.
48
+ */
49
+ function react(equation, amounts) {
50
+ const balanced = balance(equation);
51
+ const named = new Set(Object.keys(amounts));
52
+ const missing = balanced.reactants.filter((r) => !named.has(r.formula));
53
+ if (missing.length > 0) throw new Error(`no amount given for ${missing.map((r) => r.formula).join(" or ")}: every reactant needs one, since the limiting one cannot be found without them all`);
54
+ const withRuns = balanced.reactants.map((term) => {
55
+ const moles = molesOf(term.formula, amounts[term.formula]);
56
+ return {
57
+ term,
58
+ moles,
59
+ equationRuns: moles / term.coefficient
60
+ };
61
+ });
62
+ const runs = Math.min(...withRuns.map((r) => r.equationRuns));
63
+ const limitingRuns = runs;
64
+ const reactants = withRuns.map(({ term, moles, equationRuns }) => ({
65
+ formula: term.formula,
66
+ coefficient: term.coefficient,
67
+ moles,
68
+ equationRuns,
69
+ limiting: equationRuns === limitingRuns,
70
+ leftOver: moles - limitingRuns * term.coefficient
71
+ }));
72
+ return {
73
+ equation: balanced,
74
+ runs,
75
+ reactants,
76
+ products: balanced.products.map((term) => ({
77
+ formula: term.formula,
78
+ coefficient: term.coefficient,
79
+ moles: runs * term.coefficient,
80
+ mass: runs * term.coefficient * molarMass(term.formula)
81
+ })),
82
+ limiting: reactants.find((r) => r.limiting)
83
+ };
84
+ }
85
+ /** The most of a product the equation allows, in grams. */
86
+ function theoreticalYield(reaction, product) {
87
+ const found = reaction.products.find((p) => p.formula === product);
88
+ if (!found) throw new Error(`${product} is not a product of this reaction: it makes ${reaction.products.map((p) => p.formula).join(", ")}`);
89
+ return found.mass;
90
+ }
91
+ /**
92
+ * The measured mass as a percentage of the theoretical one, whatever it comes to.
93
+ *
94
+ * Reports rather than refuses, because a figure above a hundred per cent is a real thing that comes
95
+ * out of a real balance and is the single most useful measurement in the topic: it is the one that
96
+ * tells you something is wrong with the sample. A lab teaching that has to be able to SHOW 112 per
97
+ * cent before asking what it means.
98
+ *
99
+ * What it must not do is call that a yield. So the number comes back with the reason it is not one
100
+ * attached, and {@link percentageYield} is the strict form built on this for the places where the
101
+ * value has to be legitimate.
102
+ */
103
+ function apparentYield(theoretical, measured) {
104
+ if (theoretical <= 0) throw new Error("a theoretical yield of zero has no percentage");
105
+ if (measured < 0) throw new Error("a measured mass cannot be negative");
106
+ const percent = measured / theoretical * 100;
107
+ if (percent > 100.0001) return {
108
+ percent,
109
+ impossible: `${measured} g is ${percent.toFixed(1)} per cent of the ${theoretical.toFixed(3)} g the equation allows. A reaction cannot make more than its theoretical maximum, so the product is wet or impure, or the balance is wrong.`
110
+ };
111
+ return { percent };
112
+ }
113
+ /**
114
+ * The fraction of the theoretical yield actually obtained, as a percentage.
115
+ *
116
+ * Refuses anything above a hundred. A flask cannot produce more than the equation allows, so a
117
+ * figure above it is evidence about the sample rather than about the reaction, and reporting it as
118
+ * a yield hides the one piece of information the number actually carries. Use {@link apparentYield}
119
+ * where that figure needs to be shown rather than accepted.
120
+ */
121
+ function percentageYield(theoretical, measured) {
122
+ const report = apparentYield(theoretical, measured);
123
+ if (report.impossible) throw new Error(report.impossible);
124
+ return report.percent;
125
+ }
126
+ /**
127
+ * The mass of one reactant needed to use up a given amount of another exactly.
128
+ *
129
+ * What a preparation asks: how much of this do I weigh out so nothing is wasted.
130
+ */
131
+ function amountNeeded(equation, have, want) {
132
+ const balanced = balance(equation);
133
+ const from = balanced.reactants.find((r) => r.formula === have.formula);
134
+ const to = balanced.reactants.find((r) => r.formula === want);
135
+ if (!from) throw new Error(`${have.formula} is not a reactant in this equation`);
136
+ if (!to) throw new Error(`${want} is not a reactant in this equation`);
137
+ const moles = molesOf(have.formula, have.amount) / from.coefficient * to.coefficient;
138
+ return {
139
+ moles,
140
+ mass: moles * molarMass(want)
141
+ };
142
+ }
143
+
144
+ //#endregion
145
+ export { amountNeeded, apparentYield, molesOf, percentageYield, react, theoreticalYield };