From cb49ea350e24c756171e2d1d1bd0909bf6b2a30a Mon Sep 17 00:00:00 2001 From: Ford Date: Thu, 17 Oct 2024 17:40:44 -0600 Subject: [PATCH 01/14] distributed get pvgis using dask --- pvdeg/weather.py | 152 ++++++- scripts/load_pvgis_distributed.ipynb | 622 +++++++++++++++++++++++++++ 2 files changed, 773 insertions(+), 1 deletion(-) create mode 100644 scripts/load_pvgis_distributed.ipynb diff --git a/pvdeg/weather.py b/pvdeg/weather.py index dbe06f7..91b1e42 100644 --- a/pvdeg/weather.py +++ b/pvdeg/weather.py @@ -930,4 +930,154 @@ def get_anywhere(database = "PSM3", id=None, **kwargs): meta = {'result': 'This location was not found in either the NSRDB or PVGIS'} weather_db = {'result': 'NA'} - return weather_db, meta \ No newline at end of file + return weather_db, meta + + +def process_pvgis_distributed(weather_df): + """Create an xarray.Dataset using numpy array backend from a pvgis weather dataframe""" + + import dask.array as da + + weather_df.index.rename('time', inplace=True) + weather_ds = weather_df.to_xarray().drop_vars('time').copy() + + for var in weather_ds.data_vars: + dask_array = da.from_array(weather_ds[var].values, chunks='auto') + + weather_ds[var] = (weather_ds[var].dims, dask_array) + + return weather_ds + +def _weather_distributed_vec( + database: str, + coord: tuple[float], + ): + """ + Distributed weather calculation for use with dask futures/delayed + + Returns ds, dict, None if unsucessfull + Returns None, None, Exception if unsucessfull + """ + + try: + weather_df, meta_dict = get(database, coord) + except Exception as e: + return None, None, e + + weather_ds = process_pvgis_distributed(weather_df=weather_df) + + return weather_ds, meta_dict, None + +def pvgis_empty_weather_ds(gids_size): + """ + Create an empty weather dataset for pvgis hourly TMY data + + Parameters + ---------- + gids_size: int + number of gids, equivalent to number of unique locations + + Returns + ------- + weather_ds: xarray.Dataset + Weather dataset of the same format/shapes given by a `pvdeg.weather.get` geospatial call or `pvdeg.weather.weather_distributed` call or `GeosptialScenario.get_geospatial_data`. + """ + import dask.array as da + + shapes = { + "temp_air": ("gid", "time"), + "relative_humidity": ("gid", "time"), + "ghi": ("gid", "time"), + "dni": ("gid", "time"), + "dhi": ("gid", "time"), + "IR(h)": ("gid", "time"), + "wind_speed": ("gid", "time"), + "wind_direction": ("gid", "time"), + "pressure": ("gid", "time"), + } + attrs = {} + global_attrs = {} + + dims = {'gid', 'time'} + dims_size = {'time': 8760, 'gid': gids_size} + + weather_ds = xr.Dataset( + data_vars={ + var: (dim, da.empty([dims_size[d] for d in dim]), attrs.get(var)) + for var, dim in shapes.items() + }, + coords={'time': pd.date_range("2022-01-01", freq="h", periods=365 * 24), + 'gid': np.linspace(0, gids_size-1, gids_size, dtype=int)}, + attrs=global_attrs, + ) + + return weather_ds + + +def weather_distributed(database, coords): + """ + Grab weather using pvgis for all of the following locations using dask for parallelization. + You must create a dask client with multiple processes before calling this function, otherwise no speedup will be offered. + + PVGIS supports up to 30 requests per second so your dask client should not have more than $x$ workers/threads + that would put you over this limit. + + Parameters + ---------- + database : (str) + 'PVGIS' or 'NSRDB' (not implemented yet) + coords: list[tuple] + list of tuples containing (latitude, longitude) coordinates + + >>> [ + (49.95, 1.5), + (51.95, -9.5), + (51.95, -8.5), + (51.95, -4.5), + (51.95, -3.5), + ] + + Returns + -------- + weather_ds : xr.Dataset + Weather data for all locations requested in an xarray.Dataset using a dask array backend. + meta_df : pd.DataFrame + Pandas DataFrame containing metadata for all requested locations. Each row maps to a single entry in the weather_ds. + gids_failed: list + list of index failed coordinates in input `coords` + """ + + import dask.delayed + + if (database != "PVGIS"): + raise NotImplementedError(f"Only 'PVGIS' is implemented, you entered {database}") + + futures = [dask.delayed(_weather_distributed_vec)("PVGIS", coord) for coord in coords] + results = dask.compute(futures)[0] # values are returned in a list with one entry + + # what is the difference between these two approaches for dask distributed work, how can we schedule differently + # futures = [client.submit(weather_distributed, "PVGIS", coord) for coord in coords] + # client.gather(futures) + + # results is a 2d list + # results[0] is the weather_ds with dask backend + # results[1] is meta_dict + weather_ds_collection = [row[0] for row in results] + meta_dict_collection = [row[1] for row in results] + + gids_failed = [] + + weather_ds = pvgis_empty_weather_ds(len(results)) # create empty weather xr.dataset + meta_df = pd.DataFrame.from_dict(meta_dict_collection) # create populated meta pd.DataFrame + + # these gids will be spatially meaningless, they will only show corresponding entries between weather_ds and meta_df + for i, row in enumerate(results): # this loop can be refactored, kinda gross + + if row[2]: + gids_failed.append(i) + continue + + # weather_ds[dict(gid=i)] = weather_ds_collection[i].to_xarray().drop_vars('time') + weather_ds[dict(gid=i)] = weather_ds_collection[i] + + return weather_ds, meta_df, gids_failed \ No newline at end of file diff --git a/scripts/load_pvgis_distributed.ipynb b/scripts/load_pvgis_distributed.ipynb new file mode 100644 index 0000000..447e56a --- /dev/null +++ b/scripts/load_pvgis_distributed.ipynb @@ -0,0 +1,622 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pvdeg\n", + "from global_land_mask import globe\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from mpl_toolkits.basemap import Basemap\n", + "import pandas as pd\n", + "import xarray as xr\n", + "import dask.array as da\n", + "import dask.dataframe as dd\n", + "from dask.distributed import LocalCluster, Client, Lock\n", + "import dask.delayed" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# decrease the arange step size for more fine resolution\n", + "# increase the arange step size for increased granularity\n", + "lon_UK = np.arange(-10.5, 1.76, 1)\n", + "lat_UK = np.arange(49.95, 60, 2)\n", + "lon_grid_UK, lat_grid_UK = np.meshgrid(lon_UK,lat_UK)\n", + "land_UK = globe.is_land(lat_grid_UK, lon_grid_UK)\n", + "\n", + "lon_land_UK = lon_grid_UK[land_UK]\n", + "lat_land_UK = lat_grid_UK[land_UK]\n", + "\n", + "lon_Scan = np.arange(-10.5, 31.6, 0.3)\n", + "lat_Scan = np.arange(60, 71.2, 0.3)\n", + "lon_grid_Scan, lat_grid_Scan = np.meshgrid(lon_Scan,lat_Scan)\n", + "land_Scan = globe.is_land(lat_grid_Scan, lon_grid_Scan)\n", + "\n", + "lon_land_Scan = lon_grid_Scan[land_Scan]\n", + "lat_land_Scan = lat_grid_Scan[land_Scan]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\tford\\AppData\\Local\\miniconda3\\envs\\deg\\lib\\site-packages\\distributed\\node.py:182: UserWarning: Port 8787 is already in use.\n", + "Perhaps you already have a cluster running?\n", + "Hosting the HTTP server on port 60223 instead\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "http://127.0.0.1:60223/status\n" + ] + } + ], + "source": [ + "workers = 4\n", + "\n", + "cluster = LocalCluster(\n", + " n_workers=workers,\n", + " processes=True, \n", + " # number of threads may matter\n", + " )\n", + "\n", + "client = Client(cluster)\n", + "\n", + "print(client.dashboard_link)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "coords = list(zip(lat_land_UK, lon_land_UK)) # easiest way to make a list of the right shape\n", + "\n", + "weather_ds, meta_df, failed_gids = pvdeg.weather.weather_distributed(database=\"PVGIS\", coords=coords)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\tford\\AppData\\Local\\miniconda3\\envs\\deg\\lib\\site-packages\\distributed\\client.py:3362: UserWarning: Sending large graph of size 13.27 MiB.\n", + "This may cause some slowdown.\n", + "Consider loading the data with Dask directly\n", + " or using futures or delayed objects to embed the data into the graph without repetition.\n", + "See also https://docs.dask.org/en/stable/best-practices.html#load-data-with-dask for more information.\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset> Size: 14MB\n",
+       "Dimensions:            (gid: 22, time: 8760)\n",
+       "Coordinates:\n",
+       "  * time               (time) datetime64[ns] 70kB 2022-01-01 ... 2022-12-31T2...\n",
+       "  * gid                (gid) int32 88B 0 1 2 3 4 5 6 7 ... 15 16 17 18 19 20 21\n",
+       "Data variables:\n",
+       "    temp_air           (gid, time) float64 2MB 4.11 4.7 5.28 ... 0.35 0.37 0.38\n",
+       "    relative_humidity  (gid, time) float64 2MB 87.27 87.03 86.79 ... 86.37 86.14\n",
+       "    ghi                (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n",
+       "    dni                (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n",
+       "    dhi                (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n",
+       "    IR(h)              (gid, time) float64 2MB 314.4 317.4 320.4 ... 271.9 274.1\n",
+       "    wind_speed         (gid, time) float64 2MB 3.11 3.1 3.08 ... 3.53 3.45 3.37\n",
+       "    wind_direction     (gid, time) float64 2MB 269.0 274.0 279.0 ... 245.0 242.0\n",
+       "    pressure           (gid, time) float64 2MB 1.014e+05 1.014e+05 ... 9.965e+04
" + ], + "text/plain": [ + " Size: 14MB\n", + "Dimensions: (gid: 22, time: 8760)\n", + "Coordinates:\n", + " * time (time) datetime64[ns] 70kB 2022-01-01 ... 2022-12-31T2...\n", + " * gid (gid) int32 88B 0 1 2 3 4 5 6 7 ... 15 16 17 18 19 20 21\n", + "Data variables:\n", + " temp_air (gid, time) float64 2MB 4.11 4.7 5.28 ... 0.35 0.37 0.38\n", + " relative_humidity (gid, time) float64 2MB 87.27 87.03 86.79 ... 86.37 86.14\n", + " ghi (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n", + " dni (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n", + " dhi (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n", + " IR(h) (gid, time) float64 2MB 314.4 317.4 320.4 ... 271.9 274.1\n", + " wind_speed (gid, time) float64 2MB 3.11 3.1 3.08 ... 3.53 3.45 3.37\n", + " wind_direction (gid, time) float64 2MB 269.0 274.0 279.0 ... 245.0 242.0\n", + " pressure (gid, time) float64 2MB 1.014e+05 1.014e+05 ... 9.965e+04" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weather_ds.compute()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "deg", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 74b745c507e74be8853d71fc309b501f1aa20f5e Mon Sep 17 00:00:00 2001 From: Ford Date: Thu, 24 Oct 2024 15:53:15 -0600 Subject: [PATCH 02/14] local db skeleton --- pvdeg/__init__.py | 1 + pvdeg/config.py | 3 + pvdeg/store.py | 185 ++++ pvdeg/weather.py | 9 +- scripts/load_pvgis_distributed.ipynb | 1533 ++++++++++++++++++++++++-- 5 files changed, 1613 insertions(+), 118 deletions(-) create mode 100644 pvdeg/store.py diff --git a/pvdeg/__init__.py b/pvdeg/__init__.py index 0b770fc..adf1fa4 100644 --- a/pvdeg/__init__.py +++ b/pvdeg/__init__.py @@ -14,6 +14,7 @@ from . import montecarlo from .scenario import Scenario, GeospatialScenario from . import spectral +from . import store from . import symbolic from . import standards from . import temperature diff --git a/pvdeg/config.py b/pvdeg/config.py index d40706a..14afbf3 100644 --- a/pvdeg/config.py +++ b/pvdeg/config.py @@ -11,6 +11,9 @@ DATA_DIR = PVDEG_DIR / "data" TEST_DIR = PVDEG_DIR.parent / "tests" TEST_DATA_DIR = PVDEG_DIR.parent / "tests" / "data" + +# downloader target directory +METOROLOGICAL_DOWNLOAD_PATH = Path.home() / "PVDeg-Meteorological" # DATA_LIBRARY = PVDEG_DIR.parent / "DataLibrary" # if not os.path.isdir(DATA_LIBRARY): diff --git a/pvdeg/store.py b/pvdeg/store.py new file mode 100644 index 0000000..518d8ba --- /dev/null +++ b/pvdeg/store.py @@ -0,0 +1,185 @@ +from pathlib import Path +import xarray as xr +import pandas as pd +import numpy as np +import zarr +import os + +from pvdeg import METOROLOGICAL_DOWNLOAD_PATH + +def get(group): + """ + Extract a weather xarray dataset and metadata pandas dataframe from your zarr store. + `get` pulls the entire datastore into these objects. PVDeg does not make indexing available at this stage. + This is practical because all datavariables are stored in dask arrays so they are loaded lazily instead of into memmory when this is called. + Choose the points you need after this method is called by using `sel`, `isel`, `loc, `iloc`. + + `store.get` is meant to match the API of other geospatial weather api's from pvdeg like `pvdeg.weather.get`, `pvdeg.weather.distributed_weather`, `GeospatialScenario.get_geospatial_data` + + Parameters + ----------- + group : str + name of the group to access from your local zarr store. + Groups are created automatically in your store when you save data using `pvdeg.store.store`. + + *From `pvdeg.store.store` docstring* + Hourly PVGIS data will be saved to "PVGIS-1hr", 30 minute PVGIS to "PVGIS-30min", similarly 15 minute PVGIS will be saved to "PVGIS-15min" + + Returns + ------- + weather_ds : xr.Dataset + Weather data for all locations requested in an xarray.Dataset using a dask array backend. This may be larger than memory. + meta_df : pd.DataFrame + Pandas DataFrame containing metadata for all requested locations. Each row maps to a single entry in the weather_ds. + """ + + combined_ds = xr.open_zarr( + store=METOROLOGICAL_DOWNLOAD_PATH, + group=group + ) + + weather_ds, meta_df = _seperate_geo_weather_meta(ds_from_zarr=combined_ds) + + return weather_ds, meta_df + +def store(weather_ds, meta_df): + """ + Add geospatial meteorolical data to your zarr store. Data will be saved to the correct group based on its periodicity. + + Hourly PVGIS data will be saved to "PVGIS-1hr", 30 minute PVGIS to "PVGIS-30min", similarly 15 minute PVGIS will be saved to "PVGIS-15min" + + Parameters + ----------- + weather_ds : xr.Dataset + Weather data for all locations requested in an xarray.Dataset using a dask array backend. This may be larger than memory. + meta_df : pd.DataFrame + Pandas DataFrame containing metadata for all requested locations. Each row maps to a single entry in the weather_ds. + + Returns + -------- + None + """ + + group = meta_df.iloc[0]["Source"] + rows_per_entry = weather_ds.isel(gid=0).time.size + + if rows_per_entry == 8760: + periodicity = "1hr" + elif rows_per_entry == 17520: + periodicity = "30min" + elif rows_per_entry == 35040: + periodicity = "15min" + else: + raise ValueError(f"first location to store has {rows_per_entry} rows, must have 8670, 17520, 35040 rows") + + combined_ds = _combine_geo_weather_meta(weather_ds, meta_df) + + # what mode should this be + # we want to add to indexes if need be or overwrite old ones + combined_ds.to_zarr( + store=METOROLOGICAL_DOWNLOAD_PATH, + group=f"{group}-{periodicity}" + ) + + print(f"dataset saved to zarr store at {METOROLOGICAL_DOWNLOAD_PATH}") + + + +def check_store(): + """Check if you have a zarr store at the default download path defined in pvdeg.config""" + if os.path.exists(os.path.join(METOROLOGICAL_DOWNLOAD_PATH, ".zattrs")): + + size = sum(f.stat().st_size for f in METOROLOGICAL_DOWNLOAD_PATH.glob('**/*') if f.is_file()) + + print(f""" + You have a zarr store at {METOROLOGICAL_DOWNLOAD_PATH}. + + It has {size} bytes. + """) + + elif os.path.exists(METOROLOGICAL_DOWNLOAD_PATH): + print(f"You have a directory but no zarr store at {METOROLOGICAL_DOWNLOAD_PATH}") + + else: + raise FileNotFoundError(f"No Directory exists at {METOROLOGICAL_DOWNLOAD_PATH}. Data has not been saved here.") + + +def my_path(): + """Finds path to your zarr store of data if it exists""" + if os.path.exists(os.path.join(METOROLOGICAL_DOWNLOAD_PATH, ".zattrs")): + print(METOROLOGICAL_DOWNLOAD_PATH) + + else: + print("Directory not found") + +def _combine_geo_weather_meta( + weather_ds: xr.Dataset, + meta_df: pd.DataFrame + ): + """Combine weather dataset and meta dataframe into a single dataset""" + + meta_ds = xr.Dataset.from_dataframe(meta_df) + # we could do some encoding scheme here, dont need to store source? unless the zarr compression handles it for us + + meta_ds['gid'] = meta_ds['index'].values.astype(np.int32) + meta_ds = meta_ds.drop_vars(["index"]) + + combined = xr.merge([weather_ds, meta_ds]).assign_coords( + latitude=("gid", meta_ds.latitude.values), + longitude=('gid', meta_ds.longitude.values), + ) + + return combined + + +def _seperate_geo_weather_meta( + ds_from_zarr: xr.Dataset, +): + """ + Take loaded dataset in the zarr store schema (weather and meta combined) + and seperate it into `weather_ds` and `meta_df`. + """ + + # there may be a more optimal way to do this + data = np.column_stack( + [ + ds_from_zarr.gid.to_numpy(), + ds_from_zarr.latitude.to_numpy(), + ds_from_zarr.longitude.to_numpy(), + ds_from_zarr.altitude.to_numpy(), + ds_from_zarr.Source.to_numpy(), + ds_from_zarr.wind_height.to_numpy(), + ] + ) + + seperated_meta_df = pd.DataFrame(data, columns=["gid", "latitude", "longitude", "altitude", "Source", "wind_height"]).set_index("gid") + + seperated_weather_ds = ds_from_zarr.drop_vars(("latitude", "longitude", "altitude", "Source", "wind_height")) + + return seperated_weather_ds, seperated_meta_df + +def _make_coords_to_gid_da( + ds_from_zarr: xr.Dataset + ): + """Create a 2D indexable array that maps coordinates (lat and lon) to gid stored in zarr store""" + + import dask.array as da + + # only want to do this if the arrays are dask arrays + lats = ds_from_zarr.latitude.to_numpy() + lons = ds_from_zarr.longitude.to_numpy() + + gids = -1 * da.empty((len(lats), len(lons))) + + points = xr.DataArray( + data=gids, + coords={ + "latitude": lats, + "longitude": lons + }, + dims=["latitude", "longitude"], + ) + + points.set_index(latitude="latitude", longitude="longitude") + + return points \ No newline at end of file diff --git a/pvdeg/weather.py b/pvdeg/weather.py index 91b1e42..59f7365 100644 --- a/pvdeg/weather.py +++ b/pvdeg/weather.py @@ -1014,13 +1014,20 @@ def pvgis_empty_weather_ds(gids_size): return weather_ds +# add some check to see if a dask client exists +# can force user to pass dask client to ensure it exists + +# if called without dask client we will return a xr.Dataset +# with dask backend that does not appear as if it failed until we compute it def weather_distributed(database, coords): """ Grab weather using pvgis for all of the following locations using dask for parallelization. - You must create a dask client with multiple processes before calling this function, otherwise no speedup will be offered. + You must create a dask client with multiple processes before calling this function, otherwise results will not be properly calculated. PVGIS supports up to 30 requests per second so your dask client should not have more than $x$ workers/threads that would put you over this limit. + + With eventual NSRDB implementation API keys will be an issue, each key is rate limited. Parameters ---------- diff --git a/scripts/load_pvgis_distributed.ipynb b/scripts/load_pvgis_distributed.ipynb index 447e56a..5dc552e 100644 --- a/scripts/load_pvgis_distributed.ipynb +++ b/scripts/load_pvgis_distributed.ipynb @@ -46,27 +46,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\Users\\tford\\AppData\\Local\\miniconda3\\envs\\deg\\lib\\site-packages\\distributed\\node.py:182: UserWarning: Port 8787 is already in use.\n", - "Perhaps you already have a cluster running?\n", - "Hosting the HTTP server on port 60223 instead\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "http://127.0.0.1:60223/status\n" - ] - } - ], + "outputs": [], "source": [ "workers = 4\n", "\n", @@ -94,21 +76,88 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "weather_ds.compute()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Saving Geospatial Data Locally\n", + "\n", + "The goal of `pvdeg.store` is to create a living local database of meteoroligical data that grows overtime as your geospatial data needs grow. To do this `PVDeg` will save to a folder called `PVDeg-Meteorological` your user home directory. For me this is located at `C:\\Users\\tford\\PVDeg-Meteorological`. This directory will contain a `zarr` store, this is a popular format for storing multi-dimensional array data, not dissimilar to `h5` files. It was chosen over `h5` because `zarr` stores arrays in chunked compressed files that make access very easy without opening an entire file like `h5`. This is an oversimplification of the design process but we felt `zarr` was a better fit.\n", + "\n", + "## Store\n", + "\n", + "We can use `pvdeg.store.store` to save geospatial data to our living dataset in the common form provided by `pvdeg`. The data is stored in various groups and subfolders but they will be arranged based on the *source* and *periodicity*.\n", + "\n", + "For example: \n", + " - Hourly PVGIS data will be saved to a group called \"PVGIS-1hr\" \n", + " - 30 minute PVGIS to a group called \"PVGIS-30min\" \n", + " - 15 minute PVGIS will be saved to a group called \"PVGIS-15min\" " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pvdeg.store.store(weather_ds, meta_df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load\n", + "\n", + "`PVDeg` makes use of `dask` to handle larger than memory datasets. Trandionally, this was only useful in our HPC environment but as your local database grows overtime, it will eventually surpass the limits of your computer's volatile memory. Additionally, `dask` allows us to parallelize geospatial calculations via `pvdeg.geospatial.analysis`. This ability can be utilized on local machines or HPC clusters alike. \n", + "\n", + "`PVDeg` implements the ability to access your local living database via `pvdeg.store.get`. This method takes a string called `group`. Groups are created automatically in your store when you save data using `pvdeg.store.store`. As described in the `pvdeg.store.store` docstring and the *Store* section above, NSRDB will follow a similar scheme but it not implemented yet. \n", + " - Hourly PVGIS data will be saved to a group called \"PVGIS-1hr\" \n", + " - 30 minute PVGIS to a group called \"PVGIS-30min\" \n", + " - 15 minute PVGIS will be saved to a group called \"PVGIS-15min\" " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load PVGIS-1hr Data\n", + "\n", + "The example below shows us loading the hourly tmy data from PVGIS that we gathered and saved to our zarr store in the above cells. This gets us the form of a weather xarray.Dataset (`geo_weather` in this example) and a metadata dataframe (`geo_meta` in this example).\n", + "\n", + "These can be treated like any other geospatial data shown in the `pvdeg` tutorials and tools or documentation." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "geo_weather, geo_meta = pvdeg.store.get(group=\"PVGIS-1hr\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Inspecting the Results\n", + "\n", + "explain *.compute() here*" + ] + }, + { + "cell_type": "code", + "execution_count": 3, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\Users\\tford\\AppData\\Local\\miniconda3\\envs\\deg\\lib\\site-packages\\distributed\\client.py:3362: UserWarning: Sending large graph of size 13.27 MiB.\n", - "This may cause some slowdown.\n", - "Consider loading the data with Dask directly\n", - " or using futures or delayed objects to embed the data into the graph without repetition.\n", - "See also https://docs.dask.org/en/stable/best-practices.html#load-data-with-dask for more information.\n", - " warnings.warn(\n" - ] - }, { "data": { "text/html": [ @@ -479,76 +528,519 @@ "
<xarray.Dataset> Size: 14MB\n",
        "Dimensions:            (gid: 22, time: 8760)\n",
        "Coordinates:\n",
-       "  * time               (time) datetime64[ns] 70kB 2022-01-01 ... 2022-12-31T2...\n",
        "  * gid                (gid) int32 88B 0 1 2 3 4 5 6 7 ... 15 16 17 18 19 20 21\n",
+       "  * time               (time) datetime64[ns] 70kB 2022-01-01 ... 2022-12-31T2...\n",
        "Data variables:\n",
-       "    temp_air           (gid, time) float64 2MB 4.11 4.7 5.28 ... 0.35 0.37 0.38\n",
-       "    relative_humidity  (gid, time) float64 2MB 87.27 87.03 86.79 ... 86.37 86.14\n",
-       "    ghi                (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n",
-       "    dni                (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n",
-       "    dhi                (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n",
-       "    IR(h)              (gid, time) float64 2MB 314.4 317.4 320.4 ... 271.9 274.1\n",
-       "    wind_speed         (gid, time) float64 2MB 3.11 3.1 3.08 ... 3.53 3.45 3.37\n",
-       "    wind_direction     (gid, time) float64 2MB 269.0 274.0 279.0 ... 245.0 242.0\n",
-       "    pressure           (gid, time) float64 2MB 1.014e+05 1.014e+05 ... 9.965e+04
  • " ], "text/plain": [ " Size: 14MB\n", "Dimensions: (gid: 22, time: 8760)\n", "Coordinates:\n", - " * time (time) datetime64[ns] 70kB 2022-01-01 ... 2022-12-31T2...\n", " * gid (gid) int32 88B 0 1 2 3 4 5 6 7 ... 15 16 17 18 19 20 21\n", + " * time (time) datetime64[ns] 70kB 2022-01-01 ... 2022-12-31T2...\n", "Data variables:\n", - " temp_air (gid, time) float64 2MB 4.11 4.7 5.28 ... 0.35 0.37 0.38\n", - " relative_humidity (gid, time) float64 2MB 87.27 87.03 86.79 ... 86.37 86.14\n", - " ghi (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n", - " dni (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n", - " dhi (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n", - " IR(h) (gid, time) float64 2MB 314.4 317.4 320.4 ... 271.9 274.1\n", - " wind_speed (gid, time) float64 2MB 3.11 3.1 3.08 ... 3.53 3.45 3.37\n", - " wind_direction (gid, time) float64 2MB 269.0 274.0 279.0 ... 245.0 242.0\n", - " pressure (gid, time) float64 2MB 1.014e+05 1.014e+05 ... 9.965e+04" + " IR(h) (gid, time) float64 2MB dask.array\n", + " dhi (gid, time) float64 2MB dask.array\n", + " dni (gid, time) float64 2MB dask.array\n", + " ghi (gid, time) float64 2MB dask.array\n", + " pressure (gid, time) float64 2MB dask.array\n", + " relative_humidity (gid, time) float64 2MB dask.array\n", + " temp_air (gid, time) float64 2MB dask.array\n", + " wind_direction (gid, time) float64 2MB dask.array\n", + " wind_speed (gid, time) float64 2MB dask.array" ] }, - "execution_count": 7, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "weather_ds.compute()" + "geo_weather" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    latitudelongitudealtitudeSourcewind_height
    gid
    049.951.5176.0PVGIS10
    151.95-9.5330.0PVGIS10
    251.95-8.5137.0PVGIS10
    351.95-4.5184.0PVGIS10
    451.95-3.5160.0PVGIS10
    551.95-2.586.0PVGIS10
    651.95-1.5217.0PVGIS10
    751.95-0.594.0PVGIS10
    851.950.564.0PVGIS10
    953.95-9.5119.0PVGIS10
    1053.95-8.5129.0PVGIS10
    1153.95-7.597.0PVGIS10
    1253.95-6.533.0PVGIS10
    1353.95-2.5136.0PVGIS10
    1453.95-1.5115.0PVGIS10
    1553.95-0.533.0PVGIS10
    1655.95-5.5205.0PVGIS10
    1755.95-4.5248.0PVGIS10
    1855.95-3.5122.0PVGIS10
    1955.95-2.5150.0PVGIS10
    2057.95-6.5137.0PVGIS10
    2157.95-4.559.0PVGIS10
    \n", + "
    " + ], + "text/plain": [ + " latitude longitude altitude Source wind_height\n", + "gid \n", + "0 49.95 1.5 176.0 PVGIS 10\n", + "1 51.95 -9.5 330.0 PVGIS 10\n", + "2 51.95 -8.5 137.0 PVGIS 10\n", + "3 51.95 -4.5 184.0 PVGIS 10\n", + "4 51.95 -3.5 160.0 PVGIS 10\n", + "5 51.95 -2.5 86.0 PVGIS 10\n", + "6 51.95 -1.5 217.0 PVGIS 10\n", + "7 51.95 -0.5 94.0 PVGIS 10\n", + "8 51.95 0.5 64.0 PVGIS 10\n", + "9 53.95 -9.5 119.0 PVGIS 10\n", + "10 53.95 -8.5 129.0 PVGIS 10\n", + "11 53.95 -7.5 97.0 PVGIS 10\n", + "12 53.95 -6.5 33.0 PVGIS 10\n", + "13 53.95 -2.5 136.0 PVGIS 10\n", + "14 53.95 -1.5 115.0 PVGIS 10\n", + "15 53.95 -0.5 33.0 PVGIS 10\n", + "16 55.95 -5.5 205.0 PVGIS 10\n", + "17 55.95 -4.5 248.0 PVGIS 10\n", + "18 55.95 -3.5 122.0 PVGIS 10\n", + "19 55.95 -2.5 150.0 PVGIS 10\n", + "20 57.95 -6.5 137.0 PVGIS 10\n", + "21 57.95 -4.5 59.0 PVGIS 10" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "geo_meta" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Geospatial Calculations from Locally Stored Data\n", + "\n", + "As shown above we can load from our `zarr` store and treat it like any other geospatial data in `pvdeg`.\n", + "\n", + "For demonstration we can run the analysis below to estimate effective standoff height and operating temperatures for the provided data. It may look like the `geo_res` contains empty results but that is because we did not have input data for all of the points in the input grid (think of this as a 2D plane formed between the latitude and longitude axes). Clicking on the stack of three circles in the bottom cell will expand the datavariable (like an attribute of the multidimensional array structure) and show the results.\n", + "\n", + "Additionally, we can interpolate and plot the results." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The array tilt angle was not provided, therefore the latitude tilt of 50.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 52.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 52.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 52.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 52.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 52.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 52.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 52.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 52.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 54.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 54.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 54.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 54.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 54.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 54.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 54.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 56.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 56.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 56.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 56.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 58.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n", + "The array tilt angle was not provided, therefore the latitude tilt of 58.0 was used.\n", + "The array azimuth was not provided, therefore an azimuth of 180.0 was used.\n" + ] + } + ], + "source": [ + "func=pvdeg.standards.standoff\n", + "\n", + "template = pvdeg.geospatial.auto_template(\n", + " func=func,\n", + " ds_gids=geo_weather\n", + ")\n", + "\n", + "geo_res = pvdeg.geospatial.analysis(\n", + " weather_ds=geo_weather,\n", + " meta_df=geo_meta,\n", + " func=func,\n", + " template=template\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
    <xarray.Dataset> Size: 2kB\n",
    +       "Dimensions:    (latitude: 5, longitude: 12)\n",
    +       "Coordinates:\n",
    +       "  * latitude   (latitude) float64 40B 49.95 51.95 53.95 55.95 57.95\n",
    +       "  * longitude  (longitude) float64 96B -9.5 -8.5 -7.5 -6.5 ... -1.5 -0.5 0.5 1.5\n",
    +       "Data variables:\n",
    +       "    x          (latitude, longitude) float64 480B nan nan nan ... nan nan nan\n",
    +       "    T98_0      (latitude, longitude) float64 480B nan nan nan ... nan nan nan\n",
    +       "    T98_inf    (latitude, longitude) float64 480B nan nan nan ... nan nan nan
    " + ], + "text/plain": [ + " Size: 2kB\n", + "Dimensions: (latitude: 5, longitude: 12)\n", + "Coordinates:\n", + " * latitude (latitude) float64 40B 49.95 51.95 53.95 55.95 57.95\n", + " * longitude (longitude) float64 96B -9.5 -8.5 -7.5 -6.5 ... -1.5 -0.5 0.5 1.5\n", + "Data variables:\n", + " x (latitude, longitude) float64 480B nan nan nan ... nan nan nan\n", + " T98_0 (latitude, longitude) float64 480B nan nan nan ... nan nan nan\n", + " T98_inf (latitude, longitude) float64 480B nan nan nan ... nan nan nan" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "geo_res" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This plot lacks information on the area and does not include political boundary lines. For more information on plotting look at the `Scenario - Non-uniform Mountain Downselect.ipynb` tutorial in the tutorials and tools folder." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(
    ,\n", + " )" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA8YAAANKCAYAAABI41diAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAD8HUlEQVR4nOzdd5xcdb0//tfnnDNtZ3Zmtrckm05IISQEQkgiTQwgKFyKFCliR72gRsX7uzQbX1CUa7ko4qVoBBEBRQWkC5KEHiSB9E3fXmbbtHM+vz8mu+xmN8mWM3POnPN6+pgHZnd25j27s2fP67w/RUgpJYiIiIiIiIhcSrG6ACIiIiIiIiIrMRgTERERERGRqzEYExERERERkasxGBMREREREZGrMRgTERERERGRqzEYExERERERkasxGBMREREREZGrMRgTERERERGRqzEYExERERERkasxGBMRmeykk07CSSedZHUZg9x7770QQqCurs7qUmgYL7zwAoQQeOGFF7Ly+EII3HTTTVl5bCIiIidgMCairOsLZa+//vqov7anpwc33XRT1gKDndjltb788ss444wzUFNTA7/fj0mTJuHss8/G73//e0vrypW///3vEEKguroahmFYXY6tXXnllRBCHPZ25ZVX9n/Nz3/+cxx55JHw+XyoqanB1772NXR3dw957H379uFzn/scpkyZgkAggGnTpuFrX/saWlpaRl1nIpHAt771LVRXVyMQCGDx4sV4+umnx/PSiYjIYTSrCyAiOpSenh7cfPPNAGC7LqzZ7PBa//jHP+ITn/gEjj76aFxzzTUoKirC9u3b8c9//hO//vWvcckll1hSVy6tWrUKkydPRl1dHZ577jl8+MMftrqkcevt7YWmmf8n//Of//yg78/27dtxww034HOf+xyWL1/e//Fp06YBAL71rW/htttuw/nnn49rrrkGGzZswM9+9jOsX78eTz31VP/9u7q6sGTJEnR3d+Pqq6/GxIkTsW7dOvz85z/H888/jzfeeAOKMvJr+1deeSUefvhhXHvttZgxYwbuvfdenHnmmXj++eexbNkyE74TRESU7xiMiciVuru7EQwGrS7Ddm666SbMnj0ba9asgdfrHfS5xsbGnNeT659Td3c3/vznP+OWW27BPffcg1WrVjkiGPv9/qw87pIlS7BkyZL+f7/++uu44YYbsGTJEnzyk58cdN99+/bhxz/+MS677DLcf//9/R+fOXMmvvKVr+Dxxx/H2WefDQD4y1/+gh07duCvf/0rPvrRj/bft7i4GN/5znewbt06LFiwYEQ1vvrqq3jwwQfxwx/+ECtXrgQAXH755Zg7dy6++c1v4pVXXhnz6yciIufgUGoissSVV16JUCiEPXv24JxzzkEoFEJZWRlWrlwJXdcBAHV1dSgrKwMA3Hzzzf3DMgfOlXz//fdx/vnno7i4GH6/H4sWLcJf/vKXQc/VN5T7xRdfxNVXX43y8nJMmDABQCYICiHw/vvv48ILL0Q4HEZJSQmuueYaxOPxQY+TTqfx3e9+F9OmTYPP58PkyZPxX//1X0gkEod8rclkEjfccAOOOeYYRCIRBINBLF++HM8//3z/fcx6rQCwfv16nHLKKQgEApgwYQK+973vjXhI8NatW3HssccOCcUAUF5ePqheIQR+9KMf4Sc/+Qlqa2sRCARw4okn4t133x30de+88w6uvPJKTJ06FX6/H5WVlbjqqquGDInt+1ls2LABl1xyCYqKivq7efX19fjUpz6FCRMmwOfzoaqqCh//+MeHzJl+4oknsHz5cgSDQRQWFuKjH/0o1q9fP6LXDgCPPvooent7ccEFF+Ciiy7CI488MuR9AGTm7H75y1/GY489hrlz58Ln82HOnDl48sknB91vx44duPrqq3HEEUcgEAigpKQEF1xwwWHnet94443weDxoamoa8rnPfe5ziEaj/XW9/vrrWLFiBUpLSxEIBDBlyhRcddVVQ+od+F7q7OzEtddei8mTJ8Pn86G8vBynnXYa3nzzzRF+p0Zv9erVSKfTuOiiiwZ9vO/fDz74YP/HYrEYAKCiomLQfauqqgAAgUBgxM/78MMPQ1VVfO5zn+v/mN/vx6c//WmsXr0au3btGt0LISIiR2LHmIgso+s6VqxYgcWLF+NHP/oRnnnmGdx+++2YNm0avvjFL6KsrAx33nknvvjFL+Lcc8/Ff/zHfwAAjjrqKACZALh06VLU1NTguuuuQzAYxEMPPYRzzjkHf/rTn3DuuecOer6rr74aZWVluOGGG4bMabzwwgsxefJk3HLLLVizZg1++tOfoq2tbVBn6zOf+Qzuu+8+nH/++fj617+OtWvX4pZbbsF7772HRx999KCvMxaL4e6778bFF1+Mz372s+js7MRvfvMbrFixAq+++iqOPvpo015rfX09Tj75ZKTT6f773XXXXSMOErW1tXj22Wexe/fu/osHh3L//fejs7MTX/rSlxCPx/E///M/OOWUU/Dvf/+7P9Q8/fTT2LZtGz71qU+hsrIS69evx1133YX169djzZo1EEIMeswLLrgAM2bMwA9+8ANIKQEA5513HtavX4+vfOUrmDx5MhobG/H0009j586dmDx5MgDgt7/9La644gqsWLECt956K3p6enDnnXdi2bJleOutt/rvdyirVq3CySefjMrKSlx00UW47rrr8Pjjj+OCCy4Yct+XX34ZjzzyCK6++moUFhbipz/9Kc477zzs3LkTJSUlAIDXXnsNr7zyCi666CJMmDABdXV1uPPOO3HSSSdhw4YNKCgoGLaOyy67DN/5znfwhz/8AV/+8pf7P55MJvHwww/jvPPOg9/vR2NjIz7ykY+grKwM1113HaLRKOrq6vDII48c8nV+4QtfwMMPP4wvf/nLmD17NlpaWvDyyy/jvffew8KFCw/7fRqLvgtIB74X+74Hb7zxRv/HPvShD0FRFFxzzTW4/fbbMWHCBLzzzjv4/ve/j3POOQezZs0a8fO+9dZbmDlzJsLh8KCPH3fccQCAt99+GxMnThzTayIiIgeRRERZds8990gA8rXXXuv/2BVXXCEByO985zuD7rtgwQJ5zDHH9P+7qalJApA33njjkMc99dRT5bx582Q8Hu//mGEY8oQTTpAzZswY8vzLli2T6XR60GPceOONEoD82Mc+NujjV199tQQg161bJ6WU8u2335YA5Gc+85lB91u5cqUEIJ977rn+j5144onyxBNP7P93Op2WiURi0Ne1tbXJiooKedVVV5n6Wq+99loJQK5du7b/Y42NjTISiUgAcvv27UMee6Df/OY3EoD0er3y5JNPltdff7186aWXpK7rg+63fft2CUAGAgG5e/fu/o+vXbtWApBf/epX+z/W09Mz5HkeeOABCUD+85//7P9Y38/i4osvHnTftrY2CUD+8Ic/PGjdnZ2dMhqNys9+9rODPl5fXy8jkciQjw+noaFBapomf/3rX/d/7IQTTpAf//jHh9y373u0ZcuW/o+tW7dOApA/+9nP+j823GtfvXq1BCDvv//+/o89//zzEoB8/vnn+z+2ZMkSuXjx4kFf+8gjjwy636OPPjrkd2s4B76vIpGI/NKXvnTIrxmL1157TQKQ99xzz5DPvfHGGxKA/O53vzvo408++aQEIEOh0KCP33333TIajUoA/bcrrrhCplKpUdU0Z84cecoppwz5+Pr16yUA+ctf/nJUj0dERM7EodREZKkvfOELg/69fPlybNu27bBf19raiueeew4XXnghOjs70dzcjObmZrS0tGDFihXYvHkz9uzZM+hrPvvZz0JV1WEf70tf+tKgf3/lK18BkFmheOB/v/a1rw2639e//nUAwN/+9reD1qqqav/QZMMw0NrainQ6jUWLFo1o6OpoXuvf//53HH/88f3dMAAoKyvDpZdeetjnAYCrrroKTz75JE466SS8/PLL+O53v4vly5djxowZw87FPOecc1BTU9P/7+OOOw6LFy/u/34BgzuE8Xgczc3NOP744wFg2Nd/4HsiEAjA6/XihRdeQFtb27B1P/3002hvb8fFF1/c//1pbm6GqqpYvHjxoGHrB/Pggw9CURScd955/R+7+OKL8cQTTwz7vB/+8If7F5UCMt39cDg86P078LWnUim0tLRg+vTpiEajh/3ZX3755Vi7di22bt3a/7FVq1Zh4sSJOPHEEwEA0WgUAPDXv/4VqVTqsK+xTzQaxdq1a7F3794Rf814LVy4EIsXL8att96Ke+65B3V1dXjiiSfw+c9/Hh6PB729vYPuX1NTg+OOOw533HEHHn30UXzta1/DqlWrcN11143qeXt7e+Hz+YZ8vG/e9YHPS0RE7sRgTESW8fv9/fNq+xQVFR00/Ay0ZcsWSClx/fXXo6ysbNDtxhtvBDB0sagpU6Yc9PFmzJgx6N/Tpk2Doij9c0F37NgBRVEwffr0QferrKxENBrFjh07Dlnvfffdh6OOOgp+vx8lJSUoKyvD3/72N3R0dJj6Wnfs2DHktQDAEUcccdjn6bNixQo89dRTaG9vxz//+U986Utfwo4dO3DWWWcN+Z4O91wzZ84cNIe2tbUV11xzDSoqKhAIBFBWVtb/sxju9R/4c/L5fLj11lvxxBNPoKKiAh/60Idw2223ob6+vv8+mzdvBgCccsopQ75H//jHP0a0cNjvfvc7HHfccWhpacGWLVuwZcsWLFiwAMlkEn/84x+H3H/SpElDPnbg+7e3txc33HADJk6cCJ/Ph9LSUpSVlaG9vf2wP/tPfOIT8Pl8WLVq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", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pvdeg.geospatial.plot_sparse_analysis(geo_res, data_var='T98_0', method=\"nearest\")" + ] } ], "metadata": { From 33bb216e034c2c5c369191200c7f0fcf9a9b1022 Mon Sep 17 00:00:00 2001 From: Ford Date: Sat, 26 Oct 2024 22:07:26 -0600 Subject: [PATCH 03/14] add new PVGIS location to existing store --- pvdeg/store.py | 96 +++- pvdeg/weather.py | 4 +- scripts/load_pvgis_distributed.ipynb | 772 +++++++++++++++++++++++---- 3 files changed, 758 insertions(+), 114 deletions(-) diff --git a/pvdeg/store.py b/pvdeg/store.py index 518d8ba..864882b 100644 --- a/pvdeg/store.py +++ b/pvdeg/store.py @@ -2,6 +2,7 @@ import xarray as xr import pandas as pd import numpy as np +import dask.array as da import zarr import os @@ -74,20 +75,90 @@ def store(weather_ds, meta_df): combined_ds = _combine_geo_weather_meta(weather_ds, meta_df) - # what mode should this be - # we want to add to indexes if need be or overwrite old ones - combined_ds.to_zarr( - store=METOROLOGICAL_DOWNLOAD_PATH, - group=f"{group}-{periodicity}" - ) + + if not os.path.exists(os.path.join(METOROLOGICAL_DOWNLOAD_PATH, ".zmetadata")): # no zstore in directory + print("Creating Zarr") + + combined_ds.to_zarr( + store=METOROLOGICAL_DOWNLOAD_PATH, + group=f"{group}-{periodicity}", + ) + else: # store already exists + print("adding to store") + + print("opening store") + stored_ds = xr.open_zarr( + store=METOROLOGICAL_DOWNLOAD_PATH, + group=f"{group}-{periodicity}", + ) + + lat_lon_gid_2d_map = _make_coords_to_gid_da(ds_from_zarr=stored_ds) + + for gid, values in meta_df.iterrows(): + + target_lat = values["latitude"] + target_lon = values["longitude"] + + lat_exists = np.any(lat_lon_gid_2d_map.latitude == target_lat) + lon_exists = np.any(lat_lon_gid_2d_map.longitude == target_lon) + + if lat_exists and lon_exists: + print("(lat, lon) exists already") + stored_gid = lat_lon_gid_2d_map.sel(latitude=target_lat, longitude=target_lon) + + # overwrite previous value at that lat-lon, keeps old gid + + # will this be a view + # how can we assign the value + # cant slice? + stored_ds.sel(gid=stored_gid)[:] = combined_ds.sel(gid=gid).values() + + else: # coordinate pair doesnt exist and it needs to be added, this will be a HEAVY operation + print("add entry to dataset") + + # we are trying to save 1 "sheet" of weather (weather at a single gid) + # need to update the index to fit into the stored data after we concatenate + # we want to update the arbitrary gid in the input (combined_ds) to the next index in the gid array (starts at 0, current_gid + 1 = sizes["gid"] = new gid) + new_gid = stored_ds.sizes["gid"] + + # combined_ds.sel(gid=gid) = combined_ds.sel(gid=gid).assign_coords(gid=[new_gid]) # we may have the issues with this sel returning a view + updated_entry = combined_ds.sel(gid=gid).assign_coords(gid=[new_gid]) + + stored_ds = xr.concat([stored_ds, updated_entry], dim="gid") + + # trigger rechunking + # should this happen outside of the loop + stored_ds = stored_ds.chunk() + + # SAVE DATASET BACK TO STORE + stored_ds.to_zarr(METOROLOGICAL_DOWNLOAD_PATH, group=f"{group}-{periodicity}", mode='w') # test with "a" probably wont work print(f"dataset saved to zarr store at {METOROLOGICAL_DOWNLOAD_PATH}") +### THIS NEEDS TO BE DEPRECATED +def _add_entry_to_ds(combined_ds, stored_ds, target_lat, target_lon, gid): + + new_gid = stored_ds.sizes["gid"] # zero indexed so the next index will be the current size + + # new_entry = combined_ds.sel(gid=gid).expand_dims(gid=new_gid) + + # for var in new_entry.data_vars: + # existing_data = stored_ds[var] + # new_data = new_entry[var] + + # updated_data = xr.concat([existing_data, new_data], dim='gid') + stored_ds = xr.concat([stored_ds, combined_ds.sel(gid=gid)], dim="gid") + + # stored_ds[var] = updated_datag + + # stored_ds['latitude'] = xr.concat([stored_ds['latitude'], xr.DataArray([target_lat], dims='gid')], dim='gid') + # stored_ds['longitude'] = xr.concat([stored_ds['longitude'], xr.DataArray([target_lon], dims='gid')], dim='gid') + def check_store(): """Check if you have a zarr store at the default download path defined in pvdeg.config""" - if os.path.exists(os.path.join(METOROLOGICAL_DOWNLOAD_PATH, ".zattrs")): + if os.path.exists(os.path.join(METOROLOGICAL_DOWNLOAD_PATH, ".zmetadata")): size = sum(f.stat().st_size for f in METOROLOGICAL_DOWNLOAD_PATH.glob('**/*') if f.is_file()) @@ -118,17 +189,15 @@ def _combine_geo_weather_meta( ): """Combine weather dataset and meta dataframe into a single dataset""" - meta_ds = xr.Dataset.from_dataframe(meta_df) - # we could do some encoding scheme here, dont need to store source? unless the zarr compression handles it for us - - meta_ds['gid'] = meta_ds['index'].values.astype(np.int32) - meta_ds = meta_ds.drop_vars(["index"]) + meta_ds = xr.Dataset.from_dataframe(meta_df).rename({'index' : 'gid'}) combined = xr.merge([weather_ds, meta_ds]).assign_coords( latitude=("gid", meta_ds.latitude.values), longitude=('gid', meta_ds.longitude.values), ) + combined["Source"] = combined["Source"].astype(str) # save as strings + return combined @@ -140,6 +209,8 @@ def _seperate_geo_weather_meta( and seperate it into `weather_ds` and `meta_df`. """ + ds_from_zarr["Source"] = ds_from_zarr["Source"].astype(object) # geospatial.mapblocks needs this to be an object + # there may be a more optimal way to do this data = np.column_stack( [ @@ -163,7 +234,6 @@ def _make_coords_to_gid_da( ): """Create a 2D indexable array that maps coordinates (lat and lon) to gid stored in zarr store""" - import dask.array as da # only want to do this if the arrays are dask arrays lats = ds_from_zarr.latitude.to_numpy() diff --git a/pvdeg/weather.py b/pvdeg/weather.py index 59f7365..4917283 100644 --- a/pvdeg/weather.py +++ b/pvdeg/weather.py @@ -968,7 +968,7 @@ def _weather_distributed_vec( return weather_ds, meta_dict, None -def pvgis_empty_weather_ds(gids_size): +def pvgis_hourly_empty_weather_ds(gids_size): """ Create an empty weather dataset for pvgis hourly TMY data @@ -1074,7 +1074,7 @@ def weather_distributed(database, coords): gids_failed = [] - weather_ds = pvgis_empty_weather_ds(len(results)) # create empty weather xr.dataset + weather_ds = pvgis_hourly_empty_weather_ds(len(results)) # create empty weather xr.dataset meta_df = pd.DataFrame.from_dict(meta_dict_collection) # create populated meta pd.DataFrame # these gids will be spatially meaningless, they will only show corresponding entries between weather_ds and meta_df diff --git a/scripts/load_pvgis_distributed.ipynb b/scripts/load_pvgis_distributed.ipynb index 5dc552e..edc99d7 100644 --- a/scripts/load_pvgis_distributed.ipynb +++ b/scripts/load_pvgis_distributed.ipynb @@ -46,16 +46,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "http://127.0.0.1:8787/status\n" + ] + } + ], "source": [ "workers = 4\n", "\n", "cluster = LocalCluster(\n", " n_workers=workers,\n", " processes=True, \n", - " # number of threads may matter\n", " )\n", "\n", "client = Client(cluster)\n", @@ -76,9 +83,486 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
    <xarray.Dataset> Size: 14MB\n",
    +       "Dimensions:            (gid: 22, time: 8760)\n",
    +       "Coordinates:\n",
    +       "  * time               (time) datetime64[ns] 70kB 2022-01-01 ... 2022-12-31T2...\n",
    +       "  * gid                (gid) int32 88B 0 1 2 3 4 5 6 7 ... 15 16 17 18 19 20 21\n",
    +       "Data variables:\n",
    +       "    temp_air           (gid, time) float64 2MB 4.11 4.7 5.28 ... 0.35 0.37 0.38\n",
    +       "    relative_humidity  (gid, time) float64 2MB 87.27 87.03 86.79 ... 86.37 86.14\n",
    +       "    ghi                (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n",
    +       "    dni                (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n",
    +       "    dhi                (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n",
    +       "    IR(h)              (gid, time) float64 2MB 314.4 317.4 320.4 ... 271.9 274.1\n",
    +       "    wind_speed         (gid, time) float64 2MB 3.11 3.1 3.08 ... 3.53 3.45 3.37\n",
    +       "    wind_direction     (gid, time) float64 2MB 269.0 274.0 279.0 ... 245.0 242.0\n",
    +       "    pressure           (gid, time) float64 2MB 1.014e+05 1.014e+05 ... 9.965e+04
    " + ], + "text/plain": [ + " Size: 14MB\n", + "Dimensions: (gid: 22, time: 8760)\n", + "Coordinates:\n", + " * time (time) datetime64[ns] 70kB 2022-01-01 ... 2022-12-31T2...\n", + " * gid (gid) int32 88B 0 1 2 3 4 5 6 7 ... 15 16 17 18 19 20 21\n", + "Data variables:\n", + " temp_air (gid, time) float64 2MB 4.11 4.7 5.28 ... 0.35 0.37 0.38\n", + " relative_humidity (gid, time) float64 2MB 87.27 87.03 86.79 ... 86.37 86.14\n", + " ghi (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n", + " dni (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n", + " dhi (gid, time) float64 2MB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0\n", + " IR(h) (gid, time) float64 2MB 314.4 317.4 320.4 ... 271.9 274.1\n", + " wind_speed (gid, time) float64 2MB 3.11 3.1 3.08 ... 3.53 3.45 3.37\n", + " wind_direction (gid, time) float64 2MB 269.0 274.0 279.0 ... 245.0 242.0\n", + " pressure (gid, time) float64 2MB 1.014e+05 1.014e+05 ... 9.965e+04" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "weather_ds.compute()" ] @@ -103,9 +587,36 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Creating Zarr\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\tford\\AppData\\Local\\miniconda3\\envs\\deg\\lib\\site-packages\\distributed\\client.py:3362: UserWarning: Sending large graph of size 13.27 MiB.\n", + "This may cause some slowdown.\n", + "Consider loading the data with Dask directly\n", + " or using futures or delayed objects to embed the data into the graph without repetition.\n", + "See also https://docs.dask.org/en/stable/best-practices.html#load-data-with-dask for more information.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dataset saved to zarr store at C:\\Users\\tford\\PVDeg-Meteorological\n" + ] + } + ], "source": [ "pvdeg.store.store(weather_ds, meta_df)" ] @@ -137,7 +648,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -150,12 +661,12 @@ "source": [ "### Inspecting the Results\n", "\n", - "explain *.compute() here*" + "explain *.compute() and dask here*" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -539,11 +1050,11 @@ " relative_humidity (gid, time) float64 2MB dask.array<chunksize=(22, 8760), meta=np.ndarray>\n", " temp_air (gid, time) float64 2MB dask.array<chunksize=(22, 8760), meta=np.ndarray>\n", " wind_direction (gid, time) float64 2MB dask.array<chunksize=(22, 8760), meta=np.ndarray>\n", - " wind_speed (gid, time) float64 2MB dask.array<chunksize=(22, 8760), meta=np.ndarray>