def run_swmm(): #======================================= # setup all the nodes before starting #======================================= sim = Simulation('./pipe_test.inp') #======================================= # Start the simulation #======================================= print(sim._isStarted) sim.start() print(sim._isStarted) node_names = ['Inlet', 'Outlet'] link_names = ['Culvert'] nodes = [Nodes(sim)[names] for names in node_names] links = [Links(sim)[names] for names in link_names] # type, area, length, orifice_coeff, free_weir_coeff, submerged_weir_coeff opening0 = nodes[0].create_opening(4, 1.0, 1.0, 0.6, 1.6, 1.0) opening0 = nodes[1].create_opening(4, 1.0, 1.0, 0.6, 1.6, 1.0) print("\n") print("n0 is coupled? ", nodes[0].is_coupled) print("n1 is coupled? ", nodes[1].is_coupled) nodes[0].overland_depth = 1.0 nodes[0].coupling_area = 1.0 # This step_advance should be an integer multiple of the routing step # which is set in the ,inp file. Currently set to 1s. # Should be able to interrogate sim to find out what the # routing stepsize is. Maybe should issue a warning if # step_advance is set lower than the routing step size. # Indeed maybe step_advance should just allow advance n routing steps? for i in range(50): ids = dict() volumes = sim.coupling_step(1.0) print("Step:", i) print("Current time:", sim.current_time) #print("volumes:",volumes) #print(volumes) for flows in volumes: #print(flows) vols = flows[1] for key in vols: print("Volume total at node", key, "at time", flows[0], ":", vols[key])
class Env: def __init__(self, input_file): self.input_file = input_file self.sim = Simulation(self.input_file) self.sim.start() self.time = 1.0 def step(self): if self.time > 0: done = False self.time = self.sim._model.swmm_step() else: done = True print("Simulation Ended") return done def terminate(self): self.sim._model.swmm_end() self.sim._model.swmm_close() def depthN(self, node_id): return self.sim._model.getNodeResult(node_id, 5) def depthL(self, link_id): return self.sim._model.getLinkResult(link_id, 1) def flow(self, link_id): return self.sim._model.getLinkResult(link_id, 0) def get_precip(self, subcatchment_id): pass def set_precip(self, subcatchment_id): pass def get_gate(self, orifice): return self.sim._model.getLinkResult(orifice, 6) def set_gate(self, orifice, gate): self.sim._model.setLinkSetting(orifice, gate) def get_pollutant_node(self, node): return self.sim._model.getNodeResult(node, 100) def get_pollutant_link(self, link): return self.sim._model.getLinkResult(link, 100) def reset(self): self.sim._model.swmm_end() self.sim._model.swmm_close() # Start the next simulation self.sim._model.swmm_open() self.sim._model.swmm_start() self.time = 1.0
class BasicEnv(Env): def __init__(self, inp_file, fcst_file, depth=4.61): # initialize simulation self.input_file = inp_file self.sim = Simulation(self.input_file) # read input file self.fcst_file = fcst_file self.fcst = np.genfromtxt(self.fcst_file, delimiter=',') # read forecast file as array self.control_time_step = 900 # control time step in seconds self.sim.step_advance(self.control_time_step) # set control time step node_object = Nodes(self.sim) # init node object self.St1 = node_object["St1"] self.St2 = node_object["St2"] self.J1 = node_object["J1"] self.depth = depth self.St1.full_depth = self.depth self.St2.full_depth = self.depth link_object = Links(self.sim) # init link object self.R1 = link_object["R1"] self.R2 = link_object["R2"] self.sim.start() if self.sim.current_time == self.sim.start_time: self.R1.target_setting = 0.5 self.R2.target_setting = 0.5 sim_len = self.sim.end_time - self.sim.start_time self.T = int(sim_len.total_seconds() / self.control_time_step) self.t = 1 self.state = np.concatenate([ np.asarray([ self.St1.depth, self.St2.depth, self.J1.depth, self.St1.flooding, self.St2.flooding, self.J1.flooding, self.R1.current_setting, self.R2.current_setting ]), self.fcst[self.t] ]) self.action_space = spaces.Box(low=np.array([0, 0]), high=np.array([1, 1]), dtype=np.float32) self.observation_space = spaces.Box(low=0, high=1000, shape=(len(self.state), ), dtype=np.float32) def step(self, action): self.R1.target_setting = action[0] self.R2.target_setting = action[1] self.sim.__next__() self.state = np.concatenate([ np.asarray([ self.St1.depth, self.St2.depth, self.J1.depth, self.St1.flooding, self.St2.flooding, self.J1.flooding, self.R1.current_setting, self.R2.current_setting ]), self.fcst[self.t] ]) if self.t < self.T - 1: reward = 0 done = False else: reward = -(self.St1.statistics['flooding_volume'] * 100 + self.St2.statistics['flooding_volume'] * 100 + self.J1.statistics['flooding_volume'] * 0.5) done = True self.t += 1 info = {} return self.state, reward, done, info def reset(self): self.sim.close() self.sim = Simulation(self.input_file) self.fcst = np.genfromtxt(self.fcst_file, delimiter=',') # read forecast file as array self.sim.step_advance(self.control_time_step) # set control time step node_object = Nodes(self.sim) # init node object self.St1 = node_object["St1"] self.St2 = node_object["St2"] self.J1 = node_object["J1"] link_object = Links(self.sim) # init link object self.R1 = link_object["R1"] self.R2 = link_object["R2"] self.St1.full_depth = self.depth self.St2.full_depth = self.depth self.sim.start() self.t = 1 if self.sim.current_time == self.sim.start_time: self.R1.target_setting = 0.5 self.R2.target_setting = 0.5 self.state = np.concatenate([ np.asarray([ self.St1.depth, self.St2.depth, self.J1.depth, self.St1.flooding, self.St2.flooding, self.J1.flooding, self.R1.current_setting, self.R2.current_setting ]), self.fcst[self.t] ]) return self.state def close(self): self.sim.report() self.sim.close()
class SWMM_env(Environment): """This class defines a simple thermostat environment. It is a room with a heater, and when the heater is on, the room temperature will approach the max heater temperature (usually 1.0), and when off, the room will decay to a temperature of 0.0. The exponential constant that determines how fast it approaches these temperatures over timesteps is tau. """ # J: current_temp could be changed to current_flow which is Links(sim)["8"].flow*35.3147 # J: this is where we define everything and start the swmm model def __init__( self, inp_file ): # the max depth of the ponds is 2 meters. This I believe is also an intial setting ## Some initializations. Will eventually parameterize this in the constructor. self.modelfile = inp_file self.sim = Simulation(self.modelfile) self.controlstep = 900 #in seconds self.sim.step_advance(self.controlstep) node_object = Nodes(self.sim) self.P1 = node_object["P1"] self.P2 = node_object["P2"] #self.depth = depth # self.P1.depth = self.depth # self.P2.depth = self.depth # init link objects - includes downstream link and both orifices link_object = Links(self.sim) self.L8 = link_object["8"] #self.flow = flow #self.L8.flow = self.L8.flow self.O1 = link_object["1"] self.O2 = link_object["2"] self.sim.start() if self.sim.current_time == self.sim.start_time: #initially sets the orifices at half way open self.O1.target_setting = 0.5 self.O2.target_setting = 0.5 sim_len = self.sim.end_time - self.sim.start_time self.T = int(sim_len.total_seconds() / self.controlstep) self.state = np.concatenate([ np.asarray([ self.P1.depth, self.P2.depth, self.L8.flow, self.P1.flooding, self.P2.flooding, self.O1.current_setting, self.O2.current_setting ]) ]) super().__init__() # J: I think this should consider the 6 states referenced in the self.state line above. # def states(self): # return dict(type='float', shape=(6,)) # J: would the actions be the position of the valves at P1 and P2? Would we need to figure # J: out how to program the lid for this section, given two valve positions? # need to add a min and a max value to capture everything between 0 and 1 def actions(self): """Action 0 means no heater, temperature approaches 0.0. Action 1 means the heater is on and the room temperature approaches 1.0. """ return dict(type='int', num_values=2) #(original comment) Optional, should only be defined if environment has a natural maximum #(original comment) episode length # I can change the frequency (maybe 15 minutes, maybe something else) # def max_episode_timesteps(self): # return super().max_episode_timesteps() ### J: Not sure how this works with the swmm model. # Optional def close(self): self.sim.report() self.sim.close() ### J: Not sure how this works with the swmm model. def reset(self): """Reset state. """ # state = np.random.random(size=(1,)) self.sim.close() self.sim = Simulation(self.modelfile) self.sim.step_advance(self.controlstep) node_object = Nodes(self.sim) self.P1 = node_object["P1"] self.P2 = node_object["P2"] self.P1.depth = self.depth self.P2.depth = self.depth link_object = Links(self.sim) self.L8 = link_object["8"] self.L8.flow = self.flow self.sim.start() if self.sim.current_time == self.sim.start_time: self.L8.target_setting = 0 self.state = np.concatenate([ np.asarray([ self.P1.depth, self.P2.depth, self.L8.flow, self.P1.flooding, self.P2.flooding, self.O1.current_setting, self.O2.current_setting ]) ]) return self.state # J: The response should be the total flow in Pipe8, correct? We might not need this piece # def response(self, action): # """Respond to an action. When the action is 1, the temperature # exponentially decays approaches 1.0. When the action is 0, # the current temperature decays towards 0.0. # """ # return action + (self.current_temp - action) * math.exp(-1.0 / self.tau) # J: The reward is 0 if the flow in Pipe8 is betwee, X1 and X2, or else we could have # J: it negatively increase as the flow increases/decreases beyond the boundary. def reward_compute(self): """ The reward here is 0 if the current temp is between 0.4 and 0.6, else it is distance the temp is away from the 0.4 or 0.6 boundary. Return the value within the numpy array, not the numpy array. """ # the reward should take into consideration flow being outside of desired range; should it also consider flooding? # reward needs to be based on the state - need to pass in new state information to calculate reward delta = abs(self.L8.flow - 0.25) if delta < 0.1: return 0.0 else: return -delta[0] + 0.1 # check this with the step function in Ben's code def execute(self, actions): ## Check the action is either 0 or 1 -- heater on or off. self.O1.target_setting = actions[0] self.O2.target_setting = actions[1] self.sim.__next__() self.state = np.concatenate([ np.asarray([ self.P1.depth, self.P2.depth, self.P1.flooding, self.P2.flooding, self.L8.current_setting ]) ]) # ## Increment timestamp # self.timestep += 1 # ## Update the current_temp # self.current_temp = self.response(actions) ## Compute the reward reward = self.reward_compute() ## The only way to go terminal is to exceed max_episode_timestamp. ## terminal == False means episode is not done ## terminal == True means it is done. terminal = False return self.state, terminal, reward
Bi = Dirichlet_boundary([0.1, 0, 0]) # Inflow Br = Reflective_boundary(domain) # Solid reflective wall Bo = Dirichlet_boundary([-5, 0, 0]) # Outflow domain.set_boundary({'left': Br, 'right': Br, 'top': Br, 'bottom': Br}) # ------------------------------------------------------------------------------ # Setup inject water # ------------------------------------------------------------------------------ op_inlet = Rate_operator(domain, radius=0.5, center=(2., 2.)) op_outlet = Rate_operator(domain, radius=0.5, center=(12., 2.)) # from pyswmm import Simulation, Nodes, Links sim = Simulation('./pipe_test.inp') sim.start() node_names = ['Inlet', 'Outlet'] link_names = ['Culvert'] nodes = [Nodes(sim)[names] for names in node_names] links = [Links(sim)[names] for names in link_names] # type, area, length, orifice_coeff, free_weir_coeff, submerged_weir_coeff nodes[0].create_opening(4, 0.785, 1.0, 0.6, 1.6, 1.0) nodes[0].coupling_area = 0.785 nodes[1].create_opening(4, 0.785, 1.0, 0.6, 1.6, 1.0) nodes[1].coupling_area = 0.785 print("node1_is_open?:", nodes[1].is_coupled)
class BasicEnv(Env): def __init__(self,depth=5): # initialize simulation self.sim = Simulation(swmm_inp) # read input file self.control_time_step = 900 # control time step in seconds self.sim.step_advance(self.control_time_step) # set control time step node_object = Nodes(self.sim) # init node object self.St1 = node_object["St1"] self.St2 = node_object["St2"] self.J3 = node_object["J3"] self.depth = depth self.St1.full_depth = self.depth self.St2.full_depth = self.depth link_object = Links(self.sim) # init link object self.R1 = link_object["R1"] self.R2 = link_object["R2"] self.sim.start() if self.sim.current_time == self.sim.start_time: self.R1.target_setting = 0.5 self.R2.target_setting = 0.5 sim_len = self.sim.end_time - self.sim.start_time self.T = int(sim_len.total_seconds()/self.control_time_step) self.t = 1 #print('T=', self.T) self.state = np.asarray([self.St1.depth, self.St2.depth, self.J3.depth, self.St1.flooding, self.St2.flooding, self.J3.flooding]) self.action_space = spaces.Box(low=np.array([0,0]),high=np.array([1,1]), dtype=np.float32) self.observation_space = spaces.Box(low=0, high = 1000, shape=(len(self.state),),dtype=np.float32) def step(self,action): self.R1.target_setting = action[0] self.R2.target_setting = action[1] self.sim.__next__() self.state = np.asarray([self.St1.depth, self.St2.depth, self.J3.depth, self.St1.flooding, self.St2.flooding, self.J3.flooding]) reward = - (self.St1.flooding + self.St2.flooding + self.J3.flooding) if self.t < self.T-1 : done = False else: done = True # self.sim.close() self.t += 1 info = {} return self.state, reward, done, info def reset(self): self.sim.close() self.sim = Simulation(swmm_inp) self.sim.step_advance(self.control_time_step) # set control time step node_object = Nodes(self.sim) # init node object self.St1 = node_object["St1"] self.St2 = node_object["St2"] self.J3 = node_object["J3"] link_object = Links(self.sim) # init link object self.R1 = link_object["R1"] self.R2 = link_object["R2"] self.St1.full_depth = self.depth self.St2.full_depth = self.depth self.sim.start() self.t = 1 if self.sim.current_time == self.sim.start_time: self.R1.target_setting = 0.5 self.R2.target_setting = 0.5 self.state = np.asarray([self.St1.depth, self.St2.depth, self.J3.depth, self.St1.flooding, self.St2.flooding, self.J3.flooding]) return self.state def close(self): self.sim.report() self.sim.close()
class StormwaterEnv(gym.Env): metadata = {'render.modes': ['human']} def __init__(self, R=6, J=4, swmm_inp="data/simple3.inp"): super(StormwaterEnv, self).__init__() self.total_rewards = [] self.eps_reward = 0 self.global_current_step = 0 self.current_step = 0 self.control_time_step = 900 self.swmm_inp = swmm_inp self.temp_height = np.zeros(2, dtype='int32') # St1.depth, St2.depth self.temp_valve = np.zeros( 2, dtype='int32') # R1.current_setting, R2.current_setting self.R = R self.J = J self.log_dumps = [[]] def reset(self): # make this dynamic later self.swmm_inp = "data/simple3.inp" self.sim = Simulation(self.swmm_inp) self.sim.step_advance(self.control_time_step) # set control time step self.node_object = Nodes(self.sim) self.link_object = Links(self.sim) self.total_rewards.append(self.eps_reward) self.eps_reward = 0 self.global_current_step += 1 self.current_step = 0 self.done = False self.sim.start() self.sim_len = self.sim.end_time - self.sim.start_time self.T = self.sim_len.total_seconds() // self.control_time_step for i in range(1, self.R + 1): self.link_object['R' + str(i)].target_setting = random.randrange(1) self.settings = [ self.link_object['R' + str(i)].current_setting for i in range(1, self.R + 1) ] # one for loop would be faster but less readable # making new lists all the time is probably bad self.depths = [ self.node_object['St' + str(i)].depth for i in range(1, self.R + 1) ] self.depths.extend([ self.node_object['J' + str(i)].depth for i in range(2, self.J + 1) ]) self.flooding = [ self.node_object['St' + str(i)].flooding for i in range(1, self.R + 1) ] self.flooding.extend([ self.node_object['J' + str(i)].flooding for i in range(2, self.J + 1) ]) self.reward = reward_function(self.depths, self.flooding) self.eps_reward += self.reward return np.asarray(self.settings + self.depths + self.flooding) # Take action # + Initiate the step in the simulation # Make observation / calculate state # calculate the reward # check if done # Do some logging for graphing def step(self, action): self.current_step += 1 # Decide whether this should be before or after taking actions ##### Take Action ##### for i in range(1, self.R + 1): self.link_object['R' + str(i)].target_setting = action[i - 1] self.sim.__next__() ##### Make Observation ##### self.settings = [ self.link_object['R' + str(i)].current_setting for i in range(1, self.R + 1) ] self.depths = [ self.node_object['St' + str(i)].depth for i in range(1, self.R + 1) ] self.depths.extend([ self.node_object['J' + str(i)].depth for i in range(2, self.J + 1) ]) self.flooding = [ self.node_object['St' + str(i)].flooding for i in range(1, self.R + 1) ] self.flooding.extend([ self.node_object['J' + str(i)].flooding for i in range(2, self.J + 1) ]) # one for loop would be faster but less readable (For the above) # making new lists all the time is probably bad # Actually timed this and performed better than changing the elements ##### Calculate Reward ##### self.reward = -np.max(self.flooding) * np.sum(self.flooding) self.eps_reward += self.reward ##### Check if Done ##### self.done = False if self.current_step < self.T - 1 else True ##### for graphing ##### if self.current_step == 1: # self.log_dumps.append([]) self.log_dumps[-1] = [] self.log_dumps[-1].append( (self.reward, [self.settings, self.depths, self.flooding], self.current_step)) return np.asarray(self.settings + self.depths + self.flooding), self.reward, self.done, { } # {} is debugging information def close(self): self.sim.report() self.sim.close() def render(self, mode="human"): # This's probably not useful at all at the moment but should be here return str(self.settings) + "\n" + str(self.depths) + "\n" + str( self.flooding) + "\n" def graph(self, location): for plot, dump in enumerate(self.log_dumps[-1:]): settings, depths, floodings = [[] for i in range(self.R)], [ [] for i in range(self.R + self.J - 1) ], [[] for i in range(self.R + self.J - 1)] rewards = [] for reward, state, timestep in dump: # timestep should stay local here rewards.append(reward) setting, depth, flooding = state for i, R in enumerate(settings): R.append(setting[i]) for i, S_depth in enumerate(depths): S_depth.append(depth[i]) for i, S_flooding in enumerate(floodings): S_flooding.append(flooding[i]) for i in range(1, self.R + 1): plt.subplot(2, 3, i) plt.plot(settings[i - 1]) plt.ylim(0, 1) plt.title('R' + str(i)) plt.ylabel("Valve Opening") plt.xlabel("time step") plt.tight_layout() if (plot == 5): plt.savefig(location + "TEST_" + str(timestep) + "_STATES", dpi=300) else: plt.savefig(location + str(timestep) + "_STATES", dpi=300) plt.clf() for i in range(1, self.R + 1): plt.subplot(2, 3, i) plt.plot(depths[i - 1]) plt.ylim(0, 5) plt.title('St' + str(i) + " Depth") plt.ylabel("Feet") plt.xlabel("time step") plt.tight_layout() if (plot == 5): plt.savefig(location + "TEST_" + str(timestep) + "_DEPTHS", dpi=300) else: plt.savefig(location + str(timestep) + "_DEPTHS", dpi=300) plt.clf() for i in range(2, self.J + 1): plt.subplot(2, 2, i - 1) plt.plot(floodings[self.R + i - 2]) plt.title('J' + str(i) + " flooding") plt.ylabel("Feet") plt.xlabel("time step") plt.subplot(2, 2, 4) plt.bar([0, 1, 2, 3, 4, 5, 6, 7, 8], [sum(floodings[i]) for i in range(len(floodings))], tick_label=[ "St1", "St2", "St3", "St4", "St5", "St6", "J2", "J3", "J4" ]) plt.ylim(0) plt.title('total_flooding') plt.ylabel("10^3 cubic feet") plt.xlabel("time step") plt.tight_layout() if (plot == 5): plt.savefig(location + "TEST_" + str(timestep) + "_FLOODING", dpi=300) else: plt.savefig(location + str(timestep) + "_FLOODING", dpi=300) plt.clf() plt.subplot(2, 1, 1) plt.plot(rewards) # plt.ylim(0, 5) plt.title('Rewards') plt.ylabel("Reward") plt.xlabel("time step") plt.subplot(2, 1, 2) plt.ylim(-5000, 0) plt.plot(self.total_rewards) plt.title('Total Rewards') plt.ylabel("Reward") plt.xlabel("eps") plt.tight_layout() if (plot == 5): plt.savefig(location + "TEST_" + str(timestep) + "_REWARDS", dpi=300) else: plt.savefig(location + str(timestep) + "_REWARDS", dpi=300) plt.clf()
class StormwaterEnv(gym.Env): def __init__(self, swmm_inp=""): self.floodings = -1 self.eps_flooding = [] self.eps_depths = [[], [], []] self.eps_action = [[], [], []] super(StormwaterEnv, self).__init__() self.total_rewards = [] self.eps_reward = 0 self.num_steps = 0 self.timestep = 0 self.time = 0 self.swmm_inp = swmm_inp self.temp_height = np.zeros(2, dtype='int32') # St1.depth, St2.depth self.temp_valve = np.zeros( 2, dtype='int32') # R1.current_setting, R2.current_setting self.i = 0 self.flood = [] self.log_dumps = [] self.links = ['R1', 'R2', 'R3'] self.nodes = ['St1', 'St2', 'St3'] self.rl, self.baseline = [], [] def reset(self, date=False, test=False): self.test = test self.settings, self.depths, self.flooding = [], [], [] self.i += 1 self.swmm_inp = "data/simple1.inp" dTest = date if (not dTest): with open("data/dates.txt", "r") as f: date = list(csv.reader(f, delimiter=' ')) random.Random(10).shuffle(date) if not test: time = (random.randint(0, int(len(date) * 0.9))) self.test = False else: if not self.test: time = int(len(date) * 0.85) self.test = True time = 0 else: self.time += 1 time = self.time self.time = time year = int(date[time][0]) month = int(date[time][1]) day = int(date[time][2]) self.t = (str(year) + " " + str(month) + " " + str(day)) self.date = [month, day, year] with open("data/simple1.inp", "r") as File: lines = File.readlines() with open("data/simple1.inp", "w") as File: for line in lines: if "REPORT_START_DATE" in line: File.write(line) elif "START_DATE" in line: File.write("START_DATE " + str(month) + "/" + str(day) + "/" + str(year) + "\n") elif "END_DATE" in line: File.write("END_DATE " + str((month)) + "/" + str(day + 1) + "/" + str(year) + "\n") else: File.write(line) if not dTest: self.eps_flooding.append(self.floodings) self.total_rewards.append(self.eps_reward) self.timestep += 1 self.eps_reward = 0 self.floodings = 0 self.flood = [] self.eps_depths = [[], [], []] self.eps_action = [[], [], []] self.num_steps = 0 self.done = False self.current_step = 0 self.sim = Simulation(self.swmm_inp) self.control_time_step = 900 # control time step in seconds self.sim.step_advance(self.control_time_step) # set control time step self.node_object = Nodes(self.sim) self.link_object = Links(self.sim) print(self.i) self.sim.start() self.sim_len = self.sim.end_time - self.sim.start_time self.num_steps = int(self.sim_len.total_seconds() / self.control_time_step) x = 0 for i in self.links: y = random.randrange(1) self.link_object[i].target_setting = y self.eps_action[x].append(y) x += 1 for i in self.links: self.settings.append(self.link_object[i].current_setting) for i in self.nodes: self.depths.append(self.node_object[i].depth) self.flooding.append(self.node_object[i].flooding) self.reward = reward_function(self.depths, self.flooding) self.eps_reward += self.reward state = [] state = self.settings.copy() state.extend(self.depths) state.extend(self.flooding) self.day = [] time = list(open("forcast.txt", "r")) time = list(map(lambda s: s.strip(), time)) for i in time: if (self.t in i): self.day.append(i) time = str(self.sim.current_time).split(" ") time = time[1].split(":") cur = self.day[int(time[0])].split(" ")[3] nxt = self.day[int(time[0]) + 1].split(" ")[3] #cur = int(float(cur) * random.uniform(.95,1.05)) #nxt = int(float(nxt) * random.uniform(.85,1.15)) state.extend([cur, nxt]) xx = [] for x in state: xx.append(float(x) * random.uniform(0.9, 1.1)) #state = [float(x) * random.uniform(0.9,1.1) for x in state] return state def step(self, action): self.current_step += 1 self.settings, self.depths, self.flooding = [], [], [] self.node_object = Nodes(self.sim) self.link_object = Links(self.sim) x = 0 for i in self.links: self.link_object[i].target_setting = action[x] self.eps_action[x].append(action[x]) x += 1 self.sim.__next__() for i in self.links: self.settings.append(self.link_object[i].current_setting) ii = 0 for i in self.nodes: self.depths.append(self.node_object[i].depth) self.flooding.append(self.node_object[i].flooding) self.eps_depths[ii].append(self.node_object[i].depth) ii += 1 self.floodings += sum(self.flooding) self.flood.append(sum(self.flooding)) self.reward = reward_function(self.depths, self.flooding) self.eps_reward += self.reward state = [] state = self.settings.copy() state.extend(self.depths) state.extend(self.flooding) time = str(self.sim.current_time).split(" ") time = time[1].split(":") cur = self.day[int(time[0])].split(" ")[3] if (int(time[0]) < 23): nxt = self.day[int(time[0]) + 1].split(" ")[3] else: nxt = 0 cur = int(float(cur) * random.uniform(.95, 1.05)) nxt = int(float(nxt) * random.uniform(.85, 1.15)) state.extend([cur, nxt]) xx = [] for x in state: xx.append(float(x) * random.uniform(0.9, 1.1)) return state, self.reward, self.done #, {} # {} is debugging information def close(self): self.sim.report() self.sim.close() def graph(self, location, end=False): with open("plots/data.csv", "a") as f: writer = csv.writer(f, delimiter=',') writer.writerow([self.i]) self.eps_flooding.append(self.floodings) self.total_rewards.append(self.eps_reward) self.eps_depths.append(self.eps_reward) self.old_flooding = self.floodings self.old_rewards = self.eps_reward self.floodrl = self.flood self.depthsRL = self.eps_depths self.actionRL = self.eps_action self.reset(date=True) for i in range(self.num_steps - 1): self.step([1, 1, 1]) self.flooding1 = self.floodings self.eps_reward1 = self.eps_reward self.flood1 = self.flood self.depths1 = self.eps_depths self.action1 = self.eps_action #"Flooding_Sum_P, Reward_Sum_P, Flooding_CFS_P, J1_Depths_P,J2_Depths_P,J3_Depths_P,R1_P,R2_P, Flooding_Sum_RL, Reward_Sum_RL, Flooding_CFS_RL, J1_Depths_RL,J2_Depths_RL,J3_Depths_RL,R1_RL,R2_RL" rows =([[self.flooding1], [self.eps_reward1], self.flood1, self.depths1[0],self.depths1[1],self.depths1[2], self.action1[0], self.action1[1], \ [self.old_flooding], [self.old_rewards], self.floodrl, self.depthsRL[0],self.depthsRL[1],self.depthsRL[2], self.actionRL[0], self.actionRL[1]]) columns = [ "Flooding_Sum_P", "Reward_Sum_P", "Flooding_CFS_P", "J1_Depths_P", "J2_Depths_P", "J3_Depths_P", "R1_P", "R2_P", "Flooding_Sum_RL", "Reward_Sum_RL", "Flooding_CFS_RL", "J1_Depths_RL", "J2_Depths_RL", "J3_Depths_RL", "R1_RL", "R2_RL" ] with open("plots/data.csv", "a") as f: writer = csv.writer(f, delimiter=',') x = 0 for row in rows: row = list(row) row.insert(0, columns[x]) writer.writerow(row) x += 1
class BasicEnv(Env): def __init__(self, inp_file, fcst_file): # initialize simulation self.input_file = inp_file self.sim = Simulation(self.input_file) # read input file self.fcst_file = fcst_file # self.fcst = np.genfromtxt(self.fcst_file, delimiter=',') # read forecast file as array self.fcst = pd.read_csv(self.fcst_file, index_col="datetime", infer_datetime_format=True, parse_dates=True) self.control_time_step = 900 # control time step in seconds self.sim.step_advance(self.control_time_step) # set control time step node_object = Nodes(self.sim) # init node object self.St1 = node_object["st1"] self.St2 = node_object["st2"] self.St3 = node_object["F134101"] link_object = Links(self.sim) # init link object self.R1 = link_object["R1"] self.R2 = link_object["R2"] self.R3 = link_object["R3"] self.sim.start() if self.sim.current_time == self.sim.start_time: self.R1.target_setting = 0.5 self.R2.target_setting = 1 self.R3.target_setting = 0.5 sim_len = self.sim.end_time - self.sim.start_time self.T = int(sim_len.total_seconds()/self.control_time_step) self.t = 1 current_fcst = self.fcst.iloc[self.fcst.index.get_loc(self.sim.current_time, method='nearest')] rain_fcst = sum(current_fcst[:int(len(current_fcst) / 2)]) # total rainfall in forecast tide_fcst = np.mean(current_fcst[int(len(current_fcst) / 2):]) # mean tide in forecast # self.state = np.concatenate([np.asarray([self.St1.depth, self.St3.depth, self.St1.flooding, self.St3.flooding, # self.R1.current_setting, self.R3.current_setting]), # current_fcst]) # self.state = np.asarray([self.St1.depth, self.St3.depth, self.St1.flooding, self.St3.flooding, # self.R1.current_setting, self.R3.current_setting, # rain_fcst, tide_fcst]) self.state = np.asarray([self.St1.depth, self.St3.depth, self.St1.flooding, self.St3.flooding, self.R1.current_setting, self.R3.current_setting, self.R1.pollut_quality['TSS'], self.R3.pollut_quality['TSS'], rain_fcst, tide_fcst]) self.action_space = spaces.Box(low=np.array([0, 0]), high=np.array([1, 1]), dtype=np.float32) self.observation_space = spaces.Box(low=0, high=1000, shape=(len(self.state),), dtype=np.float32) def step(self, action): self.R1.target_setting = action[0] self.R3.target_setting = action[1] self.sim.__next__() # self.state = np.concatenate([np.asarray([self.St1.depth, self.St3.depth, self.St1.flooding, self.St3.flooding, # self.R1.current_setting, self.R3.current_setting]), self.fcst[self.t]]) current_fcst = self.fcst.iloc[self.fcst.index.get_loc(self.sim.current_time, method='nearest')] rain_fcst = sum(current_fcst[:int(len(current_fcst) / 2)]) # total rainfall in forecast tide_fcst = np.mean(current_fcst[int(len(current_fcst) / 2):]) # mean tide in forecast # self.state = np.asarray([self.St1.depth, self.St3.depth, self.St1.flooding, self.St3.flooding, # self.R1.current_setting, self.R3.current_setting, # rain_fcst, tide_fcst]) self.state = np.asarray([self.St1.depth, self.St3.depth, self.St1.flooding, self.St3.flooding, self.R1.current_setting, self.R3.current_setting, self.R1.pollut_quality['TSS'], self.R3.pollut_quality['TSS'], rain_fcst, tide_fcst]) # # 1 flood and depth reward # reward = - (self.St1.flooding + self.St3.flooding + abs(self.St1.depth - 7.5) + abs(self.St3.depth - 3.56)) # # 2 Conditional reward, no pollutants # if rain_fcst > 0: # check if rainfall forecast is positive # reward = - (self.St1.flooding + self.St3.flooding) # instead of flood, use abs difference from pond max? # else: # reward = - (abs(self.St1.depth - 7.5) + abs(self.St3.depth - 3.56)) # 3 flood and pollutant reward reward = - (self.St1.flooding + self.St3.flooding + abs(self.St1.depth - 7.5) + abs(self.St3.depth - 3.56) + self.R1.pollut_quality['TSS'] + self.R3.pollut_quality['TSS']) # # 4 conditional with pollutants reward # if np.sum(self.fcst[self.t, :-1]) > 0: # check if rainfall forecast is positive # reward = - (self.St1.flooding + self.St3.flooding + self.R1.pollut_quality + self.R3.pollut_quality) # else: # reward = - (abs(self.St1.depth - 7.5) + abs(self.St3.depth - 3.56) + # self.R1.pollut_quality + self.R3.pollut_quality) if self.t < self.T-1: done = False else: done = True self.t += 1 info = {} return self.state, reward, done, info def reset(self): self.sim.close() self.sim = Simulation(self.input_file) # self.fcst = np.genfromtxt(self.fcst_file, delimiter=',') # read forecast file as array self.fcst = pd.read_csv(self.fcst_file, index_col="datetime", infer_datetime_format=True, parse_dates=True) self.sim.step_advance(self.control_time_step) # set control time step node_object = Nodes(self.sim) # init node object self.St1 = node_object["st1"] self.St2 = node_object["st2"] self.St3 = node_object["F134101"] link_object = Links(self.sim) # init link object self.R1 = link_object["R1"] self.R2 = link_object["R2"] self.R3 = link_object["R3"] self.sim.start() self.t = 1 if self.sim.current_time == self.sim.start_time: self.R1.target_setting = 0.5 self.R2.target_setting = 1 self.R3.target_setting = 0.5 # self.state = np.concatenate([np.asarray([self.St1.depth, self.St3.depth, self.St1.flooding, self.St3.flooding, # self.R1.current_setting, self.R3.current_setting]), self.fcst[self.t]]) current_fcst = self.fcst.iloc[self.fcst.index.get_loc(self.sim.current_time, method='nearest')] rain_fcst = sum(current_fcst[:int(len(current_fcst) / 2)]) # total rainfall in forecast tide_fcst = np.mean(current_fcst[int(len(current_fcst) / 2):]) # mean tide in forecast # self.state = np.asarray([self.St1.depth, self.St3.depth, self.St1.flooding, self.St3.flooding, # self.R1.current_setting, self.R3.current_setting, # rain_fcst, tide_fcst]) self.state = np.asarray([self.St1.depth, self.St3.depth, self.St1.flooding, self.St3.flooding, self.R1.current_setting, self.R3.current_setting, self.R1.pollut_quality['TSS'], self.R3.pollut_quality['TSS'], rain_fcst, tide_fcst]) return self.state def close(self): self.sim.report() self.sim.close()