nx_ice_recrystal.nx
buildroot/runtime/nx_ice_recrystal.nx
about
nx_ice_recrystal.nx -- HOW FROZEN DESSERT ACTUALLY DIES.
===== WHY THIS EXISTS ============================================
The stability stack in this lane models first-order CHEMICAL degradation:
a molecule decays, potency falls, an expiry date follows. For most
products that is the failure mode. For ice cream it is not.
Ice cream almost never fails chemically. It fails because its ice
crystals GROW -- small crystals melt and re-deposit onto large ones until
the texture turns coarse and sandy. That process is not first order, it
has no activation energy in the Arrhenius sense, and it is driven mainly
by temperature FLUCTUATION rather than by mean temperature. So the lane
had a complete frozen-dessert stack and a complete stability stack, and
nothing that could say when an ice cream goes bad.
===== THE MECHANISM ==============================================
Ostwald ripening. A small crystal has high surface curvature, which by
the Gibbs-Thomson effect depresses its local melting point -- so on any
warming it is the small crystals that melt first. On the following
cooling that water refreezes, but onto the crystals that survived, which
are the large ones. Every cycle therefore removes small crystals and
feeds large ones. Nothing is lost or gained in mass; the DISTRIBUTION
coarsens, and coarseness is what the tongue detects.
Isothermal growth follows the cube law of Lifshitz-Slyozov-Wagner:
D(t)^3 = D(0)^3 + k*t
The cube is the signature of diffusion-limited ripening and is why
recrystallisation cannot be written as a rate constant on concentration.
===== WHAT IS COMPUTED VS ASSERTED ===============================
★THE CYCLING TERM IS DERIVED, NOT ASSERTED, AND THAT IS THE POINT. The
mass of ice that melts and refreezes on a warm excursion is exactly the
change in frozen fraction between the two temperatures -- and this lane
already computes frozen fraction from colligative physics
(ic_frozen_water_permil). So cycling damage falls straight out of the
dependencies 2 imports · 1 importers
imports: nx_syscalls.nxnx_icecream.nx
imported by: nx_labsci_svc.nx
structs
| none |
consts
| 65 | const IR_MAGIC_3000000: i64 = 3000000 |
| 66 | const IR_MAGIC_1000000000000: i64 = 1000000000000 |
| 67 | const IR_MAGIC_100000: i64 = 100000 |
| 69 | const IR_INVALID: i64 = 0 - 1 |
| 74 | const IR_UM: i64 = 10 |
| 78 | const IR_FRESH_D: i64 = 250 // 25 um, typical well-made fresh ice cream |
| 79 | const IR_DETECT_D: i64 = 400 // 40 um, coarseness becomes perceptible |
| 80 | const IR_COARSE_D: i64 = 500 // 50 um, unambiguously icy/sandy |
| 83 | const IR_K_DEFAULT: i64 = 1200 |
| 88 | const IR_COUPLING: i64 = 1000 |
functions
| 95 | func ir_icbrt(v: i64) -> i64 |
| 112 | func ir_cube(d: i64) -> i64 |
| 124 | func ir_k_from_observation(d0: i64, d1: i64, days: i64) -> i64 calls 1: ir_cube |
| 138 | func ir_k_is_recovered(k: i64) -> i64 called by 1: lab_icecream_recrystal |
| 143 | func ir_coupling_is_asserted() -> i64 |
| 150 | func ir_size_isothermal(d0: i64, k: i64, days: i64) -> i64 |
| 171 | func ir_cycled_fraction_permil(m: *NxIceMix, t_cold_milli_c: i64, t_warm_milli_c: i64) -> i64 |
| 188 | func ir_size_after_cycles(d0: i64, cycled_permil: i64, cycles: i64) -> i64 |
| 217 | func ir_size_after_cycles_growth(d0: i64, growth_permil: i64, cycles: i64) -> i64 |
| 234 | func ir_size_combined_growth(d0: i64, k: i64, days: i64, growth_permil: i64, cycles: i64) -> i64 |
| 241 | func ir_size_combined(d0: i64, k: i64, days: i64, cycled_permil: i64, cycles: i64) -> i64 |
| 252 | func ir_texture_grade(d: i64) -> i64 called by 1: lab_icecream_recrystal |
| 261 | func ir_days_to_detectable(d0: i64, k: i64) -> i64 calls 1: ir_cube |
| 273 | func ir_cycles_to_detectable(d0: i64, cycled_permil: i64) -> i64 calls 1: ir_size_after_cycles |
| 303 | func ir_mkt_describes_recrystallisation() -> i64 called by 1: lab_icecream_recrystal |