def estimate_consumption_from_connection_type(
        population_by_year, number_of_people_per_household,
        connection_type_table, **keywords):
    """
    Note that connection_count and consumption will be constant year over year
    if there is a local override for household_count.
    """
    d = {}
    connection_count_by_year = Series(0, index=population_by_year.index)
    consumption_by_year = Series(0, index=population_by_year.index)
    estimated_household_connection_count_by_year = divide_safely(
        population_by_year, number_of_people_per_household, 0)
    for row_index, row in connection_type_table.iterrows():
        connection_type = row['connection_type']
        count_by_year = _get_connection_count_by_year(
            keywords, connection_type,
            estimated_household_connection_count_by_year)
        consumption_per_connection = _get_consumption_per_connection(
            keywords, connection_type, row['consumption_in_kwh_per_year'])
        connection_count_by_year += count_by_year
        consumption_by_year += consumption_per_connection * count_by_year
        # Record
        connection_count_name = _name_connection_count(connection_type)
        consumption_per_connection_name = _name_consumption_per_connection(
            connection_type)
        d[connection_count_name + '_by_year'] = count_by_year
        d[connection_count_name] = get_final_value(count_by_year)
        d[consumption_per_connection_name] = consumption_per_connection
    return dict(d, **{
        'connection_count_by_year': connection_count_by_year,
        'consumption_in_kwh_by_year': consumption_by_year})
def estimate_battery_cost(
        panel_actual_system_capacity_in_kw,
        battery_kwh_per_panel_kw,
        battery_raw_cost_per_battery_kwh,
        battery_installation_cost_as_percent_of_raw_cost,
        battery_maintenance_cost_per_year_as_percent_of_raw_cost,
        battery_lifetime_in_years):
    storage_in_kwh = panel_actual_system_capacity_in_kw * \
        battery_kwh_per_panel_kw
    raw_cost = storage_in_kwh * \
        battery_raw_cost_per_battery_kwh
    installation_cost = raw_cost * \
        battery_installation_cost_as_percent_of_raw_cost / 100.
    maintenance_cost_per_year = raw_cost * \
        battery_maintenance_cost_per_year_as_percent_of_raw_cost / 100.
    replacement_cost_per_year = divide_safely(
        raw_cost + installation_cost, battery_lifetime_in_years,
        ExpectedPositive('battery_lifetime_in_years'))
    return {
        'storage_in_kwh': storage_in_kwh,
        'raw_cost': raw_cost,
        'installation_cost': installation_cost,
        'maintenance_cost_per_year': maintenance_cost_per_year,
        'replacement_cost_per_year': replacement_cost_per_year,
    }
def estimate_lv_line_cost(
        final_connection_count,
        line_length_adjustment_factor,
        average_distance_between_buildings_in_meters,
        lv_line_raw_cost_per_meter,
        lv_line_installation_cost_as_percent_of_raw_cost,
        lv_line_maintenance_cost_per_year_as_percent_of_raw_cost,
        lv_line_lifetime_in_years):
    # TODO: Compute lv line cost by year as connections come online
    line_length_in_meters = average_distance_between_buildings_in_meters * (
        final_connection_count - 1) * line_length_adjustment_factor
    raw_cost = line_length_in_meters * \
        lv_line_raw_cost_per_meter
    installation_cost = raw_cost * \
        lv_line_installation_cost_as_percent_of_raw_cost / 100.
    maintenance_cost_per_year = raw_cost * \
        lv_line_maintenance_cost_per_year_as_percent_of_raw_cost / 100.
    replacement_cost_per_year = divide_safely(
        raw_cost + installation_cost, lv_line_lifetime_in_years,
        ExpectedPositive('lv_line_lifetime_in_years'))
    return {
        'raw_cost': raw_cost,
        'installation_cost': installation_cost,
        'maintenance_cost_per_year': maintenance_cost_per_year,
        'replacement_cost_per_year': replacement_cost_per_year,
    }
def prepare_cost_summary(cost_by_year, d, keywords, prefix):
    """
    Summarize costs using the values provided in *d*
    """
    discounted_cost = compute_discounted_cash_flow(
        cost_by_year, keywords['financing_year'],
        keywords['discount_rate_as_percent_of_cash_flow_per_year'])
    levelized_cost = divide_safely(discounted_cost, keywords[
        'discounted_consumption_in_kwh'], 0)
    return merge_dictionaries(d, {
        prefix + 'cost_by_year': cost_by_year,
        prefix + 'initial_cost': sum([
            sum_by_suffix(d, '_raw_cost'),
            sum_by_suffix(d, '_installation_cost'),
        ]),
        prefix + 'recurring_fixed_cost_per_year': sum([
            sum_by_suffix(d, '_maintenance_cost_per_year'),
            sum_by_suffix(d, '_replacement_cost_per_year'),
        ]),
        prefix + 'recurring_variable_cost_per_year': sum([
            d.get('final_electricity_production_cost_per_year', 0),
        ]),
        prefix + 'discounted_cost': discounted_cost,
        prefix + 'levelized_cost_per_kwh_consumed': levelized_cost,
    })
def estimate_consumption_from_connection_count(
        population_by_year,
        number_of_people_per_connection,
        consumption_in_kwh_per_year_per_connection):
    connection_count_by_year = divide_safely(
        population_by_year, number_of_people_per_connection, 0)
    consumption_by_year = consumption_in_kwh_per_year_per_connection * \
        connection_count_by_year
    return {
        'connection_count_by_year': connection_count_by_year,
        'consumption_in_kwh_by_year': consumption_by_year}
def estimate_grid_mv_line_budget(
        internal_discounted_cost_by_technology,
        grid_mv_line_discounted_cost_per_meter, line_length_adjustment_factor):
    standalone_cost = min(
        v for k, v in internal_discounted_cost_by_technology.items()
        if k != 'grid')
    grid_mv_line_budget_in_money = \
        standalone_cost - internal_discounted_cost_by_technology['grid']
    grid_mv_line_raw_budget_in_meters = divide_safely(
        grid_mv_line_budget_in_money,
        grid_mv_line_discounted_cost_per_meter,
        ExpectedPositive('grid_mv_line_discounted_cost_per_meter'))
    # Divide line distance by factor here, which should be equivalent to
    # multiplying line distance by factor when computing the network
    grid_mv_line_adjusted_budget_in_meters = divide_safely(
        grid_mv_line_raw_budget_in_meters, line_length_adjustment_factor,
        ExpectedPositive('line_length_adjustment_factor'))
    return {
        'grid_mv_line_adjusted_budget_in_meters':
            grid_mv_line_adjusted_budget_in_meters,
    }
def estimate_panel_cost(
        final_consumption_in_kwh_per_year,
        peak_hours_of_sun_per_year,
        system_loss_as_percent_of_total_production,
        panel_table):
    final_production_in_kwh_per_year = adjust_for_losses(
        final_consumption_in_kwh_per_year,
        system_loss_as_percent_of_total_production)
    desired_system_capacity_in_kw = divide_safely(
        final_production_in_kwh_per_year, peak_hours_of_sun_per_year,
        float('inf'))
    return prepare_system_capacity_cost(
        panel_table, 'capacity_in_kw', desired_system_capacity_in_kw)
def estimate_peak_demand(
        final_consumption_in_kwh_per_year,
        consumption_during_peak_hours_as_percent_of_total_consumption,
        peak_hours_of_consumption_per_year):
    final_consumption_during_peak_hours_in_kwh_per_year = \
        final_consumption_in_kwh_per_year * \
        consumption_during_peak_hours_as_percent_of_total_consumption / 100.  # noqa
    # Choose to estimate peak demand by averaging kw over peak hours
    peak_demand_in_kw = divide_safely(
        final_consumption_during_peak_hours_in_kwh_per_year,
        peak_hours_of_consumption_per_year,
        ExpectedPositive('peak_hours_of_consumption_per_year'))
    return {
        'peak_demand_in_kw': peak_demand_in_kw,
    }
def estimate_total_levelized_cost_by_technology(
        infrastructure_graph, selected_technologies,
        discounted_cost_by_technology):
    discounted_consumption_by_technology = OrderedDefaultDict(int)
    for node_id, node_d in infrastructure_graph.cycle_nodes():
        technology = node_d['proposed_technology']
        if technology not in selected_technologies:
            continue
        discounted_consumption_by_technology[technology] += node_d[
            'discounted_consumption_in_kwh']
    levelized_cost_by_technology = OrderedDict()
    for technology in selected_technologies:
        discounted_cost = discounted_cost_by_technology[technology]
        discounted_consumption = discounted_consumption_by_technology[
            technology]
        levelized_cost_by_technology[technology] = divide_safely(
            discounted_cost, discounted_consumption, 0)
    return {'levelized_cost_by_technology': levelized_cost_by_technology}
def estimate_grid_mv_line_cost_per_meter(
        grid_mv_line_raw_cost_per_meter,
        grid_mv_line_installation_cost_as_percent_of_raw_cost,
        grid_mv_line_maintenance_cost_per_year_as_percent_of_raw_cost,
        grid_mv_line_lifetime_in_years):
    raw_cost_per_meter = grid_mv_line_raw_cost_per_meter
    installation_cost_per_meter = raw_cost_per_meter * \
        grid_mv_line_installation_cost_as_percent_of_raw_cost / 100.
    return {
        'raw_cost_per_meter': raw_cost_per_meter,
        'installation_cost_per_meter': installation_cost_per_meter,
        'maintenance_cost_per_meter_per_year':
            raw_cost_per_meter *
            grid_mv_line_maintenance_cost_per_year_as_percent_of_raw_cost / 100.,  # noqa
        'replacement_cost_per_meter_per_year': divide_safely(
            raw_cost_per_meter + installation_cost_per_meter,
            grid_mv_line_lifetime_in_years,
            ExpectedPositive('grid_mv_line_lifetime_in_years')),
    }
def estimate_lv_connection_cost(
        final_connection_count,
        lv_connection_raw_cost,
        lv_connection_installation_cost_as_percent_of_raw_cost,
        lv_connection_maintenance_cost_per_year_as_percent_of_raw_cost,
        lv_connection_lifetime_in_years):
    # TODO: Compute lv connection cost by year as connections come online
    raw_cost = final_connection_count * \
        lv_connection_raw_cost
    installation_cost = raw_cost * \
        lv_connection_installation_cost_as_percent_of_raw_cost / 100.
    maintenance_cost_per_year = raw_cost * \
        lv_connection_maintenance_cost_per_year_as_percent_of_raw_cost / 100.
    replacement_cost_per_year = divide_safely(
        raw_cost + installation_cost, lv_connection_lifetime_in_years,
        ExpectedPositive('lv_connection_lifetime_in_years'))
    return {
        'raw_cost': raw_cost,
        'installation_cost': installation_cost,
        'maintenance_cost_per_year': maintenance_cost_per_year,
        'replacement_cost_per_year': replacement_cost_per_year,
    }
def run(location_geotable):
    graph = Graph()
    for index, row in location_geotable.iterrows():
        graph.add_node(index, {
            'lat': row['Latitude'], 'lon': row['Longitude']})
    for node1_id in xrange(min(graph), max(graph)):
        for node2_id in xrange(node1_id + 1, max(graph) + 1):
            node1_d = graph.node[node1_id]
            node2_d = graph.node[node2_id]
            node1_ll = node1_d['lat'], node1_d['lon']
            node2_ll = node2_d['lat'], node2_d['lon']
            distance = get_distance(node1_ll, node2_ll).m
            graph.add_edge(node1_id, node2_id, weight=distance)
    tree = minimum_spanning_tree(graph)
    total_distance = sum(edge_d[
        'weight'] for node1_id, node2_id, edge_d in tree.edges(data=True))
    location_count = len(graph)
    average_distance = divide_safely(total_distance, location_count, 0)
    return [
        ('total_distance_between_locations_in_meters', total_distance),
        ('location_count', location_count),
        ('average_distance_between_locations_in_meters', average_distance),
    ]
def estimate_fuel_cost(
        consumption_in_kwh_by_year,
        system_loss_as_percent_of_total_production,
        generator_actual_system_capacity_in_kw,
        generator_minimum_hours_of_production_per_year,
        generator_fuel_liters_consumed_per_kwh,
        fuel_cost_per_liter):
    production_in_kwh_by_year = adjust_for_losses(
        consumption_in_kwh_by_year, system_loss_as_percent_of_total_production)
    desired_hours_of_production_by_year = divide_safely(
        production_in_kwh_by_year,
        generator_actual_system_capacity_in_kw, float('inf'))
    years = production_in_kwh_by_year.index
    minimum_hours_of_production_by_year = Series([
        generator_minimum_hours_of_production_per_year,
    ] * len(years), index=years)
    hours_of_production_by_year = DataFrame({
        'desired': desired_hours_of_production_by_year,
        'minimum': minimum_hours_of_production_by_year,
    }).max(axis=1)
    fuel_cost_by_year = fuel_cost_per_liter * \
        generator_fuel_liters_consumed_per_kwh * \
        generator_actual_system_capacity_in_kw * \
        hours_of_production_by_year
    d = {}
    # Add yearly values
    d['hours_of_production_by_year'] = hours_of_production_by_year
    d['fuel_cost_by_year'] = fuel_cost_by_year
    d['electricity_production_in_kwh_by_year'] = production_in_kwh_by_year
    # Add final values
    d['final_hours_of_production_per_year'] = get_final_value(
        hours_of_production_by_year)
    d['final_fuel_cost_per_year'] = get_final_value(fuel_cost_by_year)
    d['final_electricity_production_in_kwh_per_year'] = get_final_value(
        production_in_kwh_by_year)
    return d
def estimate_proposed_cost_per_connection(
        proposed_technology, final_connection_count, **keywords):
    proposed_cost_per_connection = divide_safely(
        keywords.get(proposed_technology + '_local_discounted_cost', 0),
        final_connection_count, 0)
    return {'proposed_cost_per_connection': proposed_cost_per_connection}