Class: SolarEventCalculator

Inherits:
Object
  • Object
show all
Defined in:
lib/solareventcalculator.rb

Instance Method Summary collapse

Constructor Details

#initialize(date, latitude, longitude) ⇒ SolarEventCalculator


11
12
13
14
15
# File 'lib/solareventcalculator.rb', line 11

def initialize(date, latitude, longitude)
  @date = date
  @latitude = latitude
  @longitude = longitude
end

Instance Method Details

#compute_astronomical_sunrise(timezone) ⇒ Object


190
191
192
# File 'lib/solareventcalculator.rb', line 190

def compute_astronomical_sunrise(timezone)
  put_in_timezone(compute_utc_solar_event(108, true), timezone)
end

#compute_astronomical_sunset(timezone) ⇒ Object


194
195
196
# File 'lib/solareventcalculator.rb', line 194

def compute_astronomical_sunset(timezone)
  put_in_timezone(compute_utc_solar_event(108, false), timezone)
end

#compute_civil_sunrise(timezone) ⇒ Object


166
167
168
# File 'lib/solareventcalculator.rb', line 166

def compute_civil_sunrise(timezone)
  put_in_timezone(compute_utc_solar_event(96, true), timezone)
end

#compute_civil_sunset(timezone) ⇒ Object


170
171
172
# File 'lib/solareventcalculator.rb', line 170

def compute_civil_sunset(timezone)
  put_in_timezone(compute_utc_solar_event(96, false), timezone)
end

#compute_cosine_sun_declination(sinSunDeclination) ⇒ Object


67
68
69
70
# File 'lib/solareventcalculator.rb', line 67

def compute_cosine_sun_declination(sinSunDeclination)
  cosDec = BigDecimal.new(Math.cos(Math.asin(sinSunDeclination)).to_s)
  cosDec.round(4)
end

#compute_cosine_sun_local_hour(sunTrueLong, zenith) ⇒ Object


72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/solareventcalculator.rb', line 72

def compute_cosine_sun_local_hour(sunTrueLong, zenith)
  cosZenith = BigDecimal.new(Math.cos(degrees_as_rads(BigDecimal.new(zenith.to_s))).to_s)
  sinLatitude = BigDecimal.new(Math.sin(degrees_as_rads(@latitude)).to_s)
  cosLatitude = BigDecimal.new(Math.cos(degrees_as_rads(@latitude)).to_s)

  sinSunDeclination = compute_sin_sun_declination(sunTrueLong)
  top = cosZenith - (sinSunDeclination * sinLatitude)
  bottom = compute_cosine_sun_declination(sinSunDeclination) * cosLatitude

  cosLocalHour = top / bottom
  cosLocalHour.round(4)
end

#compute_lnghourObject


17
18
19
20
# File 'lib/solareventcalculator.rb', line 17

def compute_lnghour
  lngHour = @longitude / BigDecimal.new("15")
  lngHour.round(4)
end

#compute_local_hour_angle(cosSunLocalHour, isSunrise) ⇒ Object


85
86
87
88
89
90
91
92
# File 'lib/solareventcalculator.rb', line 85

def compute_local_hour_angle(cosSunLocalHour, isSunrise)
  acosH = BigDecimal.new(Math.acos(cosSunLocalHour).to_s)
  acosHDegrees = rads_as_degrees(acosH)

  localHourAngle = (isSunrise) ? BigDecimal.new("360") - acosHDegrees : acosHDegrees
  localHourAngle = localHourAngle / BigDecimal.new("15")
  localHourAngle.round(4)
end

#compute_local_mean_time(sunTrueLong, longHour, t, sunLocalHour) ⇒ Object


94
95
96
97
98
99
100
101
102
103
104
# File 'lib/solareventcalculator.rb', line 94

def compute_local_mean_time(sunTrueLong, longHour, t,  sunLocalHour)
  h = sunLocalHour
  ra = put_ra_in_correct_quadrant(sunTrueLong)

  parens = BigDecimal.new("0.06571") * t
  time = h + ra - parens - BigDecimal.new("6.622")

  utcTime = time - longHour
  utcTime = put_in_range(utcTime, 0, 24, 24)
  utcTime.round(4)
end

#compute_longitude_hour(isSunrise) ⇒ Object


22
23
24
25
26
# File 'lib/solareventcalculator.rb', line 22

def compute_longitude_hour(isSunrise)
  minuend = (isSunrise) ? BigDecimal.new("6") : BigDecimal.new("18")
  longHour = @date.yday + ((minuend - compute_lnghour) / BigDecimal.new("24"))
  longHour.round(4)
end

#compute_nautical_sunrise(timezone) ⇒ Object


