flight 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,20 +1,20 @@
1
- Copyright (c) 2009 Andy Rossmeissl
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2009 Andy Rossmeissl
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc CHANGED
@@ -1,17 +1,17 @@
1
- = flight
2
-
3
- Description goes here.
4
-
5
- == Note on Patches/Pull Requests
6
-
7
- * Fork the project.
8
- * Make your feature addition or bug fix.
9
- * Add tests for it. This is important so I don't break it in a
10
- future version unintentionally.
11
- * Commit, do not mess with rakefile, version, or history.
12
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
- * Send me a pull request. Bonus points for topic branches.
14
-
15
- == Copyright
16
-
17
- Copyright (c) 2010 Andy Rossmeissl. See LICENSE for details.
1
+ = flight
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Andy Rossmeissl. See LICENSE for details.
@@ -0,0 +1,20 @@
1
+ Feature: Flight Committee Calculations
2
+ The flight model should generate correct committee calculations
3
+
4
+ Scenario Outline: Standard Calculations for origin/destination airport, airline, and craft
5
+ Given a flight has "origin_airport.iata_code" of "<source>"
6
+ And it has "destination_airport.iata_code" of "<dest>"
7
+ And it has "airline.iata_code" of "<airline>"
8
+ And it has "date" of "<date>"
9
+ And it used "aircraft.icao_code" "<aircraft>"
10
+ When emissions are calculated
11
+ Then the fuel committee should be close to <fuel>, +/-1
12
+ And the fuel_per_segment committee should be close to <fuel_per_segment>, +/-10
13
+ And the adjusted_distance_per_segment committee should be close to <adjusted_distance_per_segment>, +/-1
14
+ And the load_factor committee should be close to <load_factor>, +/-0.001
15
+ And the passengers committee should be exactly <passengers>
16
+ And the adjusted_distance committee should be close to <adjusted_distance>, +/-1
17
+ Examples:
18
+ | source | dest | airline | date | aircraft | fuel | fuel_per_segment | adjusted_distance_per_segment | load_factor | passengers | adjusted_distance |
19
+ | DTW | SFO | UA | 2010-06-25 | A320 | 24676 | 7612 | 1341 | 0.801 | 120 | 2241 |
20
+ | IAD | CDG | AF | 2010-06-25 | A320 | 43477 | 13413 | 2492 | 0.800 | 120 | 4161 |
@@ -0,0 +1,15 @@
1
+ Feature: Flight Emissions Calculations
2
+ The flight model should generate correct emission calculations
3
+
4
+ Scenario Outline: Standard Calculations for origin/destination airport, airline, and craft
5
+ Given a flight has "origin_airport.iata_code" of "<source>"
6
+ And it has "destination_airport.iata_code" of "<dest>"
7
+ And it has "airline.iata_code" of "<airline>"
8
+ And it has "date" of "<date>"
9
+ And it used "aircraft.icao_code" "<aircraft>"
10
+ When emissions are calculated
11
+ Then the emission value should be within 10 kgs of <emission>
12
+ Examples:
13
+ | source | dest | airline | date | aircraft | emission |
14
+ | DTW | SFO | UA | 2010-06-25 | A320 | 1153 |
15
+ | IAD | CDG | AF | 2010-06-25 | A320 | 2070 |
@@ -0,0 +1,57 @@
1
+ require 'time'
2
+
3
+ Given /^(a flight|it) (has|used) "(.+)" (of\s?)?"(.*)"$/ do |_, __, field, ___, value|
4
+ @activity_hash ||= {}
5
+ if value.present?
6
+ methods = field.split('.')
7
+ context = @activity_hash
8
+ methods.each do |method|
9
+ method = method.to_sym
10
+ context[method] ||= {}
11
+ value = Date.parse(value) if value =~ /\d{4}-\d{2}-\d{2}/
12
+ context[method] = value if method == methods.last.to_sym
13
+ context = context[method]
14
+ end
15
+ end
16
+ end
17
+
18
+ Given /^the current date is (.+)$/ do |current_date|
19
+ @current_date = Time.parse(current_date)
20
+ end
21
+
22
+ When /^emissions are calculated$/ do
23
+ @activity = FlightRecord.from_params_hash @activity_hash
24
+ if @current_date
25
+ Timecop.travel(@current_date) do
26
+ @emission = @activity.emission Sniff::Timeframe.this_year
27
+ end
28
+ else
29
+ @emission = @activity.emission Sniff::Timeframe.this_year
30
+ end
31
+ @characteristics = @activity.deliberations[:emission].characteristics
32
+ end
33
+
34
+ Then /^the emission value should be within (\d+) kgs of (\d+)$/ do |cusion, emissions|
35
+ @emission.should be_close(emissions.to_f, cusion.to_f)
36
+ end
37
+
38
+ Then /^the calculation should have used committees (.*)$/ do |committee_list|
39
+ committees = committee_list.split(/,\s*/)
40
+ committees.each do |committee|
41
+ @characteristics.keys.should include(committee)
42
+ end
43
+ end
44
+
45
+ Then /^the (.+) committee should be close to ([^,]+), \+\/-(.+)$/ do |committee, value, cusion|
46
+ @characteristics[committee.to_sym].to_f.should be_close(value.to_f, cusion.to_f)
47
+ end
48
+
49
+ Then /^the (.+) committee should be exactly (.*)$/ do |committee, value|
50
+ @characteristics[committee.to_sym].to_s.should == value
51
+ end
52
+
53
+ Then /^the active_subtimeframe committee should have timeframe (.*)$/ do |tf_string|
54
+ days, start, finish = tf_string.split(/,\s*/)
55
+ @characteristics[:active_subtimeframe].to_s.should =~ /#{days} days starting #{start} ending #{finish}/
56
+ end
57
+
@@ -0,0 +1,19 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ require 'cucumber'
5
+ require 'cucumber/formatter/unicode' # Remove this line if you don't want Cucumber Unicode support
6
+
7
+ require 'sniff'
8
+
9
+ Sniff.init File.join(File.dirname(__FILE__), '..', '..')
10
+
11
+ ## How to clean your database when transactions are turned off. See
12
+ ## http://github.com/bmabey/database_cleaner for more info.
13
+ #if defined?(ActiveRecord::Base)
14
+ # begin
15
+ # require 'database_cleaner'
16
+ # DatabaseCleaner.strategy = :truncation
17
+ # rescue LoadError => ignore_if_database_cleaner_not_present
18
+ # end
19
+ #end
data/lib/flight.rb CHANGED
@@ -1,256 +1,26 @@
1
+ require 'flight/carbon_model'
2
+ require 'flight/characterization'
3
+ require 'flight/data'
4
+ require 'flight/summarization'
5
+
1
6
  module BrighterPlanet
