Skip to content

Update CEC module and inverter tables with latest SAM files #1433

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

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/examples/bifacial/plot_bifi_model_mc.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
cec_modules = pvsystem.retrieve_sam('CECMod')
cec_module = cec_modules['Trina_Solar_TSM_300DEG5C_07_II_']
cec_inverters = pvsystem.retrieve_sam('cecinverter')
cec_inverter = cec_inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_']
cec_inverter = cec_inverters['Enphase_Energy_Inc___IQ6_60_ACM_US__208V_']

# create a location for site, and get solar position and clearsky data
site_location = location.Location(lat, lon, tz=tz, name='Greensboro, NC')
Expand Down
2 changes: 1 addition & 1 deletion docs/sphinx/source/user_guide/forecasts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ for details.
sandia_modules = retrieve_sam('sandiamod')
cec_inverters = retrieve_sam('cecinverter')
module = sandia_modules['Canadian_Solar_CS5P_220M___2009_']
inverter = cec_inverters['SMA_America__SC630CP_US__with_ABB_EcoDry_Ultra_transformer_']
inverter = cec_inverters['Enphase_Energy_Inc___IQ6_60_ACM_US__208V_']
temperature_model_parameters = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']

# model a big tracker for more fun
Expand Down
2 changes: 1 addition & 1 deletion docs/sphinx/source/user_guide/introtutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ configuration at a handful of sites listed below.
sandia_modules = pvlib.pvsystem.retrieve_sam('SandiaMod')
sapm_inverters = pvlib.pvsystem.retrieve_sam('cecinverter')
module = sandia_modules['Canadian_Solar_CS5P_220M___2009_']
inverter = sapm_inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_']
inverter = sapm_inverters['Enphase_Energy_Inc___IQ6_60_ACM_US__208V_']
temperature_model_parameters = pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']


Expand Down
2 changes: 1 addition & 1 deletion docs/sphinx/source/user_guide/modelchain.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ objects, module data, and inverter data.
cec_inverters = pvlib.pvsystem.retrieve_sam('cecinverter')

sandia_module = sandia_modules['Canadian_Solar_CS5P_220M___2009_']
cec_inverter = cec_inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_']
cec_inverter = cec_inverters['Enphase_Energy_Inc___IQ6_60_ACM_US__208V_']

Now we create a Location object, a Mount object, a PVSystem object, and a
ModelChain object.
Expand Down
4 changes: 2 additions & 2 deletions docs/sphinx/source/user_guide/pvsystem.rst
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,10 @@ included with pvlib python by using the :py:func:`~pvlib.pvsystem.retrieve_sam`
modules = pvsystem.retrieve_sam('cecmod')
# retrieve_sam returns a dict. the dict keys are module names,
# and the values are model parameters for that module
module_parameters = modules['Canadian_Solar_Inc__CS5P_220M']
module_parameters = modules['JA_Solar_JAM5_72_165']
# Load the database of CEC inverter model parameters
inverters = pvsystem.retrieve_sam('cecinverter')
inverter_parameters = inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_']
inverter_parameters = inverters['Enphase_Energy_Inc___IQ6_60_ACM_US__208V_']
system_one_array = pvsystem.PVSystem(module_parameters=module_parameters,
inverter_parameters=inverter_parameters)

Expand Down
3 changes: 3 additions & 0 deletions docs/sphinx/source/whatsnew/v0.9.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ Enhancements
* Added ``map_variables`` option to :func:`~pvlib.iotools.read_crn` (:pull:`1368`)
* Added :py:func:`pvlib.temperature.prilliman` for modeling cell temperature
at short time steps (:issue:`1081`, :pull:`1391`)
* Updated the CEC parameter tables returned by :py:func:`pvlib.pvsystem.retrieve_sam`
with the latest tables from SAM. Older tables can be retrieved using the new
optional ``version`` parameter. (:issue:`1345`, :pull:`1433`)

