Skip to content

leaver2000/fast_spa

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fast_spa

This is a Cython implementation of the NREL Solar Position Algorithm for Solar Radiation Applications. Designed for calculating solar zenith and azimuth across a temporal and spatial dimension.

etopo2022

git clone ...
python3 -m venv .venv && source .venv/bin/activate
pip install .
import numpy as np
import fast_spa

# 200x200km area
lats = np.linspace(30, 31, 100)
lons = np.linspace(-80, -79, 100)
lats, lons = np.meshgrid(lats, lons)
datetime_obj = (
    np.arange("2023-01-01", "2023-01-02", dtype="datetime64[h]")
    .astype("datetime64[ns]")
    .astype(str)
    .tolist()
)

%timeit fast_spa.fast_spa(datetime_obj, lats, lons)
29.1 ms ± 299 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

There is also integration with the ETOPO2022 dataset for elevation data.

import numpy as np
from numpy.typing import ArrayLike
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import fast_spa
ZENITH_ANGLE = 0
AZIMUTH_ANGLE = 1

def contourf(
    ax: GeoAxes,
    data: ArrayLike,
    lons: ArrayLike,
    lats: ArrayLike,
    title="",
    **kwargs,
) -> GeoAxes:
    ax.title.set_text(title)
    ax.coastlines()
    ax.add_feature(cfeature.STATES)
    ax.contourf(
        lons,
        lats,
        data,
        transform=ccrs.PlateCarree(),
        **kwargs,
    )
    return ax

def main(
    etopo: fast_spa.ETOPO2022 = fast_spa.ETOPO2022(),
    lons=np.linspace(-125, -65, 200),
    lats=np.linspace(25, 50, 100),
    weight: float = 1e7,
):
    fig, axes = plt.subplots(
        2, 3, figsize=(20, 6), subplot_kw={"projection": ccrs.PlateCarree()}
    )

    # - plot the non-resampled elevation data
    lons, lats = np.meshgrid(lons, lats)
    y_mask = np.logical_and(etopo.lat >= lats.min(), etopo.lat <= lats.max())
    x_mask = np.logical_and(etopo.lon >= lons.min(), etopo.lon <= lons.max())

    fig.tight_layout()

    e = etopo[y_mask, x_mask]
    e[e < -100] = -100  # set the ocean to -100m

    contourf(
        axes[0, 0],
        e,
        etopo.lon[x_mask],
        etopo.lat[y_mask],
        "elevation",
        cmap="terrain",
    )

    # - resample the elevation data to fit the lon, lat grid
    e = etopo.resample(lons, lats)
    e[e < -100] = -100  # set the ocean to -100m

    spa_data = fast_spa.fast_spa(datetime_obj, lats, lons, e)
    
    # - apply a weight to the elevation data for SPA calculation
    weighted = fast_spa.fast_spa(datetime_obj, lats, lons, e * weight) 
    weighted = np.radians(weighted)

    contourf(
        axes[1, 0],
        e,
        lons,
        lats,
        "resampled elevation",
        cmap="terrain",
    )
    contourf(
        axes[0, 1],
        spa_data[ZENITH_ANGLE, 0, :, :],
        lons,
        lats,
        "zenith angle",
    )
    contourf(
        axes[1, 1],
        weighted[ZENITH_ANGLE, 0, :, :],
        lons,
        lats,
        f"weighted zenith angle {weight:.0e}",
    )
    contourf(
        axes[0, 2],
        spa_data[AZIMUTH_ANGLE, 0, :, :],
        lons,
        lats,
        "azimuth angle",
    )
    contourf(
        axes[1, 2],
        weighted[AZIMUTH_ANGLE, 0, :, :],
        lons,
        lats,
        f"weighted azimuth angle {weight:.0e}",
    )
    plt.show()


main()

etopo2022

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages