-
Notifications
You must be signed in to change notification settings - Fork 22
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
Topology and network analytics #206
Comments
I've added a base analytics interface to the bus and branch base classes. This supports numGenerators(), numLoads() and numLines() functions and has some basic implementations based on the contents of the DataCollection object associated with each network component. These functions can be overwritten to fine-tune behavior for individual applications. I added a stub for a function numStorage() on the buses but I didn't implement it since I have no idea how to count these elements. There is also a function setData(DataCollection *data) that can be used to make the data collection object for each component visible to the default implementations. I think this can be used in the constructor for whatever we end up using as the upper level topology query module. |
I've implemented these up through the HADREC application and its Python interface. I can't test yet because of #198. |
I'm modifying the base implementations so that only elements that have status 'ON' are counted. If no status variable is found, the element is assumed to be 'ON'. |
@bjpalmer, you are probably working on this, but somewhere in the component tree, |
Won't it get overridden again, when the load function is implemented by the application? Another possibiity would be to include it in the BaseFactory implementation of the BaseFactory::load() function. This does not usually get overwritten. Yet another possibility would be to include it at the end of the BaseNetwork::partition() function. Not sure how these play out as far as maintaining clean hierarchies. |
You know best. I'm probably making bad assumptions about how the component class tree inheritence is coded. |
The analytics functionality seems to be working. I put some calls in the powerflow application that report on the total number of generators, loads and lines at the start of the calculation. I'm still a little queasy about putting this in the network class since this deals exclusively with managing the topology and is agnostic to any functionality representing the actual application. It might be better to put it an a separate template class the is initialized with the network. |
I created a separate analytics module and put the functionality for getting the total number of generators, etc. in that. I also added it to the powerflow application. I personally prefer having this functionality in a separate class but I'll go with the majority. From an implementation view, it's pretty easy to do it either way. |
@jainmilan, @bjpalmer, and @shri: The current (on
We don't have anything transformer specific. If we need to assemble tables like those, then we need to expose devices within buses and branches. First, we need counts:
with corresponding Python methods. These are easy to add. We also need to expose individual device information. I suggest for device properties (not device state) we have routines like this:
or
Returning whatever "Info" is, a single value, array, or structure. This will require some discussion. Retrieving device state also needs discussion. Just my $0.02. |
I added a complete set of bus/branch specific methods like these, with Python API in HADREC. |
I've rebased the |
As was concluded in the meeting the other day, we only need to query the
or, more likely, non-template versions
within GridPACK C++. These would return In Python, the interfaces to these would look like
which would return the value (whatever type) if successful, To use this interface, we would need to relate the necessary grid2op fields to the GridPACK data collection dictionary and know the field type. I have a few wild guesses in this table: |
I had to change course a little. GridPACK data collection objects are contained within a bus or branch. All device (load, line, generator, etc.) fields are interspersed amongst the bus and branch fields. Concequently, there is no real distinction between querying a generator or load field and this has to be done at the bus level. Also, querying a field requires knowing the type of the result which further complicates the interface. Here is a working Python script that dumps bus information from a dynamic simulation: def network_analytics_dump(ds_app):
nbus = ds_app.totalBuses()
for bus in range(0, nbus):
bnum = ds_app.getBusInfoInt(bus, "BUS_NUMBER", -1)
btype = ds_app.getBusInfoInt(bus, "BUS_TYPE", -1)
bname = ds_app.getBusInfoString(bus, "BUS_NAME", -1)
bvmag = ds_app.getBusInfoReal(bus, "BUS_VOLTAGE_MAG", -1)
print(bus, bnum, bname, btype, ds_app.numGenerators(bus),
ds_app.numLoads(bus), bvmag)
for g in range(ds_app.numGenerators(bus)):
print(" gen: ", g,
ds_app.getBusInfoInt(bus, "GENERATOR_NUMBER", g),
ds_app.getBusInfoString(bus, "GENERATOR_ID", g),
ds_app.getBusInfoReal(bus, "GENERATOR_PG", g),
ds_app.getBusInfoReal(bus, "GENERATOR_QG", g))
for l in range(ds_app.numLoads(bus)):
print("load: ", l,
ds_app.getBusInfoInt(bus, "LOAD_NUMBER", l),
ds_app.getBusInfoString(bus, "LOAD_ID", l),
ds_app.getBusInfoReal(bus, "LOAD_PL", l),
ds_app.getBusInfoReal(bus, "LOAD_QL", l)) Using the 9-bus simulation, here is what this produces:
|
Updated with branch info ... def network_analytics_dump(ds_app):
nbus = ds_app.totalBuses()
for bus in range(nbus):
print(bus,
ds_app.getBusInfoInt(bus, "BUS_NUMBER", -1),
ds_app.getBusInfoString(bus, "BUS_NAME", -1),
ds_app.getBusInfoInt(bus, "BUS_TYPE", -1),
ds_app.numGenerators(bus),
ds_app.numLoads(bus),
ds_app.getBusInfoReal(bus, "BUS_VOLTAGE_MAG", -1))
for g in range(ds_app.numGenerators(bus)):
print(" gen: ", g,
ds_app.getBusInfoInt(bus, "GENERATOR_NUMBER", g),
ds_app.getBusInfoString(bus, "GENERATOR_ID", g),
ds_app.getBusInfoReal(bus, "GENERATOR_PG", g),
ds_app.getBusInfoReal(bus, "GENERATOR_QG", g))
for l in range(ds_app.numLoads(bus)):
print("load: ", l,
ds_app.getBusInfoInt(bus, "LOAD_NUMBER", l),
ds_app.getBusInfoString(bus, "LOAD_ID", l),
ds_app.getBusInfoReal(bus, "LOAD_PL", l),
ds_app.getBusInfoReal(bus, "LOAD_QL", l))
nbranch = ds_app.totalBranches()
for branch in range(0, nbranch):
(f, t) = ds_app.getBranchEndpoints(branch)
print(branch, f, t,
ds_app.getBranchInfoInt(branch, "BRANCH_ELEMENTS", -1),
ds_app.getBranchInfoInt(branch, "BRANCH_INDEX", -1),
ds_app.getBranchInfoString(branch, "BRANCH_NAME", -1),
ds_app.getBranchInfoReal(branch, "BRANCH_LENGTH", -1)) produces
for the 9-bus case. The changes are checked into the |
Reposted with @jainmilan's descriptions: |
The ds_app.getBusInfoInt(bus, "BUS_NUMBER", -1) is just ds_app.getBusInfoInt(bus, "BUS_NUMBER") A device index is only required for device (generator, load, line, etc.) information. |
Opening this issue to track development of network topology and analytics methodology.
The text was updated successfully, but these errors were encountered: