def interpolate_values(source_table, source_column, target_value): t = source_table source_values = t[source_column] minimum_source_value = source_values.min() maximum_source_value = source_values.max() message_template = 'source_column (%s) values must be %%s' % source_column assert len(t) > 0, 'table must have at least one row' assert len(t) == len(set(source_values)), message_template % 'unique' assert minimum_source_value >= 0, message_template % 'positive' if len(t) == 1: return t.ix[t.index[0]] if target_value <= minimum_source_value: return t.ix[source_values.argmin()] if target_value >= maximum_source_value: return t.ix[source_values.argmax()] # Get two rows nearest to target value sorted_indices = (source_values - target_value).abs().argsort() row0 = t.ix[sorted_indices[0]] row1 = t.ix[sorted_indices[1]] # Compute fraction of interpolation fraction = divide_safely( target_value - row0[source_column], row1[source_column] - row0[source_column], ExpectedPositive(message_template % 'unique and positive')) # Interpolate return row0 + (row1 - row0) * fraction
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 range(min(graph), max(graph)): for node2_id in range(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 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_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 = make_zero_by_year(population_by_year) consumption_by_year = make_zero_by_year(population_by_year) estimated_household_connection_count_by_year = divide_safely( population_by_year, number_of_people_per_household, make_zero_by_year(population_by_year)) 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_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_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_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_balance_cost( panel_actual_system_capacity_in_kw, balance_raw_cost_per_panel_kw, balance_installation_cost_as_percent_of_raw_cost, balance_maintenance_cost_per_year_as_percent_of_raw_cost, balance_lifetime_in_years): raw_cost = panel_actual_system_capacity_in_kw * \ balance_raw_cost_per_panel_kw installation_cost = raw_cost * \ balance_installation_cost_as_percent_of_raw_cost / 100. maintenance_cost_per_year = raw_cost * \ balance_maintenance_cost_per_year_as_percent_of_raw_cost / 100. replacement_cost_per_year = divide_safely( raw_cost + installation_cost, balance_lifetime_in_years, ExpectedPositive('balance_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 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_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 prepare_system_capacity_cost( option_table, capacity_column, desired_system_capacity): t = option_table.copy() t['raw_cost_per_unit_capacity'] = t['raw_cost'] / t[capacity_column] x = interpolate_values(t, capacity_column, desired_system_capacity) minimum_system_capacity = t[capacity_column].min() actual_system_capacity = max( desired_system_capacity, minimum_system_capacity) # Extrapolate raw_cost = actual_system_capacity * x['raw_cost_per_unit_capacity'] installation_cost = raw_cost * x[ 'installation_cost_as_percent_of_raw_cost'] / 100. return { 'actual_system_' + capacity_column: actual_system_capacity, 'raw_cost': raw_cost, 'installation_cost': installation_cost, 'maintenance_cost_per_year': raw_cost * x[ 'maintenance_cost_per_year_as_percent_of_raw_cost'] / 100., 'replacement_cost_per_year': divide_safely( raw_cost + installation_cost, x['lifetime_in_years'], ExpectedPositive('lifetime_in_years')), }
def adjust_for_losses(x, *loss_percents): y = x for loss_percent in loss_percents: loss_fraction = loss_percent / 100. y = divide_safely(y, 1 - loss_fraction, 0) return y
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}