Compare commits
52 Commits
ca10254c52
...
0.0.6
Author | SHA1 | Date | |
---|---|---|---|
|
9f472b4bf4 | ||
|
127f005dcd | ||
|
c5edf456c5 | ||
|
d8ece46e14 | ||
|
566ebca6cd | ||
|
c8c37b756c | ||
|
4f1a47d505 | ||
|
ad9b5e6a19 | ||
|
33871fba77 | ||
|
9d143399ed | ||
|
72d4ce811e | ||
|
060fa5bff1 | ||
|
ebebd2d481 | ||
|
a330946f71 | ||
|
32e8e59c82 | ||
|
c4ec4590c2 | ||
|
cb0bd2c3e0 | ||
|
4364411485 | ||
|
54dc8b744c | ||
|
d4fde202d0 | ||
|
58a7662a8b | ||
|
d791ac481a | ||
|
4b72bc6fa3 | ||
|
eb24361ea3 | ||
|
fd3bbbf212 | ||
|
760cdc9c1f | ||
|
23826aed75 | ||
|
8cf3d6472c | ||
|
c217b6309c | ||
|
f85fcd58f2 | ||
|
cf7a66276f | ||
|
bf74e87ba0 | ||
|
2788aafbf3 | ||
|
30e8d968f2 | ||
|
8d040e64a0 | ||
|
202d313684 | ||
|
da69e7e24a | ||
|
0f49dba47e | ||
|
f9b7af6feb | ||
|
f51921dd06 | ||
|
06808d55a1 | ||
1679831dbd | |||
651833b521 | |||
3bc2478cd9 | |||
b79ffb2416 | |||
c0a7b5beff | |||
ed58e34e7e | |||
88240280ca | |||
09ef44fc21 | |||
f7afee2a64 | |||
90c96a512a | |||
3cc208035a |
145
EnergySystem.py
Normal file
145
EnergySystem.py
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
from config import pv_config, ess_config, grid_config
|
||||||
|
import pandas as pd
|
||||||
|
class EnergySystem:
|
||||||
|
def __init__(self, pv_type: pv_config, ess_type: ess_config, grid_type: grid_config):
|
||||||
|
self.pv = pv_type
|
||||||
|
self.ess = ess_type
|
||||||
|
self.grid = grid_type
|
||||||
|
self.day_generated = []
|
||||||
|
self.generated = 0
|
||||||
|
self.stored = 0
|
||||||
|
self.hour_stored = []
|
||||||
|
self.hour_stored_2 = []
|
||||||
|
self.afford = True
|
||||||
|
self.cost = self.ess.get_cost() + self.pv.get_cost()
|
||||||
|
self.overload_cnt = 0
|
||||||
|
self.spring_week_gen = []
|
||||||
|
self.summer_week_gen = []
|
||||||
|
self.autumn_week_gen = []
|
||||||
|
self.winter_week_gen = []
|
||||||
|
self.spring_week_soc = []
|
||||||
|
self.summer_week_soc = []
|
||||||
|
self.autumn_week_soc = []
|
||||||
|
self.winter_week_soc = []
|
||||||
|
self.granularity = 4
|
||||||
|
self.season_step = self.granularity * 24 * 7 * 12
|
||||||
|
self.season_start= self.granularity * 24 * 7 * 2
|
||||||
|
self.week_length = self.granularity * 24 * 7
|
||||||
|
self.unmet = []
|
||||||
|
|
||||||
|
def get_cost(self):
|
||||||
|
return self.ess.get_cost()+self.pv.get_cost()
|
||||||
|
|
||||||
|
# 优先使用PV供电给工厂 - 如果PV输出能满足工厂的需求,则直接供电,多余的电能用来给ESS充电。
|
||||||
|
# PV不足时使用ESS补充 - 如果PV输出不足以满足工厂需求,首先从ESS获取所需电量。
|
||||||
|
# 如果ESS也不足以满足需求,再从电网获取 - 当ESS中的存储电量也不足以补充时,再从电网购买剩余所需电量。
|
||||||
|
def simulate(self, data, time_interval):
|
||||||
|
total_benefit = 0
|
||||||
|
total_netto_benefit = 0
|
||||||
|
total_gen = 0
|
||||||
|
for index, row in data.iterrows():
|
||||||
|
time = row['time']
|
||||||
|
# sunlight_intensity = row['sunlight']
|
||||||
|
pv_yield = row['PV yield[kW/kWp]']
|
||||||
|
factory_demand = row['demand']
|
||||||
|
electricity_price = row['buy']
|
||||||
|
sell_price = row['sell']
|
||||||
|
# electricity_price = self.grid.get_price_for_time(time)
|
||||||
|
|
||||||
|
if time == '00:00':
|
||||||
|
self.day_generated.append(self.generated)
|
||||||
|
self.generated = 0
|
||||||
|
if time.endswith('14:00'):
|
||||||
|
soc = self.ess.storage / self.ess.capacity
|
||||||
|
self.hour_stored.append(soc)
|
||||||
|
if time.endswith('08:00'):
|
||||||
|
soc = self.ess.storage / self.ess.capacity
|
||||||
|
self.hour_stored_2.append(soc)
|
||||||
|
|
||||||
|
generated_pv_power = self.pv.capacity * pv_yield# 生成的功率,单位 kW
|
||||||
|
generated_pv_energy = generated_pv_power * time_interval * self.pv.loss # 生成的能量,单位 kWh
|
||||||
|
self.generated += generated_pv_energy
|
||||||
|
# pv生成的能量如果比工厂的需求要大
|
||||||
|
if generated_pv_energy >= factory_demand * time_interval:
|
||||||
|
# 剩余的能量(kwh) = pv生成的能量 - 工厂需求的功率 * 时间间隔
|
||||||
|
surplus_energy = generated_pv_energy - factory_demand * time_interval
|
||||||
|
# 要充到ess中的能量 = min(剩余的能量,ess的充电功率*时间间隔(ess在时间间隔内能充进的电量),ess的容量-ess储存的能量(ess中能冲进去的电量))
|
||||||
|
charge_to_ess = min(surplus_energy, self.ess.charge_power * time_interval, self.ess.capacity - self.ess.storage)
|
||||||
|
self.ess.storage += charge_to_ess
|
||||||
|
surplus_after_ess = surplus_energy - charge_to_ess
|
||||||
|
# 如果还有电量盈余,且pv功率大于ess的充电功率+工厂的需求功率则准备卖电
|
||||||
|
if surplus_after_ess > 0 and generated_pv_power > self.ess.charge_power + factory_demand:
|
||||||
|
sold_to_grid = surplus_after_ess
|
||||||
|
sell_income = sold_to_grid * sell_price
|
||||||
|
total_benefit += sell_income
|
||||||
|
# 节省的能量 = 工厂需求的能量 * 时间段
|
||||||
|
# total_energy = factory_demand * time_interval
|
||||||
|
saved_energy = factory_demand * time_interval
|
||||||
|
# pv比工厂的需求小
|
||||||
|
else:
|
||||||
|
# 从ess中需要的电量 = 工厂需要的电量 - pv中的电量
|
||||||
|
needed_from_ess = factory_demand * time_interval - generated_pv_energy
|
||||||
|
# 如果ess中存的电量比需要的多
|
||||||
|
if self.ess.storage * self.ess.loss >= needed_from_ess:
|
||||||
|
# 取出电量
|
||||||
|
if self.ess.discharge_power * time_interval * self.ess.loss < needed_from_ess:
|
||||||
|
discharging_power = self.ess.discharge_power * time_interval
|
||||||
|
else:
|
||||||
|
discharging_power = needed_from_ess / self.ess.loss
|
||||||
|
|
||||||
|
self.ess.storage -= discharging_power
|
||||||
|
# 节省下来的能量 = pv的能量 + 放出来的能量
|
||||||
|
saved_energy = generated_pv_energy + discharging_power * self.ess.loss
|
||||||
|
else:
|
||||||
|
# 如果存的电量不够
|
||||||
|
# 需要把ess中的所有电量释放出来
|
||||||
|
if self.grid.capacity * time_interval + generated_pv_energy + self.ess.storage * self.ess.loss < factory_demand * time_interval:
|
||||||
|
self.afford = False
|
||||||
|
self.overload_cnt+=1
|
||||||
|
log = f"index: {index}, time: {time}, SoC:{self.ess.storage / self.ess.capacity}%, storage: {self.ess.storage}, pv_gen:{generated_pv_power}, power_demand: {factory_demand}, overload_cnt:{self.overload_cnt}, day:{int(index/96) + 1}"
|
||||||
|
self.unmet.append((index,time,factory_demand,generated_pv_power))
|
||||||
|
# with open(f'plots/summary/ess-{self.ess.capacity}-pv-{self.pv.capacity}', 'a') as f:
|
||||||
|
# f.write(log)
|
||||||
|
# print(log)
|
||||||
|
# self.unmet.append(log)
|
||||||
|
saved_energy = generated_pv_energy + self.ess.storage * self.ess.loss
|
||||||
|
self.ess.storage = 0
|
||||||
|
needed_from_grid = factory_demand * time_interval - saved_energy
|
||||||
|
net_grid = min(self.grid.capacity * time_interval, needed_from_grid) * self.grid.loss
|
||||||
|
# grid_energy += net_grid
|
||||||
|
# total_energy += net_grid
|
||||||
|
# print(total_energy)
|
||||||
|
# 工厂需求量-总能量
|
||||||
|
# unmet_demand = max(0, factory_demand * time_interval - total_energy)
|
||||||
|
# benefit = (total_energy - unmet_demand) * electricity_price
|
||||||
|
total_gen += saved_energy
|
||||||
|
benefit = (saved_energy) * electricity_price
|
||||||
|
cost = net_grid * electricity_price
|
||||||
|
# print(f"time:{time} benefit: {benefit}, cost: {cost}")
|
||||||
|
total_netto_benefit += benefit
|
||||||
|
total_benefit += benefit - cost
|
||||||
|
# # spring
|
||||||
|
week_start = self.season_start
|
||||||
|
week_end = self.week_length + week_start
|
||||||
|
if index in range(week_start, week_end):
|
||||||
|
self.spring_week_gen.append(generated_pv_power)
|
||||||
|
self.spring_week_soc.append(self.ess.storage / self.ess.capacity)
|
||||||
|
# summer
|
||||||
|
# week_start += self.season_step
|
||||||
|
# week_end += self.season_step
|
||||||
|
# if index in range(week_start, week_end):
|
||||||
|
# self.summer_week_gen.append(generated_pv_power)
|
||||||
|
# self.summer_week_soc.append(self.ess.storage / self.ess.capacity)
|
||||||
|
# # autumn
|
||||||
|
# week_start += self.season_step
|
||||||
|
# week_end += self.season_step
|
||||||
|
# if index in range(week_start, week_end):
|
||||||
|
# self.autumn_week_gen.append(generated_pv_power)
|
||||||
|
# self.autumn_week_soc.append(self.ess.storage / self.ess.capacity)
|
||||||
|
# week_start += self.season_step
|
||||||
|
# week_end += self.season_step
|
||||||
|
# if index in range(week_start, week_end):
|
||||||
|
# self.winter_week_gen.append(generated_pv_power)
|
||||||
|
# self.winter_week_soc.append(self.ess.storage / self.ess.capacity)
|
||||||
|
|
||||||
|
return (total_benefit, total_netto_benefit, total_gen)
|
BIN
PV&PowerConsumptionData.xlsx
Normal file
BIN
PV&PowerConsumptionData.xlsx
Normal file
Binary file not shown.
19
README.md
Normal file
19
README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Simple PV Simulator
|
||||||
|
|
||||||
|
Feature list:
|
||||||
|
|
||||||
|
- [] Draw the entire year's electricity consumption figure.
|
||||||
|
- [] Draw the entire year's energy generation figure.
|
||||||
|
- [] Draw a heatmap of the system profit in different configurations.
|
||||||
|
~~- []Calculate the probability of a successful run.~~
|
||||||
|
- [] Determine whether the system can run successfully
|
||||||
|
- [] Calculate the ROI.
|
||||||
|
- [] Read the configs from the file, including `time granularity`,
|
||||||
|
- ess: `capacity`, `cost per kW`, `charge power`, `discharge power`, `loss`
|
||||||
|
- pv: `capacity`, `cost per kW`, `loss`
|
||||||
|
- grid: `capacity`, `sell price`
|
||||||
|
- file:
|
||||||
|
- `lightintensity.xlsx`: record the light intensity. Value in the file should be between 0 and 1
|
||||||
|
- `factory_power.xlsx`: record the power consumption in the factory. Default time granularity is `15min`
|
||||||
|
- `combined_data.csv`: This file is generated by the Python script, including the `light` `intensity`, `factory_power`, `time`.
|
||||||
|
- [] GUI.
|
BIN
__pycache__/EnergySystem.cpython-311.pyc
Normal file
BIN
__pycache__/EnergySystem.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/config.cpython-311.pyc
Normal file
BIN
__pycache__/config.cpython-311.pyc
Normal file
Binary file not shown.
35041
combined_data.csv
Normal file
35041
combined_data.csv
Normal file
File diff suppressed because it is too large
Load Diff
47
config.json
Normal file
47
config.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"pv":{
|
||||||
|
"loss": 0.98,
|
||||||
|
"cost_per_kW": 200,
|
||||||
|
"lifetime": 15
|
||||||
|
},
|
||||||
|
"ess":{
|
||||||
|
"loss": 0.98,
|
||||||
|
"cost_per_kW": 300,
|
||||||
|
"lifetime": 8
|
||||||
|
},
|
||||||
|
"grid":{
|
||||||
|
"loss": 0.98,
|
||||||
|
"sell_price": 0.2 ,
|
||||||
|
"capacity": 5000
|
||||||
|
},
|
||||||
|
"pv_capacities":{
|
||||||
|
"begin": 0,
|
||||||
|
"end": 50000,
|
||||||
|
"groups": 11
|
||||||
|
},
|
||||||
|
"ess_capacities":{
|
||||||
|
"begin": 0,
|
||||||
|
"end": 100000,
|
||||||
|
"groups": 11
|
||||||
|
},
|
||||||
|
"time_interval":{
|
||||||
|
"numerator": 15,
|
||||||
|
"denominator": 60
|
||||||
|
},
|
||||||
|
"annotated": {
|
||||||
|
"unmet_prob": false,
|
||||||
|
"benefit": false,
|
||||||
|
"cost": false,
|
||||||
|
"roi": false
|
||||||
|
},
|
||||||
|
"figure_size":{
|
||||||
|
"height": 9,
|
||||||
|
"length": 10
|
||||||
|
},
|
||||||
|
"plot_title":{
|
||||||
|
"unmet_prob": "Coverage Rate of Factory Electrical Demands",
|
||||||
|
"cost": "Costs of Microgrid system [m-EUR]",
|
||||||
|
"benefit": "Financial Profit Based on Py & Ess Configuration (k-EUR / year)",
|
||||||
|
"roi": "ROI"
|
||||||
|
}
|
||||||
|
}
|
29
config.py
29
config.py
@@ -1,23 +1,34 @@
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
class pv_config:
|
class pv_config:
|
||||||
def __init__(self, capacity, cost_per_kW, pv_lifetime, pv_loss):
|
def __init__(self, capacity, cost_per_kW, lifetime, loss):
|
||||||
self.capacity = capacity
|
self.capacity = capacity
|
||||||
self.cost_per_kW = cost_per_kW
|
self.cost_per_kW = cost_per_kW
|
||||||
self.pv_lifetime = pv_lifetime
|
self.lifetime = lifetime
|
||||||
self.pv_loss = pv_loss
|
self.loss = loss
|
||||||
|
def get_cost(self):
|
||||||
|
return self.capacity * self.cost_per_kW
|
||||||
|
def get_cost_per_year(self):
|
||||||
|
return self.capacity * self.cost_per_kW / self.lifetime
|
||||||
class ess_config:
|
class ess_config:
|
||||||
def __init__(self, capacity, cost_per_kW, ess_lifetime, ess_loss, charge_power, discharge_power):
|
def __init__(self, capacity, cost_per_kW, lifetime, loss, charge_power, discharge_power):
|
||||||
self.capacity = capacity
|
self.capacity = capacity
|
||||||
self.cost_per_kW = cost_per_kW
|
self.cost_per_kW = cost_per_kW
|
||||||
self.ess_lifetime = ess_lifetime
|
self.lifetime = lifetime
|
||||||
self.ess_loss = ess_loss
|
self.loss = loss
|
||||||
self.ess_storage = 0
|
self.storage = 0
|
||||||
self.charge_power = charge_power
|
self.charge_power = charge_power
|
||||||
self.discharge_power = discharge_power
|
self.discharge_power = discharge_power
|
||||||
|
def get_cost(self):
|
||||||
|
return self.capacity * self.cost_per_kW
|
||||||
|
def get_cost_per_year(self):
|
||||||
|
return self.capacity * self.cost_per_kW / self.lifetime
|
||||||
|
|
||||||
class grid_config:
|
class grid_config:
|
||||||
def __init__(self, price_schedule, grid_loss):
|
def __init__(self, capacity, grid_loss, sell_price):
|
||||||
self.price_schedule = price_schedule
|
# self.price_schedule = price_schedule
|
||||||
|
self.loss = grid_loss
|
||||||
|
self.sell_price = sell_price
|
||||||
|
self.capacity = capacity
|
||||||
|
|
||||||
def get_price_for_time(self, time):
|
def get_price_for_time(self, time):
|
||||||
hour, minute = map(int, time.split(':'))
|
hour, minute = map(int, time.split(':'))
|
||||||
|
11
convert.py
Normal file
11
convert.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import nbformat
|
||||||
|
from nbconvert import PythonExporter
|
||||||
|
|
||||||
|
with open('main.ipynb', "r", encoding="utf-8") as f:
|
||||||
|
notebook = nbformat.read(f, as_version = 4)
|
||||||
|
|
||||||
|
exporter = PythonExporter()
|
||||||
|
python_code, _ = exporter.from_notebook_node(notebook)
|
||||||
|
|
||||||
|
with open('main.py', "w", encoding="utf-8") as f:
|
||||||
|
f.write(python_code)
|
209
draw.py
Normal file
209
draw.py
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.ticker as ticker
|
||||||
|
from matplotlib.ticker import FuncFormatter
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import seaborn as sns
|
||||||
|
import json
|
||||||
|
from matplotlib.colors import LinearSegmentedColormap
|
||||||
|
|
||||||
|
def read_data(file_name: str):
|
||||||
|
with open(file_name, 'r') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
for key, value in data.items():
|
||||||
|
for subkey, subvalue in value.items():
|
||||||
|
data[key][subkey] = float(subvalue)
|
||||||
|
df = pd.DataFrame.from_dict(data, orient='index')
|
||||||
|
df = df.T
|
||||||
|
df.index = pd.to_numeric(df.index)
|
||||||
|
df.columns = pd.to_numeric(df.columns)
|
||||||
|
return df
|
||||||
|
|
||||||
|
def draw_results(results, filename, title_benefit, annot_benefit=False, figure_size=(10, 10)):
|
||||||
|
df=results
|
||||||
|
df = df.astype(float)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
min_value = df.min().min()
|
||||||
|
max_value = df.max().max()
|
||||||
|
max_scale = max(abs(min_value/1000), abs(max_value/1000))
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x,pos):
|
||||||
|
return '{:.0f}'.format(x/1000)
|
||||||
|
|
||||||
|
cmap = sns.color_palette("coolwarm", as_cmap=True)
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
ax = sns.heatmap(df/1000, fmt=".1f", cmap=cmap, vmin=-max_scale, vmax=max_scale, annot=annot_benefit)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
plt.title(title_benefit)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
def draw_cost(costs, filename, title_cost, annot_cost=False, figure_size=(10, 10)):
|
||||||
|
df = costs
|
||||||
|
df = df.astype(int)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x, pos):
|
||||||
|
return '{:.0f}'.format(x / 1000000)
|
||||||
|
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
ax = sns.heatmap(df/1000000, fmt=".1f", cmap='viridis', annot=annot_cost)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
plt.title(title_cost)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_overload(overload_cnt, filename, title_unmet, annot_unmet=False, figure_size=(10, 10)):
|
||||||
|
df = overload_cnt
|
||||||
|
df = (4 * 24 * 365 - df) / (4 * 24 * 365)
|
||||||
|
df = df.astype(float)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
min_value = df.min().min()
|
||||||
|
max_value = df.max().max()
|
||||||
|
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
# print(new_Data)
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
|
||||||
|
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
cmap = LinearSegmentedColormap.from_list("", ["white", "blue"])
|
||||||
|
ax = sns.heatmap(df, fmt=".00%", cmap=cmap, vmin=0, vmax=1, annot=annot_unmet)
|
||||||
|
|
||||||
|
cbar = ax.collections[0].colorbar
|
||||||
|
cbar.set_ticks([0, 0.25, 0.5, 0.75, 1])
|
||||||
|
cbar.set_ticklabels(['0%', '25%', '50%', '75%', '100%'])
|
||||||
|
cbar.ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: f'{x:.0%}'))
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x, pos):
|
||||||
|
return '{:.0f}%'.format(x * 100)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.title(title_unmet)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
with open('config.json', 'r') as f:
|
||||||
|
js_data = json.load(f)
|
||||||
|
|
||||||
|
data = pd.read_csv('combined_data.csv')
|
||||||
|
time_interval = js_data["time_interval"]["numerator"] / js_data["time_interval"]["denominator"]
|
||||||
|
|
||||||
|
pv_loss = js_data["pv"]["loss"]
|
||||||
|
pv_cost_per_kW = js_data["pv"]["cost_per_kW"]
|
||||||
|
pv_lifetime = js_data["pv"]["lifetime"]
|
||||||
|
|
||||||
|
ess_loss = js_data["ess"]["loss"]
|
||||||
|
ess_cost_per_kW = js_data["ess"]["cost_per_kW"]
|
||||||
|
ess_lifetime = js_data["ess"]["lifetime"]
|
||||||
|
|
||||||
|
grid_loss = js_data["grid"]["loss"]
|
||||||
|
sell_price = js_data["grid"]["sell_price"]
|
||||||
|
grid_capacity = js_data["grid"]["capacity"]
|
||||||
|
|
||||||
|
pv_begin = js_data["pv_capacities"]["begin"]
|
||||||
|
pv_end = js_data["pv_capacities"]["end"]
|
||||||
|
pv_groups = js_data["pv_capacities"]["groups"]
|
||||||
|
|
||||||
|
ess_begin = js_data["ess_capacities"]["begin"]
|
||||||
|
ess_end = js_data["ess_capacities"]["end"]
|
||||||
|
ess_groups = js_data["ess_capacities"]["groups"]
|
||||||
|
|
||||||
|
annot_unmet = js_data["annotated"]["unmet_prob"]
|
||||||
|
annot_benefit = js_data["annotated"]["benefit"]
|
||||||
|
annot_cost = js_data["annotated"]["cost"]
|
||||||
|
|
||||||
|
title_unmet = js_data["plot_title"]["unmet_prob"]
|
||||||
|
title_cost = js_data["plot_title"]["cost"]
|
||||||
|
title_benefit = js_data["plot_title"]["benefit"]
|
||||||
|
|
||||||
|
figure_size = (js_data["figure_size"]["length"], js_data["figure_size"]["height"])
|
||||||
|
|
||||||
|
directory = 'data/'
|
||||||
|
|
||||||
|
file_list = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))]
|
||||||
|
|
||||||
|
|
||||||
|
split_files = [f.split('-') for f in file_list]
|
||||||
|
|
||||||
|
costs_files = [f for f in split_files if f[-1].endswith('costs.json')]
|
||||||
|
print(f'find costs files: {costs_files}')
|
||||||
|
overload_files = [f for f in split_files if f[-1].endswith('overload_cnt.json')]
|
||||||
|
print(f'find coverage/unmet files: {overload_files}')
|
||||||
|
results_files = [f for f in split_files if f[-1].endswith('results.json')]
|
||||||
|
print(f'find profit/benefit files: {results_files}')
|
||||||
|
|
||||||
|
costs_dfs = [read_data(directory + '-'.join(f)) for f in costs_files]
|
||||||
|
overload_dfs = [read_data(directory + '-'.join(f)) for f in overload_files]
|
||||||
|
results_dfs = [read_data(directory + '-'.join(f)) for f in results_files]
|
||||||
|
|
||||||
|
for costs_df, overload_df, results_df in zip(costs_dfs, overload_dfs, results_dfs):
|
||||||
|
|
||||||
|
draw_cost(costs_df,
|
||||||
|
f'plots/costs-ess-{int(costs_df.columns[0])}-{int(costs_df.columns[-1])}-pv-{int(costs_df.index[0])}-{int(costs_df.index[-1])}.png',
|
||||||
|
title_cost=title_cost,
|
||||||
|
annot_cost=annot_cost)
|
||||||
|
|
||||||
|
draw_overload(overload_df,
|
||||||
|
f'plots/overload-ess-{overload_df.columns[0]}-{overload_df.columns[-1]}-pv-{overload_df.index[0]}-{overload_df.index[-1]}.png',
|
||||||
|
title_unmet=title_unmet,
|
||||||
|
annot_unmet=False)
|
||||||
|
|
||||||
|
draw_results(results_df,
|
||||||
|
f'plots/results-ess-{results_df.columns[0]}-{results_df.columns[-1]}-pv-{results_df.index[0]}-{results_df.index[-1]}.png',
|
||||||
|
title_benefit=title_benefit,
|
||||||
|
annot_benefit=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
BIN
factory_power.xlsx
Normal file
BIN
factory_power.xlsx
Normal file
Binary file not shown.
BIN
factory_power1.xlsx
Normal file
BIN
factory_power1.xlsx
Normal file
Binary file not shown.
BIN
lightintensity.xlsx
Normal file
BIN
lightintensity.xlsx
Normal file
Binary file not shown.
534
main.ipynb
Normal file
534
main.ipynb
Normal file
@@ -0,0 +1,534 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import os\n",
|
||||||
|
"import glob\n",
|
||||||
|
"import shutil\n",
|
||||||
|
"import matplotlib.pyplot as plt\n",
|
||||||
|
"import matplotlib.ticker as ticker\n",
|
||||||
|
"from matplotlib.ticker import FuncFormatter\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"import pandas as pd\n",
|
||||||
|
"import os\n",
|
||||||
|
"import seaborn as sns\n",
|
||||||
|
"import json\n",
|
||||||
|
"from matplotlib.colors import LinearSegmentedColormap\n",
|
||||||
|
"\n",
|
||||||
|
"def clear_folder_make_ess_pv(folder_path):\n",
|
||||||
|
" if os.path.isdir(folder_path):\n",
|
||||||
|
" shutil.rmtree(folder_path)\n",
|
||||||
|
" os.makedirs(folder_path)\n",
|
||||||
|
" os.makedirs(os.path.join(folder_path,'ess'))\n",
|
||||||
|
" os.makedirs(os.path.join(folder_path,'pv'))\n",
|
||||||
|
"\n",
|
||||||
|
"folder_path = 'plots'\n",
|
||||||
|
"clear_folder_make_ess_pv(folder_path)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import matplotlib.pyplot as plt\n",
|
||||||
|
"import seaborn as sns\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"import pandas as pd\n",
|
||||||
|
"from EnergySystem import EnergySystem\n",
|
||||||
|
"from config import pv_config, grid_config, ess_config\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import json\n",
|
||||||
|
"\n",
|
||||||
|
"print(\"Version 0.0.5\")\n",
|
||||||
|
"\n",
|
||||||
|
"with open('config.json', 'r') as f:\n",
|
||||||
|
" js_data = json.load(f)\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
" \n",
|
||||||
|
"\n",
|
||||||
|
"time_interval = js_data[\"time_interval\"][\"numerator\"] / js_data[\"time_interval\"][\"denominator\"]\n",
|
||||||
|
"print(time_interval)\n",
|
||||||
|
"\n",
|
||||||
|
"pv_loss = js_data[\"pv\"][\"loss\"]\n",
|
||||||
|
"pv_cost_per_kW = js_data[\"pv\"][\"cost_per_kW\"]\n",
|
||||||
|
"pv_lifetime = js_data[\"pv\"][\"lifetime\"]\n",
|
||||||
|
"\n",
|
||||||
|
"ess_loss = js_data[\"ess\"][\"loss\"]\n",
|
||||||
|
"ess_cost_per_kW = js_data[\"ess\"][\"cost_per_kW\"]\n",
|
||||||
|
"ess_lifetime = js_data[\"ess\"][\"lifetime\"]\n",
|
||||||
|
"\n",
|
||||||
|
"grid_loss = js_data[\"grid\"][\"loss\"]\n",
|
||||||
|
"sell_price = js_data[\"grid\"][\"sell_price\"] #kWh\n",
|
||||||
|
"grid_capacity = js_data[\"grid\"][\"capacity\"] #kWh\n",
|
||||||
|
"\n",
|
||||||
|
"pv_begin = js_data[\"pv_capacities\"][\"begin\"]\n",
|
||||||
|
"pv_end = js_data[\"pv_capacities\"][\"end\"]\n",
|
||||||
|
"pv_groups = js_data[\"pv_capacities\"][\"groups\"]\n",
|
||||||
|
"\n",
|
||||||
|
"ess_begin = js_data[\"ess_capacities\"][\"begin\"]\n",
|
||||||
|
"ess_end = js_data[\"ess_capacities\"][\"end\"]\n",
|
||||||
|
"ess_groups = js_data[\"ess_capacities\"][\"groups\"]\n",
|
||||||
|
"\n",
|
||||||
|
"annot_unmet = js_data[\"annotated\"][\"unmet_prob\"]\n",
|
||||||
|
"annot_benefit = js_data[\"annotated\"][\"benefit\"]\n",
|
||||||
|
"annot_cost = js_data[\"annotated\"][\"cost\"]\n",
|
||||||
|
"annot_roi = js_data[\"annotated\"][\"roi\"]\n",
|
||||||
|
"\n",
|
||||||
|
"title_unmet = js_data[\"plot_title\"][\"unmet_prob\"]\n",
|
||||||
|
"title_cost = js_data[\"plot_title\"][\"cost\"]\n",
|
||||||
|
"title_benefit = js_data[\"plot_title\"][\"benefit\"]\n",
|
||||||
|
"title_roi = js_data[\"plot_title\"][\"roi\"]\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"figure_size = (js_data[\"figure_size\"][\"length\"], js_data[\"figure_size\"][\"height\"])\n",
|
||||||
|
"\n",
|
||||||
|
"data = pd.read_csv('combined_data.csv')\n",
|
||||||
|
"\n",
|
||||||
|
"granularity = js_data[\"time_interval\"][\"numerator\"]\n",
|
||||||
|
"\n",
|
||||||
|
"months_days = [31,28,31,30,31,30,31,31,30,31,30,31]\n",
|
||||||
|
"def get_month_coe(num, granularity):\n",
|
||||||
|
" return 60 / granularity * 24 * months_days[num]\n",
|
||||||
|
"\n",
|
||||||
|
"months_index = [get_month_coe(num, granularity) for num in range(12)]\n",
|
||||||
|
"months_data = []\n",
|
||||||
|
"for i in range(1,12):\n",
|
||||||
|
" months_index[i] += months_index[i-1]\n",
|
||||||
|
"for i in range(12):\n",
|
||||||
|
" start = 0 if i == 0 else months_index[i-1]\n",
|
||||||
|
" end = months_index[i]\n",
|
||||||
|
" months_data.append(data.iloc[int(start):int(end)])\n",
|
||||||
|
" \n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"pv_capacities = np.linspace(pv_begin, pv_end, pv_groups)\n",
|
||||||
|
"ess_capacities = np.linspace(ess_begin, ess_end, ess_groups)\n",
|
||||||
|
"# results = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
"# affords = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
"# costs = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
"# overload_cnt = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"hour_demand = []\n",
|
||||||
|
"for index, row in data.iterrows():\n",
|
||||||
|
" time = row['time']\n",
|
||||||
|
" demand = row['demand']\n",
|
||||||
|
" if time.endswith('00'):\n",
|
||||||
|
" hour_demand.append(demand)\n",
|
||||||
|
"plt.figure(figsize=(10,8))\n",
|
||||||
|
"plt.plot(hour_demand)\n",
|
||||||
|
"plt.ylabel('Demand Power / kW')\n",
|
||||||
|
"plt.savefig('plots/demand.png')\n",
|
||||||
|
"plt.close()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def draw_results(results, filename, title_benefit, annot_benefit=False, figure_size=(10, 10)):\n",
|
||||||
|
" df=results\n",
|
||||||
|
" df = df.astype(float)\n",
|
||||||
|
" df.index = df.index / 1000\n",
|
||||||
|
" df.index = df.index.map(int)\n",
|
||||||
|
" df.columns = df.columns / 1000\n",
|
||||||
|
" df.columns = df.columns.map(int)\n",
|
||||||
|
" min_value = df.min().min()\n",
|
||||||
|
" max_value = df.max().max()\n",
|
||||||
|
" max_scale = max(abs(min_value/1000), abs(max_value/1000))\n",
|
||||||
|
"\n",
|
||||||
|
" df[df.columns[-1] + 1] = df.iloc[:, -1] \n",
|
||||||
|
" new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)\n",
|
||||||
|
" for i in df.columns:\n",
|
||||||
|
" new_Data[i] = df[i].iloc[-1]\n",
|
||||||
|
" df = pd.concat([df, new_Data])\n",
|
||||||
|
"\n",
|
||||||
|
" X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))\n",
|
||||||
|
"\n",
|
||||||
|
" def fmt(x,pos):\n",
|
||||||
|
" return '{:.0f}'.format(x/1000)\n",
|
||||||
|
"\n",
|
||||||
|
" cmap = sns.color_palette(\"coolwarm\", as_cmap=True)\n",
|
||||||
|
" plt.figure(figsize=figure_size)\n",
|
||||||
|
" ax = sns.heatmap(df/1000, fmt=\".1f\", cmap=cmap, vmin=-max_scale, vmax=max_scale, annot=annot_benefit)\n",
|
||||||
|
" CS = ax.contour(X, Y, df, colors='black', alpha=0.5)\n",
|
||||||
|
" ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))\n",
|
||||||
|
" plt.title(title_benefit)\n",
|
||||||
|
" plt.gca().invert_yaxis()\n",
|
||||||
|
" plt.xlim(0, df.shape[1] - 1)\n",
|
||||||
|
" plt.ylim(0, df.shape[0] - 1)\n",
|
||||||
|
" plt.xlabel('ESS Capacity (MWh)')\n",
|
||||||
|
" plt.ylabel('PV Capacity (MW)')\n",
|
||||||
|
" plt.savefig(filename)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def draw_roi(costs, results, filename, title_roi, days=365, annot_roi=False, figure_size=(10, 10)):\n",
|
||||||
|
" costs = costs.astype(float)\n",
|
||||||
|
" costs = costs / 365 \n",
|
||||||
|
" costs = costs * days\n",
|
||||||
|
"\n",
|
||||||
|
" df = results\n",
|
||||||
|
" df = costs / df\n",
|
||||||
|
" if 0 in df.index and 0 in df.columns:\n",
|
||||||
|
" df.loc[0,0] = 100\n",
|
||||||
|
" df[df > 80] = 100\n",
|
||||||
|
" print(df)\n",
|
||||||
|
"\n",
|
||||||
|
" df = df.astype(float)\n",
|
||||||
|
" df.index = df.index / 1000\n",
|
||||||
|
" df.index = df.index.map(int)\n",
|
||||||
|
" df.columns = df.columns / 1000\n",
|
||||||
|
" df.columns = df.columns.map(int)\n",
|
||||||
|
" min_value = df.min().min()\n",
|
||||||
|
" max_value = df.max().max()\n",
|
||||||
|
" print(max_value)\n",
|
||||||
|
" max_scale = max(abs(min_value), abs(max_value))\n",
|
||||||
|
"\n",
|
||||||
|
" df[df.columns[-1] + 1] = df.iloc[:, -1] \n",
|
||||||
|
" new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)\n",
|
||||||
|
" for i in df.columns:\n",
|
||||||
|
" new_Data[i] = df[i].iloc[-1]\n",
|
||||||
|
" df = pd.concat([df, new_Data])\n",
|
||||||
|
"\n",
|
||||||
|
" X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))\n",
|
||||||
|
"\n",
|
||||||
|
" def fmt(x,pos):\n",
|
||||||
|
" return '{:.0f}'.format(x)\n",
|
||||||
|
"\n",
|
||||||
|
" cmap = sns.color_palette(\"Greys\", as_cmap=True)\n",
|
||||||
|
" plt.figure(figsize=figure_size)\n",
|
||||||
|
" ax = sns.heatmap(df, fmt=\".1f\", cmap=cmap, vmin=0, vmax=100, annot=annot_benefit)\n",
|
||||||
|
" CS = ax.contour(X, Y, df, colors='black', alpha=0.5)\n",
|
||||||
|
" ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))\n",
|
||||||
|
" plt.title(title_roi)\n",
|
||||||
|
" plt.gca().invert_yaxis()\n",
|
||||||
|
" plt.xlim(0, df.shape[1] - 1)\n",
|
||||||
|
" plt.ylim(0, df.shape[0] - 1)\n",
|
||||||
|
" plt.xlabel('ESS Capacity (MWh)')\n",
|
||||||
|
" plt.ylabel('PV Capacity (MW)')\n",
|
||||||
|
" plt.savefig(filename)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def draw_cost(costs, filename, title_cost, annot_cost=False, figure_size=(10, 10)):\n",
|
||||||
|
" df = costs\n",
|
||||||
|
" df = df.astype(int)\n",
|
||||||
|
" df.index = df.index / 1000\n",
|
||||||
|
" df.index = df.index.map(int)\n",
|
||||||
|
" df.columns = df.columns / 1000\n",
|
||||||
|
" df.columns = df.columns.map(int)\n",
|
||||||
|
"\n",
|
||||||
|
" df[df.columns[-1] + 1] = df.iloc[:, -1] \n",
|
||||||
|
" new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)\n",
|
||||||
|
" for i in df.columns:\n",
|
||||||
|
" new_Data[i] = df[i].iloc[-1]\n",
|
||||||
|
" df = pd.concat([df, new_Data])\n",
|
||||||
|
" X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))\n",
|
||||||
|
"\n",
|
||||||
|
" def fmt(x, pos):\n",
|
||||||
|
" return '{:.0f}'.format(x / 1000000)\n",
|
||||||
|
"\n",
|
||||||
|
" plt.figure(figsize=figure_size)\n",
|
||||||
|
" ax = sns.heatmap(df/1000000, fmt=\".1f\", cmap='viridis', annot=annot_cost)\n",
|
||||||
|
" CS = ax.contour(X, Y, df, colors='black', alpha=0.5)\n",
|
||||||
|
" ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))\n",
|
||||||
|
" plt.title(title_cost)\n",
|
||||||
|
" plt.gca().invert_yaxis()\n",
|
||||||
|
" plt.xlim(0, df.shape[1] - 1)\n",
|
||||||
|
" plt.ylim(0, df.shape[0] - 1)\n",
|
||||||
|
" plt.xlabel('ESS Capacity (MWh)')\n",
|
||||||
|
" plt.ylabel('PV Capacity (MW)')\n",
|
||||||
|
" plt.savefig(filename)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def draw_overload(overload_cnt, filename, title_unmet, annot_unmet=False, figure_size=(10, 10), days=365, granularity=15):\n",
|
||||||
|
" df = overload_cnt\n",
|
||||||
|
" print(days, granularity)\n",
|
||||||
|
" coef = 60 / granularity * days * 24\n",
|
||||||
|
" print(coef)\n",
|
||||||
|
" print(df)\n",
|
||||||
|
" df = ( coef - df) / coef\n",
|
||||||
|
" print(df)\n",
|
||||||
|
"\n",
|
||||||
|
" df = df.astype(float)\n",
|
||||||
|
" df.index = df.index / 1000\n",
|
||||||
|
" df.index = df.index.map(int)\n",
|
||||||
|
" df.columns = df.columns / 1000\n",
|
||||||
|
" df.columns = df.columns.map(int)\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
" df[df.columns[-1] + 1] = df.iloc[:, -1] \n",
|
||||||
|
" new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)\n",
|
||||||
|
" for i in df.columns:\n",
|
||||||
|
" new_Data[i] = df[i].iloc[-1]\n",
|
||||||
|
" # print(new_Data)\n",
|
||||||
|
" df = pd.concat([df, new_Data])\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
" plt.figure(figsize=figure_size)\n",
|
||||||
|
" cmap = LinearSegmentedColormap.from_list(\"\", [\"white\", \"blue\"])\n",
|
||||||
|
" ax = sns.heatmap(df, fmt=\".00%\", cmap=cmap, vmin=0, vmax=1, annot=annot_unmet)\n",
|
||||||
|
"\n",
|
||||||
|
" cbar = ax.collections[0].colorbar\n",
|
||||||
|
" cbar.set_ticks([0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1])\n",
|
||||||
|
" cbar.set_ticklabels(['0%', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%'])\n",
|
||||||
|
" cbar.ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: f'{x:.0%}'))\n",
|
||||||
|
" X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))\n",
|
||||||
|
"\n",
|
||||||
|
" def fmt(x, pos):\n",
|
||||||
|
" return '{:.0f}%'.format(x * 100)\n",
|
||||||
|
" CS = ax.contour(X, Y, df, colors='black', alpha=0.5)\n",
|
||||||
|
"\n",
|
||||||
|
" ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))\n",
|
||||||
|
"\n",
|
||||||
|
" plt.xlim(0, df.shape[1] - 1)\n",
|
||||||
|
" plt.ylim(0, df.shape[0] - 1)\n",
|
||||||
|
" plt.title(title_unmet)\n",
|
||||||
|
" plt.xlabel('ESS Capacity (MWh)')\n",
|
||||||
|
" plt.ylabel('PV Capacity (MW)')\n",
|
||||||
|
" plt.savefig(filename)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def cal_profit(es: EnergySystem, saved_money, days):\n",
|
||||||
|
" profit = saved_money - es.ess.get_cost_per_year() / 365 * days - es.pv.get_cost_per_year() / 365 * days\n",
|
||||||
|
" return profit"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def generate_data(pv_capacity, pv_cost_per_kW, pv_lifetime, pv_loss, ess_capacity, ess_cost_per_kW, ess_lifetime, ess_loss, grid_capacity, grid_loss, sell_price, time_interval, data, days):\n",
|
||||||
|
" pv = pv_config(capacity=pv_capacity, \n",
|
||||||
|
" cost_per_kW=pv_cost_per_kW,\n",
|
||||||
|
" lifetime=pv_lifetime, \n",
|
||||||
|
" loss=pv_loss)\n",
|
||||||
|
" ess = ess_config(capacity=ess_capacity, \n",
|
||||||
|
" cost_per_kW=ess_cost_per_kW, \n",
|
||||||
|
" lifetime=ess_lifetime, \n",
|
||||||
|
" loss=ess_loss,\n",
|
||||||
|
" charge_power=ess_capacity,\n",
|
||||||
|
" discharge_power=ess_capacity)\n",
|
||||||
|
" grid = grid_config(capacity=grid_capacity, \n",
|
||||||
|
" grid_loss=grid_loss,\n",
|
||||||
|
" sell_price= sell_price)\n",
|
||||||
|
" energySystem = EnergySystem(pv_type=pv, \n",
|
||||||
|
" ess_type=ess, \n",
|
||||||
|
" grid_type= grid)\n",
|
||||||
|
" (benefit, netto_benefit, gen_energy) = energySystem.simulate(data, time_interval)\n",
|
||||||
|
" results = cal_profit(energySystem, benefit, days)\n",
|
||||||
|
" overload_cnt = energySystem.overload_cnt\n",
|
||||||
|
" costs = energySystem.ess.capacity * energySystem.ess.cost_per_kW + energySystem.pv.capacity * energySystem.pv.cost_per_kW\n",
|
||||||
|
" return (results, overload_cnt, costs, netto_benefit, gen_energy, energySystem.generated)\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"months_results = []\n",
|
||||||
|
"months_costs = []\n",
|
||||||
|
"months_overload = []\n",
|
||||||
|
"months_nettos = []\n",
|
||||||
|
"months_gen_energy = []\n",
|
||||||
|
"months_gen_energy2 = []\n",
|
||||||
|
"for index, month_data in enumerate(months_data):\n",
|
||||||
|
" results = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
" costs = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
" overload_cnt = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
" nettos = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
" gen_energies = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
" gen_energies2 = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
" for pv_capacity in pv_capacities:\n",
|
||||||
|
" for ess_capacity in ess_capacities:\n",
|
||||||
|
" (result, overload, cost, netto, gen_energy, gen_energy2) = generate_data(pv_capacity=pv_capacity,pv_cost_per_kW=pv_cost_per_kW, pv_lifetime=pv_lifetime, pv_loss=pv_loss, ess_capacity=ess_capacity, ess_cost_per_kW=ess_cost_per_kW, ess_lifetime=ess_lifetime, ess_loss=ess_loss, grid_capacity=grid_capacity, grid_loss=grid_loss, sell_price=sell_price, time_interval=time_interval, data=month_data, days=months_days[index])\n",
|
||||||
|
" results.loc[pv_capacity,ess_capacity] = result\n",
|
||||||
|
" overload_cnt.loc[pv_capacity,ess_capacity] = overload\n",
|
||||||
|
" costs.loc[pv_capacity,ess_capacity] = cost\n",
|
||||||
|
" nettos.loc[pv_capacity,ess_capacity] = netto\n",
|
||||||
|
" gen_energies.loc[pv_capacity, ess_capacity] = gen_energy\n",
|
||||||
|
" gen_energies2.loc[pv_capacity, ess_capacity] = gen_energy2\n",
|
||||||
|
" months_results.append(results)\n",
|
||||||
|
" months_costs.append(costs)\n",
|
||||||
|
" months_overload.append(overload_cnt)\n",
|
||||||
|
" months_nettos.append(nettos)\n",
|
||||||
|
" months_gen_energy.append(gen_energies)\n",
|
||||||
|
" months_gen_energy2.append(gen_energies2)\n",
|
||||||
|
" draw_results(results=results, \n",
|
||||||
|
" filename=f'plots/pv-{pv_capacity}-ess-{ess_capacity}-month-{index+1}-benefit.png',\n",
|
||||||
|
" title_benefit=title_benefit,\n",
|
||||||
|
" annot_benefit=annot_benefit,\n",
|
||||||
|
" figure_size=figure_size)\n",
|
||||||
|
" draw_overload(overload_cnt=overload_cnt, \n",
|
||||||
|
" filename=f'plots/pv-{pv_capacity}-ess-{ess_capacity}-month-{index+1}-unmet.png',\n",
|
||||||
|
" title_unmet=title_unmet,\n",
|
||||||
|
" annot_unmet=annot_unmet,\n",
|
||||||
|
" figure_size=figure_size,\n",
|
||||||
|
" days=months_days[index],\n",
|
||||||
|
" granularity=granularity)\n",
|
||||||
|
"\n",
|
||||||
|
"annual_result = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
"annual_costs = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
"annual_overload = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
"annual_nettos = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
"annual_gen = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
"annual_gen2 = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"# get the yearly results\n",
|
||||||
|
"for pv_capacity in pv_capacities:\n",
|
||||||
|
" for ess_capacity in ess_capacities:\n",
|
||||||
|
" results = 0\n",
|
||||||
|
" costs = 0\n",
|
||||||
|
" overload_cnt = 0\n",
|
||||||
|
" nettos = 0\n",
|
||||||
|
" gen = 0\n",
|
||||||
|
" gen2 = 0\n",
|
||||||
|
" for index, month_data in enumerate(months_data):\n",
|
||||||
|
" results += months_results[index].loc[pv_capacity,ess_capacity]\n",
|
||||||
|
" costs += months_costs[index].loc[pv_capacity,ess_capacity]\n",
|
||||||
|
" overload_cnt += months_overload[index].loc[pv_capacity, ess_capacity]\n",
|
||||||
|
" nettos += months_nettos[index].loc[pv_capacity, ess_capacity]\n",
|
||||||
|
" gen += months_gen_energy[index].loc[pv_capacity, ess_capacity]\n",
|
||||||
|
" gen2 += months_gen_energy[index].loc[pv_capacity, ess_capacity]\n",
|
||||||
|
" annual_result.loc[pv_capacity, ess_capacity] = results\n",
|
||||||
|
" annual_costs.loc[pv_capacity, ess_capacity] = costs\n",
|
||||||
|
" annual_overload.loc[pv_capacity, ess_capacity] = overload_cnt\n",
|
||||||
|
" annual_nettos.loc[pv_capacity, ess_capacity] = nettos\n",
|
||||||
|
" annual_gen.loc[pv_capacity, ess_capacity] = gen\n",
|
||||||
|
" annual_gen2.loc[pv_capacity, ess_capacity] = gen2\n",
|
||||||
|
"\n",
|
||||||
|
"draw_cost(costs=annual_costs,\n",
|
||||||
|
" filename='plots/annual_cost.png',\n",
|
||||||
|
" title_cost=title_cost,\n",
|
||||||
|
" annot_cost=annot_cost,\n",
|
||||||
|
" figure_size=figure_size)\n",
|
||||||
|
"draw_results(results=annual_result,\n",
|
||||||
|
" filename='plots/annual_benefit.png',\n",
|
||||||
|
" title_benefit=title_benefit,\n",
|
||||||
|
" annot_benefit=annot_benefit,\n",
|
||||||
|
" figure_size=figure_size)\n",
|
||||||
|
"draw_overload(overload_cnt=annual_overload,\n",
|
||||||
|
" filename='plots/annual_unmet.png',\n",
|
||||||
|
" title_unmet=title_unmet,\n",
|
||||||
|
" annot_unmet=annot_unmet,\n",
|
||||||
|
" figure_size=figure_size)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def save_data(data, filename):\n",
|
||||||
|
" data.to_csv(filename+'.csv')\n",
|
||||||
|
" data.to_json(filename + '.json')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"if not os.path.isdir('data'):\n",
|
||||||
|
" os.makedirs('data')\n",
|
||||||
|
"\n",
|
||||||
|
"save_data(annual_result, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-results')\n",
|
||||||
|
"save_data(annual_costs, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-costs')\n",
|
||||||
|
"save_data(annual_overload, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-overload_cnt')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"draw_results(annual_result, 'plots/test.png', 'test', False)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"draw_roi(annual_costs, annual_nettos, 'plots/annual_roi.png', title_roi, 365, annot_benefit, figure_size)\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.11.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 2
|
||||||
|
}
|
419
main.py
419
main.py
@@ -1 +1,418 @@
|
|||||||
import matplotlib
|
#!/usr/bin/env python
|
||||||
|
# coding: utf-8
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
import shutil
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.ticker as ticker
|
||||||
|
from matplotlib.ticker import FuncFormatter
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import seaborn as sns
|
||||||
|
import json
|
||||||
|
from matplotlib.colors import LinearSegmentedColormap
|
||||||
|
|
||||||
|
def clear_folder_make_ess_pv(folder_path):
|
||||||
|
if os.path.isdir(folder_path):
|
||||||
|
shutil.rmtree(folder_path)
|
||||||
|
os.makedirs(folder_path)
|
||||||
|
os.makedirs(os.path.join(folder_path,'ess'))
|
||||||
|
os.makedirs(os.path.join(folder_path,'pv'))
|
||||||
|
|
||||||
|
folder_path = 'plots'
|
||||||
|
clear_folder_make_ess_pv(folder_path)
|
||||||
|
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import seaborn as sns
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
from EnergySystem import EnergySystem
|
||||||
|
from config import pv_config, grid_config, ess_config
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
print("Version 0.0.5")
|
||||||
|
|
||||||
|
with open('config.json', 'r') as f:
|
||||||
|
js_data = json.load(f)
|
||||||
|
|
||||||
|
time_interval = js_data["time_interval"]["numerator"] / js_data["time_interval"]["denominator"]
|
||||||
|
print(time_interval)
|
||||||
|
|
||||||
|
pv_loss = js_data["pv"]["loss"]
|
||||||
|
pv_cost_per_kW = js_data["pv"]["cost_per_kW"]
|
||||||
|
pv_lifetime = js_data["pv"]["lifetime"]
|
||||||
|
|
||||||
|
ess_loss = js_data["ess"]["loss"]
|
||||||
|
ess_cost_per_kW = js_data["ess"]["cost_per_kW"]
|
||||||
|
ess_lifetime = js_data["ess"]["lifetime"]
|
||||||
|
|
||||||
|
grid_loss = js_data["grid"]["loss"]
|
||||||
|
sell_price = js_data["grid"]["sell_price"] #kWh
|
||||||
|
grid_capacity = js_data["grid"]["capacity"] #kWh
|
||||||
|
|
||||||
|
pv_begin = js_data["pv_capacities"]["begin"]
|
||||||
|
pv_end = js_data["pv_capacities"]["end"]
|
||||||
|
pv_groups = js_data["pv_capacities"]["groups"]
|
||||||
|
|
||||||
|
ess_begin = js_data["ess_capacities"]["begin"]
|
||||||
|
ess_end = js_data["ess_capacities"]["end"]
|
||||||
|
ess_groups = js_data["ess_capacities"]["groups"]
|
||||||
|
|
||||||
|
annot_unmet = js_data["annotated"]["unmet_prob"]
|
||||||
|
annot_benefit = js_data["annotated"]["benefit"]
|
||||||
|
annot_cost = js_data["annotated"]["cost"]
|
||||||
|
annot_roi = js_data["annotated"]["roi"]
|
||||||
|
|
||||||
|
title_unmet = js_data["plot_title"]["unmet_prob"]
|
||||||
|
title_cost = js_data["plot_title"]["cost"]
|
||||||
|
title_benefit = js_data["plot_title"]["benefit"]
|
||||||
|
title_roi = js_data["plot_title"]["roi"]
|
||||||
|
|
||||||
|
|
||||||
|
figure_size = (js_data["figure_size"]["length"], js_data["figure_size"]["height"])
|
||||||
|
|
||||||
|
data = pd.read_csv('combined_data.csv')
|
||||||
|
|
||||||
|
granularity = js_data["time_interval"]["numerator"]
|
||||||
|
|
||||||
|
months_days = [31,28,31,30,31,30,31,31,30,31,30,31]
|
||||||
|
def get_month_coe(num, granularity):
|
||||||
|
return 60 / granularity * 24 * months_days[num]
|
||||||
|
|
||||||
|
months_index = [get_month_coe(num, granularity) for num in range(12)]
|
||||||
|
months_data = []
|
||||||
|
for i in range(1,12):
|
||||||
|
months_index[i] += months_index[i-1]
|
||||||
|
for i in range(12):
|
||||||
|
start = 0 if i == 0 else months_index[i-1]
|
||||||
|
end = months_index[i]
|
||||||
|
months_data.append(data.iloc[int(start):int(end)])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pv_capacities = np.linspace(pv_begin, pv_end, pv_groups)
|
||||||
|
ess_capacities = np.linspace(ess_begin, ess_end, ess_groups)
|
||||||
|
# results = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
# affords = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
# costs = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
# overload_cnt = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
|
||||||
|
|
||||||
|
# In[ ]:
|
||||||
|
|
||||||
|
|
||||||
|
hour_demand = []
|
||||||
|
for index, row in data.iterrows():
|
||||||
|
time = row['time']
|
||||||
|
demand = row['demand']
|
||||||
|
if time.endswith('00'):
|
||||||
|
hour_demand.append(demand)
|
||||||
|
plt.figure(figsize=(10,8))
|
||||||
|
plt.plot(hour_demand)
|
||||||
|
plt.ylabel('Demand Power / kW')
|
||||||
|
plt.savefig('plots/demand.png')
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
|
||||||
|
def draw_results(results, filename, title_benefit, annot_benefit=False, figure_size=(10, 10)):
|
||||||
|
df=results
|
||||||
|
df = df.astype(float)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
min_value = df.min().min()
|
||||||
|
max_value = df.max().max()
|
||||||
|
max_scale = max(abs(min_value/1000), abs(max_value/1000))
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x,pos):
|
||||||
|
return '{:.0f}'.format(x/1000)
|
||||||
|
|
||||||
|
cmap = sns.color_palette("coolwarm", as_cmap=True)
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
ax = sns.heatmap(df/1000, fmt=".1f", cmap=cmap, vmin=-max_scale, vmax=max_scale, annot=annot_benefit)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
plt.title(title_benefit)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
|
||||||
|
# In[ ]:
|
||||||
|
|
||||||
|
|
||||||
|
def draw_roi(costs, results, filename, title_roi, days=365, annot_roi=False, figure_size=(10, 10)):
|
||||||
|
costs = costs.astype(float)
|
||||||
|
costs = costs / 365
|
||||||
|
costs = costs * days
|
||||||
|
|
||||||
|
df = results
|
||||||
|
df = costs / df
|
||||||
|
if 0 in df.index and 0 in df.columns:
|
||||||
|
df.loc[0,0] = 100
|
||||||
|
df[df > 80] = 100
|
||||||
|
print(df)
|
||||||
|
|
||||||
|
df = df.astype(float)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
min_value = df.min().min()
|
||||||
|
max_value = df.max().max()
|
||||||
|
print(max_value)
|
||||||
|
max_scale = max(abs(min_value), abs(max_value))
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x,pos):
|
||||||
|
return '{:.0f}'.format(x)
|
||||||
|
|
||||||
|
cmap = sns.color_palette("Greys", as_cmap=True)
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
ax = sns.heatmap(df, fmt=".1f", cmap=cmap, vmin=0, vmax=100, annot=annot_benefit)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
plt.title(title_roi)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
def draw_cost(costs, filename, title_cost, annot_cost=False, figure_size=(10, 10)):
|
||||||
|
df = costs
|
||||||
|
df = df.astype(int)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x, pos):
|
||||||
|
return '{:.0f}'.format(x / 1000000)
|
||||||
|
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
ax = sns.heatmap(df/1000000, fmt=".1f", cmap='viridis', annot=annot_cost)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
plt.title(title_cost)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_overload(overload_cnt, filename, title_unmet, annot_unmet=False, figure_size=(10, 10), days=365, granularity=15):
|
||||||
|
df = overload_cnt
|
||||||
|
print(days, granularity)
|
||||||
|
coef = 60 / granularity * days * 24
|
||||||
|
print(coef)
|
||||||
|
print(df)
|
||||||
|
df = ( coef - df) / coef
|
||||||
|
print(df)
|
||||||
|
|
||||||
|
df = df.astype(float)
|
||||||
|
df.index = df.index / 1000
|
||||||
|
df.index = df.index.map(int)
|
||||||
|
df.columns = df.columns / 1000
|
||||||
|
df.columns = df.columns.map(int)
|
||||||
|
|
||||||
|
|
||||||
|
df[df.columns[-1] + 1] = df.iloc[:, -1]
|
||||||
|
new_Data = pd.DataFrame(index=[df.index[-1] + 1], columns=df.columns)
|
||||||
|
for i in df.columns:
|
||||||
|
new_Data[i] = df[i].iloc[-1]
|
||||||
|
# print(new_Data)
|
||||||
|
df = pd.concat([df, new_Data])
|
||||||
|
|
||||||
|
|
||||||
|
plt.figure(figsize=figure_size)
|
||||||
|
cmap = LinearSegmentedColormap.from_list("", ["white", "blue"])
|
||||||
|
ax = sns.heatmap(df, fmt=".00%", cmap=cmap, vmin=0, vmax=1, annot=annot_unmet)
|
||||||
|
|
||||||
|
cbar = ax.collections[0].colorbar
|
||||||
|
cbar.set_ticks([0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1])
|
||||||
|
cbar.set_ticklabels(['0%', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%'])
|
||||||
|
cbar.ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: f'{x:.0%}'))
|
||||||
|
X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))
|
||||||
|
|
||||||
|
def fmt(x, pos):
|
||||||
|
return '{:.0f}%'.format(x * 100)
|
||||||
|
CS = ax.contour(X, Y, df, colors='black', alpha=0.5)
|
||||||
|
|
||||||
|
ax.clabel(CS, inline=True, fontsize=10, fmt=FuncFormatter(fmt))
|
||||||
|
|
||||||
|
plt.xlim(0, df.shape[1] - 1)
|
||||||
|
plt.ylim(0, df.shape[0] - 1)
|
||||||
|
plt.title(title_unmet)
|
||||||
|
plt.xlabel('ESS Capacity (MWh)')
|
||||||
|
plt.ylabel('PV Capacity (MW)')
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
def cal_profit(es: EnergySystem, saved_money, days):
|
||||||
|
profit = saved_money - es.ess.get_cost_per_year() / 365 * days - es.pv.get_cost_per_year() / 365 * days
|
||||||
|
return profit
|
||||||
|
|
||||||
|
def generate_data(pv_capacity, pv_cost_per_kW, pv_lifetime, pv_loss, ess_capacity, ess_cost_per_kW, ess_lifetime, ess_loss, grid_capacity, grid_loss, sell_price, time_interval, data, days):
|
||||||
|
pv = pv_config(capacity=pv_capacity,
|
||||||
|
cost_per_kW=pv_cost_per_kW,
|
||||||
|
lifetime=pv_lifetime,
|
||||||
|
loss=pv_loss)
|
||||||
|
ess = ess_config(capacity=ess_capacity,
|
||||||
|
cost_per_kW=ess_cost_per_kW,
|
||||||
|
lifetime=ess_lifetime,
|
||||||
|
loss=ess_loss,
|
||||||
|
charge_power=ess_capacity,
|
||||||
|
discharge_power=ess_capacity)
|
||||||
|
grid = grid_config(capacity=grid_capacity,
|
||||||
|
grid_loss=grid_loss,
|
||||||
|
sell_price= sell_price)
|
||||||
|
energySystem = EnergySystem(pv_type=pv,
|
||||||
|
ess_type=ess,
|
||||||
|
grid_type= grid)
|
||||||
|
(benefit, netto_benefit, gen_energy) = energySystem.simulate(data, time_interval)
|
||||||
|
results = cal_profit(energySystem, benefit, days)
|
||||||
|
overload_cnt = energySystem.overload_cnt
|
||||||
|
costs = energySystem.ess.capacity * energySystem.ess.cost_per_kW + energySystem.pv.capacity * energySystem.pv.cost_per_kW
|
||||||
|
return (results, overload_cnt, costs, netto_benefit, gen_energy, energySystem.generated)
|
||||||
|
|
||||||
|
|
||||||
|
months_results = []
|
||||||
|
months_costs = []
|
||||||
|
months_overload = []
|
||||||
|
months_nettos = []
|
||||||
|
months_gen_energy = []
|
||||||
|
months_gen_energy2 = []
|
||||||
|
for index, month_data in enumerate(months_data):
|
||||||
|
results = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
costs = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
overload_cnt = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
nettos = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
gen_energies = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
gen_energies2 = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
for pv_capacity in pv_capacities:
|
||||||
|
for ess_capacity in ess_capacities:
|
||||||
|
(result, overload, cost, netto, gen_energy, gen_energy2) = generate_data(pv_capacity=pv_capacity,pv_cost_per_kW=pv_cost_per_kW, pv_lifetime=pv_lifetime, pv_loss=pv_loss, ess_capacity=ess_capacity, ess_cost_per_kW=ess_cost_per_kW, ess_lifetime=ess_lifetime, ess_loss=ess_loss, grid_capacity=grid_capacity, grid_loss=grid_loss, sell_price=sell_price, time_interval=time_interval, data=month_data, days=months_days[index])
|
||||||
|
results.loc[pv_capacity,ess_capacity] = result
|
||||||
|
overload_cnt.loc[pv_capacity,ess_capacity] = overload
|
||||||
|
costs.loc[pv_capacity,ess_capacity] = cost
|
||||||
|
nettos.loc[pv_capacity,ess_capacity] = netto
|
||||||
|
gen_energies.loc[pv_capacity, ess_capacity] = gen_energy
|
||||||
|
gen_energies2.loc[pv_capacity, ess_capacity] = gen_energy2
|
||||||
|
months_results.append(results)
|
||||||
|
months_costs.append(costs)
|
||||||
|
months_overload.append(overload_cnt)
|
||||||
|
months_nettos.append(nettos)
|
||||||
|
months_gen_energy.append(gen_energies)
|
||||||
|
months_gen_energy2.append(gen_energies2)
|
||||||
|
draw_results(results=results,
|
||||||
|
filename=f'plots/pv-{pv_capacity}-ess-{ess_capacity}-month-{index+1}-benefit.png',
|
||||||
|
title_benefit=title_benefit,
|
||||||
|
annot_benefit=annot_benefit,
|
||||||
|
figure_size=figure_size)
|
||||||
|
draw_overload(overload_cnt=overload_cnt,
|
||||||
|
filename=f'plots/pv-{pv_capacity}-ess-{ess_capacity}-month-{index+1}-unmet.png',
|
||||||
|
title_unmet=title_unmet,
|
||||||
|
annot_unmet=annot_unmet,
|
||||||
|
figure_size=figure_size,
|
||||||
|
days=months_days[index],
|
||||||
|
granularity=granularity)
|
||||||
|
|
||||||
|
annual_result = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
annual_costs = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
annual_overload = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
annual_nettos = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
annual_gen = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
annual_gen2 = pd.DataFrame(index=pv_capacities, columns= ess_capacities)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# get the yearly results
|
||||||
|
for pv_capacity in pv_capacities:
|
||||||
|
for ess_capacity in ess_capacities:
|
||||||
|
results = 0
|
||||||
|
costs = 0
|
||||||
|
overload_cnt = 0
|
||||||
|
nettos = 0
|
||||||
|
gen = 0
|
||||||
|
gen2 = 0
|
||||||
|
for index, month_data in enumerate(months_data):
|
||||||
|
results += months_results[index].loc[pv_capacity,ess_capacity]
|
||||||
|
costs += months_costs[index].loc[pv_capacity,ess_capacity]
|
||||||
|
overload_cnt += months_overload[index].loc[pv_capacity, ess_capacity]
|
||||||
|
nettos += months_nettos[index].loc[pv_capacity, ess_capacity]
|
||||||
|
gen += months_gen_energy[index].loc[pv_capacity, ess_capacity]
|
||||||
|
gen2 += months_gen_energy[index].loc[pv_capacity, ess_capacity]
|
||||||
|
annual_result.loc[pv_capacity, ess_capacity] = results
|
||||||
|
annual_costs.loc[pv_capacity, ess_capacity] = costs
|
||||||
|
annual_overload.loc[pv_capacity, ess_capacity] = overload_cnt
|
||||||
|
annual_nettos.loc[pv_capacity, ess_capacity] = nettos
|
||||||
|
annual_gen.loc[pv_capacity, ess_capacity] = gen
|
||||||
|
annual_gen2.loc[pv_capacity, ess_capacity] = gen2
|
||||||
|
|
||||||
|
draw_cost(costs=annual_costs,
|
||||||
|
filename='plots/annual_cost.png',
|
||||||
|
title_cost=title_cost,
|
||||||
|
annot_cost=annot_cost,
|
||||||
|
figure_size=figure_size)
|
||||||
|
draw_results(results=annual_result,
|
||||||
|
filename='plots/annual_benefit.png',
|
||||||
|
title_benefit=title_benefit,
|
||||||
|
annot_benefit=annot_benefit,
|
||||||
|
figure_size=figure_size)
|
||||||
|
draw_overload(overload_cnt=annual_overload,
|
||||||
|
filename='plots/annual_unmet.png',
|
||||||
|
title_unmet=title_unmet,
|
||||||
|
annot_unmet=annot_unmet,
|
||||||
|
figure_size=figure_size)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def save_data(data, filename):
|
||||||
|
data.to_csv(filename+'.csv')
|
||||||
|
data.to_json(filename + '.json')
|
||||||
|
|
||||||
|
if not os.path.isdir('data'):
|
||||||
|
os.makedirs('data')
|
||||||
|
|
||||||
|
save_data(annual_result, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-results')
|
||||||
|
save_data(annual_costs, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-costs')
|
||||||
|
save_data(annual_overload, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-overload_cnt')
|
||||||
|
|
||||||
|
draw_results(annual_result, 'plots/test.png', 'test', False)
|
||||||
|
|
||||||
|
|
||||||
|
draw_roi(annual_costs, annual_nettos, 'plots/annual_roi.png', title_roi, 365, annot_benefit, figure_size)
|
||||||
|
|
||||||
|
19
old/generate_electricity_price.py
Normal file
19
old/generate_electricity_price.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
start_date = '2023-01-01'
|
||||||
|
end_date = '2024-01-01'
|
||||||
|
|
||||||
|
# 创建时间索引
|
||||||
|
time_index = pd.date_range(start=start_date, end=end_date, freq='15min')
|
||||||
|
|
||||||
|
# 生成电价数据,假设电价在0.28到0.32欧元/kWh之间波动
|
||||||
|
price_data = np.random.uniform(0.28, 0.32, len(time_index))
|
||||||
|
|
||||||
|
# 创建DataFrame
|
||||||
|
price_df = pd.DataFrame(data={'Time': time_index, 'ElectricityPrice': price_data})
|
||||||
|
|
||||||
|
# 保存到CSV文件
|
||||||
|
price_df.to_csv('electricity_price_data.csv', index=False)
|
||||||
|
|
||||||
|
print("Electricity price data generated and saved.")
|
56
old/generatedata.py
Normal file
56
old/generatedata.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# 设置随机种子以重现结果
|
||||||
|
np.random.seed(43)
|
||||||
|
|
||||||
|
def simulate_sunlight(hour, month):
|
||||||
|
# 假设最大日照强度在正午,根据月份调整最大日照强度
|
||||||
|
max_intensity = 1.0 # 夏季最大日照强度
|
||||||
|
if month in [12, 1, 2]: # 冬季
|
||||||
|
max_intensity = 0.6
|
||||||
|
elif month in [3, 4, 10, 11]: # 春秋
|
||||||
|
max_intensity = 0.8
|
||||||
|
|
||||||
|
# 计算日照强度,模拟早晚日照弱,中午日照强
|
||||||
|
intensity = max_intensity * np.sin(np.pi * (hour - 6) / 12)**2 if 6 <= hour <= 18 else 0
|
||||||
|
return intensity
|
||||||
|
|
||||||
|
def simulate_factory_demand(hour, day_of_week):
|
||||||
|
# 周末工厂需求可能减少
|
||||||
|
if day_of_week in [5, 6]: # 周六和周日
|
||||||
|
base_demand = 3000
|
||||||
|
else:
|
||||||
|
base_demand = 6000
|
||||||
|
|
||||||
|
# 日常波动
|
||||||
|
if 8 <= hour <= 20:
|
||||||
|
return base_demand + np.random.randint(100, 200) # 白天需求量大
|
||||||
|
else:
|
||||||
|
return base_demand - np.random.randint(0, 100) # 夜间需求量小
|
||||||
|
|
||||||
|
def generate_data(days=10):
|
||||||
|
records = []
|
||||||
|
month_demand = 0
|
||||||
|
for day in range(days):
|
||||||
|
month = (day % 365) // 30 + 1
|
||||||
|
day_of_week = day % 7
|
||||||
|
day_demand = 0
|
||||||
|
for hour in range(24):
|
||||||
|
for minute in [0, 10, 20, 30, 40, 50]:
|
||||||
|
time = f'{hour:02d}:{minute:02d}'
|
||||||
|
sunlight = simulate_sunlight(hour, month)
|
||||||
|
demand = simulate_factory_demand(hour, day_of_week)
|
||||||
|
day_demand+=demand
|
||||||
|
records.append({'time': time, 'sunlight': sunlight, 'demand': demand})
|
||||||
|
print(f"day:{day}, day_demand: {day_demand}")
|
||||||
|
month_demand += day_demand
|
||||||
|
if day%30 == 0:
|
||||||
|
print(f"month:{month}, month_demand:{month_demand}")
|
||||||
|
month_demand = 0
|
||||||
|
return pd.DataFrame(records)
|
||||||
|
|
||||||
|
# 生成数据
|
||||||
|
data = generate_data(365) # 模拟一年的数据
|
||||||
|
data.to_csv('simulation_data.csv', index=False)
|
||||||
|
print("Data generated and saved to simulation_data.csv.")
|
24
old/generatepriceschedule.py
Normal file
24
old/generatepriceschedule.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
def generate_price_schedule():
|
||||||
|
records = []
|
||||||
|
# 假设一天分为三个时段:谷时、平时、峰时
|
||||||
|
times = [('00:00', '06:00', 0.25),
|
||||||
|
('06:00', '18:00', 0.3),
|
||||||
|
('18:00', '24:00', 0.35)]
|
||||||
|
|
||||||
|
# 随机调整每天的电价以增加现实性
|
||||||
|
for time_start, time_end, base_price in times:
|
||||||
|
# 随机浮动5%以内
|
||||||
|
fluctuation = np.random.uniform(-0.005, 0.005)
|
||||||
|
price = round(base_price + fluctuation, 3)
|
||||||
|
records.append({'time_start': time_start, 'time_end': time_end, 'price': price})
|
||||||
|
|
||||||
|
return pd.DataFrame(records)
|
||||||
|
|
||||||
|
# 生成电价计划
|
||||||
|
price_schedule = generate_price_schedule()
|
||||||
|
price_schedule.to_csv('price_schedule.csv', index=False)
|
||||||
|
print("Price schedule generated and saved to price_schedule.csv.")
|
||||||
|
print(price_schedule)
|
4
old/price_schedule.csv
Normal file
4
old/price_schedule.csv
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
time_start,time_end,price
|
||||||
|
00:00,06:00,0.247
|
||||||
|
06:00,18:00,0.3
|
||||||
|
18:00,24:00,0.349
|
|
52561
old/simulation_data.csv
Normal file
52561
old/simulation_data.csv
Normal file
File diff suppressed because it is too large
Load Diff
39
read_data.py
Normal file
39
read_data.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
import csv
|
||||||
|
|
||||||
|
pv_yield_file_name = 'read_data/Serbia.csv'
|
||||||
|
# factory_demand_file_name = 'factory_power1.xlsx'
|
||||||
|
factory_demand_file_name = 'read_data/factory_power1.csv'
|
||||||
|
electricity_price_data = 'read_data/electricity_price_data.csv'
|
||||||
|
electricity_price_data_sell = 'read_data/electricity_price_data_sell.csv'
|
||||||
|
|
||||||
|
pv_df = pd.read_csv(pv_yield_file_name, index_col='Time', usecols=['Time', 'PV yield[kW/kWp]'])
|
||||||
|
pv_df.index = pd.to_datetime(pv_df.index)
|
||||||
|
|
||||||
|
df_power = pd.read_csv('factory_power1.csv', index_col='Time', usecols=['Time', 'FactoryPower'])
|
||||||
|
df_power.index = pd.to_datetime(df_power.index)
|
||||||
|
df_combined = pv_df.join(df_power)
|
||||||
|
|
||||||
|
price_df = pd.read_csv(electricity_price_data, index_col='Time', usecols=['Time', 'ElectricityBuy'])
|
||||||
|
price_df.index = pd.to_datetime(price_df.index)
|
||||||
|
price_df = price_df.reindex(df_combined.index)
|
||||||
|
df_combined2 = df_combined.join(price_df)
|
||||||
|
|
||||||
|
sell_df = pd.read_csv(electricity_price_data_sell, index_col='Time', usecols=['Time', 'ElectricitySell'])
|
||||||
|
sell_df.index = pd.to_datetime(sell_df.index)
|
||||||
|
sell_df = sell_df.reindex(df_combined.index)
|
||||||
|
df_combined3 = df_combined2.join(sell_df)
|
||||||
|
|
||||||
|
with open('combined_data.csv', 'w', newline='') as file:
|
||||||
|
writer = csv.writer(file)
|
||||||
|
writer.writerow(['time', 'PV yield[kW/kWp]', 'demand','buy', 'sell'])
|
||||||
|
cnt = 0
|
||||||
|
for index, row in df_combined3.iterrows():
|
||||||
|
time_formatted = index.strftime('%H:%M')
|
||||||
|
writer.writerow([time_formatted, row['PV yield[kW/kWp]'], row['FactoryPower'],row['ElectricityBuy'], row['ElectricitySell']])
|
||||||
|
|
||||||
|
print('The file is written to combined_data.csv')
|
||||||
|
|
||||||
|
|
||||||
|
print("Simulation data with electricity prices has been updated and saved.")
|
35041
read_data/Berlin.csv
Normal file
35041
read_data/Berlin.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/Cambodge.csv
Normal file
35041
read_data/Cambodge.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/Marcedonia.csv
Normal file
35041
read_data/Marcedonia.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/Riyahd.csv
Normal file
35041
read_data/Riyahd.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/Serbia.csv
Normal file
35041
read_data/Serbia.csv
Normal file
File diff suppressed because it is too large
Load Diff
372
read_data/convert_data.ipynb
Normal file
372
read_data/convert_data.ipynb
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 85,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import matplotlib.pyplot as plt\n",
|
||||||
|
"import pandas as pd\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"import os\n",
|
||||||
|
"import csv"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 86,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def read_csv(filename):\n",
|
||||||
|
" skip_rows = list(range(1, 17))\n",
|
||||||
|
" data = pd.read_csv(filename, sep=';', skiprows=skip_rows)\n",
|
||||||
|
" return data"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 87,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"/tmp/ipykernel_3075037/3659192646.py:3: DtypeWarning: Columns (32,33,35) have mixed types. Specify dtype option on import or set low_memory=False.\n",
|
||||||
|
" data = pd.read_csv(filename, sep=';', skiprows=skip_rows)\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"Index(['Time', 'Irradiance onto horizontal plane ',\n",
|
||||||
|
" 'Diffuse Irradiation onto Horizontal Plane ', 'Outside Temperature ',\n",
|
||||||
|
" 'Module Area 1: Height of Sun ',\n",
|
||||||
|
" 'Module Area 1: Irradiance onto tilted surface ',\n",
|
||||||
|
" 'Module Area 1: Module Temperature ', 'Grid Export ',\n",
|
||||||
|
" 'Energy from Grid ', 'Global radiation - horizontal ',\n",
|
||||||
|
" 'Deviation from standard spectrum ', 'Ground Reflection (Albedo) ',\n",
|
||||||
|
" 'Orientation and inclination of the module surface ', 'Shading ',\n",
|
||||||
|
" 'Reflection on the Module Surface ',\n",
|
||||||
|
" 'Irradiance on the rear side of the module ',\n",
|
||||||
|
" 'Global Radiation at the Module ',\n",
|
||||||
|
" 'Module Area 1: Reflection on the Module Surface ',\n",
|
||||||
|
" 'Module Area 1: Global Radiation at the Module ',\n",
|
||||||
|
" 'Global PV Radiation ', 'Bifaciality ', 'Soiling ',\n",
|
||||||
|
" 'STC Conversion (Rated Efficiency of Module) ', 'Rated PV Energy ',\n",
|
||||||
|
" 'Low-light performance ', 'Module-specific Partial Shading ',\n",
|
||||||
|
" 'Deviation from the nominal module temperature ', 'Diodes ',\n",
|
||||||
|
" 'Mismatch (Manufacturer Information) ',\n",
|
||||||
|
" 'Mismatch (Configuration/Shading) ',\n",
|
||||||
|
" 'Power optimizer (DC conversion/clipping) ',\n",
|
||||||
|
" 'PV Energy (DC) without inverter clipping ',\n",
|
||||||
|
" 'Failing to reach the DC start output ',\n",
|
||||||
|
" 'Clipping on account of the MPP Voltage Range ',\n",
|
||||||
|
" 'Clipping on account of the max. DC Current ',\n",
|
||||||
|
" 'Clipping on account of the max. DC Power ',\n",
|
||||||
|
" 'Clipping on account of the max. AC Power/cos phi ', 'MPP Matching ',\n",
|
||||||
|
" 'PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 1 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 2 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 3 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 4 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 5 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 1 - MPP 6 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 2 - MPP 1 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Inverter 2 - MPP 2 - to Module Area 1: PV energy (DC) ',\n",
|
||||||
|
" 'Energy at the Inverter Input ',\n",
|
||||||
|
" 'Input voltage deviates from rated voltage ', 'DC/AC Conversion ',\n",
|
||||||
|
" 'Own Consumption (Standby or Night) ', 'Total Cable Losses ',\n",
|
||||||
|
" 'PV energy (AC) minus standby use ', 'Feed-in energy ',\n",
|
||||||
|
" 'Inverter 1 to Module Area 1: Own Consumption (Standby or Night) ',\n",
|
||||||
|
" 'Inverter 1 to Module Area 1: PV energy (AC) minus standby use ',\n",
|
||||||
|
" 'Inverter 2 to Module Area 1: Own Consumption (Standby or Night) ',\n",
|
||||||
|
" 'Inverter 2 to Module Area 1: PV energy (AC) minus standby use ',\n",
|
||||||
|
" 'Unnamed: 58'],\n",
|
||||||
|
" dtype='object')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 87,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"\n",
|
||||||
|
"file_name = 'Riyahd_raw.csv'\n",
|
||||||
|
"df = read_csv(file_name)\n",
|
||||||
|
"df.columns"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 88,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"remain_column = ['Time','PV energy (AC) minus standby use ']\n",
|
||||||
|
"energy_row_name = remain_column[1]\n",
|
||||||
|
"\n",
|
||||||
|
"df = df[remain_column]\n",
|
||||||
|
"df[energy_row_name] = df[energy_row_name].str.replace(',','.').astype(float)\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 89,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"770594.226863267"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 89,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"sum_energy = df[energy_row_name].sum()\n",
|
||||||
|
"sum_energy"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 90,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"1975.882632982736"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 90,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"sum_energy / 390"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 91,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"group_size = 15\n",
|
||||||
|
"df['group_id'] = df.index // group_size\n",
|
||||||
|
"\n",
|
||||||
|
"sums = df.groupby('group_id')[energy_row_name].sum()\n",
|
||||||
|
"sums_df = sums.reset_index(drop=True).to_frame(name = 'Energy')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 92,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"<bound method NDFrame.head of Energy\n",
|
||||||
|
"0 0.0\n",
|
||||||
|
"1 0.0\n",
|
||||||
|
"2 0.0\n",
|
||||||
|
"3 0.0\n",
|
||||||
|
"4 0.0\n",
|
||||||
|
"... ...\n",
|
||||||
|
"35035 0.0\n",
|
||||||
|
"35036 0.0\n",
|
||||||
|
"35037 0.0\n",
|
||||||
|
"35038 0.0\n",
|
||||||
|
"35039 0.0\n",
|
||||||
|
"\n",
|
||||||
|
"[35040 rows x 1 columns]>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 92,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"sums_df.head"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 93,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
" Time\n",
|
||||||
|
"0 2023-01-01 00:00:00\n",
|
||||||
|
"1 2023-01-01 00:15:00\n",
|
||||||
|
"2 2023-01-01 00:30:00\n",
|
||||||
|
"3 2023-01-01 00:45:00\n",
|
||||||
|
"4 2023-01-01 01:00:00\n",
|
||||||
|
" Time\n",
|
||||||
|
"35035 2023-12-31 22:45:00\n",
|
||||||
|
"35036 2023-12-31 23:00:00\n",
|
||||||
|
"35037 2023-12-31 23:15:00\n",
|
||||||
|
"35038 2023-12-31 23:30:00\n",
|
||||||
|
"35039 2023-12-31 23:45:00\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"\n",
|
||||||
|
"start_date = '2023-01-01'\n",
|
||||||
|
"end_date = '2023-12-31'\n",
|
||||||
|
"\n",
|
||||||
|
"# 生成每天的15分钟间隔时间\n",
|
||||||
|
"all_dates = pd.date_range(start=start_date, end=end_date, freq='D')\n",
|
||||||
|
"all_times = pd.timedelta_range(start='0 min', end='1435 min', freq='15 min')\n",
|
||||||
|
"\n",
|
||||||
|
"# 生成完整的时间标签\n",
|
||||||
|
"date_times = [pd.Timestamp(date) + time for date in all_dates for time in all_times]\n",
|
||||||
|
"\n",
|
||||||
|
"# 创建DataFrame\n",
|
||||||
|
"time_frame = pd.DataFrame({\n",
|
||||||
|
" 'Time': date_times\n",
|
||||||
|
"})\n",
|
||||||
|
"\n",
|
||||||
|
"# 查看生成的DataFrame\n",
|
||||||
|
"print(time_frame.head())\n",
|
||||||
|
"print(time_frame.tail())\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 94,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"(35040, 1)\n",
|
||||||
|
"(35040, 1)\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"print(sums_df.shape)\n",
|
||||||
|
"print(time_frame.shape)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 95,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"# sums_df['Time'] = time_frame['Time']\n",
|
||||||
|
"sums_df = pd.concat([time_frame, sums_df], axis=1)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 96,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
" Energy\n",
|
||||||
|
"Time \n",
|
||||||
|
"2023-01-01 00:00:00 0.0\n",
|
||||||
|
"2023-01-01 00:15:00 0.0\n",
|
||||||
|
"2023-01-01 00:30:00 0.0\n",
|
||||||
|
"2023-01-01 00:45:00 0.0\n",
|
||||||
|
"2023-01-01 01:00:00 0.0\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"sums_df.set_index('Time', inplace=True)\n",
|
||||||
|
"print(sums_df.head())"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 97,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"max_value = sums_df['Energy'].max()\n",
|
||||||
|
"sums_df['Energy'] = sums_df['Energy'] / max_value\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 98,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def save_csv(df, filename, columns):\n",
|
||||||
|
" tmp_df = df.copy()\n",
|
||||||
|
" tmp_df[columns[1]] = tmp_df[columns[1]].round(4)\n",
|
||||||
|
" with open(filename, 'w', newline='') as file:\n",
|
||||||
|
" writer = csv.writer(file)\n",
|
||||||
|
" writer.writerow(columns)\n",
|
||||||
|
" for index, row in tmp_df.iterrows():\n",
|
||||||
|
" time_formatted = index.strftime('%H:%M')\n",
|
||||||
|
" writer.writerow([time_formatted, row[columns[1]]])\n",
|
||||||
|
" \n",
|
||||||
|
" print(f'The file is written to {filename}')\n",
|
||||||
|
" \n",
|
||||||
|
"\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 99,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"The file is written to Riyahd.csv\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"save_csv(sums_df, 'Riyahd.csv', ['Time', 'Energy'])"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "pv",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.11.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 2
|
||||||
|
}
|
79
read_data/convert_data.py
Normal file
79
read_data/convert_data.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
import os
|
||||||
|
import csv
|
||||||
|
|
||||||
|
def generate_min_df(mins = 15):
|
||||||
|
end = 60/mins * 24
|
||||||
|
start_date = '2023-01-01'
|
||||||
|
end_date = '2023-12-31'
|
||||||
|
|
||||||
|
all_dates = pd.date_range(start=start_date, end=end_date, freq='D')
|
||||||
|
all_times = pd.timedelta_range(start='0 min', end=f'1435 min', freq=f'{mins} min')
|
||||||
|
|
||||||
|
date_times = [pd.Timestamp(date) + time for date in all_dates for time in all_times]
|
||||||
|
|
||||||
|
time_frame = pd.DataFrame({
|
||||||
|
'Time': date_times
|
||||||
|
})
|
||||||
|
return time_frame
|
||||||
|
|
||||||
|
def save_csv(df, filename, columns):
|
||||||
|
with open(filename, 'w', newline='') as file:
|
||||||
|
writer = csv.writer(file)
|
||||||
|
writer.writerow(['Time', 'PV yield[kW/kWp]'])
|
||||||
|
for index, row in df.iterrows():
|
||||||
|
time_formatted = index.strftime('%H:%M')
|
||||||
|
writer.writerow([time_formatted, row[columns[1]]])
|
||||||
|
|
||||||
|
print(f'The file is written to {filename}')
|
||||||
|
|
||||||
|
def read_csv(filename):
|
||||||
|
skip_rows = list(range(1, 17))
|
||||||
|
data = pd.read_csv(filename, sep=';', skiprows=skip_rows)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def process(file_name):
|
||||||
|
df = read_csv(file_name)
|
||||||
|
city = file_name.split('_')[0]
|
||||||
|
|
||||||
|
remain_column = ['Time','PV energy (AC) minus standby use ']
|
||||||
|
energy_row_name = remain_column[1]
|
||||||
|
|
||||||
|
df = df[remain_column]
|
||||||
|
df[energy_row_name] = df[energy_row_name].str.replace(',','.').astype(float)
|
||||||
|
|
||||||
|
sum_energy = df[energy_row_name].sum()
|
||||||
|
group_size = 15
|
||||||
|
df['group_id'] = df.index // group_size
|
||||||
|
|
||||||
|
sums = df.groupby('group_id')[energy_row_name].sum()
|
||||||
|
sums_df = sums.reset_index(drop=True).to_frame(name = 'Energy')
|
||||||
|
|
||||||
|
pv_energy_column_name = 'PV yield[kW/kWp]'
|
||||||
|
sums_df = sums_df.rename(columns={'Energy': pv_energy_column_name})
|
||||||
|
|
||||||
|
time_frame = generate_min_df(15)
|
||||||
|
sums_df = pd.concat([time_frame, sums_df], axis=1)
|
||||||
|
# sums_df.set_index('Time', inplace=True)
|
||||||
|
# max_value = sums_df[pv_energy_column_name].max()
|
||||||
|
sums_df[pv_energy_column_name] = sums_df[pv_energy_column_name] / 390.
|
||||||
|
sums_df[pv_energy_column_name] = sums_df[pv_energy_column_name].round(4)
|
||||||
|
sums_df[pv_energy_column_name].replace(0.0, -0.0)
|
||||||
|
|
||||||
|
sums_df.to_csv(f'{city}.csv')
|
||||||
|
# save_csv(sums_df, f'{city}.csv', ['Time', 'Energy'])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
city_list = ['Riyahd', 'Cambodge', 'Berlin', 'Serbia']
|
||||||
|
for city in city_list:
|
||||||
|
print(f'Processing {city}')
|
||||||
|
file_name = f'{city}_raw.csv'
|
||||||
|
process(file_name)
|
||||||
|
print(f'Processing {city} is done\n')
|
||||||
|
|
35041
read_data/electricity_price_data.csv
Normal file
35041
read_data/electricity_price_data.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/electricity_price_data_sell.csv
Normal file
35041
read_data/electricity_price_data_sell.csv
Normal file
File diff suppressed because it is too large
Load Diff
35041
read_data/factory_power1.csv
Normal file
35041
read_data/factory_power1.csv
Normal file
File diff suppressed because it is too large
Load Diff
16
xlsx2csv.py
Normal file
16
xlsx2csv.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
excel_file = 'factory_power1.xlsx'
|
||||||
|
sheet_name = 'Sheet1'
|
||||||
|
|
||||||
|
df = pd.read_excel(excel_file, sheet_name=sheet_name)
|
||||||
|
|
||||||
|
start_date = '2023-01-01'
|
||||||
|
df_power = pd.read_excel(excel_file,
|
||||||
|
header=None,
|
||||||
|
names=['FactoryPower'],
|
||||||
|
dtype={'FactoryPower': float})
|
||||||
|
times = pd.date_range(start=start_date, periods=len(df_power), freq='15min')
|
||||||
|
df_power['Time'] = times
|
||||||
|
df_power = df_power[['Time', 'FactoryPower']]
|
||||||
|
df_power.to_csv('factory_power1.csv', index=True)
|
Reference in New Issue
Block a user