travel_emission_linear_fit.py 4.12 KB
import numpy as np
from geopy.distance import great_circle


class BaseEmissionModel():
    def __init__(self, config):  # Constructor
        self.name = config.name
        self.slug = config.slug
        self.config = config.config

    def __repr__(self):  # Cast to String
        return "Emission model\n" + \
               "==============\n" + \
               "%s (%s)" % (self.name, self.slug) + \
               repr(self.config)

    # def compute_travel_footprint()


class EmissionModel(BaseEmissionModel):
    # @abc
    def compute_travel_footprint(
            self,
            origin_latitude,        # degrees
            origin_longitude,       # degrees
            destination_latitude,   # degrees
            destination_longitude,  # degrees
            prefer_train_under_distance=0,  # meters
    ):
        footprint = 0.0

        #############################################
        # TODO: find closest airport(s) and pick one
        # We're going to need caching here as well.
        from collections import namedtuple
        origin_airport = namedtuple('Position', [
            'latitude',
            'longitude',
            'address',  # perhaps
        ])
        origin_airport.latitude = origin_latitude
        origin_airport.longitude = origin_longitude
        destination_airport = namedtuple('Position', [
            'latitude',
            'longitude',
            'address',  # perhaps
        ])
        destination_airport.latitude = destination_latitude
        destination_airport.longitude = destination_longitude
        #############################################
        #############################################

        # I.a Train travel footprint
        # ... TODO

        # I.b Airplane travel footprint
        footprint += self.compute_airplane_footprint(
            origin_latitude=origin_airport.latitude,
            origin_longitude=origin_airport.longitude,
            destination_latitude=destination_airport.latitude,
            destination_longitude=destination_airport.longitude,
        )

        # II.a Double the footprint if it's a round-trip
        footprint *= 2.0

        return footprint

    def compute_airplane_footprint(
            self,
            origin_latitude,
            origin_longitude,
            destination_latitude,
            destination_longitude
    ):
        config = self.config.plane_emission_linear_fit

        great_circle_distance = self.get_distance_between(
            origin_latitude, origin_longitude,
            destination_latitude, destination_longitude
        )

        distance = great_circle_distance

        distance = config.connecting_flights_scale * distance

        distance = distance * config.scale_before + config.offset_before

        footprint = self.apply_scaling_law(
            distance,
            config.intervals
        )

        footprint = self.adjust_footprint_for_rfi(footprint, config)

        return footprint

    def adjust_footprint_for_rfi(self, footprint, config):
        # Todo: grab data from config merged with form input?
        return config.rfi * footprint

    def apply_scaling_law(self, distance, intervals):
        footprint = distance
        for interval in intervals:
            if interval.dmin <= distance < interval.dmax:
                offset = interval.offset if interval.offset else 0
                scale = interval.scale if interval.scale else 1
                footprint = footprint * scale + offset
                break

        return footprint

    def get_distance_between(
            self,
            origin_latitude,
            origin_longitude,
            destination_latitude,
            destination_longitude
    ):
        """
        :param origin_latitude:
        :param origin_longitude:
        :param destination_latitude:
        :param destination_longitude:
        :return: Distance in meters between the two locations,
                 along Earth's great circles.
        """
        gcd = great_circle(
            (np.float(origin_latitude), np.float(origin_longitude)),
            (np.float(destination_latitude), np.float(destination_longitude))
        ).m
        return gcd