earth 0.4.0 → 0.4.1

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 (38) hide show
  1. data/earth.gemspec +2 -2
  2. data/features/automobile_fuel.feature +100 -0
  3. data/features/bus_class.feature +12 -42
  4. data/features/bus_fuel.feature +114 -0
  5. data/features/egrid_subregion.feature +113 -15
  6. data/features/support/imports/automobile_fuel_bad.csv +3 -3
  7. data/features/support/imports/automobile_fuel_good.csv +3 -3
  8. data/features/support/imports/bus_class_bad.csv +2 -3
  9. data/features/support/imports/bus_class_good.csv +2 -3
  10. data/features/support/imports/bus_fuel_bad.csv +3 -0
  11. data/features/support/imports/bus_fuel_good.csv +3 -0
  12. data/features/support/imports/egrid_subregion_bad.csv +2 -3
  13. data/features/support/imports/egrid_subregion_good.csv +2 -3
  14. data/lib/earth/automobile/automobile_fuel.rb +63 -58
  15. data/lib/earth/automobile/automobile_fuel/data_miner.rb +110 -0
  16. data/lib/earth/bus.rb +3 -0
  17. data/lib/earth/bus/bus_class.rb +21 -2
  18. data/lib/earth/bus/bus_class/data_miner.rb +79 -43
  19. data/lib/earth/bus/bus_fuel.rb +18 -0
  20. data/lib/earth/bus/bus_fuel/data_miner.rb +204 -0
  21. data/lib/earth/bus/bus_fuel_control.rb +7 -0
  22. data/lib/earth/bus/bus_fuel_control/data_miner.rb +41 -0
  23. data/lib/earth/bus/bus_fuel_year_control.rb +13 -0
  24. data/lib/earth/bus/bus_fuel_year_control/data_miner.rb +35 -0
  25. data/lib/earth/bus/data_miner.rb +3 -0
  26. data/lib/earth/fuel/fuel.rb +16 -0
  27. data/lib/earth/fuel/fuel/data_miner.rb +6 -1
  28. data/lib/earth/locality/egrid_region.rb +3 -2
  29. data/lib/earth/locality/egrid_region/data_miner.rb +8 -31
  30. data/lib/earth/locality/egrid_subregion.rb +18 -2
  31. data/lib/earth/locality/egrid_subregion/data_miner.rb +109 -56
  32. data/spec/earth/automobile/automobile_fuel_spec.rb +9 -12
  33. data/spec/earth/bus/bus_class_spec.rb +12 -0
  34. data/spec/earth/bus/bus_fuel_control_spec.rb +12 -0
  35. data/spec/earth/bus/bus_fuel_year_control_spec.rb +16 -0
  36. data/spec/earth/pet/species_spec.rb +0 -1
  37. data/spec/earth_spec.rb +2 -2
  38. metadata +46 -16
