gravitheque 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ # Calculate how many calories a beer contains
2
+ module Calories
3
+
4
+ # Calculates calories from alcohol
5
+ #
6
+ # @note
7
+ # Extract must be measured in specific gravity
8
+ #
9
+ # @example
10
+ # Calories.from_alcohol 1.055, 1.01
11
+ #
12
+ # @param [Float] original original gravity
13
+ # @param [Float] terminal terminal gravity
14
+ # @return [Fixnum] calories from alcohol
15
+ def self.from_alcohol original, terminal
16
+ ((1881.22 * terminal) *
17
+ ((original - terminal) / (1.775 - original))).round
18
+ end
19
+
20
+ # Calculates calories from extract
21
+ #
22
+ # @note
23
+ # Extract must be measured in specific gravity
24
+ #
25
+ # @example
26
+ # Calories.from_extract 1.055, 1.01
27
+ #
28
+ # @param [Float] original original gravity
29
+ # @param [Float] terminal terminal gravity
30
+ # @return [Fixnum] calories from extract
31
+ def self.from_extract original, terminal
32
+ (3550.0 * terminal *
33
+ ((0.1808 * original) + (0.8192 * terminal) - 1.0004)).round
34
+ end
35
+
36
+ # Calculates calories per serving; i.e. 500ml
37
+ #
38
+ # @note
39
+ # Extract must be measured in specific gravity
40
+ #
41
+ # @example
42
+ # Calories.per_serving 1.055, 1.01
43
+ #
44
+ # @param [Float] original original gravity
45
+ # @param [Float] terminal terminal gravity
46
+ # @return [Fixnum] calories per serving
47
+ def self.per_serving original, terminal
48
+ (from_alcohol original, terminal) +
49
+ (from_extract original, terminal)
50
+ end
51
+
52
+ end
@@ -0,0 +1,140 @@
1
+ # Various hop calculations
2
+ module Hops
3
+
4
+ # Calculates hop utilization.
5
+ #
6
+ # @note
7
+ # Extract must be measured in specific gravity
8
+ #
9
+ # @example
10
+ # Hops.utilization 20, 1.055
11
+ #
12
+ # @param [Fixnum] time remaining boil time
13
+ # @param [Float] extract specific gravity of wort
14
+ # @return [Float] hop utilization
15
+ def self.utilization time, extract
16
+ ((extract_adjustment extract) *
17
+ ((time_adjustment time) / 4.15)).round 2
18
+ end
19
+
20
+ # Calculate boil time adjustment
21
+ #
22
+ # @example
23
+ # Hops.time_adjustment 60
24
+ #
25
+ # @param [Fixnum] time remaining boil time
26
+ # @return [Float] boil time adjustment
27
+ def self.time_adjustment time
28
+ (1 - Math.exp(-0.04 * time)).round 2
29
+ end
30
+
31
+ # Calculate extract adjustment
32
+ #
33
+ # @note
34
+ # Extract must be measured in specific gravity
35
+ #
36
+ # @example
37
+ # Hops.extract_adjustment 1.065
38
+ #
39
+ # @param [Float] extract specific gravity of wort
40
+ # @return [Float] extract adjustment
41
+ def self.extract_adjustment extract
42
+ (1.65 * 0.000125 ** (extract - 1)).round 2
43
+ end
44
+
45
+ # Calculates IBUs for hop addition
46
+ #
47
+ # @note
48
+ # Extract must be measured specific gravity, mass in grams and volume in liters
49
+ #
50
+ # @example
51
+ # Hops.ibus({
52
+ # alpha: 12.4,
53
+ # extract: 1.055,
54
+ # mass: 56,
55
+ # time: 90,
56
+ # volume: 20
57
+ # })
58
+ #
59
+ # @param [Hash] data data required to calculate IBUs; `alpha`, `extract`, `mass`, `time`, `volume`
60
+ # @return [Fixnum] IBUs from hop addition
61
+ def self.ibus data
62
+ (extract_adjustment(data[:extract]) *
63
+ time_adjustment(data[:time]) * (data[:alpha] / 100) *
64
+ data[:mass] * 1000 / (data[:volume] * 4.15)).round
65
+ end
66
+
67
+ # Calculates hop mass required to achieve specific IBUs.
68
+ #
69
+ # @note
70
+ # Extract must be measured specific gravity, mass in grams and volume in liters
71
+ #
72
+ # @example
73
+ # Hops.hop_mass_required({
74
+ # alpha: 1.05,
75
+ # extract: 16,
76
+ # ibus: 25,
77
+ # time: 60,
78
+ # volume: 20
79
+ # })
80
+ #
81
+ # @param [Hash] data data required to calculate hop mass required; `alpha`, `extract`, `ibus`, `time`, `volume`
82
+ # @return [Float] hop mass required to achieve specific IBUs
83
+ def self.mass_required data
84
+ ((data[:volume] * data[:ibus]) /
85
+ (utilization(data[:time], data[:extract]) *
86
+ data[:alpha] * 10)).round
87
+ end
88
+
89
+ # Calculate milliliters of HopShot required to achieve specific IBUs.
90
+ #
91
+ # @note
92
+ # Extract must be measured specific gravity, mass in grams and volume in liters
93
+ #
94
+ # @example
95
+ # Hops.hopshot_required({
96
+ # alpha: 13.5,
97
+ # extract: 1.05,
98
+ # ibus: 25,
99
+ # time: 60,
100
+ # volume: 20
101
+ # })
102
+ #
103
+ # @param [Hash] data data required to calculate HopShot required; `alpha`, `extract`, `ibus`, `time`, `volume`
104
+ # @return [Float] milliliters of HopShot required to achieve specific IBUs
105
+ def self.hopshot_required data
106
+ unadjusted_amount = (data[:ibus] / 10.0) * (data[:volume] / 19.0)
107
+
108
+ hopshot_required = unadjusted_amount +
109
+ (unadjusted_amount * hopshot_extract_adjustment(data[:extract]))
110
+
111
+ if data[:time] >= 90
112
+ hopshot_required = hopshot_required - (unadjusted_amount * 0.1)
113
+ end
114
+
115
+ hopshot_required.round 1
116
+ end
117
+
118
+ # Calculate extract adjustment for HopShot
119
+ #
120
+ # @note
121
+ # Extract must be measured in specific gravity
122
+ #
123
+ # @example
124
+ # Hops.hopshot_extract_adjustment 1.065
125
+ #
126
+ # @param [Float] extract specific gravity of wort
127
+ # @return [Float] HopShot extract adjustment
128
+ def self.hopshot_extract_adjustment extract
129
+ if extract >= 1.08 && extract < 1.1
130
+ 0.1
131
+ elsif extract >= 1.1 && extract < 1.15
132
+ 0.2
133
+ elsif extract >= 1.15
134
+ 0.3
135
+ else
136
+ 0
137
+ end
138
+ end
139
+
140
+ end
@@ -0,0 +1,57 @@
1
+ # Various mash calculations
2
+ module Mash
3
+
4
+ # Calculates strike water temperature
5
+ #
6
+ # @note
7
+ # Temperatures must be measured in Celsius, ratio is liters per kilograms
8
+ #
9
+ # @example
10
+ # Mash.strike_water({
11
+ # initial: 20, # temperature of grain; i.e. ambient temperature
12
+ # target: 60, # target mash temperature
13
+ # ratio: 1.25 # water to grain ratio; e.g. 1.25L/kg
14
+ # })
15
+ #
16
+ # Mash.strike_water({
17
+ # initial: 20,
18
+ # target: 60,
19
+ # ratio: 1.25,
20
+ # adjustment: 1.015 # calculated temperature is multiplied by the adjustment to compensate for heat lost to the mash tun
21
+ # })
22
+ #
23
+ # @param [Hash] data data required to calculate strike temperature; `initial`, `target`, `ratio` and optionally `adjustment`
24
+ # @return [Fixnum] strike water temperature
25
+ def self.strike_temperature data
26
+ adjustment = data[:adjustment] || 1
27
+ target = data[:target]
28
+
29
+ (((0.41 / data[:ratio]) *
30
+ (target - data[:initial]) +
31
+ target) * adjustment).round
32
+ end
33
+
34
+ # Calculates volume of boiling water needed to increase mash temperature
35
+ #
36
+ # @note
37
+ # Temperatures must be measured in Celsius, mass in kilograms and volume in liters
38
+ #
39
+ # @example
40
+ # Mash.infusion_volume({
41
+ # initial: 40, # current mash temperature
42
+ # target: 60, # target mash temperature
43
+ # mass: 4, # grain mass in mash
44
+ # volume: 6 # water volume in mash
45
+ # })
46
+ #
47
+ # @param [Hash] data data required to calculate strike temperature; `initial`, `target`, `mass`, `volume`
48
+ # @return [Float] liters of infusion water needed for step
49
+ def self.infusion_volume data
50
+ target = data[:target]
51
+
52
+ ((target - data[:initial]) *
53
+ ((0.41 * data[:mass]) + data[:volume]) /
54
+ (100 - target)).round 1
55
+ end
56
+
57
+ end
@@ -0,0 +1,201 @@
1
+ # Methods for converting Fixnums between units
2
+ class Fixnum
3
+
4
+ # Covert Plato to specific gravity
5
+ #
6
+ # @example
7
+ # 14.to_specific_gravity
8
+ #
9
+ # @return [Float] degrees Plato
10
+ def to_specific_gravity
11
+ self.to_f.to_specific_gravity
12
+ end
13
+
14
+ # Covert Fahrenheit to Celsius
15
+ #
16
+ # @example
17
+ # 104.to_celsius
18
+ #
19
+ # @return [Fixnum] temperature in Celsius
20
+ def to_celsius
21
+ ((self - 32) / 1.8).round
22
+ end
23
+
24
+ # Covert Celsius to Fahrenheit
25
+ #
26
+ # @example
27
+ # 60.to_fahrenheit
28
+ #
29
+ # @return [Fixnum] temperature in Fahrenheit
30
+ def to_fahrenheit
31
+ ((self * 1.8) + 32).round
32
+ end
33
+
34
+ # Covert gallons (or quarts) to liters
35
+ #
36
+ # @example
37
+ # 5.to_liters
38
+ # 15.to_liters :quarts
39
+ #
40
+ # @return [Float] volume in liters
41
+ def to_liters unit = :gallons
42
+ self.to_f.to_liters unit
43
+ end
44
+
45
+ # Covert ounces to grams
46
+ #
47
+ # @example
48
+ # 2.to_grams
49
+ #
50
+ # @return [Float] mass in grams
51
+ def to_grams
52
+ self.to_f.to_grams
53
+ end
54
+
55
+ # Covert grams to ounces
56
+ #
57
+ # @example
58
+ # 56.to_ounces
59
+ #
60
+ # @return [Float] mass in ounces
61
+ def to_ounces
62
+ self.to_f.to_ounces
63
+ end
64
+
65
+ # Covert pounds to kilograms
66
+ #
67
+ # @example
68
+ # 10.to_kilograms
69
+ #
70
+ # @return [Float] mass in kilograms
71
+ def to_kilograms
72
+ self.to_f.to_kilograms
73
+ end
74
+
75
+ # Covert kilograms to pounds
76
+ #
77
+ # @example
78
+ # 10.to_pounds
79
+ #
80
+ # @return [Float] mass in pounds
81
+ def to_pounds
82
+ self.to_f.to_pounds
83
+ end
84
+
85
+ # Gravity correction based on sample temperature
86
+ #
87
+ # @note
88
+ # Temperature must be measured in Celsius
89
+ #
90
+ # @example
91
+ # 40.gravity_correction
92
+ #
93
+ # @return [Float] mass in pounds
94
+ def gravity_correction
95
+ if self < 3.98
96
+ -0.000032692 * self - 0.000740644
97
+ elsif self < 50
98
+ -0.0008031922 - 0.0000473773 * self + 0.000007231263 * self * self - 0.00000003078278 * self * self * self
99
+ else
100
+ -0.005431719 + 0.0001963596 * self + 0.000002661056 * self * self
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ # Methods for converting Floats between units
107
+ class Float
108
+
109
+ # Covert specific gravity to Plato
110
+ #
111
+ # @example
112
+ # 1.055.to_plato
113
+ #
114
+ # @return [Float] degrees Plato
115
+ def to_plato
116
+ (-676.67 + 1286.4 * self - 800.47 * self * self + 190.74 * self * self * self).round 1
117
+ end
118
+
119
+ # Covert Plato to specific gravity
120
+ #
121
+ # @example
122
+ # 13.6.to_specific_gravity
123
+ #
124
+ # @return [Float] degrees Plato
125
+ def to_specific_gravity
126
+ (self / (258.6 - ((self / 258.2) * 227.1)) + 1.0).round 3
127
+ end
128
+
129
+ # Covert specific gravity to temperature corrected specific gravity
130
+ #
131
+ # @example
132
+ # 1.055.to_temperature_corrected_specific_gravity 40
133
+ # 1.055.to_temperature_corrected_specific_gravity 110, :fahrenheit
134
+ #
135
+ # @param [Fixnum] temperature temperature of sample
136
+ # @param [Symbol] unit unit of temperature used; `:celsius` or `:fahrenheit`
137
+ # @return [Float] temperature corrected specific gravity
138
+ def to_temperature_corrected_specific_gravity temperature, unit = :celsius
139
+ temperature = temperature.to_celsius unless unit == :celsius
140
+ correction = temperature.gravity_correction
141
+
142
+ (self + correction).round 3
143
+ end
144
+
145
+ # Covert gallons (or quarts) to liters
146
+ #
147
+ # @example
148
+ # 5.to_liters
149
+ # 15.to_liters :quarts
150
+ #
151
+ # @return [Float] volume in liters
152
+ def to_liters unit = :gallons
153
+ case unit
154
+ when :gallons
155
+ (self * 3.785412).round 1
156
+ when :quarts
157
+ (self * 0.946353).round 1
158
+ end
159
+ end
160
+
161
+ # Covert ounces to grams
162
+ #
163
+ # @example
164
+ # 5.5.to_grams
165
+ #
166
+ # @return [Float] mass in grams
167
+ def to_grams
168
+ (self * 28.3495231).round 1
169
+ end
170
+
171
+ # Covert grams to ounces
172
+ #
173
+ # @example
174
+ # 100.5.to_ounces
175
+ #
176
+ # @return [Float] mass in ounces
177
+ def to_ounces
178
+ (self * 0.0352739619).round 1
179
+ end
180
+
181
+ # Covert pounds to kilograms
182
+ #
183
+ # @example
184
+ # 15.5.to_kilograms
185
+ #
186
+ # @return [Float] mass in kilograms
187
+ def to_kilograms
188
+ (self * 0.453592).round 1
189
+ end
190
+
191
+ # Covert kilograms to pounds
192
+ #
193
+ # @example
194
+ # 7.5.to_pounds
195
+ #
196
+ # @return [Float] mass in pounds
197
+ def to_pounds
198
+ (self * 2.204623).round 1
199
+ end
200
+
201
+ end