tikaro-sandex 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +5 -4
- data/VERSION.yml +1 -1
- data/lib/sandex.rb +72 -11
- data/lib/sandex/fanger_box.rb +50 -0
- metadata +4 -2
data/README.rdoc
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
== Description
|
6
6
|
|
7
|
-
The sandex is an index of awesome your weather is, compared to the
|
7
|
+
The sandex is an index of awesome your weather is, compared to the theoretically-perfect weather in San Diego, CA. The highest possible sandex is 100%.
|
8
8
|
|
9
9
|
This score is used to answer the question: "Is it nice enough to work outside today?" If the sandex is high, yes: go work outside. That's because EVERY day is a work-outside day in San Diego.
|
10
10
|
|
@@ -13,8 +13,9 @@ Thanks to @r38y for the concept and the name.
|
|
13
13
|
== Features
|
14
14
|
|
15
15
|
- Given a NOAA station ID, calculate the sandex.
|
16
|
-
-
|
17
|
-
|
16
|
+
- Using the work of professor Ole Fanger, determine whether the temperature and relative humidity fall inside parameters for thermal comfort:
|
17
|
+
-- is the relative humidity below 60%?
|
18
|
+
-- is the temperature above minimum, but below maximum parameters?
|
18
19
|
|
19
20
|
== Requirements
|
20
21
|
|
@@ -32,7 +33,7 @@ Note that the NOAA gem has some separate install requirements, and must update i
|
|
32
33
|
== Usage
|
33
34
|
|
34
35
|
Get the current sandex score for your location:
|
35
|
-
Sandex.calculate(station_id)
|
36
|
+
Sandex.calculate(station_id, "verbose")
|
36
37
|
|
37
38
|
== Contact
|
38
39
|
|
data/VERSION.yml
CHANGED
data/lib/sandex.rb
CHANGED
@@ -8,18 +8,79 @@ require 'libxml'
|
|
8
8
|
require 'geokit'
|
9
9
|
require 'noaa'
|
10
10
|
|
11
|
+
%w(fanger_box).each { |file| require File.join(File.dirname(__FILE__), 'sandex', file) }
|
12
|
+
|
11
13
|
module Sandex
|
12
|
-
def self.calculate(local_station='KILG')
|
13
|
-
local_conditions = NOAA.current_conditions_at_station(local_station)
|
14
|
-
ksan_conditions = NOAA.current_conditions_at_station('KSAN')
|
15
|
-
|
16
|
-
local_temperature = local_conditions.temperature
|
17
|
-
ksan_temperature = ksan_conditions.temperature
|
18
14
|
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
def self.calculate(station='KILG', verbose=nil)
|
16
|
+
|
17
|
+
# KCOS: Colorado Springs
|
18
|
+
# KILG: West Chester
|
19
|
+
# KNYC: Central Park
|
20
|
+
|
21
|
+
sandex_score = 100
|
22
|
+
humidity_decrement = 0
|
23
|
+
temperature_decrement = 0
|
24
|
+
msg = ""
|
25
|
+
|
26
|
+
humidity_penalty = 2.5
|
27
|
+
heat_penalty = 2
|
28
|
+
cold_penalty = 1
|
29
|
+
|
30
|
+
current_conditions = NOAA.current_conditions_at_station(station)
|
31
|
+
t = current_conditions.temperature
|
32
|
+
rh = current_conditions.relative_humidity
|
33
|
+
|
34
|
+
msg += "At station #{station}, it's currently #{t} degrees and #{rh}% humidity.\n\n"
|
35
|
+
|
36
|
+
# Are we within the Fanger box?
|
37
|
+
if FangerBox.acceptable?(t,rh)
|
38
|
+
msg += "Conditions are WITHIN the Fanger Box!\n"
|
39
|
+
else
|
40
|
+
|
41
|
+
msg += "Sadly, conditions are not inside the Fanger Box:\n"
|
42
|
+
|
43
|
+
# calculate the humidity decrement
|
44
|
+
if FangerBox.too_dry?(rh)
|
45
|
+
msg += "* It's too dry.\n"
|
46
|
+
elsif FangerBox.too_humid?(rh)
|
47
|
+
humidity_delta = rh - FangerBox::HIGHEST_ALLOWABLE_HUMIDITY
|
48
|
+
humidity_decrement = humidity_delta * humidity_penalty
|
49
|
+
msg += "* It's too humid: (#{humidity_delta}% outside the Fanger Box)\n"
|
50
|
+
msg += " Decrement: #{humidity_penalty} Sandex points for each percent of humidity.\n"
|
51
|
+
msg += " Subtracting #{humidity_decrement} points from the Sandex.\n"
|
52
|
+
else
|
53
|
+
msg += "* The humidity is within the box, but the temperature is outside it.\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
# calculate the temperature decrement
|
57
|
+
if FangerBox.too_cold?(t,rh)
|
58
|
+
cold_delta = FangerBox.minimum_temperature_at_humidity(rh) - t
|
59
|
+
temperature_decrement = cold_delta * cold_penalty
|
60
|
+
msg += "* It's #{cold_delta} degrees too chilly for the Fanger Box.\n"
|
61
|
+
msg += " Decrement: #{cold_penalty} Sandex points for each degree too cold.\n"
|
62
|
+
msg += " Subtracting #{temperature_decrement} points from the Sandex.\n"
|
63
|
+
elsif FangerBox.too_hot?(t,rh)
|
64
|
+
heat_delta = t - FangerBox.maximum_temperature_at_humidity(rh)
|
65
|
+
temperature_decrement = heat_delta * heat_penalty
|
66
|
+
msg += "* It's #{heat_delta} degrees too hot for the Fanger Box.\n"
|
67
|
+
msg += " Decrement: #{heat_penalty} Sandex points for each degree too hot.\n"
|
68
|
+
msg += " Subtracting #{temperature_decrement} points from the Sandex.\n"
|
69
|
+
else
|
70
|
+
msg += "* Temperature is within the Fanger box, though the humidity is outside it."
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
sandex_score -= humidity_decrement
|
76
|
+
sandex_score -= temperature_decrement
|
77
|
+
|
78
|
+
msg += "\nThe Sandex score for station #{station} is #{sandex_score}.\n"
|
22
79
|
|
23
|
-
|
24
|
-
|
80
|
+
puts msg if verbose == "verbose"
|
81
|
+
|
82
|
+
sandex_score
|
83
|
+
|
84
|
+
end
|
85
|
+
|
25
86
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module FangerBox
|
2
|
+
|
3
|
+
LOWEST_ALLOWABLE_HUMIDITY = 0
|
4
|
+
HIGHEST_ALLOWABLE_HUMIDITY = 60
|
5
|
+
|
6
|
+
def self.acceptable?(t,rh)
|
7
|
+
# I tried writing this as A < B < C, but it didn't work. Huh.
|
8
|
+
t > minimum_temperature_at_humidity(rh) && t < maximum_temperature_at_humidity(rh)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.rh_acceptable?(rh)
|
12
|
+
# A < B < C works here.
|
13
|
+
LOWEST_ALLOWABLE_HUMIDITY < rh < HIGHEST_ALLOWABLE_HUMIDITY
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.too_dry?(rh)
|
17
|
+
# Fanger believed that humidity below 30% felt weird, but not uncomfortable.
|
18
|
+
rh <= LOWEST_ALLOWABLE_HUMIDITY
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.too_humid?(rh)
|
22
|
+
# Fanger believed that humidity above 60% was pretty much always crappy.
|
23
|
+
rh > HIGHEST_ALLOWABLE_HUMIDITY
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.too_cold?(t,rh)
|
27
|
+
t < minimum_temperature_at_humidity(rh)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.too_hot?(t,rh)
|
31
|
+
t > maximum_temperature_at_humidity(rh)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.minimum_temperature_at_humidity(rh)
|
35
|
+
# Based on the two bottom corners of the Fanger box:
|
36
|
+
# * 69 degrees at 30% relative humidity
|
37
|
+
# * 68 degrees at 60% relative humidity
|
38
|
+
((1/30) * rh ) + 70
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.maximum_temperature_at_humidity(rh)
|
42
|
+
# Based on the top two corners of the Fanger box:
|
43
|
+
# * 82 degrees at 30% relative humidity
|
44
|
+
# * 78 degrees at 60% relative humidity
|
45
|
+
((4/30) * rh ) + 86
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tikaro-sandex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tikaro
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-11 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -25,6 +25,8 @@ extra_rdoc_files:
|
|
25
25
|
files:
|
26
26
|
- README.rdoc
|
27
27
|
- VERSION.yml
|
28
|
+
- lib/sandex
|
29
|
+
- lib/sandex/fanger_box.rb
|
28
30
|
- lib/sandex.rb
|
29
31
|
- test/sandex_test.rb
|
30
32
|
- test/test_helper.rb
|