@@ -1,3 +1,3 @@
1
- name,base_fuel_name,distance_key,ef_key,blend_portion
2
- regular gasoline
3
- b20,Distillate Fuel Oil No. 2,diesel,diesel,1.1
1
+ name,co2_emission_factor,co2_emission_factor_units,co2_biogenic_emission_factor,co2_biogenic_emission_factor_units,ch4_emission_factor,ch4_emission_factor_units,n2o_emission_factor,n2o_emission_factor_units,hfc_emission_factor,hfc_emission_factor_units,base_fuel_name,distance_key,ef_key,blend_portion
2
+ regular gasoline,-1,kilograms_per_gallon,-1,kilograms_per_gallon,0,kilograms_per_litre,0,kilograms_per_litre,0,kilograms_per_litre
3
+ b20,-1,kilograms_per_gallon,-1,kilograms_per_gallon,0,kilograms_per_litre,0,kilograms_per_litre,0,kilograms_per_litre,Distillate Fuel Oil No. 2,diesel,diesel,1.1
@@ -1,3 +1,3 @@
1
- name,base_fuel_name,distance_key,ef_key,blend_portion
2
- regular gasoline,Motor Gasoline,gasoline,gasoline
3
- b20,Distillate Fuel Oil No. 2,diesel,diesel,0.2
1
+ name,co2_emission_factor,co2_emission_factor_units,co2_biogenic_emission_factor,co2_biogenic_emission_factor_units,ch4_emission_factor,ch4_emission_factor_units,n2o_emission_factor,n2o_emission_factor_units,hfc_emission_factor,hfc_emission_factor_units,base_fuel_name,distance_key,ef_key,blend_portion
2
+ regular gasoline,1,kilograms_per_litre,0,kilograms_per_litre,0.1,kilograms_co2e_per_litre,0.1,kilograms_co2e_per_litre,0.1,kilograms_co2e_per_litre,Motor Gasoline,gasoline,gasoline
3
+ b20,0,kilograms_per_litre,1,kilograms_per_litre,0.1,kilograms_co2e_per_litre,0.1,kilograms_co2e_per_litre,0.1,kilograms_co2e_per_litre,Distillate Fuel Oil No. 2,diesel,diesel,0.2
@@ -1,3 +1,2 @@
1
- name,distance,distance_units,passengers,speed,speed_units,diesel_intensity,diesel_intensity_units,alternative_fuels_intensity,alternative_fuels_intensity_units,air_conditioning_emission_factor,air_conditioning_emission_factor_units
2
- transit,10,kilometres,15,20,kilometres_per_hour,0.5,litres_per_kilometre,0,litres_per_kilometre,0,kilograms_per_kilometre
3
- regional,-10,distance_units,0,,,-2,diesel_intensity_units,-2,alternative_fuels_intensity_units
1
+ name,distance,distance_units,passengers,speed,speed_units,gasoline_intensity,gasoline_intensity_units,diesel_intensity,diesel_intensity_units,cng_intensity,cng_intensity_units,lng_intensity,lng_intensity_units,lpg_intensity,lpg_intensity_units,methanol_intensity,methanol_intensity_units,biodiesel_intensity,biodiesel_intensity_units,electricity_intensity,electricity_intensity_units,air_conditioning_emission_factor,air_conditioning_emission_factor_units,alternative_fuels_intensity,alternative_fuels_intensity_units
2
+ city transit,0,miles,0,0,miles_per_hour,-1,gallons_per_mile,0,gallons_per_mile,-1,gallons_per_mile,-1,gallons_per_mile,-1,gallons_per_mile,-1,gallons_per_mile,-1,gallons_per_mile,-1,kilowatt_hours_per_mile,0,pounds_co2e_per_mile,-1,gallons_per_mile
@@ -1,3 +1,2 @@
1
- name,distance,distance_units,passengers,speed,speed_units,diesel_intensity,diesel_intensity_units,alternative_fuels_intensity,alternative_fuels_intensity_units,air_conditioning_emission_factor,air_conditioning_emission_factor_units
2
- transit,10,kilometres,15,20,kilometres_per_hour,0.5,litres_per_kilometre,0,litres_per_kilometre,0,kilograms_per_kilometre
3
- regional,100,kilometres,30,80,kilometres_per_hour,0.1,litres_per_kilometre,0.2,litres_per_kilometre,0.5,kilograms_per_kilometre
1
+ name,distance,distance_units,passengers,speed,speed_units,gasoline_intensity,gasoline_intensity_units,diesel_intensity,diesel_intensity_units,cng_intensity,cng_intensity_units,lng_intensity,lng_intensity_units,lpg_intensity,lpg_intensity_units,methanol_intensity,methanol_intensity_units,biodiesel_intensity,biodiesel_intensity_units,electricity_intensity,electricity_intensity_units,air_conditioning_emission_factor,air_conditioning_emission_factor_units,alternative_fuels_intensity,alternative_fuels_intensity_units
2
+ city transit,1,kilometres,1,1,kilometres_per_hour,0,litres_per_kilometre,1,litres_per_kilometre,0,litres_per_kilometre,0,litres_per_kilometre,0,litres_per_kilometre,0,litres_per_kilometre,0,litres_per_kilometre,0,kilowatt_hours_per_kilometre,1,kilograms_co2e_per_kilometre,0,litres_per_kilometre
@@ -0,0 +1,3 @@
1
+ name,co2_emission_factor,co2_emission_factor_units,co2_biogenic_emission_factor,co2_biogenic_emission_factor_units,ch4_emission_factor,ch4_emission_factor_units,n2o_emission_factor,n2o_emission_factor_units,fuel_name,energy_content,energy_content_units
2
+ CNG,-1,kilograms_per_gallon,-1,kilograms_per_gallon,0,kilograms_per_kilometre,0,kilograms_per_kilometre
3
+ LNG,1,kilograms_per_litre,0,kilograms_per_litre,0.1,kilograms_co2e_per_kilometre,0.1,kilograms_co2e_per_kilometre,Pipeline Natural Gas,0,btu_per_gallon
@@ -0,0 +1,3 @@
1
+ name,co2_emission_factor,co2_emission_factor_units,co2_biogenic_emission_factor,co2_biogenic_emission_factor_units,ch4_emission_factor,ch4_emission_factor_units,n2o_emission_factor,n2o_emission_factor_units,fuel_name,energy_content,energy_content_units
2
+ CNG,0,kilograms_per_litre,1,kilograms_per_litre,0.1,kilograms_co2e_per_kilometre,0.1,kilograms_co2e_per_kilometre,Pipeline Natural Gas
3
+ LNG,1,kilograms_per_litre,0,kilograms_per_litre,0.1,kilograms_co2e_per_kilometre,0.1,kilograms_co2e_per_kilometre,Pipeline Natural Gas,10,megajoules_per_litre
@@ -1,3 +1,2 @@
1
- name,egrid_region_name,electricity_emission_factor,electricity_emission_factor_units
2
- US,US,1.2,kilograms_per_kilowatt_hour
3
- AKGD,foo,0
1
+ abbreviation,net_generation,net_generation_units,electricity_co2_emission_factor,electricity_co2_emission_factor_units,electricity_co2_biogenic_emission_factor,electricity_co2_biogenic_emission_factor_units,electricity_ch4_emission_factor,electricity_ch4_emission_factor_units,electricity_n2o_emission_factor,electricity_n2o_emission_factor_units,electricity_emission_factor,electricity_emission_factor_units,egrid_region_name
2
+ NEWE,0,kilowatt_hours,0,pounds_per_megawatt_hour,-1,pounds_per_megawatt_hour,0,pounds_per_gigawatt_hour,0,pounds_per_gigawatt_hour,0,pounds_per_megawatt_hour
@@ -1,3 +1,2 @@
1
- name,egrid_region_name,electricity_emission_factor,electricity_emission_factor_units
2
- US,US,1.2,kilograms_co2e_per_kilowatt_hour
3
- AKGD,AK,0.9,kilograms_co2e_per_kilowatt_hour
1
+ abbreviation,net_generation,net_generation_units,electricity_co2_emission_factor,electricity_co2_emission_factor_units,electricity_co2_biogenic_emission_factor,electricity_co2_biogenic_emission_factor_units,electricity_ch4_emission_factor,electricity_ch4_emission_factor_units,electricity_n2o_emission_factor,electricity_n2o_emission_factor_units,electricity_emission_factor,electricity_emission_factor_units,egrid_region_name
2
+ NEWE,1350,megawatt_hours,0.4,kilograms_per_kilowatt_hour,0,kilograms_per_kilowatt_hour,0.001,kilograms_co2e_per_kilowatt_hour,0.002,kilograms_co2e_per_kilowatt_hour,0.4,kilograms_co2e_per_kilowatt_hour,E
@@ -18,74 +18,79 @@ class AutomobileFuel < ActiveRecord::Base
18
18
  diesel_use = AutomobileTypeFuelYear.where(:year => latest_year, :fuel_common_name => 'diesel').sum('fuel_consumption')
