-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Matching Python types for return values of pvsystem.calcparams_*
#1700
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
Conversation
pvsystem.calcparams_*
pvsystem.calcparams_*
pvsystem.calcparams_*
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 we need to check the all-float case.
How does test_PVSystem_calcparams_desoto
pass? My guess is that calcparams_desoto
returning all arrays as expected, and numpy's assert_allclose
is doing some work for us, e.g.,
assert_allclose(Rs, 0.1, atol=0.1)
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.
This PR has changed a lot! I like the simplicity of the latest approach.
numeric_args = (effective_irradiance, temp_cell) | ||
out = (IL, I0, Rs, Rsh, nNsVth) | ||
|
||
if all(map(np.isscalar, numeric_args)): |
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.
np.isscalar docs suggest that we should instead test if np.ndim(x) == 0
. The most likely point of failure is example table row 2: np.isscalar(np.array(3.1))
. numpy scalar arrays seem to pop up all over the place.
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.
With the goal of calcparams_*
methods' return values having the same Python type, I think we want the behavior of np.isscalar
instead of np.ndim(x) == 0
. If calcparams_*
is given a mix of floats and 0d-arrays (e.g. effective_irradiance
is a Python float
and temp_cell
is a 0d-array), using np.ndim(x) == 0
will cause the calcparams_*
methods' return values to be a mix of floats and 0d-arrays. If we use np.isscalar
, all return values will become 0d-arrays. This is because np.broadcast_arrays(1.0, np.array(2.0))
equals [np.array(1.0), np.array(2.0)]
.
pvlib/pvsystem.py
Outdated
index = tools.get_pandas_index(*numeric_args) | ||
if index is not None: | ||
return tuple(pd.Series(a, index=index).rename(None) for a in out) | ||
|
||
return np.broadcast_arrays(*out) |
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.
two alternatives here.
get_pandas_index
raises exception (TypeError?) instead of returning None, this code usestry/except/else
- return None, but swap the clauses, so
if index is none: return np.broadcast_arrays; else: return tuple(...)
option 1 feels more pythonic, but not sure that it's actually better. If keeping None, then I think option 2 is marginally cleaner.
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 went with your second alternative. get_pandas_index
can also be used here in pvsystem.singlediode, but using it there would become awkward if get_pandas_index
raised an exception. The calcparams_
functions change their behavior depending on whether get_pandas_index
returns None
so a try/except
pattern makes sense. However, in the pvsystem.singlediode
use case I linked, I want to use the None
value when creating the pd.DataFrame
.
pvlib/tests/test_tools.py
Outdated
def test_get_pandas_index(args, item_idx): | ||
pd.testing.assert_index_equal( | ||
args[item_idx].index, tools.get_pandas_index(*args) | ||
) |
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.
should be tested with all scalars and/or arrays too
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 added test cases of all scalars and all arrays where get_pandas_index
is expected to return None
.
:py:func:`pvlib.pvsystem.calcparams_pvsyst` are all numeric types and have | ||
the same Python type as the `effective_irradiance` and `temp_cell` parameters. (:issue:`1626`, :pull:`1700`) |
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 same Python type" - this suggests to me that type(output) == type(input)
in every case. This isn't actually tested and I'd be slightly surprised if there are no scalar-ish numpy gotchas.
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 sentence in the whatsnew is not exactly correct. In this PR, the calcparams_*
functions decide the Python type of the return values checking these conditions in order:
- If arguments passed to
calcparams_*
are scalars (as determined bynp.isscalar
), then return values are scalars. Sinceeffective_irradiance
andtemp_cell
are the only numeric-types, and the other arguments arefloat
, this condition only depends on the types ofeffective_irradiance
andtemp_cell
. - If either
effective_irradiance
ortemp_cell
is apd.Series
, then return values have typepd.Series
. - If either
effective_irradiance
ortemp_cell
is and.ndarray
, then return values have typenp.ndarray
. This includes 0d-arrays.
I added tests to check the return values' Python type here.
Thanks @reepoi! |
[ ] Updates entries indocs/sphinx/source/reference
for API changes.docs/sphinx/source/whatsnew
for all changes. Includes link to the GitHub Issue with:issue:`num`
or this Pull Request with:pull:`num`
. Includes contributor name and/or GitHub username (link with:ghuser:`user`
).remote-data
) and Milestone are assigned to the Pull Request and linked Issue.This PR addresses the observations about
pvsystems.calcparams_*
in #1626. These are thatpd.Series
return values can inherit the name of thepd.Series
passed to the functions, and that the numeric return values (either scalar,np.ndarray
,pd.Series
) are not always the same Python type.A helper function is added to
pvlib/tools.py
to get the firstpandas
index from a list of variables.