Open bjpalmer opened 1 month ago
I've started adding some code for generators. @jainmilan can you give me some variables that you want current values for?
In #176, I asked for a way to get the current value of voltage at each bus, not just generators and loads. Does/will this issue cover that ability?
This will probably work for you, but it might be better to add some accessors to the the DSFullBus class so you can access the values directly. Using this method, you will need to update the data collections on all buses and branches (by calling a function in the factory class), then accessing the data collection object for each bus and finally getting the variable you want. We are developing this functionality to create a python interface so the dynamic simulation can work with another code, but it may not be the optimal way for all applications to get this data.
This will probably work for you, but it might be better to add some accessors to the the DSFullBus [...]
This is on my todo list, along with Python methods. It should be done this week.
This will probably work for you, but it might be better to add some accessors to the the DSFullBus [...]
This is on my todo list, along with Python methods. It should be done this week.
Both DS and HADREC applications now have an updateData()
method, both C++ and Python.
@bjpalmer, I'm investigating why CURRENT
load data is not available after updateData()
. It appears that there are two kinds of loads on the DS bus. One is counted by p_ndyn_load
. These are governed by p_loadmodels[]
and seem to update CURRENT
values when asked (although, I have not run a case where p_ndyn_load > 0
on any bus). The other is counted by p_npowerflow_load
. These seem to have their P and Q values stored in p_powerflowload_p
and p_powerflowload_q
, respectively. These load values are never saved to CURRENT
data collection values, even if they change via scaling in the simulation.
I think DSFullBus::updateData()
may need another loop over p_powerflowload_p
and p_powerflowload_q
where those values are put in the DataCollection
. I got a little lost trying to figure out when what load applies, so I think you need to take a look.
Also, it appears that other simulation state queries only work on p_powerflowload_*
, like DSFullBus::getLoadPower()
and DSFullBus::getTotalLoadPower()
. This seems inconsistent to me.
@jainmilan, I'm pretty sure this is why we get None
when querying load power.
We looked at this last week. It seemed to me that the generator objects were not getting created by the calculation and therefore nothing was getting copied to the data collections. The basis for this assumption was that no GENERATOR_MODEL
variable was showing up in the data collections after adding a p_factory->dumpData()
to the code immediately after calling updateData
. We only ran for 1 timestep, but as far as I could tell, it didn't look like the code was setting up generators for the test case we were looking at. The GENERATOR_MODEL
variable is used inside the generator factory to create the appropriate generator instance.
I've been running the 9-bus case with dsf.py
(in current repository), where updateData()
is called at the end of the simulation. I get CURRENT
generator values for that, so it must work with some kinds of generators.
However, I'm complaining about load values.
The network is queried as follows:
def network_analytics_dump(ds_app):
nbus = ds_app.totalBuses()
for bus in range(nbus):
print(bus,
ds_app.getBusInfoInt(bus, "BUS_NUMBER"),
ds_app.getBusInfoString(bus, "BUS_NAME"),
ds_app.getBusInfoInt(bus, "BUS_TYPE"),
ds_app.numGenerators(bus),
ds_app.numLoads(bus),
ds_app.getBusInfoReal(bus, "BUS_VOLTAGE_MAG"))
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),
ds_app.getBusInfoReal(bus, "GENERATOR_PG_CURRENT", g),
ds_app.getBusInfoReal(bus, "GENERATOR_QG_CURRENT", 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),
ds_app.getBusInfoReal(bus, "LOAD_PL_CURRENT", l),
ds_app.getBusInfoReal(bus, "LOAD_QL_CURRENT", l)
)
The results of this query are as follows:
0 1 'bus-1 ' 3 1 0 1.04
gen: 0 None 1 0.669999999997691 0.7010759010981538 0.669999999997691 0.7010759010981538
1 2 'bus-2 ' 2 1 0 1.02533
gen: 0 None 1 1.63 0.6028676952146661 1.63 0.6028676952146661
2 3 'bus-3 ' 2 1 0 1.02536
gen: 0 None 1 0.85 0.4202344495139094 0.85 0.4202344495139094
3 4 'bus-4 ' 1 0 0 1.0018586298562873
4 5 'bus-5 ' 1 0 1 0.9816273801688302
load: 0 None 1 90.0 30.0 None None
5 6 'bus-6 ' 1 0 0 1.002520962766657
6 7 'bus-7 ' 1 0 1 0.9812684602469763
load: 0 None 1 100.0 35.0 None None
7 8 'bus-8 ' 1 0 0 0.9935621039389169
8 9 'bus-9 ' 1 0 1 0.9661929333427239
load: 0 None 1 125.0 50.0 None None
The lines starting with gen
all have 2 P/Q values (inital and current). I don't this this would have happened if generator models were not set up.
@jainmilan, were we looking at the same input problem that @wperkins is describing? If you dump out the data collections, do you see a LOAD_MODEL
variable defined? I'm not completely sure about this, but I think load variables only get printed out if a dynamic load model is defined, so maybe the test you are running does not have one of these, in which case no LOAD_MODEL
variable would be defined.
So, there can be loads without a LOAD_MODEL
? Shouldn't we be able to query those too?
Those loads are static. We could query them, although I don't know if there is much point in doing it more than once. @jainmilan, @abhyshr, @yliu250, this is a domain question.
Those loads are static. We could query them, although I don't know if there is much point in doing it more than once. @jainmilan, @abhyshr, @yliu250, this is a domain question.
I think it's an API consistency question.
@jainmilan needs to be able query all load P/Q's at arbitrary points in the simulation. He would first need to figure out what loads have a LOAD_MODEL
and which don't and then query those loads differently (e.g., different field name), right? I think it would be more consistent, and simple, to have "static" load P/Q's duplicated in CURRENT
data collection fields.
Also, are we sure that loads without a LOAD_MODEL
(static) do not change during the simulation? DSFullBus::scaleLoadPower()
and DSFullBus::resetPower()
seem to modify p_powerflowload_*
, but I don't know when or if those get called.
Also, based on my reading of DSFullBus::load()
handling of load input, things could get pretty messed up if a bus has a mix of static and LOAD_MODEL
loads.
@jainmilan, @wperkins, @abhyshr, @yliu250, I modified the updateData function so that it will always produce a value.
@wperkins @abhyshr @yliu250 @bjpalmer I am trying to access the from and to p and q values using getBranchInfoReal
but getting None.
https://github.com/GridOPTICS/GridPACK/blob/14db5222474ffc54d287a0d6462ed329667cc0f9/python/src/dsf.py#L44-L56
I don't think you are going to get anything using that format. The BRANCH_FROM/TO_P/Q_CURRENT
variables are all indexed by a specific line within the branch object and it doesn't look like you are including the line index in your calls to getBranchRealInfo
. You can verify that the line variables are stored in the data collection by using the dumpData()
method.
I restructured the code a bit so that the evaluation of the branch flows is in a separate function (evaluateBranchFlow) that is then called inside the branch updateData function before storing data in the data collection.
Add functionality to update values in the data collection objects for buses and branches in dynamic simulation. These values can then be queried and extracted by other applications.