The Slushee Phase-Change Optimization

Estimations
Thermodynamics
Author

Connor Lockhart

Published

April 17, 2026

Have you ever reached the end of an Icee or Slurpee only to find a desolate, dry block of white ice? This is the “Slushee Dead Zone”—a state where the liquid-to-solid ratio has collapsed, leaving the remaining ice stranded without enough liquid to be drinkable.

The problem is one of phase-change synchronization. For a perfect drinking experience, the rate at which you consume the liquid must match the rate at which the ambient heat melts the ice. We will use the 7-11 Slurpee as our standard-bearer for frozen liquid ice beverages and attempt to calculate what temperature is required for a given drink consumption rate to avoid having a dry chunk of ice at the before you’ve finished the entire beverage.

1. Geometry: The Tapered Frustum

The local geometry of the object determines how rapidly heat transfers since it changes local convection rates for heat transfer. We will model this heat transfer as uniform per unit surface area of the slushee container. While 7-11 cups are not perfect cylinders; they are frustums (tapered cones).

Cup Size Comparison

The diagram below shows the relative 3D scale of the standard 7-11 lineup.

Code
// Visual representation of cup sizes in 3D perspective
html`<div style="display: flex; align-items: flex-end; gap: 30px; justify-content: center; padding: 40px; background: #f0f4f8; border-radius: 12px;">
  ${['small', 'medium', 'large', 'xlarge'].map(size => {
    const d = {
      small: { h: 4.5, r1: 1.1, r2: 1.6, label: "12oz" },
      medium: { h: 6.0, r1: 1.25, r2: 1.87, label: "22oz" },
      large: { h: 7.0, r1: 1.37, r2: 2.12, label: "30oz" },
      xlarge: { h: 8.5, r1: 1.5, r2: 2.37, label: "40oz" }
    }[size];
    const scale = 25;
    const h = d.h * scale;
    const r1 = d.r1 * scale;
    const r2 = d.r2 * scale;
    const tilt = 0.25; // Perspective tilt factor
    
    return html`<div style="text-align: center;">
      <svg width="${r2*2 + 20}" height="${h + r2*tilt*2 + 40}" style="overflow: visible;">
        <defs>
          <linearGradient id="grad-${size}" x1="0%" y1="0%" x2="100%" y2="0%">
            <stop offset="0%" style="stop-color:#d35400;stop-opacity:1" />
            <stop offset="30%" style="stop-color:#e67e22;stop-opacity:1" />
            <stop offset="60%" style="stop-color:#f39c12;stop-opacity:1" />
            <stop offset="100%" style="stop-color:#d35400;stop-opacity:1" />
          </linearGradient>
        </defs>
        
        <!-- Background part of bottom ellipse (dashed or lighter) -->
        <ellipse cx="${r2 + 10}" cy="${h + r2*tilt}" rx="${r1}" ry="${r1*tilt}" fill="none" stroke="#ccc" stroke-dasharray="2,2" />
        
        <!-- Body of the frustum -->
        <path d="M ${10} ${r2*tilt} 
                 L ${r2 - r1 + 10} ${h + r2*tilt} 
                 A ${r1} ${r1*tilt} 0 0 0 ${r2 + r1 + 10} ${h + r2*tilt} 
                 L ${2*r2 + 10} ${r2*tilt} 
                 A ${r2} ${r2*tilt} 0 0 1 10 ${r2*tilt}" 
              fill="url(#grad-${size})" stroke="#333" stroke-width="1.5" />
        
        <!-- Top face of the slushee -->
        <ellipse cx="${r2 + 10}" cy="${r2*tilt}" rx="${r2}" ry="${r2*tilt}" fill="#fff" fill-opacity="0.8" stroke="#333" stroke-width="1.5" />
        
        <!-- Content/Ice texture on top -->
        <ellipse cx="${r2 + 10}" cy="${r2*tilt}" rx="${r2*0.9}" ry="${r2*tilt*0.9}" fill="#fdfefe" fill-opacity="0.5" />
        
        <text x="${r2 + 10}" y="${h + r2*tilt*2 + 30}" text-anchor="middle" font-family="system-ui" font-weight="bold" font-size="14px" fill="#2c3e50">${d.label}</text>
      </svg>
    </div>`;
  })}
</div>`

2. Thermodynamics: Continuous Phase Change

Units of Measurement

To model this system, we utilize a mix of SI units for physical accuracy and US Customary units for user-facing context:

  • Temperature (\(^\circ C\)): Celsius is the standard for thermodynamics involving water phase changes, where \(0^\circ C\) is the critical transition point.

  • Mass (\(g\)): Grams are used for all mass calculations to maintain a direct relationship with milliliters for density (\(1\ g/ml\) for water). We neglect the potential altered density from flavoring.

  • Energy (\(J\)): Joules allow us to use the standard Latent Heat of Fusion constant of water (\(334\ J/g\)) to determine exactly how much heat energy is required to melt the ice.

  • Volume (\(oz\) and \(ml\)): We accept input in fluid ounces (the commercial standard for 7-11) but convert internally to milliliters (\(1\ ml = 1\ cm^3\)) for all physical and geometric calculations.

  • Time (\(min\)): Minutes are used as the temporal scale for consumption to provide an intuitive ``drinking time’’’ result.

