Skip to content

Commit

Permalink
cleaned up and decoupled from the draggEnv class for RL learning, WAR…
Browse files Browse the repository at this point in the history
…NING: this version is no longer RL enabled. You must use DRAGG-Gym
  • Loading branch information
apigott committed Nov 23, 2020
1 parent f2c775e commit 52a4dec
Show file tree
Hide file tree
Showing 7 changed files with 520 additions and 1,016 deletions.
591 changes: 207 additions & 384 deletions dragg/aggregator.py

Large diffs are not rendered by default.

109 changes: 45 additions & 64 deletions dragg/data/config-template.toml
Original file line number Diff line number Diff line change
@@ -1,89 +1,70 @@
[community]
total_number_homes = [ 10, 0,]
homes_battery = [ 0, 0,]
homes_pv = [ 3, 0,]
homes_pv_battery = [ 0, 0,]
total_number_homes = 10
homes_battery = 0
homes_pv = 4
homes_pv_battery = 0
overwrite_existing = true
house_p_avg = 1.0
house_p_avg = 1.2

[simulation]
start_datetime = "2015-01-01 00"
end_datetime = "2015-01-04 00"
random_seed = 12
n_nodes = 4
load_zone = "LZ_HOUSTON"
check_type = "all"
run_rbo_mpc = true
checkpoint_interval = "daily"
named_version = "test"

[agg]
base_price = 0.07
subhourly_steps = 1
tou_enabled = true
spp_enabled = false

[agg.rl]
action_horizon = 1
forecast_horizon = 1
prev_timesteps = 12
max_rp = 0.02

[home.hvac]
r_dist = [ 6.8, 9.199999999999999,]
c_dist = [ 4.25, 5.75,]
p_cool_dist = [ 2, 9,]
p_heat_dist = [ 2.0, 13.5,]
p_cool_dist = [ 3.5, 3.5,]
p_heat_dist = [ 3.5, 3.5,]
temp_sp_dist = [ 18, 22,]
temp_deadband_dist = [ 2, 3,]

[home.wh]
r_dist = [ 18.7, 25.3,]
c_dist = [ 4.25, 5.75,]
p_dist = [ 5, 8,]
p_dist = [ 2.5, 2.5,]
sp_dist = [ 45.5, 48.5,]
deadband_dist = [ 9, 12,]
size_dist = [ 200, 300,]

[home.wh.waterdraws]
n_big_draw_dist = [ 5, 8,]
n_small_draw_dist = [ 30, 50,]
big_draw_size_dist = [ 5, 10,]
small_draw_size_dist = [ 0.2, 0.5,]
waterdraw_file = '100_Random_Flow_Profiles.csv'

[home.battery]
max_rate = 5
capacity = 13.5
cap_bounds = [ 0.15, 0.85,]
charge_eff = 0.95
discharge_eff = 0.99
cons_penalty = 0.005
max_rate = [3,5]
capacity = [9.0,13.5]
lower_bound = [ 0.01, 0.15]
upper_bound = [ 0.85, 0.99]
charge_eff = [0.85, 0.95]
discharge_eff = [0.97, 0.99]

[home.pv]
area = 32
efficiency = 0.2
area = [20, 32]
efficiency = [0.15, 0.2]

[home.hems]
prediction_horizon = [ 6,]
price_uncertainty = 0.3
sub_subhourly_steps = [ 4,]
solver = "GLPK_MI" # GLPK for linear non-integer, GUROBI (Licensed) for quadratic integer, ECOS for quadratic non-integer
prediction_horizon = 6
sub_subhourly_steps = 6
discount_factor = 0.92
solver = "GLPK_MI"

[simulation]
start_datetime = "2015-01-01 00"
end_datetime = "2015-03-01 00"
loop_days = true
random_seed = 12
n_nodes = 4
load_zone = "LZ_HOUSTON"
check_type = "all"
run_rbo_mpc = false
run_rl_agg = true
run_rl_simplified = false
checkpoint_interval = "daily"

