Skip to content

Commit

Permalink
Merge pull request #1 from pooyad359/fixes
Browse files Browse the repository at this point in the history
Restructured the library
  • Loading branch information
pooyad359 authored Feb 21, 2021
2 parents 36851c4 + 9cb0fa7 commit ddabce6
Show file tree
Hide file tree
Showing 17 changed files with 1,046 additions and 154 deletions.
89 changes: 89 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# DotEnv configuration
.env

# Database
*.db
*.rdb

# Pycharm
.idea

# VS Code
.vscode/

# Spyder
.spyproject/

# Jupyter NB Checkpoints
.ipynb_checkpoints/

# exclude data from source control by default
/data/

# Mac OS-specific storage files
.DS_Store

# vim
*.swp
*.swo

# Mypy cache
.mypy_cache/
257 changes: 215 additions & 42 deletions Examples.ipynb

Large diffs are not rendered by default.

Binary file added Examples_files/Examples_14_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
MIT License
Copyright (c) 2018 YOUR NAME
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
86 changes: 85 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,85 @@
# SolarLib
# Solarlib


```python
from solarlib.location import Location
import datetime
import pytz
```

## Define a location


```python
latitude = -31.9505
longitude = 115.8605
timezone = 'Australia/Perth'
perth = Location(latitude,longitude,timezone)
```

## Sunrise
The output is a python datetime object.


```python
print(perth.sunrise('2020-06-27'))
```

2020-06-27 07:17:33.495057+08:00


## Sunset
The output is a python datetime object.


```python
print(perth.sunset('2020-06-27'))
```

2020-06-27 17:21:50.791503+08:00


## Day length
The output is a python timedelta object.


```python
print(perth.day_length('2020-06-27'))
```

10:04:17.296446


## Solar irradiance
The output is irradiance in $kW/m^2$.


```python
perth.solar_irradiance('2020-06-27 14:27:00')
```




0.7360521598862617



## Irradiance throughout a day



```python
import matplotlib.pyplot as plt
```


```python
output = perth.daily_irradiance('2020-06-27')
time, irradiance = list(zip(*output))
plt.plot(time,irradiance)
```

![png](Examples_files/Examples_14_1.png)


1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytz
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[metadata]
description-file = README.md
12 changes: 12 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from setuptools import find_packages, setup

setup(
name='solarlib',
packages=find_packages(),
version='0.1.0',
description='A library for calculating solar irradiance, sunrise, sunset, and more. ',
author='Pooya Darvehei',
url='https://github.com/pooyad359/solarlib',
license='MIT',
install_requires=['pytz']
)
1 change: 0 additions & 1 deletion solarlib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
from .solarlib import *

23 changes: 23 additions & 0 deletions solarlib/calendar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import datetime
import pytz

JULIAN_DAYS_INIT = 1721424.5
CENTURY21 = 2451545
CENTURY_DAYS = 36525

def time2seconds(time):
hour = time.hour
minute = time.minute
seconds = time.second
return hour * 3600 + minute * 60 + seconds


def julian_day(time):
utc = pytz.timezone('UTC')
utc_time = time.astimezone(utc)
time_of_day = time2seconds(utc_time)/3600/24
return JULIAN_DAYS_INIT + utc_time.toordinal() + time_of_day

def julian_century(time):
return (julian_day(time)-CENTURY21)/CENTURY_DAYS

14 changes: 14 additions & 0 deletions solarlib/error_handling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class ValueOutOfRange(Exception):
def __init__(self, name, rng, value):
self.message = f'{name} = {value} '
self.message += 'but is expected to be in {rng} range.'
super().__init__(self.message)


def type_check(variable, types_list):
checks = [isinstance(variable, o) for o in types_list]
return any(checks)


def raise_type_error(variable_name, input_type):
raise TypeError(f'Unrecognised type {input_type} for {variable_name}')
140 changes: 140 additions & 0 deletions solarlib/location.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
from solarlib.error_handling import (
ValueOutOfRange,
raise_type_error,
type_check)
from solarlib.solar import (
sunrise,
sunset,
estimated_irradiance,
solar_noon
)
import pytz
import datetime


