diff --git a/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst b/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst index 8041d8f49b..721abbfae2 100644 --- a/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst +++ b/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst @@ -8,6 +8,7 @@ Spectrum spectrum.spectrl2 spectrum.get_example_spectral_response + spectrum.get_spectral_response_of_material spectrum.get_am15g spectrum.calc_spectral_mismatch_field spectrum.spectral_factor_caballero diff --git a/docs/sphinx/source/whatsnew/v0.11.0.rst b/docs/sphinx/source/whatsnew/v0.11.0.rst index 22d6046774..883fb7fc7c 100644 --- a/docs/sphinx/source/whatsnew/v0.11.0.rst +++ b/docs/sphinx/source/whatsnew/v0.11.0.rst @@ -21,6 +21,9 @@ Enhancements shade perpendicular to ``axis_azimuth``. The function is applicable to both fixed-tilt and one-axis tracking systems. (:issue:`1689`, :pull:`1725`, :pull:`1962`) +* Added more spectral responses materials ``monosi``, ``polysi`` and ``hit`` + with the function :py:func:`pvlib.spectrum.get_spectral_response_of_material` + (:issue:`2037`, :pull:`2038`) Bug fixes @@ -44,3 +47,4 @@ Contributors * Cliff Hansen (:ghuser:`cwhanse`) * Mark Mikofski (:ghuser:`mikofski`) * Siddharth Kaul (:ghuser:`k10blogger`) +* Anton Driesse (:ghuser:`adriesse`) diff --git a/pvlib/data/duramat_spectral_responses.csv b/pvlib/data/duramat_spectral_responses.csv new file mode 100644 index 0000000000..88ee33468b --- /dev/null +++ b/pvlib/data/duramat_spectral_responses.csv @@ -0,0 +1,182 @@ +wavelength,polysi,monosi,hit +300,0.0,0.0,0.0 +305,0.03430462,0.046272006,0.0077158213 +310,0.067423105,0.08857482,0.01129055 +315,0.099974155,0.1274098,0.0107729435 +320,0.13169432,0.16370991,0.00962472 +325,0.16080761,0.19627707,0.008452892 +330,0.18828392,0.2276486,0.0072233677 +335,0.21377945,0.2564403,0.005968213 +340,0.23356247,0.275583,0.0053931475 +345,0.24752903,0.28591865,0.0057656765 +350,0.25888252,0.29379436,0.0068725348 +355,0.2688427,0.30039543,0.008698225 +360,0.2786274,0.30690002,0.0112268925 +365,0.28945923,0.31449127,0.014442682 +370,0.30155563,0.3235986,0.030305862 +375,0.31418228,0.33355278,0.06445885 +380,0.3271351,0.3438895,0.10740852 +385,0.34021187,0.35413796,0.14966583 +390,0.35375977,0.3646153,0.19563293 +395,0.36777306,0.37546867,0.2486229 +400,0.38153076,0.3859689,0.29750824 +405,0.3943119,0.39539665,0.33116913 +410,0.40576935,0.4032473,0.34978485 +415,0.41654396,0.4107895,0.3629303 +420,0.42712402,0.41936165,0.3729782 +425,0.43742943,0.42833382,0.38117218 +430,0.44735146,0.43665642,0.3887558 +435,0.45687103,0.44399372,0.39595795 +440,0.46611214,0.4508558,0.402565 +445,0.47519302,0.4574683,0.4091568 +450,0.48422813,0.4640612,0.41630554 +455,0.4932537,0.47094616,0.4245758 +460,0.5022507,0.47808728,0.43358612 +465,0.5112419,0.48519462,0.44250488 +470,0.52025986,0.4919804,0.4505005 +475,0.5294876,0.4986169,0.45726776 +480,0.5388603,0.5053831,0.46339417 +485,0.54803467,0.5121318,0.46939087 +490,0.55667114,0.51871926,0.47575378 +495,0.564579,0.52507454,0.48273468 +500,0.5720749,0.53134376,0.48999023 +505,0.57951355,0.53767616,0.4972229 +510,0.58703995,0.5441938,0.5043335 +515,0.594532,0.550827,0.5114441 +520,0.6019516,0.5574755,0.5185089 +525,0.6092453,0.56404114,0.52545166 +530,0.6164131,0.57059807,0.53234863 +535,0.62348175,0.5771724,0.5391693 +540,0.6304512,0.5836116,0.5458679 +545,0.6373291,0.58974564,0.5523529 +550,0.64414597,0.59557885,0.5586395 +555,0.6509476,0.6012377,0.5647888 +560,0.6577034,0.6067527,0.57081604 +565,0.6644249,0.61214554,0.5767517 +570,0.6711197,0.6174469,0.5826111 +575,0.6777687,0.62268066,0.5884094 +580,0.6843834,0.6278839,0.594162 +585,0.69096375,0.6330719,0.5998993 +590,0.6974945,0.63828385,0.60565186 +595,0.7039833,0.6435438,0.6114044 +600,0.7104225,0.64887565,0.617218 +605,0.7168274,0.65431213,0.6230774 +610,0.72317886,0.65987504,0.6290283 +615,0.7294426,0.66564506,0.6351013 +620,0.7356148,0.67159164,0.6412964 +625,0.74173737,0.6775796,0.6474762 +630,0.74785995,0.68348694,0.65353394 +635,0.75401306,0.6891915,0.659317 +640,0.7602844,0.69464546,0.6648102 +645,0.76665115,0.69996864,0.6700897 +650,0.77301025,0.70524377,0.6752472 +655,0.7792702,0.71055824,0.68037415 +660,0.78533554,0.7160034,0.6855469 +665,0.7912674,0.72201973,0.69070435 +670,0.79698944,0.72805786,0.69599915 +675,0.80231476,0.73349,0.70173645 +680,0.8074875,0.7387412,0.7077484 +685,0.8127403,0.7439641,0.71380615 +690,0.8183594,0.74932206,0.71969604 +695,0.82481,0.7550441,0.72550964 +700,0.8318863,0.76101464,0.73132324 +705,0.83882904,0.7668435,0.7368469 +710,0.84488297,0.77214485,0.74176025 +715,0.84970856,0.7767029,0.745697 +720,0.85404587,0.7809339,0.74920654 +725,0.85871506,0.78542,0.7534332 +730,0.8645134,0.7907453,0.75979614 +735,0.87086487,0.796572,0.76742554 +740,0.87664413,0.80210876,0.77397156 +745,0.8816147,0.80708313,0.7785797 +750,0.88636017,0.81192017,0.78245544 +755,0.8908882,0.81686836,0.78619385 +760,0.8952484,0.8221763,0.79045105 +765,0.89949036,0.82890755,0.79571533 +770,0.903656,0.8356476,0.8012085 +775,0.9078293,0.8410209,0.80630493 +780,0.9120903,0.84603447,0.81126404 +785,0.9164429,0.85078865,0.81614685 +790,0.9208832,0.85538375,0.82095337 +795,0.9254303,0.859933,0.8257446 +800,0.9300728,0.8645434,0.8305664 +805,0.93481445,0.8693128,0.8354187 +810,0.93967056,0.8743526,0.84036255 +815,0.9450035,0.87991554,0.8453369 +820,0.9507446,0.88584244,0.85032654 +825,0.9562454,0.8916059,0.855423 +830,0.9608612,0.89669144,0.86073303 +835,0.9646683,0.901147,0.86642456 +840,0.9682121,0.905413,0.872406 +845,0.9715347,0.9095677,0.87838745 +850,0.9746666,0.9136723,0.8840332 +855,0.97792816,0.91794693,0.88916016 +860,0.9813576,0.9224439,0.89401245 +865,0.9845543,0.9269671,0.89886475 +870,0.9871063,0.9313224,0.9040222 +875,0.98947525,0.93566674,0.9099884 +880,0.99199677,0.9401049,0.9164734 +885,0.9941025,0.9443316,0.9226227 +890,0.99520874,0.9480504,0.9276123 +895,0.99557877,0.95132226,0.9312897 +900,0.9958687,0.95445687,0.9343262 +905,0.99609756,0.95751953,0.937027 +910,0.9962692,0.9605735,0.9396515 +915,0.9963989,0.96368843,0.94252014 +920,0.9964943,0.9669233,0.94592285 +925,0.9963379,0.9706334,0.9500122 +930,0.9957237,0.974823,0.9546356 +935,0.99466705,0.97904533,0.95962524 +940,0.9931793,0.9828535,0.96487427 +945,0.9912758,0.9857984,0.9702301 +950,0.988224,0.9881243,0.9767456 +955,0.98368454,0.99024093,0.9845581 +960,0.9782982,0.9919499,0.9920807 +965,0.97270584,0.99304634,0.99775696 +970,0.9675293,0.99331665,1.0 +975,0.9622688,0.9926278,0.9988861 +980,0.9560547,0.99116737,0.9964752 +985,0.9489746,0.9891488,0.9940491 +990,0.94112396,0.98680335,0.99295044 +995,0.93165207,0.98391724,0.99334717 +1000,0.9198532,0.98009384,0.99438477 +1005,0.90608597,0.9752982,0.9957123 +1010,0.8906975,0.9694868,0.9970398 +1015,0.8740425,0.9626356,0.99806213 +1020,0.856472,0.95470536,0.9984741 +1025,0.83699036,0.9440831,0.9965668 +1030,0.81474686,0.9297442,0.9912567 +1035,0.7902565,0.91251916,0.9832001 +1040,0.7640648,0.89323646,0.97299194 +1045,0.7366905,0.87270683,0.96128845 +1050,0.70866776,0.8517805,0.94873047 +1055,0.6784744,0.8289032,0.9313507 +1060,0.64549255,0.8028608,0.90708923 +1065,0.6115532,0.77492195,0.879303 +1070,0.57852554,0.7463662,0.8514404 +1075,0.5462322,0.7168862,0.8238678 +1080,0.5138664,0.685791,0.79478455 +1085,0.48231888,0.6537334,0.7641907 +1090,0.45248795,0.6213662,0.73213196 +1095,0.42430305,0.5880454,0.69776917 +1100,0.3972702,0.55379486,0.6612396 +1105,0.37163544,0.5202495,0.62402344 +1110,0.34648323,0.48674557,0.5852051 +1115,0.32086182,0.4517975,0.54338074 +1120,0.29496956,0.4157911,0.49925995 +1125,0.26901722,0.37913403,0.45350647 +1130,0.2431984,0.34222522,0.40682983 +1135,0.21771908,0.3054548,0.3599167 +1140,0.19278336,0.26922718,0.31345367 +1145,0.16859627,0.23393631,0.2681427 +1150,0.14535666,0.19998333,0.22467422 +1155,0.12326908,0.16776466,0.18373871 +1160,0.102535725,0.1376776,0.14602661 +1165,0.083360195,0.11012105,0.1122303 +1170,0.06594491,0.08549363,0.08304405 +1175,0.050492764,0.064191684,0.059161186 +1180,0.037207007,0.046614103,0.041270256 +1185,0.024567366,0.030565398,0.026574135 +1190,0.01253587,0.015515804,0.013303757 +1195,0.0035382658,0.0043616975,0.0036991835 +1200,0.0,0.0,0.0 diff --git a/pvlib/spectrum/__init__.py b/pvlib/spectrum/__init__.py index 6c97df978e..6c47823286 100644 --- a/pvlib/spectrum/__init__.py +++ b/pvlib/spectrum/__init__.py @@ -3,6 +3,7 @@ calc_spectral_mismatch_field, get_am15g, get_example_spectral_response, + get_spectral_response_of_material, spectral_factor_caballero, spectral_factor_firstsolar, spectral_factor_sapm, diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 5e00b2472d..1db24009d8 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -8,8 +8,10 @@ from scipy.interpolate import interp1d from scipy.integrate import trapezoid import os +from pathlib import Path from warnings import warn +from functools import partial def get_example_spectral_response(wavelength=None): @@ -77,6 +79,84 @@ def get_example_spectral_response(wavelength=None): return sr +def get_spectral_response_of_material(material, wavelengths=None): + """ + Read spectral response curve of a material from the database [1]_, + optionally interpolated to the specified wavelength(s). + + Parameters + ---------- + material : str + The material name of the spectral response curve to read. + The names are ``'monosi'``, ``'polysi'``, ``'hit'`` and ``'all'``. + wavelengths : numeric, optional + The wavelengths at which the spectral response is interpolated. + By default the 181 available wavelengths are returned. :math:`[nm]` + + Returns + ------- + spectral_response : pandas.Series or pandas.DataFrame + The returned spectral response curve, indexed by ``wavelengths`` if + provided. If not, the curve is indexed by the 181 default wavelengths. + + Notes + ----- + The original dataset is available in [1]_. + + Wavelengths outside of the range :math:`[300, 1200]` will result in + NaN values. + + Examples + -------- + >>> print(get_spectral_response_of_material("monosi").head()) + >>> wavelength + >>> 300 0.000000 + >>> 305 0.046272 + >>> 310 0.088575 + >>> 315 0.127410 + >>> 320 0.163710 + >>> Name: monosi, dtype: float64 + + References + ---------- + .. [1] A. Driesse, M. Theristis, and J. Stein, “PV module spectral response + measurements - Data and Resources.” EMN-DURMAT (EMN-DuraMAT); Sandia + National Laboratories (SNL-NM), Albuquerque, NM (United States), 2023. + :doi:`10.21948/2204677`. + Available: https://www.osti.gov/servlets/purl/2204677/ + """ + + sr_dataset_path = Path(pvlib.__path__[0]).joinpath( + "data", "duramat_spectral_responses.csv" + ) + dataset = pd.read_csv(sr_dataset_path, index_col=0) + + if material in dataset.columns: + dataset = dataset[material] + elif material != "all": # if material=="all", return the whole dataset + raise ValueError( + f"Material '{material}' not found in dataset.\n" + + f"Available materials are {', '.join((*dataset.columns, 'all'))}" + ) + + if wavelengths is not None: + interpolator = partial(np.interp, xp=dataset.index, left=0, right=0) + if material == "all": # returned data is a DataFrame + dataset = pd.DataFrame( + index=wavelengths, + data={ + col: interpolator(x=wavelengths, fp=dataset[col]) + for col in dataset.columns + }, + ) + else: # returned data is a Series + dataset = pd.Series( + index=wavelengths, + data=interpolator(x=wavelengths, fp=dataset), + ) + return dataset + + def get_am15g(wavelength=None): ''' Read the ASTM G173-03 AM1.5 global spectrum on a 37-degree tilted surface, diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/test_spectrum.py index 793eaacfdf..64ffaf5656 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/test_spectrum.py @@ -123,6 +123,35 @@ def test_get_example_spectral_response(): assert_allclose(sr, expected, rtol=1e-5) +def test_get_spectral_response_of_material(): + # test that the sr curves are read correctly + sr = spectrum.get_spectral_response_of_material(material="all") + assert len(sr) == 181 + pd.testing.assert_series_equal( + sr.sum(), + pd.Series({"polysi": 116.32, "monosi": 115.51, "hit": 110.07}), + atol=1e-2, + ) + + # test raise error if material not in dataset + with pytest.raises(ValueError, match="Material '.*' not found in dataset"): + sr = spectrum.get_spectral_response_of_material( + material="not in dataset" + ) + + # test correct interpolation + material, wavelength = "polysi", [270, 850, 900, 950, 1200] + expected = [0.0, 0.974667, 0.995869, 0.988224, 0.0] + result = spectrum.get_spectral_response_of_material(material, wavelength) + assert_allclose(result, expected, atol=1e-6) + + # "all" interpolation + material, wavelength = "all", [270, 850, 900, 950, 1200] + expected = [0.0, 0.974667, 0.995869, 0.988224, 0.0] + result = spectrum.get_spectral_response_of_material(material, wavelength) + assert_allclose(result["polysi"], expected, atol=1e-6) + + def test_get_am15g(): # test that the reference spectrum is read and interpolated correctly e = spectrum.get_am15g()