Space¶
-
class
grid2op.Space.
GridObjects
[source]¶ Bases:
object
This class stores in a Backend agnostic way some information about the powergrid.
It stores information about numbers of objects, and which objects are where, their names, etc.
The classes
grid2op.BaseAction.BaseAction
,grid2op.BaseAction.ActionSpace
,grid2op.BaseObservation.BaseObservation
,grid2op.BaseObservation.ObservationSpace
andgrid2op.Backend.Backend
all inherit from this class. This means that each of the above has its own representation of the powergrid.The modeling adopted for describing a powergrid is the following:
only the main objects of a powergrid are represented. An “object” is either a load (consumption) a generator (production), an end of a powerline (each powerline have exactly two extremities: “origin” (or) and “extremity” (ext)).
every “object” (see above) is connected to a unique substation. Each substation then counts a given (fixed) number of objects connected to it. [in this platform we don’t consider the possibility to build new “objects” as of today]
For each object, the bus to which it is connected is given in the *_to_subid (for example
GridObjects.load_to_subid
gives, for each load, the id of the substation to which it is connected)We suppose that, at every substation, each object (if connected) can be connected to either “busbar” 1 or “busbar” 2. This means that, at maximum, there are 2 independent buses for each substation.
With this hypothesis, we can represent (thought experiment) each substation by a vector. This vector has as many components than the number of objects in the substation (following the previous example, the vector representing the first substation would have 5 components). And each component of this vector would represent a fixed element in it. For example, if say, the load with id 1 is connected to the first element, there would be a unique component saying if the load with id 1 is connected to busbar 1 or busbar 2. For the generators, this id in this (fictive) vector is indicated in the
GridObjects.gen_to_sub_pos
vector. For example the first position ofGridObjects.gen_to_sub_pos
indicates on which component of the (fictive) vector representing the substation 1 to look to know on which bus the first generator is connected.We define the “topology” as the busbar to which each object is connected: each object being connected to either busbar 1 or busbar 2, this topology can be represented by a vector of fixed size (and it actually is in
grid2op.BaseObservation.BaseObservation.topo_vect
or ingrid2op.Backend.Backend.get_topo_vect()
). There are multiple ways to make such a vector. We decided to concatenate all the (fictive) vectors described above. This concatenation represents the actual topology of this powergrid at a given timestep. This class doesn’t store this information (seegrid2op.BaseObservation.BaseObservation
for such purpose). This entails that:the bus to which each object on a substation will be stored in consecutive components of such a vector. For example, if the first substation of the grid has 5 elements connected to it, then the first 5 elements of
grid2op.BaseObservation.BaseObservation.topo_vect
will represent these 5 elements. The number of elements in each substation is given ingrid2op.Space.GridObjects.sub_info
.the substation are stored in “order”: objects of the first substations are represented, then this is the objects of the second substation etc. So in the example above, the 6th element of
grid2op.BaseObservation.BaseObservation.topo_vect
is an object connected to the second substation.to know on which position of this “topology vector” we can find the information relative a specific element it is possible to:
method 1 (not recommended):
retrieve the substation to which this object is connected (for example looking at
GridObjects.line_or_to_subid
[l_id] to know on which substation is connected the origin of powerline with id $l_id$.)once this substation id is known, compute which are the components of the topological vector that encodes information about this substation. For example, if the substation id sub_id is 4, we a) count the number of elements in substations with id 0, 1, 2 and 3 (say it’s 42) we know, by definition that the substation 4 is encoded in ,:attr:grid2op.BaseObservation.BaseObservation.topo_vect starting at component 42 and b) this substations has
GridObjects.sub_info
[sub_id] elements (for the sake of the example say it’s 5) then the end of the vector for substation 4 will be 42+5 = 47. Finally, we got the representation of the “local topology” of the substation 4 by looking atgrid2op.BaseObservation.BaseObservation.topo_vect
[42:47].retrieve which component of this vector of dimension 5 (remember we assumed substation 4 had 5 elements) encodes information about the origin end of the line with id l_id. This information is given in
GridObjects.line_or_to_sub_pos
[l_id]. This is a number between 0 and 4, say it’s 3. 3 being the index of the object in the substation)
method 2 (not recommended): all of the above is stored (for the same powerline) in the
GridObjects.line_or_pos_topo_vect
[l_id]. In the example above, we will have:GridObjects.line_or_pos_topo_vect
[l_id] = 45 (=42+3: 42 being the index on which the substation started and 3 being the index of the object in the substation)method 3 (recommended): use any of the function that computes it for you:
grid2op.BaseObservation.BaseObservation.state_of()
is such an interesting method. The two previous methods “method 1” and “method 2” were presented as a way to give detailed and “concrete” example on how the modeling of the powergrid work.
For a given powergrid, this object should be initialized once in the
grid2op.Backend.Backend
when the first call togrid2op.Backend.Backend.load_grid()
is performed. In particular the following attributes must necessarily be defined (see above for a detailed description of some of the attributes):A call to the function
GridObjects._compute_pos_big_topo()
allow to compute the *_pos_topo_vect attributes (for exampleGridObjects.line_ex_pos_topo_vect
) can be computed from the above data:Note that if you want to model an environment with unit commitment or redispatching capabilities, you also need to provide the following attributes:
These information are loaded using the
grid2op.Backend.Backend.load_redispacthing_data()
method.NB it does not store any information about the current state of the powergrid. It stores information that cannot be modified by the BaseAgent, the Environment or any other entity.
-
n_line
¶ number of powerlines in the powergrid
- Type
int
-
n_gen
¶ number of generators in the powergrid
- Type
int
-
n_load
¶ number of loads in the
- Type
int
-
n_sub
¶ number of loads in the powergrid
- Type
int
-
dim_topo
¶ The total number of objects in the powergrid. This is also the dimension of the “topology vector” defined above.
- Type
int
-
sub_info
¶ for each substation, gives the number of elements connected to it
- Type
numpy.ndarray
, dtype:int
-
load_to_subid
¶ for each load, gives the id the substation to which it is connected. For example,
GridObjects.load_to_subid
[load_id] gives the id of the substation to which the load of id load_id is connected.- Type
numpy.ndarray
, dtype:int
-
gen_to_subid
¶ for each generator, gives the id the substation to which it is connected
- Type
numpy.ndarray
, dtype:int
-
line_or_to_subid
¶ for each line, gives the id the substation to which its “origin” end is connected
- Type
numpy.ndarray
, dtype:int
-
line_ex_to_subid
¶ for each line, gives the id the substation to which its “extremity” end is connected
- Type
numpy.ndarray
, dtype:int
-
load_to_sub_pos
¶ Suppose you represent the topoology of the substation s with a vector (each component of this vector will represent an object connected to this substation). This vector has, by definition the size
GridObject.sub_info
[s]. load_to_sub_pos tells which component of this vector encodes the current load. Suppose that load of id l is connected to the substation of id s (this information is stored inGridObjects.load_to_subid
[l]), then if you represent the topology of the substation s with a vector sub_topo_vect, then “sub_topo_vect [GridObjects.load_to_subid
[l] ]” will encode on which bus the load of id l is stored.- Type
numpy.ndarray
, dtype:int
-
gen_to_sub_pos
¶ same as
GridObjects.load_to_sub_pos
but for generators.- Type
numpy.ndarray
, dtype:int
-
line_or_to_sub_pos
¶ same as
GridObjects.load_to_sub_pos
but for “origin” end of powerlines.- Type
numpy.ndarray
, dtype:int
-
line_ex_to_sub_pos
¶ same as
GridObjects.load_to_sub_pos
but for “extremity” end of powerlines.- Type
numpy.ndarray
, dtype:int
-
load_pos_topo_vect
¶ The topology if the entire grid is given by a vector, say topo_vect of size
GridObjects.dim_topo
. For a given load of id l,GridObjects.load_to_sub_pos
[l] is the index of the load l in the vectorgrid2op.BaseObservation.BaseObservation.topo_vect
. This means that, if “topo_vect [GridObjects.load_pos_topo_vect
[l] ]=2” then load of id l is connected to the second bus of the substation.- Type
numpy.ndarray
, dtype:int
-
gen_pos_topo_vect
¶ same as
GridObjects.load_pos_topo_vect
but for generators.- Type
numpy.ndarray
, dtype:int
-
line_or_pos_topo_vect
¶ same as
GridObjects.load_pos_topo_vect
but for “origin” end of powerlines.- Type
numpy.ndarray
, dtype:int
-
line_ex_pos_topo_vect
¶ same as
GridObjects.load_pos_topo_vect
but for “extremity” end of powerlines.- Type
numpy.ndarray
, dtype:int
-
name_load
¶ ordered names of the loads in the grid.
- Type
numpy.ndarray
, dtype:str
-
name_gen
¶ ordered names of the productions in the grid.
- Type
numpy.ndarray
, dtype:str
-
name_line
¶ ordered names of the powerline in the grid.
- Type
numpy.ndarray
, dtype:str
-
name_sub
¶ ordered names of the substation in the grid
- Type
numpy.ndarray
, dtype:str
-
attr_list_vect
¶ List of string. It represents the attributes that will be stored to/from vector when the BaseObservation is converted to/from it. This parameter is also used to compute automatically
GridObjects.dtype()
andGridObjects.shape()
as well asGridObjects.size()
. If this class is derived, then it’s really important that this vector is properly set. All the attributes with the name on this vector should have consistently the same size and shape, otherwise, some methods will not behave as expected.- Type
list
-
_vectorized
¶ The representation of the GridObject as a vector. See the help of
GridObjects.to_vect()
andGridObjects.from_vect()
for more information. NB for performance reason, the conversion of the internal representation to a vector is not performed at any time. It is only performed whenGridObjects.to_vect()
is called the first time. Otherwise, this attribute is set toNone
.- Type
numpy.ndarray
, dtype:float
-
gen_type
¶ Type of the generators, among: “solar”, “wind”, “hydro”, “thermal” and “nuclear”. Optional. Used for unit commitment problems or redispacthing action.
- Type
numpy.ndarray
, dtype:str
-
gen_pmin
¶ Minimum active power production needed for a generator to work properly. Optional. Used for unit commitment problems or redispacthing action.
- Type
numpy.ndarray
, dtype:float
-
gen_pmax
¶ Maximum active power production needed for a generator to work properly. Optional. Used for unit commitment problems or redispacthing action.
- Type
numpy.ndarray
, dtype:float
-
gen_redispatchable
¶ For each generator, it says if the generator is dispatchable or not. Optional. Used for unit commitment problems or redispacthing action.
- Type
numpy.ndarray
, dtype:bool
-
gen_max_ramp_up
¶ Maximum active power variation possible between two consecutive timestep for each generator: a redispatching action on generator g_id cannot be above
GridObjects.gen_ramp_up_max
[g_id]. Optional. Used for unit commitment problems or redispacthing action.- Type
numpy.ndarray
, dtype:float
-
gen_max_ramp_down
¶ Minimum active power variationpossible between two consecutive timestep for each generator: a redispatching action on generator g_id cannot be below
GridObjects.gen_ramp_down_min
[g_id]. Optional. Used for unit commitment problems or redispacthing action.- Type
numpy.ndarray
, dtype:float
-
gen_min_uptime
¶ The minimum time (expressed in the number of timesteps) a generator needs to be turned on: it’s not possible to turn off generator gen_id that has been turned on less than gen_min_time_on [gen_id] timesteps ago. Optional. Used for unit commitment problems or redispacthing action.
- Type
numpy.ndarray
, dtype:float
-
gen_min_downtime
¶ The minimum time (expressed in the number of timesteps) a generator needs to be turned off: it’s not possible to turn on generator gen_id that has been turned off less than gen_min_time_on [gen_id] timesteps ago. Optional. Used for unit commitment problems or redispacthing action.
- Type
numpy.ndarray
, dtype:float
-
gen_cost_per_MW
¶ For each generator, it gives the “operating cost”, eg the cost, in terms of “used currency” for the production of one MW with this generator, if it is already turned on. It’s a positive real number. It’s the marginal cost for each MW. Optional. Used for unit commitment problems or redispacthing action.
- Type
numpy.ndarray
, dtype:float
-
gen_startup_cost
¶ The cost to start a generator. It’s a positive real number. Optional. Used for unit commitment problems or redispacthing action.
- Type
numpy.ndarray
, dtype:float
-
gen_shutdown_cost
¶ The cost to shut down a generator. It’s a positive real number. Optional. Used for unit commitment problems or redispacthing action.
- Type
numpy.ndarray
, dtype:float
-
redispatching_unit_commitment_availble
¶ Does the current grid allow for redispatching and / or unit commit problem. If not, any attempt to use it will raise a
grid2op.Exceptions.UnitCommitorRedispachingNotAvailable
error. For an environment to be compatible with this feature, you need to set up, when loading the backend:- Type
bool
-
grid_layout
¶ The layout of the powergrid in a form of a dictionnary with keys the substation name, and value a tuple of the coordinate of this substation. If no layout are provided, it defaults to
None
- Type
dict
orNone
-
shunts_data_available
¶ Whether or not the backend support the shunt data.
- Type
bool
-
n_shunt
¶ Number of shunts on the grid. It might be
None
if the backend does not support shunts.- Type
int
orNone
-
name_shunt
¶ Name of each shunt on the grid, or
None
if the backend does not support shunts.- Type
numpy.ndarray
, dtype:str
orNone
-
shunt_to_subid
¶ for each shunt (if supported), gives the id the substation to which it is connected
- Type
numpy.ndarray
, dtype:int
-
__weakref__
¶ list of weak references to the object (if defined)
-
assert_grid_correct
()[source]¶ Performs some checking on the loaded _grid to make sure it is consistent. It also makes sure that the vector such as sub_info, load_to_subid or gen_to_sub_pos are of the right type eg. numpy.ndarray with dtype: np.int
It is called after the _grid has been loaded.
These function is by default called by the
grid2op.Environment
class after the initialization of the environment. If these tests are not successfull, no guarantee are given that the backend will return consistent computations.In order for the backend to fully understand the structure of actions, it is strongly advised NOT to override this method.
- Returns
None
- Raise
grid2op.EnvError
and possibly all of its derived class.
-
attach_layout
(grid_layout)[source]¶ grid layout is a dictionnary with the keys the name of the substations, and the value the tuple of coordinates of each substations. No check are made it to ensure it is correct.
- Parameters
grid_layout (
dict
) – See definition ofGridObjects.grid_layout
for more information.
-
dtype
()[source]¶ The types of the components of the GridObjects, mainly used for gym compatibility is the shape of all part of the action.
It is a numpy array of objects.
The dtype vector must have the same number of components as the return value of the
GridObjects.shape()
vector.- NB: in case the class GridObjects is derived,
either
GridObjects.attr_list_vect
is properly defined for the derived class, or this function must be redefined.
- Returns
res – The dtype of the
GridObjects
- Return type
numpy.ndarray
-
staticmethod
from_dict
(dict_)[source]¶ Create a valid GridObject (or one of its derived class if this method is overide) from a dictionnary (usually read from a json file)
- Parameters
dict (
dict
) – The representation of the GridObject as a dictionary.- Returns
res – The object of the proper class that were initially represented as a dictionary.
- Return type
GridObject
-
from_vect
(vect)[source]¶ Convert a GridObjects, represented as a vector, into an GridObjects object.
NB: in case the class GridObjects is derived, either
GridObjects.attr_list_vect
is properly defined for the derived class, or this function must be redefined.Only the size is checked. If it does not match, an
grid2op.Exceptions.AmbiguousAction
is thrown. Otherwise the component of the vector are coerced into the proper type silently.It may results in an non deterministic behaviour if the input vector is not a real action, or cannot be converted to one.
- Parameters
vect (
numpy.ndarray
) – A vector representing an BaseAction.
-
get_generators_id
(sub_id)[source]¶ Returns the list of all generators id in the backend connected to the substation sub_id
- Parameters
sub_id (
int
) – The substation to which we look for the generator- Returns
res – Id of the generator id looked for.
- Return type
list
- Raises
-
get_lines_id
(_sentinel=None, from_=None, to_=None)[source]¶ Returns the list of all the powerlines id in the backend going from from_ to to_
- Parameters
_sentinel (
None
) – Internal, do not usefrom (
int
) – Id the substation to which the origin end of the powerline to look for should be connected toto (
int
) – Id the substation to which the extremity end of the powerline to look for should be connected to
- Returns
res – Id of the powerline looked for.
- Return type
list
- Raises
-
get_loads_id
(sub_id)[source]¶ Returns the list of all generators id in the backend connected to the substation sub_id
- Parameters
sub_id (
int
) – The substation to which we look for the generator- Returns
res – Id of the generator id looked for.
- Return type
list
- Raises
-
get_obj_connect_to
(_sentinel=None, substation_id=None)[source]¶ Get all the object connected to a given substation:
- Parameters
_sentinel (
None
) – Used to prevent positional parameters. Internal, do not use.substation_id (
int
) – ID of the substation we want to inspect
- Returns
res –
A dictionnary with keys:
”loads_id”: a vector giving the id of the loads connected to this substation, empty if none
”generators_id”: a vector giving the id of the generators connected to this substation, empty if none
”lines_or_id”: a vector giving the id of the origin end of the powerlines connected to this substation, empty if none
”lines_ex_id”: a vector giving the id of the extermity end of the powerlines connected to this substation, empty if none.
”nb_elements” : number of elements connected to this substation
- Return type
dict
-
init_grid
(gridobj)[source]¶ Initialize this
GridObjects
instance with a provided instance.It does not perform any check on the validity of the gridobj parameters, but it guarantees that if gridobj is a valid grid, then the initialization will lead to a valid grid too.
- Parameters
gridobj (
GridObjects
) – The representation of the powergrid
-
init_grid_vect
(name_prod, name_load, name_line, name_sub, sub_info, load_to_subid, gen_to_subid, line_or_to_subid, line_ex_to_subid, load_to_sub_pos, gen_to_sub_pos, line_or_to_sub_pos, line_ex_to_sub_pos, load_pos_topo_vect, gen_pos_topo_vect, line_or_pos_topo_vect, line_ex_pos_topo_vect)[source]¶ Initialize the object from the vectors representing the grid.
- Parameters
name_prod (
numpy.ndarray
, dtype:str) – Used to initializedGridObjects.name_gen
name_load (
numpy.ndarray
, dtype:str) – Used to initializedGridObjects.name_load
name_line (
numpy.ndarray
, dtype:str) – Used to initializedGridObjects.name_line
name_sub (
numpy.ndarray
, dtype:str) – Used to initializedGridObjects.name_sub
sub_info (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.sub_info
load_to_subid (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.load_to_subid
gen_to_subid (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.gen_to_subid
line_or_to_subid (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.line_or_to_subid
line_ex_to_subid (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.line_ex_to_subid
load_to_sub_pos (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.load_to_sub_pos
gen_to_sub_pos (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.gen_to_sub_pos
line_or_to_sub_pos (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.line_or_to_sub_pos
line_ex_to_sub_pos (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.line_ex_to_sub_pos
load_pos_topo_vect (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.load_pos_topo_vect
gen_pos_topo_vect (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.gen_pos_topo_vect
line_or_pos_topo_vect (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.line_or_pos_topo_vect
line_ex_pos_topo_vect (
numpy.ndarray
, dtype:int) – Used to initializedGridObjects.line_ex_pos_topo_vect
-
shape
()[source]¶ The shapes of all the components of the action, mainly used for gym compatibility is the shape of all part of the action.
It is a numpy integer array.
This function must return a vector from which the sum is equal to the return value of “size()”.
The shape vector must have the same number of components as the return value of the
GridObjects.dtype()
vector.- NB: in case the class GridObjects is derived,
either
GridObjects.attr_list_vect
is properly defined for the derived class, or this function must be redefined.
- Returns
res – The shape of the
GridObjects
- Return type
numpy.ndarray
-
size
()[source]¶ When the action is converted to a vector, this method return its size.
NB that it is a requirement that converting an GridObjects gives a vector of a fixed size throughout a training.
NB: in case the class GridObjects is derived, either
GridObjects.attr_list_vect
is properly defined for the derived class, or this function must be redefined.- Returns
size – The size of the GridObjects if it’s converted to a flat vector.
- Return type
int
-
to_dict
()[source]¶ Convert the object as a dictionnary. Note that unless this method is overidden, a call to it will only output the
- Returns
res – The representation of the object as a dictionary that can be json serializable.
- Return type
dict
-
to_vect
()[source]¶ Convert this instance of GridObjects to a numpy ndarray. The size of the array is always the same and is determined by the
GridObject.size()
method.- NB: in case the class GridObjects is derived,
either
GridObjects.attr_list_vect
is properly defined for the derived class, or this function must be redefined.
- Returns
res – The representation of this action as a flat numpy ndarray
- Return type
numpy.ndarray
-
class
grid2op.Space.
RandomObject
[source]¶ Bases:
object
Utility class to deal with randomness in some aspect of the game (chronics, action_space, observation_space for examples.
-
space_prng
¶ The random state of the observation (in case of non deterministic observations or BaseAction. This should not be used at the moment)
- Type
numpy.random.RandomState
-
seed_used
¶ The seed used throughout the episode in case of non deterministic observations or action.
- Type
int
-
__weakref__
¶ list of weak references to the object (if defined)
-
-
class
grid2op.Space.
SerializableSpace
(gridobj, subtype=<class 'object'>)[source]¶ Bases:
grid2op.Space.Space.GridObjects
,grid2op.Space.RandomObject.RandomObject
This class allows to serialize / de serialize the action space or observation space.
It should not be used inside an Environment, as some functions of the action might not be compatible with the serialization, especially the checking of whether or not an BaseAction is legal or not.
-
subtype
¶ Type use to build the template object
SerializableSpace.template_obj
. This type should derive fromgrid2op.BaseAction.BaseAction
orgrid2op.BaseObservation.BaseObservation
.- Type
type
-
_template_obj
¶ An instance of the “subtype” provided used to provide higher level utilities, such as the size of the action (see
grid2op.BaseAction.BaseAction.size()
) or to sample a new BaseAction (seegrid2op.BaseAction.BaseAction.sample()
) for example.- Type
grid2op.GridObjects
-
n
¶ Size of the space
- Type
int
-
shape
¶ Shape of each of the component of the Object if represented in a flat vector. An instance that derives from a GridObject (for example
grid2op.BaseAction.BaseAction
orgrid2op.BaseObservation.BaseObservation
) can be thought of as being concatenation of independant spaces. This vector gives the dimension of all the basic spaces they are made of.- Type
numpy.ndarray
, dtype:int
-
dtype
¶ Data type of each of the component of the Object if represented in a flat vector. An instance that derives from a GridObject (for example
grid2op.BaseAction.BaseAction
orgrid2op.BaseObservation.BaseObservation
) can be thought of as being concatenation of independant spaces. This vector gives the type of all the basic spaces they are made of.- Type
numpy.ndarray
, dtype:int
-
__init__
(gridobj, subtype=<class 'object'>)[source]¶ - subtype:
type
Type of action used to build
SerializableActionSpace._template_act
. This type should derive fromgrid2op.BaseAction.BaseAction
orgrid2op.BaseObservation.BaseObservation
.
- subtype:
-
staticmethod
from_dict
(dict_)[source]¶ Allows the de-serialization of an object stored as a dictionnary (for example in the case of json saving).
- Parameters
dict (
dict
) – Representation of an BaseObservation Space (akagrid2op.BaseObservation.ObservartionHelper
) or the BaseAction Space (akagrid2op.BaseAction.ActionSpace
) as a dictionnary.- Returns
res – An instance of an SerializableSpace matching the dictionnary.
- Return type
-
from_vect
(obj_as_vect)[source]¶ Convert an action, represented as a vector to a valid
BaseAction
instance- Parameters
obj_as_vect (
numpy.ndarray
) – A object living in a space represented as a vector (typically angrid2op.BaseAction.BaseAction
or angrid2op.BaseObservation.BaseObservation
represented as a numpy vector)- Returns
res – The corresponding action (or observation) as an object (and not as a vector). The return type is given by the type of
SerializableSpace._template_obj
- Return type
grid2op.Action.Action
orgrid2op.Observation.Observation
-
If you still can’t find what you’re looking for, try in one of the following pages: