MEOS/Utilities/LoadProfile.py

111 lines
3.9 KiB
Python

import numpy as np
from Utilities.Time import generate_timestrings, index_peak_times, index_operating_hours
from scipy.optimize import root_scalar
import pandas as pd
def get_no_of_peaks(peak_bounds):
peak_occurences = np.random.randint(peak_bounds["min"], peak_bounds["max"], 1)
return peak_occurences
def generate_peak_info(c, dt):
no_of_peaks = get_no_of_peaks(c["site_info"]["no_of_peaks"])
operating_hours = generate_timestrings(
c["site_info"]["operating hours"]["start"],
c["site_info"]["operating hours"]["end"],
dt,
)
peak_times = np.random.choice(operating_hours, no_of_peaks, replace=False)
peak_durations = np.random.randint(
c["site_info"]["peak_duration"]["min"],
c["site_info"]["peak_duration"]["max"],
no_of_peaks,
)
return peak_times, peak_durations
def generate_out_of_hours_consumption_ratio(c):
# Generate a random ratio for out-of-hours consumption
ratio = np.random.uniform(
c["site_info"]["out_of_hours_consumption"]["min"],
c["site_info"]["out_of_hours_consumption"]["max"],
)
return ratio
def recompute_load_profile(
load_profile,
offset,
):
# apply offset to the load profile
load_profile += offset
return load_profile
def get_load_profile(c, dt, batch_start_time, batch_process_duration):
# Generate load profile for each site
# c is the configuration dictionary
# dt is the time step in seconds
# batch_start_time is the start time for the batch process in seconds since the epoch
# batch_process_duration is the duration of the batch process in seconds
# start with indexing all the peak occurences
# generate timeseries from start to end time
start_time = batch_start_time
end_time = start_time + batch_process_duration
batch_process_duration_hours = batch_process_duration / 3600 # convert to hours
timestamps = np.arange(start_time, end_time + 1, dt)
idx_operating_hours = index_operating_hours(
timestamps, c["site_info"]["operating hours"]
)
no_of_operating_hours = np.sum(idx_operating_hours > 0)
# loop through each site in the configuration
for site in c["site_info"]["sites"]:
# Initialise the load profile
load_profile = np.zeros(len(timestamps))
# generate noise to make the profile more realistic
noise = np.random.normal(
1 - c["noise"]["range"], 1 + c["noise"]["range"], len(timestamps)
)
# Generate peak times and durations
peak_times, peak_durations = generate_peak_info(c, dt)
# Generate peak times and durations
idx_peak = index_peak_times(timestamps, peak_times, peak_durations)
# Generate out-of-hours consumption ratio
# The % of energy used outside of the operating hours
out_of_hours_ratio = generate_out_of_hours_consumption_ratio(c)
# start by computing average consumption during operating hours
# and outside of operating hours
operating_hour_consumption = site["daily_consumption_kWh"] * (
1 - out_of_hours_ratio
)
out_of_hours_consumption = site["daily_consumption_kWh"] * out_of_hours_ratio
avg_operating_hour_consumption = (
operating_hour_consumption / no_of_operating_hours
)
avg_out_of_hours_consumption = out_of_hours_consumption / (
batch_process_duration_hours - no_of_operating_hours
)
# assign base load profile
load_profile[idx_operating_hours > 0] = avg_operating_hour_consumption
load_profile[idx_operating_hours == 0] = avg_out_of_hours_consumption
# apply peak loads
for i in range(1, np.max(idx_peak) + 1):
load_profile[idx_peak == i] = site["maximum_demand_kW"]
# apply noise to the load profile, including max demand
load_profile = load_profile * noise