Bug fixes
~~~~~~~~~
Expand Down
1,324 changes: 1,324 additions & 0 deletions pvlib/data/sam-library-cec-inverters-2022-02-18.csv

Large diffs are not rendered by default.

16,833 changes: 16,833 additions & 0 deletions pvlib/data/sam-library-cec-modules-2021-12-01.csv

Large diffs are not rendered by default.

72 changes: 51 additions & 21 deletions pvlib/pvsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -2273,7 +2273,26 @@ def calcparams_pvsyst(effective_irradiance, temp_cell,
return IL, I0, Rs, Rsh, nNsVth


def retrieve_sam(name=None, path=None):
def _get_cec_version_or_latest(data_path, filename_prefix, version):
matches = list(filter(lambda fn: fn.startswith(filename_prefix),
os.listdir(data_path)))
if version is None:
# assume the lexicographic max is the latest version:
return max(matches)

filename = filename_prefix + version + ".csv"
if not os.path.exists(os.path.join(data_path, filename)):
versions = [
match.replace(filename_prefix, "").replace(".csv", "")
for match in matches
]
raise ValueError("'version' must be one of "
f"{versions}, not '{version}'")

return filename


def retrieve_sam(name=None, path=None, version=None):
'''
Retrieve latest module and inverter info from a local file or the
SAM website.
Expand Down Expand Up @@ -2303,6 +2322,11 @@ def retrieve_sam(name=None, path=None):
path : None or string, default None
Path to the SAM file. May also be a URL.

version : str, optional
Used in combination with ``name`` to select a particular version of
the CEC lists. If not specified, the latest version is returned.
Ignored for non-CEC databases.

Returns
-------
samfile : DataFrame
Expand All @@ -2313,7 +2337,7 @@ def retrieve_sam(name=None, path=None):
Raises
------
ValueError
If no name or path is provided.
If no name or path is provided, or an invalid version is provided.

Notes
-----
Expand All @@ -2327,32 +2351,36 @@ def retrieve_sam(name=None, path=None):

>>> from pvlib import pvsystem
>>> invdb = pvsystem.retrieve_sam('CECInverter')
>>> inverter = invdb.AE_Solar_Energy__AE6_0__277V__277V__CEC_2012_
>>> inverter = invdb.ABB__PVI_6000_OUTD_US_Z_M_A__277V_
>>> inverter
Vac 277.000000
Paco 6000.000000
Pdco 6165.670000
Vdco 361.123000
Pso 36.792300
Vac 277
Pso 35.3609
Paco 6000.0
Pdco 6196.81
Vdco 400.0
C0 -0.000002
C1 -0.000047
C2 -0.001861
C3 0.000721
Pnt 0.070000
Vdcmax 600.000000
Idcmax 32.000000
Mppt_low 200.000000
Mppt_high 500.000000
Name: AE_Solar_Energy__AE6_0__277V__277V__CEC_2012_, dtype: float64
C1 -0.000024
C2 -0.000044
C3 -0.001749
Pnt 0.32
Vdcmax 480.0
Idcmax 15.492
Mppt_low 100.0
Mppt_high 480.0
CEC_Date 10/15/2018
CEC_hybrid N
Name: ABB__PVI_6000_OUTD_US_Z_M_A__277V_, dtype: object
'''

if name is not None:
name = name.lower()
data_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)), 'data')
if name == 'cecmod':
csvdata = os.path.join(
data_path, 'sam-library-cec-modules-2019-03-05.csv')
fn = _get_cec_version_or_latest(data_path,
'sam-library-cec-modules-',
version)
csvdata = os.path.join(data_path, fn)
elif name == 'sandiamod':
csvdata = os.path.join(
data_path, 'sam-library-sandia-modules-2015-6-30.csv')
Expand All @@ -2361,8 +2389,10 @@ def retrieve_sam(name=None, path=None):
elif name in ['cecinverter', 'sandiainverter']:
# Allowing either, to provide for old code,
# while aligning with current expectations
csvdata = os.path.join(
data_path, 'sam-library-cec-inverters-2019-03-05.csv')
fn = _get_cec_version_or_latest(data_path,
'sam-library-cec-inverters-',
version)
csvdata = os.path.join(data_path, fn)
else:
raise ValueError(f'invalid name {name}')
elif path is not None:
Expand Down
81 changes: 80 additions & 1 deletion pvlib/tests/test_pvsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,45 @@ def test_retrieve_sam_raise_no_parameters():
assert 'A name or path must be provided!' == str(error.value)


