lib/flight/carbon_model.rb in flight-0.0.23 vs lib/flight/carbon_model.rb in flight-0.1.0
- old
+ new
@@ -1,73 +1,225 @@
-require 'timeframe'
+# Copyright © 2010 Brighter Planet.
+# See LICENSE for details.
+# Contact Brighter Planet for dual-license arrangements.
+
require 'weighted_average'
+## Flight:carbon model
+# This module is used by [Brighter Planet](http://brighterplanet.com)'s carbon emission [web service](http://carbon.brighterplanet.com) to estimate the **greenhouse gas emissions of passenger air travel**.
+#
+# The final estimate is the result of the **calculations** detailed below.
+# These calculations are performed in reverse order, starting with the last calculation listed and finishing with the `emission` calculation.
+#
+# To accomodate varying input data, each calculation may have one or more **methods**. These are listed under each calculation in order from most to least preferred.
module BrighterPlanet
module Flight
module CarbonModel
def self.included(base)
base.extend FastTimestamp
base.decide :emission, :with => :characteristics do
+ ### Emission
+ # This calculation returns the `emission` estimate in *kg CO<sub>2</sub>e*.
+ # The `emission` estimate is the passenger's share of the total flight emissions that occured during the `timeframe`.
committee :emission do
- quorum 'from fuel and passengers with coefficients',
- :needs => [:fuel, :passengers, :seat_class_multiplier, :emission_factor,
- :radiative_forcing_index, :freight_share, :date] do |characteristics, timeframe|
+ ##### From fuel, emission factor, freight share, passengers, and multipliers
+ # This method:
+ #
+ # 1. Checks that the flight occured during the `timeframe`
+ # 2. Multiplies `fuel use` (*kg fuel*) by an `emission factor` (*kg CO<sub>2</sub>e / kg fuel*) and an `aviation multiplier` to give total flight emissions in *kg CO<sub>2</sub>e*
+ # 3. Multiplies by (1 - `freight share`) to take out emissions attributed to freight cargo and mail, leaving emissions attributed to passengers and their baggage
+ # 4. Divides by the number of `passengers` and multiplies by a `seat class multiplier` to give `emission` for the passenger
+ quorum 'from fuel, emission factor, freight share, passengers, multipliers, and date',
+ :needs => [:fuel, :emission_factor, :freight_share, :passengers, :seat_class_multiplier, :aviation_multiplier, :date], :complies => [:ghg_protocol, :iso, :tcr] do |characteristics, timeframe|
date = characteristics[:date].is_a?(Date) ?
characteristics[:date] :
Date.parse(characteristics[:date].to_s)
if timeframe.include? date
- #( kg fuel ) * ( kg CO2 / kg fuel ) = kg CO2
- (characteristics[:fuel] / characteristics[:passengers] * characteristics[:seat_class_multiplier]) * characteristics[:emission_factor] * characteristics[:radiative_forcing_index] * (1 - characteristics[:freight_share])
+ characteristics[:fuel] * characteristics[:emission_factor] * characteristics[:aviation_multiplier] * (1 - characteristics[:freight_share]) / characteristics[:passengers] * characteristics[:seat_class_multiplier]
+ # If the flight did not occur during the `timeframe`, `emission` is zero.
else
0
end
end
quorum 'default' do
raise "The emission committee's default quorum should never be called"
end
end
- committee :fuel do # returns kg fuel
- quorum 'from fuel per segment and emplanements and trips', :needs => [:fuel_per_segment, :emplanements_per_trip, :trips] do |characteristics|
- characteristics[:fuel_per_segment] * characteristics[:emplanements_per_trip].to_f * characteristics[:trips].to_f
+ ### Emission factor
+ # This calculation returns the `emission factor` in *kg CO<sub>2</sub>e / kg fuel*.
+ committee :emission_factor do
+ ##### From fuel type
+ # This method looks up data on [fuel types](http://data.brighterplanet.com/fuel_types) and divides the `fuel type` `emission factor` (*kg CO<sub>2</sub> / litre fuel*) by the `fuel type` `density` (*kg fuel / litre fuel*) to give *kg CO<sub>2</sub>e / kg fuel*.
+ quorum 'from fuel type', :needs => :fuel_type, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ characteristics[:fuel_type].emission_factor / characteristics[:fuel_type].density
end
end
- committee :fuel_per_segment do # returns kg fuel
- quorum 'from adjusted distance per segment and fuel use coefficients', :needs => [:adjusted_distance_per_segment, :fuel_use_coefficients] do |characteristics|
+ ### Aviation multiplier
+ # This calculation returns the `aviation multiplier`, which approximates the extra climate impact of emissions high in the atmosphere.
+ committee :aviation_multiplier do
+ ##### Default
+ # This method uses an `aviation multiplier` of **2.0** after [Kolmuss and Crimmins (2009)](http://sei-us.org/publications/id/13).
+ quorum 'default', :complies => [:ghg_protocol, :iso, :tcr] do
+ base.fallback.aviation_multiplier
+ end
+ end
+
+ ### Fuel
+ # This calculation returns the flight's total `fuel` use in *kg fuel*.
+ committee :fuel do
+ ##### From fuel per segment and segments per trip and trips
+ # This method multiplies the `fuel per segment` (*kg fuel*) by the `segments per trip` and the number of `trips` to give *kg fuel*.
+ quorum 'from fuel per segment and segments per trip and trips', :needs => [:fuel_per_segment, :segments_per_trip, :trips], :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ characteristics[:fuel_per_segment] * characteristics[:segments_per_trip].to_f * characteristics[:trips].to_f
+ end
+ end
+
+ ### Fuel per segment
+ # This calculation returns the `fuel per segment` in *kg fuel*.
+ committee :fuel_per_segment do
+ ##### From adjusted distance per segment and fuel use coefficients
+ # This method uses a third-order polynomial equation to calculate the fuel used per segment:
+ #
+ # (m<sub>3</sub> * d^3 ) + (m<sub>2</sub> * d^2 ) + (m<sub>1</sub> * d) + endpoint fuel
+ #
+ # Where d is the `adjusted distance per segment` and m<sub>3</sub>, m<sub>2</sub>, m<sub>2</sub>, and endpoint fuel are the `fuel use coefficients`.
+ quorum 'from adjusted distance per segment and fuel use coefficients', :needs => [:adjusted_distance_per_segment, :fuel_use_coefficients], :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
characteristics[:fuel_use_coefficients].m3.to_f * characteristics[:adjusted_distance_per_segment].to_f ** 3 +
characteristics[:fuel_use_coefficients].m2.to_f * characteristics[:adjusted_distance_per_segment].to_f ** 2 +
characteristics[:fuel_use_coefficients].m1.to_f * characteristics[:adjusted_distance_per_segment].to_f +
characteristics[:fuel_use_coefficients].endpoint_fuel.to_f
end
end
+ ### Adjusted distance per segment
+ # This calculation returns the `adjusted distance per segment` in *nautical miles*.
committee :adjusted_distance_per_segment do
- quorum 'from adjusted distance and emplanements', :needs => [:adjusted_distance, :emplanements_per_trip] do |characteristics|
- characteristics[:adjusted_distance] / characteristics[:emplanements_per_trip]
+ ##### From adjusted distance and segments per trip
+ # This method divides the `adjusted distance` (*nautical miles*) by `segments per trip` to give *nautical miles*.
+ quorum 'from adjusted distance and segments per trip', :needs => [:adjusted_distance, :segments_per_trip], :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ characteristics[:adjusted_distance] / characteristics[:segments_per_trip]
end
end
+ ### Adjusted distance
+ # This calculation returns the `adjusted distance` in *nautical miles*.
+ # The `adjusted distance` accounts for factors that increase the actual distance traveled by real world flights.
+ committee :adjusted_distance do
+ ##### From distance, route inefficiency factor, and dogleg factor
+ # This method multiplies `distance` (*nautical miles*) by a `route inefficiency factor` and a `dogleg factor` to give *nautical miles*.
+ quorum 'from distance, route inefficiency factor, and dogleg factor', :needs => [:distance, :route_inefficiency_factor, :dogleg_factor], :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ characteristics[:distance] * characteristics[:route_inefficiency_factor] * characteristics[:dogleg_factor]
+ end
+ end
+
+ ### Distance
+ # This calculation returns the flight's base `distance` in *nautical miles*.
+ committee :distance do
+ ##### From airports
+ # This first-tier method calculates the great circle distance between the `origin airport` and `destination airport` and converts from *km* to *nautical miles*.
+ quorum 'from airports', :needs => [:origin_airport, :destination_airport], :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ if characteristics[:origin_airport].latitude and
+ characteristics[:origin_airport].longitude and
+ characteristics[:destination_airport].latitude and
+ characteristics[:destination_airport].longitude
+ characteristics[:origin_airport].distance_to(characteristics[:destination_airport], :units => :kms).kilometres.to :nautical_miles
+ end
+ end
+
+ ##### From distance estimate
+ # This second-tier method converts the `distance_estimate` in *km* to *nautical miles*.
+ quorum 'from distance estimate', :needs => :distance_estimate, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ characteristics[:distance_estimate].kilometres.to :nautical_miles
+ end
+
+ ##### From distance class
+ # This third-tier method looks up the [distance class](http://data.brighterplanet.com/flight_distance_classes)'s `distance` and converts from *km* to *nautical miles*.
+ quorum 'from distance class', :needs => :distance_class, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ characteristics[:distance_class].distance.kilometres.to :nautical_miles
+ end
+
+ ##### From cohort
+ # This fourth-tier method calculates the average `distance` of the `cohort` segments, weighted by their passengers, and converts from *km* to *nautical miles*.
+ quorum 'from cohort', :needs => :cohort do |characteristics| # cohort here will be some combo of origin, airline, and aircraft
+ distance = characteristics[:cohort].weighted_average(:distance, :weighted_by => :passengers).kilometres.to(:nautical_miles)
+ distance > 0 ? distance : nil
+ end
+
+ ##### Default
+ # This default method calculates the average `distance` of [all segments in the T-100 database](http://data.brighterplanet.com/flight_segments), weighted by their passengers, and converts from *km* to *nautical miles*.
+ quorum 'default' do
+ FlightSegment.fallback.distance.kilometres.to :nautical_miles
+ end
+ end
+
+ ### Route inefficiency factor
+ # This calculation returns the `route inefficiency factor`, a measure of how much farther real world flights travel than the great circle distance between their origin and destination.
+ # It accounts for factors like flight path routing around controlled airspace and circling while waiting for clearance to land.
+ committee :route_inefficiency_factor do
+ ##### From country
+ # This first-tier method looks up the `route inefficiency factor` for the [country](http://data.brighterplanet.com/countries) in which the flight occurs.
+ quorum 'from country', :needs => :country, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ characteristics[:country].andand.flight_route_inefficiency_factor
+ end
+
+ ##### Default
+ # This default method uses a `route inefficiency factor` of **10%** based on [Kettunen et al. (2005)](http://www.atmseminar.org/seminarContent/seminar6/papers/p_055_MPM.pdf)
+ quorum 'default', :complies => [:ghg_protocol, :iso, :tcr] do
+ Country.fallback.flight_route_inefficiency_factor
+ end
+ end
+
+ ### Dogleg factor
+ # This calculation returns the `dogleg factor`, a measure of how far out of the way the average layover is compared to a direct flight.
+ committee :dogleg_factor do
+ ##### From segments per trip
+ # This method assumes that each layover increases the total flight distance by **25%**.
+ quorum 'from segments per trip', :needs => :segments_per_trip, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ base.fallback.dogleg_factor ** (characteristics[:segments_per_trip] - 1)
+ end
+ end
+
+ ### Distance estimate
+ # This implied calculation returns the client-input 'distance estimate' in *km*.
+
+ ### Distance class
+ # This implied calculation returns the client-input [distance class](http://data.brighterplanet.com/distance_classes).
+
+ ### Fuel use coefficients
+ # This calculation returns the `fuel use coefficients`, the coefficients of the third-order polynomial equation that describes aircraft fuel use.
committee :fuel_use_coefficients do
- quorum 'from aircraft', :needs => :aircraft do |characteristics|
+ ##### From aircraft
+ # This first-tier method looks up the [aircraft](http://data.brighterplanet.com/aircraft)'s `fuel use coefficients`.
+ quorum 'from aircraft', :needs => :aircraft, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
aircraft = characteristics[:aircraft]
- FuelUseEquation.new aircraft.m3, aircraft.m2, aircraft.m1, aircraft.endpoint_fuel
+ fuel_use = FuelUseEquation.new aircraft.m3, aircraft.m2, aircraft.m1, aircraft.endpoint_fuel
+ if fuel_use.empty?
+ nil
+ else
+ fuel_use
+ end
end
- quorum 'from aircraft class', :needs => :aircraft_class do |characteristics|
+ ##### From aircraft class
+ # This second-tier method looks up the [aircraft class](http://data.brighterplanet.com/aircraft_classes)'s `fuel use coefficients`.
+ quorum 'from aircraft class', :needs => :aircraft_class, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
aircraft_class = characteristics[:aircraft_class]
FuelUseEquation.new aircraft_class.m3, aircraft_class.m2, aircraft_class.m1, aircraft_class.endpoint_fuel
end
- quorum 'from cohort', :needs => :cohort do |characteristics|
+ ##### From cohort
+ # This third-tier method calculates the average `fuel use coefficients` of the `cohort` segments, weighted by their passengers.
+ quorum 'from cohort', :needs => :cohort, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
flight_segments = characteristics[:cohort]
passengers = flight_segments.inject(0) do |passengers, flight_segment|
passengers + flight_segment.passengers
end
-
+
flight_segment_aircraft = flight_segments.inject({}) do |hsh, flight_segment|
bts_code = flight_segment.bts_aircraft_type_code
key = flight_segment.row_hash
aircraft = Aircraft.find_by_bts_aircraft_type_code bts_code
hsh[key] = aircraft if aircraft
@@ -91,243 +243,280 @@
m2 + (aircraft_m2 * flight_segment.passengers)
end
else
m2 = Aircraft.fallback.m2
end
-
+
if flight_segment_aircraft.values.map(&:m1).any?
m1 = flight_segments.inject(0) do |m1, flight_segment|
aircraft = flight_segment_aircraft[flight_segment.row_hash]
aircraft_m1 = aircraft.andand.m1 || 0
m1 + (aircraft_m1 * flight_segment.passengers)
end
else
m1 = Aircraft.fallback.m1
end
-
+
if flight_segment_aircraft.values.map(&:endpoint_fuel).any?
endpoint_fuel = flight_segments.inject(0) do |endpoint_fuel, flight_segment|
aircraft = flight_segment_aircraft[flight_segment.row_hash]
aircraft_epfuel = aircraft.andand.endpoint_fuel || 0
endpoint_fuel + (aircraft_epfuel * flight_segment.passengers)
end
else
endpoint_fuel = Aircraft.fallback.endpoint_fuel
end
-
+
if [m3, m2, m1, endpoint_fuel, passengers].any?(&:nonzero?)
m3 = m3 / passengers
m2 = m2 / passengers
m1 = m1 / passengers
endpoint_fuel = endpoint_fuel / passengers
-
+
FuelUseEquation.new m3, m2, m1, endpoint_fuel
end
end
- quorum 'default' do
+ ##### Default
+ # This default method calculates the average `fuel use coefficients` of [all segments in the T-100 database](http://data.brighterplanet.com/flight_segments), weighted by their passengers.
+ quorum 'default', :complies => [:ghg_protocol, :iso, :tcr] do
fallback = Aircraft.fallback
if fallback
FuelUseEquation.new fallback.m3, fallback.m2, fallback.m1, fallback.endpoint_fuel
end
end
end
+ ### Fuel type
+ # This calculation returns the `fuel type`.
+ committee :fuel_type do
+ ##### From client input
+ # This implied first-tier method uses the client-input [fuel type](http://data.brighterplanet.com/fuel_types).
+
+ ##### Default
+ # This method assumes the flight uses **Jet Fuel**.
+ quorum 'default' do
+ FuelType.find_by_name 'Jet Fuel'
+ end
+ end
+
+ ### Passengers
+ # This calculation returns the number of `passengers`.
committee :passengers do
- quorum 'from seats and load factor', :needs => [:seats, :load_factor] do |characteristics|
+ ##### From seats and load factor
+ # This method multiplies the number of `seats` by the `load factor`.
+ quorum 'from seats and load factor', :needs => [:seats, :load_factor], :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
(characteristics[:seats] * characteristics[:load_factor]).round
end
end
+ ### Seats
+ # This calculation returns the number of `seats`.
committee :seats do
- # leaving this here to explain how someday we might lookup seat count based on both airline AND aircraft
- #SE quorum 'from_airline_and_aircraft', :needs => [:airline, :aircraft] do |characteristics, timeframe|
- #SE if aircraft = AirlineAircraft.memoized_find_by_airline_id_and_aircraft_id(characteristics[:airline].id, characteristics[:aircraft].id)
- #SE aircraft.seats
- #SE end
- #SE end
-
- quorum 'from aircraft', :needs => :aircraft do |characteristics|
+ ##### From aircraft
+ # This first-tier method looks up the [aircraft](http://data.brighterplanet.com/aircraft)'s average number of `seats`.
+ quorum 'from aircraft', :needs => :aircraft, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
characteristics[:aircraft].seats
end
- quorum 'from seats estimate', :needs => :seats_estimate do |characteristics|
+ ##### From seats estimate
+ # This second-tier method uses the input estimate of the number of `seats`.
+ quorum 'from seats estimate', :needs => :seats_estimate, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
characteristics[:seats_estimate]
end
- quorum 'from cohort', :needs => :cohort do |characteristics|
+ ##### From cohort
+ # This third-tier method calculates the average number of `seats` of the `cohort` segments, weighted by their passengers.
+ quorum 'from cohort', :needs => :cohort, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
seats = characteristics[:cohort].weighted_average :seats, :weighted_by => :passengers
if seats.nil? or seats.zero?
nil
else
seats
end
end
- quorum 'from aircraft class', :needs => :aircraft_class do |characteristics|
- characteristics[:aircraft_class].seats
+ ##### From aircraft class
+ # This fourth-tier method looks up the [aircraft class](http://data.brighterplanet.com/aircraft_classes)'s average number of `seats`.
+ quorum 'from aircraft class', :needs => :aircraft_class, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ characteristics[:aircraft_class].seats_before_type_cast
end
+ ##### Default
+ # This default method calculates the average number of `seats` of [all segments in the T-100 database](http://data.brighterplanet.com/flight_segments), weighted by their passengers.
quorum 'default' do
- FlightSegment.fallback.andand.seats
+ FlightSegment.fallback.seats_before_type_cast # need before_type_cast b/c seats is an integer but the fallback value is a float
end
end
+ ### Seats estimate
+ # This implied calculation returns the client-input `seats estimate`.
+
+ ### Load factor
+ # This calculation returns the `load factor`.
+ # The `load factor` is the portion of available seats that are occupied.
committee :load_factor do
- quorum 'from cohort', :needs => :cohort do |characteristics|
+ ##### From client input
+ # This implied first-tier method uses the client-input `load factor`.
+
+ ##### From cohort
+ # This second-tier method calculates the average `load factor` of the `cohort` segments, weighted by their passengers.
+ quorum 'from cohort', :needs => :cohort, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
characteristics[:cohort].weighted_average(:load_factor, :weighted_by => :passengers)
end
-
- quorum 'default' do
- base.fallback.andand.load_factor
- end
- end
-
- committee :adjusted_distance do # returns nautical miles
- quorum 'from distance', :needs => [:distance, :emplanements_per_trip] do |characteristics|
- route_inefficiency_factor = base.research(:route_inefficiency_factor)
- dogleg_factor = base.research(:dogleg_factor)
- characteristics[:distance] * route_inefficiency_factor * ( dogleg_factor ** (characteristics[:emplanements_per_trip] - 1) )
- end
- end
-
- committee :distance do # returns nautical miles
- quorum 'from airports', :needs => [:origin_airport, :destination_airport] do |characteristics|
- if characteristics[:origin_airport].latitude and
- characteristics[:origin_airport].longitude and
- characteristics[:destination_airport].latitude and
- characteristics[:destination_airport].longitude
- characteristics[:origin_airport].distance_to(characteristics[:destination_airport], :units => :kms).kilometres.to :nautical_miles
- end
- end
- quorum 'from distance estimate', :needs => :distance_estimate do |characteristics|
- characteristics[:distance_estimate].kilometres.to :nautical_miles
+ ##### Default
+ # This default method calculates the average `load factor` of [all segments in the T-100 database](http://data.brighterplanet.com/flight_segments), weighted by their passengers.
+ quorum 'default', :complies => [:ghg_protocol, :iso, :tcr] do
+ FlightSegment.fallback.load_factor
end
-
- quorum 'from distance class', :needs => :distance_class do |characteristics|
- characteristics[:distance_class].distance.kilometres.to :nautical_miles
- end
-
- quorum 'from cohort', :needs => :cohort do |characteristics|
- distance = characteristics[:cohort].weighted_average(:distance, :weighted_by => :passengers).to_f.kilometres.to(:nautical_miles)
- distance > 0 ? distance : nil
- end
-
- quorum 'default' do
- base.fallback.distance_estimate.kilometres.to :nautical_miles
- end
end
- committee :emplanements_per_trip do # per trip
- quorum 'default' do
- base.fallback.emplanements_per_trip_before_type_cast
- end
- end
-
- committee :radiative_forcing_index do
- quorum 'from fuel type', :needs => :fuel_type do |characteristics|
- characteristics[:fuel_type].radiative_forcing_index
- end
- end
-
- committee :emission_factor do # returns kg CO2 / kg fuel
- quorum 'from fuel type', :needs => :fuel_type do |characteristics|
- #( kg CO2 / litres fuel ) * ( litres fuel / kg fuel )
- characteristics[:fuel_type].emission_factor * ( 1 / characteristics[:fuel_type].density).gallons.to(:litres)
- end
- end
-
- committee :fuel_type do
- quorum 'default' do
- FlightFuelType.fallback
- end
- end
-
+ ### Freight share
+ # This calculation returns the `freight share`.
+ # The `freight share` is the percent of the total aircraft weight that is freight cargo and mail (as opposed to passengers and their baggage).
committee :freight_share do
- quorum 'from cohort', :needs => :cohort do |characteristics|
+ ##### From cohort
+ # This first-tier method calculates the average `freight share` of the `cohort` segments, weighted by their passengers
+ quorum 'from cohort', :needs => :cohort, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
characteristics[:cohort].weighted_average(:freight_share, :weighted_by => :passengers)
end
- quorum 'default' do
- FlightSegment.fallback.andand.freight_share
+ ##### Default
+ # This default method calculates the average `freight share` of [all segments in the T-100 database](http://data.brighterplanet.com/flight_segments), weighted by their passengers.
+ quorum 'default', :complies => [:ghg_protocol, :iso, :tcr] do
+ FlightSegment.fallback.freight_share
end
end
+ ### Trips
+ # This calculation returns the number of `trips`.
+ # A one-way flight has one trip; a round-trip flight has two trips.
committee :trips do
- quorum 'default' do
- base.fallback.andand.trips_before_type_cast
+ ##### From client input
+ # This implied first-tier method uses the client-input number of `trips`.
+
+ ##### Default
+ # This default method calculates the average number of `trips` from the [U.S. National Household Travel Survey](http://www.bts.gov/publications/america_on_the_go/long_distance_transportation_patterns/html/table_07.html).
+ quorum 'default', :complies => [:ghg_protocol, :iso, :tcr] do
+ base.fallback.trips_before_type_cast # need before_type_cast b/c trips is an integer but fallback value is a float
end
end
- # Disabling this for now because domesticity is pretty useless
- # FIXME TODO make domesticity non-us-centric and check that data's ok
- # committee :domesticity do
- # quorum 'from airports', :needs => [:origin_airport, :destination_airport] do |characteristics|
- # if [characteristics[:origin_airport], characteristics[:destination_airport]].all?(&:united_states?)
- # FlightDomesticity.find_by_name('domestic')
- # elsif [characteristics[:origin_airport], characteristics[:destination_airport]].any?(&:united_states?)
- # FlightDomesticity.find_by_name('international')
- # end
- # end
- #
- # quorum 'from origin', :needs => :origin_airport do |characteristics|
- # if characteristics[:origin_airport].all_flights_from_here_domestic?
- # FlightDomesticity.find_by_name('domestic')
- # end
- # end
- #
- # quorum 'from destination', :needs => :destination_airport do |characteristics|
- # if characteristics[:destination_airport].all_flights_to_here_domestic?
- # FlightDomesticity.find_by_name('domestic')
- # end
- # end
- #
- # quorum 'from airline', :needs => :airline do |characteristics|
- # if characteristics[:airline].all_flights_domestic?
- # FlightDomesticity.find_by_name('domestic')
- # end
- # end
- # end
-
+ ### Seat class multiplier
+ # This calculation returns the `seat class multiplier`, which reflects the amount of cabin space occupied by the passenger's seat.
committee :seat_class_multiplier do
- quorum 'from seat class', :needs => :seat_class do |characteristics|
+ ##### From seat class
+ # This first-tier method looks up the [seat class](http://data.brighterplanet.com/flight_seat_classes)'s `seat class multiplier`.
+ quorum 'from seat class', :needs => :seat_class, :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
characteristics[:seat_class].multiplier
end
- quorum 'default' do
- FlightSeatClass.fallback.andand.multiplier
+ ##### Default
+ # This default method uses a `seat class multiplier` of **1**.
+ quorum 'default', :complies => [:ghg_protocol, :iso, :tcr] do
+ FlightSeatClass.fallback.multiplier
end
end
- committee :date do
- quorum 'from creation date', :needs => :creation_date do |characteristics|
- characteristics[:creation_date]
+ ### Seat class
+ # This implied calculation returns the client-input [seat class](http://data.brighterplanet.com/seat_classes).
+
+ ### Country
+ # This calculation returns the [country](http://data.brighterplanet.com/countries) in which a flight occurs.
+ committee :country do
+ ##### From origin airport and destination airport
+ # This method checks that the flight's `origin airport` and `destination airport` are within the same country.
+ # If so, that country is the `country`.
+ quorum 'from origin airport and destination airport', :needs => [:origin_airport, :destination_airport], :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ if characteristics[:origin_airport].country == characteristics[:destination_airport].country
+ characteristics[:origin_airport].country
+ end
end
- quorum 'from timeframe' do |characteristics, timeframe|
- timeframe.present? ? timeframe.from : nil
- end
+ ##### From client input
+ # This implied method uses the client-input [country](http://data.brighterplanet.com/countries).
end
+ ### Cohort
+ # This calculation returns the `cohort`, which is a set of flight segment records in the [T-100 database](http://data.brighterplanet.com/flight_segments) that match certain client-input values.
committee :cohort do
- quorum 'from t100', :appreciates => [:origin_airport, :destination_airport, :aircraft, :airline] do |characteristics|
- provided_characteristics = [:origin_airport, :destination_airport, :aircraft, :airline].
- inject(ActiveSupport::OrderedHash.new) do |memo, characteristic_name|
- memo[characteristic_name] = characteristics[characteristic_name]
- memo
- end
- cohort = FlightSegment.strict_cohort provided_characteristics
+ ##### From segments per trip and input
+ # This method:
+ #
+ # 1. Checks that the flight is direct
+ # 2. Takes the input values for `origin airport`, `destination airport`, `aircraft`, and `airline`
+ # 3. Selects all the records in the T-100 database that match the available input values
+ # 4. Drops the last input value (initially `airline`, then `aircraft`, etc.) if no records match all of the available input values
+ # 5. Repeats steps 3 and 4 until some records match or no input values remain
+ #
+ # If no records match any of the input values, or if the flight is indirect, then `cohort` is undefined.
+ quorum 'from segments per trip and input', :needs => :segments_per_trip, :appreciates => [:origin_airport, :destination_airport, :aircraft, :airline], :complies => [:ghg_protocol, :iso, :tcr] do |characteristics|
+ cohort = {}
+ if characteristics[:segments_per_trip] == 1
+ provided_characteristics = [:origin_airport, :destination_airport, :aircraft, :airline].
+ inject(ActiveSupport::OrderedHash.new) do |memo, characteristic_name|
+ memo[characteristic_name] = characteristics[characteristic_name]
+ memo
+ end
+ cohort = FlightSegment.strict_cohort provided_characteristics
+ end
if cohort.any?
cohort
else
nil
end
end
end
+
+ ### Origin airport
+ # This implied calculation returns the client-input [origin airport](http://data.brighterplanet.com/airports).
+
+ ### Destination airport
+ # This implied calculation returns the client-input [destination airport](http://data.brighterplanet.com/airports).
+
+ ### Aircraft
+ # This implied calculation returns the client-input type of [aircraft](http://data.brighterplanet.com/aircraft).
+
+ ### Aircraft class
+ # This implied calculation returns the client-input [aircraft_class](http://data.brighterplanet.com/aircraft_classes).
+
+ ### Airline
+ # This implied calculation returns the client-input [airline](http://data.brighterplanet.com/airlines) operating the flight.
+
+ ### Segments per trip
+ # This calculation returns the `segments per trip`.
+ # Direct flights have a single segment per trip. Indirect flights with one or more layovers have two or more segments per trip.
+ committee :segments_per_trip do
+ ##### From client input
+ # This implied first-tier method uses the client-input `segments per trip`.
+
+ ##### Default
+ # This default method calculates the average `segments per trip` from the [U.S. National Household Travel Survey](http://nhts.ornl.gov/).
+ quorum 'default', :complies => [:ghg_protocol, :iso, :tcr] do
+ base.fallback.segments_per_trip_before_type_cast # need before_type_cast b/c segments_per_trip is an integer but fallback value is a float
+ end
+ end
+
+ ### Date
+ # This calculation returns the `date` on which the flight occured.
+ committee :date do
+ ##### From client input
+ # This implied first-tier method uses the client-input value for `date`.
+
+ ##### From timeframe
+ # This second-tier method assumes the flight occured on the first day of the `timeframe`.
+ quorum 'from timeframe', :complies => [:ghg_protocol, :iso, :tcr] do |characteristics, timeframe|
+ timeframe.from
+ end
+ end
end
end
- class FuelUseEquation < Struct.new(:m3, :m2, :m1, :endpoint_fuel); end
+ class FuelUseEquation < Struct.new(:m3, :m2, :m1, :endpoint_fuel)
+ def empty?
+ m3.nil? and m2.nil? and m1.nil? and endpoint_fuel.nil?
+ end
+ end
end
end
end