[rl] # for naming
version = [ "test",]

[rl.parameters] # depricated for use with OpenAI Gym
learning_rate = [ 0.01,]
discount_factor = [ 1.0,]
batch_size = [ 4, 32,]
exploration_rate = [ 0.01,]
twin_q = false

[rl.utility]
rl_agg_action_horizon = [ 6, 4,]
rl_agg_forecast_horizon = 1
base_price = 0.1
action_space = [ -1.0, 1.0,]
hourly_steps = [ 1,]
minutes_per_step = 120
tou_enabled = false

[rl.utility.tou] # only necessary if tou_enabled == true
[agg.tou]
shoulder_times = [ 9, 21,]
shoulder_price = 0.09
peak_times = [ 14, 18,]
peak_price = 0.13

[rl.simplified]
response_rate = 0.3
offset = 0.2
61 changes: 21 additions & 40 deletions dragg/data/config.toml
Original file line number Diff line number Diff line change
@@ -1,46 +1,33 @@
[community]
total_number_homes = 5
total_number_homes = 10
homes_battery = 0
homes_pv = 0
homes_pv_battery = 2
homes_pv = 4
homes_pv_battery = 0
overwrite_existing = true
house_p_avg = 1.2

[simulation]
start_datetime = "2015-01-01 00"
end_datetime = "2015-03-01 00"
loop_days = true
end_datetime = "2015-01-04 00"
random_seed = 12
n_nodes = 4
load_zone = "LZ_HOUSTON"
check_type = "all"
run_rbo_mpc = false
run_rl_agg = true
run_rl_simplified = false
run_rbo_mpc = true
checkpoint_interval = "daily"
named_version = "test"

[rl]
version = [ "dn-cleaned", "dn-test", ]
[agg]
base_price = 0.07
subhourly_steps = 1
tou_enabled = true
spp_enabled = false

[rl.parameters]
learning_rate = [ 0.01,]
discount_factor = [ 1.0,]
batch_size = [ 4, 32,]
exploration_rate = [ 0.01,]
twin_q = false

[rl.utility]
rl_agg_action_horizon = [ 6, 4,]
rl_agg_forecast_horizon = 1
base_price = 0.1
action_space = [ -1.0, 1.0,]
hourly_steps = [ 1,]
minutes_per_step = 120
tou_enabled = false

[rl.simplified]
response_rate = 0.3
offset = 0.2
[agg.rl]
action_horizon = 1
forecast_horizon = 1
prev_timesteps = 12
max_rp = 0.02

[home.hvac]
r_dist = [ 6.8, 9.199999999999999,]
Expand All @@ -52,11 +39,11 @@ temp_deadband_dist = [ 2, 3,]

[home.wh]
r_dist = [ 18.7, 25.3,]
c_dist = [ 4.25, 5.75,]
p_dist = [ 2.5, 2.5,]
sp_dist = [ 45.5, 48.5,]
deadband_dist = [ 9, 12,]
size_dist = [ 200, 300,]
waterdraw_file = '100_Random_Flow_Profiles.csv'

[home.battery]
max_rate = [3,5]
Expand All @@ -71,19 +58,13 @@ area = [20, 32]
efficiency = [0.15, 0.2]

[home.hems]
prediction_horizon = [ 6,]
price_uncertainty = 0.3
sub_subhourly_steps = [ 6,]
prediction_horizon = 6
sub_subhourly_steps = 6
discount_factor = 0.92
solver = "GLPK_MI"

[rl.utility.tou]
[agg.tou]
shoulder_times = [ 9, 21,]
shoulder_price = 0.09
peak_times = [ 14, 18,]
peak_price = 0.13

[home.wh.waterdraws]
n_big_draw_dist = [ 2, 5,]
n_small_draw_dist = [ 0, 0,]
big_draw_size_dist = [ 25, 40,]
small_draw_size_dist = [ 7.5, 15.0,]
4 changes: 2 additions & 2 deletions dragg/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# include_runs = {}
# add_outputs = {}

