add Tinseth IBU calculations, require 'org-cook
[org-brew.git] / brew-calc.el
blobe2570e73246fdb21d5ebcf11cfdeb3b7725f94e2
1 ;;; brew-calc.el --- calc functions for brewing ber
2 ;;
3 ;; Copyright (C) 2009 Erik Hetzner
4 ;;
5 ;; Author: Erik Hetzner <ehetzner@gmail.com>
6 ;;
7 ;; This file is NOT part of GNU Emacs.
8 ;;
9 ;; This program is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ;; calc functions for brewing
23 (require 'org-cook)
25 (org-food-alist-append 'math-additional-units
26 '((degPlato nil "Degrees Plato")))
28 (setq math-units-table nil)
30 (defmath brewNorm (v)
31 "Get the norm of a value with units."
32 (math-simplify (math-remove-units v)))
34 (defmath brew2C (temp)
35 "Ensure that a temperature is in degC."
36 (let ((old-units (math-units-in-expr-p temp t)))
37 (math-simplify
38 (cond ((not old-units)
39 (error "Not a temperature."))
40 ((eq (nth 0 old-units) 'degC)
41 (math-simplify temp))
42 ((eq (nth 0 old-units) 'degF)
43 (math-convert-temperature temp '(var degF var-degF) '(var degC var-degC)))))))
45 (defmath brew2MG_L (expr)
46 "Ensure that a mass / vol is in mg / L."
47 (math-convert-units
48 expr
49 '(/ (var mg var-m)
50 (var L var-L))))
52 (defmath brew2min (expr)
53 "Ensure that a time is in minutes."
54 (math-convert-units expr '(var min var-min)))
56 ;; From Wikipedia, Plato_scale
57 (defmath brewSG2P (sg)
58 "Convert from Specific gravity to Plato, correcting SG vector
59 if necessary."
60 (let ((sg1 (brewSGCorr sg)))
61 (* (+ :"-616.868"
62 (+ (* :"1111.14" sg1)
63 (+ (* :"-630.272"
64 (^ sg1 2))
65 (+ (* :"135.997"
66 (^ sg1 3))))))
67 '(var degPlato var-degPlato))))
69 ;; From Wikipedia, Plato_scale
70 (defmath brewP2SG (p)
71 "Convert Plato (degPlato) to specific gravity (unitless)."
72 (let ((pn (brewNorm p)))
73 (math-simplify (/ (- 668
74 (nroot (- (^ 668 2)
75 (* 820
76 (+ 463 pn)))
77 2))
78 410))))
80 (defmath brew2P (n)
81 "Ensure that a value is in degrees Plato (degPlato)."
82 (if (eq (car (math-units-in-expr-p n t)) 'degPlato)
84 (brewSG2P n)))
86 (defmath brew2SG (n)
87 "Ensure that a value is in corrected, unitless, specific
88 gravity points."
89 (if (eq (car (math-units-in-expr-p n t)) 'degPlato)
90 (brewP2SG n)
91 (brewSGCorr n)))
93 ;;(defmath brewFpn (x)
94 ;; (let ((Pn (brewNorm (brew2P x))))
95 ;; (+ :"0.48394"
96 ;; (+ (* :"0.0024688" Pn)
97 ;; (* :"0.00001561" (^ Pn 2))))))
99 ;;(defmath brewAW (P n)
100 ;; (let ((P1 (brewNorm (brew2P P)))
101 ;; (n1 (brewNorm (brew2P n))))
102 ;; (* (brewFpn P1)
103 ;; (- P1 n1))))
105 (defmath brewAW2AV (aw ae)
106 "Convert Alcohol by weight to alcohol by volume."
107 (* aw (/ (brew2SG ae) :"0.79661")))
109 (defmath brewAV (oe ae)
110 "Calculate alc by vol. given original extract and apparent
111 final extract."
112 (brewAW2AV
113 (brewAWFix oe ae) ae))
115 ;; From George Fix, http://hbd.org/hbd/archive/880.html#880-9, due to
116 ;; Balling.
117 (defmath brewRE (oe ae)
118 "Calculate real extraction, given original extract and apparent
119 final extract."
120 (let ((oe1 (brewNorm (brew2P oe)))
121 (ae1 (brewNorm (brew2P ae))))
122 (math-simplify
123 (* (+ (* :"0.1808" oe1)
124 (* :"0.8192" ae1))
125 '(var degPlato var-degPlato)))))
127 (defmath brewAWFix (oe ae)
128 "Calculate alc. by weight, given original extract and apparent
129 final extract."
130 (let* ((oe1 (brewNorm (brew2P oe)))
131 (ae1 (brewNorm (brew2P ae)))
132 (re (brewNorm (brewRE oe ae))))
133 (/ (- oe1 re)
134 (- :"2.0665"
135 (* :"0.010665" oe1)))))
137 (defmath brewCalories (oe ae)
138 "Calculate cal/L, given original extract and apparent final
139 extract."
140 (let* ((fg (brew2SG ae))
141 (a (brewAWFix oe ae))
142 (re (brewNorm (brewRE oe ae))))
143 (* (* (* (+ (* :"6.9" a)
144 (* :"4.0" (- re :".1")))
147 (/ '(var Kcal var-Kcal)
148 '(var L var-L)))))
150 (defmath brewRA (oe ae)
151 "Calculate approximation to real attenuation."
152 (let ((re (brewNorm (brewRE oe ae)))
153 (oe1 (brewNorm (brew2P oe))))
154 (- 1 (/ re oe1))))
156 (defmath brewAA (oe ae)
157 "Calculate approximate attenuation."
158 (let ((ae1 (brewNorm (brew2P ae)))
159 (oe1 (brewNorm (brew2P oe))))
160 (- 1 (/ ae1 oe1))))
163 ;; Per http://www.csgnetwork.com/h2odenscalc.html and
164 ;; http://www.earthwardconsulting.com/density.xls
165 (defmath brewRhoCalc (temp)
166 "Calculate factor by which water at a given temp differs from
167 water at ref. temp (~4 degC)"
168 (let ((tempn (brewNorm (brew2C temp))))
169 (math-simplify
170 (- 1 (* (/ (+ tempn :"288.9414")
171 (* :"508929.2"
172 (+ tempn :"68.12963")))
173 (^ (- tempn :"3.9863") 2))))))
175 ;; Follows from above, assuming that beer has the same relationship to
176 ;; temperature as water does.
177 (defmath brewSGCorr (sg)
178 "Ensures that specific gravity is in a corrected, unitless
179 number, rather than a vector containing measured gravity, temp of
180 sampled liquid, and calibration temp, e.g. [1.010, 74 degF, 20
181 degC]"
182 (if (not (vectorp sg))
184 (let ((ir (nth 1 sg))
185 (it (nth 2 sg))
186 (ct (nth 3 sg)))
187 (/ (* (brewRhoCalc ct) ir)
188 (brewRhoCalc it)))))
190 (defmath brewTinsethBigness (ex)
191 "Calculate the Tinseth 'bigness' AA utilization factor."
192 (let ((sg (brew2SG ex)))
193 (* :"1.65"
194 (^ :"0.000125"
195 (- sg 1)))))
197 (defmath brewTinsethBoilTime (time)
198 "Calculate the Tinseth 'boil time' AA utilization factor."
199 (let ((min (brewNorm (brew2min time))))
200 (/ (- 1 (^ e (* min :"-0.04")))
201 :"4.15")))
203 (defmath brewTinsethAAUtil (ex m)
204 "Calculate the Tinseth AA utilization factor."
205 (* (brewTinsethBigness ex)
206 (brewTinsethBoilTime m)))
208 (defmath brewTinsethIBU (time hop-mass aa boil-size ex)
209 "Calculate the IBUs given a time, mass of hops, aa of hops,
210 size of boil, and extract (SG or Plato)."
211 (* (brewTinsethAAUtil ex time)
212 (brew2MG_L
213 (/ (* aa hop-mass) boil-size))))