solar_geometry_calculation 0.1.4
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.
- 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
|