def unit_commitment_model(): model = ConcreteModel() # Define input files xlsx = pd.ExcelFile( f"{Path(__file__).parent.absolute()}/input/unit_commitment.xlsx", engine="openpyxl", ) system_demand = Helper.read_excel(xlsx, "SystemDemand") storage_systems = Helper.read_excel(xlsx, "StorageSystems") generators = Helper.read_excel(xlsx, "Generators") generator_step_size = Helper.read_excel(xlsx, "GeneratorStepSize") generator_step_cost = Helper.read_excel(xlsx, "GeneratorStepCost") pv_generation = Helper.read_excel(xlsx, "PVGeneration") # Define sets model.T = Set(ordered=True, initialize=system_demand.index) model.I = Set(ordered=True, initialize=generators.index) model.F = Set(ordered=True, initialize=generator_step_size.columns) model.S = Set(ordered=True, initialize=storage_systems.index) # Define parameters model.Pmax = Param(model.I, within=NonNegativeReals, mutable=True) model.Pmin = Param(model.I, within=NonNegativeReals, mutable=True) model.RU = Param(model.I, within=NonNegativeReals, mutable=True) model.RD = Param(model.I, within=NonNegativeReals, mutable=True) model.SUC = Param(model.I, within=NonNegativeReals, mutable=True) model.SDC = Param(model.I, within=NonNegativeReals, mutable=True) model.Pini = Param(model.I, within=NonNegativeReals, mutable=True) model.uini = Param(model.I, within=Binary, mutable=True) model.C = Param(model.I, model.F, within=NonNegativeReals, mutable=True) model.B = Param(model.I, model.F, within=NonNegativeReals, mutable=True) model.SystemDemand = Param(model.T, within=NonNegativeReals, mutable=True) model.Emissions = Param(model.I, within=NonNegativeReals, mutable=True) model.PV = Param(model.T, within=NonNegativeReals, mutable=True) model.ESS_Pmax = Param(model.S, within=NonNegativeReals, mutable=True) model.ESS_SOEmax = Param(model.S, within=NonNegativeReals, mutable=True) model.ESS_SOEini = Param(model.S, within=NonNegativeReals, mutable=True) model.ESS_Eff = Param(model.S, within=NonNegativeReals, mutable=True) # Give values to parameters of the generators for i in model.I: model.Pmin[i] = generators.loc[i, "Pmin"] model.Pmax[i] = generators.loc[i, "Pmax"] model.RU[i] = generators.loc[i, "RU"] model.RD[i] = generators.loc[i, "RD"] model.SUC[i] = generators.loc[i, "SUC"] model.SDC[i] = generators.loc[i, "SDC"] model.Pini[i] = generators.loc[i, "Pini"] model.uini[i] = generators.loc[i, "uini"] model.Emissions[i] = generators.loc[i, "Emissions"] for f in model.F: model.B[i, f] = generator_step_size.loc[i, f] model.C[i, f] = generator_step_cost.loc[i, f] # Add system demand and PV generation for t in model.T: model.SystemDemand[t] = system_demand.loc[t, "SystemDemand"] model.PV[t] = pv_generation.loc[t, "PVGeneration"] # Give values to ESS parameters for s in model.S: model.ESS_Pmax[s] = storage_systems.loc[s, "Power"] model.ESS_SOEmax[s] = storage_systems.loc[s, "Energy"] model.ESS_SOEini[s] = storage_systems.loc[s, "SOEini"] model.ESS_Eff[s] = storage_systems.loc[s, "Eff"] # Define decision variables model.P = Var(model.I, model.T, within=NonNegativeReals) model.Pres = Var(model.T, within=NonNegativeReals) model.b = Var(model.I, model.F, model.T, within=NonNegativeReals) model.u = Var(model.I, model.T, within=Binary) model.CSU = Var(model.I, model.T, within=NonNegativeReals) model.CSD = Var(model.I, model.T, within=NonNegativeReals) model.SOE = Var(model.S, model.T, within=NonNegativeReals) model.Pch = Var(model.S, model.T, within=NonNegativeReals) model.Pdis = Var(model.S, model.T, within=NonNegativeReals) model.u_ess = Var(model.S, model.T, within=Binary) # -------------------------------------- # Define the objective functions # -------------------------------------- def cost_objective(model): return sum( sum( sum(model.C[i, f] * model.b[i, f, t] for f in model.F) + model.CSU[i, t] + model.CSD[i, t] for i in model.I) for t in model.T) def emissions_objective(model): return sum( sum(model.P[i, t] * model.Emissions[i] for i in model.I) for t in model.T) def unmet_objective(model): return sum(model.Pres[t] for t in model.T) # -------------------------------------- # Define the regular constraints # -------------------------------------- def power_decomposition_rule1(model, i, t): return model.P[i, t] == sum(model.b[i, f, t] for f in model.F) def power_decomposition_rule2(model, i, f, t): return model.b[i, f, t] <= model.B[i, f] def power_min_rule(model, i, t): return model.P[i, t] >= model.Pmin[i] * model.u[i, t] def power_max_rule(model, i, t): return model.P[i, t] <= model.Pmax[i] * model.u[i, t] def ramp_up_rule(model, i, t): if model.T.ord(t) == 1: return model.P[i, t] - model.Pini[i] <= 60 * model.RU[i] if model.T.ord(t) > 1: return model.P[i, t] - model.P[i, model.T.prev(t)] <= 60 * model.RU[i] def ramp_down_rule(model, i, t): if model.T.ord(t) == 1: return (model.Pini[i] - model.P[i, t]) <= 60 * model.RD[i] if model.T.ord(t) > 1: return (model.P[i, model.T.prev(t)] - model.P[i, t]) <= 60 * model.RD[i] def start_up_cost(model, i, t): if model.T.ord(t) == 1: return model.CSU[i, t] >= model.SUC[i] * (model.u[i, t] - model.uini[i]) if model.T.ord(t) > 1: return model.CSU[i, t] >= model.SUC[i] * ( model.u[i, t] - model.u[i, model.T.prev(t)]) def shut_down_cost(model, i, t): if model.T.ord(t) == 1: return model.CSD[i, t] >= model.SDC[i] * (model.uini[i] - model.u[i, t]) if model.T.ord(t) > 1: return model.CSD[i, t] >= model.SDC[i] * ( model.u[i, model.T.prev(t)] - model.u[i, t]) def ESS_SOEupdate(model, s, t): if model.T.ord(t) == 1: return (model.SOE[s, t] == model.ESS_SOEini[s] + model.ESS_Eff[s] * model.Pch[s, t] - model.Pdis[s, t] / model.ESS_Eff[s]) if model.T.ord(t) > 1: return (model.SOE[s, t] == model.SOE[s, model.T.prev(t)] + model.ESS_Eff[s] * model.Pch[s, t] - model.Pdis[s, t] / model.ESS_Eff[s]) def ESS_SOElimit(model, s, t): return model.SOE[s, t] <= model.ESS_SOEmax[s] def ESS_Charging(model, s, t): return model.Pch[s, t] <= model.ESS_Pmax[s] * model.u_ess[s, t] def ESS_Discharging(model, s, t): return model.Pdis[s, t] <= model.ESS_Pmax[s] * (1 - model.u_ess[s, t]) def Balance(model, t): return model.PV[t] + sum(model.P[i, t] for i in model.I) + sum( model.Pdis[s, t] for s in model.S) == model.SystemDemand[t] - model.Pres[t] + sum( model.Pch[s, t] for s in model.S) def Pres_max(model, t): return model.Pres[t] <= 0.1 * model.SystemDemand[t] # -------------------------------------- # Add components to the model # -------------------------------------- # Add the constraints to the model model.power_decomposition_rule1 = Constraint( model.I, model.T, rule=power_decomposition_rule1) model.power_decomposition_rule2 = Constraint( model.I, model.F, model.T, rule=power_decomposition_rule2) model.power_min_rule = Constraint(model.I, model.T, rule=power_min_rule) model.power_max_rule = Constraint(model.I, model.T, rule=power_max_rule) model.start_up_cost = Constraint(model.I, model.T, rule=start_up_cost) model.shut_down_cost = Constraint(model.I, model.T, rule=shut_down_cost) model.ConSOEUpdate = Constraint(model.S, model.T, rule=ESS_SOEupdate) model.ConCharging = Constraint(model.S, model.T, rule=ESS_Charging) model.ConDischarging = Constraint(model.S, model.T, rule=ESS_Discharging) model.ConSOElimit = Constraint(model.S, model.T, rule=ESS_SOElimit) model.ConGenUp = Constraint(model.I, model.T, rule=ramp_up_rule) model.ConGenDown = Constraint(model.I, model.T, rule=ramp_down_rule) model.ConBalance = Constraint(model.T, rule=Balance) model.Pres_max = Constraint(model.T, rule=Pres_max) # Add the objective functions to the model using ObjectiveList(). Note # that the first index is 1 instead of 0! model.obj_list = ObjectiveList() model.obj_list.add(expr=cost_objective(model), sense=minimize) model.obj_list.add(expr=emissions_objective(model), sense=minimize) model.obj_list.add(expr=unmet_objective(model), sense=minimize) # By default deactivate all the objective functions for o in range(len(model.obj_list)): model.obj_list[o + 1].deactivate() return model
def set_testl(market_instances_list, airport_list, market_data, segment_travel_time, time_zone_dict, iti_dict, fleet_data, passeger_type_dict, attr_value, marketpt_attr_sum, solver): """ 很多输入变量都是字典,就是为了在模型中生成子集的时候有筛选功能 即 if dict【m】 in dict :param airport_list: :param market_data: :param segment_travel_time: :param iti_dict:itinerary number key ,info value :{0: {'market': "M('SEA', 'LAX')", 'non_stop': ('SEA', 'LAX'), ('SEA', 'LAX'): 1, 'legs': [('SEA', 'LAX')]} :param fleet_data: :param passeger_type_dict: passenger_type as key , and it's proportions :param attr_value: :param marketpt_attr_sum: :param solver: :return: time_table, q_variable for each itinerary, """ market_iti = {} #market:itinerary list for m in market_instances_list: l = [ i for i, v in iti_dict.items() if v['market'] == 'M' + str(m.od_pair) ] market_iti.update({m: l}) model = ConcreteModel() market = list(market_data.keys()) #['M' + str(m.od_pair) for m in ] # market_segment={m:[(market_data[m][4],market_data[m][5])] for m in market_data.keys()} model.M = Set(initialize=market, doc='Player Market_obj') model.Mi = Set(list(market_iti.keys()), initialize=market_iti, doc='Player Market_obj') model.AP = Set(initialize=airport_list) model.Segment = Set(initialize=((i, j) for i in model.AP for j in model.AP if i != j)) # create time spot [1-72] and it's time a = np.linspace(1, int((1440 - 360) / 15), int((1440 - 360) / 15)) time_list = np.arange(360, 1440, 15) time_dict = dict(zip(a, time_list)) # reverse_time_dict = {v: k for k, v in time_dict.items()} model.T = Set( initialize=a, ordered=True, doc='Time period from 300 min to 1440 ,step :15min,number:73') model.I = Set(initialize=iti_dict.keys(), doc='itinerary _index,size 4334') model.Im = Set(initialize=((m, i) for m in model.M for i in market_iti[m]), doc='tuple(m,i),size 4334') # 筛选出只在m的itinerary 的 号码 model.PT = Set(initialize=passeger_type_dict.keys()) model.F = Set(initialize=fleet_data.keys()) d = {} #create a dict as which OD and time get all itinerary_index in it for ap1, ap2 in model.Segment: for t in model.T: v = [] for i, va in iti_dict.items(): if (ap1, ap2) in va['legs'] and t == va[(ap1, ap2)]: v.append(i) d[(ap1, ap2, t)] = v model.St = Set( list(d.keys()), initialize=d) # index as (ap1,ap2,time) get [itinerary index list] def _filter3(model, i, m, ap1, ap2, t): return i in model.Mi[m].value and i in model.St[(ap1, ap2, t)].value # def Parameters demand_pt = { } # get demand of pt in the market by total demand times its proportion print("passenger_type_proportion:", passeger_type_dict) for m, va in market_data.items(): for ty, rato in passeger_type_dict.items(): demand_pt.update({(m, ty): va[0] * rato}) # market demand times proportions model.Dem = Param(model.M, model.PT, initialize=demand_pt, doc='Market demand for each type of passenger') price_dict = {} for i in model.I: rato = np.linspace(1.3, 0.7, len(passeger_type_dict)) for index, ty in enumerate(passeger_type_dict): if iti_dict[i]['non_stop']: price_dict.update({ (i, ty): market_data[iti_dict[i]['market']][2] * rato[index] }) # market_data[m][2] is price else: price_dict.update({ (i, ty): 0.8 * market_data[iti_dict[i]['market']][2] * rato[index] }) # market_data[m][2] is price model.p = Param(model.I, model.PT, initialize=price_dict) model.Avail = Param( model.F, initialize={fleet: value[0] for fleet, value in fleet_data.items()}) model.Cap = Param( model.F, initialize={fleet: value[1] for fleet, value in fleet_data.items()}) model.distance = Param(model.Segment, initialize={(value[-2], value[-1]): value[1] for value in market_data.values()}) def ope_cost(model, ap1, ap2, f): if model.distance[ap1, ap2] <= 3106: return (1.6 * model.distance[ap1, ap2] + 722) * (model.Cap[f] + 104) * 0.019 else: return (1.6 * model.distance[ap1, ap2] + 2200) * (model.Cap[f] + 211) * 0.0115 model.Ope = Param(model.Segment, model.F, initialize=ope_cost, doc='cost') freq = {(market_data[m][4], market_data[m][5]): market_data[m][3] for m in market_data.keys()} model.Freq = Param(model.Segment, initialize=freq) model.A = Param(model.I, model.PT, initialize=attr_value) model.Am = Param(model.M, model.PT, initialize=marketpt_attr_sum) # Step 2: Define decision variables model.x = Var(model.Segment, model.F, model.T, within=Binary) model.y_1 = Var(model.F, model.AP, model.T, within=PositiveIntegers) model.y_2 = Var(model.F, model.AP, model.T, within=PositiveIntegers) model.q = Var(model.I, model.PT, within=NonNegativeReals) model.non_q = Var(model.M, model.PT, within=NonNegativeReals ) # number of pax that choose others airine and no fly. # Step 3: Define Objective def obj_rule(model): return sum(model.q[i, pt] * model.p[i, pt] for i in model.I for pt in model.PT) - sum(model.Ope[s, f] * model.x[s, f, t] for s in model.Segment for f in model.F for t in model.T) model.obj = Objective(rule=obj_rule, sense=maximize) def obj_cost(model): return sum(model.Ope[s, f] * model.x[s, f, t] for s in model.Segment for f in model.F for t in model.T) model.obj_cost = Expression(rule=obj_cost) def obj_revenue(model): return sum(model.q[i, pt] * model.p[i, pt] for i in model.I for pt in model.PT) model.obj_revenue = Expression(rule=obj_revenue) # add constraint # Aircraft count: def aircraft_con(model, f): return sum(model.y_1[f, ap, model.T[1]] for ap in model.AP) <= model.Avail[f] model.count = Constraint(model.F, rule=aircraft_con) # flow balance cons def flow_balance_1(model, f, ap): return model.y_1[f, ap, model.T[1]] == model.y_2[f, ap, model.T[-1]] model.con_fb_1 = Constraint(model.F, model.AP, rule=flow_balance_1) def flow_balance_2(model, f, ap, t): # if t == model.T[-1]: # return Constraint.Skip # else: return model.y_1[f, ap, t + 1] == model.y_2[f, ap, t] def filter2(model, t): return t != model.T[-1] model.Tm = Set(initialize=(i for i in model.T if i != model.T[-1])) #model.con_fb_2 = Constraint(model.F, model.AP, model.T, rule=flow_balance_2) model.con_fb_2 = Constraint(model.F, model.AP, model.Tm, rule=flow_balance_2) # time_zone_dict={('ANC', 'PDX'): 60, ('SEA', 'PDX'): 0, ('SEA', 'ANC'): -60, ('ANC', 'LAX'): 60, ('PDX', 'SEA'): 0, ('LAX', 'PDX'): 0, # ('LAX', 'SEA'): 0, ('PDX', 'ANC'): -60, ('SEA', 'LAX'): 0, ('ANC', 'SEA'): 60, ('LAX', 'ANC'): -60, ('PDX', 'LAX'): 0} Travel_time = segment_travel_time def flow_balance_3(model, f, ap, t): def D(s, t, turnaround=30): arrival_time = time_dict[t] dep_time = arrival_time - (Travel_time[s] + turnaround) - time_zone_dict[s] if dep_time >= 360: t0 = ((dep_time - 360) // 15) + 1 else: t0 = 72 - (abs(360 - dep_time) // 15) return t0 return model.y_1[f, ap, t] + sum( model.x[s, f, D(s, t)] for s in model.Segment if s[1] == ap) == model.y_2[f, ap, t] + sum( model.x[s, f, t] for s in model.Segment if s[0] == ap) model.con_fb_3 = Constraint(model.F, model.AP, model.T, rule=flow_balance_3) # Demand and capacity constrains: def attract_con(model, market, i, pt): return model.Am[market, pt] * ( model.q[i, pt] / model.Dem[market, pt]) <= model.A[i, pt] * ( model.non_q[market, pt] / model.Dem[market, pt]) model.attractiveness = Constraint(model.Im, model.PT, rule=attract_con) def capacity_con(model, ap1, ap2, t): return sum(model.q[i, pt] for i in d[(ap1, ap2, t)] for pt in model.PT) <= sum( model.Cap[f] * model.x[ap1, ap2, f, t] for f in model.F) model.con_d1 = Constraint(model.Segment, model.T, rule=capacity_con) def demand_market_con(model, market, pt): return sum(model.q[i, pt] for i in model.I if iti_dict[i]['market'] == market) + model.non_q[market, pt] == \ model.Dem[market, pt] model.con_d3 = Constraint(model.M, model.PT, rule=demand_market_con) # Itinerary selection constraints: model.AC = Set(initialize=model.I * model.M * model.Segment * model.T, filter=_filter3) def iti_selection(model, i, m, ap1, ap2, t, pt): # if i in market_iti[m] and i in d[(ap1, ap2, t)]: return sum(model.x[ap1, ap2, f, t] for f in model.F) >= model.q[i, pt] / model.Dem[m, pt] model.con_iti_selection = Constraint(model.AC, model.PT, rule=iti_selection) # Restrictions on fight leg variables: def flight_leg_con(model, ap1, ap2, t): return sum(model.x[ap1, ap2, f, t] for f in model.F) <= 1 model.con_leg_1 = Constraint(model.Segment, model.T, rule=flight_leg_con) def freq_con(model, ap1, ap2): return sum(model.x[ap1, ap2, f, t] for t in model.T for f in model.F) == model.Freq[ap1, ap2] model.con_let_2 = Constraint(model.Segment, rule=freq_con) print("____" * 5) # for con in model.component_map(Constraint).itervalues(): # con.pprint() SOLVER_NAME = solver TIME_LIMIT = 60 * 60 * 2 results = SolverFactory(SOLVER_NAME) if SOLVER_NAME == 'cplex': results.options['timelimit'] = TIME_LIMIT elif SOLVER_NAME == 'glpk': results.options['tmlim'] = TIME_LIMIT elif SOLVER_NAME == 'gurobi': results.options['TimeLimit'] = TIME_LIMIT com = results.solve(model, tee=True) com.write() #absgap = com.solution(0).gap # get x results in matrix form df_x = pd.DataFrame(columns=list(model.Segment), index=model.T) for s in model.Segment: for t in model.T: for f in model.F: if model.x[s, f, t].value > 0: df_x.loc[t, [s]] = f #df_x=df_x.reset_index()# return value is a dataframe of new time table # 所有的决策变量都遍历一遍 # for v in instance.component_objects(Var, active=True): # print("Variable", v) # varobject = getattr(instance, str(v)) # for index in varobject: # print(" ", index, varobject[index].value) varobject = getattr(model, 'q') q_data = {(i, pt): varobject[(i, pt)].value for (i, pt), v in varobject.items() if varobject[(i, pt)] != 0} df_q = pd.DataFrame.from_dict(q_data, orient="index", columns=["variable value"]) varobject2 = getattr(model, 'non_q') nonq_data = {(m, pt): varobject2[(m, pt)].value for (m, pt), v in varobject2.items() if varobject2[(m, pt)] != 0} # q = list(model.q.get_values().values()) # print('q = ', q) profit = model.obj() print('\nProfit = ', profit) cost = value_s(model.obj_cost()) #revenue=value_s(model.obj_revenue()) print('cost is:' * 10, cost) #print('revenue is:' * 10, revenue) ''' print('\nDecision Variables') #list_of_vars = [v.value for v in model.component_objects(ctype=Var, active=True, descend_into=True)] #var_names = [v.name for v in model.component_objects(ctype=Var, active=True, descend_into=True) if v.value!=0] # print("y=",y) model.obj.display() def pyomo_postprocess( options=None, instance=None, results=None ): model.x.display() pyomo_postprocess(None, model, results) for v in model.component_objects(Var, active=True): print("Variable component object", v) varobject = getattr(model, str(v)) for index in varobject: if varobject[index].value != 0: print(" ", index, varobject[index].value) ''' return df_x, q_data, profit, cost, nonq_data