Class: Aircraft

Inherits:
ActiveRecord::Base
  • Object
show all
Extended by:
Earth::Model
Defined in:
lib/earth/air/aircraft.rb

Constant Summary collapse

TABLE_STRUCTURE =
<<-EOS

CREATE TABLE aircraft
  (
     icao_code            CHARACTER VARYING(255) NOT NULL PRIMARY KEY,
     manufacturer_name    CHARACTER VARYING(255),
     model_name           CHARACTER VARYING(255),
     description          CHARACTER VARYING(255),
     aircraft_type        CHARACTER VARYING(255),
     engine_type          CHARACTER VARYING(255),
     engines              INTEGER,
     weight_class         CHARACTER VARYING(255),
     class_code           CHARACTER VARYING(255),
     passengers           FLOAT,
     seats                FLOAT,
     seats_specificity    CHARACTER VARYING(255),
     m3                   FLOAT,
     m3_units             CHARACTER VARYING(255),
     m2                   FLOAT,
     m2_units             CHARACTER VARYING(255),
     m1                   FLOAT,
     m1_units             CHARACTER VARYING(255),
     b                    FLOAT,
     b_units              CHARACTER VARYING(255),
     fuel_use_specificity CHARACTER VARYING(255)
  );
CREATE INDEX index_aircraft_on_description ON aircraft (description);

EOS

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Earth::Model

extend_mining, extended, registry

Class Method Details

.fuzzy_matchObject

set up a fuzzy_match for matching Aircraft description with FlightSegment aircraft_description



47
48
49
50
51
52
53
54
55
# File 'lib/earth/air/aircraft.rb', line 47

def fuzzy_match
  @fuzzy_match ||= FuzzyMatch.new(Aircraft.all,
      :haystack_reader => lambda { |record| record.description },
      :blockings  => RemoteTable.new(:url => 'https://spreadsheets.google.com/spreadsheet/pub?key=0AoQJbWqPrREqdDlRR2NmdzE2ZjZwTy1ucjh4cWFYOFE&gid=0&output=csv').map { |record| record['blocking'] },
      :identities => RemoteTable.new(:url => 'https://spreadsheets.google.com/spreadsheet/pub?key=0AoQJbWqPrREqdDlRR2NmdzE2ZjZwTy1ucjh4cWFYOFE&gid=1&output=csv').map { |record| record['identity'] },
      :tighteners => RemoteTable.new(:url => 'https://spreadsheets.google.com/spreadsheet/pub?key=0AoQJbWqPrREqdDlRR2NmdzE2ZjZwTy1ucjh4cWFYOFE&gid=2&output=csv').map { |record| record['tightener'] },
      :must_match_blocking => true,
      :first_blocking_decides => true)
end

.manually_cache_flight_segments!Object

Cache fuzzy matches between FlightSegment aircraft_description and Aircraft description



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/earth/air/aircraft.rb', line 100

def manually_cache_flight_segments!
  FlightSegment.run_data_miner!
  FuzzyMatch::CachedResult.auto_upgrade!
  connection.select_values("SELECT DISTINCT(aircraft_description) FROM flight_segments WHERE aircraft_description IS NOT NULL").each do |original_description|
    # If the flight segment's aircraft_description contains '/' then it describes multiple aircraft.
    # We need to synthesize descriptions for those aircraft, find all Aircraft that fuzzily match the
    # synthesized descriptions, and associate those Aircraft with the original aircraft_description.
    # e.g. boeing 747-100/200
    if original_description.include?('/')
      # Pull out the complete first aircraft description
      # e.g. 'boeing 747-100'
      first_description = original_description.split('/')[0]
      
      # Pull out the root of the description - the text up to and including the last ' ' or '-'
      # e.g. 'boeing 747-'
      root_length = first_description.rindex(/[ \-]/)
      root = first_description.slice(0..root_length)
      
      # Pull out the suffixes - the text separated by forward slashes
      # e.g. ['100', '200']
      suffixes = original_description.split(root)[1].split('/')
      
      # Create an array of synthesized descriptions by appending each suffix to the root
      # e.g. ['boeing 747-100', 'boeing 747-200']
      suffixes.map{ |suffix| root + suffix }.each do |synthesized_description|
        # Look up the Aircraft that match each synthesized description and associate
        # them with the original flight segment aircraft_description
        Aircraft.fuzzy_match.find_all(synthesized_description).each do |aircraft|
          attrs = {
            :a_class => "Aircraft",
            :a => aircraft.description,
            :b_class => "FlightSegment",
            :b => original_description
          }
          unless ::FuzzyMatch::CachedResult.exists? attrs
            ::FuzzyMatch::CachedResult.create! attrs
          end
        end
      end
    # If the flight segment's aircraft_description doesn't contain '/' we can use
    # a method provided by fuzzy_match to associate it with Aircraft
    else
      FlightSegment.find_by_aircraft_description(original_description).cache_aircraft!
    end
  end
end

.update_averages!Object

FIXME TODO do we want to restrict this to certain years? Derive some average characteristics from flight segments



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/earth/air/aircraft.rb', line 59

def update_averages!
  # Setup fuzzy matches with FlightSegment
  manually_cache_flight_segments!
  
  # Calculate seats and passengers for each aircraft based on associated flight_segments
  safe_find_each do |a|
    if a.seats = a.flight_segments.weighted_average(:seats_per_flight, :weighted_by => :passengers)
      a.seats_specificity = 'aircraft'
    end
    if (passengers = a.flight_segments.sum(:passengers)) > 0
      a.passengers = passengers
    end
    a.save!
  end
  
  # Calculate seats for any aircraft that don't have any flight_segments by averaging across all aircraft with flight segments in the aircraft class
  where(:seats => nil).safe_find_each do |a|
    if a.seats = where(:class_code => a.class_code, :seats_specificity => 'aircraft').weighted_average(:seats, :weighted_by => :passengers)
      a.seats_specificity = 'aircraft_class'
      a.save!
    end
  end
  
  # Calculate any missing fuel use coefficients by averaging across all aircraft with fuel use coefficients in the same aircraft class
  where(:m3 => nil).safe_find_each do |a|
    a.m3 = where(:class_code => a.class_code, :fuel_use_specificity => 'aircraft').weighted_average(:m3, :weighted_by => :passengers)
    a.m2 = where(:class_code => a.class_code, :fuel_use_specificity => 'aircraft').weighted_average(:m2, :weighted_by => :passengers)
    a.m1 = where(:class_code => a.class_code, :fuel_use_specificity => 'aircraft').weighted_average(:m1, :weighted_by => :passengers)
    a.b =  where(:class_code => a.class_code, :fuel_use_specificity => 'aircraft').weighted_average(:b,  :weighted_by => :passengers)
    if a.valid_fuel_use_equation?
      a.m3_units = 'kilograms_per_cubic_nautical_mile'
      a.m2_units = 'kilograms_per_square_nautical_mile'
      a.m1_units = 'kilograms_per_nautical_mile'
      a.b_units =  'kilograms'
      a.fuel_use_specificity = 'aircraft_class'
      a.save!
    end
  end
end

Instance Method Details

#valid_fuel_use_equation?Boolean

Returns:

  • (Boolean)


148
149
150
# File 'lib/earth/air/aircraft.rb', line 148

def valid_fuel_use_equation?
  [m3, m2, m1, b].all?(&:present?) and [m3, m2, m1, b].any?(&:nonzero?)
end