2
7
  module Flight
3
- def self.included(base)
4
- base.extend ::Leap::Subject
5
- base.decide :emission, :with => :characteristics do
6
- committee :emission do
7
- quorum 'from fuel and passengers with coefficients', :needs => [:fuel, :passengers, :seat_class_multiplier, :emission_factor, :radiative_forcing_index, :freight_share, :date] do |characteristics, timeframe|
8
- if timeframe.include? characteristics[:date]
9
- #( kg fuel ) * ( kg CO2 / kg fuel ) = kg CO2
10
- (characteristics[:fuel] / characteristics[:passengers] * characteristics[:seat_class_multiplier]) * characteristics[:emission_factor] * characteristics[:radiative_forcing_index] * (1 - characteristics[:freight_share])
11
- else
12
- 0
13
- end
14
- end
15
-
16
- quorum 'default' do
17
- raise "The emission committee's default quorum should never be called"
18
- end
19
- end
20
-
21
- committee :fuel do # returns kg fuel
22
- quorum 'from fuel per segment and emplanements and trips', :needs => [:fuel_per_segment, :emplanements_per_trip, :trips] do |characteristics|
23
- characteristics[:fuel_per_segment] * characteristics[:emplanements_per_trip].to_f * characteristics[:trips].to_f
24
- end
25
- end
26
-
27
- committee :fuel_per_segment do # returns kg fuel
28
- quorum 'from adjusted distance and fuel use formula and emplanements and trips', :needs => [:adjusted_distance_per_segment, :fuel_use_coefficients, :endpoint_fuel] do |characteristics|
29
- characteristics[:fuel_use_coefficients][:m3].to_f * characteristics[:adjusted_distance_per_segment].to_f ** 3 +
30
- characteristics[:fuel_use_coefficients][:m2].to_f * characteristics[:adjusted_distance_per_segment].to_f ** 2 +
31
- characteristics[:fuel_use_coefficients][:m1].to_f * characteristics[:adjusted_distance_per_segment].to_f +
32
- characteristics[:endpoint_fuel].to_f
33
- end
34
- end
35
-
36
- committee :adjusted_distance_per_segment do
37
- quorum 'from adjusted distance and emplanements', :needs => [:adjusted_distance, :emplanements_per_trip] do |characteristics|
38
- characteristics[:adjusted_distance] / characteristics[:emplanements_per_trip]
39
- end
40
- end
41
-
42
- committee :endpoint_fuel do
43
- quorum 'from aircraft', :needs => :aircraft do |characteristics|
44
- characteristics[:aircraft].endpoint_fuel
45
- end
46
-
47
- quorum 'from aircraft class', :needs => :aircraft_class do |characteristics|
48
- characteristics[:aircraft_class].endpoint_fuel
49
- end
50
-
51
- quorum 'default' do
52
- Aircraft.fallback.endpoint_fuel
53
- end
54
- end
55
-
56
- committee :fuel_use_coefficients do
57
- quorum 'from aircraft', :needs => :aircraft do |characteristics|
58
- characteristics[:aircraft].attributes.symbolize_keys.slice(:m1, :m2, :m3)
59
- end
60
-
61
- quorum 'from aircraft class', :needs => :aircraft_class do |characteristics|
62
- characteristics[:aircraft_class].attributes.symbolize_keys.slice(:m1, :m2, :m3)
63
- end
64
-
65
- quorum 'default' do
66
- Aircraft.fallback.attributes.symbolize_keys.slice(:m1, :m2, :m3)
67
- end
68
- end
69
-
70
- committee :passengers do
71
- quorum 'from seats and load factor', :needs => [:seats, :load_factor] do |characteristics|
72
- (characteristics[:seats] * characteristics[:load_factor]).round
73
- end
74
- end
75
-
76
- committee :seats do
77
- # leaving this here to explain how someday we might lookup seat count based on both airline AND aircraft
78
- #SE quorum 'from_airline_and_aircraft', :needs => [:airline, :aircraft] do |characteristics, timeframe|
79
- #SE if aircraft = AirlineAircraft.memoized_find_by_airline_id_and_aircraft_id(characteristics[:airline].id, characteristics[:aircraft].id)
80
- #SE aircraft.seats
81
- #SE end
82
- #SE end
83
-
84
- quorum 'from aircraft', :needs => :aircraft do |characteristics|
85
- characteristics[:aircraft].seats
86
- end
87
-
88
- quorum 'from seats estimate', :needs => :seats_estimate do |characteristics|
89
- characteristics[:seats_estimate]
90
- end
91
-
92
- quorum 'from cohort', :needs => :cohort do |characteristics|
93
- seats = characteristics[:cohort].weighted_average :seats, :weighted_by => :passengers
94
- if seats.nil? or seats.zero?
95
- nil
96
- else
97
- seats
98
- end
99
- end
100
-
101
- quorum 'from aircraft class', :needs => :aircraft_class do |characteristics|
102
- characteristics[:aircraft_class].seats
103
- end
104
-
105
- quorum 'default' do
106
- FlightSegment.fallback.seats
107
- end
108
- end
109
-
110
- committee :load_factor do
111
- quorum 'from cohort', :needs => :cohort do |characteristics|
112
- characteristics[:cohort].weighted_average(:load_factor, :weighted_by => :passengers)
113
- end
114
-
115
- quorum 'default' do
116
- ::Flight.fallback.load_factor
117
- end
118
- end
119
-
120
- committee :adjusted_distance do # returns nautical miles
121
- quorum 'from distance', :needs => [:distance, :emplanements_per_trip] do |characteristics|
122
- characteristics[:distance] * research(:route_inefficiency_factor) * ( research(:dogleg_factor) ** (characteristics[:emplanements_per_trip] - 1) )
123
- end
124
- end
125
-
126
- committee :distance do # returns nautical miles
127
- quorum 'from airports', :needs => [:origin_airport, :destination_airport] do |characteristics|
128
- if characteristics[:origin_airport].latitude and
129
- characteristics[:origin_airport].longitude and
130
- characteristics[:destination_airport].latitude and
131
- characteristics[:destination_airport].longitude
132
- characteristics[:origin_airport].distance_to(characteristics[:destination_airport], :units => :kms).kilometres.to :nautical_miles
133
- end
134
- end
135
-
136
- quorum 'from distance estimate', :needs => :distance_estimate do |characteristics|
137
- characteristics[:distance_estimate].kilometres.to :nautical_miles
138
- end
139
-
140
- quorum 'from distance class', :needs => :distance_class do |characteristics|
141
- characteristics[:distance_class].distance.kilometres.to :nautical_miles
142
- end
143
-
144
- quorum 'from cohort', :needs => :cohort do |characteristics|
145
- distance = characteristics[:cohort].weighted_average(:distance, :weighted_by => :passengers).to_f.kilometres.to(:nautical_miles)
146
- distance > 0 ? distance : nil
147
- end
148
-
149
- quorum 'default' do
150
- ::Flight.fallback.distance_estimate.kilometres.to :nautical_miles
151
- end
152
- end
153
-
154
- committee :emplanements_per_trip do # per trip
155
- quorum 'default' do
156
- ::Flight.fallback.emplanements_per_trip_before_type_cast
157
- end
158
- end
159
-
160
- committee :radiative_forcing_index do
161
- quorum 'from fuel type', :needs => :fuel_type do |characteristics|
162
- characteristics[:fuel_type].radiative_forcing_index
163
- end
164
- end
165
-
166
- committee :emission_factor do # returns kg CO2 / kg fuel
167
- quorum 'from fuel type', :needs => :fuel_type do |characteristics|
168
- #( kg CO2 / litres fuel ) * ( litres fuel / kg fuel )
169
- characteristics[:fuel_type].emission_factor * ( 1 / characteristics[:fuel_type].density).gallons.to(:litres)
170
- end
171
- end
172
-
173
- committee :fuel_type do
174
- quorum 'default' do
175
- FlightFuelType.fallback
176
- end
177
- end
178
-
179
- committee :freight_share do
180
- quorum 'from cohort', :needs => :cohort do |characteristics|
181
- characteristics[:cohort].weighted_average(:freight_share, :weighted_by => :passengers)
182
- end
183
-
184
- quorum 'default' do
185
- FlightSegment.fallback.freight_share
186
- end
187
- end
188
-
189
- committee :trips do
190
- quorum 'default' do
191
- ::Flight.fallback.trips_before_type_cast
192
- end
193
- end
194
-
195
- committee :domesticity do
196
- quorum 'from airports', :needs => [:origin_airport, :destination_airport] do |characteristics|
197
- if [characteristics[:origin_airport], characteristics[:destination_airport]].all?(&:united_states?)
198
- FlightDomesticity.find_by_name('domestic')
199
- elsif [characteristics[:origin_airport], characteristics[:destination_airport]].any?(&:united_states?)
200
- FlightDomesticity.find_by_name('international')
201
- end
202
- end
203
-
204
- quorum 'from origin', :needs => :origin_airport do |characteristics|
205
- if characteristics[:origin_airport].all_flights_from_here_domestic?
206
- FlightDomesticity.find_by_name('domestic')
207
- end
208
- end
209
-
210
- quorum 'from destination', :needs => :destination_airport do |characteristics|
211
- if characteristics[:destination_airport].all_flights_to_here_domestic?
212
- FlightDomesticity.find_by_name('domestic')
213
- end
214
- end
215
-
216
- quorum 'from airline', :needs => :airline do |characteristics|
217
- if characteristics[:airline].all_flights_domestic?
218
- FlightDomesticity.find_by_name('domestic')
219
- end
220
- end
221
- end
222
-
223
- committee :seat_class_multiplier do
224
- quorum 'from seat class', :needs => :seat_class do |characteristics|
225
- characteristics[:seat_class].multiplier
226
- end
227
-
228
- quorum 'default' do
229
- FlightSeatClass.fallback.multiplier
230
- end
231
- end
232
-
233
- committee :date do
234
- quorum 'from creation date', :needs => :creation_date do |characteristics|
235
- characteristics[:creation_date]
236
- end
237
-
238
- quorum 'from timeframe' do |characteristics, timeframe|
239
- timeframe.from
240
- end
241
- end
242
-
243
- committee :cohort do
244
- quorum 'from t100', :appreciates => FlightSegment::INPUT_CHARACTERISTICS do |characteristics|
245
- cohort = FlightSegment.big_cohort characteristics
246
- if cohort.any?
247
- cohort
248
- else
249
- nil
250
- end
251
- end
252
- end
8
+ extend self
9
+
10
+ def included(base)
11
+ base.send :include, BrighterPlanet::Flight::CarbonModel
12
+ base.send :include, BrighterPlanet::Flight::Characterization
13
+ # base.send :include, BrighterPlanet::Flight::Data
14
+ base.send :include, BrighterPlanet::Flight::Summarization
15
+ end
16
+ def flight_model
17
+ if Object.const_defined? 'Flight'
18
+ Flight
19
+ elsif Object.const_defined? 'FlightRecord'
20
+ FlightRecord
21
+ else
22
+ raise 'There is no flight model'
253
23
  end
254
24
  end
255
25
  end
256
- end
26
+ end