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

Creating customs chronics folder from existing chronics folder #447

Closed
AvisP opened this issue Apr 26, 2023 · 7 comments
Closed

Creating customs chronics folder from existing chronics folder #447

AvisP opened this issue Apr 26, 2023 · 7 comments

Comments

@AvisP
Copy link

AvisP commented Apr 26, 2023

Environment

  • Grid2op version: 1.8.1
  • System: osx

I would like to know if it is possible to create a custom chronics folder from the existing chronics with only 287 timesteps ( for 1 day with 5 min interval ) and it would contain only the last day when the environment terminates. For example with a DoNothing agent I determine that for l2rpn_case14_sandbox network the chronics for 0000, 0001, 0002 execute for 1091, 807 and 3001 time steps. I would like to create a custom chronics folder that would contain chronics for 0000 from 863:1051 for 0001 from 577:863 and 0002 will have 1041:3167, Reason for doing this is to evaluate the trained agent only for days when the environment terminates

Also I noticed that even though I specified max_iter in Runner it is running for all the timesteps and have the same chronic name in the following code snippet. I might be possibly making some silly mistake and can't locate it and your help would be appreciated. Thanks!

Code Snippet

import grid2op
import re
import copy
import numpy as np
from grid2op.Runner import Runner
from grid2op.Reward import LinesCapacityReward  # or any other rewards
from lightsim2grid import LightSimBackend  # highly recommended !
from grid2op.Chronics import MultifolderWithCache  # highly recommended for training

act_attr_to_keep = ["set_line_status"]

env_name = "l2rpn_case14_sandbox"
# env_name = "l2rpn_neurips_2020_track1_small"

env = grid2op.make(env_name,
                   reward_class=LinesCapacityReward,
                   backend=LightSimBackend(),
                   chronics_class=MultifolderWithCache)

runner_params = env.get_params_for_runner()
runner = Runner(**runner_params)

start_seed = 500
nb_episode = 5
nb_process = 1

res = runner.run(nb_episode=nb_episode,
                nb_process=nb_process,
                # env_seeds=[i for i in range(start_seed, start_seed+nb_episode)],
                max_iter=287
                )

print("Evaluation summary for DN:")
for _, chron_name, cum_reward, nb_time_step, max_ts in res:
    msg_tmp = "chronics at: {}".format(chron_name)
    msg_tmp += "\ttotal score: {:.6f}".format(cum_reward)
    msg_tmp += "\ttime steps: {:.0f}/{:.0f}".format(nb_time_step, max_ts)
    print(msg_tmp)

Output

Evaluation summary for DN:
chronics at: 0000       total score: 622.306925 time steps: 1091/8064
chronics at: 0000       total score: 622.306925 time steps: 1091/8064
chronics at: 0000       total score: 622.306925 time steps: 1091/8064
chronics at: 0000       total score: 622.306925 time steps: 1091/8064
chronics at: 0000       total score: 622.306925 time steps: 1091/8064
@BDonnot
Copy link
Collaborator

BDonnot commented Apr 27, 2023

Hello,

First question

For the first question, you have multiple choices :

Manually

You basically make an environment with what you want exactly.

  • copy paste the environment (in order to keep the original as is)
  • name the copy pasted folder eg l2rpn_case14_sandbox_modif
  • change all the csv in each subfolder of the "chronics" folder to the right size, beginning, end etc.
  • call the new environment eg grid2op.make("l2rpn_case14_sandbox_modif") and you're done

On the fly

You can specify how much time step you want to skip at the beginning and how long an episode should last.

See the https://grid2op.readthedocs.io/en/latest/environment.html#grid2op.Environment.BaseEnv.fast_forward_chronics and https://grid2op.readthedocs.io/en/latest/environment.html#grid2op.Environment.Environment.set_max_iter

Manually within a python script

There is a function https://grid2op.readthedocs.io/en/latest/chronics.html#grid2op.Chronics.Multifolder.split_and_save that you might use for doing what you want.

Second question

I don't really know what's going on with your runner. Have you modify the chronics folder in your environment somehow? Did you modify the config.py file in your environment?

Beside, the max_iter argument does not seem to have any effect. I'll send to you the correct behavior for your script. Because I think you modified different things and "broke" everything.

@BDonnot
Copy link
Collaborator

BDonnot commented Apr 27, 2023

Update: I found out the "bug". Have you read the documentation of MultifolderWithCache for example this https://grid2op.readthedocs.io/en/latest/environment.html#optimize-the-data-pipeline for high level view or that https://grid2op.readthedocs.io/en/latest/chronics.html#grid2op.Chronics.MultifolderWithCache for a detailed documentation ?

I think you missed a few things there and that caused your environment to have only one set of time series available.

@AvisP
Copy link
Author

AvisP commented Apr 27, 2023

