Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Adding Sampling Bounds and Random Number Generators #2

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions examples/config/natural_gas_proc_ranges.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# to specify which action should be used
defined_actions:
MSTR-000:
- Temperature
- Pressure
- Enthalpy
- Entropy
- MassFlow
- MolarFlow
- VolumetricFlow
Pre-Chiller:
- OutletTemperature:
range: [290, 305]
units: K
- HeatAdded
- Efficiency
Chiller-1:
- OutletTemperature
- HeatAdded
- Efficiency
HP Separator:
- SeparationPressure
Chiller-2:
- OutletTemperature
- HeatAdded
- Efficiency
Expander-1:
- RotationSpeed
- OutletPressure
- AdiabaticEfficiency
- AdiabaticHead
LP Separator:
- SeparationPressure
Chiller-3:
- OutletTemperature
- HeatAdded
- Efficiency
Condenser:
- OutletTemperature
- HeatAdded
- Efficiency
HEAT-052:
- OutletTemperature
- HeatAdded
- Efficiency
Chiller-4:
- OutletTemperature
- HeatAdded
- Efficiency
Compressor-1:
- RotationSpeed
- AdiabaticEfficiency
- AdiabaticHead
Compressor:
- RotationSpeed
- OutletPressure
- AdiabaticEfficiency
- AdiabaticHead
32 changes: 23 additions & 9 deletions examples/data_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from tqdm import tqdm
import pro_gym
from pro_gym.utils.utils import get_action_space, generate_random_actions, \
create_csv_headers, generate_row_data, generate_fake_time
generate_batch_actions, \
create_csv_headers, generate_row_data, generate_fake_time

# arguments
parser = argparse.ArgumentParser()
Expand All @@ -15,6 +16,7 @@
parser.add_argument("--action-config", type=str, default="config/natural_gas_proc.yaml", help="path to define the action space")
parser.add_argument("--random-range", type=float, default=0.2, help="random range 20 percent +-")
parser.add_argument("--seed", type=int, default=123, help="random seed")
parser.add_argument("--random-method", type=str, default="uniform", help="random number generator method")

if __name__ == "__main__":
# get the arguments
Expand Down Expand Up @@ -42,12 +44,24 @@
row_data = generate_row_data(init_vals, date_times_str[0])
# start to generate data
writer.writerow(row_data)
for iter in tqdm(range(args.steps)):
# generate random actions
random_actions = generate_random_actions(action_space, init_vals, args.random_range)
# execute the random actions
obs_next, _, _, _ = env.step(random_actions)
row_data = generate_row_data(obs_next, date_times_str[iter+1])
writer.writerow(row_data)
env.reset()
if args.random_method == "uniform":
for iter in tqdm(range(args.steps)):
# generate random actions
random_actions = generate_random_actions(action_space, init_vals, args.random_range)
# execute the random actions
obs_next, _, _, _ = env.step(random_actions)
row_data = generate_row_data(obs_next, date_times_str[iter+1])
writer.writerow(row_data)
env.reset()
elif args.random_method == "lhs" or args.random_method == "sobol":
# generate batch actions
batch_actions = generate_batch_actions(action_space, init_vals, number_actions = args.steps, method = args.random_method)
# execute the individual random actions in series
for iter in tqdm(range(args.steps)):
obs_next, _, _, _ = env.step(batch_actions[iter])
row_data = generate_row_data(obs_next, date_times_str[iter+1])
writer.writerow(row_data)
env.reset()
else:
raise NotImplementedError("The method {} is not implemented".format(args.random_method))
csv_file.close()
68 changes: 60 additions & 8 deletions pro_gym/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,73 @@
import yaml
import numpy as np
from datetime import datetime, timedelta
from scipy.stats import qmc

def generate_random_actions(action_space, init_val, random_range=0.2):
actions = {}
def generate_random_actions(action_space, init_val, random_range = 0.2, random_numbers = []):
""" this function is used to generate random actions of the environment """

#determine number of available specs
number_specs = sum(len(unit) for unit in action_space.values())

# if random numbers are not provided, generate them
if len(random_numbers) == 0:
random_numbers = np.random.uniform(0, 1, number_specs)
else: #check if correct size and correct range [0,1]
assert len(random_numbers) == number_specs, "The number of random numbers provided does not match the number of specs"
assert all(0 <= x <= 1 for x in random_numbers), "The random numbers provided are not in the range [0,1]"

actions = {}
for unit_name in action_space.keys():
actions[unit_name] = {}
for avail_spec in action_space[unit_name]:
init_val_ = init_val[unit_name][avail_spec]
upper = init_val_ * (1 + random_range)
lower = init_val_ * (1 - random_range)
sample_val = np.random.uniform(upper, lower)
# assign values
actions[unit_name][avail_spec] = sample_val
""" determine if avail_spec has a specific range """
if isinstance(avail_spec, dict):
avail_spec_name, avail_spec_params = next(iter(avail_spec.items()))
if 'range' in avail_spec_params:
upper = avail_spec_params["range"][1]
lower = avail_spec_params["range"][0]
else:
init_val_ = init_val[unit_name][avail_spec_name]
upper = init_val_ * (1 + random_range)
lower = init_val_ * (1 - random_range)
actions[unit_name][avail_spec_name] = sample_random_value(random_numbers, upper, lower)
else:
init_val_ = init_val[unit_name][avail_spec]
upper = init_val_ * (1 + random_range)
lower = init_val_ * (1 - random_range)
actions[unit_name][avail_spec] = sample_random_value(random_numbers, upper, lower)
return actions

def generate_batch_actions(action_space, init_val, random_range = 0.2, number_actions = 1, method = "uniform"):
""" this function is used to generate a batch of random actions """

#determine number of available specs
number_specs = sum(len(unit) for unit in action_space.values())

#generate random numbers with selected method
if method == "uniform":
random_numbers = np.random.uniform(0, 1, number_actions*number_specs)
elif method == "sobol":
random_numbers = qmc.Sobol(d = number_specs, scramble=True).random(n = number_actions).flatten()
elif method == "lhs":
random_numbers = qmc.LatinHypercube(d = number_specs, scramble=True).random(n = number_actions).flatten()
else:
raise NotImplementedError("The method {} is not implemented".format(method))

batch_actions = []
for i in range(number_actions):
actions = generate_random_actions(action_space, init_val, random_range, random_numbers[i*number_specs:(i+1)*number_specs])
batch_actions.append(actions)
return batch_actions

def sample_random_value(random_numbers, upper, lower, delete = True):
""" this function generates a random value within the range of upper and lower """
""" deletes the random number used if delete is True """
sample_val = random_numbers[0] * (upper - lower) + lower
if delete:
random_numbers = np.delete(random_numbers, 0)
return sample_val

def get_action_space(yaml_path):
""" this function is used to get the pre-defined action space in yaml file """
with open(yaml_path, "r") as file:
Expand Down