exupero's blog
RSSApps

Modeling a simple thermodynamics problem

In the previous post I walked through a process that transfers heat from hot water to cold water such that the cold water ends up warmer than the hot water ends up. To explore the paradox further, I first want to model it in code.

There are only three ways we can change the system:

For now, we won't use code to divide the water in a bottle, we'll just represent divided water as data:

[{:amount 1 :temp 80}
 {:amount 0.5 :temp 20}
 {:amount 0.5 :temp 20}]

Equalizing temperatures is the most complex step. The excess heat in the hot water must be redistributed across the total amount of water. The expression (/ (+ a1 a2) a1) calculates the total amount of water in "units" of the first amount of water given. The change in temperature is the difference in temperature divided by that total amount of water:

(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}]))

Testing it out with one bottle of 80°C water and a half-bottle of 20°C water equalizes both bottles to 60°C:

(equalize-temperatures {:amount 1 :temp 80} {:amount 0.5 :temp 20})
[{:amount 1, :temp 60.0} {:amount 0.5, :temp 60.0}]

Re-mixing cold water uses the same logic but combines both bottles into one:

(defn mix [a b]
  (let [[{a1 :amount t :temp} {a2 :amount}] (equalize-temperatures a b)]
    {:amount (+ a1 a2)
     :temp t}))

To simulate the process, we can reduce over divisions of the cold water bottle:

(defn heat-cold-water [hot colds]
  (reduce
    (fn [{:keys [hot cold]} new-cold]
      (let [[hot' cold'] (equalize-temperatures hot new-cold)]
        {:hot hot'
         :cold (if cold
                 (mix cold cold')
                 cold')}))
    {:hot hot :cold nil}
    colds))
(heat-cold-water
  {:amount 1 :temp 80}
  [{:amount 0.5 :temp 20} {:amount 0.5 :temp 20}])
{:hot {:amount 1, :temp 46.66666666666667},
 :cold {:amount 1.0, :temp 53.333333333333336}}

Good, same results as in the previous post. Now we can experiment with smaller portions of cold water.