class Location:
def __init__(self, latitude, longitude, timezone=None):
self.set_timezone(timezone)
self.set_latitude(latitude)
self.set_longitude(longitude)

def set_latitude(self, latitude):
if not type_check(latitude, [int, float]):
raise_type_error('latitude', type(latitude))
elif -90 <= latitude <= 90:
self.__latitude = latitude
else:
raise ValueError(
'latitude must be between -90 and 90 degrees ' +
f'but recieved {latitude}'
)

def set_longitude(self, longitude):
if not type_check(longitude, [int, float]):
raise_type_error('longitude', type(longitude))
elif -180 <= longitude <= 180:
self.__longitude = longitude
else:
raise ValueOutOfRange(
'longitude must be between -180 and 180 ' +
f'degrees but recieved {longitude}'
)

def set_timezone(self, timezone):
if timezone is None:
self.__timezone = pytz.timezone('UTC')
elif isinstance(timezone, str):
self.__timezone = pytz.timezone(timezone)
elif isinstance(timezone, float) or isinstance(timezone, int):
timezone_hours = round(timezone*2)/2
timedelta = datetime.timedelta(hours=timezone_hours)
self.__timezone = datetime.timezone(timedelta)
else:
raise_type_error('timezone', type(timezone))

@property
def latitude(self):
return self.__latitude

@property
def longitude(self):
return self.__longitude

@property
def timezone(self):
return self.__timezone

def __repr__(self):
lat = self.__latitude
lon = self.__longitude
tz = self.__timezone
output = f'''Location(latitude={lat},
longitude={lon},
timezone={str(tz)})'''
return output.replace(' '*4, '').replace('\n', '')

def __str__(self):
return repr(self)

def sunrise(self, date, fmt='%Y-%m-%d'):
date = self.__parse_date(date, fmt='%Y-%m-%d')
lat = self.latitude
lon = self.longitude
base = sunrise(date, lat, lon)
return sunrise(base, lat, lon)

def sunset(self, date, fmt='%Y-%m-%d'):
date = self.__parse_date(date, fmt=fmt)
lat = self.latitude
lon = self.longitude
base = sunset(date, lat, lon)
return sunset(base, lat, lon)

def solar_irradiance(self, time, fmt='%Y-%m-%d %H:%M:%S'):
time = self.__parse_time(time, fmt=fmt)
lat = self.latitude
lon = self.longitude
return estimated_irradiance(time, lat, lon)

def daily_irradiance(self, date, fmt='%Y-%m-%d', freq_min=30):
date = self.__parse_date(date, fmt=fmt)
delta = datetime.timedelta(minutes=freq_min)
n = 1440//freq_min + 1
output = [
(
date+i*delta,
self.solar_irradiance(date+i*delta)
) for i in range(n)
]
return output

def day_length(self, date, fmt='%Y-%m-%d'):
date = self.__parse_date(date, fmt=fmt)
rise_time = self.sunrise(date, fmt)
set_time = self.sunset(date, fmt)
return set_time-rise_time

def solar_noon(self, date, fmt='%Y-%m-%d'):
date = self.__parse_date(date, fmt=fmt)
lon = self.longitude
base = solar_noon(date, lon)
return solar_noon(base, lon)

def __parse_date(self, date, fmt='%Y-%m-%d'):
if isinstance(date, str):
return datetime.datetime.strptime(date, fmt)
elif isinstance(date, datetime.datetime):
return date
elif isinstance(date, datetime.date):
time = datetime.time()
return datetime.datetime.combine(date, time)
else:
raise_type_error('date', datetime.datetime)

def __parse_time(self, date, fmt='%Y-%m-%d %H:%M:%S'):
if isinstance(date, str):
return datetime.datetime.strptime(date, fmt)
elif isinstance(date, datetime.datetime):
return date
else:
raise_type_error('date', datetime.datetime)
Loading

0 comments on commit ddabce6

Please sign in to comment.