solar_geometry_calculation 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +30 -0
- data/Rakefile +8 -0
- data/lib/solar_geometry_calculation.rb +9 -0
- data/lib/solar_geometry_calculation/calculation_helper.rb +45 -0
- data/lib/solar_geometry_calculation/solar_position_calculation.rb +116 -0
- data/lib/solar_geometry_calculation/solar_time.rb +206 -0
- data/lib/solar_geometry_calculation/version.rb +3 -0
- data/solar_geometry_calculation.gemspec +26 -0
- data/spec/solar_geometry_calculation/calculation_helper_spec.rb +40 -0
- data/spec/solar_geometry_calculation/solar_position_calculation_spec.rb +176 -0
- data/spec/solar_geometry_calculation/solar_time_spec.rb +118 -0
- data/spec/spec_helper.rb +2 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 900bb37f7b3f5cdbe8dc83bd45585cc66ff45f02
|
4
|
+
data.tar.gz: d1704fa9695996338eb4d0d01f95f8deb47dbcba
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1dc72c21d597a19454cbc2a83197deda1eb428775dfc456b078bd2d138e8f206239fa218298fc0c2e78d6a4b9fe5d41fabb9ea45599411d681e690e40d8dd963
|
7
|
+
data.tar.gz: 9a2faaef30525a75e90696d0c7b9675a75cec9c5ad411912d646f8967a3d5d0500409e0ddafcdcb2f4bebaaec968659fb77bc1ea58c98015141c97fe45720d64
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
solar_geometry_calculation
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.2
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010-2014 Tadatoshi Takahashi
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Solar Geometry Calculation
|
2
|
+
|
3
|
+
Calculate solar geometry, such as height or azimuth of the Sun for the purpose of obtaining information for solar panel installation.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add to your Gemfile and run the `bundle` command to install it.
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem "solar_geometry_calculation"
|
12
|
+
```
|
13
|
+
|
14
|
+
**Requires Ruby 2.0.0 or later.**
|
15
|
+
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
Instantiate SolarPositionCalculation class.
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
solar_position_calculation = SolarPositionCalculation.new(latitude: "45.5")
|
23
|
+
```
|
24
|
+
|
25
|
+
|
26
|
+
## Development
|
27
|
+
|
28
|
+
Questions or problems? Please post them on the [issue tracker](https://github.com/tadatoshi/solar_geometry_calculation/issues). You can contribute changes by forking the project and submitting a pull request. You can ensure the tests passing by running `bundle` and `rake`.
|
29
|
+
|
30
|
+
This gem is created by Tadatoshi Takahashi and is under the MIT License.
|
data/Rakefile
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
|
3
|
+
module SolarGeometryCalculation
|
4
|
+
|
5
|
+
autoload :SolarPositionCalculation, 'solar_geometry_calculation/solar_position_calculation'
|
6
|
+
autoload :SolarTime, 'solar_geometry_calculation/solar_time'
|
7
|
+
autoload :CalculationHelper, 'solar_geometry_calculation/calculation_helper'
|
8
|
+
|
9
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module SolarGeometryCalculation
|
2
|
+
|
3
|
+
module CalculationHelper
|
4
|
+
|
5
|
+
def day_of_the_year(year, month, day, hour = 0, minute = 0)
|
6
|
+
if hour == 0 && minute == 0
|
7
|
+
BigDecimal((Date.new(year.to_i, month.to_i, day.to_i).yday).to_s)
|
8
|
+
else
|
9
|
+
day_of_the_year_one_day_before = BigDecimal((Date.new(year.to_i, month.to_i, day.to_i).yday).to_s) - 1
|
10
|
+
decimal_hour_minute = BigDecimal(hour.to_s) + BigDecimal(minute.to_s) / 60
|
11
|
+
(day_of_the_year_one_day_before * 24 + decimal_hour_minute + 12) / 24
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def degree_to_radian(degree)
|
16
|
+
degree * BigDecimal(Math::PI.to_s) / 180
|
17
|
+
end
|
18
|
+
|
19
|
+
def radian_to_degree(radian)
|
20
|
+
radian * 180 / BigDecimal(Math::PI.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
def big_decimal_sin(angle_in_radian)
|
24
|
+
BigDecimal(Math.sin(angle_in_radian).to_s)
|
25
|
+
end
|
26
|
+
|
27
|
+
def big_decimal_cos(angle_in_radian)
|
28
|
+
BigDecimal(Math.cos(angle_in_radian).to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def big_decimal_tan(angle_in_radian)
|
32
|
+
BigDecimal(Math.tan(angle_in_radian).to_s)
|
33
|
+
end
|
34
|
+
|
35
|
+
def big_decimal_asin(angle_in_radian)
|
36
|
+
BigDecimal(Math.asin(angle_in_radian).to_s)
|
37
|
+
end
|
38
|
+
|
39
|
+
def big_decimal_acos(angle_in_radian)
|
40
|
+
BigDecimal(Math.acos(angle_in_radian).to_s)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
|
3
|
+
module SolarGeometryCalculation
|
4
|
+
|
5
|
+
class SolarPositionCalculation
|
6
|
+
include CalculationHelper
|
7
|
+
|
8
|
+
attr_accessor :id, :latitude, :meridian, :longitude, :year, :month, :day, :hour, :minute, :surface_inclination, :surface_azimuth, :solar_time
|
9
|
+
attr_writer :timezone_identifier
|
10
|
+
|
11
|
+
def initialize(attributes = {})
|
12
|
+
attributes.each { |attribute_name, attribute_value| self.send("#{attribute_name}=".to_sym, attribute_value) }
|
13
|
+
get_solar_time
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def declination(with_hour_and_minutes: true)
|
18
|
+
day_of_the_year = with_hour_and_minutes ? day_of_the_year(@solar_time.year, @solar_time.month, @solar_time.day, @solar_time.hour, @solar_time.minute) : day_of_the_year(@solar_time.year, @solar_time.month, @solar_time.day)
|
19
|
+
radian = degree_to_radian(BigDecimal("360") / BigDecimal("365") * (day_of_the_year + 284))
|
20
|
+
(23.45 * big_decimal_sin(radian)).round(2)
|
21
|
+
end
|
22
|
+
|
23
|
+
def hour_angle
|
24
|
+
if @solar_time.blank?
|
25
|
+
hour_for_calculation = BigDecimal(@hour.to_s)
|
26
|
+
minute_for_calculation = BigDecimal(@minute.to_s)
|
27
|
+
else
|
28
|
+
hour_for_calculation = @solar_time.hour
|
29
|
+
minute_for_calculation = @solar_time.minute
|
30
|
+
end
|
31
|
+
|
32
|
+
hour_with_minutes_in_digit = hour_for_calculation + minute_for_calculation.div(60, 2)
|
33
|
+
|
34
|
+
((hour_with_minutes_in_digit - 12) * 15).round(2)
|
35
|
+
end
|
36
|
+
|
37
|
+
def solar_elevation
|
38
|
+
latitude_in_radian = degree_to_radian(BigDecimal(self.latitude.to_s))
|
39
|
+
declination_in_radian = degree_to_radian(self.declination)
|
40
|
+
hour_angle_in_radian = degree_to_radian(self.hour_angle)
|
41
|
+
|
42
|
+
sine_solar_elevation = big_decimal_sin(latitude_in_radian) * big_decimal_sin(declination_in_radian) +
|
43
|
+
big_decimal_cos(latitude_in_radian) * big_decimal_cos(declination_in_radian) * big_decimal_cos(hour_angle_in_radian)
|
44
|
+
radian_to_degree(big_decimal_asin(sine_solar_elevation)).round(2)
|
45
|
+
end
|
46
|
+
|
47
|
+
def solar_azimuth
|
48
|
+
declination_in_radian = degree_to_radian(self.declination)
|
49
|
+
hour_angle_in_radian = degree_to_radian(self.hour_angle)
|
50
|
+
solar_elevation_in_radian = degree_to_radian(self.solar_elevation)
|
51
|
+
|
52
|
+
sine_solar_azimuth = big_decimal_cos(declination_in_radian) * big_decimal_sin(hour_angle_in_radian) / big_decimal_cos(solar_elevation_in_radian)
|
53
|
+
radian_to_degree(big_decimal_asin(sine_solar_azimuth)).round(2)
|
54
|
+
end
|
55
|
+
|
56
|
+
def sunrise
|
57
|
+
sunrise_time_with_munutes_in_digit = BigDecimal((12 - (sunrise_sunset_base_angle / 15)).to_s)
|
58
|
+
sunrise_sunset_time(sunrise_time_with_munutes_in_digit)
|
59
|
+
end
|
60
|
+
|
61
|
+
def sunset
|
62
|
+
sunset_time_with_munutes_in_digit = BigDecimal((12 + (sunrise_sunset_base_angle / 15)).to_s)
|
63
|
+
sunrise_sunset_time(sunset_time_with_munutes_in_digit)
|
64
|
+
end
|
65
|
+
|
66
|
+
def angle_of_incidence
|
67
|
+
latitude_in_radian = degree_to_radian(BigDecimal(self.latitude.to_s))
|
68
|
+
declination_in_radian = degree_to_radian(self.declination)
|
69
|
+
hour_angle_in_radian = degree_to_radian(self.hour_angle)
|
70
|
+
surface_inclination_in_radian = degree_to_radian(BigDecimal(@surface_inclination.to_s))
|
71
|
+
surface_azimuth_in_radian = degree_to_radian(BigDecimal(@surface_azimuth.to_s))
|
72
|
+
|
73
|
+
first_value = big_decimal_sin(declination_in_radian) * big_decimal_sin(latitude_in_radian) * big_decimal_cos(surface_inclination_in_radian)
|
74
|
+
second_value = big_decimal_sin(declination_in_radian) * big_decimal_cos(latitude_in_radian) * big_decimal_sin(surface_inclination_in_radian) * big_decimal_cos(surface_azimuth_in_radian)
|
75
|
+
third_value = big_decimal_cos(declination_in_radian) * big_decimal_cos(latitude_in_radian) * big_decimal_cos(surface_inclination_in_radian) * big_decimal_cos(hour_angle_in_radian)
|
76
|
+
fourth_value = big_decimal_cos(declination_in_radian) * big_decimal_sin(latitude_in_radian) * big_decimal_sin(surface_inclination_in_radian) * big_decimal_cos(surface_azimuth_in_radian) * big_decimal_cos(hour_angle_in_radian)
|
77
|
+
fifth_value = big_decimal_cos(declination_in_radian) * big_decimal_sin(surface_inclination_in_radian) * big_decimal_sin(surface_azimuth_in_radian) * big_decimal_sin(hour_angle_in_radian)
|
78
|
+
cosine_of_angle_of_incidence = first_value - second_value + third_value + fourth_value + fifth_value
|
79
|
+
|
80
|
+
radian_to_degree(big_decimal_acos(cosine_of_angle_of_incidence)).round(2)
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
def get_solar_time
|
85
|
+
if @year.present? && @month.present? && @day.present?
|
86
|
+
if @address.present? && @place.present?
|
87
|
+
@solar_time = SolarTime.create_by_standard_time(BigDecimal(@year.to_s), BigDecimal(@month.to_s), BigDecimal(@day.to_s), BigDecimal(@hour.to_s), BigDecimal(@minute.to_s), @place.meridian, @place.longitude, @place.timezone_identifier)
|
88
|
+
elsif @meridian.present? && @longitude.present? && @timezone_identifier.present?
|
89
|
+
@solar_time = SolarTime.create_by_standard_time(BigDecimal(@year.to_s), BigDecimal(@month.to_s), BigDecimal(@day.to_s), BigDecimal(@hour.to_s), BigDecimal(@minute.to_s), @meridian, @longitude, @timezone_identifier)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def sunrise_sunset_base_angle
|
95
|
+
latitude_in_radian = degree_to_radian(BigDecimal(self.latitude.to_s))
|
96
|
+
declination_in_radian = degree_to_radian(self.declination(with_hour_and_minutes: false))
|
97
|
+
|
98
|
+
sunrise_sunset_base_angle_in_radian = big_decimal_acos(-(big_decimal_tan(latitude_in_radian) * big_decimal_tan(declination_in_radian)))
|
99
|
+
radian_to_degree(sunrise_sunset_base_angle_in_radian)
|
100
|
+
end
|
101
|
+
|
102
|
+
def sunrise_sunset_time(sunrise_or_sunset_time_with_munute_in_digit)
|
103
|
+
sunrise_or_sunset_hour, sunrise_or_sunset_minute_in_10_base = sunrise_or_sunset_time_with_munute_in_digit.divmod(1)
|
104
|
+
sunrise_or_sunset_solar_time = SolarTime.create_by_solar_time_values(@solar_time.year, @solar_time.month, @solar_time.day, sunrise_or_sunset_hour, (sunrise_or_sunset_minute_in_10_base * 60).round, @meridian, @longitude, @solar_time.timezone_identifier)
|
105
|
+
"#{sunrise_or_sunset_solar_time.standard_time_hour.to_i}:#{self.class.format_minute(sunrise_or_sunset_solar_time.standard_time_minute.to_i)}"
|
106
|
+
end
|
107
|
+
|
108
|
+
class << self
|
109
|
+
def format_minute(minute)
|
110
|
+
minute.to_s.length == 1 ? "0#{minute.to_s}" : minute.to_s
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'tzinfo'
|
2
|
+
require 'active_support/core_ext/time/calculations'
|
3
|
+
require 'active_support/core_ext/date/calculations'
|
4
|
+
|
5
|
+
module SolarGeometryCalculation
|
6
|
+
|
7
|
+
class SolarTime
|
8
|
+
|
9
|
+
attr_accessor :year, :month, :day, :hour, :minute, :meridian, :longitude, :timezone_identifier
|
10
|
+
attr_writer :standard_time
|
11
|
+
|
12
|
+
# Methods for standard_time provided because the method to get minute for Time is min and that naming is not consistent with minute method for this class:
|
13
|
+
def standard_time_year
|
14
|
+
@standard_time.year
|
15
|
+
end
|
16
|
+
|
17
|
+
def standard_time_month
|
18
|
+
@standard_time.month
|
19
|
+
end
|
20
|
+
|
21
|
+
def standard_time_day
|
22
|
+
@standard_time.day
|
23
|
+
end
|
24
|
+
|
25
|
+
def standard_time_hour
|
26
|
+
@standard_time.hour
|
27
|
+
end
|
28
|
+
|
29
|
+
def standard_time_minute
|
30
|
+
@standard_time.min
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
|
35
|
+
# Moved from app/models/factories/solar_time_factory.rb because "rails server" in development environment cannot find this module.
|
36
|
+
# -- At least after I tried rack-mini-profiler. Even after I commented it out in Gemfile, the problem still persists.
|
37
|
+
def create_by_standard_time(standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute, meridian, longitude, timezone_identifier)
|
38
|
+
solar_time = SolarTime.new
|
39
|
+
|
40
|
+
# Uses Time because DateTime doesn't take daylight savings time even with the one from Rails:
|
41
|
+
solar_time.standard_time = Time.new(standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute)
|
42
|
+
|
43
|
+
solar_time.meridian = meridian
|
44
|
+
solar_time.longitude = longitude
|
45
|
+
solar_time.timezone_identifier = timezone_identifier
|
46
|
+
|
47
|
+
standard_time_year_without_offset, standard_time_month_without_offset, standard_time_day_without_offset, standard_time_hour_without_offset, standard_time_minute_without_offset =
|
48
|
+
SolarTime.standard_time_without_daylight_savings_time_offset(standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute, meridian, longitude, timezone_identifier)
|
49
|
+
|
50
|
+
solar_time.year, solar_time.month, solar_time.day, solar_time.hour, solar_time.minute =
|
51
|
+
SolarTime.standard_time_without_daylight_savings_time_offset_to_solar_time(standard_time_year_without_offset, standard_time_month_without_offset, standard_time_day_without_offset, standard_time_hour_without_offset, standard_time_minute_without_offset, meridian, longitude, timezone_identifier)
|
52
|
+
|
53
|
+
solar_time
|
54
|
+
end
|
55
|
+
|
56
|
+
# Moved from app/models/factories/solar_time_factory.rb because "rails server" in development environment cannot find this module.
|
57
|
+
# -- At least after I tried rack-mini-profiler. Even after I commented it out in Gemfile, the problem still persists.
|
58
|
+
def create_by_solar_time_values(solar_time_year, solar_time_month, solar_time_day, solar_time_hour, solar_time_minute, meridian, longitude, timezone_identifier)
|
59
|
+
solar_time = SolarTime.new
|
60
|
+
solar_time.year = solar_time_year
|
61
|
+
solar_time.month = solar_time_month
|
62
|
+
solar_time.day = solar_time_day
|
63
|
+
solar_time.hour = solar_time_hour
|
64
|
+
solar_time.minute = solar_time_minute
|
65
|
+
solar_time.meridian = meridian
|
66
|
+
solar_time.longitude = longitude
|
67
|
+
solar_time.timezone_identifier = timezone_identifier
|
68
|
+
|
69
|
+
standard_time_year_without_offset, standard_time_month_without_offset, standard_time_day_without_offset, standard_time_hour_without_offset, standard_time_minute_without_offset =
|
70
|
+
SolarTime.solar_time_to_standard_time_without_daylight_savings_time_offset(solar_time.year, solar_time.month, solar_time.day, solar_time.hour, solar_time.minute, meridian, longitude, timezone_identifier)
|
71
|
+
|
72
|
+
standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute =
|
73
|
+
SolarTime.standard_time_with_daylight_savings_time_offset(standard_time_year_without_offset, standard_time_month_without_offset, standard_time_day_without_offset, standard_time_hour_without_offset, standard_time_minute_without_offset, meridian, longitude, timezone_identifier)
|
74
|
+
|
75
|
+
# Uses Time because DateTime doesn't take daylight savings time even with the one from Rails:
|
76
|
+
solar_time.standard_time = Time.new(standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute)
|
77
|
+
|
78
|
+
solar_time
|
79
|
+
end
|
80
|
+
|
81
|
+
def standard_time_without_daylight_savings_time_offset(standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute, meridian, longitude, timezone_identifier)
|
82
|
+
NegativeDaylightSavingsTimeConverter.new.convert(standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute, meridian, longitude, timezone_identifier)
|
83
|
+
end
|
84
|
+
|
85
|
+
def standard_time_with_daylight_savings_time_offset(standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute, meridian, longitude, timezone_identifier)
|
86
|
+
PositiveDaylightSavingsTimeConverter.new.convert(standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute, meridian, longitude, timezone_identifier)
|
87
|
+
end
|
88
|
+
|
89
|
+
def standard_time_without_daylight_savings_time_offset_to_solar_time(standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute, meridian, longitude, timezone_identifier)
|
90
|
+
ToSolarTimeConverter.new.convert(standard_time_year, standard_time_month, standard_time_day, standard_time_hour, standard_time_minute, meridian, longitude, timezone_identifier)
|
91
|
+
end
|
92
|
+
|
93
|
+
def solar_time_to_standard_time_without_daylight_savings_time_offset(solar_time_year, solar_time_month, solar_time_day, solar_time_hour, solar_time_minute, meridian, longitude, timezone_identifier)
|
94
|
+
FromSolarTimeConverter.new.convert(solar_time_year, solar_time_month, solar_time_day, solar_time_hour, solar_time_minute, meridian, longitude, timezone_identifier)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
module TimeConverter
|
102
|
+
|
103
|
+
def convert(year, month, day, hour, minute, meridian, longitude, timezone_identifier)
|
104
|
+
|
105
|
+
# Creating Time object as UTC since Time.local gets Time object in machine's timezone.
|
106
|
+
time = Time.utc(year, month, day, hour, minute)
|
107
|
+
|
108
|
+
time = convert_by_offset(time, meridian, longitude, timezone_identifier)
|
109
|
+
|
110
|
+
[BigDecimal(time.year.to_s), BigDecimal(time.month.to_s), BigDecimal(time.day.to_s), BigDecimal(time.hour.to_s), BigDecimal(time.min.to_s)]
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
def convert_by_offset(time, meridian, longitude, timezone_identifier)
|
116
|
+
raise "must be implemented by a class"
|
117
|
+
end
|
118
|
+
|
119
|
+
def target_time(time, offset_in_seconds)
|
120
|
+
raise "must be implemented by a class"
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
module DaylightSavingsTimeConverter
|
126
|
+
include TimeConverter
|
127
|
+
|
128
|
+
private
|
129
|
+
def convert_by_offset(time, meridian, longitude, timezone_identifier)
|
130
|
+
timezone = TZInfo::Timezone.get(timezone_identifier)
|
131
|
+
timezone_period = timezone.period_for_local(time, true)
|
132
|
+
|
133
|
+
if timezone_period.dst?
|
134
|
+
time = target_time(time, timezone_period.std_offset)
|
135
|
+
end
|
136
|
+
|
137
|
+
time
|
138
|
+
end
|
139
|
+
|
140
|
+
def target_time(time, offset_in_seconds)
|
141
|
+
raise "must be implemented by a class"
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
module SolarTimeConverter
|
147
|
+
include TimeConverter
|
148
|
+
include SolarGeometryCalculation::CalculationHelper
|
149
|
+
|
150
|
+
private
|
151
|
+
def convert_by_offset(time, meridian, longitude, timezone_identifier)
|
152
|
+
minutes_difference = minutes_difference(time.year, time.month, time.day, meridian, longitude)
|
153
|
+
time = target_time(time, minutes_difference * 60)
|
154
|
+
end
|
155
|
+
|
156
|
+
def target_time(time, offset_in_seconds)
|
157
|
+
raise "must be implemented by a class"
|
158
|
+
end
|
159
|
+
|
160
|
+
def minutes_difference(year, month, day, meridian, longitude)
|
161
|
+
-(4 * (BigDecimal(meridian.to_s) - BigDecimal(longitude.to_s))) + equation_of_time(year, month, day).round
|
162
|
+
end
|
163
|
+
|
164
|
+
def equation_of_time(year, month, day)
|
165
|
+
b_in_radian = degree_to_radian((day_of_the_year(year, month, day) - 1) * BigDecimal("360") / BigDecimal("365"))
|
166
|
+
|
167
|
+
BigDecimal("229.2") * (BigDecimal("0.000075") + BigDecimal("0.001868") * big_decimal_cos(b_in_radian) - BigDecimal("0.032077") * big_decimal_sin(b_in_radian) - BigDecimal("0.014615") * big_decimal_cos(2 * b_in_radian) - BigDecimal("0.04089") * big_decimal_sin(2 * b_in_radian))
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
module OffsetAdvanceConverter
|
173
|
+
private
|
174
|
+
def target_time(time, offset_in_seconds)
|
175
|
+
time.advance(seconds: offset_in_seconds)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
module OffsetSubtractionConverter
|
180
|
+
private
|
181
|
+
def target_time(time, offset_in_seconds)
|
182
|
+
time.ago(offset_in_seconds)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class NegativeDaylightSavingsTimeConverter
|
187
|
+
include DaylightSavingsTimeConverter
|
188
|
+
include OffsetSubtractionConverter
|
189
|
+
end
|
190
|
+
|
191
|
+
class PositiveDaylightSavingsTimeConverter
|
192
|
+
include DaylightSavingsTimeConverter
|
193
|
+
include OffsetAdvanceConverter
|
194
|
+
end
|
195
|
+
|
196
|
+
class ToSolarTimeConverter
|
197
|
+
include SolarTimeConverter
|
198
|
+
include OffsetAdvanceConverter
|
199
|
+
end
|
200
|
+
|
201
|
+
class FromSolarTimeConverter
|
202
|
+
include SolarTimeConverter
|
203
|
+
include OffsetSubtractionConverter
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "solar_geometry_calculation/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "solar_geometry_calculation"
|
7
|
+
s.version = SolarGeometryCalculation::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Tadatoshi Takahashi"]
|
10
|
+
s.email = ["tadatoshi@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/tadatoshi/solar_geometry_calculation"
|
12
|
+
s.summary = %q{Performs calculation for solar geometry}
|
13
|
+
s.description = %q{Mathematical part of obtaining solar geometry information}
|
14
|
+
|
15
|
+
s.rubyforge_project = "solar_geometry_calculation"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'tzinfo'
|
23
|
+
s.add_dependency 'activesupport', ">= 4.1.1"
|
24
|
+
|
25
|
+
s.add_development_dependency "rspec"
|
26
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SolarGeometryCalculation::CalculationHelper do
|
4
|
+
|
5
|
+
class CalculationHelperExtender; extend SolarGeometryCalculation::CalculationHelper; end
|
6
|
+
|
7
|
+
context "Day of the year" do
|
8
|
+
|
9
|
+
it "should calculate the day of the year" do
|
10
|
+
|
11
|
+
CalculationHelperExtender.day_of_the_year(2012, 2, 19).should == 50
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should calculate the day of the year taking into account of the time in the day" do
|
16
|
+
|
17
|
+
CalculationHelperExtender.day_of_the_year(2012, 2, 19, 6, 50).should be_within(0.01).of(49.78)
|
18
|
+
CalculationHelperExtender.day_of_the_year(2012, 2, 19, 17, 10).should be_within(0.01).of(50.22)
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
context "Radian degree" do
|
25
|
+
|
26
|
+
it "should convert a degree to Radian because Math.sin expects Radian" do
|
27
|
+
|
28
|
+
CalculationHelperExtender.degree_to_radian(1).should be_within(0.0001).of(0.0175)
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should convert radian to degree" do
|
33
|
+
|
34
|
+
CalculationHelperExtender.radian_to_degree(1).should be_within(0.0001).of(57.2958)
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SolarGeometryCalculation::SolarPositionCalculation do
|
4
|
+
|
5
|
+
context "declination" do
|
6
|
+
|
7
|
+
it "should calculate declination" do
|
8
|
+
|
9
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.5", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 9, :day => 21, :hour => 12, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
10
|
+
solar_position_calculation_1.declination.should == -0.19
|
11
|
+
|
12
|
+
solar_position_calculation_2 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.5", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 1, :day => 21, :hour => 12, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
13
|
+
solar_position_calculation_2.declination.should == -20.14
|
14
|
+
|
15
|
+
solar_position_calculation_3 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.5", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 7, :day => 24, :hour => 12, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
16
|
+
solar_position_calculation_3.declination.should == 19.83
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
context "(solar energy and applications course - homework 2)" do
|
21
|
+
|
22
|
+
it "should calculate declination with latitude 45 degrees 28 minutes" do
|
23
|
+
|
24
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.47", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2012, :month => 2, :day => 19, :hour => 12, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
25
|
+
solar_position_calculation_1.declination.should be_within(0.1).of(-11.95)
|
26
|
+
|
27
|
+
# At sunrise 6:50 (6.83h):
|
28
|
+
solar_position_calculation_2 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.47", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2012, :month => 2, :day => 19, :hour => 6, :minute => 50, :surface_inclination => "0", :surface_azimuth => "0")
|
29
|
+
solar_position_calculation_2.declination.should be_within(0.1).of(-12.02)
|
30
|
+
|
31
|
+
# At sunset 17:10 (17.17h):
|
32
|
+
solar_position_calculation_3 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.47", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 2, :day => 19, :hour => 17, :minute => 10, :surface_inclination => "0", :surface_azimuth => "0")
|
33
|
+
solar_position_calculation_3.declination.should be_within(0.1).of(-11.87)
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
context "hour angle" do
|
42
|
+
|
43
|
+
it "should calculate hour angle" do
|
44
|
+
|
45
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.5", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 9, :day => 21, :hour => 10, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
46
|
+
solar_position_calculation_1.hour_angle.should be_within(0.1).of(-42.03)
|
47
|
+
|
48
|
+
solar_position_calculation_2 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.5", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 1, :day => 21, :hour => 12, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
49
|
+
solar_position_calculation_2.hour_angle.should be_within(0.15).of(-1.40)
|
50
|
+
|
51
|
+
solar_position_calculation_3 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.5", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 7, :day => 24, :hour => 13, :minute => 15, :surface_inclination => "0", :surface_azimuth => "0")
|
52
|
+
solar_position_calculation_3.hour_angle.should be_within(0.1).of(3.37)
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
context "height of the sun" do
|
59
|
+
|
60
|
+
it "should calculate solar elevation" do
|
61
|
+
|
62
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.5", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 9, :day => 21, :hour => 12, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
63
|
+
solar_position_calculation_1.solar_elevation.should be_within(0.1).of(43.09)
|
64
|
+
|
65
|
+
solar_position_calculation_2 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.5", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 1, :day => 21, :hour => 12, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
66
|
+
solar_position_calculation_2.solar_elevation.should == 24.35
|
67
|
+
|
68
|
+
solar_position_calculation_3 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.5", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 7, :day => 24, :hour => 12, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
69
|
+
solar_position_calculation_3.solar_elevation.should be_within(0.1).of(61.37)
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
context "Solar azimuth" do
|
76
|
+
|
77
|
+
it "should calculate solar azimuth" do
|
78
|
+
|
79
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.46", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 9, :day => 21, :hour => 10, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
80
|
+
solar_position_calculation_1.solar_azimuth.should be_within(0.1).of(-51.58)
|
81
|
+
|
82
|
+
solar_position_calculation_2 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.46", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 1, :day => 21, :hour => 10, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
83
|
+
solar_position_calculation_2.solar_azimuth.should be_within(0.1).of(-31.03)
|
84
|
+
|
85
|
+
solar_position_calculation_3 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.46", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 7, :day => 24, :hour => 10, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
86
|
+
solar_position_calculation_3.solar_azimuth.should be_within(0.1).of(-70.83)
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
context "Sunrise" do
|
93
|
+
|
94
|
+
it "should calculate sunrise" do
|
95
|
+
|
96
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.46", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 9, :day => 21, :hour => 10, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
97
|
+
solar_position_calculation_1.sunrise.should == "6:49"
|
98
|
+
|
99
|
+
solar_position_calculation_2 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.46", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 1, :day => 21, :hour => 10, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
100
|
+
solar_position_calculation_2.sunrise.should == "7:34"
|
101
|
+
|
102
|
+
solar_position_calculation_3 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.46", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 7, :day => 24, :hour => 10, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
103
|
+
solar_position_calculation_3.sunrise.should == "5:36"
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should calculate the same sunrise time throughout the same day" do
|
108
|
+
|
109
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.46", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 9, :day => 21, :hour => 3, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
110
|
+
solar_position_calculation_1.sunrise.should == "6:49"
|
111
|
+
|
112
|
+
solar_position_calculation_2 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.46", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 9, :day => 21, :hour => 21, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
113
|
+
solar_position_calculation_2.sunrise.should == "6:49"
|
114
|
+
|
115
|
+
solar_position_calculation_1.sunrise.should == solar_position_calculation_2.sunrise
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
context "(solar energy and applications course - homework 2)" do
|
120
|
+
|
121
|
+
it "should calculate sunrise with latitude 45 degrees 28 minutes" do
|
122
|
+
|
123
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.47", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2012, :month => 2, :day => 19, :hour => 12, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
124
|
+
solar_position_calculation_1.sunrise.should == "6:59"
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
context "Sunset" do
|
133
|
+
|
134
|
+
it "should calculate the same sunset time throughout the same day" do
|
135
|
+
|
136
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.47", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2012, :month => 2, :day => 19, :hour => 2, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
137
|
+
solar_position_calculation_1.sunset.should == "17:19"
|
138
|
+
|
139
|
+
solar_position_calculation_2 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.47", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2012, :month => 2, :day => 19, :hour => 22, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
140
|
+
solar_position_calculation_2.sunset.should == "17:19"
|
141
|
+
|
142
|
+
solar_position_calculation_1.sunset.should == solar_position_calculation_2.sunset
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
context "(solar energy and applications course - homework 2)" do
|
147
|
+
|
148
|
+
it "should calculate sunset with latitude 45 degrees 28 minutes" do
|
149
|
+
|
150
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.47", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2012, :month => 2, :day => 19, :hour => 12, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
151
|
+
solar_position_calculation_1.sunset.should == "17:19"
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
context "Angle of incidence" do
|
160
|
+
|
161
|
+
it "should calculate angle of incidence" do
|
162
|
+
|
163
|
+
solar_position_calculation_1 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.47", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 9, :day => 21, :hour => 10, :minute => 0, :surface_inclination => "0", :surface_azimuth => "0")
|
164
|
+
solar_position_calculation_1.angle_of_incidence.should be_within(0.1).of(58.73)
|
165
|
+
|
166
|
+
solar_position_calculation_2 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.47", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 1, :day => 21, :hour => 10, :minute => 0, :surface_inclination => "70", :surface_azimuth => "-45")
|
167
|
+
solar_position_calculation_2.angle_of_incidence.should be_within(0.1).of(13.28)
|
168
|
+
|
169
|
+
solar_position_calculation_3 = SolarGeometryCalculation::SolarPositionCalculation.new(:latitude => "45.47", :meridian => "-75", :longitude => "-73.75", :timezone_identifier => "America/Montreal", :year => 2010, :month => 7, :day => 24, :hour => 10, :minute => 0, :surface_inclination => "70", :surface_azimuth => "-45")
|
170
|
+
solar_position_calculation_3.angle_of_incidence.should == 32.78
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SolarGeometryCalculation::SolarTime do
|
4
|
+
|
5
|
+
context "Factory" do
|
6
|
+
|
7
|
+
it "should create an instance based on the standard time" do
|
8
|
+
|
9
|
+
solar_time = SolarGeometryCalculation::SolarTime.create_by_standard_time(2010, 9, 21, 12, 0, -75, -73.75, "America/Los_Angeles")
|
10
|
+
|
11
|
+
solar_time.standard_time_year.should == 2010
|
12
|
+
solar_time.standard_time_month.should == 9
|
13
|
+
solar_time.standard_time_day.should == 21
|
14
|
+
solar_time.standard_time_hour.should == 12
|
15
|
+
solar_time.standard_time_minute.should == 0
|
16
|
+
|
17
|
+
solar_time.year.should == 2010
|
18
|
+
solar_time.month.should == 9
|
19
|
+
solar_time.day.should == 21
|
20
|
+
solar_time.hour.should == 11
|
21
|
+
solar_time.minute.should == 12
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should create an instance based on the solar time values" do
|
26
|
+
|
27
|
+
solar_time = SolarGeometryCalculation::SolarTime.create_by_solar_time_values(2010, 9, 21, 11, 12, -75, -73.75, "America/Los_Angeles")
|
28
|
+
|
29
|
+
solar_time.year.should == 2010
|
30
|
+
solar_time.month.should == 9
|
31
|
+
solar_time.day.should == 21
|
32
|
+
solar_time.hour.should == 11
|
33
|
+
solar_time.minute.should == 12
|
34
|
+
|
35
|
+
solar_time.standard_time_year.should == 2010
|
36
|
+
solar_time.standard_time_month.should == 9
|
37
|
+
solar_time.standard_time_day.should == 21
|
38
|
+
solar_time.standard_time_hour.should == 12
|
39
|
+
solar_time.standard_time_minute.should == 0
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
context "helper" do
|
46
|
+
|
47
|
+
it "should get the time without daylight saving time offset from the time with daylight saving time offset" do
|
48
|
+
|
49
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_without_daylight_savings_time_offset, 2012, 07, 13, 10, 12, -75, -78.63, "America/Los_Angeles").should == [2012, 7, 13, 9, 12]
|
50
|
+
|
51
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_without_daylight_savings_time_offset, 2012, 8, 1, 0, 30, -75, -78.63, "America/Los_Angeles").should == [2012, 7, 31, 23, 30]
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should get the time with daylight saving time offset from the time without daylight saving time offset" do
|
56
|
+
|
57
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_with_daylight_savings_time_offset, 2012, 07, 13, 9, 12, -75, -78.63, "America/Los_Angeles").should == [2012, 7, 13, 10, 12]
|
58
|
+
|
59
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_with_daylight_savings_time_offset, 2012, 7, 31, 23, 30, -75, -78.63, "America/Los_Angeles").should == [2012, 8, 1, 0, 30]
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should calculate solar time" do
|
64
|
+
|
65
|
+
# Data for Toronto:
|
66
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_without_daylight_savings_time_offset_to_solar_time, 2010, 2, 19, 7, 14, -75, -78.63, "America/Los_Angeles").should == [2010, 2, 19, 6, 45]
|
67
|
+
|
68
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_without_daylight_savings_time_offset_to_solar_time, 2010, 9, 21, 10, 0, -75, -73.55, "America/Los_Angeles").should == [2010, 9, 21, 10, 12]
|
69
|
+
|
70
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_without_daylight_savings_time_offset_to_solar_time, 2010, 9, 21, 10, 0, BigDecimal("-75"), BigDecimal("-73.55"), "America/Los_Angeles").should == [2010, 9, 21, 10, 12]
|
71
|
+
|
72
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_without_daylight_savings_time_offset_to_solar_time, 2010, 9, 21, 10, 0, -75, -78.30, "America/Los_Angeles").should == [2010, 9, 21, 9, 53]
|
73
|
+
|
74
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_without_daylight_savings_time_offset_to_solar_time, 2010, 8, 1, 0, 0, -75, -78.30, "America/Los_Angeles").should == [2010, 7, 31, 23, 39]
|
75
|
+
|
76
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_without_daylight_savings_time_offset_to_solar_time, 2010, 7, 31, 23, 59, -75, -78.30, "America/Los_Angeles").should == [2010, 7, 31, 23, 38]
|
77
|
+
|
78
|
+
SolarGeometryCalculation::SolarTime.send(:standard_time_without_daylight_savings_time_offset_to_solar_time, 2010, 9, 21, 12, 0, -75, -73.75, "America/Los_Angeles").should == [2010, 9, 21, 12, 12]
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
context "(solar energy and applications course - homework 2)" do
|
85
|
+
|
86
|
+
it "should calculate average solar hour" do
|
87
|
+
|
88
|
+
solar_time_1 = SolarGeometryCalculation::SolarTime.create_by_standard_time(2012, 02, 19, 12, 30, -75, -73.75, "America/Los_Angeles")
|
89
|
+
solar_time_1.year.should == 2012
|
90
|
+
solar_time_1.month.should == 2
|
91
|
+
solar_time_1.day.should == 19
|
92
|
+
solar_time_1.hour.should == 12
|
93
|
+
solar_time_1.minute.should be_within(1).of(21)
|
94
|
+
|
95
|
+
solar_time_2 = SolarGeometryCalculation::SolarTime.create_by_standard_time(2012, 02, 19, 12, 30, BigDecimal("-75"), BigDecimal("-73.75"), "America/Los_Angeles")
|
96
|
+
solar_time_1.year.should == 2012
|
97
|
+
solar_time_1.month.should == 2
|
98
|
+
solar_time_1.day.should == 19
|
99
|
+
solar_time_1.hour.should == 12
|
100
|
+
solar_time_1.minute.should be_within(1).of(21)
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
context "converter" do
|
107
|
+
|
108
|
+
class TempSolarTimeConverter; include SolarGeometryCalculation::SolarTimeConverter; end
|
109
|
+
|
110
|
+
it "should calculate the adjustment by the Equation of time" do
|
111
|
+
|
112
|
+
TempSolarTimeConverter.new.send(:equation_of_time, 2012, 02, 19).should be_within(0.01).of(-14.11)
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: solar_geometry_calculation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tadatoshi Takahashi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tzinfo
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 4.1.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 4.1.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Mathematical part of obtaining solar geometry information
|
56
|
+
email:
|
57
|
+
- tadatoshi@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".ruby-gemset"
|
65
|
+
- ".ruby-version"
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- lib/solar_geometry_calculation.rb
|
71
|
+
- lib/solar_geometry_calculation/calculation_helper.rb
|
72
|
+
- lib/solar_geometry_calculation/solar_position_calculation.rb
|
73
|
+
- lib/solar_geometry_calculation/solar_time.rb
|
74
|
+
- lib/solar_geometry_calculation/version.rb
|
75
|
+
- solar_geometry_calculation.gemspec
|
76
|
+
- spec/solar_geometry_calculation/calculation_helper_spec.rb
|
77
|
+
- spec/solar_geometry_calculation/solar_position_calculation_spec.rb
|
78
|
+
- spec/solar_geometry_calculation/solar_time_spec.rb
|
79
|
+
- spec/spec_helper.rb
|
80
|
+
homepage: https://github.com/tadatoshi/solar_geometry_calculation
|
81
|
+
licenses: []
|
82
|
+
metadata: {}
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project: solar_geometry_calculation
|
99
|
+
rubygems_version: 2.2.2
|
100
|
+
signing_key:
|
101
|
+
specification_version: 4
|
102
|
+
summary: Performs calculation for solar geometry
|
103
|
+
test_files:
|
104
|
+
- spec/solar_geometry_calculation/calculation_helper_spec.rb
|
105
|
+
- spec/solar_geometry_calculation/solar_position_calculation_spec.rb
|
106
|
+
- spec/solar_geometry_calculation/solar_time_spec.rb
|
107
|
+
- spec/spec_helper.rb
|