earth 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (189) hide show
  1. data/.document +5 -0
  2. data/.gitignore +22 -0
  3. data/.rvmrc +8 -0
  4. data/Gemfile +5 -0
  5. data/LICENSE +20 -0
  6. data/README.markdown +38 -0
  7. data/Rakefile +71 -0
  8. data/VERSION +1 -0
  9. data/earth.gemspec +265 -0
  10. data/lib/earth.rb +169 -0
  11. data/lib/earth/air.rb +13 -0
  12. data/lib/earth/air/aircraft.rb +32 -0
  13. data/lib/earth/air/aircraft/data_miner.rb +171 -0
  14. data/lib/earth/air/aircraft_class.rb +10 -0
  15. data/lib/earth/air/aircraft_class/data_miner.rb +42 -0
  16. data/lib/earth/air/aircraft_manufacturer.rb +9 -0
  17. data/lib/earth/air/aircraft_manufacturer/data_miner.rb +20 -0
  18. data/lib/earth/air/airline.rb +16 -0
  19. data/lib/earth/air/airline/data_miner.rb +57 -0
  20. data/lib/earth/air/airport.rb +44 -0
  21. data/lib/earth/air/airport/data_miner.rb +80 -0
  22. data/lib/earth/air/data_miner.rb +15 -0
  23. data/lib/earth/air/flight_configuration.rb +18 -0
  24. data/lib/earth/air/flight_configuration/data_miner.rb +4 -0
  25. data/lib/earth/air/flight_distance_class.rb +7 -0
  26. data/lib/earth/air/flight_distance_class/data_miner.rb +16 -0
  27. data/lib/earth/air/flight_domesticity.rb +6 -0
  28. data/lib/earth/air/flight_domesticity/data_miner.rb +57 -0
  29. data/lib/earth/air/flight_fuel_type.rb +17 -0
  30. data/lib/earth/air/flight_fuel_type/data_miner.rb +4 -0
  31. data/lib/earth/air/flight_propulsion.rb +18 -0
  32. data/lib/earth/air/flight_propulsion/data_miner.rb +4 -0
  33. data/lib/earth/air/flight_seat_class.rb +12 -0
  34. data/lib/earth/air/flight_seat_class/data_miner.rb +36 -0
  35. data/lib/earth/air/flight_segment.rb +38 -0
  36. data/lib/earth/air/flight_segment/data_miner.rb +334 -0
  37. data/lib/earth/air/flight_service.rb +18 -0
  38. data/lib/earth/air/flight_service/data_miner.rb +4 -0
  39. data/lib/earth/all.rb +10 -0
  40. data/lib/earth/automobile.rb +8 -0
  41. data/lib/earth/automobile/automobile_fuel_type.rb +18 -0
  42. data/lib/earth/automobile/automobile_fuel_type/data_miner.rb +45 -0
  43. data/lib/earth/automobile/automobile_make.rb +14 -0
  44. data/lib/earth/automobile/automobile_make/data_miner.rb +68 -0
  45. data/lib/earth/automobile/automobile_make_fleet_year.rb +15 -0
  46. data/lib/earth/automobile/automobile_make_fleet_year/data_miner.rb +29 -0
  47. data/lib/earth/automobile/automobile_make_year.rb +14 -0
  48. data/lib/earth/automobile/automobile_make_year/data_miner.rb +45 -0
  49. data/lib/earth/automobile/automobile_model.rb +14 -0
  50. data/lib/earth/automobile/automobile_model/data_miner.rb +38 -0
  51. data/lib/earth/automobile/automobile_model_year.rb +15 -0
  52. data/lib/earth/automobile/automobile_model_year/data_miner.rb +51 -0
  53. data/lib/earth/automobile/automobile_size_class.rb +14 -0
  54. data/lib/earth/automobile/automobile_size_class/data_miner.rb +43 -0
  55. data/lib/earth/automobile/automobile_variant.rb +17 -0
  56. data/lib/earth/automobile/automobile_variant/data_miner.rb +464 -0
  57. data/lib/earth/automobile/data_miner.rb +8 -0
  58. data/lib/earth/bus.rb +1 -0
  59. data/lib/earth/bus/bus_class.rb +19 -0
  60. data/lib/earth/bus/bus_class/data_miner.rb +41 -0
  61. data/lib/earth/bus/data_miner.rb +1 -0
  62. data/lib/earth/conversions_ext.rb +45 -0
  63. data/lib/earth/data_miner.rb +10 -0
  64. data/lib/earth/diet.rb +2 -0
  65. data/lib/earth/diet/data_miner.rb +2 -0
  66. data/lib/earth/diet/diet_class.rb +15 -0
  67. data/lib/earth/diet/diet_class/data_miner.rb +36 -0
  68. data/lib/earth/diet/food_group.rb +17 -0
  69. data/lib/earth/diet/food_group/data_miner.rb +26 -0
  70. data/lib/earth/fuel.rb +2 -0
  71. data/lib/earth/fuel/data_miner.rb +2 -0
  72. data/lib/earth/fuel/fuel_price.rb +13 -0
  73. data/lib/earth/fuel/fuel_price/data_miner.rb +20 -0
  74. data/lib/earth/fuel/fuel_type.rb +18 -0
  75. data/lib/earth/fuel/fuel_type/data_miner.rb +37 -0
  76. data/lib/earth/industry.rb +10 -0
  77. data/lib/earth/industry/data_miner.rb +2 -0
  78. data/lib/earth/industry/industries_product_lines.rb +6 -0
  79. data/lib/earth/industry/industries_sectors.rb +6 -0
  80. data/lib/earth/industry/industry.rb +12 -0
  81. data/lib/earth/industry/industry/data_miner.rb +21 -0
  82. data/lib/earth/industry/merchant.rb +5 -0
  83. data/lib/earth/industry/merchant_categories_industries.rb +8 -0
  84. data/lib/earth/industry/merchant_category.rb +6 -0
  85. data/lib/earth/industry/product_line.rb +10 -0
  86. data/lib/earth/industry/product_line/data_miner.rb +18 -0
  87. data/lib/earth/industry/product_lines_sectors.rb +6 -0
  88. data/lib/earth/industry/sector.rb +3 -0
  89. data/lib/earth/inflectors.rb +9 -0
  90. data/lib/earth/locality.rb +10 -0
  91. data/lib/earth/locality/census_division.rb +17 -0
  92. data/lib/earth/locality/census_division/data_miner.rb +21 -0
  93. data/lib/earth/locality/census_region.rb +13 -0
  94. data/lib/earth/locality/census_region/data_miner.rb +17 -0
  95. data/lib/earth/locality/climate_division.rb +17 -0
  96. data/lib/earth/locality/climate_division/data_miner.rb +20 -0
  97. data/lib/earth/locality/country.rb +13 -0
  98. data/lib/earth/locality/country/data_miner.rb +19 -0
  99. data/lib/earth/locality/data_miner.rb +10 -0
  100. data/lib/earth/locality/egrid_region.rb +15 -0
  101. data/lib/earth/locality/egrid_region/data_miner.rb +19 -0
  102. data/lib/earth/locality/egrid_subregion.rb +16 -0
  103. data/lib/earth/locality/egrid_subregion/data_miner.rb +26 -0
  104. data/lib/earth/locality/petroleum_administration_for_defense_district.rb +13 -0
  105. data/lib/earth/locality/petroleum_administration_for_defense_district/data_miner.rb +21 -0
  106. data/lib/earth/locality/state.rb +22 -0
  107. data/lib/earth/locality/state/data_miner.rb +37 -0
  108. data/lib/earth/locality/urbanity.rb +20 -0
  109. data/lib/earth/locality/urbanity/data_miner.rb +4 -0
  110. data/lib/earth/locality/zip_code.rb +29 -0
  111. data/lib/earth/locality/zip_code/data_miner.rb +36 -0
  112. data/lib/earth/pet.rb +4 -0
  113. data/lib/earth/pet/breed.rb +15 -0
  114. data/lib/earth/pet/breed/data_miner.rb +25 -0
  115. data/lib/earth/pet/breed_gender.rb +14 -0
  116. data/lib/earth/pet/breed_gender/data_miner.rb +21 -0
  117. data/lib/earth/pet/data_miner.rb +4 -0
  118. data/lib/earth/pet/gender.rb +10 -0
  119. data/lib/earth/pet/gender/data_miner.rb +13 -0
  120. data/lib/earth/pet/species.rb +40 -0
  121. data/lib/earth/pet/species/data_miner.rb +42 -0
  122. data/lib/earth/rail.rb +1 -0
  123. data/lib/earth/rail/data_miner.rb +1 -0
  124. data/lib/earth/rail/rail_class.rb +16 -0
  125. data/lib/earth/rail/rail_class/data_miner.rb +36 -0
  126. data/lib/earth/residence.rb +8 -0
  127. data/lib/earth/residence/air_conditioner_use.rb +30 -0
  128. data/lib/earth/residence/air_conditioner_use/data_miner.rb +4 -0
  129. data/lib/earth/residence/clothes_machine_use.rb +33 -0
  130. data/lib/earth/residence/clothes_machine_use/data_miner.rb +4 -0
  131. data/lib/earth/residence/data_miner.rb +8 -0
  132. data/lib/earth/residence/dishwasher_use.rb +33 -0
  133. data/lib/earth/residence/dishwasher_use/data_miner.rb +4 -0
  134. data/lib/earth/residence/residence_appliance.rb +7 -0
  135. data/lib/earth/residence/residence_appliance/data_miner.rb +19 -0
  136. data/lib/earth/residence/residence_class.rb +26 -0
  137. data/lib/earth/residence/residence_class/data_miner.rb +4 -0
  138. data/lib/earth/residence/residence_fuel_price.rb +18 -0
  139. data/lib/earth/residence/residence_fuel_price/data_miner.rb +200 -0
  140. data/lib/earth/residence/residence_fuel_type.rb +33 -0
  141. data/lib/earth/residence/residence_fuel_type/data_miner.rb +18 -0
  142. data/lib/earth/residence/residential_energy_consumption_survey_response.rb +67 -0
  143. data/lib/earth/residence/residential_energy_consumption_survey_response/data_miner.rb +264 -0
  144. data/lib/earth/schema.rb +8 -0
  145. data/spec/lib/earth_spec.rb +25 -0
  146. data/spec/spec_helper.rb +11 -0
  147. data/vendor/geokit-rails/CHANGELOG.rdoc +46 -0
  148. data/vendor/geokit-rails/MIT-LICENSE +20 -0
  149. data/vendor/geokit-rails/README.markdown +561 -0
  150. data/vendor/geokit-rails/Rakefile +18 -0
  151. data/vendor/geokit-rails/about.yml +9 -0
  152. data/vendor/geokit-rails/assets/api_keys_template +61 -0
  153. data/vendor/geokit-rails/init.rb +1 -0
  154. data/vendor/geokit-rails/install.rb +14 -0
  155. data/vendor/geokit-rails/lib/geokit-rails.rb +24 -0
  156. data/vendor/geokit-rails/lib/geokit-rails/acts_as_mappable.rb +456 -0
  157. data/vendor/geokit-rails/lib/geokit-rails/adapters/abstract.rb +31 -0
  158. data/vendor/geokit-rails/lib/geokit-rails/adapters/mysql.rb +22 -0
  159. data/vendor/geokit-rails/lib/geokit-rails/adapters/postgresql.rb +22 -0
  160. data/vendor/geokit-rails/lib/geokit-rails/adapters/sqlserver.rb +43 -0
  161. data/vendor/geokit-rails/lib/geokit-rails/defaults.rb +22 -0
  162. data/vendor/geokit-rails/lib/geokit-rails/geocoder_control.rb +16 -0
  163. data/vendor/geokit-rails/lib/geokit-rails/ip_geocode_lookup.rb +46 -0
  164. data/vendor/geokit-rails/test/acts_as_mappable_test.rb +474 -0
  165. data/vendor/geokit-rails/test/boot.rb +25 -0
  166. data/vendor/geokit-rails/test/database.yml +20 -0
  167. data/vendor/geokit-rails/test/fixtures/companies.yml +7 -0
  168. data/vendor/geokit-rails/test/fixtures/custom_locations.yml +54 -0
  169. data/vendor/geokit-rails/test/fixtures/locations.yml +54 -0
  170. data/vendor/geokit-rails/test/fixtures/mock_addresses.yml +17 -0
  171. data/vendor/geokit-rails/test/fixtures/mock_families.yml +2 -0
  172. data/vendor/geokit-rails/test/fixtures/mock_houses.yml +9 -0
  173. data/vendor/geokit-rails/test/fixtures/mock_organizations.yml +5 -0
  174. data/vendor/geokit-rails/test/fixtures/mock_people.yml +5 -0
  175. data/vendor/geokit-rails/test/fixtures/stores.yml +0 -0
  176. data/vendor/geokit-rails/test/ip_geocode_lookup_test.rb +77 -0
  177. data/vendor/geokit-rails/test/models/company.rb +3 -0
  178. data/vendor/geokit-rails/test/models/custom_location.rb +12 -0
  179. data/vendor/geokit-rails/test/models/location.rb +4 -0
  180. data/vendor/geokit-rails/test/models/mock_address.rb +4 -0
  181. data/vendor/geokit-rails/test/models/mock_family.rb +3 -0
  182. data/vendor/geokit-rails/test/models/mock_house.rb +3 -0
  183. data/vendor/geokit-rails/test/models/mock_organization.rb +4 -0
  184. data/vendor/geokit-rails/test/models/mock_person.rb +4 -0
  185. data/vendor/geokit-rails/test/models/store.rb +3 -0
  186. data/vendor/geokit-rails/test/schema.rb +60 -0
  187. data/vendor/geokit-rails/test/tasks.rake +31 -0
  188. data/vendor/geokit-rails/test/test_helper.rb +23 -0
  189. metadata +444 -0