r = Reformat(mpc_params={"mpc_discomfort":[]})
r.main() # use main to plot a suite of graphs
# r = Reformat(mpc_params={"mpc_discomfort":[]})
# r.main() # use main to plot a suite of graphs
# r.save_images() # saves the images
# r.rl2baseline() # specific plots available through named methods
36 changes: 11 additions & 25 deletions dragg/mpc_calc.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,9 @@
from dragg.redis_client import RedisClient
from dragg.logger import Logger

def manage_home_forecast(home):
"""
Calls class method as a top level function (picklizable)
:return: list
"""
return home.forecast_home()

def manage_home(home):
"""
Calls class method as a top level function (picklizable)
Calls class method as a top level function (picklizable by pathos)
:return: None
"""
home.run_home()
Expand All @@ -32,7 +25,7 @@ class MPCCalc:
def __init__(self, home):
"""
params
home: Dictionary with keys
home: Dictionary with keys for HVAC, WH, and optionally PV, battery parameters
"""
self.home = home # reset every time home retrieved from Queue
self.name = home['name']
Expand Down Expand Up @@ -122,7 +115,6 @@ def redis_get_prev_optimal_vals(self):
self.prev_optimal_vals = self.redis_client.conn.hgetall(key)

def initialize_environmental_variables(self):
# get a connection to redis
self.redis_client = RedisClient()

# collect all values necessary
Expand All @@ -132,7 +124,6 @@ def initialize_environmental_variables(self):
self.all_spp = self.redis_client.conn.lrange('SPP', 0, -1)
self.all_tou = self.redis_client.conn.lrange('tou', 0, -1)
self.base_cents = float(self.all_tou[0])
self.tracked_price = [float(i) for i in self.all_tou[:12]]

# cast all values to proper type
self.start_hour_index = int(float(self.start_hour_index))
Expand All @@ -151,13 +142,14 @@ def setup_base_problem(self):
try:
self.solver = solvers[self.home['hems']['solver']]
except:
self.solver = cp.GUROBI
self.solver = cp.GLPK_MI

# Set up the horizon for the MPC calc (min horizon = 1, no MPC)
self.sub_subhourly_steps = max(1, int(self.home['hems']['sub_subhourly_steps'][0]))
self.sub_subhourly_steps = max(1, int(self.home['hems']['sub_subhourly_steps']))
self.dt = max(1, int(self.home['hems']['hourly_agg_steps']))
self.horizon = max(1, int(self.home['hems']['horizon'] * self.dt))
self.h_plus = self.horizon + 1
self.discount = float(self.home['hems']['discount_factor'])

# Initialize RP structure so that non-forecasted RPs have an expected value of 0.
self.reward_price = np.zeros(self.horizon)
Expand Down Expand Up @@ -196,7 +188,7 @@ def setup_base_problem(self):
self.temp_in_max = cp.Constant(float(self.home["hvac"]["temp_in_max"]))
self.t_in_init = float(self.home["hvac"]["temp_in_init"])

self.max_load = max(self.hvac_p_c.value, self.hvac_p_h.value) + self.wh_p.value
self.max_load = (max(self.hvac_p_c.value, self.hvac_p_h.value) + self.wh_p.value) * self.sub_subhourly_steps

