Skip to content

Add Prilliman et al transience model to pvlib.temperature #1391

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

Merged
merged 20 commits into from
Feb 8, 2022

Conversation

kandersolar
Copy link
Member

@kandersolar kandersolar commented Jan 25, 2022

  • Closes implement transient moving-average thermal model #1081
  • I am familiar with the contributing guidelines
  • Tests added
  • Updates entries to docs/sphinx/source/api.rst for API changes.
  • Adds description and name entries in the appropriate "what's new" file in 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`).
  • New code is fully documented. Includes numpydoc compliant docstrings, examples, and comments where necessary.
  • Pull request is nearly complete and ready for detailed review.
  • Maintainer: Appropriate GitHub Labels and Milestone are assigned to the Pull Request and linked Issue.

This PR adds a cleaned-up version of prilliman_v5 from this notebook: https://gist.github.com/kanderso-nrel/1d6da384d7af8afc24c230f1f144eb57

Also: I noticed that one of the links in the PR template is out of date so I updated that here too.

@kandersolar kandersolar added this to the 0.9.1 milestone Jan 25, 2022
@kandersolar kandersolar marked this pull request as ready for review January 26, 2022 02:13
@kandersolar
Copy link
Member Author

Ready for review.

@mjprilliman comments are welcome :)

Copy link
Member

@cwhanse cwhanse left a comment

Choose a reason for hiding this comment

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

Haven't looked at the test details yet


time_step = (temp_cell.index[1] - temp_cell.index[0]).total_seconds()
if time_step >= 1200:
# too coarsely sampled for smoothing to be relevant
Copy link
Member

Choose a reason for hiding this comment

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

I think a warning here would be appropriate

Copy link
Member

Choose a reason for hiding this comment

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

Maybe extend the message to say that the return values are the original temperature?

Co-authored-by: Anton Driesse <[email protected]>
@wholmgren
Copy link
Member

Great to see this. I'll review soon.

Reproducing something like Figure 5 from the reference would be a great addition to the example library.

prilliman figure 5 winter

Copy link
Member

@wholmgren wholmgren left a comment

Choose a reason for hiding this comment

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

Looks good! All minor (hopefully) comments below.

Copy link

@mjprilliman mjprilliman left a comment

Choose a reason for hiding this comment

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

I'm not familiar enough with pvlib to give a full review but the function implementation looks good to me. Thanks @kanderso-nrel !

@kandersolar
Copy link
Member Author

Thanks @wholmgren for the comments, was just lazy of me to not document that numpy magic. I came up with it and still had to remind myself how it worked!

Copy link
Member

@wholmgren wholmgren left a comment

Choose a reason for hiding this comment

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

Any further comments or should we merge?

@cwhanse
Copy link
Member

cwhanse commented Feb 3, 2022

I'd like to take one more look.

Copy link
Member

@cwhanse cwhanse left a comment

Choose a reason for hiding this comment

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

You win some unnamed award for excellent in-line comments

Co-authored-by: Cliff Hansen <[email protected]>
@kandersolar
Copy link
Member Author

Actually I think there may be a flaw in this implementation regarding treatment of nans. Please do not merge yet!

@kandersolar
Copy link
Member Author

Ok, fixed. The problem was that NaNs in the input temperature were correctly ignored in the numerator (np.nansum(subsets * weights, axis=1)), but the corresponding weights were not set to zero in the denominator, so in effect it was treating NaN temperature as zero temperature instead of ignoring it. The fix was to replace the triu incantation, which properly ignored NaNs for the "prefix", with a simple mask that ignores all NaNs, not just the prefix. So the code is simpler now too.

I don't think this should be controversial but it's probably worth another pair of eyes. Thanks!

value. At the beginning of the series where a full 20 minute window is not
possible, partial windows are used instead.

References
Copy link
Member

Choose a reason for hiding this comment

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

One more suggestion: explain in Notes how nan in inputs corresponds to nan in output. It makes sense (to me) that output at k is nan if windspeed[k] is nan. As a user, I may be surprised non-nan at position k in output when input temp_cell[k] is nan. But that also makes sense, because the non-nan value can be produced when window of temp_cell prior to k has data.

Output ``temp_cell[k]`` is NaN when input ``wind_speed[k]`` is NaN, or when no non-NaN data are
in the input temperature for the 20 minute window preceding index ``k``.

@adriesse
Copy link
Member

adriesse commented Feb 4, 2022

You win some unnamed award for excellent in-line comments

I had noticed these also, with appreciation.

-------
temp_cell : pandas.Series
Smoothed version of the input cell temperature [C]

Copy link
Member

Choose a reason for hiding this comment

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

Add here that the original data is returned if too coarsely sampled.


time_step = (temp_cell.index[1] - temp_cell.index[0]).total_seconds()
if time_step >= 1200:
# too coarsely sampled for smoothing to be relevant
Copy link
Member

Choose a reason for hiding this comment

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

Maybe extend the message to say that the return values are the original temperature?

@cwhanse
Copy link
Member

cwhanse commented Feb 6, 2022

If no objections, will merge tomorrow.

@cwhanse cwhanse merged commit f86d71d into pvlib:master Feb 8, 2022
@kandersolar kandersolar deleted the prilliman branch February 8, 2022 12:52
# np.sum for denominator to propagate nans in input wind speed.
numerator = np.nansum(subsets * weights, axis=1)
denominator = np.sum(weights, axis=1)
smoothed = numerator / denominator
Copy link
Member

Choose a reason for hiding this comment

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

@kanderso-nrel this line emitted a warning despite the comment on lines 967-969 that suggested otherwise. Is this a version-specific issue? My versions are below...

INSTALLED VERSIONS
------------------
commit           : 66e3805b8cabe977f40c05259cc3fcf7ead5687d
python           : 3.9.7.final.0
python-bits      : 64
OS               : Windows
OS-release       : 10
Version          : 10.0.18363
machine          : AMD64
processor        : Intel64 Family 6 Model 140 Stepping 1, GenuineIntel
byteorder        : little
LC_ALL           : None
LANG             : None
LOCALE           : English_United States.1252

pandas           : 1.3.5
numpy            : 1.20.3

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, the only way I can reproduce this is if there is a stretch of NaN in the input lasting longer than 20 minutes -- is that true for your case? That comment is referring to a div by zero warning cause by a quirk of this implementation (no weights for the very first value), not a div by zero warning caused by nans in the input.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, thanks. Yes, I had 38 minutes of NaN temperatures. I filled only the middle point with a valid number and the warning disappeared.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

implement transient moving-average thermal model
5 participants