What do you think? And would you be up for a sample implementation?
Best,
Tim
Interface:
Maybe it would be good, to define operations on a power grid, e.g. replaceNode(grid, node_number, new_node_instance) which then returns soemthing like a ModifiedGridDynamics (which somehow also encodes how the old grid realtes to the modified one).
Then one could do modifications on one's own as one wants, and in a simple manner.
Furthermore, we could proide a macro for an event / contingengy
contingency = @Event t replaceNode node_number new_node_instance
which is then given as an argument for solve as well.
This would provide the user with "one good way" to do it, instead of him having to decide what makes more sense. (Attitude stolen form Python :smile_cat:.)
Implementation of the Interace
A rough sketch (not tested) for the wrapping of the event/contingengy would be:
abstract type AbstractEvent end
struct SingleEvent <: AbstractEvent
t::Time
event_call::Expr
end
(ev::SingleEvent)(grid) # maybe more arguments ... and I omitted typing
eval(ev.event_call)
end
macro Event(tExpr, funcExpr, args...)
# a bit crude, but that should work as a first test implementation
esc(:(SingleEvent($(tExpr), $(funcExpr)( grid, $(args)... ) )))
end
Backend
And with such an interface, we can do whatever we choose in the backend. We could decide internally, whether we would do that by callbacsk to DiffEq or by concatenating multiple solutions.
Side note: I realized another reason, why I did it with concatenation: During the contingency there is a different power grid (from the modeling perspective) than outside of it. As the power grid is a feature of the solution (in order to enable the handy access to the solution values), that might break things.
Example: Imagine you simulate a line outage. Then you have different nodal admittance matrices over time. But where should the GridSolution instance know, when to use which ones. Hence, I implemented CompositeGridSolution, which takes care of that. And as I had to do that anyway, I found it easier to implement it without callbacks.
Hi @luap-pik ,cc @FHell
I thougth about your question in https://github.com/JuliaEnergy/PowerDynamicsExamples/pull/5#issuecomment-482619557 a bit more and got a rough, still abstract idea.
What do you think? And would you be up for a sample implementation?
Best, Tim
Interface:
Maybe it would be good, to define operations on a power grid, e.g.
replaceNode(grid, node_number, new_node_instance)
which then returns soemthing like aModifiedGridDynamics
(which somehow also encodes how the old grid realtes to the modified one). Then one could do modifications on one's own as one wants, and in a simple manner.Furthermore, we could proide a macro for an event / contingengy
which is then given as an argument for
solve
as well.This would provide the user with "one good way" to do it, instead of him having to decide what makes more sense. (Attitude stolen form Python :smile_cat:.)
Implementation of the Interace
A rough sketch (not tested) for the wrapping of the event/contingengy would be:
Backend
And with such an interface, we can do whatever we choose in the backend. We could decide internally, whether we would do that by callbacsk to DiffEq or by concatenating multiple solutions. Side note: I realized another reason, why I did it with concatenation: During the contingency there is a different power grid (from the modeling perspective) than outside of it. As the power grid is a feature of the solution (in order to enable the handy access to the solution values), that might break things. Example: Imagine you simulate a line outage. Then you have different nodal admittance matrices over time. But where should the GridSolution instance know, when to use which ones. Hence, I implemented CompositeGridSolution, which takes care of that. And as I had to do that anyway, I found it easier to implement it without callbacks.