exupero's blog
RSSApps

Analysis of incremental water heating

Having explored this thermodynamics problem numerically, I now want to look at it analytically and see what math points to as the theoretical limit for how warm we can get the cold water (and how cold we can get the hot water).

The core logic we've used so far has been this function:

(defn equalize-temperatures [{a1 :amount t1 :temp} {a2 :amount t2 :temp}]
  (let [change (/ (- (max t1 t2) (min t1 t2))
                  (/ (+ a1 a2) a1))
        new-temp (if (<= t1 t2)
                   (- t2 change)
                   (+ t2 change))]
    [{:amount a1 :temp new-temp}
     {:amount a2 :temp new-temp}]))

To express this in symbolic math, we'll think in terms of an iterative system, in which the temperature of the hot water at each step depends on the temperature of the hot water at the previous step, the constant temperature of the cold water, and the amount of cold water immersed in the hot water.

Continuing to work in code for a moment, we can simplify the logic by making a few assumptions:

  1. a1 and t1 always refers to the hot water
  2. a1 is always 1 (all the hot water)
  3. a2 is never more than 1
  4. t2 (the cold water's temperature) is always less than t1 (the hot water's temperature)
  5. we only need the new temperature at equilibrium

With those assumptions, the code boils down to this:

(defn new-temperature [{t1 :temp} {a :amount t2 :temp}]
  (+ t2 (/ (- t1 t2) (+ 1 a))))

which is much easier to translate into math:

What we really want is the difference in temperature at each step:

Translating from discrete to continuous terms gives us this:

Stated non-symbolically, the rate of the hot water's temperature change is proportional to the difference between its temperature at any given moment and the temperature of the cold water. That means the above formulation is just Newton's Law of Cooling:

Newton's Law of Cooling is a differential equation whose solution is

Substituting in the elements from our formulation above gives us

In the discrete form, n ranged from 0 to the number of batches, which is the reciprocal of the fractional amount, or 1/a. In the continuous form, t has the same range. The final temperature of the hot water, then, is

As a goes to zero, we get

Substitute in known values:

Thus, in theory, the hot water could get down to about 42.0728°C, at which point the cold water would be 57.9272°C. Those results match to three decimal places the numbers we got numerically when we divided the cold water into 10,000 separate batches:

(heat-cold-water
  {:amount 1 :temp 80}
  (repeat 1e5 {:amount 1e-5 :temp 20}))
{:hot {:amount 1, :temp 42.072876833515096},
 :cold {:amount 0.9999999999980838, :temp 57.92712316626038}}

Since 10,000 batches got us within 0.0003% of the theoretical limit, what's the fewest batches would we need to get within just 1% of the theoretical limit?

(let [limit (+ 20 (* 60 (Math/exp -1)))]
  (sequence
    (comp
      (map (fn [batches]
             [batches
              (-> (heat-cold-water
                    {:amount 1 :temp 80}
                    (repeat batches {:amount (/ batches) :temp 20}))
                :hot :temp
                (as-> $ (/ (- $ limit) limit)))]))
      (drop-while (comp #(< 0.01 %) second))
      (take 1))
    (iterate inc 2)))
([26 0.009930457750641221])

Only 26 batches. Seems feasible (under ideal conditions).