Skip to content

Commit a7edb8b

Browse files
authored
preconfigured ModelChain for pvwatts, sapm (#1022)
* PVWatts(ModelChain) * make_chain_pvwatts classmethod * sapm * method names, comment * remove class, add pvsyst stub * fix dict update, a couple of tests * documentation * remove incomplete with_pvsyst * fix temperature model issues * fix temp model kwarg. run_model in test * complicated code is bad * remove with_pvsyst from docs
1 parent 87d1bf2 commit a7edb8b

File tree

4 files changed

+209
-0
lines changed

4 files changed

+209
-0
lines changed

docs/sphinx/source/api.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,8 @@ Creating a ModelChain object.
495495
:toctree: generated/
496496

497497
modelchain.ModelChain
498+
modelchain.ModelChain.with_pvwatts
499+
modelchain.ModelChain.with_sapm
498500

499501
Running
500502
-------

docs/sphinx/source/whatsnew/v0.8.0.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ Enhancements
4444
(:pull:`1017`)
4545
* Add :py:func:`pvlib.inverter.fit_sandia` that fits the Sandia inverter model
4646
to a set of inverter efficiency curves. (:pull:`1011`)
47+
* Add factory methods :py:meth:`~pvlib.modelchain.ModelChain.with_pvwatts`
48+
:py:meth:`~pvlib.modelchain.ModelChain.with_sapm` to create ``ModelChain``
49+
objects configured for the respective modeling paradigms. The
50+
configurations are defined in ``modelchain.PVWATTS_CONFIG``, and
51+
``modelchain.SAPM_CONFIG``. (:issue:`1013`, :pull:`1022`)
4752
* Added *racking_model*, *module_type*, and *temperature_model_parameters* to
4853
PVSystem, LocalizedPVSystem, SingleAxisTracker, and
4954
LocalizedSingleAxisTracker repr methods. (:issue:`1027`)

pvlib/modelchain.py

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,30 @@
1818
from pvlib._deprecation import pvlibDeprecationWarning
1919
from pvlib.tools import _build_kwargs
2020

21+
22+
# these dictionaries contain the default configuration for following
23+
# established modeling sequences. They can be used in combination with
24+
# basic_chain and ModelChain. They are used by the ModelChain methods
25+
# ModelChain.with_pvwatts, ModelChain.with_sapm, etc.
26+
27+
# pvwatts documentation states that it uses the following reference for
28+
# a temperature model: Fuentes, M. K. (1987). A Simplified Thermal Model
29+
# for Flat-Plate Photovoltaic Arrays. SAND85-0330. Albuquerque, NM:
30+
# Sandia National Laboratories. Accessed September 3, 2013:
31+
# http://prod.sandia.gov/techlib/access-control.cgi/1985/850330.pdf
32+
# pvlib python does not implement that model, so use the SAPM instead.
33+
PVWATTS_CONFIG = dict(
34+
dc_model='pvwatts', ac_model='pvwatts', losses_model='pvwatts',
35+
transposition_model='perez', aoi_model='physical',
36+
spectral_model='no_loss', temperature_model='sapm'
37+
)
38+
39+
SAPM_CONFIG = dict(
40+
dc_model='sapm', ac_model='sandia', losses_model='no_loss',
41+
aoi_model='sapm', spectral_model='sapm', temperature_model='sapm'
42+
)
43+
44+
2145
def basic_chain(times, latitude, longitude,
2246
module_parameters, temperature_model_parameters,
2347
inverter_parameters,
@@ -349,6 +373,171 @@ def __init__(self, system, location,
349373
self.times = None
350374
self.solar_position = None
351375

376+
@classmethod
377+
def with_pvwatts(cls, system, location,
378+
orientation_strategy=None,
379+
clearsky_model='ineichen',
380+
airmass_model='kastenyoung1989',
381+
name=None,
382+
**kwargs):
383+
"""
384+
ModelChain that follows the PVWatts methods.
385+
386+
Parameters
387+
----------
388+
system : PVSystem
389+
A :py:class:`~pvlib.pvsystem.PVSystem` object that represents
390+
the connected set of modules, inverters, etc.
391+
392+
location : Location
393+
A :py:class:`~pvlib.location.Location` object that represents
394+
the physical location at which to evaluate the model.
395+
396+
orientation_strategy : None or str, default None
397+
The strategy for aligning the modules. If not None, sets the
398+
``surface_azimuth`` and ``surface_tilt`` properties of the
399+
``system``. Allowed strategies include 'flat',
400+
'south_at_latitude_tilt'. Ignored for SingleAxisTracker systems.
401+
402+
clearsky_model : str, default 'ineichen'
403+
Passed to location.get_clearsky.
404+
405+
airmass_model : str, default 'kastenyoung1989'
406+
Passed to location.get_airmass.
407+
408+
name: None or str, default None
409+
Name of ModelChain instance.
410+
411+
**kwargs
412+
Parameters supplied here are passed to the ModelChain
413+
constructor and take precedence over the default
414+
configuration.
415+
416+
Examples
417+
--------
418+
>>> module_parameters = dict(gamma_pdc=-0.003, pdc0=4500)
419+
>>> inverter_parameters = dict(pac0=4000)
420+
>>> tparams = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']
421+
>>> system = PVSystem(surface_tilt=30, surface_azimuth=180,
422+
... module_parameters=module_parameters,
423+
... inverter_parameters=inverter_parameters,
424+
... temperature_model_parameters=tparams)
425+
>>> location = Location(32.2, -110.9)
426+
>>> ModelChain.with_pvwatts(system, location)
427+
ModelChain:
428+
name: None
429+
orientation_strategy: None
430+
clearsky_model: ineichen
431+
transposition_model: perez
432+
solar_position_method: nrel_numpy
433+
airmass_model: kastenyoung1989
434+
dc_model: pvwatts_dc
435+
ac_model: pvwatts_inverter
436+
aoi_model: physical_aoi_loss
437+
spectral_model: no_spectral_loss
438+
temperature_model: sapm_temp
439+
losses_model: pvwatts_losses
440+
""" # noqa: E501
441+
config = PVWATTS_CONFIG.copy()
442+
config.update(kwargs)
443+
return ModelChain(
444+
system, location,
445+
orientation_strategy=orientation_strategy,
446+
clearsky_model=clearsky_model,
447+
airmass_model=airmass_model,
448+
name=name,
449+
**config
450+
)
451+
452+
@classmethod
453+
def with_sapm(cls, system, location,
454+
orientation_strategy=None,
455+
clearsky_model='ineichen',
456+
transposition_model='haydavies',
457+
solar_position_method='nrel_numpy',
458+
airmass_model='kastenyoung1989',
459+
name=None,
460+
**kwargs):
461+
"""
462+
ModelChain that follows the Sandia Array Performance Model
463+
(SAPM) methods.
464+
465+
Parameters
466+
----------
467+
system : PVSystem
468+
A :py:class:`~pvlib.pvsystem.PVSystem` object that represents
469+
the connected set of modules, inverters, etc.
470+
471+
location : Location
472+
A :py:class:`~pvlib.location.Location` object that represents
473+
the physical location at which to evaluate the model.
474+
475+
orientation_strategy : None or str, default None
476+
The strategy for aligning the modules. If not None, sets the
477+
``surface_azimuth`` and ``surface_tilt`` properties of the
478+
``system``. Allowed strategies include 'flat',
479+
'south_at_latitude_tilt'. Ignored for SingleAxisTracker systems.
480+
481+
clearsky_model : str, default 'ineichen'
482+
Passed to location.get_clearsky.
483+
484+
transposition_model : str, default 'haydavies'
485+
Passed to system.get_irradiance.
486+
487+
solar_position_method : str, default 'nrel_numpy'
488+
Passed to location.get_solarposition.
489+
490+
airmass_model : str, default 'kastenyoung1989'
491+
Passed to location.get_airmass.
492+
493+
name: None or str, default None
494+
Name of ModelChain instance.
495+
496+
**kwargs
497+
Parameters supplied here are passed to the ModelChain
498+
constructor and take precedence over the default
499+
configuration.
500+
501+
Examples
502+
--------
503+
>>> mods = pvlib.pvsystem.retrieve_sam('sandiamod')
504+
>>> invs = pvlib.pvsystem.retrieve_sam('cecinverter')
505+
>>> module_parameters = mods['Canadian_Solar_CS5P_220M___2009_']
506+
>>> inverter_parameters = invs['ABB__MICRO_0_25_I_OUTD_US_240__240V_']
507+
>>> tparams = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']
508+
>>> system = PVSystem(surface_tilt=30, surface_azimuth=180,
509+
... module_parameters=module_parameters,
510+
... inverter_parameters=inverter_parameters,
511+
... temperature_model_parameters=tparams)
512+
>>> location = Location(32.2, -110.9)
513+
>>> ModelChain.with_sapm(system, location)
514+
ModelChain:
515+
name: None
516+
orientation_strategy: None
517+
clearsky_model: ineichen
518+
transposition_model: haydavies
519+
solar_position_method: nrel_numpy
520+
airmass_model: kastenyoung1989
521+
dc_model: sapm
522+
ac_model: snlinverter
523+
aoi_model: sapm_aoi_loss
524+
spectral_model: sapm_spectral_loss
525+
temperature_model: sapm_temp
526+
losses_model: no_extra_losses
527+
""" # noqa: E501
528+
config = SAPM_CONFIG.copy()
529+
config.update(kwargs)
530+
return ModelChain(
531+
system, location,
532+
orientation_strategy=orientation_strategy,
533+
clearsky_model=clearsky_model,
534+
transposition_model=transposition_model,
535+
solar_position_method=solar_position_method,
536+
airmass_model=airmass_model,
537+
name=name,
538+
**config
539+
)
540+
352541
def __repr__(self):
353542
attrs = [
354543
'name', 'orientation_strategy', 'clearsky_model',

pvlib/tests/test_modelchain.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,19 @@ def test_ModelChain_creation(sapm_dc_snl_ac_system, location):
170170
ModelChain(sapm_dc_snl_ac_system, location)
171171

172172

173+
def test_with_sapm(sapm_dc_snl_ac_system, location, weather):
174+
mc = ModelChain.with_sapm(sapm_dc_snl_ac_system, location)
175+
assert mc.dc_model == mc.sapm
176+
mc.run_model(weather)
177+
178+
179+
def test_with_pvwatts(pvwatts_dc_pvwatts_ac_system, location, weather):
180+
mc = ModelChain.with_pvwatts(pvwatts_dc_pvwatts_ac_system, location)
181+
assert mc.dc_model == mc.pvwatts_dc
182+
assert mc.temperature_model == mc.sapm_temp
183+
mc.run_model(weather)
184+
185+
173186
@pytest.mark.parametrize('strategy, expected', [
174187
(None, (32.2, 180)), ('None', (32.2, 180)), ('flat', (0, 180)),
175188
('south_at_latitude_tilt', (32.2, 180))

0 commit comments

Comments
 (0)