Skip to content

Add Array.get_cell_temperature, PVSystem.get_cell_temperature #1211

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 24 commits into from
May 14, 2021

Conversation

kandersolar
Copy link
Member

  • Closes #xxxx
  • 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.

Trying out the idea from #1176 (comment). If merged, I'd then update #1176 to have Array.get_cell_temperature grab the model parameters from the Array's Mount.

@kandersolar kandersolar added this to the 0.9.0 milestone Apr 15, 2021
@kandersolar
Copy link
Member Author

PSM3 test failures presumably related to NREL/developer.nrel.gov#208

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.

Overall this looks really good to me. The dancing around effective_irradiance is a little awkward, but I don't have a good recommendation for an alternative.

@cwhanse cwhanse self-requested a review April 21, 2021 14:46
@@ -1009,26 +1009,26 @@ def _set_celltemp(self, model):
temp_air = _tuple_from_dfs(self.results.weather, 'temp_air')
wind_speed = _tuple_from_dfs(self.results.weather, 'wind_speed')
kwargs = {}
if model == self.system.noct_sam_celltemp:
if model == 'noct_sam':
Copy link
Member

Choose a reason for hiding this comment

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

The docstring says that model is a function, it's changed to be a string here and elsewhere.

With this change, is ModelChain.temperature_model needed?

Copy link
Member

Choose a reason for hiding this comment

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

With this change, is ModelChain.temperature_model needed?

I think this question remains, but it should be explored in a separate issue.

params = _build_kwargs(['transmittance_absorptance', 'eta_m_ref',
'noct', 'array_height', 'mount_standoff'],
self.temperature_model_parameters)
if not {'noct', 'eta_m_ref'}.issubset(params):
Copy link
Member

Choose a reason for hiding this comment

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

Would be a good idea to parallel this error message for the other temperature models.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure how I feel about this. Without a check like this, the error message isn't as helpful as it could be -- TypeError: noct_sam() missing 1 required positional argument: 'noct' makes no mention of temperature_model_parameters. But I'm not really a fan of having all these lists of pvlib.temperature parameter names in pvlib.pvsystem.

What do you think about letting python raise the TypeError and we add a hint to the error message like this:

try:
    temperature_cell = func(poa_global, temp_air, wind_speed, **params)
except TypeError as e:
    msg = e.args[0] + (
        ".  Check temperature_model_parameters to make sure "
        "all required parameters are specified."
    )
    raise TypeError(msg)

Downside is that it adds irrelevant noise to TypeErrors caused by other problems.

Copy link
Member

Choose a reason for hiding this comment

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

I won't stand in the way of this PR over error messaging. If we want to verify parameters at this stage, as a kindness to users, maybe a dict in pvlib.temperature akin to pvlib.pvsystem._DC_MODEL_PARAMS.

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 the problem is that we're using _build_kwargs to build all of the arguments instead of just the optional keyword arguments. I suggest a pattern that performs explicit look ups instead of deferred checks. Fine with me to use the standard python KeyError or break into the kinder message template.

args = (self.temperature_model_par[arg] for arg in required_args)
kwargs = _build_kwargs(optional_args, self.temperature_model_parameters) 

required_args and optional_args could come from a private dict like @cwhanse suggests. I'm also ok with hard coding it here (sounds easy). And I'm ok with using inspect (I vaguely recall considering this previously and thinking it was too complicated for pvlib, but I currently like it).

Copy link
Member Author

Choose a reason for hiding this comment

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

I added something along these lines, let me know what you think.

params = _build_kwargs(['transmittance_absorptance', 'eta_m_ref',
'noct', 'array_height', 'mount_standoff'],
self.temperature_model_parameters)
if not {'noct', 'eta_m_ref'}.issubset(params):
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 the problem is that we're using _build_kwargs to build all of the arguments instead of just the optional keyword arguments. I suggest a pattern that performs explicit look ups instead of deferred checks. Fine with me to use the standard python KeyError or break into the kinder message template.

args = (self.temperature_model_par[arg] for arg in required_args)
kwargs = _build_kwargs(optional_args, self.temperature_model_parameters) 

required_args and optional_args could come from a private dict like @cwhanse suggests. I'm also ok with hard coding it here (sounds easy). And I'm ok with using inspect (I vaguely recall considering this previously and thinking it was too complicated for pvlib, but I currently like it).


# allow kwargs to override
params.update(kwargs)
temperature_cell = func(poa_global, temp_air, wind_speed, **params)
Copy link
Member

Choose a reason for hiding this comment

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

and here I would use *args and **kwargs

@cwhanse cwhanse mentioned this pull request May 5, 2021
24 tasks
@kandersolar
Copy link
Member Author

Checks are green. Anything left on this one?

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.

Close. A few minor things and a larger question about if we can replace **kwargs with effective_irradiance=None.

mc.run_model(weather)
assert m_sapm.call_count == 1
# assert_called_once_with cannot be used with series, so need to use
# assert_series_equal on call_args
assert_series_equal(m_sapm.call_args[0][1], weather['temp_air']) # temp
assert_series_equal(m_sapm.call_args[0][2], weather['wind_speed']) # wind
assert m_sapm.call_args[1]['model'] == 'sapm'
Copy link
Member

Choose a reason for hiding this comment

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

No objection to this. An alternative is modifying the spy line to mocker.spy(temperature, 'sapm_cell') and dropping this line.

# additional model-specific (and array-specific) inputs
extra_inputs = [{}] * self.num_arrays

if 'effective_irradiance' in kwargs:
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason we cannot add effective_irradiance=None to the method signature and drop kwargs? I don't see one, but I feel like I might be forgetting something from a previous discussion.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think I was anticipating new models with new weather inputs, but better to cross that bridge if we come to it. The code is much simpler now without this.

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.

Thanks @kanderso-nrel. @cwhanse can you take another look, especially double checking the handling of effective_irradiance? Ok with me to merge if you approve.

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.

It looks to me that ModelChain.temperature_model becomes obsolete with addition of these methods. I could be mistaken. Separate issue, in either case.

@wholmgren wholmgren merged commit 77ac247 into pvlib:master May 14, 2021
@kandersolar kandersolar deleted the array_tcell branch May 14, 2021 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants