Skip to content
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

Merged
merged 42 commits into from
Jan 19, 2025

Conversation

GabrielKS
Copy link
Collaborator

@GabrielKS GabrielKS commented Sep 18, 2024

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.

@GabrielKS GabrielKS force-pushed the gks/td/component_selector_port branch from d2087ba to 1c65518 Compare September 25, 2024 22:37
@GabrielKS GabrielKS changed the title Move ComponentSelector from PowerAnalytics to InfrastructureSystems: PSY portion (take two) Add ComponentSelector feature: PSY portion (take two) Sep 26, 2024
@GabrielKS GabrielKS marked this pull request as ready for review September 26, 2024 00:31
@GabrielKS
Copy link
Collaborator Author

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.

@GabrielKS GabrielKS self-assigned this Sep 27, 2024
Comment on lines 9 to 22
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)
Copy link
Contributor

@daniel-thom daniel-thom Sep 30, 2024

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)

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Collaborator Author

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.

Copy link
Collaborator Author

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).

if there is none.
- `filterby`: optional filter function to apply after evaluating the `ComponentSelector`
"""
get_component(selector::SingularComponentSelector, sys::System; filterby = nothing) =
Copy link
Contributor

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.

Copy link
Collaborator Author

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?

Copy link
Collaborator Author

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

"""
Copy link
Collaborator Author

@GabrielKS GabrielKS Dec 12, 2024

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)

@GabrielKS
Copy link
Collaborator Author

GabrielKS commented Dec 12, 2024

@daniel-thom Ready for another review. Besides the changes in the IS PR, the main new change here is discussed at the top of get_components_interface.jl.

@jd-lara
Copy link
Member

jd-lara commented Jan 8, 2025

@GabrielKS we will scope this PR for PSY 5.0

@GabrielKS GabrielKS force-pushed the gks/td/component_selector_port branch from f0de327 to 01c1146 Compare January 15, 2025 01:56
GabrielKS and others added 11 commits January 17, 2025 13:16
 - 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.
@GabrielKS GabrielKS force-pushed the gks/td/component_selector_port branch from 863f4d8 to 3332ff4 Compare January 17, 2025 20:18

# get_groups
"""
Get the groups that make up the `ComponentSelector`. Optionally specify a filter function
Copy link
Contributor

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.

  1. 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.
  2. 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 and groupby = :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.
  3. 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.

Copy link
Contributor

@daniel-thom daniel-thom left a 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.

@GabrielKS
Copy link
Collaborator Author

@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.

@jd-lara jd-lara merged commit 21160e7 into main Jan 19, 2025
1 of 8 checks passed
@jd-lara jd-lara deleted the gks/td/component_selector_port branch January 19, 2025 06:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants