def fun_decision_making(df_pp, carbon_tax, r): # ~ candidate_pp = pd.DataFrame(columns = ['name','plant_type','capacity','running_cost','investment_cost','total_lifetime','lifetime_remain','emission_intensity','profit_index']) candidate_pp = { 'CN_baseload': 0, 'coal': 0, 'gas': 0, 'solar': 0, 'wind': 0 } ## set NPV default value as 0. for pp in pp_choice.values(): ##investgate each type of plant. new_pp = deepcopy(pp) ##set up new df for new pp. new_pp[ 'marginal_cost'] = new_pp.running_cost + carbon_tax * new_pp.emission_intensity # ============================================================================= ##copy the current supply system df. df_pp_new = deepcopy(df_pp) ##group the pp by plant type. df_pp_grouped = df_pp_new.groupby('plant_type', as_index=False).agg({ 'capacity': 'sum', 'marginal_cost': 'mean', 'emission_intensity': 'mean' }) mask = df_pp_grouped.plant_type == new_pp.plant_type.item( ) ##condition. ## add capacity of the new_pp to existing df. df_pp_grouped.loc[mask, 'capacity'] += new_pp.capacity.item() # ============================================================================= ##check whether biofuel is available. if biomass in fuel_list: if df_pp_grouped.loc[ df_pp_grouped.plant_type == 'gas'].marginal_cost.values > biomass.running_cost: ##if marginal cost of natural gas(default) is bigger than biomass. index_gas = df_pp_grouped.loc[df_pp_grouped.plant_type == 'gas'].index df_pp_grouped.at[ index_gas, 'marginal_cost'] = biomass.running_cost ## switch to biomass. if new_pp.plant_type.item() == 'gas' and new_pp.marginal_cost.item( ) > biomass.running_cost: ## replace natural gas with biogas new_pp['marginal_cost'] = biomass.running_cost # ============================================================================= ##calculate for each time slice: acc_profit_year = 0 ##accumulative profit. for slice_nr in range(64): ##length is 4, loop through. demand_level = demand_64[slice_nr] avail_solar = solar_level[slice_nr] avail_wind = wind_level[slice_nr] allocated_hours = slice_hrs[slice_nr] ## hours in current slice. # ======================================================= # print('\n' +'-----new slice: '+ str(allocated_hours) + '(hours)----- ') # print('\n' +'-----the slice is: '+ str(time_slice)) # # print('the demand reference q0 is: ' + str(demand_level)) # print('The availability of solar is : ' + str (avail_solar)) # print('The availability of wind is : ' + str (avail_wind)) # ========================================================= # df_pp_grouped['capacity_available_KW'] = df_pp_grouped.apply(lambda row: # fun_availability(row.plant_type,avail_solar,avail_wind), axis=1) * df_pp_grouped.capacity availability_index = [1, 1, 1, avail_solar, avail_wind] ##CN,coal,gas,solar,wind. df_pp_grouped[ 'capacity_available_KW'] = df_pp_grouped.capacity * availability_index new_pp['capacity_available_KW'] = fun_availability( new_pp.plant_type.item(), avail_solar, avail_wind) * new_pp.capacity.item() ranked_dispatch = fun_rank_dispatch(df_pp_grouped) eq_production, eq_price, last_supply_type, last_supply_percent = fun_demand_supply( df_pp_grouped, ranked_dispatch, demand_level) new_pp['utilization'] = fun_pp_utilization( new_pp.marginal_cost.item(), last_supply_percent, eq_price) ##dispatched_KW = pp_utilization * capacity_avail new_pp[ 'dispatched_KW'] = new_pp.utilization * new_pp.capacity_available_KW new_pp['hr_profit'] = new_pp.dispatched_KW * ( eq_price - new_pp.marginal_cost.item()) new_pp['slice_profit'] = new_pp['hr_profit'] * allocated_hours # ~ if new_pp.plant_type.item() == 'solar' and avail_solar == 0: ##in this case, solar is not in the df. # ~ new_plant_slice_profit = 0 #else: #new_plant_slice_profit = new_pp['slice_profit'] #print('***//////') #print(new_plant_slice_profit) acc_profit_year += new_pp['slice_profit'].item( ) ##accumulate profit from all time-slices. # ~ print('\n' + 'The slice_profit_new_plant is : ' + str (new_plant.slice_profit)) continue # ============================================================================= ##calculate NPV: geometric sequence summation. NPV_profit = acc_profit_year * ( 1 - (1 - r) **new_pp.total_lifetime.item()) / r - new_pp.investment_cost.item( ) * new_pp.capacity.item() ##NPV minus investment_cost # ~ print('the acc_profit_year of this new ' + str(new_pp.plant_type.item())+ ' is ' + str(NPV_profit)) if NPV_profit > 0: lifetime = new_pp.total_lifetime.item() CRF_pp = r * (1 + r)**lifetime / ((1 + r)**lifetime - 1) # ~ print(CRF_pp) profit_index = CRF_pp * NPV_profit / ( new_pp.investment_cost.item() * new_pp.capacity.item()) # ~ print('the profit_index of this new ' + str(new_pp.plant_type.item())+ ' is ' + str(profit_index)) # ~ pdb.set_trace() # ~ candidate_pp = candidate_pp.append(new_pp,sort=False) ##time= 0.001 candidate_pp[new_pp.plant_type.item()] = profit_index #print('the NPV_profit and profit_index of this new ' + str(name_new)+ ' plant are ') #print(NPV_profit,profit_index) # else: # print('It is not profitable to invest in ' + str(name_new)+ ' plant.') # ============================================================================= top_pp = max(candidate_pp, key=lambda key: candidate_pp[key] ) ##return the key with highest value(NPV). if candidate_pp[top_pp] == 0: ##NPV is zero. invest_made = None else: invest_made = pp_choice[top_pp] return invest_made
df_pp['dispatched_yr'] = 0 for q0 in range(len(q0t)): ##length is 4, loop through. demand_level = q0t[q0] for solar_index in range(len(availability_levels_solar)):##4 levels of solar availability. avail_solar = availability_levels_solar[solar_index] for wind_index in range(len(availability_levels_wind)): avail_wind = availability_levels_wind[wind_index] allocated_hours = q0_hr_slice[q0][solar_index][wind_index] ## hours in current slice. # ======================================================= #print('\n' +'-----new slice: '+ str(allocated_hours) + '(hours)----- ') #print('the demand reference q0 is: ' + str(demand_level)) #print('The availability of solar is : ' + str (avail_solar)) #print('The availability of wind is : ' + str (avail_wind)) # ~ print(df_pp) df_pp['capacity_available_KW'] = df_pp.apply(lambda row: fun_availability(row.plant_type,avail_solar,avail_wind),axis=1) * df_pp.capacity ranked_dispatch = fun_rank_dispatch(df_pp) eq_production,eq_price,last_supply_type,last_supply_percent = fun_demand_supply(df_pp,ranked_dispatch,demand_level) df_pp['utilization'] = df_pp.apply(lambda row: fun_pp_utilization(row.marginal_cost,last_supply_percent,eq_price),axis=1) df_pp['dispatched_KWHs'] = df_pp.utilization * df_pp.capacity_available_KW * allocated_hours #print(df_pp_pi) df_pp['dispatched_yr'] += df_pp.dispatched_KWHs continue continue continue yr_dispatch = df_pp[['plant_type','dispatched_yr']].set_index('plant_type')
for solar_index in range(len( availability_levels_solar)): ##4 levels of solar availability. avail_solar = availability_levels_solar[solar_index] for wind_index in range(len(availability_levels_wind)): avail_wind = availability_levels_wind[wind_index] allocated_hours = q0_hr_slice[q0][solar_index][ wind_index] ## hours in current slice. # ======================================================= #print('\n' +'-----new slice: '+ str(allocated_hours) + '(hours)----- ') #print('the demand reference q0 is: ' + str(demand_level)) #print('The availability of solar is : ' + str (avail_solar)) #print('The availability of wind is : ' + str (avail_wind)) df_pp_pi['capacity_available_KW'] = df_pp_pi.apply( lambda row: fun_availability(row.plant_type, avail_solar, avail_wind), axis=1) * df_pp_pi.capacity ranked_dispatch = fun_rank_dispatch(df_pp_pi) eq_production, eq_price, last_supply_type, last_supply_percent = fun_demand_supply( df_pp_pi, ranked_dispatch, demand_level) df_pp_pi['utilization'] = df_pp_pi.apply( lambda row: fun_pp_utilization( row.marginal_cost, last_supply_percent, eq_price), axis=1) df_pp_pi[ 'dispatched_KWHs'] = df_pp_pi.utilization * df_pp_pi.capacity_available_KW * allocated_hours df_pp_pi['revenue'] = df_pp_pi.dispatched_KWHs * ( eq_price - df_pp_pi.marginal_cost)
def fun_decision_making(ts, rounds, df_pp, carbon_tax): print('--------investment process.------------') # ~ candidate_pp = pd.DataFrame(columns = ['name','plant_type','capacity','running_cost','investment_cost','total_lifetime','lifetime_remain','emission_intensity','profit_index']) candidate_pp = { 'CN_baseload': 0, 'coal': 0, 'gas': 0, 'solar': 0, 'wind': 0 } ## set NPV default value as 0. for new_pp in pp_choice.values(): ##investgate each type of plant. acc_profit_year = 0 # ============================================================================= ##set up new df for new pp. # name_new = str(pp_new.plant_type) +'_t'+str(ts) +'_r'+ str(rounds)##name the plant (unique). # type_new = pp_new.plant_type # capacity_new = pp_new.capacity # running_cost_new = pp_new.running_cost # investment_cost_new = pp_new.investment_cost # tot_life_new = pp_new.lifetime # # life_remain_new = pp_new.lifetime # emission_new = pp_new.emission_intensity # marginal_cost_new = pp_new.running_cost + carbon_tax * pp_new.emission_intensity # new_pp_params = [name_new,pp_new.plant_type,pp_new.capacity,pp_new.running_cost,pp_new.investment_cost, # pp_new.lifetime,pp_new.lifetime,pp_new.emission_intensity,marginal_cost_new] new_pp[ 'marginal_cost'] = new_pp.running_cost + carbon_tax * new_pp.emission_intensity # ~ if new_pp.plant_type.item() == 'gas' and new_pp.marginal_cost.item()> biomass.running_cost: ## replace natural gas with biogas. # ~ new_pp['marginal_cost'] = biomass.running_cost # new_pp = pd.DataFrame([new_pp_params],columns=df_pp.columns) ##copy the current energy system df. df_pp_new = deepcopy(df_pp) ##append new pp to df. # df_pp_new = df_pp_new.append(new_pp,ignore_index=True,sort=True)## append new pp to df. # ~ print(df_pp_new[['plant_type','lifetime_remain']]) # print(system_pp_new) df_pp_grouped = df_pp_new.groupby('plant_type', as_index=False).agg({ 'capacity': 'sum', 'marginal_cost': 'mean', 'emission_intensity': 'mean' }) mask = df_pp_grouped.plant_type == new_pp.plant_type.item( ) ##condition. ## add capacity of the new_pp to existing df. df_pp_grouped.loc[mask, 'capacity'] += new_pp.capacity.item() # ~ if df_pp_grouped.loc[df_pp_grouped.plant_type == 'gas'].marginal_cost.values>biomass.running_cost: ##if marginal cost of natural gas(default) is bigger than biomass. # ~ index_gas = df_pp_grouped.loc[df_pp_grouped.plant_type == 'gas'].index # ~ df_pp_grouped.at[index_gas, 'marginal_cost'] = biomass.running_cost## switch to biomass. # ============================================================================= ##calculate for each time slice: for slice_nr in range(64): ##length is 4, loop through. demand_level = demand_64[slice_nr] avail_solar = solar_level[slice_nr] avail_wind = wind_level[slice_nr] allocated_hours = slice_hrs[slice_nr] ## hours in current slice. # ======================================================= # print('\n' +'-----new slice: '+ str(allocated_hours) + '(hours)----- ') # print('\n' +'-----the slice is: '+ str(time_slice)) # # print('the demand reference q0 is: ' + str(demand_level)) # print('The availability of solar is : ' + str (avail_solar)) # print('The availability of wind is : ' + str (avail_wind)) # ========================================================= # t1_start = time.perf_counter() # print(df_pp_new[['plant_type','capacity']]) df_pp_grouped['capacity_available_KW'] = df_pp_grouped.apply( lambda row: fun_availability(row.plant_type, avail_solar, avail_wind), axis=1) * df_pp_grouped.capacity # ~ availability_index = [1,1,1,avail_solar,avail_wind] ##CN,coal,gas,solar,wind. # ~ print(df_pp_grouped) # ~ df_pp_grouped['capacity_available_KW'] = df_pp_grouped.capacity * availability_index new_pp['capacity_available_KW'] = fun_availability( new_pp.plant_type.item(), avail_solar, avail_wind) * new_pp.capacity.item() ranked_dispatch = fun_rank_dispatch(df_pp_grouped) eq_production, eq_price, last_supply_type, last_supply_percent = fun_demand_supply( df_pp_grouped, ranked_dispatch, demand_level) new_pp['utilization'] = fun_pp_utilization( new_pp.marginal_cost.item(), last_supply_percent, eq_price) #dispatched_KW = pp_utilization * capacit_avail new_pp[ 'dispatched_KW'] = new_pp.utilization * new_pp.capacity_available_KW new_pp['hr_profit'] = new_pp.dispatched_KW * ( eq_price - new_pp.marginal_cost.item()) new_pp['slice_profit'] = new_pp['hr_profit'] * allocated_hours if new_pp.plant_type.item( ) == 'solar' and avail_solar == 0: ##in this case, solar is not in the df. new_plant_slice_profit = 0 #else: #new_plant_slice_profit = new_pp['slice_profit'] #print('***//////') #print(new_plant_slice_profit) acc_profit_year += new_pp['slice_profit'].item( ) ##accumulate profit from all time-slices. # ============================================================================= # ~ print('\n' + 'The slice_profit_new_plant is : ' + str (new_plant_slice_profit)) continue #df_pp_grouped['capacity'].loc[df_pp_grouped.plant_type==type_new]-= capacity_new ##NPV: geometric sequence summation. NPV_profit = acc_profit_year * ( 1 - (1 - r) **new_pp.total_lifetime.item()) / r - new_pp.investment_cost.item( ) * new_pp.capacity.item() ##NPV minus investment_cost # ~ print('the acc_profit_year of this new ' + str(new_pp.plant_type.item())+ ' is ' + str(NPV_profit)) if NPV_profit > 0: CRF_pp = CRF[new_pp.plant_type.item()] profit_index = CRF_pp * NPV_profit / ( new_pp.investment_cost.item() * new_pp.capacity.item()) # ~ print('the profit_index of this new ' + str(new_pp.plant_type.item())+ ' is ' + str(profit_index)) # ~ new_pp['profit_index'] = profit_index## define profit index. # ~ candidate_pp = candidate_pp.append(new_pp,sort=False) ##time= 0.001 candidate_pp[new_pp.plant_type.item()] = profit_index #print('the NPV_profit and profit_index of this new ' + str(name_new)+ ' plant are ') #print(NPV_profit,profit_index) # else: # print('It is not profitable to invest in ' + str(name_new)+ ' plant.') # ============================================================================= top_pp = max(candidate_pp, key=lambda key: candidate_pp[key] ) ##return the key with highest value(NPV). if candidate_pp[top_pp] == 0: invest_made = None else: invest_made = pp_choice[top_pp] # ~ if candidate_pp.empty == False: # ~ candidate_pp.sort_values(by=['profit_index'], axis=0, ascending=False, inplace=True) ## rank candidates by NPV profit. # ~ candidate_pp.reset_index(drop=True,inplace=True) # ~ invest_made = candidate_pp.iloc[0][['name','plant_type','capacity', # ~ 'running_cost','investment_cost','total_lifetime','lifetime_remain','emission_intensity']]## select the first row-plant with the highest profit index. # ~ # print(invest_made) # ~ else: # ~ invest_made = None # print('One ' + str(invest_made) + ' is invested by ' + ' company ' + '.') # return invest_made