code wiki / (root) / nx_chem_solution.nx

nx_chem_solution.nx source

↩ module page · 79 lines · 3134 B

1// nx_chem_solution.nx -- FOOD-SCIENCE SUITE / SOLUTION CHEMISTRY rung. The 2// aqueous chemistry food runs on: buffers (Henderson-Hasselbalch), the 3// pH/pOH relation, molar concentration, dilution (C1V1 = C2V2), and 4// titratable acidity. pH is the master variable of preservation and 5// fermentation, so this grounds the whole safety story in chemistry. 6// 7// INTEGER-EXACT. pH/pKa x1000; concentration in mM; volume in mL; mass in 8// mg; molar mass x10. Henderson-Hasselbalch is exact at decade buffer 9// ratios (log10 of a power of ten is an integer): pH = pKa + log_ratio. 10// 11// THE exceed: buffer pH, dilutions, and titratable acidity are COMPUTED 12// from chemistry; and cs_is_high_acid ties straight to the preservation / 13// canning botulinum line (pH < 4.6) -- one chemical source of truth. 14// 15// grounded: henderson_hasselbalch_equation + molar_concentration 16// + c1v1_c2v2_dilution + titratable_acidity_titration 17// genealogy_id: solution_chemistry + nishi_food_science_suite 18 19import "nx_syscalls.nx" 20const CS_MAGIC_14000: i64 = 14000 21const CS_MAGIC_10000: i64 = 10000 22const CS_MAGIC_100000: i64 = 100000 23 24const CS_HIGH_ACID_PH_MILLI: i64 = 4600 // FDA acidified-foods line 25 26// ===== Buffers (Henderson-Hasselbalch) ============================ 27// 28// pH = pKa + log10([A-]/[HA]). log_ratio is the integer base-10 log of the 29// conjugate-base : acid ratio (0 for 1:1, +1 for 10:1, -1 for 1:10) -- exact. 30 31func cs_buffer_ph_milli(pka_milli: i64, log_ratio: i64) -> i64 { 32 return pka_milli + log_ratio * 1000 33} 34 35// Buffer capacity is maximal when pH == pKa (1:1 ratio). 36func cs_buffer_ph_at_pka(pka_milli: i64) -> i64 { 37 return cs_buffer_ph_milli(pka_milli, 0) 38} 39 40// pOH from pH (at 25 C, pH + pOH = 14). 41func cs_poh_milli(ph_milli: i64) -> i64 { 42 return CS_MAGIC_14000 - ph_milli 43} 44 45// Ties to preservation: is the food high-acid (botulinum cannot grow)? 46func cs_is_high_acid(ph_milli: i64) -> i64 { 47 if ph_milli < CS_HIGH_ACID_PH_MILLI { return 1 } 48 return 0 49} 50 51// ===== Concentration + dilution =================================== 52 53// Molar concentration in mM = mass(mg)/molar_mass(g/mol) per volume(mL). 54// mM = mass_mg * 10000 / (mw_x10 * vol_ml). 55func cs_molarity_mm(mass_mg: i64, mw_x10: i64, vol_ml: i64) -> i64 { 56 let denom: i64 = mw_x10 * vol_ml 57 if denom <= 0 { return 0 } 58 return mass_mg * CS_MAGIC_10000 / denom 59} 60 61// Final concentration after diluting c1 (in v1) up to volume v2: c1*v1/v2. 62func cs_dilute_final_conc(c1: i64, v1: i64, v2: i64) -> i64 { 63 if v2 <= 0 { return 0 } 64 return c1 * v1 / v2 65} 66 67// Stock volume needed to make v2 of target concentration c2 from stock c1. 68func cs_dilute_volume_needed(c1: i64, c2: i64, v2: i64) -> i64 { 69 if c1 <= 0 { return 0 } 70 return c2 * v2 / c1 71} 72 73// ===== Titratable acidity ========================================= 74 75// Acid mass (mg) from a titration: V(mL) * Normality(x1000) * milliequiv 76// weight(mg/meq, x100) / 100000. (Citric acid meq wt ~ 64.04 mg/meq.) 77func cs_titratable_acid_mg(v_ml: i64, normality_x1000: i64, meqwt_x100: i64) -> i64 { 78 return v_ml * normality_x1000 * meqwt_x100 / CS_MAGIC_100000 79}