182
183
184
# File 'lib/solareventcalculator.rb', line 182

def compute_nautical_sunrise(timezone)
  put_in_timezone(compute_utc_solar_event(102, true), timezone)
end

#compute_nautical_sunset(timezone) ⇒ Object


186
187
188
# File 'lib/solareventcalculator.rb', line 186

def compute_nautical_sunset(timezone)
  put_in_timezone(compute_utc_solar_event(102, false), timezone)
end

#compute_official_sunrise(timezone) ⇒ Object


174
175
176
# File 'lib/solareventcalculator.rb', line 174

def compute_official_sunrise(timezone)
  put_in_timezone(compute_utc_solar_event(90.8333, true), timezone)
end

#compute_official_sunset(timezone) ⇒ Object


178
179
180
# File 'lib/solareventcalculator.rb', line 178

def compute_official_sunset(timezone)
  put_in_timezone(compute_utc_solar_event(90.8333, false), timezone)
end

#compute_right_ascension(sunTrueLong) ⇒ Object


44
45
46
47
48
49
50
# File 'lib/solareventcalculator.rb', line 44

def compute_right_ascension(sunTrueLong)
  tanL = BigDecimal.new(Math.tan(degrees_as_rads(sunTrueLong).to_f).to_s)
  ra = rads_as_degrees(BigDecimal.new(Math.atan(BigDecimal.new("0.91764") * tanL).to_s))

  ra = put_in_range(ra, 0, 360, 360)
  ra.round(4)
end

#compute_sin_sun_declination(sunTrueLong) ⇒ Object


61
62
63
64
65
# File 'lib/solareventcalculator.rb', line 61

def compute_sin_sun_declination(sunTrueLong)
  sinL = BigDecimal.new(Math.sin(degrees_as_rads(sunTrueLong).to_f).to_s)
  sinDec = sinL * BigDecimal.new("0.39782")
  sinDec.round(4)
end

#compute_sun_mean_anomaly(longHour) ⇒ Object


28
29
30
31
# File 'lib/solareventcalculator.rb', line 28

def compute_sun_mean_anomaly(longHour)
  constant = BigDecimal.new("0.9856")
  ((longHour * constant) - BigDecimal.new("3.289")).round(4)
end

#compute_sun_true_longitude(meanAnomaly) ⇒ Object


33
34
35
36
37
38
39
40
41
42
# File 'lib/solareventcalculator.rb', line 33

def compute_sun_true_longitude(meanAnomaly)
  mAsRads = degrees_as_rads(meanAnomaly)
  sinM = BigDecimal.new(Math.sin(mAsRads.to_f).to_s)
  sinTwoM = BigDecimal.new(Math.sin((2 * mAsRads).to_f).to_s)
  firstParens = BigDecimal.new("1.916") * sinM
  secondParens = BigDecimal.new("0.020") * sinTwoM
  trueLong = meanAnomaly + firstParens + secondParens + BigDecimal.new("282.634")
  trueLong = put_in_range(trueLong, 0, 360, 360)
  trueLong.round(4)
end

#compute_utc_astronomical_sunriseObject


154
155
156
# File 'lib/solareventcalculator.rb', line 154

def compute_utc_astronomical_sunrise
  convert_to_datetime(compute_utc_solar_event(108, true))
end

#compute_utc_astronomical_sunsetObject


158
159
160
# File 'lib/solareventcalculator.rb', line 158

def compute_utc_astronomical_sunset
  convert_to_datetime(compute_utc_solar_event(108, false))
end

#compute_utc_civil_sunriseObject


130
131
132
# File 'lib/solareventcalculator.rb', line 130

def compute_utc_civil_sunrise
  convert_to_datetime(compute_utc_solar_event(96, true))
end

#compute_utc_civil_sunsetObject


134
135
136
# File 'lib/solareventcalculator.rb', line 134

def compute_utc_civil_sunset
  convert_to_datetime(compute_utc_solar_event(96, false))
end

#compute_utc_nautical_sunriseObject


146
147
148
# File 'lib/solareventcalculator.rb', line 146

def compute_utc_nautical_sunrise
  convert_to_datetime(compute_utc_solar_event(102, true))
end

#compute_utc_nautical_sunsetObject


150
151
152
# File 'lib/solareventcalculator.rb', line 150

def compute_utc_nautical_sunset
  convert_to_datetime(compute_utc_solar_event(102, false))
end

#compute_utc_official_sunriseObject


138
139
140
# File 'lib/solareventcalculator.rb', line 138

def compute_utc_official_sunrise
  convert_to_datetime(compute_utc_solar_event(90.8333, true))
end

#compute_utc_official_sunsetObject


142
143
144
# File 'lib/solareventcalculator.rb', line 142

def compute_utc_official_sunset
  convert_to_datetime(compute_utc_solar_event(90.8333, false))
end

#compute_utc_solar_event(zenith, isSunrise) ⇒ Object


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/solareventcalculator.rb', line 106

def compute_utc_solar_event(zenith, isSunrise)
  longHour = compute_lnghour
  eventLongHour = compute_longitude_hour(isSunrise)

  meanAnomaly = compute_sun_mean_anomaly(eventLongHour)
  sunTrueLong = compute_sun_true_longitude(meanAnomaly)
  cosineSunLocalHour = compute_cosine_sun_local_hour(sunTrueLong, zenith)

  if(cosineSunLocalHour > BigDecimal.new("1") || cosineSunLocalHour < BigDecimal.new("-1"))
    return nil
  end

  sunLocalHour = compute_local_hour_angle(cosineSunLocalHour, isSunrise)
  localMeanTime = compute_local_mean_time(sunTrueLong, longHour, eventLongHour, sunLocalHour)

  timeParts = localMeanTime.to_f.to_s.split('.')
  mins = BigDecimal.new("." + timeParts[1]) * BigDecimal.new("60")
  mins = mins.truncate()
  mins = pad_minutes(mins.to_i)
  hours = timeParts[0]

  Time.utc(@date.year, @date.mon, @date.mday, hours, pad_minutes(mins.to_i))
end

#convert_to_datetime(time) ⇒ Object


162
163
164
# File 'lib/solareventcalculator.rb', line 162

def convert_to_datetime(time)
  DateTime.parse("#{@date.strftime}T#{time.hour}:#{time.min}:00+0000") unless time == nil
end

#degrees_as_rads(degrees) ⇒ Object


236
237
238
239
240
# File 'lib/solareventcalculator.rb', line 236

def degrees_as_rads(degrees)
  pi = BigDecimal(Math::PI.to_s)
  radian = pi / BigDecimal.new("180")
  degrees * radian
end

#get_utc_offset(timezone) ⇒ Object


212
213
214
215
216
# File 'lib/solareventcalculator.rb', line 212

def get_utc_offset(timezone)
  tz = TZInfo::Timezone.get(timezone)
  noonUTC = Time.gm(@date.year, @date.mon, @date.mday, 12, 0)
  tz.utc_to_local(noonUTC) - noonUTC
end

#pad_minutes(minutes) ⇒ Object


218
219
220
221
222
223
224
# File 'lib/solareventcalculator.rb', line 218

def pad_minutes(minutes)
  if(minutes < 10)
    "0" + minutes.to_s
  else
    minutes
  end
end

#put_in_range(number, lower, upper, adjuster) ⇒ Object


226
227
228
229
230
231
232
233
234
# File 'lib/solareventcalculator.rb', line 226

def put_in_range(number, lower, upper, adjuster)
  if number > upper then
    number -= adjuster
  elsif number < lower then
    number += adjuster
  else
    number
  end
end

#put_in_timezone(utcTime, timezone) ⇒ Object


198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/solareventcalculator.rb', line 198

def put_in_timezone(utcTime, timezone)
  tz = TZInfo::Timezone.get(timezone)
  # puts "UTCTime #{utcTime}"
  local = utcTime + get_utc_offset(timezone)
  # puts "LocalTime #{local}"

  offset = (get_utc_offset(timezone) / 60 / 60).to_i
  offset = (offset > 0) ? "+" + offset.to_s : offset.to_s

  timeInZone = DateTime.parse("#{@date.strftime}T#{local.strftime('%H:%M:%S')}#{offset}")
  # puts "CALC:timeInZone #{timeInZone}"
  timeInZone
end

#put_ra_in_correct_quadrant(sunTrueLong) ⇒ Object


52
53
54
55
56
57
58
59
# File 'lib/solareventcalculator.rb', line 52

def put_ra_in_correct_quadrant(sunTrueLong)
  lQuadrant = BigDecimal.new("90") * (sunTrueLong / BigDecimal.new("90")).floor
  raQuadrant = BigDecimal.new("90") * (compute_right_ascension(sunTrueLong) / BigDecimal.new("90")).floor

  ra = compute_right_ascension(sunTrueLong) + (lQuadrant - raQuadrant)
  ra = ra / BigDecimal.new("15")
  ra.round(4)
end

#rads_as_degrees(radians) ⇒ Object


242
243
244
245
246
# File 'lib/solareventcalculator.rb', line 242

def rads_as_degrees(radians)
  pi = BigDecimal(Math::PI.to_s)
  degree = BigDecimal.new("180") / pi
  radians * degree
end