|
4 | 4 | https://developer.nrel.gov/docs/solar/nsrdb/nsrdb-GOES-tmy-v4-0-0-download/ |
5 | 5 | https://developer.nrel.gov/docs/solar/nsrdb/nsrdb-GOES-conus-v4-0-0-download/ |
6 | 6 | https://developer.nrel.gov/docs/solar/nsrdb/nsrdb-GOES-full-disc-v4-0-0-download/ |
| 7 | +https://developer.nrel.gov/docs/solar/nsrdb/nsrdb-polar-v4-0-0-download/ |
| 8 | +https://developer.nrel.gov/docs/solar/nsrdb/nsrdb-polar-tmy-v4-0-0-download/ |
7 | 9 | """ |
8 | 10 |
|
9 | 11 | import io |
|
18 | 20 | PSM4_TMY_ENDPOINT = "nsrdb-GOES-tmy-v4-0-0-download.csv" |
19 | 21 | PSM4_CON_ENDPOINT = "nsrdb-GOES-conus-v4-0-0-download.csv" |
20 | 22 | PSM4_FUL_ENDPOINT = "nsrdb-GOES-full-disc-v4-0-0-download.csv" |
| 23 | +PSM4_POL_ENDPOINT = "nsrdb-polar-v4-0-0-download.csv" |
| 24 | +PSM4_PTMY_ENDPOINT = "nsrdb-polar-tmy-v4-0-0-download.csv" |
21 | 25 | PSM4_AGG_URL = urljoin(NSRDB_API_BASE, PSM4_AGG_ENDPOINT) |
22 | 26 | PSM4_TMY_URL = urljoin(NSRDB_API_BASE, PSM4_TMY_ENDPOINT) |
23 | 27 | PSM4_CON_URL = urljoin(NSRDB_API_BASE, PSM4_CON_ENDPOINT) |
24 | 28 | PSM4_FUL_URL = urljoin(NSRDB_API_BASE, PSM4_FUL_ENDPOINT) |
| 29 | +PSM4_POL_URL = urljoin(NSRDB_API_BASE, PSM4_POL_ENDPOINT) |
| 30 | +PSM4_PTMY_URL = urljoin(NSRDB_API_BASE, PSM4_PTMY_ENDPOINT) |
25 | 31 |
|
26 | 32 | PARAMETERS = ( |
27 | 33 | 'air_temperature', 'dew_point', 'dhi', 'dni', 'ghi', 'surface_albedo', |
@@ -623,6 +629,282 @@ def get_nsrdb_psm4_full_disc(latitude, longitude, api_key, email, |
623 | 629 | return read_nsrdb_psm4(fbuf, map_variables) |
624 | 630 |
|
625 | 631 |
|
| 632 | +def get_nsrdb_psm4_polar(latitude, longitude, api_key, email, |
| 633 | + year, time_step=60, |
| 634 | + parameters=PARAMETERS, leap_day=True, |
| 635 | + full_name=PVLIB_PYTHON, |
| 636 | + affiliation=PVLIB_PYTHON, |
| 637 | + utc=False, map_variables=True, url=None, |
| 638 | + timeout=30): |
| 639 | + """ |
| 640 | + Retrieve NSRDB PSM4 Polar timeseries weather data from the PSM4 NSRDB Polar v4 API. |
| 641 | +
|
| 642 | + The NSRDB is described in [1]_ and the PSM4 NSRDB Polar v4 API is |
| 643 | + described in [2]_. |
| 644 | +
|
| 645 | + Parameters |
| 646 | + ---------- |
| 647 | + latitude : float or int |
| 648 | + in decimal degrees, between -90 and 90, north is positive |
| 649 | + longitude : float or int |
| 650 | + in decimal degrees, between -180 and 180, east is positive |
| 651 | + api_key : str |
| 652 | + NREL Developer Network API key |
| 653 | + email : str |
| 654 | + NREL API uses this to automatically communicate messages back |
| 655 | + to the user only if necessary |
| 656 | + year : int or str |
| 657 | + PSM4 API parameter specifing year (e.g. ``2023``) to download. The |
| 658 | + allowed values update periodically, so consult the NSRDB reference |
| 659 | + below for the current set of options. Called ``names`` in NSRDB API. |
| 660 | + time_step : int, {60} |
| 661 | + time step in minutes, must be 60 for PSM4 Polar. Called |
| 662 | + ``interval`` in NSRDB API. |
| 663 | + parameters : list of str, optional |
| 664 | + meteorological fields to fetch. If not specified, defaults to |
| 665 | + ``pvlib.iotools.psm4.PARAMETERS``. See reference [2]_ for a list of |
| 666 | + available fields. Alternatively, pvlib names may also be used (e.g. |
| 667 | + 'ghi' rather than 'GHI'); see :const:`REQUEST_VARIABLE_MAP`. To |
| 668 | + retrieve all available fields, set ``parameters=[]``. |
| 669 | + leap_day : bool, default : True |
| 670 | + include leap day in the results |
| 671 | + full_name : str, default 'pvlib python' |
| 672 | + optional |
| 673 | + affiliation : str, default 'pvlib python' |
| 674 | + optional |
| 675 | + utc: bool, default : False |
| 676 | + retrieve data with timestamps converted to UTC. False returns |
| 677 | + timestamps in local standard time of the selected location |
| 678 | + map_variables : bool, default True |
| 679 | + When true, renames columns of the Dataframe to pvlib variable names |
| 680 | + where applicable. See variable :const:`VARIABLE_MAP`. |
| 681 | + url : str, optional |
| 682 | + Full API endpoint URL. If not specified, the PSM4 Polar v4 |
| 683 | + URL is used. |
| 684 | + timeout : int, default 30 |
| 685 | + time in seconds to wait for server response before timeout |
| 686 | +
|
| 687 | + Returns |
| 688 | + ------- |
| 689 | + data : pandas.DataFrame |
| 690 | + timeseries data from NREL PSM4 |
| 691 | + metadata : dict |
| 692 | + metadata from NREL PSM4 about the record, see |
| 693 | + :func:`pvlib.iotools.read_nsrdb_psm4` for fields |
| 694 | +
|
| 695 | + Raises |
| 696 | + ------ |
| 697 | + requests.HTTPError |
| 698 | + if the request response status is not ok, then the ``'errors'`` field |
| 699 | + from the JSON response or any error message in the content will be |
| 700 | + raised as an exception, for example if the `api_key` was rejected or if |
| 701 | + the coordinates were not found in the NSRDB |
| 702 | +
|
| 703 | + Notes |
| 704 | + ----- |
| 705 | + The required NREL developer key, `api_key`, is available for free by |
| 706 | + registering at the `NREL Developer Network <https://developer.nrel.gov/>`_. |
| 707 | +
|
| 708 | + .. warning:: The "DEMO_KEY" `api_key` is severely rate limited and may |
| 709 | + result in rejected requests. |
| 710 | +
|
| 711 | + .. warning:: PSM4 is limited to data found in the NSRDB, please consult |
| 712 | + the references below for locations with available data. |
| 713 | +
|
| 714 | + See Also |
| 715 | + -------- |
| 716 | + pvlib.iotools.get_nsrdb_psm4_aggregated, pvlib.iotools.get_nsrdb_psm4_tmy, pvlib.iotools.get_nsrdb_psm4_conus, |
| 717 | + pvlib.iotools.get_nsrdb_psm4_full_disc, pvlib.iotools.get_nsrdb_psm4_polar_tmy, pvlib.iotools.read_nsrdb_psm4 |
| 718 | +
|
| 719 | + References |
| 720 | + ---------- |
| 721 | + .. [1] `NREL National Solar Radiation Database (NSRDB) |
| 722 | + <https://nsrdb.nrel.gov/>`_ |
| 723 | + .. [2] `NSRDB Polar V4.0.0 |
| 724 | + <https://developer.nrel.gov/docs/solar/nsrdb/nsrdb-polar-v4-0-0-download/>`_ |
| 725 | + """ |
| 726 | + # The well know text (WKT) representation of geometry notation is strict. |
| 727 | + # A POINT object is a string with longitude first, then the latitude, with |
| 728 | + # four decimals each, and exactly one space between them. |
| 729 | + longitude = ('%9.4f' % longitude).strip() |
| 730 | + latitude = ('%8.4f' % latitude).strip() |
| 731 | + # TODO: make format_WKT(object_type, *args) in tools.py |
| 732 | + |
| 733 | + # convert pvlib names in parameters to PSM4 convention |
| 734 | + parameters = [REQUEST_VARIABLE_MAP.get(a, a) for a in parameters] |
| 735 | + |
| 736 | + # required query-string parameters for request to PSM4 API |
| 737 | + params = { |
| 738 | + 'api_key': api_key, |
| 739 | + 'full_name': full_name, |
| 740 | + 'email': email, |
| 741 | + 'affiliation': affiliation, |
| 742 | + 'reason': PVLIB_PYTHON, |
| 743 | + 'mailing_list': 'false', |
| 744 | + 'wkt': 'POINT(%s %s)' % (longitude, latitude), |
| 745 | + 'names': year, |
| 746 | + 'attributes': ','.join(parameters), |
| 747 | + 'leap_day': str(leap_day).lower(), |
| 748 | + 'utc': str(utc).lower(), |
| 749 | + 'interval': time_step |
| 750 | + } |
| 751 | + # request CSV download from NREL PSM4 |
| 752 | + if url is None: |
| 753 | + url = PSM4_POL_URL |
| 754 | + |
| 755 | + response = requests.get(url, params=params, timeout=timeout) |
| 756 | + if not response.ok: |
| 757 | + # if the API key is rejected, then the response status will be 403 |
| 758 | + # Forbidden, and then the error is in the content and there is no JSON |
| 759 | + try: |
| 760 | + errors = response.json()['errors'] |
| 761 | + except JSONDecodeError: |
| 762 | + errors = response.content.decode('utf-8') |
| 763 | + raise requests.HTTPError(errors, response=response) |
| 764 | + # the CSV is in the response content as a UTF-8 bytestring |
| 765 | + # to use pandas we need to create a file buffer from the response |
| 766 | + fbuf = io.StringIO(response.content.decode('utf-8')) |
| 767 | + return read_nsrdb_psm4(fbuf, map_variables) |
| 768 | + |
| 769 | + |
| 770 | +def get_nsrdb_psm4_polar_tmy(latitude, longitude, api_key, email, |
| 771 | + year='tmy', time_step=60, |
| 772 | + parameters=PARAMETERS, leap_day=False, |
| 773 | + full_name=PVLIB_PYTHON, |
| 774 | + affiliation=PVLIB_PYTHON, |
| 775 | + utc=False, map_variables=True, url=None, |
| 776 | + timeout=30): |
| 777 | + """ |
| 778 | + Retrieve NSRDB PSM4 Polar TMY timeseries weather data from the PSM4 NSRDB Polar TMY v4 API. |
| 779 | +
|
| 780 | + The NSRDB is described in [1]_ and the PSM4 NSRDB Polar TMY v4 API is |
| 781 | + described in [2]_. |
| 782 | +
|
| 783 | + Parameters |
| 784 | + ---------- |
| 785 | + latitude : float or int |
| 786 | + in decimal degrees, between -90 and 90, north is positive |
| 787 | + longitude : float or int |
| 788 | + in decimal degrees, between -180 and 180, east is positive |
| 789 | + api_key : str |
| 790 | + NREL Developer Network API key |
| 791 | + email : str |
| 792 | + NREL API uses this to automatically communicate messages back |
| 793 | + to the user only if necessary |
| 794 | + year : str, default 'tmy' |
| 795 | + PSM4 API parameter specifing TMY variant to download (e.g. ``'tmy'`` |
| 796 | + or ``'tgy-2022'``). The allowed values update periodically, so |
| 797 | + consult the NSRDB references below for the current set of options. |
| 798 | + Called ``names`` in NSRDB API. |
| 799 | + time_step : int, {60} |
| 800 | + time step in minutes. Must be 60 for typical year requests. Called |
| 801 | + ``interval`` in NSRDB API. |
| 802 | + parameters : list of str, optional |
| 803 | + meteorological fields to fetch. If not specified, defaults to |
| 804 | + ``pvlib.iotools.psm4.PARAMETERS``. See reference [2]_ for a list of |
| 805 | + available fields. Alternatively, pvlib names may also be used (e.g. |
| 806 | + 'ghi' rather than 'GHI'); see :const:`REQUEST_VARIABLE_MAP`. To |
| 807 | + retrieve all available fields, set ``parameters=[]``. |
| 808 | + leap_day : bool, default : False |
| 809 | + Include leap day in the results. Ignored for tmy/tgy/tdy requests. |
| 810 | + full_name : str, default 'pvlib python' |
| 811 | + optional |
| 812 | + affiliation : str, default 'pvlib python' |
| 813 | + optional |
| 814 | + utc: bool, default : False |
| 815 | + retrieve data with timestamps converted to UTC. False returns |
| 816 | + timestamps in local standard time of the selected location |
| 817 | + map_variables : bool, default True |
| 818 | + When true, renames columns of the Dataframe to pvlib variable names |
| 819 | + where applicable. See variable :const:`VARIABLE_MAP`. |
| 820 | + url : str, optional |
| 821 | + Full API endpoint URL. If not specified, the PSM4 Polar TMY v4 |
| 822 | + URL is used. |
| 823 | + timeout : int, default 30 |
| 824 | + time in seconds to wait for server response before timeout |
| 825 | +
|
| 826 | + Returns |
| 827 | + ------- |
| 828 | + data : pandas.DataFrame |
| 829 | + timeseries data from NREL PSM4 Polar |
| 830 | + metadata : dict |
| 831 | + metadata from NREL PSM4 about the record, see |
| 832 | + :func:`pvlib.iotools.read_nsrdb_psm4` for fields |
| 833 | +
|
| 834 | + Raises |
| 835 | + ------ |
| 836 | + requests.HTTPError |
| 837 | + if the request response status is not ok, then the ``'errors'`` field |
| 838 | + from the JSON response or any error message in the content will be |
| 839 | + raised as an exception, for example if the `api_key` was rejected or if |
| 840 | + the coordinates were not found in the NSRDB |
| 841 | +
|
| 842 | + Notes |
| 843 | + ----- |
| 844 | + The required NREL developer key, `api_key`, is available for free by |
| 845 | + registering at the `NREL Developer Network <https://developer.nrel.gov/>`_. |
| 846 | +
|
| 847 | + .. warning:: The "DEMO_KEY" `api_key` is severely rate limited and may |
| 848 | + result in rejected requests. |
| 849 | +
|
| 850 | + .. warning:: PSM4 is limited to data found in the NSRDB, please consult |
| 851 | + the references below for locations with available data. |
| 852 | +
|
| 853 | + See Also |
| 854 | + -------- |
| 855 | + pvlib.iotools.get_nsrdb_psm4_aggregated, pvlib.iotools.get_nsrdb_psm4_tmy, pvlib.iotools.get_nsrdb_psm4_conus, |
| 856 | + pvlib.iotools.get_nsrdb_psm4_full_disc, pvlib.iotools.get_nsrdb_psm4_polar, pvlib.iotools.read_nsrdb_psm4 |
| 857 | +
|
| 858 | + References |
| 859 | + ---------- |
| 860 | + .. [1] `NREL National Solar Radiation Database (NSRDB) |
| 861 | + <https://nsrdb.nrel.gov/>`_ |
| 862 | + .. [2] `NSRDB Polar V4.0.0 |
| 863 | + <https://developer.nrel.gov/docs/solar/nsrdb/nsrdb-polar-tmy-v4-0-0-download/>`_ |
| 864 | + """ |
| 865 | + # The well know text (WKT) representation of geometry notation is strict. |
| 866 | + # A POINT object is a string with longitude first, then the latitude, with |
| 867 | + # four decimals each, and exactly one space between them. |
| 868 | + longitude = ('%9.4f' % longitude).strip() |
| 869 | + latitude = ('%8.4f' % latitude).strip() |
| 870 | + # TODO: make format_WKT(object_type, *args) in tools.py |
| 871 | + |
| 872 | + # convert pvlib names in parameters to PSM4 convention |
| 873 | + parameters = [REQUEST_VARIABLE_MAP.get(a, a) for a in parameters] |
| 874 | + |
| 875 | + # required query-string parameters for request to PSM4 API |
| 876 | + params = { |
| 877 | + 'api_key': api_key, |
| 878 | + 'full_name': full_name, |
| 879 | + 'email': email, |
| 880 | + 'affiliation': affiliation, |
| 881 | + 'reason': PVLIB_PYTHON, |
| 882 | + 'mailing_list': 'false', |
| 883 | + 'wkt': 'POINT(%s %s)' % (longitude, latitude), |
| 884 | + 'names': year, |
| 885 | + 'attributes': ','.join(parameters), |
| 886 | + 'leap_day': str(leap_day).lower(), |
| 887 | + 'utc': str(utc).lower(), |
| 888 | + 'interval': time_step |
| 889 | + } |
| 890 | + # request CSV download from NREL PSM4 |
| 891 | + if url is None: |
| 892 | + url = PSM4_PTMY_URL |
| 893 | + |
| 894 | + response = requests.get(url, params=params, timeout=timeout) |
| 895 | + if not response.ok: |
| 896 | + # if the API key is rejected, then the response status will be 403 |
| 897 | + # Forbidden, and then the error is in the content and there is no JSON |
| 898 | + try: |
| 899 | + errors = response.json()['errors'] |
| 900 | + except JSONDecodeError: |
| 901 | + errors = response.content.decode('utf-8') |
| 902 | + raise requests.HTTPError(errors, response=response) |
| 903 | + # the CSV is in the response content as a UTF-8 bytestring |
| 904 | + # to use pandas we need to create a file buffer from the response |
| 905 | + fbuf = io.StringIO(response.content.decode('utf-8')) |
| 906 | + return read_nsrdb_psm4(fbuf, map_variables) |
| 907 | + |
626 | 908 | def read_nsrdb_psm4(filename, map_variables=True): |
627 | 909 | """ |
628 | 910 | Read an NSRDB PSM4 weather file (formatted as SAM CSV). |
|
0 commit comments