19
19
  diesel_use / (gas_use + diesel_use)
20
20
  end
21
+
22
+ def fallback_co2_emission_factor
23
+ (Fuel.find_by_name("Motor Gasoline").co2_emission_factor * (1 - AutomobileFuel.fallback_blend_portion)) +
24
+ (Fuel.find_by_name("Distillate Fuel Oil No. 2").co2_emission_factor * AutomobileFuel.fallback_blend_portion)
25
+ end
26
+
27
+ def fallback_co2_emission_factor_units
28
+ Fuel.find_by_name("Motor Gasoline").co2_emission_factor_units
29
+ end
30
+
31
+ def fallback_co2_biogenic_emission_factor
32
+ (Fuel.find_by_name("Motor Gasoline").co2_biogenic_emission_factor * (1 - AutomobileFuel.fallback_blend_portion)) +
33
+ (Fuel.find_by_name("Distillate Fuel Oil No. 2").co2_biogenic_emission_factor * AutomobileFuel.fallback_blend_portion)
34
+ end
35
+
36
+ def fallback_co2_biogenic_emission_factor_units
37
+ Fuel.find_by_name("Motor Gasoline").co2_biogenic_emission_factor_units
38
+ end
39
+
40
+ def fallback_latest_type_fuel_years
41
+ AutomobileTypeFuelYear.where(:year => AutomobileTypeFuelYear.maximum('year'))
42
+ end
43
+
44
+ def fallback_ch4_emission_factor
45
+ fallback_latest_type_fuel_years.weighted_average(:ch4_emission_factor, :weighted_by => :total_travel) * GreenhouseGas[:ch4].global_warming_potential
46
+ end
47
+
48
+ def fallback_ch4_emission_factor_units
49
+ prefix = fallback_latest_type_fuel_years.first.ch4_emission_factor_units.split("_per_")[0]
50
+ suffix = fallback_latest_type_fuel_years.first.ch4_emission_factor_units.split("_per_")[1]
51
+ prefix + "_co2e_per_" + suffix
52
+ end
53
+
54
+ def fallback_n2o_emission_factor
55
+ fallback_latest_type_fuel_years.weighted_average(:n2o_emission_factor, :weighted_by => :total_travel) * GreenhouseGas[:n2o].global_warming_potential
56
+ end
57
+
58
+ def fallback_n2o_emission_factor_units
59
+ prefix = fallback_latest_type_fuel_years.first.n2o_emission_factor_units.split("_per_")[0]
60
+ suffix = fallback_latest_type_fuel_years.first.n2o_emission_factor_units.split("_per_")[1]
61
+ prefix + "_co2e_per_" + suffix
62
+ end
63
+
64
+ def fallback_hfc_emission_factor
65
+ fallback_latest_type_fuel_years.map do |tfy|
66
+ tfy.total_travel * tfy.type_year.hfc_emission_factor
67
+ end.sum / fallback_latest_type_fuel_years.sum('total_travel')
68
+ end
69
+
70
+ def fallback_hfc_emission_factor_units
71
+ fallback_latest_type_fuel_years.first.type_year.hfc_emission_factor_units
72
+ end
21
73
  end
22
74
 