@@ -0,0 +1,4 @@
1
+ DishwasherUse.class_eval do
2
+ # data_miner do
3
+ #...
4
+ end
@@ -0,0 +1,7 @@
1
+ class ResidenceAppliance < ActiveRecord::Base
2
+ set_primary_key :name
3
+
4
+ data_miner do
5
+ tap "Brighter Planet's residence appliance energy information", Earth.taps_server
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ ResidenceAppliance.class_eval do
2
+ data_miner do
3
+ schema Earth.database_options do
4
+ string 'name'
5
+ float 'annual_energy_from_electricity'
6
+ string 'annual_energy_from_electricity_units'
7
+ end
8
+
9
+ process "Derive from residential energy consumption survey responses" do
10
+ ResidentialEnergyConsumptionSurveyResponse.run_data_miner!
11
+ ResidentialEnergyConsumptionSurveyResponse.column_names.select { |column| column.match(/annual.*_count/) }.map { |column| column.gsub '_count', '' }.each do |appliance_name|
12
+ appliance = find_or_create_by_name appliance_name
13
+ appliance.annual_energy_from_electricity = ResidentialEnergyConsumptionSurveyResponse.weighted_average "annual_energy_from_electricity_for_#{appliance_name.pluralize}"
14
+ appliance.save!
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,26 @@
1
+ class ResidenceClass < ActiveRecord::Base
2
+ set_primary_key :name
3
+
4
+ has_many :residences
5
+ has_many :residential_energy_consumption_survey_responses
6
+
7
+ CLASSIFICATIONS = ['mobile home', 'house', 'apartment']
8
+
9
+ def classification
10
+ CLASSIFICATIONS.detect { |c| name.downcase.include? c }
11
+ end
12
+
13
+ data_miner do
14
+ schema do
15
+ string :name
16
+ end
17
+
18
+ process "derive from ResidentialEnergyConsumptionSurveyResponse" do
19
+ ResidentialEnergyConsumptionSurveyResponse.run_data_miner!
20
+ connection.execute %{
21
+ INSERT IGNORE INTO residence_classes(name)
22
+ SELECT DISTINCT residential_energy_consumption_survey_responses.residence_class_id FROM residential_energy_consumption_survey_responses WHERE LENGTH(residential_energy_consumption_survey_responses.residence_class_id) > 0
23
+ }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ ResidenceClass.class_eval do
2
+ # data_miner do
3
+ #...
4
+ end
@@ -0,0 +1,18 @@
1
+ class ResidenceFuelPrice < ActiveRecord::Base
2
+ set_primary_key :row_hash
3
+
4
+ extend CohortScope
5
+ self.minimum_cohort_size = 5 # ? FIXME
6
+
7
+ belongs_to :fuel, :class_name => 'ResidenceFuelType', :foreign_key => 'residence_fuel_type_name'
8
+ belongs_to :locatable, :polymorphic => true
9
+
10
+ data_miner do
11
+ tap "Brighter Planet's residence fuel price data", Earth.taps_server
12
+
13
+ process "pull dependencies" do
14
+ run_data_miner_on_belongs_to_associations
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,200 @@
1
+ ResidenceFuelPrice.class_eval do
2
+ class FuelOilParser
3
+ def initialize(options = {})
4
+ # nothing
5
+ end
6
+ def add_hints!(bus)
7
+ bus[:sheet] = 'Data 1'
8
+ bus[:skip] = 2
9
+ bus[:select] = lambda { |row| row['year'].to_i > 1989 }
10
+ end
11
+ def apply(row)
12
+ virtual_rows = []
13
+ row.keys.grep(/(.*) Residual Fuel Oil/) do |location_column_name|
14
+ match_1 = $1
15
+ next if (price = row[location_column_name]).blank? or (date = row['Date']).blank?
16
+ if match_1.starts_with?('U.S.')
17
+ locatable_id = 'US'
18
+ locatable_type = 'Country'
19
+ elsif match_1.include?('PADD')
20
+ /\(PADD (.*)\)/.match match_1
21
+ match_2 = $1
22
+ next if match_2 == '1' # skip PADD 1 because we always prefer subdistricts
23
+ locatable_id = match_2
24
+ locatable_type = 'PetroleumAdministrationForDefenseDistrict'
25
+ else
26
+ locatable_id = match_1
27
+ locatable_type = 'State'
28
+ end
29
+ date = Time.parse(date)
30
+ new_row = ActiveSupport::OrderedHash.new
31
+ new_row['locatable_id'] = locatable_id
32
+ new_row['locatable_type'] = locatable_type
33
+ new_row['price'] = price.to_f.cents.to(:dollars)
34
+ new_row['year'] = date.year
35
+ new_row['month'] = date.month
36
+ row_hash = RemoteTable::Transform.row_hash new_row
37
+ new_row['row_hash'] = row_hash
38
+ virtual_rows << new_row
39
+ end
40
+ virtual_rows
41
+ end
42
+ end
43
+
44
+ class PropaneParser
45
+ def initialize(options = {})
46
+ # nothing
47
+ end
48
+ def add_hints!(bus)
49
+ bus[:sheet] = 'Data 1'
50
+ bus[:skip] = 2
51
+ bus[:select] = lambda { |row| row['year'].to_i > 1989 }
52
+ end
53
+ def apply(row)
54
+ virtual_rows = []
55
+ row.keys.grep(/(.*) Propane Residential Price/) do |location_column_name|
56
+ match_1 = $1
57
+ next if (price = row[location_column_name]).blank? or (date = row['Date']).blank?
58
+ if match_1.starts_with?('U.S.')
59
+ locatable_id = 'US'
60
+ locatable_type = 'Country'
61
+ else
62
+ /\(PADD (.*)\)/.match match_1
63
+ match_2 = $1
64
+ next if match_2 == '1' # skip PADD 1 because we always prefer subdistricts
65
+ locatable_id = match_2
66
+ locatable_type = 'PetroleumAdministrationForDefenseDistrict'
67
+ end
68
+ date = Time.parse(date)
69
+ new_row = ActiveSupport::OrderedHash.new
70
+ new_row['locatable_id'] = locatable_id
71
+ new_row['locatable_type'] = locatable_type
72
+ new_row['price'] = price.to_f.cents.to(:dollars)
73
+ new_row['year'] = date.year
74
+ new_row['month'] = date.month
75
+ row_hash = RemoteTable::Transform.row_hash new_row
76
+ new_row['row_hash'] = row_hash
77
+ virtual_rows << new_row
78
+ end
79
+ virtual_rows
80
+ end
81
+ end
82
+
83
+ class NaturalGasParser
84
+ def initialize(options = {})
85
+ # nothing
86
+ end
87
+ def add_hints!(bus)
88
+ bus[:sheet] = 'Data 1'
89
+ bus[:skip] = 2
90
+ bus[:select] = lambda { |row| row['year'].to_i > 1989 }
91
+ end
92
+ def apply(row)
93
+ virtual_rows = []
94
+ row.keys.grep(/\A(.*) Natural Gas/) do |location_column_name|
95
+ match_1 = $1
96
+ next if (price = row[location_column_name]).blank? or (date = row['Date']).blank?
97
+ if match_1 == 'U.S.'
98
+ locatable_id = 'US'
99
+ locatable_type = 'Country'
100
+ else
101
+ locatable_id = match_1 # name
102
+ locatable_type = 'State'
103
+ end
104
+ date = Time.parse(date)
105
+ new_row = ActiveSupport::OrderedHash.new
106
+ new_row['locatable_id'] = locatable_id
107
+ new_row['locatable_type'] = locatable_type
108
+ new_row['price'] = price
109
+ new_row['year'] = date.year
110
+ new_row['month'] = date.month
111
+ row_hash = RemoteTable::Transform.row_hash new_row
112
+ new_row['row_hash'] = row_hash
113
+ virtual_rows << new_row
114
+ end
115
+ virtual_rows
116
+ end
117
+ end
118
+
119
+ data_miner do
120
+ schema Earth.database_options do
121
+ string 'row_hash'
122
+ string 'residence_fuel_type_name'
123
+ integer 'year'
124
+ integer 'month'
125
+ float 'price'
126
+ string 'price_units'
127
+ string 'price_description'
128
+ string 'locatable_id'
129
+ string 'locatable_type'
130
+ index ['price', 'residence_fuel_type_name', 'month', 'year', 'locatable_type', 'locatable_id']
131
+ index ['price', 'residence_fuel_type_name']
132
+ end
133
+
134
+ process "Define some unit conversions" do
135
+ Conversions.register :dollars, :cents, 100
136
+ Conversions.register :cubic_feet, :cubic_metres, 0.0283168466 # TODO conversions gem has 'cubic_metres'
137
+ end
138
+
139
+ # electricity in dollars per kWh
140
+ import 'residential electricity prices from the EIA',
141
+ :url => 'http://www.eia.doe.gov/cneaf/electricity/page/sales_revenue.xls',
142
+ :select => lambda { |row| row['Year'].to_s.first(4).to_i > 1989 } do
143
+ key 'row_hash'
144
+ store 'residence_fuel_type_name', :static => 'electricity'
145
+ store 'locatable_id', :field_name => 'State' # postal abbrev
146
+ store 'locatable_type', :static => 'State'
147
+ store 'price', :field_name => 'Average Retail Price Residential (c/kWh)', :from_units => :cents, :to_units => :dollars
148
+ store 'price_description', :static => 'dollars_per_kilowatt_hour'
149
+ store 'year', :field_name => 'Year'
150
+ store 'month', :field_name => 'Month'
151
+ end
152
+
153
+ # natural gas in dollars per cubic metre
154
+ # breaks if date-performance is enabled because DateTime.parse(...1899...) dies
155
+ import 'residential natural gas prices from the EIA',
156
+ :url => 'http://tonto.eia.doe.gov/dnav/ng/xls/ng_pri_sum_a_EPG0_FWA_DMcf_a.xls',
157
+ :transform => { :class => NaturalGasParser } do
158
+ key 'row_hash'
159
+ store 'residence_fuel_type_name', :static => 'natural gas'
160
+ store 'locatable_id'
161
+ store 'locatable_type'
162
+ store 'price', :from_units => :cubic_metres, :to_units => :cubic_feet # denominator
163
+ store 'price_description', :static => 'dollars_per_cubic_metre'
164
+ store 'year'
165
+ store 'month'
166
+ end
167
+
168
+ # dollars per litre
169
+ import "residential fuel oil prices from the EIA",
170
+ :url => 'http://tonto.eia.doe.gov/dnav/pet/xls/PET_PRI_RESID_A_EPPR_PTA_CPGAL_M.xls',
171
+ :transform => { :class => FuelOilParser } do
172
+ key 'row_hash'
173
+ store 'residence_fuel_type_name', :static => 'fuel oil'
174
+ store 'locatable_id'
175
+ store 'locatable_type'
176
+ store 'price', :from_units => :litres, :to_units => :gallons # denominator
177
+ store 'price_description', :static => 'dollars_per_litre'
178
+ store 'year'
179
+ store 'month'
180
+ end
181
+
182
+ # dollars per litre
183
+ import "residential propane prices from the EIA",
184
+ :url => 'http://tonto.eia.doe.gov/dnav/pet/xls/PET_PRI_PROP_A_EPLLPA_PRT_CPGAL_M.xls',
185
+ :transform => { :class => PropaneParser } do
186
+ key 'row_hash'
187
+ store 'residence_fuel_type_name', :static => 'propane'
188
+ store 'locatable_id'
189
+ store 'locatable_type'
190
+ store 'price', :from_units => :litres, :to_units => :gallons # denominator
191
+ store 'price_description', :static => 'dollars_per_litre'
192
+ store 'year'
193
+ store 'month'
194
+ end
195
+
196
+ # per Matt in https://brighterplanet.sifterapp.com/projects/30/issues/410/comments
197
+ # "For coal and kerosene, there isn't good residential price data available, because hardly anybody actually uses them residentially."
198
+ end
199
+ end
200
+
@@ -0,0 +1,33 @@
1
+ class ResidenceFuelType < ActiveRecord::Base
2
+ set_primary_key :name
3
+
4
+
5
+ has_many :prices, :class_name => 'ResidenceFuelPrice', :foreign_key => 'residence_fuel_type_name'
6
+
7
+ data_miner do
8
+ tap "Brighter Planet's residence fuel types data", Earth.taps_server
9
+ end
10
+
11
+ def price_per_unit(relaxations = [])
12
+ conditions = { :residence_fuel_type_name => self }
13
+ relaxations.push Hash.new
14
+ relaxations.grab do |relaxation|
15
+ relaxation_conditions = Hash.new
16
+ if timeframe = relaxation[:timeframe]
17
+ relaxation_conditions[:year] = timeframe.from.year
18
+ relaxation_conditions[:month] = timeframe.from.month..timeframe.to.yesterday.month
19
+ end
20
+ if location = relaxation[:location]
21
+ relaxation_conditions[:locatable_type] = location.class.to_s
22
+ relaxation_conditions[:locatable_id] = location.id
23
+ end
24
+ ResidenceFuelPrice.average :price, :conditions => conditions.merge(relaxation_conditions)
25
+ end
26
+ end
27
+
28
+ class << self
29
+ def [](fuel)
30
+ find_by_name fuel.to_s.humanize.downcase
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ ResidenceFuelType.class_eval do
2
+ data_miner do
3
+ schema Earth.database_options do
4
+ string 'name'
5
+ float 'emission_factor'
6
+ string 'emission_factor_units'
7
+ # float 'energy_content'
8
+ # string 'energy_content_units'
9
+ end
10
+
11
+ import "a list of residential fuels and their emissions factors",
12
+ :url => 'http://spreadsheets.google.com/pub?key=rukxnmuhhsOsrztTrUaFCXQ' do
13
+ key 'name'
14
+ store 'emission_factor', :field_name => 'emission_factor', :units_field_name => 'units'
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,67 @@
1
+ class ResidentialEnergyConsumptionSurveyResponse < ActiveRecord::Base
2
+ set_primary_key :department_of_energy_identifier
3
+
4
+ belongs_to :census_division, :foreign_key => 'census_division_number'
5
+ belongs_to :census_region, :foreign_key => 'census_region_number'
6
+ # what follows are entirely derived here
7
+ belongs_to :residence_class
8
+ belongs_to :urbanity
9
+ belongs_to :dishwasher_use
10
+ belongs_to :air_conditioner_use
11
+ belongs_to :clothes_machine_use
12
+
13
+ extend CohortScope
14
+ self.minimum_cohort_size = 5
15
+ SUBCOHORT_THRESHOLD = 5 # per Matt
16
+
17
+ INPUT_CHARACTERISTICS = [
18
+ :census_region,
19
+ :heating_degree_days,
20
+ :cooling_degree_days,
21
+ :residence_class,
22
+ :rooms,
23
+ :bedrooms,
24
+ :bathrooms,
25
+ :floorspace,
26
+ :residents,
27
+ :urbanity,
28
+ :construction_year,
29
+ :ownership,
30
+ ]
31
+
32
+ data_miner do
33
+ tap "Brighter Planet's sanitized RECS 2005", Earth.taps_server
34
+
35
+ process "rename certain columns so that we can use them as association names" do
36
+ connection.rename_column :residential_energy_consumption_survey_responses, :dishwasher_use, :dishwasher_use_id
37
+ end
38
+
39
+ process "synthesize air conditioner use from central AC and window AC use" do
40
+ connection.add_column :residential_energy_consumption_survey_responses, :air_conditioner_use_id, :string
41
+ update_all "air_conditioner_use_id = 'Turned on just about all summer'", " central_ac_use = 'Turned on just about all summer' OR window_ac_use = 'Turned on just about all summer'"
42
+ update_all "air_conditioner_use_id = 'Turned on quite a bit'", "(central_ac_use = 'Turned on quite a bit' OR window_ac_use = 'Turned on quite a bit') AND air_conditioner_use_id IS NULL"
43
+ update_all "air_conditioner_use_id = 'Turned on only a few days or nights when really needed'", "(central_ac_use = 'Turned on only a few days or nights when really needed' OR window_ac_use = 'Turned on only a few days or nights when really needed') AND air_conditioner_use_id IS NULL"
44
+ update_all "air_conditioner_use_id = 'Not used at all'", "(central_ac_use = 'Not used at all' OR window_ac_use = 'Not used at all') AND air_conditioner_use_id IS NULL"
45
+ end
46
+
47
+ process "synthesize clothes machine use from washer and dryer use" do
48
+ connection.add_column :residential_energy_consumption_survey_responses, :clothes_machine_use_id, :string
49
+ update_all "clothes_machine_use_id = clothes_washer_use", " clothes_dryer_use = 'Use it every time you wash clothes'"
50
+ update_all "clothes_machine_use_id = NULL", "clothes_washer_use IS NULL AND clothes_dryer_use = 'Use it for some, but not all, loads of wash'"
51
+ update_all "clothes_machine_use_id = '1 load or less each week'", "clothes_washer_use = '1 load or less each week' AND clothes_dryer_use = 'Use it for some, but not all, loads of wash'"
52
+ update_all "clothes_machine_use_id = '1 load or less each week'", "clothes_washer_use = '2 to 4 loads' AND clothes_dryer_use = 'Use it for some, but not all, loads of wash'"
53
+ update_all "clothes_machine_use_id = '2 to 4 loads'", "clothes_washer_use = '5 to 9 loads' AND clothes_dryer_use = 'Use it for some, but not all, loads of wash'"
54
+ update_all "clothes_machine_use_id = '5 to 9 loads'", "clothes_washer_use = '10 to 15 loads' AND clothes_dryer_use = 'Use it for some, but not all, loads of wash'"
55
+ update_all "clothes_machine_use_id = '10 to 15 loads'", "clothes_washer_use = 'More than 15 loads' AND clothes_dryer_use = 'Use it for some, but not all, loads of wash'"
56
+ update_all "clothes_machine_use_id = NULL", "clothes_washer_use IS NULL AND clothes_dryer_use = 'Use it infrequently'"
57
+ update_all "clothes_machine_use_id = '1 load or less each week'", "clothes_washer_use = '1 load or less each week' AND clothes_dryer_use = 'Use it infrequently'"
58
+ update_all "clothes_machine_use_id = '1 load or less each week'", "clothes_washer_use = '5 to 9 loads' AND clothes_dryer_use = 'Use it infrequently'"
59
+ update_all "clothes_machine_use_id = '2 to 4 loads'", "clothes_washer_use = '10 to 15 loads' AND clothes_dryer_use = 'Use it infrequently'"
60
+ update_all "clothes_machine_use_id = '5 to 9 loads'", "clothes_washer_use = 'More than 15 loads' AND clothes_dryer_use = 'Use it infrequently'"
61
+ end
62
+
63
+ process "pull dependencies" do
64
+ run_data_miner_on_belongs_to_associations
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,264 @@
1
+ ResidentialEnergyConsumptionSurveyResponse.class_eval do
2
+ data_miner do
3
+ process "Don't re-import too often" do
4
+ raise DataMiner::Skip unless DataMiner::Run.allowed? ResidentialEnergyConsumptionSurveyResponse
5
+ end
6
+
7
+ schema Earth.database_options do
8
+ integer 'department_of_energy_identifier'
9
+ string 'residence_class_id'
10
+ date 'construction_year'
11
+ string 'construction_period'
12
+ string 'urbanity_id'
13
+ string 'dishwasher_use_id'
14
+ string 'central_ac_use'
15
+ string 'window_ac_use'
16
+ string 'clothes_washer_use'
17
+ string 'clothes_dryer_use'
18
+ integer 'census_division_number'
19
+ string 'census_division_name'
20
+ integer 'census_region_number'
21
+ string 'census_region_name'
22
+ float 'rooms'
23
+ float 'floorspace'
24
+ string 'floorspace_units'
25
+ integer 'residents'
26
+ boolean 'ownership'
27
+ boolean 'thermostat_programmability'
28
+ integer 'refrigerator_count'
29
+ integer 'freezer_count'
30
+ float 'annual_energy_from_fuel_oil_for_heating_space'
31
+ string 'annual_energy_from_fuel_oil_for_heating_space_units'
32
+ float 'annual_energy_from_fuel_oil_for_heating_water'
33
+ string 'annual_energy_from_fuel_oil_for_heating_water_units'
34
+ float 'annual_energy_from_fuel_oil_for_appliances'
35
+ string 'annual_energy_from_fuel_oil_for_appliances_units'
36
+ float 'annual_energy_from_natural_gas_for_heating_space'
37
+ string 'annual_energy_from_natural_gas_for_heating_space_units'
38
+ float 'annual_energy_from_natural_gas_for_heating_water'
39
+ string 'annual_energy_from_natural_gas_for_heating_water_units'
40
+ float 'annual_energy_from_natural_gas_for_appliances'
41
+ string 'annual_energy_from_natural_gas_for_appliances_units'
42
+ float 'annual_energy_from_propane_for_heating_space'
43
+ string 'annual_energy_from_propane_for_heating_space_units'
44
+ float 'annual_energy_from_propane_for_heating_water'
45
+ string 'annual_energy_from_propane_for_heating_water_units'
46
+ float 'annual_energy_from_propane_for_appliances'
47
+ string 'annual_energy_from_propane_for_appliances_units'
48
+ float 'annual_energy_from_wood'
49
+ string 'annual_energy_from_wood_units'
50
+ float 'annual_energy_from_kerosene'
51
+ string 'annual_energy_from_kerosene_units'
52
+ float 'annual_energy_from_electricity_for_clothes_driers'
53
+ string 'annual_energy_from_electricity_for_clothes_driers_units'
54
+ float 'annual_energy_from_electricity_for_dishwashers'
55
+ string 'annual_energy_from_electricity_for_dishwashers_units'
56
+ float 'annual_energy_from_electricity_for_freezers'
57
+ string 'annual_energy_from_electricity_for_freezers_units'
58
+ float 'annual_energy_from_electricity_for_refrigerators'
59
+ string 'annual_energy_from_electricity_for_refrigerators_units'
60
+ float 'annual_energy_from_electricity_for_air_conditioners'
61
+ string 'annual_energy_from_electricity_for_air_conditioners_units'
62
+ float 'annual_energy_from_electricity_for_heating_space'
63
+ string 'annual_energy_from_electricity_for_heating_space_units'
64
+ float 'annual_energy_from_electricity_for_heating_water'
65
+ string 'annual_energy_from_electricity_for_heating_water_units'
66
+ float 'annual_energy_from_electricity_for_other_appliances'
67
+ string 'annual_energy_from_electricity_for_other_appliances_units'
68
+ float 'weighting'
69
+ float 'lighting_use'
70
+ string 'lighting_use_units'
71
+ float 'lighting_efficiency'
72
+ integer 'heating_degree_days'
73
+ string 'heating_degree_days_units'
74
+ integer 'cooling_degree_days'
75
+ string 'cooling_degree_days_units'
76
+ integer 'total_rooms'
77
+ integer 'full_bathrooms'
78
+ integer 'bedrooms'
79
+ integer 'half_bathrooms'
80
+ float 'bathrooms'
81
+ boolean 'heated_garage'
82
+ boolean 'attached_1car_garage'
83
+ boolean 'detached_1car_garage'
84
+ boolean 'attached_2car_garage'
85
+ boolean 'detached_2car_garage'
86
+ boolean 'attached_3car_garage'
87
+ boolean 'detached_3car_garage'
88
+ integer 'lights_on_1_to_4_hours'
89
+ integer 'efficient_lights_on_1_to_4_hours'
90
+ integer 'lights_on_4_to_12_hours'
91
+ integer 'efficient_lights_on_4_to_12_hours'
92
+ integer 'lights_on_over_12_hours'
93
+ integer 'efficient_lights_on_over_12_hours'
94
+ integer 'outdoor_all_night_lights'
95
+ integer 'outdoor_all_night_gas_lights'
96
+ integer 'air_conditioner_use_id'
97
+ integer 'clothes_machine_use_id'
98
+ end
99
+
100
+ process "Define some unit conversions" do
101
+ Conversions.register :kbtus, :joules, 1_000.0 * 1_055.05585
102
+ Conversions.register :square_feet, :square_metres, 0.09290304
103
+ end
104
+
105
+ # conversions are NOT performed here, since we first have to zero out legitimate skips
106
+ # otherwise you will get values like "999 pounds = 453.138778 kilograms" (where 999 is really a legit skip)
107
+ import 'the 2005 EIA Residential Energy Consumption Survey microdata',
108
+ :url => 'http://www.eia.doe.gov/emeu/recs/recspubuse05/datafiles/RECS05alldata.csv',
109
+ :headers => :upcase do
110
+ key 'department_of_energy_identifier', :field_name => 'DOEID'
111
+
112
+ store 'residence_class_id', :field_name => 'TYPEHUQ', :dictionary => { :input => 'Code', :output => 'Description', :url => 'http://github.com/brighterplanet/manually_curated_data/raw/master/typehuq/typehuq.csv' }
113
+ store 'construction_year', :field_name => 'YEARMADE', :dictionary => { :input => 'Code', :sprintf => '%02d', :output => 'Date in the middle (synthetic)', :url => 'http://github.com/brighterplanet/manually_curated_data/raw/master/yearmade/yearmade.csv' }
114
+ store 'construction_period', :field_name => 'YEARMADE', :dictionary => { :input => 'Code', :sprintf => '%02d', :output => 'Description', :url => 'http://github.com/brighterplanet/manually_curated_data/raw/master/yearmade/yearmade.csv' }
115
+ store 'urbanity_id', :field_name => 'URBRUR', :dictionary => { :input => 'Code', :output => 'Description', :url => 'http://github.com/brighterplanet/manually_curated_data/raw/master/urbrur/urbrur.csv' }
116
+ store 'dishwasher_use_id', :field_name => 'DWASHUSE', :dictionary => { :input => 'Code', :output => 'Description', :url => 'http://github.com/brighterplanet/manually_curated_data/raw/master/dwashuse/dwashuse.csv' }
117
+ store 'central_ac_use', :field_name => 'USECENAC', :dictionary => { :input => 'Code', :output => 'Description', :url => 'http://github.com/brighterplanet/manually_curated_data/raw/master/usecenac/usecenac.csv' }
118
+ store 'window_ac_use', :field_name => 'USEWWAC', :dictionary => { :input => 'Code', :output => 'Description', :url => 'http://github.com/brighterplanet/manually_curated_data/raw/master/usewwac/usewwac.csv' }
119
+ store 'clothes_washer_use', :field_name => 'WASHLOAD', :dictionary => { :input => 'Code', :output => 'Description', :url => 'http://github.com/brighterplanet/manually_curated_data/raw/master/washload/washload.csv' }
120
+ store 'clothes_dryer_use', :field_name => 'DRYRUSE', :dictionary => { :input => 'Code', :output => 'Description', :url => 'http://github.com/brighterplanet/manually_curated_data/raw/master/dryruse/dryruse.csv' }
121
+
122
+ store 'census_division_number', :field_name => 'DIVISION'
123
+ store 'census_division_name', :field_name => 'DIVISION', :dictionary => { :input => 'number', :output => 'name', :url => 'http://data.brighterplanet.com/census_divisions.csv' }
124
+ store 'census_region_number', :field_name => 'DIVISION', :dictionary => { :input => 'number', :output => 'census_region_number', :url => 'http://data.brighterplanet.com/census_divisions.csv' }
125
+ store 'census_region_name', :field_name => 'DIVISION', :dictionary => { :input => 'number', :output => 'census_region_name', :url => 'http://data.brighterplanet.com/census_divisions.csv' }
126
+
127
+ store 'floorspace', :field_name => 'TOTSQFT', :units => :square_metres
128
+ store 'residents', :field_name => 'NHSLDMEM'
129
+ store 'refrigerator_count', :field_name => 'NUMFRIG'
130
+ store 'freezer_count', :field_name => 'NUMFREEZ'
131
+ store 'heating_degree_days', :field_name => 'HD65', :units => :degrees_fahrenheit_days # FIXME imperial
132
+ store 'cooling_degree_days', :field_name => 'CD65', :units => :degrees_fahrenheit_days # FIXME imperial
133
+ store 'annual_energy_from_fuel_oil_for_heating_space', :field_name => 'BTUFOSPH', :units => :joules
134
+ store 'annual_energy_from_fuel_oil_for_heating_water', :field_name => 'BTUFOWTH', :units => :joules
135
+ store 'annual_energy_from_fuel_oil_for_appliances', :field_name => 'BTUFOAPL', :units => :joules
136
+ store 'annual_energy_from_natural_gas_for_heating_space', :field_name => 'BTUNGSPH', :units => :joules
137
+ store 'annual_energy_from_natural_gas_for_heating_water', :field_name => 'BTUNGWTH', :units => :joules
138
+ store 'annual_energy_from_natural_gas_for_appliances', :field_name => 'BTUNGAPL', :units => :joules
139
+ store 'annual_energy_from_propane_for_heating_space', :field_name => 'BTULPSPH', :units => :joules
140
+ store 'annual_energy_from_propane_for_heating_water', :field_name => 'BTULPWTH', :units => :joules
141
+ store 'annual_energy_from_propane_for_appliances', :field_name => 'BTULPAPL', :units => :joules
142
+ store 'annual_energy_from_wood', :field_name => 'BTUWOOD', :units => :joules
143
+ store 'annual_energy_from_kerosene', :field_name => 'BTUKER', :units => :joules
144
+ store 'annual_energy_from_electricity_for_clothes_driers', :field_name => 'BTUELCDR', :units => :joules
145
+ store 'annual_energy_from_electricity_for_dishwashers', :field_name => 'BTUELDWH', :units => :joules
146
+ store 'annual_energy_from_electricity_for_freezers', :field_name => 'BTUELFZZ', :units => :joules
147
+ store 'annual_energy_from_electricity_for_refrigerators', :field_name => 'BTUELRFG', :units => :joules
148
+ store 'annual_energy_from_electricity_for_air_conditioners', :field_name => 'BTUELCOL', :units => :joules
149
+ store 'annual_energy_from_electricity_for_heating_space', :field_name => 'BTUELSPH', :units => :joules
150
+ store 'annual_energy_from_electricity_for_heating_water', :field_name => 'BTUELWTH', :units => :joules
151
+ store 'annual_energy_from_electricity_for_other_appliances', :field_name => 'BTUELAPL', :units => :joules
152
+ store 'weighting', :field_name => 'NWEIGHT'
153
+ store 'lighting_use', :static => nil, :units => :hours
154
+ store 'total_rooms', :field_name => 'TOTROOMS'
155
+ store 'full_bathrooms', :field_name => 'NCOMBATH'
156
+ store 'half_bathrooms', :field_name => 'NHAFBATH'
157
+ store 'bedrooms', :field_name => 'BEDROOMS'
158
+ store 'lights_on_1_to_4_hours', :field_name => 'LGT1'
159
+ store 'efficient_lights_on_1_to_4_hours', :field_name => 'LGT1EE'
160
+ store 'lights_on_4_to_12_hours', :field_name => 'LGT4'
161
+ store 'efficient_lights_on_4_to_12_hours', :field_name => 'LGT4EE'
162
+ store 'lights_on_over_12_hours', :field_name => 'LGT12'
163
+ store 'efficient_lights_on_over_12_hours', :field_name => 'LGT12EE'
164
+ store 'outdoor_all_night_lights', :field_name => 'NOUTLGTNT'
165
+ store 'outdoor_all_night_gas_lights', :field_name => 'NGASLIGHT'
166
+ # booleans where we treat anything other than true (for example legitimate skip or "occupied without paying rent") as false
167
+ store 'ownership', :synthesize => lambda { |row| row['KOWNRENT'] == '1' }
168
+ store 'thermostat_programmability', :synthesize => lambda { |row| row['PROTHERM'] == '1' }
169
+ store 'heated_garage', :synthesize => lambda { |row| row['GARGHEAT'] == '1' }
170
+ store 'attached_1car_garage', :synthesize => lambda { |row| row['GARAGE1C'] == '1' }
171
+ store 'detached_1car_garage', :synthesize => lambda { |row| row['DGARG1C'] == '1' }
172
+ store 'attached_2car_garage', :synthesize => lambda { |row| row['GARAGE2C'] == '1' }
173
+ store 'detached_2car_garage', :synthesize => lambda { |row| row['DGARG2C'] == '1' }
174
+ store 'attached_3car_garage', :synthesize => lambda { |row| row['GARAGE3C'] == '1' }
175
+ store 'detached_3car_garage', :synthesize => lambda { |row| row['DGARG3C'] == '1' }
176
+ end
177
+
178
+ # Rather than nullify the continuous variables that EIA identifies as LEGITIMATE SKIPS, we convert them to zero
179
+ # This makes it easier to derive useful information like "how many rooms does the house have?"
180
+ process "Zero out what the EIA calls LEGITIMATE SKIPS" do
181
+ %w{
182
+ annual_energy_from_electricity_for_air_conditioners
183
+ annual_energy_from_electricity_for_clothes_driers
184
+ annual_energy_from_electricity_for_dishwashers
185
+ annual_energy_from_electricity_for_freezers
186
+ annual_energy_from_electricity_for_heating_space
187
+ annual_energy_from_electricity_for_heating_water
188
+ annual_energy_from_electricity_for_other_appliances
189
+ annual_energy_from_electricity_for_refrigerators
190
+ annual_energy_from_fuel_oil_for_appliances
191
+ annual_energy_from_fuel_oil_for_heating_space
192
+ annual_energy_from_fuel_oil_for_heating_water
193
+ annual_energy_from_kerosene
194
+ annual_energy_from_propane_for_appliances
195
+ annual_energy_from_propane_for_heating_space
196
+ annual_energy_from_propane_for_heating_water
197
+ annual_energy_from_natural_gas_for_appliances
198
+ annual_energy_from_natural_gas_for_heating_space
199
+ annual_energy_from_natural_gas_for_heating_water
200
+ annual_energy_from_wood
201
+ lights_on_1_to_4_hours
202
+ lights_on_over_12_hours
203
+ efficient_lights_on_over_12_hours
204
+ efficient_lights_on_1_to_4_hours
205
+ lights_on_4_to_12_hours
206
+ efficient_lights_on_4_to_12_hours
207
+ outdoor_all_night_gas_lights
208
+ outdoor_all_night_lights
209
+ }.each do |attr_name|
210
+ max = maximum attr_name, :select => "CONVERT(#{attr_name}, UNSIGNED INTEGER)"
211
+ # if the maximum value of a row is all 999's, then it's a LEGITIMATE SKIP and we should set it to zero
212
+ if /^9+$/.match(max.to_i.to_s)
213
+ update_all "#{attr_name} = 0", "#{attr_name} = #{max}"
214
+ end
215
+ end
216
+ end
217
+
218
+ process "Convert units to metric" do
219
+ [
220
+ [ 'floorspace', :square_feet, :square_metres ],
221
+ [ 'annual_energy_from_fuel_oil_for_heating_space', :kbtus, :joules ],
222
+ [ 'annual_energy_from_fuel_oil_for_heating_water', :kbtus, :joules ],
223
+ [ 'annual_energy_from_fuel_oil_for_appliances', :kbtus, :joules ],
224
+ [ 'annual_energy_from_natural_gas_for_heating_space', :kbtus, :joules ],
225
+ [ 'annual_energy_from_natural_gas_for_heating_water', :kbtus, :joules ],
226
+ [ 'annual_energy_from_natural_gas_for_appliances', :kbtus, :joules ],
227
+ [ 'annual_energy_from_propane_for_heating_space', :kbtus, :joules ],
228
+ [ 'annual_energy_from_propane_for_heating_water', :kbtus, :joules ],
229
+ [ 'annual_energy_from_propane_for_appliances', :kbtus, :joules ],
230
+ [ 'annual_energy_from_wood', :kbtus, :joules ],
231
+ [ 'annual_energy_from_kerosene', :kbtus, :joules ],
232
+ [ 'annual_energy_from_electricity_for_clothes_driers', :kbtus, :joules ],
233
+ [ 'annual_energy_from_electricity_for_dishwashers', :kbtus, :joules ],
234
+ [ 'annual_energy_from_electricity_for_freezers', :kbtus, :joules ],
235
+ [ 'annual_energy_from_electricity_for_refrigerators', :kbtus, :joules ],
236
+ [ 'annual_energy_from_electricity_for_air_conditioners', :kbtus, :joules ],
237
+ [ 'annual_energy_from_electricity_for_heating_space', :kbtus, :joules ],
238
+ [ 'annual_energy_from_electricity_for_heating_water', :kbtus, :joules ],
239
+ [ 'annual_energy_from_electricity_for_other_appliances', :kbtus, :joules ],
240
+ ].each do |attr_name, from_units, to_units|
241
+ update_all "#{attr_name} = #{attr_name} * #{Conversions::Unit.exchange_rate from_units, to_units}"
242
+ end
243
+ end
244
+
245
+ process 'Add a new field "rooms" that estimates how many rooms are in the house' do
246
+ update_all 'rooms = total_rooms + full_bathrooms/2 + half_bathrooms/4 + heated_garage*(attached_1car_garage + detached_1car_garage + 2*(attached_2car_garage + detached_2car_garage) + 3*(attached_3car_garage + detached_3car_garage))'
247
+ end
248
+
249
+ process 'Add a new field "bathrooms" that synthesizes half and full bathrooms into one number' do
250
+ update_all 'bathrooms = full_bathrooms + 0.5 * half_bathrooms'
251
+ end
252
+
253
+ process 'Add a new field "lighting_use" that estimates how many hours light bulbs are turned on in the house' do
254
+ update_all 'lighting_use = 2*(lights_on_1_to_4_hours + efficient_lights_on_1_to_4_hours) + 8*(lights_on_4_to_12_hours + efficient_lights_on_4_to_12_hours) + 16*(lights_on_over_12_hours + efficient_lights_on_over_12_hours) + 12*(outdoor_all_night_lights + outdoor_all_night_gas_lights)'
255
+ end
256
+
257
+ process 'Add a new field "lighting_efficiency" that estimates what percentage of light bulbs in a house are energy-efficient' do
258
+ update_all 'lighting_efficiency = (2*efficient_lights_on_1_to_4_hours + 8*efficient_lights_on_4_to_12_hours + 16*efficient_lights_on_over_12_hours) / lighting_use'
259
+ end
260
+
261
+ # FIXME add precalc bathrooms per https://github.com/brighterplanet/cm1/commit/77df97c50311f3c59aad891f018bf3d487afeb98
262
+ end
263
+ end
264
+