residence 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/features/residence_committees.feature +11 -0
- data/features/residence_emissions.feature +14 -0
- data/features/support/env.rb +8 -0
- data/lib/residence/carbon_model.rb +549 -0
- data/lib/residence/characterization.rb +49 -0
- data/lib/residence/data.rb +62 -0
- data/lib/residence/summarization.rb +19 -0
- data/lib/residence.rb +25 -539
- data/lib/test_support/db/schema.rb +49 -0
- data/lib/test_support/residence_record.rb +97 -0
- metadata +255 -20
- data/.document +0 -5
- data/.gitignore +0 -21
- data/Rakefile +0 -54
- data/VERSION +0 -1
- data/residence.gemspec +0 -57
- data/test/helper.rb +0 -10
- data/test/test_residence.rb +0 -7
@@ -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,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
|