import json from gurobipy import Model, GRB, quicksum model = Model("OptimizationProblem") with open("data.json", "r") as f: data = json.load(f) # Define the parameters TotalBatteryCapacity = data["TotalBatteryCapacity"] # shape: [], definition: The total capacity of the battery InitialSoc = data["InitialSoc"] # shape: [], definition: Initial state of charge of the battery InitialPg1 = data["InitialPg1"] # shape: [], definition: Initial power of generator 1 InitialPg2 = data["InitialPg2"] # shape: [], definition: Initial power of generator 2 InitialPg3 = data["InitialPg3"] # shape: [], definition: Initial power of generator 3 Price = data["Price"] # shape: [24], definition: Electricity price at each time step Load = data["Load"] # shape: [24], definition: Residential load at each time step Pv = data["Pv"] # shape: [24], definition: Photovoltaic power generation at each time step Wind = data["Wind"] # shape: [24], definition: Wind power generation at each time step # Define the variables Ag1 = model.addVars(24, vtype=GRB.CONTINUOUS, name="Ag1") Ag2 = model.addVars(24, vtype=GRB.CONTINUOUS, name="Ag2") Ag3 = model.addVars(24, vtype=GRB.CONTINUOUS, name="Ag3") PvPower = model.addVars(24, vtype=GRB.CONTINUOUS, name="PvPower") Apv = model.addVars(24, vtype=GRB.CONTINUOUS, name="Apv") Asoc = model.addVars(24, vtype=GRB.CONTINUOUS, name="Asoc") ExcessEnergy = model.addVars(24, vtype=GRB.CONTINUOUS, name="ExcessEnergy") ShortageEnergy = model.addVars(24, vtype=GRB.CONTINUOUS, name="ShortageEnergy") TotalPowerSupply = model.addVars(24, vtype=GRB.CONTINUOUS, name="TotalPowerSupply") GridTransactionLimit = model.addVar(vtype=GRB.FLOAT, name="GridTransactionLimit") # Define the constraints # Loop over each time step to add the soc constraints for t in range(24): # Calculate soc_t based on the previous soc and the adjustment factor soc_t = 0.18 * Asoc[t] + InitialSoc # Add the lower bound constraint for soc_t model.addConstr(soc_t >= 0.2) # Add the upper bound constraint for soc_t model.addConstr(soc_t <= 0.8) # Update soc to the newly calculated soc_t for the next iteration soc = soc_t # Assuming decision variables Pg1[t] have been defined for each time step t for t in range(24): if t == 0: # For the first time step, use the initial value of Pg1 model.addConstr(Pg1[t] <= 150) model.addConstr(Pg1[t] >= 10) else: # For subsequent time steps, calculate Pg1 based on the previous time step and Ag1 model.addConstr(Pg1[t] <= 150) model.addConstr(Pg1[t] >= 10) model.addConstr(Pg1[t] == 100 * Ag1[t] + Pg1[t - 1]) for t in range(1, 24): model.addConstr(InitialPg2 + 100 * Ag2[t] >= 50) model.addConstr(InitialPg2 + 100 * Ag2[t] <= 375) for t in range(24): model.addConstr(Pg3[t] >= 100) # Lower bound constraint for each time step model.addConstr(Pg3[t] <= 500) # Upper bound constraint for each time step # Assuming soc is defined as a list of decision variables for each time step soc = model.addVars(24, lb=0.2, ub=0.8, vtype=GRB.CONTINUOUS, name="soc") # Loop over each time step starting from 1 up to 24 for t in range(1, 24): # Add the constraint for the state of charge calculation model.addConstr(soc[t] == 0.18 * Asoc[t] + soc[t - 1]) for t in range(1, 24): model.addConstr(pg1[t] == 100 * Ag1[t] + pg1[t - 1]) # Assuming that `pg2` is a list of Gurobi variables representing the power of Generator 2 at each time step # and that `InitialPg2` is a parameter representing the initial power of Generator 2 at time step 0 # Define the Generator 2 power for the first time step, which is the initial value and does not have a constraint pg2 = [model.addVar(vtype=GRB.CONTINUOUS, lb=50, ub=375, name="pg2_0")] # Now add the constraints for time steps 1 to 23 for t in range(1, 24): pg2.append(model.addVar(vtype=GRB.CONTINUOUS, lb=50, ub=375, name=f"pg2_{t}")) model.addConstr(pg2[t] == 100 * Ag2[t - 1] + pg2[t - 1]) # Assuming Pg3 is defined as a list of decision variables representing power of generator 3 at each time step for t in range(1, 24): model.addConstr(Pg3[t] == 200 * Ag3[t] + Pg3[t - 1]) for t in range(24): model.addConstr(PvPower[t] == Pv[t] * (1 + Apv[t])) for t in range(24): model.addConstr(ExcessEnergy[t] >= 0) for t in range(24): # Define the total power supply at time step t TotalSupply_t = (InitialPg1 + Ag1[t] * 100 + InitialPg2 + Ag2[t] * 100 + InitialPg3 + Ag3[t] * 200 + Pv[t] * (1 + Apv[t]) + Wind[t] + InitialSoc + Asoc[t] * 0.18) # Add the constraint for excess energy at time step t model.addConstr(ExcessEnergy[t] == TotalSupply_t - Load[t]) for t in range(24): # Calculate updated generator powers and battery state of charge soc_t = InitialSoc + 0.18 * Asoc[t] if t == 0 else soc[t - 1] + 0.18 * Asoc[t] pg1_t = InitialPg1 + 100 * Ag1[t] if t == 0 else pg1[t - 1] + 100 * Ag1[t] pg2_t = InitialPg2 + 100 * Ag2[t] if t == 0 else pg2[t - 1] + 100 * Ag2[t] pg3_t = InitialPg3 + 200 * Ag3[t] if t == 0 else pg3[t - 1] + 200 * Ag3[t] # Calculate photovoltaic power PvPower_t = Pv[t] * (1 + Apv[t]) # Add the constraint for total power supply at time t model.addConstr(TotalPowerSupply[t] == soc_t + pg1_t + pg2_t + pg3_t + PvPower_t + Wind[t]) for t in range(24): model.addConstr(ShortageEnergy[t] >= 0) for t in range(24): model.addConstr(-1 <= Apv[t]) model.addConstr(Apv[t] <= 1) model.addConstr(-1 <= Asoc[t]) model.addConstr(Asoc[t] <= 1) model.addConstr(-1 <= Ag1[t]) model.addConstr(Ag1[t] <= 1) model.addConstr(-1 <= Ag2[t]) model.addConstr(Ag2[t] <= 1) model.addConstr(-1 <= Ag3[t]) model.addConstr(Ag3[t] <= 1) for t in range(1, 24): model.addConstr(100 * Asoc[t] == soc[t] - soc[t - 1]) for t in range(24): # Calculate the power from each generator based on previous state and adjustment pg1_power = InitialPg1 + 100 * Ag1[t] pg2_power = InitialPg2 + 100 * Ag2[t] pg3_power = InitialPg3 + 200 * Ag3[t] # Calculate the adjusted photovoltaic power pv_power = Pv[t] * (1 + Apv[t]) # Express the total power supply TotalPowerSupply[t] = pg1_power + pg2_power + pg3_power + pv_power + Wind[t] # Add the constraint that total power supply cannot exceed the load by more than the grid transaction limit model.addConstr(TotalPowerSupply[t] <= Load[t] + GridTransactionLimit) for t in range(24): # Assuming that Pg1, Pg2, Pg3 are defined as variables in the model with the correct initial values and adjustments Pg1[t] = model.addVar(vtype=GRB.CONTINUOUS, name=f"Pg1_{t}") Pg2[t] = model.addVar(vtype=GRB.CONTINUOUS, name=f"Pg2_{t}") Pg3[t] = model.addVar(vtype=GRB.CONTINUOUS, name=f"Pg3_{t}") # Define the auxiliary constraint for each time step model.addConstr(TotalPowerSupply[t] == Pg1[t] + Pg2[t] + Pg3[t] + PvPower[t] + Wind[t]) # Define the objective model.setObjective( quicksum( (Asoc[t] + 0.1 * soc[t - 1] + 0.0034 * pg1[t - 1] ** 2 + 3 * pg1[t - 1] + 30 + 0.001 * pg2[t - 1] ** 2 + 10 * pg2[t - 1] + 40 + 0.001 * pg3[t - 1] ** 2 + 15 * pg3[t - 1] + 70 + 0.01 * (pv[t - 1] + wind[t - 1]) + max(0, (ExcessEnergy[t] - 100) * 50) + max(0, (ShortageEnergy[t] - 100) * 50) - 0.5 * Price[t - 1] * ExcessEnergy[t] + Price[t - 1] * ShortageEnergy[t] + abs(ExcessEnergy[t]) + abs(ShortageEnergy[t]) ) for t in range(1, 25) ), GRB.MINIMIZE ) # Optimize the model model.optimize() # Output optimal objective value print("Optimal Objective Value: ", model.objVal) if model.status == GRB.OPTIMAL: with open("output_solution.txt", "w") as f: f.write(str(model.objVal)) print("Optimal Objective Value: ", model.objVal) else: with open("output_solution.txt", "w") as f: f.write(model.status)