-
Notifications
You must be signed in to change notification settings - Fork 89
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
Add ComponentSelector
feature: PSY portion (take two)
#1197
Conversation
d2087ba
to
1c65518
Compare
ComponentSelector
feature: PSY portion (take two)
This is now ready for in-depth code review! Note the dependency on NREL-Sienna/InfrastructureSystems.jl#342. For a demonstration, see https://github.nrel.gov/gkonars/PowerAnalytics-demos/blob/main/component_selector_pr_demo.ipynb. |
src/component_selector.jl
Outdated
get_components(selector::ComponentSelector, sys::System; filterby = nothing) = | ||
IS.get_components(selector, sys; filterby = filterby) | ||
|
||
""" | ||
get_components(filterby, selector, sys) | ||
Get the components of the `System` that make up the `ComponentSelector`. | ||
- `filterby`: optional filter function to apply after evaluating the `ComponentSelector` | ||
""" | ||
get_components( | ||
filterby::Union{Nothing, Function}, | ||
selector::ComponentSelector, | ||
sys::System, | ||
) = | ||
get_components(selector, sys; filterby = filterby) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would be slightly cleaner.
get_components(selector::ComponentSelector, sys::System) = IS.get_components(selector, sys)
get_components(filterby::Function, selector::ComponentSelector, sys::System) = IS.get_components(selector, sys; filterby = filterby)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filter_func
instead of filterby
? Even if the second is a better term, it's better to keep consistency in the docstrings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to our offline discussion, the fact that you can create the component selector with a filter function and then pass a separate filter function here adds complexity and possibly confusion to the user interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed this to scope_limiter
to try to reduce confusion — see this thread in the IS PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scope_limiter
is now no longer part of the user interface (see the IS PR).
src/component_selector.jl
Outdated
if there is none. | ||
- `filterby`: optional filter function to apply after evaluating the `ComponentSelector` | ||
""" | ||
get_component(selector::SingularComponentSelector, sys::System; filterby = nothing) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to above, these methods could be defined without kwargs or unions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine to add the method where the function is the first argument, but I'm hoping to keep the kwarg version as well — it makes more sense to me in the context where this would be used. Is that objectionable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was outvoted; the filterby
kwarg is no more (see the IS PR)
@@ -1184,16 +1167,10 @@ function get_components_by_name( | |||
return IS.get_components_by_name(T, sys.data, name) | |||
end | |||
|
|||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to get_components_interface
(though there's an argument that it should appear here too)
@daniel-thom Ready for another review. Besides the changes in the IS PR, the main new change here is discussed at the top of |
@GabrielKS we will scope this PR for PSY 5.0 |
f0de327
to
01c1146
Compare
- Originally, all `ComponentSelector`s always filtered out components marked not available. This is what we want in `PowerAnalytics`, but not necessarily what is wanted if `ComponentSelector` is used elsewhere. The solution is to not automatically perform this filtering but add it as an option so that `PowerAnalytics` can still have it. - This commit also defines the behavior that using a `TopologyComponentSelector` on a system that does not have that topology element returns no components/subselectors.
863f4d8
to
3332ff4
Compare
|
||
# get_groups | ||
""" | ||
Get the groups that make up the `ComponentSelector`. Optionally specify a filter function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The functionality in get_groups combined with groupby is very powerful and clever. However, the documentation is a bit lacking.
- I understand how these capabilities are used in PowerAnalytics.jl. Let's take an example where you want to sum active_power for generators grouped by fuel type. We need this functionality merged ASAP. 100% agree and let's do it.
- If this is to be a public interface that we expect users to use, the documentation needs improvement. At minimum, there should be a complete workflow example. Common questions will be, "what is the difference between
groupby = :each
andgroupby = :all
? What is an example of a function that should be passed? This leaves me with three conflicting opinions. (1) Leave it alone with the understanding that very few people will ever consider this. (2) Don't export this method. (3) Go all in and give complete documentation. - Once a power user understands what's going on here, they are likely to ask why we did all this. They might say, why not rely on existing packages, like this example
using DataFrames
julia> combine(groupby(DataFrame(get_components(ThermalStandard, sys)), :fuel), :active_power => sum)
5×2 DataFrame
Row │ fuel active_power_sum
│ ThermalF… Float64
─────┼─────────────────────────────────────────────────────
1 │ ThermalFuels.NATURAL_GAS = 7 29.7472
2 │ ThermalFuels.COAL = 1 13.6381
3 │ ThermalFuels.DISTILLATE_FUEL_OIL… 6.5
4 │ ThermalFuels.OTHER = 14 0.0
5 │ ThermalFuels.NUCLEAR = 9 0.849257
If we go all in on documentation, we should anticipate this question and address it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's ready to merge unless @jd-lara or @GabrielKS want to change something about public exports. Documentation improvements can be made in future work.
@daniel-thom I definitely agree that documentation needs elaboration (and that that should be done in a subsequent PR). I'm good with the public exports as they are right now if others are. |
Successor to #1079 and companion to/depends on NREL-Sienna/InfrastructureSystems.jl#342. Adds an immutable, lazy, system-independent representation of a grouped set of components. For more details and a demonstration, see https://github.nrel.gov/gkonars/PowerAnalytics-demos/blob/main/component_selector_pr_demo.ipynb.