-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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 consistency tests to ModelChain.dc_model #548
Conversation
pvlib/modelchain.py
Outdated
self._dc_model = self.sapm | ||
# validate module parameters | ||
missing_params = self._sapm_param_set() - \ | ||
set(self.system.module.keys()) |
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.
self.system.module_parameters.keys()
pvlib/modelchain.py
Outdated
return set(['A0', 'A1', 'A2', 'A3', 'A4', 'B0', 'B1', 'B2', 'B3', 'B4', | ||
'B5', 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'Isco', | ||
'Impo', 'Aisc', 'Aimp', 'Bvoco', 'Mbvoc', 'Bvmpo', 'Mbvmp', | ||
'N', 'Cells_in_Series', 'IX0', 'IXX0', 'FD']) |
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.
do you want to use this whole set in the ModelChain.infer_dc_model
below?
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.
yes
pvlib/modelchain.py
Outdated
missing_params = self._sapm_param_set() - \ | ||
set(self.system.module.keys()) | ||
if missing_params: # some parameters are not in module.keys() | ||
raise ValueError('SAPM selected for the DC model but ' + \ |
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 you can get by without the + \
. Strings are automatically concatenated within ()
that span multiple lines.
pvlib/modelchain.py
Outdated
else: | ||
raise ValueError(model + ' is not a valid DC power model') | ||
else: | ||
self._dc_model = partial(model, self) | ||
|
||
def _sapm_param_set(): |
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'm ok with using a function for each of these but it seems a bit overkill and harder to extend in the future.
One alternative would be defining a class or module level dictionary like this:
dc_model_parameters = {'sapm': set([....]), 'singlediode': set([...]), 'pvwatts': set([...])}
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.
One could argue that this parameter dictionary should live in pvsystem.py
and imported into modelchain.py
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.
At what point in modelchain.py
should this function be imported?
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.
Probably at the top with the rest of the imports.
I'm considering the following change, in which def dc_model(self, model):
# guess at model if None
if model is None:
self._dc_model, model = self.infer_dc_model()
# Set model and validate parameters
if isinstance(model, str):
model = model.lower()
# validate module parameters
missing_params = DC_MODEL_PARAMS[model] - \
set(self.system.module_parameters.keys())
if missing_params: # some parameters are not in module.keys()
raise ValueError(model + ' selected for the DC model but '
'one or more required parameters '
' are missing : ' +
str(missing_params))
if model == 'sapm':
self._dc_model = self.sapm
elif model == 'singlediode':
self._dc_model = self.singlediode
elif model == 'pvwatts':
self._dc_model = self.pvwatts_dc
else:
raise ValueError(model + ' is not a valid DC power model')
else:
self._dc_model = partial(model, self)
def infer_dc_model(self):
# returns both model function object and model string, could drop
# model function object in the future since the model function object
# will be set in dc_model after validating parameter consistency
params = set(self.system.module_parameters.keys())
if set(['A0', 'A1', 'C7']) <= params:
return self.sapm, 'sapm'
elif set(['a_ref', 'I_L_ref', 'I_o_ref', 'R_sh_ref', 'R_s']) <= params:
return self.singlediode, 'singlediode'
elif set(['pdc0', 'gamma_pdc']) <= params:
return self.pvwatts_dc, 'pvwatts_dc'
else:
raise ValueError('could not infer DC model from '
'system.module_parameters') |
@cwhanse that's ok with me. Your comment says "could drop model function object in the future" -- why not now? |
It’s an API change for the method, I’m hesitant to possibly break someone’s code without a warning although the risk here is probably zero. |
It's an API change either way, but I agree the risk is near 0 and not worth a deprecation cycle. |
Just picking up on the last few comments out of context... I think it would be nice to users to generate warnings related to API changes, provided you can detect that they're trying to use something form the old API, and to keep those warnings around for a good long time. This will be especially useful for occasional users, who may not update everything all the time, and new users, who may pick up examples based on any past version, and old users who can't remember stuff. |
@adriesse 0.6.0 will print deprecation warnings for the vast majority of API changes. I'd like to keep the warnings around "long enough" but I have no idea what that or "a good long time" means in practice! Realistically, we're looking at 6-12 months for the current pace of 0.x releases. For the specific API change discussed here, I'd rather not go through a deprecation cycle because I don't think anyone is explicitly using this method so It's not worth the effort. |
pvlib/modelchain.py
Outdated
if missing_params: # some parameters are not in module.keys() | ||
raise ValueError(model + ' selected for the DC model but ' | ||
'one or more required parameters ' | ||
' are missing : ' + |
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.
space in string at end of previous line and beginning of this one, so remove one of them.
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.
Removed
pvlib/test/test_modelchain.py
Outdated
@@ -376,7 +408,7 @@ def test_invalid_models(model, system, location): | |||
kwargs[model] = 'invalid' | |||
with pytest.raises(ValueError): | |||
mc = ModelChain(system, location, **kwargs) | |||
|
|||
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.
See if you can set your editor to remove extra white space from lines when saving. It makes git diffs unnecessarily busy.
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.
Done
pvlib/test/test_modelchain.py
Outdated
kwargs = {'dc_model': 'sapm', 'ac_model': 'snlinverter', | ||
'aoi_model': 'no_loss', 'spectral_model': 'no_loss', | ||
'temp_model': 'sapm', 'losses_model': 'no_loss'} | ||
tmp = copy.deepcopy(system) |
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.
Did you find that it was necessary to use copy
here for the test to pass with pytest
? I am surprised because the test fixtures should generate a new system with fresh data for each test. You're not reusing them within this test so I don't see why it would be necessary. I can see that if you were developing this test function in the interpreter/notebook then the story would be different.
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 didn't know that test fixtures are generated anew for each test. I used copy
out of concern that pop
-ing a key off the module_parameters
dict would alter system
etc. for other tests.
Removed.
pvlib python pull request guidelines
Thank you for your contribution to pvlib python! You may delete all of these instructions except for the list below.
You may submit a pull request with your code at any stage of completion.
The following items must be addressed before the code can be merged. Please don't hesitate to ask for help if you're unsure of how to accomplish any of the items below:
docs/sphinx/source/api.rst
for API changes.docs/sphinx/source/whatsnew
file for all changes.git diff upstream/master -u -- "*.py" | flake8 --diff
Brief description of the problem and proposed solution (if not already fully described in the issue linked to above):
Tests for consistency between
module
parameters anddc_model
choice.