23
- falls_back_on :name => 'fallback',
24
- :base_fuel_name => 'Motor Gasoline',
25
- :blend_fuel_name => 'Distillate Fuel Oil No. 2',
26
- :blend_portion => lambda { AutomobileFuel.fallback_blend_portion },
27
- :distance_key => 'fallback',
28
- :ef_key => 'fallback'
75
+ falls_back_on :co2_emission_factor => lambda { AutomobileFuel.fallback_co2_emission_factor },
76
+ :co2_emission_factor_units => lambda { AutomobileFuel.fallback_co2_emission_factor_units },
77
+ :co2_biogenic_emission_factor => lambda { AutomobileFuel.fallback_co2_biogenic_emission_factor },
78
+ :co2_biogenic_emission_factor_units => lambda { AutomobileFuel.fallback_co2_biogenic_emission_factor_units },
79
+ :ch4_emission_factor => lambda { AutomobileFuel.fallback_ch4_emission_factor },
80
+ :ch4_emission_factor_units => lambda { AutomobileFuel.fallback_ch4_emission_factor_units },
81
+ :n2o_emission_factor => lambda { AutomobileFuel.fallback_n2o_emission_factor },
82
+ :n2o_emission_factor_units => lambda { AutomobileFuel.fallback_n2o_emission_factor_units },
83
+ :hfc_emission_factor => lambda { AutomobileFuel.fallback_hfc_emission_factor },
84
+ :hfc_emission_factor_units => lambda { AutomobileFuel.fallback_hfc_emission_factor_units }
29
85
 
30
86
  data_miner do
31
- tap "Brighter Planet's sanitized automobile fuel type data", Earth.taps_server
87
+ tap "Brighter Planet's sanitized automobile fuel data", Earth.taps_server
32
88
 
33
89
  process "pull dependencies" do
34
90
  run_data_miner_on_belongs_to_associations
35
91
  end
36
92
  end
37
93
 