def test_retrieve_sam_cecmod_version():
"""
Test the expected data is retrieved from the CEC module database. In
particular, check for a known module in the database and check for the
expected keys for that module.
"""
data = pvsystem.retrieve_sam('cecmod', version='2019-03-05')
keys = [
'BIPV',
'Date',
'T_NOCT',
'A_c',
'N_s',
'I_sc_ref',
'V_oc_ref',
'I_mp_ref',
'V_mp_ref',
'alpha_sc',
'beta_oc',
'a_ref',
'I_L_ref',
'I_o_ref',
'R_s',
'R_sh_ref',
'Adjust',
'gamma_r',
'Version',
'STC',
'PTC',
'Technology',
'Bifacial',
'Length',
'Width',
]
module = 'Itek_Energy_LLC_iT_300_HE'
assert module in data
assert set(data[module].keys()) == set(keys)


def test_retrieve_sam_cecmod():
"""
Test the expected data is retrieved from the CEC module database. In
Expand Down Expand Up @@ -136,19 +175,59 @@ def test_retrieve_sam_cecmod():
'Bifacial',
'Length',
'Width',
'Manufacturer',
]
module = 'Itek_Energy_LLC_iT_300_HE'
# nothing special about this module; OK to switch to another
# if this one disappears from the CEC file
module = 'JA_Solar_JAM5_72_165'
assert module in data
assert set(data[module].keys()) == set(keys)


def test_retrieve_sam_bad_version():
with pytest.raises(ValueError, match="'version' must be one of"):
_ = pvsystem.retrieve_sam('cecmod', version='no good')


def test_retrieve_sam_cecinverter():
"""
Test the expected data is retrieved from the CEC inverter database. In
particular, check for a known inverter in the database and check for the
expected keys for that inverter.
"""
data = pvsystem.retrieve_sam('cecinverter')
keys = [
'Vac',
'Paco',
'Pdco',
'Vdco',
'Pso',
'C0',
'C1',
'C2',
'C3',
'Pnt',
'Vdcmax',
'Idcmax',
'Mppt_low',
'Mppt_high',
'CEC_Date',
'CEC_hybrid',
]
# nothing special about this inverter; OK to switch to another
# if this one disappears from the CEC file
inverter = 'Yaskawa_Solectria_Solar__XGI_1500_166_166__600V_'
assert inverter in data
assert set(data[inverter].keys()) == set(keys)


def test_retrieve_sam_cecinverter_version():
"""
Test the expected data is retrieved from the CEC inverter database. In
particular, check for a known inverter in the database and check for the
expected keys for that inverter.
"""
data = pvsystem.retrieve_sam('cecinverter', version='2019-03-05')
keys = [
'Vac',
'Paco',
Expand Down
4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@
'doc': ['ipython', 'matplotlib', 'sphinx == 3.1.2',
'pydata-sphinx-theme == 0.8.0', 'sphinx-gallery',
'docutils == 0.15.2', 'pillow', 'netcdf4', 'siphon',
'sphinx-toggleprompt >= 0.0.5', 'pvfactors'],
'sphinx-toggleprompt >= 0.0.5', 'pvfactors',
'jinja2<3.1', # https://github.com/sphinx-doc/sphinx/issues/10291
],
'test': TESTS_REQUIRE
}
EXTRAS_REQUIRE['all'] = sorted(set(sum(EXTRAS_REQUIRE.values(), [])))
Expand Down