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

Total PowerAnalytics Redesign: ComponentSelectors and Metrics #24

Open
wants to merge 70 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
bb3dea6
Implement ComponentEntity
GabrielKS Nov 14, 2023
c13c836
Implement ListEntitySet
GabrielKS Nov 20, 2023
c7a9729
Implement SubtypeEntitySet
GabrielKS Nov 20, 2023
0bdbd2c
Implement TopologyEntitySet
GabrielKS Nov 20, 2023
37423ae
Implement FilterEntitySet
GabrielKS Nov 21, 2023
ee2d43c
Make test simulations more interesting
GabrielKS Nov 22, 2023
c352903
Implement the very basics of Metrics
GabrielKS Nov 28, 2023
1fc29ea
Refactor test setup into its own file
GabrielKS Nov 28, 2023
438661a
Implement some input convenience functions
GabrielKS Nov 29, 2023
53809a5
Minor create_problem_results_dict bugfix
GabrielKS Nov 30, 2023
b687bd1
Add metrics wrapper functions and compute_all
GabrielKS Nov 30, 2023
b0f7b49
Make entities only return available components
GabrielKS Dec 1, 2023
233f439
More gracefully handle missing data (draft)
GabrielKS Dec 2, 2023
ea269c0
Add some Metric creation infrastructure and built-in Metrics
GabrielKS Dec 2, 2023
01e2041
Add metadata columns feature
GabrielKS Dec 22, 2023
1c61537
Add aggregate_time function
GabrielKS Dec 23, 2023
1570519
Add hcat_timed and calc_discharge_cycles
GabrielKS Dec 27, 2023
7840602
Add SystemTimedMetrics
GabrielKS Dec 28, 2023
9fe0c33
Add some more built-in metrics
GabrielKS Dec 28, 2023
0bc3769
Add ResultsTimelessMetrics
GabrielKS Dec 29, 2023
04d87d8
Add CustomTimedMetric (untested), more built-in metrics
GabrielKS Jan 4, 2024
afbd015
Implement compose_metrics
GabrielKS Jan 5, 2024
b8e54ef
Give metrics control over aggregation functions
GabrielKS Jan 5, 2024
4228377
Add more built-in metrics!
GabrielKS Jan 5, 2024
396e95b
Add another way to call compute_all
GabrielKS Jan 6, 2024
4469340
Add aggregation metadata, etc. (see details)
GabrielKS Jan 17, 2024
e731c6e
Fix calc_capacity_factor
GabrielKS Jan 17, 2024
36840da
Add author
GabrielKS Jan 18, 2024
214537d
Implement compute_set
GabrielKS Jan 23, 2024
42ec449
Resolve domain knowledge issues in builtin_metrics.jl
GabrielKS Jan 24, 2024
43b5f23
Add documentation for input, metrics
GabrielKS Jan 24, 2024
0e68361
Fix metrics documentation formatting
GabrielKS Jan 31, 2024
ed1969c
Fix compute_all kwargs bug
GabrielKS Jan 31, 2024
3d7ed17
Replace get_populated_decision_problem_results
tengis-nrl Feb 24, 2024
da4d1ca
run the formatter
tengis-nrl Feb 24, 2024
3fecf8e
Add built-in entities for load, storage, fuel types
GabrielKS Feb 27, 2024
02c72d9
Rename `Entity` to `ComponentSelector`, handle the ensuing carnage
GabrielKS Feb 28, 2024
e1c5a7a
Make use of caching in `read_component_result` for massive speedup
GabrielKS Mar 6, 2024
dbcd069
Accommodate `psy4` cost function refactor
GabrielKS Jun 25, 2024
b150277
Rename Entity-related files to refer to ComponentSelector instead
GabrielKS Mar 18, 2024
028804a
Remove ComponentSelector files for move to IS and PSY
GabrielKS Mar 18, 2024
acc3f94
make PA tests pass
tengis-nrl Mar 24, 2024
0f199e5
run formatter
tengis-nrl Mar 25, 2024
3b0e73e
Update storage naming for `psy4`
GabrielKS Jun 11, 2024
7585efc
Reevaluate `ComponentSelector`-related imports and exports
GabrielKS Jun 11, 2024
2b9ee92
Calculate metrics only on components marked available
GabrielKS Jun 26, 2024
be6d683
Only `compute` on `available` subselectors, use PSY4 storage interface
GabrielKS Jul 17, 2024
d09ee93
Prototype `ComponentSelector` grouping (tests not updated)
GabrielKS Sep 20, 2024
ea9e418
Prototype `Metric` grouping and callability (tests not updated)
GabrielKS Sep 20, 2024
2779e9a
Fix bug in calling `repeat`
GabrielKS Sep 24, 2024
50b9ecf
Rename `select_components` to `make_selector`
GabrielKS Sep 24, 2024
d195534
Add ability to disable test files like in other Sienna packages
GabrielKS Sep 26, 2024
036f57f
Accommodate upstream refactors
GabrielKS Sep 26, 2024
0245c92
Wrap built-in selectors in their own submodule
GabrielKS Sep 26, 2024
edf9e34
Rename `input.jl` to `input_utils.jl`
GabrielKS Sep 27, 2024
ac386ee
Cleanup: move helper functions to `output_utils.jl`, use `@kwdef`
GabrielKS Sep 27, 2024
ee503dc
Use `kwargs...` instead of `start_time, len`
GabrielKS Sep 27, 2024
ba5dc48
Remove `Metric` `description` field in favor of docstrings
GabrielKS Sep 27, 2024
f27bfdd
Cleanup: move more code to `utils` files, run formatter
GabrielKS Sep 27, 2024
889aad9
Make minor adjustments, finish `compute` interface change
GabrielKS Sep 30, 2024
5569eaf
Prototype `Metrics` submodule
GabrielKS Sep 30, 2024
818ee94
Replace `with_component_agg_fn`, etc. with `rebuild_metric`
GabrielKS Oct 1, 2024
c43c5e4
Make tests pass, add necessary imports, adjust documentation
GabrielKS Oct 1, 2024
d0c7e1f
Add tests for built-in metrics; fix bugs thereby uncovered
GabrielKS Oct 1, 2024
7978528
Accommodate `filterby` -> `scope_limiter` rename
GabrielKS Oct 4, 2024
db54809
Bugfix: add fallback for when `get_available` is not defined
GabrielKS Oct 8, 2024
a512703
Minor edits from PR comments 1
GabrielKS Oct 9, 2024
b37a78d
Accommodate `ComponentSelector` API changes
GabrielKS Oct 30, 2024
e139fa9
Refactor `generator_mapping.yaml`, prototype new built-in selectors
GabrielKS Oct 30, 2024
3173796
Clean up `generator_mapping.yaml` selectors implementation, test
GabrielKS Nov 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/metrics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ struct NoResultError <: Exception
end

# SMALL FUNCTIONS
"""
Whether a given `Component` should be included in analytics. Calls `PSY.get_available` if
possible, else defaults to `true`.
"""
is_available_for_analytics(comp::Component) =
try
PSY.get_available(comp)
catch e # A bit hacky but the alternative is hardcoding which component types don't have a `get_available` (or using `hasmethod`, which is probably worse)
(e isa MethodError) && return true
rethrow(e)
end

Comment on lines +112 to +119
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
is_available_for_analytics(comp::Component) =
try
PSY.get_available(comp)
catch e # A bit hacky but the alternative is hardcoding which component types don't have a `get_available` (or using `hasmethod`, which is probably worse)
(e isa MethodError) && return true
rethrow(e)
end
function is_available_for_analytics(comp::T)
if hasmethod(PSY.get_available, Tuple{T})
return PSY.get_available(comp)
else
return true
end

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My impression was that hasmethod isn't really supposed to be used in production code like this (see e.g. here) but happy to switch if the consensus is it's less bad than the try/catch

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an exported function with proper docstrings! I'm not sure about that comment. Anyway, we could implement get_available(x::Component) = true. I'll defer to @jd-lara if that is a reasonable default. It has the same outcome here.

Copy link
Contributor

@daniel-thom daniel-thom Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While hasmethod certainly isn't ideal, it is faster than try/catch: https://discourse.julialang.org/t/performance-of-hasmethod-vs-try-catch-on-methoderror/99827.

I agree with what that commenter would likely say...this is ill-formed dynamism. A default get_available is obviously still better.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that the best option for this use case is to define get_available on all Components — @jd-lara does that work for you?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without objection, moving forward with defining

get_available(::Component) = true

in PSY to eliminate this.

# Override these if you define Metric subtypes with different implementations
get_name(m::Metric) = m.name
get_eval_fn(m::Metric) = m.eval_fn
Expand Down Expand Up @@ -253,7 +265,7 @@ function _compute_one(metric::ComponentTimedMetric, results::IS.Results,
components = get_components(
selector,
PowerSimulations.get_system(results);
scope_limiter = get_available,
scope_limiter = is_available_for_analytics,
)
vals = [
compute(metric, results, com; kwargs...) for
Expand Down Expand Up @@ -304,7 +316,7 @@ function compute(metric::ComponentTimedMetric, results::IS.Results,
subents = PSY.get_groups(
selector,
PowerSimulations.get_system(results);
scope_limiter = get_available,
scope_limiter = is_available_for_analytics,
)
subcomputations = [_compute_one(metric, results, sub; kwargs...) for sub in subents]
return hcat_timed(subcomputations...)
Expand Down
Loading