1+ # Copyright (c) 2025, RTE (https://www.rte-france.com)
2+ # See AUTHORS.txt
3+ # This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0.
4+ # If a copy of the Mozilla Public License, version 2.0 was not distributed with this file,
5+ # you can obtain one at http://mozilla.org/MPL/2.0/.
6+ # SPDX-License-Identifier: MPL-2.0
7+ # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems.
8+
9+ import copy
10+ import grid2op
11+ from grid2op .Agent import BaseAgent
12+ from grid2op .Action import CompleteAction
13+ from grid2op .Chronics import ChangeNothing
14+ import unittest
15+ import warnings
16+ import numpy as np
17+ import pdb
18+ # from pypowsybl2grid import PyPowSyBlBackend
19+ # from lightsim2grid import LightSimBackend
20+
21+ class TestDetachSimulate (unittest .TestCase ):
22+ def setUp (self ):
23+ with warnings .catch_warnings ():
24+ warnings .filterwarnings ("ignore" )
25+ self .env = grid2op .make ("educ_case14_storage" ,
26+ test = True ,
27+ allow_detachment = True ,
28+ action_class = CompleteAction ,
29+ _add_to_name = type (self ).__name__ ,
30+ chronics_class = ChangeNothing ,
31+ data_feeding_kwargs = {"h_forecast" : [5 , 10 , 15 , 20 , 25 , 30 ]},
32+ # backend=PyPowSyBlBackend()
33+ )
34+ paramerters = self .env .parameters
35+ paramerters .MAX_SUB_CHANGED = 99999
36+ paramerters .MAX_LINE_STATUS_CHANGED = 99999
37+ paramerters .NB_TIMESTEP_COOLDOWN_LINE = 0
38+ paramerters .NB_TIMESTEP_COOLDOWN_SUB = 0
39+ self .env .change_parameters (paramerters )
40+ self .init_obs = self .env .reset (seed = 0 , options = {"time serie id" : 0 })
41+
42+ def tearDown (self ):
43+ self .env .close ()
44+ return super ().tearDown ()
45+
46+ def test_detach_gen (self , tol = 1e-5 ):
47+ normal_v = 1. * self .init_obs .gen_v
48+ normal_p = 1. * self .init_obs .gen_p
49+ gen_id = 0
50+ act_deco = self .env .action_space ({"set_bus" : {"generators_id" : [(gen_id , - 1 )]}})
51+ act_reco = self .env .action_space ({"set_bus" : {"generators_id" : [(gen_id , + 1 )]}})
52+ next_obs , reward , done , info = self .env .step (act_deco )
53+ assert not done
54+ assert len (info ["exception" ]) == 0
55+ assert next_obs .gen_detached [gen_id ]
56+ assert next_obs .gen_v [gen_id ] == 0.
57+ assert next_obs .gen_p [gen_id ] == 0.
58+
59+ # test simulate
60+ next_obs_sim00 , reward , done , info = next_obs .simulate (self .env .action_space ())
61+ assert not done
62+ assert len (info ["exception" ]) == 0
63+ assert next_obs_sim00 .gen_detached [gen_id ]
64+ assert next_obs_sim00 .gen_v [gen_id ] == 0.
65+ assert next_obs_sim00 .gen_p [gen_id ] == 0.
66+ print ("here here here" )
67+ next_obs_sim0 , reward , done , info = next_obs .simulate (act_reco )
68+ assert not done
69+ assert len (info ["exception" ]) == 0
70+ assert not next_obs_sim0 .gen_detached [gen_id ]
71+ assert np .abs (next_obs_sim0 .gen_v [gen_id ] - normal_v [gen_id ]) <= tol , f"error { np .abs (next_obs_sim0 .gen_v [gen_id ] - normal_v [gen_id ]).max ()} "
72+ assert np .abs (next_obs_sim0 .gen_p [gen_id ] - normal_p [gen_id ]) <= tol , f"error { np .abs (next_obs_sim0 .gen_p [gen_id ] - normal_p [gen_id ]).max ()} "
73+ next_obs_sim1 , reward , done , info = next_obs .simulate (act_deco )
74+ assert not done
75+ assert len (info ["exception" ]) == 0
76+ assert next_obs_sim1 .gen_detached [gen_id ]
77+ assert next_obs_sim1 .gen_v [gen_id ] == 0.
78+ assert next_obs_sim1 .gen_p [gen_id ] == 0.
79+ next_obs_sim2 , reward , done , info = next_obs .simulate (self .env .action_space ())
80+ assert not done
81+ assert len (info ["exception" ]) == 0
82+ assert next_obs_sim2 .gen_detached [gen_id ]
83+ assert next_obs_sim2 .gen_v [gen_id ] == 0.
84+ assert next_obs_sim2 .gen_p [gen_id ] == 0.
85+ next_obs_sim3 , reward , done , info = next_obs .simulate (act_reco )
86+ assert not done
87+ assert len (info ["exception" ]) == 0
88+ assert not next_obs_sim3 .gen_detached [gen_id ]
89+ assert np .abs (next_obs_sim3 .gen_v [gen_id ] - normal_v [gen_id ]) <= tol , f"error { np .abs (next_obs_sim3 .gen_v [gen_id ] - normal_v [gen_id ]).max ()} "
90+ assert np .abs (next_obs_sim3 .gen_p [gen_id ] - normal_p [gen_id ]) <= tol , f"error { np .abs (next_obs_sim3 .gen_p [gen_id ] - normal_p [gen_id ]).max ()} "
91+ # now change the setpoint
92+ next_obs_sim4 , reward , done , info = next_obs .simulate (act_reco + self .env .action_space ({"injection" : {"prod_v" : normal_v * 1.01 }}))
93+ assert not done
94+ assert len (info ["exception" ]) == 0
95+ assert not next_obs_sim4 .gen_detached [gen_id ]
96+ assert np .abs (next_obs_sim4 .gen_v [gen_id ] - 1.01 * normal_v [gen_id ]) <= tol , f"error { np .abs (next_obs_sim4 .gen_v [gen_id ] - 1.01 * normal_v [gen_id ]).max ()} "
97+ assert np .abs (next_obs_sim4 .gen_p [gen_id ] - normal_p [gen_id ]) <= tol , f"error { np .abs (next_obs_sim4 .gen_p [gen_id ] - normal_p [gen_id ]).max ()} "
98+ # disco
99+ next_obs_sim5 , reward , done , info = next_obs .simulate (act_deco )
100+ assert not done
101+ assert len (info ["exception" ]) == 0
102+ assert next_obs_sim5 .gen_detached [gen_id ]
103+ assert next_obs_sim5 .gen_v [gen_id ] == 0.
104+ assert next_obs_sim5 .gen_p [gen_id ] == 0.
105+ # reco again (and check the setpoint is not the last one used in obs.simulate but is the one of the observation)
106+ next_obs_sim6 , reward , done , info = next_obs .simulate (act_reco )
107+ assert not done
108+ assert len (info ["exception" ]) == 0
109+ assert not next_obs_sim6 .gen_detached [gen_id ]
110+ assert np .abs (next_obs_sim6 .gen_v [gen_id ] - normal_v [gen_id ]) <= tol , f"error { np .abs (next_obs_sim6 .gen_v [gen_id ] - normal_v [gen_id ]).max ()} "
111+ assert np .abs (next_obs_sim6 .gen_p [gen_id ] - normal_p [gen_id ]) <= tol , f"error { np .abs (next_obs_sim6 .gen_p [gen_id ] - normal_p [gen_id ]).max ()} "
112+
113+
114+ # test step
115+ next_next_obs , reward , done , info = self .env .step (act_reco )
116+ assert not done
117+ assert len (info ["exception" ]) == 0
118+ assert not next_next_obs .gen_detached [gen_id ]
119+ assert np .abs (next_next_obs .gen_v [gen_id ] - normal_v [gen_id ]) <= tol , f"error { np .abs (next_next_obs .gen_v [gen_id ] - normal_v [gen_id ]).max ()} "
120+ assert np .abs (next_next_obs .gen_p [gen_id ] - normal_p [gen_id ]) <= tol , f"error { np .abs (next_next_obs .gen_p [gen_id ] - normal_p [gen_id ]).max ()} "
121+
122+ def test_detach_load (self , tol = 1e-5 ):
123+ normal_q = 1. * self .init_obs .load_q
124+ normal_p = 1. * self .init_obs .load_p
125+ load_id = 0
126+ act_deco = self .env .action_space ({"set_bus" : {"loads_id" : [(load_id , - 1 )]}})
127+ act_reco = self .env .action_space ({"set_bus" : {"loads_id" : [(load_id , + 1 )]}})
128+ next_obs , reward , done , info = self .env .step (act_deco )
129+ assert not done
130+ assert len (info ["exception" ]) == 0
131+ assert next_obs .load_detached [load_id ]
132+ assert next_obs .load_q [load_id ] == 0.
133+ assert next_obs .load_p [load_id ] == 0.
134+
135+ # test simulate
136+ next_obs_sim00 , reward , done , info = next_obs .simulate (self .env .action_space ())
137+ assert not done
138+ assert len (info ["exception" ]) == 0
139+ assert next_obs_sim00 .load_detached [load_id ]
140+ assert next_obs_sim00 .load_q [load_id ] == 0.
141+ assert next_obs_sim00 .load_p [load_id ] == 0.
142+
143+ next_obs_sim0 , reward , done , info = next_obs .simulate (act_reco )
144+ assert not done
145+ assert len (info ["exception" ]) == 0
146+ assert not next_obs_sim0 .load_detached [load_id ]
147+ assert np .abs (next_obs_sim0 .load_q [load_id ] - normal_q [load_id ]) <= tol , f"error { np .abs (next_obs_sim0 .load_q [load_id ] - normal_q [load_id ]).max ()} "
148+ assert np .abs (next_obs_sim0 .load_p [load_id ] - normal_p [load_id ]) <= tol , f"error { np .abs (next_obs_sim0 .load_p [load_id ] - normal_p [load_id ]).max ()} "
149+ next_obs_sim1 , reward , done , info = next_obs .simulate (act_deco )
150+ assert not done
151+ assert len (info ["exception" ]) == 0
152+ assert next_obs_sim1 .load_detached [load_id ]
153+ assert next_obs_sim1 .load_q [load_id ] == 0.
154+ assert next_obs_sim1 .load_p [load_id ] == 0.
155+ next_obs_sim2 , reward , done , info = next_obs .simulate (self .env .action_space ())
156+ assert not done
157+ assert len (info ["exception" ]) == 0
158+ assert next_obs_sim2 .load_detached [load_id ]
159+ assert next_obs_sim2 .load_q [load_id ] == 0.
160+ assert next_obs_sim2 .load_p [load_id ] == 0.
161+ next_obs_sim3 , reward , done , info = next_obs .simulate (act_reco )
162+ assert not done
163+ assert len (info ["exception" ]) == 0
164+ assert not next_obs_sim3 .load_detached [load_id ]
165+ assert np .abs (next_obs_sim3 .load_q [load_id ] - normal_q [load_id ]) <= tol , f"error { np .abs (next_obs_sim3 .load_q [load_id ] - normal_q [load_id ]).max ()} "
166+ assert np .abs (next_obs_sim3 .load_p [load_id ] - normal_p [load_id ]) <= tol , f"error { np .abs (next_obs_sim3 .load_p [load_id ] - normal_p [load_id ]).max ()} "
167+ # now change the setpoint
168+ next_obs_sim4 , reward , done , info = next_obs .simulate (act_reco + self .env .action_space ({"injection" : {"load_q" : normal_q * 1.01 }}))
169+ assert not done
170+ assert len (info ["exception" ]) == 0
171+ assert not next_obs_sim4 .load_detached [load_id ]
172+ assert np .abs (next_obs_sim4 .load_q [load_id ] - 1.01 * normal_q [load_id ]) <= tol , f"error { np .abs (next_obs_sim4 .load_q [load_id ] - 1.01 * normal_q [load_id ]).max ()} "
173+ assert np .abs (next_obs_sim4 .load_p [load_id ] - normal_p [load_id ]) <= tol , f"error { np .abs (next_obs_sim4 .load_p [load_id ] - normal_p [load_id ]).max ()} "
174+ # disco
175+ next_obs_sim5 , reward , done , info = next_obs .simulate (act_deco )
176+ assert not done
177+ assert len (info ["exception" ]) == 0
178+ assert next_obs_sim5 .load_detached [load_id ]
179+ assert next_obs_sim5 .load_q [load_id ] == 0.
180+ assert next_obs_sim5 .load_p [load_id ] == 0.
181+ # reco again (and check the setpoint is not the last one used in obs.simulate but is the one of the observation)
182+ next_obs_sim6 , reward , done , info = next_obs .simulate (act_reco )
183+ assert not done
184+ assert len (info ["exception" ]) == 0
185+ assert not next_obs_sim6 .load_detached [load_id ]
186+ assert np .abs (next_obs_sim6 .load_q [load_id ] - normal_q [load_id ]) <= tol , f"error { np .abs (next_obs_sim6 .load_q [load_id ] - normal_q [load_id ]).max ()} "
187+ assert np .abs (next_obs_sim6 .load_p [load_id ] - normal_p [load_id ]) <= tol , f"error { np .abs (next_obs_sim6 .load_p [load_id ] - normal_p [load_id ]).max ()} "
188+
189+ # test step
190+ next_next_obs , reward , done , info = self .env .step (act_reco )
191+ assert not done
192+ assert len (info ["exception" ]) == 0
193+ assert not next_next_obs .load_detached [load_id ]
194+ assert np .abs (next_next_obs .load_q [load_id ] - normal_q [load_id ]) <= tol , f"error { np .abs (next_next_obs .load_q [load_id ] - normal_q [load_id ]).max ()} "
195+ assert np .abs (next_next_obs .load_p [load_id ] - normal_p [load_id ]) <= tol , f"error { np .abs (next_next_obs .load_p [load_id ] - normal_p [load_id ]).max ()} "
196+
197+
0 commit comments