earth 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+