@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,163 @@
1
+ import { periodOf, valenceElectronsOf } from "../atomic/periodic.mjs";
2
+ import { elementBySymbol } from "../atomic/elements.mjs";
3
+ import { electronegativity } from "../atomic/properties.mjs";
4
+
5
+ //#region src/chem/lewis.ts
6
+ /**
7
+ * The electron budget of a species: how many bonding pairs and how many lone pairs.
8
+ *
9
+ * ## The counting, stated once
10
+ *
11
+ * Every shape question reduces to two numbers, and both come out of one budget:
12
+ *
13
+ * 1. total valence electrons = the valence electrons of every atom, plus one for each unit of
14
+ * negative charge and minus one for each unit of positive charge;
15
+ * 2. one sigma bond to each ligand uses two of them;
16
+ * 3. each non-hydrogen ligand then takes six more to complete its own octet (hydrogen takes none,
17
+ * because its bonding pair already fills its shell);
18
+ * 4. whatever is left belongs to the central atom, as lone pairs.
19
+ *
20
+ * That is the whole method, and it gets SF4, XeF2, ClF3, NH4+ and SO4 right with no special cases.
21
+ *
22
+ * ## Multiple bonds, decided by formal charge
23
+ *
24
+ * Where the central atom ends up short of an octet, that gap is what multiple bonding closes. The
25
+ * question is whether it actually does, and the answer is not in the electron count: carbon dioxide
26
+ * closes its gap completely and boron trifluoride cannot close it at all.
27
+ *
28
+ * Formal charge settles it, with electronegativity as the guard. Every pi bond moves the central
29
+ * atom one step toward zero and the donating outer atom one step away, so pi bonds are added while
30
+ * that trade improves the structure and stopped when it does not:
31
+ *
32
+ * carbon dioxide starts as C(+2) with two O(-1), and two pi bonds take all three to zero;
33
+ * boron trifluoride starts at B(0) with three F(0), so no pi bond improves anything, and one
34
+ * would push fluorine, the most electronegative element there is, to +1.
35
+ *
36
+ * That is the whole difference between them, and it needs no special case for either. A second-
37
+ * period centre is additionally capped at an octet, which is why nitrate gets exactly one double
38
+ * bond and leaves its nitrogen at +1 rather than reaching zero.
39
+ *
40
+ * None of it affects the shape. A double bond points the same way as the single bond underneath it
41
+ * and is one region of electron density, which is why carbon dioxide is linear.
42
+ *
43
+ * ## Where the valence electron counts come from
44
+ *
45
+ * From the atomic engine, not from a table typed out here. An element's valence electron count is
46
+ * already a consequence of its configuration, and duplicating it would let the two disagree. So
47
+ * oxygen having six and xenon having eight is derived in one place and used here.
48
+ *
49
+ * ## On the octet rule and its exceptions
50
+ *
51
+ * The octet rule is a useful summary of the second period and is broken routinely below it. This
52
+ * engine does not enforce it: it counts electrons and REPORTS whether the central atom ended up
53
+ * with fewer than eight, exactly eight, or more. Boron trifluoride comes out with six and sulfur
54
+ * hexafluoride with twelve, and both are correct, so a rule that forbade them would be a rule that
55
+ * had to be switched off for the interesting cases.
56
+ *
57
+ * Expansion beyond eight needs d orbitals close enough in energy to be used, which is why it starts
58
+ * in the third period. {@link LewisCount.canExpand} says whether the central atom is in a position
59
+ * to do it, so a count that expands a second-period atom can be flagged as impossible rather than
60
+ * reported as fact.
61
+ *
62
+ * Pure: no React, no pixels.
63
+ */
64
+ /** Valence electrons of an element, from its configuration. */
65
+ function valenceElectronsFor(symbol) {
66
+ const element = elementBySymbol(symbol);
67
+ if (!element) throw new Error(`no element with symbol "${symbol}"`);
68
+ return valenceElectronsOf(element.Z);
69
+ }
70
+ /** Electrons a ligand needs beyond its bonding pair to fill its own shell. */
71
+ function ligandDemand(symbol) {
72
+ return symbol === "H" ? 0 : 6;
73
+ }
74
+ /**
75
+ * Work out the electron budget of a species.
76
+ *
77
+ * Returns the count rather than a drawing: where the electrons GO on the page is a layout decision,
78
+ * and how many there are is chemistry.
79
+ */
80
+ function lewisCount(centre) {
81
+ const centralValence = valenceElectronsFor(centre.central);
82
+ const totalValenceElectrons = centralValence + centre.bonded.reduce((total, l) => total + valenceElectronsFor(l.element) * l.count, 0) - centre.charge;
83
+ const bondingPairs = centre.bondedCount;
84
+ const usedBySigma = 2 * bondingPairs;
85
+ const demandedByLigands = centre.bonded.reduce((total, l) => total + ligandDemand(l.element) * l.count, 0);
86
+ const leftForCentre = totalValenceElectrons - usedBySigma - demandedByLigands;
87
+ const lonePairs = Math.max(0, Math.floor(leftForCentre / 2));
88
+ const stericNumber = bondingPairs + lonePairs;
89
+ const singleBondElectrons = 2 * bondingPairs + 2 * lonePairs;
90
+ const period = periodOf(elementBySymbol(centre.central).Z);
91
+ const canExpand = period >= 3;
92
+ const bondOrders = shareOutPiBonds(centre, {
93
+ centralValence,
94
+ lonePairs,
95
+ bondingPairs,
96
+ singleBondElectrons,
97
+ canExpand
98
+ });
99
+ const piBonds = bondOrders.reduce((total, b) => total + b.order - 1, 0);
100
+ const centralElectrons = singleBondElectrons + 2 * piBonds;
101
+ const octetShortfall = Math.max(0, 8 - centralElectrons);
102
+ const formalCharge = centralValence - 2 * lonePairs - (bondingPairs + piBonds);
103
+ let impossible;
104
+ if (leftForCentre < 0) impossible = `${centre.formula} has ${totalValenceElectrons} valence electrons, which is ${-leftForCentre} short of what its ${bondingPairs} bonds and its outer atoms need: check the formula and the charge`;
105
+ else if (singleBondElectrons > 8 && !canExpand) impossible = `${centre.central} is in period ${period} and has no d subshell available, so it cannot hold the ${singleBondElectrons} electrons this arrangement needs`;
106
+ return {
107
+ totalValenceElectrons,
108
+ bondingPairs,
109
+ lonePairs,
110
+ stericNumber,
111
+ piBonds,
112
+ bondOrders,
113
+ centralElectrons,
114
+ octetShortfall,
115
+ formalCharge,
116
+ canExpand,
117
+ ...impossible ? { impossible } : {}
118
+ };
119
+ }
120
+ /** Formal charge on an outer atom holding `pi` extra bonds beyond its single one. */
121
+ const outerFormalCharge = (symbol, pi) => valenceElectronsFor(symbol) - 2 * (3 - pi) - (1 + pi);
122
+ /**
123
+ * Decide how many pi bonds form, and to which outer atoms.
124
+ *
125
+ * Greedy and one bond at a time, because that is what the reasoning actually is: would drawing one
126
+ * more double bond here make the structure better? Better means the central atom's formal charge
127
+ * moves toward zero without pushing a more electronegative neighbour above it.
128
+ *
129
+ * Spread across the outer atoms rather than piled onto one, so carbon dioxide comes out as two
130
+ * double bonds and not as a triple and a single. Both satisfy the counting; only one of them is the
131
+ * molecule.
132
+ */
133
+ function shareOutPiBonds(centre, state) {
134
+ const orders = centre.bonded.flatMap((b) => Array.from({ length: b.count }, () => ({
135
+ element: b.element,
136
+ order: 1
137
+ })));
138
+ const centralPull = electronegativity(elementBySymbol(centre.central).Z);
139
+ for (;;) {
140
+ const piSoFar = orders.reduce((total, b) => total + b.order - 1, 0);
141
+ if (state.centralValence - 2 * state.lonePairs - (state.bondingPairs + piSoFar) <= 0) break;
142
+ if (!state.canExpand && state.singleBondElectrons + 2 * (piSoFar + 1) > 8) break;
143
+ const donor = orders.filter((bond) => {
144
+ if (bond.element === "H" || bond.order >= 4) return false;
145
+ if (outerFormalCharge(bond.element, bond.order) <= 0) return true;
146
+ const donorPull = electronegativity(elementBySymbol(bond.element).Z);
147
+ if (donorPull === void 0 || centralPull === void 0) return false;
148
+ return donorPull <= centralPull;
149
+ }).sort((a, b) => a.order - b.order)[0];
150
+ if (!donor) break;
151
+ donor.order += 1;
152
+ }
153
+ return orders;
154
+ }
155
+ /** Whether the central atom has fewer than eight electrons, eight, or more. */
156
+ function octetStatus(count) {
157
+ if (count.centralElectrons < 8) return "short of an octet";
158
+ if (count.centralElectrons === 8) return "an octet";
159
+ return "an expanded octet";
160
+ }
161
+
162
+ //#endregion
163
+ export { lewisCount, octetStatus, valenceElectronsFor };
@@ -0,0 +1,114 @@
1
+ //#region src/chem/molecular-orbital.d.ts
2
+ /**
3
+ * Molecular orbitals for a diatomic: bond order, and whether the molecule is magnetic.
4
+ *
5
+ * ## What this explains that dot-and-cross cannot
6
+ *
7
+ * Oxygen is paramagnetic. Liquid oxygen sticks to a magnet, which is a thing anyone can watch, and
8
+ * the Lewis structure O=O has every electron neatly paired and predicts the opposite. That failure
9
+ * is the reason molecular orbital theory is taught at all: put the electrons into orbitals that
10
+ * belong to the whole molecule rather than to one atom or one bond, and two of them end up alone in
11
+ * a pair of degenerate antibonding orbitals.
12
+ *
13
+ * So this engine answers two questions a Lewis structure cannot: how strongly the atoms are held
14
+ * together when the answer is not a whole number, and whether the molecule has unpaired electrons.
15
+ *
16
+ * bond order = (bonding electrons - antibonding electrons) / 2
17
+ *
18
+ * A bond order of zero means the molecule does not exist, which is why there is no He2 and no Ne2.
19
+ *
20
+ * ## The crossover, which is the part usually left out
21
+ *
22
+ * The order of the 2p-derived orbitals is not fixed. For the earlier second-period elements the two
23
+ * pi orbitals lie BELOW the sigma; from oxygen onward the sigma drops below the pi. The cause is
24
+ * mixing between the 2s and 2p sigma orbitals, which pushes the sigma up, and it matters most where
25
+ * the 2s and 2p levels are closest together, which is at the left of the period.
26
+ *
27
+ * This is not a detail. Boron's B2 has exactly two electrons to place in that region: with pi
28
+ * lowest they go one into each pi orbital and B2 is paramagnetic, which it is; with sigma lowest
29
+ * they pair up in it and B2 would be diamagnetic, which it is not. So an engine that ignored the
30
+ * crossover would get the right bond order and the wrong magnetism, and the magnetism is the
31
+ * evidence.
32
+ *
33
+ * ## What is covered
34
+ *
35
+ * Diatomics of the first two periods, neutral or charged: H2, He2, Li2 through Ne2, and the
36
+ * heteronuclear and ionic ones built from the same orbitals, so NO, CO, CN- and the oxygen family
37
+ * O2+, O2-, O2 2-. Core electrons are left out: they sit in bonding and antibonding pairs that
38
+ * cancel exactly, so they change no answer and only lengthen the diagram.
39
+ *
40
+ * Pure: no React, no pixels.
41
+ */
42
+ interface MolecularOrbital {
43
+ readonly label: string;
44
+ readonly bonding: boolean;
45
+ /** How many orbitals are at this energy: two for a pi level, one for a sigma. */
46
+ readonly orbitals: number;
47
+ }
48
+ /**
49
+ * Where the sigma made from 2p sits relative to the pair of pi orbitals.
50
+ *
51
+ * Mixing with the 2s sigma pushes the 2p sigma up, and the effect is strongest where 2s and 2p are
52
+ * closest in energy, which is toward the left of the period. So the pi orbitals are lower for the
53
+ * earlier elements and the sigma is lower from oxygen onward.
54
+ */
55
+ declare const S_P_MIXING_NOTE = "The sigma orbital built from 2p is pushed up by mixing with the sigma built from 2s, and that mixing is strongest where the 2s and 2p levels lie closest together, toward the left of the period. So for boron, carbon and nitrogen the two pi orbitals lie below the sigma, and from oxygen onward the sigma drops below them.";
56
+ /** The orbitals in energy order, for a diatomic with this many valence electrons. */
57
+ declare function orbitalSequence(valenceElectrons: number, firstPeriod: boolean): readonly MolecularOrbital[];
58
+ interface Level {
59
+ readonly orbital: MolecularOrbital;
60
+ readonly electrons: number;
61
+ /** Electrons in this level with no partner, by Hund's rule. */
62
+ readonly unpaired: number;
63
+ }
64
+ /**
65
+ * Fill the orbitals from the bottom, singly across a degenerate level before pairing.
66
+ *
67
+ * Hund's rule again, and for the same reason it applies inside an atom: two electrons in one
68
+ * orbital repel, so they spread out while there is anywhere to spread to. It is what leaves oxygen
69
+ * with two unpaired electrons instead of one filled antibonding orbital.
70
+ */
71
+ declare function fillOrbitals(sequence: readonly MolecularOrbital[], electrons: number): {
72
+ levels: Level[];
73
+ unpaired: number;
74
+ unplaced: number;
75
+ };
76
+ type Magnetism = 'paramagnetic' | 'diamagnetic';
77
+ interface DiatomicResult {
78
+ readonly formula: string;
79
+ readonly atoms: readonly string[];
80
+ readonly charge: number;
81
+ /** Valence electrons only: core pairs cancel and change no answer. */
82
+ readonly valenceElectrons: number;
83
+ readonly levels: readonly Level[];
84
+ readonly bondingElectrons: number;
85
+ readonly antibondingElectrons: number;
86
+ /**
87
+ * (bonding - antibonding) / 2, so it can be a half.
88
+ *
89
+ * A half-integer bond order is not a rounding error: it is what an odd number of electrons gives,
90
+ * and it is why nitrogen monoxide exists as a stable radical with a bond between a double and a
91
+ * triple.
92
+ */
93
+ readonly bondOrder: number;
94
+ readonly unpairedElectrons: number;
95
+ readonly magnetism: Magnetism;
96
+ /** A bond order of zero means there is nothing holding the atoms together. */
97
+ readonly exists: boolean;
98
+ /** True when the pi orbitals lie below the sigma, which is the crossover. */
99
+ readonly piBelowSigma: boolean;
100
+ }
101
+ /**
102
+ * Work out the molecular orbitals of a diatomic written as a formula.
103
+ *
104
+ * `diatomic('O2')`, `diatomic('N2')`, `diatomic('NO')`, `diatomic('CN-')`, `diatomic('O2+')`.
105
+ */
106
+ declare function diatomic(formula: string): DiatomicResult;
107
+ /**
108
+ * The configuration written out, for a diagram caption.
109
+ *
110
+ * Empty levels are dropped, since writing them adds nothing a reader needs.
111
+ */
112
+ declare const formatOccupancy: (result: DiatomicResult) => string;
113
+ //#endregion
114
+ export { DiatomicResult, Level, Magnetism, MolecularOrbital, S_P_MIXING_NOTE, diatomic, fillOrbitals, formatOccupancy, orbitalSequence };
@@ -0,0 +1,201 @@
1
+ import { readFormula } from "./species.mjs";
2
+ import { valenceElectronsFor } from "./lewis.mjs";
3
+
4
+ //#region src/chem/molecular-orbital.ts
5
+ /**
6
+ * Molecular orbitals for a diatomic: bond order, and whether the molecule is magnetic.
7
+ *
8
+ * ## What this explains that dot-and-cross cannot
9
+ *
10
+ * Oxygen is paramagnetic. Liquid oxygen sticks to a magnet, which is a thing anyone can watch, and
11
+ * the Lewis structure O=O has every electron neatly paired and predicts the opposite. That failure
12
+ * is the reason molecular orbital theory is taught at all: put the electrons into orbitals that
13
+ * belong to the whole molecule rather than to one atom or one bond, and two of them end up alone in
14
+ * a pair of degenerate antibonding orbitals.
15
+ *
16
+ * So this engine answers two questions a Lewis structure cannot: how strongly the atoms are held
17
+ * together when the answer is not a whole number, and whether the molecule has unpaired electrons.
18
+ *
19
+ * bond order = (bonding electrons - antibonding electrons) / 2
20
+ *
21
+ * A bond order of zero means the molecule does not exist, which is why there is no He2 and no Ne2.
22
+ *
23
+ * ## The crossover, which is the part usually left out
24
+ *
25
+ * The order of the 2p-derived orbitals is not fixed. For the earlier second-period elements the two
26
+ * pi orbitals lie BELOW the sigma; from oxygen onward the sigma drops below the pi. The cause is
27
+ * mixing between the 2s and 2p sigma orbitals, which pushes the sigma up, and it matters most where
28
+ * the 2s and 2p levels are closest together, which is at the left of the period.
29
+ *
30
+ * This is not a detail. Boron's B2 has exactly two electrons to place in that region: with pi
31
+ * lowest they go one into each pi orbital and B2 is paramagnetic, which it is; with sigma lowest
32
+ * they pair up in it and B2 would be diamagnetic, which it is not. So an engine that ignored the
33
+ * crossover would get the right bond order and the wrong magnetism, and the magnetism is the
34
+ * evidence.
35
+ *
36
+ * ## What is covered
37
+ *
38
+ * Diatomics of the first two periods, neutral or charged: H2, He2, Li2 through Ne2, and the
39
+ * heteronuclear and ionic ones built from the same orbitals, so NO, CO, CN- and the oxygen family
40
+ * O2+, O2-, O2 2-. Core electrons are left out: they sit in bonding and antibonding pairs that
41
+ * cancel exactly, so they change no answer and only lengthen the diagram.
42
+ *
43
+ * Pure: no React, no pixels.
44
+ */
45
+ /**
46
+ * Where the sigma made from 2p sits relative to the pair of pi orbitals.
47
+ *
48
+ * Mixing with the 2s sigma pushes the 2p sigma up, and the effect is strongest where 2s and 2p are
49
+ * closest in energy, which is toward the left of the period. So the pi orbitals are lower for the
50
+ * earlier elements and the sigma is lower from oxygen onward.
51
+ */
52
+ const S_P_MIXING_NOTE = "The sigma orbital built from 2p is pushed up by mixing with the sigma built from 2s, and that mixing is strongest where the 2s and 2p levels lie closest together, toward the left of the period. So for boron, carbon and nitrogen the two pi orbitals lie below the sigma, and from oxygen onward the sigma drops below them.";
53
+ /** Valence electron count at or below which the pi orbitals lie below the sigma. */
54
+ const MIXING_LIMIT = 10;
55
+ const PERIOD_1 = [{
56
+ label: "σ1s",
57
+ bonding: true,
58
+ orbitals: 1
59
+ }, {
60
+ label: "σ*1s",
61
+ bonding: false,
62
+ orbitals: 1
63
+ }];
64
+ const PI_BELOW_SIGMA = [
65
+ {
66
+ label: "σ2s",
67
+ bonding: true,
68
+ orbitals: 1
69
+ },
70
+ {
71
+ label: "σ*2s",
72
+ bonding: false,
73
+ orbitals: 1
74
+ },
75
+ {
76
+ label: "π2p",
77
+ bonding: true,
78
+ orbitals: 2
79
+ },
80
+ {
81
+ label: "σ2p",
82
+ bonding: true,
83
+ orbitals: 1
84
+ },
85
+ {
86
+ label: "π*2p",
87
+ bonding: false,
88
+ orbitals: 2
89
+ },
90
+ {
91
+ label: "σ*2p",
92
+ bonding: false,
93
+ orbitals: 1
94
+ }
95
+ ];
96
+ const SIGMA_BELOW_PI = [
97
+ {
98
+ label: "σ2s",
99
+ bonding: true,
100
+ orbitals: 1
101
+ },
102
+ {
103
+ label: "σ*2s",
104
+ bonding: false,
105
+ orbitals: 1
106
+ },
107
+ {
108
+ label: "σ2p",
109
+ bonding: true,
110
+ orbitals: 1
111
+ },
112
+ {
113
+ label: "π2p",
114
+ bonding: true,
115
+ orbitals: 2
116
+ },
117
+ {
118
+ label: "π*2p",
119
+ bonding: false,
120
+ orbitals: 2
121
+ },
122
+ {
123
+ label: "σ*2p",
124
+ bonding: false,
125
+ orbitals: 1
126
+ }
127
+ ];
128
+ /** The orbitals in energy order, for a diatomic with this many valence electrons. */
129
+ function orbitalSequence(valenceElectrons, firstPeriod) {
130
+ if (firstPeriod) return PERIOD_1;
131
+ return valenceElectrons <= MIXING_LIMIT ? PI_BELOW_SIGMA : SIGMA_BELOW_PI;
132
+ }
133
+ /**
134
+ * Fill the orbitals from the bottom, singly across a degenerate level before pairing.
135
+ *
136
+ * Hund's rule again, and for the same reason it applies inside an atom: two electrons in one
137
+ * orbital repel, so they spread out while there is anywhere to spread to. It is what leaves oxygen
138
+ * with two unpaired electrons instead of one filled antibonding orbital.
139
+ */
140
+ function fillOrbitals(sequence, electrons) {
141
+ let left = electrons;
142
+ const levels = sequence.map((orbital) => {
143
+ const capacity = 2 * orbital.orbitals;
144
+ const placed = Math.min(left, capacity);
145
+ left -= placed;
146
+ return {
147
+ orbital,
148
+ electrons: placed,
149
+ unpaired: placed <= orbital.orbitals ? placed : 2 * orbital.orbitals - placed
150
+ };
151
+ });
152
+ return {
153
+ levels,
154
+ unpaired: levels.reduce((total, l) => total + l.unpaired, 0),
155
+ unplaced: left
156
+ };
157
+ }
158
+ /**
159
+ * Work out the molecular orbitals of a diatomic written as a formula.
160
+ *
161
+ * `diatomic('O2')`, `diatomic('N2')`, `diatomic('NO')`, `diatomic('CN-')`, `diatomic('O2+')`.
162
+ */
163
+ function diatomic(formula) {
164
+ const { counts, charge } = readFormula(formula);
165
+ const atoms = counts.flatMap((c) => Array(c.count).fill(c.element));
166
+ if (atoms.length !== 2) throw new Error(`${formula} has ${atoms.length} atoms: this engine describes diatomic molecules, which have two`);
167
+ const firstPeriod = atoms.every((a) => a === "H" || a === "He");
168
+ const valenceElectrons = atoms.reduce((total, a) => total + valenceElectronsFor(a), 0) - charge;
169
+ if (valenceElectrons < 0) throw new Error(`${formula} works out to a negative electron count`);
170
+ const piBelowSigma = !firstPeriod && valenceElectrons <= MIXING_LIMIT;
171
+ const { levels, unpaired, unplaced } = fillOrbitals(orbitalSequence(valenceElectrons, firstPeriod), valenceElectrons);
172
+ if (unplaced > 0) throw new Error(`${formula} has ${valenceElectrons} valence electrons, more than the orbitals of the first two periods can hold`);
173
+ const bondingElectrons = levels.filter((l) => l.orbital.bonding).reduce((total, l) => total + l.electrons, 0);
174
+ const antibondingElectrons = levels.filter((l) => !l.orbital.bonding).reduce((total, l) => total + l.electrons, 0);
175
+ const bondOrder = (bondingElectrons - antibondingElectrons) / 2;
176
+ return {
177
+ formula,
178
+ atoms,
179
+ charge,
180
+ valenceElectrons,
181
+ levels,
182
+ bondingElectrons,
183
+ antibondingElectrons,
184
+ bondOrder,
185
+ unpairedElectrons: unpaired,
186
+ magnetism: unpaired > 0 ? "paramagnetic" : "diamagnetic",
187
+ exists: bondOrder > 0,
188
+ piBelowSigma
189
+ };
190
+ }
191
+ /**
192
+ * The configuration written out, for a diagram caption.
193
+ *
194
+ * Empty levels are dropped, since writing them adds nothing a reader needs.
195
+ */
196
+ const formatOccupancy = (result) => result.levels.filter((l) => l.electrons > 0).map((l) => `${l.orbital.label}${l.electrons === 1 ? "" : superscript(l.electrons)}`).join(" ");
197
+ const SUPERSCRIPT = "⁰¹²³⁴⁵⁶⁷⁸⁹";
198
+ const superscript = (value) => String(value).split("").map((d) => SUPERSCRIPT[Number(d)] ?? d).join("");
199
+
200
+ //#endregion
201
+ export { S_P_MIXING_NOTE, diatomic, fillOrbitals, formatOccupancy, orbitalSequence };
@@ -0,0 +1,154 @@
1
+ //#region src/chem/molecule.d.ts
2
+ /**
3
+ * molecule, a structure as a graph, so the rest can be worked out rather than declared.
4
+ *
5
+ * WHAT THIS IS FOR. Every chemistry lab and lesson we have declares its molecules as DRAWINGS: a
6
+ * chain of vertices with positions, a formula typed in as a string, a functional group named as a
7
+ * list of vertex indices. Nothing about that can be checked. A formula string can disagree with the
8
+ * structure beside it, a group can be named that the structure does not contain, and an isomer list
9
+ * is only as complete as whoever typed it.
10
+ *
11
+ * A graph fixes all of it at once. Declare the heavy atoms and the bonds, and the molecular formula,
12
+ * the relative molecular mass, the degrees of unsaturation, the functional groups and the polymer
13
+ * repeat unit all follow by computation.
14
+ *
15
+ * ## Hydrogens are implicit, and that is the point
16
+ *
17
+ * An author declares carbon, oxygen and nitrogen and never hydrogen, exactly as a skeletal formula
18
+ * is drawn. The hydrogen count comes from valence: four bonds to a carbon, three to a nitrogen, two
19
+ * to an oxygen, one to a halogen. So a structure cannot be declared with a hydrogen count that
20
+ * contradicts its own bonds, because the count is not declared at all.
21
+ *
22
+ * ## Why SMILES
23
+ *
24
+ * Because it is the notation the whole of chemistry already uses, so `CCO` is ethanol here and in
25
+ * every database a learner will ever meet, and because a molecule written as one short string is a
26
+ * molecule an author will actually declare correctly. The subset parsed here is the one A level
27
+ * needs: the organic elements, single, double, triple and aromatic bonds, branches, and ring
28
+ * closures.
29
+ *
30
+ * What is deliberately NOT here: stereochemistry, charges, isotopes and explicit bracket atoms.
31
+ * Those belong in the topics that use them, and a parser that accepted them without the rest of the
32
+ * kernel understanding them would be a promise it could not keep.
33
+ *
34
+ * Pure: no React, no pixels.
35
+ */
36
+ /** The elements A level organic chemistry uses. */
37
+ type Element = 'C' | 'N' | 'O' | 'S' | 'P' | 'F' | 'Cl' | 'Br' | 'I' | 'H';
38
+ /** Relative atomic masses, to the precision a data booklet prints. */
39
+ declare const ATOMIC_MASS: Readonly<Record<Element, number>>;
40
+ interface Atom {
41
+ readonly id: number;
42
+ readonly element: Element;
43
+ /** Part of an aromatic ring, written lowercase in SMILES. */
44
+ readonly aromatic: boolean;
45
+ /**
46
+ * Bonds this atom makes to something OUTSIDE the structure, so they take no hydrogen.
47
+ *
48
+ * An attachment point. A polymer repeat unit has two, one to the unit on each side, and without
49
+ * them the repeat unit of poly(ethene) comes out as C2H6: opening the double bond frees a bond on
50
+ * each carbon, and if nothing claims it a hydrogen does. The unit is CH2-CH2, not ethane.
51
+ */
52
+ readonly openValence?: number;
53
+ /**
54
+ * Formal charge on this atom: +1 on the nitrogen of an ammonium ion, -1 on a carboxylate oxygen.
55
+ *
56
+ * It changes how many bonds the atom makes, which is the reason it has to live on the graph
57
+ * rather than being noted alongside it. A nitrogen makes three bonds and an ammonium nitrogen
58
+ * makes four, and a kernel that did not know the charge would report ammonium as NH3 with a
59
+ * spare bond it could not explain.
60
+ */
61
+ readonly charge?: number;
62
+ /**
63
+ * Hydrogens stated outright rather than worked out from the valence.
64
+ *
65
+ * Set only by a bracket atom, where SMILES requires the count to be written. Everywhere else the
66
+ * count is computed, which is what stops a structure disagreeing with its own bonds.
67
+ */
68
+ readonly explicitHydrogens?: number;
69
+ }
70
+ interface Bond {
71
+ readonly a: number;
72
+ readonly b: number;
73
+ readonly order: 1 | 2 | 3;
74
+ /** An aromatic bond counts as one and a half when valence is totted up. */
75
+ readonly aromatic: boolean;
76
+ }
77
+ interface Structure {
78
+ readonly atoms: readonly Atom[];
79
+ readonly bonds: readonly Bond[];
80
+ }
81
+ /**
82
+ * Parse the SMILES subset A level needs.
83
+ *
84
+ * `CCO` ethanol, `CC(=O)C` propanone, `c1ccccc1` benzene, `CC(=O)OCC` ethyl ethanoate.
85
+ *
86
+ * Refuses anything it does not fully understand rather than guessing, because a parser that
87
+ * silently drops a feature produces a molecule that is not the one the author wrote, and every
88
+ * number computed from it afterwards is then confidently wrong.
89
+ */
90
+ declare function parseSmiles(smiles: string): Structure;
91
+ /** Bonds touching an atom. */
92
+ declare const bondsAt: (structure: Structure, id: number) => Bond[];
93
+ /** The atom on the other end of a bond. */
94
+ declare const otherEnd: (bond: Bond, id: number) => number;
95
+ /** Atoms directly bonded to this one, excluding any explicit hydrogens. */
96
+ declare const neighbours: (structure: Structure, id: number) => Atom[];
97
+ /** How many bonds an atom has used, counting an aromatic bond as one and a half. */
98
+ declare const bondOrderSum: (structure: Structure, id: number) => number;
99
+ /**
100
+ * Hydrogens on an atom, from what its valence has left over.
101
+ *
102
+ * Never declared, which is what stops a structure disagreeing with its own formula. An aromatic
103
+ * carbon in benzene has two aromatic bonds worth 1.5 each, leaving one hydrogen, which is right.
104
+ */
105
+ /**
106
+ * Bonds an atom can make, once its charge is taken into account.
107
+ *
108
+ * The two directions are not symmetrical, and the reason is what the charge did to the electrons.
109
+ *
110
+ * An atom with a lone pair to spare, nitrogen or oxygen or sulfur, makes an EXTRA bond when it
111
+ * loses an electron, because the lone pair becomes a bonding pair: ammonium's nitrogen makes four
112
+ * bonds, not three. Gaining one costs it a bond instead, which is why a carboxylate oxygen makes
113
+ * only one.
114
+ *
115
+ * Carbon has no lone pair to donate, so it loses a bond whichever way it is charged. A carbocation
116
+ * and a carbanion both make three.
117
+ */
118
+ declare function chargedValence(element: Element, charge?: number): number;
119
+ declare function implicitHydrogens(structure: Structure, id: number): number;
120
+ /** Total formal charge on a structure: the charge of the ion it represents. */
121
+ declare const totalCharge: (structure: Structure) => number;
122
+ /** Every element in the structure, counted, hydrogens included. */
123
+ declare function atomCounts(structure: Structure): Record<string, number>;
124
+ /**
125
+ * The molecular formula, in Hill order: carbon, then hydrogen, then everything else alphabetically.
126
+ *
127
+ * Hill order is what a database and a mark scheme both use, so C2H6O and never H6C2O or OC2H6.
128
+ */
129
+ declare function formatCounts(counts: Readonly<Record<string, number>>): string;
130
+ declare function molecularFormula(structure: Structure): string;
131
+ /** Relative molecular mass, from the same counts. */
132
+ declare const relativeMass: (structure: Structure) => number;
133
+ /**
134
+ * Degrees of unsaturation: how many rings plus double-bond equivalents the formula demands.
135
+ *
136
+ * Worth computing because it is the first thing to do with a molecular formula in a structure
137
+ * determination, and because it is the check that catches a proposed structure that cannot exist:
138
+ * a formula with zero degrees cannot contain a C=O however well the rest of the evidence fits.
139
+ *
140
+ * Oxygen does not enter the count, which surprises people every time, and the reason is that adding
141
+ * an oxygen into a chain uses two bonds and supplies two.
142
+ */
143
+ declare function degreesOfUnsaturation(structure: Structure): number;
144
+ /** Atoms in the structure that are carbon. */
145
+ declare const carbonCount: (structure: Structure) => number;
146
+ /**
147
+ * Rings, by the cycle rank of the graph: bonds minus atoms plus connected pieces.
148
+ *
149
+ * Counts independent rings rather than every closed loop, which is the number a chemist means by
150
+ * "how many rings", and naphthalene comes out as two rather than three.
151
+ */
152
+ declare function ringCount(structure: Structure): number;
153
+ //#endregion
154
+ export { ATOMIC_MASS, Atom, Bond, Element, Structure, atomCounts, bondOrderSum, bondsAt, carbonCount, chargedValence, degreesOfUnsaturation, formatCounts, implicitHydrogens, molecularFormula, neighbours, otherEnd, parseSmiles, relativeMass, ringCount, totalCharge };