Skip to content

Commit 58ecbe7

Browse files
authored
Merge pull request #1 from dpohanlon/update_readme
Update readme
2 parents ee57fbe + 4dc60d4 commit 58ecbe7

6 files changed

Lines changed: 186 additions & 40 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3+
4+
name: Limao
5+
6+
on:
7+
push:
8+
branches: [ "main" ]
9+
tags: '*'
10+
pull_request:
11+
branches: [ "main" ]
12+
13+
jobs:
14+
test:
15+
16+
runs-on: ubuntu-latest
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
python-version: ["3.9"]
21+
22+
steps:
23+
- uses: actions/checkout@v3
24+
- name: Set up Python ${{ matrix.python-version }}
25+
uses: actions/setup-python@v3
26+
with:
27+
python-version: ${{ matrix.python-version }}
28+
- name: Install dependencies
29+
run: |
30+
python -m pip install --upgrade pip
31+
python -m pip install flake8 nose2
32+
python -m pip install .
33+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
34+
- name: Lint with flake8
35+
run: |
36+
# stop the build if there are Python syntax errors or undefined names
37+
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
38+
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
39+
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
40+
- name: Test with nose2
41+
run: |
42+
nose2 --with-coverage
43+
- name: Upload coverage reports to Codecov
44+
uses: codecov/codecov-action@v3
45+
46+
build:
47+
needs: [test]
48+
if: needs.test.result == 'success'
49+
runs-on: ubuntu-latest
50+
strategy:
51+
fail-fast: false
52+
matrix:
53+
python-version: ["3.9"]
54+
55+
steps:
56+
- uses: actions/checkout@v3
57+
- name: Set up Python ${{ matrix.python-version }}
58+
uses: actions/setup-python@v3
59+
with:
60+
python-version: ${{ matrix.python-version }}
61+
- name: Install dependencies
62+
run: |
63+
python -m pip install --upgrade pip
64+
python -m pip install poetry
65+
- name: Poetry build
66+
run: |
67+
poetry build
68+
# Save the build package as an artifact
69+
- uses: actions/upload-artifact@v3
70+
with:
71+
path: dist/*
72+
73+
publish:
74+
needs: [build]
75+
runs-on: ubuntu-latest
76+
steps:
77+
- uses: actions/download-artifact@v3
78+
with:
79+
# unpacks default artifact into dist/
80+
# if `name: artifact` is omitted, the action will create extra parent dir
81+
name: artifact
82+
path: dist
83+
- name: Publish to test PyPI
84+
if: ${{!startsWith(github.ref, 'refs/tags')}}
85+
uses: pypa/gh-action-pypi-publish@release/v1
86+
with:
87+
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
88+
repository-url: https://test.pypi.org/legacy/
89+
- name: Publish tagged version to PyPI
90+
if: startsWith(github.ref, 'refs/tags')
91+
uses: pypa/gh-action-pypi-publish@release/v1
92+
with:
93+
password: ${{ secrets.PYPI_API_TOKEN }}

README.md

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,53 @@ Limão calculates projected direct sunlight intensities over time for arbitrary
66

77
Primarily this depends on the the building orientation, the latitude, and the time of the year, but also on occluding obstacles. Limão incorporates time and location dependent sunlight intensity projections, with digital surface and terrain maps, to determine an estimated overall intensity as a function of time.
88

9-
# Usage
109

11-
Requires digital surface models (DSM) and digital terrain models (DTM) for the region of interest, in addition to the latitude and longitude. For the UK these are available from [DEFRA](https://www.data.gov.uk/dataset/f0db0249-f17b-4036-9e65-309148c97ce4/national-lidar-programme) ([direct link](https://environment.data.gov.uk/DefraDataDownload/?Mode=survey)), and are derived from satellite LIDAR measurements. Latitude and longitude can be obtained from Google Maps.
10+
# Applications
11+
12+
For illumination of a wall (for example, for photovoltaic panel placement), Limão provides predicted sunlight intensities on a user-defined vertical plane in real space:
13+
14+
<p align="center">
15+
<img width="600" height="229" src="assets/profile.png">
16+
</p>
17+
18+
Here the intensities are averaged over the year, and the variation is mostly due to occluding buildings. The intensities over time for a single point `(lat, lon, height)` can also be queried:
1219

13-
**Currently this assumes UK DSM/DTMs as the lat/lon is converted into the UK OS map coordinates.**
20+
<p align="center">
21+
<img width="400" height="300" src="assets/weekAvg.png">
22+
</p>
23+
24+
This is useful for comparing the intensity from different directions, and the produced plots indicate the maximum and minimum intensity during daylight hours.
1425

15-
At the moment this ignores occlusions within a configurable distance from the indicated location to avoid 'self' intersections, but this will probably be improved later.
26+
# Installation
27+
28+
Either from the PyPI release
1629

1730
```bash
31+
pip install limao
32+
```
1833

19-
usage: limao.py [-h] [-s FILENAMEDSM] [-t FILENAMEDTM] [-lat LAT] [-lon LON] [--size SIZE]
34+
or the bleeding edge via GitHub
2035

21-
optional arguments:
22-
-h, --help show this help message and exit
23-
-s FILENAMEDSM DSM input file (.tif).
24-
-t FILENAMEDTM DTM input file (.tif).
25-
-lat LAT Latitude.
26-
-lon LON Longitude.
27-
--size SIZE Region Size around location.
36+
```bash
37+
git clone git@github.com:dpohanlon/limao.git
38+
cd limao
39+
pip install .
40+
```
41+
42+
# Usage
43+
44+
Limão requires digital surface models (DSM) and digital terrain models (DTM) for the region of interest, in addition to the latitude and longitude. For the UK these are available from [DEFRA](https://www.data.gov.uk/dataset/f0db0249-f17b-4036-9e65-309148c97ce4/national-lidar-programme) ([direct link](https://environment.data.gov.uk/DefraDataDownload/?Mode=survey)), and are derived from satellite LIDAR measurements. Latitude and longitude can be obtained from Google Maps, and must correspond to a point on the DSM and DTMs.
45+
46+
**Currently this assumes UK DSM/DTMs, as the lat/lon is converted into UK Ordnance Survey map coordinates.**
47+
48+
Limão ships with a standalone executable and as a library - here we'll just use the command line interface. All use cases require the latitude, longitude, a DSM, and a DTM:
2849

50+
```bash
51+
limao --lat 52.198 --lon 0.135 -s TL45ne_LZ_DSM_2m.tif -t TL45ne_DTM_2m.tif
52+
```
53+
54+
By default this will just produce the intensity from the north and south on the point defined by the latitude and longitude coordinates. To produce the 2D projection, additionally pass the `--proj` argument, with optional horizontal and vertical extent of the surface in metres:
55+
56+
```bash
57+
--proj --horizontal 20 --vertical 8
2958
```

assets/profile.png

55.3 KB
Loading

assets/weekAvg.png

157 KB
Loading

limao/run_limao.py

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@
4242
from limao.limao import Limao
4343

4444

45-
def intensityProjection(fileNameDSM, fileNameDTM, latLon, size):
45+
def intensityProjection(fileNameDSM, fileNameDTM, latLon, size, horizontal, vertical):
4646

47-
nx = 20
48-
ny = 8
47+
nx = horizontal
48+
ny = vertical
4949

5050
intensities = np.zeros((nx, ny))
5151

@@ -105,30 +105,30 @@ def dailyAvgIntensity(fileNameDSM, fileNameDTM, latLon, size):
105105

106106
table = limao.yearlyIntensityTable()
107107

108-
plt.plot(table[table["altitude"] > 0]["azimuth"], ".")
109-
plt.plot(table[table["altitude"] < 0]["azimuth"], ".")
110-
plt.savefig("az.pdf")
111-
plt.clf()
112-
113-
plt.plot(table["altitude"], ".")
114-
plt.savefig("alt.pdf")
115-
plt.clf()
108+
# plt.plot(table[table["altitude"] > 0]["azimuth"], ".")
109+
# plt.plot(table[table["altitude"] < 0]["azimuth"], ".")
110+
# plt.savefig("az.pdf")
111+
# plt.clf()
112+
#
113+
# plt.plot(table["altitude"], ".")
114+
# plt.savefig("alt.pdf")
115+
# plt.clf()
116116

117117
isNorth, _, _ = limao.intensityOnElevation(table)
118118
table["isNorth"] = isNorth
119119

120-
plt.plot(table[table["isNorth"]]["azimuth"], ".")
121-
plt.savefig("north_az.pdf")
122-
plt.clf()
123-
124-
plt.plot(table[~table["isNorth"]]["intensity_passed"], alpha=0.5, label="South")
125-
plt.plot(table[table["isNorth"]]["intensity_passed"], alpha=0.5, label="North")
126-
127-
plt.xlabel("Hours from 1/1", fontsize=14)
128-
plt.ylabel("Direct sunlight intensity $(W/m^2)$", fontsize=14)
129-
plt.legend(loc=0, fontsize=14)
130-
plt.savefig("test.pdf")
131-
plt.clf()
120+
# plt.plot(table[table["isNorth"]]["azimuth"], ".")
121+
# plt.savefig("north_az.pdf")
122+
# plt.clf()
123+
#
124+
# plt.plot(table[~table["isNorth"]]["intensity_passed"], alpha=0.5, label="South")
125+
# plt.plot(table[table["isNorth"]]["intensity_passed"], alpha=0.5, label="North")
126+
#
127+
# plt.xlabel("Hours from 1/1", fontsize=14)
128+
# plt.ylabel("Direct sunlight intensity $(W/m^2)$", fontsize=14)
129+
# plt.legend(loc=0, fontsize=14)
130+
# plt.savefig("test.pdf")
131+
# plt.clf()
132132

133133
tableDayAvg = (
134134
table.groupby(["day", "isNorth"])
@@ -173,7 +173,7 @@ def dailyAvgIntensity(fileNameDSM, fileNameDTM, latLon, size):
173173
plt.xlabel("Day", fontsize=14)
174174
plt.ylabel("Direct sunlight intensity $(W/m^2)$", fontsize=14)
175175
plt.legend(loc=0, fontsize=14)
176-
plt.savefig("testDayAvg.pdf")
176+
plt.savefig("dayAvg.pdf")
177177
plt.clf()
178178

179179
plt.plot(
@@ -209,11 +209,11 @@ def dailyAvgIntensity(fileNameDSM, fileNameDTM, latLon, size):
209209
plt.xlabel("Week number", fontsize=14)
210210
plt.ylabel("Direct sunlight intensity $(W/m^2)$", fontsize=14)
211211
plt.legend(loc=0, fontsize=14)
212-
plt.savefig("testWeekAvg.pdf")
212+
plt.savefig("weekAvg.pdf", dpi = 300)
213+
plt.savefig("weekAvg.png", dpi = 300)
213214
plt.clf()
214215

215-
216-
if __name__ == "__main__":
216+
def run():
217217

218218
# I'd like an argument, please
219219
argParser = argparse.ArgumentParser()
@@ -250,16 +250,37 @@ def dailyAvgIntensity(fileNameDSM, fileNameDTM, latLon, size):
250250
help="Plot a spatial 2d projection map of intensity.",
251251
)
252252

253+
argParser.add_argument(
254+
"--vertical",
255+
type=int,
256+
dest="vertical",
257+
default=10,
258+
help="Vertical extent of the projection.",
259+
)
260+
261+
argParser.add_argument(
262+
"--horizontal",
263+
type=int,
264+
dest="horizontal",
265+
default=10,
266+
help="Horizontal extent of the projection.",
267+
)
268+
253269
args = argParser.parse_args()
254270

255271
if args.proj:
256272

257273
intensityProjection(
258-
args.fileNameDSM, args.fileNameDTM, (args.lat, args.lon), args.size
274+
args.fileNameDSM, args.fileNameDTM, (args.lat, args.lon), args.size, args.horizontal, args.vertical
259275
)
260276

261277
else:
262278

263279
dailyAvgIntensity(
264280
args.fileNameDSM, args.fileNameDTM, (args.lat, args.lon), args.size
265281
)
282+
283+
284+
if __name__ == "__main__":
285+
286+
run()

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ h5py = "^3.9.0"
2424
[build-system]
2525
requires = ["poetry-core"]
2626
build-backend = "poetry.core.masonry.api"
27+
28+
[tool.poetry.scripts]
29+
limao = "limao.run_limao:run"

0 commit comments

Comments
 (0)