We model the slushee as a continuous system.

Heat Transfer

Heat flows from the ambient air (\(T_{amb}\)) through the cup walls: \[\frac{dQ}{dt} = h \cdot A \cdot (T_{amb} - 0^\circ C)\] This heat melts the ice at a rate of \(\frac{dm_{melt}}{t} = \frac{1}{L_f} \frac{dQ}{dt}\).

Consumption

We assume a constant volumetric consumption rate \(C\) (oz/min). Because of the straw’s liquid bias, the rate of ice removal \(\frac{dm}{t}_{ice\_out}\) is lower than the rate of liquid removal.

3. Governing Differential Equation

To justify our simulation results, we derive the governing equation for the Volume Ice Ratio (\(R\)), defined as \(R = V_i / V\), where \(V_i\) is the volume of ice and \(V\) is the total volume (\(V_i + V_l\)).

Conservation of Volume

The total volume of the system changes due to consumption (\(C\)) and the volume contraction associated with melting: \[\frac{dV}{dt} = -C + \dot{m}_{melt} \left( \frac{1}{\rho_l} - \frac{1}{\rho_i} \right)\] Where \(\dot{m}_{melt} = \frac{h A(V) T_{amb}}{L_f}\). Since \(\rho_i < \rho_l\), the second term is negative, representing the “shrinkage” of the slushee as it turns to liquid.

Rate of Change of Ice

The ice volume decreases through both melting and drinking: \[\frac{dV_i}{dt} = -\frac{\dot{m}_{melt}}{\rho_i} - C \beta(V) R\] Here, \(\beta(V)\) is our Ice Extraction Efficiency, which we define as a linear function of the volume fraction \(\phi = V/V_0\): \[\beta(\phi) = \beta_0 + (1 - \beta_0)(1 - \phi)\] This ensures that \(\beta = \beta_0\) at full volume and \(\beta = 1.0\) when the cup is empty.

Deriving \(dR/dt\)

Using the quotient rule on \(R = V_i/V\): \[\frac{dR}{dt} = \frac{1}{V} \left( \frac{dV_i}{dt} - R \frac{dV}{dt} \right)\]

Substituting our expressions for \(\dot{V}_i\) and \(\dot{V}\): \[\frac{dR}{dt} = \frac{1}{V} \left[ \left( -\frac{\dot{m}_{melt}}{\rho_i} - C \beta R \right) - R \left( -C + \dot{m}_{melt} \left( \frac{1}{\rho_l} - \frac{1}{\rho_i} \right) \right) \right]\]

Expanding and simplifying: \[\frac{dR}{dt} = \underbrace{\frac{\dot{m}_{melt}}{V} \left[ \frac{R-1}{\rho_i} - \frac{R}{\rho_l} \right]}_{\text{Thermodynamic Decay}} + \underbrace{\frac{C R (1 - \beta)}{V}}_{\text{Consumption Bias Enrichment}}\]

This reveals the fundamental tension: Melting always decreases the ice ratio, while Drinking (with a liquid bias \(\beta < 1\)) increases it. The “Slushee Dead Zone” occurs when the ice enrichment term dominates the ice decay term for a sustained period.

4. Interactive Optimization

Adjust the parameters below to see if your drinking habits are sustainable.

Code
viewof ambientTempC = Inputs.range([0, 45], {value: 25, step: 1, label: "Ambient Temp (°C)"})
viewof cupSize = Inputs.select(new Map([
  ["Small (12 oz)", "small"],
  ["Medium (22 oz)", "medium"],
  ["Large (30 oz)", "large"],
  ["X-Large (40 oz)", "xlarge"]
]), {label: "Cup Size"})
viewof consumptionRate = Inputs.range([0.1, 5.0], {value: 2.0, step: 0.1, label: "Consumption (oz/min)"})
viewof initialIceRatio = Inputs.range([0.4, 0.8], {value: 0.6, step: 0.05, label: "Initial Ice Ratio"})
viewof liquidBias = Inputs.range([0.1, 1.0], {value: 0.5, step: 0.1, label: "Ice-in-Straw Bias"})
viewof runTrigger = Inputs.button("Run Simulation")
Code
ozToMl = 29.57
inchToCm = 2.54
Lf = 334 // J/g
h_coeff = 9.5 // W/m^2K
rho_ice = 0.917 // g/cm^3
rho_liq = 1.0 // g/cm^3