Hi Benjamin,

Thanks for your prompt response and excellent suggestions. For the first issue the manual python script solution is what I was looking for. I used the following script to generate customized chronics and load them

Generate custom chronics and load

import grid2op
import os
import re
import numpy as np
from grid2op.Runner import Runner
from grid2op.Reward import LinesCapacityReward  # or any other rewards
from lightsim2grid import LightSimBackend  # highly recommended !
from grid2op.Chronics import MultifolderWithCache  # highly recommended for training

env_name = "l2rpn_case14_sandbox"
# env_name = "l2rpn_neurips_2020_track1_small"

env = grid2op.make(env_name,
                   reward_class=LinesCapacityReward,
                   backend=LightSimBackend(),
                   chronics_class=MultifolderWithCache)

env.chronics_handler.real_data.set_filter(lambda x: re.match(".*0*$", x) is not None)
# create the cache
env.chronics_handler.reset()

env.chronics_handler.real_data.split_and_save({"0004": "2019-01-08 02:00",
                                     "0005": "2019-01-30 08:00",
                                     "0006": "2019-01-17 00:00",
                                     "0007": "2019-01-17 01:00",
                                     "0008": "2019-01-21 09:00",
                                     "0009": "2019-01-22 12:00",
                                     "0010": "2019-01-27 19:00",
                                     "0011": "2019-01-15 12:00",
                                     "0012": "2019-01-08 13:00",
                                     "0013": "2019-01-22 00:00"},
                                    {"0004": "2019-01-11 02:00",
                                     "0005": "2019-02-01 08:00",
                                     "0006": "2019-01-18 00:00",
                                     "0007": "2019-01-18 01:00",
                                     "0008": "2019-01-22 09:00",
                                     "0009": "2019-01-24 12:00",
                                     "0010": "2019-01-29 19:00",
                                     "0011": "2019-01-17 12:00",
                                     "0012": "2019-01-10 13:00",
                                     "0013": "2019-01-24 00:00"},
                           path_out=os.path.join("./path_out/"))

env2 = grid2op.make(env_name,
                   reward_class=LinesCapacityReward,
                   backend=LightSimBackend(),
                   chronics_class=MultifolderWithCache)

env2.chronics_handler.path = './path_out/'
# set the chronics to limit to one week of data (lower memory footprint)
env2.chronics_handler.set_max_iter(7*288)
# assign a filter, use only chronics that have "december" in their name
# env2.chronics_handler.real_data.set_filter(lambda x: re.match(".*december.*", x) is not None)
env2.chronics_handler.real_data.set_filter(lambda x: re.match(".*0*$", x) is not None)
# create the cache
env2.chronics_handler.reset()

runner_params = env2.get_params_for_runner()
runner = Runner(**runner_params)

nb_episode = 10
nb_process = 1

res = runner.run(nb_episode=nb_episode,
                nb_process=nb_process,
                max_iter=287)

print("Evaluation summary for DN:")
for _, chron_name, cum_reward, nb_time_step, max_ts in res:
    msg_tmp = "chronics at: {}".format(chron_name)
    msg_tmp += "\ttotal score: {:.6f}".format(cum_reward)
    msg_tmp += "\ttime steps: {:.0f}/{:.0f}".format(nb_time_step, max_ts)
    print(msg_tmp)

Second Question

Thanks for finding out the issue in the script I provided, seems like I was missing some extra initialization and filtering lines for MultifolderWithCache. But I noticed that setting max_iter in Runner is not limiting the runs to the specified duration. However that is not an issue as I can set it in chronics_handler.set_max_iter. I will provide the script and output just in case you notice something I might have missed.

Script

import grid2op
import re
import numpy as np
from grid2op.Runner import Runner
from grid2op.Reward import LinesCapacityReward  # or any other rewards
from lightsim2grid import LightSimBackend  # highly recommended !
from grid2op.Chronics import MultifolderWithCache  # highly recommended for training

env_name = "l2rpn_case14_sandbox"

env = grid2op.make(env_name,
                   reward_class=LinesCapacityReward,
                   backend=LightSimBackend(),
                   chronics_class=MultifolderWithCache)

env.chronics_handler.path = '/Users/paula/Desktop/Projects/RL Practice/StableBaselinePractice/path_out/'
# set the chronics to limit to one week of data (lower memory footprint)
env.chronics_handler.set_max_iter(7*288)
# assign a filter, use only chronics that have "december" in their name
# env.chronics_handler.real_data.set_filter(lambda x: re.match(".*december.*", x) is not None)
env.chronics_handler.real_data.set_filter(lambda x: re.match(".*0*$", x) is not None)
# create the cache
env.chronics_handler.reset()

runner_params = env.get_params_for_runner()
runner = Runner(**runner_params)