38
- # FIXME TODO should I run data miner on has_many associations?
39
- # AutomobileTypeFuelYearAge
40
- # => AutomobileTypeFuelYearControl
41
- # => AutomobileTypeFuelControl
42
- # AutomobileTypeYear
43
-
44
- # FIXME TODO should I run data miner on other classes we need?
45
- # Fuel
46
- # => FuelYear
47
- # GreenhouseGas
48
-
49
- def annual_distance # returns km
50
- scope = type_fuel_year_ages.any? ? type_fuel_year_ages : AutomobileTypeFuelYearAge
51
- scope.where(:year => scope.maximum('year')).weighted_average(:annual_distance, :weighted_by => :vehicles)
52
- end
53
-
54
- def co2_emission_factor # returns kg co2 / litre
55
- if blend_fuel.present?
56
- (base_fuel.co2_emission_factor * (1 - blend_portion)) + (blend_fuel.co2_emission_factor * blend_portion)
57
- else
58
- base_fuel.co2_emission_factor
59
- end
60
- end
61
-
62
- def co2_biogenic_emission_factor # returns kg co2 / litre
63
- if blend_fuel.present?
64
- (base_fuel.co2_biogenic_emission_factor * (1 - blend_portion)) + (blend_fuel.co2_biogenic_emission_factor * blend_portion)
65
- else
66
- base_fuel.co2_biogenic_emission_factor
67
- end
68
- end
69
-
70
- def latest_type_fuel_years
71
- scope = type_fuel_years.any? ? type_fuel_years : AutomobileTypeFuelYear
72
- scope.where(:year => scope.maximum('year'))
73
- end
74
-
75
- def ch4_emission_factor # returns kg co2e / litre
76
- latest_type_fuel_years.weighted_average(:ch4_emission_factor, :weighted_by => :total_travel) * GreenhouseGas[:ch4].global_warming_potential
77
- end
78
-
79
- def n2o_emission_factor # returns kg co2e / litre
80
- latest_type_fuel_years.weighted_average(:n2o_emission_factor, :weighted_by => :total_travel) * GreenhouseGas[:n2o].global_warming_potential
81
- end
82
-
83
- def hfc_emission_factor # returns kg co2e / litre (hfc emission factor is already in co2e)
84
- latest_type_fuel_years.map do |type_fuel_year|
85
- type_fuel_year.total_travel * type_fuel_year.type_year.hfc_emission_factor
86
- end.sum / latest_type_fuel_years.sum('total_travel')
87
- end
88
-
89
94
  CODES = {
90
95
  :electricity => 'El',
91
96
  :diesel => 'D'
@@ -8,6 +8,18 @@ AutomobileFuel.class_eval do
8
8
  float 'blend_portion' # the portion of the blend that is the blend fuel
9
9
  string 'distance_key' # used to look up annual distance from AutomobileTypeFuelYear
10
10
  string 'ef_key' # used to look up ch4 n2o and hfc emission factors from AutomobileTypeFuelYear
11
+ float 'annual_distance'
12
+ string 'annual_distance_units'
13
+ float 'co2_emission_factor'
14
+ string 'co2_emission_factor_units'
15
+ float 'co2_biogenic_emission_factor'
16
+ string 'co2_biogenic_emission_factor_units'
17
+ float 'ch4_emission_factor'
18
+ string 'ch4_emission_factor_units'
19
+ float 'n2o_emission_factor'
20
+ string 'n2o_emission_factor_units'
21
+ float 'hfc_emission_factor'
22
+ string 'hfc_emission_factor_units'
11
23
  end
12
24
 
13
25
  import "a list of pure automobile fuels",
@@ -30,6 +42,60 @@ AutomobileFuel.class_eval do
30
42
  store 'ef_key'
31
43
  end
32
44
 
45
+ process "Ensure necessary datasets are imported" do
46
+ AutomobileTypeFuelYearAge.run_data_miner!
47
+ AutomobileTypeYear.run_data_miner!
48
+ Fuel.run_data_miner!
49
+ GreenhouseGas.run_data_miner!
50
+ end
51
+
52
+ process "Derive annual distance" do
53
+ AutomobileFuel.all.each do |record|
54
+ scope = record.type_fuel_year_ages.where(:year => record.type_fuel_year_ages.maximum('year'))
55
+ record.annual_distance = scope.weighted_average(:annual_distance, :weighted_by => :vehicles)
56
+ record.annual_distance_units = scope.first.annual_distance_units
57
+ record.save
58
+ end
59
+ end
60
+
61
+ process "Derive co2 emission factor and co2 biogenic emission factors" do
62
+ AutomobileFuel.all.each do |record|
63
+ if record.blend_fuel.present?
64
+ record.co2_emission_factor = (record.base_fuel.co2_emission_factor * (1 - record.blend_portion)) + (record.blend_fuel.co2_emission_factor * record.blend_portion)
65
+ record.co2_biogenic_emission_factor = (record.base_fuel.co2_biogenic_emission_factor * (1 - record.blend_portion)) + (record.blend_fuel.co2_biogenic_emission_factor * record.blend_portion)
66
+ else
67
+ record.co2_emission_factor = record.base_fuel.co2_emission_factor
68
+ record.co2_biogenic_emission_factor = record.base_fuel.co2_biogenic_emission_factor
69
+ end
70
+ record.co2_emission_factor_units = record.base_fuel.co2_emission_factor_units
71
+ record.co2_biogenic_emission_factor_units = record.base_fuel.co2_biogenic_emission_factor_units
72
+ record.save
73
+ end
74
+ end
75
+
76
+ process "Derive ch4, n2o, and hfc emission factors" do
77
+ AutomobileFuel.all.each do |record|
78
+ scope = record.type_fuel_years.where(:year => record.type_fuel_years.maximum('year'))
79
+
80
+ record.ch4_emission_factor = scope.weighted_average(:ch4_emission_factor, :weighted_by => :total_travel) * GreenhouseGas[:ch4].global_warming_potential
81
+ ch4_prefix = scope.first.ch4_emission_factor_units.split("_per_")[0]
82
+ ch4_suffix = scope.first.ch4_emission_factor_units.split("_per_")[1]
83
+ record.ch4_emission_factor_units = ch4_prefix + "_co2e_per_" + ch4_suffix
84
+
85
+ record.n2o_emission_factor = scope.weighted_average(:n2o_emission_factor, :weighted_by => :total_travel) * GreenhouseGas[:n2o].global_warming_potential
86
+ n2o_prefix = scope.first.n2o_emission_factor_units.split("_per_")[0]
87
+ n2o_suffix = scope.first.n2o_emission_factor_units.split("_per_")[1]
88
+ record.n2o_emission_factor_units = n2o_prefix + "_co2e_per_" + n2o_suffix
89
+
90
+ record.hfc_emission_factor = scope.map do |tfy|
91
+ tfy.total_travel * tfy.type_year.hfc_emission_factor
92
+ end.sum / scope.sum('total_travel')
93
+ record.hfc_emission_factor_units = scope.first.type_year.hfc_emission_factor_units
94
+
95
+ record.save
96
+ end
97
+ end
98
+
33
99
  # FIXME TODO verify code somehow
34
100
 
35
101
  %w{ base_fuel_name distance_key ef_key }.each do |attribute|
@@ -37,6 +103,7 @@ AutomobileFuel.class_eval do
37
103
  AutomobileFuel.all.each do |fuel|
38
104
  value = fuel.send(:"#{attribute}")
39
105
  unless value.present?
106
+ puts "Missing #{attribute.humanize.downcase} for AutomobileFuel #{fuel.name}"
40
107
  raise "Missing #{attribute.humanize.downcase} for AutomobileFuel #{fuel.name}"
41
108
  end
42
109
  end
@@ -51,10 +118,53 @@ AutomobileFuel.class_eval do
51
118
  AutomobileFuel.all.each do |fuel|
52
119
  if fuel.blend_portion.present?
53
120
  unless fuel.blend_portion >=0 and fuel.blend_portion <= 1
121
+ puts "Invalid blend portion for AutomobileFuel #{fuel.name}: #{fuel.blend_portion} (should be from 0 to 1)"
54
122
  raise "Invalid blend portion for AutomobileFuel #{fuel.name}: #{fuel.blend_portion} (should be from 0 to 1)"
55
123
  end
56
124
  end
57
125
  end
58
126
  end
127
+
128
+ ["co2_emission_factor", "co2_biogenic_emission_factor"].each do |attribute|
129
+ verify "#{attribute.humanize} should be 0 or more" do
130
+ AutomobileFuel.all.each do |fuel|
131
+ value = fuel.send(attribute)
132
+ unless value >= 0
133
+ puts "Invalid #{attribute.humanize.downcase} for AutomobileFuel #{fuel.name}: #{value} (should be 0 or more)"
134
+ raise "Invalid #{attribute.humanize.downcase} for AutomobileFuel #{fuel.name}: #{value} (should be 0 or more)"
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ ["ch4_emission_factor", "n2o_emission_factor", "hfc_emission_factor"].each do |attribute|
141
+ verify "#{attribute.humanize} should be > 0" do
142
+ AutomobileFuel.all.each do |fuel|
143
+ value = fuel.send(attribute)
144
+ unless value > 0
145
+ puts "Invalid #{attribute.humanize.downcase} for AutomobileFuel #{fuel.name}: #{value} (should be > 0)"
146
+ raise "Invalid #{attribute.humanize.downcase} for AutomobileFuel #{fuel.name}: #{value} (should be > 0)"
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ [["co2_emission_factor_units", "kilograms_per_litre"],
153
+ ["co2_biogenic_emission_factor_units", "kilograms_per_litre"],
154
+ ["ch4_emission_factor_units", "kilograms_co2e_per_litre"],
155
+ ["n2o_emission_factor_units", "kilograms_co2e_per_litre"],
156
+ ["hfc_emission_factor_units", "kilograms_co2e_per_litre"]].each do |pair|
157
+ attribute = pair[0]
158
+ proper_units = pair[1]
159
+ verify "#{attribute.humanize} should be #{proper_units.humanize.downcase}" do
160
+ AutomobileFuel.all.each do |fuel|
161
+ units = fuel.send(attribute)
162
+ unless units == proper_units
163
+ puts "Invalid #{attribute.humanize.downcase} for AutomobileFuel #{fuel.name}: #{units} (should be #{proper_units})"
164
+ fail
165
+ end
166
+ end
167
+ end
168
+ end
59
169
  end
60
170
  end
data/lib/earth/bus.rb CHANGED
@@ -1 +1,4 @@
1
1
  require 'earth/bus/bus_class'
2
+ require 'earth/bus/bus_fuel'
3
+ require 'earth/bus/bus_fuel_control'
4
+ require 'earth/bus/bus_fuel_year_control'
@@ -4,10 +4,29 @@ class BusClass < ActiveRecord::Base
4
4
  # https://spreadsheets.google.com/pub?key=0AoQJbWqPrREqdHY0R0hjZnhRaTIxTnpvRk1HNThwUmc&hl=en&output=html
5
5
  falls_back_on :passengers => 7.485,
6
6
  :distance => 4.9726.miles.to(:kilometres),
7
+ :distance_units => 'kilometres',
7
8
  :speed => 19.849.miles.to(:kilometres),
9
+ :speed_units => 'kilometres_per_hour',
10
+ :gasoline_intensity => 0.00064134.gallons_per_mile.to(:litres_per_kilometre),
11
+ :gasoline_intensity_units => 'litres_per_kilometre',
8
12
  :diesel_intensity => 0.13836.gallons_per_mile.to(:litres_per_kilometre),
9
- :alternative_fuels_intensity => 0.04632038.gallons_per_mile.to(:litres_per_kilometre),
10
- :air_conditioning_emission_factor => 0.04779 / 1.miles.to(:kilometres)
13
+ :diesel_intensity_units => 'litres_per_kilometre',
14
+ :cng_intensity => 0.03175.gallons_per_mile.to(:litres_per_kilometre),
15
+ :cng_intensity_units => 'litres_per_kilometre',
16
+ :lng_intensity => 0.00419.gallons_per_mile.to(:litres_per_kilometre),
17
+ :lng_intensity_units => 'litres_per_kilometre',
18
+ :lpg_intensity => 0.00037.gallons_per_mile.to(:litres_per_kilometre),
19
+ :lpg_intensity_units => 'litres_per_kilometre',
20
+ :methanol_intensity => 0.00021.gallons_per_mile.to(:litres_per_kilometre),
21
+ :methanol_intensity_units => 'litres_per_kilometre',
22
+ :biodiesel_intensity => 0.00979.gallons_per_mile.to(:litres_per_kilometre),
23
+ :biodiesel_intensity_units => 'litres_per_kilometre',
24
+ :electricity_intensity => 0.00001804 / 1.miles.to(:kilometres),
25
+ :electricity_intensity_units => 'kilowatt_hours_per_kilometre',
26
+ :air_conditioning_emission_factor => 0.04779 / 1.miles.to(:kilometres),
27
+ :air_conditioning_emission_factor_units => 'kilograms_co2e_per_kilometre',
28
+ :alternative_fuels_intensity => 0.04632038.gallons_per_mile.to(:litres_per_kilometre), # deprecated
29
+ :alternative_fuels_intensity_units => 'litres_per_kilometre' # deprecated
11
30
 
12
31
  data_miner do
13
32
  tap "Brighter Planet's sanitized bus class data", Earth.taps_server
@@ -7,94 +7,130 @@ BusClass.class_eval do
7
7
  float 'passengers'
8
8
  float 'speed'
9
9
  string 'speed_units'
10
+ float 'gasoline_intensity'
11
+ string 'gasoline_intensity_units'
10
12
  float 'diesel_intensity'
11
13
  string 'diesel_intensity_units'
12
- float 'alternative_fuels_intensity'
13
- string 'alternative_fuels_intensity_units'
14
+ float 'cng_intensity'
15
+ string 'cng_intensity_units'
16
+ float 'lng_intensity'
17
+ string 'lng_intensity_units'
18
+ float 'lpg_intensity'
19
+ string 'lpg_intensity_units'
20
+ float 'methanol_intensity'
21
+ string 'methanol_intensity_units'
22
+ float 'biodiesel_intensity'
23
+ string 'biodiesel_intensity_units'
24
+ float 'electricity_intensity'
25
+ string 'electricity_intensity_units'
14
26
  float 'air_conditioning_emission_factor'
15
27
  string 'air_conditioning_emission_factor_units'
28
+ float 'alternative_fuels_intensity'
29
+ string 'alternative_fuels_intensity_units'
16
30
  end
17
31
 
18
32
  import "a list of bus classes and pre-calculated trip and fuel use characteristics",
19
- :url => 'https://spreadsheets.google.com/pub?key=0AoQJbWqPrREqdGRsSnJoS1hraGJvR012cDROWXFPbVE&hl=en&single=true&gid=0&output=csv' do
33
+ :url => 'https://spreadsheets.google.com/pub?hl=en&hl=en&key=0AoQJbWqPrREqdGRsSnJoS1hraGJvR012cDROWXFPbVE&output=csv' do
20
34
  key 'name'
21
35
  store 'distance', :units_field_name => 'distance_units'
22
36
  store 'passengers'
23
37
  store 'speed', :units_field_name => 'speed_units'
38
+ store 'gasoline_intensity', :units_field_name => 'gasoline_intensity_units'
24
39
  store 'diesel_intensity', :units_field_name => 'diesel_intensity_units'
25
- store 'alternative_fuels_intensity', :units_field_name => 'alternative_fuels_intensity_units'
40
+ store 'cng_intensity', :units_field_name => 'cng_intensity_units'
41
+ store 'lng_intensity', :units_field_name => 'lng_intensity_units'
42
+ store 'lpg_intensity', :units_field_name => 'lpg_intensity_units'
43
+ store 'methanol_intensity', :units_field_name => 'methanol_intensity_units'
44
+ store 'biodiesel_intensity', :units_field_name => 'biodiesel_intensity_units'
45
+ store 'electricity_intensity', :units_field_name => 'electricity_intensity_units'
26
46
  store 'air_conditioning_emission_factor', :units_field_name => 'air_conditioning_emission_factor_units'
47
+ store 'alternative_fuels_intensity', :units_field_name => 'alternative_fuels_intensity_units'
27
48
  end
28
49
 
29
- verify "Distance, passengers, speed, and diesel intensity should be greater than zero" do
50
+ verify "Some attributes should be greater than zero" do
30
51
  BusClass.all.each do |bus_class|
31
- %w{ distance passengers speed diesel_intensity }.each do |attribute|
52
+ %w{ distance passengers speed diesel_intensity air_conditioning_emission_factor }.each do |attribute|
32
53
  value = bus_class.send(:"#{attribute}")
33
54
  unless value > 0
34
- raise "Invalid #{attribute} for BusClass #{bus_class.name}: #{value} (should be > 0)"
55
+ puts "Invalid #{attribute.humanize.downcase} for BusClass #{bus_class.name}: #{value} (should be > 0)"
56
+ fail
35
57
  end
36
58
  end
37
59
  end
38
60
  end
39
61
 
40
- verify "Alternative fuels intensity and air conditioning emission factor should be zero or more" do
62
+ verify "Some attributes should be zero or more" do
41
63
  BusClass.all.each do |bus_class|
42
- %w{ alternative_fuels_intensity air_conditioning_emission_factor }.each do |attribute|
64
+ %w{ gasoline_intensity cng_intensity lng_intensity lpg_intensity methanol_intensity biodiesel_intensity electricity_intensity alternative_fuels_intensity }.each do |attribute|
43
65
  value = bus_class.send(:"#{attribute}")
44
66
  unless value >= 0
45
- raise "Invalid #{attribute} for BusClass #{bus_class.name}: #{value} (should be >= 0)"
67
+ puts "Invalid #{attribute.humanize.downcase} for BusClass #{bus_class.name}: #{value} (should be >= 0)"
68
+ fail
46
69
  end
47
70
  end
48
71
  end
49
72
  end
50
73
 
51
- verify "Distance units should be kilometres" do
52
- BusClass.all.each do |bus_class|
53
- unless bus_class.distance_units == "kilometres"
54
- raise "Invalid distance units for BusClass #{bus_class.name}: #{bus_class.distance_units} (should be kilometres)"
55
- end
56
- end
57
- end
58
-
59
- verify "Speed units should be kilometres per hour" do
60
- BusClass.all.each do |bus_class|
61
- unless bus_class.speed_units == "kilometres_per_hour"
62
- raise "Invalid speed units for BusClass #{bus_class.name}: #{bus_class.speed_units} (should be kilometres_per_hour)"
63
- end
64
- end
65
- end
66
-
67
- verify "Diesel intensity and alternative fuel intensity units should be litres per kilometre" do
74
+ verify "Units should be correct" do
68
75
  BusClass.all.each do |bus_class|
69
- %w{ diesel_intensity alternative_fuels_intensity }.each do |attribute|
70
- units = bus_class.send(:"#{attribute}_units")
71
- unless units == "litres_per_kilometre"
72
- raise "Invalid #{attribute}_units for BusClass #{bus_class.name}: #{units} (should be litres_per_kilometre)"
76
+ [["distance_units", "kilometres"],
77
+ ["speed_units", "kilometres_per_hour"],
78
+ ["diesel_intensity_units", "litres_per_kilometre"],
79
+ ["gasoline_intensity_units", "litres_per_kilometre"],
80
+ ["cng_intensity_units", "litres_per_kilometre"],
81
+ ["lng_intensity_units", "litres_per_kilometre"],
82
+ ["lpg_intensity_units", "litres_per_kilometre"],
83
+ ["methanol_intensity_units", "litres_per_kilometre"],
84
+ ["biodiesel_intensity_units", "litres_per_kilometre"],
85
+ ["electricity_intensity_units", "kilowatt_hours_per_kilometre"],
86
+ ["air_conditioning_emission_factor_units", "kilograms_co2e_per_kilometre"],
87
+ ["alternative_fuels_intensity_units", "litres_per_kilometre"]].each do |pair|
88
+ attribute = pair[0]
89
+ proper_units = pair[1]
90
+ units = bus_class.send(:"#{attribute}")
91
+ unless units == proper_units
92
+ puts "Invalid #{attribute.humanize.downcase} for BusClass #{bus_class.name}: #{units} (should be #{proper_units})"
93
+ fail
73
94
  end
74
95
  end
75
96
  end
76
97
  end
77
98
 
78
- verify "Air conditioning emission factor units should be kilograms per kilometre" do
79
- BusClass.all.each do |bus_class|
80
- unless bus_class.air_conditioning_emission_factor_units == "kilograms_per_kilometre"
81
- raise "Invalid air conditioning emission factor units for BusClass #{bus_class.name}: #{bus_class.air_conditioning_emission_factor_units} (should be kilograms_per_kilometre)"
82
- end
83
- end
84
- end
85
-
86
99
  verify "Fallbacks should satisfy same constraints as data" do
87
- %w{ distance passengers speed diesel_intensity }.each do |attribute|
100
+ %w{ distance passengers speed diesel_intensity air_conditioning_emission_factor }.each do |attribute|
88
101
  value = BusClass.fallback.send(:"#{attribute}")
89
102
  unless value > 0
90
- raise "Invalid BusClass fallback #{attribute}: #{value} (should be > 0)"
103
+ puts "Invalid #{attribute.humanize.downcase} for fallback BusClass: #{value} (should be > 0)"
104
+ fail
91
105
  end
92
106
  end
93
107
 
94
- %w{ alternative_fuels_intensity air_conditioning_emission_factor }.each do |attribute|
108
+ %w{ gasoline_intensity cng_intensity lng_intensity lpg_intensity methanol_intensity biodiesel_intensity electricity_intensity alternative_fuels_intensity }.each do |attribute|
95
109
  value = BusClass.fallback.send(:"#{attribute}")
96
110
  unless value >= 0
97
- raise "Invalid BusClass fallback #{attribute}: #{value} (should be >= 0)"
111
+ puts "Invalid #{attribute.humanize.downcase} for fallback BusClass: #{value} (should be >= 0)"
112
+ fail
113
+ end
114
+ end
115
+
116
+ [["distance_units", "kilometres"],
117
+ ["speed_units", "kilometres_per_hour"],
118
+ ["diesel_intensity_units", "litres_per_kilometre"],
119
+ ["gasoline_intensity_units", "litres_per_kilometre"],
120
+ ["cng_intensity_units", "litres_per_kilometre"],
121
+ ["lng_intensity_units", "litres_per_kilometre"],
122
+ ["lpg_intensity_units", "litres_per_kilometre"],
123
+ ["methanol_intensity_units", "litres_per_kilometre"],
124
+ ["biodiesel_intensity_units", "litres_per_kilometre"],
125
+ ["electricity_intensity_units", "kilowatt_hours_per_kilometre"],
126
+ ["air_conditioning_emission_factor_units", "kilograms_co2e_per_kilometre"],
127
+ ["alternative_fuels_intensity_units", "litres_per_kilometre"]].each do |pair|
128
+ attribute = pair[0]
129
+ proper_units = pair[1]
130
+ units = BusClass.fallback.send(:"#{attribute}")
131
+ unless units == proper_units
132
+ puts "Invalid #{attribute.humanize.downcase} for fallback BusClass: #{units} (should be #{proper_units})"
133
+ fail
98
134
  end
99
135
  end
100
136
  end