cupSizes = ({
  small: { h: 4.5 * inchToCm, r1: (2.25/2) * inchToCm, r2: (3.25/2) * inchToCm },
  medium: { h: 6.0 * inchToCm, r1: (2.5/2) * inchToCm, r2: (3.75/2) * inchToCm },
  large: { h: 7.0 * inchToCm, r1: (2.75/2) * inchToCm, r2: (4.25/2) * inchToCm },
  xlarge: { h: 8.5 * inchToCm, r1: (3.0/2) * inchToCm, r2: (4.75/2) * inchToCm }
})

// Simulation Function
function runSimulation(temp, sizeKey, rate, initRatio, initBias, trigger) {
  const d = cupSizes[sizeKey];
  const dt = 0.1; // minutes
  const C_ml = rate * ozToMl;
  
  const startingIce = (d.h * Math.PI / 3 * (d.r1**2 + d.r1*d.r2 + d.r2**2)) * initRatio * rho_ice;
  const startingLiq = (d.h * Math.PI / 3 * (d.r1**2 + d.r1*d.r2 + d.r2**2)) * (1 - initRatio) * rho_liq;
  const startingVol = (startingIce / rho_ice) + (startingLiq / rho_liq);

  let m_ice = startingIce;
  let m_liq = startingLiq;
  
  const history = [];
  let t = 0;

  while (m_ice + m_liq > 1 && history.length < 1000) {
    let currentVol = (m_ice / rho_ice) + (m_liq / rho_liq);
    let iceRatio = m_ice / (m_ice + m_liq);
    let volFrac = Math.max(0, currentVol / startingVol);
    
    // Dynamic bias: At volFrac=1, bias is initBias. At volFrac=0, bias is 1.0 (no effect).
    // The "Bias Error" (1 - initBias) scales to 0 as volume drops.
    let currentBias = initBias + (1 - initBias) * (1 - volFrac);
    
    let heightFrac = Math.max(0, currentVol / (d.h * Math.PI / 3 * (d.r1**2 + d.r1*d.r2 + d.r2**2)));
    let y = d.h * heightFrac;
    let ry = d.r1 + (d.r2 - d.r1) * heightFrac;
    let Area = Math.PI * (d.r1 + ry) * Math.sqrt((ry - d.r1)**2 + y**2) + Math.PI * d.r1**2;
    Area = Area / 10000;

    history.push({ time: t, iceRatio: iceRatio * 100, vol: currentVol / ozToMl });

    let dQ = h_coeff * Area * (temp - 0) * (dt * 60);
    let melted = dQ / Lf;
    melted = Math.min(melted, m_ice);
    m_ice -= melted;
    m_liq += melted;

    let volOut = C_ml * dt;
    let r_out = iceRatio * currentBias;
    m_ice -= Math.min(m_ice, volOut * r_out * rho_ice);
    m_liq -= Math.min(m_liq, volOut * (1 - r_out) * rho_liq);

    t += dt;
  }
  return history;
}
Code
results = runSimulation(ambientTempC, cupSize, consumptionRate, initialIceRatio, liquidBias, runTrigger)

// Plot
Plot.plot({
  title: "Ice Ratio Projection",
  subtitle: "Keep the ratio below 90% for a successful finish",
  y: { label: "Ice Ratio (%)", domain: [0, 100] },
  x: { label: "Time (minutes)" },
  marks: [
    Plot.lineY(results, {x: "time", y: "iceRatio", stroke: "steelblue", strokeWidth: 3}),
    Plot.ruleY([90], {stroke: "red", strokeDasharray: "4,4"}),
    Plot.text(["DEAD ZONE"], {x: 0, y: 92, frameAnchor: "left", fill: "red"})
  ]
})
Code
md`
### Analysis
# Under the assumption you would not like ice with no liquid:

Final Ice Ratio: **${results[results.length-1].iceRatio.toFixed(1)}%**  
Total Time: **${results[results.length-1].time.toFixed(1)} minutes**

${results[results.length-1].iceRatio > 90 
  ? "❌ **FAILED**: You were left with a block of dry ice! Decrease your consumption rate or find a warmer spot." 
  : "✅ **SUCCESS**: A perfect balance of phase-change and consumption."}
`

Summary of Optimal Temperatures

The following table shows the minimum ambient temperature required to finish a 7-11 slushee at two different steady consumption rates without hitting the Dead Zone (assuming an initial ice ratio of 60%).

Cup Size 2 oz/min (Standard) 3 oz/min (Fast)
Small (12 oz) ~14°C (57°F) ~20°C (68°F)
Medium (22 oz) ~21°C (70°F) ~27°C (81°F)
Large (30 oz) ~26°C (79°F) ~33°C (91°F)
X-Large (40 oz) ~32°C (90°F) ~39°C (102°F)

Conclusion

The larger the cup, the lower the surface-area-to-volume ratio, and thus the slower the relative melting rate. If you want to drink the entire thing without having to wait around for more to melt and you’re going for the 40oz X-Large, you’d better be drinking it in the heat of mid-July.

Stay tuned for the sequel when I empirically test this on my next bike ride home.

All this is to say, keep ICE out of all things, including the final moments of drinking a slushee!