start_seed = 500
nb_episode = 10
nb_process = 1

res = runner.run(nb_episode=nb_episode,
                nb_process=nb_process,
                # env_seeds=[i for i in range(start_seed, start_seed+nb_episode)],
                max_iter=287
                )

print("Evaluation summary for DN:")
for _, chron_name, cum_reward, nb_time_step, max_ts in res:
    msg_tmp = "chronics at: {}".format(chron_name)
    msg_tmp += "\ttotal score: {:.6f}".format(cum_reward)
    msg_tmp += "\ttime steps: {:.0f}/{:.0f}".format(nb_time_step, max_ts)
    print(msg_tmp)

Output

Evaluation summary for DN:
chronics at: 0000       total score: 622.306925 time steps: 1091/2016
chronics at: 0001       total score: 464.387165 time steps: 807/2016
chronics at: 0002       total score: 1187.459036        time steps: 2016/2016
chronics at: 0003       total score: 1.020729   time steps: 3/2016
chronics at: 0004       total score: 479.332989 time steps: 804/2016
chronics at: 0005       total score: 305.495747 time steps: 513/2016
chronics at: 0006       total score: 715.684838 time steps: 1272/2016
chronics at: 0007       total score: 716.417765 time steps: 1261/2016
chronics at: 0008       total score: 283.670804 time steps: 480/2016
chronics at: 0009       total score: 1171.101457        time steps: 2016/2016

@BDonnot
Copy link
Collaborator

BDonnot commented Apr 28, 2023

Hello

Thanks for the feedback.

Concerning your first question, you directly give the path you want to use for the time series ("chronics") when you create the environment. You can do this with the chronics_path argument in make:

env2 = grid2op.make(..., chronics_path="./path_out")

for example

About your second question, i did not really paid much attention to the "max_iter" kwargs indeed. Your code looks ok, i'll check for a possible bug with the runner max_iter

@AvisP
Copy link
Author

AvisP commented May 3, 2023

Hi Benjamin,

I noticed an issue when I am trying to split_and_save more than 180 chronics at one go. I have uploaded a beginning and end file dictionary in pickle format here . If the following code is executed

import grid2op
import os
import re
import datetime
from grid2op.Runner import Runner
from grid2op.Reward import LinesCapacityReward  # or any other rewards
from lightsim2grid import LightSimBackend  # highly recommended !
from grid2op.Chronics import MultifolderWithCache  # highly recommended for training

env = grid2op.make(env_name,
                   reward_class=LinesCapacityReward,
                   backend=LightSimBackend(),
                   chronics_class=MultifolderWithCache)

env.chronics_handler.real_data.set_filter(lambda x: re.match(".*0*$", x) is not None)
# create the cache
env.chronics_handler.reset()

with open('timings.pickle', 'rb') as handle:
    [episode_info_beginning, episode_info_end] = pickle.load(handle)

env.chronics_handler.real_data.split_and_save(episode_info_beginning, episode_info_end,
                          path_out=os.path.join("/....../Chronics_congestion/l2rpn_case14_sandbox/"))

I am getting the error

Exception has occurred: StopIteration       (note: full exception trace is shown but execution is paused at: _run_module_as_main)
exception: no description
  File "/........................../lib/python3.10/site-packages/grid2op/Chronics/gridStateFromFile.py", line 783, in load_next
    raise StopIteration
  File "/........................../lib/python3.10/site-packages/grid2op/Chronics/gridStateFromFile.py", line 1146, in split_and_save
    curr_dt, *_ = tmp.load_next()
  File "/........................../lib/python3.10/site-packages/grid2op/Chronics/multiFolder.py", line 746, in split_and_save
    tmp.split_and_save(
  File "/........................../Chronic_Custom_Test.py", line 45, in <module>
    env.chronics_handler.real_data.split_and_save(episode_info_beginning, episode_info_end,
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/runpy.py", line 196, in _run_module_as_main (Current frame)
    return _run_code(code, main_globals, None,
StopIteration: 

I think it might be happening because the self.current_index does not get reset here at each call https://github.com/rte-france/Grid2Op/blob/72befa1d24880175a91382d7749109632c338c87/grid2op/Chronics/gridStateFromFile.py#L774

@BDonnot
Copy link
Collaborator

BDonnot commented May 25, 2023

Hello,

Sorry for long delay in answering. Can you create a dedicated issue (following the issue template) for this please ? Thanks

Also, "chronics" (time series) are just csv, so if you can load a csv (using pandas for example) and only write part of it in a different folder (using pandas for example) you can probably write your own script that does just what you want to do.

@BDonnot
Copy link
Collaborator

BDonnot commented Aug 25, 2023

I am closing this issue as it appears to be working (i'm keeping opened the other one)

@BDonnot BDonnot closed this as completed Aug 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants