perezsky 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- perezsky-1.0.0/.github/workflows/publish.yml +39 -0
- perezsky-1.0.0/.gitignore +9 -0
- perezsky-1.0.0/CITATION.cff +25 -0
- perezsky-1.0.0/CLAUDE.md +88 -0
- perezsky-1.0.0/LICENSE +21 -0
- perezsky-1.0.0/PKG-INFO +266 -0
- perezsky-1.0.0/README.md +233 -0
- perezsky-1.0.0/pyproject.toml +47 -0
- perezsky-1.0.0/src/perezsky/__init__.py +24 -0
- perezsky-1.0.0/src/perezsky/coefficients.py +66 -0
- perezsky-1.0.0/src/perezsky/grid.py +88 -0
- perezsky-1.0.0/src/perezsky/horizon.py +120 -0
- perezsky-1.0.0/src/perezsky/model.py +203 -0
- perezsky-1.0.0/src/perezsky/plot.py +31 -0
- perezsky-1.0.0/src/perezsky/radiance.py +81 -0
- perezsky-1.0.0/src/perezsky/sky.py +222 -0
- perezsky-1.0.0/tests/conftest.py +36 -0
- perezsky-1.0.0/tests/test_model.py +103 -0
- perezsky-1.0.0/tests/test_radiance.py +97 -0
- perezsky-1.0.0/tests/test_sky.py +118 -0
- perezsky-1.0.0/validation/brightness_correction.py +99 -0
- perezsky-1.0.0/validation/results/brightness_correction.md +33 -0
- perezsky-1.0.0/validation/results/validation.md +47 -0
- perezsky-1.0.0/validation/validate.py +174 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Build, test and publish to PyPI when a GitHub release is published.
|
|
2
|
+
# PyPI trusted publishing: project "perezsky", owner "WildSolar", repository "PerezSky",
|
|
3
|
+
# workflow "publish.yml", environment "pypi" (no API token needed).
|
|
4
|
+
name: Publish to PyPI
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
release:
|
|
8
|
+
types: [published]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: astral-sh/setup-uv@v5
|
|
16
|
+
- name: Build sdist and wheel
|
|
17
|
+
run: uv build
|
|
18
|
+
- name: Test the built wheel
|
|
19
|
+
run: |
|
|
20
|
+
uv venv
|
|
21
|
+
uv pip install dist/*.whl pytest pandas pvlib matplotlib
|
|
22
|
+
.venv/bin/python -m pytest -q -p no:cacheprovider
|
|
23
|
+
- uses: actions/upload-artifact@v4
|
|
24
|
+
with:
|
|
25
|
+
name: dist
|
|
26
|
+
path: dist/
|
|
27
|
+
|
|
28
|
+
publish:
|
|
29
|
+
needs: build
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
environment: pypi
|
|
32
|
+
permissions:
|
|
33
|
+
id-token: write
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/download-artifact@v4
|
|
36
|
+
with:
|
|
37
|
+
name: dist
|
|
38
|
+
path: dist/
|
|
39
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it using the metadata from this file."
|
|
3
|
+
type: software
|
|
4
|
+
title: "perezsky: Perez all-weather sky radiance distribution, plane irradiance and horizon masking"
|
|
5
|
+
abstract: >-
|
|
6
|
+
Python implementation of the Perez (1993) all-weather sky as a radiance or luminance
|
|
7
|
+
distribution on a discretised hemisphere, normalised to measured irradiance, with irradiance
|
|
8
|
+
on arbitrarily oriented planes, masking by a local horizon with a terrain model, Perez (1990)
|
|
9
|
+
luminous efficacy and export to Radiance. Validated against Radiance's gendaylit and rtrace.
|
|
10
|
+
authors:
|
|
11
|
+
- family-names: Wild
|
|
12
|
+
given-names: Michael
|
|
13
|
+
orcid: "https://orcid.org/0000-0002-7730-3064"
|
|
14
|
+
affiliation: "ZHAW Zurich University of Applied Sciences"
|
|
15
|
+
version: 1.0.0
|
|
16
|
+
license: MIT
|
|
17
|
+
repository-code: "https://github.com/WildSolar/PerezSky"
|
|
18
|
+
keywords:
|
|
19
|
+
- solar energy
|
|
20
|
+
- sky model
|
|
21
|
+
- Perez
|
|
22
|
+
- diffuse irradiance
|
|
23
|
+
- photovoltaics
|
|
24
|
+
- daylighting
|
|
25
|
+
- Radiance
|
perezsky-1.0.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# perezsky — notes for Claude sessions
|
|
2
|
+
|
|
3
|
+
Python package for the Perez (1993) all-weather sky: radiance/luminance distribution on a
|
|
4
|
+
discretised hemisphere, normalised to measured DNI/DHI. Also covers plane irradiance (incl.
|
|
5
|
+
long time series), horizon masking with a terrain model, Perez (1990) luminous efficacy and
|
|
6
|
+
export to Radiance. Validated against Radiance's gendaylit and rtrace. Extracted from the
|
|
7
|
+
slopevf project (`C:\Users\wimm\Documents\GitHub\General_Irradiation_Model\python`), where the
|
|
8
|
+
same model was corrected relative to the user's older MATLAB code. `README.md` is the full user
|
|
9
|
+
documentation.
|
|
10
|
+
|
|
11
|
+
## Using it from another project
|
|
12
|
+
|
|
13
|
+
Declare it in that project's `pyproject.toml` (editable, so it follows this repository), then
|
|
14
|
+
`uv sync`:
|
|
15
|
+
|
|
16
|
+
```toml
|
|
17
|
+
[project]
|
|
18
|
+
dependencies = ["perezsky[plot]"]
|
|
19
|
+
|
|
20
|
+
[tool.uv.sources]
|
|
21
|
+
perezsky = { path = "C:/Users/wimm/Documents/packages/PerezSky", editable = true }
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
To freeze a finished project, depend on a released version from PyPI instead
|
|
25
|
+
(`perezsky>=1.0`, without the uv source). Don't copy the code into the other project.
|
|
26
|
+
Public repository: https://github.com/WildSolar/PerezSky; releases are archived on Zenodo and
|
|
27
|
+
published to PyPI by `.github/workflows/publish.yml` (trusted publishing) when a GitHub release
|
|
28
|
+
is published. Bump the version in `pyproject.toml`, `src/perezsky/__init__.py` and
|
|
29
|
+
`CITATION.cff` together.
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
import perezsky as ps
|
|
33
|
+
|
|
34
|
+
# angles in degrees; azimuth from NORTH, clockwise (east = 90); DNI/DHI/GHI in W/m2
|
|
35
|
+
sky = ps.perez_sky(dni, solar_zenith, solar_azimuth, dhi=dhi, # or ghi=ghi
|
|
36
|
+
day_of_year=doy, # date-dependent E0 (optional)
|
|
37
|
+
grid="medium", # "low" | "medium" | "high" | "ultra"
|
|
38
|
+
sun_model="point", # "point" (beam separate) | "buie" (circumsolar)
|
|
39
|
+
horizon=None, # ps.Horizon(...), see below
|
|
40
|
+
quantity="radiance") # or "luminance" (cd/m2, lux)
|
|
41
|
+
sky.L, sky.beam, sky.ghi # (n_cells, n_t) radiance, (n_t,) point beam, local GHI
|
|
42
|
+
sky.plane_irradiance(tilt, azimuth, albedo) # dict "beam","sky","ground","total": (n_t, n_planes)
|
|
43
|
+
|
|
44
|
+
out = ps.poa_irradiance(tilt, azimuth, dni, zen, az, dhi=dhi, albedo=0.2, day_of_year=doy) # chunked series
|
|
45
|
+
|
|
46
|
+
hor = ps.Horizon.from_file("site.hor") # .hor files: SOUTH = 0 (default convention there)
|
|
47
|
+
hor = ps.Horizon.from_horizontool(ht_horizon, albedo=0.3, terrain="facing")
|
|
48
|
+
p = ps.perez_parameters(dni, dhi, zen) # epsilon, delta, category, a..e
|
|
49
|
+
ps.write_radiance_sky(sky, "sky.rad", index=0) # writes sky.rad + sky.cal (point sun, no horizon)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Pitfalls:
|
|
53
|
+
|
|
54
|
+
- **Azimuth conventions.** The API uses north = 0, clockwise (as pvlib and the horizontool
|
|
55
|
+
API). `.hor` files use south = 0: `Horizon.from_file` assumes that, `Horizon(...)` assumes
|
|
56
|
+
north unless `convention="south"`. slopevf uses south = 0, positive towards west; convert with
|
|
57
|
+
`az_north = az_south + 180`.
|
|
58
|
+
- **Night and memory.** `perez_sky` requires the sun above the horizontal and holds
|
|
59
|
+
n_cells × n_t floats. For long series use `poa_irradiance`, which chunks and returns 0 at
|
|
60
|
+
night.
|
|
61
|
+
- **Defaults keep the model in its range.** `clamp`, `brightness_correction` and
|
|
62
|
+
`limit_gradation` are on by default.
|
|
63
|
+
- Without `limit_gradation`, very bright overcast skies, and clear skies with a sun below
|
|
64
|
+
about 5°, can give b > 0, and vertical planes then receive many times the GHI.
|
|
65
|
+
- gendaylit-identical parameters: `airmass_model="kasten1966", solar_constant=1367,
|
|
66
|
+
limit_gradation=False`. gendaylit also uses day number 0 with `-ang`.
|
|
67
|
+
- **`sun_model`.** `"point"` is the right choice for plane irradiance. `"buie"` spreads the
|
|
68
|
+
beam over a 6° cone; use it only when angular acceptance matters (concentrators,
|
|
69
|
+
circumsolar studies).
|
|
70
|
+
- **Horizon.** DNI/DHI are treated as free-horizon values. The terrain model `"facing"`
|
|
71
|
+
(default) is better than `"horizontal"`; it was validated in slopevf.
|
|
72
|
+
- **Ground term.** `plane_irradiance` treats the ground as an isotropic reflector of the local
|
|
73
|
+
GHI, the standard approach. Shading by rows or other obstacles is not included; use a
|
|
74
|
+
dedicated model for that, e.g. slopevf for PV arrays.
|
|
75
|
+
|
|
76
|
+
## Working on this repository
|
|
77
|
+
|
|
78
|
+
- Tests: `.venv\Scripts\python.exe -m pytest -q -p no:cacheprovider`. The `radiance` tests
|
|
79
|
+
compare with gendaylit/rtrace and need `RADIANCE_DIR` (here `C:\Users\wimm\tools\Radiance`);
|
|
80
|
+
without it they are skipped. Run the full suite with Radiance before committing.
|
|
81
|
+
- Model or numerical changes: rerun `validation/validate.py` (needs Radiance and pvlib) and
|
|
82
|
+
commit the updated `validation/results/validation.md`. The gendaylit comparison must stay
|
|
83
|
+
within print precision.
|
|
84
|
+
- Coefficients are transcribed from gendaylit.c, the reference implementation;
|
|
85
|
+
`tests/test_model.py` holds an independent transcription.
|
|
86
|
+
- git is not on PATH: use GitHub Desktop's bundled
|
|
87
|
+
`%LOCALAPPDATA%\GitHubDesktop\app-*\resources\app\git\cmd\git.exe`. Commit on `main` with a
|
|
88
|
+
message file (`commit -F`, UTF-8 without BOM); never push — the user pushes from GitHub Desktop.
|
perezsky-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael Wild
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
perezsky-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: perezsky
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Perez (1993) all-weather sky radiance and luminance distribution on a discretised sky, with plane irradiance, horizon masking and Radiance export.
|
|
5
|
+
Project-URL: Homepage, https://github.com/WildSolar/PerezSky
|
|
6
|
+
Project-URL: Repository, https://github.com/WildSolar/PerezSky
|
|
7
|
+
Project-URL: Issues, https://github.com/WildSolar/PerezSky/issues
|
|
8
|
+
Author-email: Michael Wild <michael.wild@zhaw.ch>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: Perez,Radiance,daylighting,diffuse irradiance,photovoltaics,sky model,solar energy
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: numpy>=1.25
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: matplotlib>=3.6; extra == 'dev'
|
|
27
|
+
Requires-Dist: pandas>=1.5; extra == 'dev'
|
|
28
|
+
Requires-Dist: pvlib>=0.10; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
30
|
+
Provides-Extra: plot
|
|
31
|
+
Requires-Dist: matplotlib>=3.6; extra == 'plot'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# perezsky
|
|
35
|
+
|
|
36
|
+
The Perez (1993) all-weather sky as a radiance (or luminance) distribution on a discretised
|
|
37
|
+
hemisphere, normalised to measured irradiance. On top of it:
|
|
38
|
+
|
|
39
|
+
- irradiance on arbitrarily oriented planes, also for long time series;
|
|
40
|
+
- masking by a local horizon, with a model of the terrain radiance;
|
|
41
|
+
- luminance and illuminance via the Perez (1990) luminous efficacy models;
|
|
42
|
+
- export of the same sky to Radiance;
|
|
43
|
+
- a polar plot of the sky.
|
|
44
|
+
|
|
45
|
+
The implementation is validated against Radiance's `gendaylit` and `rtrace`
|
|
46
|
+
([validation/results/validation.md](https://github.com/WildSolar/PerezSky/blob/main/validation/results/validation.md)).
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install perezsky # with plotting: pip install "perezsky[plot]"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quick start
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
import perezsky as ps
|
|
56
|
+
|
|
57
|
+
# one or many time steps; angles in degrees, azimuth from north, clockwise
|
|
58
|
+
sky = ps.perez_sky(dni=[850, 120], solar_zenith=[35, 70], solar_azimuth=[140, 250],
|
|
59
|
+
dhi=[90, 200], day_of_year=[172, 172])
|
|
60
|
+
sky.L # (n_cells, n_t) sky radiance [W/m2/sr]
|
|
61
|
+
sky.beam # (n_t,) DNI of the point sun [W/m2] (0 while hidden by a horizon)
|
|
62
|
+
res = sky.plane_irradiance(tilt=[30, 90], azimuth=[180, 90], albedo=0.2)
|
|
63
|
+
res["total"] # (n_t, n_planes); also "beam", "sky", "ground"
|
|
64
|
+
|
|
65
|
+
# a year of hourly data in chunks (sun below the horizontal -> 0)
|
|
66
|
+
out = ps.poa_irradiance(35, 180, dni, solar_zenith, solar_azimuth, dhi=dhi,
|
|
67
|
+
albedo=0.2, day_of_year=doy)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Model
|
|
71
|
+
|
|
72
|
+
**Sky condition.** For each time step:
|
|
73
|
+
|
|
74
|
+
- the sky clearness ε = ((DHI + DNI)/DHI + 1.041 Z³) / (1 + 1.041 Z³);
|
|
75
|
+
- the sky brightness Δ = DHI · m / E₀, with the relative air mass m and the extraterrestrial
|
|
76
|
+
irradiance E₀;
|
|
77
|
+
- one of eight clearness categories, determined by ε.
|
|
78
|
+
|
|
79
|
+
**Distribution.** The relative distribution is
|
|
80
|
+
|
|
81
|
+
L ∝ (1 + a exp(b / cos ζ)) · (1 + c exp(d γ) + e cos² γ),
|
|
82
|
+
|
|
83
|
+
with ζ the zenith angle of the sky element and γ its angle to the sun. The parameters a..e
|
|
84
|
+
come from the coefficients of Perez et al. (1993); for the overcast category, c and d use
|
|
85
|
+
their own formulas.
|
|
86
|
+
|
|
87
|
+
**Normalisation.**
|
|
88
|
+
|
|
89
|
+
- The sky cells above the horizontal integrate exactly to DHI, for any grid resolution.
|
|
90
|
+
- With `sun_model="point"` (default), the beam DNI is kept as a separate point source in the
|
|
91
|
+
exact sun direction. For irradiance on planes, this is more accurate than spreading it over
|
|
92
|
+
sky cells.
|
|
93
|
+
- With `sun_model="buie"`, the beam is distributed over a circumsolar cone (default 6°)
|
|
94
|
+
following the Buie et al. (2003) sunshape. Inside the cone it replaces the Perez radiance and
|
|
95
|
+
integrates to DNI cos Z. This matters when angular acceptance is relevant, e.g. for
|
|
96
|
+
concentrators.
|
|
97
|
+
|
|
98
|
+
**Range of validity.** By default the inputs are kept within the range of the model:
|
|
99
|
+
|
|
100
|
+
- `clamp=True`: ε ∈ [1, 12.01) and Δ ∈ [0.01, 0.6], as gendaylit does.
|
|
101
|
+
- `brightness_correction=True`: Δ ≥ 0.2 for 1.065 < ε < 2.8 when computing a..e, as
|
|
102
|
+
gendaylit does. gendaylit marks it as a correction of the Perez model, without a
|
|
103
|
+
reference; see the section below.
|
|
104
|
+
- `limit_gradation=True`: b ≤ 0.
|
|
105
|
+
- For very bright overcast skies (e.g. cloud enhancement over snow, GHI ≈ 700 W/m² with
|
|
106
|
+
DNI ≈ 0) and for clear skies with a very low sun, the model gives b > 0.
|
|
107
|
+
- The factor exp(b / cos ζ) then grows without bound towards the horizon. Vertical planes
|
|
108
|
+
received up to 30 times the GHI in a real data set.
|
|
109
|
+
- gendaylit refuses such skies and outputs a black sky ("positive Perez parameter B");
|
|
110
|
+
perezsky caps b at 0 instead.
|
|
111
|
+
|
|
112
|
+
**The brightness correction.** It changes only the *shape* of the distribution; the
|
|
113
|
+
normalisation to the actual DHI stays the same.
|
|
114
|
+
|
|
115
|
+
- **Where it acts:** on dark skies of intermediate clearness (thin or broken cloud with little
|
|
116
|
+
diffuse light, Δ < 0.2 for 1.065 < ε < 2.8).
|
|
117
|
+
- **Why it is needed:** the parameters are linear in Δ and were fitted to measured skies. For
|
|
118
|
+
low Δ in categories 2–5 they extrapolate to a gradation 1 + a·exp(b/cos ζ) with
|
|
119
|
+
a·exp(b) ≈ −1. The zenith then becomes almost black, and the horizon up to 3.5 times
|
|
120
|
+
brighter than the average sky radiance DHI/π. Real skies of this type do not look like that.
|
|
121
|
+
- **What it does:** raising Δ to 0.2 makes b more negative. The gradation then approaches 1
|
|
122
|
+
only close to the horizon, which gives a moderately brighter horizon and a zenith of 0.4–1.0
|
|
123
|
+
times the average radiance.
|
|
124
|
+
- **Size of the effect:** in such hours the sky-diffuse irradiance on vertical planes drops by
|
|
125
|
+
a median of 4–15% (up to about 45%). In the opposite direction, a few very dark skies
|
|
126
|
+
(Δ ≈ 0.05) gain up to 25%.
|
|
127
|
+
- **How often:** such hours make up 1–2% of the daylight hours (Davos PVGIS TMY, Greensboro
|
|
128
|
+
TMY3). Annual sums change by at most 0.2% of the sky-diffuse and 0.1% of the total
|
|
129
|
+
irradiation, on any plane.
|
|
130
|
+
|
|
131
|
+
See [validation/results/brightness_correction.md](https://github.com/WildSolar/PerezSky/blob/main/validation/results/brightness_correction.md).
|
|
132
|
+
|
|
133
|
+
**Other settings.**
|
|
134
|
+
|
|
135
|
+
- **Air mass:** Kasten & Young (1989) by default; `airmass_model="kasten1966"` selects
|
|
136
|
+
gendaylit's formula.
|
|
137
|
+
- **E₀:** the solar constant of 1361 W/m², corrected for the Earth–Sun distance (Spencer 1971)
|
|
138
|
+
if `day_of_year` is given; gendaylit uses 1367 W/m².
|
|
139
|
+
|
|
140
|
+
**Grids.** Elevation bands of 0.5°, each divided into azimuthal cells of near-constant size,
|
|
141
|
+
with exact solid angles:
|
|
142
|
+
|
|
143
|
+
| Resolution | Cells |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `low` | 10'401 |
|
|
146
|
+
| `medium` | 20'716 |
|
|
147
|
+
| `high` | 41'335 |
|
|
148
|
+
| `ultra` | 82'594 |
|
|
149
|
+
|
|
150
|
+
Plane irradiance on `low` is within 0.3% of `ultra`. `poa_irradiance` uses `low` by default.
|
|
151
|
+
|
|
152
|
+
## Planes and ground
|
|
153
|
+
|
|
154
|
+
`Sky.plane_irradiance(tilt, azimuth, albedo)` sums three parts:
|
|
155
|
+
|
|
156
|
+
- **beam:** DNI · cos(incidence), zero while the sun is behind the plane or the horizon;
|
|
157
|
+
- **sky:** the sky cells in front of the plane, weighted with the cosine;
|
|
158
|
+
- **ground:** isotropic reflection of the local global horizontal irradiance below the
|
|
159
|
+
horizontal, albedo · GHI · (1 − cos tilt)/2.
|
|
160
|
+
|
|
161
|
+
## Horizon
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
hor = ps.Horizon.from_file("site.hor") # PVsyst/horizontool .hor: south = 0
|
|
165
|
+
hor = ps.Horizon(azimuth, elevation, convention="north") # arrays, north = 0
|
|
166
|
+
hor = ps.Horizon.from_horizontool(ht.compute_horizon(lat, lon), albedo=0.3)
|
|
167
|
+
sky = ps.perez_sky(..., horizon=hor)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Masking.** Sky cells below the horizon get the radiance of the terrain, and the beam is
|
|
171
|
+
blocked while the sun is behind the horizon. DNI and DHI are treated as free-horizon values.
|
|
172
|
+
If they were measured on site behind the horizon, this is still a good approximation for the
|
|
173
|
+
sky: the masked part is replaced anyway.
|
|
174
|
+
|
|
175
|
+
**Terrain models.**
|
|
176
|
+
|
|
177
|
+
| `terrain=` | Model | Deviation from ray-traced terrain |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| `"facing"` (default) | Slopes of 30° facing the observer: beam (if the sun is visible from the observer), isotropic sky, own surroundings | ≤ 2% on tilted planes |
|
|
180
|
+
| `"horizontal"` | albedo · GHI / π | up to 14% |
|
|
181
|
+
|
|
182
|
+
The deviations were determined with Radiance in the slopevf project. Negative horizon
|
|
183
|
+
elevations are treated as 0.
|
|
184
|
+
|
|
185
|
+
## Luminance
|
|
186
|
+
|
|
187
|
+
`perez_sky(..., quantity="luminance")` gives luminance [cd/m²] and illuminance [lux].
|
|
188
|
+
|
|
189
|
+
- **Conversion:** DNI and DHI are converted with the Perez et al. (1990) luminous efficacies
|
|
190
|
+
of the direct and diffuse components (`precipitable_water` in cm, default 2 as in
|
|
191
|
+
gendaylit), and the same distribution is normalised to them.
|
|
192
|
+
- **Efficacies:** `luminous_efficacy(params, zenith)` returns the global, diffuse and direct
|
|
193
|
+
efficacies [lm/W] directly.
|
|
194
|
+
|
|
195
|
+
## Radiance export
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
ps.write_radiance_sky(sky, "sky.rad", index=0, ground_albedo=0.2) # writes sky.rad and sky.cal
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The exported sky differs from gendaylit's in two ways:
|
|
202
|
+
|
|
203
|
+
- **No horizon blending.** gendaylit's `perezlum.cal` mixes about 45% ground brightness into
|
|
204
|
+
the sky at the horizon, which changes vertical-plane irradiance by up to 5%; the exported sky
|
|
205
|
+
has no such blending.
|
|
206
|
+
- **Same normalisation.** It is normalised to the same DHI as the discrete sky.
|
|
207
|
+
|
|
208
|
+
`rtrace` on the exported sky reproduces `Sky.plane_irradiance` within 0.1%. Only skies with
|
|
209
|
+
`sun_model="point"` and without horizon can be exported.
|
|
210
|
+
|
|
211
|
+
## Corrections relative to earlier MATLAB implementations
|
|
212
|
+
|
|
213
|
+
The MATLAB code this package replaces (`skyLuminanceBatch.m`, `totalSkyLuminance.m`) had
|
|
214
|
+
several deviations from the published model. All of them are corrected here:
|
|
215
|
+
|
|
216
|
+
- Three coefficients were mistyped:
|
|
217
|
+
- `x4` of b in category 1: −1.233 instead of −0.1233;
|
|
218
|
+
- `x3` of c in category 6: −7.1407 instead of −7.1406;
|
|
219
|
+
- `x4` of d in category 7: 0.2652 instead of 0.2656.
|
|
220
|
+
- The category-1 formula for c raised only (x1 + x2 Z) to the power x3 instead of
|
|
221
|
+
Δ (x1 + x2 Z): exp(Δ (x1 + x2 Z)^x3) instead of exp((Δ (x1 + x2 Z))^x3).
|
|
222
|
+
- The air mass function was called with the elevation in radians instead of sin(elevation),
|
|
223
|
+
which gives complex values above 1 rad.
|
|
224
|
+
- The model ran without range limits.
|
|
225
|
+
|
|
226
|
+
## Validation
|
|
227
|
+
|
|
228
|
+
`validation/validate.py` (needs Radiance and pvlib) writes
|
|
229
|
+
[validation/results/validation.md](https://github.com/WildSolar/PerezSky/blob/main/validation/results/validation.md):
|
|
230
|
+
|
|
231
|
+
- **Parameters and luminous efficacies vs. gendaylit:** 86 sky conditions, solar altitudes
|
|
232
|
+
5–80°, overcast to clear. Agreement within gendaylit's print precision:
|
|
233
|
+
- parameters a..e to 2.5·10⁻⁶;
|
|
234
|
+
- diffuse efficacy to 0.06%;
|
|
235
|
+
- direct efficacy to 0.04 lm/W.
|
|
236
|
+
|
|
237
|
+
gendaylit refuses 2 of the conditions as error skies, exactly those with b > 0.
|
|
238
|
+
- **Plane irradiance vs. rtrace:** 5 skies × 9 planes on the exported sky, within 0.1%.
|
|
239
|
+
- **Annual POA vs. pvlib (TMY3, Greensboro):** within about 1% of pvlib's Perez (1990)
|
|
240
|
+
transposition model for south-facing and vertical planes. The isotropic model deviates by up
|
|
241
|
+
to 15% (vertical north).
|
|
242
|
+
|
|
243
|
+
The tests (`pytest`) include the gendaylit and rtrace comparisons, marked `radiance` and skipped
|
|
244
|
+
without Radiance.
|
|
245
|
+
|
|
246
|
+
## Citation
|
|
247
|
+
|
|
248
|
+
If you use perezsky in published work, please cite the archived version on Zenodo (see
|
|
249
|
+
[CITATION.cff](https://github.com/WildSolar/PerezSky/blob/main/CITATION.cff); the DOI badge is added with the first release).
|
|
250
|
+
|
|
251
|
+
## License
|
|
252
|
+
|
|
253
|
+
MIT, see [LICENSE](https://github.com/WildSolar/PerezSky/blob/main/LICENSE).
|
|
254
|
+
|
|
255
|
+
## References
|
|
256
|
+
|
|
257
|
+
- Perez, R., Seals, R., Michalsky, J. (1993). All-weather model for sky luminance
|
|
258
|
+
distribution — preliminary configuration and validation. Solar Energy 50(3), 235–245.
|
|
259
|
+
- Perez, R., Ineichen, P., Seals, R., Michalsky, J., Stewart, R. (1990). Modeling daylight
|
|
260
|
+
availability and irradiance components from direct and global irradiance. Solar Energy 44(5),
|
|
261
|
+
271–289.
|
|
262
|
+
- Buie, D., Monger, A. G., Dey, C. J. (2003). Sunshape distributions for terrestrial solar
|
|
263
|
+
simulations. Solar Energy 74(2), 113–122.
|
|
264
|
+
- Kasten, F., Young, A. T. (1989). Revised optical air mass tables and approximation formula.
|
|
265
|
+
Applied Optics 28(22), 4735–4738.
|
|
266
|
+
- Spencer, J. W. (1971). Fourier series representation of the position of the sun. Search 2(5).
|