residence 0.0.3 → 0.0.4

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.
@@ -0,0 +1,11 @@
1
+ Feature: Residence Committee Calculations
2
+ The residence model should generate correct committee calculations
3
+
4
+ Scenario Outline: Bathrooms committee
5
+ Given a residence has "full_bathrooms" of "<full_baths>"
6
+ And it has "half_bathrooms" of "<half_baths>"
7
+ When emissions are calculated
8
+ Then the bathrooms committee should be exactly <bathrooms>
9
+ Examples:
10
+ | full_baths | half_baths | bathrooms |
11
+ | 2 | 0.5 | 2.5 |
@@ -0,0 +1,14 @@
1
+ Feature: Residence Emissions Calculations
2
+ The residence model should generate correct emission calculations
3
+
4
+ Scenario Outline: Standard Calculations for residence
5
+ Given a residence has "zip_code.name" of "<zip_code>"
6
+ And it has "floorspace_estimate" of "<floorspace>"
7
+ And it has "residence_class.name" of "<residence_class>"
8
+ And it has "urbanity.name" of "<urbanity>"
9
+ And it has "dishwasher_use.name" of "<dishwasher_use>"
10
+ When emissions are calculated
11
+ Then the emission value should be within 0.1 kgs of <emission>
12
+ Examples:
13
+ | zip_code | floorspace | residence_class | urbanity | dishwasher_use | emission |
14
+ | 48915 | 1400 | Single-family detached house (a one-family house detached from any other house) | City | 4 to 6 times a week | 6068.6 |
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ require 'cucumber'
5
+ require 'cucumber/formatter/unicode'
6
+
7
+ require 'sniff'
8
+ Sniff.init File.join(File.dirname(__FILE__), '..', '..'), :earth => [:residence, :locality]
@@ -0,0 +1,549 @@
1
+ require 'leap'
2
+ require 'weighted_average'
3
+
4
+ module BrighterPlanet
5
+ module Residence
6
+ module CarbonModel
7
+ def self.included(base)
8
+ base.extend ::Leap::Subject
9
+ base.decide :emission, :with => :characteristics do
10
+ committee :emission do
11
+ quorum 'from fuel and electricity use and occupation and residents', :needs => [:fuel_oil_consumed, :natural_gas_consumed, :dirty_electricity_generated, :propane_consumed, :biomass_consumed, :kerosene_consumed, :coal_consumed, :residents, :electricity_emission_factor, :floorspace_estimate, :air_conditioner_use, :active_subtimeframe, :occupation] do |characteristics, timeframe|
12
+ ( characteristics[:fuel_oil_consumed] * ResidenceFuelType.find_by_name('fuel oil').emission_factor +
13
+ characteristics[:natural_gas_consumed] * ResidenceFuelType.find_by_name('natural gas').emission_factor +
14
+ characteristics[:propane_consumed] * ResidenceFuelType.find_by_name('propane').emission_factor +
15
+ characteristics[:biomass_consumed] * ResidenceFuelType.find_by_name('biomass').emission_factor +
16
+ characteristics[:kerosene_consumed] * ResidenceFuelType.find_by_name('kerosene').emission_factor +
17
+ characteristics[:coal_consumed] * ResidenceFuelType.find_by_name('coal').emission_factor +
18
+ characteristics[:dirty_electricity_generated] * characteristics[:electricity_emission_factor] +
19
+ characteristics[:floorspace_estimate] * characteristics[:air_conditioner_use].fugitive_emission * (timeframe / timeframe.year) * characteristics[:occupation]
20
+ ) *
21
+ (characteristics[:active_subtimeframe] / timeframe) / characteristics[:residents]
22
+ end
23
+
24
+ quorum 'default' do
25
+ raise "Residence's default emission quorum should never be called"
26
+ end
27
+ end
28
+
29
+ committee :fuel_oil_consumed do # returns litres
30
+ quorum 'from reports', :needs => :reported_annual_fuel_oil_consumption do |characteristics, timeframe|
31
+ characteristics[:reported_annual_fuel_oil_consumption] * (timeframe / timeframe.year)
32
+ end
33
+ quorum 'from research', :needs => [:predicted_annual_fuel_oil_consumption, :predicted_fuel_shares, :missing_annual_energy, :occupation] do |characteristics, timeframe|
34
+ (characteristics[:predicted_annual_fuel_oil_consumption] + (characteristics[:missing_annual_energy] * characteristics[:predicted_fuel_shares][:fuel_oil]).joules.to(:litres_of_fuel_oil) ) * (timeframe / timeframe.year) * characteristics[:occupation] / Residence.residence_model.fallback.occupation
35
+ end
36
+ end
37
+
38
+ committee :natural_gas_consumed do # returns joules
39
+ quorum 'from reports', :needs => :reported_annual_natural_gas_consumption do |characteristics, timeframe|
40
+ characteristics[:reported_annual_natural_gas_consumption] * (timeframe / timeframe.year)
41
+ end
42
+ quorum 'from research', :needs => [:predicted_annual_natural_gas_consumption, :predicted_fuel_shares, :missing_annual_energy, :occupation] do |characteristics, timeframe|
43
+ (characteristics[:predicted_annual_natural_gas_consumption] + (characteristics[:missing_annual_energy] * characteristics[:predicted_fuel_shares][:natural_gas])) * (timeframe / timeframe.year) * characteristics[:occupation] / Residence.residence_model.fallback.occupation
44
+ end
45
+ end
46
+
47
+ committee :propane_consumed do # returns litres
48
+ quorum 'from reports', :needs => :reported_annual_propane_consumption do |characteristics, timeframe|
49
+ characteristics[:reported_annual_propane_consumption] * (timeframe / timeframe.year)
50
+ end
51
+ quorum 'from research', :needs => [:predicted_annual_propane_consumption, :predicted_fuel_shares, :missing_annual_energy, :occupation] do |characteristics, timeframe|
52
+ (characteristics[:predicted_annual_propane_consumption] + (characteristics[:missing_annual_energy] * characteristics[:predicted_fuel_shares][:propane]).joules.to(:litres_of_propane)) * (timeframe / timeframe.year) * characteristics[:occupation] / Residence.residence_model.fallback.occupation
53
+ end
54
+ end
55
+
56
+ committee :biomass_consumed do # returns joules
57
+ quorum 'from reports', :needs => :reported_annual_biomass_consumption do |characteristics, timeframe|
58
+ characteristics[:reported_annual_biomass_consumption] * (timeframe / timeframe.year)
59
+ end
60
+ quorum 'from research', :needs => [:predicted_annual_biomass_consumption, :predicted_fuel_shares, :missing_annual_energy, :occupation] do |characteristics, timeframe|
61
+ (characteristics[:predicted_annual_biomass_consumption] + (characteristics[:missing_annual_energy] * characteristics[:predicted_fuel_shares][:biomass])) * (timeframe / timeframe.year) * characteristics[:occupation] / Residence.residence_model.fallback.occupation
62
+ end
63
+ end
64
+
65
+ committee :kerosene_consumed do # returns litres
66
+ quorum 'from reports', :needs => :reported_annual_kerosene_consumption do |characteristics, timeframe|
67
+ characteristics[:reported_annual_kerosene_consumption] * (timeframe / timeframe.year)
68
+ end
69
+ quorum 'from research', :needs => [:predicted_annual_kerosene_consumption, :predicted_fuel_shares, :missing_annual_energy, :occupation] do |characteristics, timeframe|
70
+ (characteristics[:predicted_annual_kerosene_consumption] + (characteristics[:missing_annual_energy] * characteristics[:predicted_fuel_shares][:kerosene]).joules.to(:litres_of_kerosene)) * (timeframe / timeframe.year) * characteristics[:occupation] / Residence.residence_model.fallback.occupation
71
+ end
72
+ end
73
+
74
+ committee :coal_consumed do # returns kg
75
+ quorum 'from reports', :needs => :reported_annual_coal_consumption do |characteristics, timeframe|
76
+ characteristics[:reported_annual_coal_consumption] * (timeframe / timeframe.year)
77
+ end
78
+ quorum 'from research', :needs => [:predicted_annual_coal_consumption, :predicted_fuel_shares, :missing_annual_energy, :occupation] do |characteristics, timeframe|
79
+ (characteristics[:predicted_annual_coal_consumption] + (characteristics[:missing_annual_energy] * characteristics[:predicted_fuel_shares][:coal]).joules.to(:kilograms_of_coal)) * (timeframe / timeframe.year) * characteristics[:occupation] / Residence.residence_model.fallback.occupation
80
+ end
81
+ end
82
+
83
+ committee :dirty_electricity_generated do
84
+ quorum 'from electricity generated and green electricity', :needs => [:electricity_generated, :green_electricity] do |characteristics|
85
+ characteristics[:electricity_generated] * (1.0 - characteristics[:green_electricity])
86
+ end
87
+ end
88
+
89
+ committee :green_electricity do
90
+ quorum 'default' do
91
+ Residence.residence_model.fallback.green_electricity
92
+ end
93
+ end
94
+
95
+ committee :electricity_generated do # returns kWh
96
+ quorum 'from electricity used and loss rate', :needs => [:electricity_used, :electricity_loss_rate] do |characteristics|
97
+ characteristics[:electricity_used] / (1.0 - characteristics[:electricity_loss_rate])
98
+ end
99
+ end
100
+
101
+ committee :electricity_used do # returns kWh
102
+ quorum 'from reports', :needs => :reported_annual_electricity_use do |characteristics, timeframe|
103
+ characteristics[:reported_annual_electricity_use] * (timeframe / timeframe.year)
104
+ end
105
+
106
+ quorum 'from research', :needs => [:predicted_annual_electricity_use, :predicted_fuel_shares, :missing_annual_energy, :occupation] do |characteristics, timeframe|
107
+ (characteristics[:predicted_annual_electricity_use] + ((characteristics[:missing_annual_energy] * characteristics[:predicted_fuel_shares][:electricity]).joules.to(:kilowatt_hours))) * (timeframe / timeframe.year) * characteristics[:occupation] / Residence.residence_model.fallback.occupation
108
+ end
109
+ end
110
+
111
+ committee :missing_annual_energy do # returns joules
112
+ quorum 'from fuel reports', :needs => [:predicted_annual_fuel_oil_consumption, :predicted_annual_natural_gas_consumption, :predicted_annual_propane_consumption, :predicted_annual_kerosene_consumption, :predicted_annual_biomass_consumption, :predicted_annual_coal_consumption, :predicted_annual_electricity_use], :appreciates => [:reported_annual_fuel_oil_consumption, :reported_annual_natural_gas_consumption, :reported_annual_propane_consumption, :reported_annual_kerosene_consumption, :reported_annual_biomass_consumption, :reported_annual_coal_consumption, :reported_annual_electricity_use] do |characteristics|
113
+ energy = 0
114
+ if characteristics[:reported_annual_fuel_oil_consumption] and characteristics[:reported_annual_fuel_oil_consumption].zero?
115
+ energy += characteristics[:predicted_annual_fuel_oil_consumption].litres_of_fuel_oil.to :joules
116
+ end
117
+ if characteristics[:reported_annual_natural_gas_consumption] and characteristics[:reported_annual_natural_gas_consumption].zero?
118
+ energy += characteristics[:predicted_annual_natural_gas_consumption]
119
+ end
120
+ if characteristics[:reported_annual_propane_consumption] and characteristics[:reported_annual_propane_consumption].zero?
121
+ energy += characteristics[:predicted_annual_propane_consumption].litres_of_propane.to :joules
122
+ end
123
+ if characteristics[:reported_annual_kerosene_consumption] and characteristics[:reported_annual_kerosene_consumption].zero?
124
+ energy += characteristics[:predicted_annual_kerosene_consumption].litres_of_kerosene.to :joules
125
+ end
126
+ if characteristics[:reported_annual_biomass_consumption] and characteristics[:reported_annual_biomass_consumption].zero?
127
+ energy += characteristics[:predicted_annual_biomass_consumption]
128
+ end
129
+ if characteristics[:reported_annual_coal_consumption] and characteristics[:reported_annual_coal_consumption].zero?
130
+ energy += characteristics[:predicted_annual_coal_consumption].kilograms_of_coal.to :joules
131
+ end
132
+ if characteristics[:reported_annual_electricity_use] and characteristics[:reported_annual_electricity_use].zero?
133
+ energy += characteristics[:predicted_annual_electricity_use].kilowatt_hours.to :joules
134
+ end
135
+ energy
136
+ end
137
+ end
138
+
139
+ committee :electricity_loss_rate do # returns percentage
140
+ quorum 'from egrid region', :needs => :egrid_region do |characteristics|
141
+ characteristics[:egrid_region].loss_factor
142
+ end
143
+
144
+ quorum 'default' do
145
+ EgridRegion.fallback.loss_factor
146
+ end
147
+ end
148
+
149
+ committee :electricity_emission_factor do # returns kg CO2 / kWh
150
+ quorum 'from egrid subregion', :needs => :egrid_subregion do |characteristics|
151
+ characteristics[:egrid_subregion].electricity_emission_factor
152
+ end
153
+
154
+ quorum 'default' do
155
+ EgridSubregion.fallback.electricity_emission_factor
156
+ end
157
+ end
158
+
159
+ committee :egrid_region do
160
+ quorum 'from egrid subregion', :needs => :egrid_subregion do |characteristics|
161
+ characteristics[:egrid_subregion].egrid_region
162
+ end
163
+ end
164
+
165
+ committee :egrid_subregion do
166
+ quorum 'from_zip_code', :needs => :zip_code do |characteristics|
167
+ characteristics[:zip_code].egrid_subregion
168
+ end
169
+ end
170
+
171
+ committee :occupation do
172
+ quorum 'default' do
173
+ Residence.residence_model.fallback.occupation
174
+ end
175
+ end
176
+
177
+ committee :residents do
178
+ quorum 'from cohort', :needs => :cohort do |characteristics|
179
+ characteristics[:cohort].weighted_average :residents
180
+ end
181
+
182
+ quorum 'default' do
183
+ Residence.residence_model.fallback.residents_before_type_cast
184
+ end
185
+ end
186
+
187
+ committee :air_conditioner_use do
188
+ quorum 'default' do
189
+ AirConditionerUse.fallback
190
+ end
191
+ end
192
+
193
+ committee :predicted_fuel_shares do # returns an array of percentages
194
+ quorum 'from research', :needs => [:predicted_annual_energy_consumption, :predicted_annual_fuel_oil_consumption, :predicted_annual_natural_gas_consumption, :predicted_annual_propane_consumption, :predicted_annual_kerosene_consumption, :predicted_annual_biomass_consumption, :predicted_annual_coal_consumption, :predicted_annual_electricity_use] do |characteristics|
195
+ {
196
+ :fuel_oil => characteristics[:predicted_annual_fuel_oil_consumption].litres_of_fuel_oil.to(:joules) / characteristics[:predicted_annual_energy_consumption],
197
+ :natural_gas => characteristics[:predicted_annual_natural_gas_consumption] / characteristics[:predicted_annual_energy_consumption],
198
+ :propane => characteristics[:predicted_annual_propane_consumption].litres_of_propane.to(:joules) / characteristics[:predicted_annual_energy_consumption],
199
+ :kerosene => characteristics[:predicted_annual_kerosene_consumption].litres_of_kerosene.to(:joules) / characteristics[:predicted_annual_energy_consumption],
200
+ :biomass => characteristics[:predicted_annual_biomass_consumption] / characteristics[:predicted_annual_energy_consumption],
201
+ :coal => characteristics[:predicted_annual_coal_consumption].kilograms_of_coal.to(:joules) / characteristics[:predicted_annual_energy_consumption],
202
+ :electricity => characteristics[:predicted_annual_electricity_use].kilowatt_hours.to(:joules) / characteristics[:predicted_annual_energy_consumption]
203
+ }
204
+ end
205
+ end
206
+
207
+ committee :predicted_annual_energy_consumption do # returns BTUs
208
+ quorum 'from research', :needs => [:predicted_annual_fuel_oil_consumption, :predicted_annual_natural_gas_consumption, :predicted_annual_propane_consumption, :predicted_annual_kerosene_consumption, :predicted_annual_biomass_consumption, :predicted_annual_coal_consumption, :predicted_annual_electricity_use] do |characteristics|
209
+ energy = 0
210
+ energy += characteristics[:predicted_annual_fuel_oil_consumption].litres_of_fuel_oil.to :joules
211
+ energy += characteristics[:predicted_annual_natural_gas_consumption]
212
+ energy += characteristics[:predicted_annual_propane_consumption].litres_of_propane.to :joules
213
+ energy += characteristics[:predicted_annual_kerosene_consumption].litres_of_kerosene.to :joules
214
+ energy += characteristics[:predicted_annual_biomass_consumption]
215
+ energy += characteristics[:predicted_annual_coal_consumption].kilograms_of_coal.to :joules
216
+ energy += characteristics[:predicted_annual_electricity_use].kilowatt_hours.to :joules
217
+ end
218
+ end
219
+
220
+ committee :reported_annual_fuel_oil_consumption do # returns litres
221
+ quorum 'from volume estimate', :needs => :annual_fuel_oil_volume_estimate do |characteristics|
222
+ characteristics[:annual_fuel_oil_volume_estimate]
223
+ end
224
+
225
+ quorum 'from cost', :needs => :annual_fuel_oil_cost, :appreciates => :state do |characteristics, timeframe|
226
+ relaxations = []
227
+ relaxations << { :timeframe => timeframe, :location => characteristics[:state] } if characteristics[:state]
228
+ relaxations << { :timeframe => timeframe.last_year, :location => characteristics[:state] } if characteristics[:state]
229
+ relaxations << { :timeframe => timeframe, :location => Country.united_states }
230
+ relaxations << { :timeframe => timeframe.last_year, :location => Country.united_states }
231
+ if price_per_unit = ResidenceFuelType[:fuel_oil].price_per_unit(relaxations)
232
+ characteristics[:annual_fuel_oil_cost] / price_per_unit
233
+ else
234
+ nil
235
+ end
236
+ end
237
+ end
238
+
239
+ committee :predicted_annual_fuel_oil_consumption do # returns litres
240
+ quorum 'from cohort', :needs => :cohort do |characteristics|
241
+ characteristics[:cohort].weighted_average(%w(heating_space heating_water appliances).map { |purpose| "annual_energy_from_fuel_oil_for_#{purpose}".to_sym }).to_f.joules.to(:litres_of_fuel_oil)
242
+ end
243
+
244
+ quorum 'default' do
245
+ Residence.residence_model.fallback.annual_fuel_oil_volume_estimate
246
+ end
247
+ end
248
+
249
+ committee :reported_annual_natural_gas_consumption do # returns joules
250
+ quorum 'from volume estimate', :needs => :monthly_natural_gas_volume_estimate do |characteristics|
251
+ characteristics[:monthly_natural_gas_volume_estimate] * 12
252
+ end
253
+
254
+ quorum 'from cost', :needs => :monthly_natural_gas_cost, :appreciates => :state do |characteristics, timeframe|
255
+ relaxations = []
256
+ relaxations << { :timeframe => timeframe, :location => characteristics[:state] } if characteristics[:state]
257
+ relaxations << { :timeframe => timeframe.last_year, :location => characteristics[:state] } if characteristics[:state]
258
+ relaxations << { :timeframe => timeframe, :location => Country.united_states }
259
+ relaxations << { :timeframe => timeframe.last_year, :location => Country.united_states }
260
+ if price_per_unit = ResidenceFuelType[:natural_gas].price_per_unit(relaxations) #FIXME joules vs. cubic metres issue
261
+ characteristics[:monthly_natural_gas_cost] * 12 / price_per_unit
262
+ else
263
+ nil
264
+ end
265
+ end
266
+ end
267
+
268
+ committee :predicted_annual_natural_gas_consumption do # returns joules
269
+ quorum 'from cohort', :needs => :cohort do |characteristics|
270
+ characteristics[:cohort].weighted_average(%w(heating_space heating_water appliances).map { |purpose| "annual_energy_from_natural_gas_for_#{purpose}".to_sym }).to_f
271
+ end
272
+
273
+ quorum 'default' do
274
+ Residence.residence_model.fallback.monthly_natural_gas_volume_estimate * 12
275
+ end
276
+ end
277
+
278
+ committee :reported_annual_propane_consumption do # returns litres
279
+ quorum 'from volume estimate', :needs => :annual_propane_volume_estimate do |characteristics|
280
+ characteristics[:annual_propane_volume_estimate]
281
+ end
282
+
283
+ quorum 'from cost', :needs => :annual_propane_cost, :appreciates => :state do |characteristics, timeframe|
284
+ relaxations = []
285
+ relaxations << { :timeframe => timeframe, :location => characteristics[:state].petroleum_administration_for_defense_district } if characteristics[:state]
286
+ relaxations << { :timeframe => timeframe.last_year, :location => characteristics[:state].petroleum_administration_for_defense_district } if characteristics[:state]
287
+ relaxations << { :timeframe => timeframe, :location => Country.united_states }
288
+ relaxations << { :timeframe => timeframe.last_year, :location => Country.united_states }
289
+ if price_per_unit = ResidenceFuelType[:propane].price_per_unit(relaxations)
290
+ characteristics[:annual_propane_cost] / price_per_unit
291
+ else
292
+ nil
293
+ end
294
+ end
295
+ end
296
+
297
+ committee :predicted_annual_propane_consumption do # returns litres
298
+ quorum 'from cohort', :needs => :cohort do |characteristics|
299
+ characteristics[:cohort].weighted_average(%w(heating_space heating_water appliances).map { |purpose| "annual_energy_from_propane_for_#{purpose}".to_sym }).to_f.joules.to(:litres_of_propane)
300
+ end
301
+
302
+ quorum 'default' do
303
+ Residence.residence_model.fallback.annual_propane_volume_estimate
304
+ end
305
+ end
306
+
307
+ committee :reported_annual_kerosene_consumption do # returns litres
308
+ quorum 'from volume estimate', :needs => :annual_kerosene_volume_estimate do |characteristics|
309
+ characteristics[:annual_kerosene_volume_estimate]
310
+ end
311
+ end
312
+
313
+ committee :predicted_annual_kerosene_consumption do # returns litres
314
+ quorum 'from cohort', :needs => :cohort do |characteristics|
315
+ characteristics[:cohort].weighted_average(:annual_energy_from_kerosene).to_f.joules.to(:litres_of_kerosene)
316
+ end
317
+
318
+ quorum 'default' do
319
+ Residence.residence_model.fallback.annual_kerosene_volume_estimate
320
+ end
321
+ end
322
+
323
+ committee :reported_annual_biomass_consumption do # returns joules
324
+ quorum 'from volume estimate', :needs => :annual_wood_volume_estimate do |characteristics|
325
+ characteristics[:annual_wood_volume_estimate]
326
+ end
327
+ end
328
+
329
+ committee :predicted_annual_biomass_consumption do # returns joules
330
+ quorum 'from cohort', :needs => :cohort do |characteristics|
331
+ characteristics[:cohort].weighted_average(:annual_energy_from_wood)
332
+ end
333
+
334
+ quorum 'default' do
335
+ Residence.residence_model.fallback.annual_wood_volume_estimate
336
+ end
337
+ end
338
+
339
+ committee :reported_annual_coal_consumption do # returns kg
340
+ quorum 'from volume estimate', :needs => :annual_coal_volume_estimate do |characteristics|
341
+ characteristics[:annual_coal_volume_estimate]
342
+ end
343
+ end
344
+
345
+ committee :predicted_annual_coal_consumption do # returns kg
346
+ quorum 'default' do
347
+ Residence.residence_model.fallback.annual_coal_volume_estimate
348
+ end
349
+ end
350
+
351
+ committee :reported_annual_electricity_use do # returns kWh
352
+ quorum 'from use estimate', :needs => :monthly_electricity_use_estimate do |characteristics|
353
+ characteristics[:monthly_electricity_use_estimate] * 12
354
+ end
355
+
356
+ quorum 'from cost', :needs => :monthly_electricity_cost, :appreciates => :state do |characteristics, timeframe|
357
+ relaxations = []
358
+ relaxations << { :timeframe => timeframe, :location => characteristics[:state] } if characteristics[:state]
359
+ relaxations << { :timeframe => timeframe.last_year, :location => characteristics[:state] } if characteristics[:state]
360
+ relaxations << { :timeframe => timeframe, :location => Country.united_states }
361
+ relaxations << { :timeframe => timeframe.last_year, :location => Country.united_states }
362
+ if price_per_unit = ResidenceFuelType[:electricity].price_per_unit(relaxations)
363
+ characteristics[:monthly_electricity_cost] * 12 / price_per_unit
364
+ else
365
+ nil
366
+ end
367
+ end
368
+ end
369
+
370
+ committee :predicted_annual_electricity_use do # returns kWh
371
+ quorum 'from cohort', :needs => :cohort, :appreciates => [:clothes_machine_use, :refrigerator_count, :freezer_count, :dishwasher_use, :lighting_efficiency] do |characteristics|
372
+ cohort = characteristics[:cohort]
373
+ energy = cohort.weighted_average([:annual_energy_from_electricity_for_clothes_driers,
374
+ :annual_energy_from_electricity_for_dishwashers,
375
+ :annual_energy_from_electricity_for_freezers,
376
+ :annual_energy_from_electricity_for_refrigerators,
377
+ :annual_energy_from_electricity_for_air_conditioners,
378
+ :annual_energy_from_electricity_for_heating_space,
379
+ :annual_energy_from_electricity_for_heating_water,
380
+ :annual_energy_from_electricity_for_other_appliances]).to_f
381
+
382
+ if clothes_machine_use = characteristics[:clothes_machine_use]
383
+ energy -= cohort.weighted_average(:annual_energy_from_electricity_for_clothes_driers)
384
+ clothes_machine_use_cohort = ResidentialEnergyConsumptionSurveyResponse.big_cohort(characteristics.slice(*([:clothes_machine_use].push(*ResidentialEnergyConsumptionSurveyResponse::INPUT_CHARACTERISTICS))), ResidentialEnergyConsumptionSurveyResponse::SUBCOHORT_THRESHOLD)
385
+ if clothes_machine_use_cohort.any?
386
+ energy += clothes_machine_use_cohort.weighted_average(:annual_energy_from_electricity_for_clothes_driers).to_f
387
+ else
388
+ energy += charcteristics[:clothes_machine_use].annual_energy_from_electricity_for_clothes_driers
389
+ end
390
+ end
391
+
392
+ if refrigerator_count = characteristics[:refrigerator_count]
393
+ energy -= cohort.weighted_average(:annual_energy_from_electricity_for_refrigerators)
394
+ if refrigerator_count == 0
395
+ energy += 0
396
+ else
397
+ refrigerator_count_subcohort = ResidentialEnergyConsumptionSurveyResponse.big_cohort(characteristics.slice(*([:refrigerator_count].push(*ResidentialEnergyConsumptionSurveyResponse::INPUT_CHARACTERISTICS))), ResidentialEnergyConsumptionSurveyResponse::SUBCOHORT_THRESHOLD)
398
+ if refrigerator_count_subcohort.any?
399
+ energy += refrigerator_count_subcohort.weighted_average(:annual_energy_from_electricity_for_refrigerators).to_f
400
+ else
401
+ energy += refrigerator_count * ResidenceAppliance.annual_energy_from_electricity_for(:refrigerators)
402
+ end
403
+ end
404
+ end
405
+
406
+ if freezer_count = characteristics[:freezer_count]
407
+ energy -= cohort.weighted_average(:annual_energy_from_electricity_for_freezers)
408
+ if freezer_count == 0
409
+ energy += 0
410
+ else
411
+ freezer_count_subcohort = ResidentialEnergyConsumptionSurveyResponse.big_cohort(characteristics.slice(*([:freezer_count].push(*ResidentialEnergyConsumptionSurveyResponse::INPUT_CHARACTERISTICS))), ResidentialEnergyConsumptionSurveyResponse::SUBCOHORT_THRESHOLD)
412
+ if freezer_count_subcohort.any?
413
+ energy += freezer_count_subcohort.weighted_average(:annual_energy_from_electricity_for_freezers).to_f
414
+ else
415
+ energy += freezer_count * ResidenceAppliance.annual_energy_from_electricity_for(:freezers)
416
+ end
417
+ end
418
+ end
419
+
420
+ if dishwasher_use = characteristics[:dishwasher_use]
421
+ energy -= cohort.weighted_average(:annual_energy_from_electricity_for_dishwashers)
422
+ dishwasher_use_cohort = ResidentialEnergyConsumptionSurveyResponse.big_cohort(characteristics.slice(*([:dishwasher_use].push(*ResidentialEnergyConsumptionSurveyResponse::INPUT_CHARACTERISTICS))), ResidentialEnergyConsumptionSurveyResponse::SUBCOHORT_THRESHOLD)
423
+ if dishwasher_use_cohort.any?
424
+ energy += dishwasher_use_cohort.weighted_average(:annual_energy_from_electricity_for_dishwashers).to_f
425
+ else
426
+ energy += characteristics[:dishwasher_use].annual_energy_from_electricity_for_dishwashers
427
+ end
428
+ end
429
+
430
+ if lighting_efficiency = characteristics[:lighting_efficiency]
431
+ lighting_electricity_use_in_cohort =
432
+ cohort.weighted_average(:lighting_efficiency) * cohort.weighted_average(:lighting_use) * research(:efficient_lightbulb_power) +
433
+ (1 - cohort.weighted_average(:lighting_efficiency)) * cohort.weighted_average(:lighting_use) * research(:standard_lightbulb_power)
434
+ energy -= lighting_electricity_use_in_cohort.watt_hours.to :joules
435
+ lighting_electricity_use_in_residence =
436
+ lighting_efficiency * cohort.weighted_average(:lighting_use) * research(:efficient_lightbulb_power) +
437
+ (1 - lighting_efficiency) * cohort.weighted_average(:lighting_use) * research(:standard_lightbulb_power)
438
+ energy += lighting_electricity_use_in_residence.watt_hours.to :joules
439
+ end
440
+
441
+ energy.joules.to(:kilowatt_hours)
442
+ end
443
+
444
+ quorum 'default' do
445
+ Residence.residence_model.fallback.monthly_electricity_use_estimate * 12
446
+ end
447
+ end
448
+
449
+ committee :active_subtimeframe do
450
+ quorum 'from acquisition and retirement', :needs => [:acquisition, :retirement] do |characteristics, timeframe|
451
+ Timeframe.constrained_new characteristics[:acquisition].to_date, characteristics[:retirement].to_date, timeframe
452
+ end
453
+ end
454
+
455
+ committee :acquisition do
456
+ quorum 'from construction year', :needs => :construction_year do |characteristics|
457
+ #FIXME this is an imperfect substitution for a line in https://app1.yerba.brighterplanet.com/changesets/9463
458
+ characteristics[:construction_year] - 1.year
459
+ end
460
+ quorum 'from retirement', :appreciates => :retirement do |characteristics, timeframe|
461
+ [ timeframe.from, characteristics[:retirement] ].compact.min
462
+ end
463
+ end
464
+
465
+ committee :retirement do
466
+ quorum 'from acquisition', :appreciates => :acquisition do |characteristics, timeframe|
467
+ [ timeframe.to, characteristics[:acquisition] ].compact.max
468
+ end
469
+ end
470
+
471
+ # This is kindof "hacky"
472
+ # As implemented, this needs to be above floorspace committee or else cohort will always
473
+ # use the Residence.residence_model.fallback
474
+ committee :floorspace_estimate do
475
+ quorum 'from cohort', :needs => :cohort do |characteristics|
476
+ characteristics[:cohort].weighted_average :floorspace
477
+ end
478
+
479
+ quorum 'default' do
480
+ Residence.residence_model.fallback.floorspace_estimate
481
+ end
482
+ end
483
+
484
+ committee :cohort do
485
+ quorum 'from residential energy consumption survey', :appreciates => ResidentialEnergyConsumptionSurveyResponse::INPUT_CHARACTERISTICS do |characteristics|
486
+ cohort = ResidentialEnergyConsumptionSurveyResponse.big_cohort characteristics
487
+ if cohort.any?
488
+ cohort
489
+ else
490
+ nil
491
+ end
492
+ end
493
+ end
494
+
495
+ committee :bathrooms do
496
+ quorum 'from fractional bathroom counts', :needs => [:full_bathrooms, :half_bathrooms] do |characteristics|
497
+ characteristics[:full_bathrooms] + 0.5 * characteristics[:half_bathrooms]
498
+ end
499
+ end
500
+
501
+ committee :census_region do
502
+ quorum 'from census division', :needs => :census_division do |characteristics|
503
+ characteristics[:census_division].census_region
504
+ end
505
+ end
506
+
507
+ committee :census_division do
508
+ quorum 'from state', :needs => :state do |characteristics|
509
+ characteristics[:state].census_division
510
+ end
511
+ end
512
+
513
+ committee :state do
514
+ quorum 'from climate division', :needs => :climate_division do |characteristics|
515
+ characteristics[:climate_division].state
516
+ end
517
+ end
518
+
519
+ committee :floorspace do # returns a Range of floorspaces
520
+ quorum 'from floorspace estimate', :needs => :floorspace_estimate do |characteristics|
521
+ floorspace_estimate = characteristics[:floorspace_estimate]
522
+ (floorspace_estimate - 50)..(floorspace_estimate + 50)
523
+ end
524
+ end
525
+
526
+ committee :heating_degree_days do # returns a Range of degree-days
527
+ quorum 'from climate division', :needs => :climate_division do |characteristics|
528
+ days = characteristics[:climate_division].heating_degree_days
529
+ (days - ClimateDivision::RADIUS)..(days + ClimateDivision::RADIUS)
530
+ end
531
+ end
532
+
533
+ committee :cooling_degree_days do
534
+ quorum 'from climate division', :needs => :climate_division do |characteristics|
535
+ days = characteristics[:climate_division].cooling_degree_days
536
+ (days - ClimateDivision::RADIUS)..(days + ClimateDivision::RADIUS)
537
+ end
538
+ end
539
+
540
+ committee :climate_division do
541
+ quorum 'from zip code', :needs => :zip_code do |characteristics|
542
+ characteristics[:zip_code].climate_division
543
+ end
544
+ end
545
+ end
546
+ end
547
+ end
548
+ end
549
+ end
@@ -0,0 +1,49 @@
1
+ require 'characterizable'
2
+
3
+ module BrighterPlanet
4
+ module Residence
5
+ module Characterization
6
+ def self.included(base)
7
+ base.send :include, Characterizable
8
+ base.characterize do
9
+ has :zip_code
10
+ has :urbanity
11
+ has :ownership
12
+ has :residence_class
13
+ has :residents
14
+ has :clothes_machine_use
15
+ has :dishwasher_use
16
+ has :air_conditioner_use
17
+ has :refrigerator_count
18
+ has :freezer_count
19
+ has :lighting_efficiency, :measures => :percentage
20
+ has :floorspace_estimate, :trumps => :rooms, :measures => :area
21
+ has :floors # not used
22
+ has :bathrooms
23
+ has :bedrooms
24
+ has :full_bathrooms, :hidden => true
25
+ has :half_bathrooms, :hidden => true
26
+ has :rooms, :trumps => [:bathrooms, :bedrooms, :full_bathrooms, :half_bathrooms]
27
+ has :acquisition
28
+ has :retirement
29
+ has :construction_year # TODO show year only
30
+ has :occupation, :measures => :percentage
31
+ has :annual_fuel_oil_volume_estimate, :trumps => :annual_fuel_oil_cost, :measures => :volume
32
+ has :annual_fuel_oil_cost, :trumps => :annual_fuel_oil_volume_estimate, :measures => :cost
33
+ has :monthly_natural_gas_volume_estimate, :trumps => :monthly_natural_gas_cost, :measurement_options => { :external => :therms, :internal => :joules }
34
+ has :monthly_natural_gas_cost, :trumps => :monthly_natural_gas_volume_estimate, :measures => :cost
35
+ has :monthly_electricity_use_estimate, :trumps => :monthly_electricity_cost, :measures => :electrical_energy
36
+ has :monthly_electricity_cost, :trumps => :monthly_electricity_use_estimate, :measures => :cost
37
+ has :green_electricity, :measures => :percentage
38
+ has :annual_propane_volume_estimate, :trumps => :annual_propane_cost, :measures => :volume
39
+ has :annual_propane_cost, :trumps => :annual_propane_volume_estimate, :measures => :cost
40
+ has :annual_wood_volume_estimate, :measures => :biomass
41
+ has :annual_kerosene_volume_estimate, :trumps => :annual_kerosene_cost, :measures => :volume
42
+ has :annual_coal_volume_estimate, :trumps => :annual_coal_cost, :measures => :mass # it says volume, but it wants mass
43
+ # has :annual_coal_cost, :trumps => :annual_coal_volume_estimate, :measures => :cost
44
+ end
45
+ base.add_implicit_characteristics
46
+ end
47
+ end
48
+ end
49
+ end