def water_draws(self):
draw_sizes = (self.horizon // self.dt + 1) * [0] + self.home["wh"]["draw_sizes"]
Expand Down Expand Up @@ -273,6 +265,8 @@ def get_initial_conditions(self):
self.water_draws()

if self.timestep == 0:
self.initialize_environmental_variables()

self.temp_in_init = cp.Constant(self.t_in_init)
self.temp_wh_init = cp.Constant((self.t_wh_init*(self.wh_size - self.draw_size[0]) + self.tap_temp * self.draw_size[0]) / self.wh_size)

Expand Down Expand Up @@ -309,12 +303,10 @@ def add_base_constraints(self):
if max(self.oat_current_ev) <= 30: # "winter"
self.hvac_heat_max = self.sub_subhourly_steps
self.hvac_cool_max = 0
# self.constraints += [self.hvac_cool_on == 0]

else: # "summer"
self.hvac_heat_max = 0
self.hvac_cool_max = self.sub_subhourly_steps
# self.constraints += [self.hvac_heat_on == 0]

self.constraints = [
# Indoor air temperature constraints
Expand All @@ -341,7 +333,7 @@ def add_base_constraints(self):
self.temp_wh_ev >= self.temp_wh_min,
self.temp_wh_ev <= self.temp_wh_max,

self.temp_wh == self.temp_wh_init # !!!! significant change (dT/R) + (p/C) rather than (dT/R + p)/C
self.temp_wh == self.temp_wh_init
+ 3600 * (((self.temp_in_ev[1] - self.temp_wh_init) / self.wh_r)
+ self.wh_heat_on[0] * self.wh_p) / (self.wh_c * self.dt),
self.temp_wh >= self.temp_wh_min,
Expand Down Expand Up @@ -400,7 +392,7 @@ def set_base_p_grid(self):
"""
self.constraints += [
# Set grid load
self.p_grid == self.p_load # p_load = p_hvac + p_wh
self.p_grid == self.p_load # where p_load = p_hvac + p_wh
]

def set_battery_only_p_grid(self):
Expand Down Expand Up @@ -450,7 +442,7 @@ def solve_mpc(self):
self.wh_weighting = 10
self.objective = cp.Variable(self.horizon)
self.constraints += [self.cost == cp.multiply(self.total_price, self.p_grid)] # think this should work
self.weights = cp.Constant(np.power(0.92*np.ones(self.horizon), np.arange(self.horizon)))
self.weights = cp.Constant(np.power(self.discount*np.ones(self.horizon), np.arange(self.horizon)))
self.obj = cp.Minimize(cp.sum(cp.multiply(self.cost, self.weights))) #+ self.wh_weighting * cp.sum(cp.abs(self.temp_wh_max - self.temp_wh_ev))) #cp.sum(self.temp_wh_sp - self.temp_wh_ev))
self.prob = cp.Problem(self.obj, self.constraints)
if not self.prob.is_dcp():
Expand All @@ -476,8 +468,6 @@ def implement_presolve(self):
+ (((self.temp_in_ev[1:self.h_plus] - self.temp_wh_ev[:self.horizon]) / self.wh_r)
+ self.wh_heat_on * self.wh_p) / (self.wh_c * self.dt),

# self.p_load == self.sub_subhourly_steps * (self.hvac_p_c * self.hvac_cool_on + self.hvac_p_h * self.hvac_heat_on + self.wh_p * self.wh_heat_on),

self.hvac_cool_on == np.array(self.presolve_hvac_cool_on, dtype=np.double),
self.hvac_heat_on == np.array(self.presolve_hvac_heat_on, dtype=np.double),
self.wh_heat_on == np.array(self.presolve_wh_heat_on, dtype=np.double)
Expand Down Expand Up @@ -643,11 +633,7 @@ def cast_redis_curr_rps(self):
:return: None
"""
rp = self.redis_client.conn.lrange('reward_price', 0, -1)
# num_agg_steps_seen = int(np.ceil(self.horizon / self.sub_subhourly_steps))
# self.reward_price[:min(len(rp), num_agg_steps_seen)] = rp[:min(len(rp), num_agg_steps_seen)]
self.reward_price = rp[:self.horizon]
self.tracked_price[:-1] = self.tracked_price[1:]
self.tracked_price[0] = self.reward_price[0]
self.log.info(f"ts: {self.timestep}; RP: {self.reward_price[0]}")

def solve_type_problem(self):
Expand Down
Loading

0 comments on commit 52a4dec

Please sign in to comment.